SDL_shaders_gl.c (13945B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 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{ 37 GLhandleARB program; 38 GLhandleARB vert_shader; 39 GLhandleARB frag_shader; 40} GL_ShaderData; 41 42struct GL_ShaderContext 43{ 44 GLenum (*glGetError)(void); 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 */ 69static 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 269static SDL_bool 270CompileShader(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); 288 SDL_LogError(SDL_LOG_CATEGORY_RENDER, 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 302static SDL_bool 303CompileShaderProgram(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 363static void 364DestroyShaderProgram(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 371GL_ShaderContext * 372GL_CreateShaderContext() 373{ 374 GL_ShaderContext *ctx; 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])) { 435 GL_DestroyShaderContext(ctx); 436 return NULL; 437 } 438 } 439 440 /* We're done! */ 441 return ctx; 442} 443 444void 445GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader) 446{ 447 ctx->glUseProgramObjectARB(ctx->shaders[shader].program); 448} 449 450void 451GL_DestroyShaderContext(GL_ShaderContext *ctx) 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: */