From f3f08a4b47ecc2089be616eb9774ac3dd32e8a8d Mon Sep 17 00:00:00 2001 From: Emir Date: Tue, 23 Jul 2024 20:37:26 +0300 Subject: [PATCH 01/10] Add sdl2glue to `vendor:wgpu` package + triangle example --- .../wgpu/{example => examples/glfw}/Makefile | 6 +- .../wgpu/{example => examples/glfw}/build.bat | 4 +- .../wgpu/{example => examples/glfw}/main.odin | 0 .../{example => examples/glfw}/os_glfw.odin | 0 .../{example => examples/glfw}/os_js.odin | 0 .../{example => examples/glfw}/web/index.html | 0 vendor/wgpu/examples/sdl2/main.odin | 229 ++++++++++++++++++ vendor/wgpu/sdl2glue/glue.odin | 6 + vendor/wgpu/sdl2glue/glue_darwin.odin | 25 ++ vendor/wgpu/sdl2glue/glue_windows.odin | 25 ++ 10 files changed, 290 insertions(+), 5 deletions(-) rename vendor/wgpu/{example => examples/glfw}/Makefile (78%) rename vendor/wgpu/{example => examples/glfw}/build.bat (84%) rename vendor/wgpu/{example => examples/glfw}/main.odin (100%) rename vendor/wgpu/{example => examples/glfw}/os_glfw.odin (100%) rename vendor/wgpu/{example => examples/glfw}/os_js.odin (100%) rename vendor/wgpu/{example => examples/glfw}/web/index.html (100%) create mode 100644 vendor/wgpu/examples/sdl2/main.odin create mode 100644 vendor/wgpu/sdl2glue/glue.odin create mode 100644 vendor/wgpu/sdl2glue/glue_darwin.odin create mode 100644 vendor/wgpu/sdl2glue/glue_windows.odin diff --git a/vendor/wgpu/example/Makefile b/vendor/wgpu/examples/glfw/Makefile similarity index 78% rename from vendor/wgpu/example/Makefile rename to vendor/wgpu/examples/glfw/Makefile index f19997881..fdecdbb91 100644 --- a/vendor/wgpu/example/Makefile +++ b/vendor/wgpu/examples/glfw/Makefile @@ -8,10 +8,10 @@ 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 +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 + 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/examples/glfw/build.bat similarity index 84% rename from vendor/wgpu/example/build.bat rename to vendor/wgpu/examples/glfw/build.bat index cd3ca63ba..61afcbe66 100644 --- a/vendor/wgpu/example/build.bat +++ b/vendor/wgpu/examples/glfw/build.bat @@ -8,5 +8,5 @@ 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 +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/examples/glfw/main.odin similarity index 100% rename from vendor/wgpu/example/main.odin rename to vendor/wgpu/examples/glfw/main.odin diff --git a/vendor/wgpu/example/os_glfw.odin b/vendor/wgpu/examples/glfw/os_glfw.odin similarity index 100% rename from vendor/wgpu/example/os_glfw.odin rename to vendor/wgpu/examples/glfw/os_glfw.odin diff --git a/vendor/wgpu/example/os_js.odin b/vendor/wgpu/examples/glfw/os_js.odin similarity index 100% rename from vendor/wgpu/example/os_js.odin rename to vendor/wgpu/examples/glfw/os_js.odin diff --git a/vendor/wgpu/example/web/index.html b/vendor/wgpu/examples/glfw/web/index.html similarity index 100% rename from vendor/wgpu/example/web/index.html rename to vendor/wgpu/examples/glfw/web/index.html diff --git a/vendor/wgpu/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin new file mode 100644 index 000000000..80cdeb7bd --- /dev/null +++ b/vendor/wgpu/examples/sdl2/main.odin @@ -0,0 +1,229 @@ +package vendor_wgpu_example_triangle + +import "base:runtime" + +import "core:fmt" + +import "vendor:sdl2" +import "vendor:wgpu" +import "vendor:wgpu/sdl2glue" + +State :: struct { + ctx: runtime.Context, + window: ^sdl2.Window, + running: bool, + + 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 + + sdl_flags := sdl2.InitFlags{.VIDEO, .JOYSTICK, .GAMECONTROLLER, .EVENTS} + if res := sdl2.Init(sdl_flags); res != 0 { + fmt.eprintf("ERROR: Failed to initialize SDL: [%s]\n", sdl2.GetError()) + return + } + + window_flags: sdl2.WindowFlags = {.SHOWN, .ALLOW_HIGHDPI, .RESIZABLE} + state.window = sdl2.CreateWindow( + "wgpu triangle", + sdl2.WINDOWPOS_CENTERED, + sdl2.WINDOWPOS_CENTERED, + 800, + 600, + window_flags, + ) + if state.window == nil { + fmt.eprintf("ERROR: Failed to create the SDL Window: [%s]\n", sdl2.GetError()) + return + } + + state.instance = wgpu.CreateInstance(nil) + if state.instance == nil { + panic("WebGPU is not supported") + } + + state.surface = sdl2glue.GetSurface(state.instance, state.window) + + 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 : u32 = 800, 600 // 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, + }, + }) + + now := sdl2.GetPerformanceCounter() + last : u64 = 0 + dt: f32 = 0 + main_loop: for { + last = now + now := sdl2.GetPerformanceCounter() + dt = auto_cast((now - last)*1000 / sdl2.GetPerformanceFrequency()) + + e: sdl2.Event + + for sdl2.PollEvent(&e) { + #partial switch (e.type) { + case .QUIT: + break main_loop + + case .WINDOWEVENT: + #partial switch (e.window.event) { + case .SIZE_CHANGED: + case .RESIZED: + state.config.width = cast(u32)e.window.data1 + state.config.height = cast(u32)e.window.data2 + wgpu.SurfaceConfigure(state.surface, &state.config) + } + } + } + + frame(dt) + } + } +} + +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) + } + // todo - 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/sdl2glue/glue.odin b/vendor/wgpu/sdl2glue/glue.odin new file mode 100644 index 000000000..9da9a0738 --- /dev/null +++ b/vendor/wgpu/sdl2glue/glue.odin @@ -0,0 +1,6 @@ +//+build !linux +//+build !windows +//+build !darwin +package wgpu_sdl2_glue + +#panic("package wgpu/sdl2glue is not supported on the current target") diff --git a/vendor/wgpu/sdl2glue/glue_darwin.odin b/vendor/wgpu/sdl2glue/glue_darwin.odin new file mode 100644 index 000000000..6c962f714 --- /dev/null +++ b/vendor/wgpu/sdl2glue/glue_darwin.odin @@ -0,0 +1,25 @@ +package wgpu_sdl2_glue + +import "vendor:sdl2" +import "vendor:wgpu" +import CA "vendor:darwin/QuartzCore" +import NS "core:sys/darwin/Foundation" + +GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) + ns_window := cast(^NS.Window)window_info.info.cocoa.window + 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), + }, + }, + ) +} \ No newline at end of file diff --git a/vendor/wgpu/sdl2glue/glue_windows.odin b/vendor/wgpu/sdl2glue/glue_windows.odin new file mode 100644 index 000000000..4bd30d452 --- /dev/null +++ b/vendor/wgpu/sdl2glue/glue_windows.odin @@ -0,0 +1,25 @@ +package wgpu_sdl2_glue + +import win "core:sys/windows" + +import "vendor:sdl2" +import "vendor:wgpu" + +GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) + hwnd := cast(win.HWND)window_info.info.win.window + hinstance := win.GetModuleHandleW(nil) + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromMetalLayer{ + chain = wgpu.ChainedStruct{ + sType = .SurfaceDescriptorFromMetalLayer, + }, + hinstance = rawptr(hinstance), + hwnd = rawptr(hwnd), + }, + }, + ) +} \ No newline at end of file From a4296031955c53d7d21b2dc14876384299978ec2 Mon Sep 17 00:00:00 2001 From: Emir Date: Tue, 23 Jul 2024 20:39:09 +0300 Subject: [PATCH 02/10] Remove unused variable from example --- vendor/wgpu/examples/sdl2/main.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/vendor/wgpu/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin index 80cdeb7bd..c593e7c2d 100644 --- a/vendor/wgpu/examples/sdl2/main.odin +++ b/vendor/wgpu/examples/sdl2/main.odin @@ -11,7 +11,6 @@ import "vendor:wgpu/sdl2glue" State :: struct { ctx: runtime.Context, window: ^sdl2.Window, - running: bool, instance: wgpu.Instance, surface: wgpu.Surface, From e8e51db9ff5534226c5e51d6518497d5ba55ecb0 Mon Sep 17 00:00:00 2001 From: Emir Date: Tue, 23 Jul 2024 20:42:26 +0300 Subject: [PATCH 03/10] Update glue.odin --- vendor/wgpu/sdl2glue/glue.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/vendor/wgpu/sdl2glue/glue.odin b/vendor/wgpu/sdl2glue/glue.odin index 9da9a0738..f4deb28dc 100644 --- a/vendor/wgpu/sdl2glue/glue.odin +++ b/vendor/wgpu/sdl2glue/glue.odin @@ -1,4 +1,3 @@ -//+build !linux //+build !windows //+build !darwin package wgpu_sdl2_glue From f9ef951b22b582af3fc5a228525ba546695a3d78 Mon Sep 17 00:00:00 2001 From: Emir Date: Tue, 23 Jul 2024 22:39:50 +0300 Subject: [PATCH 04/10] Add `sdl2glue/glue_linux.odin` --- vendor/wgpu/sdl2glue/glue.odin | 1 + vendor/wgpu/sdl2glue/glue_linux.odin | 42 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 vendor/wgpu/sdl2glue/glue_linux.odin diff --git a/vendor/wgpu/sdl2glue/glue.odin b/vendor/wgpu/sdl2glue/glue.odin index f4deb28dc..9da9a0738 100644 --- a/vendor/wgpu/sdl2glue/glue.odin +++ b/vendor/wgpu/sdl2glue/glue.odin @@ -1,3 +1,4 @@ +//+build !linux //+build !windows //+build !darwin package wgpu_sdl2_glue diff --git a/vendor/wgpu/sdl2glue/glue_linux.odin b/vendor/wgpu/sdl2glue/glue_linux.odin new file mode 100644 index 000000000..222a4ebc7 --- /dev/null +++ b/vendor/wgpu/sdl2glue/glue_linux.odin @@ -0,0 +1,42 @@ +package wgpu_sdl2_glue + +import "vendor:sdl2" +import "vendor:wgpu" + +GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) + if window_info.subsystem == .WAYLAND { + display := window_info.info.wl.display + surface := window_info.info.wl.surface + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromWaylandSurface{ + chain = { + sType = .SurfaceDescriptorFromWaylandSurface, + }, + display = display, + surface = surface, + }, + }, + ) + } else if window_info.subsystem == .X11 { + display := window_info.info.x11.display + window := window_info.info.x11.window + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromXlibWindow{ + chain = { + sType = .SurfaceDescriptorFromXlibWindow, + }, + display = display, + window = u64(window), + }, + }, + ) + } else { + panic("wgpu sdl2 glue: unsupported platform, expected Wayland or X11") + } +} From 2a2bedc85ca811641a0087545f65c56f27f43a53 Mon Sep 17 00:00:00 2001 From: Emir Date: Wed, 24 Jul 2024 10:22:18 +0300 Subject: [PATCH 05/10] Fix indentation and add full example --- vendor/wgpu/examples/sdl2/Makefile | 17 +++++ vendor/wgpu/examples/sdl2/build.bat | 12 ++++ vendor/wgpu/examples/sdl2/main.odin | 65 ++++-------------- vendor/wgpu/examples/sdl2/os_js.odin | 60 ++++++++++++++++ vendor/wgpu/examples/sdl2/os_sdl2.odin | 87 ++++++++++++++++++++++++ vendor/wgpu/examples/sdl2/web/index.html | 23 +++++++ vendor/wgpu/sdl2glue/glue_darwin.odin | 18 ++--- vendor/wgpu/sdl2glue/glue_linux.odin | 66 +++++++++--------- vendor/wgpu/sdl2glue/glue_windows.odin | 26 +++---- 9 files changed, 266 insertions(+), 108 deletions(-) create mode 100644 vendor/wgpu/examples/sdl2/Makefile create mode 100644 vendor/wgpu/examples/sdl2/build.bat create mode 100644 vendor/wgpu/examples/sdl2/os_js.odin create mode 100644 vendor/wgpu/examples/sdl2/os_sdl2.odin create mode 100644 vendor/wgpu/examples/sdl2/web/index.html diff --git a/vendor/wgpu/examples/sdl2/Makefile b/vendor/wgpu/examples/sdl2/Makefile new file mode 100644 index 000000000..fdecdbb91 --- /dev/null +++ b/vendor/wgpu/examples/sdl2/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/examples/sdl2/build.bat b/vendor/wgpu/examples/sdl2/build.bat new file mode 100644 index 000000000..61afcbe66 --- /dev/null +++ b/vendor/wgpu/examples/sdl2/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/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin index c593e7c2d..646f04c40 100644 --- a/vendor/wgpu/examples/sdl2/main.odin +++ b/vendor/wgpu/examples/sdl2/main.odin @@ -4,13 +4,11 @@ import "base:runtime" import "core:fmt" -import "vendor:sdl2" import "vendor:wgpu" -import "vendor:wgpu/sdl2glue" State :: struct { ctx: runtime.Context, - window: ^sdl2.Window, + os: OS, instance: wgpu.Instance, surface: wgpu.Surface, @@ -29,32 +27,13 @@ state: State main :: proc() { state.ctx = context - sdl_flags := sdl2.InitFlags{.VIDEO, .JOYSTICK, .GAMECONTROLLER, .EVENTS} - if res := sdl2.Init(sdl_flags); res != 0 { - fmt.eprintf("ERROR: Failed to initialize SDL: [%s]\n", sdl2.GetError()) - return - } - - window_flags: sdl2.WindowFlags = {.SHOWN, .ALLOW_HIGHDPI, .RESIZABLE} - state.window = sdl2.CreateWindow( - "wgpu triangle", - sdl2.WINDOWPOS_CENTERED, - sdl2.WINDOWPOS_CENTERED, - 800, - 600, - window_flags, - ) - if state.window == nil { - fmt.eprintf("ERROR: Failed to create the SDL Window: [%s]\n", sdl2.GetError()) - return - } + os_init(&state.os) state.instance = wgpu.CreateInstance(nil) if state.instance == nil { panic("WebGPU is not supported") } - - state.surface = sdl2glue.GetSurface(state.instance, state.window) + state.surface = os_get_surface(&state.os, state.instance) wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, on_adapter, nil) @@ -135,37 +114,17 @@ main :: proc() { }, }) - now := sdl2.GetPerformanceCounter() - last : u64 = 0 - dt: f32 = 0 - main_loop: for { - last = now - now := sdl2.GetPerformanceCounter() - dt = auto_cast((now - last)*1000 / sdl2.GetPerformanceFrequency()) - - e: sdl2.Event - - for sdl2.PollEvent(&e) { - #partial switch (e.type) { - case .QUIT: - break main_loop - - case .WINDOWEVENT: - #partial switch (e.window.event) { - case .SIZE_CHANGED: - case .RESIZED: - state.config.width = cast(u32)e.window.data1 - state.config.height = cast(u32)e.window.data2 - wgpu.SurfaceConfigure(state.surface, &state.config) - } - } - } - - frame(dt) - } + 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 @@ -178,7 +137,7 @@ frame :: proc "c" (dt: f32) { if surface_texture.texture != nil { wgpu.TextureRelease(surface_texture.texture) } - // todo - resize() + resize() return case .OutOfMemory, .DeviceLost: // Fatal error diff --git a/vendor/wgpu/examples/sdl2/os_js.odin b/vendor/wgpu/examples/sdl2/os_js.odin new file mode 100644 index 000000000..9634f4afe --- /dev/null +++ b/vendor/wgpu/examples/sdl2/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/examples/sdl2/os_sdl2.odin b/vendor/wgpu/examples/sdl2/os_sdl2.odin new file mode 100644 index 000000000..bc48fd353 --- /dev/null +++ b/vendor/wgpu/examples/sdl2/os_sdl2.odin @@ -0,0 +1,87 @@ +//+build !js +package vendor_wgpu_example_triangle + +import "core:c" +import "core:fmt" + +import "vendor:sdl2" +import "vendor:wgpu" +import "vendor:wgpu/sdl2glue" + +OS :: struct { + window: ^sdl2.Window, +} + +os_init :: proc(os: ^OS) { + sdl_flags := sdl2.InitFlags{.VIDEO, .JOYSTICK, .GAMECONTROLLER, .EVENTS} + if res := sdl2.Init(sdl_flags); res != 0 { + fmt.eprintfln("ERROR: Failed to initialize SDL: [%s]", sdl2.GetError()) + return + } + + window_flags: sdl2.WindowFlags = {.SHOWN, .ALLOW_HIGHDPI, .RESIZABLE} + os.window = sdl2.CreateWindow( + "wgpu triangle", + sdl2.WINDOWPOS_CENTERED, + sdl2.WINDOWPOS_CENTERED, + 800, + 600, + window_flags, + ) + if os.window == nil { + fmt.eprintfln("ERROR: Failed to create the SDL Window: [%s]", sdl2.GetError()) + return + } + + sdl2.AddEventWatch(size_callback, nil) +} + +os_run :: proc(os: ^OS) { + now := sdl2.GetPerformanceCounter() + last : u64 + dt: f32 + main_loop: for { + last = now + now = sdl2.GetPerformanceCounter() + dt = f32((now - last) * 1000) / f32(sdl2.GetPerformanceFrequency()) + + e: sdl2.Event + + for sdl2.PollEvent(&e) { + #partial switch (e.type) { + case .QUIT: + break main_loop + } + } + + frame(dt) + } + + sdl2.DestroyWindow(os.window) + sdl2.Quit() + + finish() +} + + +os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) { + iw, ih: c.int + sdl2.GetWindowSize(os.window, &iw, &ih) + return u32(iw), u32(ih) +} + +os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { + return sdl2glue.GetSurface(instance, os.window) +} + +@(private="file") +size_callback :: proc "c" (userdata: rawptr, event: ^sdl2.Event) -> c.int { + + if event.type == .WINDOWEVENT { + if event.window.event == .SIZE_CHANGED || event.window.event == .RESIZED { + resize() + } + } + + return 0 +} diff --git a/vendor/wgpu/examples/sdl2/web/index.html b/vendor/wgpu/examples/sdl2/web/index.html new file mode 100644 index 000000000..61872e35a --- /dev/null +++ b/vendor/wgpu/examples/sdl2/web/index.html @@ -0,0 +1,23 @@ + + + + + + WGPU WASM Triangle + + + + + + + + + diff --git a/vendor/wgpu/sdl2glue/glue_darwin.odin b/vendor/wgpu/sdl2glue/glue_darwin.odin index 6c962f714..ba52f8824 100644 --- a/vendor/wgpu/sdl2glue/glue_darwin.odin +++ b/vendor/wgpu/sdl2glue/glue_darwin.odin @@ -6,14 +6,14 @@ import CA "vendor:darwin/QuartzCore" import NS "core:sys/darwin/Foundation" GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { - window_info: sdl2.SysWMinfo - sdl2.GetWindowWMInfo(window, &window_info) - ns_window := cast(^NS.Window)window_info.info.cocoa.window - metal_layer := CA.MetalLayer_layer() - ns_window->contentView()->setLayer(metal_layer) - return wgpu.InstanceCreateSurface( - instance, - &wgpu.SurfaceDescriptor{ + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) + ns_window := cast(^NS.Window)window_info.info.cocoa.window + 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, @@ -21,5 +21,5 @@ GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surfac layer = rawptr(metal_layer), }, }, - ) + ) } \ No newline at end of file diff --git a/vendor/wgpu/sdl2glue/glue_linux.odin b/vendor/wgpu/sdl2glue/glue_linux.odin index 222a4ebc7..b01df251a 100644 --- a/vendor/wgpu/sdl2glue/glue_linux.odin +++ b/vendor/wgpu/sdl2glue/glue_linux.odin @@ -4,39 +4,39 @@ import "vendor:sdl2" import "vendor:wgpu" GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { - window_info: sdl2.SysWMinfo - sdl2.GetWindowWMInfo(window, &window_info) + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) if window_info.subsystem == .WAYLAND { - display := window_info.info.wl.display - surface := window_info.info.wl.surface - return wgpu.InstanceCreateSurface( - instance, - &wgpu.SurfaceDescriptor{ - nextInChain = &wgpu.SurfaceDescriptorFromWaylandSurface{ - chain = { - sType = .SurfaceDescriptorFromWaylandSurface, - }, - display = display, - surface = surface, - }, - }, - ) + display := window_info.info.wl.display + surface := window_info.info.wl.surface + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromWaylandSurface{ + chain = { + sType = .SurfaceDescriptorFromWaylandSurface, + }, + display = display, + surface = surface, + }, + }, + ) } else if window_info.subsystem == .X11 { - display := window_info.info.x11.display - window := window_info.info.x11.window - return wgpu.InstanceCreateSurface( - instance, - &wgpu.SurfaceDescriptor{ - nextInChain = &wgpu.SurfaceDescriptorFromXlibWindow{ - chain = { - sType = .SurfaceDescriptorFromXlibWindow, - }, - display = display, - window = u64(window), - }, - }, - ) - } else { - panic("wgpu sdl2 glue: unsupported platform, expected Wayland or X11") - } + display := window_info.info.x11.display + window := window_info.info.x11.window + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromXlibWindow{ + chain = { + sType = .SurfaceDescriptorFromXlibWindow, + }, + display = display, + window = u64(window), + }, + }, + ) + } else { + panic("wgpu sdl2 glue: unsupported platform, expected Wayland or X11") + } } diff --git a/vendor/wgpu/sdl2glue/glue_windows.odin b/vendor/wgpu/sdl2glue/glue_windows.odin index 4bd30d452..a2b1437ab 100644 --- a/vendor/wgpu/sdl2glue/glue_windows.odin +++ b/vendor/wgpu/sdl2glue/glue_windows.odin @@ -2,24 +2,24 @@ package wgpu_sdl2_glue import win "core:sys/windows" -import "vendor:sdl2" -import "vendor:wgpu" +import "vendor:sdl2" +import "vendor:wgpu" GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { - window_info: sdl2.SysWMinfo - sdl2.GetWindowWMInfo(window, &window_info) - hwnd := cast(win.HWND)window_info.info.win.window - hinstance := win.GetModuleHandleW(nil) - return wgpu.InstanceCreateSurface( - instance, - &wgpu.SurfaceDescriptor{ - nextInChain = &wgpu.SurfaceDescriptorFromMetalLayer{ + window_info: sdl2.SysWMinfo + sdl2.GetWindowWMInfo(window, &window_info) + hwnd := window_info.info.win.window + hinstance := win.GetModuleHandleW(nil) + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromWindowsHWND{ chain = wgpu.ChainedStruct{ - sType = .SurfaceDescriptorFromMetalLayer, + sType = .SurfaceDescriptorFromWindowsHWND, }, hinstance = rawptr(hinstance), hwnd = rawptr(hwnd), }, }, - ) -} \ No newline at end of file + ) +} From 95412df129fa3c6b19d5597b0aee78afcaa32340 Mon Sep 17 00:00:00 2001 From: Emir Date: Wed, 24 Jul 2024 10:27:00 +0300 Subject: [PATCH 06/10] Add newline to glue_darwin.odin --- vendor/wgpu/sdl2glue/glue_darwin.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/wgpu/sdl2glue/glue_darwin.odin b/vendor/wgpu/sdl2glue/glue_darwin.odin index ba52f8824..c48b8488c 100644 --- a/vendor/wgpu/sdl2glue/glue_darwin.odin +++ b/vendor/wgpu/sdl2glue/glue_darwin.odin @@ -22,4 +22,4 @@ GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surfac }, }, ) -} \ No newline at end of file +} From 57dc6c2e94473ec45ad6a8980e359fcd9cb8c409 Mon Sep 17 00:00:00 2001 From: Emir Date: Wed, 24 Jul 2024 10:27:22 +0300 Subject: [PATCH 07/10] Update os_sdl2.odin --- vendor/wgpu/examples/sdl2/os_sdl2.odin | 2 -- 1 file changed, 2 deletions(-) diff --git a/vendor/wgpu/examples/sdl2/os_sdl2.odin b/vendor/wgpu/examples/sdl2/os_sdl2.odin index bc48fd353..bbcec9923 100644 --- a/vendor/wgpu/examples/sdl2/os_sdl2.odin +++ b/vendor/wgpu/examples/sdl2/os_sdl2.odin @@ -76,12 +76,10 @@ os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { @(private="file") size_callback :: proc "c" (userdata: rawptr, event: ^sdl2.Event) -> c.int { - if event.type == .WINDOWEVENT { if event.window.event == .SIZE_CHANGED || event.window.event == .RESIZED { resize() } } - return 0 } From ba81a81ca8ada09a896a1a8fa3818d8b0c09be62 Mon Sep 17 00:00:00 2001 From: Emir Date: Wed, 24 Jul 2024 10:29:34 +0300 Subject: [PATCH 08/10] Update os_sdl2.odin --- vendor/wgpu/examples/sdl2/os_sdl2.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/wgpu/examples/sdl2/os_sdl2.odin b/vendor/wgpu/examples/sdl2/os_sdl2.odin index bbcec9923..0e6c5b57a 100644 --- a/vendor/wgpu/examples/sdl2/os_sdl2.odin +++ b/vendor/wgpu/examples/sdl2/os_sdl2.odin @@ -21,11 +21,11 @@ os_init :: proc(os: ^OS) { window_flags: sdl2.WindowFlags = {.SHOWN, .ALLOW_HIGHDPI, .RESIZABLE} os.window = sdl2.CreateWindow( - "wgpu triangle", + "WGPU Native Triangle", sdl2.WINDOWPOS_CENTERED, sdl2.WINDOWPOS_CENTERED, - 800, - 600, + 960, + 540, window_flags, ) if os.window == nil { From c98bb7da39b2acdfe1dc5a3426102ed27944b358 Mon Sep 17 00:00:00 2001 From: Emir Date: Wed, 24 Jul 2024 10:33:34 +0300 Subject: [PATCH 09/10] Update README.md --- vendor/wgpu/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/vendor/wgpu/README.md b/vendor/wgpu/README.md index 59b31567f..8b2c95b5e 100644 --- a/vendor/wgpu/README.md +++ b/vendor/wgpu/README.md @@ -37,13 +37,20 @@ 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`. +It exports one procedure `GetSurface(wgpu.Instance, glfw.WindowHandle) -> wgpu.Surface`. The procedure will call the needed target specific procedures and return a surface configured for the given window. 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. +## SDL2 Glue + +There is an inner package `sdl2glue` that can be used to glue together WGPU and SDL2. +It exports one procedure `GetSurface(wgpu.Instance, ^sdl2.Window) -> wgpu.Surface`. +The procedure will call the needed target specific procedures and return a surface configured +for the given window. + ### Wayland GLFW supports Wayland from version 3.4 onwards and only if it is compiled with `-DGLFW_EXPOSE_NATIVE_WAYLAND`. From e55d09bdfac42a512863342193b68de508f26c51 Mon Sep 17 00:00:00 2001 From: Emir <60936780+elvodqa@users.noreply.github.com> Date: Fri, 2 Aug 2024 18:04:36 +0300 Subject: [PATCH 10/10] Update vendor/wgpu/examples/sdl2/main.odin Co-authored-by: Laytan --- vendor/wgpu/examples/sdl2/main.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/wgpu/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin index 646f04c40..3d79346d0 100644 --- a/vendor/wgpu/examples/sdl2/main.odin +++ b/vendor/wgpu/examples/sdl2/main.odin @@ -53,7 +53,7 @@ main :: proc() { } state.device = device - width, height : u32 = 800, 600 // os_get_render_bounds(&state.os) + width, height := os_get_render_bounds(&state.os) state.config = wgpu.SurfaceConfiguration { device = state.device,