commit 8c8177ad310cc58fa5c2b58dc70b2e20bfa22b79
parent a1aad2e716e9ba326bfeab248c59f920ce8887e5
Author: Lee Salzman <lsalzman@mozilla.com>
Date: Tue, 18 Nov 2025 22:26:56 +0000
Bug 2000253 - Do earlier readback of surface data when growing data surface shmem. r=aosmond
Readback in the GPU process currently happens after the content process attempts to reallocate
the data surface shmem into which it will read the data. This leaves the GPU process stalled
waiting for the content process to finish allocation.
If we know reallocation is necessary, we can issue an earlier readback into the data surface
that can proceed even while the content process is reallocating the data surface shmem. When
allocation finishes, this surface can then be copied into the shmem. While this might incur
an extra memory copy sometimes, it is still quicker than stalling on the large shem
allocation.
Differential Revision: https://phabricator.services.mozilla.com/D273065
Diffstat:
2 files changed, 44 insertions(+), 12 deletions(-)
diff --git a/gfx/layers/ipc/CanvasChild.cpp b/gfx/layers/ipc/CanvasChild.cpp
@@ -517,24 +517,32 @@ already_AddRefed<gfx::DrawTargetRecording> CanvasChild::CreateDrawTarget(
return dt.forget();
}
-bool CanvasChild::EnsureDataSurfaceShmem(gfx::IntSize aSize,
- gfx::SurfaceFormat aFormat) {
- NS_ASSERT_OWNINGTHREAD(CanvasChild);
-
+size_t CanvasChild::SizeOfDataSurfaceShmem(gfx::IntSize aSize,
+ gfx::SurfaceFormat aFormat) {
if (!mRecorder) {
- return false;
+ return 0;
}
-
size_t sizeRequired =
ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
- if (!sizeRequired) {
+ return sizeRequired > 0 ? ipc::shared_memory::PageAlignedSize(sizeRequired)
+ : 0;
+}
+
+bool CanvasChild::ShouldGrowDataSurfaceShmem(size_t aSizeRequired) {
+ return aSizeRequired > 0 && (!mDataSurfaceShmemAvailable ||
+ mDataSurfaceShmem->Size() < aSizeRequired);
+}
+
+bool CanvasChild::EnsureDataSurfaceShmem(size_t aSizeRequired) {
+ NS_ASSERT_OWNINGTHREAD(CanvasChild);
+
+ if (!aSizeRequired) {
return false;
}
- sizeRequired = ipc::shared_memory::PageAlignedSize(sizeRequired);
- if (!mDataSurfaceShmemAvailable || mDataSurfaceShmem->Size() < sizeRequired) {
+ if (ShouldGrowDataSurfaceShmem(aSizeRequired)) {
RecordEvent(RecordedPauseTranslation());
- auto shmemHandle = ipc::shared_memory::Create(sizeRequired);
+ auto shmemHandle = ipc::shared_memory::Create(aSizeRequired);
if (!shmemHandle) {
return false;
}
@@ -557,6 +565,16 @@ bool CanvasChild::EnsureDataSurfaceShmem(gfx::IntSize aSize,
return true;
}
+bool CanvasChild::EnsureDataSurfaceShmem(gfx::IntSize aSize,
+ gfx::SurfaceFormat aFormat) {
+ size_t sizeRequired = SizeOfDataSurfaceShmem(aSize, aFormat);
+ if (!sizeRequired) {
+ return false;
+ }
+
+ return EnsureDataSurfaceShmem(sizeRequired);
+}
+
void CanvasChild::RecordEvent(const gfx::RecordedEvent& aEvent) {
NS_ASSERT_OWNINGTHREAD(CanvasChild);
@@ -625,9 +643,20 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
}
}
- RecordEvent(RecordedCacheDataSurface(aSurface));
+ size_t sizeRequired = SizeOfDataSurfaceShmem(ssSize, ssFormat);
+ if (!sizeRequired) {
+ return nullptr;
+ }
+
+ // If growing the data surface shmem, allocation may require significant time
+ // in the content process, during which the GPU process may issue an earlier
+ // readback while the content process is still busy. If the existing data
+ // surface shmem is to be reused instead, then try to instead read the data
+ // directly into the shmem to avoid a superfluous copy after readback.
+ bool forceData = ShouldGrowDataSurfaceShmem(sizeRequired);
+ RecordEvent(RecordedCacheDataSurface(aSurface, forceData));
- if (!EnsureDataSurfaceShmem(ssSize, ssFormat)) {
+ if (!EnsureDataSurfaceShmem(sizeRequired)) {
return nullptr;
}
diff --git a/gfx/layers/ipc/CanvasChild.h b/gfx/layers/ipc/CanvasChild.h
@@ -179,6 +179,9 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
~CanvasChild() final;
+ size_t SizeOfDataSurfaceShmem(gfx::IntSize, gfx::SurfaceFormat aFormat);
+ bool ShouldGrowDataSurfaceShmem(size_t aSizeRequired);
+ bool EnsureDataSurfaceShmem(size_t aSizeRequired);
bool EnsureDataSurfaceShmem(gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
static void ReleaseDataShmemHolder(void* aClosure);