feat(gpu): suport Metal/MSL a macOS i shaders SPIR-V embedits

This commit is contained in:
2026-05-20 23:07:49 +02:00
parent ac5434fc30
commit 6259f594c8
15 changed files with 6823 additions and 227 deletions
@@ -0,0 +1,34 @@
// line_frag.msl.h - Metal Shading Language del fragment shader de línies
// © 2026 JailDesigner
//
// IMPORTANT: mantenir sincronitzat a mà amb shaders/line.frag.glsl. SDL3 GPU
// compila aquest string MSL en runtime; no hi ha generador automàtic.
//
// Aplica antialias geomètric via smoothstep sobre edge_dist (±1 als laterals,
// 0 al centre del quad). Sense uniforms ni samplers.
#pragma once
#ifdef __APPLE__
namespace Rendering::GPU::Msl {
inline constexpr const char* LINE_FRAG_MSL = R"(
#include <metal_stdlib>
using namespace metal;
struct VOut {
float4 pos [[position]];
float4 color;
float edge_dist;
};
fragment float4 line_fs(VOut in [[stage_in]]) {
float d = abs(in.edge_dist);
float alpha = 1.0 - smoothstep(0.7, 1.0, d);
return float4(in.color.rgb, in.color.a * alpha);
}
)";
} // namespace Rendering::GPU::Msl
#endif // __APPLE__
@@ -0,0 +1,54 @@
// line_vert.msl.h - Metal Shading Language del vertex shader de línies
// © 2026 JailDesigner
//
// IMPORTANT: mantenir sincronitzat a mà amb shaders/line.vert.glsl. SDL3 GPU
// compila aquest string MSL en runtime; no hi ha generador automàtic. Qualsevol
// canvi al UBO o al layout de vèrtex cal replicar-lo ací al mateix commit.
//
// Mapping SDL3 GPU → Metal (segons src/gpu/metal/SDL_gpu_metal.m upstream):
// - Vertex buffers d'usuari: [[buffer(14 + slot)]] (METAL_FIRST_VERTEX_BUFFER_SLOT=14).
// A través de [[stage_in]] amb [[attribute(N)]], Metal resol automàticament
// a partir del MTLVertexDescriptor del pipeline state (transparent al MSL).
// - Vertex UBO slot 0 SDL → [[buffer(0)]] MSL (sense offset).
#pragma once
#ifdef __APPLE__
namespace Rendering::GPU::Msl {
inline constexpr const char* LINE_VERT_MSL = R"(
#include <metal_stdlib>
using namespace metal;
struct VIn {
float2 in_position [[attribute(0)]];
float4 in_color [[attribute(1)]];
float in_edge_dist[[attribute(2)]];
};
struct VOut {
float4 pos [[position]];
float4 color;
float edge_dist;
};
struct LineUBO {
float2 viewport_size;
float2 _padding;
};
vertex VOut line_vs(VIn in [[stage_in]],
constant LineUBO& ubo [[buffer(0)]]) {
float2 ndc = (in.in_position / ubo.viewport_size) * 2.0 - 1.0;
ndc.y = -ndc.y;
VOut out;
out.pos = float4(ndc, 0.0, 1.0);
out.color = in.in_color;
out.edge_dist = in.in_edge_dist;
return out;
}
)";
} // namespace Rendering::GPU::Msl
#endif // __APPLE__
@@ -0,0 +1,90 @@
// postfx_frag.msl.h - Metal Shading Language del fragment shader del postpro
// © 2026 JailDesigner
//
// IMPORTANT: mantenir sincronitzat a mà amb shaders/postfx.frag.glsl. SDL3 GPU
// compila aquest string MSL en runtime; no hi ha generador automàtic. Qualsevol
// canvi al struct PostFxUniforms (gpu_postfx_pipeline.hpp), al GLSL o al MSL
// cal replicar-lo a totes tres al mateix commit.
//
// Composició final: bloom 5×5 amb high-pass, flicker sinusoidal global,
// background pulse sumat. Recursos:
// - texture2d<float> scene [[texture(0)]] + sampler [[sampler(0)]]
// - constant PostFxUBO& ubo [[buffer(0)]] (slot 0 SDL → buffer(0) MSL)
//
// L'struct PostFxUBO té layout idèntic a PostFxUniforms (5×vec4 = 80 bytes).
#pragma once
#ifdef __APPLE__
namespace Rendering::GPU::Msl {
inline constexpr const char* POSTFX_FRAG_MSL = R"(
#include <metal_stdlib>
using namespace metal;
struct PostVOut {
float4 pos [[position]];
float2 uv;
};
struct PostFxUBO {
float time;
float bloom_intensity;
float bloom_threshold;
float bloom_radius_px;
float flicker_amplitude;
float flicker_frequency_hz;
float background_pulse_freq_hz;
float pad_a;
float4 background_min;
float4 background_max;
float2 texel_size;
float2 pad_b;
};
constant float TAU = 6.28318530718;
fragment float4 postfx_fs(PostVOut in [[stage_in]],
texture2d<float> scene [[texture(0)]],
sampler samp [[sampler(0)]],
constant PostFxUBO& ubo [[buffer(0)]]) {
// === BLOOM ===
float3 src = scene.sample(samp, in.uv).rgb;
float3 bloom = float3(0.0);
float total_weight = 0.0;
for (int dy = -2; dy <= 2; ++dy) {
for (int dx = -2; dx <= 2; ++dx) {
float2 offset = float2(float(dx), float(dy)) * ubo.texel_size * ubo.bloom_radius_px;
float3 c = scene.sample(samp, in.uv + offset).rgb;
float luma = max(c.r, max(c.g, c.b));
float high_pass = max(0.0, luma - ubo.bloom_threshold);
float w = exp(-float(dx * dx + dy * dy) / 4.0);
bloom += c * high_pass * w;
total_weight += w;
}
}
if (total_weight > 0.0) {
bloom /= total_weight;
}
bloom *= ubo.bloom_intensity;
// === FLICKER ===
float pulse = (sin(ubo.time * ubo.flicker_frequency_hz * TAU) * 0.5) + 0.5;
float flicker = 1.0 - (ubo.flicker_amplitude * (1.0 - pulse));
// === BACKGROUND PULSE ===
float bg_pulse = (sin(ubo.time * ubo.background_pulse_freq_hz * TAU) * 0.5) + 0.5;
float3 background = mix(ubo.background_min.rgb, ubo.background_max.rgb, bg_pulse);
// === COMPOSICIÓ ===
float3 lines_and_glow = (src + bloom) * flicker;
return float4(background + lines_and_glow, 1.0);
}
)";
} // namespace Rendering::GPU::Msl
#endif // __APPLE__
@@ -0,0 +1,38 @@
// postfx_vert.msl.h - Metal Shading Language del vertex shader del postpro
// © 2026 JailDesigner
//
// IMPORTANT: mantenir sincronitzat a mà amb shaders/postfx.vert.glsl. SDL3 GPU
// compila aquest string MSL en runtime; no hi ha generador automàtic.
//
// Fullscreen triangle: 3 vèrtexs en (-1,-1), (3,-1), (-1,3) generats per
// [[vertex_id]]. UV.y invertida per compensar la diferència de convenció
// entre clip-space del line shader (Y-flip) i el mostreig SDL_gpu (origen
// top-left). Sense uniforms ni vertex buffers (DrawPrimitives vertex_count=3).
#pragma once
#ifdef __APPLE__
namespace Rendering::GPU::Msl {
inline constexpr const char* POSTFX_VERT_MSL = R"(
#include <metal_stdlib>
using namespace metal;
struct PostVOut {
float4 pos [[position]];
float2 uv;
};
vertex PostVOut postfx_vs(uint vid [[vertex_id]]) {
const float2 positions[3] = { {-1.0, -1.0}, { 3.0, -1.0}, {-1.0, 3.0} };
const float2 uvs[3] = { { 0.0, 1.0}, { 2.0, 1.0}, { 0.0, -1.0} };
PostVOut out;
out.pos = float4(positions[vid], 0.0, 1.0);
out.uv = uvs[vid];
return out;
}
)";
} // namespace Rendering::GPU::Msl
#endif // __APPLE__