Mozilla Home
Privacy
Cookies
Legal
Bugzilla
Browse
Advanced Search
New Bug
Reports
Documentation
Log In
Log In with GitHub
or
Remember me
Browse
Advanced Search
New Bug
Reports
Documentation
Attachment 514156 Details for
Bug 635373
[patch]
GL fix
bug635373-gl (text/plain), 30.95 KB, created by
Robert O'Callahan (:roc) (email my personal email if necessary)
(
hide
)
Description:
GL fix
Filename:
MIME Type:
Creator:
Robert O'Callahan (:roc) (email my personal email if necessary)
Size:
30.95 KB
patch
obsolete
>From: Robert O'Callahan <robert@ocallahan.org> >Bug 635373. ThebesLayerOGL needs to make sure we only sample valid pixels too. r=mattwoodrow > >diff --git a/gfx/layers/ThebesLayerBuffer.cpp b/gfx/layers/ThebesLayerBuffer.cpp >--- a/gfx/layers/ThebesLayerBuffer.cpp >+++ b/gfx/layers/ThebesLayerBuffer.cpp >@@ -175,88 +175,90 @@ WrapRotationAxis(PRInt32* aRotationPoint > *aRotationPoint += aSize; > } else if (*aRotationPoint >= aSize) { > *aRotationPoint -= aSize; > } > } > > ThebesLayerBuffer::PaintState > ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType, >+ const nsIntRegion& aNeededRegion, > float aXResolution, float aYResolution) > { > PaintState result; > >- result.mRegionToDraw.Sub(aLayer->GetVisibleRegion(), aLayer->GetValidRegion()); >+ result.mRegionToDraw.Sub(aNeededRegion, aLayer->GetValidRegion()); > > float curXRes = aLayer->GetXResolution(); > float curYRes = aLayer->GetYResolution(); > if (mBuffer && > (aContentType != mBuffer->GetContentType() || > aXResolution != curXRes || aYResolution != curYRes)) { > // We're effectively clearing the valid region, so we need to draw >- // the entire visible region now. >+ // the entire needed region now. > // > // XXX/cjones: a possibly worthwhile optimization to keep in mind > // is to re-use buffers when the resolution and visible region > // have changed in such a way that the buffer size stays the same. > // It might make even more sense to allocate buffers from a > // recyclable pool, so that we could keep this logic simple and > // still get back the same buffer. >- result.mRegionToDraw = aLayer->GetVisibleRegion(); >+ result.mRegionToDraw = aNeededRegion; > result.mRegionToInvalidate = aLayer->GetValidRegion(); > Clear(); > } > > if (result.mRegionToDraw.IsEmpty()) > return result; > nsIntRect drawBounds = result.mRegionToDraw.GetBounds(); > >- nsIntRect visibleBounds = aLayer->GetVisibleRegion().GetBounds(); >- nsIntSize destBufferDims = ScaledSize(visibleBounds.Size(), >+ nsIntRect neededBounds = aNeededRegion.GetBounds(); >+ nsIntSize destBufferDims = ScaledSize(neededBounds.Size(), > aXResolution, aYResolution); > nsRefPtr<gfxASurface> destBuffer; > nsIntRect destBufferRect; > PRBool bufferDimsChanged = PR_FALSE; > > if (BufferSizeOkFor(destBufferDims)) { > NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution, > "resolution changes must Clear()!"); > >- // The current buffer is big enough to hold the visible area. >- if (mBufferRect.Contains(visibleBounds)) { >+ // The current buffer is big enough to hold the needed area. >+ if (mBufferRect.Contains(neededBounds)) { > // We don't need to adjust mBufferRect. > destBufferRect = mBufferRect; > } else { > // The buffer's big enough but doesn't contain everything that's > // going to be visible. We'll move it. >- destBufferRect = nsIntRect(visibleBounds.TopLeft(), mBufferRect.Size()); >+ destBufferRect = nsIntRect(neededBounds.TopLeft(), mBufferRect.Size()); > } > nsIntRect keepArea; > if (keepArea.IntersectRect(destBufferRect, mBufferRect)) { > // Set mBufferRotation so that the pixels currently in mBuffer > // will still be rendered in the right place when mBufferRect > // changes to destBufferRect. > nsIntPoint newRotation = mBufferRotation + > (destBufferRect.TopLeft() - mBufferRect.TopLeft()); > WrapRotationAxis(&newRotation.x, mBufferRect.width); > WrapRotationAxis(&newRotation.y, mBufferRect.height); > NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation), > "newRotation out of bounds"); > PRInt32 xBoundary = destBufferRect.XMost() - newRotation.x; > PRInt32 yBoundary = destBufferRect.YMost() - newRotation.y; > if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) || >- (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost())) { >+ (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) || >+ (!mEnableRotationOptimization && newRotation != nsIntPoint(0,0))) { > // The stuff we need to redraw will wrap around an edge of the > // buffer, so we will need to do a self-copy > if (mBuffer->SupportsSelfCopy() && mBufferRotation == nsIntPoint(0,0)) { > destBuffer = mBuffer; > } else { > // We can't do a real self-copy because the buffer is rotated. > // So allocate a new buffer for the destination. >- destBufferRect = visibleBounds; >+ destBufferRect = neededBounds; > destBufferDims = ScaledSize(destBufferRect.Size(), > aXResolution, aYResolution); > bufferDimsChanged = PR_TRUE; > destBuffer = CreateBuffer(aContentType, destBufferDims); > if (!destBuffer) > return result; > } > } else { >@@ -267,17 +269,17 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye > // No pixels are going to be kept. The whole visible region > // will be redrawn, so we don't need to copy anything, so we don't > // set destBuffer. > mBufferRect = destBufferRect; > mBufferRotation = nsIntPoint(0,0); > } > } else { > // The buffer's not big enough, so allocate a new one >- destBufferRect = visibleBounds; >+ destBufferRect = neededBounds; > destBufferDims = ScaledSize(destBufferRect.Size(), > aXResolution, aYResolution); > bufferDimsChanged = PR_TRUE; > destBuffer = CreateBuffer(aContentType, destBufferDims); > if (!destBuffer) > return result; > } > >@@ -300,16 +302,18 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye > > mBuffer = destBuffer.forget(); > mBufferRect = destBufferRect; > mBufferRotation = nsIntPoint(0,0); > } > if (bufferDimsChanged) { > mBufferDims = destBufferDims; > } >+ NS_ASSERTION(mEnableRotationOptimization || mBufferRotation == nsIntPoint(0,0), >+ "Rotation disabled, but we have nonzero rotation?"); > > nsIntRegion invalidate; > invalidate.Sub(aLayer->GetValidRegion(), destBufferRect); > result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate); > > result.mContext = GetContextForQuadrantUpdate(drawBounds, > aXResolution, aYResolution); > >diff --git a/gfx/layers/ThebesLayerBuffer.h b/gfx/layers/ThebesLayerBuffer.h >--- a/gfx/layers/ThebesLayerBuffer.h >+++ b/gfx/layers/ThebesLayerBuffer.h >@@ -80,24 +80,35 @@ public: > SizedToVisibleBounds, > ContainsVisibleBounds > }; > > ThebesLayerBuffer(BufferSizePolicy aBufferSizePolicy) > : mBufferDims(0,0) > , mBufferRotation(0,0) > , mBufferSizePolicy(aBufferSizePolicy) >+ , mEnableRotationOptimization(PR_FALSE) > { > MOZ_COUNT_CTOR(ThebesLayerBuffer); > } > virtual ~ThebesLayerBuffer() > { > MOZ_COUNT_DTOR(ThebesLayerBuffer); > } > >+ void SetEnableRotationOptimization(PRBool aEnable) >+ { >+ if (mEnableRotationOptimization != aEnable) { >+ // Force a new buffer to be created, since subclasses may decide >+ // to create different buffer types depending on whether rotation is allowed >+ Clear(); >+ mEnableRotationOptimization = aEnable; >+ } >+ } >+ > /** > * Wipe out all retained contents. Call this when the entire > * buffer becomes invalid. > */ > void Clear() > { > mBuffer = nsnull; > mBufferDims.SizeTo(0, 0); >@@ -122,16 +133,17 @@ public: > * Start a drawing operation. This returns a PaintState describing what > * needs to be drawn to bring the buffer up to date in the visible region. > * This queries aLayer to get the currently valid and visible regions. > * The returned mContext may be null if mRegionToDraw is empty. > * Otherwise it must not be null. > * mRegionToInvalidate will contain mRegionToDraw. > */ > PaintState BeginPaint(ThebesLayer* aLayer, ContentType aContentType, >+ const nsIntRegion& aNeededRegion, > float aXResolution, float aYResolution); > > /** > * Return a new surface of |aSize| and |aType|. > */ > virtual already_AddRefed<gfxASurface> > CreateBuffer(ContentType aType, const nsIntSize& aSize) = 0; > >@@ -214,14 +226,17 @@ private: > * So the pixel at mBufferRotation within the buffer is what gets painted at > * mBufferRect.TopLeft(). > * This is "rotation" in the sense of rotating items in a linear buffer, > * where items falling off the end of the buffer are returned to the > * buffer at the other end, not 2D rotation! > */ > nsIntPoint mBufferRotation; > BufferSizePolicy mBufferSizePolicy; >+ >+protected: >+ PRPackedBool mEnableRotationOptimization; > }; > > } > } > > #endif /* THEBESLAYERBUFFER_H_ */ >diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp >--- a/gfx/layers/basic/BasicLayers.cpp >+++ b/gfx/layers/basic/BasicLayers.cpp >@@ -303,17 +303,19 @@ ContainerRemoveChild(Layer* aChild, Cont > class BasicThebesLayer; > class BasicThebesLayerBuffer : public ThebesLayerBuffer { > typedef ThebesLayerBuffer Base; > > public: > BasicThebesLayerBuffer(BasicThebesLayer* aLayer) > : Base(ContainsVisibleBounds) > , mLayer(aLayer) >- {} >+ { >+ mEnableRotationOptimization = PR_TRUE; >+ } > > virtual ~BasicThebesLayerBuffer() > {} > > using Base::BufferRect; > using Base::BufferRotation; > > /** >@@ -348,16 +350,17 @@ public: > > private: > BasicThebesLayerBuffer(gfxASurface* aBuffer, > const nsIntRect& aRect, const nsIntPoint& aRotation) > // The size policy doesn't really matter here; this constructor is > // intended to be used for creating temporaries > : ThebesLayerBuffer(ContainsVisibleBounds) > { >+ mEnableRotationOptimization = PR_TRUE; > gfxIntSize sz = aBuffer->GetSize(); > SetBuffer(aBuffer, nsIntSize(sz.width, sz.height), aRect, aRotation); > } > > BasicThebesLayer* mLayer; > }; > > class BasicThebesLayer : public ThebesLayer, BasicImplData { >@@ -573,17 +576,17 @@ BasicThebesLayer::PaintThebes(gfxContext > return; > } > > { > gfxSize scale = aContext->CurrentMatrix().ScaleFactors(PR_TRUE); > float paintXRes = BasicManager()->XResolution() * gfxUtils::ClampToScaleFactor(scale.width); > float paintYRes = BasicManager()->YResolution() * gfxUtils::ClampToScaleFactor(scale.height); > Buffer::PaintState state = >- mBuffer.BeginPaint(this, contentType, paintXRes, paintYRes); >+ mBuffer.BeginPaint(this, contentType, mVisibleRegion, paintXRes, paintYRes); > mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); > > if (state.mContext) { > // The area that became invalid and is visible needs to be repainted > // (this could be the whole visible area if our buffer switched > // from RGB to RGBA, because we might need to repaint with > // subpixel AA) > state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion); >diff --git a/gfx/layers/opengl/ThebesLayerOGL.cpp b/gfx/layers/opengl/ThebesLayerOGL.cpp >--- a/gfx/layers/opengl/ThebesLayerOGL.cpp >+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp >@@ -47,28 +47,32 @@ > #include "gfxTeeSurface.h" > > namespace mozilla { > namespace layers { > > using gl::GLContext; > using gl::TextureImage; > >+static const int ALLOW_REPEAT = 0x01; >+ > // BindAndDrawQuadWithTextureRect can work with either GL_REPEAT (preferred) > // or GL_CLAMP_TO_EDGE textures. We select based on whether REPEAT is > // valid for non-power-of-two textures -- if we have NPOT support we use it, > // otherwise we stick with CLAMP_TO_EDGE and decompose. > static already_AddRefed<TextureImage> > CreateClampOrRepeatTextureImage(GLContext *aGl, > const nsIntSize& aSize, >- TextureImage::ContentType aContentType) >+ TextureImage::ContentType aContentType, >+ PRUint32 aFlags) > { > GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE; >- if (aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) || >- aGl->IsExtensionSupported(GLContext::OES_texture_npot)) >+ if ((aFlags & ALLOW_REPEAT) && >+ (aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) || >+ aGl->IsExtensionSupported(GLContext::OES_texture_npot))) > { > wrapMode = LOCAL_GL_REPEAT; > } > > return aGl->CreateTextureImage(aSize, aContentType, wrapMode); > } > > // |aTexCoordRect| is the rectangle from the texture that we want to >@@ -151,17 +155,20 @@ public: > typedef ThebesLayerBuffer::PaintState PaintState; > > ThebesLayerBufferOGL(ThebesLayer* aLayer, LayerOGL* aOGLLayer) > : mLayer(aLayer) > , mOGLLayer(aOGLLayer) > {} > virtual ~ThebesLayerBufferOGL() {} > >+ virtual void SetEnableRotationOptimization(PRBool aEnable) = 0; >+ > virtual PaintState BeginPaint(ContentType aContentType, >+ const nsIntRegion& aNeededRegion, > float aXResolution, > float aYResolution) = 0; > > void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager); > > nsIntSize GetSize() { > if (mTexImage) > return mTexImage->GetSize(); >@@ -228,17 +235,17 @@ ThebesLayerBufferOGL::RenderTo(const nsI > DEBUG_GL_ERROR_CHECK(gl()); > alphaProgram->SetBlackTextureUnit(0); > alphaProgram->SetWhiteTextureUnit(1); > program = alphaProgram; > } else { > // Note BGR: Cairo's image surfaces are always in what > // OpenGL and our shaders consider BGR format. > ColorTextureLayerProgram *basicProgram = >- aManager->GetBasicLayerProgram(mLayer->CanUseOpaqueSurface(), >+ aManager->GetBasicLayerProgram(mTexImage->GetContentType() == gfxASurface::CONTENT_COLOR, > mTexImage->IsRGB()); > > basicProgram->Activate(); > DEBUG_GL_ERROR_CHECK(gl()); > basicProgram->SetTextureUnit(0); > program = basicProgram; > } > >@@ -286,35 +293,43 @@ public: > > SurfaceBufferOGL(ThebesLayerOGL* aLayer) > : ThebesLayerBufferOGL(aLayer, aLayer) > , ThebesLayerBuffer(SizedToVisibleBounds) > { > } > virtual ~SurfaceBufferOGL() {} > >+ virtual void SetEnableRotationOptimization(PRBool aEnable) >+ { >+ ThebesLayerBuffer::SetEnableRotationOptimization(aEnable); >+ } >+ > // ThebesLayerBufferOGL interface > virtual PaintState BeginPaint(ContentType aContentType, >- float aXResolution, >+ const nsIntRegion& aNeededRegion, >+ float aXResolution, > float aYResolution) > { > // Let ThebesLayerBuffer do all the hard work for us! :D > return ThebesLayerBuffer::BeginPaint(mLayer, > aContentType, >+ aNeededRegion, > aXResolution, > aYResolution); > } > > // ThebesLayerBuffer interface > virtual already_AddRefed<gfxASurface> > CreateBuffer(ContentType aType, const nsIntSize& aSize) > { > NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color"); > >- mTexImage = CreateClampOrRepeatTextureImage(gl(), aSize, aType); >+ mTexImage = CreateClampOrRepeatTextureImage(gl(), aSize, aType, >+ mEnableRotationOptimization ? ALLOW_REPEAT : 0); > return mTexImage ? mTexImage->GetBackingSurface() : nsnull; > } > > protected: > virtual nsIntPoint GetOriginOffset() { > return BufferRect().TopLeft() - BufferRotation(); > } > }; >@@ -326,20 +341,26 @@ protected: > // and implementing them here using GL hacketry. > class BasicBufferOGL : public ThebesLayerBufferOGL > { > public: > BasicBufferOGL(ThebesLayerOGL* aLayer) > : ThebesLayerBufferOGL(aLayer, aLayer) > , mBufferRect(0,0,0,0) > , mBufferRotation(0,0) >+ , mEnableRotationOptimization(PR_FALSE) > {} > virtual ~BasicBufferOGL() {} > >+ virtual void SetEnableRotationOptimization(PRBool aEnable) >+ { >+ mEnableRotationOptimization = aEnable; >+ } > virtual PaintState BeginPaint(ContentType aContentType, >+ const nsIntRegion& aNeededRegion, > float aXResolution, > float aYResolution); > > protected: > enum XSide { > LEFT, RIGHT > }; > enum YSide { >@@ -349,16 +370,17 @@ protected: > > virtual nsIntPoint GetOriginOffset() { > return mBufferRect.TopLeft() - mBufferRotation; > } > > private: > nsIntRect mBufferRect; > nsIntPoint mBufferRotation; >+ PRPackedBool mEnableRotationOptimization; > }; > > static void > WrapRotationAxis(PRInt32* aRotationPoint, PRInt32 aSize) > { > if (*aRotationPoint < 0) { > *aRotationPoint += aSize; > } else if (*aRotationPoint >= aSize) { >@@ -397,117 +419,126 @@ ScaledSize(const nsIntSize& aSize, float > > nsIntRect rect(0, 0, aSize.width, aSize.height); > rect.ScaleRoundOut(aXScale, aYScale); > return rect.Size(); > } > > BasicBufferOGL::PaintState > BasicBufferOGL::BeginPaint(ContentType aContentType, >+ const nsIntRegion& aNeededRegion, > float aXResolution, > float aYResolution) > { > PaintState result; > >- result.mRegionToDraw.Sub(mLayer->GetVisibleRegion(), mLayer->GetValidRegion()); >+ result.mRegionToDraw.Sub(aNeededRegion, mLayer->GetValidRegion()); > > float curXRes = mLayer->GetXResolution(); > float curYRes = mLayer->GetYResolution(); > Layer::SurfaceMode mode = mLayer->GetSurfaceMode(); > > if (mode == Layer::SURFACE_COMPONENT_ALPHA) { > #ifdef MOZ_GFX_OPTIMIZE_MOBILE > mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA; > #else > if (!mLayer->GetParent() || !mLayer->GetParent()->SupportsComponentAlphaChildren()) { > mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA; > } else { > aContentType = gfxASurface::CONTENT_COLOR; > } > #endif > } >+ if (mode == Layer::SURFACE_OPAQUE && aContentType == gfxASurface::CONTENT_COLOR_ALPHA) { >+ // The caller may be forcing us to use an RGBA texture >+ mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA; >+ } > > if (!mTexImage || mTexImage->GetContentType() != aContentType || > aXResolution != curXRes || aYResolution != curYRes || > (mode == Layer::SURFACE_COMPONENT_ALPHA) != (mTexImageOnWhite != nsnull)) { > // We're effectively clearing the valid region, so we need to draw >- // the entire visible region now. >+ // the entire needed region now. > // > // XXX/cjones: a possibly worthwhile optimization to keep in mind > // is to re-use buffers when the resolution and visible region > // have changed in such a way that the buffer size stays the same. > // It might make even more sense to allocate buffers from a > // recyclable pool, so that we could keep this logic simple and > // still get back the same buffer. >- result.mRegionToDraw = mLayer->GetVisibleRegion(); >+ result.mRegionToDraw = aNeededRegion; > result.mRegionToInvalidate = mLayer->GetValidRegion(); > mTexImage = nsnull; > mTexImageOnWhite = nsnull; > mBufferRect.SetRect(0, 0, 0, 0); > mBufferRotation.MoveTo(0, 0); > } > > if (result.mRegionToDraw.IsEmpty()) > return result; > >- nsIntRect visibleBounds = mLayer->GetVisibleRegion().GetBounds(); >+ nsIntRect neededBounds = aNeededRegion.GetBounds(); > nsIntRect drawBounds = result.mRegionToDraw.GetBounds(); >- nsIntSize destBufferDims = ScaledSize(visibleBounds.Size(), >+ nsIntSize destBufferDims = ScaledSize(neededBounds.Size(), > aXResolution, aYResolution); > > if (destBufferDims.width > gl()->GetMaxTextureSize() || > destBufferDims.height > gl()->GetMaxTextureSize()) { > return result; > } > > nsRefPtr<TextureImage> destBuffer; > nsRefPtr<TextureImage> destBufferOnWhite; > nsIntRect destBufferRect; >+ PRUint32 textureFlags = mEnableRotationOptimization ? ALLOW_REPEAT : 0; > >- if (visibleBounds.Size() <= mBufferRect.Size()) { >+ if (neededBounds.Size() <= mBufferRect.Size() && >+ mTexImage && >+ (mTexImage->GetWrapMode() == LOCAL_GL_CLAMP_TO_EDGE || mEnableRotationOptimization)) { > NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution, > "resolution changes must clear the buffer!"); > // The current buffer is big enough to hold the visible area. >- if (mBufferRect.Contains(visibleBounds)) { >+ if (mBufferRect.Contains(neededBounds)) { > // We don't need to adjust mBufferRect. > destBufferRect = mBufferRect; > } else { > // The buffer's big enough but doesn't contain everything that's > // going to be visible. We'll move it. >- destBufferRect = nsIntRect(visibleBounds.TopLeft(), mBufferRect.Size()); >+ destBufferRect = nsIntRect(neededBounds.TopLeft(), mBufferRect.Size()); > } > nsIntRect keepArea; > if (keepArea.IntersectRect(destBufferRect, mBufferRect)) { > // Set mBufferRotation so that the pixels currently in mBuffer > // will still be rendered in the right place when mBufferRect > // changes to destBufferRect. > nsIntPoint newRotation = mBufferRotation + > (destBufferRect.TopLeft() - mBufferRect.TopLeft()); > WrapRotationAxis(&newRotation.x, mBufferRect.width); > WrapRotationAxis(&newRotation.y, mBufferRect.height); > NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation), > "newRotation out of bounds"); > PRInt32 xBoundary = destBufferRect.XMost() - newRotation.x; > PRInt32 yBoundary = destBufferRect.YMost() - newRotation.y; > if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) || >- (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost())) { >+ (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) || >+ (!mEnableRotationOptimization && newRotation != nsIntPoint(0,0))) { > // The stuff we need to redraw will wrap around an edge of the > // buffer, so we will need to do a self-copy > // If mBufferRotation == nsIntPoint(0,0) we could do a real > // self-copy but we're not going to do that in GL yet. > // We can't do a real self-copy because the buffer is rotated. > // So allocate a new buffer for the destination. >- destBufferRect = visibleBounds; >- destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); >+ destBufferRect = neededBounds; >+ destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); > DEBUG_GL_ERROR_CHECK(gl()); > if (!destBuffer) > return result; > if (mode == Layer::SURFACE_COMPONENT_ALPHA) { > destBufferOnWhite = >- CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); >+ CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); > DEBUG_GL_ERROR_CHECK(gl()); > if (!destBufferOnWhite) > return result; > } > } else { > mBufferRect = destBufferRect; > mBufferRotation = newRotation; > } >@@ -515,25 +546,25 @@ BasicBufferOGL::BeginPaint(ContentType a > // No pixels are going to be kept. The whole visible region > // will be redrawn, so we don't need to copy anything, so we don't > // set destBuffer. > mBufferRect = destBufferRect; > mBufferRotation = nsIntPoint(0,0); > } > } else { > // The buffer's not big enough, so allocate a new one >- destBufferRect = visibleBounds; >- destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); >+ destBufferRect = neededBounds; >+ destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); > DEBUG_GL_ERROR_CHECK(gl()); > if (!destBuffer) > return result; > > if (mode == Layer::SURFACE_COMPONENT_ALPHA) { > destBufferOnWhite = >- CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); >+ CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); > DEBUG_GL_ERROR_CHECK(gl()); > if (!destBufferOnWhite) > return result; > } > } > > if (!destBuffer && !mTexImage) { > return result; >@@ -560,32 +591,34 @@ BasicBufferOGL::BeginPaint(ContentType a > destBuffer, dstRect); > if (mode == Layer::SURFACE_COMPONENT_ALPHA) { > destBufferOnWhite->Resize(size); > gl()->BlitTextureImage(mTexImageOnWhite, srcRect, > destBufferOnWhite, dstRect); > } > } else { > // can't blit, just draw everything >- destBufferRect = visibleBounds; >- destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); >+ destBufferRect = neededBounds; >+ destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); > if (mode == Layer::SURFACE_COMPONENT_ALPHA) { > destBufferOnWhite = >- CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); >+ CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); > } > } > } > > mTexImage = destBuffer.forget(); > if (mode == Layer::SURFACE_COMPONENT_ALPHA) { > mTexImageOnWhite = destBufferOnWhite.forget(); > } > mBufferRect = destBufferRect; > mBufferRotation = nsIntPoint(0,0); > } >+ NS_ASSERTION(mEnableRotationOptimization || mBufferRotation == nsIntPoint(0,0), >+ "Rotation disabled, but we have nonzero rotation?"); > > nsIntRegion invalidate; > invalidate.Sub(mLayer->GetValidRegion(), destBufferRect); > result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate); > > // Figure out which quadrant to draw in > PRInt32 xBoundary = mBufferRect.XMost() - mBufferRotation.x; > PRInt32 yBoundary = mBufferRect.YMost() - mBufferRotation.y; >@@ -625,17 +658,17 @@ BasicBufferOGL::BeginPaint(ContentType a > // be incorrect. > surf->SetAllowUseAsSource(PR_FALSE); > result.mContext = new gfxContext(surf); > } else { > result.mContext = new gfxContext(mTexImage->BeginUpdate(result.mRegionToDraw)); > if (mTexImage->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) { > gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw); > result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR); >- result.mContext->Fill(); >+ result.mContext->Paint(); > result.mContext->SetOperator(gfxContext::OPERATOR_OVER); > } > } > if (!result.mContext) { > NS_WARNING("unable to get context for update"); > return result; > } > result.mContext->Scale(aXResolution, aYResolution); >@@ -719,45 +752,59 @@ ThebesLayerOGL::RenderLayer(int aPreviou > mOGLManager->MakeCurrent(); > gl()->fActiveTexture(LOCAL_GL_TEXTURE0); > > TextureImage::ContentType contentType = > CanUseOpaqueSurface() ? gfxASurface::CONTENT_COLOR : > gfxASurface::CONTENT_COLOR_ALPHA; > > const gfx3DMatrix& transform = GetEffectiveTransform(); >+ nsIntRegion neededRegion = mVisibleRegion; > gfxMatrix transform2d; > gfxSize scale(1.0, 1.0); >+ float paintXRes = 1.0; >+ float paintYRes = 1.0; >+ bool willResample; > if (transform.Is2D(&transform2d)) { > scale = transform2d.ScaleFactors(PR_TRUE); >+ paintXRes = gfxUtils::ClampToScaleFactor(scale.width); >+ paintYRes = gfxUtils::ClampToScaleFactor(scale.height); >+ transform2d.Scale(1.0/paintXRes, 1.0/paintYRes); >+ willResample = transform2d.HasNonIntegerTranslation(); >+ } else { >+ willResample = true; > } >- float paintXRes = gfxUtils::ClampToScaleFactor(scale.width); >- float paintYRes = gfxUtils::ClampToScaleFactor(scale.height); >+ if (willResample && neededRegion.GetNumRects() > 1) { >+ neededRegion = mVisibleRegion.GetBounds(); >+ contentType = gfxASurface::CONTENT_COLOR_ALPHA; >+ } > >- Buffer::PaintState state = mBuffer->BeginPaint(contentType, paintXRes, paintYRes); >+ mBuffer->SetEnableRotationOptimization(!willResample); >+ Buffer::PaintState state = >+ mBuffer->BeginPaint(contentType, neededRegion, paintXRes, paintYRes); > mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); > > if (state.mContext) { >- state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion); >+ state.mRegionToInvalidate.And(state.mRegionToInvalidate, neededRegion); > mXResolution = paintXRes; > mYResolution = paintYRes; > > LayerManager::DrawThebesLayerCallback callback = > mOGLManager->GetThebesLayerCallback(); > if (!callback) { > NS_ERROR("GL should never need to update ThebesLayers in an empty transaction"); > } else { > void* callbackData = mOGLManager->GetThebesLayerCallbackData(); > callback(this, state.mContext, state.mRegionToDraw, > state.mRegionToInvalidate, callbackData); > // Everything that's visible has been validated. Do this instead of > // OR-ing with aRegionToDraw, since that can lead to a very complex region > // here (OR doesn't automatically simplify to the simplest possible > // representation of a region.) >- mValidRegion.Or(mValidRegion, mVisibleRegion); >+ mValidRegion.Or(mValidRegion, neededRegion); > } > } > > DEBUG_GL_ERROR_CHECK(gl()); > > gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer); > mBuffer->RenderTo(aOffset, mOGLManager); > DEBUG_GL_ERROR_CHECK(gl()); >@@ -780,29 +827,23 @@ ThebesLayerOGL::IsEmpty() > > class ShadowBufferOGL : public ThebesLayerBufferOGL > { > public: > ShadowBufferOGL(ShadowThebesLayerOGL* aLayer) > : ThebesLayerBufferOGL(aLayer, aLayer) > {} > >- virtual PaintState BeginPaint(ContentType aContentType, float, float) { >+ virtual void SetEnableRotationOptimization(PRBool aEnable) {} >+ virtual PaintState BeginPaint(ContentType aContentType, >+ const nsIntRegion&, float, float) { > NS_RUNTIMEABORT("can't BeginPaint for a shadow layer"); > return PaintState(); > } > >- void >- CreateTexture(ContentType aType, const nsIntSize& aSize) >- { >- NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color"); >- >- mTexImage = CreateClampOrRepeatTextureImage(gl(), aSize, aType); >- } >- > void Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated, > const nsIntRect& aRect, const nsIntPoint& aRotation); > > protected: > virtual nsIntPoint GetOriginOffset() { > return mBufferRect.TopLeft() - mBufferRotation; > } > >@@ -812,18 +853,20 @@ private: > }; > > void > ShadowBufferOGL::Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated, > const nsIntRect& aRect, const nsIntPoint& aRotation) > { > gfxIntSize size = aUpdate->GetSize(); > if (GetSize() != nsIntSize(size.width, size.height)) { >- CreateTexture(aUpdate->GetContentType(), >- nsIntSize(size.width, size.height)); >+ // XXX we should do something here to decide whether to use REPEAT or not, >+ // but I'm not sure what >+ mTexImage = CreateClampOrRepeatTextureImage(gl(), >+ nsIntSize(size.width, size.height), aUpdate->GetContentType(), ALLOW_REPEAT); > } > > nsIntRegion destRegion(aUpdated); > // aUpdated is in screen coordinates. Move it so that the layer's > // top-left is 0,0 > nsIntPoint visTopLeft = mLayer->GetVisibleRegion().GetBounds().TopLeft(); > destRegion.MoveBy(-visTopLeft); >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Flags:
mattwoodrow
: review+
Actions:
View
|
Diff
|
Review
Attachments on
bug 635373
:
513923
|
513924
|
513926
|
514069
|
514078
|
514128
|
514129
|
514156
|
514449
|
514973
|
514974
|
522336