SDL 2.0
SDL_shaders_gl.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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#if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
24
25#include "SDL_stdinc.h"
26#include "SDL_log.h"
27#include "SDL_opengl.h"
28#include "SDL_video.h"
29#include "SDL_shaders_gl.h"
30
31/* OpenGL shader implementation */
32
33/* #define DEBUG_SHADERS */
34
35typedef struct
36{
38 GLhandleARB vert_shader;
39 GLhandleARB frag_shader;
40} GL_ShaderData;
41
43{
45
46 PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
47 PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
48 PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
49 PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
50 PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
51 PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
52 PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
53 PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
54 PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
55 PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
56 PFNGLUNIFORM1IARBPROC glUniform1iARB;
57 PFNGLUNIFORM1FARBPROC glUniform1fARB;
58 PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
59
60 SDL_bool GL_ARB_texture_rectangle_supported;
61
62 GL_ShaderData shaders[NUM_SHADERS];
63};
64
65#define COLOR_VERTEX_SHADER \
66"varying vec4 v_color;\n" \
67"\n" \
68"void main()\n" \
69"{\n" \
70" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" \
71" v_color = gl_Color;\n" \
72"}" \
73
74#define TEXTURE_VERTEX_SHADER \
75"varying vec4 v_color;\n" \
76"varying vec2 v_texCoord;\n" \
77"\n" \
78"void main()\n" \
79"{\n" \
80" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" \
81" v_color = gl_Color;\n" \
82" v_texCoord = vec2(gl_MultiTexCoord0);\n" \
83"}" \
84
85#define JPEG_SHADER_CONSTANTS \
86"// YUV offset \n" \
87"const vec3 offset = vec3(0, -0.501960814, -0.501960814);\n" \
88"\n" \
89"// RGB coefficients \n" \
90"const vec3 Rcoeff = vec3(1, 0.000, 1.402);\n" \
91"const vec3 Gcoeff = vec3(1, -0.3441, -0.7141);\n" \
92"const vec3 Bcoeff = vec3(1, 1.772, 0.000);\n" \
93
94#define BT601_SHADER_CONSTANTS \
95"// YUV offset \n" \
96"const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n" \
97"\n" \
98"// RGB coefficients \n" \
99"const vec3 Rcoeff = vec3(1.1644, 0.000, 1.596);\n" \
100"const vec3 Gcoeff = vec3(1.1644, -0.3918, -0.813);\n" \
101"const vec3 Bcoeff = vec3(1.1644, 2.0172, 0.000);\n" \
102
103#define BT709_SHADER_CONSTANTS \
104"// YUV offset \n" \
105"const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n" \
106"\n" \
107"// RGB coefficients \n" \
108"const vec3 Rcoeff = vec3(1.1644, 0.000, 1.7927);\n" \
109"const vec3 Gcoeff = vec3(1.1644, -0.2132, -0.5329);\n" \
110"const vec3 Bcoeff = vec3(1.1644, 2.1124, 0.000);\n" \
111
112#define YUV_SHADER_PROLOGUE \
113"varying vec4 v_color;\n" \
114"varying vec2 v_texCoord;\n" \
115"uniform sampler2D tex0; // Y \n" \
116"uniform sampler2D tex1; // U \n" \
117"uniform sampler2D tex2; // V \n" \
118"\n" \
119
120#define YUV_SHADER_BODY \
121"\n" \
122"void main()\n" \
123"{\n" \
124" vec2 tcoord;\n" \
125" vec3 yuv, rgb;\n" \
126"\n" \
127" // Get the Y value \n" \
128" tcoord = v_texCoord;\n" \
129" yuv.x = texture2D(tex0, tcoord).r;\n" \
130"\n" \
131" // Get the U and V values \n" \
132" tcoord *= UVCoordScale;\n" \
133" yuv.y = texture2D(tex1, tcoord).r;\n" \
134" yuv.z = texture2D(tex2, tcoord).r;\n" \
135"\n" \
136" // Do the color transform \n" \
137" yuv += offset;\n" \
138" rgb.r = dot(yuv, Rcoeff);\n" \
139" rgb.g = dot(yuv, Gcoeff);\n" \
140" rgb.b = dot(yuv, Bcoeff);\n" \
141"\n" \
142" // That was easy. :) \n" \
143" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \
144"}" \
145
146#define NV12_SHADER_PROLOGUE \
147"varying vec4 v_color;\n" \
148"varying vec2 v_texCoord;\n" \
149"uniform sampler2D tex0; // Y \n" \
150"uniform sampler2D tex1; // U/V \n" \
151"\n" \
152
153#define NV12_SHADER_BODY \
154"\n" \
155"void main()\n" \
156"{\n" \
157" vec2 tcoord;\n" \
158" vec3 yuv, rgb;\n" \
159"\n" \
160" // Get the Y value \n" \
161" tcoord = v_texCoord;\n" \
162" yuv.x = texture2D(tex0, tcoord).r;\n" \
163"\n" \
164" // Get the U and V values \n" \
165" tcoord *= UVCoordScale;\n" \
166" yuv.yz = texture2D(tex1, tcoord).ra;\n" \
167"\n" \
168" // Do the color transform \n" \
169" yuv += offset;\n" \
170" rgb.r = dot(yuv, Rcoeff);\n" \
171" rgb.g = dot(yuv, Gcoeff);\n" \
172" rgb.b = dot(yuv, Bcoeff);\n" \
173"\n" \
174" // That was easy. :) \n" \
175" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \
176"}" \
177
178#define NV21_SHADER_PROLOGUE \
179"varying vec4 v_color;\n" \
180"varying vec2 v_texCoord;\n" \
181"uniform sampler2D tex0; // Y \n" \
182"uniform sampler2D tex1; // U/V \n" \
183"\n" \
184
185#define NV21_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 += offset;\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/*
211 * NOTE: Always use sampler2D, etc here. We'll #define them to the
212 * texture_rectangle versions if we choose to use that extension.
213 */
214static const char *shader_source[NUM_SHADERS][2] =
215{
216 /* SHADER_NONE */
217 { NULL, NULL },
218
219 /* SHADER_SOLID */
220 {
221 /* vertex shader */
222 COLOR_VERTEX_SHADER,
223 /* fragment shader */
224"varying vec4 v_color;\n"
225"\n"
226"void main()\n"
227"{\n"
228" gl_FragColor = v_color;\n"
229"}"
230 },
231
232 /* SHADER_RGB */
233 {
234 /* vertex shader */
235 TEXTURE_VERTEX_SHADER,
236 /* fragment shader */
237"varying vec4 v_color;\n"
238"varying vec2 v_texCoord;\n"
239"uniform sampler2D tex0;\n"
240"\n"
241"void main()\n"
242"{\n"
243" gl_FragColor = texture2D(tex0, v_texCoord);\n"
244" gl_FragColor.a = 1.0;\n"
245" gl_FragColor *= v_color;\n"
246"}"
247 },
248
249 /* SHADER_RGBA */
250 {
251 /* vertex shader */
252 TEXTURE_VERTEX_SHADER,
253 /* fragment shader */
254"varying vec4 v_color;\n"
255"varying vec2 v_texCoord;\n"
256"uniform sampler2D tex0;\n"
257"\n"
258"void main()\n"
259"{\n"
260" gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"
261"}"
262 },
263
264 /* SHADER_YUV_JPEG */
265 {
266 /* vertex shader */
267 TEXTURE_VERTEX_SHADER,
268 /* fragment shader */
269 YUV_SHADER_PROLOGUE
270 JPEG_SHADER_CONSTANTS
271 YUV_SHADER_BODY
272 },
273 /* SHADER_YUV_BT601 */
274 {
275 /* vertex shader */
276 TEXTURE_VERTEX_SHADER,
277 /* fragment shader */
278 YUV_SHADER_PROLOGUE
279 BT601_SHADER_CONSTANTS
280 YUV_SHADER_BODY
281 },
282 /* SHADER_YUV_BT709 */
283 {
284 /* vertex shader */
285 TEXTURE_VERTEX_SHADER,
286 /* fragment shader */
287 YUV_SHADER_PROLOGUE
288 BT709_SHADER_CONSTANTS
289 YUV_SHADER_BODY
290 },
291 /* SHADER_NV12_JPEG */
292 {
293 /* vertex shader */
294 TEXTURE_VERTEX_SHADER,
295 /* fragment shader */
296 NV12_SHADER_PROLOGUE
297 JPEG_SHADER_CONSTANTS
298 NV12_SHADER_BODY
299 },
300 /* SHADER_NV12_BT601 */
301 {
302 /* vertex shader */
303 TEXTURE_VERTEX_SHADER,
304 /* fragment shader */
305 NV12_SHADER_PROLOGUE
306 BT601_SHADER_CONSTANTS
307 NV12_SHADER_BODY
308 },
309 /* SHADER_NV12_BT709 */
310 {
311 /* vertex shader */
312 TEXTURE_VERTEX_SHADER,
313 /* fragment shader */
314 NV12_SHADER_PROLOGUE
315 BT709_SHADER_CONSTANTS
316 NV12_SHADER_BODY
317 },
318 /* SHADER_NV21_JPEG */
319 {
320 /* vertex shader */
321 TEXTURE_VERTEX_SHADER,
322 /* fragment shader */
323 NV21_SHADER_PROLOGUE
324 JPEG_SHADER_CONSTANTS
325 NV21_SHADER_BODY
326 },
327 /* SHADER_NV21_BT601 */
328 {
329 /* vertex shader */
330 TEXTURE_VERTEX_SHADER,
331 /* fragment shader */
332 NV21_SHADER_PROLOGUE
333 BT601_SHADER_CONSTANTS
334 NV21_SHADER_BODY
335 },
336 /* SHADER_NV21_BT709 */
337 {
338 /* vertex shader */
339 TEXTURE_VERTEX_SHADER,
340 /* fragment shader */
341 NV21_SHADER_PROLOGUE
342 BT709_SHADER_CONSTANTS
343 NV21_SHADER_BODY
344 },
345};
346
347static SDL_bool
348CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *defines, const char *source)
349{
350 GLint status;
351 const char *sources[2];
352
353 sources[0] = defines;
354 sources[1] = source;
355
356 ctx->glShaderSourceARB(shader, SDL_arraysize(sources), sources, NULL);
357 ctx->glCompileShaderARB(shader);
358 ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
359 if (status == 0) {
360 SDL_bool isstack;
362 char *info;
363
364 ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
365 info = SDL_small_alloc(char, length+1, &isstack);
366 ctx->glGetInfoLogARB(shader, length, NULL, info);
368 "Failed to compile shader:\n%s%s\n%s", defines, source, info);
369#ifdef DEBUG_SHADERS
370 fprintf(stderr,
371 "Failed to compile shader:\n%s%s\n%s", defines, source, info);
372#endif
373 SDL_small_free(info, isstack);
374
375 return SDL_FALSE;
376 } else {
377 return SDL_TRUE;
378 }
379}
380
381static SDL_bool
382CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data)
383{
384 const int num_tmus_bound = 4;
385 const char *vert_defines = "";
386 const char *frag_defines = "";
387 int i;
389
390 if (index == SHADER_NONE) {
391 return SDL_TRUE;
392 }
393
394 ctx->glGetError();
395
396 /* Make sure we use the correct sampler type for our texture type */
397 if (ctx->GL_ARB_texture_rectangle_supported) {
398 frag_defines =
399"#define sampler2D sampler2DRect\n"
400"#define texture2D texture2DRect\n"
401"#define UVCoordScale 0.5\n";
402 } else {
403 frag_defines =
404"#define UVCoordScale 1.0\n";
405 }
406
407 /* Create one program object to rule them all */
408 data->program = ctx->glCreateProgramObjectARB();
409
410 /* Create the vertex shader */
411 data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
412 if (!CompileShader(ctx, data->vert_shader, vert_defines, shader_source[index][0])) {
413 return SDL_FALSE;
414 }
415
416 /* Create the fragment shader */
417 data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
418 if (!CompileShader(ctx, data->frag_shader, frag_defines, shader_source[index][1])) {
419 return SDL_FALSE;
420 }
421
422 /* ... and in the darkness bind them */
423 ctx->glAttachObjectARB(data->program, data->vert_shader);
424 ctx->glAttachObjectARB(data->program, data->frag_shader);
425 ctx->glLinkProgramARB(data->program);
426
427 /* Set up some uniform variables */
428 ctx->glUseProgramObjectARB(data->program);
429 for (i = 0; i < num_tmus_bound; ++i) {
430 char tex_name[10];
431 SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
432 location = ctx->glGetUniformLocationARB(data->program, tex_name);
433 if (location >= 0) {
434 ctx->glUniform1iARB(location, i);
435 }
436 }
437 ctx->glUseProgramObjectARB(0);
438
439 return (ctx->glGetError() == GL_NO_ERROR);
440}
441
442static void
443DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data)
444{
445 ctx->glDeleteObjectARB(data->vert_shader);
446 ctx->glDeleteObjectARB(data->frag_shader);
447 ctx->glDeleteObjectARB(data->program);
448}
449
452{
454 SDL_bool shaders_supported;
455 int i;
456
457 ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx));
458 if (!ctx) {
459 return NULL;
460 }
461
462 if (!SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two") &&
463 (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
464 SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle"))) {
465 ctx->GL_ARB_texture_rectangle_supported = SDL_TRUE;
466 }
467
468 /* Check for shader support */
469 shaders_supported = SDL_FALSE;
470 if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
471 SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
472 SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
473 SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
474 ctx->glGetError = (GLenum (*)(void)) SDL_GL_GetProcAddress("glGetError");
475 ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
476 ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
477 ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
478 ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
479 ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
480 ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
481 ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
482 ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
483 ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
484 ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
485 ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
486 ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
487 ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
488 if (ctx->glGetError &&
489 ctx->glAttachObjectARB &&
490 ctx->glCompileShaderARB &&
491 ctx->glCreateProgramObjectARB &&
492 ctx->glCreateShaderObjectARB &&
493 ctx->glDeleteObjectARB &&
494 ctx->glGetInfoLogARB &&
495 ctx->glGetObjectParameterivARB &&
496 ctx->glGetUniformLocationARB &&
497 ctx->glLinkProgramARB &&
498 ctx->glShaderSourceARB &&
499 ctx->glUniform1iARB &&
500 ctx->glUniform1fARB &&
501 ctx->glUseProgramObjectARB) {
502 shaders_supported = SDL_TRUE;
503 }
504 }
505
506 if (!shaders_supported) {
507 SDL_free(ctx);
508 return NULL;
509 }
510
511 /* Compile all the shaders */
512 for (i = 0; i < NUM_SHADERS; ++i) {
513 if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) {
515 return NULL;
516 }
517 }
518
519 /* We're done! */
520 return ctx;
521}
522
523void
525{
526 ctx->glUseProgramObjectARB(ctx->shaders[shader].program);
527}
528
529void
531{
532 int i;
533
534 for (i = 0; i < NUM_SHADERS; ++i) {
535 DestroyShaderProgram(ctx, &ctx->shaders[i]);
536 }
537 SDL_free(ctx);
538}
539
540#endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
541
542/* vi: set ts=4 sw=4 expandtab: */
#define SDL_LogError
#define SDL_free
#define SDL_GL_GetProcAddress
#define SDL_GL_ExtensionSupported
#define SDL_snprintf
#define SDL_calloc
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
#define SDL_small_alloc(type, count, pisstack)
Definition: SDL_internal.h:39
#define SDL_small_free(ptr, isstack)
Definition: SDL_internal.h:40
@ SDL_LOG_CATEGORY_RENDER
Definition: SDL_log.h:72
unsigned int GLenum
Definition: SDL_opengl.h:176
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
#define GL_NO_ERROR
Definition: SDL_opengl.h:719
GLAPI GLenum GLAPIENTRY glGetError(void)
int GLint
Definition: SDL_opengl.h:182
#define GL_OBJECT_INFO_LOG_LENGTH_ARB
GLuint shader
GLuint index
#define GL_FRAGMENT_SHADER_ARB
#define GL_OBJECT_COMPILE_STATUS_ARB
GLsizei GLsizei GLchar * source
GLint location
#define GL_VERTEX_SHADER_ARB
unsigned int GLhandleARB
GLsizei GLsizei GLuint * shaders
GLuint GLsizei GLsizei * length
GLbitfield GLuint program
GLsizei GLenum * sources
@ NUM_SHADERS
void GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader)
void GL_DestroyShaderContext(GL_ShaderContext *ctx)
struct GL_ShaderContext GL_ShaderContext
GL_Shader
@ SHADER_NONE
GL_ShaderContext * GL_CreateShaderContext(void)
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
EGLContext ctx
Definition: eglext.h:208