1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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
|