From 5a079a2d114f96d4847d1ee305d5b7c16eeec50e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 27 Dec 2025 12:03:39 -0800 Subject: Initial commit --- .../src/render/metal/SDL_shaders_metal.metal | 299 +++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal.metal (limited to 'contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal.metal') diff --git a/contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal.metal b/contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal.metal new file mode 100644 index 0000000..c266670 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal.metal @@ -0,0 +1,299 @@ +#include +#include +#include + +using namespace metal; + +// These should mirror the definitions in SDL_render_metal.m +#define TONEMAP_NONE 0 +#define TONEMAP_LINEAR 1 +#define TONEMAP_CHROME 2 + +#define TEXTURETYPE_NONE 0 +#define TEXTURETYPE_RGB 1 +#define TEXTURETYPE_NV12 2 +#define TEXTURETYPE_NV21 3 +#define TEXTURETYPE_YUV 4 + +#define INPUTTYPE_UNSPECIFIED 0 +#define INPUTTYPE_SRGB 1 +#define INPUTTYPE_SCRGB 2 +#define INPUTTYPE_HDR10 3 + +struct ShaderConstants +{ + float scRGB_output; + float texture_type; + float input_type; + float color_scale; + + float tonemap_method; + float tonemap_factor1; + float tonemap_factor2; + float sdr_white_point; +}; + +struct YUVDecode +{ + float3 offset; + float3x3 matrix; +}; + +float sRGBtoLinear(float v) +{ + if (v <= 0.04045) { + v = (v / 12.92); + } else { + v = pow(abs(v + 0.055) / 1.055, 2.4); + } + return v; +} + +float sRGBfromLinear(float v) +{ + if (v <= 0.0031308) { + v = (v * 12.92); + } else { + v = (pow(abs(v), 1.0 / 2.4) * 1.055 - 0.055); + } + return v; +} + +float3 PQtoLinear(float3 v, float sdr_white_point) +{ + const float c1 = 0.8359375; + const float c2 = 18.8515625; + const float c3 = 18.6875; + const float oo_m1 = 1.0 / 0.1593017578125; + const float oo_m2 = 1.0 / 78.84375; + + float3 num = max(pow(abs(v), oo_m2) - c1, 0.0); + float3 den = c2 - c3 * pow(abs(v), oo_m2); + return (10000.0 * pow(abs(num / den), oo_m1) / sdr_white_point); +} + +float3 ApplyTonemap(float3 v, float input_type, float tonemap_method, float tonemap_factor1, float tonemap_factor2) +{ + const float3x3 mat709to2020 = { + { 0.627404, 0.329283, 0.043313 }, + { 0.069097, 0.919541, 0.011362 }, + { 0.016391, 0.088013, 0.895595 } + }; + const float3x3 mat2020to709 = { + { 1.660496, -0.587656, -0.072840 }, + { -0.124547, 1.132895, -0.008348 }, + { -0.018154, -0.100597, 1.118751 } + }; + + if (tonemap_method == TONEMAP_LINEAR) { + v *= tonemap_factor1; + } else if (tonemap_method == TONEMAP_CHROME) { + if (input_type == INPUTTYPE_SCRGB) { + // Convert to BT.2020 colorspace for tone mapping + v = v * mat709to2020; + } + + float vmax = max(v.r, max(v.g, v.b)); + if (vmax > 0.0) { + float scale = (1.0 + tonemap_factor1 * vmax) / (1.0 + tonemap_factor2 * vmax); + v *= scale; + } + + if (input_type == INPUTTYPE_SCRGB) { + // Convert to BT.709 colorspace after tone mapping + v = v * mat2020to709; + } + } + return v; +} + +float4 GetOutputColorSimple(float4 rgba, float color_scale) +{ + float4 output; + + output.rgb = rgba.rgb * color_scale; + output.a = rgba.a; + + return output; +} + +float3 GetOutputColorFromSRGB(float3 rgb, float scRGB_output, float color_scale) +{ + float3 output; + + if (scRGB_output) { + rgb.r = sRGBtoLinear(rgb.r); + rgb.g = sRGBtoLinear(rgb.g); + rgb.b = sRGBtoLinear(rgb.b); + } + + output = rgb * color_scale; + + return output; +} + +float3 GetOutputColorFromLinear(float3 rgb, float scRGB_output, float color_scale) +{ + float3 output; + + output = rgb * color_scale; + + if (!scRGB_output) { + output.r = sRGBfromLinear(output.r); + output.g = sRGBfromLinear(output.g); + output.b = sRGBfromLinear(output.b); + output = clamp(output, 0.0, 1.0); + } + + return output; +} + +float4 GetOutputColor(float4 rgba, constant ShaderConstants &c) +{ + const float3x3 mat2020to709 = { + { 1.660496, -0.587656, -0.072840 }, + { -0.124547, 1.132895, -0.008348 }, + { -0.018154, -0.100597, 1.118751 } + }; + float4 output; + + if (c.input_type == INPUTTYPE_HDR10) { + rgba.rgb = PQtoLinear(rgba.rgb, c.sdr_white_point); + } + + if (c.tonemap_method != TONEMAP_NONE) { + rgba.rgb = ApplyTonemap(rgba.rgb, c.input_type, c.tonemap_method, c.tonemap_factor1, c.tonemap_factor2); + } + + if (c.input_type == INPUTTYPE_SRGB) { + if (c.texture_type == TEXTURETYPE_RGB) { + // The sampler has already converted to linear if necessary + output.rgb = rgba.rgb * c.color_scale; + } else { + output.rgb = GetOutputColorFromSRGB(rgba.rgb, c.scRGB_output, c.color_scale); + } + } else if (c.input_type == INPUTTYPE_SCRGB) { + output.rgb = GetOutputColorFromLinear(rgba.rgb, c.scRGB_output, c.color_scale); + } else if (c.input_type == INPUTTYPE_HDR10) { + rgba.rgb = rgba.rgb * mat2020to709; + output.rgb = GetOutputColorFromLinear(rgba.rgb, c.scRGB_output, c.color_scale); + } else { + // Unexpected input type, use magenta error color + output.rgb = float3(1.0, 0.0, 1.0); + } + output.a = rgba.a; + + return output; +} + +struct SolidVertexInput +{ + float2 position [[attribute(0)]]; + float4 color [[attribute(1)]]; +}; + +struct SolidVertexOutput +{ + float4 position [[position]]; + float4 color; + float pointSize [[point_size]]; +}; + +vertex SolidVertexOutput SDL_Solid_vertex(SolidVertexInput in [[stage_in]], + constant float4x4 &projection [[buffer(2)]], + constant float4x4 &transform [[buffer(3)]]) +{ + SolidVertexOutput v; + v.position = (projection * transform) * float4(in.position, 0.0f, 1.0f); + v.color = in.color; + v.pointSize = 1.0f; + return v; +} + +fragment float4 SDL_Solid_fragment(SolidVertexInput in [[stage_in]], + constant ShaderConstants &c [[buffer(0)]]) +{ + return GetOutputColorSimple(1.0, c.color_scale) * in.color; +} + +struct CopyVertexInput +{ + float2 position [[attribute(0)]]; + float4 color [[attribute(1)]]; + float2 texcoord [[attribute(2)]]; +}; + +struct CopyVertexOutput +{ + float4 position [[position]]; + float4 color; + float2 texcoord; +}; + +vertex CopyVertexOutput SDL_Copy_vertex(CopyVertexInput in [[stage_in]], + constant float4x4 &projection [[buffer(2)]], + constant float4x4 &transform [[buffer(3)]]) +{ + CopyVertexOutput v; + v.position = (projection * transform) * float4(in.position, 0.0f, 1.0f); + v.color = in.color; + v.texcoord = in.texcoord; + return v; +} + +fragment float4 SDL_Copy_fragment(CopyVertexOutput vert [[stage_in]], + constant ShaderConstants &c [[buffer(0)]], + texture2d tex [[texture(0)]], + sampler s [[sampler(0)]]) +{ + float4 rgba = tex.sample(s, vert.texcoord); + return GetOutputColor(rgba, c) * vert.color; +} + +fragment float4 SDL_YUV_fragment(CopyVertexOutput vert [[stage_in]], + constant ShaderConstants &c [[buffer(0)]], + constant YUVDecode &decode [[buffer(1)]], + texture2d texY [[texture(0)]], + texture2d_array texUV [[texture(1)]], + sampler s [[sampler(0)]]) +{ + float3 yuv; + yuv.x = texY.sample(s, vert.texcoord).r; + yuv.y = texUV.sample(s, vert.texcoord, 0).r; + yuv.z = texUV.sample(s, vert.texcoord, 1).r; + + float4 rgba; + rgba.rgb = (yuv + decode.offset) * decode.matrix; + rgba.a = 1.0; + + return GetOutputColor(rgba, c) * vert.color; +} + +fragment float4 SDL_NV12_fragment(CopyVertexOutput vert [[stage_in]], + constant ShaderConstants &c [[buffer(0)]], + constant YUVDecode &decode [[buffer(1)]], + texture2d texY [[texture(0)]], + texture2d texUV [[texture(1)]], + sampler s [[sampler(0)]]) +{ + float4 rgba; + if (c.texture_type == TEXTURETYPE_NV12) { + float3 yuv; + yuv.x = texY.sample(s, vert.texcoord).r; + yuv.yz = texUV.sample(s, vert.texcoord).rg; + + rgba.rgb = (yuv + decode.offset) * decode.matrix; + } else if (c.texture_type == TEXTURETYPE_NV21) { + float3 yuv; + yuv.x = texY.sample(s, vert.texcoord).r; + yuv.yz = texUV.sample(s, vert.texcoord).gr; + + rgba.rgb = (yuv + decode.offset) * decode.matrix; + } else { + // Unexpected texture type, use magenta error color + rgba.rgb = float3(1.0, 0.0, 1.0); + } + rgba.a = 1.0; + + return GetOutputColor(rgba, c) * vert.color; +} -- cgit v1.2.3