Bug 735378 - Cache temporary composite surfaces - r=bgirard

This commit is contained in:
Jeff Gilbert 2012-03-25 12:50:26 -07:00
parent d57a9c568f
commit ab6e9099ad
7 changed files with 123 additions and 26 deletions

View File

@ -1081,6 +1081,30 @@ protected:
bool mGLBufferIsPremultiplied;
bool mNeedsYFlip;
nsRefPtr<gfxImageSurface> mCachedTempSurface;
gfxIntSize mCachedSize;
gfxImageFormat mCachedFormat;
gfxImageSurface* GetTempSurface(const gfxIntSize& aSize, const gfxImageFormat aFormat)
{
if (!mCachedTempSurface ||
aSize.width != mCachedSize.width ||
aSize.height != mCachedSize.height ||
aFormat != mCachedFormat)
{
mCachedTempSurface = new gfxImageSurface(aSize, aFormat);
mCachedSize = aSize;
mCachedFormat = aFormat;
}
return mCachedTempSurface;
}
void DiscardTempSurface()
{
mCachedTempSurface = nsnull;
}
};
void
@ -1139,7 +1163,7 @@ BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface)
mGLContext->MakeCurrent();
#if defined (MOZ_X11) && defined (MOZ_EGL_XRENDER_COMPOSITE)
mGLContext->fFinish();
mGLContext->GuaranteeResolve();
gfxASurface* offscreenSurface = mGLContext->GetOffscreenPixmapSurface();
// XRender can only blend premuliplied alpha, so only allow xrender
@ -1147,16 +1171,22 @@ BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface)
if (offscreenSurface && (mGLBufferIsPremultiplied || (GetContentFlags() & CONTENT_OPAQUE))) {
mSurface = offscreenSurface;
mNeedsYFlip = false;
return;
}
else
#endif
{
nsRefPtr<gfxImageSurface> isurf = aDestSurface ?
static_cast<gfxImageSurface*>(aDestSurface) :
new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
(GetContentFlags() & CONTENT_OPAQUE)
? gfxASurface::ImageFormatRGB24
: gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxImageSurface> isurf;
if (aDestSurface) {
DiscardTempSurface();
isurf = static_cast<gfxImageSurface*>(aDestSurface);
} else {
nsIntSize size(mBounds.width, mBounds.height);
gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
? gfxASurface::ImageFormatRGB24
: gfxASurface::ImageFormatARGB32;
isurf = GetTempSurface(size, format);
}
if (!isurf || isurf->CairoStatus() != 0) {
return;
@ -1194,7 +1224,6 @@ BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface)
}
}
}
}
void
BasicCanvasLayer::Paint(gfxContext* aContext)

View File

@ -172,10 +172,13 @@ CanvasLayerD3D10::UpdateSurface()
return;
}
const bool stridesMatch = map.RowPitch == mBounds.width * 4;
PRUint8 *destination;
if (map.RowPitch != mBounds.width * 4) {
destination = new PRUint8[mBounds.width * mBounds.height * 4];
if (!stridesMatch) {
destination = GetTempBlob(mBounds.width * mBounds.height * 4);
} else {
DiscardTempBlob();
destination = (PRUint8*)map.pData;
}
@ -204,13 +207,12 @@ CanvasLayerD3D10::UpdateSurface()
if (currentFramebuffer != mCanvasFramebuffer)
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, currentFramebuffer);
if (map.RowPitch != mBounds.width * 4) {
if (!stridesMatch) {
for (int y = 0; y < mBounds.height; y++) {
memcpy((PRUint8*)map.pData + map.RowPitch * y,
destination + mBounds.width * 4 * y,
mBounds.width * 4);
}
delete [] destination;
}
mTexture->Unmap(0);
} else if (mSurface) {

View File

@ -87,6 +87,24 @@ private:
bool mIsD2DTexture;
bool mUsingSharedTexture;
bool mHasAlpha;
nsAutoArrayPtr<PRUint8> mCachedTempBlob;
PRUint32 mCachedTempBlob_Size;
PRUint8* GetTempBlob(const PRUint32 aSize)
{
if (!mCachedTempBlob || aSize != mCachedTempBlob_Size) {
mCachedTempBlob = new PRUint8[aSize];
mCachedTempBlob_Size = aSize;
}
return mCachedTempBlob;
}
void DiscardTempBlob()
{
mCachedTempBlob = nsnull;
}
};
} /* layers */

View File

@ -113,10 +113,13 @@ CanvasLayerD3D9::UpdateSurface()
D3DLOCKED_RECT r = textureLock.GetLockRect();
const bool stridesMatch = r.Pitch == mBounds.width * 4;
PRUint8 *destination;
if (r.Pitch != mBounds.width * 4) {
destination = new PRUint8[mBounds.width * mBounds.height * 4];
if (!stridesMatch) {
destination = GetTempBlob(mBounds.width * mBounds.height * 4);
} else {
DiscardTempBlob();
destination = (PRUint8*)r.pBits;
}
@ -145,13 +148,12 @@ CanvasLayerD3D9::UpdateSurface()
if (currentFramebuffer != mCanvasFramebuffer)
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, currentFramebuffer);
if (r.Pitch != mBounds.width * 4) {
if (!stridesMatch) {
for (int y = 0; y < mBounds.height; y++) {
memcpy((PRUint8*)r.pBits + r.Pitch * y,
destination + mBounds.width * 4 * y,
mBounds.width * 4);
}
delete [] destination;
}
} else {
RECT r;

View File

@ -92,6 +92,24 @@ protected:
bool mDataIsPremultiplied;
bool mNeedsYFlip;
bool mHasAlpha;
nsAutoArrayPtr<PRUint8> mCachedTempBlob;
PRUint32 mCachedTempBlob_Size;
PRUint8* GetTempBlob(const PRUint32 aSize)
{
if (!mCachedTempBlob || aSize != mCachedTempBlob_Size) {
mCachedTempBlob = new PRUint8[aSize];
mCachedTempBlob_Size = aSize;
}
return mCachedTempBlob;
}
void DiscardTempBlob()
{
mCachedTempBlob = nsnull;
}
};
// NB: eventually we'll have separate shadow canvas2d and shadow

View File

@ -178,6 +178,8 @@ CanvasLayerOGL::UpdateSurface()
if (mCanvasGLContext &&
mCanvasGLContext->GetContextType() == gl()->GetContextType())
{
DiscardTempSurface();
// Can texture share, just make sure it's resolved first
mCanvasGLContext->MakeCurrent();
mCanvasGLContext->GuaranteeResolve();
@ -190,6 +192,7 @@ CanvasLayerOGL::UpdateSurface()
}
} else {
nsRefPtr<gfxASurface> updatedAreaSurface;
if (mDrawTarget) {
// TODO: This is suboptimal - We should have direct handling for the surface types instead of
// going via a gfxASurface.
@ -197,23 +200,24 @@ CanvasLayerOGL::UpdateSurface()
} else if (mCanvasSurface) {
updatedAreaSurface = mCanvasSurface;
} else if (mCanvasGLContext) {
gfxIntSize size(mBounds.width, mBounds.height);
nsRefPtr<gfxImageSurface> updatedAreaImageSurface =
new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
gfxASurface::ImageFormatARGB32);
GetTempSurface(size, gfxASurface::ImageFormatARGB32);
mCanvasGLContext->ReadPixelsIntoImageSurface(0, 0,
mBounds.width,
mBounds.height,
updatedAreaImageSurface);
updatedAreaSurface = updatedAreaImageSurface;
}
mOGLManager->MakeCurrent();
mLayerProgram =
gl()->UploadSurfaceToTexture(updatedAreaSurface,
mBounds,
mTexture,
false,
nsIntPoint(0, 0));
mLayerProgram = gl()->UploadSurfaceToTexture(updatedAreaSurface,
mBounds,
mTexture,
false,
nsIntPoint(0, 0));
}
}

View File

@ -94,6 +94,30 @@ protected:
#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
GLXPixmap mPixmap;
#endif
nsRefPtr<gfxImageSurface> mCachedTempSurface;
gfxIntSize mCachedSize;
gfxImageFormat mCachedFormat;
gfxImageSurface* GetTempSurface(const gfxIntSize& aSize, const gfxImageFormat aFormat)
{
if (!mCachedTempSurface ||
aSize.width != mCachedSize.width ||
aSize.height != mCachedSize.height ||
aFormat != mCachedFormat)
{
mCachedTempSurface = new gfxImageSurface(aSize, aFormat);
mCachedSize = aSize;
mCachedFormat = aFormat;
}
return mCachedTempSurface;
}
void DiscardTempSurface()
{
mCachedTempSurface = nsnull;
}
};
// NB: eventually we'll have separate shadow canvas2d and shadow