Merge pull request #3740 from laytan/wgpu

Add `vendor:wgpu`
This commit is contained in:
gingerBill
2024-06-20 11:39:58 +01:00
committed by GitHub
23 changed files with 5430 additions and 18 deletions

2
.gitignore vendored
View File

@@ -303,7 +303,7 @@ bin/
# - Linux/MacOS
odin
!odin/
odin.dSYM
**/*.dSYM
*.bin
demo.bin
libLLVM*.so*

View File

@@ -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)
}

View File

@@ -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* */ ---
}

View File

@@ -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) {

9
vendor/wgpu/.gitignore vendored Normal file
View File

@@ -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

48
vendor/wgpu/README.md vendored Normal file
View File

@@ -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.

17
vendor/wgpu/example/Makefile vendored Normal file
View File

@@ -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

12
vendor/wgpu/example/build.bat vendored Normal file
View File

@@ -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"

187
vendor/wgpu/example/main.odin vendored Normal file
View File

@@ -0,0 +1,187 @@
package vendor_wgpu_example_triangle
import "base:runtime"
import "core:fmt"
import "vendor:wgpu"
State :: struct {
ctx: runtime.Context,
os: OS,
instance: wgpu.Instance,
surface: wgpu.Surface,
adapter: wgpu.Adapter,
device: wgpu.Device,
config: wgpu.SurfaceConfiguration,
queue: wgpu.Queue,
module: wgpu.ShaderModule,
pipeline_layout: wgpu.PipelineLayout,
pipeline: wgpu.RenderPipeline,
}
@(private="file")
state: State
main :: proc() {
state.ctx = context
os_init(&state.os)
state.instance = wgpu.CreateInstance(nil)
if state.instance == nil {
panic("WebGPU is not supported")
}
state.surface = os_get_surface(&state.os, state.instance)
wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, on_adapter, nil)
on_adapter :: proc "c" (status: wgpu.RequestAdapterStatus, adapter: wgpu.Adapter, message: cstring, userdata: rawptr) {
context = state.ctx
if status != .Success || adapter == nil {
fmt.panicf("request adapter failure: [%v] %s", status, message)
}
state.adapter = adapter
wgpu.AdapterRequestDevice(adapter, nil, on_device)
}
on_device :: proc "c" (status: wgpu.RequestDeviceStatus, device: wgpu.Device, message: cstring, userdata: rawptr) {
context = state.ctx
if status != .Success || device == nil {
fmt.panicf("request device failure: [%v] %s", status, message)
}
state.device = device
width, height := os_get_render_bounds(&state.os)
state.config = wgpu.SurfaceConfiguration {
device = state.device,
usage = { .RenderAttachment },
format = .BGRA8Unorm,
width = width,
height = height,
presentMode = .Fifo,
alphaMode = .Opaque,
}
wgpu.SurfaceConfigure(state.surface, &state.config)
state.queue = wgpu.DeviceGetQueue(state.device)
shader :: `
@vertex
fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
let x = f32(i32(in_vertex_index) - 1);
let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
return vec4<f32>(x, y, 0.0, 1.0);
}
@fragment
fn fs_main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}`
state.module = wgpu.DeviceCreateShaderModule(state.device, &{
nextInChain = &wgpu.ShaderModuleWGSLDescriptor{
sType = .ShaderModuleWGSLDescriptor,
code = shader,
},
})
state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(state.device, &{})
state.pipeline = wgpu.DeviceCreateRenderPipeline(state.device, &{
layout = state.pipeline_layout,
vertex = {
module = state.module,
entryPoint = "vs_main",
},
fragment = &{
module = state.module,
entryPoint = "fs_main",
targetCount = 1,
targets = &wgpu.ColorTargetState{
format = .BGRA8Unorm,
writeMask = wgpu.ColorWriteMaskFlags_All,
},
},
primitive = {
topology = .TriangleList,
},
multisample = {
count = 1,
mask = 0xFFFFFFFF,
},
})
os_run(&state.os)
}
}
resize :: proc "c" () {
context = state.ctx
state.config.width, state.config.height = os_get_render_bounds(&state.os)
wgpu.SurfaceConfigure(state.surface, &state.config)
}
frame :: proc "c" (dt: f32) {
context = state.ctx
surface_texture := wgpu.SurfaceGetCurrentTexture(state.surface)
switch surface_texture.status {
case .Success:
// All good, could check for `surface_texture.suboptimal` here.
case .Timeout, .Outdated, .Lost:
// Skip this frame, and re-configure surface.
if surface_texture.texture != nil {
wgpu.TextureRelease(surface_texture.texture)
}
resize()
return
case .OutOfMemory, .DeviceLost:
// Fatal error
fmt.panicf("[triangle] get_current_texture status=%v", surface_texture.status)
}
defer wgpu.TextureRelease(surface_texture.texture)
frame := wgpu.TextureCreateView(surface_texture.texture, nil)
defer wgpu.TextureViewRelease(frame)
command_encoder := wgpu.DeviceCreateCommandEncoder(state.device, nil)
defer wgpu.CommandEncoderRelease(command_encoder)
render_pass_encoder := wgpu.CommandEncoderBeginRenderPass(
command_encoder, &{
colorAttachmentCount = 1,
colorAttachments = &wgpu.RenderPassColorAttachment{
view = frame,
loadOp = .Clear,
storeOp = .Store,
clearValue = { r = 0, g = 1, b = 0, a = 1 },
},
},
)
defer wgpu.RenderPassEncoderRelease(render_pass_encoder)
wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline)
wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
wgpu.RenderPassEncoderEnd(render_pass_encoder)
command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
defer wgpu.CommandBufferRelease(command_buffer)
wgpu.QueueSubmit(state.queue, { command_buffer })
wgpu.SurfacePresent(state.surface)
}
finish :: proc() {
wgpu.RenderPipelineRelease(state.pipeline)
wgpu.PipelineLayoutRelease(state.pipeline_layout)
wgpu.ShaderModuleRelease(state.module)
wgpu.QueueRelease(state.queue)
wgpu.DeviceRelease(state.device)
wgpu.AdapterRelease(state.adapter)
wgpu.SurfaceRelease(state.surface)
wgpu.InstanceRelease(state.instance)
}

55
vendor/wgpu/example/os_glfw.odin vendored Normal file
View File

@@ -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()
}

60
vendor/wgpu/example/os_js.odin vendored Normal file
View File

@@ -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()
}

23
vendor/wgpu/example/web/index.html vendored Normal file
View File

@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en" style="height: 100%;">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>WGPU WASM Triangle</title>
</head>
<body id="body" style="height: 100%; padding: 0; margin: 0; overflow: hidden;">
<canvas id="wgpu-canvas"></canvas>
<script type="text/javascript" src="runtime.js"></script>
<script type="text/javascript" src="wgpu.js"></script>
<script type="text/javascript">
const mem = new WebAssembly.Memory({ initial: 2000, maximum: 65536, shared: false });
const memInterface = new odin.WasmMemoryInterface();
memInterface.setMemory(mem);
const wgpuInterface = new odin.WebGPUInterface(memInterface);
odin.runWasm("triangle.wasm", null, { wgpu: wgpuInterface.getInterface() }, memInterface, /*intSize=8*/);
</script>
</body>
</html>

6
vendor/wgpu/glfwglue/glue.odin vendored Normal file
View File

@@ -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")

23
vendor/wgpu/glfwglue/glue_darwin.odin vendored Normal file
View File

@@ -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),
},
},
)
}

43
vendor/wgpu/glfwglue/glue_linux.odin vendored Normal file
View File

@@ -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),
},
},
)
}

23
vendor/wgpu/glfwglue/glue_windows.odin vendored Normal file
View File

@@ -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),
},
},
)
}

0
vendor/wgpu/lib/.gitkeep vendored Normal file
View File

2916
vendor/wgpu/wgpu.js vendored Normal file

File diff suppressed because it is too large Load Diff

1636
vendor/wgpu/wgpu.odin vendored Normal file

File diff suppressed because it is too large Load Diff

26
vendor/wgpu/wgpu_js.odin vendored Normal file
View File

@@ -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")
}

75
vendor/wgpu/wgpu_native.odin vendored Normal file
View File

@@ -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
}

212
vendor/wgpu/wgpu_native_types.odin vendored Normal file
View File

@@ -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,
}

View File

@@ -24,6 +24,9 @@ Cursor :: XID
Colormap :: XID
GContext :: XID
RRCrtc :: XID
RROutput :: XID
KeyCode :: u8
/* ---- X11/Xlib.h ---------------------------------------------------------*/