--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -100,60 +100,73 @@ WebGL2Context::GetFramebufferAttachmentP
GLenum attachment,
GLenum pname,
ErrorResult& out_error)
{
return WebGLContext::GetFramebufferAttachmentParameter(cx, target, attachment, pname,
out_error);
}
-// Map attachments intended for the default buffer, to attachments for a non-
-// default buffer.
+////
+
static bool
-TranslateDefaultAttachments(const dom::Sequence<GLenum>& in, dom::Sequence<GLenum>* out)
+ValidateBackbufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
+ GLenum attachment)
{
- for (size_t i = 0; i < in.Length(); i++) {
- switch (in[i]) {
- case LOCAL_GL_COLOR:
- if (!out->AppendElement(LOCAL_GL_COLOR_ATTACHMENT0, fallible)) {
- return false;
- }
- break;
+ switch (attachment) {
+ case LOCAL_GL_COLOR:
+ case LOCAL_GL_DEPTH:
+ case LOCAL_GL_STENCIL:
+ return true;
- case LOCAL_GL_DEPTH:
- if (!out->AppendElement(LOCAL_GL_DEPTH_ATTACHMENT, fallible)) {
- return false;
- }
- break;
+ default:
+ webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
+ funcName, attachment);
+ return false;
+ }
+}
- case LOCAL_GL_STENCIL:
- if (!out->AppendElement(LOCAL_GL_STENCIL_ATTACHMENT, fallible)) {
- return false;
- }
- break;
- }
+static bool
+ValidateFramebufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
+ GLenum attachment)
+{
+ if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
+ attachment <= webgl->LastColorAttachmentEnum())
+ {
+ return true;
}
- return true;
+ switch (attachment) {
+ case LOCAL_GL_DEPTH_ATTACHMENT:
+ case LOCAL_GL_STENCIL_ATTACHMENT:
+ case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
+ return true;
+
+ default:
+ webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
+ funcName, attachment);
+ return false;
+ }
}
-void
-WebGL2Context::InvalidateFramebuffer(GLenum target,
- const dom::Sequence<GLenum>& attachments,
- ErrorResult& rv)
+bool
+WebGLContext::ValidateInvalidateFramebuffer(const char* funcName, GLenum target,
+ const dom::Sequence<GLenum>& attachments,
+ ErrorResult* const out_rv,
+ std::vector<GLenum>* const scopedVector,
+ GLsizei* const out_glNumAttachments,
+ const GLenum** const out_glAttachments)
{
- const char funcName[] = "invalidateSubFramebuffer";
+ if (IsContextLost())
+ return false;
- if (IsContextLost())
- return;
-
- MakeContextCurrent();
+ gl->MakeCurrent();
if (!ValidateFramebufferTarget(target, funcName))
- return;
+ return false;
const WebGLFramebuffer* fb;
bool isDefaultFB;
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
case LOCAL_GL_DRAW_FRAMEBUFFER:
fb = mBoundDrawFramebuffer;
isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
@@ -163,111 +176,118 @@ WebGL2Context::InvalidateFramebuffer(GLe
fb = mBoundReadFramebuffer;
isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
break;
default:
MOZ_CRASH("GFX: Bad target.");
}
- const bool badColorAttachmentIsInvalidOp = true;
- for (size_t i = 0; i < attachments.Length(); i++) {
- if (!ValidateFramebufferAttachment(fb, attachments[i], funcName,
- badColorAttachmentIsInvalidOp))
- {
- return;
+ *out_glNumAttachments = attachments.Length();
+ *out_glAttachments = attachments.Elements();
+
+ if (fb) {
+ for (const auto& attachment : attachments) {
+ if (!ValidateFramebufferAttachmentEnum(this, funcName, attachment))
+ return false;
+ }
+ } else {
+ for (const auto& attachment : attachments) {
+ if (!ValidateBackbufferAttachmentEnum(this, funcName, attachment))
+ return false;
+ }
+
+ if (!isDefaultFB) {
+ MOZ_ASSERT(scopedVector->empty());
+ scopedVector->reserve(attachments.Length());
+ for (const auto& attachment : attachments) {
+ switch (attachment) {
+ case LOCAL_GL_COLOR:
+ scopedVector->push_back(LOCAL_GL_COLOR_ATTACHMENT0);
+ break;
+
+ case LOCAL_GL_DEPTH:
+ scopedVector->push_back(LOCAL_GL_DEPTH_ATTACHMENT);
+ break;
+
+ case LOCAL_GL_STENCIL:
+ scopedVector->push_back(LOCAL_GL_STENCIL_ATTACHMENT);
+ break;
+
+ default:
+ MOZ_CRASH();
+ }
+ }
+ *out_glNumAttachments = scopedVector->size();
+ *out_glAttachments = scopedVector->data();
}
}
- // InvalidateFramebuffer is a hint to the driver. Should be OK to
- // skip calls if not supported, for example by OSX 10.9 GL
- // drivers.
- if (!gl->IsSupported(gl::GLFeature::invalidate_framebuffer))
- return;
+ return true;
+}
+
+void
+WebGL2Context::InvalidateFramebuffer(GLenum target,
+ const dom::Sequence<GLenum>& attachments,
+ ErrorResult& rv)
+{
+ const char funcName[] = "invalidateSubFramebuffer";
- if (!fb && !isDefaultFB) {
- dom::Sequence<GLenum> tmpAttachments;
- if (!TranslateDefaultAttachments(attachments, &tmpAttachments)) {
- rv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
+ std::vector<GLenum> scopedVector;
+ GLsizei glNumAttachments;
+ const GLenum* glAttachments;
+ if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
+ &glNumAttachments, &glAttachments))
+ {
+ return;
+ }
+
+ ////
- gl->fInvalidateFramebuffer(target, tmpAttachments.Length(),
- tmpAttachments.Elements());
- } else {
- gl->fInvalidateFramebuffer(target, attachments.Length(), attachments.Elements());
+ // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
+ const bool useFBInvalidation = (mAllowFBInvalidation &&
+ gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
+ if (useFBInvalidation) {
+ gl->fInvalidateFramebuffer(target, glNumAttachments, glAttachments);
+ return;
}
+
+ // Use clear instead?
+ // No-op for now.
}
void
WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
GLint x, GLint y, GLsizei width, GLsizei height,
ErrorResult& rv)
{
const char funcName[] = "invalidateSubFramebuffer";
- if (IsContextLost())
- return;
-
- MakeContextCurrent();
-
- if (!ValidateFramebufferTarget(target, funcName))
- return;
-
- if (width < 0 || height < 0) {
- ErrorInvalidValue("%s: width and height must be >= 0.", funcName);
+ std::vector<GLenum> scopedVector;
+ GLsizei glNumAttachments;
+ const GLenum* glAttachments;
+ if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
+ &glNumAttachments, &glAttachments))
+ {
return;
}
- const WebGLFramebuffer* fb;
- bool isDefaultFB;
- switch (target) {
- case LOCAL_GL_FRAMEBUFFER:
- case LOCAL_GL_DRAW_FRAMEBUFFER:
- fb = mBoundDrawFramebuffer;
- isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
- break;
+ ////
- case LOCAL_GL_READ_FRAMEBUFFER:
- fb = mBoundReadFramebuffer;
- isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
- break;
-
- default:
- MOZ_CRASH("GFX: Bad target.");
+ // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
+ const bool useFBInvalidation = (mAllowFBInvalidation &&
+ gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
+ if (useFBInvalidation) {
+ gl->fInvalidateSubFramebuffer(target, glNumAttachments, glAttachments, x, y,
+ width, height);
+ return;
}
- const bool badColorAttachmentIsInvalidOp = true;
- for (size_t i = 0; i < attachments.Length(); i++) {
- if (!ValidateFramebufferAttachment(fb, attachments[i], funcName,
- badColorAttachmentIsInvalidOp))
- {
- return;
- }
- }
-
- // InvalidateFramebuffer is a hint to the driver. Should be OK to
- // skip calls if not supported, for example by OSX 10.9 GL
- // drivers.
- if (!gl->IsSupported(gl::GLFeature::invalidate_framebuffer))
- return;
-
- if (!fb && !isDefaultFB) {
- dom::Sequence<GLenum> tmpAttachments;
- if (!TranslateDefaultAttachments(attachments, &tmpAttachments)) {
- rv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
-
- gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(),
- tmpAttachments.Elements(), x, y, width, height);
- } else {
- gl->fInvalidateSubFramebuffer(target, attachments.Length(),
- attachments.Elements(), x, y, width, height);
- }
+ // Use clear instead?
+ // No-op for now.
}
void
WebGL2Context::ReadBuffer(GLenum mode)
{
const char funcName[] = "readBuffer";
if (IsContextLost())
return;
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -121,16 +121,17 @@ WebGLContext::WebGLContext()
, mLayerIsMirror(false)
, mBypassShaderValidation(false)
, mBuffersForUB_Dirty(true)
, mContextLossHandler(this)
, mNeedsFakeNoAlpha(false)
, mNeedsFakeNoDepth(false)
, mNeedsFakeNoStencil(false)
, mNeedsEmulatedLoneDepthStencil(false)
+ , mAllowFBInvalidation(gfxPrefs::WebGLFBInvalidation())
{
mGeneration = 0;
mInvalidated = false;
mCapturedFrameInvalidated = false;
mShouldPresent = true;
mResetLayer = true;
mOptionsFrozen = false;
mMinCapability = false;
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -531,21 +531,16 @@ public:
void Flush();
void Finish();
void FramebufferRenderbuffer(GLenum target, GLenum attachment,
GLenum rbTarget, WebGLRenderbuffer* rb);
void FramebufferTexture2D(GLenum target, GLenum attachment,
GLenum texImageTarget, WebGLTexture* tex,
GLint level);
- // Framebuffer validation
- bool ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
- const char* funcName,
- bool badColorAttachmentIsInvalidOp = false);
-
void FrontFace(GLenum mode);
already_AddRefed<WebGLActiveInfo> GetActiveAttrib(const WebGLProgram& prog,
GLuint index);
already_AddRefed<WebGLActiveInfo> GetActiveUniform(const WebGLProgram& prog,
GLuint index);
void
GetAttachedShaders(const WebGLProgram& prog,
@@ -1682,16 +1677,22 @@ protected:
nsTArray<WebGLRefPtr<WebGLSampler> > mBoundSamplers;
void ResolveTexturesForDraw() const;
WebGLRefPtr<WebGLProgram> mCurrentProgram;
RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo;
bool ValidateFramebufferTarget(GLenum target, const char* const info);
+ bool ValidateInvalidateFramebuffer(const char* funcName, GLenum target,
+ const dom::Sequence<GLenum>& attachments,
+ ErrorResult* const out_rv,
+ std::vector<GLenum>* const scopedVector,
+ GLsizei* const out_glNumAttachments,
+ const GLenum** const out_glAttachments);
WebGLRefPtr<WebGLFramebuffer> mBoundDrawFramebuffer;
WebGLRefPtr<WebGLFramebuffer> mBoundReadFramebuffer;
WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
WebGLRefPtr<WebGLTransformFeedback> mBoundTransformFeedback;
WebGLRefPtr<WebGLVertexArray> mBoundVertexArray;
LinkedList<WebGLBuffer> mBuffers;
@@ -1823,16 +1824,18 @@ protected:
uint64_t mLastUseIndex;
bool mNeedsFakeNoAlpha;
bool mNeedsFakeNoDepth;
bool mNeedsFakeNoStencil;
bool mNeedsEmulatedLoneDepthStencil;
+ const bool mAllowFBInvalidation;
+
bool Has64BitTimestamps() const;
struct ScopedMaskWorkaround {
WebGLContext& mWebGL;
const bool mFakeNoAlpha;
const bool mFakeNoDepth;
const bool mFakeNoStencil;
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -192,60 +192,16 @@ WebGLContext::ValidateDrawModeEnum(GLenu
default:
ErrorInvalidEnumInfo(info, mode);
return false;
}
}
bool
-WebGLContext::ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
- const char* funcName,
- bool badColorAttachmentIsInvalidOp)
-{
- if (!fb) {
- switch (attachment) {
- case LOCAL_GL_COLOR:
- case LOCAL_GL_DEPTH:
- case LOCAL_GL_STENCIL:
- return true;
-
- default:
- ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
- funcName, attachment);
- return false;
- }
- }
-
- if (attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
- attachment == LOCAL_GL_STENCIL_ATTACHMENT ||
- attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
- {
- return true;
- }
-
- if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
- attachment <= LastColorAttachmentEnum())
- {
- return true;
- }
-
- if (badColorAttachmentIsInvalidOp &&
- attachment >= LOCAL_GL_COLOR_ATTACHMENT0)
- {
- const uint32_t offset = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
- ErrorInvalidOperation("%s: Bad color attachment: COLOR_ATTACHMENT%u. (0x%04x)",
- funcName, offset, attachment);
- } else {
- ErrorInvalidEnum("%s: attachment: Bad attachment 0x%x.", funcName, attachment);
- }
- return false;
-}
-
-bool
WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName)
{
/* GLES 2.0.25, p38:
* If the value of location is -1, the Uniform* commands will silently
* ignore the data passed in, and the current uniform values will not be
* changed.
*/
if (!loc)
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -603,16 +603,17 @@ private:
DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false);
DECL_GFX_PREF(Live, "webgl.lose-context-on-memory-pressure", WebGLLoseContextOnMemoryPressure, bool, false);
DECL_GFX_PREF(Live, "webgl.max-warnings-per-context", WebGLMaxWarningsPerContext, uint32_t, 32);
DECL_GFX_PREF(Live, "webgl.min_capability_mode", WebGLMinCapabilityMode, bool, false);
DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, bool, false);
DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false);
DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true);
DECL_GFX_PREF(Live, "webgl.allow-immediate-queries", WebGLImmediateQueries, bool, false);
+ DECL_GFX_PREF(Live, "webgl.allow-fb-invalidation", WebGLFBInvalidation, bool, false);
DECL_GFX_PREF(Live, "webgl.webgl2-compat-mode", WebGL2CompatMode, bool, false);
// WARNING:
// Please make sure that you've added your new preference to the list above in alphabetical order.
// Please do not just append it to the end of the list.
public:
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4489,16 +4489,17 @@ pref("webgl.lose-context-on-memory-press
pref("webgl.can-lose-context-in-foreground", true);
pref("webgl.restore-context-when-visible", true);
pref("webgl.max-warnings-per-context", 32);
pref("webgl.enable-draft-extensions", false);
pref("webgl.enable-privileged-extensions", false);
pref("webgl.bypass-shader-validation", false);
pref("webgl.disable-fail-if-major-performance-caveat", false);
pref("webgl.disable-DOM-blit-uploads", false);
+pref("webgl.allow-fb-invalidation", false);
pref("webgl.webgl2-compat-mode", false);
pref("webgl.enable-webgl2", true);
#ifdef RELEASE_OR_BETA
// Keep this disabled on Release and Beta for now. (see bug 1171228)
pref("webgl.enable-debug-renderer-info", false);
#else