SDL  2.0
SDL_shaders_gl.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 
35 typedef struct
36 {
38  GLhandleARB vert_shader;
39  GLhandleARB frag_shader;
40 } GL_ShaderData;
41 
42 struct GL_ShaderContext
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  */
214 static 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) * v_color;\n"
244 "}"
245  },
246 
247  /* SHADER_YUV_JPEG */
248  {
249  /* vertex shader */
250  TEXTURE_VERTEX_SHADER,
251  /* fragment shader */
252  YUV_SHADER_PROLOGUE
253  JPEG_SHADER_CONSTANTS
254  YUV_SHADER_BODY
255  },
256  /* SHADER_YUV_BT601 */
257  {
258  /* vertex shader */
259  TEXTURE_VERTEX_SHADER,
260  /* fragment shader */
261  YUV_SHADER_PROLOGUE
262  BT601_SHADER_CONSTANTS
263  YUV_SHADER_BODY
264  },
265  /* SHADER_YUV_BT709 */
266  {
267  /* vertex shader */
268  TEXTURE_VERTEX_SHADER,
269  /* fragment shader */
270  YUV_SHADER_PROLOGUE
271  BT709_SHADER_CONSTANTS
272  YUV_SHADER_BODY
273  },
274  /* SHADER_NV12_JPEG */
275  {
276  /* vertex shader */
277  TEXTURE_VERTEX_SHADER,
278  /* fragment shader */
279  NV12_SHADER_PROLOGUE
280  JPEG_SHADER_CONSTANTS
281  NV12_SHADER_BODY
282  },
283  /* SHADER_NV12_BT601 */
284  {
285  /* vertex shader */
286  TEXTURE_VERTEX_SHADER,
287  /* fragment shader */
288  NV12_SHADER_PROLOGUE
289  BT601_SHADER_CONSTANTS
290  NV12_SHADER_BODY
291  },
292  /* SHADER_NV12_BT709 */
293  {
294  /* vertex shader */
295  TEXTURE_VERTEX_SHADER,
296  /* fragment shader */
297  NV12_SHADER_PROLOGUE
298  BT709_SHADER_CONSTANTS
299  NV12_SHADER_BODY
300  },
301  /* SHADER_NV21_JPEG */
302  {
303  /* vertex shader */
304  TEXTURE_VERTEX_SHADER,
305  /* fragment shader */
306  NV21_SHADER_PROLOGUE
307  JPEG_SHADER_CONSTANTS
308  NV21_SHADER_BODY
309  },
310  /* SHADER_NV21_BT601 */
311  {
312  /* vertex shader */
313  TEXTURE_VERTEX_SHADER,
314  /* fragment shader */
315  NV21_SHADER_PROLOGUE
316  BT601_SHADER_CONSTANTS
317  NV21_SHADER_BODY
318  },
319  /* SHADER_NV21_BT709 */
320  {
321  /* vertex shader */
322  TEXTURE_VERTEX_SHADER,
323  /* fragment shader */
324  NV21_SHADER_PROLOGUE
325  BT709_SHADER_CONSTANTS
326  NV21_SHADER_BODY
327  },
328 };
329 
330 static SDL_bool
331 CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *defines, const char *source)
332 {
333  GLint status;
334  const char *sources[2];
335 
336  sources[0] = defines;
337  sources[1] = source;
338 
339  ctx->glShaderSourceARB(shader, SDL_arraysize(sources), sources, NULL);
340  ctx->glCompileShaderARB(shader);
341  ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
342  if (status == 0) {
343  GLint length;
344  char *info;
345 
346  ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
347  info = SDL_stack_alloc(char, length+1);
348  ctx->glGetInfoLogARB(shader, length, NULL, info);
350  "Failed to compile shader:\n%s%s\n%s", defines, source, info);
351 #ifdef DEBUG_SHADERS
352  fprintf(stderr,
353  "Failed to compile shader:\n%s%s\n%s", defines, source, info);
354 #endif
355  SDL_stack_free(info);
356 
357  return SDL_FALSE;
358  } else {
359  return SDL_TRUE;
360  }
361 }
362 
363 static SDL_bool
364 CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data)
365 {
366  const int num_tmus_bound = 4;
367  const char *vert_defines = "";
368  const char *frag_defines = "";
369  int i;
370  GLint location;
371 
372  if (index == SHADER_NONE) {
373  return SDL_TRUE;
374  }
375 
376  ctx->glGetError();
377 
378  /* Make sure we use the correct sampler type for our texture type */
379  if (ctx->GL_ARB_texture_rectangle_supported) {
380  frag_defines =
381 "#define sampler2D sampler2DRect\n"
382 "#define texture2D texture2DRect\n"
383 "#define UVCoordScale 0.5\n";
384  } else {
385  frag_defines =
386 "#define UVCoordScale 1.0\n";
387  }
388 
389  /* Create one program object to rule them all */
390  data->program = ctx->glCreateProgramObjectARB();
391 
392  /* Create the vertex shader */
393  data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
394  if (!CompileShader(ctx, data->vert_shader, vert_defines, shader_source[index][0])) {
395  return SDL_FALSE;
396  }
397 
398  /* Create the fragment shader */
399  data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
400  if (!CompileShader(ctx, data->frag_shader, frag_defines, shader_source[index][1])) {
401  return SDL_FALSE;
402  }
403 
404  /* ... and in the darkness bind them */
405  ctx->glAttachObjectARB(data->program, data->vert_shader);
406  ctx->glAttachObjectARB(data->program, data->frag_shader);
407  ctx->glLinkProgramARB(data->program);
408 
409  /* Set up some uniform variables */
410  ctx->glUseProgramObjectARB(data->program);
411  for (i = 0; i < num_tmus_bound; ++i) {
412  char tex_name[10];
413  SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
414  location = ctx->glGetUniformLocationARB(data->program, tex_name);
415  if (location >= 0) {
416  ctx->glUniform1iARB(location, i);
417  }
418  }
419  ctx->glUseProgramObjectARB(0);
420 
421  return (ctx->glGetError() == GL_NO_ERROR);
422 }
423 
424 static void
425 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 
434 {
436  SDL_bool shaders_supported;
437  int i;
438 
439  ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx));
440  if (!ctx) {
441  return NULL;
442  }
443 
444  if (!SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two") &&
445  (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
446  SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle"))) {
447  ctx->GL_ARB_texture_rectangle_supported = SDL_TRUE;
448  }
449 
450  /* Check for shader support */
451  shaders_supported = SDL_FALSE;
452  if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
453  SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
454  SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
455  SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
456  ctx->glGetError = (GLenum (*)(void)) SDL_GL_GetProcAddress("glGetError");
457  ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
458  ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
459  ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
460  ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
461  ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
462  ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
463  ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
464  ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
465  ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
466  ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
467  ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
468  ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
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->glUseProgramObjectARB) {
484  shaders_supported = SDL_TRUE;
485  }
486  }
487 
488  if (!shaders_supported) {
489  SDL_free(ctx);
490  return NULL;
491  }
492 
493  /* Compile all the shaders */
494  for (i = 0; i < NUM_SHADERS; ++i) {
495  if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) {
497  return NULL;
498  }
499  }
500 
501  /* We're done! */
502  return ctx;
503 }
504 
505 void
507 {
508  ctx->glUseProgramObjectARB(ctx->shaders[shader].program);
509 }
510 
511 void
513 {
514  int i;
515 
516  for (i = 0; i < NUM_SHADERS; ++i) {
517  DestroyShaderProgram(ctx, &ctx->shaders[i]);
518  }
519  SDL_free(ctx);
520 }
521 
522 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
523 
524 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_GL_ExtensionSupported
GL_ShaderContext * GL_CreateShaderContext(void)
GLsizei GLenum * sources
int GLint
Definition: SDL_opengl.h:182
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
#define GL_VERTEX_SHADER_ARB
GLsizei GLsizei GLuint * shaders
unsigned int GLhandleARB
struct GL_ShaderContext GL_ShaderContext
void GL_DestroyShaderContext(GL_ShaderContext *ctx)
#define SDL_LogError
#define GL_NO_ERROR
Definition: SDL_opengl.h:719
GL_Shader
#define SDL_free
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:354
#define SDL_GL_GetProcAddress
GLint location
#define GL_OBJECT_INFO_LOG_LENGTH_ARB
#define GL_OBJECT_COMPILE_STATUS_ARB
GLsizei GLsizei GLchar * source
GLuint index
#define GL_FRAGMENT_SHADER_ARB
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
unsigned int GLenum
Definition: SDL_opengl.h:176
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:139
#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
GLAPI GLenum GLAPIENTRY glGetError(void)
#define SDL_snprintf
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
GLbitfield GLuint program
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:355
GLuint GLsizei GLsizei * length
void GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader)
GLuint shader
EGLContext ctx
Definition: eglext.h:208