From afce20bb053e07e0f7cd20fd94d15d963984f376 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Thu, 16 Dec 2010 23:19:28 -0800 Subject: [PATCH] Bug 615741 - Too large canvases don't draw and be black. r=joe a=joe --- gfx/layers/opengl/CanvasLayerOGL.cpp | 42 ++++++++++++++++++++++++++-- gfx/layers/opengl/CanvasLayerOGL.h | 4 ++- gfx/thebes/GLContext.cpp | 2 ++ gfx/thebes/GLContext.h | 4 +++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/gfx/layers/opengl/CanvasLayerOGL.cpp b/gfx/layers/opengl/CanvasLayerOGL.cpp index 3b5963fb399..cfcfa66d88d 100644 --- a/gfx/layers/opengl/CanvasLayerOGL.cpp +++ b/gfx/layers/opengl/CanvasLayerOGL.cpp @@ -103,6 +103,18 @@ CanvasLayerOGL::Initialize(const Data& aData) } mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); + + // Check the maximum texture size supported by GL. glTexImage2D supports + // images of up to 2 + GL_MAX_TEXTURE_SIZE + GLint texSize = gl()->GetMaxTextureSize(); + if (mBounds.width > (2 + texSize) || mBounds.height > (2 + texSize)) { + mDelayedUpdates = PR_TRUE; + MakeTexture(); + // This should only ever occur with 2d canvas, WebGL can't already have a texture + // of this size can it? + NS_ABORT_IF_FALSE(mCanvasSurface, + "Invalid texture size when WebGL surface already exists at that size?"); + } } void @@ -125,7 +137,7 @@ CanvasLayerOGL::MakeTexture() void CanvasLayerOGL::Updated(const nsIntRect& aRect) { - if (mDestroyed) { + if (mDestroyed || mDelayedUpdates) { return; } @@ -202,6 +214,7 @@ CanvasLayerOGL::Updated(const nsIntRect& aRect) } if (newTexture) { + gl()->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, @@ -250,6 +263,8 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination, bool useGLContext = mCanvasGLContext && mCanvasGLContext->GetContextType() == gl()->GetContextType(); + nsIntRect drawRect = mBounds; + if (useGLContext) { mCanvasGLContext->MakeCurrent(); mCanvasGLContext->fFlush(); @@ -257,6 +272,29 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination, gl()->MakeCurrent(); gl()->BindTex2DOffscreen(mCanvasGLContext); DEBUG_GL_ERROR_CHECK(gl()); + } else if (mDelayedUpdates) { + NS_ABORT_IF_FALSE(mCanvasSurface, "WebGL canvases should always be using full texture upload"); + + drawRect.IntersectRect(drawRect, GetEffectiveVisibleRegion().GetBounds()); + + nsRefPtr imageSurface = + new gfxImageSurface(gfxIntSize(drawRect.width, drawRect.height), + gfxASurface::ImageFormatARGB32); + nsRefPtr ctx = new gfxContext(imageSurface); + ctx->Translate(gfxPoint(-drawRect.x, -drawRect.y)); + ctx->SetOperator(gfxContext::OPERATOR_SOURCE); + ctx->SetSource(mCanvasSurface); + ctx->Paint(); + + gl()->fTexImage2D(LOCAL_GL_TEXTURE_2D, + 0, + LOCAL_GL_RGBA, + drawRect.width, + drawRect.height, + 0, + LOCAL_GL_RGBA, + LOCAL_GL_UNSIGNED_BYTE, + imageSurface->Data()); } program = mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(), @@ -265,7 +303,7 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination, ApplyFilter(mFilter); program->Activate(); - program->SetLayerQuadRect(mBounds); + program->SetLayerQuadRect(drawRect); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); diff --git a/gfx/layers/opengl/CanvasLayerOGL.h b/gfx/layers/opengl/CanvasLayerOGL.h index 8092062f42b..8cad80cb1b3 100644 --- a/gfx/layers/opengl/CanvasLayerOGL.h +++ b/gfx/layers/opengl/CanvasLayerOGL.h @@ -57,7 +57,8 @@ public: CanvasLayerOGL(LayerManagerOGL *aManager) : CanvasLayer(aManager, NULL), LayerOGL(aManager), - mTexture(0) + mTexture(0), + mDelayedUpdates(PR_FALSE) { mImplData = static_cast(this); } @@ -82,6 +83,7 @@ protected: nsIntRect mUpdatedRect; + PRPackedBool mDelayedUpdates; PRPackedBool mGLBufferIsPremultiplied; PRPackedBool mNeedsYFlip; }; diff --git a/gfx/thebes/GLContext.cpp b/gfx/thebes/GLContext.cpp index e1a5667b7c6..f5255e3f5fe 100644 --- a/gfx/thebes/GLContext.cpp +++ b/gfx/thebes/GLContext.cpp @@ -337,6 +337,8 @@ GLContext::InitWithPrefix(const char *prefix, PRBool trygl) "Qualcomm" }; + fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + mVendor = VendorOther; for (int i = 0; i < VendorOther; ++i) { if (DoesVendorStringMatch(glVendorString, vendorMatchStrings[i])) { diff --git a/gfx/thebes/GLContext.h b/gfx/thebes/GLContext.h index 0ecb3852a67..d51417536ef 100644 --- a/gfx/thebes/GLContext.h +++ b/gfx/thebes/GLContext.h @@ -770,6 +770,8 @@ public: static PRBool ListHasExtension(const GLubyte *extensions, const char *extension); + GLint GetMaxTextureSize() { return mMaxTextureSize; } + protected: PRPackedBool mInitialized; PRPackedBool mIsOffscreen; @@ -867,6 +869,8 @@ protected: nsTArray mViewportStack; nsTArray mScissorStack; + GLint mMaxTextureSize; + public: #ifdef DEBUG