summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/render/opengl/SDL_shaders_gl.c
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/opengl/SDL_shaders_gl.c
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/render/opengl/SDL_shaders_gl.c')
-rw-r--r--contrib/SDL-3.2.8/src/render/opengl/SDL_shaders_gl.c545
1 files changed, 545 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/render/opengl/SDL_shaders_gl.c b/contrib/SDL-3.2.8/src/render/opengl/SDL_shaders_gl.c
new file mode 100644
index 0000000..b09b12e
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/opengl/SDL_shaders_gl.c
@@ -0,0 +1,545 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifdef SDL_VIDEO_RENDER_OGL
24
25#include <SDL3/SDL_opengl.h>
26#include "SDL_shaders_gl.h"
27
28// OpenGL shader implementation
29
30// #define DEBUG_SHADERS
31
32typedef struct
33{
34 GLhandleARB program;
35 GLhandleARB vert_shader;
36 GLhandleARB frag_shader;
37} GL_ShaderData;
38
39struct GL_ShaderContext
40{
41 GLenum (*glGetError)(void);
42
43 PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
44 PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
45 PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
46 PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
47 PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
48 PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
49 PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
50 PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
51 PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
52 PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
53 PFNGLUNIFORM1IARBPROC glUniform1iARB;
54 PFNGLUNIFORM1FARBPROC glUniform1fARB;
55 PFNGLUNIFORM3FARBPROC glUniform3fARB;
56 PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
57
58 bool GL_ARB_texture_rectangle_supported;
59
60 GL_ShaderData shaders[NUM_SHADERS];
61 const float *shader_params[NUM_SHADERS];
62};
63
64/* *INDENT-OFF* */ // clang-format off
65
66#define COLOR_VERTEX_SHADER \
67"varying vec4 v_color;\n" \
68"\n" \
69"void main()\n" \
70"{\n" \
71" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" \
72" v_color = gl_Color;\n" \
73"}" \
74
75#define TEXTURE_VERTEX_SHADER \
76"varying vec4 v_color;\n" \
77"varying vec2 v_texCoord;\n" \
78"\n" \
79"void main()\n" \
80"{\n" \
81" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" \
82" v_color = gl_Color;\n" \
83" v_texCoord = vec2(gl_MultiTexCoord0);\n" \
84"}" \
85
86#define YUV_SHADER_PROLOGUE \
87"varying vec4 v_color;\n" \
88"varying vec2 v_texCoord;\n" \
89"uniform sampler2D tex0; // Y \n" \
90"uniform sampler2D tex1; // U \n" \
91"uniform sampler2D tex2; // V \n" \
92"uniform vec3 Yoffset;\n" \
93"uniform vec3 Rcoeff;\n" \
94"uniform vec3 Gcoeff;\n" \
95"uniform vec3 Bcoeff;\n" \
96"\n" \
97
98#define YUV_SHADER_BODY \
99"\n" \
100"void main()\n" \
101"{\n" \
102" vec2 tcoord;\n" \
103" vec3 yuv, rgb;\n" \
104"\n" \
105" // Get the Y value \n" \
106" tcoord = v_texCoord;\n" \
107" yuv.x = texture2D(tex0, tcoord).r;\n" \
108"\n" \
109" // Get the U and V values \n" \
110" tcoord *= UVCoordScale;\n" \
111" yuv.y = texture2D(tex1, tcoord).r;\n" \
112" yuv.z = texture2D(tex2, tcoord).r;\n" \
113"\n" \
114" // Do the color transform \n" \
115" yuv += Yoffset;\n" \
116" rgb.r = dot(yuv, Rcoeff);\n" \
117" rgb.g = dot(yuv, Gcoeff);\n" \
118" rgb.b = dot(yuv, Bcoeff);\n" \
119"\n" \
120" // That was easy. :) \n" \
121" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \
122"}" \
123
124#define NV12_SHADER_PROLOGUE \
125"varying vec4 v_color;\n" \
126"varying vec2 v_texCoord;\n" \
127"uniform sampler2D tex0; // Y \n" \
128"uniform sampler2D tex1; // U/V \n" \
129"uniform vec3 Yoffset;\n" \
130"uniform vec3 Rcoeff;\n" \
131"uniform vec3 Gcoeff;\n" \
132"uniform vec3 Bcoeff;\n" \
133"\n" \
134
135#define NV12_RA_SHADER_BODY \
136"\n" \
137"void main()\n" \
138"{\n" \
139" vec2 tcoord;\n" \
140" vec3 yuv, rgb;\n" \
141"\n" \
142" // Get the Y value \n" \
143" tcoord = v_texCoord;\n" \
144" yuv.x = texture2D(tex0, tcoord).r;\n" \
145"\n" \
146" // Get the U and V values \n" \
147" tcoord *= UVCoordScale;\n" \
148" yuv.yz = texture2D(tex1, tcoord).ra;\n" \
149"\n" \
150" // Do the color transform \n" \
151" yuv += Yoffset;\n" \
152" rgb.r = dot(yuv, Rcoeff);\n" \
153" rgb.g = dot(yuv, Gcoeff);\n" \
154" rgb.b = dot(yuv, Bcoeff);\n" \
155"\n" \
156" // That was easy. :) \n" \
157" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \
158"}" \
159
160#define NV12_RG_SHADER_BODY \
161"\n" \
162"void main()\n" \
163"{\n" \
164" vec2 tcoord;\n" \
165" vec3 yuv, rgb;\n" \
166"\n" \
167" // Get the Y value \n" \
168" tcoord = v_texCoord;\n" \
169" yuv.x = texture2D(tex0, tcoord).r;\n" \
170"\n" \
171" // Get the U and V values \n" \
172" tcoord *= UVCoordScale;\n" \
173" yuv.yz = texture2D(tex1, tcoord).rg;\n" \
174"\n" \
175" // Do the color transform \n" \
176" yuv += Yoffset;\n" \
177" rgb.r = dot(yuv, Rcoeff);\n" \
178" rgb.g = dot(yuv, Gcoeff);\n" \
179" rgb.b = dot(yuv, Bcoeff);\n" \
180"\n" \
181" // That was easy. :) \n" \
182" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \
183"}" \
184
185#define NV21_RA_SHADER_BODY \
186"\n" \
187"void main()\n" \
188"{\n" \
189" vec2 tcoord;\n" \
190" vec3 yuv, rgb;\n" \
191"\n" \
192" // Get the Y value \n" \
193" tcoord = v_texCoord;\n" \
194" yuv.x = texture2D(tex0, tcoord).r;\n" \
195"\n" \
196" // Get the U and V values \n" \
197" tcoord *= UVCoordScale;\n" \
198" yuv.yz = texture2D(tex1, tcoord).ar;\n" \
199"\n" \
200" // Do the color transform \n" \
201" yuv += Yoffset;\n" \
202" rgb.r = dot(yuv, Rcoeff);\n" \
203" rgb.g = dot(yuv, Gcoeff);\n" \
204" rgb.b = dot(yuv, Bcoeff);\n" \
205"\n" \
206" // That was easy. :) \n" \
207" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \
208"}" \
209
210#define NV21_RG_SHADER_BODY \
211"\n" \
212"void main()\n" \
213"{\n" \
214" vec2 tcoord;\n" \
215" vec3 yuv, rgb;\n" \
216"\n" \
217" // Get the Y value \n" \
218" tcoord = v_texCoord;\n" \
219" yuv.x = texture2D(tex0, tcoord).r;\n" \
220"\n" \
221" // Get the U and V values \n" \
222" tcoord *= UVCoordScale;\n" \
223" yuv.yz = texture2D(tex1, tcoord).gr;\n" \
224"\n" \
225" // Do the color transform \n" \
226" yuv += Yoffset;\n" \
227" rgb.r = dot(yuv, Rcoeff);\n" \
228" rgb.g = dot(yuv, Gcoeff);\n" \
229" rgb.b = dot(yuv, Bcoeff);\n" \
230"\n" \
231" // That was easy. :) \n" \
232" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \
233"}" \
234
235/*
236 * NOTE: Always use sampler2D, etc here. We'll #define them to the
237 * texture_rectangle versions if we choose to use that extension.
238 */
239static const char *shader_source[NUM_SHADERS][2] = {
240 // SHADER_NONE
241 { NULL, NULL },
242
243 // SHADER_SOLID
244 {
245 // vertex shader
246 COLOR_VERTEX_SHADER,
247 // fragment shader
248"varying vec4 v_color;\n"
249"\n"
250"void main()\n"
251"{\n"
252" gl_FragColor = v_color;\n"
253"}"
254 },
255
256 // SHADER_RGB
257 {
258 // vertex shader
259 TEXTURE_VERTEX_SHADER,
260 // fragment shader
261"varying vec4 v_color;\n"
262"varying vec2 v_texCoord;\n"
263"uniform sampler2D tex0;\n"
264"\n"
265"void main()\n"
266"{\n"
267" gl_FragColor = texture2D(tex0, v_texCoord);\n"
268" gl_FragColor.a = 1.0;\n"
269" gl_FragColor *= v_color;\n"
270"}"
271 },
272
273 // SHADER_RGBA
274 {
275 // vertex shader
276 TEXTURE_VERTEX_SHADER,
277 // fragment shader
278"varying vec4 v_color;\n"
279"varying vec2 v_texCoord;\n"
280"uniform sampler2D tex0;\n"
281"\n"
282"void main()\n"
283"{\n"
284" gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"
285"}"
286 },
287#ifdef SDL_HAVE_YUV
288 // SHADER_YUV
289 {
290 // vertex shader
291 TEXTURE_VERTEX_SHADER,
292 // fragment shader
293 YUV_SHADER_PROLOGUE
294 YUV_SHADER_BODY
295 },
296 // SHADER_NV12_RA
297 {
298 // vertex shader
299 TEXTURE_VERTEX_SHADER,
300 // fragment shader
301 NV12_SHADER_PROLOGUE
302 NV12_RA_SHADER_BODY
303 },
304 // SHADER_NV12_RG
305 {
306 // vertex shader
307 TEXTURE_VERTEX_SHADER,
308 // fragment shader
309 NV12_SHADER_PROLOGUE
310 NV12_RG_SHADER_BODY
311 },
312 // SHADER_NV21_RA
313 {
314 // vertex shader
315 TEXTURE_VERTEX_SHADER,
316 // fragment shader
317 NV12_SHADER_PROLOGUE
318 NV21_RA_SHADER_BODY
319 },
320 // SHADER_NV21_RG
321 {
322 // vertex shader
323 TEXTURE_VERTEX_SHADER,
324 // fragment shader
325 NV12_SHADER_PROLOGUE
326 NV21_RG_SHADER_BODY
327 },
328#endif // SDL_HAVE_YUV
329};
330
331/* *INDENT-ON* */ // clang-format on
332
333static bool CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *defines, const char *source)
334{
335 GLint status;
336 const char *sources[2];
337
338 sources[0] = defines;
339 sources[1] = source;
340
341 ctx->glShaderSourceARB(shader, SDL_arraysize(sources), sources, NULL);
342 ctx->glCompileShaderARB(shader);
343 ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
344 if (status == 0) {
345 bool isstack;
346 GLint length;
347 char *info;
348
349 ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
350 info = SDL_small_alloc(char, length + 1, &isstack);
351 if (info) {
352 ctx->glGetInfoLogARB(shader, length, NULL, info);
353 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to compile shader:");
354 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", defines);
355 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", source);
356 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", info);
357 SDL_small_free(info, isstack);
358 }
359 return false;
360 } else {
361 return true;
362 }
363}
364
365static bool CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data)
366{
367 const int num_tmus_bound = 4;
368 const char *vert_defines = "";
369 const char *frag_defines = "";
370 int i;
371 GLint location;
372
373 if (index == SHADER_NONE) {
374 return true;
375 }
376
377 ctx->glGetError();
378
379 // Make sure we use the correct sampler type for our texture type
380 if (ctx->GL_ARB_texture_rectangle_supported) {
381 frag_defines =
382 "#define sampler2D sampler2DRect\n"
383 "#define texture2D texture2DRect\n"
384 "#define UVCoordScale 0.5\n";
385 } else {
386 frag_defines =
387 "#define UVCoordScale 1.0\n";
388 }
389
390 // Create one program object to rule them all
391 data->program = ctx->glCreateProgramObjectARB();
392
393 // Create the vertex shader
394 data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
395 if (!CompileShader(ctx, data->vert_shader, vert_defines, shader_source[index][0])) {
396 return false;
397 }
398
399 // Create the fragment shader
400 data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
401 if (!CompileShader(ctx, data->frag_shader, frag_defines, shader_source[index][1])) {
402 return false;
403 }
404
405 // ... and in the darkness bind them
406 ctx->glAttachObjectARB(data->program, data->vert_shader);
407 ctx->glAttachObjectARB(data->program, data->frag_shader);
408 ctx->glLinkProgramARB(data->program);
409
410 // Set up some uniform variables
411 ctx->glUseProgramObjectARB(data->program);
412 for (i = 0; i < num_tmus_bound; ++i) {
413 char tex_name[10];
414 (void)SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
415 location = ctx->glGetUniformLocationARB(data->program, tex_name);
416 if (location >= 0) {
417 ctx->glUniform1iARB(location, i);
418 }
419 }
420 ctx->glUseProgramObjectARB(0);
421
422 return ctx->glGetError() == GL_NO_ERROR;
423}
424
425static void DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data)
426{
427 ctx->glDeleteObjectARB(data->vert_shader);
428 ctx->glDeleteObjectARB(data->frag_shader);
429 ctx->glDeleteObjectARB(data->program);
430}
431
432GL_ShaderContext *GL_CreateShaderContext(void)
433{
434 GL_ShaderContext *ctx;
435 bool shaders_supported;
436 int i;
437
438 ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx));
439 if (!ctx) {
440 return NULL;
441 }
442
443 if (!SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two") &&
444 (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
445 SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle"))) {
446 ctx->GL_ARB_texture_rectangle_supported = true;
447 }
448
449 // Check for shader support
450 shaders_supported = false;
451 if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
452 SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
453 SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
454 SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
455 ctx->glGetError = (GLenum(*)(void))SDL_GL_GetProcAddress("glGetError");
456 ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)SDL_GL_GetProcAddress("glAttachObjectARB");
457 ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)SDL_GL_GetProcAddress("glCompileShaderARB");
458 ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glCreateProgramObjectARB");
459 ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)SDL_GL_GetProcAddress("glCreateShaderObjectARB");
460 ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)SDL_GL_GetProcAddress("glDeleteObjectARB");
461 ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)SDL_GL_GetProcAddress("glGetInfoLogARB");
462 ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)SDL_GL_GetProcAddress("glGetObjectParameterivARB");
463 ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)SDL_GL_GetProcAddress("glGetUniformLocationARB");
464 ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)SDL_GL_GetProcAddress("glLinkProgramARB");
465 ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)SDL_GL_GetProcAddress("glShaderSourceARB");
466 ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC)SDL_GL_GetProcAddress("glUniform1iARB");
467 ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC)SDL_GL_GetProcAddress("glUniform1fARB");
468 ctx->glUniform3fARB = (PFNGLUNIFORM3FARBPROC)SDL_GL_GetProcAddress("glUniform3fARB");
469 ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glUseProgramObjectARB");
470 if (ctx->glGetError &&
471 ctx->glAttachObjectARB &&
472 ctx->glCompileShaderARB &&
473 ctx->glCreateProgramObjectARB &&
474 ctx->glCreateShaderObjectARB &&
475 ctx->glDeleteObjectARB &&
476 ctx->glGetInfoLogARB &&
477 ctx->glGetObjectParameterivARB &&
478 ctx->glGetUniformLocationARB &&
479 ctx->glLinkProgramARB &&
480 ctx->glShaderSourceARB &&
481 ctx->glUniform1iARB &&
482 ctx->glUniform1fARB &&
483 ctx->glUniform3fARB &&
484 ctx->glUseProgramObjectARB) {
485 shaders_supported = true;
486 }
487 }
488
489 if (!shaders_supported) {
490 SDL_free(ctx);
491 return NULL;
492 }
493
494 // Compile all the shaders
495 for (i = 0; i < NUM_SHADERS; ++i) {
496 if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) {
497 GL_DestroyShaderContext(ctx);
498 return NULL;
499 }
500 }
501
502 // We're done!
503 return ctx;
504}
505
506void GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader, const float *shader_params)
507{
508 GLint location;
509 GLhandleARB program = ctx->shaders[shader].program;
510
511 ctx->glUseProgramObjectARB(program);
512
513 if (shader_params && shader_params != ctx->shader_params[shader]) {
514 // YUV shader params are Yoffset, 0, Rcoeff, 0, Gcoeff, 0, Bcoeff, 0
515 location = ctx->glGetUniformLocationARB(program, "Yoffset");
516 if (location >= 0) {
517 ctx->glUniform3fARB(location, shader_params[0], shader_params[1], shader_params[2]);
518 }
519 location = ctx->glGetUniformLocationARB(program, "Rcoeff");
520 if (location >= 0) {
521 ctx->glUniform3fARB(location, shader_params[4], shader_params[5], shader_params[6]);
522 }
523 location = ctx->glGetUniformLocationARB(program, "Gcoeff");
524 if (location >= 0) {
525 ctx->glUniform3fARB(location, shader_params[8], shader_params[9], shader_params[10]);
526 }
527 location = ctx->glGetUniformLocationARB(program, "Bcoeff");
528 if (location >= 0) {
529 ctx->glUniform3fARB(location, shader_params[12], shader_params[13], shader_params[14]);
530 }
531 ctx->shader_params[shader] = shader_params;
532 }
533}
534
535void GL_DestroyShaderContext(GL_ShaderContext *ctx)
536{
537 int i;
538
539 for (i = 0; i < NUM_SHADERS; ++i) {
540 DestroyShaderProgram(ctx, &ctx->shaders[i]);
541 }
542 SDL_free(ctx);
543}
544
545#endif // SDL_VIDEO_RENDER_OGL