From 108b8feb357dab8b3faf788c382406567bd99d33 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Fri, 31 May 2024 21:31:57 +0200 Subject: [PATCH] Add `vendor:wgpu` --- .gitignore | 2 +- core/sys/darwin/Foundation/NSWindow.odin | 4 + vendor/glfw/native_linux.odin | 24 +- vendor/wasm/js/runtime.js | 44 +- vendor/wgpu/.gitignore | 9 + vendor/wgpu/README.md | 48 + vendor/wgpu/example/Makefile | 17 + vendor/wgpu/example/build.bat | 12 + vendor/wgpu/example/main.odin | 187 ++ vendor/wgpu/example/os_glfw.odin | 55 + vendor/wgpu/example/os_js.odin | 60 + vendor/wgpu/example/web/index.html | 23 + vendor/wgpu/glfwglue/glue.odin | 6 + vendor/wgpu/glfwglue/glue_darwin.odin | 23 + vendor/wgpu/glfwglue/glue_linux.odin | 43 + vendor/wgpu/glfwglue/glue_windows.odin | 23 + vendor/wgpu/lib/.gitkeep | 0 vendor/wgpu/wgpu.js | 2916 ++++++++++++++++++++++ vendor/wgpu/wgpu.odin | 1636 ++++++++++++ vendor/wgpu/wgpu_js.odin | 26 + vendor/wgpu/wgpu_native.odin | 75 + vendor/wgpu/wgpu_native_types.odin | 212 ++ vendor/x11/xlib/xlib_types.odin | 3 + 23 files changed, 5430 insertions(+), 18 deletions(-) create mode 100644 vendor/wgpu/.gitignore create mode 100644 vendor/wgpu/README.md create mode 100644 vendor/wgpu/example/Makefile create mode 100644 vendor/wgpu/example/build.bat create mode 100644 vendor/wgpu/example/main.odin create mode 100644 vendor/wgpu/example/os_glfw.odin create mode 100644 vendor/wgpu/example/os_js.odin create mode 100644 vendor/wgpu/example/web/index.html create mode 100644 vendor/wgpu/glfwglue/glue.odin create mode 100644 vendor/wgpu/glfwglue/glue_darwin.odin create mode 100644 vendor/wgpu/glfwglue/glue_linux.odin create mode 100644 vendor/wgpu/glfwglue/glue_windows.odin create mode 100644 vendor/wgpu/lib/.gitkeep create mode 100644 vendor/wgpu/wgpu.js create mode 100644 vendor/wgpu/wgpu.odin create mode 100644 vendor/wgpu/wgpu_js.odin create mode 100644 vendor/wgpu/wgpu_native.odin create mode 100644 vendor/wgpu/wgpu_native_types.odin 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); +import "vendor:x11/xlib" -// struct wl_display* glfwGetWaylandDisplay(void); -// struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); -// struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); +@(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 { + let x = f32(i32(in_vertex_index) - 1); + let y = f32(i32(in_vertex_index & 1u) * 2 - 1); + return vec4(x, y, 0.0, 1.0); + } + + @fragment + fn fs_main() -> @location(0) vec4 { + return vec4(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 @@ + + + + + + WGPU WASM Triangle + + + + + + + + + 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 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} */ + this.adapters = new WebGPUObjectManager("Adapter", this.mem); + + /** @type {WebGPUObjectManager} */ + this.bindGroups = new WebGPUObjectManager("BindGroup", this.mem); + + /** @type {WebGPUObjectManager} */ + 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} */ + this.devices = new WebGPUObjectManager("Device", this.mem); + + /** @type {WebGPUObjectManager} */ + this.commandBuffers = new WebGPUObjectManager("CommandBuffer", this.mem); + + /** @type {WebGPUObjectManager} */ + this.commandEncoders = new WebGPUObjectManager("CommandEncoder", this.mem); + + /** @type {WebGPUObjectManager} */ + this.computePassEncoders = new WebGPUObjectManager("ComputePassEncoder", this.mem); + + /** @type {WebGPUObjectManager} */ + this.renderPassEncoders = new WebGPUObjectManager("RenderPassEncoder", this.mem); + + /** @type {WebGPUObjectManager} */ + this.querySets = new WebGPUObjectManager("QuerySet", this.mem); + + /** @type {WebGPUObjectManager} */ + this.computePipelines = new WebGPUObjectManager("ComputePipeline", this.mem); + + /** @type {WebGPUObjectManager} */ + this.pipelineLayouts = new WebGPUObjectManager("PipelineLayout", this.mem); + + /** @type {WebGPUObjectManager} */ + this.queues = new WebGPUObjectManager("Queue", this.mem); + + /** @type {WebGPUObjectManager} */ + this.renderBundles = new WebGPUObjectManager("RenderBundle", this.mem); + + /** @type {WebGPUObjectManager} */ + this.renderBundleEncoders = new WebGPUObjectManager("RenderBundleEncoder", this.mem); + + /** @type {WebGPUObjectManager} */ + this.renderPipelines = new WebGPUObjectManager("RenderPipeline", this.mem); + + /** @type {WebGPUObjectManager} */ + this.samplers = new WebGPUObjectManager("Sampler", this.mem); + + /** @type {WebGPUObjectManager} */ + this.shaderModules = new WebGPUObjectManager("ShaderModule", this.mem); + + /** @type {WebGPUObjectManager} */ + this.surfaces = new WebGPUObjectManager("Surface", this.mem); + + /** @type {WebGPUObjectManager} */ + this.textures = new WebGPUObjectManager("Texture", this.mem); + + /** @type {WebGPUObjectManager} */ + 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} + */ + 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} */ + 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 ---------------------------------------------------------*/