Bug 771350, part 2: Use OpenDescriptorForTexturing() in ShadowThebesLayerOGL, where possible. r=BenWa

This commit is contained in:
Chris Jones 2012-07-23 16:58:37 -07:00
parent 73a85b798a
commit 708bd2e4ae
2 changed files with 98 additions and 14 deletions

View File

@ -27,6 +27,17 @@ using gl::TextureImage;
static const int ALLOW_REPEAT = ThebesLayerBuffer::ALLOW_REPEAT;
GLenum
WrapMode(GLContext *aGl, PRUint32 aFlags)
{
if ((aFlags & ALLOW_REPEAT) &&
(aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) ||
aGl->IsExtensionSupported(GLContext::OES_texture_npot))) {
return LOCAL_GL_REPEAT;
}
return LOCAL_GL_CLAMP_TO_EDGE;
}
// BindAndDrawQuadWithTextureRect can work with either GL_REPEAT (preferred)
// or GL_CLAMP_TO_EDGE textures. If ALLOW_REPEAT is set in aFlags, we
// select based on whether REPEAT is valid for non-power-of-two textures --
@ -39,15 +50,8 @@ CreateClampOrRepeatTextureImage(GLContext *aGl,
TextureImage::ContentType aContentType,
PRUint32 aFlags)
{
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
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);
return aGl->CreateTextureImage(aSize, aContentType, WrapMode(aGl, aFlags));
}
static void
@ -880,6 +884,11 @@ public:
void Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated,
const nsIntRect& aRect, const nsIntPoint& aRotation);
already_AddRefed<TextureImage>
Swap(TextureImage* aNewBackBuffer,
const nsIntRect& aRect, const nsIntPoint& aRotation,
nsIntRect* aPrevRect, nsIntPoint* aPrevRotation);
protected:
virtual nsIntPoint GetOriginOffset() {
return mBufferRect.TopLeft() - mBufferRotation;
@ -940,6 +949,24 @@ ShadowBufferOGL::Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated,
mBufferRotation = aRotation;
}
already_AddRefed<TextureImage>
ShadowBufferOGL::Swap(TextureImage* aNewBackBuffer,
const nsIntRect& aRect, const nsIntPoint& aRotation,
nsIntRect* aPrevRect, nsIntPoint* aPrevRotation)
{
nsRefPtr<TextureImage> prevBuffer = mTexImage;
*aPrevRect = mBufferRect;
*aPrevRotation = mBufferRotation;
mTexImage = aNewBackBuffer;
mBufferRect = aRect;
mBufferRotation = aRotation;
mInitialised = !!mTexImage;
return prevBuffer.forget();
}
ShadowThebesLayerOGL::ShadowThebesLayerOGL(LayerManagerOGL *aManager)
: ShadowThebesLayer(aManager, nsnull)
, LayerOGL(aManager)
@ -968,22 +995,77 @@ ShadowThebesLayerOGL::Swap(const ThebesBuffer& aNewFront,
return;
}
if (IsSurfaceDescriptorValid(mBufferDescriptor)) {
AutoOpenSurface currentFront(OPEN_READ_ONLY, mBufferDescriptor);
AutoOpenSurface newFront(OPEN_READ_ONLY, aNewFront.buffer());
if (currentFront.Size() != newFront.Size()) {
// The buffer changed size making the current front buffer
// obsolete.
DestroyFrontBuffer();
}
}
if (!mBuffer) {
mBuffer = new ShadowBufferOGL(this);
}
AutoOpenSurface frontSurface(OPEN_READ_ONLY, aNewFront.buffer());
mBuffer->Upload(frontSurface.Get(), aUpdatedRegion, aNewFront.rect(), aNewFront.rotation());
if (nsRefPtr<TextureImage> texImage =
ShadowLayerManager::OpenDescriptorForDirectTexturing(
gl(), aNewFront.buffer(), WrapMode(gl(), ALLOW_REPEAT))) {
// We can directly texture the drawn surface. Use that as our new
// front buffer, and return our previous directly-textured surface
// to the renderer.
ThebesBuffer newBack;
{
nsRefPtr<TextureImage> destroy = mBuffer->Swap(
texImage, aNewFront.rect(), aNewFront.rotation(),
&newBack.rect(), &newBack.rotation());
}
newBack.buffer() = mBufferDescriptor;
mBufferDescriptor = aNewFront.buffer();
if (IsSurfaceDescriptorValid(newBack.buffer())) {
*aNewBack = newBack;
// We have to invalidate the pixels painted into the new buffer.
// They might overlap with our old pixels.
aNewBackValidRegion->Sub(mValidRegionForNextBackBuffer, aUpdatedRegion);
} else {
*aNewBack = null_t();
aNewBackValidRegion->SetEmpty();
}
*aReadOnlyFront = aNewFront;
*aFrontUpdatedRegion = aUpdatedRegion;
} else {
// We're using resources owned by our texture as the front buffer.
// Upload the changed region and then return the surface back to
// the renderer.
AutoOpenSurface frontSurface(OPEN_READ_ONLY, aNewFront.buffer());
mBuffer->Upload(frontSurface.Get(), aUpdatedRegion, aNewFront.rect(), aNewFront.rotation());
*aNewBack = aNewFront;
*aNewBackValidRegion = mValidRegion;
*aReadOnlyFront = null_t();
aFrontUpdatedRegion->SetEmpty();
*aNewBack = aNewFront;
*aNewBackValidRegion = mValidRegion;
*aReadOnlyFront = null_t();
aFrontUpdatedRegion->SetEmpty();
}
// Save the current valid region of our front buffer, because if
// we're double buffering, it's going to be the valid region for the
// next back buffer sent back to the renderer.
//
// NB: we rely here on the fact that mValidRegion is initialized to
// empty, and that the first time Swap() is called we don't have a
// valid front buffer that we're going to return to content.
mValidRegionForNextBackBuffer = mValidRegion;
}
void
ShadowThebesLayerOGL::DestroyFrontBuffer()
{
mBuffer = nsnull;
mValidRegionForNextBackBuffer.SetEmpty();
if (IsSurfaceDescriptorValid(mBufferDescriptor)) {
mAllocator->DestroySharedSurface(&mBufferDescriptor);
}
}
void

View File

@ -138,6 +138,8 @@ public:
private:
nsRefPtr<ShadowBufferOGL> mBuffer;
SurfaceDescriptor mBufferDescriptor;
nsIntRegion mValidRegionForNextBackBuffer;
};
} /* layers */