From 433fd9550298c795acb63af5ad8be27c2ca3d0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Tue, 14 May 2024 13:30:43 +0200 Subject: [PATCH 1/9] Add Surface API --- src/generated_struct_info32.json | 29 ++++++ src/generated_struct_info64.json | 29 ++++++ src/library_webgpu.js | 92 ++++++++++++++++++ src/struct_info.json | 26 ++++++ system/include/webgpu/README.md | 8 +- system/include/webgpu/webgpu.h | 63 +++++++++++++ system/include/webgpu/webgpu_cpp.h | 60 ++++++++++++ system/lib/webgpu/webgpu_cpp.cpp | 144 ++++++++++++++++++++++++++++- test/webgpu_basic_rendering.cpp | 86 ++++++++++------- 9 files changed, 495 insertions(+), 42 deletions(-) diff --git a/src/generated_struct_info32.json b/src/generated_struct_info32.json index dceaadbed8d76..2b8017a8e6d35 100644 --- a/src/generated_struct_info32.json +++ b/src/generated_struct_info32.json @@ -1260,6 +1260,29 @@ "limits": 8, "nextInChain": 0 }, + "WGPUSurfaceCapabilities": { + "__size__": 28, + "alphaModeCount": 20, + "alphaModes": 24, + "formatCount": 4, + "formats": 8, + "nextInChain": 0, + "presentModeCount": 12, + "presentModes": 16 + }, + "WGPUSurfaceConfiguration": { + "__size__": 40, + "alphaMode": 24, + "device": 4, + "format": 8, + "height": 32, + "nextInChain": 0, + "presentMode": 36, + "usage": 12, + "viewFormatCount": 16, + "viewFormats": 20, + "width": 28 + }, "WGPUSurfaceDescriptor": { "__size__": 8, "label": 4, @@ -1270,6 +1293,12 @@ "chain": 0, "selector": 8 }, + "WGPUSurfaceTexture": { + "__size__": 12, + "status": 8, + "suboptimal": 4, + "texture": 0 + }, "WGPUSwapChainDescriptor": { "__size__": 28, "format": 12, diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json index ef23e32b4a9e0..5b819ad23f6d2 100644 --- a/src/generated_struct_info64.json +++ b/src/generated_struct_info64.json @@ -1260,6 +1260,29 @@ "limits": 8, "nextInChain": 0 }, + "WGPUSurfaceCapabilities": { + "__size__": 56, + "alphaModeCount": 40, + "alphaModes": 48, + "formatCount": 8, + "formats": 16, + "nextInChain": 0, + "presentModeCount": 24, + "presentModes": 32 + }, + "WGPUSurfaceConfiguration": { + "__size__": 56, + "alphaMode": 40, + "device": 8, + "format": 16, + "height": 48, + "nextInChain": 0, + "presentMode": 52, + "usage": 20, + "viewFormatCount": 24, + "viewFormats": 32, + "width": 44 + }, "WGPUSurfaceDescriptor": { "__size__": 16, "label": 8, @@ -1270,6 +1293,12 @@ "chain": 0, "selector": 16 }, + "WGPUSurfaceTexture": { + "__size__": 16, + "status": 12, + "suboptimal": 8, + "texture": 0 + }, "WGPUSwapChainDescriptor": { "__size__": 40, "format": 20, diff --git a/src/library_webgpu.js b/src/library_webgpu.js index 838a600a5e2bb..9cd24fd8e1f24 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -99,6 +99,13 @@ wgpu${type}Release: (id) => WebGPU.mgr${type}.release(id),`; DeviceLost: 2, Unknown: 3, }, + CompositeAlphaMode: [ + 'auto', + 'opaque', + 'premultiplied', + 'unpremultiplied', + 'inherit', + ], CreatePipelineAsyncStatus: { Success: 0, ValidationError: 1, @@ -568,6 +575,14 @@ var LibraryWebGPU = { 'store', 'discard', ], + SurfaceGetCurrentTextureStatus: [ + 'success', + 'timeout', + 'outdated', + 'lost', + 'out-of-memory', + 'device-lost', + ], TextureAspect: [ undefined, 'all', @@ -2673,13 +2688,90 @@ var LibraryWebGPU = { sampler.label = UTF8ToString(labelPtr); }, + // WGPUSurfaceCapabilities + + wgpuSurfaceCapabilitiesFreeMembers: (value) => { + // wgpuSurfaceCapabilities does currently allocate anything + }, + // WGPUSurface + wgpuSurfaceConfigure: (surfaceId, config) => { + {{{ gpu.makeCheckDescriptor('config') }}} + var deviceId = {{{ makeGetValue('config', C_STRUCTS.WGPUSurfaceConfiguration.device, '*') }}}; + var context = WebGPU.mgrSurface.get(surfaceId); + +#if ASSERTIONS + assert({{{ gpu.PresentMode.Fifo }}} === + {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.presentMode) }}}); +#endif + + var canvasSize = [ + {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.width) }}}, + {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.height) }}} + ]; + + if (canvasSize[0] !== 0) { + context["canvas"]["width"] = canvasSize[0]; + } + + if (canvasSize[1] !== 0) { + context["canvas"]["height"] = canvasSize[1]; + } + + var configuration = { + "device": WebGPU.mgrDevice.get(deviceId), + "format": WebGPU.TextureFormat[ + {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.format) }}}], + "usage": {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.usage) }}}, + // viewFormatCount + // viewFormats + "alphaMode": "opaque", + "width": canvasSize[0], + "height": canvasSize[1], + "presentMode": {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.presentMode) }}}, + }; + context.configure(configuration); + }, + + wgpuSurfaceGetCapabilities: (surfaceId, adapterId, capabilitiesPtr) => { + if (capabilitiesPtr !== 0) { + {{{ makeSetValue('capabilitiesPtr', C_STRUCTS.WGPUSurfaceCapabilities.formatCount, '1', 'i32') }}}; + var format = navigator["gpu"]["getPreferredCanvasFormat"](); + var formatsPtr = WebGPU.Int_PreferredFormat[format]; // FIXME + {{{ makeSetValue('capabilitiesPtr', C_STRUCTS.WGPUSurfaceCapabilities.formats, 'formatsPtr', '*') }}}; + // "presentModeCount", + // "presentModes", + // "alphaModeCount", + // "alphaModes" + } + }, + + wgpuSurfaceGetCurrentTexture: (surfaceId, surfaceTexturePtr) => { + var context = WebGPU.mgrSurface.get(surfaceId); + var texture = WebGPU.mgrTexture.create(context.getCurrentTexture()); + if (surfaceTexturePtr !== 0) { + {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.texture, 'texture', '*') }}}; + {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.suboptimal, '0', 'i32') }}}; + {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.status, '0', 'i32') }}}; + } + }, + wgpuSurfaceGetPreferredFormat: (surfaceId, adapterId) => { var format = navigator["gpu"]["getPreferredCanvasFormat"](); return WebGPU.Int_PreferredFormat[format]; }, + wgpuSurfacePresent: (surfaceId) => { + // TODO: This could probably be emulated with ASYNCIFY. + abort('wgpuSurfacePresent is unsupported (use requestAnimationFrame via html5.h instead)'); + }, + + wgpuSurfaceUnconfigure: (surfaceId) => { + var context = WebGPU.mgrSurface.get(surfaceId); + context.unconfigure(); + }, + // WGPUSwapChain wgpuDeviceCreateSwapChain: (deviceId, surfaceId, descriptor) => { diff --git a/src/struct_info.json b/src/struct_info.json index 32e18a0fab008..f0120e70ff607 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -1480,6 +1480,27 @@ "format", "viewDimension" ], + "WGPUSurfaceCapabilities": [ + "nextInChain", + "formatCount", + "formats", + "presentModeCount", + "presentModes", + "alphaModeCount", + "alphaModes" + ], + "WGPUSurfaceConfiguration": [ + "nextInChain", + "device", + "format", + "usage", + "viewFormatCount", + "viewFormats", + "alphaMode", + "width", + "height", + "presentMode" + ], "WGPUSurfaceDescriptor": [ "nextInChain", "label" @@ -1488,6 +1509,11 @@ "chain", "selector" ], + "WGPUSurfaceTexture": [ + "texture", + "suboptimal", + "status" + ], "WGPUSwapChainDescriptor": [ "nextInChain", "label", diff --git a/system/include/webgpu/README.md b/system/include/webgpu/README.md index cff52662b8d46..340d68620c753 100644 --- a/system/include/webgpu/README.md +++ b/system/include/webgpu/README.md @@ -2,7 +2,7 @@ These files, and several snippets of other files, are generated by Dawn (Chromium's WebGPU library): - [Generator](https://source.chromium.org/chromium/chromium/src/+/main:third_party/dawn/generator/) - [Generator input](https://source.chromium.org/chromium/chromium/src/+/main:third_party/dawn/dawn.json) -- [Generator output](https://source.chromium.org/chromium/chromium/src/+/main:out/Debug/gen/third_party/dawn/emscripten-bits/) +- [Generator output](https://source.chromium.org/chromium/chromium/src/+/main:out/linux-Debug/gen/third_party/dawn/emscripten-bits/) The C header is intended to be mostly the same as the "upstream" [`webgpu.h`](https://github.com/webgpu-native/webgpu-headers/blob/main/webgpu.h), @@ -16,13 +16,13 @@ is included here because it is strongly tied to an exact `webgpu.h` revision. To update these bindings from Dawn: 1. Copy [`webgpu_enum_class_bitmasks.h`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/dawn/include/webgpu/webgpu_enum_class_bitmasks.h) from Dawn's source to `system/include/webgpu/webgpu_enum_class_bitmasks.h` 1. Build Dawn's `emscripten_bits_gen` target (in a gn or CMake build of Dawn, or a build of Chromium) - or, use the Chromium Code Search copy of the generated files if no changes are needed -1. Copy the generated [`emscripten-bits/system`](https://source.chromium.org/chromium/chromium/src/+/main:out/Debug/gen/third_party/dawn/emscripten-bits/system/) files into Emscripten's `system` directory +1. Copy the generated [`emscripten-bits/system`](https://source.chromium.org/chromium/chromium/src/+/main:out/linux-Debug/gen/third_party/dawn/emscripten-bits/system/) files into Emscripten's `system` directory - `system/include/webgpu/webgpu.h` - `system/include/webgpu/webgpu_cpp.h` - `system/include/webgpu/webgpu_cpp_chained_struct.h` - `system/lib/webgpu/webgpu_cpp.cpp` -1. Paste the contents of [`library_webgpu_enum_tables.js`](https://source.chromium.org/chromium/chromium/src/+/main:out/Debug/gen/third_party/dawn/emscripten-bits/library_webgpu_enum_tables.js) over the "Map from enum number to enum string" section of [`library_webgpu.js`](../../../src/library_webgpu.js) -1. Paste [`webgpu_struct_info.json`](https://source.chromium.org/chromium/chromium/src/+/main:out/Debug/gen/third_party/dawn/emscripten-bits/webgpu_struct_info.json) over the "WebGPU" section of [`struct_info.json`](../../../src/struct_info.json). +1. Paste the contents of [`library_webgpu_enum_tables.js`](https://source.chromium.org/chromium/chromium/src/+/main:out/linux-Debug/gen/third_party/dawn/emscripten-bits/library_webgpu_enum_tables.js) over the "Map from enum number to enum string" section of [`library_webgpu.js`](../../../src/library_webgpu.js) +1. Paste [`webgpu_struct_info.json`](https://source.chromium.org/chromium/chromium/src/+/main:out/linux-Debug/gen/third_party/dawn/emscripten-bits/webgpu_struct_info.json) over the "WebGPU" section of [`struct_info.json`](../../../src/struct_info.json). 1. **Manually update the `globalThis.gpu` compile-time enum tables (AdapterType, BackendType, etc.)**: - Inspect the `webgpu.h` diff for changes to the integer values of any enums used here. (It's not necessary to add new enum values to these tables until they're needed for something.) 1. **Manually update the "Map from enum string back to enum number" tables.** diff --git a/system/include/webgpu/webgpu.h b/system/include/webgpu/webgpu.h index b3e5218e12b8a..b3542f8964db5 100644 --- a/system/include/webgpu/webgpu.h +++ b/system/include/webgpu/webgpu.h @@ -143,8 +143,11 @@ struct WGPUShaderModuleWGSLDescriptor; struct WGPUShaderModuleDescriptor; struct WGPUStencilFaceState; struct WGPUStorageTextureBindingLayout; +struct WGPUSurfaceCapabilities; +struct WGPUSurfaceConfiguration; struct WGPUSurfaceDescriptor; struct WGPUSurfaceDescriptorFromCanvasHTMLSelector; +struct WGPUSurfaceTexture; struct WGPUSwapChainDescriptor; struct WGPUTextureBindingLayout; struct WGPUTextureBindingViewDimensionDescriptor; @@ -305,6 +308,15 @@ typedef enum WGPUCompilationMessageType { WGPUCompilationMessageType_Force32 = 0x7FFFFFFF } WGPUCompilationMessageType WGPU_ENUM_ATTRIBUTE; +typedef enum WGPUCompositeAlphaMode { + WGPUCompositeAlphaMode_Auto = 0x00000000, + WGPUCompositeAlphaMode_Opaque = 0x00000001, + WGPUCompositeAlphaMode_Premultiplied = 0x00000002, + WGPUCompositeAlphaMode_Unpremultiplied = 0x00000003, + WGPUCompositeAlphaMode_Inherit = 0x00000004, + WGPUCompositeAlphaMode_Force32 = 0x7FFFFFFF +} WGPUCompositeAlphaMode WGPU_ENUM_ATTRIBUTE; + typedef enum WGPUCreatePipelineAsyncStatus { WGPUCreatePipelineAsyncStatus_Success = 0x00000000, WGPUCreatePipelineAsyncStatus_ValidationError = 0x00000001, @@ -497,6 +509,16 @@ typedef enum WGPUStoreOp { WGPUStoreOp_Force32 = 0x7FFFFFFF } WGPUStoreOp WGPU_ENUM_ATTRIBUTE; +typedef enum WGPUSurfaceGetCurrentTextureStatus { + WGPUSurfaceGetCurrentTextureStatus_Success = 0x00000000, + WGPUSurfaceGetCurrentTextureStatus_Timeout = 0x00000001, + WGPUSurfaceGetCurrentTextureStatus_Outdated = 0x00000002, + WGPUSurfaceGetCurrentTextureStatus_Lost = 0x00000003, + WGPUSurfaceGetCurrentTextureStatus_OutOfMemory = 0x00000004, + WGPUSurfaceGetCurrentTextureStatus_DeviceLost = 0x00000005, + WGPUSurfaceGetCurrentTextureStatus_Force32 = 0x7FFFFFFF +} WGPUSurfaceGetCurrentTextureStatus WGPU_ENUM_ATTRIBUTE; + typedef enum WGPUTextureAspect { WGPUTextureAspect_Undefined = 0x00000000, WGPUTextureAspect_All = 0x00000001, @@ -1069,6 +1091,29 @@ typedef struct WGPUStorageTextureBindingLayout { WGPUTextureViewDimension viewDimension; } WGPUStorageTextureBindingLayout WGPU_STRUCTURE_ATTRIBUTE; +typedef struct WGPUSurfaceCapabilities { + WGPUChainedStructOut * nextInChain; + size_t formatCount; + WGPUTextureFormat const * formats; + size_t presentModeCount; + WGPUPresentMode const * presentModes; + size_t alphaModeCount; + WGPUCompositeAlphaMode const * alphaModes; +} WGPUSurfaceCapabilities WGPU_STRUCTURE_ATTRIBUTE; + +typedef struct WGPUSurfaceConfiguration { + WGPUChainedStruct const * nextInChain; + WGPUDevice device; + WGPUTextureFormat format; + WGPUTextureUsageFlags usage; + size_t viewFormatCount; + WGPUTextureFormat const * viewFormats; + WGPUCompositeAlphaMode alphaMode; + uint32_t width; + uint32_t height; + WGPUPresentMode presentMode; +} WGPUSurfaceConfiguration WGPU_STRUCTURE_ATTRIBUTE; + typedef struct WGPUSurfaceDescriptor { WGPUChainedStruct const * nextInChain; WGPU_NULLABLE char const * label; @@ -1080,6 +1125,12 @@ typedef struct WGPUSurfaceDescriptorFromCanvasHTMLSelector { char const * selector; } WGPUSurfaceDescriptorFromCanvasHTMLSelector WGPU_STRUCTURE_ATTRIBUTE; +typedef struct WGPUSurfaceTexture { + WGPUTexture texture; + WGPUBool suboptimal; + WGPUSurfaceGetCurrentTextureStatus status; +} WGPUSurfaceTexture WGPU_STRUCTURE_ATTRIBUTE; + typedef struct WGPUSwapChainDescriptor { WGPUChainedStruct const * nextInChain; WGPU_NULLABLE char const * label; @@ -1332,6 +1383,7 @@ typedef void (*WGPUProcAdapterPropertiesFreeMembers)(WGPUAdapterProperties value typedef WGPUInstance (*WGPUProcCreateInstance)(WGPUInstanceDescriptor const * descriptor) WGPU_FUNCTION_ATTRIBUTE; typedef WGPUBool (*WGPUProcGetInstanceFeatures)(WGPUInstanceFeatures * features) WGPU_FUNCTION_ATTRIBUTE; typedef WGPUProc (*WGPUProcGetProcAddress)(WGPUDevice device, char const * procName) WGPU_FUNCTION_ATTRIBUTE; +typedef void (*WGPUProcSurfaceCapabilitiesFreeMembers)(WGPUSurfaceCapabilities value) WGPU_FUNCTION_ATTRIBUTE; // Procs of Adapter typedef size_t (*WGPUProcAdapterEnumerateFeatures)(WGPUAdapter adapter, WGPUFeatureName * features) WGPU_FUNCTION_ATTRIBUTE; @@ -1532,7 +1584,12 @@ typedef void (*WGPUProcShaderModuleReference)(WGPUShaderModule shaderModule) WGP typedef void (*WGPUProcShaderModuleRelease)(WGPUShaderModule shaderModule) WGPU_FUNCTION_ATTRIBUTE; // Procs of Surface +typedef void (*WGPUProcSurfaceConfigure)(WGPUSurface surface, WGPUSurfaceConfiguration const * config) WGPU_FUNCTION_ATTRIBUTE; +typedef void (*WGPUProcSurfaceGetCapabilities)(WGPUSurface surface, WGPUAdapter adapter, WGPUSurfaceCapabilities * capabilities) WGPU_FUNCTION_ATTRIBUTE; +typedef void (*WGPUProcSurfaceGetCurrentTexture)(WGPUSurface surface, WGPUSurfaceTexture * surfaceTexture) WGPU_FUNCTION_ATTRIBUTE; typedef WGPUTextureFormat (*WGPUProcSurfaceGetPreferredFormat)(WGPUSurface surface, WGPUAdapter adapter) WGPU_FUNCTION_ATTRIBUTE; +typedef void (*WGPUProcSurfacePresent)(WGPUSurface surface) WGPU_FUNCTION_ATTRIBUTE; +typedef void (*WGPUProcSurfaceUnconfigure)(WGPUSurface surface) WGPU_FUNCTION_ATTRIBUTE; typedef void (*WGPUProcSurfaceReference)(WGPUSurface surface) WGPU_FUNCTION_ATTRIBUTE; typedef void (*WGPUProcSurfaceRelease)(WGPUSurface surface) WGPU_FUNCTION_ATTRIBUTE; @@ -1572,6 +1629,7 @@ WGPU_EXPORT void wgpuAdapterPropertiesFreeMembers(WGPUAdapterProperties value) W WGPU_EXPORT WGPUInstance wgpuCreateInstance(WGPU_NULLABLE WGPUInstanceDescriptor const * descriptor) WGPU_FUNCTION_ATTRIBUTE; WGPU_EXPORT WGPUBool wgpuGetInstanceFeatures(WGPUInstanceFeatures * features) WGPU_FUNCTION_ATTRIBUTE; WGPU_EXPORT WGPUProc wgpuGetProcAddress(WGPU_NULLABLE WGPUDevice device, char const * procName) WGPU_FUNCTION_ATTRIBUTE; +WGPU_EXPORT void wgpuSurfaceCapabilitiesFreeMembers(WGPUSurfaceCapabilities value) WGPU_FUNCTION_ATTRIBUTE; // Methods of Adapter WGPU_EXPORT size_t wgpuAdapterEnumerateFeatures(WGPUAdapter adapter, WGPUFeatureName * features) WGPU_FUNCTION_ATTRIBUTE; @@ -1771,7 +1829,12 @@ WGPU_EXPORT void wgpuShaderModuleReference(WGPUShaderModule shaderModule) WGPU_F WGPU_EXPORT void wgpuShaderModuleRelease(WGPUShaderModule shaderModule) WGPU_FUNCTION_ATTRIBUTE; // Methods of Surface +WGPU_EXPORT void wgpuSurfaceConfigure(WGPUSurface surface, WGPUSurfaceConfiguration const * config) WGPU_FUNCTION_ATTRIBUTE; +WGPU_EXPORT void wgpuSurfaceGetCapabilities(WGPUSurface surface, WGPUAdapter adapter, WGPUSurfaceCapabilities * capabilities) WGPU_FUNCTION_ATTRIBUTE; +WGPU_EXPORT void wgpuSurfaceGetCurrentTexture(WGPUSurface surface, WGPUSurfaceTexture * surfaceTexture) WGPU_FUNCTION_ATTRIBUTE; WGPU_EXPORT WGPUTextureFormat wgpuSurfaceGetPreferredFormat(WGPUSurface surface, WGPUAdapter adapter) WGPU_FUNCTION_ATTRIBUTE; +WGPU_EXPORT void wgpuSurfacePresent(WGPUSurface surface) WGPU_FUNCTION_ATTRIBUTE; +WGPU_EXPORT void wgpuSurfaceUnconfigure(WGPUSurface surface) WGPU_FUNCTION_ATTRIBUTE; WGPU_EXPORT void wgpuSurfaceReference(WGPUSurface surface) WGPU_FUNCTION_ATTRIBUTE; WGPU_EXPORT void wgpuSurfaceRelease(WGPUSurface surface) WGPU_FUNCTION_ATTRIBUTE; diff --git a/system/include/webgpu/webgpu_cpp.h b/system/include/webgpu/webgpu_cpp.h index 57ca2dcca9f6b..3f84c07ce8f8b 100644 --- a/system/include/webgpu/webgpu_cpp.h +++ b/system/include/webgpu/webgpu_cpp.h @@ -170,6 +170,14 @@ namespace wgpu { Info = 0x00000003, }; + enum class CompositeAlphaMode : uint32_t { + Auto = 0x00000000, + Opaque = 0x00000001, + Premultiplied = 0x00000002, + Unpremultiplied = 0x00000003, + Inherit = 0x00000004, + }; + enum class CreatePipelineAsyncStatus : uint32_t { Success = 0x00000000, ValidationError = 0x00000001, @@ -339,6 +347,15 @@ namespace wgpu { Discard = 0x00000002, }; + enum class SurfaceGetCurrentTextureStatus : uint32_t { + Success = WGPUSurfaceGetCurrentTextureStatus_Success, + Timeout = WGPUSurfaceGetCurrentTextureStatus_Timeout, + Outdated = WGPUSurfaceGetCurrentTextureStatus_Outdated, + Lost = WGPUSurfaceGetCurrentTextureStatus_Lost, + OutOfMemory = WGPUSurfaceGetCurrentTextureStatus_OutOfMemory, + DeviceLost = WGPUSurfaceGetCurrentTextureStatus_DeviceLost, + }; + enum class TextureAspect : uint32_t { Undefined = 0x00000000, All = 0x00000001, @@ -642,8 +659,11 @@ namespace wgpu { struct ShaderModuleDescriptor; struct StencilFaceState; struct StorageTextureBindingLayout; + struct SurfaceCapabilities; + struct SurfaceConfiguration; struct SurfaceDescriptor; struct SurfaceDescriptorFromCanvasHTMLSelector; + struct SurfaceTexture; struct SwapChainDescriptor; struct TextureBindingLayout; struct TextureBindingViewDimensionDescriptor; @@ -1124,7 +1144,12 @@ namespace wgpu { using ObjectBase::ObjectBase; using ObjectBase::operator=; + void Configure(SurfaceConfiguration const * config) const; + void GetCapabilities(Adapter const& adapter, SurfaceCapabilities * capabilities) const; + void GetCurrentTexture(SurfaceTexture * surfaceTexture) const; TextureFormat GetPreferredFormat(Adapter const& adapter) const; + void Present() const; + void Unconfigure() const; private: friend ObjectBase; @@ -1511,6 +1536,35 @@ namespace wgpu { TextureViewDimension viewDimension = TextureViewDimension::e2D; }; + struct SurfaceCapabilities { + SurfaceCapabilities() = default; + ~SurfaceCapabilities(); + SurfaceCapabilities(const SurfaceCapabilities&) = delete; + SurfaceCapabilities& operator=(const SurfaceCapabilities&) = delete; + SurfaceCapabilities(SurfaceCapabilities&&); + SurfaceCapabilities& operator=(SurfaceCapabilities&&); + ChainedStructOut * nextInChain = nullptr; + size_t const formatCount = {}; + TextureFormat const * const formats = {}; + size_t const presentModeCount = {}; + PresentMode const * const presentModes = {}; + size_t const alphaModeCount = {}; + CompositeAlphaMode const * const alphaModes = {}; + }; + + struct SurfaceConfiguration { + ChainedStruct const * nextInChain = nullptr; + Device device; + TextureFormat format; + TextureUsage usage = TextureUsage::RenderAttachment; + size_t viewFormatCount = 0; + TextureFormat const * viewFormats; + CompositeAlphaMode alphaMode = CompositeAlphaMode::Opaque; + uint32_t width; + uint32_t height; + PresentMode presentMode = PresentMode::Fifo; + }; + struct SurfaceDescriptor { ChainedStruct const * nextInChain = nullptr; char const * label = nullptr; @@ -1525,6 +1579,12 @@ namespace wgpu { alignas(kFirstMemberAlignment) char const * selector; }; + struct SurfaceTexture { + Texture texture; + Bool suboptimal; + SurfaceGetCurrentTextureStatus status; + }; + struct SwapChainDescriptor { ChainedStruct const * nextInChain = nullptr; char const * label = nullptr; diff --git a/system/lib/webgpu/webgpu_cpp.cpp b/system/lib/webgpu/webgpu_cpp.cpp index 2a6d457ece616..15e1def269155 100644 --- a/system/lib/webgpu/webgpu_cpp.cpp +++ b/system/lib/webgpu/webgpu_cpp.cpp @@ -191,6 +191,17 @@ namespace wgpu { static_assert(static_cast(CompilationMessageType::Warning) == WGPUCompilationMessageType_Warning, "value mismatch for CompilationMessageType::Warning"); static_assert(static_cast(CompilationMessageType::Info) == WGPUCompilationMessageType_Info, "value mismatch for CompilationMessageType::Info"); + // CompositeAlphaMode + + static_assert(sizeof(CompositeAlphaMode) == sizeof(WGPUCompositeAlphaMode), "sizeof mismatch for CompositeAlphaMode"); + static_assert(alignof(CompositeAlphaMode) == alignof(WGPUCompositeAlphaMode), "alignof mismatch for CompositeAlphaMode"); + + static_assert(static_cast(CompositeAlphaMode::Auto) == WGPUCompositeAlphaMode_Auto, "value mismatch for CompositeAlphaMode::Auto"); + static_assert(static_cast(CompositeAlphaMode::Opaque) == WGPUCompositeAlphaMode_Opaque, "value mismatch for CompositeAlphaMode::Opaque"); + static_assert(static_cast(CompositeAlphaMode::Premultiplied) == WGPUCompositeAlphaMode_Premultiplied, "value mismatch for CompositeAlphaMode::Premultiplied"); + static_assert(static_cast(CompositeAlphaMode::Unpremultiplied) == WGPUCompositeAlphaMode_Unpremultiplied, "value mismatch for CompositeAlphaMode::Unpremultiplied"); + static_assert(static_cast(CompositeAlphaMode::Inherit) == WGPUCompositeAlphaMode_Inherit, "value mismatch for CompositeAlphaMode::Inherit"); + // CreatePipelineAsyncStatus static_assert(sizeof(CreatePipelineAsyncStatus) == sizeof(WGPUCreatePipelineAsyncStatus), "sizeof mismatch for CreatePipelineAsyncStatus"); @@ -429,6 +440,18 @@ namespace wgpu { static_assert(static_cast(StoreOp::Store) == WGPUStoreOp_Store, "value mismatch for StoreOp::Store"); static_assert(static_cast(StoreOp::Discard) == WGPUStoreOp_Discard, "value mismatch for StoreOp::Discard"); + // SurfaceGetCurrentTextureStatus + + static_assert(sizeof(SurfaceGetCurrentTextureStatus) == sizeof(WGPUSurfaceGetCurrentTextureStatus), "sizeof mismatch for SurfaceGetCurrentTextureStatus"); + static_assert(alignof(SurfaceGetCurrentTextureStatus) == alignof(WGPUSurfaceGetCurrentTextureStatus), "alignof mismatch for SurfaceGetCurrentTextureStatus"); + + static_assert(static_cast(SurfaceGetCurrentTextureStatus::Success) == WGPUSurfaceGetCurrentTextureStatus_Success, "value mismatch for SurfaceGetCurrentTextureStatus::Success"); + static_assert(static_cast(SurfaceGetCurrentTextureStatus::Timeout) == WGPUSurfaceGetCurrentTextureStatus_Timeout, "value mismatch for SurfaceGetCurrentTextureStatus::Timeout"); + static_assert(static_cast(SurfaceGetCurrentTextureStatus::Outdated) == WGPUSurfaceGetCurrentTextureStatus_Outdated, "value mismatch for SurfaceGetCurrentTextureStatus::Outdated"); + static_assert(static_cast(SurfaceGetCurrentTextureStatus::Lost) == WGPUSurfaceGetCurrentTextureStatus_Lost, "value mismatch for SurfaceGetCurrentTextureStatus::Lost"); + static_assert(static_cast(SurfaceGetCurrentTextureStatus::OutOfMemory) == WGPUSurfaceGetCurrentTextureStatus_OutOfMemory, "value mismatch for SurfaceGetCurrentTextureStatus::OutOfMemory"); + static_assert(static_cast(SurfaceGetCurrentTextureStatus::DeviceLost) == WGPUSurfaceGetCurrentTextureStatus_DeviceLost, "value mismatch for SurfaceGetCurrentTextureStatus::DeviceLost"); + // TextureAspect static_assert(sizeof(TextureAspect) == sizeof(WGPUTextureAspect), "sizeof mismatch for TextureAspect"); @@ -1301,6 +1324,96 @@ namespace wgpu { static_assert(offsetof(StorageTextureBindingLayout, viewDimension) == offsetof(WGPUStorageTextureBindingLayout, viewDimension), "offsetof mismatch for StorageTextureBindingLayout::viewDimension"); +template + static T& AsNonConstReference(const T& value) { + return const_cast(value); + } + + // SurfaceCapabilities + SurfaceCapabilities::~SurfaceCapabilities() { + if (this->formats != nullptr || this->presentModes != nullptr || this->alphaModes != nullptr) { + wgpuSurfaceCapabilitiesFreeMembers( + *reinterpret_cast(this)); + } + } + + static void Reset(SurfaceCapabilities& value) { + SurfaceCapabilities defaultValue{}; + AsNonConstReference(value.formatCount) = defaultValue.formatCount; + AsNonConstReference(value.formats) = defaultValue.formats; + AsNonConstReference(value.presentModeCount) = defaultValue.presentModeCount; + AsNonConstReference(value.presentModes) = defaultValue.presentModes; + AsNonConstReference(value.alphaModeCount) = defaultValue.alphaModeCount; + AsNonConstReference(value.alphaModes) = defaultValue.alphaModes; + } + + SurfaceCapabilities::SurfaceCapabilities(SurfaceCapabilities&& rhs) + : formatCount(rhs.formatCount), + formats(rhs.formats), + presentModeCount(rhs.presentModeCount), + presentModes(rhs.presentModes), + alphaModeCount(rhs.alphaModeCount), + alphaModes(rhs.alphaModes){ + Reset(rhs); + } + + SurfaceCapabilities& SurfaceCapabilities::operator=(SurfaceCapabilities&& rhs) { + if (&rhs == this) { + return *this; + } + this->~SurfaceCapabilities(); + AsNonConstReference(this->formatCount) = std::move(rhs.formatCount); + AsNonConstReference(this->formats) = std::move(rhs.formats); + AsNonConstReference(this->presentModeCount) = std::move(rhs.presentModeCount); + AsNonConstReference(this->presentModes) = std::move(rhs.presentModes); + AsNonConstReference(this->alphaModeCount) = std::move(rhs.alphaModeCount); + AsNonConstReference(this->alphaModes) = std::move(rhs.alphaModes); + Reset(rhs); + return *this; + } + + static_assert(sizeof(SurfaceCapabilities) == sizeof(WGPUSurfaceCapabilities), "sizeof mismatch for SurfaceCapabilities"); + static_assert(alignof(SurfaceCapabilities) == alignof(WGPUSurfaceCapabilities), "alignof mismatch for SurfaceCapabilities"); + static_assert(offsetof(SurfaceCapabilities, nextInChain) == offsetof(WGPUSurfaceCapabilities, nextInChain), + "offsetof mismatch for SurfaceCapabilities::nextInChain"); + static_assert(offsetof(SurfaceCapabilities, formatCount) == offsetof(WGPUSurfaceCapabilities, formatCount), + "offsetof mismatch for SurfaceCapabilities::formatCount"); + static_assert(offsetof(SurfaceCapabilities, formats) == offsetof(WGPUSurfaceCapabilities, formats), + "offsetof mismatch for SurfaceCapabilities::formats"); + static_assert(offsetof(SurfaceCapabilities, presentModeCount) == offsetof(WGPUSurfaceCapabilities, presentModeCount), + "offsetof mismatch for SurfaceCapabilities::presentModeCount"); + static_assert(offsetof(SurfaceCapabilities, presentModes) == offsetof(WGPUSurfaceCapabilities, presentModes), + "offsetof mismatch for SurfaceCapabilities::presentModes"); + static_assert(offsetof(SurfaceCapabilities, alphaModeCount) == offsetof(WGPUSurfaceCapabilities, alphaModeCount), + "offsetof mismatch for SurfaceCapabilities::alphaModeCount"); + static_assert(offsetof(SurfaceCapabilities, alphaModes) == offsetof(WGPUSurfaceCapabilities, alphaModes), + "offsetof mismatch for SurfaceCapabilities::alphaModes"); + + // SurfaceConfiguration + + static_assert(sizeof(SurfaceConfiguration) == sizeof(WGPUSurfaceConfiguration), "sizeof mismatch for SurfaceConfiguration"); + static_assert(alignof(SurfaceConfiguration) == alignof(WGPUSurfaceConfiguration), "alignof mismatch for SurfaceConfiguration"); + static_assert(offsetof(SurfaceConfiguration, nextInChain) == offsetof(WGPUSurfaceConfiguration, nextInChain), + "offsetof mismatch for SurfaceConfiguration::nextInChain"); + static_assert(offsetof(SurfaceConfiguration, device) == offsetof(WGPUSurfaceConfiguration, device), + "offsetof mismatch for SurfaceConfiguration::device"); + static_assert(offsetof(SurfaceConfiguration, format) == offsetof(WGPUSurfaceConfiguration, format), + "offsetof mismatch for SurfaceConfiguration::format"); + static_assert(offsetof(SurfaceConfiguration, usage) == offsetof(WGPUSurfaceConfiguration, usage), + "offsetof mismatch for SurfaceConfiguration::usage"); + static_assert(offsetof(SurfaceConfiguration, viewFormatCount) == offsetof(WGPUSurfaceConfiguration, viewFormatCount), + "offsetof mismatch for SurfaceConfiguration::viewFormatCount"); + static_assert(offsetof(SurfaceConfiguration, viewFormats) == offsetof(WGPUSurfaceConfiguration, viewFormats), + "offsetof mismatch for SurfaceConfiguration::viewFormats"); + static_assert(offsetof(SurfaceConfiguration, alphaMode) == offsetof(WGPUSurfaceConfiguration, alphaMode), + "offsetof mismatch for SurfaceConfiguration::alphaMode"); + static_assert(offsetof(SurfaceConfiguration, width) == offsetof(WGPUSurfaceConfiguration, width), + "offsetof mismatch for SurfaceConfiguration::width"); + static_assert(offsetof(SurfaceConfiguration, height) == offsetof(WGPUSurfaceConfiguration, height), + "offsetof mismatch for SurfaceConfiguration::height"); + static_assert(offsetof(SurfaceConfiguration, presentMode) == offsetof(WGPUSurfaceConfiguration, presentMode), + "offsetof mismatch for SurfaceConfiguration::presentMode"); + // SurfaceDescriptor static_assert(sizeof(SurfaceDescriptor) == sizeof(WGPUSurfaceDescriptor), "sizeof mismatch for SurfaceDescriptor"); @@ -1319,6 +1432,17 @@ namespace wgpu { static_assert(offsetof(SurfaceDescriptorFromCanvasHTMLSelector, selector) == offsetof(WGPUSurfaceDescriptorFromCanvasHTMLSelector, selector), "offsetof mismatch for SurfaceDescriptorFromCanvasHTMLSelector::selector"); + // SurfaceTexture + + static_assert(sizeof(SurfaceTexture) == sizeof(WGPUSurfaceTexture), "sizeof mismatch for SurfaceTexture"); + static_assert(alignof(SurfaceTexture) == alignof(WGPUSurfaceTexture), "alignof mismatch for SurfaceTexture"); + static_assert(offsetof(SurfaceTexture, texture) == offsetof(WGPUSurfaceTexture, texture), + "offsetof mismatch for SurfaceTexture::texture"); + static_assert(offsetof(SurfaceTexture, suboptimal) == offsetof(WGPUSurfaceTexture, suboptimal), + "offsetof mismatch for SurfaceTexture::suboptimal"); + static_assert(offsetof(SurfaceTexture, status) == offsetof(WGPUSurfaceTexture, status), + "offsetof mismatch for SurfaceTexture::status"); + // SwapChainDescriptor static_assert(sizeof(SwapChainDescriptor) == sizeof(WGPUSwapChainDescriptor), "sizeof mismatch for SwapChainDescriptor"); @@ -1798,10 +1922,6 @@ namespace wgpu { "offsetof mismatch for RenderPipelineDescriptor::multisample"); static_assert(offsetof(RenderPipelineDescriptor, fragment) == offsetof(WGPURenderPipelineDescriptor, fragment), "offsetof mismatch for RenderPipelineDescriptor::fragment"); -template - static T& AsNonConstReference(const T& value) { - return const_cast(value); - } // AdapterProperties AdapterProperties::~AdapterProperties() { @@ -2565,10 +2685,26 @@ template static_assert(sizeof(Surface) == sizeof(WGPUSurface), "sizeof mismatch for Surface"); static_assert(alignof(Surface) == alignof(WGPUSurface), "alignof mismatch for Surface"); + void Surface::Configure(SurfaceConfiguration const * config) const { + wgpuSurfaceConfigure(Get(), reinterpret_cast(config)); + } + void Surface::GetCapabilities(Adapter const& adapter, SurfaceCapabilities * capabilities) const { + *capabilities = SurfaceCapabilities(); + wgpuSurfaceGetCapabilities(Get(), adapter.Get(), reinterpret_cast(capabilities)); + } + void Surface::GetCurrentTexture(SurfaceTexture * surfaceTexture) const { + wgpuSurfaceGetCurrentTexture(Get(), reinterpret_cast(surfaceTexture)); + } TextureFormat Surface::GetPreferredFormat(Adapter const& adapter) const { auto result = wgpuSurfaceGetPreferredFormat(Get(), adapter.Get()); return static_cast(result); } + void Surface::Present() const { + wgpuSurfacePresent(Get()); + } + void Surface::Unconfigure() const { + wgpuSurfaceUnconfigure(Get()); + } void Surface::WGPUReference(WGPUSurface handle) { if (handle != nullptr) { wgpuSurfaceReference(handle); diff --git a/test/webgpu_basic_rendering.cpp b/test/webgpu_basic_rendering.cpp index a6d2b7ce2e360..f12419d4baed3 100644 --- a/test/webgpu_basic_rendering.cpp +++ b/test/webgpu_basic_rendering.cpp @@ -20,26 +20,6 @@ static const wgpu::Instance instance = wgpuCreateInstance(nullptr); -void GetDevice(void (*callback)(wgpu::Device)) { - instance.RequestAdapter(nullptr, [](WGPURequestAdapterStatus status, WGPUAdapter cAdapter, const char* message, void* userdata) { - if (message) { - printf("RequestAdapter: %s\n", message); - } - assert(status == WGPURequestAdapterStatus_Success); - - wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter); - adapter.RequestDevice(nullptr, [](WGPURequestDeviceStatus status, WGPUDevice cDevice, const char* message, void* userdata) { - if (message) { - printf("RequestDevice: %s\n", message); - } - assert(status == WGPURequestDeviceStatus_Success); - - wgpu::Device device = wgpu::Device::Acquire(cDevice); - reinterpret_cast(userdata)(device); - }, userdata); - }, reinterpret_cast(callback)); -} - static const char shaderCode[] = R"( @vertex fn main_v(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4 { @@ -54,12 +34,37 @@ static const char shaderCode[] = R"( } )"; +static wgpu::Adapter adapter; static wgpu::Device device; static wgpu::Queue queue; static wgpu::Buffer readbackBuffer; static wgpu::RenderPipeline pipeline; static int testsCompleted = 0; +void GetAdapter(void (*callback)(wgpu::Adapter)) { + instance.RequestAdapter(nullptr, [](WGPURequestAdapterStatus status, WGPUAdapter cAdapter, const char* message, void* userdata) { + if (message) { + printf("RequestAdapter: %s\n", message); + } + assert(status == WGPURequestAdapterStatus_Success); + + wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter); + reinterpret_cast(userdata)(adapter); + }, reinterpret_cast(callback)); +} + +void GetDevice(void (*callback)(wgpu::Device)) { + adapter.RequestDevice(nullptr, [](WGPURequestDeviceStatus status, WGPUDevice cDevice, const char* message, void* userdata) { + if (message) { + printf("RequestDevice: %s\n", message); + } + assert(status == WGPURequestDeviceStatus_Success); + + wgpu::Device device = wgpu::Device::Acquire(cDevice); + reinterpret_cast(userdata)(device); + }, reinterpret_cast(callback)); +} + void init() { device.SetUncapturedErrorCallback( [](WGPUErrorType errorType, const char* message, void*) { @@ -350,13 +355,16 @@ void doRenderTest() { issueContentsCheck(__FUNCTION__, readbackBuffer, expectData); } -wgpu::SwapChain swapChain; +wgpu::Surface surface; wgpu::TextureView canvasDepthStencilView; const uint32_t kWidth = 300; const uint32_t kHeight = 150; void frame() { - wgpu::TextureView backbuffer = swapChain.GetCurrentTextureView(); + wgpu::SurfaceTexture surfaceTexture; + surface.GetCurrentTexture(&surfaceTexture); + + wgpu::TextureView backbuffer = surfaceTexture.texture.CreateView(); render(backbuffer, canvasDepthStencilView); // TODO: Read back from the canvas with drawImage() (or something) and @@ -383,15 +391,22 @@ void run() { wgpu::SurfaceDescriptor surfDesc{}; surfDesc.nextInChain = &canvasDesc; - wgpu::Surface surface = instance.CreateSurface(&surfDesc); - - wgpu::SwapChainDescriptor scDesc{}; - scDesc.usage = wgpu::TextureUsage::RenderAttachment; - scDesc.format = wgpu::TextureFormat::BGRA8Unorm; - scDesc.width = kWidth; - scDesc.height = kHeight; - scDesc.presentMode = wgpu::PresentMode::Fifo; - swapChain = device.CreateSwapChain(surface, &scDesc); + surface = instance.CreateSurface(&surfDesc); + + wgpu::SurfaceCapabilities capabilities; + surface.GetCapabilities(adapter, &capabilities); + + wgpu::SurfaceConfiguration config{ + .device = device, + .format = wgpu::TextureFormat::BGRA8Unorm, + // .format = capabilities.formats[0], + .usage = wgpu::TextureUsage::RenderAttachment, + .alphaMode = capabilities.alphaModes[0], + .width = kWidth, + .height = kHeight, + // .presentMode = capabilities.presentModes[0]}; + .presentMode = wgpu::PresentMode::Fifo}; + surface.Configure(&config); { wgpu::TextureDescriptor descriptor{}; @@ -405,9 +420,12 @@ void run() { } int main() { - GetDevice([](wgpu::Device dev) { - device = dev; - run(); + GetAdapter([](wgpu::Adapter a) { + adapter = a; + GetDevice([](wgpu::Device dev) { + device = dev; + run(); + }); }); // The test result will be reported when the main_loop completes. From 767b08d29013aefd327e3446b68cf5c9164693e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Thu, 16 May 2024 11:18:13 +0200 Subject: [PATCH 2/9] Address first pass of feedback --- src/library_webgpu.js | 41 ++++++++------------------------- system/lib/webgpu/webgpu.cpp | 32 +++++++++++++++++++++++++ test/webgpu_basic_rendering.cpp | 3 +-- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index 9cd24fd8e1f24..62c9802e5f955 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -99,13 +99,6 @@ wgpu${type}Release: (id) => WebGPU.mgr${type}.release(id),`; DeviceLost: 2, Unknown: 3, }, - CompositeAlphaMode: [ - 'auto', - 'opaque', - 'premultiplied', - 'unpremultiplied', - 'inherit', - ], CreatePipelineAsyncStatus: { Success: 0, ValidationError: 1, @@ -575,14 +568,6 @@ var LibraryWebGPU = { 'store', 'discard', ], - SurfaceGetCurrentTextureStatus: [ - 'success', - 'timeout', - 'outdated', - 'lost', - 'out-of-memory', - 'device-lost', - ], TextureAspect: [ undefined, 'all', @@ -2734,26 +2719,20 @@ var LibraryWebGPU = { context.configure(configuration); }, - wgpuSurfaceGetCapabilities: (surfaceId, adapterId, capabilitiesPtr) => { - if (capabilitiesPtr !== 0) { - {{{ makeSetValue('capabilitiesPtr', C_STRUCTS.WGPUSurfaceCapabilities.formatCount, '1', 'i32') }}}; - var format = navigator["gpu"]["getPreferredCanvasFormat"](); - var formatsPtr = WebGPU.Int_PreferredFormat[format]; // FIXME - {{{ makeSetValue('capabilitiesPtr', C_STRUCTS.WGPUSurfaceCapabilities.formats, 'formatsPtr', '*') }}}; - // "presentModeCount", - // "presentModes", - // "alphaModeCount", - // "alphaModes" - } - }, - wgpuSurfaceGetCurrentTexture: (surfaceId, surfaceTexturePtr) => { + {{{ gpu.makeCheck('surfaceTexturePtr') }}} var context = WebGPU.mgrSurface.get(surfaceId); - var texture = WebGPU.mgrTexture.create(context.getCurrentTexture()); - if (surfaceTexturePtr !== 0) { + + try { + var texture = WebGPU.mgrTexture.create(context.getCurrentTexture()); {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.texture, 'texture', '*') }}}; {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.suboptimal, '0', 'i32') }}}; - {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.status, '0', 'i32') }}}; + {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.status, /*Success=*/0, 'i32') }}}; + } catch (ex) { +#if ASSERTIONS + err(`wgpuSurfaceGetCurrentTexture() failed: ${ex}`); +#endif + {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.status, /*Timeout=*/1, 'i32') }}}; } }, diff --git a/system/lib/webgpu/webgpu.cpp b/system/lib/webgpu/webgpu.cpp index 42171dee01195..cdea5dae60465 100644 --- a/system/lib/webgpu/webgpu.cpp +++ b/system/lib/webgpu/webgpu.cpp @@ -9,8 +9,19 @@ #include +#include #include +static constexpr std::array + kBGRA8UnormPreferredContextFormats = {WGPUTextureFormat_BGRA8Unorm, + WGPUTextureFormat_RGBA8Unorm, + WGPUTextureFormat_RGBA16Float}; + +static constexpr std::array + kRGBA8UnormPreferredContextFormats = {WGPUTextureFormat_RGBA8Unorm, + WGPUTextureFormat_BGRA8Unorm, + WGPUTextureFormat_RGBA16Float}; + // // WebGPU function definitions, with methods organized by "class". Note these // don't need to be extern "C" because they are already declared in webgpu.h. @@ -27,3 +38,24 @@ WGPUInstance wgpuCreateInstance(const WGPUInstanceDescriptor* descriptor) { void wgpuInstanceReference(WGPUInstance) { /* no-op for now */ } void wgpuInstanceRelease(WGPUInstance) { /* no-op for now */ } + +// WGPUSurface + +void wgpuSurfaceGetCapabilities(WGPUSurface surface, + WGPUAdapter adapter, + WGPUSurfaceCapabilities* capabilities) { + WGPUTextureFormat preferredFormat = + wgpuSurfaceGetPreferredFormat(surface, adapter); + assert(preferredFormat == WGPUTextureFormat_BGRA8Unorm || + preferredFormat == WGPUTextureFormat_RGBA8Unorm); + capabilities->formatCount = 3; + if (preferredFormat == WGPUTextureFormat_RGBA8Unorm) { + capabilities->formats = reinterpret_cast( + kBGRA8UnormPreferredContextFormats.data()); + } else { + capabilities->formats = reinterpret_cast( + kRGBA8UnormPreferredContextFormats.data()); + } + + // TODO: What do we return for presentModes and alphaModes? +}; diff --git a/test/webgpu_basic_rendering.cpp b/test/webgpu_basic_rendering.cpp index f12419d4baed3..f781b6da4f65b 100644 --- a/test/webgpu_basic_rendering.cpp +++ b/test/webgpu_basic_rendering.cpp @@ -398,8 +398,7 @@ void run() { wgpu::SurfaceConfiguration config{ .device = device, - .format = wgpu::TextureFormat::BGRA8Unorm, - // .format = capabilities.formats[0], + .format = capabilities.formats[0], .usage = wgpu::TextureUsage::RenderAttachment, .alphaMode = capabilities.alphaModes[0], .width = kWidth, From a0d767ead8b73f3b4e69d0f15620109f5af24871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Fri, 17 May 2024 08:51:39 +0200 Subject: [PATCH 3/9] Run gen_struct_info.py --- src/library_sigs.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/library_sigs.js b/src/library_sigs.js index 34b8b4426ce5f..0c135213f43b1 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -1711,9 +1711,14 @@ sigs = { wgpuShaderModuleReference__sig: 'vp', wgpuShaderModuleRelease__sig: 'vp', wgpuShaderModuleSetLabel__sig: 'vpp', + wgpuSurfaceCapabilitiesFreeMembers__sig: 'vp', + wgpuSurfaceConfigure__sig: 'vpp', + wgpuSurfaceGetCurrentTexture__sig: 'vpp', wgpuSurfaceGetPreferredFormat__sig: 'ipp', + wgpuSurfacePresent__sig: 'vp', wgpuSurfaceReference__sig: 'vp', wgpuSurfaceRelease__sig: 'vp', + wgpuSurfaceUnconfigure__sig: 'vp', wgpuSwapChainGetCurrentTexture__sig: 'pp', wgpuSwapChainGetCurrentTextureView__sig: 'pp', wgpuSwapChainPresent__sig: 'vp', From ad186cec4ce9c18e49a8b4541a536a04c4b0d721 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Fri, 17 May 2024 15:46:51 -0700 Subject: [PATCH 4/9] Apply suggestions from code review --- src/library_webgpu.js | 9 +++++++-- system/lib/webgpu/webgpu.cpp | 1 + test/webgpu_basic_rendering.cpp | 3 +-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index 62c9802e5f955..f04c24b80be02 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -2727,12 +2727,17 @@ var LibraryWebGPU = { var texture = WebGPU.mgrTexture.create(context.getCurrentTexture()); {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.texture, 'texture', '*') }}}; {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.suboptimal, '0', 'i32') }}}; - {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.status, /*Success=*/0, 'i32') }}}; + {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.status, + gpu.SurfaceGetCurrentTextureStatus.Success, 'i32') }}}; } catch (ex) { #if ASSERTIONS err(`wgpuSurfaceGetCurrentTexture() failed: ${ex}`); #endif - {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.status, /*Timeout=*/1, 'i32') }}}; + {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.texture, '0', '*') }}}; + {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.suboptimal, '0', 'i32') }}}; + // TODO(https://github.com/webgpu-native/webgpu-headers/issues/291): What should the status be here? + {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.status, + gpu.SurfaceGetCurrentTextureStatus.DeviceLost, 'i32') }}}; } }, diff --git a/system/lib/webgpu/webgpu.cpp b/system/lib/webgpu/webgpu.cpp index cdea5dae60465..40716d3f9272b 100644 --- a/system/lib/webgpu/webgpu.cpp +++ b/system/lib/webgpu/webgpu.cpp @@ -44,6 +44,7 @@ void wgpuInstanceRelease(WGPUInstance) { /* no-op for now */ } void wgpuSurfaceGetCapabilities(WGPUSurface surface, WGPUAdapter adapter, WGPUSurfaceCapabilities* capabilities) { + assert(capabilities->nextInChain == nullptr); // TODO: Return WGPUStatus_Error WGPUTextureFormat preferredFormat = wgpuSurfaceGetPreferredFormat(surface, adapter); assert(preferredFormat == WGPUTextureFormat_BGRA8Unorm || diff --git a/test/webgpu_basic_rendering.cpp b/test/webgpu_basic_rendering.cpp index f781b6da4f65b..ef7c746bf2b78 100644 --- a/test/webgpu_basic_rendering.cpp +++ b/test/webgpu_basic_rendering.cpp @@ -400,10 +400,9 @@ void run() { .device = device, .format = capabilities.formats[0], .usage = wgpu::TextureUsage::RenderAttachment, - .alphaMode = capabilities.alphaModes[0], + .alphaMode = wgpu::CompositeAlphaMode::Auto, .width = kWidth, .height = kHeight, - // .presentMode = capabilities.presentModes[0]}; .presentMode = wgpu::PresentMode::Fifo}; surface.Configure(&config); From 222ef5aab875798a0a376294280452607b595a0d Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Fri, 17 May 2024 15:47:25 -0700 Subject: [PATCH 5/9] Apply more suggestions from code review --- src/library_webgpu.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index f04c24b80be02..b6e8f2be93f53 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -154,6 +154,10 @@ wgpu${type}Release: (id) => WebGPU.mgr${type}.release(id),`; RenderPassDescriptorMaxDrawCount: 0xF, TextureBindingViewDimensionDescriptor: 0x11, }, + SurfaceGetCurrentTextureStatus: { + Success: 0, + DeviceLost: 5, + }, QueueWorkDoneStatus: { Success: 0, Error: 1, From c03ef6a64bb1970c41118b9e71cc1e4a8f6d3611 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Fri, 17 May 2024 16:04:33 -0700 Subject: [PATCH 6/9] Apply more suggestions --- src/library_webgpu.js | 8 +---- system/lib/webgpu/webgpu.cpp | 65 ++++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index b6e8f2be93f53..c22f1575c8681 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -2667,7 +2667,7 @@ var LibraryWebGPU = { // WGPUAdapterProperties wgpuAdapterPropertiesFreeMembers: (value) => { - // wgpuAdapterGetProperties does currently allocate anything + // wgpuAdapterGetProperties doesn't currently allocate anything. }, // WGPUSampler @@ -2677,12 +2677,6 @@ var LibraryWebGPU = { sampler.label = UTF8ToString(labelPtr); }, - // WGPUSurfaceCapabilities - - wgpuSurfaceCapabilitiesFreeMembers: (value) => { - // wgpuSurfaceCapabilities does currently allocate anything - }, - // WGPUSurface wgpuSurfaceConfigure: (surfaceId, config) => { diff --git a/system/lib/webgpu/webgpu.cpp b/system/lib/webgpu/webgpu.cpp index 40716d3f9272b..f14c1fddc8abe 100644 --- a/system/lib/webgpu/webgpu.cpp +++ b/system/lib/webgpu/webgpu.cpp @@ -12,16 +12,6 @@ #include #include -static constexpr std::array - kBGRA8UnormPreferredContextFormats = {WGPUTextureFormat_BGRA8Unorm, - WGPUTextureFormat_RGBA8Unorm, - WGPUTextureFormat_RGBA16Float}; - -static constexpr std::array - kRGBA8UnormPreferredContextFormats = {WGPUTextureFormat_RGBA8Unorm, - WGPUTextureFormat_BGRA8Unorm, - WGPUTextureFormat_RGBA16Float}; - // // WebGPU function definitions, with methods organized by "class". Note these // don't need to be extern "C" because they are already declared in webgpu.h. @@ -45,18 +35,49 @@ void wgpuSurfaceGetCapabilities(WGPUSurface surface, WGPUAdapter adapter, WGPUSurfaceCapabilities* capabilities) { assert(capabilities->nextInChain == nullptr); // TODO: Return WGPUStatus_Error - WGPUTextureFormat preferredFormat = - wgpuSurfaceGetPreferredFormat(surface, adapter); - assert(preferredFormat == WGPUTextureFormat_BGRA8Unorm || - preferredFormat == WGPUTextureFormat_RGBA8Unorm); - capabilities->formatCount = 3; - if (preferredFormat == WGPUTextureFormat_RGBA8Unorm) { - capabilities->formats = reinterpret_cast( - kBGRA8UnormPreferredContextFormats.data()); - } else { - capabilities->formats = reinterpret_cast( - kRGBA8UnormPreferredContextFormats.data()); + + static constexpr std::array kSurfaceFormatsRGBAFirst = { + WGPUTextureFormat_RGBA8Unorm, + WGPUTextureFormat_BGRA8Unorm, + WGPUTextureFormat_RGBA16Float, + }; + static constexpr std::array kSurfaceFormatsBGRAFirst = { + WGPUTextureFormat_BGRA8Unorm, + WGPUTextureFormat_RGBA8Unorm, + WGPUTextureFormat_RGBA16Float, + }; + WGPUTextureFormat preferredFormat = wgpuSurfaceGetPreferredFormat(surface, adapter); + switch (preferredFormat) { + case WGPUTextureFormat_RGBA8Unorm: + capabilities->formatCount = kSurfaceFormatsRGBAFirst.size(); + capabilities->formats = kSurfaceFormatsRGBAFirst.data(); + break; + case WGPUTextureFormat_BGRA8Unorm: + capabilities->formatCount = kSurfaceFormatsBGRAFirst.size(); + capabilities->formats = kSurfaceFormatsBGRAFirst.data(); + break; + default: + assert(false); + } + + { + static constexpr WGPUPresentMode kPresentMode = WGPUPresentMode_Fifo; + capabilities->presentModeCount = 1; + capabilities->presentModes = &kPresentMode; } - // TODO: What do we return for presentModes and alphaModes? + { + static constexpr std::array kAlphaModes = { + WGPUCompositeAlphaMode_Opaque, + WGPUCompositeAlphaMode_Premultiplied, + }; + capabilities->alphaModeCount = kAlphaModes.size(); + capabilities->alphaModes = kAlphaModes.data(); + } }; + +// WGPUSurfaceCapabilities + +void wgpuSurfaceCapabilitiesFreeMembers(WGPUSurfaceCapabilities value) { + // wgpuSurfaceCapabilities doesn't currently allocate anything. +} From d9dbf13fee7de337b2491036660caa9eb2f77b37 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Fri, 17 May 2024 18:05:06 -0700 Subject: [PATCH 7/9] rerun gen_sig_info --- src/library_sigs.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/library_sigs.js b/src/library_sigs.js index 0c135213f43b1..0eec5211f87b9 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -1711,7 +1711,6 @@ sigs = { wgpuShaderModuleReference__sig: 'vp', wgpuShaderModuleRelease__sig: 'vp', wgpuShaderModuleSetLabel__sig: 'vpp', - wgpuSurfaceCapabilitiesFreeMembers__sig: 'vp', wgpuSurfaceConfigure__sig: 'vpp', wgpuSurfaceGetCurrentTexture__sig: 'vpp', wgpuSurfaceGetPreferredFormat__sig: 'ipp', From 6f82930f34abf492216089128bee23f827268258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Wed, 22 May 2024 07:49:22 +0200 Subject: [PATCH 8/9] Address latest feedback --- src/library_webgpu.js | 13 ++++++++----- test/webgpu_basic_rendering.cpp | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index a802448ccaebc..d3b59d52a74a5 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -99,6 +99,9 @@ wgpu${type}Release: (id) => WebGPU.mgr${type}.release(id),`; DeviceLost: 2, Unknown: 3, }, + CompositeAlphaMode: { + Opaque: 1, + }, CreatePipelineAsyncStatus: { Success: 0, ValidationError: 1, @@ -2686,6 +2689,11 @@ var LibraryWebGPU = { var context = WebGPU.mgrSurface.get(surfaceId); #if ASSERTIONS + var viewFormatCount = {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.viewFormatCount) }}}; + var viewFormats = {{{ makeGetValue('config', C_STRUCTS.WGPUSurfaceConfiguration.viewFormats, '*') }}}; + assert(viewFormatCount === 0 && viewFormats === 0, "TODO: Support viewFormats."); + var alphaMode = {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.alphaMode) }}}; + assert({{{ gpu.CompositeAlphaMode.Opaque }}} === alphaMode, "TODO: Support alphaMode."); assert({{{ gpu.PresentMode.Fifo }}} === {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.presentMode) }}}); #endif @@ -2708,12 +2716,7 @@ var LibraryWebGPU = { "format": WebGPU.TextureFormat[ {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.format) }}}], "usage": {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.usage) }}}, - // viewFormatCount - // viewFormats "alphaMode": "opaque", - "width": canvasSize[0], - "height": canvasSize[1], - "presentMode": {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.presentMode) }}}, }; context.configure(configuration); }, diff --git a/test/webgpu_basic_rendering.cpp b/test/webgpu_basic_rendering.cpp index ef7c746bf2b78..1768a8ed7edbc 100644 --- a/test/webgpu_basic_rendering.cpp +++ b/test/webgpu_basic_rendering.cpp @@ -400,7 +400,7 @@ void run() { .device = device, .format = capabilities.formats[0], .usage = wgpu::TextureUsage::RenderAttachment, - .alphaMode = wgpu::CompositeAlphaMode::Auto, + .alphaMode = wgpu::CompositeAlphaMode::Opaque, .width = kWidth, .height = kHeight, .presentMode = wgpu::PresentMode::Fifo}; From 8390ae315f6168d1f95c3db0246480c52e29d419 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Wed, 22 May 2024 18:29:40 -0700 Subject: [PATCH 9/9] also allow CompositeAlphaMode::Auto --- src/library_webgpu.js | 5 ++++- test/webgpu_basic_rendering.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index d3b59d52a74a5..5a849eb5141a7 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -100,6 +100,7 @@ wgpu${type}Release: (id) => WebGPU.mgr${type}.release(id),`; Unknown: 3, }, CompositeAlphaMode: { + Auto: 0, Opaque: 1, }, CreatePipelineAsyncStatus: { @@ -2693,7 +2694,9 @@ var LibraryWebGPU = { var viewFormats = {{{ makeGetValue('config', C_STRUCTS.WGPUSurfaceConfiguration.viewFormats, '*') }}}; assert(viewFormatCount === 0 && viewFormats === 0, "TODO: Support viewFormats."); var alphaMode = {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.alphaMode) }}}; - assert({{{ gpu.CompositeAlphaMode.Opaque }}} === alphaMode, "TODO: Support alphaMode."); + assert(alphaMode === {{{ gpu.CompositeAlphaMode.Auto }}} || + alphaMode === {{{ gpu.CompositeAlphaMode.Opaque }}}, + "TODO: Support WGPUCompositeAlphaMode_Premultiplied."); assert({{{ gpu.PresentMode.Fifo }}} === {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.presentMode) }}}); #endif diff --git a/test/webgpu_basic_rendering.cpp b/test/webgpu_basic_rendering.cpp index 1768a8ed7edbc..ef7c746bf2b78 100644 --- a/test/webgpu_basic_rendering.cpp +++ b/test/webgpu_basic_rendering.cpp @@ -400,7 +400,7 @@ void run() { .device = device, .format = capabilities.formats[0], .usage = wgpu::TextureUsage::RenderAttachment, - .alphaMode = wgpu::CompositeAlphaMode::Opaque, + .alphaMode = wgpu::CompositeAlphaMode::Auto, .width = kWidth, .height = kHeight, .presentMode = wgpu::PresentMode::Fifo};