Skip to content

Commit

Permalink
Add vendor:wgpu
Browse files Browse the repository at this point in the history
  • Loading branch information
laytan committed Jun 12, 2024
1 parent 68781f8 commit 108b8fe
Show file tree
Hide file tree
Showing 23 changed files with 5,431 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ bin/
# - Linux/MacOS
odin
!odin/
odin.dSYM
**/*.dSYM
*.bin
demo.bin
libLLVM*.so*
Expand Down
4 changes: 4 additions & 0 deletions core/sys/darwin/Foundation/NSWindow.odin
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
26 changes: 15 additions & 11 deletions vendor/glfw/native_linux.odin
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

package glfw

// TODO: Native Linux
// Display* glfwGetX11Display(void);
// RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
// RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
// Window glfwGetX11Window(GLFWwindow* window);
// void glfwSetX11SelectionString(const char* string);
// const char* glfwGetX11SelectionString(void);

// struct wl_display* glfwGetWaylandDisplay(void);
// struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
// struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
import "vendor:x11/xlib"

@(default_calling_convention="c", link_prefix="glfw")
foreign {
GetX11Display :: proc() -> ^xlib.Display ---
GetX11Window :: proc(window: WindowHandle) -> xlib.Window ---
GetX11Adapter :: proc(monitor: MonitorHandle) -> xlib.RRCrtc ---
GetX11Monitor :: proc(monitor: MonitorHandle) -> xlib.RROutput ---
SetX11SelectionString :: proc(string: cstring) ---
GetX11SelectionString :: proc() -> cstring ---

GetWaylandDisplay :: proc() -> rawptr /* struct wl_display* */ ---
GetWaylandWindow :: proc(window: WindowHandle) -> rawptr /* struct wl_surface* */ ---
GetWaylandMonitor :: proc(monitor: MonitorHandle) -> rawptr /* struct wl_output* */ ---
}
44 changes: 37 additions & 7 deletions vendor/wasm/js/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand All @@ -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); }
Expand Down Expand Up @@ -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 = {};
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down
9 changes: 9 additions & 0 deletions vendor/wgpu/.gitignore
Original file line number Diff line number Diff line change
@@ -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 changes: 48 additions & 0 deletions vendor/wgpu/README.md
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions vendor/wgpu/example/Makefile
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions vendor/wgpu/example/build.bat
Original file line number Diff line number Diff line change
@@ -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"
Loading

0 comments on commit 108b8fe

Please sign in to comment.