Bug 1312865 - ClearBuffer and similar funcs should mirror Clear's behavior. - r=daoshengmu
MozReview-Commit-ID: 4Gm5aNZ1PXX
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -51,16 +51,20 @@ WebGL2Context::BlitFramebuffer(GLint src
if (drawFB &&
!drawFB->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
{
return;
}
////
+ if (!mBoundReadFramebuffer) {
+ ClearBackbufferIfNeeded();
+ }
+
WebGLFramebuffer::BlitFramebuffer(this,
readFB, srcX0, srcY0, srcX1, srcY1,
drawFB, dstX0, dstY0, dstX1, dstY1,
mask, filter);
}
void
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
@@ -216,16 +220,26 @@ WebGLContext::ValidateInvalidateFramebuf
MOZ_CRASH();
}
}
*out_glNumAttachments = scopedVector->size();
*out_glAttachments = scopedVector->data();
}
}
+ ////
+
+ if (!fb) {
+ ClearBackbufferIfNeeded();
+
+ // Don't do more validation after these.
+ Invalidate();
+ mShouldPresent = true;
+ }
+
return true;
}
void
WebGL2Context::InvalidateFramebuffer(GLenum target,
const dom::Sequence<GLenum>& attachments,
ErrorResult& rv)
{
@@ -256,31 +270,31 @@ WebGL2Context::InvalidateFramebuffer(GLe
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 (!ValidateNonNegative(funcName, "width", width) ||
+ !ValidateNonNegative(funcName, "height", height))
+ {
+ return;
+ }
+
std::vector<GLenum> scopedVector;
GLsizei glNumAttachments;
const GLenum* glAttachments;
if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
&glNumAttachments, &glAttachments))
{
return;
}
- if (!ValidateNonNegative(funcName, "width", width) ||
- !ValidateNonNegative(funcName, "height", height))
- {
- return;
- }
-
////
// 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);
--- a/dom/canvas/WebGL2ContextMRTs.cpp
+++ b/dom/canvas/WebGL2ContextMRTs.cpp
@@ -78,40 +78,46 @@ WebGL2Context::ValidateClearBuffer(const
void
WebGL2Context::ClearBufferfv(GLenum buffer, GLint drawBuffer, const Float32Arr& src,
GLuint srcElemOffset)
{
const char funcName[] = "clearBufferfv";
if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset))
return;
+ ScopedDrawCallWrapper wrapper(*this);
+
const auto ptr = src.elemBytes + srcElemOffset;
gl->fClearBufferfv(buffer, drawBuffer, ptr);
}
void
WebGL2Context::ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32Arr& src,
GLuint srcElemOffset)
{
const char funcName[] = "clearBufferiv";
if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset))
return;
+ ScopedDrawCallWrapper wrapper(*this);
+
const auto ptr = src.elemBytes + srcElemOffset;
gl->fClearBufferiv(buffer, drawBuffer, ptr);
}
void
WebGL2Context::ClearBufferuiv(GLenum buffer, GLint drawBuffer, const Uint32Arr& src,
- GLuint srcElemOffset)
+ GLuint srcElemOffset)
{
const char funcName[] = "clearBufferuiv";
if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset))
return;
+ ScopedDrawCallWrapper wrapper(*this);
+
const auto ptr = src.elemBytes + srcElemOffset;
gl->fClearBufferuiv(buffer, drawBuffer, ptr);
}
////
void
WebGL2Context::ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth,
@@ -119,12 +125,14 @@ WebGL2Context::ClearBufferfi(GLenum buff
{
const char funcName[] = "clearBufferfi";
if (!ValidateClearBuffer(funcName, LOCAL_GL_DEPTH, drawBuffer, 1, 0))
return;
if (buffer != LOCAL_GL_DEPTH_STENCIL)
return ErrorInvalidEnumInfo(funcName, buffer);
+ ScopedDrawCallWrapper wrapper(*this);
+
gl->fClearBufferfi(buffer, drawBuffer, depth, stencil);
}
} // namespace mozilla
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -2033,55 +2033,64 @@ WebGLContext::ValidateCurFBForRead(const
}
return mBoundReadFramebuffer->ValidateForRead(funcName, out_format, out_width,
out_height);
}
////////////////////////////////////////////////////////////////////////////////
-WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
+WebGLContext::ScopedDrawCallWrapper::ScopedDrawCallWrapper(WebGLContext& webgl)
: mWebGL(webgl)
, mFakeNoAlpha(ShouldFakeNoAlpha(webgl))
, mFakeNoDepth(ShouldFakeNoDepth(webgl))
, mFakeNoStencil(ShouldFakeNoStencil(webgl))
{
+ if (!mWebGL.mBoundDrawFramebuffer) {
+ mWebGL.ClearBackbufferIfNeeded();
+ }
+
if (mFakeNoAlpha) {
mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
mWebGL.mColorWriteMask[1],
mWebGL.mColorWriteMask[2],
false);
}
if (mFakeNoDepth) {
mWebGL.gl->fDisable(LOCAL_GL_DEPTH_TEST);
}
if (mFakeNoStencil) {
mWebGL.gl->fDisable(LOCAL_GL_STENCIL_TEST);
}
}
-WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround()
+WebGLContext::ScopedDrawCallWrapper::~ScopedDrawCallWrapper()
{
if (mFakeNoAlpha) {
mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
mWebGL.mColorWriteMask[1],
mWebGL.mColorWriteMask[2],
mWebGL.mColorWriteMask[3]);
}
if (mFakeNoDepth) {
mWebGL.gl->fEnable(LOCAL_GL_DEPTH_TEST);
}
if (mFakeNoStencil) {
MOZ_ASSERT(mWebGL.mStencilTestEnabled);
mWebGL.gl->fEnable(LOCAL_GL_STENCIL_TEST);
}
+
+ if (!mWebGL.mBoundDrawFramebuffer) {
+ mWebGL.Invalidate();
+ mWebGL.mShouldPresent = true;
+ }
}
/*static*/ bool
-WebGLContext::ScopedMaskWorkaround::HasDepthButNoStencil(const WebGLFramebuffer* fb)
+WebGLContext::ScopedDrawCallWrapper::HasDepthButNoStencil(const WebGLFramebuffer* fb)
{
const auto& depth = fb->DepthAttachment();
const auto& stencil = fb->StencilAttachment();
return depth.IsDefined() && !stencil.IsDefined();
}
////////////////////////////////////////
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1895,17 +1895,17 @@ protected:
bool mNeedsFakeNoDepth;
bool mNeedsFakeNoStencil;
bool mNeedsEmulatedLoneDepthStencil;
const bool mAllowFBInvalidation;
bool Has64BitTimestamps() const;
- struct ScopedMaskWorkaround {
+ struct ScopedDrawCallWrapper final {
WebGLContext& mWebGL;
const bool mFakeNoAlpha;
const bool mFakeNoDepth;
const bool mFakeNoStencil;
static bool ShouldFakeNoAlpha(WebGLContext& webgl) {
// We should only be doing this if we're about to draw to the backbuffer, but
// the backbuffer needs to have this fake-no-alpha workaround.
@@ -1944,19 +1944,19 @@ protected:
HasDepthButNoStencil(webgl.mBoundDrawFramebuffer))
{
return true;
}
return false;
}
- explicit ScopedMaskWorkaround(WebGLContext& webgl);
+ explicit ScopedDrawCallWrapper(WebGLContext& webgl);
- ~ScopedMaskWorkaround();
+ ~ScopedDrawCallWrapper();
};
void LoseOldestWebGLContextIfLimitExceeded();
void UpdateLastUseIndex();
template <typename WebGLObjectType>
JS::Value WebGLObjectAsJSValue(JSContext* cx, const WebGLObjectType*,
ErrorResult& rv) const;
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -509,17 +509,17 @@ WebGLContext::DrawArrays(GLenum mode, GL
return;
const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
instanceCount, &error);
if (error)
return;
{
- ScopedMaskWorkaround autoMask(*this);
+ ScopedDrawCallWrapper wrapper(*this);
gl->fDrawArrays(mode, first, vertCount);
}
Draw_cleanup(funcName);
scopedTF.Advance();
}
void
@@ -548,17 +548,17 @@ WebGLContext::DrawArraysInstanced(GLenum
return;
const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
instanceCount, &error);
if (error)
return;
{
- ScopedMaskWorkaround autoMask(*this);
+ ScopedDrawCallWrapper wrapper(*this);
gl->fDrawArraysInstanced(mode, first, vertCount, instanceCount);
}
Draw_cleanup(funcName);
scopedTF.Advance();
}
////////////////////////////////////////
@@ -714,17 +714,17 @@ WebGLContext::DrawElements(GLenum mode,
return;
const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
&error);
if (error)
return;
{
- ScopedMaskWorkaround autoMask(*this);
+ ScopedDrawCallWrapper wrapper(*this);
gl->fDrawElements(mode, vertCount, type,
reinterpret_cast<GLvoid*>(byteOffset));
}
Draw_cleanup(funcName);
}
void
@@ -749,36 +749,30 @@ WebGLContext::DrawElementsInstanced(GLen
return;
const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
&error);
if (error)
return;
{
- ScopedMaskWorkaround autoMask(*this);
+ ScopedDrawCallWrapper wrapper(*this);
gl->fDrawElementsInstanced(mode, vertCount, type,
reinterpret_cast<GLvoid*>(byteOffset),
instanceCount);
}
Draw_cleanup(funcName);
}
////////////////////////////////////////
void
WebGLContext::Draw_cleanup(const char* funcName)
{
- if (!mBoundDrawFramebuffer) {
- Invalidate();
- mShouldPresent = true;
- MOZ_ASSERT(!mBackbufferNeedsClear);
- }
-
if (gl->WorkAroundDriverBugs()) {
if (gl->Renderer() == gl::GLRenderer::Tegra) {
mDrawCallsSinceLastFlush++;
if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
gl->fFlush();
mDrawCallsSinceLastFlush = 0;
}
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -27,34 +27,24 @@ WebGLContext::Clear(GLbitfield mask)
return ErrorInvalidValue("%s: invalid mask bits", funcName);
if (mask == 0) {
GenerateWarning("Calling gl.clear(0) has no effect.");
} else if (mRasterizerDiscardEnabled) {
GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects.");
}
- if (mBoundDrawFramebuffer) {
- if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
- return;
-
- gl->fClear(mask);
+ if (mBoundDrawFramebuffer &&
+ !mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
+ {
return;
- } else {
- ClearBackbufferIfNeeded();
}
- // Ok, we're clearing the default framebuffer/screen.
- {
- ScopedMaskWorkaround autoMask(*this);
- gl->fClear(mask);
- }
-
- Invalidate();
- mShouldPresent = true;
+ ScopedDrawCallWrapper wrapper(*this);
+ gl->fClear(mask);
}
static GLfloat
GLClampFloat(GLfloat val)
{
if (val < 0.0)
return 0.0;
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -1814,16 +1814,17 @@ WebGLFramebuffer::BlitFramebuffer(WebGLC
} else if (!srcFB && !dstFB) {
webgl->ErrorInvalidOperation("%s: Feedback with default framebuffer.", funcName);
return;
}
////
gl->MakeCurrent();
+ WebGLContext::ScopedDrawCallWrapper wrapper(*webgl);
gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
}
////////////////////////////////////////////////////////////////////////////////
// Goop.
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -978,37 +978,45 @@ private:
public:
void fClear(GLbitfield mask) {
BeforeGLDrawCall();
raw_fClear(mask);
AfterGLDrawCall();
}
void fClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
+ BeforeGLDrawCall();
BEFORE_GL_CALL;
mSymbols.fClearBufferfi(buffer, drawbuffer, depth, stencil);
AFTER_GL_CALL;
+ AfterGLDrawCall();
}
void fClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {
+ BeforeGLDrawCall();
BEFORE_GL_CALL;
mSymbols.fClearBufferfv(buffer, drawbuffer, value);
AFTER_GL_CALL;
+ AfterGLDrawCall();
}
void fClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {
+ BeforeGLDrawCall();
BEFORE_GL_CALL;
mSymbols.fClearBufferiv(buffer, drawbuffer, value);
AFTER_GL_CALL;
+ AfterGLDrawCall();
}
void fClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
+ BeforeGLDrawCall();
BEFORE_GL_CALL;
mSymbols.fClearBufferuiv(buffer, drawbuffer, value);
AFTER_GL_CALL;
+ AfterGLDrawCall();
}
void fClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
BEFORE_GL_CALL;
mSymbols.fClearColor(r, g, b, a);
AFTER_GL_CALL;
}