Platform checks

This commit is contained in:
Zachary Levy
2026-04-20 10:08:06 -07:00
parent 90fba74243
commit 1e2c2936a8
4 changed files with 55 additions and 29 deletions

View File

@@ -555,3 +555,26 @@ odin run meta -- gen-shaders
``` ```
Requires `glslangValidator` and `spirv-cross` on PATH. 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.

View File

@@ -11,12 +11,17 @@ import sdl_ttf "vendor:sdl3/ttf"
import clay "../vendor/clay" import clay "../vendor/clay"
when ODIN_OS == .Darwin { when ODIN_OS == .Darwin {
SHADER_TYPE :: sdl.GPUShaderFormat{.MSL} PLATFORM_SHADER_FORMAT_FLAG :: sdl.GPUShaderFormatFlag.MSL
ENTRY_POINT :: "main0" 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 { } else {
SHADER_TYPE :: sdl.GPUShaderFormat{.SPIRV} PLATFORM_SHADER_FORMAT_FLAG :: sdl.GPUShaderFormatFlag.SPIRV
ENTRY_POINT :: "main" 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 BUFFER_INIT_SIZE :: 256
INITIAL_LAYER_SIZE :: 5 INITIAL_LAYER_SIZE :: 5
@@ -367,11 +372,7 @@ prepare_text :: proc(layer: ^Layer, text: Text) {
uv := data.uv[i] uv := data.uv[i]
append( append(
&GLOB.tmp_text_verts, &GLOB.tmp_text_verts,
Vertex { Vertex{position = {pos.x + base_x, -pos.y + base_y}, uv = {uv.x, uv.y}, color = text.color},
position = {pos.x + base_x, -pos.y + base_y},
uv = {uv.x, uv.y},
color = text.color,
},
) )
} }

View File

@@ -12,7 +12,7 @@ JETBRAINS_MONO_REGULAR: draw.Font_Id = max(draw.Font_Id) // Max so we crash if r
hellope_shapes :: proc() { hellope_shapes :: proc() {
if !sdl.Init({.VIDEO}) do os.exit(1) if !sdl.Init({.VIDEO}) do os.exit(1)
window := sdl.CreateWindow("Hellope!", 500, 500, {.HIGH_PIXEL_DENSITY}) 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 !sdl.ClaimWindowForGPUDevice(gpu, window) do os.exit(1)
if !draw.init(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) if !sdl.Init({.VIDEO}) do os.exit(1)
window := sdl.CreateWindow("Hellope!", 600, 600, {.HIGH_PIXEL_DENSITY}) 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 !sdl.ClaimWindowForGPUDevice(gpu, window) do os.exit(1)
if !draw.init(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) JETBRAINS_MONO_REGULAR = draw.register_font(JETBRAINS_MONO_REGULAR_RAW)
@@ -206,7 +206,7 @@ hellope_text :: proc() {
hellope_clay :: proc() { hellope_clay :: proc() {
if !sdl.Init({.VIDEO}) do os.exit(1) if !sdl.Init({.VIDEO}) do os.exit(1)
window := sdl.CreateWindow("Hellope!", 500, 500, {.HIGH_PIXEL_DENSITY}) 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 !sdl.ClaimWindowForGPUDevice(gpu, window) do os.exit(1)
if !draw.init(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) JETBRAINS_MONO_REGULAR = draw.register_font(JETBRAINS_MONO_REGULAR_RAW)
@@ -250,7 +250,7 @@ hellope_clay :: proc() {
hellope_custom :: proc() { hellope_custom :: proc() {
if !sdl.Init({.VIDEO}) do os.exit(1) if !sdl.Init({.VIDEO}) do os.exit(1)
window := sdl.CreateWindow("Hellope Custom!", 600, 400, {.HIGH_PIXEL_DENSITY}) 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 !sdl.ClaimWindowForGPUDevice(gpu, window) do os.exit(1)
if !draw.init(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) JETBRAINS_MONO_REGULAR = draw.register_font(JETBRAINS_MONO_REGULAR_RAW)

View File

@@ -144,32 +144,34 @@ create_pipeline_2d_base :: proc(
if pipeline.sdl_pipeline != nil do sdl.ReleaseGPUGraphicsPipeline(device, pipeline.sdl_pipeline) if pipeline.sdl_pipeline != nil do sdl.ReleaseGPUGraphicsPipeline(device, pipeline.sdl_pipeline)
} }
when ODIN_OS == .Darwin { active_shader_formats := sdl.GetGPUShaderFormats(device)
base_2d_vert_raw := #load("shaders/generated/base_2d.vert.metal") if PLATFORM_SHADER_FORMAT_FLAG not_in active_shader_formats {
base_2d_frag_raw := #load("shaders/generated/base_2d.frag.metal") log.errorf(
} else { "draw: no embedded shader matches active GPU formats; this build supports %v but device reports %v",
base_2d_vert_raw := #load("shaders/generated/base_2d.vert.spv") PLATFORM_SHADER_FORMAT,
base_2d_frag_raw := #load("shaders/generated/base_2d.frag.spv") active_shader_formats,
)
return pipeline, false
} }
log.debug("Loaded", len(base_2d_vert_raw), "vert bytes") log.debug("Loaded", len(BASE_VERT_2D_RAW), "vert bytes")
log.debug("Loaded", len(base_2d_frag_raw), "frag bytes") log.debug("Loaded", len(BASE_FRAG_2D_RAW), "frag bytes")
vert_info := sdl.GPUShaderCreateInfo { vert_info := sdl.GPUShaderCreateInfo {
code_size = len(base_2d_vert_raw), code_size = len(BASE_VERT_2D_RAW),
code = raw_data(base_2d_vert_raw), code = raw_data(BASE_VERT_2D_RAW),
entrypoint = ENTRY_POINT, entrypoint = SHADER_ENTRY,
format = SHADER_TYPE, format = {PLATFORM_SHADER_FORMAT_FLAG},
stage = .VERTEX, stage = .VERTEX,
num_uniform_buffers = 1, num_uniform_buffers = 1,
num_storage_buffers = 1, num_storage_buffers = 1,
} }
frag_info := sdl.GPUShaderCreateInfo { frag_info := sdl.GPUShaderCreateInfo {
code_size = len(base_2d_frag_raw), code_size = len(BASE_FRAG_2D_RAW),
code = raw_data(base_2d_frag_raw), code = raw_data(BASE_FRAG_2D_RAW),
entrypoint = ENTRY_POINT, entrypoint = SHADER_ENTRY,
format = SHADER_TYPE, format = {PLATFORM_SHADER_FORMAT_FLAG},
stage = .FRAGMENT, stage = .FRAGMENT,
num_samplers = 1, num_samplers = 1,
} }