Bug 622072. Part 1: Remove rect parameter from Updated() and change implementations to defer updates to render time. r=bas
The rectangle parameter is currently not used --- all callers always pass the full canvas bounds. In the long term,
we probably won't want this parameter since all implementations should be doing accelerated drawing direct to buffers
with no intermediate copies, hence there will be no need to optimize the size of those copies. Plus, performance-sensitive
testcases tend to paint most or all of the canvas on every frame anyway.
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -622,17 +622,17 @@ static PRUint8 gWebGLLayerUserData;
already_AddRefed<layers::CanvasLayer>
WebGLContext::GetCanvasLayer(CanvasLayer *aOldLayer,
LayerManager *aManager)
{
if (!mResetLayer && aOldLayer &&
aOldLayer->HasUserData(&gWebGLLayerUserData)) {
NS_ADDREF(aOldLayer);
if (mInvalidated) {
- aOldLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
+ aOldLayer->Updated();
mInvalidated = PR_FALSE;
HTMLCanvasElement()->GetPrimaryCanvasFrame()->MarkLayersActive();
}
return aOldLayer;
}
nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
if (!canvasLayer) {
@@ -656,17 +656,17 @@ WebGLContext::GetCanvasLayer(CanvasLayer
}
data.mSize = nsIntSize(mWidth, mHeight);
data.mGLBufferIsPremultiplied = mOptions.premultipliedAlpha ? PR_TRUE : PR_FALSE;
canvasLayer->Initialize(data);
PRUint32 flags = gl->CreationFormat().alpha == 0 ? Layer::CONTENT_OPAQUE : 0;
canvasLayer->SetContentFlags(flags);
- canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
+ canvasLayer->Updated();
mInvalidated = PR_FALSE;
mResetLayer = PR_FALSE;
return canvasLayer.forget().get();
}
NS_IMETHODIMP
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -4125,19 +4125,17 @@ nsCanvasRenderingContext2D::GetCanvasLay
{
if (!mValid)
return nsnull;
if (!mResetLayer && aOldLayer &&
aOldLayer->HasUserData(&g2DContextLayerUserData)) {
NS_ADDREF(aOldLayer);
if (mIsEntireFrameInvalid || mInvalidateCount > 0) {
- // XXX Need to just update the changed area here; we should keep track
- // of the rectangle based on Redraw args.
- aOldLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
+ aOldLayer->Updated();
MarkContextClean();
HTMLCanvasElement()->GetPrimaryCanvasFrame()->MarkLayersActive();
}
return aOldLayer;
}
nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
@@ -4150,17 +4148,17 @@ nsCanvasRenderingContext2D::GetCanvasLay
CanvasLayer::Data data;
data.mSurface = mSurface.get();
data.mSize = nsIntSize(mWidth, mHeight);
canvasLayer->Initialize(data);
PRUint32 flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
canvasLayer->SetContentFlags(flags);
- canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
+ canvasLayer->Updated();
mResetLayer = PR_FALSE;
MarkContextClean();
return canvasLayer.forget().get();
}
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1171,23 +1171,20 @@ public:
* have either mSurface or mGLContext initialized (but not both), as
* well as mSize.
*
* This must only be called once.
*/
virtual void Initialize(const Data& aData) = 0;
/**
- * CONSTRUCTION PHASE ONLY
- * Notify this CanvasLayer that the rectangle given by aRect
- * has been updated, and any work that needs to be done
- * to bring the contents from the Surface/GLContext to the
- * Layer in preparation for compositing should be performed.
+ * Notify this CanvasLayer that the canvas surface contents have
+ * changed (or will change) before the next transaction.
*/
- virtual void Updated(const nsIntRect& aRect) = 0;
+ void Updated() { mDirty = PR_TRUE; }
/**
* CONSTRUCTION PHASE ONLY
* Set the filter used to resample this image (if necessary).
*/
void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; }
gfxPattern::GraphicsFilter GetFilter() const { return mFilter; }
@@ -1202,23 +1199,27 @@ public:
mEffectiveTransform =
SnapTransform(GetLocalTransform(), gfxRect(0, 0, mBounds.width, mBounds.height),
nsnull)*
SnapTransform(aTransformToSurface, gfxRect(0, 0, 0, 0), nsnull);
}
protected:
CanvasLayer(LayerManager* aManager, void* aImplData)
- : Layer(aManager, aImplData), mFilter(gfxPattern::FILTER_GOOD) {}
+ : Layer(aManager, aImplData), mFilter(gfxPattern::FILTER_GOOD), mDirty(PR_FALSE) {}
virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
/**
* 0, 0, canvaswidth, canvasheight
*/
nsIntRect mBounds;
gfxPattern::GraphicsFilter mFilter;
+ /**
+ * Set to true in Updated(), cleared during a transaction.
+ */
+ PRPackedBool mDirty;
};
}
}
#endif /* GFX_LAYERS_H */
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -888,45 +888,41 @@ public:
virtual void SetVisibleRegion(const nsIntRegion& aRegion)
{
NS_ASSERTION(BasicManager()->InConstruction(),
"Can only set properties in construction phase");
CanvasLayer::SetVisibleRegion(aRegion);
}
virtual void Initialize(const Data& aData);
- virtual void Updated(const nsIntRect& aRect);
virtual void Paint(gfxContext* aContext);
virtual void PaintWithOpacity(gfxContext* aContext,
float aOpacity);
protected:
BasicLayerManager* BasicManager()
{
return static_cast<BasicLayerManager*>(mManager);
}
+ void UpdateSurface();
nsRefPtr<gfxASurface> mSurface;
nsRefPtr<mozilla::gl::GLContext> mGLContext;
PRUint32 mCanvasFramebuffer;
- nsIntRect mUpdatedRect;
-
PRPackedBool mGLBufferIsPremultiplied;
PRPackedBool mNeedsYFlip;
};
void
BasicCanvasLayer::Initialize(const Data& aData)
{
NS_ASSERTION(mSurface == nsnull, "BasicCanvasLayer::Initialize called twice!");
- mUpdatedRect.Empty();
-
if (aData.mSurface) {
mSurface = aData.mSurface;
NS_ASSERTION(aData.mGLContext == nsnull,
"CanvasLayer can't have both surface and GLContext");
mNeedsYFlip = PR_FALSE;
} else if (aData.mGLContext) {
NS_ASSERTION(aData.mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
mGLContext = aData.mGLContext;
@@ -936,22 +932,21 @@ BasicCanvasLayer::Initialize(const Data&
} else {
NS_ERROR("CanvasLayer created without mSurface or mGLContext?");
}
mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
}
void
-BasicCanvasLayer::Updated(const nsIntRect& aRect)
+BasicCanvasLayer::UpdateSurface()
{
- NS_ASSERTION(mUpdatedRect.IsEmpty(),
- "CanvasLayer::Updated called more than once in a transaction!");
-
- mUpdatedRect.UnionRect(mUpdatedRect, aRect);
+ if (!mDirty)
+ return;
+ mDirty = PR_FALSE;
if (mGLContext) {
nsRefPtr<gfxImageSurface> isurf =
new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
(GetContentFlags() & CONTENT_OPAQUE)
? gfxASurface::ImageFormatRGB24
: gfxASurface::ImageFormatARGB32);
if (!isurf || isurf->CairoStatus() != 0) {
@@ -971,19 +966,16 @@ BasicCanvasLayer::Updated(const nsIntRec
mGLContext->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)¤tFramebuffer);
// Make sure that we read pixels from the correct framebuffer, regardless
// of what's currently bound.
if (currentFramebuffer != mCanvasFramebuffer)
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mCanvasFramebuffer);
- // For simplicity, we read the entire framebuffer for now -- in
- // the future we should use mUpdatedRect, though with WebGL we don't
- // have an easy way to generate one.
mGLContext->ReadPixelsIntoImageSurface(0, 0,
mBounds.width, mBounds.height,
isurf);
// Put back the previous framebuffer binding.
if (currentFramebuffer != mCanvasFramebuffer)
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, currentFramebuffer);
@@ -992,25 +984,22 @@ BasicCanvasLayer::Updated(const nsIntRec
// Note that this is a WebGL attribute; GL itself has no knowledge of
// premultiplied or unpremultiplied alpha.
if (!mGLBufferIsPremultiplied)
gfxUtils::PremultiplyImageSurface(isurf);
// stick our surface into mSurface, so that the Paint() path is the same
mSurface = isurf;
}
-
- // sanity
- NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect),
- "CanvasLayer: Updated rect bigger than bounds!");
}
void
BasicCanvasLayer::Paint(gfxContext* aContext)
{
+ UpdateSurface();
PaintWithOpacity(aContext, GetEffectiveOpacity());
}
void
BasicCanvasLayer::PaintWithOpacity(gfxContext* aContext,
float aOpacity)
{
NS_ASSERTION(BasicManager()->InDrawing(),
@@ -1032,18 +1021,16 @@ BasicCanvasLayer::PaintWithOpacity(gfxCo
// No need to snap here; our transform is already set up to snap our rect
aContext->Rectangle(gfxRect(0, 0, mBounds.width, mBounds.height));
aContext->SetPattern(pat);
aContext->FillWithOpacity(aOpacity);
if (mNeedsYFlip) {
aContext->SetMatrix(m);
}
-
- mUpdatedRect.Empty();
}
class BasicReadbackLayer : public ReadbackLayer,
BasicImplData
{
public:
BasicReadbackLayer(BasicLayerManager* aLayerManager) :
ReadbackLayer(aLayerManager, static_cast<BasicImplData*>(this))
@@ -2559,19 +2546,16 @@ public:
virtual void Disconnect()
{
DestroyFrontBuffer();
ShadowCanvasLayer::Disconnect();
}
virtual void Initialize(const Data& aData);
- virtual void Updated(const nsIntRect& aRect)
- {}
-
virtual already_AddRefed<gfxSharedImageSurface>
Swap(gfxSharedImageSurface* newFront);
virtual void DestroyFrontBuffer()
{
if (mFrontSurface) {
BasicManager()->ShadowLayerManager::DestroySharedSurface(mFrontSurface, mAllocator);
}
--- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp
@@ -109,18 +109,22 @@ CanvasLayerD3D10::Initialize(const Data&
return;
}
}
device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
}
void
-CanvasLayerD3D10::Updated(const nsIntRect& aRect)
+CanvasLayerD3D10::UpdateSurface()
{
+ if (!mDirty)
+ return;
+ mDirty = PR_FALSE;
+
if (mIsD2DTexture) {
mSurface->Flush();
return;
}
if (mUsingSharedTexture) {
// need to sync on the d3d9 device
if (mGLContext) {
@@ -156,19 +160,16 @@ CanvasLayerD3D10::Updated(const nsIntRec
mGLContext->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)¤tFramebuffer);
// Make sure that we read pixels from the correct framebuffer, regardless
// of what's currently bound.
if (currentFramebuffer != mCanvasFramebuffer)
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mCanvasFramebuffer);
- // For simplicity, we read the entire framebuffer for now -- in
- // the future we should use aRect, though with WebGL we don't
- // have an easy way to generate one.
nsRefPtr<gfxImageSurface> tmpSurface =
new gfxImageSurface(destination,
gfxIntSize(mBounds.width, mBounds.height),
mBounds.width * 4,
gfxASurface::ImageFormatARGB32);
mGLContext->ReadPixelsIntoImageSurface(0, 0,
mBounds.width, mBounds.height,
tmpSurface);
@@ -184,40 +185,36 @@ CanvasLayerD3D10::Updated(const nsIntRec
destination + mBounds.width * 4 * y,
mBounds.width * 4);
}
delete [] destination;
}
mTexture->Unmap(0);
} else if (mSurface) {
RECT r;
- r.left = aRect.x;
- r.top = aRect.y;
- r.right = aRect.XMost();
- r.bottom = aRect.YMost();
+ r.left = 0;
+ r.top = 0;
+ r.right = mBounds.width;
+ r.bottom = mBounds.height;
D3D10_MAPPED_TEXTURE2D map;
HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
if (FAILED(hr)) {
NS_WARNING("Failed to lock CanvasLayer texture.");
return;
}
- PRUint8 *startBits;
- PRUint32 sourceStride;
-
nsRefPtr<gfxImageSurface> dstSurface;
dstSurface = new gfxImageSurface((unsigned char*)map.pData,
- gfxIntSize(aRect.width, aRect.height),
+ gfxIntSize(mBounds.width, mBounds.height),
map.RowPitch,
gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> ctx = new gfxContext(dstSurface);
- ctx->Translate(gfxPoint(-aRect.x, -aRect.y));
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(mSurface);
ctx->Paint();
mTexture->Unmap(0);
}
}
@@ -225,16 +222,18 @@ Layer*
CanvasLayerD3D10::GetLayer()
{
return this;
}
void
CanvasLayerD3D10::RenderLayer()
{
+ UpdateSurface();
+
if (!mTexture) {
return;
}
nsIntRect visibleRect = mVisibleRegion.GetBounds();
SetEffectTransformAndOpacity();
--- a/gfx/layers/d3d10/CanvasLayerD3D10.h
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.h
@@ -59,25 +59,26 @@ public:
{
mImplData = static_cast<LayerD3D10*>(this);
}
~CanvasLayerD3D10();
// CanvasLayer implementation
virtual void Initialize(const Data& aData);
- virtual void Updated(const nsIntRect& aRect);
// LayerD3D10 implementation
virtual Layer* GetLayer();
virtual void RenderLayer();
private:
typedef mozilla::gl::GLContext GLContext;
+ void UpdateSurface();
+
nsRefPtr<gfxASurface> mSurface;
nsRefPtr<GLContext> mGLContext;
nsRefPtr<ID3D10Texture2D> mTexture;
nsRefPtr<ID3D10ShaderResourceView> mSRView;
PRUint32 mCanvasFramebuffer;
PRPackedBool mDataIsPremultiplied;
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -74,18 +74,22 @@ CanvasLayerD3D9::Initialize(const Data&
}
mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
CreateTexture();
}
void
-CanvasLayerD3D9::Updated(const nsIntRect& aRect)
+CanvasLayerD3D9::UpdateSurface()
{
+ if (!mDirty)
+ return;
+ mDirty = PR_FALSE;
+
if (!mTexture) {
CreateTexture();
NS_WARNING("CanvasLayerD3D9::Updated called but no texture present!");
return;
}
if (mGLContext) {
// WebGL reads entire surface.
@@ -112,19 +116,16 @@ CanvasLayerD3D9::Updated(const nsIntRect
mGLContext->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)¤tFramebuffer);
// Make sure that we read pixels from the correct framebuffer, regardless
// of what's currently bound.
if (currentFramebuffer != mCanvasFramebuffer)
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mCanvasFramebuffer);
- // For simplicity, we read the entire framebuffer for now -- in
- // the future we should use aRect, though with WebGL we don't
- // have an easy way to generate one.
nsRefPtr<gfxImageSurface> tmpSurface =
new gfxImageSurface(destination,
gfxIntSize(mBounds.width, mBounds.height),
mBounds.width * 4,
gfxASurface::ImageFormatARGB32);
mGLContext->ReadPixelsIntoImageSurface(0, 0,
mBounds.width, mBounds.height,
tmpSurface);
@@ -140,90 +141,81 @@ CanvasLayerD3D9::Updated(const nsIntRect
destination + mBounds.width * 4 * y,
mBounds.width * 4);
}
delete [] destination;
}
mTexture->UnlockRect(0);
} else if (mSurface) {
RECT r;
- r.left = aRect.x;
- r.top = aRect.y;
- r.right = aRect.XMost();
- r.bottom = aRect.YMost();
+ r.left = mBounds.x;
+ r.top = mBounds.y;
+ r.right = mBounds.XMost();
+ r.bottom = mBounds.YMost();
D3DLOCKED_RECT lockedRect;
HRESULT hr = mTexture->LockRect(0, &lockedRect, &r, 0);
if (FAILED(hr)) {
NS_WARNING("Failed to lock CanvasLayer texture.");
return;
}
- PRUint8 *startBits;
- PRUint32 sourceStride;
-
nsRefPtr<gfxImageSurface> sourceSurface;
if (mSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
sourceSurface = mSurface->GetAsImageSurface();
- startBits = sourceSurface->Data() + sourceSurface->Stride() * aRect.y +
- aRect.x * 4;
- sourceStride = sourceSurface->Stride();
} else if (mSurface->GetType() == gfxASurface::SurfaceTypeImage) {
sourceSurface = static_cast<gfxImageSurface*>(mSurface.get());
if (sourceSurface->Format() != gfxASurface::ImageFormatARGB32 &&
sourceSurface->Format() != gfxASurface::ImageFormatRGB24)
{
mTexture->UnlockRect(0);
return;
}
- startBits = sourceSurface->Data() + sourceSurface->Stride() * aRect.y +
- aRect.x * 4;
- sourceStride = sourceSurface->Stride();
} else {
- sourceSurface = new gfxImageSurface(gfxIntSize(aRect.width, aRect.height),
+ sourceSurface = new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> ctx = new gfxContext(sourceSurface);
- ctx->Translate(gfxPoint(-aRect.x, -aRect.y));
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(mSurface);
ctx->Paint();
- startBits = sourceSurface->Data();
- sourceStride = sourceSurface->Stride();
}
+ PRUint8 *startBits = sourceSurface->Data();
+ PRUint32 sourceStride = sourceSurface->Stride();
+
if (sourceSurface->Format() != gfxASurface::ImageFormatARGB32) {
mHasAlpha = false;
} else {
mHasAlpha = true;
}
- for (int y = 0; y < aRect.height; y++) {
+ for (int y = 0; y < mBounds.height; y++) {
memcpy((PRUint8*)lockedRect.pBits + lockedRect.Pitch * y,
startBits + sourceStride * y,
- aRect.width * 4);
+ mBounds.width * 4);
}
mTexture->UnlockRect(0);
}
}
Layer*
CanvasLayerD3D9::GetLayer()
{
return this;
}
void
CanvasLayerD3D9::RenderLayer()
{
- if (!mTexture) {
- Updated(mBounds);
- }
+ UpdateSurface();
+ if (!mTexture)
+ return;
/*
* We flip the Y axis here, note we can only do this because we are in
* CULL_NONE mode!
*/
ShaderConstantRect quad(0, 0, mBounds.width, mBounds.height);
if (mNeedsYFlip) {
--- a/gfx/layers/d3d9/CanvasLayerD3D9.h
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.h
@@ -61,29 +61,30 @@ public:
mImplData = static_cast<LayerD3D9*>(this);
aManager->deviceManager()->mLayersWithResources.AppendElement(this);
}
~CanvasLayerD3D9();
// CanvasLayer implementation
virtual void Initialize(const Data& aData);
- virtual void Updated(const nsIntRect& aRect);
// LayerD3D9 implementation
virtual Layer* GetLayer();
virtual void RenderLayer();
virtual void CleanResources();
virtual void LayerManagerDestroyed();
void CreateTexture();
protected:
typedef mozilla::gl::GLContext GLContext;
+ void UpdateSurface();
+
nsRefPtr<gfxASurface> mSurface;
nsRefPtr<GLContext> mGLContext;
nsRefPtr<IDirect3DTexture9> mTexture;
PRUint32 mCanvasFramebuffer;
PRPackedBool mDataIsPremultiplied;
PRPackedBool mNeedsYFlip;
--- a/gfx/layers/ipc/PLayers.ipdl
+++ b/gfx/layers/ipc/PLayers.ipdl
@@ -167,17 +167,16 @@ struct OpRemoveChild { PLayer container
struct OpPaintThebesBuffer {
PLayer layer;
ThebesBuffer newFrontBuffer;
nsIntRegion updatedRegion;
};
struct OpPaintCanvas {
PLayer layer;
- nsIntRect updated;
Shmem newFrontBuffer;
};
struct OpPaintImage {
PLayer layer;
Shmem newFrontBuffer;
};
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -296,17 +296,16 @@ ShadowLayerForwarder::PaintedImage(Shado
mTxn->AddPaint(OpPaintImage(NULL, Shadow(aImage),
aNewFrontSurface->GetShmem()));
}
void
ShadowLayerForwarder::PaintedCanvas(ShadowableLayer* aCanvas,
gfxSharedImageSurface* aNewFrontSurface)
{
mTxn->AddPaint(OpPaintCanvas(NULL, Shadow(aCanvas),
- nsIntRect(),
aNewFrontSurface->GetShmem()));
}
PRBool
ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies)
{
NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
NS_ABORT_IF_FALSE(!mTxn->Finished(), "forgot BeginTransaction?");
--- a/gfx/layers/ipc/ShadowLayersParent.cpp
+++ b/gfx/layers/ipc/ShadowLayersParent.cpp
@@ -417,17 +417,17 @@ ShadowLayersParent::RecvUpdate(const Inf
nsRefPtr<gfxSharedImageSurface> newFront =
gfxSharedImageSurface::Open(op.newFrontBuffer());
nsRefPtr<gfxSharedImageSurface> newBack = canvas->Swap(newFront);
if (newFront == newBack) {
newFront.forget();
}
- canvas->Updated(op.updated());
+ canvas->Updated();
replyv.push_back(OpBufferSwap(shadow, NULL,
newBack->GetShmem()));
break;
}
case Edit::TOpPaintImage: {
MOZ_LAYERS_LOG(("[ParentSide] Paint ImageLayer"));
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -130,73 +130,66 @@ CanvasLayerOGL::MakeTexture()
gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
}
void
-CanvasLayerOGL::Updated(const nsIntRect& aRect)
+CanvasLayerOGL::UpdateSurface()
{
+ if (!mDirty)
+ return;
+ mDirty = PR_FALSE;
+
if (mDestroyed || mDelayedUpdates) {
return;
}
- NS_ASSERTION(mUpdatedRect.IsEmpty(),
- "CanvasLayer::Updated called more than once during a transaction!");
-
mOGLManager->MakeCurrent();
- mUpdatedRect.UnionRect(mUpdatedRect, aRect);
-
if (mCanvasGLContext &&
mCanvasGLContext->GetContextType() == gl()->GetContextType())
{
if (gl()->BindOffscreenNeedsTexture(mCanvasGLContext) &&
mTexture == 0)
{
MakeTexture();
}
} else {
- if (!mTexture) {
- mUpdatedRect = mBounds;
- }
-
nsRefPtr<gfxASurface> updatedAreaSurface;
if (mCanvasSurface) {
updatedAreaSurface = mCanvasSurface;
} else if (mCanvasGLContext) {
nsRefPtr<gfxImageSurface> updatedAreaImageSurface =
- new gfxImageSurface(gfxIntSize(mUpdatedRect.width, mUpdatedRect.height),
+ new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
gfxASurface::ImageFormatARGB32);
- mCanvasGLContext->ReadPixelsIntoImageSurface(mUpdatedRect.x, mUpdatedRect.y,
- mUpdatedRect.width,
- mUpdatedRect.height,
+ mCanvasGLContext->ReadPixelsIntoImageSurface(0, 0,
+ mBounds.width,
+ mBounds.height,
updatedAreaImageSurface);
updatedAreaSurface = updatedAreaImageSurface;
}
mLayerProgram =
gl()->UploadSurfaceToTexture(updatedAreaSurface,
- mUpdatedRect,
+ mBounds,
mTexture,
false,
- mUpdatedRect.TopLeft());
+ nsIntPoint(0, 0));
}
-
- // sanity
- NS_ASSERTION(mBounds.Contains(mUpdatedRect),
- "CanvasLayer: Updated rect bigger than bounds!");
}
void
CanvasLayerOGL::RenderLayer(int aPreviousDestination,
const nsIntPoint& aOffset)
{
+ UpdateSurface();
+
mOGLManager->MakeCurrent();
// XXX We're going to need a different program depending on if
// mGLBufferIsPremultiplied is TRUE or not. The RGBLayerProgram
// assumes that it's true.
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
@@ -243,18 +236,16 @@ CanvasLayerOGL::RenderLayer(int aPreviou
program->SetRenderOffset(aOffset);
program->SetTextureUnit(0);
mOGLManager->BindAndDrawQuad(program, mNeedsYFlip ? true : false);
if (useGLContext) {
gl()->UnbindTex2DOffscreen(mCanvasGLContext);
}
-
- mUpdatedRect.Empty();
}
#ifdef MOZ_IPC
ShadowCanvasLayerOGL::ShadowCanvasLayerOGL(LayerManagerOGL* aManager)
: ShadowCanvasLayer(aManager, nsnull)
, LayerOGL(aManager)
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -61,34 +61,33 @@ public:
mDelayedUpdates(PR_FALSE)
{
mImplData = static_cast<LayerOGL*>(this);
}
~CanvasLayerOGL() { Destroy(); }
// CanvasLayer implementation
virtual void Initialize(const Data& aData);
- virtual void Updated(const nsIntRect& aRect);
// LayerOGL implementation
virtual void Destroy();
virtual Layer* GetLayer() { return this; }
virtual void RenderLayer(int aPreviousFrameBuffer,
const nsIntPoint& aOffset);
protected:
+ void UpdateSurface();
+
nsRefPtr<gfxASurface> mCanvasSurface;
nsRefPtr<GLContext> mCanvasGLContext;
gl::ShaderProgramType mLayerProgram;
void MakeTexture();
GLuint mTexture;
- nsIntRect mUpdatedRect;
-
PRPackedBool mDelayedUpdates;
PRPackedBool mGLBufferIsPremultiplied;
PRPackedBool mNeedsYFlip;
};
#ifdef MOZ_IPC
// NB: eventually we'll have separate shadow canvas2d and shadow
// canvas3d layers, but currently they look the same from the