Bug 705559. Part 2: Keep only one snapshot per DrawTargetD2D since all stored snapshots represent the 'last state'. Reuse that snapshot if the state hasn't changed since the last snapshot. Keep the last snapshot alive and make the snapshot's mDrawTarget weak instead. Change mDependingOnTargets/mDependentTargets to be hashsets instead of vectors. Remove SourceSurfaceD2DTarget::mIsCopy since the null-ness of mDrawTarget means the same thing. r=bas

This commit is contained in:
Robert O'Callahan 2011-12-09 22:51:57 +13:00
parent b7b3435216
commit 6857f8955e
5 changed files with 79 additions and 74 deletions

View File

@ -464,6 +464,11 @@ public:
virtual ~DrawTarget() {}
virtual BackendType GetType() const = 0;
/**
* Returns a SourceSurface which is a snapshot of the current contents of the DrawTarget.
* Multiple calls to Snapshot() without any drawing operations in between will
* normally return the same SourceSurface object.
*/
virtual TemporaryRef<SourceSurface> Snapshot() = 0;
virtual IntSize GetSize() = 0;

View File

@ -189,18 +189,27 @@ DrawTargetD2D::~DrawTargetD2D()
mTempRT->EndDraw();
}
if (mSnapshot) {
// We may hold the only reference. MarkIndependent will clear mSnapshot;
// keep the snapshot object alive so it doesn't get destroyed while
// MarkIndependent is running.
RefPtr<SourceSurfaceD2DTarget> deathGrip = mSnapshot;
// mSnapshot can be treated as independent of this DrawTarget since we know
// this DrawTarget won't change again.
deathGrip->MarkIndependent();
// mSnapshot will be cleared now.
}
// Targets depending on us can break that dependency, since we're obviously not going to
// be modified in the future.
for (std::vector<DrawTargetD2D*>::iterator iter = mDependentTargets.begin();
for (TargetSet::iterator iter = mDependentTargets.begin();
iter != mDependentTargets.end(); iter++) {
(*iter)->mDependingOnTargets.erase(
std::find((*iter)->mDependingOnTargets.begin(), (*iter)->mDependingOnTargets.end(), this));
(*iter)->mDependingOnTargets.erase(this);
}
// Our dependencies on other targets no longer matter.
for (std::vector<DrawTargetD2D*>::iterator iter = mDependingOnTargets.begin();
for (TargetSet::iterator iter = mDependingOnTargets.begin();
iter != mDependingOnTargets.end(); iter++) {
(*iter)->mDependentTargets.erase(
std::find((*iter)->mDependentTargets.begin(), (*iter)->mDependentTargets.end(), this));
(*iter)->mDependentTargets.erase(this);
}
}
@ -210,17 +219,12 @@ DrawTargetD2D::~DrawTargetD2D()
TemporaryRef<SourceSurface>
DrawTargetD2D::Snapshot()
{
RefPtr<SourceSurfaceD2DTarget> newSurf = new SourceSurfaceD2DTarget();
if (!mSnapshot) {
mSnapshot = new SourceSurfaceD2DTarget(this, mTexture, mFormat);
Flush();
}
newSurf->mFormat = mFormat;
newSurf->mTexture = mTexture;
newSurf->mDrawTarget = this;
mSnapshots.push_back(newSurf);
Flush();
return newSurf;
return mSnapshot;
}
void
@ -235,14 +239,22 @@ DrawTargetD2D::Flush()
}
// We no longer depend on any target.
for (std::vector<DrawTargetD2D*>::iterator iter = mDependingOnTargets.begin();
for (TargetSet::iterator iter = mDependingOnTargets.begin();
iter != mDependingOnTargets.end(); iter++) {
(*iter)->mDependentTargets.erase(
std::find((*iter)->mDependentTargets.begin(), (*iter)->mDependentTargets.end(), this));
(*iter)->mDependentTargets.erase(this);
}
mDependingOnTargets.clear();
}
void
DrawTargetD2D::AddDependencyOnSource(SourceSurfaceD2DTarget* aSource)
{
if (aSource->mDrawTarget) {
aSource->mDrawTarget->mDependentTargets.insert(this);
mDependingOnTargets.insert(aSource->mDrawTarget);
}
}
void
DrawTargetD2D::DrawSurface(SourceSurface *aSurface,
const Rect &aDest,
@ -292,11 +304,7 @@ DrawTargetD2D::DrawSurface(SourceSurface *aSurface,
{
SourceSurfaceD2DTarget *srcSurf = static_cast<SourceSurfaceD2DTarget*>(aSurface);
bitmap = srcSurf->GetBitmap(mRT);
if (!srcSurf->IsCopy()) {
srcSurf->mDrawTarget->mDependentTargets.push_back(this);
mDependingOnTargets.push_back(srcSurf->mDrawTarget);
}
AddDependencyOnSource(srcSurf);
}
break;
}
@ -721,11 +729,7 @@ DrawTargetD2D::CopySurface(SourceSurface *aSurface,
{
SourceSurfaceD2DTarget *srcSurf = static_cast<SourceSurfaceD2DTarget*>(aSurface);
bitmap = srcSurf->GetBitmap(mRT);
if (!srcSurf->IsCopy()) {
srcSurf->mDrawTarget->mDependentTargets.push_back(this);
mDependingOnTargets.push_back(srcSurf->mDrawTarget);
}
AddDependencyOnSource(srcSurf);
}
break;
}
@ -1271,18 +1275,20 @@ DrawTargetD2D::PrepareForDrawing(ID2D1RenderTarget *aRT)
void
DrawTargetD2D::MarkChanged()
{
if (mSnapshots.size()) {
for (std::vector<SourceSurfaceD2DTarget*>::iterator iter = mSnapshots.begin();
iter != mSnapshots.end(); iter++) {
(*iter)->DrawTargetWillChange();
if (mSnapshot) {
if (mSnapshot->hasOneRef()) {
// Just destroy it, since no-one else knows about it.
mSnapshot = NULL;
} else {
mSnapshot->DrawTargetWillChange();
// The snapshot will no longer depend on this target.
MOZ_ASSERT(!mSnapshot);
}
// All snapshots will now have copied data.
mSnapshots.clear();
}
if (mDependentTargets.size()) {
// Copy mDependentTargets since the Flush()es below will modify it.
std::vector<DrawTargetD2D*> tmpTargets = mDependentTargets;
for (std::vector<DrawTargetD2D*>::iterator iter = tmpTargets.begin();
TargetSet tmpTargets = mDependentTargets;
for (TargetSet::iterator iter = tmpTargets.begin();
iter != tmpTargets.end(); iter++) {
(*iter)->Flush();
}
@ -1678,13 +1684,8 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
{
SourceSurfaceD2DTarget *surf =
static_cast<SourceSurfaceD2DTarget*>(pat->mSurface.get());
bitmap = surf->GetBitmap(mRT);
if (!surf->IsCopy()) {
surf->mDrawTarget->mDependentTargets.push_back(this);
mDependingOnTargets.push_back(surf->mDrawTarget);
}
AddDependencyOnSource(surf);
}
break;
}

View File

@ -45,6 +45,7 @@
#include <vector>
#include <sstream>
#include <hash_set>
namespace mozilla {
namespace gfx {
@ -148,12 +149,15 @@ private:
friend class AutoSaveRestoreClippedOut;
friend class SourceSurfaceD2DTarget;
typedef stdext::hash_set<DrawTargetD2D*> TargetSet;
bool InitD2DRenderTarget();
void PrepareForDrawing(ID2D1RenderTarget *aRT);
// This function will mark the surface as changing, and make sure any
// copy-on-write snapshots are notified.
void MarkChanged();
void AddDependencyOnSource(SourceSurfaceD2DTarget* aSource);
ID3D10BlendState *GetBlendStateForOperator(CompositionOp aOperator);
ID2D1RenderTarget *GetRTForOperation(CompositionOp aOperator, const Pattern &aPattern);
@ -194,13 +198,13 @@ private:
};
std::vector<PushedClip> mPushedClips;
// List of Snapshots of this surface, these need to be told when this
// surface is modified. Possibly vector is not the best choice here.
std::vector<SourceSurfaceD2DTarget*> mSnapshots;
// The latest snapshot of this surface. This needs to be told when this
// target is modified. We keep it alive as a cache.
RefPtr<SourceSurfaceD2DTarget> mSnapshot;
// A list of targets we need to flush when we're modified.
std::vector<DrawTargetD2D*> mDependentTargets;
// A list of targets which have this object in their mDependentTargets array
std::vector<DrawTargetD2D*> mDependingOnTargets;
TargetSet mDependentTargets;
// A list of targets which have this object in their mDependentTargets set
TargetSet mDependingOnTargets;
// True of the current clip stack is pushed to the main RT.
bool mClipsArePushed;

View File

@ -44,16 +44,20 @@
namespace mozilla {
namespace gfx {
SourceSurfaceD2DTarget::SourceSurfaceD2DTarget()
: mFormat(FORMAT_B8G8R8A8)
, mIsCopy(false)
SourceSurfaceD2DTarget::SourceSurfaceD2DTarget(DrawTargetD2D* aDrawTarget,
ID3D10Texture2D* aTexture,
SurfaceFormat aFormat)
: mDrawTarget(aDrawTarget)
, mTexture(aTexture)
, mFormat(aFormat)
{
}
SourceSurfaceD2DTarget::~SourceSurfaceD2DTarget()
{
// Our drawtarget no longer needs to worry about us.
MarkIndependent();
// We don't need to do anything special here to notify our mDrawTarget. It must
// already have cleared its mSnapshot field, otherwise this object would
// be kept alive.
}
IntSize
@ -115,13 +119,8 @@ SourceSurfaceD2DTarget::GetSRView()
void
SourceSurfaceD2DTarget::DrawTargetWillChange()
{
// assert(!mIsCopy)
RefPtr<ID3D10Texture2D> oldTexture = mTexture;
// It's important we set this here, that way DrawTargets that we are calling
// flush on will not try to remove themselves from our dependent surfaces.
mIsCopy = true;
D3D10_TEXTURE2D_DESC desc;
mTexture->GetDesc(&desc);
@ -171,9 +170,10 @@ SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT)
void
SourceSurfaceD2DTarget::MarkIndependent()
{
if (!mIsCopy) {
std::vector<SourceSurfaceD2DTarget*> *snapshots = &mDrawTarget->mSnapshots;
snapshots->erase(std::find(snapshots->begin(), snapshots->end(), this));
if (mDrawTarget) {
MOZ_ASSERT(mDrawTarget->mSnapshot == this);
mDrawTarget->mSnapshot = NULL;
mDrawTarget = NULL;
}
}

View File

@ -51,7 +51,8 @@ class DrawTargetD2D;
class SourceSurfaceD2DTarget : public SourceSurface
{
public:
SourceSurfaceD2DTarget();
SourceSurfaceD2DTarget(DrawTargetD2D* aDrawTarget, ID3D10Texture2D* aTexture,
SurfaceFormat aFormat);
~SourceSurfaceD2DTarget();
virtual SurfaceType GetType() const { return SURFACE_D2D1_DRAWTARGET; }
@ -63,10 +64,6 @@ private:
friend class DrawTargetD2D;
ID3D10ShaderResourceView *GetSRView();
// This returns true if this source surface has been copied from its
// drawtarget, in that case changes no longer need to be tracked.
bool IsCopy() { return mIsCopy; }
// This function is called by the draw target this texture belongs to when
// it is about to be changed. The texture will be required to make a copy
// of itself when this happens.
@ -80,15 +77,13 @@ private:
RefPtr<ID3D10ShaderResourceView> mSRView;
RefPtr<ID2D1Bitmap> mBitmap;
RefPtr<DrawTargetD2D> mDrawTarget;
// Non-null if this is a "lazy copy" of the given draw target.
// Null if we've made a copy. The target is not kept alive, otherwise we'd
// have leaks since it might keep us alive. If the target is destroyed, it
// will notify us.
DrawTargetD2D* mDrawTarget;
mutable RefPtr<ID3D10Texture2D> mTexture;
SurfaceFormat mFormat;
// This is a list of the drawtargets that need to be notified when the
// underlying drawtarget is changed.
std::vector<RefPtr<DrawTargetD2D>> mDependentSurfaces;
bool mIsCopy;
};
class DataSourceSurfaceD2DTarget : public DataSourceSurface