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