Bug 1965093 - Add Image::BuildSurfaceDescriptorBuffer fallback implementation. r=gfx-reviewers,jnicol

This patch implements BuildSurfaceDescriptorBuffer for the Image
base class. While it does not have the performance benefits of the
more specific implementations in the derived classes, it allows the
callers to not worry about the edge cases where GetSourceSurface is
available.

Differential Revision: https://phabricator.services.mozilla.com/D248352
This commit is contained in:
Andrew Osmond
2025-05-09 23:33:25 +00:00
committed by aosmond@mozilla.com
parent 826bf1fd4b
commit 09959678c3
4 changed files with 83 additions and 40 deletions

View File

@@ -290,7 +290,7 @@ mozilla::ipc::IPCResult RemoteDecoderManagerParent::RecvReadback(
return IPC_OK();
}
// Let's try reading directly into the shmem first to avoid extra copies.
// Read directly into the shmem to avoid extra copies, if possible.
SurfaceDescriptorBuffer sdb;
nsresult rv = image->BuildSurfaceDescriptorBuffer(
sdb, Image::BuildSdbFlags::RgbOnly, [&](uint32_t aBufferSize) {
@@ -309,43 +309,7 @@ mozilla::ipc::IPCResult RemoteDecoderManagerParent::RecvReadback(
if (sdb.data().type() == MemoryOrShmem::TShmem) {
DeallocShmem(sdb.data().get_Shmem());
}
if (rv != NS_ERROR_NOT_IMPLEMENTED) {
*aResult = null_t();
return IPC_OK();
}
// Fallback to reading to a SourceSurface and copying that into a shmem.
RefPtr<SourceSurface> source = image->GetAsSourceSurface();
if (!source) {
*aResult = null_t();
return IPC_OK();
}
SurfaceFormat format = source->GetFormat();
IntSize size = source->GetSize();
size_t length = ImageDataSerializer::ComputeRGBBufferSize(size, format);
Shmem buffer;
if (!length || !AllocShmem(length, &buffer)) {
*aResult = null_t();
return IPC_OK();
}
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
gfx::BackendType::CAIRO, buffer.get<uint8_t>(), size,
ImageDataSerializer::ComputeRGBStride(format, size.width), format);
if (!dt) {
DeallocShmem(buffer);
*aResult = null_t();
return IPC_OK();
}
dt->CopySurface(source, IntRect(0, 0, size.width, size.height), IntPoint());
dt->Flush();
*aResult = SurfaceDescriptorBuffer(RGBDescriptor(size, format),
MemoryOrShmem(std::move(buffer)));
*aResult = null_t();
return IPC_OK();
}

View File

@@ -269,7 +269,13 @@ MediaResult RemoteVideoDecoderParent::ProcessDecodedData(
}
return MemoryOrShmem();
});
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
if (sdBuffer.data().type() == MemoryOrShmem::TShmem) {
DeallocShmem(sdBuffer.data().get_Shmem());
}
return rv;
}
sd = sdBuffer;
size = image->GetSize();

View File

@@ -14,6 +14,7 @@
#include "gfx2DGlue.h"
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxUtils.h" // for gfxUtils
#include "GPUVideoImage.h"
#include "libyuv.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/ProfilerLabels.h"
@@ -239,7 +240,68 @@ ImageContainer::~ImageContainer() {
nsresult Image::BuildSurfaceDescriptorBuffer(
SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags,
const std::function<MemoryOrShmem(uint32_t)>& aAllocate) {
return NS_ERROR_NOT_IMPLEMENTED;
RefPtr<SourceSurface> surface = GetAsSourceSurface();
if (NS_WARN_IF(!surface)) {
return NS_ERROR_NOT_AVAILABLE;
}
RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
if (NS_WARN_IF(!dataSurface)) {
return NS_ERROR_FAILURE;
}
DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ);
if (NS_WARN_IF(!map.IsMapped())) {
return NS_ERROR_FAILURE;
}
SurfaceFormat format = dataSurface->GetFormat();
IntSize size = dataSurface->GetSize();
uint8_t* output = nullptr;
int32_t stride = 0;
nsresult rv = AllocateSurfaceDescriptorBufferRgb(
size, format, output, aSdBuffer, stride, aAllocate);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(!SwizzleData(map.GetData(), map.GetStride(), format, output,
stride, format, size))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult Image::BuildSurfaceDescriptorGPUVideoOrBuffer(
SurfaceDescriptor& aSd, BuildSdbFlags aFlags,
const Maybe<VideoBridgeSource>& aDest,
const std::function<MemoryOrShmem(uint32_t)>& aAllocate,
const std::function<void(MemoryOrShmem&&)>& aFree) {
if (auto* gpuImage = AsGPUVideoImage()) {
if (auto maybeSd = gpuImage->GetDesc()) {
if (!aDest ||
(maybeSd->type() == SurfaceDescriptor::TSurfaceDescriptorGPUVideo &&
maybeSd->get_SurfaceDescriptorGPUVideo()
.get_SurfaceDescriptorRemoteDecoder()
.source() == aDest)) {
aSd = std::move(*maybeSd);
return NS_OK;
}
}
}
SurfaceDescriptorBuffer sdb;
nsresult rv = BuildSurfaceDescriptorBuffer(sdb, aFlags, aAllocate);
if (NS_FAILED(rv)) {
if (sdb.data().type() != MemoryOrShmem::Type::T__None) {
aFree(std::move(sdb.data()));
}
return rv;
}
aSd = std::move(sdb);
return NS_OK;
}
Maybe<SurfaceDescriptor> Image::GetDesc() { return GetDescFromTexClient(); }

View File

@@ -69,6 +69,7 @@ class D3D11YCbCrRecycleAllocator;
class MacIOSurfaceRecycleAllocator;
#endif
class SurfaceDescriptorBuffer;
enum class VideoBridgeSource : uint8_t;
struct ImageBackendData {
virtual ~ImageBackendData() = default;
@@ -145,6 +146,16 @@ class Image {
SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags,
const std::function<MemoryOrShmem(uint32_t)>& aAllocate);
/**
* Get a SurfaceDescriptorGPUVideo if possible, with the source matching aDest
* if given. Otherwise copy the data into a SurfaceDescriptorBuffer.
*/
nsresult BuildSurfaceDescriptorGPUVideoOrBuffer(
SurfaceDescriptor& aSd, BuildSdbFlags aFlags,
const Maybe<VideoBridgeSource>& aDest,
const std::function<MemoryOrShmem(uint32_t)>& aAllocate,
const std::function<void(MemoryOrShmem&&)>& aFree);
virtual bool IsValid() const { return true; }
/**