Atlas - SDL_shaders_gl.c
Home / ext / SDL / src / render / opengl Lines: 245 | Size: 31525 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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#ifdef SDL_VIDEO_RENDER_OGL 24 25#include <SDL3/SDL_opengl.h> 26#include "SDL_shaders_gl.h" 27 28// OpenGL shader implementation 29 30// #define DEBUG_SHADERS 31 32typedef struct 33{ 34 GLhandleARB program; 35 GLhandleARB vert_shader; 36 GLhandleARB frag_shader; 37} GL_ShaderData; 38 39struct GL_ShaderContext 40{ 41 GLenum (*glGetError)(void); 42 43 PFNGLATTACHOBJECTARBPROC glAttachObjectARB; 44 PFNGLCOMPILESHADERARBPROC glCompileShaderARB; 45 PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; 46 PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; 47 PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; 48 PFNGLGETINFOLOGARBPROC glGetInfoLogARB; 49 PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; 50 PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; 51 PFNGLLINKPROGRAMARBPROC glLinkProgramARB; 52 PFNGLSHADERSOURCEARBPROC glShaderSourceARB; 53 PFNGLUNIFORM1IARBPROC glUniform1iARB; 54 PFNGLUNIFORM1FARBPROC glUniform1fARB; 55 PFNGLUNIFORM3FARBPROC glUniform3fARB; 56 PFNGLUNIFORM4FARBPROC glUniform4fARB; 57 PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; 58 59 bool GL_ARB_texture_rectangle_supported; 60 61 GL_ShaderData shaders[NUM_SHADERS]; 62 float *shader_params[NUM_SHADERS]; 63}; 64 65/* *INDENT-OFF* */ // clang-format off 66 67#define COLOR_VERTEX_SHADER \ 68"varying vec4 v_color;\n" \ 69"\n" \ 70"void main()\n" \ 71"{\n" \ 72" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" \ 73" v_color = gl_Color;\n" \ 74"}" \ 75 76#define TEXTURE_VERTEX_SHADER \ 77"varying vec4 v_color;\n" \ 78"varying vec2 v_texCoord;\n" \ 79"\n" \ 80"void main()\n" \ 81"{\n" \ 82" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" \ 83" v_color = gl_Color;\n" \ 84" v_texCoord = vec2(gl_MultiTexCoord0);\n" \ 85"}" \ 86 87#define RGB_SHADER_PROLOGUE \ 88"varying vec4 v_color;\n" \ 89"varying vec2 v_texCoord;\n" \ 90"uniform sampler2D tex0;\n" \ 91"\n" 92 93#define RGB_PIXELART_SHADER_PROLOGUE \ 94"varying vec4 v_color;\n" \ 95"varying vec2 v_texCoord;\n" \ 96"uniform sampler2D tex0;\n" \ 97"uniform vec4 texel_size; // texel size (xy: texel size, zw: texture dimensions)\n" \ 98"\n" 99 100#define PALETTE_SHADER_PROLOGUE \ 101"varying vec4 v_color;\n" \ 102"varying vec2 v_texCoord;\n" \ 103"uniform sampler2D tex0;\n" \ 104"uniform sampler2D tex1;\n" \ 105"uniform vec4 texel_size; // texel size (xy: texel size, zw: texture dimensions)\n" \ 106"\n" 107 108// Implementation with thanks from bgolus: 109// https://discussions.unity.com/t/how-to-make-data-shader-support-bilinear-trilinear/598639/8 110#define PALETTE_SHADER_FUNCTIONS \ 111"vec4 SamplePaletteNearest(vec2 uv)\n" \ 112"{\n" \ 113" float index = texture2D(tex0, uv).r * 255.0;\n" \ 114" return texture2D(tex1, vec2((index + 0.5) / 256.0, 0.5));\n" \ 115"}\n" \ 116"\n" \ 117"vec4 SamplePaletteLinear(vec2 uv)\n" \ 118"{\n" \ 119" // scale & offset uvs to integer values at texel centers\n" \ 120" vec2 uv_texels = uv * texel_size.zw + 0.5;\n" \ 121"\n" \ 122" // get uvs for the center of the 4 surrounding texels by flooring\n" \ 123" vec4 uv_min_max = vec4((floor(uv_texels) - 0.5) * texel_size.xy, (floor(uv_texels) + 0.5) * texel_size.xy);\n" \ 124"\n" \ 125" // blend factor\n" \ 126" vec2 uv_frac = fract(uv_texels);\n" \ 127"\n" \ 128" // sample all 4 texels\n" \ 129" vec4 texelA = SamplePaletteNearest(uv_min_max.xy);\n" \ 130" vec4 texelB = SamplePaletteNearest(uv_min_max.xw);\n" \ 131" vec4 texelC = SamplePaletteNearest(uv_min_max.zy);\n" \ 132" vec4 texelD = SamplePaletteNearest(uv_min_max.zw);\n" \ 133"\n" \ 134" // bilinear interpolation\n" \ 135" return mix(mix(texelA, texelB, uv_frac.y), mix(texelC, texelD, uv_frac.y), uv_frac.x);\n" \ 136"}\n" \ 137"\n" 138 139#define PIXELART_SHADER_FUNCTIONS \ 140"vec2 GetPixelArtUV(vec2 uv)\n" \ 141"{\n" \ 142" vec2 boxSize = clamp(fwidth(uv) * texel_size.zw, 1e-5, 1.0);\n" \ 143" vec2 tx = uv * texel_size.zw - 0.5 * boxSize;\n" \ 144" vec2 txOffset = smoothstep(vec2(1.0) - boxSize, vec2(1.0), fract(tx));\n" \ 145" return (floor(tx) + 0.5 + txOffset) * texel_size.xy;\n" \ 146"}\n" \ 147"\n" \ 148"vec4 GetPixelArtSample(vec2 uv)\n" \ 149"{\n" \ 150" return textureGrad(tex0, GetPixelArtUV(uv), dFdx(v_texCoord), dFdy(v_texCoord));\n" \ 151"}\n" \ 152"\n" \ 153 154#define YUV_SHADER_PROLOGUE \ 155"varying vec4 v_color;\n" \ 156"varying vec2 v_texCoord;\n" \ 157"uniform sampler2D tex0; // Y \n" \ 158"uniform sampler2D tex1; // U \n" \ 159"uniform sampler2D tex2; // V \n" \ 160"uniform vec3 Yoffset;\n" \ 161"uniform vec3 Rcoeff;\n" \ 162"uniform vec3 Gcoeff;\n" \ 163"uniform vec3 Bcoeff;\n" \ 164"\n" \ 165 166#define YUV_SHADER_BODY \ 167"\n" \ 168"void main()\n" \ 169"{\n" \ 170" vec2 tcoord;\n" \ 171" vec3 yuv, rgb;\n" \ 172"\n" \ 173" // Get the Y value \n" \ 174" tcoord = v_texCoord;\n" \ 175" yuv.x = texture2D(tex0, tcoord).r;\n" \ 176"\n" \ 177" // Get the U and V values \n" \ 178" tcoord *= UVCoordScale;\n" \ 179" yuv.y = texture2D(tex1, tcoord).r;\n" \ 180" yuv.z = texture2D(tex2, tcoord).r;\n" \ 181"\n" \ 182" // Do the color transform \n" \ 183" yuv += Yoffset;\n" \ 184" rgb.r = dot(yuv, Rcoeff);\n" \ 185" rgb.g = dot(yuv, Gcoeff);\n" \ 186" rgb.b = dot(yuv, Bcoeff);\n" \ 187"\n" \ 188" // That was easy. :) \n" \ 189" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \ 190"}" \ 191 192#define NV12_SHADER_PROLOGUE \ 193"varying vec4 v_color;\n" \ 194"varying vec2 v_texCoord;\n" \ 195"uniform sampler2D tex0; // Y \n" \ 196"uniform sampler2D tex1; // U/V \n" \ 197"uniform vec3 Yoffset;\n" \ 198"uniform vec3 Rcoeff;\n" \ 199"uniform vec3 Gcoeff;\n" \ 200"uniform vec3 Bcoeff;\n" \ 201"\n" \ 202 203#define NV12_RA_SHADER_BODY \ 204"\n" \ 205"void main()\n" \ 206"{\n" \ 207" vec2 tcoord;\n" \ 208" vec3 yuv, rgb;\n" \ 209"\n" \ 210" // Get the Y value \n" \ 211" tcoord = v_texCoord;\n" \ 212" yuv.x = texture2D(tex0, tcoord).r;\n" \ 213"\n" \ 214" // Get the U and V values \n" \ 215" tcoord *= UVCoordScale;\n" \ 216" yuv.yz = texture2D(tex1, tcoord).ra;\n" \ 217"\n" \ 218" // Do the color transform \n" \ 219" yuv += Yoffset;\n" \ 220" rgb.r = dot(yuv, Rcoeff);\n" \ 221" rgb.g = dot(yuv, Gcoeff);\n" \ 222" rgb.b = dot(yuv, Bcoeff);\n" \ 223"\n" \ 224" // That was easy. :) \n" \ 225" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \ 226"}" \ 227 228#define NV12_RG_SHADER_BODY \ 229"\n" \ 230"void main()\n" \ 231"{\n" \ 232" vec2 tcoord;\n" \ 233" vec3 yuv, rgb;\n" \ 234"\n" \ 235" // Get the Y value \n" \ 236" tcoord = v_texCoord;\n" \ 237" yuv.x = texture2D(tex0, tcoord).r;\n" \ 238"\n" \ 239" // Get the U and V values \n" \ 240" tcoord *= UVCoordScale;\n" \ 241" yuv.yz = texture2D(tex1, tcoord).rg;\n" \ 242"\n" \ 243" // Do the color transform \n" \ 244" yuv += Yoffset;\n" \ 245" rgb.r = dot(yuv, Rcoeff);\n" \ 246" rgb.g = dot(yuv, Gcoeff);\n" \ 247" rgb.b = dot(yuv, Bcoeff);\n" \ 248"\n" \ 249" // That was easy. :) \n" \ 250" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \ 251"}" \ 252 253#define NV21_RA_SHADER_BODY \ 254"\n" \ 255"void main()\n" \ 256"{\n" \ 257" vec2 tcoord;\n" \ 258" vec3 yuv, rgb;\n" \ 259"\n" \ 260" // Get the Y value \n" \ 261" tcoord = v_texCoord;\n" \ 262" yuv.x = texture2D(tex0, tcoord).r;\n" \ 263"\n" \ 264" // Get the U and V values \n" \ 265" tcoord *= UVCoordScale;\n" \ 266" yuv.yz = texture2D(tex1, tcoord).ar;\n" \ 267"\n" \ 268" // Do the color transform \n" \ 269" yuv += Yoffset;\n" \ 270" rgb.r = dot(yuv, Rcoeff);\n" \ 271" rgb.g = dot(yuv, Gcoeff);\n" \ 272" rgb.b = dot(yuv, Bcoeff);\n" \ 273"\n" \ 274" // That was easy. :) \n" \ 275" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \ 276"}" \ 277 278#define NV21_RG_SHADER_BODY \ 279"\n" \ 280"void main()\n" \ 281"{\n" \ 282" vec2 tcoord;\n" \ 283" vec3 yuv, rgb;\n" \ 284"\n" \ 285" // Get the Y value \n" \ 286" tcoord = v_texCoord;\n" \ 287" yuv.x = texture2D(tex0, tcoord).r;\n" \ 288"\n" \ 289" // Get the U and V values \n" \ 290" tcoord *= UVCoordScale;\n" \ 291" yuv.yz = texture2D(tex1, tcoord).gr;\n" \ 292"\n" \ 293" // Do the color transform \n" \ 294" yuv += Yoffset;\n" \ 295" rgb.r = dot(yuv, Rcoeff);\n" \ 296" rgb.g = dot(yuv, Gcoeff);\n" \ 297" rgb.b = dot(yuv, Bcoeff);\n" \ 298"\n" \ 299" // That was easy. :) \n" \ 300" gl_FragColor = vec4(rgb, 1.0) * v_color;\n" \ 301"}" \ 302 303/* 304 * NOTE: Always use sampler2D, etc here. We'll #define them to the 305 * texture_rectangle versions if we choose to use that extension. 306 */ 307static struct { 308 const char *vertex_shader; 309 const char *fragment_shader; 310 const char *fragment_version; 311} shader_source[NUM_SHADERS] = { 312 // SHADER_NONE 313 { NULL, NULL, NULL }, 314 315 // SHADER_SOLID 316 { 317 // vertex shader 318 COLOR_VERTEX_SHADER, 319 // fragment shader 320"varying vec4 v_color;\n" 321"\n" 322"void main()\n" 323"{\n" 324" gl_FragColor = v_color;\n" 325"}", 326 // fragment version 327 NULL 328 }, 329 330 // SHADER_PALETTE_NEAREST 331 { 332 // vertex shader 333 TEXTURE_VERTEX_SHADER, 334 // fragment shader 335 PALETTE_SHADER_PROLOGUE 336 PALETTE_SHADER_FUNCTIONS 337"\n" 338"void main()\n" 339"{\n" 340" gl_FragColor = SamplePaletteNearest(v_texCoord) * v_color;\n" 341"}", 342 // fragment version 343 NULL 344 }, 345 346 // SHADER_PALETTE_LINEAR 347 { 348 // vertex shader 349 TEXTURE_VERTEX_SHADER, 350 // fragment shader 351 PALETTE_SHADER_PROLOGUE 352 PALETTE_SHADER_FUNCTIONS 353"\n" 354"void main()\n" 355"{\n" 356" gl_FragColor = SamplePaletteLinear(v_texCoord) * v_color;\n" 357"}", 358 // fragment version 359 NULL 360 }, 361 362 // SHADER_PALETTE_PIXELART 363 { 364 // vertex shader 365 TEXTURE_VERTEX_SHADER, 366 // fragment shader 367 PALETTE_SHADER_PROLOGUE 368 PALETTE_SHADER_FUNCTIONS 369 PIXELART_SHADER_FUNCTIONS 370"\n" 371"void main()\n" 372"{\n" 373" gl_FragColor = SamplePaletteLinear(GetPixelArtUV(v_texCoord)) * v_color;\n" 374"}", 375 // fragment version 376 "#version 130\n" 377 }, 378 379 // SHADER_RGB 380 { 381 // vertex shader 382 TEXTURE_VERTEX_SHADER, 383 // fragment shader 384 RGB_SHADER_PROLOGUE 385"\n" 386"void main()\n" 387"{\n" 388" gl_FragColor = texture2D(tex0, v_texCoord);\n" 389" gl_FragColor.a = 1.0;\n" 390" gl_FragColor *= v_color;\n" 391"}", 392 // fragment version 393 NULL 394 }, 395 396 // SHADER_RGB_PIXELART 397 { 398 // vertex shader 399 TEXTURE_VERTEX_SHADER, 400 // fragment shader 401 RGB_PIXELART_SHADER_PROLOGUE 402 PIXELART_SHADER_FUNCTIONS 403"\n" 404"void main()\n" 405"{\n" 406" gl_FragColor = GetPixelArtSample(v_texCoord);\n" 407" gl_FragColor.a = 1.0;\n" 408" gl_FragColor *= v_color;\n" 409"}", 410 // fragment version 411 "#version 130\n" 412 }, 413 414 // SHADER_RGBA 415 { 416 // vertex shader 417 TEXTURE_VERTEX_SHADER, 418 // fragment shader 419 RGB_SHADER_PROLOGUE 420"\n" 421"void main()\n" 422"{\n" 423" gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n" 424"}", 425 // fragment version 426 NULL 427 }, 428 429 // SHADER_RGBA_PIXELART 430 { 431 // vertex shader 432 TEXTURE_VERTEX_SHADER, 433 // fragment shader 434 RGB_PIXELART_SHADER_PROLOGUE 435 PIXELART_SHADER_FUNCTIONS 436"\n" 437"void main()\n" 438"{\n" 439" gl_FragColor = GetPixelArtSample(v_texCoord);\n" 440" gl_FragColor *= v_color;\n" 441"}", 442 // fragment version 443 "#version 130\n" 444 }, 445 446#ifdef SDL_HAVE_YUV 447 // SHADER_YUV 448 { 449 // vertex shader 450 TEXTURE_VERTEX_SHADER, 451 // fragment shader 452 YUV_SHADER_PROLOGUE 453 YUV_SHADER_BODY, 454 // fragment version 455 NULL 456 }, 457 // SHADER_NV12_RA 458 { 459 // vertex shader 460 TEXTURE_VERTEX_SHADER, 461 // fragment shader 462 NV12_SHADER_PROLOGUE 463 NV12_RA_SHADER_BODY, 464 // fragment version 465 NULL 466 }, 467 // SHADER_NV12_RG 468 { 469 // vertex shader 470 TEXTURE_VERTEX_SHADER, 471 // fragment shader 472 NV12_SHADER_PROLOGUE 473 NV12_RG_SHADER_BODY, 474 // fragment version 475 NULL 476 }, 477 // SHADER_NV21_RA 478 { 479 // vertex shader 480 TEXTURE_VERTEX_SHADER, 481 // fragment shader 482 NV12_SHADER_PROLOGUE 483 NV21_RA_SHADER_BODY, 484 // fragment version 485 NULL 486 }, 487 // SHADER_NV21_RG 488 { 489 // vertex shader 490 TEXTURE_VERTEX_SHADER, 491 // fragment shader 492 NV12_SHADER_PROLOGUE 493 NV21_RG_SHADER_BODY, 494 // fragment version 495 NULL 496 }, 497#endif // SDL_HAVE_YUV 498}; 499 500/* *INDENT-ON* */ // clang-format on 501 502static bool CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *version, const char *defines, const char *source) 503{ 504 GLint status; 505 const char *sources[3]; 506 507 sources[0] = version; 508 sources[1] = defines; 509 sources[2] = source; 510 511 ctx->glShaderSourceARB(shader, SDL_arraysize(sources), sources, NULL); 512 ctx->glCompileShaderARB(shader); 513 ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status); 514 if (status == 0) { 515 bool isstack; 516 GLint length; 517 char *info; 518 519 ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); 520 info = SDL_small_alloc(char, length + 1, &isstack); 521 if (info) { 522 ctx->glGetInfoLogARB(shader, length, NULL, info); 523 SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "Failed to compile shader:"); 524 if (version) { 525 SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "%s", version); 526 } 527 if (defines) { 528 SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "%s", defines); 529 } 530 SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "%s", source); 531 SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "%s", info); 532 SDL_small_free(info, isstack); 533 } 534 return false; 535 } else { 536 return true; 537 } 538} 539 540static bool CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data) 541{ 542 const int num_tmus_bound = 4; 543 const char *vert_defines = ""; 544 const char *frag_defines = ""; 545 const char *frag_version = ""; 546 int i; 547 GLint location; 548 549 if (index == SHADER_NONE) { 550 return true; 551 } 552 553 ctx->glGetError(); 554 555 // Make sure we use the correct sampler type for our texture type 556 if (ctx->GL_ARB_texture_rectangle_supported) { 557 frag_defines = 558 "#define sampler2D sampler2DRect\n" 559 "#define texture2D texture2DRect\n" 560 "#define UVCoordScale 0.5\n"; 561 } else { 562 frag_defines = 563 "#define UVCoordScale 1.0\n"; 564 } 565 if (shader_source[index].fragment_version) { 566 frag_version = shader_source[index].fragment_version; 567 } 568 569 // Create one program object to rule them all 570 data->program = ctx->glCreateProgramObjectARB(); 571 572 // Create the vertex shader 573 data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); 574 if (!CompileShader(ctx, data->vert_shader, "", vert_defines, shader_source[index].vertex_shader)) { 575 return false; 576 } 577 578 // Create the fragment shader 579 data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); 580 if (!CompileShader(ctx, data->frag_shader, frag_version, frag_defines, shader_source[index].fragment_shader)) { 581 return false; 582 } 583 584 // ... and in the darkness bind them 585 ctx->glAttachObjectARB(data->program, data->vert_shader); 586 ctx->glAttachObjectARB(data->program, data->frag_shader); 587 ctx->glLinkProgramARB(data->program); 588 589 // Set up some uniform variables 590 ctx->glUseProgramObjectARB(data->program); 591 for (i = 0; i < num_tmus_bound; ++i) { 592 char tex_name[10]; 593 (void)SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i); 594 location = ctx->glGetUniformLocationARB(data->program, tex_name); 595 if (location >= 0) { 596 ctx->glUniform1iARB(location, i); 597 } 598 } 599 ctx->glUseProgramObjectARB(0); 600 601 return ctx->glGetError() == GL_NO_ERROR; 602} 603 604static void DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data) 605{ 606 if (data->vert_shader) { 607 ctx->glDeleteObjectARB(data->vert_shader); 608 data->vert_shader = 0; 609 } 610 if (data->frag_shader) { 611 ctx->glDeleteObjectARB(data->frag_shader); 612 data->frag_shader = 0; 613 } 614 if (data->program) { 615 ctx->glDeleteObjectARB(data->program); 616 data->program = 0; 617 } 618} 619 620GL_ShaderContext *GL_CreateShaderContext(void) 621{ 622 GL_ShaderContext *ctx; 623 bool shaders_supported; 624 int i; 625 626 ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx)); 627 if (!ctx) { 628 return NULL; 629 } 630 631 if (!SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two") && 632 (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") || 633 SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle"))) { 634 ctx->GL_ARB_texture_rectangle_supported = true; 635 } 636 637 // Check for shader support 638 shaders_supported = false; 639 if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") && 640 SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") && 641 SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") && 642 SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) { 643 ctx->glGetError = (GLenum(*)(void))SDL_GL_GetProcAddress("glGetError"); 644 ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)SDL_GL_GetProcAddress("glAttachObjectARB"); 645 ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)SDL_GL_GetProcAddress("glCompileShaderARB"); 646 ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glCreateProgramObjectARB"); 647 ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)SDL_GL_GetProcAddress("glCreateShaderObjectARB"); 648 ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)SDL_GL_GetProcAddress("glDeleteObjectARB"); 649 ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)SDL_GL_GetProcAddress("glGetInfoLogARB"); 650 ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)SDL_GL_GetProcAddress("glGetObjectParameterivARB"); 651 ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)SDL_GL_GetProcAddress("glGetUniformLocationARB"); 652 ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)SDL_GL_GetProcAddress("glLinkProgramARB"); 653 ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)SDL_GL_GetProcAddress("glShaderSourceARB"); 654 ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC)SDL_GL_GetProcAddress("glUniform1iARB"); 655 ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC)SDL_GL_GetProcAddress("glUniform1fARB"); 656 ctx->glUniform3fARB = (PFNGLUNIFORM3FARBPROC)SDL_GL_GetProcAddress("glUniform3fARB"); 657 ctx->glUniform4fARB = (PFNGLUNIFORM4FARBPROC)SDL_GL_GetProcAddress("glUniform4fARB"); 658 ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glUseProgramObjectARB"); 659 if (ctx->glGetError && 660 ctx->glAttachObjectARB && 661 ctx->glCompileShaderARB && 662 ctx->glCreateProgramObjectARB && 663 ctx->glCreateShaderObjectARB && 664 ctx->glDeleteObjectARB && 665 ctx->glGetInfoLogARB && 666 ctx->glGetObjectParameterivARB && 667 ctx->glGetUniformLocationARB && 668 ctx->glLinkProgramARB && 669 ctx->glShaderSourceARB && 670 ctx->glUniform1iARB && 671 ctx->glUniform1fARB && 672 ctx->glUniform3fARB && 673 ctx->glUseProgramObjectARB) { 674 shaders_supported = true; 675 } 676 } 677 678 if (!shaders_supported) { 679 SDL_free(ctx); 680 return NULL; 681 } 682 683 // Compile all the shaders 684 for (i = 0; i < NUM_SHADERS; ++i) { 685 if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) { 686 DestroyShaderProgram(ctx, &ctx->shaders[i]); 687 } 688 } 689 690 // We're done! 691 return ctx; 692} 693 694bool GL_SupportsShader(GL_ShaderContext *ctx, GL_Shader shader) 695{ 696 return ctx && ctx->shaders[shader].program; 697} 698 699void GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader, const float *shader_params) 700{ 701 GLint location; 702 GLhandleARB program = ctx->shaders[shader].program; 703 704 ctx->glUseProgramObjectARB(program); 705 706 int shader_params_len = 0; 707 if (shader == SHADER_PALETTE_LINEAR || 708 shader == SHADER_PALETTE_PIXELART || 709 shader == SHADER_RGB_PIXELART || 710 shader == SHADER_RGBA_PIXELART) { 711 shader_params_len = 4 * sizeof(float); 712#ifdef SDL_HAVE_YUV 713 } else if (shader >= SHADER_YUV) { 714 shader_params_len = 16 * sizeof(float); 715#endif 716 } 717 SDL_assert(!shader_params || shader_params_len > 0); 718 719 if (shader_params && 720 (!ctx->shader_params[shader] || 721 SDL_memcmp(shader_params, ctx->shader_params[shader], shader_params_len) != 0)) { 722 if (shader == SHADER_PALETTE_LINEAR || 723 shader == SHADER_PALETTE_PIXELART || 724 shader == SHADER_RGB_PIXELART || 725 shader == SHADER_RGBA_PIXELART) { 726 location = ctx->glGetUniformLocationARB(program, "texel_size"); 727 if (location >= 0) { 728 ctx->glUniform4fARB(location, shader_params[0], shader_params[1], shader_params[2], shader_params[3]); 729 } 730 } 731 732#ifdef SDL_HAVE_YUV 733 if (shader >= SHADER_YUV) { 734 // YUV shader params are Yoffset, 0, Rcoeff, 0, Gcoeff, 0, Bcoeff, 0 735 location = ctx->glGetUniformLocationARB(program, "Yoffset"); 736 if (location >= 0) { 737 ctx->glUniform3fARB(location, shader_params[0], shader_params[1], shader_params[2]); 738 } 739 location = ctx->glGetUniformLocationARB(program, "Rcoeff"); 740 if (location >= 0) { 741 ctx->glUniform3fARB(location, shader_params[4], shader_params[5], shader_params[6]); 742 } 743 location = ctx->glGetUniformLocationARB(program, "Gcoeff"); 744 if (location >= 0) { 745 ctx->glUniform3fARB(location, shader_params[8], shader_params[9], shader_params[10]); 746 } 747 location = ctx->glGetUniformLocationARB(program, "Bcoeff"); 748 if (location >= 0) { 749 ctx->glUniform3fARB(location, shader_params[12], shader_params[13], shader_params[14]); 750 } 751 } 752#endif // SDL_HAVE_YUV 753 754 if (!ctx->shader_params[shader]) { 755 ctx->shader_params[shader] = (float *)SDL_malloc(shader_params_len); 756 } 757 if (ctx->shader_params[shader]) { 758 SDL_memcpy(ctx->shader_params[shader], shader_params, shader_params_len); 759 } 760 } 761} 762 763void GL_DestroyShaderContext(GL_ShaderContext *ctx) 764{ 765 int i; 766 767 for (i = 0; i < NUM_SHADERS; ++i) { 768 DestroyShaderProgram(ctx, &ctx->shaders[i]); 769 SDL_free(ctx->shader_params[i]); 770 } 771 SDL_free(ctx); 772} 773 774#endif // SDL_VIDEO_RENDER_OGL 775[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.