Bug 1951735 - Fix ImageContainer::ClearAllImages() r=gfx-reviewers,media-playback-reviewers,alwu,aosmond

The ClearAllImages() does not actually clear all images in WebRenderImageHost. Update the function as to have a capability to clear all images in WebRenderImageHost. And re-name it to ImageContainer::ClearImagesInHost().

Differential Revision: https://phabricator.services.mozilla.com/D240360
This commit is contained in:
sotaro
2025-03-07 11:23:26 +00:00
parent 543c4f22b8
commit ea83a8d3e7
18 changed files with 126 additions and 43 deletions

View File

@@ -39,7 +39,7 @@ void OffscreenCanvasDisplayHelper::DestroyElement() {
MutexAutoLock lock(mMutex);
if (mImageContainer) {
mImageContainer->ClearAllImages();
mImageContainer->ClearImagesInHost(layers::ClearImagesType::All);
mImageContainer = nullptr;
}
mFrontBufferSurface = nullptr;
@@ -53,7 +53,7 @@ void OffscreenCanvasDisplayHelper::DestroyCanvas() {
MutexAutoLock lock(mMutex);
if (mImageContainer) {
mImageContainer->ClearAllImages();
mImageContainer->ClearImagesInHost(layers::ClearImagesType::All);
mImageContainer = nullptr;
}
mFrontBufferSurface = nullptr;
@@ -309,7 +309,7 @@ bool OffscreenCanvasDisplayHelper::CommitFrameToCompositor(
image, TimeStamp(), mLastFrameID++, mImageProducerID));
mImageContainer->SetCurrentImages(imageList);
} else {
mImageContainer->ClearAllImages();
mImageContainer->ClearImagesInHost(layers::ClearImagesType::All);
}
return true;

View File

@@ -144,7 +144,7 @@ void VideoFrameContainer::SetCurrentFramesLocked(
}
if (aImages.IsEmpty()) {
mImageContainer->ClearAllImages();
mImageContainer->ClearImagesInHost(layers::ClearImagesType::All);
} else {
mImageContainer->SetCurrentImages(aImages);
}
@@ -196,6 +196,11 @@ void VideoFrameContainer::ClearCachedResources() {
mImageContainer->ClearCachedResources();
}
void VideoFrameContainer::ClearImagesInHost(layers::ClearImagesType aType) {
MutexAutoLock lock(mMutex);
mImageContainer->ClearImagesInHost(aType);
}
ImageContainer* VideoFrameContainer::GetImageContainer() {
// Note - you'll need the lock to manipulate this. The pointer is not
// modified from multiple threads, just the data pointed to by it.

View File

@@ -68,9 +68,12 @@ class VideoFrameContainer {
// but was actually painted at t+n, this returns n in seconds. Threadsafe.
double GetFrameDelay();
// Clear any resources that are not immediately necessary.
// Clear any resources in client that are not immediately necessary.
void ClearCachedResources();
// Clear images in host.
void ClearImagesInHost(layers::ClearImagesType aType);
// Returns a new frame ID for SetCurrentFrames(). The client must either
// call this on only one thread or provide barriers. Do not use together
// with SetCurrentFrame().

View File

@@ -709,7 +709,7 @@ void VideoSink::SetSecondaryVideoContainer(VideoFrameContainer* aSecondary) {
if (mSecondaryContainer && aSecondary != mSecondaryContainer) {
ImageContainer* secondaryImageContainer =
mSecondaryContainer->GetImageContainer();
secondaryImageContainer->ClearAllImages();
secondaryImageContainer->ClearImagesInHost(layers::ClearImagesType::All);
}
mSecondaryContainer = aSecondary;
if (!IsPlaying() && mSecondaryContainer) {

View File

@@ -371,17 +371,22 @@ void ImageContainer::SetCurrentImages(const nsTArray<NonOwningImage>& aImages) {
SetCurrentImageInternal(aImages);
}
void ImageContainer::ClearAllImages() {
void ImageContainer::ClearImagesInHost(ClearImagesType aType) {
MOZ_ASSERT(mIsAsync);
if (!mIsAsync) {
return;
}
mRecursiveMutex.Lock();
if (mImageClient) {
RefPtr<ImageClient> imageClient = mImageClient;
mRecursiveMutex.Unlock();
// Let ImageClient release all TextureClients. This doesn't return
// until ImageBridge has called ClearCurrentImageFromImageBridge.
// Let ImageClient clear Images(TextureClients). This doesn't return
// until ImageBridge has called ImageClient::ClearImagesInHost.
if (RefPtr<ImageBridgeChild> imageBridge =
ImageBridgeChild::GetSingleton()) {
imageBridge->FlushAllImages(imageClient, this);
imageBridge->ClearImagesInHost(imageClient, this, aType);
}
return;
}

View File

@@ -293,6 +293,8 @@ class ImageContainerListener final {
ImageContainer* mImageContainer MOZ_GUARDED_BY(mLock);
};
enum class ClearImagesType { All, CacheOnly };
/**
* A class that manages Images for an ImageLayer. The only reason
* we need a separate class here is that ImageLayers aren't threadsafe
@@ -397,11 +399,11 @@ class ImageContainer final : public SupportsThreadSafeWeakPtr<ImageContainer> {
void SetCurrentImages(const nsTArray<NonOwningImage>& aImages);
/**
* Clear all images. Let ImageClient release all TextureClients. Because we
* may release the lock after acquiring it in this method, it cannot be called
* with the lock held.
* Clear images in host. It could be used only with async ImageContainer.
* Because we may release the lock after acquiring it in this method, it
* cannot be called with the lock held.
*/
void ClearAllImages() MOZ_EXCLUDES(mRecursiveMutex);
void ClearImagesInHost(ClearImagesType aType) MOZ_EXCLUDES(mRecursiveMutex);
/**
* Clear any resources that are not immediately necessary. This may be called

View File

@@ -75,14 +75,8 @@ TextureInfo ImageClientSingle::GetTextureInfo() const {
TextureFlags::DEFAULT);
}
void ImageClientSingle::FlushAllImages() {
for (auto& b : mBuffers) {
// It should be safe to just assume a default render root here, even if
// the texture actually presents in a content render root, as the only
// risk would be if the content render root has not / is not going to
// generate a frame before the texture gets cleared.
RemoveTexture(b.mTextureClient);
}
void ImageClientSingle::ClearImagesInHost(ClearImagesType aType) {
GetForwarder()->ClearImagesFromCompositable(this, aType);
mBuffers.Clear();
}

View File

@@ -54,10 +54,10 @@ class ImageClient : public CompositableClient {
virtual bool UpdateImage(ImageContainer* aContainer) = 0;
/**
* asynchronously remove all the textures used by the image client.
* asynchronously clear Images(textures) in host.
*
*/
virtual void FlushAllImages() {}
virtual void ClearImagesInHost(ClearImagesType aType) {}
virtual void RemoveTexture(TextureClient* aTexture) override;
@@ -98,7 +98,7 @@ class ImageClientSingle : public ImageClient {
TextureInfo GetTextureInfo() const override;
void FlushAllImages() override;
void ClearImagesInHost(ClearImagesType aType) override;
ImageClientSingle* AsImageClientSingle() override { return this; }

View File

@@ -88,6 +88,8 @@ class CompositableHost {
virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures);
virtual void RemoveTextureHost(TextureHost* aTexture);
virtual void ClearImages(ClearImagesType aType) {}
const AsyncCompositableRef& GetAsyncRef() const { return mAsyncRef; }
void SetAsyncRef(const AsyncCompositableRef& aRef) { mAsyncRef = aRef; }

View File

@@ -166,7 +166,6 @@ const ImageComposite::TimedImage* ImageComposite::ChooseImage() {
void ImageComposite::RemoveImagesWithTextureHost(TextureHost* aTexture) {
for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
if (mImages[i].mTextureHost == aTexture) {
aTexture->UnbindTextureSource();
mImages.RemoveElementAt(i);
}
}

View File

@@ -8,6 +8,8 @@
#define MOZILLA_LAYERS_COMPOSITABLEFORWARDER
#include <stdint.h> // for int32_t, uint32_t, uint64_t
#include "ImageContainer.h"
#include "mozilla/Assertions.h" // for AssertionConditionType, MOZ_ASSERT, MOZ_ASSERT_HELPER1
#include "mozilla/Atomics.h"
#include "mozilla/RefPtr.h" // for RefPtr
@@ -22,7 +24,6 @@ namespace mozilla {
namespace layers {
class CompositableClient;
class CompositableHandle;
class ImageContainer;
class PTextureChild;
class SurfaceDescriptorTiles;
class TextureClient;
@@ -137,6 +138,13 @@ class CompositableForwarder : public KnowsCompositor {
virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
TextureClient* aTexture) = 0;
/**
* Tell the CompositableHost on the compositor side to clear Images
* from the CompositableHost.
*/
virtual void ClearImagesFromCompositable(CompositableClient* aCompositable,
ClearImagesType aType) {}
struct TimedTextureClient {
TimedTextureClient()
: mTextureClient(nullptr), mFrameID(0), mProducerID(0) {}

View File

@@ -51,6 +51,12 @@ bool CompositableParentManager::ReceiveCompositableUpdate(
aCompositable->RemoveTextureHost(tex);
break;
}
case CompositableOperationDetail::TOpClearImages: {
const OpClearImages& op = aDetail.get_OpClearImages();
aCompositable->ClearImages(op.type());
break;
}
case CompositableOperationDetail::TOpUseTexture: {
const OpUseTexture& op = aDetail.get_OpUseTexture();

View File

@@ -357,9 +357,10 @@ void ImageBridgeChild::UpdateCompositable(
EndTransaction();
}
void ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask,
ImageClient* aClient,
ImageContainer* aContainer) {
void ImageBridgeChild::ClearImagesInHostSync(SynchronousTask* aTask,
ImageClient* aClient,
ImageContainer* aContainer,
ClearImagesType aType) {
AutoCompleteTask complete(aTask);
if (!CanSend()) {
@@ -371,27 +372,29 @@ void ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask,
if (aContainer) {
aContainer->ClearImagesFromImageBridge();
}
aClient->FlushAllImages();
aClient->ClearImagesInHost(aType);
EndTransaction();
}
void ImageBridgeChild::FlushAllImages(ImageClient* aClient,
ImageContainer* aContainer) {
void ImageBridgeChild::ClearImagesInHost(ImageClient* aClient,
ImageContainer* aContainer,
ClearImagesType aType) {
MOZ_ASSERT(aClient);
MOZ_ASSERT(!InImageBridgeChildThread());
if (InImageBridgeChildThread()) {
NS_ERROR(
"ImageBridgeChild::FlushAllImages() is called on ImageBridge thread.");
"ImageBridgeChild::ClearImagesInHost() is called on ImageBridge "
"thread.");
return;
}
SynchronousTask task("FlushAllImages Lock");
SynchronousTask task("ClearImagesInHost Lock");
// RefPtrs on arguments are not needed since this dispatches synchronously.
RefPtr<Runnable> runnable = WrapRunnable(
RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::FlushAllImagesSync,
&task, aClient, aContainer);
RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::ClearImagesInHostSync,
&task, aClient, aContainer, aType);
GetThread()->Dispatch(runnable.forget());
task.Wait();
@@ -905,6 +908,18 @@ void ImageBridgeChild::RemoveTextureFromCompositable(
OpRemoveTexture(WrapNotNull(aTexture->GetIPDLActor()))));
}
void ImageBridgeChild::ClearImagesFromCompositable(
CompositableClient* aCompositable, ClearImagesType aType) {
MOZ_ASSERT(CanSend());
MOZ_ASSERT(aCompositable->IsConnected());
if (!aCompositable->IsConnected()) {
return;
}
mTxn->AddNoSwapEdit(CompositableOperation(aCompositable->GetIPCHandle(),
OpClearImages(aType)));
}
bool ImageBridgeChild::IsSameProcess() const {
return OtherPid() == base::GetCurrentProcId();
}

View File

@@ -11,6 +11,7 @@
#include <stdint.h> // for uint32_t, uint64_t
#include <unordered_map>
#include "ImageContainer.h"
#include "mozilla/Attributes.h" // for override
#include "mozilla/Atomics.h"
#include "mozilla/RefPtr.h" // for already_AddRefed
@@ -206,9 +207,10 @@ class ImageBridgeChild final : public PImageBridgeChild,
const RefPtr<FwdTransactionTracker> aTracker);
/**
* Flush all Images sent to CompositableHost.
* Clear Images in host.
*/
void FlushAllImages(ImageClient* aClient, ImageContainer* aContainer);
void ClearImagesInHost(ImageClient* aClient, ImageContainer* aContainer,
ClearImagesType aType);
bool IPCOpen() const override { return mCanSend; }
@@ -225,8 +227,8 @@ class ImageBridgeChild final : public PImageBridgeChild,
CompositableType aType,
ImageContainer* aImageContainer);
void FlushAllImagesSync(SynchronousTask* aTask, ImageClient* aClient,
ImageContainer* aContainer);
void ClearImagesInHostSync(SynchronousTask* aTask, ImageClient* aClient,
ImageContainer* aContainer, ClearImagesType aType);
void ProxyAllocShmemNow(SynchronousTask* aTask, size_t aSize,
mozilla::ipc::Shmem* aShmem, bool aUnsafe,
@@ -282,6 +284,9 @@ class ImageBridgeChild final : public PImageBridgeChild,
void RemoveTextureFromCompositable(CompositableClient* aCompositable,
TextureClient* aTexture) override;
void ClearImagesFromCompositable(CompositableClient* aCompositable,
ClearImagesType aType) override;
// ISurfaceAllocator
/**

View File

@@ -14,6 +14,7 @@
#include "FrameMetrics.h"
#include "VsyncSource.h"
#include "chrome/common/ipc_message_utils.h"
#include "ImageContainer.h"
#include "ipc/EnumSerializer.h"
#include "ipc/IPCMessageUtils.h"
#include "mozilla/ScrollSnapInfo.h"
@@ -1130,6 +1131,13 @@ struct ParamTraits<mozilla::layers::CompositionPayload> {
}
};
template <>
struct ParamTraits<mozilla::layers::ClearImagesType>
: public ContiguousEnumSerializerInclusive<
mozilla::layers::ClearImagesType,
mozilla::layers::ClearImagesType::All,
mozilla::layers::ClearImagesType::CacheOnly> {};
template <>
struct ParamTraits<mozilla::layers::CantZoomOutBehavior>
: public ContiguousEnumSerializerInclusive<

View File

@@ -49,6 +49,7 @@ using mozilla::ParentLayerRect from "Units.h";
using mozilla::LayoutDeviceIntRect from "Units.h";
using mozilla::LayoutDevicePoint from "Units.h";
using mozilla::LayoutDeviceRect from "Units.h";
using mozilla::layers::ClearImagesType from "ImageContainer.h";
using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
using mozilla::layers::EventRegionsOverride from "mozilla/layers/LayersTypes.h";
using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
@@ -278,6 +279,13 @@ struct OpRemoveTexture {
PTexture texture;
};
/**
* Tells the CompositableHost to clear Images
*/
struct OpClearImages {
ClearImagesType type;
};
struct TimedTexture {
PTexture texture;
TimeStamp timeStamp;
@@ -322,6 +330,8 @@ struct OpNotifyNotUsed {
union CompositableOperationDetail {
OpRemoveTexture;
OpClearImages;
OpUseTexture;
OpUseRemoteTexture;

View File

@@ -252,15 +252,34 @@ void WebRenderImageHost::UseRemoteTexture() {
}
void WebRenderImageHost::CleanupResources() {
ClearImages();
ImageComposite::ClearImages();
SetCurrentTextureHost(nullptr);
}
void WebRenderImageHost::RemoveTextureHost(TextureHost* aTexture) {
CompositableHost::RemoveTextureHost(aTexture);
RemoveImagesWithTextureHost(aTexture);
}
void WebRenderImageHost::ClearImages(ClearImagesType aType) {
ImageComposite::ClearImages();
if (aType == ClearImagesType::All) {
if (!mPendingRemoteTextureWrappers.empty()) {
mPendingRemoteTextureWrappers.clear();
}
SetCurrentTextureHost(nullptr);
if (GetAsyncRef()) {
for (const auto& it : mWrBridges) {
RefPtr<WebRenderBridgeParent> wrBridge = it.second->WrBridge();
if (wrBridge && wrBridge->CompositorScheduler()) {
wrBridge->CompositorScheduler()->ScheduleComposition(
wr::RenderReasons::ASYNC_IMAGE);
}
}
}
}
}
TimeStamp WebRenderImageHost::GetCompositionTime() const {
TimeStamp time;

View File

@@ -34,6 +34,8 @@ class WebRenderImageHost : public CompositableHost, public ImageComposite {
void UseTextureHost(const nsTArray<TimedTexture>& aTextures) override;
void RemoveTextureHost(TextureHost* aTexture) override;
void ClearImages(ClearImagesType aType) override;
void Dump(std::stringstream& aStream, const char* aPrefix = "",
bool aDumpHtml = false) override;