From 95ea53535b66adad750c110cbd621888b18c0ee3 Mon Sep 17 00:00:00 2001 From: sotaro Date: Wed, 11 Dec 2024 02:00:23 +0000 Subject: [PATCH] Bug 1910520 - Add Metal SharedEvent handling around WebRender for compositing IOSurface of WebGPU r=gfx-reviewers,lsalzman Differential Revision: https://phabricator.services.mozilla.com/D228946 --- dom/webgpu/ExternalTexture.cpp | 13 ++-- dom/webgpu/ExternalTexture.h | 4 +- dom/webgpu/ExternalTextureMacIOSurface.cpp | 27 +++++++- dom/webgpu/ExternalTextureMacIOSurface.h | 8 ++- dom/webgpu/ipc/WebGPUParent.cpp | 2 +- dom/webgpu/ipc/WebGPUParent.h | 2 + gfx/gl/SharedSurfaceIO.cpp | 3 +- gfx/layers/GpuFence.h | 29 +++++++++ gfx/layers/GpuFenceMTLSharedEvent.cpp | 38 +++++++++++ gfx/layers/GpuFenceMTLSharedEvent.h | 46 +++++++++++++ gfx/layers/NativeLayer.h | 3 + gfx/layers/NativeLayerCA.h | 1 + gfx/layers/NativeLayerCA.mm | 16 +++++ gfx/layers/NativeLayerWayland.h | 1 + gfx/layers/ipc/LayersMessageUtils.h | 34 ++++++++++ gfx/layers/ipc/LayersSurfaces.ipdlh | 2 + gfx/layers/moz.build | 3 + .../opengl/MacIOSurfaceTextureClientOGL.cpp | 14 ++-- .../opengl/MacIOSurfaceTextureHostOGL.cpp | 4 +- .../opengl/MacIOSurfaceTextureHostOGL.h | 3 + .../RenderCompositorNative.cpp | 64 ++++++++++++++----- .../RenderCompositorNative.h | 16 ++++- .../RenderMacIOSurfaceTextureHost.cpp | 5 +- .../RenderMacIOSurfaceTextureHost.h | 9 ++- gfx/wgpu_bindings/src/server.rs | 56 ++++++++++++++++ gfx/wgpu_bindings/wgpu.h | 8 +++ 26 files changed, 370 insertions(+), 41 deletions(-) create mode 100644 gfx/layers/GpuFence.h create mode 100644 gfx/layers/GpuFenceMTLSharedEvent.cpp create mode 100644 gfx/layers/GpuFenceMTLSharedEvent.h diff --git a/dom/webgpu/ExternalTexture.cpp b/dom/webgpu/ExternalTexture.cpp index 6907d635e5bf..9cf9a3a80829 100644 --- a/dom/webgpu/ExternalTexture.cpp +++ b/dom/webgpu/ExternalTexture.cpp @@ -5,6 +5,8 @@ #include "ExternalTexture.h" +#include "mozilla/webgpu/WebGPUParent.h" + #ifdef XP_WIN # include "mozilla/webgpu/ExternalTextureD3D11.h" #endif @@ -21,19 +23,22 @@ namespace mozilla::webgpu { // static UniquePtr ExternalTexture::Create( - const ffi::WGPUGlobal* aContext, const ffi::WGPUDeviceId aDeviceId, + WebGPUParent* aParent, const ffi::WGPUDeviceId aDeviceId, const uint32_t aWidth, const uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat, const ffi::WGPUTextureUsages aUsage) { + MOZ_ASSERT(aParent); + UniquePtr texture; #ifdef XP_WIN texture = ExternalTextureD3D11::Create(aWidth, aHeight, aFormat, aUsage); #elif defined(MOZ_WIDGET_GTK) - texture = ExternalTextureDMABuf::Create(aContext, aDeviceId, aWidth, aHeight, + auto* context = aParent->GetContext(); + texture = ExternalTextureDMABuf::Create(context, aDeviceId, aWidth, aHeight, aFormat, aUsage); #elif defined(XP_MACOSX) - texture = - ExternalTextureMacIOSurface::Create(aWidth, aHeight, aFormat, aUsage); + texture = ExternalTextureMacIOSurface::Create(aParent, aDeviceId, aWidth, + aHeight, aFormat, aUsage); #endif return texture; } diff --git a/dom/webgpu/ExternalTexture.h b/dom/webgpu/ExternalTexture.h index fcfcf9eb1106..7394f92cc8a3 100644 --- a/dom/webgpu/ExternalTexture.h +++ b/dom/webgpu/ExternalTexture.h @@ -9,6 +9,7 @@ #include "mozilla/gfx/Point.h" #include "mozilla/layers/LayersSurfaces.h" #include "mozilla/webgpu/ffi/wgpu.h" +#include "mozilla/webgpu/WebGPUTypes.h" namespace mozilla { @@ -20,13 +21,14 @@ namespace webgpu { class ExternalTextureDMABuf; class ExternalTextureMacIOSurface; +class WebGPUParent; // A texture that can be used by the WebGPU implementation but is created and // owned by Gecko class ExternalTexture { public: static UniquePtr Create( - const ffi::WGPUGlobal* aContext, const ffi::WGPUDeviceId aDeviceId, + WebGPUParent* aParent, const ffi::WGPUDeviceId aDeviceId, const uint32_t aWidth, const uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat, const ffi::WGPUTextureUsages aUsage); diff --git a/dom/webgpu/ExternalTextureMacIOSurface.cpp b/dom/webgpu/ExternalTextureMacIOSurface.cpp index 0fbe24806365..76bf75139453 100644 --- a/dom/webgpu/ExternalTextureMacIOSurface.cpp +++ b/dom/webgpu/ExternalTextureMacIOSurface.cpp @@ -7,12 +7,15 @@ #include "mozilla/gfx/Logging.h" #include "mozilla/gfx/MacIOSurface.h" +#include "mozilla/layers/GpuFenceMTLSharedEvent.h" #include "mozilla/layers/ImageDataSerializer.h" +#include "mozilla/webgpu/WebGPUParent.h" namespace mozilla::webgpu { // static UniquePtr ExternalTextureMacIOSurface::Create( + WebGPUParent* aParent, const ffi::WGPUDeviceId aDeviceId, const uint32_t aWidth, const uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat, const ffi::WGPUTextureUsages aUsage) { @@ -24,18 +27,23 @@ UniquePtr ExternalTextureMacIOSurface::Create( RefPtr surface = MacIOSurface::CreateIOSurface(aWidth, aHeight, true); if (!surface) { + gfxCriticalNoteOnce << "Failed to create MacIOSurface: (" << aWidth << ", " + << aHeight << ")"; return nullptr; } - return MakeUnique(aWidth, aHeight, aFormat, - aUsage, std::move(surface)); + return MakeUnique( + aParent, aDeviceId, aWidth, aHeight, aFormat, aUsage, std::move(surface)); } ExternalTextureMacIOSurface::ExternalTextureMacIOSurface( + WebGPUParent* aParent, const ffi::WGPUDeviceId aDeviceId, const uint32_t aWidth, const uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat, const ffi::WGPUTextureUsages aUsage, RefPtr&& aSurface) : ExternalTexture(aWidth, aHeight, aFormat, aUsage), + mParent(aParent), + mDeviceId(aDeviceId), mSurface(std::move(aSurface)) {} ExternalTextureMacIOSurface::~ExternalTextureMacIOSurface() {} @@ -51,9 +59,22 @@ uint32_t ExternalTextureMacIOSurface::GetIOSurfaceId() { Maybe ExternalTextureMacIOSurface::ToSurfaceDescriptor( Maybe& aFenceInfo) { + MOZ_ASSERT(mSubmissionIndex > 0); + + RefPtr gpuFence; + UniquePtr eventHandle( + wgpu_server_get_device_fence_metal_shared_event(mParent->GetContext(), + mDeviceId)); + if (eventHandle) { + gpuFence = layers::GpuFenceMTLSharedEvent::Create(std::move(eventHandle), + mSubmissionIndex); + } else { + gfxCriticalNoteOnce << "Failed to get MetalSharedEventHandle"; + } + return Some(layers::SurfaceDescriptorMacIOSurface( mSurface->GetIOSurfaceID(), !mSurface->HasAlpha(), - mSurface->GetYUVColorSpace())); + mSurface->GetYUVColorSpace(), std::move(gpuFence))); } void ExternalTextureMacIOSurface::GetSnapshot(const ipc::Shmem& aDestShmem, diff --git a/dom/webgpu/ExternalTextureMacIOSurface.h b/dom/webgpu/ExternalTextureMacIOSurface.h index d2c6f9464693..031e9193759c 100644 --- a/dom/webgpu/ExternalTextureMacIOSurface.h +++ b/dom/webgpu/ExternalTextureMacIOSurface.h @@ -7,6 +7,7 @@ #define GPU_ExternalTextureMacIOSurface_H_ #include "mozilla/gfx/FileHandleWrapper.h" +#include "mozilla/WeakPtr.h" #include "mozilla/webgpu/ExternalTexture.h" class MacIOSurface; @@ -18,11 +19,14 @@ namespace webgpu { class ExternalTextureMacIOSurface final : public ExternalTexture { public: static UniquePtr Create( + WebGPUParent* aParent, const ffi::WGPUDeviceId aDeviceId, const uint32_t aWidth, const uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat, const ffi::WGPUTextureUsages aUsage); - ExternalTextureMacIOSurface(const uint32_t aWidth, const uint32_t aHeight, + ExternalTextureMacIOSurface(WebGPUParent* aParent, + const ffi::WGPUDeviceId aDeviceId, + const uint32_t aWidth, const uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat, const ffi::WGPUTextureUsages aUsage, RefPtr&& aSurface); @@ -43,6 +47,8 @@ class ExternalTextureMacIOSurface final : public ExternalTexture { uint32_t GetIOSurfaceId(); protected: + const WeakPtr mParent; + const RawId mDeviceId; const RefPtr mSurface; }; diff --git a/dom/webgpu/ipc/WebGPUParent.cpp b/dom/webgpu/ipc/WebGPUParent.cpp index 4ed03f1ac04c..3ceeed8c334f 100644 --- a/dom/webgpu/ipc/WebGPUParent.cpp +++ b/dom/webgpu/ipc/WebGPUParent.cpp @@ -1635,7 +1635,7 @@ std::shared_ptr WebGPUParent::CreateExternalTexture( mExternalTextures.end()); UniquePtr texture = ExternalTexture::Create( - mContext.get(), aDeviceId, aWidth, aHeight, aFormat, aUsage); + this, aDeviceId, aWidth, aHeight, aFormat, aUsage); if (!texture) { return nullptr; } diff --git a/dom/webgpu/ipc/WebGPUParent.h b/dom/webgpu/ipc/WebGPUParent.h index 5b815ca93079..6f38ffcb6b5c 100644 --- a/dom/webgpu/ipc/WebGPUParent.h +++ b/dom/webgpu/ipc/WebGPUParent.h @@ -178,6 +178,8 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr { return ForwardError(Some(aDeviceId), aError); } + ffi::WGPUGlobal* GetContext() const { return mContext.get(); } + private: static void MapCallback(uint8_t* aUserData, ffi::WGPUBufferMapAsyncStatus aStatus); diff --git a/gfx/gl/SharedSurfaceIO.cpp b/gfx/gl/SharedSurfaceIO.cpp index 459faa64b358..fa14601cd0ca 100644 --- a/gfx/gl/SharedSurfaceIO.cpp +++ b/gfx/gl/SharedSurfaceIO.cpp @@ -95,7 +95,8 @@ Maybe SharedSurface_IOSurface::ToSurfaceDescriptor() { const bool isOpaque = false; // RGBA return Some(layers::SurfaceDescriptorMacIOSurface( - mIOSurf->GetIOSurfaceID(), isOpaque, mIOSurf->GetYUVColorSpace())); + mIOSurf->GetIOSurfaceID(), isOpaque, mIOSurf->GetYUVColorSpace(), + (layers::GpuFence*)nullptr)); } } // namespace gl diff --git a/gfx/layers/GpuFence.h b/gfx/layers/GpuFence.h new file mode 100644 index 000000000000..f939365a6f86 --- /dev/null +++ b/gfx/layers/GpuFence.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_GpuFence_H +#define MOZILLA_GFX_GpuFence_H + +#include "nsISupportsImpl.h" + +namespace mozilla { +namespace layers { + +class GpuFence { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GpuFence); + + virtual bool HasCompleted() = 0; + + protected: + GpuFence() = default; + virtual ~GpuFence() = default; +}; + +} // namespace layers +} // namespace mozilla + +#endif /* MOZILLA_GFX_GpuFence_H */ diff --git a/gfx/layers/GpuFenceMTLSharedEvent.cpp b/gfx/layers/GpuFenceMTLSharedEvent.cpp new file mode 100644 index 000000000000..2d5daf67f629 --- /dev/null +++ b/gfx/layers/GpuFenceMTLSharedEvent.cpp @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GpuFenceMTLSharedEvent.h" + +#include "mozilla/gfx/Logging.h" + +namespace mozilla { +namespace layers { + +/* static */ +RefPtr GpuFenceMTLSharedEvent::Create( + UniquePtr&& aSharedEventHandle, + const uint64_t aFenceValue) { + if (!aSharedEventHandle) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return nullptr; + } + return new GpuFenceMTLSharedEvent(std::move(aSharedEventHandle), aFenceValue); +} + +GpuFenceMTLSharedEvent::GpuFenceMTLSharedEvent( + UniquePtr&& aSharedEventHandle, + const uint64_t aFenceValue) + : mSharedEventHandle(std::move(aSharedEventHandle)), + mFenceValue(aFenceValue) {} + +bool GpuFenceMTLSharedEvent::HasCompleted() { + auto value = + wgpu_server_metal_shared_event_signaled_value(mSharedEventHandle.get()); + return value >= mFenceValue; +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/GpuFenceMTLSharedEvent.h b/gfx/layers/GpuFenceMTLSharedEvent.h new file mode 100644 index 000000000000..0d992ee29745 --- /dev/null +++ b/gfx/layers/GpuFenceMTLSharedEvent.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_GpuFenceMTLSharedEvent_H +#define MOZILLA_GFX_GpuFenceMTLSharedEvent_H + +#include "mozilla/layers/GpuFence.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/webgpu/ffi/wgpu.h" +#include "mozilla/webgpu/WebGPUTypes.h" + +namespace mozilla { + +namespace webgpu { +namespace ffi { +struct WGPUMetalSharedEventHandle; +} +} // namespace webgpu + +namespace layers { + +class GpuFenceMTLSharedEvent : public GpuFence { + public: + static RefPtr Create( + UniquePtr&& aSharedEventHandle, + const uint64_t aFenceValue); + + bool HasCompleted() override; + + protected: + GpuFenceMTLSharedEvent( + UniquePtr&& aSharedEventHandle, + const uint64_t aFenceValue); + virtual ~GpuFenceMTLSharedEvent() = default; + + UniquePtr mSharedEventHandle; + const uint64_t mFenceValue; +}; + +} // namespace layers +} // namespace mozilla + +#endif /* MOZILLA_GFX_GpuFenceMTLSharedEvent_H */ diff --git a/gfx/layers/NativeLayer.h b/gfx/layers/NativeLayer.h index 5cdb51fd35d8..9b481cfdc615 100644 --- a/gfx/layers/NativeLayer.h +++ b/gfx/layers/NativeLayer.h @@ -28,6 +28,7 @@ class RenderTextureHost; namespace layers { +class GpuFence; class NativeLayer; class NativeLayerCA; class NativeLayerWayland; @@ -235,6 +236,8 @@ class NativeLayer { virtual void AttachExternalImage(wr::RenderTextureHost* aExternalImage) = 0; + virtual GpuFence* GetGpuFence() = 0; + protected: virtual ~NativeLayer() = default; }; diff --git a/gfx/layers/NativeLayerCA.h b/gfx/layers/NativeLayerCA.h index 93b6b3a6dece..15acfc692e01 100644 --- a/gfx/layers/NativeLayerCA.h +++ b/gfx/layers/NativeLayerCA.h @@ -268,6 +268,7 @@ class NativeLayerCA : public NativeLayer { void DumpLayer(std::ostream& aOutputStream); void AttachExternalImage(wr::RenderTextureHost* aExternalImage) override; + GpuFence* GetGpuFence() override; void SetRootWindowIsFullscreen(bool aFullscreen); diff --git a/gfx/layers/NativeLayerCA.mm b/gfx/layers/NativeLayerCA.mm index 6fc67b9052d8..d4fbbcc8ba1c 100644 --- a/gfx/layers/NativeLayerCA.mm +++ b/gfx/layers/NativeLayerCA.mm @@ -937,6 +937,22 @@ void NativeLayerCA::AttachExternalImage(wr::RenderTextureHost* aExternalImage) { }); } +GpuFence* NativeLayerCA::GetGpuFence() { + if (!mTextureHost) { + return nullptr; + } + + wr::RenderMacIOSurfaceTextureHost* texture = + mTextureHost->AsRenderMacIOSurfaceTextureHost(); + if (!texture) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "ExternalImage is not RenderMacIOSurfaceTextureHost"; + return nullptr; + } + + return texture->GetGpuFence(); +} + bool NativeLayerCA::IsVideo(const MutexAutoLock& aProofOfLock) { // If we have a texture host, we've checked to see if it's providing video. // And if we don't have a texture host, it isn't video, so we just check diff --git a/gfx/layers/NativeLayerWayland.h b/gfx/layers/NativeLayerWayland.h index 47167ab11b50..77942878edc9 100644 --- a/gfx/layers/NativeLayerWayland.h +++ b/gfx/layers/NativeLayerWayland.h @@ -125,6 +125,7 @@ class NativeLayerWayland final : public NativeLayer { bool SurfaceIsFlipped() override; void AttachExternalImage(wr::RenderTextureHost* aExternalImage) override; + GpuFence* GetGpuFence() override { return nullptr; } void Commit(); void Unmap(); diff --git a/gfx/layers/ipc/LayersMessageUtils.h b/gfx/layers/ipc/LayersMessageUtils.h index 2607beb9f2db..a0e1430ce095 100644 --- a/gfx/layers/ipc/LayersMessageUtils.h +++ b/gfx/layers/ipc/LayersMessageUtils.h @@ -29,6 +29,7 @@ #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/FocusTarget.h" #include "mozilla/layers/GeckoContentControllerTypes.h" +#include "mozilla/layers/GpuFence.h" #include "mozilla/layers/KeyboardMap.h" #include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/MatrixMessage.h" @@ -1172,6 +1173,39 @@ struct ParamTraits { } /* namespace IPC */ +namespace mozilla { +namespace ipc { + +template <> +struct IPDLParamTraits { + static void Write(IPC::MessageWriter* aWriter, IProtocol* aActor, + layers::GpuFence* aParam) { + if (aParam) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + } + WriteIPDLParam(aWriter, aActor, false); + } + + static bool Read(IPC::MessageReader* aReader, IProtocol* aActor, + RefPtr* aResult) { + *aResult = nullptr; + bool notnull = false; + if (!ReadIPDLParam(aReader, aActor, ¬null)) { + return false; + } + + if (!notnull) { + return true; + } + + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return true; + } +}; + +} // namespace ipc +} // namespace mozilla + #define DEFINE_SERVO_PARAMTRAITS(ty_) \ MOZ_DEFINE_RUST_PARAMTRAITS(mozilla::ty_, Servo_##ty_##_Serialize, \ Servo_##ty_##_Deserialize) diff --git a/gfx/layers/ipc/LayersSurfaces.ipdlh b/gfx/layers/ipc/LayersSurfaces.ipdlh index 497559e10021..6158673574cc 100644 --- a/gfx/layers/ipc/LayersSurfaces.ipdlh +++ b/gfx/layers/ipc/LayersSurfaces.ipdlh @@ -29,6 +29,7 @@ using gfxImageFormat from "gfxTypes.h"; using mozilla::layers::MaybeVideoBridgeSource from "mozilla/layers/VideoBridgeUtils.h"; using mozilla::layers::RemoteTextureId from "mozilla/layers/LayersTypes.h"; using mozilla::layers::RemoteTextureOwnerId from "mozilla/layers/LayersTypes.h"; +[RefCounted] using mozilla::layers::GpuFence from "mozilla/layers/GpuFence.h"; using mozilla::layers::GpuProcessTextureId from "mozilla/layers/LayersTypes.h"; using mozilla::layers::GpuProcessQueryId from "mozilla/layers/LayersTypes.h"; using mozilla::wr::ExternalImageSource from "mozilla/webrender/WebRenderTypes.h"; @@ -67,6 +68,7 @@ namespace layers { uint32_t surfaceId; bool isOpaque; YUVColorSpace yUVColorSpace; + nullable GpuFence gpuFence; }; [Comparable] struct SurfaceDescriptorDMABuf { diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index a29cadb10f9d..b76bc2c36023 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -145,6 +145,7 @@ EXPORTS.mozilla.layers += [ "D3D11ZeroCopyTextureImage.h", "DirectionUtils.h", "Effects.h", + "GpuFence.h", "ImageDataSerializer.h", "ipc/ActiveResource.h", "ipc/APZChild.h", @@ -263,6 +264,7 @@ if CONFIG["MOZ_WAYLAND"]: if CONFIG["MOZ_WIDGET_TOOLKIT"] in ("cocoa", "uikit"): EXPORTS.mozilla.layers += [ + "GpuFenceMTLSharedEvent.h", "NativeLayerCA.h", "SurfacePoolCA.h", ] @@ -275,6 +277,7 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] in ("cocoa", "uikit"): "SurfacePoolCA.mm", ] SOURCES += [ + "GpuFenceMTLSharedEvent.cpp", "MacIOSurfaceHelpers.cpp", "MacIOSurfaceImage.cpp", ] diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp index dc601a1b0631..622f2a32c607 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp +++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp @@ -50,17 +50,19 @@ MacIOSurfaceTextureData* MacIOSurfaceTextureData::Create(const IntSize& aSize, } bool MacIOSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) { - aOutDescriptor = SurfaceDescriptorMacIOSurface(mSurface->GetIOSurfaceID(), - !mSurface->HasAlpha(), - mSurface->GetYUVColorSpace()); + RefPtr gpuFence; + aOutDescriptor = SurfaceDescriptorMacIOSurface( + mSurface->GetIOSurfaceID(), !mSurface->HasAlpha(), + mSurface->GetYUVColorSpace(), std::move(gpuFence)); return true; } void MacIOSurfaceTextureData::GetSubDescriptor( RemoteDecoderVideoSubDescriptor* const aOutDesc) { - *aOutDesc = SurfaceDescriptorMacIOSurface(mSurface->GetIOSurfaceID(), - !mSurface->HasAlpha(), - mSurface->GetYUVColorSpace()); + RefPtr gpuFence; + *aOutDesc = SurfaceDescriptorMacIOSurface( + mSurface->GetIOSurfaceID(), !mSurface->HasAlpha(), + mSurface->GetYUVColorSpace(), std::move(gpuFence)); } void MacIOSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const { diff --git a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp index 98f9d62ede50..7d53ded551b1 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp +++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp @@ -7,6 +7,7 @@ #include "MacIOSurfaceTextureHostOGL.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/MacIOSurface.h" +#include "mozilla/layers/GpuFence.h" #include "mozilla/webrender/RenderMacIOSurfaceTextureHost.h" #include "mozilla/webrender/RenderThread.h" #include "mozilla/webrender/WebRenderAPI.h" @@ -24,6 +25,7 @@ MacIOSurfaceTextureHostOGL::MacIOSurfaceTextureHostOGL( if (!mSurface) { gfxCriticalNote << "Failed to look up MacIOSurface"; } + mGpuFence = aDescriptor.gpuFence(); } MacIOSurfaceTextureHostOGL::~MacIOSurfaceTextureHostOGL() { @@ -74,7 +76,7 @@ void MacIOSurfaceTextureHostOGL::CreateRenderTexture( MOZ_ASSERT(mExternalImageId.isSome()); RefPtr texture = - new wr::RenderMacIOSurfaceTextureHost(GetMacIOSurface()); + new wr::RenderMacIOSurfaceTextureHost(GetMacIOSurface(), mGpuFence); bool isDRM = (bool)(mFlags & TextureFlags::DRM_SOURCE); texture->SetIsFromDRMSource(isDRM); diff --git a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h index e3615c5f8476..df24af26e977 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h +++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h @@ -17,6 +17,8 @@ class MacIOSurface; namespace mozilla { namespace layers { +class GpuFence; + /** * A TextureHost for shared MacIOSurface * @@ -77,6 +79,7 @@ class MacIOSurfaceTextureHostOGL : public TextureHost { protected: RefPtr mTextureSource; RefPtr mSurface; + RefPtr mGpuFence; }; } // namespace layers diff --git a/gfx/webrender_bindings/RenderCompositorNative.cpp b/gfx/webrender_bindings/RenderCompositorNative.cpp index 3b5a29948ef8..409b2ab86ce5 100644 --- a/gfx/webrender_bindings/RenderCompositorNative.cpp +++ b/gfx/webrender_bindings/RenderCompositorNative.cpp @@ -13,6 +13,7 @@ #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/Logging.h" #include "mozilla/layers/CompositionRecorder.h" +#include "mozilla/layers/GpuFence.h" #include "mozilla/layers/NativeLayer.h" #include "mozilla/layers/SurfacePool.h" #include "mozilla/StaticPrefs_gfx.h" @@ -88,6 +89,8 @@ RenderedFrameId RenderCompositorNative::EndFrame( DoSwap(); + MOZ_ASSERT(mPendingGpuFeces.empty()); + if (mNativeLayerForEntireWindow) { mNativeLayerForEntireWindow->NotifySurfaceReady(); mNativeLayerRoot->CommitToScreen(); @@ -431,6 +434,13 @@ void RenderCompositorNative::AddSurface( layer->SetSamplingFilter(ToSamplingFilter(aImageRendering)); mAddedLayers.AppendElement(layer); + if (surface.mIsExternal) { + RefPtr fence = layer->GetGpuFence(); + if (fence && BackendType() == layers::WebRenderBackend::HARDWARE) { + mPendingGpuFeces.emplace_back(fence); + } + } + if (!surface.mIsExternal) { mAddedTilePixelCount += layerSize.width * layerSize.height; } @@ -471,16 +481,16 @@ RenderCompositorNativeOGL::~RenderCompositorNativeOGL() { gfxCriticalNote << "Failed to make render context current during destroying."; // Leak resources! - mPreviousFrameDoneSync = nullptr; - mThisFrameDoneSync = nullptr; + mPreviousFrameDoneFences = nullptr; + mThisFrameDoneFences = nullptr; return; } - if (mPreviousFrameDoneSync) { - mGL->fDeleteSync(mPreviousFrameDoneSync); + if (mPreviousFrameDoneFences && mPreviousFrameDoneFences->mSync) { + mGL->fDeleteSync(mPreviousFrameDoneFences->mSync); } - if (mThisFrameDoneSync) { - mGL->fDeleteSync(mThisFrameDoneSync); + if (mThisFrameDoneFences && mThisFrameDoneFences->mSync) { + mGL->fDeleteSync(mThisFrameDoneFences->mSync); } } @@ -512,23 +522,43 @@ void RenderCompositorNativeOGL::InsertFrameDoneSync() { #ifdef XP_DARWIN // Only do this on macOS. // On other platforms, SwapBuffers automatically applies back-pressure. - if (mThisFrameDoneSync) { - mGL->fDeleteSync(mThisFrameDoneSync); + if (mThisFrameDoneFences && mThisFrameDoneFences->mSync) { + mGL->fDeleteSync(mThisFrameDoneFences->mSync); } - mThisFrameDoneSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + mThisFrameDoneFences = + MakeUnique(std::move(mPendingGpuFeces)); + mThisFrameDoneFences->mSync = + mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0); #endif } bool RenderCompositorNativeOGL::WaitForGPU() { - if (mPreviousFrameDoneSync) { - AUTO_PROFILER_LABEL("Waiting for GPU to finish previous frame", GRAPHICS); - mGL->fClientWaitSync(mPreviousFrameDoneSync, - LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT, - LOCAL_GL_TIMEOUT_IGNORED); - mGL->fDeleteSync(mPreviousFrameDoneSync); + if (mPreviousFrameDoneFences) { + bool complete = false; + while (!complete) { + complete = true; + for (const auto& fence : mPreviousFrameDoneFences->mGpuFeces) { + if (!fence->HasCompleted()) { + complete = false; + break; + } + } + + if (!complete) { + PR_Sleep(PR_MillisecondsToInterval(1)); + } + } + + if (mPreviousFrameDoneFences->mSync) { + AUTO_PROFILER_LABEL("Waiting for GPU to finish previous frame", GRAPHICS); + mGL->fClientWaitSync(mPreviousFrameDoneFences->mSync, + LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT, + LOCAL_GL_TIMEOUT_IGNORED); + mGL->fDeleteSync(mPreviousFrameDoneFences->mSync); + } } - mPreviousFrameDoneSync = mThisFrameDoneSync; - mThisFrameDoneSync = nullptr; + mPreviousFrameDoneFences = std::move(mThisFrameDoneFences); + MOZ_ASSERT(!mThisFrameDoneFences); return true; } diff --git a/gfx/webrender_bindings/RenderCompositorNative.h b/gfx/webrender_bindings/RenderCompositorNative.h index 936fdd3db8e1..7f4f180ae418 100644 --- a/gfx/webrender_bindings/RenderCompositorNative.h +++ b/gfx/webrender_bindings/RenderCompositorNative.h @@ -7,6 +7,7 @@ #ifndef MOZILLA_GFX_RENDERCOMPOSITOR_NATIVE_H #define MOZILLA_GFX_RENDERCOMPOSITOR_NATIVE_H +#include #include #include "GLTypes.h" @@ -18,6 +19,7 @@ namespace mozilla { namespace layers { +class GpuFence; class NativeLayerRootSnapshotter; class NativeLayerRoot; class NativeLayer; @@ -140,6 +142,7 @@ class RenderCompositorNative : public RenderCompositor { gfx::IntRect mVisibleBounds; std::unordered_map mSurfaces; TimeStamp mBeginFrameTimeStamp; + std::deque> mPendingGpuFeces; }; static inline bool operator==(const RenderCompositorNative::TileKey& a0, @@ -176,9 +179,18 @@ class RenderCompositorNativeOGL : public RenderCompositorNative { RefPtr mGL; + struct BackPressureFences { + explicit BackPressureFences( + std::deque>&& aGpuFeces) + : mGpuFeces(std::move(aGpuFeces)) {} + + GLsync mSync = nullptr; + std::deque> mGpuFeces; + }; + // Used to apply back-pressure in WaitForGPU(). - GLsync mPreviousFrameDoneSync = nullptr; - GLsync mThisFrameDoneSync = nullptr; + UniquePtr mPreviousFrameDoneFences; + UniquePtr mThisFrameDoneFences; }; // RenderCompositorNativeSWGL is a NativeLayer compositor that only diff --git a/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.cpp b/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.cpp index 54cc845b1c49..28469a1ceb8b 100644 --- a/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.cpp +++ b/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.cpp @@ -13,6 +13,7 @@ #endif #include "mozilla/gfx/Logging.h" +#include "mozilla/layers/GpuFence.h" #include "ScopedGLHelpers.h" namespace mozilla { @@ -41,8 +42,8 @@ static bool CreateTextureForPlane(uint8_t aPlaneID, gl::GLContext* aGL, } RenderMacIOSurfaceTextureHost::RenderMacIOSurfaceTextureHost( - MacIOSurface* aSurface) - : mSurface(aSurface), mTextureHandles{0, 0, 0} { + MacIOSurface* aSurface, layers::GpuFence* aGpuFence) + : mSurface(aSurface), mGpuFence(aGpuFence), mTextureHandles{0, 0, 0} { MOZ_COUNT_CTOR_INHERITED(RenderMacIOSurfaceTextureHost, RenderTextureHost); } diff --git a/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.h b/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.h index 173cd3c2238a..2ff1ea17fad4 100644 --- a/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.h +++ b/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.h @@ -14,14 +14,16 @@ namespace mozilla { namespace layers { +class GpuFence; class SurfaceDescriptorMacIOSurface; -} +} // namespace layers namespace wr { class RenderMacIOSurfaceTextureHost final : public RenderTextureHostSWGL { public: - explicit RenderMacIOSurfaceTextureHost(MacIOSurface* aSurface); + explicit RenderMacIOSurfaceTextureHost(MacIOSurface* aSurface, + layers::GpuFence* aGpuFence); wr::WrExternalImage Lock(uint8_t aChannelIndex, gl::GLContext* aGL) override; void Unlock() override; @@ -46,11 +48,14 @@ class RenderMacIOSurfaceTextureHost final : public RenderTextureHostSWGL { PlaneInfo& aPlaneInfo) override; void UnmapPlanes() override; + layers::GpuFence* GetGpuFence() { return mGpuFence; } + private: virtual ~RenderMacIOSurfaceTextureHost(); void DeleteTextureHandle(); RefPtr mSurface; + RefPtr mGpuFence; RefPtr mGL; GLuint mTextureHandles[3]; }; diff --git a/gfx/wgpu_bindings/src/server.rs b/gfx/wgpu_bindings/src/server.rs index f666c725e8ec..bf99817ae22e 100644 --- a/gfx/wgpu_bindings/src/server.rs +++ b/gfx/wgpu_bindings/src/server.rs @@ -1270,6 +1270,62 @@ pub extern "C" fn wgpu_vkimage_get_dma_buf_info(handle: &VkImageHandle) -> DMABu } } +#[cfg(target_os = "macos")] +pub struct MetalSharedEventHandle(metal::SharedEvent); +#[cfg(not(target_os = "macos"))] +pub struct MetalSharedEventHandle; + +#[no_mangle] +#[allow(unreachable_code)] +#[allow(unused_variables)] +pub extern "C" fn wgpu_server_get_device_fence_metal_shared_event( + global: &Global, + device_id: id::DeviceId, +) -> *mut MetalSharedEventHandle { + #[cfg(target_os = "macos")] + { + let shared_event = unsafe { + global.device_fence_as_hal::>( + device_id, + |hal_fence| hal_fence.map(|fence| fence.raw_shared_event().unwrap().clone()), + ) + }; + let shared_event = match shared_event { + Some(shared_event) => shared_event, + None => { + return ptr::null_mut(); + } + }; + return Box::into_raw(Box::new(MetalSharedEventHandle(shared_event))); + } + + ptr::null_mut() +} + +#[no_mangle] +#[allow(unreachable_code)] +#[allow(unused_variables)] +pub extern "C" fn wgpu_server_metal_shared_event_signaled_value( + shared_event: &mut MetalSharedEventHandle, +) -> u64 { + #[cfg(target_os = "macos")] + { + return shared_event.0.signaled_value(); + } + + u64::MAX +} + +#[no_mangle] +#[allow(unreachable_code)] +#[allow(unused_variables)] +pub extern "C" fn wgpu_server_delete_metal_shared_event(shared_event: *mut MetalSharedEventHandle) { + #[cfg(target_os = "macos")] + { + let _ = unsafe { Box::from_raw(shared_event) }; + } +} + extern "C" { #[allow(dead_code)] fn gfx_critical_note(msg: *const c_char); diff --git a/gfx/wgpu_bindings/wgpu.h b/gfx/wgpu_bindings/wgpu.h index 52c9cf4449eb..206f6b1eaae6 100644 --- a/gfx/wgpu_bindings/wgpu.h +++ b/gfx/wgpu_bindings/wgpu.h @@ -68,6 +68,14 @@ class DefaultDelete { }; #endif +template <> +class DefaultDelete { + public: + void operator()(webgpu::ffi::WGPUMetalSharedEventHandle* aPtr) const { + webgpu::ffi::wgpu_server_delete_metal_shared_event(aPtr); + } +}; + } // namespace mozilla #endif // WGPU_h