mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-26 14:46:02 +00:00
Bug 1711061 - Part 4. Implement AnimationSurfaceProvider for animated rasterized images. r=tnikkel
Differential Revision: https://phabricator.services.mozilla.com/D126790
This commit is contained in:
parent
bd93e83c2a
commit
546e3f7640
@ -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();
|
||||
@ -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;
|
||||
@ -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
|
||||
|
@ -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.
|
||||
@ -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.
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
@ -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.
|
||||
|
@ -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 {
|
||||
@ -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(),
|
||||
@ -47,6 +52,7 @@ AnimationSurfaceProvider::AnimationSurfaceProvider(
|
||||
AnimationSurfaceProvider::~AnimationSurfaceProvider() {
|
||||
DropImageReference();
|
||||
|
||||
mSharedAnimation->Destroy();
|
||||
if (mDecoder) {
|
||||
mDecoder->SetFrameRecycler(nullptr);
|
||||
}
|
||||
@ -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) {
|
||||
@ -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
|
||||
|
@ -19,6 +19,10 @@
|
||||
#include "AnimationFrameBuffer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class SharedSurfacesAnimation;
|
||||
}
|
||||
|
||||
namespace image {
|
||||
|
||||
/**
|
||||
@ -41,12 +45,6 @@ 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;
|
||||
@ -54,6 +52,8 @@ class AnimationSurfaceProvider final : public ISurfaceProvider,
|
||||
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;
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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());
|
||||
|
@ -35,7 +35,6 @@ class AnimationState {
|
||||
mHasRequestedDecode(false),
|
||||
mIsCurrentlyDecoded(false),
|
||||
mCompositedFrameInvalid(false),
|
||||
mCompositedFrameRequested(false),
|
||||
mDiscarded(false) {}
|
||||
|
||||
/**
|
||||
@ -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;
|
||||
|
@ -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
|
||||
@ -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(
|
||||
|
Loading…
x
Reference in New Issue
Block a user