Bug 1740127 - Combine copy/swizzle/premultiply operations in ClientWebGLContext::GetFrontBufferSnapshot. r=jgilbert

The swizzling operations were showing up in talos profiles on Linux with
GLX and using OOP WebGL. If DMABuf has been disabled, similar performance
should be observed with EGL as well. This patch combines the necessary
copies, swizzling between RGBA and BGRA, and premultiplication operations
as much as possible for GetFrontBufferSnapshot.

It also has the advantage of unblocking the WebGL thread in the
compositor process sooner since it is a sync IPC call and moving that
work to the caller which would be blocked anyways.

Differential Revision: https://phabricator.services.mozilla.com/D130690
This commit is contained in:
Andrew Osmond 2021-12-15 12:15:36 +00:00
Родитель 487df1c1c4
Коммит 25fe6561f6
2 изменённых файлов: 67 добавлений и 61 удалений

Просмотреть файл

@ -21,6 +21,7 @@
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/CanvasManagerChild.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/gfx/Swizzle.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/OOPCanvasRenderer.h"
@ -884,53 +885,15 @@ RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
/*zero=*/true));
};
auto snapshot = [&]() -> RefPtr<gfx::DataSourceSurface> {
const auto& inProcess = mNotLost->inProcess;
if (inProcess) {
const auto maybeSize = inProcess->FrontBufferSnapshotInto({});
if (!maybeSize) return nullptr;
const auto& surfSize = *maybeSize;
const auto stride = surfSize.x * 4;
const auto byteSize = stride * surfSize.y;
const auto surf = fnNewSurf(surfSize);
if (!surf) return nullptr;
{
const gfx::DataSourceSurface::ScopedMap map(
surf, gfx::DataSourceSurface::READ_WRITE);
if (!map.IsMapped()) {
MOZ_ASSERT(false);
return nullptr;
}
MOZ_RELEASE_ASSERT(map.GetStride() == static_cast<int64_t>(stride));
auto range = Range<uint8_t>{map.GetData(), byteSize};
if (!inProcess->FrontBufferSnapshotInto(Some(range))) {
gfxCriticalNote << "ClientWebGLContext::GetFrontBufferSnapshot: "
"FrontBufferSnapshotInto(some) failed after "
"FrontBufferSnapshotInto(none)";
return nullptr;
}
}
return surf;
}
const auto& child = mNotLost->outOfProcess;
child->FlushPendingCmds();
webgl::FrontBufferSnapshotIpc res;
if (!child->SendGetFrontBufferSnapshot(&res)) {
res = {};
}
if (!res.shmem) return nullptr;
const auto& surfSize = res.surfSize;
const webgl::RaiiShmem shmem{child, res.shmem.ref()};
const auto& shmemBytes = shmem.ByteRange();
if (!surfSize.x) return nullptr; // Zero means failure.
const auto& inProcess = mNotLost->inProcess;
if (inProcess) {
const auto maybeSize = inProcess->FrontBufferSnapshotInto({});
if (!maybeSize) return nullptr;
const auto& surfSize = *maybeSize;
const auto stride = surfSize.x * 4;
const auto byteSize = stride * surfSize.y;
const auto surf = fnNewSurf(surfSize);
if (!surf) return nullptr;
{
const gfx::DataSourceSurface::ScopedMap map(
surf, gfx::DataSourceSurface::READ_WRITE);
@ -939,26 +902,71 @@ RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
return nullptr;
}
MOZ_RELEASE_ASSERT(map.GetStride() == static_cast<int64_t>(stride));
MOZ_RELEASE_ASSERT(shmemBytes.length() == byteSize);
memcpy(map.GetData(), shmemBytes.begin().get(), byteSize);
auto range = Range<uint8_t>{map.GetData(), byteSize};
if (!inProcess->FrontBufferSnapshotInto(Some(range))) {
gfxCriticalNote << "ClientWebGLContext::GetFrontBufferSnapshot: "
"FrontBufferSnapshotInto(some) failed after "
"FrontBufferSnapshotInto(none)";
return nullptr;
}
if (requireAlphaPremult && options.alpha && !options.premultipliedAlpha) {
bool rv = gfx::PremultiplyData(
map.GetData(), map.GetStride(), gfx::SurfaceFormat::R8G8B8A8,
map.GetData(), map.GetStride(), gfx::SurfaceFormat::B8G8R8A8,
surf->GetSize());
MOZ_RELEASE_ASSERT(rv, "PremultiplyData failed!");
} else {
bool rv = gfx::SwizzleData(
map.GetData(), map.GetStride(), gfx::SurfaceFormat::R8G8B8A8,
map.GetData(), map.GetStride(), gfx::SurfaceFormat::B8G8R8A8,
surf->GetSize());
MOZ_RELEASE_ASSERT(rv, "SwizzleData failed!");
}
}
return surf;
}();
if (!snapshot) return nullptr;
if (requireAlphaPremult && options.alpha && !options.premultipliedAlpha) {
const auto nonPremultSurf = snapshot;
const auto& size = nonPremultSurf->GetSize();
const auto format = nonPremultSurf->GetFormat();
snapshot =
gfx::Factory::CreateDataSourceSurface(size, format, /*zero=*/false);
if (!snapshot) {
gfxCriticalNote << "CreateDataSourceSurface failed for size " << size;
}
gfxUtils::PremultiplyDataSurface(nonPremultSurf, snapshot);
}
const auto& child = mNotLost->outOfProcess;
child->FlushPendingCmds();
webgl::FrontBufferSnapshotIpc res;
if (!child->SendGetFrontBufferSnapshot(&res)) {
res = {};
}
if (!res.shmem) return nullptr;
return snapshot;
const auto& surfSize = res.surfSize;
const webgl::RaiiShmem shmem{child, res.shmem.ref()};
const auto& shmemBytes = shmem.ByteRange();
if (!surfSize.x) return nullptr; // Zero means failure.
const auto stride = surfSize.x * 4;
const auto byteSize = stride * surfSize.y;
const auto surf = fnNewSurf(surfSize);
if (!surf) return nullptr;
{
const gfx::DataSourceSurface::ScopedMap map(
surf, gfx::DataSourceSurface::READ_WRITE);
if (!map.IsMapped()) {
MOZ_ASSERT(false);
return nullptr;
}
MOZ_RELEASE_ASSERT(shmemBytes.length() == byteSize);
if (requireAlphaPremult && options.alpha && !options.premultipliedAlpha) {
bool rv = gfx::PremultiplyData(
shmemBytes.begin().get(), stride, gfx::SurfaceFormat::R8G8B8A8,
map.GetData(), map.GetStride(), gfx::SurfaceFormat::B8G8R8A8,
surf->GetSize());
MOZ_RELEASE_ASSERT(rv, "PremultiplyData failed!");
} else {
bool rv = gfx::SwizzleData(shmemBytes.begin().get(), stride,
gfx::SurfaceFormat::R8G8B8A8, map.GetData(),
map.GetStride(), gfx::SurfaceFormat::B8G8R8A8,
surf->GetSize());
MOZ_RELEASE_ASSERT(rv, "SwizzleData failed!");
}
}
return surf;
}
RefPtr<gfx::DataSourceSurface> ClientWebGLContext::BackBufferSnapshot() {

Просмотреть файл

@ -17,7 +17,6 @@
#include "gfxCrashReporterUtils.h"
#include "gfxEnv.h"
#include "gfxPattern.h"
#include "gfxUtils.h"
#include "MozFramebuffer.h"
#include "GLBlitHelper.h"
#include "GLContext.h"
@ -1017,7 +1016,6 @@ Maybe<uvec2> WebGLContext::FrontBufferSnapshotInto(
}
gl->fReadPixels(0, 0, size.width, size.height, LOCAL_GL_RGBA,
LOCAL_GL_UNSIGNED_BYTE, dest.begin().get());
gfxUtils::ConvertBGRAtoRGBA(dest.begin().get(), dstByteCount);
return ret;
}