mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-25 20:01:50 +00:00
Bug 1868397 - Make WebGL use VideoBridge to avoid copies with GPUVideoImage. r=jgilbert
This patch makes it so that WebGL that runs in the compositor process can take advantage of the fact that GPUVideoImage should have an already created TextureHost between the compositor process and the producing utility process. For software decoders, this will allow us to avoid a copy into a shmem from the utility process, and another copy into a shmem to the compositor process. Differential Revision: https://phabricator.services.mozilla.com/D195559
This commit is contained in:
parent
da74a43f47
commit
ec51df1bde
@ -4414,27 +4414,53 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
|
||||
return Some(ToString(msg));
|
||||
}
|
||||
|
||||
if (sdType == layers::SurfaceDescriptor::TSurfaceDescriptorBuffer) {
|
||||
const auto& sdb = sd.get_SurfaceDescriptorBuffer();
|
||||
const auto& data = sdb.data();
|
||||
if (data.type() == layers::MemoryOrShmem::TShmem) {
|
||||
pShmem = &data.get_Shmem();
|
||||
} else {
|
||||
return Some(
|
||||
std::string{"SurfaceDescriptorBuffer data is not Shmem."});
|
||||
}
|
||||
}
|
||||
switch (sdType) {
|
||||
default:
|
||||
break;
|
||||
case layers::SurfaceDescriptor::TSurfaceDescriptorBuffer: {
|
||||
const auto& sdb = sd.get_SurfaceDescriptorBuffer();
|
||||
const auto& data = sdb.data();
|
||||
if (data.type() == layers::MemoryOrShmem::TShmem) {
|
||||
pShmem = &data.get_Shmem();
|
||||
} else {
|
||||
return Some(
|
||||
std::string{"SurfaceDescriptorBuffer data is not Shmem."});
|
||||
}
|
||||
} break;
|
||||
case layers::SurfaceDescriptor::TSurfaceDescriptorD3D10: {
|
||||
const auto& sdD3D = sd.get_SurfaceDescriptorD3D10();
|
||||
const auto& inProcess = mNotLost->inProcess;
|
||||
MOZ_ASSERT(desc->image);
|
||||
keepAliveImage = desc->image;
|
||||
|
||||
if (sdType == layers::SurfaceDescriptor::TSurfaceDescriptorD3D10) {
|
||||
const auto& sdD3D = sd.get_SurfaceDescriptorD3D10();
|
||||
const auto& inProcess = mNotLost->inProcess;
|
||||
MOZ_ASSERT(desc->image);
|
||||
keepAliveImage = desc->image;
|
||||
|
||||
if (sdD3D.gpuProcessTextureId().isSome() && inProcess) {
|
||||
return Some(
|
||||
std::string{"gpuProcessTextureId works only in GPU process."});
|
||||
}
|
||||
if (sdD3D.gpuProcessTextureId().isSome() && inProcess) {
|
||||
return Some(
|
||||
std::string{"gpuProcessTextureId works only in GPU process."});
|
||||
}
|
||||
} break;
|
||||
case layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo: {
|
||||
const auto& inProcess = mNotLost->inProcess;
|
||||
MOZ_ASSERT(desc->image);
|
||||
keepAliveImage = desc->image;
|
||||
if (inProcess) {
|
||||
return Some(std::string{
|
||||
"SurfaceDescriptorGPUVideo works only in GPU process."});
|
||||
}
|
||||
const auto& sdv = sd.get_SurfaceDescriptorGPUVideo();
|
||||
if (sdv.type() != layers::SurfaceDescriptorGPUVideo::
|
||||
TSurfaceDescriptorRemoteDecoder) {
|
||||
return Some(std::string{
|
||||
"SurfaceDescriptorGPUVideo does not contain RemoteDecoder."});
|
||||
}
|
||||
const auto& sdrd = sdv.get_SurfaceDescriptorRemoteDecoder();
|
||||
const auto& subdesc = sdrd.subdesc();
|
||||
if (subdesc.type() !=
|
||||
layers::RemoteDecoderVideoSubDescriptor::Tnull_t) {
|
||||
return Some(
|
||||
std::string{"SurfaceDescriptorGPUVideo does not contain "
|
||||
"RemoteDecoder null subdesc."});
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
switch (respecFormat) {
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/layers/VideoBridgeParent.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "WebGLBuffer.h"
|
||||
@ -299,6 +301,17 @@ static bool SDIsRGBBuffer(const layers::SurfaceDescriptor& sd) {
|
||||
layers::BufferDescriptor::TRGBDescriptor;
|
||||
}
|
||||
|
||||
// Check if the surface descriptor describes a GPUVideo texture for which we
|
||||
// only have an opaque source/handle from SurfaceDescriptorRemoteDecoder to
|
||||
// derive the actual texture from.
|
||||
static bool SDIsNullRemoteDecoder(const layers::SurfaceDescriptor& sd) {
|
||||
return sd.type() == layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo &&
|
||||
sd.get_SurfaceDescriptorGPUVideo()
|
||||
.get_SurfaceDescriptorRemoteDecoder()
|
||||
.subdesc()
|
||||
.type() == layers::RemoteDecoderVideoSubDescriptor::Tnull_t;
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<TexUnpackBlob> TexUnpackBlob::Create(
|
||||
const TexUnpackBlobDesc& desc) {
|
||||
@ -324,7 +337,9 @@ std::unique_ptr<TexUnpackBlob> TexUnpackBlob::Create(
|
||||
// Otherwise, TexUnpackImage will try to blit the surface descriptor as
|
||||
// if it can be mapped as a framebuffer, whereas the Shmem is still CPU
|
||||
// data.
|
||||
if (SDIsRGBBuffer(*desc.sd)) return new TexUnpackSurface(desc);
|
||||
if (SDIsRGBBuffer(*desc.sd) || SDIsNullRemoteDecoder(*desc.sd)) {
|
||||
return new TexUnpackSurface(desc);
|
||||
}
|
||||
return new TexUnpackImage(desc);
|
||||
}
|
||||
if (desc.dataSurf) {
|
||||
@ -874,15 +889,34 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
|
||||
if (mDesc.sd) {
|
||||
// If we get here, we assume the SD describes an RGBA Shmem.
|
||||
const auto& sd = *(mDesc.sd);
|
||||
MOZ_ASSERT(SDIsRGBBuffer(sd));
|
||||
const auto& sdb = sd.get_SurfaceDescriptorBuffer();
|
||||
const auto& rgb = sdb.desc().get_RGBDescriptor();
|
||||
const auto& data = sdb.data();
|
||||
MOZ_ASSERT(data.type() == layers::MemoryOrShmem::TShmem);
|
||||
const auto& shmem = data.get_Shmem();
|
||||
surf = gfx::Factory::CreateWrappingDataSourceSurface(
|
||||
shmem.get<uint8_t>(), layers::ImageDataSerializer::GetRGBStride(rgb),
|
||||
rgb.size(), rgb.format());
|
||||
if (SDIsRGBBuffer(sd)) {
|
||||
const auto& sdb = sd.get_SurfaceDescriptorBuffer();
|
||||
const auto& rgb = sdb.desc().get_RGBDescriptor();
|
||||
const auto& data = sdb.data();
|
||||
MOZ_ASSERT(data.type() == layers::MemoryOrShmem::TShmem);
|
||||
const auto& shmem = data.get_Shmem();
|
||||
surf = gfx::Factory::CreateWrappingDataSourceSurface(
|
||||
shmem.get<uint8_t>(), layers::ImageDataSerializer::GetRGBStride(rgb),
|
||||
rgb.size(), rgb.format());
|
||||
} else if (SDIsNullRemoteDecoder(sd)) {
|
||||
const auto& sdrd = sd.get_SurfaceDescriptorGPUVideo()
|
||||
.get_SurfaceDescriptorRemoteDecoder();
|
||||
RefPtr<layers::VideoBridgeParent> parent =
|
||||
layers::VideoBridgeParent::GetSingleton(sdrd.source());
|
||||
if (!parent) {
|
||||
gfxCriticalNote << "TexUnpackSurface failed to get VideoBridgeParent";
|
||||
return false;
|
||||
}
|
||||
RefPtr<layers::TextureHost> texture =
|
||||
parent->LookupTexture(webgl->GetContentId(), sdrd.handle());
|
||||
if (!texture) {
|
||||
gfxCriticalNote << "TexUnpackSurface failed to get TextureHost";
|
||||
return false;
|
||||
}
|
||||
surf = texture->GetAsSurface();
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected surface descriptor!");
|
||||
}
|
||||
if (!surf) {
|
||||
gfxCriticalError() << "TexUnpackSurface failed to create wrapping "
|
||||
"DataSourceSurface for Shmem.";
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "ImageEncoder.h"
|
||||
#include "LayerUserData.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/HTMLVideoElement.h"
|
||||
@ -619,6 +620,15 @@ RefPtr<WebGLContext> WebGLContext::Create(HostWebGLContext& host,
|
||||
const auto UploadableSdTypes = [&]() {
|
||||
webgl::EnumMask<layers::SurfaceDescriptor::Type> types;
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorBuffer] = true;
|
||||
// This is conditional on not using the Compositor thread because we may
|
||||
// need to synchronize with the RDD process over the PVideoBridge protocol
|
||||
// to wait for the texture to be available in the compositor process. We
|
||||
// cannot block on the Compositor thread, so in that configuration, we would
|
||||
// prefer to do the readback from the RDD which is guaranteed to work, and
|
||||
// only block the owning thread for WebGL.
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo] =
|
||||
gfx::gfxVars::UseCanvasRenderThread() ||
|
||||
!gfx::gfxVars::SupportsThreadsafeGL();
|
||||
if (webgl->gl->IsANGLE()) {
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorD3D10] = true;
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr] = true;
|
||||
@ -1386,6 +1396,17 @@ void WebGLContext::DummyReadFramebufferOperation() {
|
||||
}
|
||||
}
|
||||
|
||||
dom::ContentParentId WebGLContext::GetContentId() const {
|
||||
const auto* outOfProcess = mHost ? mHost->mOwnerData.outOfProcess : nullptr;
|
||||
if (outOfProcess) {
|
||||
return outOfProcess->mContentId;
|
||||
}
|
||||
if (XRE_IsContentProcess()) {
|
||||
return dom::ContentChild::GetSingleton()->GetID();
|
||||
}
|
||||
return dom::ContentParentId();
|
||||
}
|
||||
|
||||
bool WebGLContext::Has64BitTimestamps() const {
|
||||
// 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or
|
||||
// GLES3+.
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
@ -461,6 +462,8 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr {
|
||||
|
||||
void DummyReadFramebufferOperation();
|
||||
|
||||
dom::ContentParentId GetContentId() const;
|
||||
|
||||
WebGLTexture* GetActiveTex(const GLenum texTarget) const;
|
||||
|
||||
gl::GLContext* GL() const { return gl; }
|
||||
|
@ -24,7 +24,9 @@ mozilla::ipc::IPCResult WebGLParent::RecvInitialize(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
WebGLParent::WebGLParent() = default;
|
||||
WebGLParent::WebGLParent(const dom::ContentParentId& aContentId)
|
||||
: mContentId(aContentId) {}
|
||||
|
||||
WebGLParent::~WebGLParent() = default;
|
||||
|
||||
// -
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define WEBGLPARENT_H_
|
||||
|
||||
#include "mozilla/GfxMessageUtils.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/dom/PWebGLParent.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
|
||||
@ -31,7 +32,7 @@ class WebGLParent : public PWebGLParent, public SupportsWeakPtr {
|
||||
mozilla::ipc::IPCResult RecvInitialize(const webgl::InitContextDesc&,
|
||||
webgl::InitContextResult* out);
|
||||
|
||||
WebGLParent(); // For IPDL
|
||||
explicit WebGLParent(const dom::ContentParentId& aContentId); // For IPDL
|
||||
|
||||
using IPCResult = mozilla::ipc::IPCResult;
|
||||
|
||||
@ -108,6 +109,8 @@ class WebGLParent : public PWebGLParent, public SupportsWeakPtr {
|
||||
|
||||
// -
|
||||
|
||||
const dom::ContentParentId mContentId;
|
||||
|
||||
private:
|
||||
~WebGLParent();
|
||||
|
||||
|
@ -27,10 +27,11 @@ nsTArray<CanvasManagerParent::ReplayTexture>
|
||||
bool CanvasManagerParent::sReplayTexturesEnabled(true);
|
||||
|
||||
/* static */ void CanvasManagerParent::Init(
|
||||
Endpoint<PCanvasManagerParent>&& aEndpoint) {
|
||||
Endpoint<PCanvasManagerParent>&& aEndpoint,
|
||||
const dom::ContentParentId& aContentId) {
|
||||
MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
|
||||
|
||||
auto manager = MakeRefPtr<CanvasManagerParent>();
|
||||
auto manager = MakeRefPtr<CanvasManagerParent>(aContentId);
|
||||
|
||||
nsCOMPtr<nsIThread> owningThread =
|
||||
gfx::CanvasRenderThread::GetCanvasRenderThread();
|
||||
@ -203,7 +204,9 @@ CanvasManagerParent::WaitForReplayTexture(base::ProcessId aOtherPid,
|
||||
return desc;
|
||||
}
|
||||
|
||||
CanvasManagerParent::CanvasManagerParent() = default;
|
||||
CanvasManagerParent::CanvasManagerParent(const dom::ContentParentId& aContentId)
|
||||
: mContentId(aContentId) {}
|
||||
|
||||
CanvasManagerParent::~CanvasManagerParent() = default;
|
||||
|
||||
void CanvasManagerParent::Bind(Endpoint<PCanvasManagerParent>&& aEndpoint) {
|
||||
@ -220,7 +223,7 @@ void CanvasManagerParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
}
|
||||
|
||||
already_AddRefed<dom::PWebGLParent> CanvasManagerParent::AllocPWebGLParent() {
|
||||
return MakeAndAddRef<dom::WebGLParent>();
|
||||
return MakeAndAddRef<dom::WebGLParent>(mContentId);
|
||||
}
|
||||
|
||||
already_AddRefed<webgpu::PWebGPUParent>
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define _include_gfx_ipc_CanvasManagerParent_h__
|
||||
|
||||
#include "mozilla/gfx/PCanvasManagerParent.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/StaticMonitor.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsHashtablesFwd.h"
|
||||
@ -24,7 +25,8 @@ class CanvasManagerParent final : public PCanvasManagerParent {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CanvasManagerParent, override);
|
||||
|
||||
static void Init(Endpoint<PCanvasManagerParent>&& aEndpoint);
|
||||
static void Init(Endpoint<PCanvasManagerParent>&& aEndpoint,
|
||||
const dom::ContentParentId& aContentId);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
@ -42,7 +44,7 @@ class CanvasManagerParent final : public PCanvasManagerParent {
|
||||
static UniquePtr<layers::SurfaceDescriptor> WaitForReplayTexture(
|
||||
base::ProcessId aOtherPid, int64_t aTextureId);
|
||||
|
||||
CanvasManagerParent();
|
||||
explicit CanvasManagerParent(const dom::ContentParentId& aContentId);
|
||||
|
||||
void Bind(Endpoint<PCanvasManagerParent>&& aEndpoint);
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
@ -67,6 +69,7 @@ class CanvasManagerParent final : public PCanvasManagerParent {
|
||||
|
||||
~CanvasManagerParent() override;
|
||||
|
||||
const dom::ContentParentId mContentId;
|
||||
uint32_t mId = 0;
|
||||
|
||||
using ManagerSet = nsTHashSet<RefPtr<CanvasManagerParent>>;
|
||||
|
@ -319,7 +319,7 @@ mozilla::ipc::IPCResult CompositorManagerParent::RecvReportMemory(
|
||||
|
||||
mozilla::ipc::IPCResult CompositorManagerParent::RecvInitCanvasManager(
|
||||
Endpoint<PCanvasManagerParent>&& aEndpoint) {
|
||||
gfx::CanvasManagerParent::Init(std::move(aEndpoint));
|
||||
gfx::CanvasManagerParent::Init(std::move(aEndpoint), mContentId);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user