summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal.metal
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal.metal
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal.metal')
-rw-r--r--contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal.metal299
1 files changed, 299 insertions, 0 deletions
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 @@
1#include <metal_common>
2#include <metal_texture>
3#include <metal_matrix>
4
5using namespace metal;
6
7// These should mirror the definitions in SDL_render_metal.m
8#define TONEMAP_NONE 0
9#define TONEMAP_LINEAR 1
10#define TONEMAP_CHROME 2
11
12#define TEXTURETYPE_NONE 0
13#define TEXTURETYPE_RGB 1
14#define TEXTURETYPE_NV12 2
15#define TEXTURETYPE_NV21 3
16#define TEXTURETYPE_YUV 4
17
18#define INPUTTYPE_UNSPECIFIED 0
19#define INPUTTYPE_SRGB 1
20#define INPUTTYPE_SCRGB 2
21#define INPUTTYPE_HDR10 3
22
23struct ShaderConstants
24{
25 float scRGB_output;
26 float texture_type;
27 float input_type;
28 float color_scale;
29
30 float tonemap_method;
31 float tonemap_factor1;
32 float tonemap_factor2;
33 float sdr_white_point;
34};
35
36struct YUVDecode
37{
38 float3 offset;
39 float3x3 matrix;
40};
41
42float sRGBtoLinear(float v)
43{
44 if (v <= 0.04045) {
45 v = (v / 12.92);
46 } else {
47 v = pow(abs(v + 0.055) / 1.055, 2.4);
48 }
49 return v;
50}
51
52float sRGBfromLinear(float v)
53{
54 if (v <= 0.0031308) {
55 v = (v * 12.92);
56 } else {
57 v = (pow(abs(v), 1.0 / 2.4) * 1.055 - 0.055);
58 }
59 return v;
60}
61
62float3 PQtoLinear(float3 v, float sdr_white_point)
63{
64 const float c1 = 0.8359375;
65 const float c2 = 18.8515625;
66 const float c3 = 18.6875;
67 const float oo_m1 = 1.0 / 0.1593017578125;
68 const float oo_m2 = 1.0 / 78.84375;
69
70 float3 num = max(pow(abs(v), oo_m2) - c1, 0.0);
71 float3 den = c2 - c3 * pow(abs(v), oo_m2);
72 return (10000.0 * pow(abs(num / den), oo_m1) / sdr_white_point);
73}
74
75float3 ApplyTonemap(float3 v, float input_type, float tonemap_method, float tonemap_factor1, float tonemap_factor2)
76{
77 const float3x3 mat709to2020 = {
78 { 0.627404, 0.329283, 0.043313 },
79 { 0.069097, 0.919541, 0.011362 },
80 { 0.016391, 0.088013, 0.895595 }
81 };
82 const float3x3 mat2020to709 = {
83 { 1.660496, -0.587656, -0.072840 },
84 { -0.124547, 1.132895, -0.008348 },
85 { -0.018154, -0.100597, 1.118751 }
86 };
87
88 if (tonemap_method == TONEMAP_LINEAR) {
89 v *= tonemap_factor1;
90 } else if (tonemap_method == TONEMAP_CHROME) {
91 if (input_type == INPUTTYPE_SCRGB) {
92 // Convert to BT.2020 colorspace for tone mapping
93 v = v * mat709to2020;
94 }
95
96 float vmax = max(v.r, max(v.g, v.b));
97 if (vmax > 0.0) {
98 float scale = (1.0 + tonemap_factor1 * vmax) / (1.0 + tonemap_factor2 * vmax);
99 v *= scale;
100 }
101
102 if (input_type == INPUTTYPE_SCRGB) {
103 // Convert to BT.709 colorspace after tone mapping
104 v = v * mat2020to709;
105 }
106 }
107 return v;
108}
109
110float4 GetOutputColorSimple(float4 rgba, float color_scale)
111{
112 float4 output;
113
114 output.rgb = rgba.rgb * color_scale;
115 output.a = rgba.a;
116
117 return output;
118}
119
120float3 GetOutputColorFromSRGB(float3 rgb, float scRGB_output, float color_scale)
121{
122 float3 output;
123
124 if (scRGB_output) {
125 rgb.r = sRGBtoLinear(rgb.r);
126 rgb.g = sRGBtoLinear(rgb.g);
127 rgb.b = sRGBtoLinear(rgb.b);
128 }
129
130 output = rgb * color_scale;
131
132 return output;
133}
134
135float3 GetOutputColorFromLinear(float3 rgb, float scRGB_output, float color_scale)
136{
137 float3 output;
138
139 output = rgb * color_scale;
140
141 if (!scRGB_output) {
142 output.r = sRGBfromLinear(output.r);
143 output.g = sRGBfromLinear(output.g);
144 output.b = sRGBfromLinear(output.b);
145 output = clamp(output, 0.0, 1.0);
146 }
147
148 return output;
149}
150
151float4 GetOutputColor(float4 rgba, constant ShaderConstants &c)
152{
153 const float3x3 mat2020to709 = {
154 { 1.660496, -0.587656, -0.072840 },
155 { -0.124547, 1.132895, -0.008348 },
156 { -0.018154, -0.100597, 1.118751 }
157 };
158 float4 output;
159
160 if (c.input_type == INPUTTYPE_HDR10) {
161 rgba.rgb = PQtoLinear(rgba.rgb, c.sdr_white_point);
162 }
163
164 if (c.tonemap_method != TONEMAP_NONE) {
165 rgba.rgb = ApplyTonemap(rgba.rgb, c.input_type, c.tonemap_method, c.tonemap_factor1, c.tonemap_factor2);
166 }
167
168 if (c.input_type == INPUTTYPE_SRGB) {
169 if (c.texture_type == TEXTURETYPE_RGB) {
170 // The sampler has already converted to linear if necessary
171 output.rgb = rgba.rgb * c.color_scale;
172 } else {
173 output.rgb = GetOutputColorFromSRGB(rgba.rgb, c.scRGB_output, c.color_scale);
174 }
175 } else if (c.input_type == INPUTTYPE_SCRGB) {
176 output.rgb = GetOutputColorFromLinear(rgba.rgb, c.scRGB_output, c.color_scale);
177 } else if (c.input_type == INPUTTYPE_HDR10) {
178 rgba.rgb = rgba.rgb * mat2020to709;
179 output.rgb = GetOutputColorFromLinear(rgba.rgb, c.scRGB_output, c.color_scale);
180 } else {
181 // Unexpected input type, use magenta error color
182 output.rgb = float3(1.0, 0.0, 1.0);
183 }
184 output.a = rgba.a;
185
186 return output;
187}
188
189struct SolidVertexInput
190{
191 float2 position [[attribute(0)]];
192 float4 color [[attribute(1)]];
193};
194
195struct SolidVertexOutput
196{
197 float4 position [[position]];
198 float4 color;
199 float pointSize [[point_size]];
200};
201
202vertex SolidVertexOutput SDL_Solid_vertex(SolidVertexInput in [[stage_in]],
203 constant float4x4 &projection [[buffer(2)]],
204 constant float4x4 &transform [[buffer(3)]])
205{
206 SolidVertexOutput v;
207 v.position = (projection * transform) * float4(in.position, 0.0f, 1.0f);
208 v.color = in.color;
209 v.pointSize = 1.0f;
210 return v;
211}
212
213fragment float4 SDL_Solid_fragment(SolidVertexInput in [[stage_in]],
214 constant ShaderConstants &c [[buffer(0)]])
215{
216 return GetOutputColorSimple(1.0, c.color_scale) * in.color;
217}
218
219struct CopyVertexInput
220{
221 float2 position [[attribute(0)]];
222 float4 color [[attribute(1)]];
223 float2 texcoord [[attribute(2)]];
224};
225
226struct CopyVertexOutput
227{
228 float4 position [[position]];
229 float4 color;
230 float2 texcoord;
231};
232
233vertex CopyVertexOutput SDL_Copy_vertex(CopyVertexInput in [[stage_in]],
234 constant float4x4 &projection [[buffer(2)]],
235 constant float4x4 &transform [[buffer(3)]])
236{
237 CopyVertexOutput v;
238 v.position = (projection * transform) * float4(in.position, 0.0f, 1.0f);
239 v.color = in.color;
240 v.texcoord = in.texcoord;
241 return v;
242}
243
244fragment float4 SDL_Copy_fragment(CopyVertexOutput vert [[stage_in]],
245 constant ShaderConstants &c [[buffer(0)]],
246 texture2d<float> tex [[texture(0)]],
247 sampler s [[sampler(0)]])
248{
249 float4 rgba = tex.sample(s, vert.texcoord);
250 return GetOutputColor(rgba, c) * vert.color;
251}
252
253fragment float4 SDL_YUV_fragment(CopyVertexOutput vert [[stage_in]],
254 constant ShaderConstants &c [[buffer(0)]],
255 constant YUVDecode &decode [[buffer(1)]],
256 texture2d<float> texY [[texture(0)]],
257 texture2d_array<float> texUV [[texture(1)]],
258 sampler s [[sampler(0)]])
259{
260 float3 yuv;
261 yuv.x = texY.sample(s, vert.texcoord).r;
262 yuv.y = texUV.sample(s, vert.texcoord, 0).r;
263 yuv.z = texUV.sample(s, vert.texcoord, 1).r;
264
265 float4 rgba;
266 rgba.rgb = (yuv + decode.offset) * decode.matrix;
267 rgba.a = 1.0;
268
269 return GetOutputColor(rgba, c) * vert.color;
270}
271
272fragment float4 SDL_NV12_fragment(CopyVertexOutput vert [[stage_in]],
273 constant ShaderConstants &c [[buffer(0)]],
274 constant YUVDecode &decode [[buffer(1)]],
275 texture2d<float> texY [[texture(0)]],
276 texture2d<float> texUV [[texture(1)]],
277 sampler s [[sampler(0)]])
278{
279 float4 rgba;
280 if (c.texture_type == TEXTURETYPE_NV12) {
281 float3 yuv;
282 yuv.x = texY.sample(s, vert.texcoord).r;
283 yuv.yz = texUV.sample(s, vert.texcoord).rg;
284
285 rgba.rgb = (yuv + decode.offset) * decode.matrix;
286 } else if (c.texture_type == TEXTURETYPE_NV21) {
287 float3 yuv;
288 yuv.x = texY.sample(s, vert.texcoord).r;
289 yuv.yz = texUV.sample(s, vert.texcoord).gr;
290
291 rgba.rgb = (yuv + decode.offset) * decode.matrix;
292 } else {
293 // Unexpected texture type, use magenta error color
294 rgba.rgb = float3(1.0, 0.0, 1.0);
295 }
296 rgba.a = 1.0;
297
298 return GetOutputColor(rgba, c) * vert.color;
299}