aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2024-06-20 11:39:58 +0100
committerGitHub <noreply@github.com>2024-06-20 11:39:58 +0100
commit7184792f7ab31fcea9b892ece42440b3b225f414 (patch)
treef8f082bb0871ad34e715e39726d477d43b325bc5
parentd4aa6c3288f9b28560e55239a92466f87066fb39 (diff)
parent108b8feb357dab8b3faf788c382406567bd99d33 (diff)
Merge pull request #3740 from laytan/wgpu
Add `vendor:wgpu`
-rw-r--r--.gitignore2
-rw-r--r--core/sys/darwin/Foundation/NSWindow.odin4
-rw-r--r--vendor/glfw/native_linux.odin26
-rw-r--r--vendor/wasm/js/runtime.js44
-rw-r--r--vendor/wgpu/.gitignore9
-rw-r--r--vendor/wgpu/README.md48
-rw-r--r--vendor/wgpu/example/Makefile17
-rw-r--r--vendor/wgpu/example/build.bat12
-rw-r--r--vendor/wgpu/example/main.odin187
-rw-r--r--vendor/wgpu/example/os_glfw.odin55
-rw-r--r--vendor/wgpu/example/os_js.odin60
-rw-r--r--vendor/wgpu/example/web/index.html23
-rw-r--r--vendor/wgpu/glfwglue/glue.odin6
-rw-r--r--vendor/wgpu/glfwglue/glue_darwin.odin23
-rw-r--r--vendor/wgpu/glfwglue/glue_linux.odin43
-rw-r--r--vendor/wgpu/glfwglue/glue_windows.odin23
-rw-r--r--vendor/wgpu/lib/.gitkeep0
-rw-r--r--vendor/wgpu/wgpu.js2916
-rw-r--r--vendor/wgpu/wgpu.odin1636
-rw-r--r--vendor/wgpu/wgpu_js.odin26
-rw-r--r--vendor/wgpu/wgpu_native.odin75
-rw-r--r--vendor/wgpu/wgpu_native_types.odin212
-rw-r--r--vendor/x11/xlib/xlib_types.odin3
23 files changed, 5431 insertions, 19 deletions
diff --git a/.gitignore b/.gitignore
index 2b6b5281a..c8a66d288 100644
--- a/.gitignore
+++ b/.gitignore
@@ -303,7 +303,7 @@ bin/
# - Linux/MacOS
odin
!odin/
-odin.dSYM
+**/*.dSYM
*.bin
demo.bin
libLLVM*.so*
diff --git a/core/sys/darwin/Foundation/NSWindow.odin b/core/sys/darwin/Foundation/NSWindow.odin
index 7159a7c3a..e6103a58a 100644
--- a/core/sys/darwin/Foundation/NSWindow.odin
+++ b/core/sys/darwin/Foundation/NSWindow.odin
@@ -712,3 +712,7 @@ Window_setDelegate :: proc "c" (self: ^Window, delegate: ^WindowDelegate) {
Window_backingScaleFactor :: proc "c" (self: ^Window) -> Float {
return msgSend(Float, self, "backingScaleFactor")
}
+@(objc_type=Window, objc_name="setWantsLayer")
+Window_setWantsLayer :: proc "c" (self: ^Window, ok: BOOL) {
+ msgSend(nil, self, "setWantsLayer:", ok)
+}
diff --git a/vendor/glfw/native_linux.odin b/vendor/glfw/native_linux.odin
index 9b9e14790..6833d2893 100644
--- a/vendor/glfw/native_linux.odin
+++ b/vendor/glfw/native_linux.odin
@@ -2,14 +2,18 @@
package glfw
-// TODO: Native Linux
-// Display* glfwGetX11Display(void);
-// RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
-// RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
-// Window glfwGetX11Window(GLFWwindow* window);
-// void glfwSetX11SelectionString(const char* string);
-// const char* glfwGetX11SelectionString(void);
-
-// struct wl_display* glfwGetWaylandDisplay(void);
-// struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
-// struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
+import "vendor:x11/xlib"
+
+@(default_calling_convention="c", link_prefix="glfw")
+foreign {
+ GetX11Display :: proc() -> ^xlib.Display ---
+ GetX11Window :: proc(window: WindowHandle) -> xlib.Window ---
+ GetX11Adapter :: proc(monitor: MonitorHandle) -> xlib.RRCrtc ---
+ GetX11Monitor :: proc(monitor: MonitorHandle) -> xlib.RROutput ---
+ SetX11SelectionString :: proc(string: cstring) ---
+ GetX11SelectionString :: proc() -> cstring ---
+
+ GetWaylandDisplay :: proc() -> rawptr /* struct wl_display* */ ---
+ GetWaylandWindow :: proc(window: WindowHandle) -> rawptr /* struct wl_surface* */ ---
+ GetWaylandMonitor :: proc(monitor: MonitorHandle) -> rawptr /* struct wl_output* */ ---
+}
diff --git a/vendor/wasm/js/runtime.js b/vendor/wasm/js/runtime.js
index 5c7f97fae..74ad7568e 100644
--- a/vendor/wasm/js/runtime.js
+++ b/vendor/wasm/js/runtime.js
@@ -96,6 +96,10 @@ class WasmMemoryInterface {
};
loadPtr(addr) { return this.loadU32(addr); }
+ loadB32(addr) {
+ return this.loadU32(addr) != 0;
+ }
+
loadBytes(ptr, len) {
return new Uint8Array(this.memory.buffer, ptr, Number(len));
}
@@ -104,6 +108,16 @@ class WasmMemoryInterface {
const bytes = this.loadBytes(ptr, Number(len));
return new TextDecoder().decode(bytes);
}
+
+ loadCstring(ptr) {
+ const start = this.loadPtr(ptr);
+ if (start == 0) {
+ return null;
+ }
+ let len = 0;
+ for (; this.mem.getUint8(start+len) != 0; len += 1) {}
+ return this.loadString(start, len);
+ }
storeU8(addr, value) { this.mem.setUint8 (addr, value); }
storeI8(addr, value) { this.mem.setInt8 (addr, value); }
@@ -1245,7 +1259,7 @@ class WebGLInterface {
};
-function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
+function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
const MAX_INFO_CONSOLE_LINES = 512;
let infoConsoleLines = new Array();
let currentLine = {};
@@ -1366,8 +1380,15 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
let event_temp_data = {};
let webglContext = new WebGLInterface(wasmMemoryInterface);
+
+ const env = {};
+
+ if (memory) {
+ env.memory = memory;
+ }
+
return {
- "env": {},
+ env,
"odin_env": {
write: (fd, ptr, len) => {
const str = wasmMemoryInterface.loadString(ptr, len);
@@ -1720,13 +1741,16 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
* @param {string} wasmPath - Path to the WASM module to run
* @param {?HTMLPreElement} consoleElement - Optional console/pre element to append output to, in addition to the console
* @param {any} extraForeignImports - Imports, in addition to the default runtime to provide the module
+ * @param {?WasmMemoryInterface} wasmMemoryInterface - Optional memory to use instead of the defaults
* @param {?int} intSize - Size (in bytes) of the integer type, should be 4 on `js_wasm32` and 8 on `js_wasm64p32`
*/
-async function runWasm(wasmPath, consoleElement, extraForeignImports, intSize = 4) {
- const wasmMemoryInterface = new WasmMemoryInterface();
+async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemoryInterface, intSize = 4) {
+ if (!wasmMemoryInterface) {
+ wasmMemoryInterface = new WasmMemoryInterface();
+ }
wasmMemoryInterface.setIntSize(intSize);
- let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement);
+ let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement, wasmMemoryInterface.memory);
let exports = {};
if (extraForeignImports !== undefined) {
@@ -1741,11 +1765,17 @@ async function runWasm(wasmPath, consoleElement, extraForeignImports, intSize =
const wasm = await WebAssembly.instantiate(file, imports);
exports = wasm.instance.exports;
wasmMemoryInterface.setExports(exports);
- wasmMemoryInterface.setMemory(exports.memory);
+
+ if (exports.memory) {
+ if (wasmMemoryInterface.memory) {
+ console.warn("WASM module exports memory, but `runWasm` was given an interface with existing memory too");
+ }
+ wasmMemoryInterface.setMemory(exports.memory);
+ }
exports._start();
- // Define a `@export step :: proc(dt: f32) -> (continue: bool) {`
+ // Define a `@export step :: proc(dt: f32) -> (keep_going: bool) {`
// in your app and it will get called every frame.
// return `false` to stop the execution of the module.
if (exports.step) {
diff --git a/vendor/wgpu/.gitignore b/vendor/wgpu/.gitignore
new file mode 100644
index 000000000..330d70755
--- /dev/null
+++ b/vendor/wgpu/.gitignore
@@ -0,0 +1,9 @@
+lib/*
+!lib/.gitkeep
+example/web/triangle.wasm
+example/web/wgpu.js
+example/web/runtime.js
+example/example
+example/example.exe
+example/triangle
+example/triangle.exe
diff --git a/vendor/wgpu/README.md b/vendor/wgpu/README.md
new file mode 100644
index 000000000..3561642f4
--- /dev/null
+++ b/vendor/wgpu/README.md
@@ -0,0 +1,48 @@
+# WGPU
+
+A cross-platform (and WASM) GPU API.
+
+WASM support is achieved by providing wrappers around the browser native WebGPU API
+that are called instead of the [wgpu-native](https://github.com/gfx-rs/wgpu-native) library,
+the wgpu-native library provides support for all other targets.
+
+Have a look at the `example/` directory for the rendering of a basic triangle.
+
+## Getting the wgpu-native libraries
+
+For native support (not the browser), some libraries are required. Fortunately this is
+extremely easy, just download them from the [releases on GitHub](https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1),
+the bindings are for v0.19.4.1 at the moment.
+
+These are expected in the `lib` folder under the same name as they are released (just unzipped).
+By default it will look for a static release version (`wgpu-OS-ARCH-release.a|lib`),
+you can set `-define:WGPU_DEBUG=true` for it to look for a debug version,
+and use `-define:WGPU_SHARED=true` to look for the shared libraries.
+
+## WASM
+
+For WASM, the module has to be built with a function table to enable callbacks.
+You can do so using `-extra-linker-flags:"--export-table"`.
+
+Being able to allocate is also required (for some auxiliary APIs but also for mapping/unmapping buffers).
+
+You can set the context that is used for allocations by setting the global variable `wpgu.g_context`.
+It will default to the `runtime.default_context`.
+
+Again, have a look at the `example/` and how it is set up, doing the `--import-memory` and the likes
+is not strictly necessary but allows your app more memory than the minimal default.
+
+The bindings work on both `-target:js_wasm32` and `-target:js_wasm64p32`.
+
+## GLFW Glue
+
+There is an inner package `glfwglue` that can be used to glue together WGPU and GLFW.
+It exports one procedure `GetSurface(wgpu.Instance, glfw.WindowHandle) -> glfw.Surface`.
+The procedure will call the needed target specific procedures and return a surface configured
+for the given window.
+
+To support Wayland on Linux, you need to have GLFW compiled to support it, and use
+`-define:WGPU_GFLW_GLUE_SUPPORT_WAYLAND=true` to enable the package to check for Wayland.
+
+Do note that wgpu does not require GLFW, you can use native windows or another windowing library too.
+For that you can take inspiration from `glfwglue` on glueing them together.
diff --git a/vendor/wgpu/example/Makefile b/vendor/wgpu/example/Makefile
new file mode 100644
index 000000000..f19997881
--- /dev/null
+++ b/vendor/wgpu/example/Makefile
@@ -0,0 +1,17 @@
+FILES := $(wildcard *)
+
+# NOTE: changing this requires changing the same values in the `web/index.html`.
+INITIAL_MEMORY_PAGES := 2000
+MAX_MEMORY_PAGES := 65536
+
+PAGE_SIZE := 65536
+INITIAL_MEMORY_BYTES := $(shell expr $(INITIAL_MEMORY_PAGES) \* $(PAGE_SIZE))
+MAX_MEMORY_BYTES := $(shell expr $(MAX_MEMORY_PAGES) \* $(PAGE_SIZE))
+
+web/triangle.wasm: $(FILES) ../wgpu.js ../../wasm/js/runtime.js
+ odin build . \
+ -target:js_wasm32 -out:web/triangle.wasm -o:size \
+ -extra-linker-flags:"--export-table --import-memory --initial-memory=$(INITIAL_MEMORY_BYTES) --max-memory=$(MAX_MEMORY_BYTES)"
+
+ cp ../wgpu.js web/wgpu.js
+ cp ../../wasm/js/runtime.js web/runtime.js
diff --git a/vendor/wgpu/example/build.bat b/vendor/wgpu/example/build.bat
new file mode 100644
index 000000000..cd3ca63ba
--- /dev/null
+++ b/vendor/wgpu/example/build.bat
@@ -0,0 +1,12 @@
+REM NOTE: changing this requires changing the same values in the `web/index.html`.
+set INITIAL_MEMORY_PAGES=2000
+set MAX_MEMORY_PAGES=65536
+
+set PAGE_SIZE=65536
+set /a INITIAL_MEMORY_BYTES=%INITIAL_MEMORY_PAGES% * %PAGE_SIZE%
+set /a MAX_MEMORY_BYTES=%MAX_MEMORY_PAGES% * %PAGE_SIZE%
+
+call odin.exe build . -target:js_wasm32 -out:web/triangle.wasm -o:size -extra-linker-flags:"--export-table --import-memory --initial-memory=%INITIAL_MEMORY_BYTES% --max-memory=%MAX_MEMORY_BYTES%"
+
+copy "..\wgpu.js" "web\wgpu.js"
+copy "..\..\wasm\js\runtime.js" "web\runtime.js" \ No newline at end of file
diff --git a/vendor/wgpu/example/main.odin b/vendor/wgpu/example/main.odin
new file mode 100644
index 000000000..39161311c
--- /dev/null
+++ b/vendor/wgpu/example/main.odin
@@ -0,0 +1,187 @@
+package vendor_wgpu_example_triangle
+
+import "base:runtime"
+
+import "core:fmt"
+
+import "vendor:wgpu"
+
+State :: struct {
+ ctx: runtime.Context,
+ os: OS,
+
+ instance: wgpu.Instance,
+ surface: wgpu.Surface,
+ adapter: wgpu.Adapter,
+ device: wgpu.Device,
+ config: wgpu.SurfaceConfiguration,
+ queue: wgpu.Queue,
+ module: wgpu.ShaderModule,
+ pipeline_layout: wgpu.PipelineLayout,
+ pipeline: wgpu.RenderPipeline,
+}
+
+@(private="file")
+state: State
+
+main :: proc() {
+ state.ctx = context
+
+ os_init(&state.os)
+
+ state.instance = wgpu.CreateInstance(nil)
+ if state.instance == nil {
+ panic("WebGPU is not supported")
+ }
+ state.surface = os_get_surface(&state.os, state.instance)
+
+ wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, on_adapter, nil)
+
+ on_adapter :: proc "c" (status: wgpu.RequestAdapterStatus, adapter: wgpu.Adapter, message: cstring, userdata: rawptr) {
+ context = state.ctx
+ if status != .Success || adapter == nil {
+ fmt.panicf("request adapter failure: [%v] %s", status, message)
+ }
+ state.adapter = adapter
+ wgpu.AdapterRequestDevice(adapter, nil, on_device)
+ }
+
+ on_device :: proc "c" (status: wgpu.RequestDeviceStatus, device: wgpu.Device, message: cstring, userdata: rawptr) {
+ context = state.ctx
+ if status != .Success || device == nil {
+ fmt.panicf("request device failure: [%v] %s", status, message)
+ }
+ state.device = device
+
+ width, height := os_get_render_bounds(&state.os)
+
+ state.config = wgpu.SurfaceConfiguration {
+ device = state.device,
+ usage = { .RenderAttachment },
+ format = .BGRA8Unorm,
+ width = width,
+ height = height,
+ presentMode = .Fifo,
+ alphaMode = .Opaque,
+ }
+ wgpu.SurfaceConfigure(state.surface, &state.config)
+
+ state.queue = wgpu.DeviceGetQueue(state.device)
+
+ shader :: `
+ @vertex
+ fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
+ let x = f32(i32(in_vertex_index) - 1);
+ let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
+ return vec4<f32>(x, y, 0.0, 1.0);
+ }
+
+ @fragment
+ fn fs_main() -> @location(0) vec4<f32> {
+ return vec4<f32>(1.0, 0.0, 0.0, 1.0);
+ }`
+
+ state.module = wgpu.DeviceCreateShaderModule(state.device, &{
+ nextInChain = &wgpu.ShaderModuleWGSLDescriptor{
+ sType = .ShaderModuleWGSLDescriptor,
+ code = shader,
+ },
+ })
+
+ state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(state.device, &{})
+ state.pipeline = wgpu.DeviceCreateRenderPipeline(state.device, &{
+ layout = state.pipeline_layout,
+ vertex = {
+ module = state.module,
+ entryPoint = "vs_main",
+ },
+ fragment = &{
+ module = state.module,
+ entryPoint = "fs_main",
+ targetCount = 1,
+ targets = &wgpu.ColorTargetState{
+ format = .BGRA8Unorm,
+ writeMask = wgpu.ColorWriteMaskFlags_All,
+ },
+ },
+ primitive = {
+ topology = .TriangleList,
+
+ },
+ multisample = {
+ count = 1,
+ mask = 0xFFFFFFFF,
+ },
+ })
+
+ os_run(&state.os)
+ }
+}
+
+resize :: proc "c" () {
+ context = state.ctx
+
+ state.config.width, state.config.height = os_get_render_bounds(&state.os)
+ wgpu.SurfaceConfigure(state.surface, &state.config)
+}
+
+frame :: proc "c" (dt: f32) {
+ context = state.ctx
+
+ surface_texture := wgpu.SurfaceGetCurrentTexture(state.surface)
+ switch surface_texture.status {
+ case .Success:
+ // All good, could check for `surface_texture.suboptimal` here.
+ case .Timeout, .Outdated, .Lost:
+ // Skip this frame, and re-configure surface.
+ if surface_texture.texture != nil {
+ wgpu.TextureRelease(surface_texture.texture)
+ }
+ resize()
+ return
+ case .OutOfMemory, .DeviceLost:
+ // Fatal error
+ fmt.panicf("[triangle] get_current_texture status=%v", surface_texture.status)
+ }
+ defer wgpu.TextureRelease(surface_texture.texture)
+
+ frame := wgpu.TextureCreateView(surface_texture.texture, nil)
+ defer wgpu.TextureViewRelease(frame)
+
+ command_encoder := wgpu.DeviceCreateCommandEncoder(state.device, nil)
+ defer wgpu.CommandEncoderRelease(command_encoder)
+
+ render_pass_encoder := wgpu.CommandEncoderBeginRenderPass(
+ command_encoder, &{
+ colorAttachmentCount = 1,
+ colorAttachments = &wgpu.RenderPassColorAttachment{
+ view = frame,
+ loadOp = .Clear,
+ storeOp = .Store,
+ clearValue = { r = 0, g = 1, b = 0, a = 1 },
+ },
+ },
+ )
+ defer wgpu.RenderPassEncoderRelease(render_pass_encoder)
+
+ wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline)
+ wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
+ wgpu.RenderPassEncoderEnd(render_pass_encoder)
+
+ command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
+ defer wgpu.CommandBufferRelease(command_buffer)
+
+ wgpu.QueueSubmit(state.queue, { command_buffer })
+ wgpu.SurfacePresent(state.surface)
+}
+
+finish :: proc() {
+ wgpu.RenderPipelineRelease(state.pipeline)
+ wgpu.PipelineLayoutRelease(state.pipeline_layout)
+ wgpu.ShaderModuleRelease(state.module)
+ wgpu.QueueRelease(state.queue)
+ wgpu.DeviceRelease(state.device)
+ wgpu.AdapterRelease(state.adapter)
+ wgpu.SurfaceRelease(state.surface)
+ wgpu.InstanceRelease(state.instance)
+}
diff --git a/vendor/wgpu/example/os_glfw.odin b/vendor/wgpu/example/os_glfw.odin
new file mode 100644
index 000000000..2b1817fa5
--- /dev/null
+++ b/vendor/wgpu/example/os_glfw.odin
@@ -0,0 +1,55 @@
+//+build !js
+package vendor_wgpu_example_triangle
+
+import "core:time"
+
+import "vendor:glfw"
+import "vendor:wgpu"
+import "vendor:wgpu/glfwglue"
+
+OS :: struct {
+ window: glfw.WindowHandle,
+}
+
+os_init :: proc(os: ^OS) {
+ if !glfw.Init() {
+ panic("[glfw] init failure")
+ }
+
+ glfw.WindowHint(glfw.CLIENT_API, glfw.NO_API)
+ os.window = glfw.CreateWindow(960, 540, "WGPU Native Triangle", nil, nil)
+
+ glfw.SetFramebufferSizeCallback(os.window, size_callback)
+}
+
+os_run :: proc(os: ^OS) {
+ dt: f32
+
+ for !glfw.WindowShouldClose(os.window) {
+ start := time.tick_now()
+
+ glfw.PollEvents()
+ frame(dt)
+
+ dt = f32(time.duration_seconds(time.tick_since(start)))
+ }
+
+ finish()
+
+ glfw.DestroyWindow(os.window)
+ glfw.Terminate()
+}
+
+os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) {
+ iw, ih := glfw.GetWindowSize(os.window)
+ return u32(iw), u32(ih)
+}
+
+os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface {
+ return glfwglue.GetSurface(instance, os.window)
+}
+
+@(private="file")
+size_callback :: proc "c" (window: glfw.WindowHandle, width, height: i32) {
+ resize()
+}
diff --git a/vendor/wgpu/example/os_js.odin b/vendor/wgpu/example/os_js.odin
new file mode 100644
index 000000000..9634f4afe
--- /dev/null
+++ b/vendor/wgpu/example/os_js.odin
@@ -0,0 +1,60 @@
+package vendor_wgpu_example_triangle
+
+import "vendor:wgpu"
+import "vendor:wasm/js"
+
+OS :: struct {
+ initialized: bool,
+}
+
+@(private="file")
+g_os: ^OS
+
+os_init :: proc(os: ^OS) {
+ g_os = os
+ assert(js.add_window_event_listener(.Resize, nil, size_callback))
+}
+
+// NOTE: frame loop is done by the runtime.js repeatedly calling `step`.
+os_run :: proc(os: ^OS) {
+ os.initialized = true
+}
+
+os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) {
+ rect := js.get_bounding_client_rect("body")
+ return u32(rect.width), u32(rect.height)
+}
+
+os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface {
+ return wgpu.InstanceCreateSurface(
+ instance,
+ &wgpu.SurfaceDescriptor{
+ nextInChain = &wgpu.SurfaceDescriptorFromCanvasHTMLSelector{
+ sType = .SurfaceDescriptorFromCanvasHTMLSelector,
+ selector = "#wgpu-canvas",
+ },
+ },
+ )
+}
+
+@(private="file", export)
+step :: proc(dt: f32) -> bool {
+ if !g_os.initialized {
+ return true
+ }
+
+ frame(dt)
+ return true
+}
+
+@(private="file", fini)
+os_fini :: proc() {
+ js.remove_window_event_listener(.Resize, nil, size_callback)
+
+ finish()
+}
+
+@(private="file")
+size_callback :: proc(e: js.Event) {
+ resize()
+}
diff --git a/vendor/wgpu/example/web/index.html b/vendor/wgpu/example/web/index.html
new file mode 100644
index 000000000..61872e35a
--- /dev/null
+++ b/vendor/wgpu/example/web/index.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en" style="height: 100%;">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>WGPU WASM Triangle</title>
+ </head>
+ <body id="body" style="height: 100%; padding: 0; margin: 0; overflow: hidden;">
+ <canvas id="wgpu-canvas"></canvas>
+
+ <script type="text/javascript" src="runtime.js"></script>
+ <script type="text/javascript" src="wgpu.js"></script>
+ <script type="text/javascript">
+ const mem = new WebAssembly.Memory({ initial: 2000, maximum: 65536, shared: false });
+ const memInterface = new odin.WasmMemoryInterface();
+ memInterface.setMemory(mem);
+
+ const wgpuInterface = new odin.WebGPUInterface(memInterface);
+
+ odin.runWasm("triangle.wasm", null, { wgpu: wgpuInterface.getInterface() }, memInterface, /*intSize=8*/);
+ </script>
+ </body>
+</html>
diff --git a/vendor/wgpu/glfwglue/glue.odin b/vendor/wgpu/glfwglue/glue.odin
new file mode 100644
index 000000000..83c497543
--- /dev/null
+++ b/vendor/wgpu/glfwglue/glue.odin
@@ -0,0 +1,6 @@
+//+build !linux
+//+build !windows
+//+build !darwin
+package wgpu_glfw_glue
+
+#panic("package wgpu/glfwglue is not supported on the current target")
diff --git a/vendor/wgpu/glfwglue/glue_darwin.odin b/vendor/wgpu/glfwglue/glue_darwin.odin
new file mode 100644
index 000000000..c1477f4b0
--- /dev/null
+++ b/vendor/wgpu/glfwglue/glue_darwin.odin
@@ -0,0 +1,23 @@
+package wgpu_glfw_glue
+
+import "vendor:glfw"
+import "vendor:wgpu"
+import CA "vendor:darwin/QuartzCore"
+
+GetSurface :: proc(instance: wgpu.Instance, window: glfw.WindowHandle) -> wgpu.Surface {
+ ns_window := glfw.GetCocoaWindow(window)
+ ns_window->contentView()->setWantsLayer(true)
+ metal_layer := CA.MetalLayer_layer()
+ ns_window->contentView()->setLayer(metal_layer)
+ return wgpu.InstanceCreateSurface(
+ instance,
+ &wgpu.SurfaceDescriptor{
+ nextInChain = &wgpu.SurfaceDescriptorFromMetalLayer{
+ chain = wgpu.ChainedStruct{
+ sType = .SurfaceDescriptorFromMetalLayer,
+ },
+ layer = rawptr(metal_layer),
+ },
+ },
+ )
+}
diff --git a/vendor/wgpu/glfwglue/glue_linux.odin b/vendor/wgpu/glfwglue/glue_linux.odin
new file mode 100644
index 000000000..35c36a37d
--- /dev/null
+++ b/vendor/wgpu/glfwglue/glue_linux.odin
@@ -0,0 +1,43 @@
+package wgpu_glfw_glue
+
+import "vendor:glfw"
+import "vendor:wgpu"
+
+// GLFW needs to be compiled with wayland support for this to work.
+SUPPORT_WAYLAND :: #config(WGPU_GFLW_GLUE_SUPPORT_WAYLAND, false)
+
+GetSurface :: proc(instance: wgpu.Instance, window: glfw.WindowHandle) -> wgpu.Surface {
+ when SUPPORT_WAYLAND {
+ if glfw.GetPlatform() == glfw.PLATFORM_WAYLAND {
+ display := glfw.GetWaylandDisplay()
+ surface := glfw.GetWaylandWindow(window)
+ return wgpu.InstanceCreateSurface(
+ instance,
+ &wgpu.SurfaceDescriptor{
+ nextInChain = &wgpu.SurfaceDescriptorFromWaylandSurface{
+ chain = {
+ sType = .SurfaceDescriptorFromWaylandSurface,
+ },
+ display = display,
+ surface = surface,
+ },
+ },
+ )
+ }
+ }
+
+ display := glfw.GetX11Display()
+ window := glfw.GetX11Window(window)
+ return wgpu.InstanceCreateSurface(
+ instance,
+ &wgpu.SurfaceDescriptor{
+ nextInChain = &wgpu.SurfaceDescriptorFromXlibWindow{
+ chain = {
+ sType = .SurfaceDescriptorFromXlibWindow,
+ },
+ display = display,
+ window = u64(window),
+ },
+ },
+ )
+}
diff --git a/vendor/wgpu/glfwglue/glue_windows.odin b/vendor/wgpu/glfwglue/glue_windows.odin
new file mode 100644
index 000000000..73a933f37
--- /dev/null
+++ b/vendor/wgpu/glfwglue/glue_windows.odin
@@ -0,0 +1,23 @@
+package wgpu_glfw_glue
+
+import win "core:sys/windows"
+
+import "vendor:glfw"
+import "vendor:wgpu"
+
+GetSurface :: proc(instance: wgpu.Instance, window: glfw.WindowHandle) -> wgpu.Surface {
+ hwnd := glfw.GetWin32Window(window)
+ hinstance := win.GetModuleHandleW(nil)
+ return wgpu.InstanceCreateSurface(
+ instance,
+ &wgpu.SurfaceDescriptor{
+ nextInChain = &wgpu.SurfaceDescriptorFromWindowsHWND{
+ chain = wgpu.ChainedStruct{
+ sType = .SurfaceDescriptorFromWindowsHWND,
+ },
+ hinstance = rawptr(hinstance),
+ hwnd = rawptr(hwnd),
+ },
+ },
+ )
+}
diff --git a/vendor/wgpu/lib/.gitkeep b/vendor/wgpu/lib/.gitkeep
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/wgpu/lib/.gitkeep
diff --git a/vendor/wgpu/wgpu.js b/vendor/wgpu/wgpu.js
new file mode 100644
index 000000000..4fe78c992
--- /dev/null
+++ b/vendor/wgpu/wgpu.js
@@ -0,0 +1,2916 @@
+(function() {
+
+/**
+ * Assumptions:
+ * - Ability to allocate memory, set the context to allocate with using the global `wgpu.g_context`
+ * - Exports a function table (for callbacks), added with `-extra-linker-flags:"--export-table"`
+ */
+class WebGPUInterface {
+
+ /**
+ * @param {WasmMemoryInterface} mem
+ */
+ constructor(mem) {
+ this.mem = mem;
+
+ this.enums = {
+ FeatureName: [undefined, "depth-clip-control", "depth32float-stencil8", "timestamp-query", "texture-compression-bc", "texture-compression-etc2", "texture-compression-astc", "indirect-first-instance", "shader-f16", "rg11b10ufloat-renderable", "bgra8unorm-storage", "float32-filterable", ],
+ StoreOp: [undefined, "store", "discard", ],
+ LoadOp: [undefined, "clear", "load", ],
+ BufferBindingType: [undefined, "uniform", "storage", "read-only-storage", ],
+ SamplerBindingType: [undefined, "filtering", "non-filtering", "comparison", ],
+ TextureSampleType: [undefined, "float", "unfilterable-float", "depth", "sint", "uint", ],
+ TextureViewDimension: [undefined, "1d", "2d", "2d-array", "cube", "cube-array", "3d", ],
+ StorageTextureAccess: [undefined, "write-only", "read-only", "read-write", ],
+ TextureFormat: [undefined, "r8unorm", "r8snorm", "r8uint", "r8sint", "r16uint", "r16sint", "r16float", "rg8unorm", "rg8snorm", "rg8uint", "rg8sint", "r32float", "r32uint", "r32sint", "rg16uint", "rg16sint", "rg16float", "rgba8unorm", "rgba8unorm-srgb", "rgba8snorm", "rgba8uint", "rgba8sint", "bgra8unorm", "bgra8unorm-srgb", "rgb10a2uint", "rgb10a2unorm", "rg11b10ufloat", "rgb9e5ufloat", "rg32float", "rg32uint", "rg32sint", "rgba16uint", "rgba16sint", "rgba16float", "rgba32float", "rgba32uint", "rgba32sint", "stencil8", "depth16unorm", "depth24plus", "depth24plus-stencil8", "depth32float", "depth32float-stencil8", "bc1-rgba-unorm", "bc1-rgba-unorm-srgb", "bc2-rgba-unorm", "bc2-rgba-unorm-srgb", "bc3-rgba-unorm", "bc3-rgba-unorm-srgb", "bc4-r-unorm", "bc4-r-snorm", "bc5-rg-unorm", "bc5-rg-snorm", "bc6h-rgb-ufloat", "bc6h-rgb-float", "bc7-rgba-unorm", "bc7-rgba-unorm-srgb", "etc2-rgb8unorm", "etc2-rgb8unorm-srgb", "etc2-rgb8a1unorm", "etc2-rgb8a1unorm-srgb", "etc2-rgba8unorm", "etc2-rgba8unorm-srgb", "eac-r11unorm", "eac-r11snorm", "eac-rg11unorm", "eac-rg11snorm", "astc-4x4-unorm", "astc-4x4-unorm-srgb", "astc-5x4-unorm", "astc-5x4-unorm-srgb", "astc-5x5-unorm", "astc-5x5-unorm-srgb", "astc-6x5-unorm", "astc-6x5-unorm-srgb", "astc-6x6-unorm", "astc-6x6-unorm-srgb", "astc-8x5-unorm", "astc-8x5-unorm-srgb", "astc-8x6-unorm", "astc-8x6-unorm-srgb", "astc-8x8-unorm", "astc-8x8-unorm-srgb", "astc-10x5-unorm", "astc-10x5-unorm-srgb", "astc-10x6-unorm", "astc-10x6-unorm-srgb", "astc-10x8-unorm", "astc-10x8-unorm-srgb", "astc-10x10-unorm", "astc-10x10-unorm-srgb", "astc-12x10-unorm", "astc-12x10-unorm-srgb", "astc-12x12-unorm", "astc-12x12-unorm-srgb", ],
+ QueryType: ["occlusion", "timestamp", ],
+ VertexStepMode: ["vertex", "instance", "vertex-buffer-not-used", ],
+ VertexFormat: [undefined, "uint8x2", "uint8x4", "sint8x2", "sint8x4", "unorm8x2", "unorm8x4", "snorm8x2", "snorm8x4", "uint16x2", "uint16x4", "sint16x2", "sint16x4", "unorm16x2", "unorm16x4", "snorm16x2", "snorm16x4", "float16x2", "float16x4", "float32", "float32x2", "float32x3", "float32x4", "uint32", "uint32x2", "uint32x3", "uint32x4", "sint32", "sint32x2", "sint32x3", "sint32x4", ],
+ PrimitiveTopology: ["point-list", "line-list", "line-strip", "triangle-list", "triangle-strip", ],
+ IndexFormat: [undefined, "uint16", "uint32", ],
+ FrontFace: ["ccw", "cw", ],
+ CullMode: ["none", "front", "back", ],
+ AddressMode: ["repeat", "mirror-repeat", "clamp-to-edge", ],
+ FilterMode: ["nearest", "linear", ],
+ MipmapFilterMode: ["nearest", "linear", ],
+ CompareFunction: [undefined, "never", "less", "less-equal", "greater", "greater-equal", "equal", "not-equal", "always", ],
+ TextureDimension: ["1d", "2d", "3d", ],
+ ErrorType: ["no-error", "validation", "out-of-memory", "internal", "unknown", "device-lost", ],
+ WGSLFeatureName: [undefined, "readonly_and_readwrite_storage_textures", "packed_4x8_integer_dot_product", "unrestricted_pointer_parameters", "pointer_composite_access", ],
+ PowerPreference: [undefined, "low-power", "high-performance", ],
+ CompositeAlphaMode: ["auto", "opaque", "premultiplied", "unpremultiplied", "inherit", ],
+ StencilOperation: ["keep", "zero", "replace", "invert", "increment-clamp", "decrement-clamp", "increment-wrap", "decrement-wrap", ],
+ BlendOperation: ["add", "subtract", "reverse-subtract", "min", "max", ],
+ BlendFactor: ["zero", "one", "src", "one-minus-src", "src-alpha", "one-minus-src-alpha", "dst", "one-minus-dst", "dst-alpha", "one-minus-dst-alpha", "src-alpha-saturated", "constant", "one-minus-constant", ],
+ PresentMode: ["fifo", "fifo-relaxed", "immediate", "mailbox", ],
+ TextureAspect: ["all", "stencil-only", "depth-only"],
+ };
+
+ /** @type {WebGPUObjectManager<{}>} */
+ this.instances = new WebGPUObjectManager("Instance", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUAdapter>} */
+ this.adapters = new WebGPUObjectManager("Adapter", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUBindGroup>} */
+ this.bindGroups = new WebGPUObjectManager("BindGroup", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUBindGroupLayout>} */
+ this.bindGroupLayouts = new WebGPUObjectManager("BindGroupLayout", this.mem);
+
+ /** @type {WebGPUObjectManager<{ buffer: GPUBuffer, mapping: ?{ range: ArrayBuffer, ptr: number, size: number } }>} */
+ this.buffers = new WebGPUObjectManager("Buffer", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUDevice>} */
+ this.devices = new WebGPUObjectManager("Device", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUCommandBuffer>} */
+ this.commandBuffers = new WebGPUObjectManager("CommandBuffer", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUCommandEncoder>} */
+ this.commandEncoders = new WebGPUObjectManager("CommandEncoder", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUComputePassEncoder>} */
+ this.computePassEncoders = new WebGPUObjectManager("ComputePassEncoder", this.mem);
+
+ /** @type {WebGPUObjectManager<GPURenderPassEncoder>} */
+ this.renderPassEncoders = new WebGPUObjectManager("RenderPassEncoder", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUQuerySet>} */
+ this.querySets = new WebGPUObjectManager("QuerySet", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUComputePipeline>} */
+ this.computePipelines = new WebGPUObjectManager("ComputePipeline", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUPipelineLayout>} */
+ this.pipelineLayouts = new WebGPUObjectManager("PipelineLayout", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUQueue>} */
+ this.queues = new WebGPUObjectManager("Queue", this.mem);
+
+ /** @type {WebGPUObjectManager<GPURenderBundle>} */
+ this.renderBundles = new WebGPUObjectManager("RenderBundle", this.mem);
+
+ /** @type {WebGPUObjectManager<GPURenderBundleEncoder>} */
+ this.renderBundleEncoders = new WebGPUObjectManager("RenderBundleEncoder", this.mem);
+
+ /** @type {WebGPUObjectManager<GPURenderPipeline>} */
+ this.renderPipelines = new WebGPUObjectManager("RenderPipeline", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUSampler>} */
+ this.samplers = new WebGPUObjectManager("Sampler", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUShaderModule>} */
+ this.shaderModules = new WebGPUObjectManager("ShaderModule", this.mem);
+
+ /** @type {WebGPUObjectManager<HTMLCanvasElement>} */
+ this.surfaces = new WebGPUObjectManager("Surface", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUTexture>} */
+ this.textures = new WebGPUObjectManager("Texture", this.mem);
+
+ /** @type {WebGPUObjectManager<GPUTextureView>} */
+ this.textureViews = new WebGPUObjectManager("TextureView", this.mem);
+ }
+
+ /**
+ * @param {number|BigInt} src
+ * @returns {number|BigInt}
+ */
+ uint(src) {
+ if (this.mem.intSize == 8) {
+ return BigInt(src);
+ } else if (this.mem.intSize == 4) {
+ return src;
+ } else {
+ throw new Error("unreachable");
+ }
+ }
+
+ /**
+ * @param {number|BigInt} src
+ * @returns {number}
+ */
+ unwrapBigInt(src) {
+ if (typeof src == "number") {
+ return src;
+ }
+
+ const MAX_SAFE_INTEGER = 9007199254740991n;
+ if (typeof src != "bigint") {
+ throw new TypeError(`unwrapBigInt got invalid param of type ${typeof src}`);
+ }
+
+ if (src > MAX_SAFE_INTEGER) {
+ throw new Error(`unwrapBigInt precision would be lost converting ${src}`);
+ }
+
+ return Number(src);
+ }
+
+ /**
+ * @param {boolean} condition
+ * @param {string} message
+ */
+ assert(condition, message = "assertion failure") {
+ if (!condition) {
+ throw new Error(message);
+ }
+ }
+
+ /**
+ * @template T
+ *
+ * @param {number} count
+ * @param {number} start
+ * @param {function(number): T} decoder
+ * @param {number} stride
+ * @returns {Array<T>}
+ */
+ array(count, start, decoder, stride) {
+ if (count == 0) {
+ return [];
+ }
+ this.assert(start != 0);
+
+ const out = [];
+ for (let i = 0; i < count; i += 1) {
+ out.push(decoder.call(this, start));
+ start += stride;
+ }
+ return out;
+ }
+
+ /**
+ * @param {string} name
+ * @param {number} ptr
+ * @returns {`GPU${name}`}
+ */
+ enumeration(name, ptr) {
+ const int = this.mem.loadI32(ptr);
+ this.assert(this.enums[name], `Unknown enumeration "${name}"`);
+ return this.enums[name][int];
+ }
+
+ /**
+ * @param {GPUSupportedFeatures} features
+ * @param {number} ptr
+ * @returns {BigInt|number}
+ */
+ genericEnumerateFeatures(features, ptr) {
+ const availableFeatures = [];
+ this.enums.FeatureName.forEach((feature, value) => {
+ if (!feature) {
+ return;
+ }
+
+ if (features.has(feature)) {
+ availableFeatures.push(value);
+ }
+ });
+
+ if (ptr != 0) {
+ for (let i = 0; i < availableFeatures.length; i += 1) {
+ this.mem.storeI32(ptr + (i * 4), availableFeatures[i]);
+ }
+ }
+
+ return this.uint(availableFeatures.length);
+ }
+
+ /**
+ * @param {GPUSupportedLimits} limits
+ * @param {number} ptr
+ */
+ genericGetLimits(limits, supportedLimitsPtr) {
+ this.assert(supportedLimitsPtr != 0);
+ const limitsPtr = supportedLimitsPtr + 8;
+
+ this.mem.storeU32(limitsPtr + 0, limits.maxTextureDimension1D);
+ this.mem.storeU32(limitsPtr + 4, limits.maxTextureDimension2D);
+ this.mem.storeU32(limitsPtr + 8, limits.maxTextureDimension3D);
+ this.mem.storeU32(limitsPtr + 12, limits.maxTextureArrayLayers);
+ this.mem.storeU32(limitsPtr + 16, limits.maxBindGroups);
+ this.mem.storeU32(limitsPtr + 20, limits.maxBindGroupsPlusVertexBuffers);
+ this.mem.storeU32(limitsPtr + 24, limits.maxBindingsPerBindGroup);
+ this.mem.storeU32(limitsPtr + 28, limits.maxDynamicUniformBuffersPerPipelineLayout);
+ this.mem.storeU32(limitsPtr + 32, limits.maxDynamicStorageBuffersPerPipelineLayout);
+ this.mem.storeU32(limitsPtr + 36, limits.maxSampledTexturesPerShaderStage);
+ this.mem.storeU32(limitsPtr + 40, limits.maxSamplersPerShaderStage);
+ this.mem.storeU32(limitsPtr + 44, limits.maxStorageBuffersPerShaderStage);
+ this.mem.storeU32(limitsPtr + 48, limits.maxStorageTexturesPerShaderStage);
+ this.mem.storeU32(limitsPtr + 52, limits.maxUniformBuffersPerShaderStage);
+ this.mem.storeU64(limitsPtr + 56, limits.maxUniformBufferBindingSize);
+ this.mem.storeU64(limitsPtr + 64, limits.maxStorageBufferBindingSize);
+ this.mem.storeU32(limitsPtr + 72, limits.minUniformBufferOffsetAlignment);
+ this.mem.storeU32(limitsPtr + 76, limits.minStorageBufferOffsetAlignment);
+ this.mem.storeU32(limitsPtr + 80, limits.maxVertexBuffers);
+ this.mem.storeU64(limitsPtr + 88, limits.maxBufferSize);
+ this.mem.storeU32(limitsPtr + 96, limits.maxVertexAttributes);
+ this.mem.storeU32(limitsPtr + 100, limits.maxVertexBufferArrayStride);
+ this.mem.storeU32(limitsPtr + 104, limits.maxInterStageShaderComponents);
+ this.mem.storeU32(limitsPtr + 108, limits.maxInterStageShaderVariables);
+ this.mem.storeU32(limitsPtr + 112, limits.maxColorAttachments);
+ this.mem.storeU32(limitsPtr + 116, limits.maxColorAttachmentBytesPerSample);
+ this.mem.storeU32(limitsPtr + 120, limits.maxComputeWorkgroupStorageSize);
+ this.mem.storeU32(limitsPtr + 124, limits.maxComputeInvocationsPerWorkgroup);
+ this.mem.storeU32(limitsPtr + 128, limits.maxComputeWorkgroupSizeX);
+ this.mem.storeU32(limitsPtr + 132, limits.maxComputeWorkgroupSizeY);
+ this.mem.storeU32(limitsPtr + 136, limits.maxComputeWorkgroupSizeZ);
+ this.mem.storeU32(limitsPtr + 140, limits.maxComputeWorkgroupsPerDimension);
+
+ return true;
+ }
+
+ /**
+ * @param {number} ptr
+ * @returns {GPUFeatureName}
+ */
+ FeatureNamePtr(ptr) {
+ return this.FeatureName(this.mem.loadI32(ptr));
+ }
+
+ /**
+ * @param {number} featureInt
+ * @returns {GPUFeatureName}
+ */
+ FeatureName(featureInt) {
+ return this.enums.FeatureName[featureInt];
+ }
+
+ /**
+ * @param {number} ptr
+ * @returns {GPUSupportedLimits}
+ */
+ RequiredLimitsPtr(ptr) {
+ const start = this.mem.loadPtr(ptr);
+ if (start == 0) {
+ return undefined;
+ }
+
+ return this.Limits(start + 8);
+ }
+
+ /**
+ * @param {number} start
+ * @return {GPUSupportedLimits}
+ */
+ Limits(start) {
+ const limitU32 = (ptr) => {
+ const value = this.mem.loadU32(ptr);
+ if (value == 0xFFFFFFFF) { // LIMIT_32_UNDEFINED.
+ return undefined;
+ }
+ return value;
+ };
+
+ const limitU64 = (ptr) => {
+ const part1 = this.mem.loadU32(ptr);
+ const part2 = this.mem.loadU32(ptr + 4);
+ if (part1 != 0xFFFFFFFF || part2 != 0xFFFFFFFF) { // LIMIT_64_UNDEFINED.
+ return this.mem.loadU64(ptr);
+ }
+ return undefined;
+ };
+
+ return {
+ maxTextureDimension1D: limitU32(start + 0),
+ maxTextureDimension2D: limitU32(start + 4),
+ maxTextureDimension3D: limitU32(start + 8),
+ maxTextureArrayLayers: limitU32(start + 12),
+ maxBindGroups: limitU32(start + 16),
+ maxBindGroupsPlusVertexBuffers: limitU32(start + 20),
+ maxBindingsPerBindGroup: limitU32(start + 24),
+ maxDynamicUniformBuffersPerPipelineLayout: limitU32(start + 28),
+ maxDynamicStorageBuffersPerPipelineLayout: limitU32(start + 32),
+ maxSampledTexturesPerShaderStage: limitU32(start + 36),
+ maxSamplersPerShaderStage: limitU32(start + 40),
+ maxStorageBuffersPerShaderStage: limitU32(start + 44),
+ maxStorageTexturesPerShaderStage: limitU32(start + 48),
+ maxUniformBuffersPerShaderStage: limitU32(start + 52),
+ maxUniformBufferBindingSize: limitU64(start + 56),
+ maxStorageBufferBindingSize: limitU64(start + 64),
+ minUniformBufferOffsetAlignment: limitU32(start + 72),
+ minStorageBufferOffsetAlignment: limitU32(start + 76),
+ maxVertexBuffers: limitU32(start + 80),
+ maxBufferSize: limitU64(start + 88),
+ maxVertexAttributes: limitU32(start + 96),
+ maxVertexBufferArrayStride: limitU32(start + 100),
+ maxInterStageShaderComponents: limitU32(start + 104),
+ maxInterStageShaderVariables: limitU32(start + 108),
+ maxColorAttachments: limitU32(start + 112),
+ maxColorAttachmentBytesPerSample: limitU32(start + 116),
+ maxComputeWorkgroupStorageSize: limitU32(start + 120),
+ maxComputeInvocationsPerWorkgroup: limitU32(start + 124),
+ maxComputeWorkgroupSizeX: limitU32(start + 128),
+ maxComputeWorkgroupSizeY: limitU32(start + 132),
+ maxComputeWorkgroupSizeZ: limitU32(start + 136),
+ maxComputeWorkgroupsPerDimension: limitU32(start + 140),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUQueueDescriptor}
+ */
+ QueueDescriptor(start) {
+ return {
+ label: this.mem.loadCstring(start + 4),
+ };
+ }
+
+ /**
+ * @param {number} ptr
+ * @returns {GPUComputePassTimestampWrites}
+ */
+ ComputePassTimestampWritesPtr(ptr) {
+ const start = this.mem.loadPtr(ptr);
+ if (start == 0) {
+ return undefined;
+ }
+
+ return {
+ querySet: this.querySets.get(this.mem.loadPtr(start + 0)),
+ beginningOfPassWriteIndex: this.mem.loadU32(start + 4),
+ endOfPassWriteIndex: this.mem.loadU32(start + 8),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPURenderPassColorAttachment}
+ */
+ RenderPassColorAttachment(start) {
+ const viewIdx = this.mem.loadPtr(start + 4);
+ const resolveTargetIdx = this.mem.loadPtr(start + 8);
+
+ return {
+ view: viewIdx > 0 ? this.textureViews.get(viewIdx) : undefined,
+ resolveTarget: resolveTargetIdx > 0 ? this.textureViews.get(resolveTargetIdx) : undefined,
+ loadOp: this.enumeration("LoadOp", start + 12),
+ storeOp: this.enumeration("StoreOp", start + 16),
+ clearValue: this.Color(start + 24),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUColor}
+ */
+ Color(start) {
+ return {
+ r: this.mem.loadF64(start + 0),
+ g: this.mem.loadF64(start + 8),
+ b: this.mem.loadF64(start + 16),
+ a: this.mem.loadF64(start + 24),
+ };
+ }
+
+ /**
+ * @param {number} ptr
+ * @returns {GPURenderPassDepthStencilAttachment}
+ */
+ RenderPassDepthStencilAttachmentPtr(ptr) {
+ const start = this.mem.loadPtr(ptr);
+ if (start == 0) {
+ return undefined;
+ }
+
+ return {
+ view: this.textureViews.get(this.mem.loadPtr(start + 0)),
+ depthLoadOp: this.enumeration("LoadOp", start + 4),
+ depthStoreOp: this.enumeration("StoreOp", start + 8),
+ depthClearValue: this.mem.loadF32(start + 12),
+ depthReadOnly: this.mem.loadB32(start + 16),
+ stencilLoadOp: this.enumeration("LoadOp", start + 20),
+ stencilStoreOp: this.enumeration("StoreOp", start + 24),
+ stencilClearValue: this.mem.loadF32(start + 28),
+ stencilReadOnly: this.mem.loadB32(start + 32),
+ };
+ }
+
+ /**
+ * @param {number} ptr
+ * @returns {undefined|GPUQuerySet}
+ */
+ QuerySet(ptr) {
+ ptr = this.mem.loadPtr(ptr);
+ if (ptr == 0) {
+ return undefined;
+ }
+
+ return this.querySets.get(ptr);
+ }
+
+ /**
+ * @param {number} ptr
+ * @returns {GPURenderPassTimestampWrites}
+ */
+ RenderPassTimestampWritesPtr(ptr) {
+ return this.ComputePassTimestampWritesPtr(ptr);
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUImageDataLayout}
+ */
+ TextureDataLayout(start) {
+ return {
+ offset: this.mem.loadU64(start + 8),
+ bytesPerRow: this.mem.loadU32(start + 16),
+ rowsPerImage: this.mem.loadU32(start + 20),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUImageCopyBuffer}
+ */
+ ImageCopyBuffer(start) {
+ return {
+ ...this.TextureDataLayout(start + 8),
+ buffer: this.buffers.get(this.mem.loadPtr(start + 32)).buffer,
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUImageCopyTexture}
+ */
+ ImageCopyTexture(start) {
+ return {
+ texture: this.textures.get(this.mem.loadPtr(start + 4)),
+ mipLevel: this.mem.loadU32(start + 8),
+ origin: this.Origin3D(start + 12),
+ aspect: this.enumeration("TextureAspect", start + 24),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUOrigin3D}
+ */
+ Origin3D(start) {
+ return {
+ x: this.mem.loadU32(start + 0),
+ y: this.mem.loadU32(start + 4),
+ z: this.mem.loadU32(start + 8),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUExtent3D}
+ */
+ Extent3D(start) {
+ return {
+ width: this.mem.loadU32(start + 0),
+ height: this.mem.loadU32(start + 4),
+ depthOrArrayLayers: this.mem.loadU32(start + 8),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUBindGroupEntry}
+ */
+ BindGroupEntry(start) {
+ const buffer = this.mem.loadPtr(start + 8);
+ const sampler = this.mem.loadPtr(start + 32);
+ const textureView = this.mem.loadPtr(start + 36);
+
+ /** @type {GPUBindingResource} */
+ let resource;
+ if (buffer > 0) {
+ resource = {
+ buffer: this.buffers.get(buffer).buffer,
+ offset: this.mem.loadU64(start + 16),
+ size: this.mem.loadU64(start + 24),
+ }
+ } else if (sampler > 0) {
+ resource = this.samplers.get(sampler);
+ } else if (textureView > 0) {
+ resource = this.textureViews.get(textureView);
+ }
+
+ return {
+ binding: this.mem.loadU32(start + 4),
+ resource: resource,
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUBindGroupLayoutEntry}
+ */
+ BindGroupLayoutEntry(start) {
+ const entry = {
+ binding: this.mem.loadU32(start + 4),
+ visibility: this.mem.loadU32(start + 8),
+ buffer: this.BufferBindingLayout(start + 16),
+ sampler: this.SamplerBindingLayout(start + 40),
+ texture: this.TextureBindingLayout(start + 48),
+ storageTexture: this.StorageTextureBindingLayout(start + 64),
+ };
+ if (!entry.buffer.type) {
+ entry.buffer = undefined;
+ }
+ if (!entry.sampler.type) {
+ entry.sampler = undefined;
+ }
+ if (!entry.texture.sampleType) {
+ entry.texture = undefined;
+ }
+ if (!entry.storageTexture.access) {
+ entry.storageTexture = undefined;
+ }
+ return entry;
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUBufferBindingLayout}
+ */
+ BufferBindingLayout(start) {
+ return {
+ type: this.enumeration("BufferBindingType", start + 4),
+ hasDynamicOffset: this.mem.loadB32(start + 8),
+ minBindingSize: this.mem.loadU64(start + 16),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUSamplerBindingLayout}
+ */
+ SamplerBindingLayout(start) {
+ return {
+ type: this.enumeration("SamplerBindingType", start + 4),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUTextureBindingLayout}
+ */
+ TextureBindingLayout(start) {
+ return {
+ sampleType: this.enumeration("TextureSampleType", start + 4),
+ viewDimension: this.enumeration("TextureViewDimension", start + 8),
+ multisampled: this.mem.loadB32(start + 12),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUStorageTextureBindingLayout}
+ */
+ StorageTextureBindingLayout(start) {
+ return {
+ access: this.enumeration("StorageTextureAccess", start + 4),
+ format: this.enumeration("TextureFormat", start + 8),
+ viewDimension: this.enumeration("TextureViewDimension", start + 12),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUProgrammableStage}
+ */
+ ProgrammableStageDescriptor(start) {
+ const constantsArray = this.array(
+ this.mem.loadUint(start + 8 + this.mem.intSize),
+ this.mem.loadPtr(start + 8 + this.mem.intSize*2),
+ this.ConstantEntry,
+ 16,
+ );
+ return {
+ module: this.shaderModules.get(this.mem.loadPtr(start + 4)),
+ entryPoint: this.mem.loadCstring(start + 8),
+ constants: constantsArray.reduce((prev, curr) => {
+ prev[curr.key] = curr.value;
+ return prev;
+ }, {}),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {{ key: string, value: number }}
+ */
+ ConstantEntry(start) {
+ return {
+ key: this.mem.loadCstring(start + 4),
+ value: this.mem.loadF64(start + 8),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUComputePipelineDescriptor}
+ */
+ ComputePipelineDescriptor(start) {
+ const layoutIdx = this.mem.loadPtr(start + 8)
+ return {
+ label: this.mem.loadCstring(start + 4),
+ layout: layoutIdx > 0 ? this.pipelineLayouts.get(layoutIdx) : undefined,
+ compute: this.ProgrammableStageDescriptor(start + 8 + this.mem.intSize),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUVertexState}
+ */
+ VertexState(start) {
+ let off = 8 + this.mem.intSize;
+ const constantsArray = this.array(
+ this.mem.loadUint(start + off),
+ this.mem.loadPtr(start + off + this.mem.intSize),
+ this.ConstantEntry,
+ 16,
+ );
+
+ off += this.mem.intSize * 2;
+
+ return {
+ module: this.shaderModules.get(this.mem.loadPtr(start + 4)),
+ entryPoint: this.mem.loadCstring(start + 8),
+ constants: constantsArray.reduce((prev, curr) => {
+ prev[curr.key] = curr.value;
+ return prev;
+ }, {}),
+ buffers: this.array(
+ this.mem.loadUint(start + off),
+ this.mem.loadPtr(start + off + this.mem.intSize),
+ this.VertexBufferLayout,
+ this.mem.intSize == 8 ? 32 : 24,
+ ),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {?GPUVertexBufferLayout}
+ */
+ VertexBufferLayout(start) {
+ const stepMode = this.enumeration("VertexStepMode", start + 8);
+ if (stepMode == "vertex-buffer-not-used") {
+ return null;
+ }
+ return {
+ arrayStride: this.mem.loadU64(start + 0),
+ stepMode: stepMode,
+ attributes: this.array(
+ this.mem.loadUint(start + 8 + this.mem.intSize),
+ this.mem.loadPtr(start + 8 + this.mem.intSize*2),
+ this.VertexAttribute,
+ 24,
+ ),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUVertexAttribute}
+ */
+ VertexAttribute(start) {
+ return {
+ format: this.enumeration("VertexFormat", start + 0),
+ offset: this.mem.loadU64(start + 8),
+ shaderLocation: this.mem.loadU32(start + 16),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUPrimitiveState}
+ */
+ PrimitiveState(start) {
+ let unclippedDepth = undefined;
+ const nextInChain = this.mem.loadPtr(start);
+ if (nextInChain != 0) {
+ const nextInChainType = this.mem.loadI32(nextInChain + 4);
+ // PrimitiveDepthClipControl = 0x00000007,
+ if (nextInChainType == 7) {
+ unclippedDepth = this.mem.loadB32(nextInChain + 8);
+ }
+ }
+
+ return {
+ topology: this.enumeration("PrimitiveTopology", start + 4),
+ stripIndexFormat: this.enumeration("IndexFormat", start + 8),
+ frontFace: this.enumeration("FrontFace", start + 12),
+ cullMode: this.enumeration("CullMode", start + 16),
+ unclippedDepth: unclippedDepth,
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPURenderPipelineDescriptor}
+ */
+ RenderPipelineDescriptor(start) {
+ const layoutIdx = this.mem.loadPtr(start + 8);
+ const offs = this.mem.intSize == 8 ? [64, 84, 88, 104] : [40, 60, 64, 80];
+ return {
+ label: this.mem.loadCstring(start + 4),
+ layout: layoutIdx > 0 ? this.pipelineLayouts.get(layoutIdx) : undefined,
+ vertex: this.VertexState(start + 8 + this.mem.intSize),
+ primitive: this.PrimitiveState(start + offs[0]),
+ depthStencil: this.DepthStencilStatePtr(start + offs[1]),
+ multisample: this.MultisampleState(start + offs[2]),
+ fragment: this.FragmentStatePtr(start + offs[3]),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUShaderModuleCompilationHint}
+ */
+ ShaderModuleCompilationHint(start) {
+ return {
+ entryPoint: this.mem.loadCstring(start + 4),
+ layout: this.pipelineLayouts.get(this.mem.loadPtr(start + 8)),
+ };
+ }
+
+ /**
+ * @param {number} ptr
+ * @returns {?GPUDepthStencilState}
+ */
+ DepthStencilStatePtr(ptr) {
+ const start = this.mem.loadPtr(ptr);
+ if (start == 0) {
+ return undefined;
+ }
+
+ return {
+ format: this.enumeration("TextureFormat", start + 4),
+ depthWriteEnabled: this.mem.loadB32(start + 8),
+ depthCompare: this.enumeration("CompareFunction", start + 12),
+ stencilFront: this.StencilFaceState(start + 16),
+ stencilBack: this.StencilFaceState(start + 32),
+ stencilReadMask: this.mem.loadU32(start + 48),
+ stencilWriteMask: this.mem.loadU32(start + 52),
+ depthBias: this.mem.loadI32(start + 56),
+ depthBiasSlopeScale: this.mem.loadF32(start + 60),
+ depthBiasClamp: this.mem.loadF32(start + 64),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUStencilFaceState}
+ */
+ StencilFaceState(start) {
+ return {
+ compare: this.enumeration("CompareFunction", start + 0),
+ failOp: this.enumeration("StencilOperation", start + 4),
+ depthFailOp: this.enumeration("StencilOperation", start + 8),
+ passOp: this.enumeration("StencilOperation", start + 12),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUMultisampleState}
+ */
+ MultisampleState(start) {
+ return {
+ count: this.mem.loadU32(start + 4),
+ mask: this.mem.loadU32(start + 8),
+ alphaToCoverageEnabled: this.mem.loadB32(start + 12),
+ };
+ }
+
+ /**
+ * @param {number} ptr
+ * @returns {?GPUFragmentState}
+ */
+ FragmentStatePtr(ptr) {
+ const start = this.mem.loadPtr(ptr);
+ if (start == 0) {
+ return undefined;
+ }
+
+ let off = 8 + this.mem.intSize;
+
+ const constantsArray = this.array(
+ this.mem.loadUint(start + off),
+ this.mem.loadPtr(start + off + this.mem.intSize),
+ this.ConstantEntry,
+ 16,
+ );
+
+ off += this.mem.intSize * 2;
+
+ return {
+ module: this.shaderModules.get(this.mem.loadPtr(start + 4)),
+ entryPoint: this.mem.loadCstring(start + 8),
+ constants: constantsArray.reduce((prev, curr) => {
+ prev[curr.key] = curr.value;
+ return prev;
+ }, {}),
+ targets: this.array(
+ this.mem.loadUint(start + off),
+ this.mem.loadPtr(start + off + this.mem.intSize),
+ this.ColorTargetState,
+ 16,
+ ),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {GPUColorTargetState}
+ */
+ ColorTargetState(start) {
+ return {
+ format: this.enumeration("TextureFormat", start + 4),
+ blend: this.BlendStatePtr(start + 8),
+ writeMask: this.mem.loadU32(start + 12),
+ };
+ }
+
+ /**
+ * @param {number} ptr
+ * @returns {?GPUBlendState}
+ */
+ BlendStatePtr(ptr) {
+ const start = this.mem.loadPtr(ptr);
+ if (start == 0) {
+ return undefined;
+ }
+
+ return {
+ color: this.BlendComponent(start + 0),
+ alpha: this.BlendComponent(start + 12),
+ };
+ }
+
+ /**
+ * @param {number} start
+ * @returns {?GPUBlendComponent}
+ */
+ BlendComponent(start) {
+ return {
+ operation: this.enumeration("BlendOperation", start + 0),
+ srcFactor: this.enumeration("BlendFactor", start + 4),
+ dstFactor: this.enumeration("BlendFactor", start + 8),
+ };
+ }
+
+ getInterface() {
+ return {
+ /**
+ * @param {0|number} descriptorPtr
+ * @returns {number}
+ */
+ wgpuCreateInstance: (descriptorPtr) => {
+ if (!navigator.gpu) {
+ console.error("WebGPU is not supported by this browser");
+ return 0;
+ }
+
+ return this.instances.create({});
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} procNamePtr
+ * @returns {number}
+ */
+ wgpuGetProcAddress: (deviceIdx, procNamePtr) => {
+ console.error(`unimplemented: wgpuGetProcAddress`);
+ return 0;
+ },
+
+ /* ---------------------- Adapter ---------------------- */
+
+ /**
+ * @param {number} adapterIdx
+ * @param {number} featuresPtr
+ * @returns {number|BigInt}
+ */
+ wgpuAdapterEnumerateFeatures: (adapterIdx, featuresPtr) => {
+ const adapter = this.adapters.get(adapterIdx);
+ return this.genericEnumerateFeatures(adapter.features, featuresPtr);
+ },
+
+ /**
+ * @param {number} adapterIdx
+ * @param {number} supportedLimitsPtr
+ * @returns {boolean}
+ */
+ wgpuAdapterGetLimits: (adapterIdx, supportedLimitsPtr) => {
+ const adapter = this.adapters.get(adapterIdx);
+ return this.genericGetLimits(adapter.limits, supportedLimitsPtr);
+ },
+
+ /**
+ * @param {number} adapterIdx
+ * @param {number} propertiesPtr
+ */
+ wgpuAdapterGetProperties: (adapterIdx, propertiesPtr) => {
+ this.assert(propertiesPtr != 0);
+ // Unknown adapter.
+ this.mem.storeI32(propertiesPtr + 28, 3);
+ // WebGPU backend.
+ this.mem.storeI32(propertiesPtr + 32, 2);
+ },
+
+ /**
+ * @param {number} adapterIdx
+ * @param {number} featureInt
+ * @returns {boolean}
+ */
+ wgpuAdapterHasFeature: (adapterIdx, featureInt) => {
+ const adapter = this.adapters.get(adapterIdx);
+ return adapter.features.has(this.enums.FeatureName[featureInt]);
+ },
+
+ /**
+ * @param {number} adapterIdx
+ * @param {number} callbackPtr
+ * @param {0|number} userdata
+ */
+ wgpuAdapterRequestAdapterInfo: async (adapterIdx, callbackPtr, userdata) => {
+ const adapter = this.adapters.get(adapterIdx);
+ const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
+
+ const info = await adapter.requestAdapterInfo();
+
+ const addr = this.mem.exports.wgpu_alloc(16);
+
+ const vendorLength = new TextEncoder().encode(info.vendor).length;
+ const vendorAddr = this.mem.exports.wgpu_alloc(vendorLength);
+ this.mem.storeString(vendorAddr, info.vendor);
+ this.mem.storeI32(addr + 0, vendorAddr);
+
+ const architectureLength = new TextEncoder().encode(info.architecture).length;
+ const architectureAddr = this.mem.exports.wgpu_alloc(architectureLength);
+ this.mem.storeString(architectureAddr, info.architecture);
+ this.mem.storeI32(addr + 4, architectureAddr);
+
+
+ const deviceLength = new TextEncoder().encode(info.device).length;
+ const deviceAddr = this.mem.exports.wgpu_alloc(deviceLength);
+ this.mem.storeString(deviceAddr, info.device);
+ this.mem.storeI32(addr + 8, deviceAddr);
+
+
+ const descriptionLength = new TextEncoder().encode(info.description).length;
+ const descriptionAddr = this.mem.exports.wgpu_alloc(descriptionLength);
+ this.mem.storeString(descriptionAddr, info.description);
+ this.mem.storeI32(addr + 12, descriptionAddr);
+
+ callback(addr, userdata);
+
+ this.mem.exports.wgpu_free(descriptionAddr);
+ this.mem.exports.wgpu_free(deviceAddr);
+ this.mem.exports.wgpu_free(architectureAddr);
+ this.mem.exports.wgpu_free(vendorAddr);
+ this.mem.exports.wgpu_free(addr);
+ },
+
+ /**
+ * @param {number} adapterIdx
+ * @param {0|number} descriptorPtr
+ * @param {number} callbackPtr
+ * @param {0|number} userdata
+ */
+ wgpuAdapterRequestDevice: async (adapterIdx, descriptorPtr, callbackPtr, userdata) => {
+ const adapter = this.adapters.get(adapterIdx);
+ const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
+
+ /** @type {GPUDeviceDescriptor} */
+ let descriptor;
+ if (descriptorPtr != 0) {
+ descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ requiredFeatures: this.array(
+ this.mem.loadUint(descriptorPtr + 8),
+ this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize),
+ this.FeatureNamePtr,
+ 4,
+ ),
+ requiredLimits: this.RequiredLimitsPtr(descriptorPtr + 8 + this.mem.intSize + 4),
+ defaultQueue: this.QueueDescriptor( descriptorPtr + 8 + this.mem.intSize + 4 + 4),
+ };
+ }
+
+ let deviceIdx;
+ try {
+ const device = await adapter.requestDevice(descriptor);
+ deviceIdx = this.devices.create(device);
+ // NOTE: don't callback here, any errors that happen later will then be caught by the catch here.
+ } catch (e) {
+ console.warn(e);
+ callback(1, null, null, userdata);
+ }
+
+ callback(0, deviceIdx, null, userdata);
+ },
+
+ ...this.adapters.interface(),
+
+ /* ---------------------- BindGroup ---------------------- */
+
+ ...this.bindGroups.interface(true),
+
+ /* ---------------------- BindGroupLayout ---------------------- */
+
+ ...this.bindGroupLayouts.interface(true),
+
+ /* ---------------------- Buffer ---------------------- */
+
+ /** @param {number} bufferIdx */
+ wgpuBufferDestroy: (bufferIdx) => {
+ const buffer = this.buffers.get(bufferIdx);
+ buffer.buffer.destroy();
+ },
+
+ /**
+ * @param {number} bufferIdx
+ * @param {number|BigInt} offset
+ * @param {number|BigInt} size
+ * @returns {number}
+ */
+ wgpuBufferGetMappedRange: (bufferIdx, offset, size) => {
+ const buffer = this.buffers.get(bufferIdx);
+ offset = this.unwrapBigInt(offset);
+ size = this.unwrapBigInt(size);
+
+ this.assert(!buffer.mapping, "buffer already mapped");
+
+ const range = buffer.buffer.getMappedRange(offset, size);
+
+ const ptr = this.mem.exports.wgpu_alloc(range.byteLength);
+
+ buffer.mapping = { range: range, ptr: ptr, size: range.byteLength };
+ return ptr;
+ },
+
+ /**
+ * @param {number} bufferIdx
+ * @returns {BigInt}
+ */
+ wgpuBufferGetSize: (bufferIdx) => {
+ const buffer = this.buffers.get(bufferIdx);
+ return BigInt(buffer.buffer.size);
+ },
+
+ /**
+ * @param {number} bufferIdx
+ * @returns {number}
+ */
+ wgpuBufferGetUsage: (bufferIdx) => {
+ const buffer = this.buffers.get(bufferIdx);
+ return buffer.buffer.usage;
+ },
+
+ /**
+ * @param {number} bufferIdx
+ * @param {number} mode
+ * @param {number|BigInt} offset
+ * @param {number|BigInt} size
+ * @param {number} callbackPtr
+ * @param {0|number} userdata
+ */
+ wgpuBufferMapAsync: async (bufferIdx, mode, offset, size, callbackPtr, userdata) => {
+ const buffer = this.buffers.get(bufferIdx);
+ const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
+ offset = this.unwrapBigInt(offset);
+ size = this.unwrapBigInt(size);
+
+ if (buffer.buffer.mapState == "pending") {
+ callback(this.enums.BufferMapAsyncStatus.MappingAlreadyPending, userdata);
+ } else {
+ let result;
+ try {
+ await buffer.buffer.mapAsync(mode, offset, size);
+ result = 0; // Success.
+ } catch(e) {
+ console.warn(e);
+ result = 2; // Unknown error.
+
+ if (e instanceof DomException) {
+ if (e.name == "OperationError") {
+ result = 1; // Validation error.
+ }
+ }
+ }
+
+ callback(result, userdata);
+ }
+ },
+
+ /**
+ * @param {number} bufferIdx
+ * @param {number} labelPtr
+ */
+ wgpuBufferSetLabel: (bufferIdx, labelPtr) => {
+ const buffer = this.buffers.get(bufferIdx);
+ buffer.buffer.label = this.mem.loadCstring(labelPtr);
+ },
+
+ /**
+ * @param {number} bufferIdx
+ */
+ wgpuBufferUnmap: (bufferIdx) => {
+ const buffer = this.buffers.get(bufferIdx);
+ this.assert(buffer.mapping, "buffer not mapped");
+
+ const mapping = new Uint8Array(this.mem.memory.buffer, buffer.mapping.ptr, buffer.mapping.size);
+ (new Uint8Array(buffer.mapping.range)).set(mapping);
+
+ buffer.buffer.unmap();
+
+ this.mem.exports.wgpu_free(buffer.mapping.ptr);
+ buffer.mapping = null;
+ },
+
+ ...this.buffers.interface(),
+
+ /* ---------------------- CommandBuffer ---------------------- */
+
+ ...this.commandBuffers.interface(true),
+
+ /* ---------------------- CommandEncoder ---------------------- */
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {0|number} descriptorPtr
+ * @return {number} The compute pass encoder
+ */
+ wgpuCommandEncoderBeginComputePass: (commandEncoderIdx, descriptorPtr) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+
+ /** @type {?GPUComputePassDescriptor} */
+ let descriptor;
+ if (descriptorPtr != 0) {
+ descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ timestampWrites: this.ComputePassTimestampWritesPtr(descriptorPtr + 8),
+ };
+ }
+
+ const computePassEncoder = commandEncoder.beginComputePass(descriptor);
+ return this.computePassEncoders.create(computePassEncoder);
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {number} descriptorPtr
+ * @return {number} The render pass encoder
+ */
+ wgpuCommandEncoderBeginRenderPass: (commandEncoderIdx, descriptorPtr) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ this.assert(descriptorPtr != 0);
+
+ let maxDrawCount = undefined;
+ const nextInChain = this.mem.loadPtr(descriptorPtr);
+ if (nextInChain != 0) {
+ const nextInChainType = this.mem.loadI32(nextInChain + 4);
+ // RenderPassDescriptorMaxDrawCount = 0x0000000F,
+ if (nextInChainType == 0x0000000F) {
+ maxDrawCount = this.mem.loadU64(nextInChain + 8);
+ }
+ }
+
+ /** @type {GPURenderPassDescriptor} */
+ const descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ colorAttachments: this.array(
+ this.mem.loadUint(descriptorPtr + 8),
+ this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize),
+ this.RenderPassColorAttachment,
+ 56,
+ ),
+ depthStencilAttachment: this.RenderPassDepthStencilAttachmentPtr(descriptorPtr + 8 + this.mem.intSize + 4),
+ occlusionQuerySet: this.QuerySet(descriptorPtr + 8 + this.mem.intSize + 4 + 4),
+ timestampWrites: this.RenderPassTimestampWritesPtr(descriptorPtr + 8 + this.mem.intSize + 4 + 4),
+ maxDrawCount: maxDrawCount,
+ };
+
+ const renderPassEncoder = commandEncoder.beginRenderPass(descriptor);
+ return this.renderPassEncoders.create(renderPassEncoder);
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {number} bufferIdx
+ * @param {BigInt} offset
+ * @param {BigInt} size
+ */
+ wgpuCommandEncoderClearBuffer: (commandEncoderIdx, bufferIdx, offset, size) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ const buffer = this.buffers.get(bufferIdx);
+ offset = this.unwrapBigInt(offset);
+ size = this.unwrapBigInt(size);
+ commandEncoder.clearBuffer(buffer.buffer, offset, size);
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {number} sourceIdx
+ * @param {BigInt} sourceOffset
+ * @param {number} destinationIdx
+ * @param {BigInt} destinationOffset
+ * @param {BigInt} size
+ */
+ wgpuCommandEncoderCopyBufferToBuffer: (commandEncoderIdx, sourceIdx, sourceOffset, destinationIdx, destinationOffset, size) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ const source = this.buffers.get(sourceIdx);
+ const destination = this.buffers.get(destinationIdx);
+ sourceOffset = this.unwrapBigInt(sourceOffset);
+ destinationOffset = this.unwrapBigInt(destinationOffset);
+ size = this.unwrapBigInt(size);
+ commandEncoder.copyBufferToBuffer(source.buffer, sourceOffset, destination.buffer, destinationOffset, size);
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {number} sourcePtr
+ * @param {number} destinationPtr
+ * @param {number} copySizePtr
+ */
+ wgpuCommandEncoderCopyBufferToTexture: (commandEncoderIdx, sourcePtr, destinationPtr, copySizePtr) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ commandEncoder.copyBufferToTexture(
+ this.ImageCopyBuffer(sourcePtr),
+ this.ImageCopyTexture(destinationPtr),
+ this.Extent3D(copySizePtr),
+ );
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {number} sourcePtr
+ * @param {number} destinationPtr
+ * @param {number} copySizePtr
+ */
+ wgpuCommandEncoderCopyTextureToBuffer: (commandEncoderIdx, sourcePtr, destinationPtr, copySizePtr) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ commandEncoder.copyTextureToBuffer(
+ this.ImageCopyTexture(sourcePtr),
+ this.ImageCopyBuffer(destinationPtr),
+ this.Extent3D(copySizePtr),
+ );
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {number} sourcePtr
+ * @param {number} destinationPtr
+ * @param {number} copySizePtr
+ */
+ wgpuCommandEncoderCopyTextureToTexture: (commandEncoderIdx, sourcePtr, destinationPtr, copySizePtr) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ commandEncoder.copyTextureToTexture(
+ this.ImageCopyTexture(sourcePtr),
+ this.ImageCopyTexture(destinationPtr),
+ this.Extent3D(copySizePtr),
+ );
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {0|number} descriptorPtr
+ * @returns {number} The command buffer.
+ */
+ wgpuCommandEncoderFinish: (commandEncoderIdx, descriptorPtr) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+
+ /** @type {undefined|GPUCommandBufferDescriptor} */
+ let descriptor;
+ if (descriptorPtr != 0) {
+ descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ };
+ }
+
+ const commandBuffer = commandEncoder.finish(descriptor);
+ return this.commandBuffers.create(commandBuffer);
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {number} markerLabelPtr
+ */
+ wgpuCommandEncoderInsertDebugMarker: (commandEncoderIdx, markerLabelPtr) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ commandEncoder.insertDebugMarker(this.mem.loadCstring(markerLabelPtr));
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ */
+ wgpuCommandEncoderPopDebugGroup: (commandEncoderIdx) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ commandEncoder.popDebugGroup();
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {number} markerLabelPtr
+ */
+ wgpuCommandEncoderPushDebugGroup: (commandEncoderIdx, groupLabelPtr) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ commandEncoder.pushDebugGroup(this.mem.loadCstring(groupLabelPtr));
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {number} querySetIdx
+ * @param {number} firstQuery
+ * @param {number} queryCount
+ * @param {number} destinationIdx
+ * @param {BigInt} destinationOffset
+ */
+ wgpuCommandEncoderResolveQuerySet: (commandEncoderIdx, querySetIdx, firstQuery, queryCount, destinationIdx, destinationOffset) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ const querySet = this.querySets.get(querySetIdx);
+ const destination = this.buffers.get(destinationIdx);
+ destinationOffset = this.unwrapBigInt(destinationOffset);
+ commandEncoder.resolveQuerySet(querySet, firstQuery, queryCount, destination.buffer, destinationOffset);
+ },
+
+ /**
+ * @param {number} commandEncoderIdx
+ * @param {number} querySetIdx
+ * @param {number} queryIndex
+ */
+ wgpuCommandEncoderWriteTimestamp: (commandEncoderIdx, querySetIdx, queryIndex) => {
+ const commandEncoder = this.commandEncoders.get(commandEncoderIdx);
+ const querySet = this.querySets.get(querySetIdx);
+ commandEncoder.writeTimestamp(querySet, queryIndex);
+ },
+
+ ...this.commandEncoders.interface(true),
+
+ /* ---------------------- ComputePassEncoder ---------------------- */
+
+
+ /**
+ * @param {number} computePassEncoderIdx
+ * @param {number} workgroupCountX
+ * @param {number} workgroupCountY
+ * @param {number} workgroupCountZ
+ */
+ wgpuComputePassEncoderDispachWorkgroups: (computePassEncoderIdx, workgroupCountX, workgroupCountY, workgroupCountZ) => {
+ const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx);
+ computePassEncoder.dispatchWorkgroups(workgroupCountX, workgroupCountY, workgroupCountZ);
+ },
+
+ /**
+ * @param {number} computePassEncoderIdx
+ * @param {number} indirectBufferIdx
+ * @param {BigInt} indirectOffset
+ */
+ wgpuComputePassEncoderDispachWorkgroupsIndirect: (computePassEncoderIdx, indirectBufferIdx, indirectOffset) => {
+ const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx);
+ const indirectBuffer = this.buffers.get(indirectBufferIdx);
+ indirectOffset = this.unwrapBigInt(indirectOffset);
+ computePassEncoder.dispatchWorkgroupsIndirect(indirectBuffer.buffer, indirectOffset);
+ },
+
+ /**
+ * @param {number} computePassEncoderIdx
+ */
+ wgpuComputePassEncoderEnd: (computePassEncoderIdx) => {
+ const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx);
+ computePassEncoder.end();
+ },
+
+ /**
+ * @param {number} computePassEncoderIdx
+ * @param {number} markerLabelPtr
+ */
+ wgpuComputePassEncoderInsertDebugMarker: (computePassEncoderIdx, markerLabelPtr) => {
+ const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx);
+ computePassEncoder.insertDebugMarker(this.mem.loadCstring(markerLabelPtr));
+ },
+
+ /**
+ * @param {number} computePassEncoderIdx
+ */
+ wgpuComputePassEncoderPopDebugGroup: (computePassEncoderIdx) => {
+ const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx);
+ computePassEncoder.popDebugGroup();
+ },
+
+ /**
+ * @param {number} computePassEncoderIdx
+ * @param {number} markerLabelPtr
+ */
+ wgpuComputePassEncoderPushDebugGroup: (computePassEncoderIdx, groupLabelPtr) => {
+ const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx);
+ computePassEncoder.pushDebugGroup(this.mem.loadCstring(groupLabelPtr));
+ },
+
+ /**
+ * @param {number} computePassEncoderIdx
+ * @param {number} groupIndex
+ * @param {0|number} groupIdx
+ * @param {number|BigInt} dynamicOffsetCount
+ * @param {number} dynamicOffsetsPtr
+ */
+ wgpuComputePassEncoderSetBindGroup: (computePassEncoderIdx, groupIndex, groupIdx, dynamicOffsetCount, dynamicOffsetsPtr) => {
+ const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx);
+ dynamicOffsetCount = this.unwrapBigInt(dynamicOffsetCount);
+
+ let bindGroup;
+ if (groupIdx != 0) {
+ bindGroup = this.bindGroups.get(groupIdx);
+ }
+
+ const dynamicOffsets = [];
+ for (let i = 0; i < dynamicOffsetCount; i += 1) {
+ dynamicOffsets.push(this.mem.loadU32(dynamicOffsetsPtr));
+ dynamicOffsetsPtr += 4;
+ }
+
+ computePassEncoder.setBindGroup(groupIndex, bindGroup, dynamicOffsets);
+ },
+
+ /**
+ * @param {number} computePassEncoderIdx
+ * @param {number} pipelineIdx
+ */
+ wgpuComputePassEncoderSetPipeline: (computePassEncoderIdx, pipelineIdx) => {
+ const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx);
+ const pipeline = this.computePipelines.get(pipelineIdx);
+ computePassEncoder.setPipeline(pipeline);
+ },
+
+ ...this.computePassEncoders.interface(true),
+
+ /* ---------------------- ComputePipeline ---------------------- */
+
+ /**
+ * @param {number} computePipelineIdx
+ * @param {number} groupIndex
+ * @returns {number}
+ */
+ wgpuComputePipelineGetBindGroupLayout: (computePipelineIdx, groupIndex) => {
+ const computePipeline = this.computePipelines.get(computePipelineIdx);
+ const bindGroupLayout = computePipeline.getBindGroupLayout(groupIndex);
+ return this.bindGroupLayouts.create(bindGroupLayout);
+ },
+
+ ...this.computePipelines.interface(true),
+
+ /* ---------------------- Device ---------------------- */
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @returns {number} The bind group.
+ */
+ wgpuDeviceCreateBindGroup: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+ this.assert(descriptorPtr != 0);
+
+ /** @type {GPUBindGroupDescriptor} */
+ const descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ layout: this.bindGroupLayouts.get(this.mem.loadPtr(descriptorPtr + 8)),
+ entries: this.array(
+ this.mem.loadUint(descriptorPtr + 8 + this.mem.intSize),
+ this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize * 2),
+ this.BindGroupEntry,
+ 40,
+ ),
+ };
+
+ const bindGroup = device.createBindGroup(descriptor);
+ return this.bindGroups.create(bindGroup);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @returns {number} The bind group layout.
+ */
+ wgpuDeviceCreateBindGroupLayout: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+ this.assert(descriptorPtr != 0);
+
+ /** @type {GPUBindGroupLayoutDescriptor} */
+ const descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ entries: this.array(
+ this.mem.loadUint(descriptorPtr + 8),
+ this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize),
+ this.BindGroupLayoutEntry,
+ 80,
+ ),
+ };
+
+ const bindGroupLayout = device.createBindGroupLayout(descriptor);
+ return this.bindGroupLayouts.create(bindGroupLayout);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @returns {number} The buffer.
+ */
+ wgpuDeviceCreateBuffer: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+ this.assert(descriptorPtr != 0);
+
+ /** @type {GPUBufferDescriptor} */
+ const descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ usage: this.mem.loadU32(descriptorPtr + 8),
+ size: this.mem.loadU64(descriptorPtr + 16),
+ mappedAtCreation: this.mem.loadB32(descriptorPtr + 24),
+ };
+
+ const buffer = device.createBuffer(descriptor);
+ return this.buffers.create({buffer: buffer, mapping: null});
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {0|number} descriptorPtr
+ * @returns {number} The command encoder.
+ */
+ wgpuDeviceCreateCommandEncoder: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+
+ /** @type {GPUCommandEncoderDescriptor} */
+ let descriptor;
+ if (descriptor != 0) {
+ descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ };
+ }
+
+ const commandEncoder = device.createCommandEncoder(descriptor);
+ return this.commandEncoders.create(commandEncoder);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @returns {number} The compute pipeline.
+ */
+ wgpuDeviceCreateComputePipeline: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+ this.assert(descriptorPtr != 0);
+ const computePipeline = device.createComputePipeline(this.ComputePipelineDescriptor(descriptorPtr));
+ return this.computePipelines.create(computePipeline);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @param {number} callbackPtr
+ * @param {number} userdata
+ */
+ wgpuDeviceCreateComputePipelineAsync: async (deviceIdx, descriptorPtr, callbackPtr, userdata) => {
+ const device = this.devices.get(deviceIdx);
+ const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
+ this.assert(descriptorPtr != 0);
+
+ let result;
+ let resultIdx;
+ try {
+ const computePipeline = await device.createComputePipelineAsync(this.ComputePipelineDescriptor(descriptorPtr));
+ resultIdx = this.computePipelines.create(computePipeline);
+ result = 0; /* Success */
+ // NOTE: don't callback here, any errors that happen later will then be caught by the catch here.
+ } catch (e) {
+ console.warn(e);
+ result = 5; /* Unknown error */
+ }
+
+ callback(result, resultIdx, null, userdata);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @returns {number} The pipeline layout.
+ */
+ wgpuDeviceCreatePipelineLayout: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+ this.assert(descriptorPtr != 0);
+
+ /** @type {GPUPipelineLayoutDescriptor} */
+ const descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ bindGroupLayouts: this.array(
+ this.mem.loadUint(descriptorPtr + 8),
+ this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize),
+ (ptr) => this.bindGroupLayouts.get(this.mem.loadPtr(ptr)),
+ 4,
+ ),
+ };
+
+ const pipelineLayout = device.createPipelineLayout(descriptor);
+ return this.pipelineLayouts.create(pipelineLayout);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @returns {number} The query set.
+ */
+ wgpuDeviceCreateQuerySet: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+ this.assert(descriptorPtr != 0);
+
+ /** @type {GPUQuerySetDescriptor} */
+ const descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ type: this.QueryType(descriptorPtr + 8),
+ count: this.mem.loadU32(descriptorPtr + 12),
+ };
+
+ const querySet = device.createQuerySet(descriptor);
+ return this.querySets.create(querySet);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @returns {number} The query set.
+ */
+ wgpuDeviceCreateRenderBundleEncoder: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+ this.assert(descriptorPtr != 0);
+
+ /** @type {GPURenderBundleEncoderDescriptor} */
+ const descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ colorFormats: this.array(
+ this.mem.loadUint(descriptorPtr + 8),
+ this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize),
+ this.TextureFormat,
+ 4,
+ ),
+ depthStencilFormat: this.enumeration("TextureFormat", descriptorPtr + 8 + this.mem.intSize + 4),
+ sampleCount: this.mem.loadU32(descriptorPtr + 8 + this.mem.intSize + 8),
+ depthReadOnly: this.mem.loadB32(descriptorPtr + 8 + this.mem.intSize + 12),
+ stencilReadOnly: this.mem.loadB32(descriptorPtr + 8 + this.mem.intSize + 16),
+ };
+
+ const renderBundleEncoder = device.createRenderBundleEncoder(descriptor);
+ return this.renderBundleEncoders.create(renderBundleEncoder);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @returns {number} The render pipeline.
+ */
+ wgpuDeviceCreateRenderPipeline: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+ this.assert(descriptorPtr != 0);
+
+ const descriptor = this.RenderPipelineDescriptor(descriptorPtr);
+ const renderPipeline = device.createRenderPipeline(descriptor);
+ return this.renderPipelines.create(renderPipeline);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @param {number} callbackPtr
+ * @param {number} userdata
+ */
+ wgpuDeviceCreateRenderPipelineAsync: async (deviceIdx, descriptorPtr, callbackPtr, userdata) => {
+ const device = this.devices.get(deviceIdx);
+ const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
+ this.assert(descriptorPtr != 0);
+
+ let result;
+ let resultIdx;
+ try {
+ const renderPipeline = await device.createRenderPipelineAsync(this.RenderPipelineDescriptor(descriptorPtr));
+ resultIdx = this.renderPipelines.create(renderPipeline);
+ result = 0; /* Success */
+ // NOTE: don't callback here, any errors that happen later will then be caught by the catch here.
+ } catch (e) {
+ console.warn(e);
+ result = 5; /* Unknown error */
+ }
+
+ callback(result, resultIdx, null, userdata);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {0|number} descriptorPtr
+ * @returns {number} The sampler.
+ */
+ wgpuDeviceCreateSampler: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+
+ /** @type {?GPUSamplerDescriptor} */
+ let descriptor;
+ if (descriptorPtr != 0) {
+ descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ addressModeU: this.enumeration("AddressMode", descriptorPtr + 8),
+ addressModeV: this.enumeration("AddressMode", descriptorPtr + 12),
+ addressModeW: this.enumeration("AddressMode", descriptorPtr + 16),
+ magFilter: this.enumeration("FilterMode", descriptorPtr + 20),
+ minFilter: this.enumeration("FilterMode", descriptorPtr + 24),
+ mipMapFilter: this.enumeration("MipmapFilterMode", descriptorPtr + 28),
+ lodMinClamp: this.mem.loadF32(descriptorPtr + 32),
+ lodMaxClamp: this.mem.loadF32(descriptorPtr + 36),
+ compare: this.enumeration("CompareFunction", descriptorPtr + 40),
+ maxAnisotropy: this.mem.loadU16(descriptorPtr + 44),
+ };
+ }
+
+ const sampler = device.createSampler(descriptor);
+ return this.samplers.create(sampler);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @returns {number} The shader module.
+ */
+ wgpuDeviceCreateShaderModule: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+ this.assert(descriptorPtr != 0);
+
+ const nextInChain = this.mem.loadPtr(descriptorPtr);
+ const nextInChainType = this.mem.loadI32(nextInChain + 4);
+
+ // ShaderModuleWGSLDescriptor = 0x00000006,
+ if (nextInChainType != 6) {
+ throw new TypeError(`Descriptor type should be 'ShaderModuleWGSLDescriptor', got ${nextInChainType}`);
+ }
+
+ /** @type {GPUShaderModuleDescriptor} */
+ const descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ code: this.mem.loadCstring(nextInChain + 8),
+ compilationHints: this.array(
+ this.mem.loadUint(descriptorPtr + 8),
+ this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize),
+ this.ShaderModuleCompilationHint,
+ 12,
+ ),
+ };
+
+ const shaderModule = device.createShaderModule(descriptor);
+ return this.shaderModules.create(shaderModule);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} descriptorPtr
+ * @returns {number} The texture.
+ */
+ wgpuDeviceCreateTexture: (deviceIdx, descriptorPtr) => {
+ const device = this.devices.get(deviceIdx);
+ this.assert(descriptorPtr != 0);
+
+ /** @type {GPUTextureDescriptor} */
+ const descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ usage: this.mem.loadU32(descriptorPtr + 8),
+ dimension: this.enumeration("TextureDimension", descriptorPtr + 12),
+ size: this.Extent3D(descriptorPtr + 16),
+ format: this.enumeration("TextureFormat", descriptorPtr + 28),
+ mipLevelCount: this.mem.loadU32(descriptorPtr + 32),
+ sampleCount: this.mem.loadU32(descriptorPtr + 36),
+ viewFormats: this.array(
+ this.mem.loadUint(descriptorPtr + 40),
+ this.mem.loadPtr(descriptorPtr + 40 + this.mem.intSize),
+ (ptr) => this.enumeration("TextureFormat", ptr),
+ 4,
+ ),
+ };
+
+ const texture = device.createTexture(descriptor);
+ return this.textures.create(texture);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ */
+ wgpuDeviceDestroy: (deviceIdx) => {
+ const device = this.devices.get(deviceIdx);
+ device.destroy();
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} featuresPtr
+ * @returns {number|BigInt}
+ */
+ wgpuDeviceEnumerateFeatures: (deviceIdx, featuresPtr) => {
+ const device = this.devices.get(deviceIdx);
+ return this.genericEnumerateFeatures(device.features, featuresPtr);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} limitsPtr
+ * @returns {boolean}
+ */
+ wgpuDeviceGetLimits: (deviceIdx, limitsPtr) => {
+ const device = this.devices.get(deviceIdx);
+ return this.genericGetLimits(device.limits, limitsPtr);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @returns {number}
+ */
+ wgpuDeviceGetQueue: (deviceIdx) => {
+ const device = this.devices.get(deviceIdx);
+ return this.queues.create(device.queue);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} featureInt
+ * @returns {boolean}
+ */
+ wgpuDeviceHasFeature: (deviceIdx, featureInt) => {
+ const device = this.devices.get(deviceIdx);
+ return device.features.has(this.enums.FeatureName[featureInt]);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} callbackPtr
+ * @param {number} userdata
+ */
+ wgpuDevicePopErrorScope: async (deviceIdx, callbackPtr, userdata) => {
+ const device = this.devices.get(deviceIdx);
+ const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
+ const error = await device.popErrorScope();
+ if (!error) {
+ callback(0, null, userdata);
+ return;
+ }
+ console.warn(error);
+ let status = 4;
+ if (error instanceof GPUValidationError) {
+ status = 1;
+ } else if (error instanceof GPUOutOfMemoryError) {
+ status = 2;
+ } else if (error instanceof GPUInternalError) {
+ status = 3;
+ }
+ callback(status, null, userdata);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} filterInt
+ */
+ wgpuDevicePushErrorScope: (deviceIdx, filterInt) => {
+ const device = this.devices.get(deviceIdx);
+ device.pushErrorScope(this.enums.ErrorFilter[filterInt]);
+ },
+
+ /**
+ * @param {number} deviceIdx
+ * @param {number} callbackPtr
+ * @param {number} userdata
+ */
+ wgpuDeviceSetUncapturedErrorCallback: (deviceIdx, callbackPtr, userdata) => {
+ const device = this.devices.get(deviceIdx);
+ const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
+
+ device.onuncapturederror = (ev) => {
+ console.warn(ev.error);
+ let status = 4;
+ if (error instanceof GPUValidationError) {
+ status = 1;
+ } else if (error instanceof GPUOutOfMemoryError) {
+ status = 2;
+ } else if (error instanceof GPUInternalError) {
+ status = 3;
+ }
+ callback(status, null, userdata);
+ };
+ },
+
+ ...this.devices.interface(true),
+
+ /* ---------------------- Instance ---------------------- */
+
+ /**
+ * @param {number} instanceIdx
+ * @param {number} descriptorPtr
+ */
+ wgpuInstanceCreateSurface: (instanceIdx, descriptorPtr) => {
+ this.assert(instanceIdx > 0);
+ this.assert(descriptorPtr != 0);
+
+ const nextInChain = this.mem.loadPtr(descriptorPtr);
+ const nextInChainType = this.mem.loadI32(nextInChain + 4);
+
+ // SurfaceDescriptorFromCanvasHTMLSelector = 0x00000004,
+ if (nextInChainType != 4) {
+ throw new TypeError(`Descriptor type should be 'SurfaceDescriptorFromCanvasHTMLSelector', got ${nextInChainType}`);
+ }
+
+ const selector = this.mem.loadCstring(nextInChain + 8);
+ const surface = document.querySelector(selector);
+ if (!surface) {
+ throw new Error(`Selector '${selector}' did not match any element`);
+ }
+ if (!(surface instanceof HTMLCanvasElement)) {
+ throw new Error('Selector matches an element that is not a canvas');
+ }
+
+ return this.surfaces.create(surface);
+ },
+
+ /**
+ * @param {number} instanceIdx
+ * @param {number} featureInt
+ * @returns {boolean}
+ */
+ wgpuInstanceHasWGSLLanguageFeature: (instanceIdx, featureInt) => {
+ return navigator.gpu.wgslLanguageFeatures.has(this.enums.WGSLFeatureName[featureInt]);
+ },
+
+ /**
+ * @param {number} instanceIdx
+ */
+ wgpuInstanceProcessEvents: (instanceIdx) => {
+ console.warn("unimplemented: wgpuInstanceProcessEvents");
+ },
+
+ /**
+ * @param {number} instanceIdx
+ * @param {0|number} optionsPtr
+ * @param {number} callbackPtr
+ * @param {number} userdata
+ */
+ wgpuInstanceRequestAdapter: async (instanceIdx, optionsPtr, callbackPtr, userdata) => {
+ this.assert(instanceIdx > 0);
+ const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
+
+ /** @type {GPURequestAdapterOptions} */
+ let options;
+ if (optionsPtr != 0) {
+ options = {
+ powerPreference: this.enumeration("PowerPreference", optionsPtr + 8),
+ forceFallbackAdapter: this.mem.loadB32(optionsPtr + 16),
+ };
+ }
+
+ let adapterIdx;
+ try {
+ const adapter = await navigator.gpu.requestAdapter(options);
+ adapterIdx = this.adapters.create(adapter);
+ // NOTE: don't callback here, any errors that happen later will then be caught by the catch here.
+ } catch(e) {
+ console.warn(e);
+ callback(2, null, null, userdata);
+ }
+
+ callback(0, adapterIdx, null, userdata);
+ },
+
+ ...this.instances.interface(false),
+
+ /* ---------------------- PipelineLayout ---------------------- */
+
+ ...this.pipelineLayouts.interface(true),
+
+ /* ---------------------- QuerySet ---------------------- */
+
+ /**
+ * @param {number} querySetIdx
+ */
+ wgpuQuerySetDestroy: (querySetIdx) => {
+ const querySet = this.querySets.get(querySetIdx);
+ querySet.destroy();
+ },
+
+ /**
+ * @param {number} querySetIdx
+ * @returns {number}
+ */
+ wgpuQuerySetGetCount: (querySetIdx) => {
+ const querySet = this.querySets.get(querySetIdx);
+ return querySet.count;
+ },
+
+ /**
+ * @param {number} querySetIdx
+ * @returns {number}
+ */
+ wgpuQuerySetGetType: (querySetIdx) => {
+ const querySet = this.querySets.get(querySetIdx);
+ return this.enums.QueryType.indexOf(querySet.type);
+ },
+
+ ...this.querySets.interface(true),
+
+ /* ---------------------- Queue ---------------------- */
+
+ /**
+ * @param {number} queueIdx
+ * @param {number} callbackPtr
+ * @param {number} userdata
+ */
+ wgpuQueueOnSubmittedWorkDone: async (queueIdx, callbackPtr, userdata) => {
+ const queue = this.queues.get(queueIdx);
+ const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
+ let result;
+ try {
+ await queue.onSubmittedWorkDone();
+ result = 0;
+ } catch(e) {
+ console.warn(e);
+ result = 1;
+ }
+ callback(result, userdata);
+ },
+
+ /**
+ * @param {number} queueIdx
+ * @param {BigInt|number} commandCount
+ * @param {number} commandsPtr
+ */
+ wgpuQueueSubmit: (queueIdx, commandCount, commandsPtr) => {
+ const queue = this.queues.get(queueIdx);
+ const commands = this.array(
+ this.unwrapBigInt(commandCount),
+ commandsPtr,
+ (ptr) => this.commandBuffers.get(this.mem.loadPtr(ptr)),
+ 4,
+ );
+ queue.submit(commands);
+ },
+
+ /**
+ * @param {number} queueIdx
+ * @param {number} bufferIdx
+ * @param {BigInt} bufferOffset
+ * @param {number} dataPtr
+ * @param {number|BigInt} size
+ */
+ wgpuQueueWriteBuffer: (queueIdx, bufferIdx, bufferOffset, dataPtr, size) => {
+ const queue = this.queues.get(queueIdx);
+ const buffer = this.buffers.get(bufferIdx);
+ bufferOffset = this.unwrapBigInt(bufferOffset);
+ size = this.unwrapBigInt(size);
+ queue.writeBuffer(buffer.buffer, bufferOffset, this.mem.loadBytes(dataPtr, size), 0, size);
+ },
+
+ /**
+ * @param {number} queueIdx
+ * @param {number} destinationPtr
+ * @param {number} dataPtr
+ * @param {number|BigInt} dataSize
+ * @param {number} dataLayoutPtr
+ * @param {number} writeSizePtr
+ */
+ wgpuQueueWriteTexture: (queueIdx, destinationPtr, dataPtr, dataSize, dataLayoutPtr, writeSizePtr) => {
+ const queue = this.queues.get(queueIdx);
+ const destination = this.ImageCopyTexture(destinationPtr);
+ dataSize = this.unwrapBigInt(dataSize);
+ const dataLayout = this.TextureDataLayout(dataLayoutPtr);
+ const writeSize = this.Extent3D(writeSizePtr);
+ queue.writeTexture(destination, this.mem.loadBytes(dataPtr, dataSize), dataLayout, writeSize);
+ },
+
+ ...this.queues.interface(true),
+
+ /* ---------------------- RenderBundle ---------------------- */
+
+ ...this.renderBundles.interface(true),
+
+ /* ---------------------- RenderBundleEncoder ---------------------- */
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {number} vertexCount
+ * @param {number} instanceCount
+ * @param {number} firstVertex
+ * @param {number} firstInstance
+ */
+ wgpuRenderBundleEncoderDraw: (renderBundleEncoderIdx, vertexCount, instanceCount, firstVertex, firstInstance) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+ renderBundleEncoder.draw(vertexCount, instanceCount, firstVertex, firstInstance);
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {number} indexCount
+ * @param {number} instanceCount
+ * @param {number} firstIndex
+ * @param {number} baseVertex
+ * @param {number} firstInstance
+ */
+ wgpuRenderBundleEncoderDrawIndexed: (renderBundleEncoderIdx, indexCount, instanceCount, firstIndex, baseVertex, firstInstance) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+ renderBundleEncoder.drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance);
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {number} indirectBufferIdx
+ * @param {BigInt} indirectOffset
+ */
+ wgpuRenderBundleEncoderDrawIndexedIndirect: (renderBundleEncoderIdx, indirectBufferIdx, indirectOffset) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+ indirectOffset = this.unwrapBigInt(indirectOffset);
+ const buffer = this.buffers.get(indirectBufferIdx);
+ renderBundleEncoder.drawIndexedIndirect(buffer.buffer, indirectOffset);
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {number} indirectBufferIdx
+ * @param {BigInt} indirectOffset
+ */
+ wgpuRenderBundleEncoderDrawIndirect: (renderBundleEncoderIdx, indirectBufferIdx, indirectOffset) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+ indirectOffset = this.unwrapBigInt(indirectOffset);
+ const buffer = this.buffers.get(indirectBufferIdx);
+ renderBundleEncoder.drawIndirect(buffer.buffer, indirectOffset);
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {0|number} descriptorPtr
+ * @returns {number}
+ */
+ wgpuRenderBundleEncoderFinish: (renderBundleEncoderIdx, descriptorPtr) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+
+ /** @type {?GPURenderBundleDescriptor} */
+ let descriptor;
+ if (descriptorPtr != 0) {
+ descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ };
+ }
+
+ const renderBundle = renderBundleEncoder.finish(descriptor);
+ return this.renderBundles.create(renderBundle);
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {number} markerLabelPtr
+ */
+ wgpuRenderBundleEncoderInsertDebugMarker: (renderBundleEncoderIdx, markerLabelPtr) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+ this.assert(markerLabelPtr != 0);
+ const markerLabel = this.mem.loadCstring(markerLabelPtr);
+ renderBundleEncoder.insertDebugMarker(markerLabel);
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ */
+ wgpuRenderBundleEncoderPopDebugGroup: (renderBundleEncoderIdx) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+ renderBundleEncoder.popDebugGroup();
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {number} groupLabelPtr
+ */
+ wgpuRenderBundleEncoderPushDebugGroup: (renderBundleEncoderIdx, groupLabelPtr) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+ this.assert(groupLabelPtr!= 0);
+ const groupLabel = this.mem.loadCstring(groupLabelPtr);
+ renderBundleEncoder.pushDebugGroup(groupLabel);
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {number} groupIndex
+ * @param {0|number} groupIdx
+ * @param {number|BigInt} dynamicOffsetCount
+ * @param {number} dynamicOffsetsPtr
+ */
+ wgpuRenderBundleEncoderSetBindGroup: (renderBundleEncoderIdx, groupIndex, groupIdx, dynamicOffsetCount, dynamicOffsetsPtr) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+
+ let group;
+ if (groupIdx > 0) {
+ group = this.bindGroups.get(groupIdx);
+ }
+
+ dynamicOffsetCount = this.unwrapBigInt(dynamicOffsetCount);
+ const dynamicOffsets = this.array(dynamicOffsetCount, dynamicOffsetsPtr, this.mem.loadU32, 4);
+
+ renderBundleEncoder.setBindGroup(groupIndex, group, dynamicOffsets);
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {number} bufferIdx
+ * @param {number} formatInt
+ * @param {BigInt} offset
+ * @param {BigInt} size
+ */
+ wgpuRenderBundleEncoderSetIndexBuffer: (renderBundleEncoderIdx, bufferIdx, formatInt, offset, size) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+ const buffer = this.buffers.get(bufferIdx);
+ const format = this.enums.IndexFormat[formatInt];
+ offset = this.unwrapBigInt(offset);
+ size = this.unwrapBigInt(size);
+ renderBundleEncoder.setIndexBuffer(buffer.buffer, format, offset, size);
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {number} pipelineIdx
+ */
+ wgpuRenderBundleEncoderSetPipeline: (renderBundleEncoderIdx, pipelineIdx) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+ const pipeline = this.renderPipelines.get(pipelineIdx);
+ renderBundleEncoder.setPipeline(pipeline);
+ },
+
+ /**
+ * @param {number} renderBundleEncoderIdx
+ * @param {number} slot
+ * @param {0|number} bufferIdx
+ * @param {BigInt} offset
+ * @param {BigInt} size
+ */
+ wgpuRenderBundleEncoderSetVertexBuffer: (renderBundleEncoderIdx, slot, bufferIdx, offset, size) => {
+ const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx);
+
+ let buffer;
+ if (bufferIdx > 0) {
+ buffer = this.buffers.get(bufferIdx).buffer;
+ }
+
+ offset = this.unwrapBigInt(offset);
+ size = this.unwrapBigInt(size);
+ renderBundleEncoder.setVertexBuffer(slot, buffer, offset, size);
+ },
+
+ ...this.renderBundleEncoders.interface(true),
+
+ /* ---------------------- RenderPassEncoder ---------------------- */
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} queryIndex
+ */
+ wgpuRenderPassEncoderBeginOcclusionQuery: (renderPassEncoderIdx, queryIndex) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ renderPassEncoder.beginOcclusionQuery(queryIndex);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} vertexCount
+ * @param {number} instanceCount
+ * @param {number} firstVertex
+ * @param {number} firstInstance
+ */
+ wgpuRenderPassEncoderDraw: (renderPassEncoderIdx, vertexCount, instanceCount, firstVertex, firstInstance) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ renderPassEncoder.draw(vertexCount, instanceCount, firstVertex, firstInstance);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} indexCount
+ * @param {number} instanceCount
+ * @param {number} firstIndex
+ * @param {number} baseVertex
+ * @param {number} firstInstance
+ */
+ wgpuRenderPassEncoderDrawIndexed: (renderPassEncoderIdx, indexCount, instanceCount, firstIndex, baseVertex, firstInstance) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ renderPassEncoder.drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} indirectBufferIdx
+ * @param {BigInt} indirectOffset
+ */
+ wgpuRenderPassEncoderDrawIndexedIndirect: (renderPassEncoderIdx, indirectBufferIdx, indirectOffset) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ const buffer = this.buffers.get(indirectBufferIdx);
+ indirectOffset = this.unwrapBigInt(indirectOffset);
+ renderPassEncoder.drawIndexedIndirect(buffer.buffer, indirectOffset);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} indirectBufferIdx
+ * @param {BigInt} indirectOffset
+ */
+ wgpuRenderPassEncoderDrawIndirect: (renderPassEncoderIdx, indirectBufferIdx, indirectOffset) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ const buffer = this.buffers.get(indirectBufferIdx);
+ indirectOffset = this.unwrapBigInt(indirectOffset);
+ renderPassEncoder.drawIndirect(buffer.buffer, indirectOffset);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ */
+ wgpuRenderPassEncoderEnd: (renderPassEncoderIdx) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ renderPassEncoder.end();
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ */
+ wgpuRenderPassEncoderEndOcclusionQuery: (renderPassEncoderIdx) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ renderPassEncoder.endOcclusionQuery();
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number|BigInt} bundleCount
+ * @param {number} bundlesPtr
+ */
+ wgpuRenderPassEncoderExecuteBundles: (renderPassEncoderIdx, bundleCount, bundlesPtr) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ bundleCount = this.unwrapBigInt(bundleCount);
+ const bundles = this.array(
+ bundleCount,
+ bundlesPtr,
+ (ptr) => this.renderBundles.get(this.mem.loadPtr(ptr)),
+ 4,
+ );
+ renderPassEncoder.executeBundles(bundles);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} markerLabelPtr
+ */
+ wgpuRenderPassEncoderInsertDebugMarker: (renderPassEncoderIdx, markerLabelPtr) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ const markerLabel = this.mem.loadCstring(markerLabelPtr);
+ renderPassEncoder.insertDebugMarker(markerLabel);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ */
+ wgpuRenderPassEncoderPopDebugGroup: (renderPassEncoderIdx) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ renderPassEncoder.popDebugGroup();
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} groupLabelPtr
+ */
+ wgpuRenderPassEncoderPushDebugGroup: (renderPassEncoderIdx, groupLabelPtr) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ const groupLabel = this.mem.loadCstring(groupLabelPtr);
+ renderPassEncoder.pushDebugGroup(groupLabel);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} groupIndex
+ * @param {0|number} groupIdx
+ * @param {number|BigInt} dynamicOffsetCount
+ * @param {number} dynamicOffsetsPtr
+ */
+ wgpuRenderPassEncoderSetBindGroup: (renderPassEncoderIdx, groupIndex, groupIdx, dynamicOffsetCount, dynamicOffsetsPtr) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+
+ let group;
+ if (groupIdx > 0) {
+ group = this.bindGroups.get(groupIdx);
+ }
+
+ dynamicOffsetCount = this.unwrapBigInt(dynamicOffsetCount);
+ const dynamicOffsets = this.array(dynamicOffsetCount, dynamicOffsetsPtr, this.mem.loadU32, 4);
+
+ renderPassEncoder.setBindGroup(groupIndex, group, dynamicOffsets);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} bufferIdx
+ * @param {number} formatInt
+ * @param {BigInt} offset
+ * @param {BigInt} size
+ */
+ wgpuRenderPassEncoderSetIndexBuffer: (renderPassEncoderIdx, bufferIdx, formatInt, offset, size) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ const buffer = this.buffers.get(bufferIdx);
+ const format = this.enums.IndexFormat[formatInt];
+ offset = this.unwrapBigInt(offset);
+ size = this.unwrapBigInt(size);
+ renderPassEncoder.setIndexBuffer(buffer.buffer, format, offset, size);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} pipelineIdx
+ */
+ wgpuRenderPassEncoderSetPipeline: (renderPassEncoderIdx, pipelineIdx) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ const pipeline = this.renderPipelines.get(pipelineIdx);
+ renderPassEncoder.setPipeline(pipeline);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ */
+ wgpuRenderPassEncoderSetScissorRect: (renderPassEncoderIdx, x, y, width, height) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ renderPassEncoder.setScissorRect(x, y, width, height);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} reference
+ */
+ wgpuRenderPassEncoderSetStencilReference: (renderPassEncoderIdx, reference) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ renderPassEncoder.setStencilReference(reference);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} slot
+ * @param {0|number} bufferIdx
+ * @param {BigInt} offset
+ * @param {BigInt} size
+ */
+ wgpuRenderPassEncoderSetVertexBuffer: (renderPassEncoderIdx, slot, bufferIdx, offset, size) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+
+ let buffer;
+ if (bufferIdx > 0) {
+ buffer = this.buffers.get(bufferIdx).buffer;
+ }
+
+ offset = this.unwrapBigInt(offset);
+ size = this.unwrapBigInt(size);
+ renderPassEncoder.setVertexBuffer(slot, buffer, offset, size);
+ },
+
+ /**
+ * @param {number} renderPassEncoderIdx
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ * @param {number} minDepth
+ * @param {number} maxDepth
+ */
+ wgpuRenderPassEncoderSetViewport: (renderPassEncoderIdx, x, y, width, height, minDepth, maxDepth) => {
+ const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx);
+ renderPassEncoder.setViewport(x, y, width, height, minDepth, maxDepth);
+ },
+
+ ...this.renderPassEncoders.interface(true),
+
+ /* ---------------------- RenderPipeline ---------------------- */
+
+ /**
+ * @param {number} renderPipelineIdx
+ * @param {number} groupIndex
+ * @returns {number}
+ */
+ wgpuRenderPipelineGetBindGroupLayout: (renderPipelineIdx, groupIndex) => {
+ const renderPipeline = this.renderPipelines.get(renderPipelineIdx);
+ const bindGroupLayout = renderPipeline.getBindGroupLayout(groupIndex);
+ return this.bindGroupLayouts.create(bindGroupLayout);
+ },
+
+ ...this.renderPipelines.interface(true),
+
+ /* ---------------------- Sampler ---------------------- */
+
+ ...this.samplers.interface(true),
+
+ /* ---------------------- ShaderModule ---------------------- */
+
+ /**
+ * @param {number} shaderModuleIdx
+ * @param {number} callbackPtr
+ * @param {number} userdata
+ */
+ wgpuShaderModuleGetCompilationInfo: async (shaderModuleIdx, callbackPtr, userdata) => {
+ const shaderModule = this.shaderModules.get(shaderModuleIdx);
+ const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
+
+ let status = 0;
+ let retAddr = 0;
+
+ const ptrsToFree = [];
+
+ try {
+ const compilationInfo = await shaderModule.getCompilationInfo();
+
+ const size = compilationInfo.messages.length * 72;
+ const addr = this.mem.exports.wgpu_alloc(size);
+ ptrsToFree.push(addr);
+ compilationInfo.messages.forEach((message, i) => {
+ const messageLength = new TextEncoder().encode(message.message).length;
+ const messageAddr = this.mem.exports.wgpu_alloc(messageLength);
+ ptrsToFree.push(messageAddr);
+ this.mem.storeString(messageAddr, message.message);
+ this.mem.storeI32(addr + (i * size) + 4);
+
+ this.mem.storeI32(addr + (i * size) + 8, this.enums.CompilationMessageType.indexOf(message.type));
+
+ this.mem.storeU64(addr + (i * size) + 16, message.lineNum);
+ this.mem.storeU64(addr + (i * size) + 24, message.linePos);
+ this.mem.storeU64(addr + (i * size) + 32, message.offset);
+ this.mem.storeU64(addr + (i * size) + 40, message.length);
+
+ // TODO: UTF16 units.
+ this.mem.storeU64(addr + (i * size) + 48, message.linePos);
+ this.mem.storeU64(addr + (i * size) + 56, message.offset);
+ this.mem.storeU64(addr + (i * size) + 64, message.length);
+ });
+
+ retAddr = this.mem.exports.wgpu_alloc(3*this.mem.intSize);
+ ptrsToFree.push(retAddr);
+ this.mem.storeUint(retAddr + this.mem.intSize, compilationInfo.messages.length);
+ this.mem.storeI32(retAddr + this.mem.intSize*2, addr);
+ } catch (e) {
+ console.warn(e);
+ status = 1;
+ }
+
+ callback(status, retAddr, userdata);
+
+ ptrsToFree.forEach(ptr => this.mem.exports.wgpu_free(ptr));
+ },
+
+ ...this.shaderModules.interface(true),
+
+ /* ---------------------- Surface ---------------------- */
+
+ /**
+ * @param {number} surfaceIdx
+ * @param {number} configPtr
+ */
+ wgpuSurfaceConfigure: (surfaceIdx, configPtr) => {
+ const surface = this.surfaces.get(surfaceIdx);
+ const context = surface.getContext('webgpu');
+
+ const widthOff = 16 + this.mem.intSize + 8;
+ surface.width = this.mem.loadU32(configPtr + widthOff);
+ surface.height = this.mem.loadU32(configPtr + widthOff + 4);
+
+ /** @type {GPUCanvasConfiguration} */
+ const config = {
+ device: this.devices.get(this.mem.loadPtr(configPtr + 4)),
+ format: this.enumeration("TextureFormat", configPtr + 8),
+ usage: this.mem.loadU32(configPtr + 12),
+ viewFormats: this.array(
+ this.mem.loadUint(configPtr + 16),
+ this.mem.loadPtr(configPtr + 16 + this.mem.intSize),
+ (ptr) => this.enumeration("TextureFormat", ptr),
+ 4,
+ ),
+ alphaMode: this.enumeration("CompositeAlphaMode", configPtr + widthOff - 4),
+ // // NOTE: present mode seems unused.
+ presentMode: this.enumeration("PresentMode", configPtr + widthOff + 4),
+ };
+
+ context.configure(config);
+ },
+
+ /**
+ * @param {number} surfaceIdx
+ * @param {number} adapterIdx
+ * @param {number} capabilitiesPtr
+ */
+ wgpuSurfaceGetCapabilities: (surfaceIdx, adapterIdx, capabilitiesPtr) => {
+ const formatStr = navigator.gpu.getPreferredCanvasFormat();
+ const format = this.enums.TextureFormat.indexOf(formatStr);
+
+ this.mem.storeUint(capabilitiesPtr + this.mem.intSize, 1);
+ const formatAddr = this.mem.exports.wgpu_alloc(4);
+ this.mem.storeI32(formatAddr, format);
+ this.mem.storeI32(capabilitiesPtr + this.mem.intSize*2, formatAddr);
+
+ // NOTE: present modes don't seem to actually do anything in JS, we can just give back a default FIFO though.
+ this.mem.storeUint(capabilitiesPtr + this.mem.intSize*3, 1);
+ const presentModesAddr = this.mem.exports.wgpu_alloc(4);
+ this.mem.storeI32(presentModesAddr, 0);
+ this.mem.storeI32(capabilitiesPtr + this.mem.intSize*4, presentModesAddr);
+
+ // Browser seems to support opaque (1) and premultiplied (2).
+ this.mem.storeUint(capabilitiesPtr + this.mem.intSize*5, 2);
+ const alphaModesAddr = this.mem.exports.wgpu_alloc(8);
+ this.mem.storeI32(alphaModesAddr + 0, 1); // Opaque.
+ this.mem.storeI32(alphaModesAddr + 4, 2); // premultiplied.
+ this.mem.storeI32(capabilitiesPtr + this.mem.intSize*6, alphaModesAddr);
+ },
+
+ /**
+ * @param {number} surfaceIdx
+ * @param {number} texturePtr
+ */
+ wgpuSurfaceGetCurrentTexture: (surfaceIdx, texturePtr) => {
+ const surface = this.surfaces.get(surfaceIdx);
+ const context = surface.getContext('webgpu');
+ const texture = context.getCurrentTexture();
+
+ const textureIdx = this.textures.create(texture);
+ this.mem.storeI32(texturePtr, textureIdx);
+
+ // TODO: determine suboptimal and/or status.
+ },
+
+ /**
+ * @param {number} surfaceIdx
+ * @param {number} texturePtr
+ * @returns {number}
+ */
+ wgpuSurfaceGetPreferredFormat: (surfaceIdx, adapterIdx) => {
+ const formatStr = navigator.gpu.getPreferredCanvasFormat();
+ const format = this.enums.TextureFormat.indexOf(formatStr);
+ return format;
+ },
+
+ /**
+ * @param {number} surfaceIdx
+ */
+ wgpuSurfacePresent: (surfaceIdx) => {
+ // NOTE: Not really anything to do here.
+ },
+
+ /**
+ * @param {number} surfaceIdx
+ */
+ wgpuSurfaceUnconfigure: (surfaceIdx) => {
+ const surface = this.surfaces.get(surfaceIdx);
+ surface.getContext('webgpu').unconfigure();
+ },
+
+ ...this.surfaces.interface(true),
+
+ /* ---------------------- SurfaceCapabilities ---------------------- */
+
+ /**
+ * @param {number} surfaceCapabilitiesPtr
+ */
+ wgpuSurfaceCapabilitiesFreeMembers: (surfaceCapabilitiesPtr) => {
+ const formatsAddr = this.mem.loadI32(surfaceCapabilitiesPtr + this.mem.intSize*2);
+ this.mem.exports.wgpu_free(formatsAddr);
+
+ const presentModesAddr = this.mem.loadI32(surfaceCapabilitiesPtr + this.mem.intSize*4);
+ this.mem.exports.wgpu_free(presentModesAddr);
+
+ const alphaModesAddr = this.mem.loadI32(surfaceCapabilitiesPtr + this.mem.intSize*6);
+ this.mem.exports.wgpu_free(alphaModesAddr);
+ },
+
+ /* ---------------------- Texture ---------------------- */
+
+ /**
+ * @param {number} textureIdx
+ * @param {0|number} descriptorPtr
+ * @returns {number}
+ */
+ wgpuTextureCreateView: (textureIdx, descriptorPtr) => {
+ const texture = this.textures.get(textureIdx);
+
+ /** @type {?GPUTextureViewDescriptor} */
+ let descriptor;
+ if (descriptorPtr != 0) {
+ descriptor = {
+ label: this.mem.loadCstring(descriptorPtr + 4),
+ format: this.enumeration("TextureFormat", descriptorPtr + 8),
+ dimension: this.enumeration("TextureViewDimension", descriptorPtr + 12),
+ baseMipLevel: this.mem.loadU32(descriptorPtr + 16),
+ mipLevelCount: this.mem.loadU32(descriptorPtr + 20),
+ baseArrayLayer: this.mem.loadU32(descriptorPtr + 24),
+ arrayLayerCount: this.mem.loadU32(descriptorPtr + 28),
+ aspect: this.enumeration("TextureAspect", descriptorPtr + 32),
+ };
+ if (descriptor.arrayLayerCount == 0xFFFFFFFF) {
+ descriptor.arrayLayerCount = undefined;
+ }
+ if (descriptor.mipLevelCount == 0xFFFFFFFF) {
+ descriptor.mipLevelCount = undefined;
+ }
+ }
+
+ const textureView = texture.createView(descriptor);
+ return this.textureViews.create(textureView);
+ },
+
+ /**
+ * @param {number} textureIdx
+ */
+ wgpuTextureDestroy: (textureIdx) => {
+ const texture = this.textures.get(textureIdx);
+ texture.destroy();
+ },
+
+ /**
+ * @param {number} textureIdx
+ * @returns {number}
+ */
+ wgpuTextureDepthOrArrayLayers: (textureIdx) => {
+ const texture = this.textures.get(textureIdx);
+ return texture.depthOrArrayLayers;
+ },
+
+ /**
+ * @param {number} textureIdx
+ * @returns {number}
+ */
+ wgpuTextureGetDimension: (textureIdx) => {
+ const texture = this.textures.get(textureIdx);
+ return this.enums.TextureDimension.indexOf(texture.dimension);
+ },
+
+ /**
+ * @param {number} textureIdx
+ * @returns {number}
+ */
+ wgpuTextureGetFormat: (textureIdx) => {
+ const texture = this.textures.get(textureIdx);
+ return this.enums.TextureFormat.indexOf(texture.format);
+ },
+
+ /**
+ * @param {number} textureIdx
+ * @returns {number}
+ */
+ wgpuTextureGetHeight: (textureIdx) => {
+ const texture = this.textures.get(textureIdx);
+ return texture.height;
+ },
+
+ /**
+ * @param {number} textureIdx
+ * @returns {number}
+ */
+ wgpuTextureGetMipLevelCount: (textureIdx) => {
+ const texture = this.textures.get(textureIdx);
+ return texture.mipLevelCount;
+ },
+
+ /**
+ * @param {number} textureIdx
+ * @returns {number}
+ */
+ wgpuTextureGetSampleCount: (textureIdx) => {
+ const texture = this.textures.get(textureIdx);
+ return texture.sampleCount;
+ },
+
+ /**
+ * @param {number} textureIdx
+ * @returns {number}
+ */
+ wgpuTextureGetUsage: (textureIdx) => {
+ const texture = this.textures.get(textureIdx);
+ return texture.usage;
+ },
+
+ /**
+ * @param {number} textureIdx
+ * @returns {number}
+ */
+ wgpuTextureGetWidth: (textureIdx) => {
+ const texture = this.textures.get(textureIdx);
+ return texture.width;
+ },
+
+ ...this.textures.interface(true),
+
+ /* ---------------------- TextureView ---------------------- */
+
+ ...this.textureViews.interface(true),
+ };
+ }
+}
+
+/** @template T */
+class WebGPUObjectManager {
+
+ /**
+ * @param {string} name
+ * @param {WasmMemoryInterface} mem
+ */
+ constructor(name, mem) {
+ this.name = name;
+ this.mem = mem;
+
+ this.idx = 0;
+
+ /** @type {Record<number, { references: number, object: T }>} */
+ this.objects = {};
+ }
+
+ /**
+ * @param {T} object
+ * @returns {number}
+ */
+ create(object) {
+ this.objects[this.idx] = { references: 1, object };
+ this.idx += 1;
+ return this.idx;
+ }
+
+ /**
+ * @param {number} idx
+ * @returns {T}
+ */
+ get(idx) {
+ return this.objects[idx-1].object;
+ }
+
+ /** @param {number} idx */
+ release(idx) {
+ this.objects[idx-1].references -= 1;
+ if (this.objects[idx-1].references == 0) {
+ delete this.objects[idx-1];
+ }
+ }
+
+ /** @param {number} idx */
+ reference(idx) {
+ this.objects[idx-1].references += 1;
+ }
+
+ interface(withLabelSetter = false) {
+ const inter = {};
+ inter[`wgpu${this.name}Reference`] = this.reference.bind(this);
+ inter[`wgpu${this.name}Release`] = this.release.bind(this);
+ if (withLabelSetter) {
+ inter[`wgpu${this.name}SetLabel`] = (idx, labelPtr) => {
+ const obj = this.get(idx);
+ obj.label = this.mem.loadCstring(labelPtr);
+ };
+ }
+ return inter;
+ }
+}
+
+window.odin = window.odin || {};
+window.odin.WebGPUInterface = WebGPUInterface;
+
+})();
diff --git a/vendor/wgpu/wgpu.odin b/vendor/wgpu/wgpu.odin
new file mode 100644
index 000000000..24e3f01c2
--- /dev/null
+++ b/vendor/wgpu/wgpu.odin
@@ -0,0 +1,1636 @@
+package wgpu
+
+import "base:intrinsics"
+
+WGPU_SHARED :: #config(WGPU_SHARED, false)
+WGPU_DEBUG :: #config(WGPU_DEBUG, false)
+
+@(private) TYPE :: "debug" when WGPU_DEBUG else "release"
+
+when ODIN_OS == .Windows {
+ @(private) ARCH :: "x86_64" when ODIN_ARCH == .amd64 else "i686" when ODIN_ARCH == .i386 else #panic("unsupported WGPU Native architecture")
+ @(private) EXT :: ".dll.lib" when WGPU_SHARED else ".lib"
+ @(private) LIB :: "lib/wgpu-windows-" + ARCH + "-" + TYPE + "/wgpu-native" + EXT
+
+ when !#exists(LIB) {
+ #panic("Could not find the compiled WGPU Native library at '" + ODIN_ROOT + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + ODIN_ROOT + "vendor/wgpu/README.md'")
+ }
+
+ foreign import libwgpu {
+ LIB,
+ "system:d3dcompiler.lib",
+ "system:ws2_32.lib",
+ "system:userenv.lib",
+ "system:bcrypt.lib",
+ "system:ntdll.lib",
+ "system:opengl32.lib",
+ "system:advapi32.lib",
+ }
+} else when ODIN_OS == .Darwin {
+ @(private) ARCH :: "x86_64" when ODIN_ARCH == .amd64 else "aarch64" when ODIN_ARCH == .arm64 else #panic("unsupported WGPU Native architecture")
+ @(private) EXT :: ".dylib" when WGPU_SHARED else ".a"
+ @(private) LIB :: "lib/wgpu-macos-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT
+
+ when !#exists(LIB) {
+ #panic("Could not find the compiled WGPU Native library at '" + ODIN_ROOT + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + ODIN_ROOT + "vendor/wgpu/README.md'")
+ }
+
+ foreign import libwgpu {
+ LIB,
+ "system:CoreFoundation.framework",
+ "system:QuartzCore.framework",
+ "system:Metal.framework",
+ }
+} else when ODIN_OS == .Linux {
+ @(private) ARCH :: "x86_64" when ODIN_ARCH == .amd64 else "aarch64" when ODIN_ARCH == .arm64 else #panic("unsupported WGPU Native architecture")
+ @(private) EXT :: ".so" when WGPU_SHARED else ".a"
+ @(private) LIB :: "lib/wgpu-linux-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT
+
+ when !#exists(LIB) {
+ #panic("Could not find the compiled WGPU Native library at '" + ODIN_ROOT + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + ODIN_ROOT + "vendor/wgpu/README.md'")
+ }
+
+ foreign import libwgpu {
+ LIB,
+ "system:ld",
+ "system:m",
+ }
+} else when ODIN_OS == .JS {
+ foreign import libwgpu "wgpu"
+}
+
+ARRAY_LAYER_COUNT_UNDEFINED :: max(u32)
+COPY_STRIDE_UNDEFINED :: max(u32)
+DEPTH_SLICE_UNDEFINED :: max(u32)
+LIMIT_U32_UNDEFINED :: max(u32)
+LIMIT_U64_UNDEFINED :: max(u64)
+MIP_LEVEL_COUNT_UNDEFINED :: max(u32)
+QUERY_SET_INDEX_UNDEFINED :: max(u32)
+WHOLE_MAP_SIZE :: max(uint)
+WHOLE_SIZE :: max(u64)
+
+Flags :: u32
+
+Adapter :: distinct rawptr
+BindGroup :: distinct rawptr
+BindGroupLayout :: distinct rawptr
+Buffer :: distinct rawptr
+CommandBuffer :: distinct rawptr
+CommandEncoder :: distinct rawptr
+ComputePassEncoder :: distinct rawptr
+ComputePipeline :: distinct rawptr
+Device :: distinct rawptr
+Instance :: distinct rawptr
+PipelineLayout :: distinct rawptr
+QuerySet :: distinct rawptr
+Queue :: distinct rawptr
+RenderBundle :: distinct rawptr
+RenderBundleEncoder :: distinct rawptr
+RenderPassEncoder :: distinct rawptr
+RenderPipeline :: distinct rawptr
+Sampler :: distinct rawptr
+ShaderModule :: distinct rawptr
+Surface :: distinct rawptr
+Texture :: distinct rawptr
+TextureView :: distinct rawptr
+
+AdapterType :: enum i32 {
+ DiscreteGPU = 0x00000000,
+ IntegratedGPU = 0x00000001,
+ CPU = 0x00000002,
+ Unknown = 0x00000003,
+}
+
+AddressMode :: enum i32 {
+ Repeat = 0x00000000,
+ MirrorRepeat = 0x00000001,
+ ClampToEdge = 0x00000002,
+}
+
+BackendType :: enum i32 {
+ Undefined = 0x00000000,
+ Null = 0x00000001,
+ WebGPU = 0x00000002,
+ D3D11 = 0x00000003,
+ D3D12 = 0x00000004,
+ Metal = 0x00000005,
+ Vulkan = 0x00000006,
+ OpenGL = 0x00000007,
+ OpenGLES = 0x00000008,
+}
+
+BlendFactor :: enum i32 {
+ Zero = 0x00000000,
+ One = 0x00000001,
+ Src = 0x00000002,
+ OneMinusSrc = 0x00000003,
+ SrcAlpha = 0x00000004,
+ OneMinusSrcAlpha = 0x00000005,
+ Dst = 0x00000006,
+ OneMinusDst = 0x00000007,
+ DstAlpha = 0x00000008,
+ OneMinusDstAlpha = 0x00000009,
+ SrcAlphaSaturated = 0x0000000A,
+ Constant = 0x0000000B,
+ OneMinusConstant = 0x0000000C,
+}
+
+BlendOperation :: enum i32 {
+ Add = 0x00000000,
+ Subtract = 0x00000001,
+ ReverseSubtract = 0x00000002,
+ Min = 0x00000003,
+ Max = 0x00000004,
+}
+
+BufferBindingType :: enum i32 {
+ Undefined = 0x00000000,
+ Uniform = 0x00000001,
+ Storage = 0x00000002,
+ ReadOnlyStorage = 0x00000003,
+}
+
+BufferMapAsyncStatus :: enum i32 {
+ Success = 0x00000000,
+ ValidationError = 0x00000001,
+ Unknown = 0x00000002,
+ DeviceLost = 0x00000003,
+ DestroyedBeforeCallback = 0x00000004,
+ UnmappedBeforeCallback = 0x00000005,
+ MappingAlreadyPending = 0x00000006,
+ OffsetOutOfRange = 0x00000007,
+ SizeOutOfRange = 0x00000008,
+}
+
+BufferMapState :: enum i32 {
+ Unmapped = 0x00000000,
+ Pending = 0x00000001,
+ Mapped = 0x00000002,
+}
+
+CompareFunction :: enum i32 {
+ Undefined = 0x00000000,
+ Never = 0x00000001,
+ Less = 0x00000002,
+ LessEqual = 0x00000003,
+ Greater = 0x00000004,
+ GreaterEqual = 0x00000005,
+ Equal = 0x00000006,
+ NotEqual = 0x00000007,
+ Always = 0x00000008,
+}
+
+CompilationInfoRequestStatus :: enum i32 {
+ Success = 0x00000000,
+ Error = 0x00000001,
+ DeviceLost = 0x00000002,
+ Unknown = 0x00000003,
+}
+
+CompilationMessageType :: enum i32 {
+ Error = 0x00000000,
+ Warning = 0x00000001,
+ Info = 0x00000002,
+}
+
+CompositeAlphaMode :: enum i32 {
+ Auto = 0x00000000,
+ Opaque = 0x00000001,
+ Premultiplied = 0x00000002,
+ Unpremultiplied = 0x00000003,
+ Inherit = 0x00000004,
+}
+
+CreatePipelineAsyncStatus :: enum i32 {
+ Success = 0x00000000,
+ ValidationError = 0x00000001,
+ InternalError = 0x00000002,
+ DeviceLost = 0x00000003,
+ DeviceDestroyed = 0x00000004,
+ Unknown = 0x00000005,
+}
+
+CullMode :: enum i32 {
+ None = 0x00000000,
+ Front = 0x00000001,
+ Back = 0x00000002,
+}
+
+DeviceLostReason :: enum i32 {
+ Undefined = 0x00000000,
+ Destroyed = 0x00000001,
+}
+
+ErrorFilter :: enum i32 {
+ Validation = 0x00000000,
+ OutOfMemory = 0x00000001,
+ Internal = 0x00000002,
+}
+
+ErrorType :: enum i32 {
+ NoError = 0x00000000,
+ Validation = 0x00000001,
+ OutOfMemory = 0x00000002,
+ Internal = 0x00000003,
+ Unknown = 0x00000004,
+ DeviceLost = 0x00000005,
+}
+
+FeatureName :: enum i32 {
+ // WebGPU.
+ Undefined = 0x00000000,
+ DepthClipControl = 0x00000001,
+ Depth32FloatStencil8 = 0x00000002,
+ TimestampQuery = 0x00000003,
+ TextureCompressionBC = 0x00000004,
+ TextureCompressionETC2 = 0x00000005,
+ TextureCompressionASTC = 0x00000006,
+ IndirectFirstInstance = 0x00000007,
+ ShaderF16 = 0x00000008,
+ RG11B10UfloatRenderable = 0x00000009,
+ BGRA8UnormStorage = 0x0000000A,
+ Float32Filterable = 0x0000000B,
+
+ // Native.
+ PushConstants = 0x00030001,
+ TextureAdapterSpecificFormatFeatures,
+ MultiDrawIndirect,
+ MultiDrawIndirectCount,
+ VertexWritableStorage,
+ TextureBindingArray,
+ SampledTextureAndStorageBufferArrayNonUniformIndexing,
+ PipelineStatisticsQuery,
+ StorageResourceBindingArray,
+ PartiallyBoundBindingArray,
+}
+
+FilterMode :: enum i32 {
+ Nearest = 0x00000000,
+ Linear = 0x00000001,
+}
+
+FrontFace :: enum i32 {
+ CCW = 0x00000000,
+ CW = 0x00000001,
+}
+
+IndexFormat :: enum i32 {
+ Undefined = 0x00000000,
+ Uint16 = 0x00000001,
+ Uint32 = 0x00000002,
+}
+
+LoadOp :: enum i32 {
+ Undefined = 0x00000000,
+ Clear = 0x00000001,
+ Load = 0x00000002,
+}
+
+MipmapFilterMode :: enum i32 {
+ Nearest = 0x00000000,
+ Linear = 0x00000001,
+}
+
+PowerPreference :: enum i32 {
+ Undefined = 0x00000000,
+ LowPower = 0x00000001,
+ HighPerformance = 0x00000002,
+}
+
+PresentMode :: enum i32 {
+ Fifo = 0x00000000,
+ FifoRelaxed = 0x00000001,
+ Immediate = 0x00000002,
+ Mailbox = 0x00000003,
+}
+
+PrimitiveTopology :: enum i32 {
+ PointList = 0x00000000,
+ LineList = 0x00000001,
+ LineStrip = 0x00000002,
+ TriangleList = 0x00000003,
+ TriangleStrip = 0x00000004,
+}
+
+QueryType :: enum i32 {
+ // WebGPU.
+ Occlusion = 0x00000000,
+ Timestamp = 0x00000001,
+
+ // Native.
+ PipelineStatistics = 0x00030000,
+}
+
+QueueWorkDoneStatus :: enum i32 {
+ Success = 0x00000000,
+ Error = 0x00000001,
+ Unknown = 0x00000002,
+ DeviceLost = 0x00000003,
+}
+
+RequestAdapterStatus :: enum i32 {
+ Success = 0x00000000,
+ Unavailable = 0x00000001,
+ Error = 0x00000002,
+ Unknown = 0x00000003,
+}
+
+RequestDeviceStatus :: enum i32 {
+ Success = 0x00000000,
+ Error = 0x00000001,
+ Unknown = 0x00000002,
+}
+
+SType :: enum i32 {
+ // WebGPU.
+ Invalid = 0x00000000,
+ SurfaceDescriptorFromMetalLayer = 0x00000001,
+ SurfaceDescriptorFromWindowsHWND = 0x00000002,
+ SurfaceDescriptorFromXlibWindow = 0x00000003,
+ SurfaceDescriptorFromCanvasHTMLSelector = 0x00000004,
+ ShaderModuleSPIRVDescriptor = 0x00000005,
+ ShaderModuleWGSLDescriptor = 0x00000006,
+ PrimitiveDepthClipControl = 0x00000007,
+ SurfaceDescriptorFromWaylandSurface = 0x00000008,
+ SurfaceDescriptorFromAndroidNativeWindow = 0x00000009,
+ SurfaceDescriptorFromXcbWindow = 0x0000000A,
+ RenderPassDescriptorMaxDrawCount = 0x0000000F,
+
+ // Native.
+ DeviceExtras = 0x00030001,
+ RequiredLimitsExtras,
+ PipelineLayoutExtras,
+ ShaderModuleGLSLDescriptor,
+ SupportedLimitsExtras,
+ InstanceExtras,
+ BindGroupEntryExtras,
+ BindGroupLayoutEntryExtras,
+ QuerySetDescriptorExtras,
+ SurfaceConfigurationExtras,
+}
+
+SamplerBindingType :: enum i32 {
+ Undefined = 0x00000000,
+ Filtering = 0x00000001,
+ NonFiltering = 0x00000002,
+ Comparison = 0x00000003,
+}
+
+StencilOperation :: enum i32 {
+ Keep = 0x00000000,
+ Zero = 0x00000001,
+ Replace = 0x00000002,
+ Invert = 0x00000003,
+ IncrementClamp = 0x00000004,
+ DecrementClamp = 0x00000005,
+ IncrementWrap = 0x00000006,
+ DecrementWrap = 0x00000007,
+}
+
+StorageTextureAccess :: enum i32 {
+ Undefined = 0x00000000,
+ WriteOnly = 0x00000001,
+ ReadOnly = 0x00000002,
+ ReadWrite = 0x00000003,
+}
+
+StoreOp :: enum i32 {
+ Undefined = 0x00000000,
+ Store = 0x00000001,
+ Discard = 0x00000002,
+}
+
+SurfaceGetCurrentTextureStatus :: enum i32 {
+ Success = 0x00000000,
+ Timeout = 0x00000001,
+ Outdated = 0x00000002,
+ Lost = 0x00000003,
+ OutOfMemory = 0x00000004,
+ DeviceLost = 0x00000005,
+}
+
+TextureAspect :: enum i32 {
+ All = 0x00000000,
+ StencilOnly = 0x00000001,
+ DepthOnly = 0x00000002,
+}
+
+TextureDimension :: enum i32 {
+ _1D = 0x00000000,
+ _2D = 0x00000001,
+ _3D = 0x00000002,
+}
+
+TextureFormat :: enum i32 {
+ Undefined = 0x00000000,
+ R8Unorm = 0x00000001,
+ R8Snorm = 0x00000002,
+ R8Uint = 0x00000003,
+ R8Sint = 0x00000004,
+ R16Uint = 0x00000005,
+ R16Sint = 0x00000006,
+ R16Float = 0x00000007,
+ RG8Unorm = 0x00000008,
+ RG8Snorm = 0x00000009,
+ RG8Uint = 0x0000000A,
+ RG8Sint = 0x0000000B,
+ R32Float = 0x0000000C,
+ R32Uint = 0x0000000D,
+ R32Sint = 0x0000000E,
+ RG16Uint = 0x0000000F,
+ RG16Sint = 0x00000010,
+ RG16Float = 0x00000011,
+ RGBA8Unorm = 0x00000012,
+ RGBA8UnormSrgb = 0x00000013,
+ RGBA8Snorm = 0x00000014,
+ RGBA8Uint = 0x00000015,
+ RGBA8Sint = 0x00000016,
+ BGRA8Unorm = 0x00000017,
+ BGRA8UnormSrgb = 0x00000018,
+ RGB10A2Uint = 0x00000019,
+ RGB10A2Unorm = 0x0000001A,
+ RG11B10Ufloat = 0x0000001B,
+ RGB9E5Ufloat = 0x0000001C,
+ RG32Float = 0x0000001D,
+ RG32Uint = 0x0000001E,
+ RG32Sint = 0x0000001F,
+ RGBA16Uint = 0x00000020,
+ RGBA16Sint = 0x00000021,
+ RGBA16Float = 0x00000022,
+ RGBA32Float = 0x00000023,
+ RGBA32Uint = 0x00000024,
+ RGBA32Sint = 0x00000025,
+ Stencil8 = 0x00000026,
+ Depth16Unorm = 0x00000027,
+ Depth24Plus = 0x00000028,
+ Depth24PlusStencil8 = 0x00000029,
+ Depth32Float = 0x0000002A,
+ Depth32FloatStencil8 = 0x0000002B,
+ BC1RGBAUnorm = 0x0000002C,
+ BC1RGBAUnormSrgb = 0x0000002D,
+ BC2RGBAUnorm = 0x0000002E,
+ BC2RGBAUnormSrgb = 0x0000002F,
+ BC3RGBAUnorm = 0x00000030,
+ BC3RGBAUnormSrgb = 0x00000031,
+ BC4RUnorm = 0x00000032,
+ BC4RSnorm = 0x00000033,
+ BC5RGUnorm = 0x00000034,
+ BC5RGSnorm = 0x00000035,
+ BC6HRGBUfloat = 0x00000036,
+ BC6HRGBFloat = 0x00000037,
+ BC7RGBAUnorm = 0x00000038,
+ BC7RGBAUnormSrgb = 0x00000039,
+ ETC2RGB8Unorm = 0x0000003A,
+ ETC2RGB8UnormSrgb = 0x0000003B,
+ ETC2RGB8A1Unorm = 0x0000003C,
+ ETC2RGB8A1UnormSrgb = 0x0000003D,
+ ETC2RGBA8Unorm = 0x0000003E,
+ ETC2RGBA8UnormSrgb = 0x0000003F,
+ EACR11Unorm = 0x00000040,
+ EACR11Snorm = 0x00000041,
+ EACRG11Unorm = 0x00000042,
+ EACRG11Snorm = 0x00000043,
+ ASTC4x4Unorm = 0x00000044,
+ ASTC4x4UnormSrgb = 0x00000045,
+ ASTC5x4Unorm = 0x00000046,
+ ASTC5x4UnormSrgb = 0x00000047,
+ ASTC5x5Unorm = 0x00000048,
+ ASTC5x5UnormSrgb = 0x00000049,
+ ASTC6x5Unorm = 0x0000004A,
+ ASTC6x5UnormSrgb = 0x0000004B,
+ ASTC6x6Unorm = 0x0000004C,
+ ASTC6x6UnormSrgb = 0x0000004D,
+ ASTC8x5Unorm = 0x0000004E,
+ ASTC8x5UnormSrgb = 0x0000004F,
+ ASTC8x6Unorm = 0x00000050,
+ ASTC8x6UnormSrgb = 0x00000051,
+ ASTC8x8Unorm = 0x00000052,
+ ASTC8x8UnormSrgb = 0x00000053,
+ ASTC10x5Unorm = 0x00000054,
+ ASTC10x5UnormSrgb = 0x00000055,
+ ASTC10x6Unorm = 0x00000056,
+ ASTC10x6UnormSrgb = 0x00000057,
+ ASTC10x8Unorm = 0x00000058,
+ ASTC10x8UnormSrgb = 0x00000059,
+ ASTC10x10Unorm = 0x0000005A,
+ ASTC10x10UnormSrgb = 0x0000005B,
+ ASTC12x10Unorm = 0x0000005C,
+ ASTC12x10UnormSrgb = 0x0000005D,
+ ASTC12x12Unorm = 0x0000005E,
+ ASTC12x12UnormSrgb = 0x0000005F,
+}
+
+TextureSampleType :: enum i32 {
+ Undefined = 0x00000000,
+ Float = 0x00000001,
+ UnfilterableFloat = 0x00000002,
+ Depth = 0x00000003,
+ Sint = 0x00000004,
+ Uint = 0x00000005,
+}
+
+TextureViewDimension :: enum i32 {
+ Undefined = 0x00000000,
+ _1D = 0x00000001,
+ _2D = 0x00000002,
+ _2DArray = 0x00000003,
+ Cube = 0x00000004,
+ CubeArray = 0x00000005,
+ _3D = 0x00000006,
+}
+
+VertexFormat :: enum i32 {
+ Undefined = 0x00000000,
+ Uint8x2 = 0x00000001,
+ Uint8x4 = 0x00000002,
+ Sint8x2 = 0x00000003,
+ Sint8x4 = 0x00000004,
+ Unorm8x2 = 0x00000005,
+ Unorm8x4 = 0x00000006,
+ Snorm8x2 = 0x00000007,
+ Snorm8x4 = 0x00000008,
+ Uint16x2 = 0x00000009,
+ Uint16x4 = 0x0000000A,
+ Sint16x2 = 0x0000000B,
+ Sint16x4 = 0x0000000C,
+ Unorm16x2 = 0x0000000D,
+ Unorm16x4 = 0x0000000E,
+ Snorm16x2 = 0x0000000F,
+ Snorm16x4 = 0x00000010,
+ Float16x2 = 0x00000011,
+ Float16x4 = 0x00000012,
+ Float32 = 0x00000013,
+ Float32x2 = 0x00000014,
+ Float32x3 = 0x00000015,
+ Float32x4 = 0x00000016,
+ Uint32 = 0x00000017,
+ Uint32x2 = 0x00000018,
+ Uint32x3 = 0x00000019,
+ Uint32x4 = 0x0000001A,
+ Sint32 = 0x0000001B,
+ Sint32x2 = 0x0000001C,
+ Sint32x3 = 0x0000001D,
+ Sint32x4 = 0x0000001E,
+}
+
+VertexStepMode :: enum i32 {
+ Vertex = 0x00000000,
+ Instance = 0x00000001,
+ VertexBufferNotUsed = 0x00000002,
+}
+
+// WGSLFeatureName :: enum i32 {
+// Undefined = 0x00000000,
+// ReadonlyAndReadwriteStorageTextures = 0x00000001,
+// Packed4x8IntegerDotProduct = 0x00000002,
+// UnrestrictedPointerParameters = 0x00000003,
+// PointerCompositeAccess = 0x00000004,
+// }
+
+BufferUsage :: enum i32 {
+ MapRead = 0x00000000,
+ MapWrite = 0x00000001,
+ CopySrc = 0x00000002,
+ CopyDst = 0x00000003,
+ Index = 0x00000004,
+ Vertex = 0x00000005,
+ Uniform = 0x00000006,
+ Storage = 0x00000007,
+ Indirect = 0x00000008,
+ QueryResolve = 0x00000009,
+}
+BufferUsageFlags :: bit_set[BufferUsage; Flags]
+
+ColorWriteMask :: enum i32 {
+ Red = 0x00000000,
+ Green = 0x00000001,
+ Blue = 0x00000002,
+ Alpha = 0x00000003,
+}
+ColorWriteMaskFlags :: bit_set[ColorWriteMask; Flags]
+ColorWriteMaskFlags_All :: ColorWriteMaskFlags{ .Red, .Green, .Blue, .Alpha }
+
+MapMode :: enum i32 {
+ Read = 0x00000000,
+ Write = 0x00000001,
+}
+MapModeFlags :: bit_set[MapMode; Flags]
+
+ShaderStage :: enum i32 {
+ Vertex = 0x00000000,
+ Fragment = 0x00000001,
+ Compute = 0x00000002,
+}
+ShaderStageFlags :: bit_set[ShaderStage; Flags]
+
+TextureUsage :: enum i32 {
+ CopySrc = 0x00000000,
+ CopyDst = 0x00000001,
+ TextureBinding = 0x00000002,
+ StorageBinding = 0x00000003,
+ RenderAttachment = 0x00000004,
+}
+TextureUsageFlags :: bit_set[TextureUsage; Flags]
+
+
+BufferMapAsyncCallback :: #type proc "c" (status: BufferMapAsyncStatus, /* NULLABLE */ userdata: rawptr)
+ShaderModuleGetCompilationInfoCallback :: #type proc "c" (status: CompilationInfoRequestStatus, compilationInfo: ^CompilationInfo, /* NULLABLE */ userdata: rawptr)
+DeviceCreateComputePipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: ComputePipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
+DeviceCreateRenderPipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: RenderPipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
+
+DeviceLostCallback :: #type proc "c" (reason: DeviceLostReason, message: cstring, userdata: rawptr)
+ErrorCallback :: #type proc "c" (type: ErrorType, message: cstring, userdata: rawptr)
+
+Proc :: distinct rawptr
+
+QueueOnSubmittedWorkDoneCallback :: #type proc "c" (status: QueueWorkDoneStatus, /* NULLABLE */ userdata: rawptr)
+InstanceRequestAdapterCallback :: #type proc "c" (status: RequestAdapterStatus, adapter: Adapter, message: cstring, /* NULLABLE */ userdata: rawptr)
+AdapterRequestDeviceCallback :: #type proc "c" (status: RequestDeviceStatus, device: Device, message: cstring, /* NULLABLE */ userdata: rawptr)
+
+// AdapterRequestAdapterInfoCallback :: #type proc "c" (adapterInfo: AdapterInfo, /* NULLABLE */ userdata: rawptr)
+
+ChainedStruct :: struct {
+ next: ^ChainedStruct,
+ sType: SType,
+}
+
+ChainedStructOut :: struct {
+ next: ^ChainedStructOut,
+ sType: SType,
+}
+
+// AdapterInfo :: struct {
+// next: ^ChainedStructOut,
+// vendor: cstring,
+// architecture: cstring,
+// device: cstring,
+// description: cstring,
+// backendType: BackendType,
+// adapterType: AdapterType,
+// vendorID: u32,
+// deviceID: u32,
+// }
+
+AdapterProperties :: struct {
+ nextInChain: ^ChainedStructOut,
+ vendorID: u32,
+ vendorName: cstring,
+ architecture: cstring,
+ deviceID: u32,
+ name: cstring,
+ driverDescription: cstring,
+ adapterType: AdapterType,
+ backendType: BackendType,
+}
+
+BindGroupEntry :: struct {
+ nextInChain: ^ChainedStruct,
+ binding: u32,
+ /* NULLABLE */ buffer: Buffer,
+ offset: u64,
+ size: u64,
+ /* NULLABLE */ sampler: Sampler,
+ /* NULLABLE */ textureView: TextureView,
+}
+
+BlendComponent :: struct {
+ operation: BlendOperation,
+ srcFactor: BlendFactor,
+ dstFactor: BlendFactor,
+}
+
+BufferBindingLayout :: struct {
+ nextInChain: ^ChainedStruct,
+ type: BufferBindingType,
+ hasDynamicOffset: b32,
+ minBindingSize: u64,
+}
+
+BufferDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ usage: BufferUsageFlags,
+ size: u64,
+ mappedAtCreation: b32,
+}
+
+Color :: struct {
+ r: f64,
+ g: f64,
+ b: f64,
+ a: f64,
+}
+
+CommandBufferDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+}
+
+CommandEncoderDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+}
+
+CompilationMessage :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ message: cstring,
+ type: CompilationMessageType,
+ lineNum: u64,
+ linePos: u64,
+ offset: u64,
+ length: u64,
+ utf16LinePos: u64,
+ utf16Offset: u64,
+ utf16Length: u64,
+}
+
+ComputePassTimestampWrites :: struct {
+ querySet: QuerySet,
+ beginningOfPassWriteIndex: u32,
+ endOfPassWriteIndex: u32,
+}
+
+ConstantEntry :: struct {
+ nextInChain: ^ChainedStruct,
+ key: cstring,
+ value: f64,
+}
+
+Extent3D :: struct {
+ width: u32,
+ height: u32,
+ depthOrArrayLayers: u32,
+}
+
+InstanceDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+}
+
+Limits :: struct {
+ maxTextureDimension1D: u32,
+ maxTextureDimension2D: u32,
+ maxTextureDimension3D: u32,
+ maxTextureArrayLayers: u32,
+ maxBindGroups: u32,
+ maxBindGroupsPlusVertexBuffers: u32,
+ maxBindingsPerBindGroup: u32,
+ maxDynamicUniformBuffersPerPipelineLayout: u32,
+ maxDynamicStorageBuffersPerPipelineLayout: u32,
+ maxSampledTexturesPerShaderStage: u32,
+ maxSamplersPerShaderStage: u32,
+ maxStorageBuffersPerShaderStage: u32,
+ maxStorageTexturesPerShaderStage: u32,
+ maxUniformBuffersPerShaderStage: u32,
+ maxUniformBufferBindingSize: u64,
+ maxStorageBufferBindingSize: u64,
+ minUniformBufferOffsetAlignment: u32,
+ minStorageBufferOffsetAlignment: u32,
+ maxVertexBuffers: u32,
+ maxBufferSize: u64,
+ maxVertexAttributes: u32,
+ maxVertexBufferArrayStride: u32,
+ maxInterStageShaderComponents: u32,
+ maxInterStageShaderVariables: u32,
+ maxColorAttachments: u32,
+ maxColorAttachmentBytesPerSample: u32,
+ maxComputeWorkgroupStorageSize: u32,
+ maxComputeInvocationsPerWorkgroup: u32,
+ maxComputeWorkgroupSizeX: u32,
+ maxComputeWorkgroupSizeY: u32,
+ maxComputeWorkgroupSizeZ: u32,
+ maxComputeWorkgroupsPerDimension: u32,
+}
+
+MultisampleState :: struct {
+ nextInChain: ^ChainedStruct,
+ count: u32,
+ mask: u32,
+ alphaToCoverageEnabled: b32,
+}
+
+Origin3D :: struct {
+ x: u32,
+ y: u32,
+ z: u32,
+}
+
+PipelineLayoutDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ bindGroupLayoutCount: uint,
+ bindGroupLayouts: [^]BindGroupLayout `fmt:"v,bindGroupLayoutCount"`,
+}
+
+PrimitiveDepthClipControl :: struct {
+ using chain: ChainedStruct,
+ unclippedDepth: b32,
+}
+
+PrimitiveState :: struct {
+ nextInChain: ^ChainedStruct,
+ topology: PrimitiveTopology,
+ stripIndexFormat: IndexFormat,
+ frontFace: FrontFace,
+ cullMode: CullMode,
+}
+
+QuerySetDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ type: QueryType,
+ count: u32,
+}
+
+QueueDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+}
+
+RenderBundleDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+}
+
+RenderBundleEncoderDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ colorFormatCount: uint,
+ colorFormats: [^]TextureFormat `fmt:"v,colorFormatCount"`,
+ depthStencilFormat: TextureFormat,
+ sampleCount: u32,
+ depthReadOnly: b32,
+ stencilReadOnly: b32,
+}
+
+RenderPassDepthStencilAttachment :: struct {
+ view: TextureView,
+ depthLoadOp: LoadOp,
+ depthStoreOp: StoreOp,
+ depthClearValue: f32,
+ depthReadOnly: b32,
+ stencilLoadOp: LoadOp,
+ stencilStoreOp: StoreOp,
+ stencilClearValue: u32,
+ stencilReadOnly: b32,
+}
+
+RenderPassDescriptorMaxDrawCount :: struct {
+ using chain: ChainedStruct,
+ maxDrawCount: u64,
+}
+
+RenderPassTimestampWrites :: struct {
+ querySet: QuerySet,
+ beginningOfPassWriteIndex: u32,
+ endOfPassWriteIndex: u32,
+}
+
+RequestAdapterOptions :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ compatibleSurface: Surface,
+ powerPreference: PowerPreference,
+ backendType: BackendType,
+ forceFallbackAdapter: b32,
+}
+
+SamplerBindingLayout :: struct {
+ nextInChain: ^ChainedStruct,
+ type: SamplerBindingType,
+}
+
+SamplerDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ addressModeU: AddressMode,
+ addressModeV: AddressMode,
+ addressModeW: AddressMode,
+ magFilter: FilterMode,
+ minFilter: FilterMode,
+ mipmapFilter: MipmapFilterMode,
+ lodMinClamp: f32,
+ lodMaxClamp: f32,
+ compare: CompareFunction,
+ maxAnisotropy: u16,
+}
+
+ShaderModuleCompilationHint :: struct {
+ nextInChain: ^ChainedStruct,
+ entryPoint: cstring,
+ layout: PipelineLayout,
+}
+
+ShaderModuleSPIRVDescriptor :: struct {
+ using chain: ChainedStruct,
+ codeSize: u32,
+ code: /* const */ [^]u32 `fmt:"v,codeSize"`,
+}
+
+ShaderModuleWGSLDescriptor :: struct {
+ using chain: ChainedStruct,
+ code: cstring,
+}
+
+StencilFaceState :: struct {
+ compare: CompareFunction,
+ failOp: StencilOperation,
+ depthFailOp: StencilOperation,
+ passOp: StencilOperation,
+}
+
+StorageTextureBindingLayout :: struct {
+ nextInChain: ^ChainedStruct,
+ access: StorageTextureAccess,
+ format: TextureFormat,
+ viewDimension: TextureViewDimension,
+}
+
+SurfaceCapabilities :: struct {
+ nextInChain: ^ChainedStructOut,
+ formatCount: uint,
+ formats: /* const */ [^]TextureFormat `fmt:"v,formatCount"`,
+ presentModeCount: uint,
+ presentModes: /* const */ [^]PresentMode `fmt:"v,presentModeCount"`,
+ alphaModeCount: uint,
+ alphaModes: /* const */ [^]CompositeAlphaMode `fmt:"v,alphaModeCount"`,
+}
+
+SurfaceConfiguration :: struct {
+ nextInChain: ^ChainedStruct,
+ device: Device,
+ format: TextureFormat,
+ usage: TextureUsageFlags,
+ viewFormatCount: uint,
+ viewFormats: [^]TextureFormat `fmt:"v,viewFormatCount"`,
+ alphaMode: CompositeAlphaMode,
+ width: u32,
+ height: u32,
+ presentMode: PresentMode,
+}
+
+SurfaceDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+}
+
+SurfaceDescriptorFromAndroidNativeWindow :: struct {
+ using chain: ChainedStruct,
+ window: rawptr,
+}
+
+SurfaceDescriptorFromCanvasHTMLSelector :: struct {
+ using chain: ChainedStruct,
+ selector: cstring,
+}
+
+SurfaceDescriptorFromMetalLayer :: struct {
+ using chain: ChainedStruct,
+ layer: rawptr,
+}
+
+SurfaceDescriptorFromWaylandSurface :: struct {
+ using chain: ChainedStruct,
+ display: rawptr,
+ surface: rawptr,
+}
+
+SurfaceDescriptorFromWindowsHWND :: struct {
+ using chain: ChainedStruct,
+ hinstance: rawptr,
+ hwnd: rawptr,
+}
+
+SurfaceDescriptorFromXcbWindow :: struct {
+ using chain: ChainedStruct,
+ connection: rawptr,
+ window: u32,
+}
+
+SurfaceDescriptorFromXlibWindow :: struct {
+ using chain: ChainedStruct,
+ display: rawptr,
+ window: u64,
+}
+
+SurfaceTexture :: struct {
+ texture: Texture,
+ suboptimal: b32,
+ status: SurfaceGetCurrentTextureStatus,
+}
+
+TextureBindingLayout :: struct {
+ nextInChain: ^ChainedStruct,
+ sampleType: TextureSampleType,
+ viewDimension: TextureViewDimension,
+ multisampled: b32,
+}
+
+TextureDataLayout :: struct {
+ nextInChain: ^ChainedStruct,
+ offset: u64,
+ bytesPerRow: u32,
+ rowsPerImage: u32,
+}
+
+TextureViewDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ format: TextureFormat,
+ dimension: TextureViewDimension,
+ baseMipLevel: u32,
+ mipLevelCount: u32,
+ baseArrayLayer: u32,
+ arrayLayerCount: u32,
+ aspect: TextureAspect,
+}
+
+VertexAttribute :: struct {
+ format: VertexFormat,
+ offset: u64,
+ shaderLocation: u32,
+}
+
+BindGroupDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ layout: BindGroupLayout,
+ entryCount: uint,
+ entries: [^]BindGroupEntry `fmt:"v,entryCount"`,
+}
+
+BindGroupLayoutEntry :: struct {
+ nextInChain: ^ChainedStruct,
+ binding: u32,
+ visibility: ShaderStageFlags,
+ buffer: BufferBindingLayout,
+ sampler: SamplerBindingLayout,
+ texture: TextureBindingLayout,
+ storageTexture: StorageTextureBindingLayout,
+}
+
+BlendState :: struct {
+ color: BlendComponent,
+ alpha: BlendComponent,
+}
+
+CompilationInfo :: struct {
+ nextInChain: ^ChainedStruct,
+ messageCount: uint,
+ messages: [^]CompilationMessage `fmt:"v,messageCount"`,
+}
+
+ComputePassDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ /* NULLABLE */ timestampWrites: /* const */ ^ComputePassTimestampWrites,
+}
+
+DepthStencilState :: struct {
+ nextInChain: ^ChainedStruct,
+ format: TextureFormat,
+ depthWriteEnabled: b32,
+ depthCompare: CompareFunction,
+ stencilFront: StencilFaceState,
+ stencilBack: StencilFaceState,
+ stencilReadMask: u32,
+ stencilWriteMask: u32,
+ depthBias: i32,
+ depthBiasSlopeScale: f32,
+ depthBiasClamp: f32,
+}
+
+ImageCopyBuffer :: struct {
+ nextInChain: ^ChainedStruct,
+ layout: TextureDataLayout,
+ buffer: Buffer,
+}
+
+ImageCopyTexture :: struct {
+ nextInChain: ^ChainedStruct,
+ texture: Texture,
+ mipLevel: u32,
+ origin: Origin3D,
+ aspect: TextureAspect,
+}
+
+ProgrammableStageDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ module: ShaderModule,
+ /* NULLABLE */ entryPoint: cstring,
+ constantCount: uint,
+ constants: [^]ConstantEntry `fmt:"v,constantCount"`,
+}
+
+RenderPassColorAttachment :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ view: TextureView,
+ // depthSlice: u32,
+ /* NULLABLE */ resolveTarget: TextureView,
+ loadOp: LoadOp,
+ storeOp: StoreOp,
+ clearValue: Color,
+}
+
+RequiredLimits :: struct {
+ nextInChain: ^ChainedStruct,
+ limits: Limits,
+}
+
+ShaderModuleDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ hintCount: uint,
+ hints: [^]ShaderModuleCompilationHint `fmt:"v,hintCount"`,
+}
+
+SupportedLimits :: struct {
+ nextInChain: ^ChainedStructOut,
+ limits: Limits,
+}
+
+TextureDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ usage: TextureUsageFlags,
+ dimension: TextureDimension,
+ size: Extent3D,
+ format: TextureFormat,
+ mipLevelCount: u32,
+ sampleCount: u32,
+ viewFormatCount: uint,
+ viewFormats: [^]TextureFormat `fmt:"v,viewFormatCount"`,
+}
+
+VertexBufferLayout :: struct {
+ arrayStride: u64,
+ stepMode: VertexStepMode,
+ attributeCount: uint,
+ attributes: [^]VertexAttribute `fmt:"v,attributeCount"`,
+}
+
+BindGroupLayoutDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ entryCount: uint,
+ entries: [^]BindGroupLayoutEntry `fmt:"v,entryCount"`,
+}
+
+ColorTargetState :: struct {
+ nextInChain: ^ChainedStruct,
+ format: TextureFormat,
+ /* NULLABLE */ blend: /* const */ ^BlendState,
+ writeMask: ColorWriteMaskFlags,
+}
+
+ComputePipelineDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ /* NULLABLE */ layout: PipelineLayout,
+ compute: ProgrammableStageDescriptor,
+}
+
+DeviceDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ requiredFeatureCount: uint,
+ requiredFeatures: [^]FeatureName `fmt:"v,requiredFeatureCount"`,
+ /* NULLABLE */ requiredLimits: /* const */ ^RequiredLimits,
+ defaultQueue: QueueDescriptor,
+ deviceLostCallback: DeviceLostCallback,
+ deviceLostUserdata: rawptr,
+}
+
+RenderPassDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ colorAttachmentCount: uint,
+ colorAttachments: [^]RenderPassColorAttachment `fmt:"v,colorAttachmentCount"`,
+ /* NULLABLE */ depthStencilAttachment: /* const */ ^RenderPassDepthStencilAttachment,
+ /* NULLABLE */ occlusionQuerySet: QuerySet,
+ /* NULLABLE */ timestampWrites: /* const */ ^RenderPassTimestampWrites,
+}
+
+VertexState :: struct {
+ nextInChain: ^ChainedStruct,
+ module: ShaderModule,
+ /* NULLABLE */ entryPoint: cstring,
+ constantCount: uint,
+ constants: [^]ConstantEntry `fmt:"v,constantCount"`,
+ bufferCount: uint,
+ buffers: [^]VertexBufferLayout `fmt:"v,bufferCount"`,
+}
+
+FragmentState :: struct {
+ nextInChain: ^ChainedStruct,
+ module: ShaderModule,
+ /* NULLABLE */ entryPoint: cstring,
+ constantCount: uint,
+ constants: [^]ConstantEntry `fmt:"v,constantCount"`,
+ targetCount: uint,
+ targets: [^]ColorTargetState `fmt:"v,targetCount"`,
+}
+
+RenderPipelineDescriptor :: struct {
+ nextInChain: ^ChainedStruct,
+ /* NULLABLE */ label: cstring,
+ /* NULLABLE */ layout: PipelineLayout,
+ vertex: VertexState,
+ primitive: PrimitiveState,
+ /* NULLABLE */ depthStencil: /* const */ ^DepthStencilState,
+ multisample: MultisampleState,
+ /* NULLABLE */ fragment: /* const */ ^FragmentState,
+}
+
+@(link_prefix="wgpu", default_calling_convention="c")
+foreign libwgpu {
+ CreateInstance :: proc(/* NULLABLE */ descriptor: /* const */ ^InstanceDescriptor = nil) -> Instance ---
+ GetProcAddress :: proc(device: Device, procName: cstring) -> Proc ---
+
+ // Methods of Adapter
+ @(link_name="wgpuAdapterEnumerateFeatures")
+ RawAdapterEnumerateFeatures :: proc(adapter: Adapter, features: [^]FeatureName) -> uint ---
+ @(link_name="wgpuAdapterGetLimits")
+ RawAdapterGetLimits :: proc(adapter: Adapter, limits: ^SupportedLimits) -> b32 ---
+ @(link_name="wgpuAdapterGetProperties")
+ RawAdapterGetProperties :: proc(adapter: Adapter, properties: ^AdapterProperties) ---
+ AdapterHasFeature :: proc(adapter: Adapter, feature: FeatureName) -> b32 ---
+ // AdapterRequestAdapterInfo :: proc(adapter: Adapter, callback: AdapterRequestAdapterInfoCallback, /* NULLABLE */ userdata: rawptr) ---
+ AdapterRequestDevice :: proc(adapter: Adapter, /* NULLABLE */ descriptor: /* const */ ^DeviceDescriptor, callback: AdapterRequestDeviceCallback, /* NULLABLE */ userdata: rawptr = nil) ---
+ AdapterReference :: proc(adapter: Adapter) ---
+ AdapterRelease :: proc(adapter: Adapter) ---
+
+ // Methods of BindGroup
+ BindGroupSetLabel :: proc(bindGroup: BindGroup, label: cstring) ---
+ BindGroupReference :: proc(bindGroup: BindGroup) ---
+ BindGroupRelease :: proc(bindGroup: BindGroup) ---
+
+ // Methods of BindGroupLayout
+ BindGroupLayoutSetLabel :: proc(bindGroupLayout: BindGroupLayout, label: cstring) ---
+ BindGroupLayoutReference :: proc(bindGroupLayout: BindGroupLayout) ---
+ BindGroupLayoutRelease :: proc(bindGroupLayout: BindGroupLayout) ---
+
+ // Methods of Buffer
+ BufferDestroy :: proc(buffer: Buffer) ---
+ @(link_name="wgpuBufferGetConstMappedRange")
+ RawBufferGetConstMappedRange :: proc(buffer: Buffer, offset: uint, size: uint) -> /* const */ rawptr ---
+ BufferGetMapState :: proc(buffer: Buffer) -> BufferMapState ---
+ @(link_name="wgpuBufferGetMappedRange")
+ RawBufferGetMappedRange :: proc(buffer: Buffer, offset: uint, size: uint) -> rawptr ---
+ BufferGetSize :: proc(buffer: Buffer) -> u64 ---
+ BufferGetUsage :: proc(buffer: Buffer) -> BufferUsageFlags ---
+ BufferMapAsync :: proc(buffer: Buffer, mode: MapModeFlags, offset: uint, size: uint, callback: BufferMapAsyncCallback, /* NULLABLE */ userdata: rawptr = nil) ---
+ BufferSetLabel :: proc(buffer: Buffer, label: cstring) ---
+ BufferUnmap :: proc(buffer: Buffer) ---
+ BufferReference :: proc(buffer: Buffer) ---
+ BufferRelease :: proc(buffer: Buffer) ---
+
+ // Methods of CommandBuffer
+ CommandBufferSetLabel :: proc(commandBuffer: CommandBuffer, label: cstring) ---
+ CommandBufferReference :: proc(commandBuffer: CommandBuffer) ---
+ CommandBufferRelease :: proc(commandBuffer: CommandBuffer) ---
+
+ // Methods of CommandEncoder
+ CommandEncoderBeginComputePass :: proc(commandEncoder: CommandEncoder, /* NULLABLE */ descriptor: /* const */ ^ComputePassDescriptor = nil) -> ComputePassEncoder ---
+ CommandEncoderBeginRenderPass :: proc(commandEncoder: CommandEncoder, descriptor: /* const */ ^RenderPassDescriptor) -> RenderPassEncoder ---
+ CommandEncoderClearBuffer :: proc(commandEncoder: CommandEncoder, buffer: Buffer, offset: u64, size: u64) ---
+ CommandEncoderCopyBufferToBuffer :: proc(commandEncoder: CommandEncoder, source: Buffer, sourceOffset: u64, destination: Buffer, destinationOffset: u64, size: u64) ---
+ CommandEncoderCopyBufferToTexture :: proc(commandEncoder: CommandEncoder, source: /* const */ ^ImageCopyBuffer, destination: /* const */ ^ImageCopyTexture, copySize: /* const */ ^Extent3D) ---
+ CommandEncoderCopyTextureToBuffer :: proc(commandEncoder: CommandEncoder, source: /* const */ ^ImageCopyTexture, destination: /* const */ ^ImageCopyBuffer, copySize: /* const */ ^Extent3D) ---
+ CommandEncoderCopyTextureToTexture :: proc(commandEncoder: CommandEncoder, source: /* const */ ^ImageCopyTexture, destination: /* const */ ^ImageCopyTexture, copySize: /* const */ ^Extent3D) ---
+ CommandEncoderFinish :: proc(commandEncoder: CommandEncoder, /* NULLABLE */ descriptor: /* const */ ^CommandBufferDescriptor = nil) -> CommandBuffer ---
+ CommandEncoderInsertDebugMarker :: proc(commandEncoder: CommandEncoder, markerLabel: cstring) ---
+ CommandEncoderPopDebugGroup :: proc(commandEncoder: CommandEncoder) ---
+ CommandEncoderPushDebugGroup :: proc(commandEncoder: CommandEncoder, groupLabel: cstring) ---
+ CommandEncoderResolveQuerySet :: proc(commandEncoder: CommandEncoder, querySet: QuerySet, firstQuery: u32, queryCount: u32, destination: Buffer, destinationOffset: u64) ---
+ CommandEncoderSetLabel :: proc(commandEncoder: CommandEncoder, label: cstring) ---
+ CommandEncoderWriteTimestamp :: proc(commandEncoder: CommandEncoder, querySet: QuerySet, queryIndex: u32) ---
+ CommandEncoderReference :: proc(commandEncoder: CommandEncoder) ---
+ CommandEncoderRelease :: proc(commandEncoder: CommandEncoder) ---
+
+ // Methods of ComputePassEncoder
+ ComputePassEncoderDispatchWorkgroups :: proc(computePassEncoder: ComputePassEncoder, workgroupCountX: u32, workgroupCountY: u32, workgroupCountZ: u32) ---
+ ComputePassEncoderDispatchWorkgroupsIndirect :: proc(computePassEncoder: ComputePassEncoder, indirectBuffer: Buffer, indirectOffset: u64) ---
+ ComputePassEncoderEnd :: proc(computePassEncoder: ComputePassEncoder) ---
+ ComputePassEncoderInsertDebugMarker :: proc(computePassEncoder: ComputePassEncoder, markerLabel: cstring) ---
+ ComputePassEncoderPopDebugGroup :: proc(computePassEncoder: ComputePassEncoder) ---
+ ComputePassEncoderPushDebugGroup :: proc(computePassEncoder: ComputePassEncoder, groupLabel: cstring) ---
+ @(link_name="wgpuComputePassEncoderSetBindGroup")
+ RawComputePassEncoderSetBindGroup :: proc(computePassEncoder: ComputePassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: [^]u32) ---
+ ComputePassEncoderSetLabel :: proc(computePassEncoder: ComputePassEncoder, label: cstring) ---
+ ComputePassEncoderSetPipeline :: proc(computePassEncoder: ComputePassEncoder, pipeline: ComputePipeline) ---
+ ComputePassEncoderReference :: proc(computePassEncoder: ComputePassEncoder) ---
+ ComputePassEncoderRelease :: proc(computePassEncoder: ComputePassEncoder) ---
+
+ // Methods of ComputePipeline
+ ComputePipelineGetBindGroupLayout :: proc(computePipeline: ComputePipeline, groupIndex: u32) -> BindGroupLayout ---
+ ComputePipelineSetLabel :: proc(computePipeline: ComputePipeline, label: cstring) ---
+ ComputePipelineReference :: proc(computePipeline: ComputePipeline) ---
+ ComputePipelineRelease :: proc(computePipeline: ComputePipeline) ---
+
+ // Methods of Device
+ DeviceCreateBindGroup :: proc(device: Device, descriptor: /* const */ ^BindGroupDescriptor) -> BindGroup ---
+ DeviceCreateBindGroupLayout :: proc(device: Device, descriptor: /* const */ ^BindGroupLayoutDescriptor) -> BindGroupLayout ---
+ DeviceCreateBuffer :: proc(device: Device, descriptor: /* const */ ^BufferDescriptor) -> Buffer ---
+ DeviceCreateCommandEncoder :: proc(device: Device, /* NULLABLE */ descriptor: /* const */ ^CommandEncoderDescriptor = nil) -> CommandEncoder ---
+ DeviceCreateComputePipeline :: proc(device: Device, descriptor: /* const */ ^ComputePipelineDescriptor) -> ComputePipeline ---
+ DeviceCreateComputePipelineAsync :: proc(device: Device, descriptor: /* const */ ^ComputePipelineDescriptor, callback: DeviceCreateComputePipelineAsyncCallback, /* NULLABLE */ userdata: rawptr = nil) ---
+ DeviceCreatePipelineLayout :: proc(device: Device, descriptor: /* const */ ^PipelineLayoutDescriptor) -> PipelineLayout ---
+ DeviceCreateQuerySet :: proc(device: Device, descriptor: /* const */ ^QuerySetDescriptor) -> QuerySet ---
+ DeviceCreateRenderBundleEncoder :: proc(device: Device, descriptor: /* const */ ^RenderBundleEncoderDescriptor) -> RenderBundleEncoder ---
+ DeviceCreateRenderPipeline :: proc(device: Device, descriptor: /* const */ ^RenderPipelineDescriptor) -> RenderPipeline ---
+ DeviceCreateRenderPipelineAsync :: proc(device: Device, descriptor: /* const */ ^RenderPipelineDescriptor, callback: DeviceCreateRenderPipelineAsyncCallback, /* NULLABLE */ userdata: rawptr = nil) ---
+ DeviceCreateSampler :: proc(device: Device, /* NULLABLE */ descriptor: /* const */ ^SamplerDescriptor = nil) -> Sampler ---
+ DeviceCreateShaderModule :: proc(device: Device, descriptor: /* const */ ^ShaderModuleDescriptor) -> ShaderModule ---
+ DeviceCreateTexture :: proc(device: Device, descriptor: /* const */ ^TextureDescriptor) -> Texture ---
+ DeviceDestroy :: proc(device: Device) ---
+ @(link_name="wgpuDeviceEnumerateFeatures")
+ RawDeviceEnumerateFeatures :: proc(device: Device, features: ^FeatureName) -> uint ---
+ @(link_name="wgpuDeviceGetLimits")
+ RawDeviceGetLimits :: proc(device: Device, limits: ^SupportedLimits) -> b32 ---
+ DeviceGetQueue :: proc(device: Device) -> Queue ---
+ DeviceHasFeature :: proc(device: Device, feature: FeatureName) -> b32 ---
+ DevicePopErrorScope :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) ---
+ DevicePushErrorScope :: proc(device: Device, filter: ErrorFilter) ---
+ DeviceSetLabel :: proc(device: Device, label: cstring) ---
+ DeviceSetUncapturedErrorCallback :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) ---
+ DeviceReference :: proc(device: Device) ---
+ DeviceRelease :: proc(device: Device) ---
+
+ // Methods of Instance
+ InstanceCreateSurface :: proc(instance: Instance, descriptor: /* const */ ^SurfaceDescriptor) -> Surface ---
+ // InstanceHasWGSLLanguageFeature :: proc(instance: Instance, feature: WGSLFeatureName) -> b32 ---
+ InstanceProcessEvents :: proc(instance: Instance) ---
+ InstanceRequestAdapter :: proc(instance: Instance, /* NULLABLE */ options: /* const */ ^RequestAdapterOptions, callback: InstanceRequestAdapterCallback, /* NULLABLE */ userdata: rawptr = nil) ---
+ InstanceReference :: proc(instance: Instance) ---
+ InstanceRelease :: proc(instance: Instance) ---
+
+ // Methods of PipelineLayout
+ PipelineLayoutSetLabel :: proc(pipelineLayout: PipelineLayout, label: cstring) ---
+ PipelineLayoutReference :: proc(pipelineLayout: PipelineLayout) ---
+ PipelineLayoutRelease :: proc(pipelineLayout: PipelineLayout) ---
+
+ // Methods of QuerySet
+ QuerySetDestroy :: proc(querySet: QuerySet) ---
+ QuerySetGetCount :: proc(querySet: QuerySet) -> u32 ---
+ QuerySetGetType :: proc(querySet: QuerySet) -> QueryType ---
+ QuerySetSetLabel :: proc(querySet: QuerySet, label: cstring) ---
+ QuerySetReference :: proc(querySet: QuerySet) ---
+ QuerySetRelease :: proc(querySet: QuerySet) ---
+
+ // Methods of Queue
+ QueueOnSubmittedWorkDone :: proc(queue: Queue, callback: QueueOnSubmittedWorkDoneCallback, /* NULLABLE */ userdata: rawptr = nil) ---
+ QueueSetLabel :: proc(queue: Queue, label: cstring) ---
+ @(link_name="wgpuQueueSubmit")
+ RawQueueSubmit :: proc(queue: Queue, commandCount: uint, commands: [^]CommandBuffer) ---
+ QueueWriteBuffer :: proc(queue: Queue, buffer: Buffer, bufferOffset: u64, data: /* const */ rawptr, size: uint) ---
+ QueueWriteTexture :: proc(queue: Queue, destination: /* const */ ^ImageCopyTexture, data: /* const */ rawptr, dataSize: uint, dataLayout: /* const */ ^TextureDataLayout, writeSize: /* const */ ^Extent3D) ---
+ QueueReference :: proc(queue: Queue) ---
+ QueueRelease :: proc(queue: Queue) ---
+
+ // Methods of RenderBundle
+ RenderBundleSetLabel :: proc(renderBundle: RenderBundle, label: cstring) ---
+ RenderBundleReference :: proc(renderBundle: RenderBundle) ---
+ RenderBundleRelease :: proc(renderBundle: RenderBundle) ---
+
+ // Methods of RenderBundleEncoder
+ RenderBundleEncoderDraw :: proc(renderBundleEncoder: RenderBundleEncoder, vertexCount: u32, instanceCount: u32, firstVertex: u32, firstInstance: u32) ---
+ RenderBundleEncoderDrawIndexed :: proc(renderBundleEncoder: RenderBundleEncoder, indexCount: u32, instanceCount: u32, firstIndex: u32, baseVertex: i32, firstInstance: u32) ---
+ RenderBundleEncoderDrawIndexedIndirect :: proc(renderBundleEncoder: RenderBundleEncoder, indirectBuffer: Buffer, indirectOffset: u64) ---
+ RenderBundleEncoderDrawIndirect :: proc(renderBundleEncoder: RenderBundleEncoder, indirectBuffer: Buffer, indirectOffset: u64) ---
+ RenderBundleEncoderFinish :: proc(renderBundleEncoder: RenderBundleEncoder, /* NULLABLE */ descriptor: /* const */ ^RenderBundleDescriptor = nil) -> RenderBundle ---
+ RenderBundleEncoderInsertDebugMarker :: proc(renderBundleEncoder: RenderBundleEncoder, markerLabel: cstring) ---
+ RenderBundleEncoderPopDebugGroup :: proc(renderBundleEncoder: RenderBundleEncoder) ---
+ RenderBundleEncoderPushDebugGroup :: proc(renderBundleEncoder: RenderBundleEncoder, groupLabel: cstring) ---
+ @(link_name="wgpuRenderBundleEncoderSetBindGroup")
+ RawRenderBundleEncoderSetBindGroup :: proc(renderBundleEncoder: RenderBundleEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: [^]u32) ---
+ RenderBundleEncoderSetIndexBuffer :: proc(renderBundleEncoder: RenderBundleEncoder, buffer: Buffer, format: IndexFormat, offset: u64, size: u64) ---
+ RenderBundleEncoderSetLabel :: proc(renderBundleEncoder: RenderBundleEncoder, label: cstring) ---
+ RenderBundleEncoderSetPipeline :: proc(renderBundleEncoder: RenderBundleEncoder, pipeline: RenderPipeline) ---
+ RenderBundleEncoderSetVertexBuffer :: proc(renderBundleEncoder: RenderBundleEncoder, slot: u32, /* NULLABLE */ buffer: Buffer, offset: u64, size: u64) ---
+ RenderBundleEncoderReference :: proc(renderBundleEncoder: RenderBundleEncoder) ---
+ RenderBundleEncoderRelease :: proc(renderBundleEncoder: RenderBundleEncoder) ---
+
+ // Methods of RenderPassEncoder
+ RenderPassEncoderBeginOcclusionQuery :: proc(renderPassEncoder: RenderPassEncoder, queryIndex: u32) ---
+ RenderPassEncoderDraw :: proc(renderPassEncoder: RenderPassEncoder, vertexCount: u32, instanceCount: u32, firstVertex: u32, firstInstance: u32) ---
+ RenderPassEncoderDrawIndexed :: proc(renderPassEncoder: RenderPassEncoder, indexCount: u32, instanceCount: u32, firstIndex: u32, baseVertex: i32, firstInstance: u32) ---
+ RenderPassEncoderDrawIndexedIndirect :: proc(renderPassEncoder: RenderPassEncoder, indirectBuffer: Buffer, indirectOffset: u64) ---
+ RenderPassEncoderDrawIndirect :: proc(renderPassEncoder: RenderPassEncoder, indirectBuffer: Buffer, indirectOffset: u64) ---
+ RenderPassEncoderEnd :: proc(renderPassEncoder: RenderPassEncoder) ---
+ RenderPassEncoderEndOcclusionQuery :: proc(renderPassEncoder: RenderPassEncoder) ---
+ @(link_name="wgpuRenderPassEncoderExecuteBundles")
+ RawRenderPassEncoderExecuteBundles :: proc(renderPassEncoder: RenderPassEncoder, bundleCount: uint, bundles: [^]RenderBundle) ---
+ RenderPassEncoderInsertDebugMarker :: proc(renderPassEncoder: RenderPassEncoder, markerLabel: cstring) ---
+ RenderPassEncoderPopDebugGroup :: proc(renderPassEncoder: RenderPassEncoder) ---
+ RenderPassEncoderPushDebugGroup :: proc(renderPassEncoder: RenderPassEncoder, groupLabel: cstring) ---
+ @(link_name="wgpuRenderPassEncoderSetBindGroup")
+ RawRenderPassEncoderSetBindGroup :: proc(renderPassEncoder: RenderPassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: [^]u32) ---
+ RenderPassEncoderSetBlendConstant :: proc(renderPassEncoder: RenderPassEncoder, color: /* const */ ^Color) ---
+ RenderPassEncoderSetIndexBuffer :: proc(renderPassEncoder: RenderPassEncoder, buffer: Buffer, format: IndexFormat, offset: u64, size: u64) ---
+ RenderPassEncoderSetLabel :: proc(renderPassEncoder: RenderPassEncoder, label: cstring) ---
+ RenderPassEncoderSetPipeline :: proc(renderPassEncoder: RenderPassEncoder, pipeline: RenderPipeline) ---
+ RenderPassEncoderSetScissorRect :: proc(renderPassEncoder: RenderPassEncoder, x: u32, y: u32, width: u32, height: u32) ---
+ RenderPassEncoderSetStencilReference :: proc(renderPassEncoder: RenderPassEncoder, reference: u32) ---
+ RenderPassEncoderSetVertexBuffer :: proc(renderPassEncoder: RenderPassEncoder, slot: u32, /* NULLABLE */ buffer: Buffer, offset: u64, size: u64) ---
+ RenderPassEncoderSetViewport :: proc(renderPassEncoder: RenderPassEncoder, x: f32, y: f32, width: f32, height: f32, minDepth: f32, maxDepth: f32) ---
+ RenderPassEncoderReference :: proc(renderPassEncoder: RenderPassEncoder) ---
+ RenderPassEncoderRelease :: proc(renderPassEncoder: RenderPassEncoder) ---
+
+ // Methods of RenderPipeline
+ RenderPipelineGetBindGroupLayout :: proc(renderPipeline: RenderPipeline, groupIndex: u32) -> BindGroupLayout ---
+ RenderPipelineSetLabel :: proc(renderPipeline: RenderPipeline, label: cstring) ---
+ RenderPipelineReference :: proc(renderPipeline: RenderPipeline) ---
+ RenderPipelineRelease :: proc(renderPipeline: RenderPipeline) ---
+
+ // Methods of Sampler
+ SamplerSetLabel :: proc(sampler: Sampler, label: cstring) ---
+ SamplerReference :: proc(sampler: Sampler) ---
+ SamplerRelease :: proc(sampler: Sampler) ---
+
+ // Methods of ShaderModule
+ ShaderModuleGetCompilationInfo :: proc(shaderModule: ShaderModule, callback: ShaderModuleGetCompilationInfoCallback, /* NULLABLE */ userdata: rawptr = nil) ---
+ ShaderModuleSetLabel :: proc(shaderModule: ShaderModule, label: cstring) ---
+ ShaderModuleReference :: proc(shaderModule: ShaderModule) ---
+ ShaderModuleRelease :: proc(shaderModule: ShaderModule) ---
+
+ // Methods of Surface
+ SurfaceConfigure :: proc(surface: Surface, config: /* const */ ^SurfaceConfiguration) ---
+ @(link_name="wgpuSurfaceGetCapabilities")
+ RawSurfaceGetCapabilities :: proc(surface: Surface, adapter: Adapter, capabilities: ^SurfaceCapabilities) ---
+ @(link_name="wgpuSurfaceGetCurrentTexture")
+ RawSurfaceGetCurrentTexture :: proc(surface: Surface, surfaceTexture: ^SurfaceTexture) ---
+ SurfaceGetPreferredFormat :: proc(surface: Surface, adapter: Adapter) -> TextureFormat ---
+ SurfacePresent :: proc(surface: Surface) ---
+ // SurfaceSetLabel :: proc(surface: Surface, label: cstring) ---
+ SurfaceUnconfigure :: proc(surface: Surface) ---
+ SurfaceReference :: proc(surface: Surface) ---
+ SurfaceRelease :: proc(surface: Surface) ---
+
+ // Methods of SurfaceCapabilities
+ SurfaceCapabilitiesFreeMembers :: proc(surfaceCapabilities: SurfaceCapabilities) ---
+
+ // Methods of Texture
+ TextureCreateView :: proc(texture: Texture, /* NULLABLE */ descriptor: /* const */ ^TextureViewDescriptor = nil) -> TextureView ---
+ TextureDestroy :: proc(texture: Texture) ---
+ TextureGetDepthOrArrayLayers :: proc(texture: Texture) -> u32 ---
+ TextureGetDimension :: proc(texture: Texture) -> TextureDimension ---
+ TextureGetFormat :: proc(texture: Texture) -> TextureFormat ---
+ TextureGetHeight :: proc(texture: Texture) -> u32 ---
+ TextureGetMipLevelCount :: proc(texture: Texture) -> u32 ---
+ TextureGetSampleCount :: proc(texture: Texture) -> u32 ---
+ TextureGetUsage :: proc(texture: Texture) -> TextureUsageFlags ---
+ TextureGetWidth :: proc(texture: Texture) -> u32 ---
+ TextureSetLabel :: proc(texture: Texture, label: cstring) ---
+ TextureReference :: proc(texture: Texture) ---
+ TextureRelease :: proc(texture: Texture) ---
+
+ // Methods of TextureView
+ TextureViewSetLabel :: proc(textureView: TextureView, label: cstring) ---
+ TextureViewReference :: proc(textureView: TextureView) ---
+ TextureViewRelease :: proc(textureView: TextureView) ---
+}
+
+// Wrappers of Adapter
+
+AdapterEnumerateFeatures :: proc(adapter: Adapter, allocator := context.allocator) -> []FeatureName {
+ count := RawAdapterEnumerateFeatures(adapter, nil)
+ features := make([]FeatureName, count, allocator)
+ RawAdapterEnumerateFeatures(adapter, raw_data(features))
+ return features
+}
+
+AdapterGetLimits :: proc(adapter: Adapter) -> (limits: SupportedLimits, ok: bool) {
+ ok = bool(RawAdapterGetLimits(adapter, &limits))
+ return
+}
+
+AdapterGetProperties :: proc(adapter: Adapter) -> (properties: AdapterProperties) {
+ RawAdapterGetProperties(adapter, &properties)
+ return
+}
+
+// Wrappers of Buffer
+
+BufferGetConstMappedRange :: proc(buffer: Buffer, offset: uint, size: uint) -> []byte {
+ return ([^]byte)(RawBufferGetConstMappedRange(buffer, offset, size))[:size]
+}
+
+BufferGetConstMappedRangeTyped :: proc(buffer: Buffer, offset: uint, $T: typeid) -> ^T
+ where !intrinsics.type_is_sliceable(T) {
+
+ return (^T)(RawBufferGetConstMappedRange(buffer, 0, size_of(T)))
+}
+
+BufferGetConstMappedRangeSlice :: proc(buffer: Buffer, offset: uint, length: uint, $T: typeid) -> []T {
+ return ([^]T)(RawBufferGetConstMappedRange(buffer, offset, size_of(T)*length))[:length]
+}
+
+BufferGetMappedRange :: proc(buffer: Buffer, offset: uint, size: uint) -> []byte {
+ return ([^]byte)(RawBufferGetMappedRange(buffer, offset, size))[:size]
+}
+
+BufferGetMappedRangeTyped :: proc(buffer: Buffer, offset: uint, $T: typeid) -> ^T
+ where !intrinsics.type_is_sliceable(T) {
+
+ return (^T)(RawBufferGetMappedRange(buffer, offset, size_of(T)))
+}
+
+BufferGetMappedRangeSlice :: proc(buffer: Buffer, offset: uint, $T: typeid, length: uint) -> []T {
+ return ([^]T)(RawBufferGetMappedRange(buffer, offset, size_of(T)*length))[:length]
+}
+
+// Wrappers of ComputePassEncoder
+
+ComputePassEncoderSetBindGroup :: proc(computePassEncoder: ComputePassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsets: []u32 = nil) {
+ RawComputePassEncoderSetBindGroup(computePassEncoder, groupIndex, group, len(dynamicOffsets), raw_data(dynamicOffsets))
+}
+
+// Wrappers of Device
+
+DeviceEnumerateFeatures :: proc(device: Device, allocator := context.allocator) -> []FeatureName {
+ count := RawDeviceEnumerateFeatures(device, nil)
+ features := make([]FeatureName, count, allocator)
+ RawDeviceEnumerateFeatures(device, raw_data(features))
+ return features
+}
+
+DeviceGetLimits :: proc(device: Device) -> (limits: SupportedLimits, ok: bool) {
+ ok = bool(RawDeviceGetLimits(device, &limits))
+ return
+}
+
+BufferWithDataDescriptor :: struct {
+ /* NULLABLE */ label: cstring,
+ usage: BufferUsageFlags,
+}
+
+DeviceCreateBufferWithDataSlice :: proc(device: Device, descriptor: /* const */ ^BufferWithDataDescriptor, data: []$T) -> (buf: Buffer) {
+ size := u64(size_of(T) * len(data))
+ buf = DeviceCreateBuffer(device, &{
+ label = descriptor.label,
+ usage = descriptor.usage,
+ size = size,
+ mappedAtCreation = true,
+ })
+
+ mapping := BufferGetMappedRangeSlice(buf, 0, T, len(data))
+ copy(mapping, data)
+
+ BufferUnmap(buf)
+ return
+}
+
+DeviceCreateBufferWithDataTyped :: proc(device: Device, descriptor: /* const */ ^BufferWithDataDescriptor, data: $T) -> (buf: Buffer)
+ where !intrinsics.type_is_sliceable(T) {
+
+ buf = DeviceCreateBuffer(device, &{
+ label = descriptor.label,
+ usage = descriptor.usage,
+ size = size_of(T),
+ mappedAtCreation = true,
+ })
+
+ mapping := BufferGetMappedRangeTyped(buf, 0, T)
+ mapping^ = data
+
+ BufferUnmap(buf)
+ return
+}
+
+DeviceCreateBufferWithData :: proc {
+ DeviceCreateBufferWithDataSlice,
+ DeviceCreateBufferWithDataTyped,
+}
+
+// Wrappers of Queue
+
+QueueSubmit :: proc(queue: Queue, commands: []CommandBuffer) {
+ RawQueueSubmit(queue, len(commands), raw_data(commands))
+}
+
+// Wrappers of RenderBundleEncoder
+
+RenderBundleEncoderSetBindGroup :: proc(renderBundleEncoder: RenderBundleEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsets: []u32 = nil) {
+ RawRenderBundleEncoderSetBindGroup(renderBundleEncoder, groupIndex, group, len(dynamicOffsets), raw_data(dynamicOffsets))
+}
+
+// Wrappers of RenderPassEncoder
+
+RenderPassEncoderExecuteBundles :: proc(renderPassEncoder: RenderPassEncoder, bundles: []RenderBundle) {
+ RawRenderPassEncoderExecuteBundles(renderPassEncoder, len(bundles), raw_data(bundles))
+}
+
+RenderPassEncoderSetBindGroup :: proc(renderPassEncoder: RenderPassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsets: []u32 = nil) {
+ RawRenderPassEncoderSetBindGroup(renderPassEncoder, groupIndex, group, len(dynamicOffsets), raw_data(dynamicOffsets))
+}
+
+// Wrappers of Surface
+
+SurfaceGetCapabilities :: proc(surface: Surface, adapter: Adapter) -> (capabilities: SurfaceCapabilities) {
+ RawSurfaceGetCapabilities(surface, adapter, &capabilities)
+ return
+}
+
+SurfaceGetCurrentTexture :: proc(surface: Surface) -> (surface_texture: SurfaceTexture) {
+ RawSurfaceGetCurrentTexture(surface, &surface_texture)
+ return
+}
diff --git a/vendor/wgpu/wgpu_js.odin b/vendor/wgpu/wgpu_js.odin
new file mode 100644
index 000000000..f375a0d69
--- /dev/null
+++ b/vendor/wgpu/wgpu_js.odin
@@ -0,0 +1,26 @@
+package wgpu
+
+import "base:runtime"
+
+g_context: runtime.Context
+
+@(private="file", init)
+wgpu_init_allocator :: proc() {
+ if g_context.allocator.procedure == nil {
+ g_context = runtime.default_context()
+ }
+}
+
+@(private="file", export)
+wgpu_alloc :: proc "contextless" (size: i32) -> [^]byte {
+ context = g_context
+ bytes, err := runtime.mem_alloc(int(size), 16)
+ assert(err == nil, "wgpu_alloc failed")
+ return raw_data(bytes)
+}
+
+@(private="file", export)
+wgpu_free :: proc "contextless" (ptr: rawptr) {
+ context = g_context
+ assert(free(ptr) == nil, "wgpu_free failed")
+}
diff --git a/vendor/wgpu/wgpu_native.odin b/vendor/wgpu/wgpu_native.odin
new file mode 100644
index 000000000..2b10e3c17
--- /dev/null
+++ b/vendor/wgpu/wgpu_native.odin
@@ -0,0 +1,75 @@
+//+build !js
+package wgpu
+
+BINDINGS_VERSION :: [4]u8{0, 19, 4, 1}
+BINDINGS_VERSION_STRING :: "0.19.4.1"
+
+@(private="file", init)
+wgpu_native_version_check :: proc() {
+ v := (transmute([4]u8)GetVersion()).wzyx
+
+ if v != BINDINGS_VERSION {
+ buf: [1024]byte
+ n := copy(buf[:], "wgpu-native version mismatch: ")
+ n += copy(buf[n:], "bindings are for version ")
+ n += copy(buf[n:], BINDINGS_VERSION_STRING)
+ n += copy(buf[n:], ", but a different version is linked")
+ panic(string(buf[:n]))
+ }
+}
+
+@(link_prefix="wgpu")
+foreign {
+ @(link_name="wgpuGenerateReport")
+ RawGenerateReport :: proc(instance: Instance, report: ^GlobalReport) ---
+ @(link_name="wgpuInstanceEnumerateAdapters")
+ RawInstanceEnumerateAdapters :: proc(instance: Instance, /* NULLABLE */ options: /* const */ ^InstanceEnumerateAdapterOptions, adapters: [^]Adapter) -> uint ---
+
+ @(link_name="wgpuQueueSubmitForIndex")
+ RawQueueSubmitForIndex :: proc(queue: Queue, commandCount: uint, commands: [^]CommandBuffer) -> SubmissionIndex ---
+
+ // Returns true if the queue is empty, or false if there are more queue submissions still in flight.
+ @(link_name="wgpuDevicePoll")
+ RawDevicePoll :: proc(device: Device, wait: b32, /* NULLABLE */ wrappedSubmissionIndex: /* const */ ^WrappedSubmissionIndex) -> b32 ---
+
+ SetLogCallback :: proc "odin" (callback: LogCallback) ---
+
+ SetLogLevel :: proc(level: LogLevel) ---
+
+ GetVersion :: proc() -> u32 ---
+
+ RenderPassEncoderSetPushConstants :: proc(encoder: RenderPassEncoder, stages: ShaderStageFlags, offset: u32, sizeBytes: u32, data: cstring) ---
+
+ RenderPassEncoderMultiDrawIndirect :: proc(encoder: RenderPassEncoder, buffer: Buffer, offset: u64, count: u32) ---
+ RenderPassEncoderMultiDrawIndexedIndirect :: proc(encoder: RenderPassEncoder, buffer: Buffer, offset: u64, count: u32) ---
+
+ RenderPassEncoderMultiDrawIndirectCount :: proc(encoder: RenderPassEncoder, buffer: Buffer, offset: u64, count_buffer: Buffer, count_buffer_offset: u64, max_count: u32) ---
+ RenderPassEncoderMultiDrawIndexedIndirectCount :: proc(encoder: RenderPassEncoder, buffer: Buffer, offset: u64, count_buffer: Buffer, count_buffer_offset: u64, max_count: u32) ---
+
+ ComputePassEncoderBeginPipelineStatisticsQuery :: proc(computePassEncoder: ComputePassEncoder, querySet: QuerySet, queryIndex: u32) ---
+ ComputePassEncoderEndPipelineStatisticsQuery :: proc(computePassEncoder: ComputePassEncoder) ---
+ RenderPassEncoderBeginPipelineStatisticsQuery :: proc(renderPassEncoder: RenderPassEncoder, querySet: QuerySet, queryIndex: u32) ---
+ RenderPassEncoderEndPipelineStatisticsQuery :: proc(renderPassEncoder: RenderPassEncoder) ---
+}
+
+GenerateReport :: proc(instance: Instance) -> (report: GlobalReport) {
+ RawGenerateReport(instance, &report)
+ return
+}
+
+InstanceEnumerateAdapters :: proc(instance: Instance, options: ^InstanceEnumerateAdapterOptions = nil, allocator := context.allocator) -> (adapters: []Adapter) {
+ count := RawInstanceEnumerateAdapters(instance, options, nil)
+ adapters = make([]Adapter, count, allocator)
+ RawInstanceEnumerateAdapters(instance, options, raw_data(adapters))
+ return
+}
+
+QueueSubmitForIndex :: proc(queue: Queue, commands: []CommandBuffer) -> SubmissionIndex {
+ return RawQueueSubmitForIndex(queue, len(commands), raw_data(commands))
+}
+
+DevicePoll :: proc(device: Device, wait: b32) -> (wrappedSubmissionIndex: WrappedSubmissionIndex, ok: bool) {
+ ok = bool(RawDevicePoll(device, wait, &wrappedSubmissionIndex))
+ return
+}
+
diff --git a/vendor/wgpu/wgpu_native_types.odin b/vendor/wgpu/wgpu_native_types.odin
new file mode 100644
index 000000000..b0837198f
--- /dev/null
+++ b/vendor/wgpu/wgpu_native_types.odin
@@ -0,0 +1,212 @@
+package wgpu
+
+import "base:runtime"
+
+LogLevel :: enum i32 {
+ Off,
+ Error,
+ Warn,
+ Info,
+ Debug,
+ Trace,
+}
+
+InstanceBackend :: enum i32 {
+ Vulkan,
+ GL,
+ Metal,
+ DX12,
+ DX11,
+ BrowserWebGPU,
+}
+InstanceBackendFlags :: bit_set[InstanceBackend; Flags]
+InstanceBackendFlags_All :: InstanceBackendFlags{}
+InstanceBackendFlags_Primary :: InstanceBackendFlags{ .Vulkan, .Metal, .DX12, .BrowserWebGPU }
+InstanceBackendFlags_Secondary :: InstanceBackendFlags{ .GL, .DX11 }
+
+InstanceFlag :: enum i32 {
+ Debug,
+ Validation,
+ DiscardHalLabels,
+}
+InstanceFlags :: bit_set[InstanceFlag; Flags]
+InstanceFlags_Default :: InstanceFlags{}
+
+Dx12Compiler :: enum i32 {
+ Undefined,
+ Fxc,
+ Dxc,
+}
+
+Gles3MinorVersion :: enum i32 {
+ Automatic,
+ Version0,
+ Version1,
+ Version2,
+}
+
+PipelineStatisticName :: enum i32 {
+ VertexShaderInvocations,
+ ClipperInvocations,
+ ClipperPrimitivesOut,
+ FragmentShaderInvocations,
+ ComputeShaderInvocations,
+}
+
+InstanceExtras :: struct {
+ using chain: ChainedStruct,
+ backends: InstanceBackendFlags,
+ flags: InstanceFlags,
+ dx12ShaderCompiler: Dx12Compiler,
+ gles3MinorVersion: Gles3MinorVersion,
+ dxilPath: cstring,
+ dxcPath: cstring,
+}
+
+DeviceExtras :: struct {
+ using chain: ChainedStruct,
+ tracePath: cstring,
+}
+
+NativeLimits :: struct {
+ maxPushConstantSize: u32,
+ maxNonSamplerBindings: u32,
+}
+
+RequiredLimitsExtras :: struct {
+ using chain: ChainedStruct,
+ limits: NativeLimits,
+}
+
+SupportedLimitsExtras :: struct {
+ using chain: ChainedStruct,
+ limits: NativeLimits,
+}
+
+PushConstantRange :: struct {
+ stages: ShaderStageFlags,
+ start: u32,
+ end: u32,
+}
+
+PipelineLayoutExtras :: struct {
+ using chain: ChainedStruct,
+ pushConstantRangeCount: uint,
+ pushConstantRanges: [^]PushConstantRange `fmt:"v,pushConstantRangeCount"`,
+}
+
+SubmissionIndex :: distinct u64
+
+WrappedSubmissionIndex :: struct {
+ queue: Queue,
+ submissionIndex: SubmissionIndex,
+}
+
+ShaderDefine :: struct {
+ name: cstring,
+ value: cstring,
+}
+
+ShaderModuleGLSLDescriptor :: struct {
+ using chain: ChainedStruct,
+ stage: ShaderStage,
+ code: cstring,
+ defineCount: uint,
+ defines: [^]ShaderDefine `fmt:"v,defineCount"`,
+}
+
+RegistryReport :: struct {
+ numAllocated: uint,
+ numKeptFromUser: uint,
+ numReleasedFromUser: uint,
+ numErrors: uint,
+ elementSize: uint,
+}
+
+HubReport :: struct {
+ adapters: RegistryReport,
+ devices: RegistryReport,
+ queues: RegistryReport,
+ pipelineLayouts: RegistryReport,
+ shaderModules: RegistryReport,
+ bindGroupLayouts: RegistryReport,
+ bindGroups: RegistryReport,
+ commandBuffers: RegistryReport,
+ renderBundles: RegistryReport,
+ renderPipelines: RegistryReport,
+ computePipelines: RegistryReport,
+ querySets: RegistryReport,
+ buffers: RegistryReport,
+ textures: RegistryReport,
+ textureViews: RegistryReport,
+ samplers: RegistryReport,
+}
+
+GlobalReport :: struct {
+ surfaces: RegistryReport,
+ backendType: BackendType,
+ vulkan: HubReport,
+ metal: HubReport,
+ dx12: HubReport,
+ gl: HubReport,
+}
+
+InstanceEnumerateAdapterOptions :: struct {
+ nextInChain: ^ChainedStruct,
+ backends: InstanceBackendFlags,
+}
+
+BindGroupEntryExtras :: struct {
+ using chain: ChainedStruct,
+ buffers: [^]Buffer `fmt:"v,bufferCount"`,
+ bufferCount: uint,
+ samplers: [^]Sampler `fmt:"v,samplerCount"`,
+ samplerCount: uint,
+ textureViews: [^]TextureView `fmt:"v,textureViewCount"`,
+ textureViewCount: uint,
+}
+
+BindGroupLayoutEntryExtras :: struct {
+ using chain: ChainedStruct,
+ count: u32,
+}
+
+QuerySetDescriptorExtras :: struct {
+ using chain: ChainedStruct,
+ pipelineStatistics: [^]PipelineStatisticName `fmt:"v,pipelineStatisticCount"`,
+ pipelineStatisticCount: uint,
+}
+
+SurfaceConfigurationExtras :: struct {
+ using chain: ChainedStruct,
+ desiredMaximumFrameLatency: i32,
+}
+
+LogCallback :: #type proc "odin" (level: LogLevel, message: cstring)
+
+// Wrappers
+
+ConvertOdinToWGPULogLevel :: proc(level: runtime.Logger_Level) -> LogLevel {
+ switch {
+ case level < .Debug: return .Trace
+ case level < .Info: return .Debug
+ case level < .Warning: return .Info
+ case level < .Error: return .Warn
+ case: return .Error
+ }
+}
+
+ConvertWGPUToOdinLogLevel :: proc(level: LogLevel) -> runtime.Logger_Level {
+ switch level {
+ case .Off, .Trace, .Debug: return .Debug
+ case .Info: return .Info
+ case .Warn: return .Warning
+ case .Error: return .Error
+ case: return .Error
+ }
+}
+
+ConvertLogLevel :: proc {
+ ConvertOdinToWGPULogLevel,
+ ConvertWGPUToOdinLogLevel,
+}
diff --git a/vendor/x11/xlib/xlib_types.odin b/vendor/x11/xlib/xlib_types.odin
index d333c3c79..8cd0131fe 100644
--- a/vendor/x11/xlib/xlib_types.odin
+++ b/vendor/x11/xlib/xlib_types.odin
@@ -24,6 +24,9 @@ Cursor :: XID
Colormap :: XID
GContext :: XID
+RRCrtc :: XID
+RROutput :: XID
+
KeyCode :: u8
/* ---- X11/Xlib.h ---------------------------------------------------------*/