feat(gpu): afegir suport SPIRV (Vulkan) per Linux/Windows

- Nou: shaders/sprite.vert|frag, postfx.vert|frag, ball.vert (GLSL)
- Nou: cmake/spv_to_header.cmake — converteix .spv → uint8_t C header
- CMakeLists.txt: bloc non-Apple troba glslc, compila GLSL → SPIRV en
  build-time i genera headers embeguts a build/generated_shaders/
- gpu_context.cpp: MSL|METALLIB en Apple, SPIRV en la resta
- gpu_pipeline.cpp: createShaderSPIRV() + branques #ifdef __APPLE__
  per sprite/ball/postfx pipelines
- Corregeix crash a engine.cpp:821 (Windows/Linux) causat per pipelines
  null quan init() fallava en no trobar suport MSL

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 09:47:36 +01:00
parent 5c0d0479ad
commit 6ffe7594ab
9 changed files with 201 additions and 5 deletions

23
shaders/ball.vert Normal file
View File

@@ -0,0 +1,23 @@
#version 450
// Per-instance data (input_rate = INSTANCE in the pipeline)
layout(location=0) in vec2 center;
layout(location=1) in vec2 halfsize;
layout(location=2) in vec4 col;
layout(location=0) out vec2 v_uv;
layout(location=1) out vec4 v_col;
void main() {
// gl_VertexIndex cycles 0..5 per instance (6 vertices = 2 triangles)
// Vertex order: TL TR BL | TR BR BL (CCW winding)
const vec2 offsets[6] = vec2[6](
vec2(-1.0, 1.0), vec2(1.0, 1.0), vec2(-1.0,-1.0),
vec2( 1.0, 1.0), vec2(1.0,-1.0), vec2(-1.0,-1.0)
);
const vec2 uvs[6] = vec2[6](
vec2(0.0,0.0), vec2(1.0,0.0), vec2(0.0,1.0),
vec2(1.0,0.0), vec2(1.0,1.0), vec2(0.0,1.0)
);
int vid = gl_VertexIndex;
gl_Position = vec4(center + offsets[vid] * halfsize, 0.0, 1.0);
v_uv = uvs[vid];
v_col = col;
}

24
shaders/postfx.frag Normal file
View File

@@ -0,0 +1,24 @@
#version 450
layout(location=0) in vec2 v_uv;
layout(location=0) out vec4 out_color;
layout(set=2, binding=0) uniform sampler2D scene;
layout(set=3, binding=0) uniform PostFXUniforms {
float vignette_strength;
float chroma_strength;
float scanline_strength;
float time;
} u;
void main() {
float ca = u.chroma_strength * 0.005;
vec4 color;
color.r = texture(scene, v_uv + vec2( ca, 0.0)).r;
color.g = texture(scene, v_uv).g;
color.b = texture(scene, v_uv - vec2( ca, 0.0)).b;
color.a = texture(scene, v_uv).a;
float scan = 0.85 + 0.15 * sin(v_uv.y * 3.14159265 * 720.0);
color.rgb *= mix(1.0, scan, u.scanline_strength);
vec2 d = v_uv - vec2(0.5, 0.5);
float vignette = 1.0 - dot(d, d) * u.vignette_strength;
color.rgb *= clamp(vignette, 0.0, 1.0);
out_color = color;
}

10
shaders/postfx.vert Normal file
View File

@@ -0,0 +1,10 @@
#version 450
layout(location=0) out vec2 v_uv;
void main() {
// Full-screen triangle from vertex index (no vertex buffer needed)
// NDC/UV mapping matches the MSL version (SDL3 GPU normalizes Y-up on all backends)
vec2 positions[3] = vec2[3](vec2(-1.0,-1.0), vec2(3.0,-1.0), vec2(-1.0,3.0));
vec2 uvs[3] = vec2[3](vec2(0.0, 1.0), vec2(2.0, 1.0), vec2(0.0,-1.0));
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
v_uv = uvs[gl_VertexIndex];
}

9
shaders/sprite.frag Normal file
View File

@@ -0,0 +1,9 @@
#version 450
layout(location=0) in vec2 v_uv;
layout(location=1) in vec4 v_col;
layout(location=0) out vec4 out_color;
layout(set=2, binding=0) uniform sampler2D tex;
void main() {
vec4 t = texture(tex, v_uv);
out_color = vec4(t.rgb * v_col.rgb, t.a * v_col.a);
}

11
shaders/sprite.vert Normal file
View File

@@ -0,0 +1,11 @@
#version 450
layout(location=0) in vec2 pos;
layout(location=1) in vec2 uv;
layout(location=2) in vec4 col;
layout(location=0) out vec2 v_uv;
layout(location=1) out vec4 v_col;
void main() {
gl_Position = vec4(pos, 0.0, 1.0);
v_uv = uv;
v_col = col;
}