diff --git a/.gitignore b/.gitignore index afcc94f..651dd90 100644 --- a/.gitignore +++ b/.gitignore @@ -6,9 +6,6 @@ daemon/build/ daemon/dev/ daemon/META-INF/ -# Compiled shaders -client/odin/shaders/compiled/ - # Odin build output /odin client/odin/odin diff --git a/README.md b/README.md index a0fe970..591f7fb 100644 --- a/README.md +++ b/README.md @@ -76,13 +76,13 @@ Gradle workspace import records module source roots, test source roots, resource Use `Ctrl+Shift+T` to toggle Gradle tasks in the right sidebar. Use Up/Down, PageUp/PageDown, Home/End, mouse wheel, or row clicks to select tasks, and Enter to run the selected task; the sidebar shows the loaded task count and reports started/finished/failed events, the final response, and recent stdout/stderr output. -Compile starter SDL3 GPU shaders with: +The SDL3 GPU shaders are compiled to SPIR-V under `client/odin/shaders/compiled/` and embedded into the client binary at build time, so the editor has no runtime shader files to find. The compiled files are committed; after editing the GLSL sources, regenerate them with: ```sh scripts/compile-shaders.sh ``` -The script uses `glslc` from shaderc and emits Vulkan/SPIR-V files under `client/odin/shaders/compiled/`. On Fedora, install it with `sudo dnf install glslc`. +The script uses `glslc` from shaderc. On Fedora, install it with `sudo dnf install glslc`. Run autonomous opencode continuation loops with: diff --git a/client/odin/gpu_renderer.odin b/client/odin/gpu_renderer.odin index 6a4c613..945948b 100644 --- a/client/odin/gpu_renderer.odin +++ b/client/odin/gpu_renderer.odin @@ -47,6 +47,14 @@ GPU_Renderer :: struct { height: int, } +// Compiled SPIR-V is embedded at build time so the binary never depends on +// finding shader files at runtime. Regenerate with scripts/compile-shaders.sh +// after editing the GLSL sources, then rebuild. +GPU_RECT_VERT_SPV :: #load("shaders/compiled/rect.vert.spv") +GPU_RECT_FRAG_SPV :: #load("shaders/compiled/rect.frag.spv") +GPU_TEXT_VERT_SPV :: #load("shaders/compiled/text.vert.spv") +GPU_TEXT_FRAG_SPV :: #load("shaders/compiled/text.frag.spv") + GPU_MAX_VERTICES :: 240000 GPU_MAX_TEXT_VERTICES :: 120000 GPU_FONT_ATLAS_SIZE :: 512 @@ -83,12 +91,12 @@ gpu_renderer_make :: proc(window: ^SDL.Window) -> GPU_Renderer { return GPU_Renderer{} } - gpu.vertex_shader = gpu_create_shader(gpu.device, "client/odin/shaders/compiled/rect.vert.spv", .VERTEX) - gpu.fragment_shader = gpu_create_shader(gpu.device, "client/odin/shaders/compiled/rect.frag.spv", .FRAGMENT) - gpu.text_vertex_shader = gpu_create_shader(gpu.device, "client/odin/shaders/compiled/text.vert.spv", .VERTEX) - gpu.text_fragment_shader = gpu_create_shader(gpu.device, "client/odin/shaders/compiled/text.frag.spv", .FRAGMENT) + gpu.vertex_shader = gpu_create_shader(gpu.device, "rect.vert", GPU_RECT_VERT_SPV, .VERTEX, 0) + gpu.fragment_shader = gpu_create_shader(gpu.device, "rect.frag", GPU_RECT_FRAG_SPV, .FRAGMENT, 0) + gpu.text_vertex_shader = gpu_create_shader(gpu.device, "text.vert", GPU_TEXT_VERT_SPV, .VERTEX, 0) + gpu.text_fragment_shader = gpu_create_shader(gpu.device, "text.frag", GPU_TEXT_FRAG_SPV, .FRAGMENT, 1) if gpu.vertex_shader == nil || gpu.fragment_shader == nil || gpu.text_vertex_shader == nil || gpu.text_fragment_shader == nil { - fmt.println("SDL GPU shaders unavailable; run scripts/compile-shaders.sh") + fmt.println("SDL GPU shader creation failed, falling back:", SDL.GetError()) gpu_renderer_destroy(&gpu) return GPU_Renderer{} } @@ -222,25 +230,18 @@ gpu_renderer_destroy :: proc(gpu: ^GPU_Renderer) { gpu^ = {} } -gpu_create_shader :: proc(device: ^SDL.GPUDevice, path: string, stage: SDL.GPUShaderStage) -> ^SDL.GPUShader { - bytes, err := os.read_entire_file(path, context.allocator) - if err != nil { - fmt.println("read shader failed:", path, err) - return nil - } - defer delete(bytes) - +gpu_create_shader :: proc(device: ^SDL.GPUDevice, name: string, code: []u8, stage: SDL.GPUShaderStage, num_samplers: u32) -> ^SDL.GPUShader { shader := SDL.CreateGPUShader(device, { - code_size = len(bytes), - code = raw_data(bytes), + code_size = len(code), + code = raw_data(code), entrypoint = "main", format = {.SPIRV}, stage = stage, num_uniform_buffers = 1 if stage == .VERTEX else 0, - num_samplers = 1 if stage == .FRAGMENT && strings_has_suffix(path, "text.frag.spv") else 0, + num_samplers = num_samplers, }) if shader == nil { - fmt.println("CreateGPUShader failed:", path, SDL.GetError()) + fmt.println("CreateGPUShader failed:", name, SDL.GetError()) } return shader } @@ -545,11 +546,6 @@ gpu_global_font_advance :: proc(ch: u8) -> f32 { return 8 } -strings_has_suffix :: proc(s, suffix: string) -> bool { - if len(suffix) > len(s) do return false - return s[len(s) - len(suffix):] == suffix -} - color_f32 :: proc(r, g, b, a: u8) -> [4]f32 { return {f32(r) / 255.0, f32(g) / 255.0, f32(b) / 255.0, f32(a) / 255.0} } diff --git a/client/odin/shaders/compiled/rect.frag.spv b/client/odin/shaders/compiled/rect.frag.spv new file mode 100644 index 0000000..86ea3d5 Binary files /dev/null and b/client/odin/shaders/compiled/rect.frag.spv differ diff --git a/client/odin/shaders/compiled/rect.vert.spv b/client/odin/shaders/compiled/rect.vert.spv new file mode 100644 index 0000000..bbce493 Binary files /dev/null and b/client/odin/shaders/compiled/rect.vert.spv differ diff --git a/client/odin/shaders/compiled/text.frag.spv b/client/odin/shaders/compiled/text.frag.spv new file mode 100644 index 0000000..2496ea5 Binary files /dev/null and b/client/odin/shaders/compiled/text.frag.spv differ diff --git a/client/odin/shaders/compiled/text.vert.spv b/client/odin/shaders/compiled/text.vert.spv new file mode 100644 index 0000000..c49d649 Binary files /dev/null and b/client/odin/shaders/compiled/text.vert.spv differ diff --git a/docs/shader-toolchain.md b/docs/shader-toolchain.md index 885c2f2..e08ae5a 100644 --- a/docs/shader-toolchain.md +++ b/docs/shader-toolchain.md @@ -12,7 +12,7 @@ For this Linux-first prototype, use GLSL compiled to SPIR-V with `glslc` from sh scripts/compile-shaders.sh ``` -Outputs are written to `client/odin/shaders/compiled/` and intentionally ignored by git. +Outputs are written to `client/odin/shaders/compiled/` and are committed to git: the Odin client embeds them at compile time with `#load`, so they must exist to build. After editing the GLSL sources, rerun the script and rebuild the client. Fedora install: @@ -34,7 +34,8 @@ Current recommendation: Current renderer state: -- The editor loads `rect.vert.spv` and `rect.frag.spv` for the direct SDL3 GPU path. -- The editor loads `text.vert.spv` and `text.frag.spv` for font-atlas text. +- The editor embeds `rect.vert.spv` and `rect.frag.spv` for the direct SDL3 GPU path. +- The editor embeds `text.vert.spv` and `text.frag.spv` for font-atlas text. +- The binary has no runtime dependency on the shader files; they are baked in at build time. - Text is rendered from a baked `stb_truetype` atlas using `/usr/share/fonts/google-noto/NotoSansMono-Regular.ttf`. - A later portability step should bundle a project font or add configurable font discovery.