Skip to content

Commit 730010c

Browse files
feat(🗿): add Dawn device toggles via dawnToggles (#374)
Co-authored-by: William Candillon <wcandillon@gmail.com>
1 parent 9c84ecb commit 730010c

6 files changed

Lines changed: 148 additions & 2 deletions

File tree

‎packages/webgpu/cpp/rnwgpu/api/GPUAdapter.cpp‎

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,35 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
135135
deviceLostBinding,
136136
creationRuntime](const async::AsyncTaskHandle::ResolveFunction &resolve,
137137
const async::AsyncTaskHandle::RejectFunction &reject) {
138-
(void)descriptor;
138+
// Build a local mutable copy so we can chain Dawn's device toggles.
139+
// The toggle name strings are owned by `descriptor` (captured above),
140+
// and the const char* / DawnTogglesDescriptor locals live for the
141+
// whole synchronous RequestDevice call below, which is when Dawn reads
142+
// the chained struct.
143+
wgpu::DeviceDescriptor deviceDesc = aDescriptor;
144+
wgpu::DawnTogglesDescriptor toggles{};
145+
std::vector<const char *> enabledToggles;
146+
std::vector<const char *> disabledToggles;
147+
if (descriptor.has_value() && descriptor.value()->dawnToggles) {
148+
const auto &dawnToggles = descriptor.value()->dawnToggles.value();
149+
if (dawnToggles->enabledToggles) {
150+
for (const auto &t : dawnToggles->enabledToggles.value()) {
151+
enabledToggles.push_back(t.c_str());
152+
}
153+
toggles.enabledToggleCount = enabledToggles.size();
154+
toggles.enabledToggles = enabledToggles.data();
155+
}
156+
if (dawnToggles->disabledToggles) {
157+
for (const auto &t : dawnToggles->disabledToggles.value()) {
158+
disabledToggles.push_back(t.c_str());
159+
}
160+
toggles.disabledToggleCount = disabledToggles.size();
161+
toggles.disabledToggles = disabledToggles.data();
162+
}
163+
deviceDesc.nextInChain = &toggles;
164+
}
139165
_instance.RequestDevice(
140-
&aDescriptor, wgpu::CallbackMode::AllowProcessEvents,
166+
&deviceDesc, wgpu::CallbackMode::AllowProcessEvents,
141167
[asyncRunner = _async, resolve, reject, label, creationRuntime,
142168
deviceLostBinding](wgpu::RequestDeviceStatus status,
143169
wgpu::Device device,
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#pragma once
2+
3+
#include <memory>
4+
#include <string>
5+
#include <vector>
6+
7+
#include "webgpu/webgpu_cpp.h"
8+
9+
#include "JSIConverter.h"
10+
#include "WGPULogger.h"
11+
12+
namespace jsi = facebook::jsi;
13+
14+
namespace rnwgpu {
15+
16+
// Non-standard, Dawn-only. Mirrors wgpu::DawnTogglesDescriptor field-for-field
17+
// so the mapping to the native chained struct is 1:1. Chained onto the
18+
// wgpu::DeviceDescriptor in GPUAdapter::requestDevice.
19+
struct GPUDawnTogglesDescriptor {
20+
std::optional<std::vector<std::string>> enabledToggles; // Iterable<string>
21+
std::optional<std::vector<std::string>> disabledToggles; // Iterable<string>
22+
};
23+
24+
} // namespace rnwgpu
25+
26+
namespace rnwgpu {
27+
28+
template <>
29+
struct JSIConverter<std::shared_ptr<rnwgpu::GPUDawnTogglesDescriptor>> {
30+
static std::shared_ptr<rnwgpu::GPUDawnTogglesDescriptor>
31+
fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) {
32+
auto result = std::make_unique<rnwgpu::GPUDawnTogglesDescriptor>();
33+
if (!outOfBounds && arg.isObject()) {
34+
auto value = arg.getObject(runtime);
35+
if (value.hasProperty(runtime, "enabledToggles")) {
36+
auto prop = value.getProperty(runtime, "enabledToggles");
37+
result->enabledToggles =
38+
JSIConverter<std::optional<std::vector<std::string>>>::fromJSI(
39+
runtime, prop, false);
40+
}
41+
if (value.hasProperty(runtime, "disabledToggles")) {
42+
auto prop = value.getProperty(runtime, "disabledToggles");
43+
result->disabledToggles =
44+
JSIConverter<std::optional<std::vector<std::string>>>::fromJSI(
45+
runtime, prop, false);
46+
}
47+
}
48+
return result;
49+
}
50+
static jsi::Value
51+
toJSI(jsi::Runtime &runtime,
52+
std::shared_ptr<rnwgpu::GPUDawnTogglesDescriptor> arg) {
53+
throw std::runtime_error("Invalid GPUDawnTogglesDescriptor::toJSI()");
54+
}
55+
};
56+
57+
} // namespace rnwgpu

‎packages/webgpu/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "RnFeatures.h"
1212
#include "WGPULogger.h"
1313

14+
#include "GPUDawnTogglesDescriptor.h"
1415
#include "GPUQueueDescriptor.h"
1516

1617
namespace jsi = facebook::jsi;
@@ -25,6 +26,9 @@ struct GPUDeviceDescriptor {
2526
std::optional<std::shared_ptr<GPUQueueDescriptor>>
2627
defaultQueue; // GPUQueueDescriptor
2728
std::optional<std::string> label; // string
29+
// Non-standard Dawn-only device toggles, chained onto the wgpu::Device
30+
// descriptor in GPUAdapter::requestDevice.
31+
std::optional<std::shared_ptr<GPUDawnTogglesDescriptor>> dawnToggles;
2832
};
2933

3034
} // namespace rnwgpu
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { client } from "./setup";
2+
3+
describe("Dawn toggles", () => {
4+
it("requests a device with enabled and disabled dawnToggles", async () => {
5+
const result = await client.eval(({ gpu }) => {
6+
return gpu.requestAdapter().then((adapter) =>
7+
adapter!
8+
.requestDevice({
9+
dawnToggles: {
10+
enabledToggles: ["disable_symbol_renaming"],
11+
disabledToggles: ["lazy_clear_resource_on_first_use"],
12+
},
13+
})
14+
.then((device) => !!device),
15+
);
16+
});
17+
expect(result).toBe(true);
18+
});
19+
20+
it("requests a device with no dawnToggles (unchanged behavior)", async () => {
21+
const result = await client.eval(({ gpu }) => {
22+
return gpu
23+
.requestAdapter()
24+
.then((adapter) => adapter!.requestDevice().then((device) => !!device));
25+
});
26+
expect(result).toBe(true);
27+
});
28+
29+
it("ignores unknown toggle names without failing device creation", async () => {
30+
const result = await client.eval(({ gpu }) => {
31+
return gpu.requestAdapter().then((adapter) =>
32+
adapter!
33+
.requestDevice({
34+
dawnToggles: { enabledToggles: ["this_toggle_does_not_exist"] },
35+
})
36+
.then((device) => !!device),
37+
);
38+
});
39+
expect(result).toBe(true);
40+
});
41+
});

‎packages/webgpu/src/index.tsx‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference types="@webgpu/types" />
22
import type {
3+
GPUDawnTogglesDescriptor,
34
GPUSharedTextureMemory,
45
GPUSharedTextureMemoryDescriptor,
56
NativeCanvas,
@@ -17,6 +18,7 @@ export type {
1718
CreateVideoPlayerOptions,
1819
GPUSharedTextureMemory,
1920
GPUSharedTextureMemoryDescriptor,
21+
GPUDawnTogglesDescriptor,
2022
} from "./types";
2123

2224
declare global {
@@ -56,6 +58,11 @@ declare global {
5658
): GPUSharedTextureMemory;
5759
}
5860

61+
// Non-standard, Dawn-only. Lets callers set Dawn device-stage toggles at
62+
// device creation: adapter.requestDevice({ dawnToggles: { ... } }).
63+
interface GPUDeviceDescriptor {
64+
dawnToggles?: GPUDawnTogglesDescriptor;
65+
}
5966
// Non-spec extension: camera frames arrive in the sensor's native
6067
// orientation, which differs between iOS and Android. `rotation` (degrees,
6168
// one of 0/90/180/270) and `mirrored` (horizontal flip) are baked into the

‎packages/webgpu/src/types.ts‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ export interface GPUSharedTextureMemoryDescriptor {
7575
label?: string;
7676
}
7777

78+
// Non-standard, Dawn-only device toggles. Mirrors Dawn's DawnTogglesDescriptor
79+
// and is chained onto the native device descriptor at requestDevice time.
80+
// Pass it via the (augmented) GPUDeviceDescriptor: adapter.requestDevice({
81+
// dawnToggles: { enabledToggles: ["dump_shaders"] } }). Toggle names are open
82+
// strings (see Dawn's Toggles.cpp); these flags are Dawn-specific and
83+
// non-portable.
84+
export interface GPUDawnTogglesDescriptor {
85+
enabledToggles?: string[];
86+
disabledToggles?: string[];
87+
}
88+
7889
// A piece of shared GPU memory backed by a native surface. Use createTexture()
7990
// to obtain a regular GPUTexture that aliases the surface's pixels. The
8091
// returned texture must be bracketed by beginAccess/endAccess around any

0 commit comments

Comments
 (0)