Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions packages/webgpu/cpp/rnwgpu/api/GPUAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,35 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
deviceLostBinding,
creationRuntime](const async::AsyncTaskHandle::ResolveFunction &resolve,
const async::AsyncTaskHandle::RejectFunction &reject) {
(void)descriptor;
// Build a local mutable copy so we can chain Dawn's device toggles.
// The toggle name strings are owned by `descriptor` (captured above),
// and the const char* / DawnTogglesDescriptor locals live for the
// whole synchronous RequestDevice call below, which is when Dawn reads
// the chained struct.
wgpu::DeviceDescriptor deviceDesc = aDescriptor;
wgpu::DawnTogglesDescriptor toggles{};
std::vector<const char *> enabledToggles;
std::vector<const char *> disabledToggles;
if (descriptor.has_value() && descriptor.value()->dawnToggles) {
const auto &dawnToggles = descriptor.value()->dawnToggles.value();
if (dawnToggles->enabledToggles) {
for (const auto &t : dawnToggles->enabledToggles.value()) {
enabledToggles.push_back(t.c_str());
}
toggles.enabledToggleCount = enabledToggles.size();
toggles.enabledToggles = enabledToggles.data();
}
if (dawnToggles->disabledToggles) {
for (const auto &t : dawnToggles->disabledToggles.value()) {
disabledToggles.push_back(t.c_str());
}
toggles.disabledToggleCount = disabledToggles.size();
toggles.disabledToggles = disabledToggles.data();
}
deviceDesc.nextInChain = &toggles;
}
_instance.RequestDevice(
&aDescriptor, wgpu::CallbackMode::AllowProcessEvents,
&deviceDesc, wgpu::CallbackMode::AllowProcessEvents,
[asyncRunner = _async, resolve, reject, label, creationRuntime,
deviceLostBinding](wgpu::RequestDeviceStatus status,
wgpu::Device device,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#pragma once

#include <memory>
#include <string>
#include <vector>

#include "webgpu/webgpu_cpp.h"

#include "JSIConverter.h"
#include "WGPULogger.h"

namespace jsi = facebook::jsi;

namespace rnwgpu {

// Non-standard, Dawn-only. Mirrors wgpu::DawnTogglesDescriptor field-for-field
// so the mapping to the native chained struct is 1:1. Chained onto the
// wgpu::DeviceDescriptor in GPUAdapter::requestDevice.
struct GPUDawnTogglesDescriptor {
std::optional<std::vector<std::string>> enabledToggles; // Iterable<string>
std::optional<std::vector<std::string>> disabledToggles; // Iterable<string>
};

} // namespace rnwgpu

namespace rnwgpu {

template <>
struct JSIConverter<std::shared_ptr<rnwgpu::GPUDawnTogglesDescriptor>> {
static std::shared_ptr<rnwgpu::GPUDawnTogglesDescriptor>
fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) {
auto result = std::make_unique<rnwgpu::GPUDawnTogglesDescriptor>();
if (!outOfBounds && arg.isObject()) {
auto value = arg.getObject(runtime);
if (value.hasProperty(runtime, "enabledToggles")) {
auto prop = value.getProperty(runtime, "enabledToggles");
result->enabledToggles =
JSIConverter<std::optional<std::vector<std::string>>>::fromJSI(
runtime, prop, false);
}
if (value.hasProperty(runtime, "disabledToggles")) {
auto prop = value.getProperty(runtime, "disabledToggles");
result->disabledToggles =
JSIConverter<std::optional<std::vector<std::string>>>::fromJSI(
runtime, prop, false);
}
}
return result;
}
static jsi::Value
toJSI(jsi::Runtime &runtime,
std::shared_ptr<rnwgpu::GPUDawnTogglesDescriptor> arg) {
throw std::runtime_error("Invalid GPUDawnTogglesDescriptor::toJSI()");
}
};

} // namespace rnwgpu
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "RnFeatures.h"
#include "WGPULogger.h"

#include "GPUDawnTogglesDescriptor.h"
#include "GPUQueueDescriptor.h"

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

} // namespace rnwgpu
Expand Down
41 changes: 41 additions & 0 deletions packages/webgpu/src/__tests__/DawnToggles.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { client } from "./setup";

describe("Dawn toggles", () => {
it("requests a device with enabled and disabled dawnToggles", async () => {
const result = await client.eval(({ gpu }) => {
return gpu.requestAdapter().then((adapter) =>
adapter!
.requestDevice({
dawnToggles: {
enabledToggles: ["disable_symbol_renaming"],
disabledToggles: ["lazy_clear_resource_on_first_use"],
},
})
.then((device) => !!device),
);
});
expect(result).toBe(true);
});

it("requests a device with no dawnToggles (unchanged behavior)", async () => {
const result = await client.eval(({ gpu }) => {
return gpu
.requestAdapter()
.then((adapter) => adapter!.requestDevice().then((device) => !!device));
});
expect(result).toBe(true);
});

it("ignores unknown toggle names without failing device creation", async () => {
const result = await client.eval(({ gpu }) => {
return gpu.requestAdapter().then((adapter) =>
adapter!
.requestDevice({
dawnToggles: { enabledToggles: ["this_toggle_does_not_exist"] },
})
.then((device) => !!device),
);
});
expect(result).toBe(true);
});
});
7 changes: 7 additions & 0 deletions packages/webgpu/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="@webgpu/types" />
import type {
GPUDawnTogglesDescriptor,
GPUSharedTextureMemory,
GPUSharedTextureMemoryDescriptor,
NativeCanvas,
Expand All @@ -17,6 +18,7 @@ export type {
CreateVideoPlayerOptions,
GPUSharedTextureMemory,
GPUSharedTextureMemoryDescriptor,
GPUDawnTogglesDescriptor,
} from "./types";

declare global {
Expand Down Expand Up @@ -56,6 +58,11 @@ declare global {
): GPUSharedTextureMemory;
}

// Non-standard, Dawn-only. Lets callers set Dawn device-stage toggles at
// device creation: adapter.requestDevice({ dawnToggles: { ... } }).
interface GPUDeviceDescriptor {
dawnToggles?: GPUDawnTogglesDescriptor;
}
// Non-spec extension: camera frames arrive in the sensor's native
// orientation, which differs between iOS and Android. `rotation` (degrees,
// one of 0/90/180/270) and `mirrored` (horizontal flip) are baked into the
Expand Down
11 changes: 11 additions & 0 deletions packages/webgpu/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ export interface GPUSharedTextureMemoryDescriptor {
label?: string;
}

// Non-standard, Dawn-only device toggles. Mirrors Dawn's DawnTogglesDescriptor
// and is chained onto the native device descriptor at requestDevice time.
// Pass it via the (augmented) GPUDeviceDescriptor: adapter.requestDevice({
// dawnToggles: { enabledToggles: ["dump_shaders"] } }). Toggle names are open
// strings (see Dawn's Toggles.cpp); these flags are Dawn-specific and
// non-portable.
export interface GPUDawnTogglesDescriptor {
enabledToggles?: string[];
disabledToggles?: string[];
}

// A piece of shared GPU memory backed by a native surface. Use createTexture()
// to obtain a regular GPUTexture that aliases the surface's pixels. The
// returned texture must be bracketed by beginAccess/endAccess around any
Expand Down
Loading