- CMakeLists: bloc if(APPLE) que transpila .spv → .spv.msl amb spirv-cross - gpu_shader_preset: carrega MSL (main0) a macOS, SPIR-V (main) a la resta - Afegeix null-terminator als buffers MSL (SDL3 els tracta com C-string) - README: secció de dependències de shaders per plataforma (Vulkan SDK, spirv-cross) - Inclou .spv.msl generats per ntsc-md-rainbows Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
62 lines
3.1 KiB
Plaintext
62 lines
3.1 KiB
Plaintext
#include <metal_stdlib>
|
|
#include <simd/simd.h>
|
|
|
|
using namespace metal;
|
|
|
|
struct NTSCParams
|
|
{
|
|
float source_width;
|
|
float source_height;
|
|
float a_value;
|
|
float b_value;
|
|
float cc_value;
|
|
float scan_time;
|
|
float notch_width;
|
|
float y_freq;
|
|
float i_freq;
|
|
float q_freq;
|
|
float _pad0;
|
|
float _pad1;
|
|
};
|
|
|
|
struct main0_out
|
|
{
|
|
float4 FragColor [[color(0)]];
|
|
};
|
|
|
|
struct main0_in
|
|
{
|
|
float2 v_uv [[user(locn0)]];
|
|
};
|
|
|
|
fragment main0_out main0(main0_in in [[stage_in]], constant NTSCParams& u [[buffer(0)]], texture2d<float> Source [[texture(0)]], sampler SourceSmplr [[sampler(0)]])
|
|
{
|
|
main0_out out = {};
|
|
float2 source_dims = float2(u.source_width, u.source_height);
|
|
float2 PValueSourceTexel = float2(1.0, 0.0) / source_dims;
|
|
float2 C0 = in.v_uv + (PValueSourceTexel * float2(0.0));
|
|
float2 C1 = in.v_uv + (PValueSourceTexel * float2(0.25, 0.0));
|
|
float2 C2 = in.v_uv + (PValueSourceTexel * float2(0.5, 0.0));
|
|
float2 C3 = in.v_uv + (PValueSourceTexel * float2(0.75, 0.0));
|
|
float4 Cx = float4(C0.x, C1.x, C2.x, C3.x);
|
|
float4 Cy = float4(C0.y, C1.y, C2.y, C3.y);
|
|
float4 Texel0 = Source.sample(SourceSmplr, C0);
|
|
float4 Texel1 = Source.sample(SourceSmplr, C1);
|
|
float4 Texel2 = Source.sample(SourceSmplr, C2);
|
|
float4 Texel3 = Source.sample(SourceSmplr, C3);
|
|
float4 HPosition = Cx;
|
|
float4 VPosition = Cy;
|
|
float4 Y = float4(dot(Texel0, float4(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625, 0.0)), dot(Texel1, float4(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625, 0.0)), dot(Texel2, float4(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625, 0.0)), dot(Texel3, float4(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625, 0.0)));
|
|
float4 I = float4(dot(Texel0, float4(0.595715999603271484375, -0.2744530141353607177734375, -0.3212629854679107666015625, 0.0)), dot(Texel1, float4(0.595715999603271484375, -0.2744530141353607177734375, -0.3212629854679107666015625, 0.0)), dot(Texel2, float4(0.595715999603271484375, -0.2744530141353607177734375, -0.3212629854679107666015625, 0.0)), dot(Texel3, float4(0.595715999603271484375, -0.2744530141353607177734375, -0.3212629854679107666015625, 0.0)));
|
|
float4 Q = float4(dot(Texel0, float4(0.211456000804901123046875, -0.52259099483489990234375, 0.311134994029998779296875, 0.0)), dot(Texel1, float4(0.211456000804901123046875, -0.52259099483489990234375, 0.311134994029998779296875, 0.0)), dot(Texel2, float4(0.211456000804901123046875, -0.52259099483489990234375, 0.311134994029998779296875, 0.0)), dot(Texel3, float4(0.211456000804901123046875, -0.52259099483489990234375, 0.311134994029998779296875, 0.0)));
|
|
float W = (6.283185482025146484375 * u.cc_value) * u.scan_time;
|
|
float WoPI = W / 3.1415927410125732421875;
|
|
float HOffset = u.a_value / WoPI;
|
|
float VScale = (u.b_value * source_dims.y) / WoPI;
|
|
float4 T = (HPosition + float4(HOffset)) + (VPosition * float4(VScale));
|
|
float4 TW = T * W;
|
|
out.FragColor = (Y + (I * cos(TW))) + (Q * sin(TW));
|
|
return out;
|
|
}
|
|
|