Skip to content

Commit

Permalink
Split WebGPU runtime into two variants (#7248 workaround)
Browse files Browse the repository at this point in the history
Halide promises that you can crosscompile to *any* supported target from a 'stock' build of libHalide. Unfortunately, the initial landing of WebGPU support breaks that promise: we compile the webgpu runtime support (webgpu.cpp) with code that is predicated on `WITH_DAWN_NATIVE` (for Dawn vs Emscripten, respectively).

This means that if you build Halide with `WITH_DAWN_NATIVE` defined, you can *only* target Dawn with that build of Halide; similarly, if you build with `WITH_DAWN_NATIVE` not-defined, you can only target Emscripten. (Trying to use the 'wrong' version will produce link-time errors.)

For people who build everything from source, this isn't a big deal, but for people who just pull binary builds, this is a big problem.

This PR proposes a temporary workaround until the API discrepancies are resolved:
- Compile the existing webgpu.cpp runtime *both* ways
- in LLVM_Runtime_Linker.cpp, select the correct variant based on whether the Target is targeting wasm or not
- Profit!

This is a rather ugly hack, but it should hopefully be (relatively) temporary.
  • Loading branch information
steven-johnson committed Mar 14, 2023
1 parent ae59b91 commit ac41747
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 15 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,8 @@ RUNTIME_CPP_COMPONENTS = \
trace_helper \
tracing \
wasm_cpu_features \
webgpu \
webgpu_dawn \
webgpu_emscripten \
windows_clock \
windows_cuda \
windows_d3d12compute_arm \
Expand Down
13 changes: 11 additions & 2 deletions src/LLVM_Runtime_Linker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ DECLARE_CPP_INITMOD(timer_profiler)
DECLARE_CPP_INITMOD(to_string)
DECLARE_CPP_INITMOD(trace_helper)
DECLARE_CPP_INITMOD(tracing)
DECLARE_CPP_INITMOD(webgpu)
// TODO(https://github.com/halide/Halide/issues/7248)
// DECLARE_CPP_INITMOD(webgpu)
DECLARE_CPP_INITMOD(webgpu_dawn)
DECLARE_CPP_INITMOD(webgpu_emscripten)
DECLARE_CPP_INITMOD(windows_clock)
DECLARE_CPP_INITMOD(windows_cuda)
DECLARE_CPP_INITMOD(windows_get_symbol)
Expand Down Expand Up @@ -1194,7 +1197,13 @@ std::unique_ptr<llvm::Module> get_initial_module_for_target(Target t, llvm::LLVM
// See https://github.com/halide/Halide/issues/7249
user_error << "WebGPU runtime not yet supported on Windows.\n";
} else {
modules.push_back(get_initmod_webgpu(c, bits_64, debug));
// Select the right WebGPU runtime variant based on the Target's OS:
// if we are targeting wasm, use the Emscripten variant; in all other cases, use Dawn variant.
if (t.os == Target::WebAssemblyRuntime) {
modules.push_back(get_initmod_webgpu_emscripten(c, bits_64, debug));
} else {
modules.push_back(get_initmod_webgpu_dawn(c, bits_64, debug));
}
}
}
if (t.arch != Target::Hexagon && t.has_feature(Target::HVX)) {
Expand Down
9 changes: 4 additions & 5 deletions src/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ set(RUNTIME_CPP
trace_helper
tracing
wasm_cpu_features
webgpu
# TODO(https://github.com/halide/Halide/issues/7248)
# webgpu
webgpu_dawn
webgpu_emscripten
windows_clock
windows_cuda
windows_d3d12compute_arm
Expand Down Expand Up @@ -227,10 +230,6 @@ foreach (i IN LISTS RUNTIME_CPP)
set(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${i}.cpp")

set(RUNTIME_DEFINES -DCOMPILING_HALIDE_RUNTIME -DBITS_${j})
if (WEBGPU_NATIVE_LIB)
# TODO: Remove this once Emscripten and Dawn agree with each other.
set(RUNTIME_DEFINES -DWITH_DAWN_NATIVE ${RUNTIME_DEFINES})
endif ()
set(RUNTIME_DEFINES_debug -g -DDEBUG_RUNTIME ${RUNTIME_DEFINES})

foreach (SUFFIX IN ITEMS "" "_debug")
Expand Down
18 changes: 11 additions & 7 deletions src/runtime/webgpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

#include "mini_webgpu.h"

#ifndef HALIDE_RUNTIME_WEBGPU_NATIVE_API
#error "HALIDE_RUNTIME_WEBGPU_NATIVE_API must be defined"
#endif

namespace Halide {
namespace Runtime {
namespace Internal {
Expand Down Expand Up @@ -40,7 +44,7 @@ using namespace Halide::Runtime::Internal::WebGPU;
extern "C" {
// TODO: Remove all of this when wgpuInstanceProcessEvents() is supported.
// See https://github.com/halide/Halide/issues/7248
#ifdef WITH_DAWN_NATIVE
#if HALIDE_RUNTIME_WEBGPU_NATIVE_API
// Defined by Dawn, and used to yield execution to asynchronous commands.
void wgpuDeviceTick(WGPUDevice);
// From <unistd.h>, used to spin-lock while waiting for device initialization.
Expand Down Expand Up @@ -274,7 +278,7 @@ void request_adapter_callback(WGPURequestAdapterStatus status,

// TODO: Enable for Emscripten when wgpuAdapterGetLimits is supported.
// See https://github.com/halide/Halide/issues/7248
#ifdef WITH_DAWN_NATIVE
#if HALIDE_RUNTIME_WEBGPU_NATIVE_API
WGPUSupportedLimits supportedLimits{};
supportedLimits.nextInChain = nullptr;
if (!wgpuAdapterGetLimits(adapter, &supportedLimits)) {
Expand Down Expand Up @@ -310,7 +314,7 @@ size_t round_up_to_multiple_of_4(size_t x) {
WEAK int create_webgpu_context(void *user_context) {
// TODO: Unify this when Emscripten implements wgpuCreateInstance().
// See https://github.com/halide/Halide/issues/7248
#ifdef WITH_DAWN_NATIVE
#if HALIDE_RUNTIME_WEBGPU_NATIVE_API
WGPUInstanceDescriptor desc{};
desc.nextInChain = nullptr;
global_instance = wgpuCreateInstance(&desc);
Expand All @@ -325,10 +329,10 @@ WEAK int create_webgpu_context(void *user_context) {
while (!global_device && init_error_code == halide_error_code_success) {
// TODO: Use wgpuInstanceProcessEvents() when it is supported.
// See https://github.com/halide/Halide/issues/7248
#ifndef WITH_DAWN_NATIVE
emscripten_sleep(10);
#else
#if HALIDE_RUNTIME_WEBGPU_NATIVE_API
usleep(1000);
#else
emscripten_sleep(10);
#endif
}
if (init_error_code != halide_error_code_success) {
Expand Down Expand Up @@ -514,7 +518,7 @@ WEAK int halide_webgpu_device_release(void *user_context) {

// TODO: Unify this when Emscripten supports wgpuInstanceRelease().
// See https://github.com/halide/Halide/issues/7248
#ifdef WITH_DAWN_NATIVE
#if HALIDE_RUNTIME_WEBGPU_NATIVE_API
wgpuInstanceRelease(instance);
global_instance = nullptr;
#endif
Expand Down
12 changes: 12 additions & 0 deletions src/runtime/webgpu_dawn.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// TODO(https://github.com/halide/Halide/issues/7248):
//
// For now, we must build the webgpu runtime two ways:
// - once for the native API (Dawn)
// - once for the Emscripten API (Chrome)
//
// Once the API discrepancies are resolved we can
// go back to building this in a sane manner, but for now,
// we use this sad-but-effective approach.

#define HALIDE_RUNTIME_WEBGPU_NATIVE_API 1
#include "webgpu.cpp"
12 changes: 12 additions & 0 deletions src/runtime/webgpu_emscripten.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// TODO(https://github.com/halide/Halide/issues/7248):
//
// For now, we must build the webgpu runtime two ways:
// - once for the native API (Dawn)
// - once for the Emscripten API (Chrome)
//
// Once the API discrepancies are resolved we can
// go back to building this in a sane manner, but for now,
// we use this sad-but-effective approach.

#define HALIDE_RUNTIME_WEBGPU_NATIVE_API 0
#include "webgpu.cpp"

0 comments on commit ac41747

Please sign in to comment.