sparkbun 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/bin/sparkbun.cjs +18 -0
  2. package/dist-linux-arm64/bsdiff +0 -0
  3. package/dist-linux-arm64/bspatch +0 -0
  4. package/dist-linux-arm64/libElectrobunCore.so +0 -0
  5. package/dist-linux-arm64/libNativeWrapper.so +0 -0
  6. package/dist-linux-arm64/libasar.so +0 -0
  7. package/dist-linux-x64/bsdiff +0 -0
  8. package/dist-linux-x64/bspatch +0 -0
  9. package/dist-linux-x64/libElectrobunCore.so +0 -0
  10. package/dist-linux-x64/libNativeWrapper.so +0 -0
  11. package/dist-linux-x64/libasar.so +0 -0
  12. package/dist-macos-arm64/bsdiff +0 -0
  13. package/dist-macos-arm64/bspatch +0 -0
  14. package/dist-macos-arm64/libElectrobunCore.dylib +0 -0
  15. package/dist-macos-arm64/libNativeWrapper.dylib +0 -0
  16. package/dist-macos-arm64/libasar.dylib +0 -0
  17. package/dist-macos-arm64/libwebgpu_dawn.dylib +0 -0
  18. package/dist-macos-arm64/preload-full.js +885 -0
  19. package/dist-macos-arm64/preload-sandboxed.js +111 -0
  20. package/dist-macos-arm64/process_helper +0 -0
  21. package/dist-win-x64/ElectrobunCore.dll +0 -0
  22. package/dist-win-x64/WebView2Loader.dll +0 -0
  23. package/dist-win-x64/bsdiff.exe +0 -0
  24. package/dist-win-x64/bspatch.exe +0 -0
  25. package/dist-win-x64/libNativeWrapper.dll +0 -0
  26. package/dist-win-x64/zig-asar/arm64/libasar.dll +0 -0
  27. package/dist-win-x64/zig-asar/x64/libasar.dll +0 -0
  28. package/package.json +47 -0
  29. package/scripts/build-and-upload-artifacts.js +207 -0
  30. package/scripts/gen-webgpu-ffi.mjs +162 -0
  31. package/scripts/install-windows-deps.ps1 +80 -0
  32. package/scripts/package-release.js +237 -0
  33. package/scripts/push-version.js +84 -0
  34. package/scripts/update-bun-version.ts +122 -0
  35. package/scripts/update-cef-version.ts +145 -0
  36. package/src/browser/builtinrpcSchema.ts +19 -0
  37. package/src/browser/global.d.ts +36 -0
  38. package/src/browser/index.ts +234 -0
  39. package/src/browser/webviewtag.ts +88 -0
  40. package/src/browser/wgputag.ts +48 -0
  41. package/src/bun/SparkBunConfig.ts +497 -0
  42. package/src/bun/__tests__/ffi-contract.test.ts +105 -0
  43. package/src/bun/core/ApplicationMenu.ts +70 -0
  44. package/src/bun/core/BrowserView.ts +416 -0
  45. package/src/bun/core/BrowserWindow.ts +396 -0
  46. package/src/bun/core/BuildConfig.ts +71 -0
  47. package/src/bun/core/ContextMenu.ts +75 -0
  48. package/src/bun/core/GpuWindow.ts +289 -0
  49. package/src/bun/core/Paths.ts +5 -0
  50. package/src/bun/core/Socket.ts +22 -0
  51. package/src/bun/core/Tray.ts +197 -0
  52. package/src/bun/core/Updater.ts +1131 -0
  53. package/src/bun/core/Utils.ts +487 -0
  54. package/src/bun/core/WGPUView.ts +167 -0
  55. package/src/bun/core/menuRoles.ts +181 -0
  56. package/src/bun/events/ApplicationEvents.ts +22 -0
  57. package/src/bun/events/event.ts +27 -0
  58. package/src/bun/events/eventEmitter.ts +45 -0
  59. package/src/bun/events/trayEvents.ts +11 -0
  60. package/src/bun/events/webviewEvents.ts +39 -0
  61. package/src/bun/events/windowEvents.ts +23 -0
  62. package/src/bun/index.ts +120 -0
  63. package/src/bun/preload/.generated/compiled.ts +2 -0
  64. package/src/bun/preload/build.ts +65 -0
  65. package/src/bun/preload/dragRegions.ts +41 -0
  66. package/src/bun/preload/encryption.ts +86 -0
  67. package/src/bun/preload/events.ts +171 -0
  68. package/src/bun/preload/globals.d.ts +45 -0
  69. package/src/bun/preload/index-sandboxed.ts +28 -0
  70. package/src/bun/preload/index.ts +77 -0
  71. package/src/bun/preload/internalRpc.ts +80 -0
  72. package/src/bun/preload/overlaySync.ts +107 -0
  73. package/src/bun/preload/webviewTag.ts +451 -0
  74. package/src/bun/preload/wgpuTag.ts +246 -0
  75. package/src/bun/proc/linux.md +43 -0
  76. package/src/bun/proc/native.ts +3253 -0
  77. package/src/bun/webGPU.ts +346 -0
  78. package/src/bun/webgpuAdapter.ts +3011 -0
  79. package/src/cli/bun.lockb +0 -0
  80. package/src/cli/index.ts +4653 -0
  81. package/src/cli/package-lock.json +81 -0
  82. package/src/cli/package.json +11 -0
  83. package/src/cli/templates/embedded.ts +2 -0
  84. package/src/core/build.zig +16 -0
  85. package/src/core/main.zig +3378 -0
  86. package/src/extractor/build.zig +22 -0
  87. package/src/installer/installer-template.ts +216 -0
  88. package/src/launcher/main.ts +221 -0
  89. package/src/native/build/libNativeWrapper.so +0 -0
  90. package/src/native/linux/build/nativeWrapper.o +0 -0
  91. package/src/native/linux/cef_loader.cpp +110 -0
  92. package/src/native/linux/cef_loader.h +28 -0
  93. package/src/native/linux/cef_process_helper_linux.cpp +160 -0
  94. package/src/native/linux/nativeWrapper.cpp +11768 -0
  95. package/src/native/macos/cef_process_helper_mac.cc +160 -0
  96. package/src/native/macos/nativeWrapper.mm +9172 -0
  97. package/src/native/shared/accelerator_parser.h +72 -0
  98. package/src/native/shared/app_paths.h +110 -0
  99. package/src/native/shared/asar.h +35 -0
  100. package/src/native/shared/cache_migration.h +244 -0
  101. package/src/native/shared/callbacks.h +57 -0
  102. package/src/native/shared/cef_response_filter.h +189 -0
  103. package/src/native/shared/chromium_flags.h +181 -0
  104. package/src/native/shared/config.h +66 -0
  105. package/src/native/shared/download_event.h +197 -0
  106. package/src/native/shared/ffi_helpers.h +139 -0
  107. package/src/native/shared/glob_match.h +59 -0
  108. package/src/native/shared/json_menu_parser.h +223 -0
  109. package/src/native/shared/mime_types.h +101 -0
  110. package/src/native/shared/navigation_rules.h +98 -0
  111. package/src/native/shared/partition_context.h +137 -0
  112. package/src/native/shared/pending_resize_queue.h +45 -0
  113. package/src/native/shared/permissions.h +118 -0
  114. package/src/native/shared/permissions_cef.h +74 -0
  115. package/src/native/shared/preload_script.h +71 -0
  116. package/src/native/shared/shutdown_guard.h +134 -0
  117. package/src/native/shared/thread_safe_map.h +138 -0
  118. package/src/native/shared/webview_storage.h +91 -0
  119. package/src/native/win/cef_process_helper_win.cpp +143 -0
  120. package/src/native/win/dcomp_compositor.h +352 -0
  121. package/src/native/win/nativeWrapper.cpp +12434 -0
  122. package/src/npmbin/index.js +34 -0
  123. package/src/shared/bun-version.ts +3 -0
  124. package/src/shared/cef-version.ts +5 -0
  125. package/src/shared/naming.test.ts +327 -0
  126. package/src/shared/naming.ts +188 -0
  127. package/src/shared/platform.ts +48 -0
  128. package/src/shared/rpc.ts +541 -0
  129. package/src/shared/sparkbun-version.ts +2 -0
  130. package/src/types/three.d.ts +1 -0
  131. package/tsconfig.json +31 -0
@@ -0,0 +1,3011 @@
1
+ // @ts-nocheck
2
+ import { WGPUView } from "./core/WGPUView";
3
+ import { GpuWindow } from "./core/GpuWindow";
4
+ import WGPU from "./webGPU";
5
+ import { WGPUBridge } from "./proc/native";
6
+ import { ptr, CString, toArrayBuffer, type Pointer, JSCallback } from "bun:ffi";
7
+ import { inflateSync } from "zlib";
8
+
9
+ const WGPUNative = WGPU.native;
10
+ const WGPUTextureFormat_BGRA8Unorm = 0x0000001B;
11
+ const WGPUTextureFormat_BGRA8UnormSrgb = 0x0000001C;
12
+ const WGPUTextureFormat_RGBA8Unorm = 0x00000016;
13
+ const WGPUTextureFormat_RGBA8UnormSrgb = 0x00000017;
14
+ const WGPUTextureFormat_Depth24Plus = 0x0000002E;
15
+ const WGPUTextureFormat_Depth24PlusStencil8 = 0x0000002F;
16
+ const WGPUTextureFormat_Depth32Float = 0x00000030;
17
+ const WGPUTextureFormat_Depth16Unorm = 0x0000002D;
18
+ const WGPUTextureFormat_Depth32FloatStencil8 = 0x00000031;
19
+ const WGPUTextureFormat_RGBA32Sint = 0x0000002B;
20
+ const WGPUTextureFormat_RGBA32Uint = 0x0000002A;
21
+ const WGPUTextureFormat_RGBA16Sint = 0x00000027;
22
+ const WGPUTextureFormat_RGBA16Uint = 0x00000026;
23
+ const WGPUTextureFormat_RGBA16Float = 0x00000028;
24
+ const WGPUTextureFormat_RG32Sint = 0x00000023;
25
+ const WGPUTextureFormat_RG32Uint = 0x00000022;
26
+ const WGPUTextureFormat_RG32Float = 0x00000021;
27
+ const WGPUTextureFormat_R32Sint = 0x00000010;
28
+ const WGPUTextureFormat_R32Uint = 0x0000000F;
29
+ const WGPUTextureFormat_R32Float = 0x0000000E;
30
+ const WGPUTextureFormat_RGBA8Snorm = 0x00000018;
31
+ const WGPUTextureFormat_RGBA8Uint = 0x00000019;
32
+ const WGPUTextureFormat_RGBA8Sint = 0x0000001A;
33
+ const WGPUTextureFormat_RG8Unorm = 0x0000000A;
34
+ const WGPUTextureFormat_RG8Snorm = 0x0000000B;
35
+ const WGPUTextureFormat_RG8Uint = 0x0000000C;
36
+ const WGPUTextureFormat_RG8Sint = 0x0000000D;
37
+ const WGPUTextureFormat_R8Unorm = 0x00000001;
38
+ const WGPUTextureFormat_R8Snorm = 0x00000002;
39
+ const WGPUTextureFormat_R8Uint = 0x00000003;
40
+ const WGPUTextureFormat_R8Sint = 0x00000004;
41
+ const WGPUTextureUsage_RenderAttachment = 0x0000000000000010n;
42
+ const WGPUTextureUsage_CopyDst = 0x0000000000000002n;
43
+ const WGPUTextureUsage_CopySrc = 0x0000000000000001n;
44
+ const WGPUTextureUsage_TextureBinding = 0x0000000000000004n;
45
+ const WGPUTextureUsage_StorageBinding = 0x0000000000000008n;
46
+ const WGPUTextureUsage_TransientAttachment = 0x0000000000000020n;
47
+ const WGPUTextureUsage_Present = 0x0000000000000040n;
48
+ const WGPUPresentMode_Fifo = 0x00000001;
49
+ const WGPUCompositeAlphaMode_Opaque = 0x00000001;
50
+ const WGPUCompositeAlphaMode_Premultiplied = 0x00000002;
51
+ const WGPUCompositeAlphaMode_Unpremultiplied = 0x00000003;
52
+ const WGPUVertexFormat_Float32 = 0x0000001C;
53
+ const WGPUVertexFormat_Float32x2 = 0x0000001D;
54
+ const WGPUVertexFormat_Float32x3 = 0x0000001E;
55
+ const WGPUVertexFormat_Float32x4 = 0x0000001F;
56
+ const WGPUVertexFormat_Uint32 = 0x00000020;
57
+ const WGPUVertexFormat_Uint32x2 = 0x00000021;
58
+ const WGPUVertexFormat_Uint32x3 = 0x00000022;
59
+ const WGPUVertexFormat_Uint32x4 = 0x00000023;
60
+ const WGPUVertexFormat_Sint32 = 0x00000024;
61
+ const WGPUVertexFormat_Sint32x2 = 0x00000025;
62
+ const WGPUVertexFormat_Sint32x3 = 0x00000026;
63
+ const WGPUVertexFormat_Sint32x4 = 0x00000027;
64
+ const WGPUVertexStepMode_Vertex = 0x00000001;
65
+ const WGPUVertexStepMode_Instance = 0x00000002;
66
+ const WGPUPrimitiveTopology_PointList = 0x00000001;
67
+ const WGPUPrimitiveTopology_LineList = 0x00000002;
68
+ const WGPUPrimitiveTopology_LineStrip = 0x00000003;
69
+ const WGPUPrimitiveTopology_TriangleList = 0x00000004;
70
+ const WGPUPrimitiveTopology_TriangleStrip = 0x00000005;
71
+ const WGPUFrontFace_CCW = 0x00000001;
72
+ const WGPUFrontFace_CW = 0x00000002;
73
+ const WGPUCullMode_None = 0x00000001;
74
+ const WGPUCullMode_Front = 0x00000002;
75
+ const WGPUCullMode_Back = 0x00000003;
76
+ const WGPULoadOp_Load = 0x00000001;
77
+ const WGPULoadOp_Clear = 0x00000002;
78
+ const WGPUStoreOp_Store = 0x00000001;
79
+ const WGPUStoreOp_Discard = 0x00000002;
80
+ const WGPUTextureDimension_2D = 0x00000002;
81
+ const WGPUTextureViewDimension_2D = 0x00000002;
82
+ const WGPUTextureViewDimension_2DArray = 0x00000003;
83
+ const WGPUTextureViewDimension_3D = 0x00000006;
84
+ const WGPUTextureViewDimension_Cube = 0x00000004;
85
+ const WGPUTextureViewDimension_CubeArray = 0x00000005;
86
+ const WGPUTextureAspect_All = 0x00000001;
87
+ const WGPUTextureAspect_StencilOnly = 0x00000002;
88
+ const WGPUTextureAspect_DepthOnly = 0x00000003;
89
+ const WGPUCompareFunction_Never = 0x00000001;
90
+ const WGPUCompareFunction_Less = 0x00000002;
91
+ const WGPUCompareFunction_Equal = 0x00000003;
92
+ const WGPUCompareFunction_LessEqual = 0x00000004;
93
+ const WGPUCompareFunction_Greater = 0x00000005;
94
+ const WGPUCompareFunction_NotEqual = 0x00000006;
95
+ const WGPUCompareFunction_GreaterEqual = 0x00000007;
96
+ const WGPUCompareFunction_Always = 0x00000008;
97
+ const WGPUAddressMode_ClampToEdge = 0x00000001;
98
+ const WGPUAddressMode_Repeat = 0x00000002;
99
+ const WGPUAddressMode_MirrorRepeat = 0x00000003;
100
+ const WGPUFilterMode_Nearest = 0x00000001;
101
+ const WGPUFilterMode_Linear = 0x00000002;
102
+ const WGPUMipmapFilterMode_Nearest = 0x00000001;
103
+ const WGPUMipmapFilterMode_Linear = 0x00000002;
104
+ const WGPUBufferUsage_MapRead = 0x0000000000000001n;
105
+ const WGPUBufferUsage_MapWrite = 0x0000000000000002n;
106
+ const WGPUBufferUsage_CopySrc = 0x0000000000000004n;
107
+ const WGPUBufferUsage_CopyDst = 0x0000000000000008n;
108
+ const WGPUBufferUsage_Index = 0x0000000000000010n;
109
+ const WGPUBufferUsage_Vertex = 0x0000000000000020n;
110
+ const WGPUBufferUsage_Uniform = 0x0000000000000040n;
111
+ const WGPUBufferUsage_Storage = 0x0000000000000080n;
112
+ const WGPUBufferUsage_Indirect = 0x0000000000000100n;
113
+ const WGPUBufferUsage_QueryResolve = 0x0000000000000200n;
114
+ const WGPUMapMode_Read = 0x0000000000000001n;
115
+ const WGPUMapMode_Write = 0x0000000000000002n;
116
+ const WGPUCallbackMode_AllowSpontaneous = 0x00000003;
117
+ const WGPUBufferMapState_Mapped = 0x00000003;
118
+ const WGPUMapAsyncStatus_Success = 0x00000001;
119
+ const WGPUQueueWorkDoneStatus_Success = 0x00000001;
120
+ const WGPUColorWriteMask_All = 0x000000000000000F;
121
+ const WGPUBlendOperation_Add = 0x00000001;
122
+ const WGPUBlendFactor_One = 0x00000002;
123
+ const WGPUBlendFactor_Zero = 0x00000001;
124
+ const WGPUBlendFactor_SrcAlpha = 0x00000005;
125
+ const WGPUBlendFactor_OneMinusSrcAlpha = 0x00000006;
126
+ const WGPUShaderStage_Vertex = 0x0000000000000001;
127
+ const WGPUShaderStage_Fragment = 0x0000000000000002;
128
+ const WGPUShaderStage_Compute = 0x0000000000000004;
129
+ const WGPUBufferBindingType_Uniform = 0x00000002;
130
+ const WGPUBufferBindingType_Storage = 0x00000003;
131
+ const WGPUBufferBindingType_ReadOnlyStorage = 0x00000004;
132
+ const WGPUSamplerBindingType_Filtering = 0x00000002;
133
+ const WGPUSamplerBindingType_NonFiltering = 0x00000003;
134
+ const WGPUSamplerBindingType_Comparison = 0x00000004;
135
+ const WGPUTextureSampleType_Float = 0x00000002;
136
+ const WGPUTextureSampleType_UnfilterableFloat = 0x00000003;
137
+ const WGPUTextureSampleType_Depth = 0x00000004;
138
+ const WGPUTextureSampleType_Sint = 0x00000005;
139
+ const WGPUTextureSampleType_Uint = 0x00000006;
140
+ const WGPUStorageTextureAccess_WriteOnly = 0x00000002;
141
+ const WGPUStorageTextureAccess_ReadOnly = 0x00000003;
142
+ const WGPUStorageTextureAccess_ReadWrite = 0x00000004;
143
+ const WGPU_STRLEN = 0xffffffffffffffffn;
144
+ const WGPU_DEPTH_SLICE_UNDEFINED = 0xffffffff;
145
+
146
+ const WGPU_KEEPALIVE: any[] = [];
147
+ let LAST_SURFACE_PTR: number | null = null;
148
+ let LAST_SURFACE_HAS_TEXTURE = false;
149
+ let LAST_CREATED_CONTEXT: GPUCanvasContext | null = null;
150
+ const VIEW_CONTEXTS = new Map<number, { instance: number; surface: number; context: GPUCanvasContext }>();
151
+ const MAP_ASYNC_RESOLVERS = new Map<number, (mapped: boolean) => void>();
152
+ const WORK_DONE_RESOLVERS = new Map<number, (ok: boolean) => void>();
153
+
154
+ const bufferMapCallback = new JSCallback(
155
+ (status: number, _message: number, userdata1: number, _userdata2: number) => {
156
+ const key = Number(userdata1);
157
+ const resolve = MAP_ASYNC_RESOLVERS.get(key);
158
+ if (resolve) {
159
+ MAP_ASYNC_RESOLVERS.delete(key);
160
+ resolve(status === WGPUMapAsyncStatus_Success);
161
+ }
162
+ },
163
+ {
164
+ args: ["u32", "ptr", "ptr", "ptr"],
165
+ returns: "void",
166
+ threadsafe: true,
167
+ },
168
+ );
169
+ WGPU_KEEPALIVE.push(bufferMapCallback);
170
+
171
+ const queueWorkDoneCallback = new JSCallback(
172
+ (status: number, _message: number, userdata1: number, _userdata2: number) => {
173
+ const key = Number(userdata1);
174
+ const resolve = WORK_DONE_RESOLVERS.get(key);
175
+ if (resolve) {
176
+ WORK_DONE_RESOLVERS.delete(key);
177
+ resolve(status === WGPUQueueWorkDoneStatus_Success);
178
+ }
179
+ },
180
+ {
181
+ args: ["u32", "ptr", "ptr", "ptr"],
182
+ returns: "void",
183
+ threadsafe: true,
184
+ },
185
+ );
186
+ WGPU_KEEPALIVE.push(queueWorkDoneCallback);
187
+
188
+ function toBigInt(value: unknown, fallback = 0n) {
189
+ if (typeof value === "bigint") return value;
190
+ if (typeof value === "number" && Number.isFinite(value)) {
191
+ return BigInt(Math.trunc(value));
192
+ }
193
+ if (typeof value === "string") {
194
+ const trimmed = value.trim();
195
+ if (/^(0x[0-9a-fA-F]+|\d+)$/.test(trimmed)) {
196
+ return BigInt(trimmed);
197
+ }
198
+ }
199
+ return fallback;
200
+ }
201
+
202
+ function writePtr(view: DataView, offset: number, value: number | bigint | null) {
203
+ view.setBigUint64(offset, toBigInt(value ?? 0), true);
204
+ }
205
+
206
+ function writeU32(view: DataView, offset: number, value: number | bigint) {
207
+ view.setUint32(offset, Number(value) >>> 0, true);
208
+ }
209
+
210
+ function writeU64(view: DataView, offset: number, value: bigint | number | string) {
211
+ view.setBigUint64(offset, toBigInt(value), true);
212
+ }
213
+
214
+ function writeF32(view: DataView, offset: number, value: number) {
215
+ view.setFloat32(offset, value, true);
216
+ }
217
+
218
+ function writeF64(view: DataView, offset: number, value: number) {
219
+ view.setFloat64(offset, value, true);
220
+ }
221
+
222
+ function makeStringView(str?: string | null) {
223
+ if (!str) {
224
+ return { ptr: 0, len: 0n, cstr: null };
225
+ }
226
+ const cstr = new CString(str);
227
+ WGPU_KEEPALIVE.push(cstr);
228
+ return { ptr: cstr.ptr, len: WGPU_STRLEN, cstr };
229
+ }
230
+
231
+ function makeSurfaceConfiguration(
232
+ devicePtr: number,
233
+ width: number,
234
+ height: number,
235
+ format: number,
236
+ alphaMode: number,
237
+ usage: bigint = WGPUTextureUsage_RenderAttachment,
238
+ ) {
239
+ const buffer = new ArrayBuffer(64);
240
+ const view = new DataView(buffer);
241
+ writePtr(view, 0, 0);
242
+ writePtr(view, 8, devicePtr);
243
+ writeU32(view, 16, format);
244
+ writeU32(view, 20, 0);
245
+ writeU64(view, 24, usage);
246
+ writeU32(view, 32, width);
247
+ writeU32(view, 36, height);
248
+ writeU64(view, 40, 0n);
249
+ writePtr(view, 48, 0);
250
+ writeU32(view, 56, alphaMode);
251
+ writeU32(view, 60, WGPUPresentMode_Fifo);
252
+ return { buffer, ptr: ptr(buffer) };
253
+ }
254
+
255
+ function makeBufferDescriptor(
256
+ size: number,
257
+ usage: bigint,
258
+ mappedAtCreation: boolean,
259
+ ) {
260
+ const buffer = new ArrayBuffer(48);
261
+ const view = new DataView(buffer);
262
+ writePtr(view, 0, 0);
263
+ writePtr(view, 8, 0);
264
+ writeU64(view, 16, 0n);
265
+ writeU64(view, 24, usage);
266
+ writeU64(view, 32, BigInt(size));
267
+ writeU32(view, 40, mappedAtCreation ? 1 : 0);
268
+ writeU32(view, 44, 0);
269
+ return { buffer, ptr: ptr(buffer) };
270
+ }
271
+
272
+ function makeTextureDescriptor(
273
+ width: number,
274
+ height: number,
275
+ depthOrArrayLayers: number,
276
+ format: number,
277
+ usage: bigint,
278
+ mipLevelCount = 1,
279
+ sampleCount = 1,
280
+ viewFormatsPtr: number | null = null,
281
+ viewFormatCount = 0,
282
+ ) {
283
+ const buffer = new ArrayBuffer(80);
284
+ const view = new DataView(buffer);
285
+ writePtr(view, 0, 0); // nextInChain
286
+ writePtr(view, 8, 0); // label.ptr
287
+ writeU64(view, 16, 0n); // label.length
288
+ writeU64(view, 24, usage);
289
+ writeU32(view, 32, WGPUTextureDimension_2D);
290
+ writeU32(view, 36, width);
291
+ writeU32(view, 40, height);
292
+ writeU32(view, 44, depthOrArrayLayers);
293
+ writeU32(view, 48, format);
294
+ writeU32(view, 52, mipLevelCount);
295
+ writeU32(view, 56, sampleCount);
296
+ writeU32(view, 60, 0); // padding for size_t alignment
297
+ writeU64(view, 64, BigInt(viewFormatCount));
298
+ writePtr(view, 72, viewFormatsPtr ?? 0);
299
+ return { buffer, ptr: ptr(buffer) };
300
+ }
301
+
302
+ function makeTextureViewDescriptor(options?: {
303
+ format?: number;
304
+ dimension?: number;
305
+ baseMipLevel?: number;
306
+ mipLevelCount?: number;
307
+ baseArrayLayer?: number;
308
+ arrayLayerCount?: number;
309
+ aspect?: number;
310
+ usage?: bigint;
311
+ }) {
312
+ const buffer = new ArrayBuffer(64);
313
+ const view = new DataView(buffer);
314
+ writePtr(view, 0, 0);
315
+ writePtr(view, 8, 0);
316
+ writeU64(view, 16, 0n);
317
+ writeU32(view, 24, options?.format ?? 0);
318
+ writeU32(view, 28, options?.dimension ?? 0);
319
+ writeU32(view, 32, options?.baseMipLevel ?? 0);
320
+ writeU32(view, 36, options?.mipLevelCount ?? 0xffffffff);
321
+ writeU32(view, 40, options?.baseArrayLayer ?? 0);
322
+ writeU32(view, 44, options?.arrayLayerCount ?? 0xffffffff);
323
+ writeU32(view, 48, options?.aspect ?? 0);
324
+ writeU32(view, 52, 0);
325
+ writeU64(view, 56, options?.usage ?? 0n);
326
+ return { buffer, ptr: ptr(buffer) };
327
+ }
328
+
329
+ function makeSamplerDescriptor(options?: {
330
+ addressModeU?: number;
331
+ addressModeV?: number;
332
+ addressModeW?: number;
333
+ magFilter?: number;
334
+ minFilter?: number;
335
+ mipmapFilter?: number;
336
+ lodMinClamp?: number;
337
+ lodMaxClamp?: number;
338
+ compare?: number;
339
+ maxAnisotropy?: number;
340
+ }) {
341
+ const buffer = new ArrayBuffer(64);
342
+ const view = new DataView(buffer);
343
+ writePtr(view, 0, 0);
344
+ writePtr(view, 8, 0);
345
+ writeU64(view, 16, 0n);
346
+ writeU32(view, 24, options?.addressModeU ?? WGPUAddressMode_ClampToEdge);
347
+ writeU32(view, 28, options?.addressModeV ?? WGPUAddressMode_ClampToEdge);
348
+ writeU32(view, 32, options?.addressModeW ?? WGPUAddressMode_ClampToEdge);
349
+ writeU32(view, 36, options?.magFilter ?? WGPUFilterMode_Linear);
350
+ writeU32(view, 40, options?.minFilter ?? WGPUFilterMode_Linear);
351
+ writeU32(view, 44, options?.mipmapFilter ?? WGPUMipmapFilterMode_Linear);
352
+ writeF32(view, 48, options?.lodMinClamp ?? 0);
353
+ writeF32(view, 52, options?.lodMaxClamp ?? 32);
354
+ writeU32(view, 56, options?.compare ?? 0);
355
+ view.setUint16(60, options?.maxAnisotropy ?? 1, true);
356
+ view.setUint16(62, 0, true);
357
+ return { buffer, ptr: ptr(buffer) };
358
+ }
359
+
360
+ function makeVertexAttribute(
361
+ offset: number,
362
+ shaderLocation: number,
363
+ format: number,
364
+ ) {
365
+ const buffer = new ArrayBuffer(32);
366
+ const view = new DataView(buffer);
367
+ writePtr(view, 0, 0);
368
+ writeU32(view, 8, format);
369
+ writeU32(view, 12, 0);
370
+ writeU64(view, 16, BigInt(offset));
371
+ writeU32(view, 24, shaderLocation);
372
+ writeU32(view, 28, 0);
373
+ return { buffer, ptr: ptr(buffer) };
374
+ }
375
+
376
+ function makeVertexBufferLayout(
377
+ attributePtr: number,
378
+ attributeCount: number,
379
+ arrayStride: bigint,
380
+ stepMode: number,
381
+ ) {
382
+ const buffer = new ArrayBuffer(40);
383
+ const view = new DataView(buffer);
384
+ writePtr(view, 0, 0);
385
+ writeU32(view, 8, stepMode);
386
+ writeU32(view, 12, 0);
387
+ writeU64(view, 16, arrayStride);
388
+ writeU64(view, 24, BigInt(attributeCount));
389
+ writePtr(view, 32, attributePtr);
390
+ return { buffer, ptr: ptr(buffer) };
391
+ }
392
+
393
+ function makeVertexState(
394
+ modulePtr: number,
395
+ entryPoint: { ptr: number; len: bigint },
396
+ bufferLayoutPtr: number,
397
+ bufferLayoutCount: number,
398
+ ) {
399
+ const buffer = new ArrayBuffer(64);
400
+ const view = new DataView(buffer);
401
+ writePtr(view, 0, 0);
402
+ writePtr(view, 8, modulePtr);
403
+ writePtr(view, 16, entryPoint.ptr);
404
+ writeU64(view, 24, entryPoint.len);
405
+ writeU64(view, 32, 0n);
406
+ writePtr(view, 40, 0);
407
+ writeU64(view, 48, BigInt(bufferLayoutCount));
408
+ writePtr(view, 56, bufferLayoutPtr);
409
+ return { buffer, ptr: ptr(buffer) };
410
+ }
411
+
412
+ function makeFragmentState(
413
+ modulePtr: number,
414
+ entryPoint: { ptr: number; len: bigint },
415
+ targetPtr: number,
416
+ targetCount: number,
417
+ ) {
418
+ const buffer = new ArrayBuffer(64);
419
+ const view = new DataView(buffer);
420
+ writePtr(view, 0, 0);
421
+ writePtr(view, 8, modulePtr);
422
+ writePtr(view, 16, entryPoint.ptr);
423
+ writeU64(view, 24, entryPoint.len);
424
+ writeU64(view, 32, 0n);
425
+ writePtr(view, 40, 0);
426
+ writeU64(view, 48, BigInt(targetCount));
427
+ writePtr(view, 56, targetPtr);
428
+ return { buffer, ptr: ptr(buffer) };
429
+ }
430
+
431
+ function makeColorTargetState(
432
+ format: number,
433
+ blendPtr: number | null,
434
+ writeMask = WGPUColorWriteMask_All,
435
+ ) {
436
+ const buffer = new ArrayBuffer(32);
437
+ const view = new DataView(buffer);
438
+ writePtr(view, 0, 0);
439
+ writeU32(view, 8, format);
440
+ writeU32(view, 12, 0);
441
+ writePtr(view, 16, blendPtr ?? 0);
442
+ writeU64(view, 24, BigInt(writeMask));
443
+ return { buffer, ptr: ptr(buffer) };
444
+ }
445
+
446
+ function makeBlendComponent(
447
+ operation: number,
448
+ srcFactor: number,
449
+ dstFactor: number,
450
+ ) {
451
+ const buffer = new ArrayBuffer(12);
452
+ const view = new DataView(buffer);
453
+ writeU32(view, 0, operation);
454
+ writeU32(view, 4, srcFactor);
455
+ writeU32(view, 8, dstFactor);
456
+ return { buffer, ptr: ptr(buffer) };
457
+ }
458
+
459
+ function makeBlendState(color: ArrayBuffer, alpha: ArrayBuffer) {
460
+ const buffer = new ArrayBuffer(24);
461
+ new Uint8Array(buffer, 0, 12).set(new Uint8Array(color, 0, 12));
462
+ new Uint8Array(buffer, 12, 12).set(new Uint8Array(alpha, 0, 12));
463
+ return { buffer, ptr: ptr(buffer) };
464
+ }
465
+
466
+ function makePrimitiveState(options?: {
467
+ topology?: number;
468
+ stripIndexFormat?: number;
469
+ frontFace?: number;
470
+ cullMode?: number;
471
+ unclippedDepth?: number;
472
+ }) {
473
+ const buffer = new ArrayBuffer(32);
474
+ const view = new DataView(buffer);
475
+ writePtr(view, 0, 0);
476
+ writeU32(view, 8, options?.topology ?? WGPUPrimitiveTopology_TriangleList);
477
+ writeU32(view, 12, options?.stripIndexFormat ?? 0);
478
+ writeU32(view, 16, options?.frontFace ?? WGPUFrontFace_CCW);
479
+ writeU32(view, 20, options?.cullMode ?? WGPUCullMode_None);
480
+ writeU32(view, 24, options?.unclippedDepth ?? 0);
481
+ writeU32(view, 28, 0);
482
+ return { buffer, ptr: ptr(buffer) };
483
+ }
484
+
485
+ function makeMultisampleState(options?: {
486
+ count?: number;
487
+ mask?: number;
488
+ alphaToCoverageEnabled?: boolean;
489
+ }) {
490
+ const buffer = new ArrayBuffer(24);
491
+ const view = new DataView(buffer);
492
+ writePtr(view, 0, 0);
493
+ writeU32(view, 8, options?.count ?? 1);
494
+ writeU32(view, 12, options?.mask ?? 0xffffffff);
495
+ writeU32(view, 16, options?.alphaToCoverageEnabled ? 1 : 0);
496
+ writeU32(view, 20, 0);
497
+ return { buffer, ptr: ptr(buffer) };
498
+ }
499
+
500
+ function makeDepthStencilState(options?: {
501
+ format?: number;
502
+ depthWriteEnabled?: boolean;
503
+ depthCompare?: number;
504
+ stencilReadMask?: number;
505
+ stencilWriteMask?: number;
506
+ depthBias?: number;
507
+ depthBiasSlopeScale?: number;
508
+ depthBiasClamp?: number;
509
+ }) {
510
+ const buffer = new ArrayBuffer(72);
511
+ const view = new DataView(buffer);
512
+ writePtr(view, 0, 0);
513
+ writeU32(view, 8, options?.format ?? 0);
514
+ writeU32(view, 12, options?.depthWriteEnabled ? 1 : 0);
515
+ writeU32(view, 16, options?.depthCompare ?? 0);
516
+ writeU32(view, 20, 0); // stencilFront.compare
517
+ writeU32(view, 24, 0); // stencilFront.failOp
518
+ writeU32(view, 28, 0); // stencilFront.depthFailOp
519
+ writeU32(view, 32, 0); // stencilFront.passOp
520
+ writeU32(view, 36, 0); // stencilBack.compare
521
+ writeU32(view, 40, 0); // stencilBack.failOp
522
+ writeU32(view, 44, 0); // stencilBack.depthFailOp
523
+ writeU32(view, 48, 0); // stencilBack.passOp
524
+ writeU32(view, 52, options?.stencilReadMask ?? 0xffffffff);
525
+ writeU32(view, 56, options?.stencilWriteMask ?? 0xffffffff);
526
+ view.setInt32(60, options?.depthBias ?? 0, true);
527
+ writeF32(view, 64, options?.depthBiasSlopeScale ?? 0);
528
+ writeF32(view, 68, options?.depthBiasClamp ?? 0);
529
+ return { buffer, ptr: ptr(buffer) };
530
+ }
531
+
532
+ function makeRenderPipelineDescriptor(
533
+ layoutPtr: number | null,
534
+ vertexStateBuffer: ArrayBuffer,
535
+ primitiveStateBuffer: ArrayBuffer,
536
+ depthStencilPtr: number | null,
537
+ multisampleBuffer: ArrayBuffer,
538
+ fragmentStatePtr: number | null,
539
+ ) {
540
+ const buffer = new ArrayBuffer(168);
541
+ const view = new DataView(buffer);
542
+ writePtr(view, 0, 0);
543
+ writePtr(view, 8, 0);
544
+ writeU64(view, 16, 0n);
545
+ writePtr(view, 24, layoutPtr ?? 0);
546
+ new Uint8Array(buffer, 32, 64).set(new Uint8Array(vertexStateBuffer, 0, 64));
547
+ new Uint8Array(buffer, 96, 32).set(new Uint8Array(primitiveStateBuffer, 0, 32));
548
+ writePtr(view, 128, depthStencilPtr ?? 0);
549
+ new Uint8Array(buffer, 136, 24).set(new Uint8Array(multisampleBuffer, 0, 24));
550
+ writePtr(view, 160, fragmentStatePtr ?? 0);
551
+ return { buffer, ptr: ptr(buffer) };
552
+ }
553
+
554
+ function makeProgrammableStageDescriptor(
555
+ modulePtr: number,
556
+ entryPoint: { ptr: number; len: bigint },
557
+ ) {
558
+ const buffer = new ArrayBuffer(48);
559
+ const view = new DataView(buffer);
560
+ writePtr(view, 0, 0);
561
+ writePtr(view, 8, modulePtr);
562
+ writePtr(view, 16, entryPoint.ptr);
563
+ writeU64(view, 24, entryPoint.len);
564
+ writeU64(view, 32, 0n); // constantCount
565
+ writePtr(view, 40, 0); // constants
566
+ return { buffer, ptr: ptr(buffer) };
567
+ }
568
+
569
+ function makeComputePipelineDescriptor(
570
+ layoutPtr: number | null,
571
+ stageBuffer: ArrayBuffer,
572
+ ) {
573
+ const buffer = new ArrayBuffer(80);
574
+ const view = new DataView(buffer);
575
+ writePtr(view, 0, 0);
576
+ writePtr(view, 8, 0);
577
+ writeU64(view, 16, 0n);
578
+ writePtr(view, 24, layoutPtr ?? 0);
579
+ new Uint8Array(buffer, 32, 48).set(new Uint8Array(stageBuffer, 0, 48));
580
+ return { buffer, ptr: ptr(buffer) };
581
+ }
582
+
583
+ function makeComputePassDescriptor() {
584
+ const buffer = new ArrayBuffer(32);
585
+ const view = new DataView(buffer);
586
+ writePtr(view, 0, 0);
587
+ writePtr(view, 8, 0);
588
+ writeU64(view, 16, 0n);
589
+ writePtr(view, 24, 0);
590
+ return { buffer, ptr: ptr(buffer) };
591
+ }
592
+
593
+ function makeBufferMapCallbackInfo(
594
+ callbackPtr: number,
595
+ userdata1: number,
596
+ userdata2: number,
597
+ ) {
598
+ const buffer = new ArrayBuffer(40);
599
+ const view = new DataView(buffer);
600
+ writePtr(view, 0, 0);
601
+ writeU32(view, 8, WGPUCallbackMode_AllowSpontaneous);
602
+ writeU32(view, 12, 0);
603
+ writePtr(view, 16, callbackPtr);
604
+ writePtr(view, 24, userdata1);
605
+ writePtr(view, 32, userdata2);
606
+ return { buffer, ptr: ptr(buffer) };
607
+ }
608
+
609
+ function makeQueueWorkDoneCallbackInfo(
610
+ callbackPtr: number,
611
+ userdata1: number,
612
+ userdata2: number,
613
+ ) {
614
+ const buffer = new ArrayBuffer(40);
615
+ const view = new DataView(buffer);
616
+ writePtr(view, 0, 0);
617
+ writeU32(view, 8, WGPUCallbackMode_AllowSpontaneous);
618
+ writeU32(view, 12, 0);
619
+ writePtr(view, 16, callbackPtr);
620
+ writePtr(view, 24, userdata1);
621
+ writePtr(view, 32, userdata2);
622
+ return { buffer, ptr: ptr(buffer) };
623
+ }
624
+
625
+ function makeBindGroupLayoutEntry(entry: {
626
+ binding: number;
627
+ visibility: number;
628
+ bindingArraySize?: number;
629
+ buffer?: { type?: number; hasDynamicOffset?: boolean; minBindingSize?: number };
630
+ sampler?: { type?: number };
631
+ texture?: { sampleType?: number; viewDimension?: number; multisampled?: boolean };
632
+ storageTexture?: { access?: number; format?: number; viewDimension?: number };
633
+ }) {
634
+ const buffer = new ArrayBuffer(120);
635
+ const view = new DataView(buffer);
636
+ writePtr(view, 0, 0);
637
+ writeU32(view, 8, entry.binding);
638
+ writeU32(view, 16, entry.visibility);
639
+ writeU32(view, 24, entry.bindingArraySize ?? 0);
640
+
641
+ // BufferBindingLayout at 32
642
+ writePtr(view, 32, 0);
643
+ writeU32(view, 40, entry.buffer?.type ?? 0);
644
+ writeU32(view, 44, entry.buffer?.hasDynamicOffset ? 1 : 0);
645
+ writeU64(view, 48, entry.buffer?.minBindingSize ?? 0);
646
+
647
+ // SamplerBindingLayout at 56
648
+ writePtr(view, 56, 0);
649
+ writeU32(view, 64, entry.sampler?.type ?? 0);
650
+
651
+ // TextureBindingLayout at 72
652
+ writePtr(view, 72, 0);
653
+ writeU32(view, 80, entry.texture?.sampleType ?? 0);
654
+ writeU32(view, 84, entry.texture?.viewDimension ?? 0);
655
+ writeU32(view, 88, entry.texture?.multisampled ? 1 : 0);
656
+
657
+ // StorageTextureBindingLayout at 96
658
+ writePtr(view, 96, 0);
659
+ writeU32(view, 104, entry.storageTexture?.access ?? 0);
660
+ writeU32(view, 108, entry.storageTexture?.format ?? 0);
661
+ writeU32(view, 112, entry.storageTexture?.viewDimension ?? 0);
662
+
663
+ return { buffer, ptr: ptr(buffer) };
664
+ }
665
+
666
+ function makeBindGroupLayoutDescriptor(entriesPtr: number, count: number) {
667
+ const buffer = new ArrayBuffer(40);
668
+ const view = new DataView(buffer);
669
+ writePtr(view, 0, 0);
670
+ writePtr(view, 8, 0);
671
+ writeU64(view, 16, 0n);
672
+ writeU64(view, 24, BigInt(count));
673
+ writePtr(view, 32, entriesPtr);
674
+ return { buffer, ptr: ptr(buffer) };
675
+ }
676
+
677
+ function makeBindGroupEntry(entry: {
678
+ binding: number;
679
+ buffer?: { buffer: GPUBuffer; offset?: number; size?: number };
680
+ sampler?: GPUSampler;
681
+ textureView?: GPUTextureView;
682
+ }) {
683
+ const buffer = new ArrayBuffer(56);
684
+ const view = new DataView(buffer);
685
+ writePtr(view, 0, 0);
686
+ writeU32(view, 8, entry.binding);
687
+ writeU32(view, 12, 0);
688
+ writePtr(view, 16, entry.buffer ? entry.buffer.buffer.ptr : 0);
689
+ writeU64(view, 24, BigInt(entry.buffer?.offset ?? 0));
690
+ const sizeValue =
691
+ entry.buffer?.size ?? 0xffffffffffffffffn;
692
+ writeU64(view, 32, toBigInt(sizeValue, 0xffffffffffffffffn));
693
+ writePtr(view, 40, entry.sampler ? entry.sampler.ptr : 0);
694
+ writePtr(view, 48, entry.textureView ? entry.textureView.ptr : 0);
695
+ return { buffer, ptr: ptr(buffer) };
696
+ }
697
+
698
+ function makeBindGroupDescriptor(
699
+ layoutPtr: number,
700
+ entriesPtr: number,
701
+ count: number,
702
+ ) {
703
+ const buffer = new ArrayBuffer(48);
704
+ const view = new DataView(buffer);
705
+ writePtr(view, 0, 0);
706
+ writePtr(view, 8, 0);
707
+ writeU64(view, 16, 0n);
708
+ writePtr(view, 24, layoutPtr);
709
+ writeU64(view, 32, BigInt(count));
710
+ writePtr(view, 40, entriesPtr);
711
+ return { buffer, ptr: ptr(buffer) };
712
+ }
713
+
714
+ function makePipelineLayoutDescriptor(layoutsPtr: number, count: number) {
715
+ const buffer = new ArrayBuffer(48);
716
+ const view = new DataView(buffer);
717
+ writePtr(view, 0, 0);
718
+ writePtr(view, 8, 0);
719
+ writeU64(view, 16, 0n);
720
+ writeU64(view, 24, BigInt(count));
721
+ writePtr(view, 32, layoutsPtr);
722
+ writeU32(view, 40, 0);
723
+ writeU32(view, 44, 0);
724
+ return { buffer, ptr: ptr(buffer) };
725
+ }
726
+
727
+ function makeCommandEncoderDescriptor() {
728
+ const buffer = new ArrayBuffer(24);
729
+ const view = new DataView(buffer);
730
+ writePtr(view, 0, 0);
731
+ writePtr(view, 8, 0);
732
+ writeU64(view, 16, 0n);
733
+ return { buffer, ptr: ptr(buffer) };
734
+ }
735
+
736
+ function makeSurfaceTexture() {
737
+ const buffer = new ArrayBuffer(24);
738
+ return { buffer, view: new DataView(buffer), ptr: ptr(buffer) };
739
+ }
740
+
741
+ function makeRenderPassColorAttachment(
742
+ viewPtr: number,
743
+ resolveTargetPtr: number | null,
744
+ clear = { r: 0, g: 0, b: 0, a: 1 },
745
+ loadOp = WGPULoadOp_Clear,
746
+ storeOp = WGPUStoreOp_Store,
747
+ ) {
748
+ const buffer = new ArrayBuffer(72);
749
+ const view = new DataView(buffer);
750
+ writePtr(view, 0, 0);
751
+ writePtr(view, 8, viewPtr);
752
+ writeU32(view, 16, WGPU_DEPTH_SLICE_UNDEFINED);
753
+ writeU32(view, 20, 0);
754
+ writePtr(view, 24, resolveTargetPtr ?? 0);
755
+ writeU32(view, 32, loadOp);
756
+ writeU32(view, 36, storeOp);
757
+ writeF64(view, 40, clear.r);
758
+ writeF64(view, 48, clear.g);
759
+ writeF64(view, 56, clear.b);
760
+ writeF64(view, 64, clear.a);
761
+ return { buffer, ptr: ptr(buffer) };
762
+ }
763
+
764
+ function makeRenderPassDepthStencilAttachment(options: {
765
+ view: number;
766
+ depthLoadOp: number;
767
+ depthStoreOp: number;
768
+ depthClearValue: number;
769
+ depthReadOnly?: boolean;
770
+ stencilLoadOp: number;
771
+ stencilStoreOp: number;
772
+ stencilClearValue: number;
773
+ stencilReadOnly?: boolean;
774
+ }) {
775
+ const buffer = new ArrayBuffer(48);
776
+ const view = new DataView(buffer);
777
+ writePtr(view, 0, 0);
778
+ writePtr(view, 8, options.view);
779
+ writeU32(view, 16, options.depthLoadOp);
780
+ writeU32(view, 20, options.depthStoreOp);
781
+ writeF32(view, 24, options.depthClearValue);
782
+ writeU32(view, 28, options.depthReadOnly ? 1 : 0);
783
+ writeU32(view, 32, options.stencilLoadOp);
784
+ writeU32(view, 36, options.stencilStoreOp);
785
+ writeU32(view, 40, options.stencilClearValue);
786
+ writeU32(view, 44, options.stencilReadOnly ? 1 : 0);
787
+ return { buffer, ptr: ptr(buffer) };
788
+ }
789
+
790
+ function makeRenderPassDescriptor(
791
+ colorAttachmentsPtr: number,
792
+ colorAttachmentCount: number,
793
+ depthStencilPtr: number | null,
794
+ ) {
795
+ const buffer = new ArrayBuffer(64);
796
+ const view = new DataView(buffer);
797
+ writePtr(view, 0, 0);
798
+ writePtr(view, 8, 0);
799
+ writeU64(view, 16, 0n);
800
+ writeU64(view, 24, BigInt(colorAttachmentCount));
801
+ writePtr(view, 32, colorAttachmentsPtr);
802
+ writePtr(view, 40, depthStencilPtr ?? 0);
803
+ writePtr(view, 48, 0);
804
+ writePtr(view, 56, 0);
805
+ return { buffer, ptr: ptr(buffer) };
806
+ }
807
+
808
+ function makeCommandBufferArray(cmdPtr: number) {
809
+ const buffer = new BigUint64Array(1);
810
+ buffer[0] = BigInt(cmdPtr);
811
+ return { buffer, ptr: ptr(buffer) };
812
+ }
813
+
814
+ function makeSurfaceCapabilities() {
815
+ const buffer = new ArrayBuffer(64);
816
+ const view = new DataView(buffer);
817
+ writePtr(view, 0, 0);
818
+ writeU64(view, 8, 0n);
819
+ writeU64(view, 16, 0n);
820
+ writePtr(view, 24, 0);
821
+ writeU64(view, 32, 0n);
822
+ writePtr(view, 40, 0);
823
+ writeU64(view, 48, 0n);
824
+ writePtr(view, 56, 0);
825
+ return { buffer, view, ptr: ptr(buffer) };
826
+ }
827
+
828
+ function readU64(view: DataView, offset: number) {
829
+ return Number(view.getBigUint64(offset, true));
830
+ }
831
+
832
+ function readPtr(view: DataView, offset: number) {
833
+ const val = view.getBigUint64(offset, true);
834
+ return val === 0n ? 0 : Number(val);
835
+ }
836
+
837
+ function pickSurfaceFormatAlpha(capsView: DataView, preferredFormat: number) {
838
+ const formatCount = readU64(capsView, 16);
839
+ const formatPtr = readPtr(capsView, 24);
840
+ let format = preferredFormat;
841
+ if (formatCount && formatPtr) {
842
+ const formats = new Uint32Array(toArrayBuffer(formatPtr, 0, formatCount * 4));
843
+ if (formats.length) {
844
+ format = formats[0]!;
845
+ }
846
+ }
847
+
848
+ const alphaCount = readU64(capsView, 48);
849
+ const alphaPtr = readPtr(capsView, 56);
850
+ let alphaMode = WGPUCompositeAlphaMode_Opaque;
851
+ const alphaModes: number[] = [];
852
+ if (alphaCount && alphaPtr) {
853
+ const alphas = new Uint32Array(toArrayBuffer(alphaPtr, 0, alphaCount * 4));
854
+ if (alphas.length) {
855
+ alphaModes.push(...alphas);
856
+ alphaMode = alphas[0]!;
857
+ }
858
+ }
859
+
860
+ return { format, alphaMode, alphaModes };
861
+ }
862
+
863
+ class GPUTexture {
864
+ ptr: number;
865
+ format?: number;
866
+ constructor(ptr: number, format?: number) {
867
+ this.ptr = ptr;
868
+ this.format = format;
869
+ }
870
+ createView(descriptor?: {
871
+ format?: string;
872
+ dimension?: string;
873
+ baseMipLevel?: number;
874
+ mipLevelCount?: number;
875
+ baseArrayLayer?: number;
876
+ arrayLayerCount?: number;
877
+ aspect?: string;
878
+ usage?: number;
879
+ }) {
880
+ let descPtr = 0;
881
+ if (descriptor) {
882
+ let format = mapTextureFormat(descriptor.format) ?? 0;
883
+ const baseFormat =
884
+ this.format ?? WGPUNative.symbols.wgpuTextureGetFormat(this.ptr);
885
+ if (isDepthFormat(baseFormat) && !isDepthFormat(format)) {
886
+ format = 0;
887
+ }
888
+ const desc = makeTextureViewDescriptor({
889
+ format,
890
+ dimension: mapTextureViewDimension(descriptor.dimension) ?? 0,
891
+ baseMipLevel: descriptor.baseMipLevel ?? 0,
892
+ mipLevelCount:
893
+ descriptor.mipLevelCount ?? 0xffffffff,
894
+ baseArrayLayer: descriptor.baseArrayLayer ?? 0,
895
+ arrayLayerCount:
896
+ descriptor.arrayLayerCount ?? 0xffffffff,
897
+ aspect: mapTextureAspect(descriptor.aspect) ?? 0,
898
+ usage: toBigInt(descriptor.usage ?? 0),
899
+ });
900
+ WGPU_KEEPALIVE.push(desc.buffer);
901
+ descPtr = desc.ptr as any;
902
+ }
903
+ const view = WGPUNative.symbols.wgpuTextureCreateView(
904
+ this.ptr,
905
+ descPtr,
906
+ );
907
+ return new GPUTextureView(view, this.format);
908
+ }
909
+ destroy() {
910
+ WGPUNative.symbols.wgpuTextureDestroy(this.ptr);
911
+ }
912
+ }
913
+
914
+ class GPUTextureView {
915
+ ptr: number;
916
+ format?: number;
917
+ constructor(ptr: number, format?: number) {
918
+ this.ptr = ptr;
919
+ this.format = format;
920
+ }
921
+ }
922
+
923
+ class GPUQueue {
924
+ ptr: number;
925
+ _device?: GPUDevice;
926
+ constructor(ptr: number) {
927
+ this.ptr = ptr;
928
+ }
929
+ submit(commandBuffers: GPUCommandBuffer[]) {
930
+ const buffer = new BigUint64Array(commandBuffers.length);
931
+ for (let i = 0; i < commandBuffers.length; i += 1) {
932
+ buffer[i] = BigInt(commandBuffers[i]!.ptr);
933
+ }
934
+ WGPU_KEEPALIVE.push(buffer);
935
+ WGPUNative.symbols.wgpuQueueSubmit(
936
+ this.ptr,
937
+ BigInt(commandBuffers.length) as any,
938
+ ptr(buffer),
939
+ );
940
+ if (LAST_SURFACE_PTR && LAST_SURFACE_HAS_TEXTURE) {
941
+ LAST_SURFACE_HAS_TEXTURE = false;
942
+ WGPUBridge.surfacePresent(LAST_SURFACE_PTR as any);
943
+ }
944
+ }
945
+ writeBuffer(buffer: GPUBuffer, offset: number, data: ArrayBufferView) {
946
+ WGPUNative.symbols.wgpuQueueWriteBuffer(
947
+ this.ptr,
948
+ buffer.ptr,
949
+ BigInt(offset),
950
+ ptr(data),
951
+ data.byteLength,
952
+ );
953
+ }
954
+ writeTexture(
955
+ destination: { texture: GPUTexture; mipLevel?: number; origin?: { x?: number; y?: number; z?: number } },
956
+ data: ArrayBufferView,
957
+ dataLayout: { bytesPerRow: number; rowsPerImage?: number },
958
+ size: { width: number; height: number; depthOrArrayLayers?: number },
959
+ ) {
960
+ if (!data || data.byteLength === 0) return;
961
+ let bytesPerPixel = bytesPerPixelForFormat(destination.texture.format);
962
+ let width =
963
+ Number.isFinite(size.width) && size.width > 0
964
+ ? size.width
965
+ : Math.max(
966
+ 1,
967
+ Math.floor(
968
+ (dataLayout.bytesPerRow ?? data.byteLength) / bytesPerPixel,
969
+ ),
970
+ );
971
+ let height =
972
+ Number.isFinite(size.height) && size.height > 0
973
+ ? size.height
974
+ : Math.max(1, dataLayout.rowsPerImage ?? 1);
975
+ const layers = size.depthOrArrayLayers ?? 1;
976
+ if (width <= 0 || height <= 0 || layers <= 0) return;
977
+ const inferredBpp = Math.floor(
978
+ data.byteLength / Math.max(1, width * height * layers),
979
+ );
980
+ if (inferredBpp > bytesPerPixel) {
981
+ bytesPerPixel = inferredBpp;
982
+ }
983
+ const exactRGBABytes = width * height * layers * 4;
984
+ if (data.byteLength === exactRGBABytes) {
985
+ bytesPerPixel = 4;
986
+ }
987
+ let minBytesPerRow = Math.max(1, width * bytesPerPixel);
988
+ const minExpectedSize = minBytesPerRow * height * layers;
989
+ if (data.byteLength > minExpectedSize && height > 0) {
990
+ const widthFromData = Math.floor(
991
+ data.byteLength / Math.max(1, height * layers * bytesPerPixel),
992
+ );
993
+ if (widthFromData > width) {
994
+ width = widthFromData;
995
+ minBytesPerRow = Math.max(1, width * bytesPerPixel);
996
+ }
997
+ }
998
+ let bytesPerRow = dataLayout.bytesPerRow ?? minBytesPerRow;
999
+ if (bytesPerRow < minBytesPerRow) bytesPerRow = minBytesPerRow;
1000
+ const derivedRowBytes = Math.ceil(
1001
+ data.byteLength / Math.max(1, height * layers),
1002
+ );
1003
+ if (bytesPerRow < derivedRowBytes) {
1004
+ bytesPerRow = derivedRowBytes;
1005
+ }
1006
+ let rowsPerImage = dataLayout.rowsPerImage ?? height;
1007
+ if (rowsPerImage === 0) rowsPerImage = height;
1008
+
1009
+ let writeData = data;
1010
+ const needsPadding = bytesPerRow % 256 !== 0;
1011
+ if (needsPadding) {
1012
+ const aligned = alignTo(bytesPerRow, 256);
1013
+ const srcStride = Math.max(
1014
+ minBytesPerRow,
1015
+ dataLayout.bytesPerRow ?? minBytesPerRow,
1016
+ );
1017
+ writeData = repackTextureData(
1018
+ data,
1019
+ srcStride,
1020
+ aligned,
1021
+ minBytesPerRow,
1022
+ height,
1023
+ rowsPerImage,
1024
+ layers,
1025
+ );
1026
+ bytesPerRow = aligned;
1027
+ }
1028
+
1029
+ const texInfo = makeTexelCopyTextureInfo(
1030
+ destination.texture.ptr,
1031
+ destination.mipLevel ?? 0,
1032
+ destination.origin ?? {},
1033
+ );
1034
+ const layout = makeTexelCopyBufferLayout(
1035
+ (dataLayout as { offset?: number }).offset ?? 0,
1036
+ bytesPerRow,
1037
+ rowsPerImage,
1038
+ );
1039
+ const extent = makeExtent3D(
1040
+ width,
1041
+ height,
1042
+ layers,
1043
+ );
1044
+ WGPU_KEEPALIVE.push(texInfo.buffer, layout.buffer, extent.buffer);
1045
+ WGPUNative.symbols.wgpuQueueWriteTexture(
1046
+ this.ptr,
1047
+ texInfo.ptr as any,
1048
+ ptr(writeData),
1049
+ writeData.byteLength,
1050
+ layout.ptr as any,
1051
+ extent.ptr as any,
1052
+ );
1053
+ }
1054
+ onSubmittedWorkDone() {
1055
+ const callbackPtr = (queueWorkDoneCallback as any).ptr ?? queueWorkDoneCallback;
1056
+ const info = makeQueueWorkDoneCallbackInfo(
1057
+ Number(callbackPtr),
1058
+ this.ptr,
1059
+ 0,
1060
+ );
1061
+ WGPU_KEEPALIVE.push(info.buffer);
1062
+ WGPUBridge.queueOnSubmittedWorkDone(
1063
+ this.ptr as any,
1064
+ info.ptr as any,
1065
+ );
1066
+ return new Promise<boolean>((resolve) => {
1067
+ let done = false;
1068
+ const resolveOnce = () => {
1069
+ if (done) return;
1070
+ done = true;
1071
+ resolve(true);
1072
+ };
1073
+ WORK_DONE_RESOLVERS.set(this.ptr, () => resolveOnce());
1074
+
1075
+ const start = Date.now();
1076
+ const poll = () => {
1077
+ if (done) return;
1078
+ try {
1079
+ if ((this as any)._device?.instancePtr) {
1080
+ WGPUNative.symbols.wgpuInstanceProcessEvents(
1081
+ (this as any)._device.instancePtr,
1082
+ );
1083
+ }
1084
+ WGPUNative.symbols.wgpuDeviceTick((this as any)._device?.ptr ?? 0);
1085
+ } catch {}
1086
+ if (Date.now() - start > 5000) {
1087
+ resolve(false);
1088
+ return;
1089
+ }
1090
+ setTimeout(poll, 5);
1091
+ };
1092
+ setTimeout(poll, 5);
1093
+ });
1094
+ }
1095
+ }
1096
+
1097
+ class GPUDevice {
1098
+ ptr: number;
1099
+ queue: GPUQueue;
1100
+ features = new Set<string>();
1101
+ limits: Record<string, number> = {};
1102
+ _uncapturedErrorListeners: ((event: { error: Error }) => void)[] = [];
1103
+ instancePtr: number | null = null;
1104
+ constructor(ptr: number, instancePtr?: number) {
1105
+ if (!ptr) {
1106
+ throw new Error("Failed to create WGPU device");
1107
+ }
1108
+ this.ptr = ptr;
1109
+ this.instancePtr = instancePtr ?? null;
1110
+ this.queue = new GPUQueue(WGPUNative.symbols.wgpuDeviceGetQueue(ptr));
1111
+ this.queue._device = this;
1112
+ }
1113
+ destroy() {
1114
+ if (!this.ptr) return;
1115
+ try {
1116
+ WGPUNative.symbols.wgpuDeviceDestroy(this.ptr);
1117
+ } catch {}
1118
+ try {
1119
+ WGPUNative.symbols.wgpuDeviceRelease(this.ptr);
1120
+ } catch {}
1121
+ }
1122
+ createBuffer(descriptor: { size: number; usage: number; mappedAtCreation?: boolean }) {
1123
+ let usage = toBigInt(descriptor.usage ?? 0);
1124
+ const desc = makeBufferDescriptor(
1125
+ descriptor.size,
1126
+ usage,
1127
+ !!descriptor.mappedAtCreation,
1128
+ );
1129
+ WGPU_KEEPALIVE.push(desc.buffer);
1130
+ const bufferPtr = WGPUNative.symbols.wgpuDeviceCreateBuffer(
1131
+ this.ptr,
1132
+ desc.ptr as any,
1133
+ );
1134
+ return new GPUBuffer(
1135
+ bufferPtr,
1136
+ descriptor.size,
1137
+ usage,
1138
+ this,
1139
+ !!descriptor.mappedAtCreation,
1140
+ );
1141
+ }
1142
+ createTexture(descriptor: {
1143
+ size: { width: number; height: number; depthOrArrayLayers?: number };
1144
+ format: string;
1145
+ usage: number;
1146
+ mipLevelCount?: number;
1147
+ sampleCount?: number;
1148
+ viewFormats?: string[];
1149
+ }) {
1150
+ const mappedFormat =
1151
+ mapTextureFormat(descriptor.format) ?? WGPUTextureFormat_BGRA8Unorm;
1152
+ const rawSample = Number(descriptor.sampleCount ?? 1);
1153
+ let sampleCount = Number.isFinite(rawSample) ? rawSample : 1;
1154
+ if (sampleCount > 1 && isIntegerFormat(mappedFormat)) {
1155
+ sampleCount = 1;
1156
+ }
1157
+ let viewFormatsPtr: number | null = null;
1158
+ let viewFormatCount = 0;
1159
+ if (descriptor.viewFormats && descriptor.viewFormats.length) {
1160
+ const arr = new Uint32Array(descriptor.viewFormats.length);
1161
+ descriptor.viewFormats.forEach((f, i) => {
1162
+ arr[i] = mapTextureFormat(f) ?? 0;
1163
+ });
1164
+ WGPU_KEEPALIVE.push(arr);
1165
+ viewFormatsPtr = ptr(arr) as any;
1166
+ viewFormatCount = descriptor.viewFormats.length;
1167
+ }
1168
+ const desc = makeTextureDescriptor(
1169
+ descriptor.size.width,
1170
+ descriptor.size.height,
1171
+ descriptor.size.depthOrArrayLayers ?? 1,
1172
+ mappedFormat,
1173
+ toBigInt(descriptor.usage ?? 0),
1174
+ descriptor.mipLevelCount ?? 1,
1175
+ sampleCount,
1176
+ viewFormatsPtr,
1177
+ viewFormatCount,
1178
+ );
1179
+ WGPU_KEEPALIVE.push(desc.buffer);
1180
+ const texPtr = WGPUNative.symbols.wgpuDeviceCreateTexture(
1181
+ this.ptr,
1182
+ desc.ptr as any,
1183
+ );
1184
+ return new GPUTexture(texPtr, mappedFormat);
1185
+ }
1186
+ createSampler(descriptor?: {
1187
+ addressModeU?: string;
1188
+ addressModeV?: string;
1189
+ addressModeW?: string;
1190
+ magFilter?: string;
1191
+ minFilter?: string;
1192
+ mipmapFilter?: string;
1193
+ lodMinClamp?: number;
1194
+ lodMaxClamp?: number;
1195
+ compare?: string;
1196
+ maxAnisotropy?: number;
1197
+ }) {
1198
+ const desc = makeSamplerDescriptor({
1199
+ addressModeU: mapAddressMode(descriptor?.addressModeU),
1200
+ addressModeV: mapAddressMode(descriptor?.addressModeV),
1201
+ addressModeW: mapAddressMode(descriptor?.addressModeW),
1202
+ magFilter: mapFilterMode(descriptor?.magFilter),
1203
+ minFilter: mapFilterMode(descriptor?.minFilter),
1204
+ mipmapFilter: mapMipmapFilterMode(descriptor?.mipmapFilter),
1205
+ lodMinClamp: descriptor?.lodMinClamp,
1206
+ lodMaxClamp: descriptor?.lodMaxClamp,
1207
+ compare: mapCompareFunction(descriptor?.compare),
1208
+ maxAnisotropy: descriptor?.maxAnisotropy,
1209
+ });
1210
+ WGPU_KEEPALIVE.push(desc.buffer);
1211
+ const samplerPtr = WGPUNative.symbols.wgpuDeviceCreateSampler(
1212
+ this.ptr,
1213
+ desc.ptr as any,
1214
+ );
1215
+ return new GPUSampler(samplerPtr);
1216
+ }
1217
+ createBindGroupLayout(descriptor: { entries: any[] }) {
1218
+ const entries = descriptor.entries.map((entry) => {
1219
+ const hasBindingKind =
1220
+ !!entry.buffer ||
1221
+ !!entry.sampler ||
1222
+ !!entry.texture ||
1223
+ !!entry.storageTexture;
1224
+ const normalized = hasBindingKind
1225
+ ? entry
1226
+ : {
1227
+ ...entry,
1228
+ buffer: { type: "uniform" },
1229
+ };
1230
+ const bindingEntry = makeBindGroupLayoutEntry({
1231
+ binding: normalized.binding ?? 0,
1232
+ visibility: mapShaderStage(normalized.visibility) ?? 0,
1233
+ bindingArraySize: normalized.bindingArraySize ?? 0,
1234
+ buffer: normalized.buffer
1235
+ ? {
1236
+ type: mapBufferBindingType(normalized.buffer.type),
1237
+ hasDynamicOffset: !!normalized.buffer.hasDynamicOffset,
1238
+ minBindingSize: normalized.buffer.minBindingSize ?? 0,
1239
+ }
1240
+ : undefined,
1241
+ sampler: normalized.sampler
1242
+ ? { type: mapSamplerBindingType(normalized.sampler.type) }
1243
+ : undefined,
1244
+ texture: normalized.texture
1245
+ ? {
1246
+ sampleType: mapTextureSampleType(normalized.texture.sampleType),
1247
+ viewDimension: mapTextureViewDimension(
1248
+ normalized.texture.viewDimension,
1249
+ ),
1250
+ multisampled: !!normalized.texture.multisampled,
1251
+ }
1252
+ : undefined,
1253
+ storageTexture: normalized.storageTexture
1254
+ ? {
1255
+ access: mapStorageTextureAccess(
1256
+ normalized.storageTexture.access,
1257
+ ),
1258
+ format: mapTextureFormat(normalized.storageTexture.format),
1259
+ viewDimension: mapTextureViewDimension(
1260
+ normalized.storageTexture.viewDimension,
1261
+ ),
1262
+ }
1263
+ : undefined,
1264
+ });
1265
+ WGPU_KEEPALIVE.push(bindingEntry.buffer);
1266
+ return bindingEntry;
1267
+ });
1268
+ const entryBuf = new ArrayBuffer(entries.length * 120);
1269
+ entries.forEach((entry, i) => {
1270
+ new Uint8Array(entryBuf, i * 120, 120).set(
1271
+ new Uint8Array(entry.buffer),
1272
+ );
1273
+ });
1274
+ const entryPtr = ptr(entryBuf);
1275
+ WGPU_KEEPALIVE.push(entryBuf);
1276
+ const desc = makeBindGroupLayoutDescriptor(
1277
+ entryPtr as any,
1278
+ entries.length,
1279
+ );
1280
+ WGPU_KEEPALIVE.push(desc.buffer);
1281
+ const layoutPtr = WGPUNative.symbols.wgpuDeviceCreateBindGroupLayout(
1282
+ this.ptr,
1283
+ desc.ptr as any,
1284
+ );
1285
+ return new GPUBindGroupLayout(layoutPtr);
1286
+ }
1287
+ createBindGroup(descriptor: { layout: GPUBindGroupLayout; entries: any[] }) {
1288
+ const entries = descriptor.entries.map((entry) => {
1289
+ if (entry.resource?.buffer || entry.resource instanceof GPUBuffer) {
1290
+ const buffer = entry.resource.buffer ?? entry.resource;
1291
+ return makeBindGroupEntry({
1292
+ binding: entry.binding ?? 0,
1293
+ buffer: {
1294
+ buffer,
1295
+ offset: entry.resource.offset ?? 0,
1296
+ size: entry.resource.size ?? 0xffffffffffffffffn,
1297
+ },
1298
+ });
1299
+ }
1300
+ if (entry.resource instanceof GPUSampler) {
1301
+ return makeBindGroupEntry({
1302
+ binding: entry.binding ?? 0,
1303
+ sampler: entry.resource,
1304
+ });
1305
+ }
1306
+ if (entry.resource instanceof GPUTextureView) {
1307
+ return makeBindGroupEntry({
1308
+ binding: entry.binding ?? 0,
1309
+ textureView: entry.resource,
1310
+ });
1311
+ }
1312
+ if (entry.resource?.sampler) {
1313
+ return makeBindGroupEntry({
1314
+ binding: entry.binding ?? 0,
1315
+ sampler: entry.resource.sampler,
1316
+ });
1317
+ }
1318
+ if (entry.resource?.textureView) {
1319
+ return makeBindGroupEntry({
1320
+ binding: entry.binding ?? 0,
1321
+ textureView: entry.resource.textureView,
1322
+ });
1323
+ }
1324
+ return makeBindGroupEntry({ binding: entry.binding ?? 0 });
1325
+ });
1326
+ const entryBuf = new ArrayBuffer(entries.length * 56);
1327
+ entries.forEach((entry, i) => {
1328
+ new Uint8Array(entryBuf, i * 56, 56).set(
1329
+ new Uint8Array(entry.buffer),
1330
+ );
1331
+ });
1332
+ const entryPtr = ptr(entryBuf);
1333
+ WGPU_KEEPALIVE.push(entryBuf);
1334
+ const desc = makeBindGroupDescriptor(
1335
+ descriptor.layout.ptr,
1336
+ entryPtr as any,
1337
+ entries.length,
1338
+ );
1339
+ WGPU_KEEPALIVE.push(desc.buffer);
1340
+ const bindGroupPtr = WGPUNative.symbols.wgpuDeviceCreateBindGroup(
1341
+ this.ptr,
1342
+ desc.ptr as any,
1343
+ );
1344
+ return new GPUBindGroup(bindGroupPtr);
1345
+ }
1346
+ createPipelineLayout(descriptor: { bindGroupLayouts: GPUBindGroupLayout[] }) {
1347
+ const layouts = new BigUint64Array(descriptor.bindGroupLayouts.length);
1348
+ for (let i = 0; i < layouts.length; i += 1) {
1349
+ layouts[i] = BigInt(descriptor.bindGroupLayouts[i]!.ptr);
1350
+ }
1351
+ WGPU_KEEPALIVE.push(layouts);
1352
+ const desc = makePipelineLayoutDescriptor(ptr(layouts) as any, layouts.length);
1353
+ WGPU_KEEPALIVE.push(desc.buffer);
1354
+ const layoutPtr = WGPUNative.symbols.wgpuDeviceCreatePipelineLayout(
1355
+ this.ptr,
1356
+ desc.ptr as any,
1357
+ );
1358
+ return new GPUPipelineLayout(layoutPtr);
1359
+ }
1360
+ createShaderModule(descriptor: { code: string }) {
1361
+ const code = new TextEncoder().encode(descriptor.code + "\0");
1362
+ const codeBuf = new Uint8Array(code);
1363
+ WGPU_KEEPALIVE.push(codeBuf);
1364
+ const codePtr = ptr(codeBuf);
1365
+ const source = makeShaderSourceWGSL(codePtr as any, WGPU_STRLEN);
1366
+ const desc = makeShaderModuleDescriptor(source.ptr as any);
1367
+ WGPU_KEEPALIVE.push(source.buffer, desc.buffer);
1368
+ const modulePtr = WGPUNative.symbols.wgpuDeviceCreateShaderModule(
1369
+ this.ptr,
1370
+ desc.ptr as any,
1371
+ );
1372
+ return new GPUShaderModule(modulePtr);
1373
+ }
1374
+ createRenderPipeline(descriptor: any) {
1375
+ const vertexModule = descriptor.vertex.module as GPUShaderModule;
1376
+ const vertexEntry = makeStringView(descriptor.vertex.entryPoint ?? "main");
1377
+ const vertexBuffers = descriptor.vertex.buffers ?? [];
1378
+ const vertexLayouts: ArrayBuffer[] = [];
1379
+ const vertexLayoutPtrs: number[] = [];
1380
+ for (const buf of vertexBuffers) {
1381
+ const attrs = buf.attributes ?? [];
1382
+ const attrBuf = new ArrayBuffer(attrs.length * 32);
1383
+ attrs.forEach((attr: any, idx: number) => {
1384
+ const format = mapVertexFormat(attr.format);
1385
+ const attrStruct = makeVertexAttribute(
1386
+ attr.offset ?? 0,
1387
+ attr.shaderLocation ?? 0,
1388
+ format,
1389
+ );
1390
+ new Uint8Array(attrBuf, idx * 32, 32).set(
1391
+ new Uint8Array(attrStruct.buffer),
1392
+ );
1393
+ });
1394
+ const attrPtr = ptr(attrBuf);
1395
+ WGPU_KEEPALIVE.push(attrBuf);
1396
+ const layout = makeVertexBufferLayout(
1397
+ attrPtr as any,
1398
+ attrs.length,
1399
+ BigInt(buf.arrayStride ?? 0),
1400
+ mapVertexStepMode(buf.stepMode),
1401
+ );
1402
+ WGPU_KEEPALIVE.push(layout.buffer);
1403
+ vertexLayouts.push(layout.buffer);
1404
+ vertexLayoutPtrs.push(layout.ptr as any);
1405
+ }
1406
+
1407
+ const vertexLayoutsBuf = new ArrayBuffer(vertexLayouts.length * 40);
1408
+ vertexLayouts.forEach((layoutBuf, i) => {
1409
+ new Uint8Array(vertexLayoutsBuf, i * 40, 40).set(
1410
+ new Uint8Array(layoutBuf),
1411
+ );
1412
+ });
1413
+ const vertexLayoutsPtr = ptr(vertexLayoutsBuf);
1414
+ WGPU_KEEPALIVE.push(vertexLayoutsBuf);
1415
+
1416
+ const vertexState = makeVertexState(
1417
+ vertexModule.ptr,
1418
+ { ptr: vertexEntry.ptr as any, len: vertexEntry.len },
1419
+ vertexLayoutsPtr as any,
1420
+ vertexLayouts.length,
1421
+ );
1422
+ WGPU_KEEPALIVE.push(vertexState.buffer);
1423
+
1424
+ let fragmentStatePtr: number | null = null;
1425
+ if (descriptor.fragment) {
1426
+ const fragModule = descriptor.fragment.module as GPUShaderModule;
1427
+ const fragEntry = makeStringView(descriptor.fragment.entryPoint ?? "main");
1428
+ const targets = descriptor.fragment.targets ?? [];
1429
+ const targetBuf = new ArrayBuffer(targets.length * 32);
1430
+ targets.forEach((t: any, i: number) => {
1431
+ let blendPtr: number | null = null;
1432
+ if (t.blend) {
1433
+ const colorComp = makeBlendComponent(
1434
+ mapBlendOperation(t.blend.color?.operation),
1435
+ mapBlendFactor(t.blend.color?.srcFactor),
1436
+ mapBlendFactor(t.blend.color?.dstFactor),
1437
+ );
1438
+ const alphaComp = makeBlendComponent(
1439
+ mapBlendOperation(t.blend.alpha?.operation),
1440
+ mapBlendFactor(t.blend.alpha?.srcFactor),
1441
+ mapBlendFactor(t.blend.alpha?.dstFactor),
1442
+ );
1443
+ const blend = makeBlendState(colorComp.buffer, alphaComp.buffer);
1444
+ WGPU_KEEPALIVE.push(colorComp.buffer, alphaComp.buffer, blend.buffer);
1445
+ blendPtr = blend.ptr as any;
1446
+ }
1447
+ const target = makeColorTargetState(
1448
+ mapTextureFormat(t.format) ?? WGPUTextureFormat_BGRA8Unorm,
1449
+ blendPtr,
1450
+ t.writeMask ?? WGPUColorWriteMask_All,
1451
+ );
1452
+ new Uint8Array(targetBuf, i * 32, 32).set(
1453
+ new Uint8Array(target.buffer),
1454
+ );
1455
+ });
1456
+ const targetPtr = ptr(targetBuf);
1457
+ WGPU_KEEPALIVE.push(targetBuf);
1458
+ const fragState = makeFragmentState(
1459
+ fragModule.ptr,
1460
+ { ptr: fragEntry.ptr as any, len: fragEntry.len },
1461
+ targetPtr as any,
1462
+ targets.length,
1463
+ );
1464
+ WGPU_KEEPALIVE.push(fragState.buffer);
1465
+ fragmentStatePtr = fragState.ptr as any;
1466
+ }
1467
+
1468
+ const primitive = makePrimitiveState({
1469
+ topology: mapPrimitiveTopology(descriptor.primitive?.topology),
1470
+ stripIndexFormat: mapIndexFormat(descriptor.primitive?.stripIndexFormat),
1471
+ frontFace: mapFrontFace(descriptor.primitive?.frontFace),
1472
+ cullMode: mapCullMode(descriptor.primitive?.cullMode),
1473
+ unclippedDepth: descriptor.primitive?.unclippedDepth ? 1 : 0,
1474
+ });
1475
+ WGPU_KEEPALIVE.push(primitive.buffer);
1476
+
1477
+ let depthStencilPtr: number | null = null;
1478
+ if (descriptor.depthStencil) {
1479
+ const depth = makeDepthStencilState({
1480
+ format:
1481
+ mapTextureFormat(descriptor.depthStencil.format) ??
1482
+ WGPUTextureFormat_Depth24Plus,
1483
+ depthWriteEnabled: !!descriptor.depthStencil.depthWriteEnabled,
1484
+ depthCompare: mapCompareFunction(descriptor.depthStencil.depthCompare),
1485
+ stencilReadMask: descriptor.depthStencil.stencilReadMask ?? 0xffffffff,
1486
+ stencilWriteMask: descriptor.depthStencil.stencilWriteMask ?? 0xffffffff,
1487
+ depthBias: descriptor.depthStencil.depthBias ?? 0,
1488
+ depthBiasSlopeScale: descriptor.depthStencil.depthBiasSlopeScale ?? 0,
1489
+ depthBiasClamp: descriptor.depthStencil.depthBiasClamp ?? 0,
1490
+ });
1491
+ WGPU_KEEPALIVE.push(depth.buffer);
1492
+ depthStencilPtr = depth.ptr as any;
1493
+ }
1494
+
1495
+ const multisample = makeMultisampleState({
1496
+ count: descriptor.multisample?.count ?? 1,
1497
+ mask: descriptor.multisample?.mask ?? 0xffffffff,
1498
+ alphaToCoverageEnabled: !!descriptor.multisample?.alphaToCoverageEnabled,
1499
+ });
1500
+ WGPU_KEEPALIVE.push(multisample.buffer);
1501
+
1502
+ const pipelineDesc = makeRenderPipelineDescriptor(
1503
+ descriptor.layout && descriptor.layout !== "auto"
1504
+ ? (descriptor.layout as GPUPipelineLayout).ptr
1505
+ : null,
1506
+ vertexState.buffer,
1507
+ primitive.buffer,
1508
+ depthStencilPtr,
1509
+ multisample.buffer,
1510
+ fragmentStatePtr,
1511
+ );
1512
+ WGPU_KEEPALIVE.push(pipelineDesc.buffer);
1513
+
1514
+ const pipelinePtr = WGPUNative.symbols.wgpuDeviceCreateRenderPipeline(
1515
+ this.ptr,
1516
+ pipelineDesc.ptr as any,
1517
+ );
1518
+ return new GPURenderPipeline(pipelinePtr);
1519
+ }
1520
+ createComputePipeline(descriptor: {
1521
+ layout?: GPUPipelineLayout | "auto";
1522
+ compute: { module: GPUShaderModule; entryPoint?: string };
1523
+ }) {
1524
+ const module = descriptor.compute.module as GPUShaderModule;
1525
+ const entry = makeStringView(descriptor.compute.entryPoint ?? "main");
1526
+ const stage = makeProgrammableStageDescriptor(
1527
+ module.ptr,
1528
+ { ptr: entry.ptr as any, len: entry.len },
1529
+ );
1530
+ WGPU_KEEPALIVE.push(stage.buffer);
1531
+ const pipelineDesc = makeComputePipelineDescriptor(
1532
+ descriptor.layout && descriptor.layout !== "auto"
1533
+ ? (descriptor.layout as GPUPipelineLayout).ptr
1534
+ : null,
1535
+ stage.buffer,
1536
+ );
1537
+ WGPU_KEEPALIVE.push(pipelineDesc.buffer);
1538
+ const pipelinePtr = WGPUNative.symbols.wgpuDeviceCreateComputePipeline(
1539
+ this.ptr,
1540
+ pipelineDesc.ptr as any,
1541
+ );
1542
+ return new GPUComputePipeline(pipelinePtr);
1543
+ }
1544
+ createCommandEncoder() {
1545
+ const desc = makeCommandEncoderDescriptor();
1546
+ WGPU_KEEPALIVE.push(desc.buffer);
1547
+ const encoderPtr = WGPUNative.symbols.wgpuDeviceCreateCommandEncoder(
1548
+ this.ptr,
1549
+ desc.ptr as any,
1550
+ );
1551
+ return new GPUCommandEncoder(encoderPtr, this);
1552
+ }
1553
+ addEventListener(type: string, handler: (event: any) => void) {
1554
+ if (type !== "uncapturederror") return;
1555
+ this._uncapturedErrorListeners.push(handler);
1556
+ }
1557
+ pushErrorScope(_filter: any) {
1558
+ return;
1559
+ }
1560
+ popErrorScope() {
1561
+ return Promise.resolve(null);
1562
+ }
1563
+ }
1564
+
1565
+ class GPUBuffer {
1566
+ ptr: number;
1567
+ size: number;
1568
+ usage: bigint;
1569
+ _device: GPUDevice;
1570
+ _mapped: boolean;
1571
+ constructor(ptr: number, size: number, usage: bigint, device: GPUDevice, mapped = false) {
1572
+ this.ptr = ptr;
1573
+ this.size = size;
1574
+ this.usage = usage;
1575
+ this._device = device;
1576
+ this._mapped = mapped;
1577
+ }
1578
+ getMappedRange(_offset = 0, _size?: number) {
1579
+ if (!this._mapped) {
1580
+ return new ArrayBuffer(0);
1581
+ }
1582
+ const size = Math.max(0, _size ?? this.size - _offset);
1583
+ const mapped = WGPUNative.symbols.wgpuBufferGetMappedRange(
1584
+ this.ptr,
1585
+ BigInt(_offset),
1586
+ BigInt(size),
1587
+ );
1588
+ if (!mapped) {
1589
+ return new ArrayBuffer(0);
1590
+ }
1591
+ return toArrayBuffer(mapped as any, 0, size);
1592
+ }
1593
+ mapAsync(mode?: number, offset = 0, size?: number) {
1594
+ const mapMode =
1595
+ mode ??
1596
+ ((this.usage & WGPUBufferUsage_MapRead) !== 0n
1597
+ ? Number(WGPUMapMode_Read)
1598
+ : Number(WGPUMapMode_Write));
1599
+ const mapSize = size ?? this.size - offset;
1600
+ const callbackPtr = (bufferMapCallback as any).ptr ?? bufferMapCallback;
1601
+ const info = makeBufferMapCallbackInfo(
1602
+ Number(callbackPtr),
1603
+ this.ptr,
1604
+ 0,
1605
+ );
1606
+ WGPU_KEEPALIVE.push(info.buffer);
1607
+ WGPUBridge.bufferMapAsync(
1608
+ this.ptr as any,
1609
+ BigInt(mapMode),
1610
+ BigInt(offset),
1611
+ BigInt(mapSize),
1612
+ info.ptr as any,
1613
+ );
1614
+ return new Promise<boolean>((resolve) => {
1615
+ let done = false;
1616
+ const resolveOnce = () => {
1617
+ if (done) return;
1618
+ done = true;
1619
+ resolve(true);
1620
+ };
1621
+
1622
+ MAP_ASYNC_RESOLVERS.set(this.ptr, (mapped) => {
1623
+ if (mapped) {
1624
+ this._mapped = true;
1625
+ resolveOnce();
1626
+ } else {
1627
+ resolve(false);
1628
+ }
1629
+ });
1630
+
1631
+ const start = Date.now();
1632
+ const poll = () => {
1633
+ if (done) return;
1634
+ try {
1635
+ if (this._device.instancePtr) {
1636
+ WGPUNative.symbols.wgpuInstanceProcessEvents(
1637
+ this._device.instancePtr,
1638
+ );
1639
+ }
1640
+ WGPUNative.symbols.wgpuDeviceTick(this._device.ptr);
1641
+ } catch {
1642
+ // ignore
1643
+ }
1644
+ const state = WGPUNative.symbols.wgpuBufferGetMapState(this.ptr);
1645
+ if (state === WGPUBufferMapState_Mapped) {
1646
+ this._mapped = true;
1647
+ resolveOnce();
1648
+ return;
1649
+ }
1650
+ if (Date.now() - start > 2000) {
1651
+ resolve(false);
1652
+ return;
1653
+ }
1654
+ setTimeout(poll, 5);
1655
+ };
1656
+ setTimeout(poll, 5);
1657
+ });
1658
+ }
1659
+ unmap() {
1660
+ WGPUNative.symbols.wgpuBufferUnmap(this.ptr);
1661
+ this._mapped = false;
1662
+ }
1663
+ readSync(offset = 0, size?: number, timeoutNs = 2_000_000_000) {
1664
+ if (!this._device.instancePtr) return null;
1665
+ const readSize = Math.max(0, size ?? this.size - offset);
1666
+ const out = new ArrayBuffer(readSize);
1667
+ const ok = WGPUBridge.bufferReadSyncInto(
1668
+ this._device.instancePtr as any,
1669
+ this.ptr as any,
1670
+ BigInt(offset),
1671
+ BigInt(readSize),
1672
+ BigInt(timeoutNs),
1673
+ ptr(out) as any,
1674
+ );
1675
+ if (!ok) return null;
1676
+ return out;
1677
+ }
1678
+ readbackAsync(
1679
+ dst: Uint8Array,
1680
+ offset = 0,
1681
+ size?: number,
1682
+ timeoutMs = 2000,
1683
+ ) {
1684
+ const readSize = Math.max(0, size ?? dst.byteLength);
1685
+ const jobPtr = WGPUBridge.bufferReadbackBegin(
1686
+ this.ptr as any,
1687
+ BigInt(offset),
1688
+ BigInt(readSize),
1689
+ ptr(dst) as any,
1690
+ );
1691
+ if (!jobPtr) return Promise.resolve(0);
1692
+ return new Promise<number>((resolve) => {
1693
+ const start = Date.now();
1694
+ const poll = () => {
1695
+ try {
1696
+ if (this._device.instancePtr) {
1697
+ WGPUNative.symbols.wgpuInstanceProcessEvents(
1698
+ this._device.instancePtr,
1699
+ );
1700
+ }
1701
+ WGPUNative.symbols.wgpuDeviceTick(this._device.ptr);
1702
+ } catch {}
1703
+ const status = WGPUBridge.bufferReadbackStatus(jobPtr as any);
1704
+ if (status === 1) {
1705
+ WGPUBridge.bufferReadbackFree(jobPtr as any);
1706
+ resolve(1);
1707
+ return;
1708
+ }
1709
+ if (status === 2 || status === 3 || Date.now() - start > timeoutMs) {
1710
+ WGPUBridge.bufferReadbackFree(jobPtr as any);
1711
+ resolve(status === 0 ? 2 : status);
1712
+ return;
1713
+ }
1714
+ setTimeout(poll, 5);
1715
+ };
1716
+ setTimeout(poll, 5);
1717
+ });
1718
+ }
1719
+ destroy() {
1720
+ WGPUNative.symbols.wgpuBufferDestroy(this.ptr);
1721
+ }
1722
+ }
1723
+
1724
+ class GPUSampler {
1725
+ ptr: number;
1726
+ constructor(ptr: number) {
1727
+ this.ptr = ptr;
1728
+ }
1729
+ }
1730
+
1731
+ class GPUBindGroupLayout {
1732
+ ptr: number;
1733
+ constructor(ptr: number) {
1734
+ this.ptr = ptr;
1735
+ }
1736
+ }
1737
+
1738
+ class GPUBindGroup {
1739
+ ptr: number;
1740
+ constructor(ptr: number) {
1741
+ this.ptr = ptr;
1742
+ }
1743
+ }
1744
+
1745
+ class GPUPipelineLayout {
1746
+ ptr: number;
1747
+ constructor(ptr: number) {
1748
+ this.ptr = ptr;
1749
+ }
1750
+ }
1751
+
1752
+ class GPUShaderModule {
1753
+ ptr: number;
1754
+ constructor(ptr: number) {
1755
+ this.ptr = ptr;
1756
+ }
1757
+ }
1758
+
1759
+ class GPURenderPipeline {
1760
+ ptr: number;
1761
+ constructor(ptr: number) {
1762
+ this.ptr = ptr;
1763
+ }
1764
+ getBindGroupLayout(index: number) {
1765
+ const layoutPtr = WGPUNative.symbols.wgpuRenderPipelineGetBindGroupLayout(
1766
+ this.ptr,
1767
+ index,
1768
+ );
1769
+ return new GPUBindGroupLayout(layoutPtr);
1770
+ }
1771
+ }
1772
+
1773
+ class GPUComputePipeline {
1774
+ ptr: number;
1775
+ constructor(ptr: number) {
1776
+ this.ptr = ptr;
1777
+ }
1778
+ getBindGroupLayout(index: number) {
1779
+ const layoutPtr = WGPUNative.symbols.wgpuComputePipelineGetBindGroupLayout(
1780
+ this.ptr,
1781
+ index,
1782
+ );
1783
+ return new GPUBindGroupLayout(layoutPtr);
1784
+ }
1785
+ }
1786
+
1787
+ class GPUCommandBuffer {
1788
+ ptr: number;
1789
+ constructor(ptr: number) {
1790
+ this.ptr = ptr;
1791
+ }
1792
+ }
1793
+
1794
+ class GPUCommandEncoder {
1795
+ ptr: number;
1796
+ _device: GPUDevice;
1797
+ constructor(ptr: number, device: GPUDevice) {
1798
+ this.ptr = ptr;
1799
+ this._device = device;
1800
+ }
1801
+ beginRenderPass(descriptor: {
1802
+ colorAttachments: Array<{
1803
+ view: GPUTextureView;
1804
+ resolveTarget?: GPUTextureView | null;
1805
+ clearValue?: { r: number; g: number; b: number; a: number };
1806
+ loadOp?: string;
1807
+ storeOp?: string;
1808
+ }>;
1809
+ depthStencilAttachment?: {
1810
+ view: GPUTextureView;
1811
+ depthClearValue?: number;
1812
+ depthLoadOp?: string;
1813
+ depthStoreOp?: string;
1814
+ depthReadOnly?: boolean;
1815
+ stencilClearValue?: number;
1816
+ stencilLoadOp?: string;
1817
+ stencilStoreOp?: string;
1818
+ stencilReadOnly?: boolean;
1819
+ };
1820
+ }) {
1821
+ const colorAttachments = descriptor.colorAttachments.map((c) =>
1822
+ makeRenderPassColorAttachment(
1823
+ c.view.ptr,
1824
+ c.resolveTarget ? c.resolveTarget.ptr : null,
1825
+ c.clearValue ?? { r: 0, g: 0, b: 0, a: 1 },
1826
+ mapLoadOp(c.loadOp),
1827
+ mapStoreOp(c.storeOp),
1828
+ ),
1829
+ );
1830
+ const colorBuf = new ArrayBuffer(colorAttachments.length * 72);
1831
+ colorAttachments.forEach((c, i) => {
1832
+ new Uint8Array(colorBuf, i * 72, 72).set(new Uint8Array(c.buffer));
1833
+ });
1834
+ const colorPtr = ptr(colorBuf);
1835
+ WGPU_KEEPALIVE.push(colorBuf);
1836
+
1837
+ let depthPtr: number | null = null;
1838
+ if (descriptor.depthStencilAttachment) {
1839
+ const d = descriptor.depthStencilAttachment;
1840
+ const viewFormat = d.view.format ?? 0;
1841
+ if (viewFormat && !isDepthFormat(viewFormat)) {
1842
+ // Skip invalid depth/stencil view attachments.
1843
+ } else {
1844
+ const depth = makeRenderPassDepthStencilAttachment({
1845
+ view: d.view.ptr,
1846
+ depthLoadOp: mapLoadOp(d.depthLoadOp),
1847
+ depthStoreOp: mapStoreOp(d.depthStoreOp),
1848
+ depthClearValue: d.depthClearValue ?? 1,
1849
+ depthReadOnly: !!d.depthReadOnly,
1850
+ stencilLoadOp: mapLoadOp(d.stencilLoadOp),
1851
+ stencilStoreOp: mapStoreOp(d.stencilStoreOp),
1852
+ stencilClearValue: d.stencilClearValue ?? 0,
1853
+ stencilReadOnly: !!d.stencilReadOnly,
1854
+ });
1855
+ WGPU_KEEPALIVE.push(depth.buffer);
1856
+ depthPtr = depth.ptr as any;
1857
+ }
1858
+ }
1859
+
1860
+ const passDesc = makeRenderPassDescriptor(
1861
+ colorPtr as any,
1862
+ colorAttachments.length,
1863
+ depthPtr,
1864
+ );
1865
+ WGPU_KEEPALIVE.push(passDesc.buffer);
1866
+ const passPtr = WGPUNative.symbols.wgpuCommandEncoderBeginRenderPass(
1867
+ this.ptr,
1868
+ passDesc.ptr as any,
1869
+ );
1870
+ return new GPURenderPassEncoder(passPtr);
1871
+ }
1872
+ beginComputePass() {
1873
+ const desc = makeComputePassDescriptor();
1874
+ WGPU_KEEPALIVE.push(desc.buffer);
1875
+ const passPtr = WGPUNative.symbols.wgpuCommandEncoderBeginComputePass(
1876
+ this.ptr,
1877
+ desc.ptr as any,
1878
+ );
1879
+ return new GPUComputePassEncoder(passPtr);
1880
+ }
1881
+ copyBufferToTexture(
1882
+ source: {
1883
+ buffer: GPUBuffer;
1884
+ offset?: number;
1885
+ bytesPerRow?: number;
1886
+ rowsPerImage?: number;
1887
+ },
1888
+ destination: {
1889
+ texture: GPUTexture;
1890
+ mipLevel?: number;
1891
+ origin?: { x?: number; y?: number; z?: number };
1892
+ },
1893
+ size: { width: number; height: number; depthOrArrayLayers?: number },
1894
+ ) {
1895
+ const offset = source.offset ?? 0;
1896
+ const mapped = source.buffer.getMappedRange(0, source.buffer.size);
1897
+ const data =
1898
+ offset > 0
1899
+ ? new Uint8Array(mapped, offset)
1900
+ : new Uint8Array(mapped);
1901
+ this._device.queue.writeTexture(
1902
+ destination,
1903
+ data,
1904
+ {
1905
+ bytesPerRow: source.bytesPerRow ?? 0,
1906
+ rowsPerImage: source.rowsPerImage ?? 0,
1907
+ },
1908
+ size,
1909
+ );
1910
+ }
1911
+ copyBufferToBuffer(
1912
+ source: GPUBuffer,
1913
+ sourceOffset: number,
1914
+ destination: GPUBuffer,
1915
+ destinationOffset: number,
1916
+ size: number,
1917
+ ) {
1918
+ WGPUNative.symbols.wgpuCommandEncoderCopyBufferToBuffer(
1919
+ this.ptr,
1920
+ source.ptr,
1921
+ BigInt(sourceOffset),
1922
+ destination.ptr,
1923
+ BigInt(destinationOffset),
1924
+ BigInt(size),
1925
+ );
1926
+ }
1927
+ finish() {
1928
+ const cmdPtr = WGPUNative.symbols.wgpuCommandEncoderFinish(this.ptr, 0);
1929
+ return new GPUCommandBuffer(cmdPtr);
1930
+ }
1931
+ }
1932
+
1933
+ class GPURenderPassEncoder {
1934
+ ptr: number;
1935
+ constructor(ptr: number) {
1936
+ this.ptr = ptr;
1937
+ }
1938
+ setPipeline(pipeline: GPURenderPipeline) {
1939
+ WGPUNative.symbols.wgpuRenderPassEncoderSetPipeline(
1940
+ this.ptr,
1941
+ pipeline.ptr,
1942
+ );
1943
+ }
1944
+ setBindGroup(index: number, bindGroup: GPUBindGroup, offsets?: number[]) {
1945
+ let offsetsPtr = 0;
1946
+ let count = 0n;
1947
+ if (offsets && offsets.length) {
1948
+ const arr = new BigUint64Array(offsets.length);
1949
+ offsets.forEach((o, i) => {
1950
+ arr[i] = BigInt(o);
1951
+ });
1952
+ WGPU_KEEPALIVE.push(arr);
1953
+ offsetsPtr = ptr(arr) as any;
1954
+ count = BigInt(offsets.length);
1955
+ }
1956
+ WGPUNative.symbols.wgpuRenderPassEncoderSetBindGroup(
1957
+ this.ptr,
1958
+ index,
1959
+ bindGroup.ptr,
1960
+ count as any,
1961
+ offsetsPtr as any,
1962
+ );
1963
+ }
1964
+ setVertexBuffer(slot: number, buffer: GPUBuffer, offset = 0, size?: number) {
1965
+ WGPUNative.symbols.wgpuRenderPassEncoderSetVertexBuffer(
1966
+ this.ptr,
1967
+ slot,
1968
+ buffer.ptr,
1969
+ BigInt(offset),
1970
+ BigInt(size ?? buffer.size),
1971
+ );
1972
+ }
1973
+ setIndexBuffer(buffer: GPUBuffer, indexFormat: string, offset = 0, size?: number) {
1974
+ const format = mapIndexFormat(indexFormat);
1975
+ WGPUNative.symbols.wgpuRenderPassEncoderSetIndexBuffer(
1976
+ this.ptr,
1977
+ buffer.ptr,
1978
+ format ?? 0,
1979
+ BigInt(offset),
1980
+ BigInt(size ?? buffer.size),
1981
+ );
1982
+ }
1983
+ setViewport(x: number, y: number, width: number, height: number, minDepth = 0, maxDepth = 1) {
1984
+ WGPUNative.symbols.wgpuRenderPassEncoderSetViewport(
1985
+ this.ptr,
1986
+ x,
1987
+ y,
1988
+ width,
1989
+ height,
1990
+ minDepth,
1991
+ maxDepth,
1992
+ );
1993
+ }
1994
+ setScissorRect(x: number, y: number, width: number, height: number) {
1995
+ WGPUNative.symbols.wgpuRenderPassEncoderSetScissorRect(
1996
+ this.ptr,
1997
+ x,
1998
+ y,
1999
+ width,
2000
+ height,
2001
+ );
2002
+ }
2003
+ draw(vertexCount: number, instanceCount = 1, firstVertex = 0, firstInstance = 0) {
2004
+ WGPUNative.symbols.wgpuRenderPassEncoderDraw(
2005
+ this.ptr,
2006
+ vertexCount,
2007
+ instanceCount,
2008
+ firstVertex,
2009
+ firstInstance,
2010
+ );
2011
+ }
2012
+ drawIndexed(indexCount: number, instanceCount = 1, firstIndex = 0, baseVertex = 0, firstInstance = 0) {
2013
+ WGPUNative.symbols.wgpuRenderPassEncoderDrawIndexed(
2014
+ this.ptr,
2015
+ indexCount,
2016
+ instanceCount,
2017
+ firstIndex,
2018
+ baseVertex,
2019
+ firstInstance,
2020
+ );
2021
+ }
2022
+ end() {
2023
+ WGPUNative.symbols.wgpuRenderPassEncoderEnd(this.ptr);
2024
+ }
2025
+ }
2026
+
2027
+ class GPUComputePassEncoder {
2028
+ ptr: number;
2029
+ constructor(ptr: number) {
2030
+ this.ptr = ptr;
2031
+ }
2032
+ setPipeline(pipeline: GPUComputePipeline) {
2033
+ WGPUNative.symbols.wgpuComputePassEncoderSetPipeline(
2034
+ this.ptr,
2035
+ pipeline.ptr,
2036
+ );
2037
+ }
2038
+ setBindGroup(index: number, bindGroup: GPUBindGroup, offsets?: number[]) {
2039
+ let offsetsPtr = 0;
2040
+ let count = 0n;
2041
+ if (offsets && offsets.length) {
2042
+ const arr = new BigUint64Array(offsets.length);
2043
+ offsets.forEach((o, i) => {
2044
+ arr[i] = BigInt(o);
2045
+ });
2046
+ WGPU_KEEPALIVE.push(arr);
2047
+ offsetsPtr = ptr(arr) as any;
2048
+ count = BigInt(offsets.length);
2049
+ }
2050
+ WGPUNative.symbols.wgpuComputePassEncoderSetBindGroup(
2051
+ this.ptr,
2052
+ index,
2053
+ bindGroup.ptr,
2054
+ count as any,
2055
+ offsetsPtr as any,
2056
+ );
2057
+ }
2058
+ dispatchWorkgroups(x: number, y = 1, z = 1) {
2059
+ WGPUNative.symbols.wgpuComputePassEncoderDispatchWorkgroups(
2060
+ this.ptr,
2061
+ x,
2062
+ y,
2063
+ z,
2064
+ );
2065
+ }
2066
+ end() {
2067
+ WGPUNative.symbols.wgpuComputePassEncoderEnd(this.ptr);
2068
+ }
2069
+ }
2070
+
2071
+ class GPUAdapter {
2072
+ instancePtr: number;
2073
+ surfacePtr: number;
2074
+ features = new Set<string>();
2075
+ limits: Record<string, number> = {};
2076
+ info: Record<string, string> = {};
2077
+ constructor(instancePtr: number, surfacePtr: number) {
2078
+ this.instancePtr = instancePtr;
2079
+ this.surfacePtr = surfacePtr;
2080
+ }
2081
+ async requestDevice() {
2082
+ const adapterDevice = new BigUint64Array(2);
2083
+ WGPUBridge.createAdapterDeviceMainThread(
2084
+ this.instancePtr as any,
2085
+ this.surfacePtr as any,
2086
+ ptr(adapterDevice),
2087
+ );
2088
+ const devicePtr = adapterDevice[1];
2089
+ if (devicePtr === 0n) {
2090
+ throw new Error("Failed to create WGPU device");
2091
+ }
2092
+ const device = Number(devicePtr);
2093
+ return new GPUDevice(device, this.instancePtr);
2094
+ }
2095
+ }
2096
+
2097
+ class GPUCanvasContext {
2098
+ surfacePtr: number;
2099
+ instancePtr: number | null = null;
2100
+ devicePtr: number | null = null;
2101
+ format: number = WGPUTextureFormat_BGRA8UnormSrgb;
2102
+ alphaMode: number = WGPUCompositeAlphaMode_Opaque;
2103
+ supportedAlphaModes = new Set<number>([WGPUCompositeAlphaMode_Opaque]);
2104
+ width = 1;
2105
+ height = 1;
2106
+ private _hasCurrentTexture = false;
2107
+ _fallbackSize?: { width: number; height: number };
2108
+ constructor(surfacePtr: number, instancePtr?: number) {
2109
+ this.surfacePtr = surfacePtr;
2110
+ this.instancePtr = instancePtr ?? null;
2111
+ }
2112
+ configure(options: {
2113
+ device: GPUDevice;
2114
+ format?: number | string;
2115
+ alphaMode?: number | string;
2116
+ usage?: number;
2117
+ size?: { width: number; height: number };
2118
+ }) {
2119
+ if (!options.size && this._fallbackSize) {
2120
+ this.width = this._fallbackSize.width;
2121
+ this.height = this._fallbackSize.height;
2122
+ }
2123
+ this.devicePtr = options.device.ptr;
2124
+ if (options.format) {
2125
+ this.format =
2126
+ typeof options.format === "string"
2127
+ ? mapTextureFormat(options.format) ?? this.format
2128
+ : options.format;
2129
+ }
2130
+ if (options.alphaMode) {
2131
+ const requestedAlphaMode =
2132
+ typeof options.alphaMode === "string"
2133
+ ? mapAlphaMode(options.alphaMode)
2134
+ : options.alphaMode;
2135
+ if (
2136
+ typeof requestedAlphaMode === "number" &&
2137
+ this.supportedAlphaModes.has(requestedAlphaMode)
2138
+ ) {
2139
+ this.alphaMode = requestedAlphaMode;
2140
+ } else if (
2141
+ typeof requestedAlphaMode === "number" &&
2142
+ !this.supportedAlphaModes.has(requestedAlphaMode)
2143
+ ) {
2144
+ this.alphaMode =
2145
+ this.supportedAlphaModes.values().next().value ??
2146
+ WGPUCompositeAlphaMode_Opaque;
2147
+ }
2148
+ }
2149
+ if (options.size) {
2150
+ this.width = options.size.width;
2151
+ this.height = options.size.height;
2152
+ }
2153
+ const config = makeSurfaceConfiguration(
2154
+ this.devicePtr,
2155
+ this.width,
2156
+ this.height,
2157
+ this.format,
2158
+ this.alphaMode,
2159
+ toBigInt(options.usage ?? WGPUTextureUsage_RenderAttachment),
2160
+ );
2161
+ WGPUBridge.surfaceConfigure(this.surfacePtr as any, config.ptr as any);
2162
+ this._hasCurrentTexture = false;
2163
+ }
2164
+ getCurrentTexture() {
2165
+ const surfaceTexture = makeSurfaceTexture();
2166
+ WGPUBridge.surfaceGetCurrentTexture(
2167
+ this.surfacePtr as any,
2168
+ surfaceTexture.ptr as any,
2169
+ );
2170
+ const status = surfaceTexture.view.getUint32(16, true);
2171
+ if (status !== 1 && status !== 2) {
2172
+ throw new Error(`Surface status ${status}`);
2173
+ }
2174
+ const texPtr = Number(surfaceTexture.view.getBigUint64(8, true));
2175
+ LAST_SURFACE_PTR = this.surfacePtr;
2176
+ this._hasCurrentTexture = true;
2177
+ LAST_SURFACE_HAS_TEXTURE = true;
2178
+ return new GPUTexture(texPtr, this.format);
2179
+ }
2180
+ present() {
2181
+ if (!this._hasCurrentTexture) return;
2182
+ this._hasCurrentTexture = false;
2183
+ LAST_SURFACE_HAS_TEXTURE = false;
2184
+ return WGPUBridge.surfacePresent(this.surfacePtr as any);
2185
+ }
2186
+ unconfigure() {
2187
+ this._hasCurrentTexture = false;
2188
+ LAST_SURFACE_HAS_TEXTURE = false;
2189
+ return WGPUNative.symbols.wgpuSurfaceUnconfigure(this.surfacePtr as any);
2190
+ }
2191
+ }
2192
+
2193
+ function getViewPtr(view: WGPUView | GpuWindow): Pointer | null {
2194
+ if (view instanceof GpuWindow) return view.wgpuView.ptr;
2195
+ return view.ptr;
2196
+ }
2197
+
2198
+ function getViewContextKey(view: WGPUView | GpuWindow) {
2199
+ return view.id;
2200
+ }
2201
+
2202
+ function createContext(view: WGPUView | GpuWindow) {
2203
+ const key = getViewContextKey(view);
2204
+ const existing = VIEW_CONTEXTS.get(key);
2205
+ if (existing) {
2206
+ LAST_CREATED_CONTEXT = existing.context;
2207
+ return existing;
2208
+ }
2209
+
2210
+ const viewPtr = getViewPtr(view);
2211
+ if (!viewPtr) throw new Error("WGPUView pointer not available");
2212
+ const instance = WGPUNative.symbols.wgpuCreateInstance(0);
2213
+ const surface = WGPUBridge.createSurfaceForView(
2214
+ instance as Pointer,
2215
+ viewPtr,
2216
+ );
2217
+ if (!surface) throw new Error("Failed to create WGPU surface");
2218
+
2219
+ const caps = makeSurfaceCapabilities();
2220
+ WGPUNative.symbols.wgpuSurfaceGetCapabilities(
2221
+ surface as any,
2222
+ 0,
2223
+ caps.ptr as any,
2224
+ );
2225
+ const pick = pickSurfaceFormatAlpha(caps.view, WGPUTextureFormat_BGRA8UnormSrgb);
2226
+
2227
+ const ctx = new GPUCanvasContext(
2228
+ surface as unknown as number,
2229
+ Number(instance),
2230
+ );
2231
+ ctx.format = pick.format;
2232
+ ctx.alphaMode = pick.alphaMode;
2233
+ ctx.supportedAlphaModes = new Set(
2234
+ pick.alphaModes.length ? pick.alphaModes : [pick.alphaMode],
2235
+ );
2236
+ try {
2237
+ if (view instanceof GpuWindow) {
2238
+ const size = view.getSize();
2239
+ ctx.width = size.width;
2240
+ ctx.height = size.height;
2241
+ ctx._fallbackSize = { width: size.width, height: size.height };
2242
+ }
2243
+ } catch {}
2244
+
2245
+ const created = {
2246
+ instance: Number(instance),
2247
+ surface: Number(surface),
2248
+ context: ctx,
2249
+ };
2250
+ VIEW_CONTEXTS.set(key, created);
2251
+ LAST_CREATED_CONTEXT = ctx;
2252
+ return created;
2253
+ }
2254
+
2255
+ function createCanvasShim(win: GpuWindow) {
2256
+ const size = win.getSize();
2257
+ const ctx = createContext(win);
2258
+ return {
2259
+ width: size.width,
2260
+ height: size.height,
2261
+ clientWidth: size.width,
2262
+ clientHeight: size.height,
2263
+ style: {},
2264
+ getContext: (type: string) => {
2265
+ if (type !== "webgpu") return null;
2266
+ return ctx.context;
2267
+ },
2268
+ getBoundingClientRect: () => {
2269
+ const current = win.getSize();
2270
+ return {
2271
+ left: 0,
2272
+ top: 0,
2273
+ width: current.width,
2274
+ height: current.height,
2275
+ };
2276
+ },
2277
+ addEventListener: () => {},
2278
+ removeEventListener: () => {},
2279
+ setAttribute: () => {},
2280
+ };
2281
+ }
2282
+
2283
+ function decodePngRGBA(data: Uint8Array) {
2284
+ if (data.byteLength < 8) throw new Error("Invalid PNG header");
2285
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
2286
+ const readU32 = (offset: number) => view.getUint32(offset, false);
2287
+ if (readU32(0) !== 0x89504e47) {
2288
+ throw new Error("Invalid PNG header");
2289
+ }
2290
+ let offset = 8;
2291
+ let width = 0;
2292
+ let height = 0;
2293
+ let bitDepth = 0;
2294
+ let colorType = 0;
2295
+ let compressed: Uint8Array | null = null;
2296
+
2297
+ while (offset < data.length) {
2298
+ const length = readU32(offset);
2299
+ const type = String.fromCharCode(
2300
+ data[offset + 4]!,
2301
+ data[offset + 5]!,
2302
+ data[offset + 6]!,
2303
+ data[offset + 7]!,
2304
+ );
2305
+ const chunkStart = offset + 8;
2306
+ if (type === "IHDR") {
2307
+ width = readU32(chunkStart);
2308
+ height = readU32(chunkStart + 4);
2309
+ bitDepth = data[chunkStart + 8]!;
2310
+ colorType = data[chunkStart + 9]!;
2311
+ } else if (type === "IDAT") {
2312
+ const chunk = data.subarray(chunkStart, chunkStart + length);
2313
+ if (!compressed) {
2314
+ compressed = chunk;
2315
+ } else {
2316
+ const combined = new Uint8Array(compressed.length + chunk.length);
2317
+ combined.set(compressed);
2318
+ combined.set(chunk, compressed.length);
2319
+ compressed = combined;
2320
+ }
2321
+ } else if (type === "IEND") {
2322
+ break;
2323
+ }
2324
+ offset += 12 + length;
2325
+ }
2326
+
2327
+ if (!compressed) throw new Error("No IDAT chunk found");
2328
+ if (bitDepth !== 8) throw new Error("Only 8-bit PNG supported");
2329
+ if (colorType !== 6) throw new Error("Only RGBA PNG supported");
2330
+
2331
+ const inflated = inflateSync(compressed);
2332
+ const stride = width * 4;
2333
+ const out = new Uint8Array(width * height * 4);
2334
+ let inOffset = 0;
2335
+ let outOffset = 0;
2336
+ let prior = new Uint8Array(stride);
2337
+
2338
+ for (let y = 0; y < height; y += 1) {
2339
+ const filter = inflated[inOffset]!;
2340
+ inOffset += 1;
2341
+ const row = inflated.subarray(inOffset, inOffset + stride);
2342
+ inOffset += stride;
2343
+ const recon = new Uint8Array(stride);
2344
+
2345
+ if (filter === 0) {
2346
+ recon.set(row);
2347
+ } else if (filter === 1) {
2348
+ for (let i = 0; i < stride; i += 1) {
2349
+ const left = i >= 4 ? recon[i - 4]! : 0;
2350
+ recon[i] = (row[i]! + left) & 0xff;
2351
+ }
2352
+ } else if (filter === 2) {
2353
+ for (let i = 0; i < stride; i += 1) {
2354
+ recon[i] = (row[i]! + prior[i]!) & 0xff;
2355
+ }
2356
+ } else if (filter === 3) {
2357
+ for (let i = 0; i < stride; i += 1) {
2358
+ const left = i >= 4 ? recon[i - 4]! : 0;
2359
+ const up = prior[i]!;
2360
+ recon[i] = (row[i]! + Math.floor((left + up) / 2)) & 0xff;
2361
+ }
2362
+ } else if (filter === 4) {
2363
+ const paeth = (a: number, b: number, c: number) => {
2364
+ const p = a + b - c;
2365
+ const pa = Math.abs(p - a);
2366
+ const pb = Math.abs(p - b);
2367
+ const pc = Math.abs(p - c);
2368
+ if (pa <= pb && pa <= pc) return a;
2369
+ if (pb <= pc) return b;
2370
+ return c;
2371
+ };
2372
+ for (let i = 0; i < stride; i += 1) {
2373
+ const left = i >= 4 ? recon[i - 4]! : 0;
2374
+ const up = prior[i]!;
2375
+ const upLeft = i >= 4 ? prior[i - 4]! : 0;
2376
+ recon[i] = (row[i]! + paeth(left, up, upLeft)) & 0xff;
2377
+ }
2378
+ } else {
2379
+ throw new Error(`Unsupported PNG filter ${filter}`);
2380
+ }
2381
+
2382
+ out.set(recon, outOffset);
2383
+ outOffset += stride;
2384
+ prior = recon;
2385
+ }
2386
+
2387
+ return { width, height, data: out };
2388
+ }
2389
+
2390
+ function mapTextureFormat(format?: string | number | null) {
2391
+ if (typeof format === "number") return format;
2392
+ switch (format) {
2393
+ case "r8unorm":
2394
+ return WGPUTextureFormat_R8Unorm;
2395
+ case "r8snorm":
2396
+ return WGPUTextureFormat_R8Snorm;
2397
+ case "r8uint":
2398
+ return WGPUTextureFormat_R8Uint;
2399
+ case "r8sint":
2400
+ return WGPUTextureFormat_R8Sint;
2401
+ case "rg8unorm":
2402
+ return WGPUTextureFormat_RG8Unorm;
2403
+ case "rg8snorm":
2404
+ return WGPUTextureFormat_RG8Snorm;
2405
+ case "rg8uint":
2406
+ return WGPUTextureFormat_RG8Uint;
2407
+ case "rg8sint":
2408
+ return WGPUTextureFormat_RG8Sint;
2409
+ case "bgra8unorm":
2410
+ return WGPUTextureFormat_BGRA8Unorm;
2411
+ case "bgra8unorm-srgb":
2412
+ return WGPUTextureFormat_BGRA8UnormSrgb;
2413
+ case "rgba8unorm":
2414
+ return WGPUTextureFormat_RGBA8Unorm;
2415
+ case "rgba8unorm-srgb":
2416
+ return WGPUTextureFormat_RGBA8UnormSrgb;
2417
+ case "rgba8snorm":
2418
+ return WGPUTextureFormat_RGBA8Snorm;
2419
+ case "rgba8uint":
2420
+ return WGPUTextureFormat_RGBA8Uint;
2421
+ case "rgba8sint":
2422
+ return WGPUTextureFormat_RGBA8Sint;
2423
+ case "r32float":
2424
+ return WGPUTextureFormat_R32Float;
2425
+ case "r32uint":
2426
+ return WGPUTextureFormat_R32Uint;
2427
+ case "r32sint":
2428
+ return WGPUTextureFormat_R32Sint;
2429
+ case "rg32float":
2430
+ return WGPUTextureFormat_RG32Float;
2431
+ case "rg32uint":
2432
+ return WGPUTextureFormat_RG32Uint;
2433
+ case "rg32sint":
2434
+ return WGPUTextureFormat_RG32Sint;
2435
+ case "rgba16float":
2436
+ return WGPUTextureFormat_RGBA16Float;
2437
+ case "rgba16uint":
2438
+ return WGPUTextureFormat_RGBA16Uint;
2439
+ case "rgba16sint":
2440
+ return WGPUTextureFormat_RGBA16Sint;
2441
+ case "rgba32uint":
2442
+ return WGPUTextureFormat_RGBA32Uint;
2443
+ case "rgba32sint":
2444
+ return WGPUTextureFormat_RGBA32Sint;
2445
+ case "depth24plus":
2446
+ return WGPUTextureFormat_Depth24Plus;
2447
+ case "depth24plus-stencil8":
2448
+ return WGPUTextureFormat_Depth24PlusStencil8;
2449
+ case "depth32float":
2450
+ return WGPUTextureFormat_Depth32Float;
2451
+ case "depth16unorm":
2452
+ return WGPUTextureFormat_Depth16Unorm;
2453
+ case "depth32float-stencil8":
2454
+ return WGPUTextureFormat_Depth32FloatStencil8;
2455
+ default:
2456
+ return undefined;
2457
+ }
2458
+ }
2459
+
2460
+ function isIntegerFormat(format: number) {
2461
+ return (
2462
+ format === WGPUTextureFormat_R8Uint ||
2463
+ format === WGPUTextureFormat_R8Sint ||
2464
+ format === WGPUTextureFormat_RG8Uint ||
2465
+ format === WGPUTextureFormat_RG8Sint ||
2466
+ format === WGPUTextureFormat_RGBA8Uint ||
2467
+ format === WGPUTextureFormat_RGBA8Sint ||
2468
+ format === WGPUTextureFormat_R32Uint ||
2469
+ format === WGPUTextureFormat_R32Sint ||
2470
+ format === WGPUTextureFormat_RG32Uint ||
2471
+ format === WGPUTextureFormat_RG32Sint ||
2472
+ format === WGPUTextureFormat_RGBA16Uint ||
2473
+ format === WGPUTextureFormat_RGBA16Sint ||
2474
+ format === WGPUTextureFormat_RGBA32Uint ||
2475
+ format === WGPUTextureFormat_RGBA32Sint
2476
+ );
2477
+ }
2478
+
2479
+ function isDepthFormat(format: number) {
2480
+ return (
2481
+ format === WGPUTextureFormat_Depth24Plus ||
2482
+ format === WGPUTextureFormat_Depth24PlusStencil8 ||
2483
+ format === WGPUTextureFormat_Depth32Float ||
2484
+ format === WGPUTextureFormat_Depth16Unorm ||
2485
+ format === WGPUTextureFormat_Depth32FloatStencil8
2486
+ );
2487
+ }
2488
+
2489
+ function mapTextureViewDimension(dim?: string | number | null) {
2490
+ if (typeof dim === "number") return dim;
2491
+ switch (dim) {
2492
+ case "2d":
2493
+ return WGPUTextureViewDimension_2D;
2494
+ case "2d-array":
2495
+ return WGPUTextureViewDimension_2DArray;
2496
+ case "3d":
2497
+ return WGPUTextureViewDimension_3D;
2498
+ case "cube":
2499
+ return WGPUTextureViewDimension_Cube;
2500
+ case "cube-array":
2501
+ return WGPUTextureViewDimension_CubeArray;
2502
+ default:
2503
+ return undefined;
2504
+ }
2505
+ }
2506
+
2507
+ function mapTextureAspect(aspect?: string | number | null) {
2508
+ if (typeof aspect === "number") return aspect;
2509
+ switch (aspect) {
2510
+ case "all":
2511
+ return WGPUTextureAspect_All;
2512
+ case "depth-only":
2513
+ return WGPUTextureAspect_DepthOnly;
2514
+ case "stencil-only":
2515
+ return WGPUTextureAspect_StencilOnly;
2516
+ default:
2517
+ return undefined;
2518
+ }
2519
+ }
2520
+
2521
+ function mapVertexFormat(format?: string | number | null) {
2522
+ if (typeof format === "number") return format;
2523
+ switch (format) {
2524
+ case "float32":
2525
+ return WGPUVertexFormat_Float32;
2526
+ case "float32x2":
2527
+ return WGPUVertexFormat_Float32x2;
2528
+ case "float32x3":
2529
+ return WGPUVertexFormat_Float32x3;
2530
+ case "float32x4":
2531
+ return WGPUVertexFormat_Float32x4;
2532
+ case "uint32":
2533
+ return WGPUVertexFormat_Uint32;
2534
+ case "uint32x2":
2535
+ return WGPUVertexFormat_Uint32x2;
2536
+ case "uint32x3":
2537
+ return WGPUVertexFormat_Uint32x3;
2538
+ case "uint32x4":
2539
+ return WGPUVertexFormat_Uint32x4;
2540
+ case "sint32":
2541
+ return WGPUVertexFormat_Sint32;
2542
+ case "sint32x2":
2543
+ return WGPUVertexFormat_Sint32x2;
2544
+ case "sint32x3":
2545
+ return WGPUVertexFormat_Sint32x3;
2546
+ case "sint32x4":
2547
+ return WGPUVertexFormat_Sint32x4;
2548
+ default:
2549
+ return WGPUVertexFormat_Float32x3;
2550
+ }
2551
+ }
2552
+
2553
+ function mapVertexStepMode(mode?: string | number | null) {
2554
+ if (typeof mode === "number") return mode;
2555
+ switch (mode) {
2556
+ case "instance":
2557
+ return WGPUVertexStepMode_Instance;
2558
+ case "vertex":
2559
+ default:
2560
+ return WGPUVertexStepMode_Vertex;
2561
+ }
2562
+ }
2563
+
2564
+ function mapPrimitiveTopology(topology?: string | number | null) {
2565
+ if (typeof topology === "number") return topology;
2566
+ switch (topology) {
2567
+ case "point-list":
2568
+ return WGPUPrimitiveTopology_PointList;
2569
+ case "line-list":
2570
+ return WGPUPrimitiveTopology_LineList;
2571
+ case "line-strip":
2572
+ return WGPUPrimitiveTopology_LineStrip;
2573
+ case "triangle-strip":
2574
+ return WGPUPrimitiveTopology_TriangleStrip;
2575
+ case "triangle-list":
2576
+ default:
2577
+ return WGPUPrimitiveTopology_TriangleList;
2578
+ }
2579
+ }
2580
+
2581
+ function mapFrontFace(face?: string | number | null) {
2582
+ if (typeof face === "number") return face;
2583
+ switch (face) {
2584
+ case "cw":
2585
+ return WGPUFrontFace_CW;
2586
+ case "ccw":
2587
+ default:
2588
+ return WGPUFrontFace_CCW;
2589
+ }
2590
+ }
2591
+
2592
+ function mapCullMode(mode?: string | number | null) {
2593
+ if (typeof mode === "number") return mode;
2594
+ switch (mode) {
2595
+ case "front":
2596
+ return WGPUCullMode_Front;
2597
+ case "back":
2598
+ return WGPUCullMode_Back;
2599
+ case "none":
2600
+ default:
2601
+ return WGPUCullMode_None;
2602
+ }
2603
+ }
2604
+
2605
+ function mapCompareFunction(fn?: string | number | null) {
2606
+ if (fn == null) return 0;
2607
+ if (typeof fn === "number") return fn;
2608
+ switch (fn) {
2609
+ case "never":
2610
+ return WGPUCompareFunction_Never;
2611
+ case "less":
2612
+ return WGPUCompareFunction_Less;
2613
+ case "equal":
2614
+ return WGPUCompareFunction_Equal;
2615
+ case "less-equal":
2616
+ return WGPUCompareFunction_LessEqual;
2617
+ case "greater":
2618
+ return WGPUCompareFunction_Greater;
2619
+ case "not-equal":
2620
+ return WGPUCompareFunction_NotEqual;
2621
+ case "greater-equal":
2622
+ return WGPUCompareFunction_GreaterEqual;
2623
+ case "always":
2624
+ default:
2625
+ return WGPUCompareFunction_Always;
2626
+ }
2627
+ }
2628
+
2629
+ function mapAddressMode(mode?: string | number | null) {
2630
+ if (typeof mode === "number") return mode;
2631
+ switch (mode) {
2632
+ case "repeat":
2633
+ return WGPUAddressMode_Repeat;
2634
+ case "mirror-repeat":
2635
+ return WGPUAddressMode_MirrorRepeat;
2636
+ case "clamp-to-edge":
2637
+ default:
2638
+ return WGPUAddressMode_ClampToEdge;
2639
+ }
2640
+ }
2641
+
2642
+ function mapFilterMode(mode?: string | number | null) {
2643
+ if (typeof mode === "number") return mode;
2644
+ switch (mode) {
2645
+ case "nearest":
2646
+ return WGPUFilterMode_Nearest;
2647
+ case "linear":
2648
+ default:
2649
+ return WGPUFilterMode_Linear;
2650
+ }
2651
+ }
2652
+
2653
+ function mapMipmapFilterMode(mode?: string | number | null) {
2654
+ if (typeof mode === "number") return mode;
2655
+ switch (mode) {
2656
+ case "nearest":
2657
+ return WGPUMipmapFilterMode_Nearest;
2658
+ case "linear":
2659
+ default:
2660
+ return WGPUMipmapFilterMode_Linear;
2661
+ }
2662
+ }
2663
+
2664
+ function mapShaderStage(stage?: string | number | null) {
2665
+ if (typeof stage === "number") return stage;
2666
+ switch (stage) {
2667
+ case "vertex":
2668
+ return WGPUShaderStage_Vertex;
2669
+ case "fragment":
2670
+ return WGPUShaderStage_Fragment;
2671
+ case "compute":
2672
+ return WGPUShaderStage_Compute;
2673
+ default:
2674
+ return 0;
2675
+ }
2676
+ }
2677
+
2678
+ function mapBufferBindingType(type?: string | number | null) {
2679
+ if (typeof type === "number") return type;
2680
+ switch (type) {
2681
+ case "uniform":
2682
+ return WGPUBufferBindingType_Uniform;
2683
+ case "storage":
2684
+ return WGPUBufferBindingType_Storage;
2685
+ case "read-only-storage":
2686
+ return WGPUBufferBindingType_ReadOnlyStorage;
2687
+ default:
2688
+ return WGPUBufferBindingType_Uniform;
2689
+ }
2690
+ }
2691
+
2692
+ function mapSamplerBindingType(type?: string | number | null) {
2693
+ if (typeof type === "number") return type;
2694
+ switch (type) {
2695
+ case "comparison":
2696
+ return WGPUSamplerBindingType_Comparison;
2697
+ case "non-filtering":
2698
+ return WGPUSamplerBindingType_NonFiltering;
2699
+ case "filtering":
2700
+ default:
2701
+ return WGPUSamplerBindingType_Filtering;
2702
+ }
2703
+ }
2704
+
2705
+ function mapTextureSampleType(type?: string | number | null) {
2706
+ if (typeof type === "number") return type;
2707
+ switch (type) {
2708
+ case "unfilterable-float":
2709
+ return WGPUTextureSampleType_UnfilterableFloat;
2710
+ case "depth":
2711
+ return WGPUTextureSampleType_Depth;
2712
+ case "sint":
2713
+ return WGPUTextureSampleType_Sint;
2714
+ case "uint":
2715
+ return WGPUTextureSampleType_Uint;
2716
+ case "float":
2717
+ default:
2718
+ return WGPUTextureSampleType_Float;
2719
+ }
2720
+ }
2721
+
2722
+ function mapStorageTextureAccess(access?: string | number | null) {
2723
+ if (typeof access === "number") return access;
2724
+ switch (access) {
2725
+ case "read-only":
2726
+ return WGPUStorageTextureAccess_ReadOnly;
2727
+ case "read-write":
2728
+ return WGPUStorageTextureAccess_ReadWrite;
2729
+ case "write-only":
2730
+ default:
2731
+ return WGPUStorageTextureAccess_WriteOnly;
2732
+ }
2733
+ }
2734
+
2735
+ function mapBlendOperation(op?: string | number | null) {
2736
+ if (typeof op === "number") return op;
2737
+ switch (op) {
2738
+ case "add":
2739
+ default:
2740
+ return WGPUBlendOperation_Add;
2741
+ }
2742
+ }
2743
+
2744
+ function mapBlendFactor(factor?: string | number | null) {
2745
+ if (typeof factor === "number") return factor;
2746
+ switch (factor) {
2747
+ case "one":
2748
+ return WGPUBlendFactor_One;
2749
+ case "zero":
2750
+ return WGPUBlendFactor_Zero;
2751
+ case "src-alpha":
2752
+ return WGPUBlendFactor_SrcAlpha;
2753
+ case "one-minus-src-alpha":
2754
+ return WGPUBlendFactor_OneMinusSrcAlpha;
2755
+ default:
2756
+ return WGPUBlendFactor_One;
2757
+ }
2758
+ }
2759
+
2760
+ function mapLoadOp(op?: string | number | null) {
2761
+ if (typeof op === "number") return op;
2762
+ switch (op) {
2763
+ case "load":
2764
+ return WGPULoadOp_Load;
2765
+ case "clear":
2766
+ default:
2767
+ return WGPULoadOp_Clear;
2768
+ }
2769
+ }
2770
+
2771
+ function mapStoreOp(op?: string | number | null) {
2772
+ if (typeof op === "number") return op;
2773
+ switch (op) {
2774
+ case "discard":
2775
+ return WGPUStoreOp_Discard;
2776
+ case "store":
2777
+ default:
2778
+ return WGPUStoreOp_Store;
2779
+ }
2780
+ }
2781
+
2782
+ function mapIndexFormat(format?: string | number | null) {
2783
+ if (typeof format === "number") return format;
2784
+ switch (format) {
2785
+ case "uint32":
2786
+ return 0x00000002;
2787
+ case "uint16":
2788
+ return 0x00000001;
2789
+ default:
2790
+ return 0;
2791
+ }
2792
+ }
2793
+
2794
+ function mapAlphaMode(mode?: string | number | null) {
2795
+ if (typeof mode === "number") return mode;
2796
+ switch (mode) {
2797
+ case "premultiplied":
2798
+ return WGPUCompositeAlphaMode_Premultiplied;
2799
+ case "unpremultiplied":
2800
+ return WGPUCompositeAlphaMode_Unpremultiplied;
2801
+ case "opaque":
2802
+ default:
2803
+ return WGPUCompositeAlphaMode_Opaque;
2804
+ }
2805
+ }
2806
+
2807
+ function makeShaderSourceWGSL(codePtr: number, codeLen: bigint) {
2808
+ const buffer = new ArrayBuffer(32);
2809
+ const view = new DataView(buffer);
2810
+ writePtr(view, 0, 0);
2811
+ writeU32(view, 8, 0x00000002);
2812
+ writeU32(view, 12, 0);
2813
+ writePtr(view, 16, codePtr);
2814
+ writeU64(view, 24, codeLen);
2815
+ return { buffer, ptr: ptr(buffer) };
2816
+ }
2817
+
2818
+ function makeShaderModuleDescriptor(nextInChainPtr: number) {
2819
+ const buffer = new ArrayBuffer(24);
2820
+ const view = new DataView(buffer);
2821
+ writePtr(view, 0, nextInChainPtr);
2822
+ writePtr(view, 8, 0);
2823
+ writeU64(view, 16, 0n);
2824
+ return { buffer, ptr: ptr(buffer) };
2825
+ }
2826
+
2827
+ function makeTexelCopyTextureInfo(
2828
+ texturePtr: number,
2829
+ mipLevel = 0,
2830
+ origin?: { x?: number; y?: number; z?: number },
2831
+ ) {
2832
+ const buffer = new ArrayBuffer(32);
2833
+ const view = new DataView(buffer);
2834
+ writePtr(view, 0, texturePtr);
2835
+ writeU32(view, 8, mipLevel);
2836
+ writeU32(view, 12, origin?.x ?? 0);
2837
+ writeU32(view, 16, origin?.y ?? 0);
2838
+ writeU32(view, 20, origin?.z ?? 0);
2839
+ writeU32(view, 24, 0);
2840
+ writeU32(view, 28, 0);
2841
+ return { buffer, ptr: ptr(buffer) };
2842
+ }
2843
+
2844
+ function makeTexelCopyBufferLayout(
2845
+ offset: number | bigint,
2846
+ bytesPerRow: number,
2847
+ rowsPerImage: number,
2848
+ ) {
2849
+ const buffer = new ArrayBuffer(16);
2850
+ const view = new DataView(buffer);
2851
+ writeU64(view, 0, BigInt(offset));
2852
+ writeU32(view, 8, bytesPerRow);
2853
+ writeU32(view, 12, rowsPerImage);
2854
+ return { buffer, ptr: ptr(buffer) };
2855
+ }
2856
+
2857
+ function makeImageCopyBuffer(
2858
+ bufferPtr: number,
2859
+ offset: number,
2860
+ bytesPerRow: number,
2861
+ rowsPerImage: number,
2862
+ ) {
2863
+ const buffer = new ArrayBuffer(24);
2864
+ const view = new DataView(buffer);
2865
+ writeU64(view, 0, BigInt(offset));
2866
+ writeU32(view, 8, bytesPerRow);
2867
+ writeU32(view, 12, rowsPerImage);
2868
+ writePtr(view, 16, bufferPtr);
2869
+ return { buffer, ptr: ptr(buffer) };
2870
+ }
2871
+
2872
+ function makeExtent3D(width: number, height: number, depth: number) {
2873
+ const buffer = new ArrayBuffer(12);
2874
+ const view = new DataView(buffer);
2875
+ writeU32(view, 0, width);
2876
+ writeU32(view, 4, height);
2877
+ writeU32(view, 8, depth);
2878
+ return { buffer, ptr: ptr(buffer) };
2879
+ }
2880
+
2881
+ function alignTo(value: number, alignment: number) {
2882
+ return Math.ceil(value / alignment) * alignment;
2883
+ }
2884
+
2885
+ function bytesPerPixelForFormat(format?: number) {
2886
+ switch (format) {
2887
+ case WGPUTextureFormat_R8Unorm:
2888
+ case WGPUTextureFormat_R8Snorm:
2889
+ case WGPUTextureFormat_R8Uint:
2890
+ case WGPUTextureFormat_R8Sint:
2891
+ return 1;
2892
+ case WGPUTextureFormat_RG8Unorm:
2893
+ case WGPUTextureFormat_RG8Snorm:
2894
+ case WGPUTextureFormat_RG8Uint:
2895
+ case WGPUTextureFormat_RG8Sint:
2896
+ return 2;
2897
+ case WGPUTextureFormat_BGRA8Unorm:
2898
+ case WGPUTextureFormat_BGRA8UnormSrgb:
2899
+ case WGPUTextureFormat_RGBA8Unorm:
2900
+ case WGPUTextureFormat_RGBA8UnormSrgb:
2901
+ case WGPUTextureFormat_Depth24Plus:
2902
+ case WGPUTextureFormat_Depth24PlusStencil8:
2903
+ case WGPUTextureFormat_Depth32Float:
2904
+ return 4;
2905
+ case WGPUTextureFormat_Depth32FloatStencil8:
2906
+ return 8;
2907
+ case WGPUTextureFormat_RG32Float:
2908
+ case WGPUTextureFormat_RG32Uint:
2909
+ case WGPUTextureFormat_RG32Sint:
2910
+ case WGPUTextureFormat_RGBA16Float:
2911
+ case WGPUTextureFormat_RGBA16Uint:
2912
+ case WGPUTextureFormat_RGBA16Sint:
2913
+ return 8;
2914
+ case WGPUTextureFormat_RGBA32Uint:
2915
+ case WGPUTextureFormat_RGBA32Sint:
2916
+ return 16;
2917
+ default:
2918
+ return 4;
2919
+ }
2920
+ }
2921
+
2922
+ function repackTextureData(
2923
+ data: ArrayBufferView,
2924
+ srcStride: number,
2925
+ dstStride: number,
2926
+ minRowBytes: number,
2927
+ height: number,
2928
+ rowsPerImage: number,
2929
+ layers: number,
2930
+ ) {
2931
+ const src = new Uint8Array(
2932
+ data.buffer,
2933
+ data.byteOffset,
2934
+ data.byteLength,
2935
+ );
2936
+ const totalRows = rowsPerImage * layers;
2937
+ const dst = new Uint8Array(dstStride * totalRows);
2938
+ let srcOffset = 0;
2939
+ let dstOffset = 0;
2940
+
2941
+ for (let layer = 0; layer < layers; layer += 1) {
2942
+ for (let row = 0; row < rowsPerImage; row += 1) {
2943
+ if (row < height) {
2944
+ dst.set(
2945
+ src.subarray(srcOffset, srcOffset + minRowBytes),
2946
+ dstOffset,
2947
+ );
2948
+ }
2949
+ srcOffset += srcStride;
2950
+ dstOffset += dstStride;
2951
+ }
2952
+ }
2953
+
2954
+ return dst;
2955
+ }
2956
+
2957
+ const webgpu = {
2958
+ navigator: {
2959
+ async requestAdapter(options?: { compatibleSurface?: GPUCanvasContext }) {
2960
+ const compatibleSurface =
2961
+ options?.compatibleSurface ?? LAST_CREATED_CONTEXT ?? undefined;
2962
+ if (compatibleSurface?.instancePtr) {
2963
+ return new GPUAdapter(
2964
+ compatibleSurface.instancePtr,
2965
+ compatibleSurface.surfacePtr,
2966
+ );
2967
+ }
2968
+ const instance = WGPUNative.symbols.wgpuCreateInstance(0);
2969
+ return new GPUAdapter(Number(instance), 0);
2970
+ },
2971
+ getPreferredCanvasFormat() {
2972
+ return "bgra8unorm";
2973
+ },
2974
+ },
2975
+ createContext,
2976
+ GPUCanvasContext,
2977
+ utils: {
2978
+ createCanvasShim,
2979
+ decodePngRGBA,
2980
+ },
2981
+ install() {
2982
+ const nav = (globalThis as any).navigator ?? {};
2983
+ nav.gpu = webgpu.navigator;
2984
+ (globalThis as any).navigator = nav;
2985
+ (globalThis as any).GPUCanvasContext = GPUCanvasContext;
2986
+ },
2987
+ };
2988
+
2989
+ export {
2990
+ webgpu,
2991
+ GPUCanvasContext,
2992
+ GPUAdapter,
2993
+ GPUDevice,
2994
+ GPUQueue,
2995
+ GPUTexture,
2996
+ GPUTextureView,
2997
+ GPUBuffer,
2998
+ GPUSampler,
2999
+ GPUBindGroupLayout,
3000
+ GPUBindGroup,
3001
+ GPUPipelineLayout,
3002
+ GPUShaderModule,
3003
+ GPURenderPipeline,
3004
+ GPUComputePipeline,
3005
+ GPUCommandEncoder,
3006
+ GPUCommandBuffer,
3007
+ GPURenderPassEncoder,
3008
+ createCanvasShim,
3009
+ decodePngRGBA,
3010
+ };
3011
+ export default webgpu;