Skip to content

Commit bec8376

Browse files
committed
Update
[ghstack-poisoned]
2 parents c5ff88f + 2ab8691 commit bec8376

4 files changed

Lines changed: 62 additions & 69 deletions

File tree

.ci/scripts/setup-webgpu-linux-deps.sh

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
# * Dawn : Google's official nightly prebuilt, downloaded directly from
1111
# github.com/google/dawn/releases (pinned tag+rev+sha256) -- the same
1212
# "fetch a pinned upstream prebuilt" pattern used for other CI deps.
13-
# * SwiftShader : reuse the prebuilt ALREADY on the ossci-android bucket (the one
14-
# setup-vulkan-linux-deps.sh uses). No new S3 uploads anywhere.
13+
# * SwiftShader : built from source at a pinned rev compatible with the Dawn
14+
# above (the ossci prebuilt is from 2020, too old for current Dawn). No S3.
1515
# Dawn (Chrome's WebGPU impl; its WGSL compiler Tint is the spec reference) on
1616
# SwiftShader gives a headless, deterministic, spec-faithful CLI backend.
1717
#
@@ -24,7 +24,9 @@ set -ex
2424
DAWN_TAG="${DAWN_TAG:-v20260423.175430}"
2525
DAWN_REV="${DAWN_REV:-31e25af254ab572c77054edec4946d2244e184dd}"
2626
DAWN_SHA256="${DAWN_SHA256:-ac76fac090162dc1ecea5ed0f28a557bb8f49efc47faab01886105ace82b7b64}"
27-
SWIFTSHADER_ARCHIVE="${SWIFTSHADER_ARCHIVE:-swiftshader-abe07b943-prebuilt.tar.gz}"
27+
# SwiftShader rev verified compatible with DAWN_REV (the old ossci prebuilt is
28+
# from 2020 and is incompatible with current Dawn -> no adapter / zero compute).
29+
SWIFTSHADER_REV="${SWIFTSHADER_REV:-9898204d91d6a60b6a08ad74fe4ac52a6913111b}"
2830

2931
_dawn_dir="${DAWN_PREBUILT_DIR:-/tmp/dawn-ci}"
3032
_ss_dir=/tmp/swiftshader
@@ -68,16 +70,28 @@ if [[ ! -d "${_dawn_dir}/lib64/cmake/Dawn" ]]; then
6870
tar -C "${_dawn_dir}" --strip-components=1 -xzf "${_dawn_tar}"
6971
fi
7072

71-
# --- SwiftShader: reuse the existing ossci prebuilt (no new upload) -----------
72-
if [[ ! -f "${_ss_dir}/swiftshader/build/Linux/vk_swiftshader_icd.json" ]]; then
73-
_ss_aws=https://ossci-android.s3.amazonaws.com
74-
mkdir -p "${_ss_dir}"
75-
curl --silent --show-error --location --fail --retry 3 --retry-all-errors \
76-
--output "/tmp/${SWIFTSHADER_ARCHIVE}" "${_ss_aws}/${SWIFTSHADER_ARCHIVE}"
77-
tar -C "${_ss_dir}" -xzf "/tmp/${SWIFTSHADER_ARCHIVE}"
73+
# --- SwiftShader: build from source at a pinned rev (no S3) -------------------
74+
# The old ossci prebuilt (swiftshader-abe07b943, 2020) is incompatible with the
75+
# current Dawn; build a matching modern SwiftShader instead. Self-contained
76+
# cmake build (vendored LLVM); the ICD lands under build/<OS>/.
77+
if [[ ! -d "${_ss_dir}/build" ]]; then
78+
if [[ ! -d "${_ss_dir}/.git" ]]; then
79+
git clone https://github.com/google/swiftshader "${_ss_dir}"
80+
fi
81+
git -C "${_ss_dir}" checkout "${SWIFTSHADER_REV}"
82+
# vk_swiftshader's deps are vendored in-tree; tolerate unreachable
83+
# disabled-feature submodules (angle, test-only) failing to fetch.
84+
git -C "${_ss_dir}" submodule update --init --recursive || true
85+
cmake -S "${_ss_dir}" -B "${_ss_dir}/build" -DCMAKE_BUILD_TYPE=Release \
86+
-DSWIFTSHADER_BUILD_TESTS=OFF -DSWIFTSHADER_BUILD_PVR=OFF \
87+
-DSWIFTSHADER_BUILD_BENCHMARKS=OFF
88+
cmake --build "${_ss_dir}/build" --parallel "$(nproc)" --target vk_swiftshader
7889
fi
90+
_ss_icd="$(find "${_ss_dir}/build" -name vk_swiftshader_icd.json 2>/dev/null | head -1)"
91+
[[ -n "${_ss_icd}" ]] || { echo "ERROR: SwiftShader ICD not found after build" >&2; exit 1; }
7992

93+
_ss_libdir="$(dirname "${_ss_icd}")"
8094
export Dawn_DIR="${_dawn_dir}/lib64/cmake/Dawn"
81-
export VK_ICD_FILENAMES="${_ss_dir}/swiftshader/build/Linux/vk_swiftshader_icd.json"
82-
export LD_LIBRARY_PATH="${_ss_dir}/swiftshader/build/Linux/:${LD_LIBRARY_PATH:-}"
95+
export VK_ICD_FILENAMES="${_ss_icd}"
96+
export LD_LIBRARY_PATH="${_ss_libdir}:${LD_LIBRARY_PATH:-}"
8397
export WEBGPU_USING_SWIFTSHADER=1

backends/webgpu/runtime/WebGPUCompat.h

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,15 @@
1010

1111
#include <webgpu/webgpu.h>
1212

13-
#if defined(__EMSCRIPTEN__)
14-
#include <emscripten/emscripten.h>
15-
#else
16-
#include <chrono>
17-
#include <thread>
18-
#endif
13+
#include <cstdint>
1914

2015
namespace executorch::backends::webgpu {
2116

22-
// Make progress on pending WebGPU callbacks; callers loop until their done flag
23-
// is set. Native (Dawn): pump the event queue + brief yield (no busy-spin).
24-
// Browser: yield to the JS event loop.
25-
inline void webgpu_poll(WGPUInstance instance) {
26-
#if defined(__EMSCRIPTEN__)
27-
(void)instance;
28-
emscripten_sleep(0);
29-
#else
30-
wgpuInstanceProcessEvents(instance);
31-
std::this_thread::sleep_for(std::chrono::microseconds(50));
32-
#endif
17+
// Caller's instance must enable TimedWaitAny; returns the WaitAny status.
18+
inline WGPUWaitStatus webgpu_wait(WGPUInstance instance, WGPUFuture future) {
19+
WGPUFutureWaitInfo info = {};
20+
info.future = future;
21+
return wgpuInstanceWaitAny(instance, 1, &info, UINT64_MAX);
3322
}
3423

3524
} // namespace executorch::backends::webgpu

backends/webgpu/runtime/WebGPUDevice.cpp

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,10 @@ namespace {
2222

2323
struct AdapterResult {
2424
WGPUAdapter adapter = nullptr;
25-
bool done = false;
2625
};
2726

2827
struct DeviceResult {
2928
WGPUDevice device = nullptr;
30-
bool done = false;
3129
};
3230

3331
void on_adapter_request(
@@ -47,7 +45,6 @@ void on_adapter_request(
4745
static_cast<int>(message.length),
4846
message.data);
4947
}
50-
result->done = true;
5148
}
5249

5350
void on_device_request(
@@ -67,7 +64,6 @@ void on_device_request(
6764
static_cast<int>(message.length),
6865
message.data);
6966
}
70-
result->done = true;
7167
}
7268

7369
void on_device_error(
@@ -89,34 +85,36 @@ void on_device_error(
8985
WebGPUContext create_webgpu_context() {
9086
WebGPUContext ctx;
9187

92-
ctx.instance = wgpuCreateInstance(nullptr);
88+
// TimedWaitAny lets webgpu_wait() block on futures via wgpuInstanceWaitAny.
89+
WGPUInstanceDescriptor instance_desc = {};
90+
#if defined(__EMSCRIPTEN__)
91+
instance_desc.capabilities.timedWaitAnyEnable = true;
92+
instance_desc.capabilities.timedWaitAnyMaxCount = 1;
93+
#else
94+
WGPUInstanceFeatureName features[1] = {WGPUInstanceFeatureName_TimedWaitAny};
95+
instance_desc.requiredFeatureCount = 1;
96+
instance_desc.requiredFeatures = features;
97+
#endif
98+
ctx.instance = wgpuCreateInstance(&instance_desc);
9399
if (!ctx.instance) {
94100
throw std::runtime_error("Failed to create WebGPU instance");
95101
}
96102

97-
// Request adapter using AllowSpontaneous mode (fires during
98-
// wgpuInstanceProcessEvents or any other API call).
99103
AdapterResult adapter_result;
100104
WGPURequestAdapterCallbackInfo adapter_cb = {};
101-
adapter_cb.mode = WGPUCallbackMode_AllowSpontaneous;
105+
adapter_cb.mode = WGPUCallbackMode_WaitAnyOnly;
102106
adapter_cb.callback = on_adapter_request;
103107
adapter_cb.userdata1 = &adapter_result;
104108

105-
// Release Dawn has no bundled fallback adapter; pick the platform backend
106-
// (Metal on Apple, Vulkan elsewhere -- SwiftShader via VK_ICD_FILENAMES).
109+
// No backend pin or forced fallback; Dawn auto-selects the adapter.
107110
WGPURequestAdapterOptions adapter_opts = {};
108-
#if defined(__APPLE__)
109-
adapter_opts.backendType = WGPUBackendType_Metal;
110-
#else
111-
adapter_opts.backendType = WGPUBackendType_Vulkan;
112-
#endif
111+
adapter_opts.powerPreference = WGPUPowerPreference_HighPerformance;
113112
adapter_opts.forceFallbackAdapter = false;
114-
wgpuInstanceRequestAdapter(ctx.instance, &adapter_opts, adapter_cb);
115-
while (!adapter_result.done) {
116-
webgpu_poll(ctx.instance);
117-
}
113+
WGPUWaitStatus adapter_wait = webgpu_wait(
114+
ctx.instance,
115+
wgpuInstanceRequestAdapter(ctx.instance, &adapter_opts, adapter_cb));
118116

119-
if (!adapter_result.adapter) {
117+
if (adapter_wait != WGPUWaitStatus_Success || !adapter_result.adapter) {
120118
wgpuInstanceRelease(ctx.instance);
121119
ctx.instance = nullptr;
122120
throw std::runtime_error(
@@ -128,7 +126,7 @@ WebGPUContext create_webgpu_context() {
128126
// Request device
129127
DeviceResult device_result;
130128
WGPURequestDeviceCallbackInfo device_cb = {};
131-
device_cb.mode = WGPUCallbackMode_AllowSpontaneous;
129+
device_cb.mode = WGPUCallbackMode_WaitAnyOnly;
132130
device_cb.callback = on_device_request;
133131
device_cb.userdata1 = &device_result;
134132

@@ -141,12 +139,11 @@ WebGPUContext create_webgpu_context() {
141139
}
142140
device_desc.uncapturedErrorCallbackInfo.callback = on_device_error;
143141

144-
wgpuAdapterRequestDevice(ctx.adapter, &device_desc, device_cb);
145-
while (!device_result.done) {
146-
webgpu_poll(ctx.instance);
147-
}
142+
WGPUWaitStatus device_wait = webgpu_wait(
143+
ctx.instance,
144+
wgpuAdapterRequestDevice(ctx.adapter, &device_desc, device_cb));
148145

149-
if (!device_result.device) {
146+
if (device_wait != WGPUWaitStatus_Success || !device_result.device) {
150147
wgpuAdapterRelease(ctx.adapter);
151148
wgpuInstanceRelease(ctx.instance);
152149
ctx.adapter = nullptr;

backends/webgpu/runtime/WebGPUGraph.cpp

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,6 @@ void WebGPUGraph::execute() {
471471
namespace {
472472

473473
struct MapCallbackData {
474-
bool done = false;
475474
WGPUMapAsyncStatus status = WGPUMapAsyncStatus_Error;
476475
};
477476

@@ -482,7 +481,6 @@ void buffer_map_callback(
482481
void* /*userdata2*/) {
483482
auto* data = static_cast<MapCallbackData*>(userdata1);
484483
data->status = status;
485-
data->done = true;
486484
}
487485

488486
} // namespace
@@ -491,34 +489,29 @@ void WebGPUGraph::copy_outputs(std::vector<std::pair<void*, size_t>>& outputs) {
491489
const size_t count = std::min(outputs.size(), output_staging_buffers_.size());
492490

493491
std::vector<MapCallbackData> cb_data(count);
492+
std::vector<WGPUFuture> map_futures(count, WGPUFuture{});
494493

495494
for (size_t i = 0; i < count; i++) {
496495
if (outputs[i].second == 0) {
497-
cb_data[i].done = true;
498496
cb_data[i].status = WGPUMapAsyncStatus_Success;
499497
continue;
500498
}
501499
WGPUBufferMapCallbackInfo cb_info = {};
502-
cb_info.mode = WGPUCallbackMode_AllowSpontaneous;
500+
cb_info.mode = WGPUCallbackMode_WaitAnyOnly;
503501
cb_info.callback = buffer_map_callback;
504502
cb_info.userdata1 = &cb_data[i];
505-
wgpuBufferMapAsync(
503+
map_futures[i] = wgpuBufferMapAsync(
506504
output_staging_buffers_[i],
507505
WGPUMapMode_Read,
508506
0,
509507
outputs[i].second,
510508
cb_info);
511509
}
512510

513-
bool all_mapped = false;
514-
while (!all_mapped) {
515-
webgpu_poll(instance_);
516-
all_mapped = true;
517-
for (size_t i = 0; i < count; i++) {
518-
if (outputs[i].second != 0 && !cb_data[i].done) {
519-
all_mapped = false;
520-
break;
521-
}
511+
for (size_t i = 0; i < count; i++) {
512+
if (outputs[i].second != 0 &&
513+
webgpu_wait(instance_, map_futures[i]) != WGPUWaitStatus_Success) {
514+
throw std::runtime_error("WebGPU: WaitAny failed for output map");
522515
}
523516
}
524517

0 commit comments

Comments
 (0)