Bug 1852485 - Present WebGPU by using DX11 texture in swap chain with readback on Windows r=webgpu-reviewers,nical

The change is preparation for Bug 1843891.
Current gecko uses a internal texture for SwapChain's texture. This bug changes as to use external dx11 texture for WebGPU dx12 backend on Windows.

WebGPUParent allocates dx11 texture for SwapChain's texture of dx12 backend WebGPU. wgpu uses the dx11 texture as ID3D12Resource. The readback for presenting to WebRender still exists.
The change handles only RBGA format.

Differential Revision: https://phabricator.services.mozilla.com/D187870
This commit is contained in:
sotaro 2023-09-15 11:14:51 +00:00
Родитель 8506bd8355
Коммит a8dfa5bebe
20 изменённых файлов: 571 добавлений и 32 удалений

2
Cargo.lock сгенерированный
Просмотреть файл

@ -6391,6 +6391,7 @@ name = "wgpu_bindings"
version = "0.1.0"
dependencies = [
"bincode",
"d3d12",
"log",
"nsstring",
"parking_lot",
@ -6399,6 +6400,7 @@ dependencies = [
"wgpu-core",
"wgpu-hal",
"wgpu-types",
"winapi",
]
[[package]]

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

@ -117,7 +117,12 @@ void CanvasContext::Configure(const dom::GPUCanvasConfiguration& aConfig) {
mConfig.reset(new dom::GPUCanvasConfiguration(aConfig));
mRemoteTextureOwnerId = Some(layers::RemoteTextureOwnerId::GetNext());
mUseExternalTextureInSwapChain =
wgpu_client_use_external_texture_in_swapChain(
aConfig.mDevice->mId,
WebGPUChild::ConvertTextureFormat(aConfig.mFormat));
mTexture = aConfig.mDevice->InitSwapChain(aConfig, *mRemoteTextureOwnerId,
mUseExternalTextureInSwapChain,
mGfxFormat, mCanvasSize);
if (!mTexture) {
Unconfigure();

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

@ -100,6 +100,7 @@ class CanvasContext final : public nsICanvasRenderingContextInternal,
Maybe<layers::RemoteTextureId> mLastRemoteTextureId;
Maybe<layers::RemoteTextureOwnerId> mRemoteTextureOwnerId;
bool mUseExternalTextureInSwapChain = false;
};
} // namespace webgpu

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

@ -121,9 +121,15 @@ already_AddRefed<Buffer> Device::CreateBuffer(
already_AddRefed<Texture> Device::CreateTexture(
const dom::GPUTextureDescriptor& aDesc) {
return CreateTexture(aDesc, /* aOwnerId */ Nothing());
}
already_AddRefed<Texture> Device::CreateTexture(
const dom::GPUTextureDescriptor& aDesc,
Maybe<layers::RemoteTextureOwnerId> aOwnerId) {
RawId id = 0;
if (mBridge->CanSend()) {
id = mBridge->DeviceCreateTexture(mId, aDesc);
id = mBridge->DeviceCreateTexture(mId, aDesc, aOwnerId);
}
RefPtr<Texture> texture = new Texture(this, id, aDesc);
return texture.forget();
@ -294,7 +300,8 @@ already_AddRefed<dom::Promise> Device::CreateRenderPipelineAsync(
already_AddRefed<Texture> Device::InitSwapChain(
const dom::GPUCanvasConfiguration& aDesc,
const layers::RemoteTextureOwnerId aOwnerId, gfx::SurfaceFormat aFormat,
const layers::RemoteTextureOwnerId aOwnerId,
bool aUseExternalTextureInSwapChain, gfx::SurfaceFormat aFormat,
gfx::IntSize aCanvasSize) {
if (!mBridge->CanSend()) {
return nullptr;
@ -303,7 +310,8 @@ already_AddRefed<Texture> Device::InitSwapChain(
const layers::RGBDescriptor rgbDesc(aCanvasSize, aFormat);
// buffer count doesn't matter much, will be created on demand
const size_t maxBufferCount = 10;
mBridge->DeviceCreateSwapChain(mId, rgbDesc, maxBufferCount, aOwnerId);
mBridge->DeviceCreateSwapChain(mId, rgbDesc, maxBufferCount, aOwnerId,
aUseExternalTextureInSwapChain);
dom::GPUTextureDescriptor desc;
desc.mDimension = dom::GPUTextureDimension::_2d;
@ -318,7 +326,7 @@ already_AddRefed<Texture> Device::InitSwapChain(
desc.mViewFormats = aDesc.mViewFormats;
// TODO: `mColorSpace`: <https://bugzilla.mozilla.org/show_bug.cgi?id=1846608>
// TODO: `mAlphaMode`: <https://bugzilla.mozilla.org/show_bug.cgi?id=1846605>
return CreateTexture(desc);
return CreateTexture(desc, Some(aOwnerId));
}
bool Device::CheckNewWarning(const nsACString& aMessage) {

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

@ -94,7 +94,8 @@ class Device final : public DOMEventTargetHelper, public SupportsWeakPtr {
RefPtr<WebGPUChild> GetBridge();
already_AddRefed<Texture> InitSwapChain(
const dom::GPUCanvasConfiguration& aDesc,
const layers::RemoteTextureOwnerId aOwnerId, gfx::SurfaceFormat aFormat,
const layers::RemoteTextureOwnerId aOwnerId,
bool aUseExternalTextureInSwapChain, gfx::SurfaceFormat aFormat,
gfx::IntSize aCanvasSize);
bool CheckNewWarning(const nsACString& aMessage);
@ -130,6 +131,9 @@ class Device final : public DOMEventTargetHelper, public SupportsWeakPtr {
already_AddRefed<Texture> CreateTexture(
const dom::GPUTextureDescriptor& aDesc);
already_AddRefed<Texture> CreateTexture(
const dom::GPUTextureDescriptor& aDesc,
Maybe<layers::RemoteTextureOwnerId> aOwnerId);
already_AddRefed<Sampler> CreateSampler(
const dom::GPUSamplerDescriptor& aDesc);

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

@ -0,0 +1,31 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "ExternalTexture.h"
#ifdef XP_WIN
# include "mozilla/webgpu/ExternalTextureD3D11.h"
#endif
namespace mozilla::webgpu {
// static
UniquePtr<ExternalTexture> ExternalTexture::Create(
const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat) {
UniquePtr<ExternalTexture> texture;
#ifdef XP_WIN
texture = ExternalTextureD3D11::Create(aWidth, aHeight, aFormat);
#endif
return texture;
}
ExternalTexture::ExternalTexture(const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat)
: mWidth(aWidth), mHeight(aHeight), mFormat(aFormat) {}
ExternalTexture::~ExternalTexture() {}
} // namespace mozilla::webgpu

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

@ -0,0 +1,43 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 ExternalTexture_H_
#define ExternalTexture_H_
#include "mozilla/gfx/Point.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/webgpu/ffi/wgpu.h"
namespace mozilla {
namespace webgpu {
// A texture that can be used by the WebGPU implementation but is created and
// owned by Gecko
class ExternalTexture {
public:
static UniquePtr<ExternalTexture> Create(
const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat);
ExternalTexture(const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat);
virtual ~ExternalTexture();
virtual void* GetExternalTextureHandle() { return nullptr; }
virtual Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() = 0;
gfx::IntSize GetSize() { return gfx::IntSize(mWidth, mHeight); }
const uint32_t mWidth;
const uint32_t mHeight;
const struct ffi::WGPUTextureFormat mFormat;
};
} // namespace webgpu
} // namespace mozilla
#endif // GPU_ExternalTexture_H_

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

@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "ExternalTextureD3D11.h"
#include <d3d11.h>
#include "mozilla/gfx/DeviceManagerDx.h"
namespace mozilla::webgpu {
// static
UniquePtr<ExternalTextureD3D11> ExternalTextureD3D11::Create(
const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat) {
const RefPtr<ID3D11Device> d3d11Device =
gfx::DeviceManagerDx::Get()->GetCompositorDevice();
if (!d3d11Device) {
gfxCriticalNoteOnce << "CompositorDevice does not exist";
return nullptr;
}
if (aFormat.tag != ffi::WGPUTextureFormat_Bgra8Unorm) {
gfxCriticalNoteOnce << "Non supported format: " << aFormat.tag;
return nullptr;
}
CD3D11_TEXTURE2D_DESC desc(
DXGI_FORMAT_B8G8R8A8_UNORM, aWidth, aHeight, 1, 1,
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
RefPtr<ID3D11Texture2D> texture;
HRESULT hr =
d3d11Device->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
if (FAILED(hr)) {
gfxCriticalNoteOnce << "CreateTexture2D failed: " << gfx::hexa(hr);
return nullptr;
}
return MakeUnique<ExternalTextureD3D11>(aWidth, aHeight, aFormat, texture);
}
ExternalTextureD3D11::ExternalTextureD3D11(
const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat,
RefPtr<ID3D11Texture2D> aTexture)
: ExternalTexture(aWidth, aHeight, aFormat), mTexture(aTexture) {
MOZ_ASSERT(mTexture);
}
ExternalTextureD3D11::~ExternalTextureD3D11() {}
void* ExternalTextureD3D11::GetExternalTextureHandle() {
RefPtr<IDXGIResource> resource;
mTexture->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
if (!resource) {
gfxCriticalNoteOnce << "Failed to get IDXGIResource";
return 0;
}
HANDLE sharedHandle;
HRESULT hr = resource->GetSharedHandle(&sharedHandle);
if (FAILED(hr)) {
gfxCriticalNoteOnce << "GetSharedHandle failed: " << gfx::hexa(hr);
return 0;
}
return sharedHandle;
}
Maybe<layers::SurfaceDescriptor> ExternalTextureD3D11::ToSurfaceDescriptor() {
const auto format = gfx::SurfaceFormat::B8G8R8A8;
return Some(layers::SurfaceDescriptorD3D10(
(WindowsHandle)GetExternalTextureHandle(),
/* gpuProcessTextureId */ Nothing(),
/* arrayIndex */ 0, format, gfx::IntSize(mWidth, mHeight),
gfx::ColorSpace2::SRGB, gfx::ColorRange::FULL, /* hasKeyedMutex */ true));
}
} // namespace mozilla::webgpu

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

@ -0,0 +1,39 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 GPU_ExternalTextureD3D11_H_
#define GPU_ExternalTextureD3D11_H_
#include "mozilla/webgpu/ExternalTexture.h"
struct ID3D11Texture2D;
namespace mozilla {
namespace webgpu {
class ExternalTextureD3D11 final : public ExternalTexture {
public:
static UniquePtr<ExternalTextureD3D11> Create(
const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat);
ExternalTextureD3D11(const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat,
RefPtr<ID3D11Texture2D> aTexture);
virtual ~ExternalTextureD3D11();
void* GetExternalTextureHandle() override;
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override;
protected:
RefPtr<ID3D11Texture2D> mTexture;
};
} // namespace webgpu
} // namespace mozilla
#endif // GPU_Texture_H_

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

@ -75,7 +75,7 @@ parent:
async ComputePipelineDestroy(RawId selfId);
async RenderPipelineDestroy(RawId selfId);
async ImplicitLayoutDestroy(RawId implicitPlId, RawId[] implicitBglIds);
async DeviceCreateSwapChain(RawId selfId, RawId queueId, RGBDescriptor desc, RawId[] bufferIds, RemoteTextureOwnerId ownerId);
async DeviceCreateSwapChain(RawId selfId, RawId queueId, RGBDescriptor desc, RawId[] bufferIds, RemoteTextureOwnerId ownerId, bool useExternalTextureInSwapChain);
async SwapChainPresent(RawId textureId, RawId commandEncoderId, RemoteTextureId remoteTextureId, RemoteTextureOwnerId remoteTextureOwnerId);
async SwapChainDestroy(RemoteTextureOwnerId ownerId);

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

@ -302,8 +302,9 @@ RawId WebGPUChild::DeviceCreateBuffer(RawId aSelfId,
return bufferId;
}
RawId WebGPUChild::DeviceCreateTexture(RawId aSelfId,
const dom::GPUTextureDescriptor& aDesc) {
RawId WebGPUChild::DeviceCreateTexture(
RawId aSelfId, const dom::GPUTextureDescriptor& aDesc,
Maybe<layers::RemoteTextureOwnerId> aOwnerId) {
ffi::WGPUTextureDescriptor desc = {};
webgpu::StringHelper label(aDesc.mLabel);
@ -334,9 +335,14 @@ RawId WebGPUChild::DeviceCreateTexture(RawId aSelfId,
}
desc.view_formats = {viewFormats.Elements(), viewFormats.Length()};
Maybe<ffi::WGPUSwapChainId> ownerId;
if (aOwnerId.isSome()) {
ownerId = Some(ffi::WGPUSwapChainId{aOwnerId->mId});
}
ByteBuf bb;
RawId id = ffi::wgpu_client_create_texture(mClient.get(), aSelfId, &desc,
ToFFI(&bb));
RawId id = ffi::wgpu_client_create_texture(
mClient.get(), aSelfId, &desc, ownerId.ptrOr(nullptr), ToFFI(&bb));
if (!SendDeviceAction(aSelfId, std::move(bb))) {
MOZ_CRASH("IPC failure");
}
@ -1124,14 +1130,16 @@ ipc::IPCResult WebGPUChild::RecvDropAction(const ipc::ByteBuf& aByteBuf) {
void WebGPUChild::DeviceCreateSwapChain(
RawId aSelfId, const RGBDescriptor& aRgbDesc, size_t maxBufferCount,
const layers::RemoteTextureOwnerId& aOwnerId) {
const layers::RemoteTextureOwnerId& aOwnerId,
bool aUseExternalTextureInSwapChain) {
RawId queueId = aSelfId; // TODO: multiple queues
nsTArray<RawId> bufferIds(maxBufferCount);
for (size_t i = 0; i < maxBufferCount; ++i) {
bufferIds.AppendElement(
ffi::wgpu_client_make_buffer_id(mClient.get(), aSelfId));
}
SendDeviceCreateSwapChain(aSelfId, queueId, aRgbDesc, bufferIds, aOwnerId);
SendDeviceCreateSwapChain(aSelfId, queueId, aRgbDesc, bufferIds, aOwnerId,
aUseExternalTextureInSwapChain);
}
void WebGPUChild::QueueOnSubmittedWorkDone(

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

@ -67,7 +67,8 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
RawId DeviceCreateBuffer(RawId aSelfId, const dom::GPUBufferDescriptor& aDesc,
ipc::UnsafeSharedMemoryHandle&& aShmem);
RawId DeviceCreateTexture(RawId aSelfId,
const dom::GPUTextureDescriptor& aDesc);
const dom::GPUTextureDescriptor& aDesc,
Maybe<layers::RemoteTextureOwnerId> aOwnerId);
RawId TextureCreateView(RawId aSelfId, RawId aDeviceId,
const dom::GPUTextureViewDescriptor& aDesc);
RawId DeviceCreateSampler(RawId aSelfId,
@ -105,7 +106,8 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
void DeviceCreateSwapChain(RawId aSelfId, const RGBDescriptor& aRgbDesc,
size_t maxBufferCount,
const layers::RemoteTextureOwnerId& aOwnerId);
const layers::RemoteTextureOwnerId& aOwnerId,
bool aUseExternalTextureInSwapChain);
void QueueOnSubmittedWorkDone(const RawId aSelfId,
const RefPtr<dom::Promise>& aPromise);

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

@ -7,13 +7,14 @@
#include "mozilla/PodOperations.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/dom/WebGPUBinding.h"
#include "mozilla/webgpu/ffi/wgpu.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/RemoteTextureMap.h"
#include "mozilla/layers/TextureHost.h"
#include "mozilla/layers/WebRenderImageHost.h"
#include "mozilla/layers/WebRenderTextureHost.h"
#include "mozilla/webgpu/ExternalTexture.h"
#include "mozilla/webgpu/ffi/wgpu.h"
namespace mozilla::webgpu {
@ -21,6 +22,39 @@ const uint64_t POLL_TIME_MS = 100;
static mozilla::LazyLogModule sLogger("WebGPU");
namespace ffi {
extern bool wgpu_server_use_external_texture_for_swap_chain(
void* aParam, WGPUSwapChainId aSwapChainId) {
auto* parent = static_cast<WebGPUParent*>(aParam);
return parent->UseExternalTextureForSwapChain(aSwapChainId);
}
extern bool wgpu_server_create_external_texture_for_swap_chain(
void* aParam, WGPUSwapChainId aSwapChainId, WGPUDeviceId aDeviceId,
WGPUTextureId aTextureId, uint32_t aWidth, uint32_t aHeight,
struct WGPUTextureFormat aFormat) {
auto* parent = static_cast<WebGPUParent*>(aParam);
return parent->CreateExternalTextureForSwapChain(
aSwapChainId, aDeviceId, aTextureId, aWidth, aHeight, aFormat);
}
extern void* wgpu_server_get_external_texture_handle(void* aParam,
WGPUTextureId aId) {
auto* parent = static_cast<WebGPUParent*>(aParam);
auto externalTexture = parent->GetExternalTexture(aId);
if (!externalTexture) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
}
return externalTexture->GetExternalTextureHandle();
}
} // namespace ffi
// A fixed-capacity buffer for receiving textual error messages from
// `wgpu_bindings`.
//
@ -96,6 +130,7 @@ class PresentationData {
NS_INLINE_DECL_REFCOUNTING(PresentationData);
public:
const bool mUseExternalTextureInSwapChain;
const RawId mDeviceId;
const RawId mQueueId;
const layers::RGBDescriptor mDesc;
@ -105,10 +140,11 @@ class PresentationData {
std::vector<RawId> mQueuedBufferIds MOZ_GUARDED_BY(mBuffersLock);
Mutex mBuffersLock;
PresentationData(RawId aDeviceId, RawId aQueueId,
const layers::RGBDescriptor& aDesc, uint32_t aSourcePitch,
const nsTArray<RawId>& aBufferIds)
: mDeviceId(aDeviceId),
PresentationData(bool aUseExternalTextureInSwapChain, RawId aDeviceId,
RawId aQueueId, const layers::RGBDescriptor& aDesc,
uint32_t aSourcePitch, const nsTArray<RawId>& aBufferIds)
: mUseExternalTextureInSwapChain(aUseExternalTextureInSwapChain),
mDeviceId(aDeviceId),
mQueueId(aQueueId),
mDesc(aDesc),
mSourcePitch(aSourcePitch),
@ -250,7 +286,7 @@ static ffi::WGPUIdentityRecyclerFactory MakeFactory(void* param) {
}
WebGPUParent::WebGPUParent()
: mContext(ffi::wgpu_server_new(MakeFactory(this))) {
: mContext(ffi::wgpu_server_new(MakeFactory(this), this)) {
mTimer.Start(base::TimeDelta::FromMilliseconds(POLL_TIME_MS), this,
&WebGPUParent::MaintainDevices);
}
@ -608,6 +644,11 @@ ipc::IPCResult WebGPUParent::RecvBufferDestroy(RawId aBufferId) {
ipc::IPCResult WebGPUParent::RecvTextureDestroy(RawId aTextureId) {
ffi::wgpu_server_texture_drop(mContext.get(), aTextureId);
auto it = mExternalTextures.find(aTextureId);
if (it != mExternalTextures.end()) {
mExternalTextures.erase(it);
}
return IPC_OK();
}
@ -746,7 +787,8 @@ ipc::IPCResult WebGPUParent::RecvImplicitLayoutDestroy(
ipc::IPCResult WebGPUParent::RecvDeviceCreateSwapChain(
RawId aDeviceId, RawId aQueueId, const RGBDescriptor& aDesc,
const nsTArray<RawId>& aBufferIds,
const layers::RemoteTextureOwnerId& aOwnerId) {
const layers::RemoteTextureOwnerId& aOwnerId,
bool aUseExternalTextureInSwapChain) {
switch (aDesc.format()) {
case gfx::SurfaceFormat::R8G8B8A8:
case gfx::SurfaceFormat::B8G8R8A8:
@ -781,8 +823,9 @@ ipc::IPCResult WebGPUParent::RecvDeviceCreateSwapChain(
// RemoteTextureMap::GetRemoteTextureForDisplayList() works synchronously.
mRemoteTextureOwner->RegisterTextureOwner(aOwnerId, /* aIsSyncMode */ true);
auto data = MakeRefPtr<PresentationData>(aDeviceId, aQueueId, aDesc,
bufferStride, aBufferIds);
auto data =
MakeRefPtr<PresentationData>(aUseExternalTextureInSwapChain, aDeviceId,
aQueueId, aDesc, bufferStride, aBufferIds);
if (!mPresentationDataMap.emplace(aOwnerId, data).second) {
NS_ERROR("External image is already registered as WebGPU canvas!");
}
@ -1226,4 +1269,71 @@ ipc::IPCResult WebGPUParent::RecvGenerateError(const Maybe<RawId> aDeviceId,
return IPC_OK();
}
bool WebGPUParent::UseExternalTextureForSwapChain(
ffi::WGPUSwapChainId aSwapChainId) {
auto ownerId = layers::RemoteTextureOwnerId{aSwapChainId._0};
const auto& lookup = mPresentationDataMap.find(ownerId);
if (lookup == mPresentationDataMap.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return IPC_OK();
}
RefPtr<PresentationData> data = lookup->second.get();
return data->mUseExternalTextureInSwapChain;
}
bool WebGPUParent::CreateExternalTextureForSwapChain(
ffi::WGPUSwapChainId aSwapChainId, ffi::WGPUDeviceId aDeviceId,
ffi::WGPUTextureId aTextureId, uint32_t aWidth, uint32_t aHeight,
struct ffi::WGPUTextureFormat aFormat) {
auto ownerId = layers::RemoteTextureOwnerId{aSwapChainId._0};
const auto& lookup = mPresentationDataMap.find(ownerId);
if (lookup == mPresentationDataMap.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return false;
}
RefPtr<PresentationData> data = lookup->second.get();
if (!data->mUseExternalTextureInSwapChain) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return false;
}
auto externalTexture =
CreateExternalTexture(aDeviceId, aTextureId, aWidth, aHeight, aFormat);
if (!externalTexture) {
return false;
}
return true;
}
std::shared_ptr<ExternalTexture> WebGPUParent::CreateExternalTexture(
ffi::WGPUDeviceId aDeviceId, ffi::WGPUTextureId aTextureId, uint32_t aWidth,
uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat) {
MOZ_RELEASE_ASSERT(mExternalTextures.find(aTextureId) ==
mExternalTextures.end());
UniquePtr<ExternalTexture> texture =
ExternalTexture::Create(aWidth, aHeight, aFormat);
if (!texture) {
return nullptr;
}
std::shared_ptr<ExternalTexture> shared(texture.release());
mExternalTextures.emplace(aTextureId, shared);
return shared;
}
std::shared_ptr<ExternalTexture> WebGPUParent::GetExternalTexture(
ffi::WGPUTextureId aId) {
auto it = mExternalTextures.find(aId);
if (it == mExternalTextures.end()) {
return nullptr;
}
return it->second;
}
} // namespace mozilla::webgpu

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

@ -6,6 +6,8 @@
#ifndef WEBGPU_PARENT_H_
#define WEBGPU_PARENT_H_
#include <unordered_map>
#include "mozilla/webgpu/ffi/wgpu.h"
#include "mozilla/webgpu/PWebGPUParent.h"
#include "mozilla/webrender/WebRenderAPI.h"
@ -22,6 +24,7 @@ class RemoteTextureOwnerClient;
namespace webgpu {
class ErrorBuffer;
class ExternalTexture;
class PresentationData;
class WebGPUParent final : public PWebGPUParent {
@ -75,7 +78,8 @@ class WebGPUParent final : public PWebGPUParent {
ipc::IPCResult RecvDeviceCreateSwapChain(
RawId aDeviceId, RawId aQueueId, const layers::RGBDescriptor& aDesc,
const nsTArray<RawId>& aBufferIds,
const layers::RemoteTextureOwnerId& aOwnerId);
const layers::RemoteTextureOwnerId& aOwnerId,
bool aUseExternalTextureInSwapChain);
ipc::IPCResult RecvDeviceCreateShaderModule(
RawId aDeviceId, RawId aModuleId, const nsString& aLabel,
const nsCString& aCode, DeviceCreateShaderModuleResolver&& aOutMessage);
@ -123,6 +127,21 @@ class WebGPUParent final : public PWebGPUParent {
BufferMapData* GetBufferMapData(RawId aBufferId);
bool UseExternalTextureForSwapChain(ffi::WGPUSwapChainId aSwapChainId);
bool CreateExternalTextureForSwapChain(ffi::WGPUSwapChainId aSwapChainId,
ffi::WGPUDeviceId aDeviceId,
ffi::WGPUTextureId aTextureId,
uint32_t aWidth, uint32_t aHeight,
struct ffi::WGPUTextureFormat aFormat);
std::shared_ptr<ExternalTexture> CreateExternalTexture(
ffi::WGPUDeviceId aDeviceId, ffi::WGPUTextureId aTextureId,
uint32_t aWidth, uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat);
std::shared_ptr<ExternalTexture> GetExternalTexture(ffi::WGPUTextureId aId);
private:
void DeallocBufferShmem(RawId aBufferId);
@ -154,6 +173,9 @@ class WebGPUParent final : public PWebGPUParent {
/// Associated stack of error scopes for each device.
std::unordered_map<uint64_t, std::vector<ErrorScope>>
mErrorScopeStackByDevice;
std::unordered_map<ffi::WGPUTextureId, std::shared_ptr<ExternalTexture>>
mExternalTextures;
};
} // namespace webgpu

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

@ -29,6 +29,7 @@ h_and_cpp = [
"Device",
"DeviceLostInfo",
"Error",
"ExternalTexture",
"Instance",
"InternalError",
"ObjectModel",
@ -69,6 +70,15 @@ UNIFIED_SOURCES += [
"ipc/WebGPUParent.cpp",
]
if CONFIG["MOZ_ENABLE_D3D10_LAYER"]:
DEFINES["MOZ_ENABLE_D3D10_LAYER"] = True
EXPORTS.mozilla.webgpu += [
"ExternalTextureD3D11.h",
]
UNIFIED_SOURCES += [
"ExternalTextureD3D11.cpp",
]
if CONFIG["CC_TYPE"] in ("clang", "clang-cl"):
CXXFLAGS += ["-Werror=implicit-int-conversion"]
CXXFLAGS += ["-Werror=switch"]

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

@ -54,6 +54,10 @@ package = "wgpu-hal"
git = "https://github.com/gfx-rs/wgpu"
rev = "332cd0325da52675432830870584ec9766679c34"
[target.'cfg(windows)'.dependencies]
d3d12 = "0.7.0"
winapi = "0.3"
[dependencies]
bincode = "1"
log = "0.4"

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

@ -8,6 +8,8 @@ use crate::{
QueueWriteAction, RawString, TextureAction,
};
use crate::SwapChainId;
use wgc::{id, identity::IdentityManager};
use wgt::{Backend, TextureFormat};
@ -504,6 +506,7 @@ pub extern "C" fn wgpu_client_create_texture(
client: &Client,
device_id: id::DeviceId,
desc: &wgt::TextureDescriptor<Option<&nsACString>, crate::FfiSlice<TextureFormat>>,
swap_chain_id: Option<&SwapChainId>,
bb: &mut ByteBuf,
) -> id::TextureId {
let label = wgpu_string(desc.label);
@ -521,6 +524,7 @@ pub extern "C" fn wgpu_client_create_texture(
let action = DeviceAction::CreateTexture(
id,
desc.map_label_and_view_formats(|_| label, |_| view_formats),
swap_chain_id.copied(),
);
*bb = make_byte_buf(&action);
@ -1250,3 +1254,24 @@ pub unsafe extern "C" fn wgpu_queue_write_texture(
pub extern "C" fn wgpu_texture_format_block_size_single_aspect(format: wgt::TextureFormat) -> u32 {
format.block_size(None).unwrap_or(0)
}
#[no_mangle]
pub extern "C" fn wgpu_client_use_external_texture_in_swapChain(
device_id: id::DeviceId,
format: wgt::TextureFormat,
) -> bool {
if device_id.backend() != wgt::Backend::Dx12 {
return false;
}
if !static_prefs::pref!("dom.webgpu.swap-chain.external-texture-dx12") {
return false;
}
let supported = match format {
wgt::TextureFormat::Bgra8Unorm => true,
_ => false,
};
supported
}

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

@ -118,7 +118,11 @@ struct ImplicitLayout<'a> {
#[derive(serde::Serialize, serde::Deserialize)]
enum DeviceAction<'a> {
CreateTexture(id::TextureId, wgc::resource::TextureDescriptor<'a>),
CreateTexture(
id::TextureId,
wgc::resource::TextureDescriptor<'a>,
Option<SwapChainId>,
),
CreateSampler(id::SamplerId, wgc::resource::SamplerDescriptor<'a>),
CreateBindGroupLayout(
id::BindGroupLayoutId,
@ -222,3 +226,7 @@ impl<'a> ImageDataLayout<'a> {
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct SwapChainId(pub u64);

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

@ -6,7 +6,7 @@ use crate::{
error::{ErrMsg, ErrorBuffer, ErrorBufferType},
identity::IdentityRecyclerFactory,
wgpu_string, AdapterInformation, ByteBuf, CommandEncoderAction, DeviceAction, DropAction,
QueueWriteAction, TextureAction,
QueueWriteAction, SwapChainId, TextureAction,
};
use nsstring::{nsACString, nsCString, nsString};
@ -15,9 +15,15 @@ use wgc::{gfx_select, id};
use wgc::{pipeline::CreateShaderModuleError, resource::BufferAccessError};
use std::borrow::Cow;
use std::os::raw::c_void;
use std::slice;
use std::sync::atomic::{AtomicU32, Ordering};
#[cfg(target_os = "windows")]
use winapi::um::d3d12 as d3d12_ty;
#[cfg(target_os = "windows")]
use winapi::Interface;
// The seemingly redundant u64 suffixes help cbindgen with generating the right C++ code.
// See https://github.com/mozilla/cbindgen/issues/849.
@ -42,17 +48,24 @@ fn restrict_limits(limits: wgt::Limits) -> wgt::Limits {
}
// hide wgc's global in private
pub struct Global(wgc::global::Global<IdentityRecyclerFactory>);
pub struct Global {
global: wgc::global::Global<IdentityRecyclerFactory>,
#[allow(dead_code)]
owner: *mut c_void,
}
impl std::ops::Deref for Global {
type Target = wgc::global::Global<IdentityRecyclerFactory>;
fn deref(&self) -> &Self::Target {
&self.0
&self.global
}
}
#[no_mangle]
pub extern "C" fn wgpu_server_new(factory: IdentityRecyclerFactory) -> *mut Global {
pub extern "C" fn wgpu_server_new(
factory: IdentityRecyclerFactory,
owner: *mut c_void,
) -> *mut Global {
log::info!("Initializing WGPU server");
let backends_pref = static_prefs::pref!("dom.webgpu.wgpu-backend").to_string();
let backends = if backends_pref.is_empty() {
@ -64,7 +77,7 @@ pub extern "C" fn wgpu_server_new(factory: IdentityRecyclerFactory) -> *mut Glob
);
wgc::instance::parse_backends_from_comma_list(&backends_pref)
};
let global = Global(wgc::global::Global::new(
let global = wgc::global::Global::new(
"wgpu",
factory,
wgt::InstanceDescriptor {
@ -72,7 +85,8 @@ pub extern "C" fn wgpu_server_new(factory: IdentityRecyclerFactory) -> *mut Glob
dx12_shader_compiler: wgt::Dx12Compiler::Fxc,
gles_minor_version: wgt::Gles3MinorVersion::Automatic,
},
));
);
let global = Global { global, owner };
Box::into_raw(Box::new(global))
}
@ -413,6 +427,29 @@ pub extern "C" fn wgpu_server_buffer_drop(global: &Global, self_id: id::BufferId
gfx_select!(self_id => global.buffer_drop(self_id, false));
}
extern "C" {
#[allow(dead_code)]
fn wgpu_server_use_external_texture_for_swap_chain(
param: *mut c_void,
swap_chain_id: SwapChainId,
) -> bool;
#[allow(dead_code)]
fn wgpu_server_create_external_texture_for_swap_chain(
param: *mut c_void,
swap_chain_id: SwapChainId,
device_id: id::DeviceId,
texture_id: id::TextureId,
width: u32,
height: u32,
format: wgt::TextureFormat,
) -> bool;
#[allow(dead_code)]
fn wgpu_server_get_external_texture_handle(
param: *mut c_void,
id: id::TextureId,
) -> *mut c_void;
}
impl Global {
fn device_action<A: wgc::hal_api::HalApi>(
&self,
@ -421,7 +458,7 @@ impl Global {
mut error_buf: ErrorBuffer,
) {
match action {
DeviceAction::CreateTexture(id, desc) => {
DeviceAction::CreateTexture(id, desc, swap_chain_id) => {
let max = MAX_TEXTURE_EXTENT;
if desc.size.width > max
|| desc.size.height > max
@ -434,6 +471,98 @@ impl Global {
});
return;
}
#[cfg(target_os = "windows")]
{
let use_external_texture = if swap_chain_id.is_some() {
unsafe {
wgpu_server_use_external_texture_for_swap_chain(
self.owner,
swap_chain_id.unwrap(),
)
}
} else {
false
};
if use_external_texture && self_id.backend() == wgt::Backend::Dx12 {
let ret = unsafe {
wgpu_server_create_external_texture_for_swap_chain(
self.owner,
swap_chain_id.unwrap(),
self_id,
id,
desc.size.width,
desc.size.height,
desc.format,
)
};
if ret != true {
error_buf.init(ErrMsg {
message: "Failed to create external texture",
r#type: ErrorBufferType::Internal,
});
}
let dx12_device = unsafe {
self.device_as_hal::<wgc::api::Dx12, _, d3d12::Device>(
self_id,
|hal_device| hal_device.unwrap().raw_device().clone(),
)
};
let handle =
unsafe { wgpu_server_get_external_texture_handle(self.owner, id) };
if handle.is_null() {
error_buf.init(ErrMsg {
message: "Failed to get external texture handle",
r#type: ErrorBufferType::Internal,
});
}
let mut resource = d3d12::Resource::null();
let hr = unsafe {
dx12_device.OpenSharedHandle(
handle,
&d3d12_ty::ID3D12Resource::uuidof(),
resource.mut_void(),
)
};
if hr != 0 {
error_buf.init(ErrMsg {
message: "Failed to open shared handle",
r#type: ErrorBufferType::Internal,
});
}
let hal_texture = unsafe {
<wgh::api::Dx12 as wgh::Api>::Device::texture_from_raw(
resource,
wgt::TextureFormat::Bgra8Unorm,
wgt::TextureDimension::D2,
desc.size,
1,
1,
)
};
let (_, error) = unsafe {
self.create_texture_from_hal::<wgh::api::Dx12>(
hal_texture,
self_id,
&desc,
id,
)
};
if let Some(err) = error {
error_buf.init(err);
}
return;
}
}
if swap_chain_id.is_some() && self_id.backend() != wgt::Backend::Dx12 {
debug_assert!(false, "Unexpected to be called");
}
let (_, error) = self.device_create_texture::<A>(self_id, &desc, id);
if let Some(err) = error {
error_buf.init(err);

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

@ -4614,6 +4614,12 @@
mirror: always
rust: true
- name: dom.webgpu.swap-chain.external-texture-dx12
type: RelaxedAtomicBool
value: false
mirror: always
rust: true
# Is support for HTMLInputElement.webkitEntries enabled?
- name: dom.webkitBlink.filesystem.enabled
type: bool