SDL  2.0
SDL_shaders_gl.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2017 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 /*
66  * NOTE: Always use sampler2D, etc here. We'll #define them to the
67  * texture_rectangle versions if we choose to use that extension.
68  */
69 static const char *shader_source[NUM_SHADERS][2] =
70 {
71  /* SHADER_NONE */
72  { NULL, NULL },
73 
74  /* SHADER_SOLID */
75  {
76  /* vertex shader */
77 "varying vec4 v_color;\n"
78 "\n"
79 "void main()\n"
80 "{\n"
81 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
82 " v_color = gl_Color;\n"
83 "}",
84  /* fragment shader */
85 "varying vec4 v_color;\n"
86 "\n"
87 "void main()\n"
88 "{\n"
89 " gl_FragColor = v_color;\n"
90 "}"
91  },
92 
93  /* SHADER_RGB */
94  {
95  /* vertex shader */
96 "varying vec4 v_color;\n"
97 "varying vec2 v_texCoord;\n"
98 "\n"
99 "void main()\n"
100 "{\n"
101 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
102 " v_color = gl_Color;\n"
103 " v_texCoord = vec2(gl_MultiTexCoord0);\n"
104 "}",
105  /* fragment shader */
106 "varying vec4 v_color;\n"
107 "varying vec2 v_texCoord;\n"
108 "uniform sampler2D tex0;\n"
109 "\n"
110 "void main()\n"
111 "{\n"
112 " gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"
113 "}"
114  },
115 
116  /* SHADER_YUV */
117  {
118  /* vertex shader */
119 "varying vec4 v_color;\n"
120 "varying vec2 v_texCoord;\n"
121 "\n"
122 "void main()\n"
123 "{\n"
124 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
125 " v_color = gl_Color;\n"
126 " v_texCoord = vec2(gl_MultiTexCoord0);\n"
127 "}",
128  /* fragment shader */
129 "varying vec4 v_color;\n"
130 "varying vec2 v_texCoord;\n"
131 "uniform sampler2D tex0; // Y \n"
132 "uniform sampler2D tex1; // U \n"
133 "uniform sampler2D tex2; // V \n"
134 "\n"
135 "// YUV offset \n"
136 "const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
137 "\n"
138 "// RGB coefficients \n"
139 "const vec3 Rcoeff = vec3(1.164, 0.000, 1.596);\n"
140 "const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
141 "const vec3 Bcoeff = vec3(1.164, 2.018, 0.000);\n"
142 "\n"
143 "void main()\n"
144 "{\n"
145 " vec2 tcoord;\n"
146 " vec3 yuv, rgb;\n"
147 "\n"
148 " // Get the Y value \n"
149 " tcoord = v_texCoord;\n"
150 " yuv.x = texture2D(tex0, tcoord).r;\n"
151 "\n"
152 " // Get the U and V values \n"
153 " tcoord *= UVCoordScale;\n"
154 " yuv.y = texture2D(tex1, tcoord).r;\n"
155 " yuv.z = texture2D(tex2, tcoord).r;\n"
156 "\n"
157 " // Do the color transform \n"
158 " yuv += offset;\n"
159 " rgb.r = dot(yuv, Rcoeff);\n"
160 " rgb.g = dot(yuv, Gcoeff);\n"
161 " rgb.b = dot(yuv, Bcoeff);\n"
162 "\n"
163 " // That was easy. :) \n"
164 " gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
165 "}"
166  },
167 
168  /* SHADER_NV12 */
169  {
170  /* vertex shader */
171 "varying vec4 v_color;\n"
172 "varying vec2 v_texCoord;\n"
173 "\n"
174 "void main()\n"
175 "{\n"
176 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
177 " v_color = gl_Color;\n"
178 " v_texCoord = vec2(gl_MultiTexCoord0);\n"
179 "}",
180  /* fragment shader */
181 "varying vec4 v_color;\n"
182 "varying vec2 v_texCoord;\n"
183 "uniform sampler2D tex0; // Y \n"
184 "uniform sampler2D tex1; // U/V \n"
185 "\n"
186 "// YUV offset \n"
187 "const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
188 "\n"
189 "// RGB coefficients \n"
190 "const vec3 Rcoeff = vec3(1.164, 0.000, 1.596);\n"
191 "const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
192 "const vec3 Bcoeff = vec3(1.164, 2.018, 0.000);\n"
193 "\n"
194 "void main()\n"
195 "{\n"
196 " vec2 tcoord;\n"
197 " vec3 yuv, rgb;\n"
198 "\n"
199 " // Get the Y value \n"
200 " tcoord = v_texCoord;\n"
201 " yuv.x = texture2D(tex0, tcoord).r;\n"
202 "\n"
203 " // Get the U and V values \n"
204 " tcoord *= UVCoordScale;\n"
205 " yuv.yz = texture2D(tex1, tcoord).ra;\n"
206 "\n"
207 " // Do the color transform \n"
208 " yuv += offset;\n"
209 " rgb.r = dot(yuv, Rcoeff);\n"
210 " rgb.g = dot(yuv, Gcoeff);\n"
211 " rgb.b = dot(yuv, Bcoeff);\n"
212 "\n"
213 " // That was easy. :) \n"
214 " gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
215 "}"
216  },
217 
218  /* SHADER_NV21 */
219  {
220  /* vertex shader */
221 "varying vec4 v_color;\n"
222 "varying vec2 v_texCoord;\n"
223 "\n"
224 "void main()\n"
225 "{\n"
226 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
227 " v_color = gl_Color;\n"
228 " v_texCoord = vec2(gl_MultiTexCoord0);\n"
229 "}",
230  /* fragment shader */
231 "varying vec4 v_color;\n"
232 "varying vec2 v_texCoord;\n"
233 "uniform sampler2D tex0; // Y \n"
234 "uniform sampler2D tex1; // U/V \n"
235 "\n"
236 "// YUV offset \n"
237 "const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
238 "\n"
239 "// RGB coefficients \n"
240 "const vec3 Rcoeff = vec3(1.164, 0.000, 1.596);\n"
241 "const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
242 "const vec3 Bcoeff = vec3(1.164, 2.018, 0.000);\n"
243 "\n"
244 "void main()\n"
245 "{\n"
246 " vec2 tcoord;\n"
247 " vec3 yuv, rgb;\n"
248 "\n"
249 " // Get the Y value \n"
250 " tcoord = v_texCoord;\n"
251 " yuv.x = texture2D(tex0, tcoord).r;\n"
252 "\n"
253 " // Get the U and V values \n"
254 " tcoord *= UVCoordScale;\n"
255 " yuv.yz = texture2D(tex1, tcoord).ar;\n"
256 "\n"
257 " // Do the color transform \n"
258 " yuv += offset;\n"
259 " rgb.r = dot(yuv, Rcoeff);\n"
260 " rgb.g = dot(yuv, Gcoeff);\n"
261 " rgb.b = dot(yuv, Bcoeff);\n"
262 "\n"
263 " // That was easy. :) \n"
264 " gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
265 "}"
266  },
267 };
268 
269 static SDL_bool
270 CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *defines, const char *source)
271 {
272  GLint status;
273  const char *sources[2];
274 
275  sources[0] = defines;
276  sources[1] = source;
277 
278  ctx->glShaderSourceARB(shader, SDL_arraysize(sources), sources, NULL);
279  ctx->glCompileShaderARB(shader);
280  ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
281  if (status == 0) {
282  GLint length;
283  char *info;
284 
285  ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
286  info = SDL_stack_alloc(char, length+1);
287  ctx->glGetInfoLogARB(shader, length, NULL, info);
289  "Failed to compile shader:\n%s%s\n%s", defines, source, info);
290 #ifdef DEBUG_SHADERS
291  fprintf(stderr,
292  "Failed to compile shader:\n%s%s\n%s", defines, source, info);
293 #endif
294  SDL_stack_free(info);
295 
296  return SDL_FALSE;
297  } else {
298  return SDL_TRUE;
299  }
300 }
301 
302 static SDL_bool
303 CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data)
304 {
305  const int num_tmus_bound = 4;
306  const char *vert_defines = "";
307  const char *frag_defines = "";
308  int i;
309  GLint location;
310 
311  if (index == SHADER_NONE) {
312  return SDL_TRUE;
313  }
314 
315  ctx->glGetError();
316 
317  /* Make sure we use the correct sampler type for our texture type */
318  if (ctx->GL_ARB_texture_rectangle_supported) {
319  frag_defines =
320 "#define sampler2D sampler2DRect\n"
321 "#define texture2D texture2DRect\n"
322 "#define UVCoordScale 0.5\n";
323  } else {
324  frag_defines =
325 "#define UVCoordScale 1.0\n";
326  }
327 
328  /* Create one program object to rule them all */
329  data->program = ctx->glCreateProgramObjectARB();
330 
331  /* Create the vertex shader */
332  data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
333  if (!CompileShader(ctx, data->vert_shader, vert_defines, shader_source[index][0])) {
334  return SDL_FALSE;
335  }
336 
337  /* Create the fragment shader */
338  data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
339  if (!CompileShader(ctx, data->frag_shader, frag_defines, shader_source[index][1])) {
340  return SDL_FALSE;
341  }
342 
343  /* ... and in the darkness bind them */
344  ctx->glAttachObjectARB(data->program, data->vert_shader);
345  ctx->glAttachObjectARB(data->program, data->frag_shader);
346  ctx->glLinkProgramARB(data->program);
347 
348  /* Set up some uniform variables */
349  ctx->glUseProgramObjectARB(data->program);
350  for (i = 0; i < num_tmus_bound; ++i) {
351  char tex_name[10];
352  SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
353  location = ctx->glGetUniformLocationARB(data->program, tex_name);
354  if (location >= 0) {
355  ctx->glUniform1iARB(location, i);
356  }
357  }
358  ctx->glUseProgramObjectARB(0);
359 
360  return (ctx->glGetError() == GL_NO_ERROR);
361 }
362 
363 static void
364 DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data)
365 {
366  ctx->glDeleteObjectARB(data->vert_shader);
367  ctx->glDeleteObjectARB(data->frag_shader);
368  ctx->glDeleteObjectARB(data->program);
369 }
370 
373 {
375  SDL_bool shaders_supported;
376  int i;
377 
378  ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx));
379  if (!ctx) {
380  return NULL;
381  }
382 
383  if (!SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two") &&
384  (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
385  SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle"))) {
386  ctx->GL_ARB_texture_rectangle_supported = SDL_TRUE;
387  }
388 
389  /* Check for shader support */
390  shaders_supported = SDL_FALSE;
391  if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
392  SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
393  SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
394  SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
395  ctx->glGetError = (GLenum (*)(void)) SDL_GL_GetProcAddress("glGetError");
396  ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
397  ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
398  ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
399  ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
400  ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
401  ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
402  ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
403  ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
404  ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
405  ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
406  ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
407  ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
408  ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
409  if (ctx->glGetError &&
410  ctx->glAttachObjectARB &&
411  ctx->glCompileShaderARB &&
412  ctx->glCreateProgramObjectARB &&
413  ctx->glCreateShaderObjectARB &&
414  ctx->glDeleteObjectARB &&
415  ctx->glGetInfoLogARB &&
416  ctx->glGetObjectParameterivARB &&
417  ctx->glGetUniformLocationARB &&
418  ctx->glLinkProgramARB &&
419  ctx->glShaderSourceARB &&
420  ctx->glUniform1iARB &&
421  ctx->glUniform1fARB &&
422  ctx->glUseProgramObjectARB) {
423  shaders_supported = SDL_TRUE;
424  }
425  }
426 
427  if (!shaders_supported) {
428  SDL_free(ctx);
429  return NULL;
430  }
431 
432  /* Compile all the shaders */
433  for (i = 0; i < NUM_SHADERS; ++i) {
434  if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) {
436  return NULL;
437  }
438  }
439 
440  /* We're done! */
441  return ctx;
442 }
443 
444 void
446 {
447  ctx->glUseProgramObjectARB(ctx->shaders[shader].program);
448 }
449 
450 void
452 {
453  int i;
454 
455  for (i = 0; i < NUM_SHADERS; ++i) {
456  DestroyShaderProgram(ctx, &ctx->shaders[i]);
457  }
458  SDL_free(ctx);
459 }
460 
461 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
462 
463 /* 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
void * SDL_calloc(size_t nmemb, size_t size)
GL_Shader
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:354
#define SDL_GL_GetProcAddress
void SDL_free(void *mem)
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
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