Bug 1428558 - Part 5. Add SharedSurfacesAnimation to manage single ImageKey for animated images. r=nical

Differential Revision: https://phabricator.services.mozilla.com/D7502
This commit is contained in:
Andrew Osmond 2018-10-02 13:28:17 -04:00
parent ed51ad4899
commit 6a77ac0bd5
2 changed files with 126 additions and 8 deletions

View File

@ -59,33 +59,36 @@ SharedSurfacesChild::ImageKeyData::MergeDirtyRect(const Maybe<IntRect>& aDirtyRe
SharedSurfacesChild::SharedUserData::~SharedUserData()
{
if (mShared) {
mShared = false;
if (mShared || !mKeys.IsEmpty()) {
if (NS_IsMainThread()) {
SharedSurfacesChild::Unshare(mId, mKeys);
SharedSurfacesChild::Unshare(mId, mShared, mKeys);
} else {
class DestroyRunnable final : public Runnable
{
public:
DestroyRunnable(const wr::ExternalImageId& aId,
bool aReleaseId,
nsTArray<ImageKeyData>&& aKeys)
: Runnable("SharedSurfacesChild::SharedUserData::DestroyRunnable")
, mId(aId)
, mReleaseId(aReleaseId)
, mKeys(std::move(aKeys))
{ }
NS_IMETHOD Run() override
{
SharedSurfacesChild::Unshare(mId, mKeys);
SharedSurfacesChild::Unshare(mId, mReleaseId, mKeys);
return NS_OK;
}
private:
wr::ExternalImageId mId;
bool mReleaseId;
AutoTArray<ImageKeyData, 1> mKeys;
};
nsCOMPtr<nsIRunnable> task = new DestroyRunnable(mId, std::move(mKeys));
nsCOMPtr<nsIRunnable> task =
new DestroyRunnable(mId, mShared, std::move(mKeys));
SystemGroup::Dispatch(TaskCategory::Other, task.forget());
}
}
@ -129,6 +132,7 @@ SharedSurfacesChild::SharedUserData::UpdateKey(WebRenderLayerManager* aManager,
entry.MergeDirtyRect(aDirtyRect);
Maybe<IntRect> dirtyRect = entry.TakeDirtyRect();
if (dirtyRect) {
MOZ_ASSERT(mShared);
aResources.UpdateExternalImage(mId, entry.mImageKey,
ViewAs<ImagePixel>(dirtyRect.ref()));
}
@ -370,6 +374,7 @@ SharedSurfacesChild::Share(SourceSurface* aSurface,
/* static */ void
SharedSurfacesChild::Unshare(const wr::ExternalImageId& aId,
bool aReleaseId,
nsTArray<ImageKeyData>& aKeys)
{
MOZ_ASSERT(NS_IsMainThread());
@ -380,6 +385,11 @@ SharedSurfacesChild::Unshare(const wr::ExternalImageId& aId,
}
}
if (!aReleaseId) {
// We don't own the external image ID itself.
return;
}
CompositorManagerChild* manager = CompositorManagerChild::GetInstance();
if (MOZ_UNLIKELY(!manager || !manager->CanSend())) {
return;
@ -418,5 +428,66 @@ SharedSurfacesChild::GetExternalId(const SourceSurfaceSharedData* aSurface)
return Some(data->Id());
}
nsresult
SharedSurfacesAnimation::SetCurrentFrame(SourceSurfaceSharedData* aSurface,
const gfx::IntRect& aDirtyRect)
{
MOZ_ASSERT(aSurface);
SharedUserData* data = nullptr;
nsresult rv = SharedSurfacesChild::ShareInternal(aSurface, &data);
if (NS_FAILED(rv)) {
return rv;
}
MOZ_ASSERT(data);
mId = data->Id();
auto i = mKeys.Length();
while (i > 0) {
--i;
SharedSurfacesChild::ImageKeyData& entry = mKeys[i];
if (entry.mManager->IsDestroyed()) {
mKeys.RemoveElementAt(i);
continue;
}
entry.MergeDirtyRect(Some(aDirtyRect));
Maybe<IntRect> dirtyRect = entry.TakeDirtyRect();
if (dirtyRect) {
auto& resourceUpdates = entry.mManager->AsyncResourceUpdates();
resourceUpdates.UpdateExternalImage(mId, entry.mImageKey,
ViewAs<ImagePixel>(dirtyRect.ref()));
}
}
return NS_OK;
}
nsresult
SharedSurfacesAnimation::UpdateKey(SourceSurfaceSharedData* aSurface,
WebRenderLayerManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey)
{
SharedUserData* data = nullptr;
nsresult rv = SharedSurfacesChild::ShareInternal(aSurface, &data);
if (NS_FAILED(rv)) {
return rv;
}
MOZ_ASSERT(data);
if (mId.mHandle != data->Id().mHandle) {
mKeys.Clear();
mId = data->Id();
}
aKey = SharedSurfacesChild::SharedUserData::UpdateKey(aManager,
aResources,
Nothing());
return NS_OK;
}
} // namespace layers
} // namespace mozilla

View File

@ -84,6 +84,8 @@ private:
SharedSurfacesChild() = delete;
~SharedSurfacesChild() = delete;
friend class SharedSurfacesAnimation;
class ImageKeyData final {
public:
ImageKeyData(WebRenderLayerManager* aManager,
@ -107,8 +109,12 @@ private:
wr::ImageKey mImageKey;
};
class SharedUserData final {
class SharedUserData {
public:
SharedUserData()
: mShared(false)
{ }
explicit SharedUserData(const wr::ExternalImageId& aId)
: mId(aId)
, mShared(false)
@ -116,6 +122,12 @@ private:
~SharedUserData();
SharedUserData(const SharedUserData& aOther) = delete;
SharedUserData& operator=(const SharedUserData& aOther) = delete;
SharedUserData(SharedUserData&& aOther) = delete;
SharedUserData& operator=(SharedUserData&& aOther) = delete;
const wr::ExternalImageId& Id() const
{
return mId;
@ -143,7 +155,7 @@ private:
wr::IpcResourceUpdateQueue& aResources,
const Maybe<gfx::IntRect>& aDirtyRect);
private:
protected:
AutoTArray<ImageKeyData, 1> mKeys;
wr::ExternalImageId mId;
bool mShared : 1;
@ -152,12 +164,47 @@ private:
static nsresult ShareInternal(gfx::SourceSurfaceSharedData* aSurface,
SharedUserData** aUserData);
static void Unshare(const wr::ExternalImageId& aId, nsTArray<ImageKeyData>& aKeys);
static void Unshare(const wr::ExternalImageId& aId,
bool aReleaseId,
nsTArray<ImageKeyData>& aKeys);
static void DestroySharedUserData(void* aClosure);
static gfx::UserDataKey sSharedKey;
};
/**
* This helper class owns a single ImageKey which will map to different external
* image IDs representing different frames in an animation.
*/
class SharedSurfacesAnimation final : private SharedSurfacesChild::SharedUserData
{
public:
SharedSurfacesAnimation()
{ }
/**
* Set the animation to display the given frame.
* @param aSurface The current frame.
* @param aDirtyRect Dirty rect representing the change between the new frame
* and the previous frame. We will request only the delta
* be reuploaded by WebRender.
*/
nsresult SetCurrentFrame(gfx::SourceSurfaceSharedData* aSurface,
const gfx::IntRect& aDirtyRect);
/**
* Generate an ImageKey for the given frame.
* @param aSurface The current frame. This should match what was cached via
* SetCurrentFrame, but if it does not, it will need to
* regenerate the cached ImageKey.
*/
nsresult UpdateKey(gfx::SourceSurfaceSharedData* aSurface,
WebRenderLayerManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey);
};
} // namespace layers
} // namespace mozilla