Skip to content

Commit 2e90471

Browse files
ramezgergesclaude
andcommitted
mono/skia: Graphite-on-WebGPU patches for Emscripten
Threads Skia's Graphite/Dawn backend through Emscripten's bundled WebGPU shim (-sUSE_WEBGPU=1) so it links cleanly into libSkiaSharp.a under is_canvaskit=true. Five surgical edits: * include/c/sk_graphite_dawn.h + src/c/sk_graphite_dawn.cpp -- new sk_graphite_dawn_backend_texture_new C entry point that wraps a caller-supplied WGPUTexture (e.g. canvas.getContext('webgpu') .getCurrentTexture()) via BackendTextures::MakeDawn. The wrapper does not retain or release the WGPUTexture; any SkSurface/SkImage that wraps it will retain for its own lifetime. * src/gpu/graphite/dawn/DawnCaps.cpp -- guard YCbCr/biplanar texture formats (R8BG8Biplanar420Unorm, R10X6BG10X6Biplanar420Unorm, R8BG8A8Triplanar420Unorm, OpaqueYCbCrAndroid, DualSourceBlending, TextureFormatsTier1) under #if !defined(__EMSCRIPTEN__). These wgpu::TextureFormat enum values do not exist in Emscripten's bundled webgpu_cpp.h and would fail to compile. * src/gpu/graphite/dawn/DawnBuffer.cpp -- replace SKGPU_LOG(...) macro with explicit SKGPU_LOG_D / SKGPU_LOG_E; Emscripten's preprocessor rejects the macro form in this position. * third_party/dawn/BUILD.gn -- skip the native Dawn CMake build AND the libdawn_combined.a link step when is_canvaskit=true. On Emscripten the wgpu_* symbols are provided by -sUSE_WEBGPU=1 at the consumer's final link step; building native Dawn for WASM is both unnecessary and breaks (the Dawn CMake build assumes desktop toolchains). Build prerequisite (out-of-tree): externals/dawn requires one extra #include in third_party/externals/dawn/include/tint/tint.h -- 'src/tint/api/common/bindings.h'. Dawn isn't a git submodule of skia (it is checked out via DEPS), so we cannot land that patch here. Apply it separately if a fresh DEPS sync is needed and Dawn pre-m146. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 33ab5da commit 2e90471

5 files changed

Lines changed: 49 additions & 4 deletions

File tree

include/c/sk_graphite_dawn.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ SK_C_API sk_graphite_context_t* sk_graphite_context_make_dawn(
3838
const sk_graphite_dawn_backend_context_t* bc,
3939
const sk_graphite_context_options_t* opts /* nullable -> defaults */);
4040

41+
// Wrap an externally-allocated WGPUTexture as a Graphite BackendTexture. The
42+
// shim queries width/height/format/usage directly from the texture, so this
43+
// is the path for WebGPU swap-chain textures (canvas.getContext('webgpu')
44+
// .getCurrentTexture()).
45+
//
46+
// Lifetime: the BackendTexture does NOT retain or release the WGPUTexture —
47+
// caller keeps it alive for the wrapper's lifetime. Any SkSurface/SkImage that
48+
// wraps this BackendTexture *will* retain it for its own lifetime, so caller
49+
// can drop their reference once the Surface is built.
50+
SK_C_API sk_graphite_backend_texture_t* sk_graphite_dawn_backend_texture_new(
51+
void* wgpuTexture); // WGPUTexture
52+
4153
SK_C_PLUS_PLUS_END_GUARD
4254

4355
#endif // sk_graphite_dawn_DEFINED

src/c/sk_graphite_dawn.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111

1212
#if defined(SK_GRAPHITE) && defined(SK_DAWN)
1313

14+
#include "include/gpu/graphite/BackendTexture.h"
1415
#include "include/gpu/graphite/Context.h"
1516
#include "include/gpu/graphite/ContextOptions.h"
1617
#include "include/gpu/graphite/dawn/DawnBackendContext.h"
18+
#include "include/gpu/graphite/dawn/DawnGraphiteTypes.h"
1719

1820
#include "src/c/sk_types_priv.h"
1921

@@ -61,10 +63,18 @@ extern "C" SK_C_API sk_graphite_context_t* sk_graphite_context_make_dawn(
6163
return reinterpret_cast<sk_graphite_context_t*>(context.release());
6264
}
6365

66+
extern "C" SK_C_API sk_graphite_backend_texture_t* sk_graphite_dawn_backend_texture_new(void* wgpuTexture) {
67+
if (!wgpuTexture) return nullptr;
68+
auto bt = gr::BackendTextures::MakeDawn(static_cast<WGPUTexture>(wgpuTexture));
69+
if (!bt.isValid()) return nullptr;
70+
return reinterpret_cast<sk_graphite_backend_texture_t*>(new gr::BackendTexture(bt));
71+
}
72+
6473
#else // !(SK_GRAPHITE && SK_DAWN)
6574

6675
extern "C" SK_C_API sk_graphite_dawn_backend_context_t* sk_graphite_dawn_backend_context_new(const sk_graphite_dawn_backend_context_init_t*) { return nullptr; }
6776
extern "C" SK_C_API void sk_graphite_dawn_backend_context_delete(sk_graphite_dawn_backend_context_t*) {}
6877
extern "C" SK_C_API sk_graphite_context_t* sk_graphite_context_make_dawn(const sk_graphite_dawn_backend_context_t*, const sk_graphite_context_options_t*) { return nullptr; }
78+
extern "C" SK_C_API sk_graphite_backend_texture_t* sk_graphite_dawn_backend_texture_new(void*) { return nullptr; }
6979

7080
#endif // SK_GRAPHITE && SK_DAWN

src/gpu/graphite/dawn/DawnBuffer.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ void log_map_error(WGPUBufferMapAsyncStatus status, const char*) {
5555
statusStr = "<other>";
5656
break;
5757
}
58-
SKGPU_LOG(priority, "Buffer async map failed with status %s.", statusStr);
58+
if (priority == SkLogPriority::kDebug) {
59+
SKGPU_LOG_D("Buffer async map failed with status %s.", statusStr);
60+
} else {
61+
SKGPU_LOG_E("Buffer async map failed with status %s.", statusStr);
62+
}
5963
}
6064

6165
#else

src/gpu/graphite/dawn/DawnCaps.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ static constexpr wgpu::TextureFormat kFormats[] = {
8282
wgpu::TextureFormat::ETC2RGBA8Unorm,
8383
wgpu::TextureFormat::ETC2RGBA8UnormSrgb,
8484

85+
#if !defined(__EMSCRIPTEN__)
8586
wgpu::TextureFormat::R8BG8Biplanar420Unorm,
8687
wgpu::TextureFormat::R10X6BG10X6Biplanar420Unorm,
8788

88-
#if !defined(__EMSCRIPTEN__)
8989
wgpu::TextureFormat::OpaqueYCbCrAndroid,
9090
#endif
9191

@@ -501,9 +501,13 @@ void DawnCaps::initShaderCaps(const wgpu::Device& device) {
501501
// WGSL supports shader derivatives in the fragment shader
502502
shaderCaps->fShaderDerivativeSupport = true;
503503

504+
#if !defined(__EMSCRIPTEN__)
505+
// DualSourceBlending is a Dawn-extension feature not exposed by Emscripten's
506+
// bundled webgpu.h; gate it the same way as FramebufferFetch below.
504507
if (device.HasFeature(wgpu::FeatureName::DualSourceBlending)) {
505508
shaderCaps->fDualSourceBlendingSupport = true;
506509
}
510+
#endif
507511
#if !defined(__EMSCRIPTEN__)
508512
if (device.HasFeature(wgpu::FeatureName::FramebufferFetch)) {
509513
shaderCaps->fFBFetchSupport = true;
@@ -550,9 +554,15 @@ void DawnCaps::initFormatTable(const wgpu::Device& device) {
550554
{
551555
info = &fFormatTable[GetFormatIndex(wgpu::TextureFormat::R8Unorm)];
552556
info->fFlags = FormatInfo::kAllFlags;
557+
#if defined(__EMSCRIPTEN__)
558+
// TextureFormatsTier1 is a Dawn-extension feature not exposed by
559+
// Emscripten's bundled webgpu.h. Conservatively drop the storage flag.
560+
info->fFlags &= ~FormatInfo::kStorage_Flag;
561+
#else
553562
if (!device.HasFeature(wgpu::FeatureName::TextureFormatsTier1)) {
554563
info->fFlags &= ~FormatInfo::kStorage_Flag;
555564
}
565+
#endif
556566
info->fColorTypeInfoCount = 3;
557567
info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
558568
int ctIdx = 0;

third_party/dawn/BUILD.gn

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,12 @@ config("dawn_api_config") {
154154
} else {
155155
libs = []
156156
}
157-
libs += [ "$root_out_dir/$_dawn_lib_name" ]
157+
# On WASM/canvaskit builds we let Emscripten's bundled webgpu.h resolve the
158+
# wgpu_* symbols via -sUSE_WEBGPU=1 at the final link. There's no
159+
# libdawn_combined.a produced (see below), so don't reference it as a lib.
160+
if (!is_canvaskit) {
161+
libs += [ "$root_out_dir/$_dawn_lib_name" ]
162+
}
158163

159164
# https://dawn.googlesource.com/dawn/+/647c352f57aa8a4c2666258455158a36c0c385af/src/dawn/native/BUILD.gn#645
160165
if (is_mac || is_ios) {
@@ -291,7 +296,11 @@ action("dawn_cmake") {
291296
}
292297

293298
group("dawn") {
294-
public_deps = [ ":dawn_cmake" ]
299+
if (!is_canvaskit) {
300+
# canvaskit (incl. our WASM-Graphite build) does NOT build native Dawn
301+
# because Emscripten's webgpu_cpp.h + -sUSE_WEBGPU=1 provide the wgpu API.
302+
public_deps = [ ":dawn_cmake" ]
303+
}
295304

296305
public_configs = [ ":dawn_api_config" ]
297306
}

0 commit comments

Comments
 (0)