Bug 1777872 - Use Shmem for backing DrawTargetWebgl's Skia target. r=jgilbert

When rendering large and/or fullscreen Canvas2Ds, excessive time can be spent
in calls to TexImage/ReadPixels copying into and out of Shmems to the separate
buffer for DrawTargetSkia. To alleviate this, we can make the DrawTargetSkia
directly wrap the Shmem, so that calls to TexImage/ReadPixels then directly
read or write to this without any separate copy. We modify RawTexImage to use
the IPDL SendTexImage path so that Shmems can be sent via SurfaceDescriptor.
Since SendTexImage is nominally async (which is beneficial), we rely on a
call to GetError later to verify that the Shmem processing is completely before
we further modify the DrawTargetSkia. We further add a ReadPixelsIntoShmem IPDL
call to allow sending the Shmem in the other direction directly.

Differential Revision: https://phabricator.services.mozilla.com/D151286
This commit is contained in:
Lee Salzman
2022-07-12 09:25:35 +00:00
parent 0e7144b825
commit ff19bc4536
9 changed files with 198 additions and 29 deletions

View File

@@ -4358,11 +4358,35 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
}
}
void ClientWebGLContext::RawTexImage(
uint32_t level, GLenum respecFormat, uvec3 offset,
const webgl::PackingInfo& pi, const webgl::TexUnpackBlobDesc& desc) const {
void ClientWebGLContext::RawTexImage(uint32_t level, GLenum respecFormat,
uvec3 offset, const webgl::PackingInfo& pi,
webgl::TexUnpackBlobDesc&& desc) const {
const FuncScope funcScope(*this, "tex(Sub)Image[23]D");
if (IsContextLost()) return;
if (desc.sd) {
// Shmems are stored in Buffer surface descriptors. We need to ensure first
// that all queued commands are flushed and then send the Shmem over IPDL.
const auto& sd = *(desc.sd);
if (sd.type() == layers::SurfaceDescriptor::TSurfaceDescriptorBuffer &&
sd.get_SurfaceDescriptorBuffer().data().type() ==
layers::MemoryOrShmem::TShmem) {
const auto& inProcess = mNotLost->inProcess;
if (inProcess) {
inProcess->TexImage(level, respecFormat, offset, pi, desc);
} else {
const auto& child = mNotLost->outOfProcess;
child->FlushPendingCmds();
(void)child->SendTexImage(level, respecFormat, offset, pi,
std::move(desc));
}
} else {
NS_WARNING(
"RawTexImage with SurfaceDescriptor only supports "
"SurfaceDescriptorBuffer with Shmem");
}
return;
}
Run<RPROC(TexImage)>(level, respecFormat, offset, pi, desc);
}
@@ -4896,10 +4920,10 @@ bool ClientWebGLContext::DoReadPixels(const webgl::ReadPixelsDesc& desc,
if (!child->SendReadPixels(desc, dest.length(), &res)) {
res = {};
}
if (!res.byteStride) return false;
if (!res.byteStride || !res.shmem) return false;
const auto& byteStride = res.byteStride;
const auto& subrect = res.subrect;
const webgl::RaiiShmem shmem{child, res.shmem};
const webgl::RaiiShmem shmem{child, res.shmem.ref()};
if (!shmem) {
EnqueueError(LOCAL_GL_OUT_OF_MEMORY, "Failed to map in back buffer.");
return false;
@@ -4939,6 +4963,30 @@ bool ClientWebGLContext::DoReadPixels(const webgl::ReadPixelsDesc& desc,
return true;
}
bool ClientWebGLContext::DoReadPixels(const webgl::ReadPixelsDesc& desc,
const mozilla::ipc::Shmem& shmem) const {
const auto notLost =
mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
if (!notLost) return false;
const auto& inProcess = notLost->inProcess;
if (inProcess) {
const auto& shmemBytes = shmem.Range<uint8_t>();
inProcess->ReadPixelsInto(desc, shmemBytes);
return true;
}
const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
webgl::ReadPixelsResultIpc res = {};
// We assume the input is an unsafe shmem which won't be consumed by this
// request. Since SendReadPixels expects a Shmem rvalue, we must create a copy
// to provide it that can be consumed instead of the original descriptor.
mozilla::ipc::Shmem dest = shmem;
if (!child->SendReadPixels(desc, dest, &res)) {
res = {};
}
return res.byteStride > 0;
}
bool ClientWebGLContext::ReadPixels_SharedPrecheck(
dom::CallerType aCallerType, ErrorResult& out_error) const {
if (IsContextLost()) return false;