diff options
Diffstat (limited to 'dom/webgpu/Adapter.cpp')
-rw-r--r-- | dom/webgpu/Adapter.cpp | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/dom/webgpu/Adapter.cpp b/dom/webgpu/Adapter.cpp new file mode 100644 index 0000000000..ef857b70e8 --- /dev/null +++ b/dom/webgpu/Adapter.cpp @@ -0,0 +1,134 @@ +/* -*- 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 "mozilla/dom/WebGPUBinding.h" +#include "Adapter.h" + +#include "Device.h" +#include "Instance.h" +#include "SupportedFeatures.h" +#include "SupportedLimits.h" +#include "ipc/WebGPUChild.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/webgpu/ffi/wgpu.h" + +namespace mozilla::webgpu { + +GPU_IMPL_CYCLE_COLLECTION(Adapter, mParent, mBridge, mFeatures, mLimits) +GPU_IMPL_JS_WRAP(Adapter) + +Maybe<uint32_t> Adapter::MakeFeatureBits( + const dom::Sequence<dom::GPUFeatureName>& aFeatures) { + uint32_t bits = 0; + for (const auto& feature : aFeatures) { + if (feature == dom::GPUFeatureName::Depth_clip_control) { + bits |= WGPUFeatures_DEPTH_CLIP_CONTROL; + } else if (feature == dom::GPUFeatureName::Texture_compression_bc) { + bits |= WGPUFeatures_TEXTURE_COMPRESSION_BC; + } else if (feature == dom::GPUFeatureName::Indirect_first_instance) { + bits |= WGPUFeatures_INDIRECT_FIRST_INSTANCE; + } else { + NS_WARNING( + nsPrintfCString("Requested feature bit '%d' is not recognized.", + static_cast<int>(feature)) + .get()); + return Nothing(); + } + } + return Some(bits); +} + +Adapter::Adapter(Instance* const aParent, WebGPUChild* const aBridge, + const ffi::WGPUAdapterInformation& aInfo) + : ChildOf(aParent), + mBridge(aBridge), + mId(aInfo.id), + mFeatures(new SupportedFeatures(this)), + mLimits( + new SupportedLimits(this, MakeUnique<ffi::WGPULimits>(aInfo.limits))), + mIsFallbackAdapter(aInfo.ty == ffi::WGPUDeviceType_Cpu) { + ErrorResult result; // TODO: should this come from outside + // This list needs to match `AdapterRequestDevice` + if (aInfo.features & WGPUFeatures_DEPTH_CLIP_CONTROL) { + dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add( + mFeatures, u"depth-clip-control"_ns, result); + } + if (aInfo.features & WGPUFeatures_TEXTURE_COMPRESSION_BC) { + dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add( + mFeatures, u"texture-compression-bc"_ns, result); + } + if (aInfo.features & WGPUFeatures_INDIRECT_FIRST_INSTANCE) { + dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add( + mFeatures, u"indirect-first-instance"_ns, result); + } +} + +Adapter::~Adapter() { Cleanup(); } + +void Adapter::Cleanup() { + if (mValid && mBridge && mBridge->CanSend()) { + mValid = false; + mBridge->SendAdapterDestroy(mId); + } +} + +const RefPtr<SupportedFeatures>& Adapter::Features() const { return mFeatures; } +const RefPtr<SupportedLimits>& Adapter::Limits() const { return mLimits; } + +already_AddRefed<dom::Promise> Adapter::RequestDevice( + const dom::GPUDeviceDescriptor& aDesc, ErrorResult& aRv) { + RefPtr<dom::Promise> promise = dom::Promise::Create(GetParentObject(), aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + if (!mBridge->CanSend()) { + promise->MaybeRejectWithInvalidStateError( + "WebGPUChild cannot send, must recreate Adapter"); + return promise.forget(); + } + + ffi::WGPULimits limits = {}; + auto request = mBridge->AdapterRequestDevice(mId, aDesc, &limits); + if (request) { + RefPtr<Device> device = + new Device(this, request->mId, MakeUnique<ffi::WGPULimits>(limits)); + // copy over the features + for (const auto& feature : aDesc.mRequiredFeatures) { + NS_ConvertASCIItoUTF16 string( + dom::GPUFeatureNameValues::GetString(feature)); + dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add(device->mFeatures, + string, aRv); + } + + request->mPromise->Then( + GetCurrentSerialEventTarget(), __func__, + [promise, device](bool aSuccess) { + if (aSuccess) { + promise->MaybeResolve(device); + } else { + // In this path, request->mId has an error entry in the wgpu + // registry, so let Device::~Device clean things up on both the + // child and parent side. + promise->MaybeRejectWithInvalidStateError( + "Unable to fulfill requested features and limits"); + } + }, + [promise, device](const ipc::ResponseRejectReason& aReason) { + // We can't be sure how far along the WebGPUParent got in handling + // our AdapterRequestDevice message, but we can't communicate with it, + // so clear up our client state for this Device without trying to + // communicate with the parent about it. + device->CleanupUnregisteredInParent(); + promise->MaybeRejectWithNotSupportedError("IPC error"); + }); + } else { + promise->MaybeRejectWithNotSupportedError("Unable to instantiate a Device"); + } + + return promise.forget(); +} + +} // namespace mozilla::webgpu |