Bug 1900677 - Add a capability to recycle DataSourceSurface allocated in CanvasTranslator::LookupSourceSurfaceFromSurfaceDescriptor() if possible r=gfx-reviewers,lsalzman

By default, it is disabled by pref gfx.canvas.remote.recycle-used-data-surface = false.

Add a capability to reuse used DataSourceSurface that was previously used for storing converted video data.

Add argument gfx::DataSourceSurface* aSurface to TextureHost::GetAsSurface(). aSurface may be used as returned DataSourceSurfacefi the TextureHost supports it.

Differential Revision: https://phabricator.services.mozilla.com/D212608
This commit is contained in:
sotaro 2024-06-06 03:25:53 +00:00
parent 68fdfb66c4
commit d3bd7ab3f1
18 changed files with 113 additions and 31 deletions

View file

@ -95,7 +95,8 @@ class DcompSurfaceHandleHost : public TextureHost {
const char* Name() override { return "DcompSurfaceHandleHost"; }
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
return nullptr;
}

View file

@ -149,7 +149,7 @@ static nsresult CopyFromLockedMacIOSurface(MacIOSurface* aSurface,
}
already_AddRefed<SourceSurface> CreateSourceSurfaceFromMacIOSurface(
MacIOSurface* aSurface) {
MacIOSurface* aSurface, gfx::DataSourceSurface* aDataSurface) {
aSurface->Lock();
auto scopeExit = MakeScopeExit([&]() { aSurface->Unlock(); });
@ -163,10 +163,21 @@ already_AddRefed<SourceSurface> CreateSourceSurfaceFromMacIOSurface(
? SurfaceFormat::B8G8R8X8
: SurfaceFormat::B8G8R8A8;
RefPtr<DataSourceSurface> dataSurface =
Factory::CreateDataSourceSurface(size, format);
if (NS_WARN_IF(!dataSurface)) {
return nullptr;
RefPtr<DataSourceSurface> dataSurface;
if (aDataSurface) {
MOZ_ASSERT(aDataSurface->GetSize() == size);
MOZ_ASSERT(aDataSurface->GetFormat() == format);
if (aDataSurface->GetSize() == size &&
aDataSurface->GetFormat() == format) {
dataSurface = aDataSurface;
}
}
if (!dataSurface) {
dataSurface = Factory::CreateDataSourceSurface(size, format);
if (NS_WARN_IF(!dataSurface)) {
return nullptr;
}
}
DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::WRITE);

View file

@ -24,7 +24,7 @@ namespace layers {
// Unlike MacIOSurface::GetAsSurface, this also handles IOSurface formats
// with multiple planes and does YCbCr to RGB conversion, if necessary.
already_AddRefed<gfx::SourceSurface> CreateSourceSurfaceFromMacIOSurface(
MacIOSurface* aSurface);
MacIOSurface* aSurface, gfx::DataSourceSurface* aDataSurface = nullptr);
nsresult CreateSurfaceDescriptorBufferFromMacIOSurface(
MacIOSurface* aSurface, SurfaceDescriptorBuffer& aSdBuffer,

View file

@ -24,7 +24,8 @@ class GPUVideoTextureHost : public TextureHost {
gfx::SurfaceFormat GetFormat() const override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}

View file

@ -27,7 +27,8 @@ class RemoteTextureHostWrapper : public TextureHost {
gfx::SurfaceFormat GetFormat() const override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
return nullptr;
}

View file

@ -702,14 +702,15 @@ int32_t BufferTextureHost::GetCbCrStride() const {
return 0;
}
already_AddRefed<gfx::DataSourceSurface> BufferTextureHost::GetAsSurface() {
already_AddRefed<gfx::DataSourceSurface> BufferTextureHost::GetAsSurface(
gfx::DataSourceSurface* aSurface) {
RefPtr<gfx::DataSourceSurface> result;
if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
NS_WARNING("BufferTextureHost: unsupported format!");
return nullptr;
} else if (mFormat == gfx::SurfaceFormat::YUV) {
result = ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
GetBuffer(), mDescriptor.get_YCbCrDescriptor());
GetBuffer(), mDescriptor.get_YCbCrDescriptor(), aSurface);
if (NS_WARN_IF(!result)) {
return nullptr;
}

View file

@ -90,7 +90,7 @@ class TextureHostWrapperD3D11;
class BigImageIterator {
public:
virtual void BeginBigImageIteration() = 0;
virtual void EndBigImageIteration(){};
virtual void EndBigImageIteration() {};
virtual gfx::IntRect GetTileRect() = 0;
virtual size_t GetTileCount() = 0;
virtual bool NextTile() = 0;
@ -498,10 +498,14 @@ class TextureHost : public AtomicRefCountedWithFinalize<TextureHost> {
virtual void SetCropRect(nsIntRect aCropRect) {}
/**
* Debug facility.
* Return TextureHost's data as DataSourceSurface.
*
* @param aSurface may be used as returned DataSourceSurface.
*
* XXX - cool kids use Moz2D. See bug 882113.
*/
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() = 0;
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface = nullptr) = 0;
/**
* XXX - Flags should only be set at creation time, this will be removed.
@ -813,7 +817,8 @@ class BufferTextureHost : public TextureHost {
gfx::IntSize GetSize() const override { return mSize; }
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override;
bool NeedsDeferredDeletion() const override {
return TextureHost::NeedsDeferredDeletion() || UseExternalTextures();

View file

@ -921,7 +921,8 @@ bool DXGITextureHostD3D11::LockInternal() {
return mIsLocked;
}
already_AddRefed<gfx::DataSourceSurface> DXGITextureHostD3D11::GetAsSurface() {
already_AddRefed<gfx::DataSourceSurface> DXGITextureHostD3D11::GetAsSurface(
gfx::DataSourceSurface* aSurface) {
switch (GetFormat()) {
case gfx::SurfaceFormat::R8G8B8X8:
case gfx::SurfaceFormat::R8G8B8A8:

View file

@ -358,7 +358,8 @@ class DXGITextureHostD3D11 : public TextureHost {
gfx::IntSize GetSize() const override { return mSize; }
gfx::ColorRange GetColorRange() const override { return mColorRange; }
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override;
void CreateRenderTexture(
const wr::ExternalImageId& aExternalImageId) override;
@ -427,7 +428,8 @@ class DXGIYCbCrTextureHostD3D11 : public TextureHost {
gfx::IntSize GetSize() const override { return mSize; }
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
return nullptr;
}

View file

@ -93,7 +93,8 @@ class TextureHostWrapperD3D11 : public TextureHost {
gfx::SurfaceFormat GetFormat() const override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}

View file

@ -865,6 +865,7 @@ void CanvasTranslator::PrepareShmem(int64_t aTextureId) {
}
void CanvasTranslator::ClearCachedResources() {
mUsedDataSurfaceForSurfaceDescriptor = nullptr;
if (mSharedContext) {
// If there are any DrawTargetWebgls, then try to cache their framebuffers
// in software surfaces, just in case the GL context is lost. So long as
@ -1153,6 +1154,7 @@ bool CanvasTranslator::PushRemoteTexture(int64_t aTextureId, TextureData* aData,
}
void CanvasTranslator::ClearTextureInfo() {
mUsedDataSurfaceForSurfaceDescriptor = nullptr;
for (auto const& entry : mTextureInfo) {
if (entry.second.mTextureData) {
entry.second.mTextureData->Unlock();
@ -1214,6 +1216,36 @@ static bool SDIsSupportedRemoteDecoder(const SurfaceDescriptor& sd) {
return false;
}
already_AddRefed<gfx::DataSourceSurface>
CanvasTranslator::GetRecycledDataSurfaceForSurfaceDescriptor(
TextureHost* aTextureHost) {
if (!StaticPrefs::gfx_canvas_remote_recycle_used_data_surface()) {
return nullptr;
}
auto& usedSurf = mUsedDataSurfaceForSurfaceDescriptor;
bool isYuvVideo = false;
if (aTextureHost->AsMacIOSurfaceTextureHost()) {
if (aTextureHost->GetFormat() == SurfaceFormat::NV12 ||
aTextureHost->GetFormat() == SurfaceFormat::YUV422) {
isYuvVideo = true;
}
} else if (aTextureHost->GetFormat() == gfx::SurfaceFormat::YUV) {
isYuvVideo = true;
}
if (isYuvVideo && usedSurf && usedSurf->refCount() == 1 &&
usedSurf->GetFormat() == gfx::SurfaceFormat::B8G8R8X8 &&
aTextureHost->GetSize() == usedSurf->GetSize()) {
// Reuse previously used DataSourceSurface if it is not used and same
// size/format.
return usedSurf.forget();
}
usedSurf = nullptr;
return nullptr;
}
already_AddRefed<gfx::SourceSurface>
CanvasTranslator::LookupSourceSurfaceFromSurfaceDescriptor(
const SurfaceDescriptor& aDesc) {
@ -1244,11 +1276,19 @@ CanvasTranslator::LookupSourceSurfaceFromSurfaceDescriptor(
if (subdescType ==
RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorMacIOSurface) {
MOZ_ASSERT(texture->AsMacIOSurfaceTextureHost());
return texture->GetAsSurface();
RefPtr<gfx::DataSourceSurface> reuseSurf =
GetRecycledDataSurfaceForSurfaceDescriptor(texture);
RefPtr<gfx::DataSourceSurface> surf = texture->GetAsSurface(reuseSurf);
mUsedDataSurfaceForSurfaceDescriptor = surf;
return surf.forget();
}
if (subdescType == RemoteDecoderVideoSubDescriptor::Tnull_t) {
RefPtr<gfx::DataSourceSurface> surf = texture->GetAsSurface();
RefPtr<gfx::DataSourceSurface> reuseSurf =
GetRecycledDataSurfaceForSurfaceDescriptor(texture);
RefPtr<gfx::DataSourceSurface> surf = texture->GetAsSurface(reuseSurf);
mUsedDataSurfaceForSurfaceDescriptor = surf;
return surf.forget();
}

View file

@ -36,6 +36,7 @@ namespace layers {
class SharedSurfacesHolder;
class TextureData;
class TextureHost;
class CanvasTranslator final : public gfx::InlineTranslator,
public PCanvasParent {
@ -333,6 +334,9 @@ class CanvasTranslator final : public gfx::InlineTranslator,
void ClearCachedResources();
already_AddRefed<gfx::DataSourceSurface>
GetRecycledDataSurfaceForSurfaceDescriptor(TextureHost* aTextureHost);
const RefPtr<TaskQueue> mTranslationTaskQueue;
const RefPtr<SharedSurfacesHolder> mSharedSurfacesHolder;
#if defined(XP_WIN)
@ -396,6 +400,7 @@ class CanvasTranslator final : public gfx::InlineTranslator,
Atomic<bool> mIPDLClosed{false};
bool mIsInTransaction = false;
bool mDeviceResetInProgress = false;
RefPtr<gfx::DataSourceSurface> mUsedDataSurfaceForSurfaceDescriptor;
};
} // namespace layers

View file

@ -28,7 +28,8 @@ class DMABUFTextureHostOGL : public TextureHost {
gfx::SurfaceFormat GetFormat() const override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}

View file

@ -34,9 +34,10 @@ class MacIOSurfaceTextureHostOGL : public TextureHost {
gfx::SurfaceFormat GetFormat() const override;
gfx::SurfaceFormat GetReadFormat() const override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
RefPtr<gfx::SourceSurface> surf =
CreateSourceSurfaceFromMacIOSurface(GetMacIOSurface());
CreateSourceSurfaceFromMacIOSurface(GetMacIOSurface(), aSurface);
return surf->GetDataSurface();
}

View file

@ -317,7 +317,8 @@ class GLTextureHost : public TextureHost {
gfx::SurfaceFormat GetFormat() const override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}
@ -396,7 +397,8 @@ class SurfaceTextureHost : public TextureHost {
gfx::SurfaceFormat GetFormat() const override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}
@ -509,7 +511,8 @@ class AndroidHardwareBufferTextureHost : public TextureHost {
void NotifyNotUsed() override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}
@ -615,7 +618,8 @@ class EGLImageTextureHost final : public TextureHost {
gfx::SurfaceFormat GetFormat() const override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override {
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}

View file

@ -75,8 +75,9 @@ void WebRenderTextureHost::UnbindTextureSource() {
TextureHost::UnbindTextureSource();
}
already_AddRefed<gfx::DataSourceSurface> WebRenderTextureHost::GetAsSurface() {
return mWrappedTextureHost->GetAsSurface();
already_AddRefed<gfx::DataSourceSurface> WebRenderTextureHost::GetAsSurface(
gfx::DataSourceSurface* aSurface) {
return mWrappedTextureHost->GetAsSurface(aSurface);
}
gfx::ColorDepth WebRenderTextureHost::GetColorDepth() const {

View file

@ -43,7 +43,8 @@ class WebRenderTextureHost : public TextureHost {
// Please check TextureHost::GetReadFormat().
gfx::SurfaceFormat GetReadFormat() const override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
already_AddRefed<gfx::DataSourceSurface> GetAsSurface(
gfx::DataSourceSurface* aSurface) override;
gfx::ColorDepth GetColorDepth() const override;
gfx::YUVColorSpace GetYUVColorSpace() const override;

View file

@ -5873,6 +5873,11 @@
value: true
mirror: always
- name: gfx.canvas.remote.recycle-used-data-surface
type: RelaxedAtomicBool
value: false
mirror: always
- name: gfx.canvas.willreadfrequently.enabled
type: bool
#if defined(XP_WIN)