summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/Adapter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webgpu/Adapter.cpp')
-rw-r--r--dom/webgpu/Adapter.cpp231
1 files changed, 231 insertions, 0 deletions
diff --git a/dom/webgpu/Adapter.cpp b/dom/webgpu/Adapter.cpp
new file mode 100644
index 0000000000..381378206b
--- /dev/null
+++ b/dom/webgpu/Adapter.cpp
@@ -0,0 +1,231 @@
+/* -*- 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/BindingDeclarations.h"
+#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 {
+
+bool AdapterInfo::WrapObject(JSContext* const cx,
+ JS::Handle<JSObject*> givenProto,
+ JS::MutableHandle<JSObject*> reflector) {
+ return dom::GPUAdapterInfo_Binding::Wrap(cx, this, givenProto, reflector);
+}
+
+void AdapterInfo::GetWgpuName(nsString& s) const {
+ s = mAboutSupportInfo->name;
+}
+
+uint32_t AdapterInfo::WgpuVendor() const { return mAboutSupportInfo->vendor; }
+
+uint32_t AdapterInfo::WgpuDevice() const { return mAboutSupportInfo->device; }
+
+void AdapterInfo::GetWgpuDeviceType(nsString& s) const {
+ switch (mAboutSupportInfo->device_type) {
+ case ffi::WGPUDeviceType_Cpu:
+ s.AssignLiteral("Cpu");
+ return;
+ case ffi::WGPUDeviceType_DiscreteGpu:
+ s.AssignLiteral("DiscreteGpu");
+ return;
+ case ffi::WGPUDeviceType_IntegratedGpu:
+ s.AssignLiteral("IntegratedGpu");
+ return;
+ case ffi::WGPUDeviceType_VirtualGpu:
+ s.AssignLiteral("VirtualGpu");
+ return;
+ case ffi::WGPUDeviceType_Other:
+ s.AssignLiteral("Other");
+ return;
+ case ffi::WGPUDeviceType_Sentinel:
+ break;
+ }
+ MOZ_CRASH("Bad `ffi::WGPUDeviceType`");
+}
+
+void AdapterInfo::GetWgpuDriver(nsString& s) const {
+ s = mAboutSupportInfo->driver;
+}
+
+void AdapterInfo::GetWgpuDriverInfo(nsString& s) const {
+ s = mAboutSupportInfo->driver_info;
+}
+
+void AdapterInfo::GetWgpuBackend(nsString& s) const {
+ switch (mAboutSupportInfo->backend) {
+ case ffi::WGPUBackend_Empty:
+ s.AssignLiteral("Empty");
+ return;
+ case ffi::WGPUBackend_Vulkan:
+ s.AssignLiteral("Vulkan");
+ return;
+ case ffi::WGPUBackend_Metal:
+ s.AssignLiteral("Metal");
+ return;
+ case ffi::WGPUBackend_Dx12:
+ s.AssignLiteral("Dx12");
+ return;
+ case ffi::WGPUBackend_Dx11:
+ s.AssignLiteral("Dx11");
+ return;
+ case ffi::WGPUBackend_Gl:
+ s.AssignLiteral("Gl");
+ return;
+ case ffi::WGPUBackend_BrowserWebGpu: // This should never happen, because
+ // we _are_ the browser.
+ case ffi::WGPUBackend_Sentinel:
+ break;
+ }
+ MOZ_CRASH("Bad `ffi::WGPUBackend`");
+}
+
+// -
+
+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 if (feature == dom::GPUFeatureName::Depth32float_stencil8) {
+ bits |= WGPUFeatures_DEPTH32FLOAT_STENCIL8;
+ } 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 std::shared_ptr<ffi::WGPUAdapterInformation>& aInfo)
+ : ChildOf(aParent),
+ mBridge(aBridge),
+ mId(aInfo->id),
+ mFeatures(new SupportedFeatures(this)),
+ mLimits(new SupportedLimits(this,
+ MakeUnique<ffi::WGPULimits>(aInfo->limits))),
+ mInfo(aInfo) {
+ 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);
+ }
+ if (aInfo->features & WGPUFeatures_DEPTH32FLOAT_STENCIL8) {
+ dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add(
+ mFeatures, u"depth32float-stencil8"_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; }
+bool Adapter::IsFallbackAdapter() const {
+ return mInfo->device_type == ffi::WGPUDeviceType::WGPUDeviceType_Cpu;
+}
+
+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();
+}
+
+// -
+
+already_AddRefed<dom::Promise> Adapter::RequestAdapterInfo(
+ const dom::Sequence<nsString>& /*aUnmaskHints*/, ErrorResult& aRv) const {
+ RefPtr<dom::Promise> promise = dom::Promise::Create(GetParentObject(), aRv);
+ if (!promise) return nullptr;
+
+ auto rai = UniquePtr<AdapterInfo>{new AdapterInfo(mInfo)};
+ promise->MaybeResolve(std::move(rai));
+ return promise.forget();
+}
+
+} // namespace mozilla::webgpu