diff --git a/draw/README.md b/draw/README.md index e6a3d8a..5f9225a 100644 --- a/draw/README.md +++ b/draw/README.md @@ -555,3 +555,26 @@ odin run meta -- gen-shaders ``` Requires `glslangValidator` and `spirv-cross` on PATH. + +### Shader format selection + +The library embeds shader bytecode per compile target — MSL + `main0` entry point on Darwin (via +`spirv-cross --msl`, which renames `main` because it is reserved in Metal), SPIR-V + `main` entry +point elsewhere. Three compile-time constants in `draw.odin` expose the build's shader configuration: + +| Constant | Type | Darwin | Other | +| ----------------------------- | ------------------------- | --------- | ---------- | +| `PLATFORM_SHADER_FORMAT_FLAG` | `sdl.GPUShaderFormatFlag` | `.MSL` | `.SPIRV` | +| `PLATFORM_SHADER_FORMAT` | `sdl.GPUShaderFormat` | `{.MSL}` | `{.SPIRV}` | +| `SHADER_ENTRY` | `cstring` | `"main0"` | `"main"` | + +Pass `PLATFORM_SHADER_FORMAT` to `sdl.CreateGPUDevice` so SDL selects a backend compatible with the +embedded bytecode: + +``` +gpu := sdl.CreateGPUDevice(draw.PLATFORM_SHADER_FORMAT, true, nil) +``` + +At init time the library calls `sdl.GetGPUShaderFormats(device)` to verify the active backend +accepts `PLATFORM_SHADER_FORMAT_FLAG`. If it does not, `draw.init` returns `false` with a +descriptive log message showing both the embedded and active format sets. diff --git a/draw/draw.odin b/draw/draw.odin index 66dc384..0ed28b0 100644 --- a/draw/draw.odin +++ b/draw/draw.odin @@ -11,12 +11,17 @@ import sdl_ttf "vendor:sdl3/ttf" import clay "../vendor/clay" when ODIN_OS == .Darwin { - SHADER_TYPE :: sdl.GPUShaderFormat{.MSL} - ENTRY_POINT :: "main0" + PLATFORM_SHADER_FORMAT_FLAG :: sdl.GPUShaderFormatFlag.MSL + SHADER_ENTRY :: cstring("main0") + BASE_VERT_2D_RAW :: #load("shaders/generated/base_2d.vert.metal") + BASE_FRAG_2D_RAW :: #load("shaders/generated/base_2d.frag.metal") } else { - SHADER_TYPE :: sdl.GPUShaderFormat{.SPIRV} - ENTRY_POINT :: "main" + PLATFORM_SHADER_FORMAT_FLAG :: sdl.GPUShaderFormatFlag.SPIRV + SHADER_ENTRY :: cstring("main") + BASE_VERT_2D_RAW :: #load("shaders/generated/base_2d.vert.spv") + BASE_FRAG_2D_RAW :: #load("shaders/generated/base_2d.frag.spv") } +PLATFORM_SHADER_FORMAT :: sdl.GPUShaderFormat{PLATFORM_SHADER_FORMAT_FLAG} BUFFER_INIT_SIZE :: 256 INITIAL_LAYER_SIZE :: 5 @@ -367,11 +372,7 @@ prepare_text :: proc(layer: ^Layer, text: Text) { uv := data.uv[i] append( &GLOB.tmp_text_verts, - Vertex { - position = {pos.x + base_x, -pos.y + base_y}, - uv = {uv.x, uv.y}, - color = text.color, - }, + Vertex{position = {pos.x + base_x, -pos.y + base_y}, uv = {uv.x, uv.y}, color = text.color}, ) } diff --git a/draw/examples/hellope.odin b/draw/examples/hellope.odin index d90aee8..08026da 100644 --- a/draw/examples/hellope.odin +++ b/draw/examples/hellope.odin @@ -12,7 +12,7 @@ JETBRAINS_MONO_REGULAR: draw.Font_Id = max(draw.Font_Id) // Max so we crash if r hellope_shapes :: proc() { if !sdl.Init({.VIDEO}) do os.exit(1) window := sdl.CreateWindow("Hellope!", 500, 500, {.HIGH_PIXEL_DENSITY}) - gpu := sdl.CreateGPUDevice({.MSL}, true, nil) + gpu := sdl.CreateGPUDevice(draw.PLATFORM_SHADER_FORMAT, true, nil) if !sdl.ClaimWindowForGPUDevice(gpu, window) do os.exit(1) if !draw.init(gpu, window) do os.exit(1) @@ -116,7 +116,7 @@ hellope_text :: proc() { if !sdl.Init({.VIDEO}) do os.exit(1) window := sdl.CreateWindow("Hellope!", 600, 600, {.HIGH_PIXEL_DENSITY}) - gpu := sdl.CreateGPUDevice({.MSL}, true, nil) + gpu := sdl.CreateGPUDevice(draw.PLATFORM_SHADER_FORMAT, true, nil) if !sdl.ClaimWindowForGPUDevice(gpu, window) do os.exit(1) if !draw.init(gpu, window) do os.exit(1) JETBRAINS_MONO_REGULAR = draw.register_font(JETBRAINS_MONO_REGULAR_RAW) @@ -206,7 +206,7 @@ hellope_text :: proc() { hellope_clay :: proc() { if !sdl.Init({.VIDEO}) do os.exit(1) window := sdl.CreateWindow("Hellope!", 500, 500, {.HIGH_PIXEL_DENSITY}) - gpu := sdl.CreateGPUDevice({.MSL}, true, nil) + gpu := sdl.CreateGPUDevice(draw.PLATFORM_SHADER_FORMAT, true, nil) if !sdl.ClaimWindowForGPUDevice(gpu, window) do os.exit(1) if !draw.init(gpu, window) do os.exit(1) JETBRAINS_MONO_REGULAR = draw.register_font(JETBRAINS_MONO_REGULAR_RAW) @@ -250,7 +250,7 @@ hellope_clay :: proc() { hellope_custom :: proc() { if !sdl.Init({.VIDEO}) do os.exit(1) window := sdl.CreateWindow("Hellope Custom!", 600, 400, {.HIGH_PIXEL_DENSITY}) - gpu := sdl.CreateGPUDevice({.MSL}, true, nil) + gpu := sdl.CreateGPUDevice(draw.PLATFORM_SHADER_FORMAT, true, nil) if !sdl.ClaimWindowForGPUDevice(gpu, window) do os.exit(1) if !draw.init(gpu, window) do os.exit(1) JETBRAINS_MONO_REGULAR = draw.register_font(JETBRAINS_MONO_REGULAR_RAW) diff --git a/draw/pipeline_2d_base.odin b/draw/pipeline_2d_base.odin index 80b4cd3..7b27ca2 100644 --- a/draw/pipeline_2d_base.odin +++ b/draw/pipeline_2d_base.odin @@ -144,32 +144,34 @@ create_pipeline_2d_base :: proc( if pipeline.sdl_pipeline != nil do sdl.ReleaseGPUGraphicsPipeline(device, pipeline.sdl_pipeline) } - when ODIN_OS == .Darwin { - base_2d_vert_raw := #load("shaders/generated/base_2d.vert.metal") - base_2d_frag_raw := #load("shaders/generated/base_2d.frag.metal") - } else { - base_2d_vert_raw := #load("shaders/generated/base_2d.vert.spv") - base_2d_frag_raw := #load("shaders/generated/base_2d.frag.spv") + active_shader_formats := sdl.GetGPUShaderFormats(device) + if PLATFORM_SHADER_FORMAT_FLAG not_in active_shader_formats { + log.errorf( + "draw: no embedded shader matches active GPU formats; this build supports %v but device reports %v", + PLATFORM_SHADER_FORMAT, + active_shader_formats, + ) + return pipeline, false } - log.debug("Loaded", len(base_2d_vert_raw), "vert bytes") - log.debug("Loaded", len(base_2d_frag_raw), "frag bytes") + log.debug("Loaded", len(BASE_VERT_2D_RAW), "vert bytes") + log.debug("Loaded", len(BASE_FRAG_2D_RAW), "frag bytes") vert_info := sdl.GPUShaderCreateInfo { - code_size = len(base_2d_vert_raw), - code = raw_data(base_2d_vert_raw), - entrypoint = ENTRY_POINT, - format = SHADER_TYPE, + code_size = len(BASE_VERT_2D_RAW), + code = raw_data(BASE_VERT_2D_RAW), + entrypoint = SHADER_ENTRY, + format = {PLATFORM_SHADER_FORMAT_FLAG}, stage = .VERTEX, num_uniform_buffers = 1, num_storage_buffers = 1, } frag_info := sdl.GPUShaderCreateInfo { - code_size = len(base_2d_frag_raw), - code = raw_data(base_2d_frag_raw), - entrypoint = ENTRY_POINT, - format = SHADER_TYPE, + code_size = len(BASE_FRAG_2D_RAW), + code = raw_data(BASE_FRAG_2D_RAW), + entrypoint = SHADER_ENTRY, + format = {PLATFORM_SHADER_FORMAT_FLAG}, stage = .FRAGMENT, num_samplers = 1, }