fune/gfx/layers/ipc/SharedSurfacesChild.h
Andrew Osmond 310254c18d Bug 1869933 - Avoid allocating external image ID until ready for sharing with compositor process. r=gfx-reviewers,lsalzman
There are some error paths where we could allocate an external image ID
for a SourceSurfaceSharedData before we are able to finish sharing it.
This patch makes it so that we defer allocating the ID until the last
possible moment. This will ensure they are always increasing in order.

The patch also adds in the necessary plumbing for notifications for
waking up threads blocked on a particular external image ID for a shared
surface inside the compositor process. This is less relevant now since
it should always been in the SharedSurfacesParent map, as recordings are
only created from the main thread, but may become more important as we
add recordings to DOM workers.

Differential Revision: https://phabricator.services.mozilla.com/D196422
2023-12-14 20:08:59 +00:00

259 lines
8.5 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_GFX_SHAREDSURFACESCHILD_H
#define MOZILLA_GFX_SHAREDSURFACESCHILD_H
#include <stdint.h> // for uint32_t, uint64_t
#include "mozilla/Attributes.h" // for override
#include "mozilla/Maybe.h" // for Maybe
#include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/StaticPtr.h" // for StaticRefPtr
#include "mozilla/gfx/UserData.h" // for UserDataKey
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/webrender/WebRenderTypes.h" // for wr::ImageKey
#include "nsTArray.h" // for AutoTArray
#include "nsThreadUtils.h" // for Runnable
#include "ImageTypes.h" // for ContainerProducerID
namespace mozilla {
namespace layers {
class AnimationImageKeyData;
} // namespace layers
} // namespace mozilla
template <>
struct nsTArray_RelocationStrategy<mozilla::layers::AnimationImageKeyData> {
typedef nsTArray_RelocateUsingMoveConstructor<
mozilla::layers::AnimationImageKeyData>
Type;
};
namespace mozilla {
namespace gfx {
class SourceSurface;
class SourceSurfaceSharedData;
} // namespace gfx
namespace wr {
class IpcResourceUpdateQueue;
} // namespace wr
namespace layers {
class CompositorManagerChild;
class RenderRootStateManager;
class SharedSurfacesChild {
public:
/**
* Request that the surface be mapped into the compositor thread's memory
* space. This is useful for when the caller itself has no present need for
* the surface to be mapped, but knows there will be such a need in the
* future. This may be called from any thread, but it may cause a dispatch to
* the main thread.
*/
static void Share(gfx::SourceSurfaceSharedData* aSurface);
/**
* Request that the surface be mapped into the compositor thread's memory
* space, and a valid ExternalImageId be generated for it for use with
* WebRender. This must be called from the main thread.
*/
static nsresult Share(gfx::SourceSurface* aSurface, wr::ExternalImageId& aId);
/**
* Request that the surface be mapped into the compositor thread's memory
* space, and a valid ExternalImageId be generated for it for use with
* WebRender. This must be called from the main thread.
*/
static nsresult Share(gfx::SourceSurface* aSurface,
Maybe<SurfaceDescriptor>& aDesc);
/**
* Request that the surface be mapped into the compositor thread's memory
* space, and a valid ImageKey be generated for it for use with WebRender.
* This must be called from the main thread.
*/
static nsresult Share(gfx::SourceSurfaceSharedData* aSurface,
RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey);
/**
* Request that the surface be mapped into the compositor thread's memory
* space, and a valid ImageKey be generated for it for use with WebRender.
* This must be called from the main thread.
*/
static nsresult Share(gfx::SourceSurface* aSurface,
RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey);
/**
* Get the external ID, if any, bound to the shared surface. Used for memory
* reporting purposes.
*/
static Maybe<wr::ExternalImageId> GetExternalId(
const gfx::SourceSurfaceSharedData* aSurface);
/**
* Get the surface (or its underlying surface) as a SourceSurfaceSharedData
* pointer, if valid.
*/
static gfx::SourceSurfaceSharedData* AsSourceSurfaceSharedData(
gfx::SourceSurface* aSurface);
class ImageKeyData {
public:
ImageKeyData(RenderRootStateManager* aManager,
const wr::ImageKey& aImageKey);
virtual ~ImageKeyData();
ImageKeyData(ImageKeyData&& aOther);
ImageKeyData& operator=(ImageKeyData&& aOther);
ImageKeyData(const ImageKeyData&) = delete;
ImageKeyData& operator=(const ImageKeyData&) = delete;
void MergeDirtyRect(const Maybe<gfx::IntRect>& aDirtyRect);
Maybe<gfx::IntRect> TakeDirtyRect() { return std::move(mDirtyRect); }
RefPtr<RenderRootStateManager> mManager;
Maybe<gfx::IntRect> mDirtyRect;
wr::ImageKey mImageKey;
};
private:
SharedSurfacesChild() = delete;
~SharedSurfacesChild() = delete;
friend class SharedSurfacesAnimation;
class SharedUserData final : public Runnable {
public:
SharedUserData();
virtual ~SharedUserData();
SharedUserData(const SharedUserData& aOther) = delete;
SharedUserData& operator=(const SharedUserData& aOther) = delete;
SharedUserData(SharedUserData&& aOther) = delete;
SharedUserData& operator=(SharedUserData&& aOther) = delete;
static void Destroy(void* aClosure);
NS_IMETHOD Run() override;
const wr::ExternalImageId& Id() const { return mId; }
void ClearShared() {
mKeys.Clear();
mShared = false;
}
bool IsShared() const { return mShared; }
void MarkShared(const wr::ExternalImageId& aId) {
MOZ_ASSERT(!mShared);
mId = aId;
mShared = true;
}
wr::ImageKey UpdateKey(RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
const Maybe<gfx::IntRect>& aDirtyRect);
protected:
AutoTArray<ImageKeyData, 1> mKeys;
wr::ExternalImageId mId;
bool mShared : 1;
};
static nsresult ShareInternal(gfx::SourceSurfaceSharedData* aSurface,
SharedUserData** aUserData);
static void Unshare(const wr::ExternalImageId& aId, bool aReleaseId,
nsTArray<ImageKeyData>& aKeys);
static void DestroySharedUserData(void* aClosure);
static gfx::UserDataKey sSharedKey;
};
class AnimationImageKeyData final : public SharedSurfacesChild::ImageKeyData {
public:
AnimationImageKeyData(RenderRootStateManager* aManager,
const wr::ImageKey& aImageKey);
virtual ~AnimationImageKeyData();
AnimationImageKeyData(AnimationImageKeyData&& aOther);
AnimationImageKeyData& operator=(AnimationImageKeyData&& aOther);
AutoTArray<RefPtr<gfx::SourceSurfaceSharedData>, 2> mPendingRelease;
};
/**
* This helper class owns a single ImageKey which will map to different external
* image IDs representing different frames in an animation.
*/
class SharedSurfacesAnimation final {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedSurfacesAnimation)
SharedSurfacesAnimation() = default;
void Destroy();
/**
* 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,
RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey);
/**
* Release our reference to all frames up to and including the frame which
* has an external image ID which matches aId.
*/
void ReleasePreviousFrame(RenderRootStateManager* aManager,
const wr::ExternalImageId& aId);
/**
* Destroy any state information bound for the given layer manager. Any
* image keys are already invalid.
*/
void Invalidate(RenderRootStateManager* aManager);
private:
~SharedSurfacesAnimation();
void HoldSurfaceForRecycling(AnimationImageKeyData& aEntry,
gfx::SourceSurfaceSharedData* aSurface);
AutoTArray<AnimationImageKeyData, 1> mKeys;
wr::ExternalImageId mId;
};
} // namespace layers
} // namespace mozilla
#endif