Skip to content

Commit

Permalink
Bug 1711061 - Part 4. Implement AnimationSurfaceProvider for animated…
Browse files Browse the repository at this point in the history
… rasterized images. r=tnikkel

Differential Revision: https://phabricator.services.mozilla.com/D126790
  • Loading branch information
aosmond committed Nov 27, 2021
1 parent 5642718 commit 68f4024
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 36 deletions.
18 changes: 6 additions & 12 deletions image/AnimationFrameBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ bool AnimationFrameRetainedBuffer::ResetInternal() {
bool AnimationFrameRetainedBuffer::MarkComplete(
const gfx::IntRect& aFirstFrameRefreshArea) {
MOZ_ASSERT(!mSizeKnown);
mFirstFrameRefreshArea = aFirstFrameRefreshArea;
mSizeKnown = true;
mPending = 0;
mFrames.Compact();
Expand Down Expand Up @@ -192,6 +193,11 @@ bool AnimationFrameDiscardingQueue::MarkComplete(
mPending = 0;
}

// If we encounter a redecode error, just make the first frame refresh area to
// be the full frame, because we don't really know what we can safely recycle.
mFirstFrameRefreshArea =
mRedecodeError ? mFirstFrame->GetRect() : aFirstFrameRefreshArea;

// We reached the end of the animation, the next frame we get, if we get
// another, will be the first frame again.
mInsertIndex = 0;
Expand Down Expand Up @@ -461,17 +467,5 @@ RawAccessFrameRef AnimationFrameRecyclingQueue::RecycleFrame(
return recycledFrame;
}

bool AnimationFrameRecyclingQueue::MarkComplete(
const gfx::IntRect& aFirstFrameRefreshArea) {
bool continueDecoding =
AnimationFrameDiscardingQueue::MarkComplete(aFirstFrameRefreshArea);

// If we encounter a redecode error, just make the first frame refresh area to
// be the full frame, because we don't really know what we can safely recycle.
mFirstFrameRefreshArea =
mRedecodeError ? mFirstFrame->GetRect() : aFirstFrameRefreshArea;
return continueDecoding;
}

} // namespace image
} // namespace mozilla
20 changes: 12 additions & 8 deletions image/AnimationFrameBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ class AnimationFrameBuffer {
*/
size_t Size() const { return mSize; }

/**
* @returns The first frame refresh area. This is used instead of the dirty
* rect for the last frame when transitioning back to the first frame.
*/
const gfx::IntRect& FirstFrameRefreshArea() const {
return mFirstFrameRefreshArea;
}

/**
* @returns True if encountered an error during redecode which should cause
* the caller to stop inserting frames.
Expand Down Expand Up @@ -286,6 +294,10 @@ class AnimationFrameBuffer {
*/
virtual bool ResetInternal() = 0;

/// The first frame refresh area. This is used instead of the dirty rect for
/// the last frame when transitioning back to the first frame.
gfx::IntRect mFirstFrameRefreshArea;

// The total number of frames in the animation. If mSizeKnown is true, it is
// the actual total regardless of how many frames are available, otherwise it
// is the total number of inserted frames.
Expand Down Expand Up @@ -420,7 +432,6 @@ class AnimationFrameRecyclingQueue final
public:
explicit AnimationFrameRecyclingQueue(AnimationFrameRetainedBuffer&& aQueue);

bool MarkComplete(const gfx::IntRect& aFirstFrameRefreshArea) override;
void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
const AddSizeOfCb& aCallback) override;

Expand All @@ -447,9 +458,6 @@ class AnimationFrameRecyclingQueue final
};

const std::deque<RecycleEntry>& Recycle() const { return mRecycle; }
const gfx::IntRect& FirstFrameRefreshArea() const {
return mFirstFrameRefreshArea;
}

protected:
void AdvanceInternal() override;
Expand All @@ -460,10 +468,6 @@ class AnimationFrameRecyclingQueue final
/// is adjacent to the first frame in the mDisplay queue.
std::deque<RecycleEntry> mRecycle;

/// The first frame refresh area. This is used instead of the dirty rect for
/// the last frame when transitioning back to the first frame.
gfx::IntRect mFirstFrameRefreshArea;

/// Force recycled frames to use the first frame refresh area as their dirty
/// rect. This is used when we are recycling frames from the end of an
/// animation to produce frames at the beginning of an animation.
Expand Down
47 changes: 46 additions & 1 deletion image/AnimationSurfaceProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@

#include "mozilla/StaticPrefs_image.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/SharedSurfacesChild.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "nsProxyRelease.h"

#include "DecodePool.h"
#include "Decoder.h"

using namespace mozilla::gfx;
using namespace mozilla::layers;

namespace mozilla {
namespace image {
Expand All @@ -25,7 +28,9 @@ AnimationSurfaceProvider::AnimationSurfaceProvider(
mImage(aImage.get()),
mDecodingMutex("AnimationSurfaceProvider::mDecoder"),
mDecoder(aDecoder.get()),
mFramesMutex("AnimationSurfaceProvider::mFrames") {
mFramesMutex("AnimationSurfaceProvider::mFrames"),
mCompositedFrameRequested(false),
mSharedAnimation(MakeRefPtr<SharedSurfacesAnimation>()) {
MOZ_ASSERT(!mDecoder->IsMetadataDecode(),
"Use MetadataDecodingTask for metadata decodes");
MOZ_ASSERT(!mDecoder->IsFirstFrameDecode(),
Expand All @@ -47,6 +52,7 @@ AnimationSurfaceProvider::AnimationSurfaceProvider(
AnimationSurfaceProvider::~AnimationSurfaceProvider() {
DropImageReference();

mSharedAnimation->Destroy();
if (mDecoder) {
mDecoder->SetFrameRecycler(nullptr);
}
Expand Down Expand Up @@ -115,15 +121,32 @@ void AnimationSurfaceProvider::Reset() {
void AnimationSurfaceProvider::Advance(size_t aFrame) {
bool restartDecoder;

RefPtr<SourceSurface> surface;
IntRect dirtyRect;
{
// Typical advancement of a frame.
MutexAutoLock lock(mFramesMutex);
restartDecoder = mFrames->AdvanceTo(aFrame);

imgFrame* frame = mFrames->Get(aFrame, /* aForDisplay */ true);
MOZ_ASSERT(frame);
if (aFrame != 0) {
dirtyRect = frame->GetDirtyRect();
} else {
MOZ_ASSERT(mFrames->SizeKnown());
dirtyRect = mFrames->FirstFrameRefreshArea();
}
surface = frame->GetSourceSurface();
MOZ_ASSERT(surface);
}

if (restartDecoder) {
DecodePool::Singleton()->AsyncRun(this);
}

mCompositedFrameRequested = false;
auto* sharedSurface = static_cast<SourceSurfaceSharedData*>(surface.get());
mSharedAnimation->SetCurrentFrame(sharedSurface, dirtyRect);
}

DrawableFrameRef AnimationSurfaceProvider::DrawableRef(size_t aFrame) {
Expand Down Expand Up @@ -485,5 +508,27 @@ RawAccessFrameRef AnimationSurfaceProvider::RecycleFrame(
return mFrames->RecycleFrame(aRecycleRect);
}

nsresult AnimationSurfaceProvider::UpdateKey(
layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey) {
MOZ_ASSERT(NS_IsMainThread());

RefPtr<SourceSurface> surface;
{
MutexAutoLock lock(mFramesMutex);
imgFrame* frame =
mFrames->Get(mFrames->Displayed(), /* aForDisplay */ true);
if (!frame) {
return NS_ERROR_NOT_AVAILABLE;
}

surface = frame->GetSourceSurface();
}

mCompositedFrameRequested = true;
auto* sharedSurface = static_cast<SourceSurfaceSharedData*>(surface.get());
return mSharedAnimation->UpdateKey(sharedSurface, aManager, aResources, aKey);
}

} // namespace image
} // namespace mozilla
28 changes: 22 additions & 6 deletions image/AnimationSurfaceProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include "AnimationFrameBuffer.h"

namespace mozilla {
namespace layers {
class SharedSurfacesAnimation;
}

namespace image {

/**
Expand All @@ -41,19 +45,15 @@ class AnimationSurfaceProvider final : public ISurfaceProvider,
//////////////////////////////////////////////////////////////////////////////

public:
// We use the ISurfaceProvider constructor of DrawableSurface to indicate that
// our surfaces are computed lazily.
DrawableSurface Surface() override {
return DrawableSurface(WrapNotNull(this));
}

bool IsFinished() const override;
bool IsFullyDecoded() const override;
size_t LogicalSizeInBytes() const override;
void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
const AddSizeOfCb& aCallback) override;
void Reset() override;
void Advance(size_t aFrame) override;
bool MayAdvance() const override { return mCompositedFrameRequested; }
void MarkMayAdvance() override { mCompositedFrameRequested = true; }

protected:
DrawableFrameRef DrawableRef(size_t aFrame) override;
Expand Down Expand Up @@ -86,6 +86,15 @@ class AnimationSurfaceProvider final : public ISurfaceProvider,
public:
RawAccessFrameRef RecycleFrame(gfx::IntRect& aRecycleRect) override;

//////////////////////////////////////////////////////////////////////////////
// IDecoderFrameRecycler implementation.
//////////////////////////////////////////////////////////////////////////////

public:
nsresult UpdateKey(layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey) override;

private:
virtual ~AnimationSurfaceProvider();

Expand Down Expand Up @@ -114,6 +123,13 @@ class AnimationSurfaceProvider final : public ISurfaceProvider,

/// The frames of this animation, in order.
UniquePtr<AnimationFrameBuffer> mFrames;

/// Whether the current frame was requested for display since the last time we
/// advanced the animation.
bool mCompositedFrameRequested;

///
RefPtr<layers::SharedSurfacesAnimation> mSharedAnimation;
};

} // namespace image
Expand Down
12 changes: 8 additions & 4 deletions image/FrameAnimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,6 @@ RefreshResult FrameAnimator::AdvanceFrame(AnimationState& aState,

// Set currentAnimationFrameIndex at the last possible moment
aState.mCurrentAnimationFrameIndex = nextFrameIndex;
aState.mCompositedFrameRequested = false;
aCurrentFrame = std::move(nextFrame);
aFrames.Advance(nextFrameIndex);

Expand Down Expand Up @@ -395,7 +394,7 @@ RefreshResult FrameAnimator::RequestRefresh(AnimationState& aState,
// If nothing has accessed the composited frame since the last time we
// advanced, then there is no point in continuing to advance the animation.
// This has the effect of freezing the animation while not in view.
if (!aState.mCompositedFrameRequested &&
if (!result.Surface().MayAdvance() &&
aState.MaybeAdvanceAnimationFrameTime(aTime)) {
return ret;
}
Expand Down Expand Up @@ -443,13 +442,18 @@ RefreshResult FrameAnimator::RequestRefresh(AnimationState& aState,

LookupResult FrameAnimator::GetCompositedFrame(AnimationState& aState,
bool aMarkUsed) {
aState.mCompositedFrameRequested = true;

LookupResult result = SurfaceCache::Lookup(
ImageKey(mImage),
RasterSurfaceKey(mSize, DefaultSurfaceFlags(), PlaybackType::eAnimated),
aMarkUsed);

if (result) {
// If we are getting the frame directly (e.g. through tests or canvas), we
// need to ensure the animation is marked to allow advancing to the next
// frame.
result.Surface().MarkMayAdvance();
}

if (aState.mCompositedFrameInvalid) {
MOZ_ASSERT(StaticPrefs::image_mem_animated_discardable_AtStartup());
MOZ_ASSERT(aState.GetHasRequestedDecode());
Expand Down
5 changes: 0 additions & 5 deletions image/FrameAnimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class AnimationState {
mHasRequestedDecode(false),
mIsCurrentlyDecoded(false),
mCompositedFrameInvalid(false),
mCompositedFrameRequested(false),
mDiscarded(false) {}

/**
Expand Down Expand Up @@ -240,10 +239,6 @@ class AnimationState {
//! valid to draw to the screen.
bool mCompositedFrameInvalid;

//! Whether the composited frame was requested from the animator since the
//! last time we advanced the animation.
bool mCompositedFrameRequested;

//! Whether this image is currently discarded. Only set to true after the
//! image has been decoded at least once.
bool mDiscarded;
Expand Down
20 changes: 20 additions & 0 deletions image/ISurfaceProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class ISurfaceProvider : public WebRenderImageProvider {

virtual void Reset() {}
virtual void Advance(size_t aFrame) {}
virtual bool MayAdvance() const { return false; }
virtual void MarkMayAdvance() {}

/// @return the availability state of this ISurfaceProvider, which indicates
/// whether DrawableRef() could successfully return a surface. Should only be
Expand Down Expand Up @@ -220,6 +222,24 @@ class MOZ_STACK_CLASS DrawableSurface final {
mProvider->Advance(aFrame);
}

bool MayAdvance() const {
if (!mProvider) {
MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
return false;
}

return mProvider->MayAdvance();
}

void MarkMayAdvance() {
if (!mProvider) {
MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
return;
}

mProvider->MarkMayAdvance();
}

bool IsFullyDecoded() const {
if (!mProvider) {
MOZ_ASSERT_UNREACHABLE(
Expand Down

0 comments on commit 68f4024

Please sign in to comment.