| 1 | /* | 
| 2 |   Simple DirectMedia Layer | 
| 3 |   Copyright (C) 1997-2025 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 | #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 |  | 
| 32 | typedef struct | 
| 33 | { | 
| 34 |     GLhandleARB program; | 
| 35 |     GLhandleARB vert_shader; | 
| 36 |     GLhandleARB frag_shader; | 
| 37 | } GL_ShaderData; | 
| 38 |  | 
| 39 | struct 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 |     const 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 YUV_SHADER_PROLOGUE                                     \ | 
| 88 | "varying vec4 v_color;\n"                                       \ | 
| 89 | "varying vec2 v_texCoord;\n"                                    \ | 
| 90 | "uniform sampler2D tex0; // Y \n"                               \ | 
| 91 | "uniform sampler2D tex1; // U \n"                               \ | 
| 92 | "uniform sampler2D tex2; // V \n"                               \ | 
| 93 | "uniform vec3 Yoffset;\n"                                       \ | 
| 94 | "uniform vec3 Rcoeff;\n"                                        \ | 
| 95 | "uniform vec3 Gcoeff;\n"                                        \ | 
| 96 | "uniform vec3 Bcoeff;\n"                                        \ | 
| 97 | "\n"                                                            \ | 
| 98 |  | 
| 99 | #define YUV_SHADER_BODY                                         \ | 
| 100 | "\n"                                                            \ | 
| 101 | "void main()\n"                                                 \ | 
| 102 | "{\n"                                                           \ | 
| 103 | "    vec2 tcoord;\n"                                            \ | 
| 104 | "    vec3 yuv, rgb;\n"                                          \ | 
| 105 | "\n"                                                            \ | 
| 106 | "    // Get the Y value \n"                                     \ | 
| 107 | "    tcoord = v_texCoord;\n"                                    \ | 
| 108 | "    yuv.x = texture2D(tex0, tcoord).r;\n"                      \ | 
| 109 | "\n"                                                            \ | 
| 110 | "    // Get the U and V values \n"                              \ | 
| 111 | "    tcoord *= UVCoordScale;\n"                                 \ | 
| 112 | "    yuv.y = texture2D(tex1, tcoord).r;\n"                      \ | 
| 113 | "    yuv.z = texture2D(tex2, tcoord).r;\n"                      \ | 
| 114 | "\n"                                                            \ | 
| 115 | "    // Do the color transform \n"                              \ | 
| 116 | "    yuv += Yoffset;\n"                                         \ | 
| 117 | "    rgb.r = dot(yuv, Rcoeff);\n"                               \ | 
| 118 | "    rgb.g = dot(yuv, Gcoeff);\n"                               \ | 
| 119 | "    rgb.b = dot(yuv, Bcoeff);\n"                               \ | 
| 120 | "\n"                                                            \ | 
| 121 | "    // That was easy. :) \n"                                   \ | 
| 122 | "    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"                \ | 
| 123 | "}"                                                             \ | 
| 124 |  | 
| 125 | #define NV12_SHADER_PROLOGUE                                    \ | 
| 126 | "varying vec4 v_color;\n"                                       \ | 
| 127 | "varying vec2 v_texCoord;\n"                                    \ | 
| 128 | "uniform sampler2D tex0; // Y \n"                               \ | 
| 129 | "uniform sampler2D tex1; // U/V \n"                             \ | 
| 130 | "uniform vec3 Yoffset;\n"                                       \ | 
| 131 | "uniform vec3 Rcoeff;\n"                                        \ | 
| 132 | "uniform vec3 Gcoeff;\n"                                        \ | 
| 133 | "uniform vec3 Bcoeff;\n"                                        \ | 
| 134 | "\n"                                                            \ | 
| 135 |  | 
| 136 | #define NV12_RA_SHADER_BODY                                     \ | 
| 137 | "\n"                                                            \ | 
| 138 | "void main()\n"                                                 \ | 
| 139 | "{\n"                                                           \ | 
| 140 | "    vec2 tcoord;\n"                                            \ | 
| 141 | "    vec3 yuv, rgb;\n"                                          \ | 
| 142 | "\n"                                                            \ | 
| 143 | "    // Get the Y value \n"                                     \ | 
| 144 | "    tcoord = v_texCoord;\n"                                    \ | 
| 145 | "    yuv.x = texture2D(tex0, tcoord).r;\n"                      \ | 
| 146 | "\n"                                                            \ | 
| 147 | "    // Get the U and V values \n"                              \ | 
| 148 | "    tcoord *= UVCoordScale;\n"                                 \ | 
| 149 | "    yuv.yz = texture2D(tex1, tcoord).ra;\n"                    \ | 
| 150 | "\n"                                                            \ | 
| 151 | "    // Do the color transform \n"                              \ | 
| 152 | "    yuv += Yoffset;\n"                                         \ | 
| 153 | "    rgb.r = dot(yuv, Rcoeff);\n"                               \ | 
| 154 | "    rgb.g = dot(yuv, Gcoeff);\n"                               \ | 
| 155 | "    rgb.b = dot(yuv, Bcoeff);\n"                               \ | 
| 156 | "\n"                                                            \ | 
| 157 | "    // That was easy. :) \n"                                   \ | 
| 158 | "    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"                \ | 
| 159 | "}"                                                             \ | 
| 160 |  | 
| 161 | #define NV12_RG_SHADER_BODY                                     \ | 
| 162 | "\n"                                                            \ | 
| 163 | "void main()\n"                                                 \ | 
| 164 | "{\n"                                                           \ | 
| 165 | "    vec2 tcoord;\n"                                            \ | 
| 166 | "    vec3 yuv, rgb;\n"                                          \ | 
| 167 | "\n"                                                            \ | 
| 168 | "    // Get the Y value \n"                                     \ | 
| 169 | "    tcoord = v_texCoord;\n"                                    \ | 
| 170 | "    yuv.x = texture2D(tex0, tcoord).r;\n"                      \ | 
| 171 | "\n"                                                            \ | 
| 172 | "    // Get the U and V values \n"                              \ | 
| 173 | "    tcoord *= UVCoordScale;\n"                                 \ | 
| 174 | "    yuv.yz = texture2D(tex1, tcoord).rg;\n"                    \ | 
| 175 | "\n"                                                            \ | 
| 176 | "    // Do the color transform \n"                              \ | 
| 177 | "    yuv += Yoffset;\n"                                         \ | 
| 178 | "    rgb.r = dot(yuv, Rcoeff);\n"                               \ | 
| 179 | "    rgb.g = dot(yuv, Gcoeff);\n"                               \ | 
| 180 | "    rgb.b = dot(yuv, Bcoeff);\n"                               \ | 
| 181 | "\n"                                                            \ | 
| 182 | "    // That was easy. :) \n"                                   \ | 
| 183 | "    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"                \ | 
| 184 | "}"                                                             \ | 
| 185 |  | 
| 186 | #define NV21_RA_SHADER_BODY                                     \ | 
| 187 | "\n"                                                            \ | 
| 188 | "void main()\n"                                                 \ | 
| 189 | "{\n"                                                           \ | 
| 190 | "    vec2 tcoord;\n"                                            \ | 
| 191 | "    vec3 yuv, rgb;\n"                                          \ | 
| 192 | "\n"                                                            \ | 
| 193 | "    // Get the Y value \n"                                     \ | 
| 194 | "    tcoord = v_texCoord;\n"                                    \ | 
| 195 | "    yuv.x = texture2D(tex0, tcoord).r;\n"                      \ | 
| 196 | "\n"                                                            \ | 
| 197 | "    // Get the U and V values \n"                              \ | 
| 198 | "    tcoord *= UVCoordScale;\n"                                 \ | 
| 199 | "    yuv.yz = texture2D(tex1, tcoord).ar;\n"                    \ | 
| 200 | "\n"                                                            \ | 
| 201 | "    // Do the color transform \n"                              \ | 
| 202 | "    yuv += Yoffset;\n"                                         \ | 
| 203 | "    rgb.r = dot(yuv, Rcoeff);\n"                               \ | 
| 204 | "    rgb.g = dot(yuv, Gcoeff);\n"                               \ | 
| 205 | "    rgb.b = dot(yuv, Bcoeff);\n"                               \ | 
| 206 | "\n"                                                            \ | 
| 207 | "    // That was easy. :) \n"                                   \ | 
| 208 | "    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"                \ | 
| 209 | "}"                                                             \ | 
| 210 |  | 
| 211 | #define NV21_RG_SHADER_BODY                                     \ | 
| 212 | "\n"                                                            \ | 
| 213 | "void main()\n"                                                 \ | 
| 214 | "{\n"                                                           \ | 
| 215 | "    vec2 tcoord;\n"                                            \ | 
| 216 | "    vec3 yuv, rgb;\n"                                          \ | 
| 217 | "\n"                                                            \ | 
| 218 | "    // Get the Y value \n"                                     \ | 
| 219 | "    tcoord = v_texCoord;\n"                                    \ | 
| 220 | "    yuv.x = texture2D(tex0, tcoord).r;\n"                      \ | 
| 221 | "\n"                                                            \ | 
| 222 | "    // Get the U and V values \n"                              \ | 
| 223 | "    tcoord *= UVCoordScale;\n"                                 \ | 
| 224 | "    yuv.yz = texture2D(tex1, tcoord).gr;\n"                    \ | 
| 225 | "\n"                                                            \ | 
| 226 | "    // Do the color transform \n"                              \ | 
| 227 | "    yuv += Yoffset;\n"                                         \ | 
| 228 | "    rgb.r = dot(yuv, Rcoeff);\n"                               \ | 
| 229 | "    rgb.g = dot(yuv, Gcoeff);\n"                               \ | 
| 230 | "    rgb.b = dot(yuv, Bcoeff);\n"                               \ | 
| 231 | "\n"                                                            \ | 
| 232 | "    // That was easy. :) \n"                                   \ | 
| 233 | "    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"                \ | 
| 234 | "}"                                                             \ | 
| 235 |  | 
| 236 | /* | 
| 237 |  * NOTE: Always use sampler2D, etc here. We'll #define them to the | 
| 238 |  *  texture_rectangle versions if we choose to use that extension. | 
| 239 |  */ | 
| 240 | static struct { | 
| 241 |     const char *vertex_shader; | 
| 242 |     const char *fragment_shader; | 
| 243 |     const char *fragment_version; | 
| 244 | } shader_source[NUM_SHADERS] = { | 
| 245 |     // SHADER_NONE | 
| 246 |     { NULL, NULL, NULL }, | 
| 247 |  | 
| 248 |     // SHADER_SOLID | 
| 249 |     { | 
| 250 |         // vertex shader | 
| 251 |         COLOR_VERTEX_SHADER, | 
| 252 |         // fragment shader | 
| 253 | "varying vec4 v_color;\n"  | 
| 254 | "\n"  | 
| 255 | "void main()\n"  | 
| 256 | "{\n"  | 
| 257 | "    gl_FragColor = v_color;\n"  | 
| 258 | "}" , | 
| 259 |         // fragment version | 
| 260 |         NULL | 
| 261 |     }, | 
| 262 |  | 
| 263 |     // SHADER_RGB | 
| 264 |     { | 
| 265 |         // vertex shader | 
| 266 |         TEXTURE_VERTEX_SHADER, | 
| 267 |         // fragment shader | 
| 268 | "varying vec4 v_color;\n"  | 
| 269 | "varying vec2 v_texCoord;\n"  | 
| 270 | "uniform sampler2D tex0;\n"  | 
| 271 | "uniform vec4 texel_size; // texel size (xy: texel size, zw: texture dimensions)\n"  | 
| 272 | "\n"  | 
| 273 | "void main()\n"  | 
| 274 | "{\n"  | 
| 275 | "    gl_FragColor = texture2D(tex0, v_texCoord);\n"  | 
| 276 | "    gl_FragColor.a = 1.0;\n"  | 
| 277 | "    gl_FragColor *= v_color;\n"  | 
| 278 | "}" , | 
| 279 |         // fragment version | 
| 280 |         NULL | 
| 281 |     }, | 
| 282 |  | 
| 283 |     // SHADER_RGBA | 
| 284 |     { | 
| 285 |         // vertex shader | 
| 286 |         TEXTURE_VERTEX_SHADER, | 
| 287 |         // fragment shader | 
| 288 | "varying vec4 v_color;\n"  | 
| 289 | "varying vec2 v_texCoord;\n"  | 
| 290 | "uniform sampler2D tex0;\n"  | 
| 291 | "\n"  | 
| 292 | "void main()\n"  | 
| 293 | "{\n"  | 
| 294 | "    gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"  | 
| 295 | "}" , | 
| 296 |         // fragment version | 
| 297 |         NULL | 
| 298 |     }, | 
| 299 |  | 
| 300 |     // SHADER_RGB_PIXELART | 
| 301 |     { | 
| 302 |         // vertex shader | 
| 303 |         TEXTURE_VERTEX_SHADER, | 
| 304 |         // fragment shader | 
| 305 | "varying vec4 v_color;\n"  | 
| 306 | "varying vec2 v_texCoord;\n"  | 
| 307 | "uniform sampler2D tex0;\n"  | 
| 308 | "uniform vec4 texel_size;\n"  | 
| 309 | "\n"  | 
| 310 | "void main()\n"  | 
| 311 | "{\n"  | 
| 312 | "    vec2 boxSize = clamp(fwidth(v_texCoord) * texel_size.zw, 1e-5, 1.0);\n"  | 
| 313 | "    vec2 tx = v_texCoord * texel_size.zw - 0.5 * boxSize;\n"  | 
| 314 | "    vec2 txOffset = smoothstep(vec2(1.0) - boxSize, vec2(1.0), fract(tx));\n"  | 
| 315 | "    vec2 uv = (floor(tx) + 0.5 + txOffset) * texel_size.xy;\n"  | 
| 316 | "    gl_FragColor = textureGrad(tex0, uv, dFdx(v_texCoord), dFdy(v_texCoord));\n"  | 
| 317 | "    gl_FragColor.a = 1.0;\n"  | 
| 318 | "    gl_FragColor *= v_color;\n"  | 
| 319 | "}" , | 
| 320 |         // fragment version | 
| 321 |         "#version 130\n"  | 
| 322 |     }, | 
| 323 |  | 
| 324 |     // SHADER_RGBA_PIXELART | 
| 325 |     { | 
| 326 |         // vertex shader | 
| 327 |         TEXTURE_VERTEX_SHADER, | 
| 328 |         // fragment shader | 
| 329 | "varying vec4 v_color;\n"  | 
| 330 | "varying vec2 v_texCoord;\n"  | 
| 331 | "uniform sampler2D tex0;\n"  | 
| 332 | "uniform vec4 texel_size;\n"  | 
| 333 | "\n"  | 
| 334 | "void main()\n"  | 
| 335 | "{\n"  | 
| 336 | "    vec2 boxSize = clamp(fwidth(v_texCoord) * texel_size.zw, 1e-5, 1.0);\n"  | 
| 337 | "    vec2 tx = v_texCoord * texel_size.zw - 0.5 * boxSize;\n"  | 
| 338 | "    vec2 txOffset = smoothstep(vec2(1.0) - boxSize, vec2(1.0), fract(tx));\n"  | 
| 339 | "    vec2 uv = (floor(tx) + 0.5 + txOffset) * texel_size.xy;\n"  | 
| 340 | "    gl_FragColor = textureGrad(tex0, uv, dFdx(v_texCoord), dFdy(v_texCoord));\n"  | 
| 341 | "    gl_FragColor *= v_color;\n"  | 
| 342 | "}" , | 
| 343 |         // fragment version | 
| 344 |         "#version 130\n"  | 
| 345 |     }, | 
| 346 |  | 
| 347 | #ifdef SDL_HAVE_YUV | 
| 348 |     // SHADER_YUV | 
| 349 |     { | 
| 350 |         // vertex shader | 
| 351 |         TEXTURE_VERTEX_SHADER, | 
| 352 |         // fragment shader | 
| 353 |         YUV_SHADER_PROLOGUE | 
| 354 |         YUV_SHADER_BODY, | 
| 355 |         // fragment version | 
| 356 |         NULL | 
| 357 |     }, | 
| 358 |     // SHADER_NV12_RA | 
| 359 |     { | 
| 360 |         // vertex shader | 
| 361 |         TEXTURE_VERTEX_SHADER, | 
| 362 |         // fragment shader | 
| 363 |         NV12_SHADER_PROLOGUE | 
| 364 |         NV12_RA_SHADER_BODY, | 
| 365 |         // fragment version | 
| 366 |         NULL | 
| 367 |     }, | 
| 368 |     // SHADER_NV12_RG | 
| 369 |     { | 
| 370 |         // vertex shader | 
| 371 |         TEXTURE_VERTEX_SHADER, | 
| 372 |         // fragment shader | 
| 373 |         NV12_SHADER_PROLOGUE | 
| 374 |         NV12_RG_SHADER_BODY, | 
| 375 |         // fragment version | 
| 376 |         NULL | 
| 377 |     }, | 
| 378 |     // SHADER_NV21_RA | 
| 379 |     { | 
| 380 |         // vertex shader | 
| 381 |         TEXTURE_VERTEX_SHADER, | 
| 382 |         // fragment shader | 
| 383 |         NV12_SHADER_PROLOGUE | 
| 384 |         NV21_RA_SHADER_BODY, | 
| 385 |         // fragment version | 
| 386 |         NULL | 
| 387 |     }, | 
| 388 |     // SHADER_NV21_RG | 
| 389 |     { | 
| 390 |         // vertex shader | 
| 391 |         TEXTURE_VERTEX_SHADER, | 
| 392 |         // fragment shader | 
| 393 |         NV12_SHADER_PROLOGUE | 
| 394 |         NV21_RG_SHADER_BODY, | 
| 395 |         // fragment version | 
| 396 |         NULL | 
| 397 |     }, | 
| 398 | #endif // SDL_HAVE_YUV | 
| 399 | }; | 
| 400 |  | 
| 401 | /* *INDENT-ON* */ // clang-format on | 
| 402 |  | 
| 403 | static bool CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *version, const char *defines, const char *source) | 
| 404 | { | 
| 405 |     GLint status; | 
| 406 |     const char *sources[3]; | 
| 407 |  | 
| 408 |     sources[0] = version; | 
| 409 |     sources[1] = defines; | 
| 410 |     sources[2] = source; | 
| 411 |  | 
| 412 |     ctx->glShaderSourceARB(shader, SDL_arraysize(sources), sources, NULL); | 
| 413 |     ctx->glCompileShaderARB(shader); | 
| 414 |     ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status); | 
| 415 |     if (status == 0) { | 
| 416 |         bool isstack; | 
| 417 |         GLint length; | 
| 418 |         char *info; | 
| 419 |  | 
| 420 |         ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); | 
| 421 |         info = SDL_small_alloc(char, length + 1, &isstack); | 
| 422 |         if (info) { | 
| 423 |             ctx->glGetInfoLogARB(shader, length, NULL, info); | 
| 424 |             SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to compile shader:" ); | 
| 425 | 	    SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s" , defines); | 
| 426 | 	    SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s" , source); | 
| 427 | 	    SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s" , info); | 
| 428 |             SDL_small_free(info, isstack); | 
| 429 |         } | 
| 430 |         return false; | 
| 431 |     } else { | 
| 432 |         return true; | 
| 433 |     } | 
| 434 | } | 
| 435 |  | 
| 436 | static bool CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data) | 
| 437 | { | 
| 438 |     const int num_tmus_bound = 4; | 
| 439 |     const char *vert_defines = "" ; | 
| 440 |     const char *frag_defines = "" ; | 
| 441 |     const char *frag_version = "" ; | 
| 442 |     int i; | 
| 443 |     GLint location; | 
| 444 |  | 
| 445 |     if (index == SHADER_NONE) { | 
| 446 |         return true; | 
| 447 |     } | 
| 448 |  | 
| 449 |     ctx->glGetError(); | 
| 450 |  | 
| 451 |     // Make sure we use the correct sampler type for our texture type | 
| 452 |     if (ctx->GL_ARB_texture_rectangle_supported) { | 
| 453 |         frag_defines = | 
| 454 |             "#define sampler2D sampler2DRect\n"  | 
| 455 |             "#define texture2D texture2DRect\n"  | 
| 456 |             "#define UVCoordScale 0.5\n" ; | 
| 457 |     } else { | 
| 458 |         frag_defines = | 
| 459 |             "#define UVCoordScale 1.0\n" ; | 
| 460 |     } | 
| 461 |     if (shader_source[index].fragment_version) { | 
| 462 |         frag_version = shader_source[index].fragment_version; | 
| 463 |     } | 
| 464 |  | 
| 465 |     // Create one program object to rule them all | 
| 466 |     data->program = ctx->glCreateProgramObjectARB(); | 
| 467 |  | 
| 468 |     // Create the vertex shader | 
| 469 |     data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); | 
| 470 |     if (!CompileShader(ctx, data->vert_shader, "" , vert_defines, shader_source[index].vertex_shader)) { | 
| 471 |         return false; | 
| 472 |     } | 
| 473 |  | 
| 474 |     // Create the fragment shader | 
| 475 |     data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); | 
| 476 |     if (!CompileShader(ctx, data->frag_shader, frag_version, frag_defines, shader_source[index].fragment_shader)) { | 
| 477 |         return false; | 
| 478 |     } | 
| 479 |  | 
| 480 |     // ... and in the darkness bind them | 
| 481 |     ctx->glAttachObjectARB(data->program, data->vert_shader); | 
| 482 |     ctx->glAttachObjectARB(data->program, data->frag_shader); | 
| 483 |     ctx->glLinkProgramARB(data->program); | 
| 484 |  | 
| 485 |     // Set up some uniform variables | 
| 486 |     ctx->glUseProgramObjectARB(data->program); | 
| 487 |     for (i = 0; i < num_tmus_bound; ++i) { | 
| 488 |         char tex_name[10]; | 
| 489 |         (void)SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d" , i); | 
| 490 |         location = ctx->glGetUniformLocationARB(data->program, tex_name); | 
| 491 |         if (location >= 0) { | 
| 492 |             ctx->glUniform1iARB(location, i); | 
| 493 |         } | 
| 494 |     } | 
| 495 |     ctx->glUseProgramObjectARB(0); | 
| 496 |  | 
| 497 |     return ctx->glGetError() == GL_NO_ERROR; | 
| 498 | } | 
| 499 |  | 
| 500 | static void DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data) | 
| 501 | { | 
| 502 |     ctx->glDeleteObjectARB(data->vert_shader); | 
| 503 |     ctx->glDeleteObjectARB(data->frag_shader); | 
| 504 |     ctx->glDeleteObjectARB(data->program); | 
| 505 | } | 
| 506 |  | 
| 507 | GL_ShaderContext *GL_CreateShaderContext(void) | 
| 508 | { | 
| 509 |     GL_ShaderContext *ctx; | 
| 510 |     bool shaders_supported; | 
| 511 |     int i; | 
| 512 |  | 
| 513 |     ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx)); | 
| 514 |     if (!ctx) { | 
| 515 |         return NULL; | 
| 516 |     } | 
| 517 |  | 
| 518 |     if (!SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two" ) && | 
| 519 |         (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle" ) || | 
| 520 |          SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle" ))) { | 
| 521 |         ctx->GL_ARB_texture_rectangle_supported = true; | 
| 522 |     } | 
| 523 |  | 
| 524 |     // Check for shader support | 
| 525 |     shaders_supported = false; | 
| 526 |     if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects" ) && | 
| 527 |         SDL_GL_ExtensionSupported("GL_ARB_shading_language_100" ) && | 
| 528 |         SDL_GL_ExtensionSupported("GL_ARB_vertex_shader" ) && | 
| 529 |         SDL_GL_ExtensionSupported("GL_ARB_fragment_shader" )) { | 
| 530 |         ctx->glGetError = (GLenum(*)(void))SDL_GL_GetProcAddress("glGetError" ); | 
| 531 |         ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)SDL_GL_GetProcAddress("glAttachObjectARB" ); | 
| 532 |         ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)SDL_GL_GetProcAddress("glCompileShaderARB" ); | 
| 533 |         ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glCreateProgramObjectARB" ); | 
| 534 |         ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)SDL_GL_GetProcAddress("glCreateShaderObjectARB" ); | 
| 535 |         ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)SDL_GL_GetProcAddress("glDeleteObjectARB" ); | 
| 536 |         ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)SDL_GL_GetProcAddress("glGetInfoLogARB" ); | 
| 537 |         ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)SDL_GL_GetProcAddress("glGetObjectParameterivARB" ); | 
| 538 |         ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)SDL_GL_GetProcAddress("glGetUniformLocationARB" ); | 
| 539 |         ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)SDL_GL_GetProcAddress("glLinkProgramARB" ); | 
| 540 |         ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)SDL_GL_GetProcAddress("glShaderSourceARB" ); | 
| 541 |         ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC)SDL_GL_GetProcAddress("glUniform1iARB" ); | 
| 542 |         ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC)SDL_GL_GetProcAddress("glUniform1fARB" ); | 
| 543 |         ctx->glUniform3fARB = (PFNGLUNIFORM3FARBPROC)SDL_GL_GetProcAddress("glUniform3fARB" ); | 
| 544 |         ctx->glUniform4fARB = (PFNGLUNIFORM4FARBPROC)SDL_GL_GetProcAddress("glUniform4fARB" ); | 
| 545 |         ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glUseProgramObjectARB" ); | 
| 546 |         if (ctx->glGetError && | 
| 547 |             ctx->glAttachObjectARB && | 
| 548 |             ctx->glCompileShaderARB && | 
| 549 |             ctx->glCreateProgramObjectARB && | 
| 550 |             ctx->glCreateShaderObjectARB && | 
| 551 |             ctx->glDeleteObjectARB && | 
| 552 |             ctx->glGetInfoLogARB && | 
| 553 |             ctx->glGetObjectParameterivARB && | 
| 554 |             ctx->glGetUniformLocationARB && | 
| 555 |             ctx->glLinkProgramARB && | 
| 556 |             ctx->glShaderSourceARB && | 
| 557 |             ctx->glUniform1iARB && | 
| 558 |             ctx->glUniform1fARB && | 
| 559 |             ctx->glUniform3fARB && | 
| 560 |             ctx->glUseProgramObjectARB) { | 
| 561 |             shaders_supported = true; | 
| 562 |         } | 
| 563 |     } | 
| 564 |  | 
| 565 |     if (!shaders_supported) { | 
| 566 |         SDL_free(ctx); | 
| 567 |         return NULL; | 
| 568 |     } | 
| 569 |  | 
| 570 |     // Compile all the shaders | 
| 571 |     for (i = 0; i < NUM_SHADERS; ++i) { | 
| 572 |         if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) { | 
| 573 |             GL_DestroyShaderContext(ctx); | 
| 574 |             return NULL; | 
| 575 |         } | 
| 576 |     } | 
| 577 |  | 
| 578 |     // We're done! | 
| 579 |     return ctx; | 
| 580 | } | 
| 581 |  | 
| 582 | void GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader, const float *shader_params) | 
| 583 | { | 
| 584 |     GLint location; | 
| 585 |     GLhandleARB program = ctx->shaders[shader].program; | 
| 586 |  | 
| 587 |     ctx->glUseProgramObjectARB(program); | 
| 588 |  | 
| 589 |     if (shader_params && shader_params != ctx->shader_params[shader]) { | 
| 590 |         if (shader == SHADER_RGB_PIXELART || | 
| 591 |             shader == SHADER_RGBA_PIXELART) { | 
| 592 |             location = ctx->glGetUniformLocationARB(program, "texel_size" ); | 
| 593 |             if (location >= 0) { | 
| 594 |                 ctx->glUniform4fARB(location, shader_params[0], shader_params[1], shader_params[2], shader_params[3]); | 
| 595 |             } | 
| 596 |         } | 
| 597 |  | 
| 598 | #ifdef SDL_HAVE_YUV | 
| 599 |         if (shader >= SHADER_YUV) { | 
| 600 |             // YUV shader params are Yoffset, 0, Rcoeff, 0, Gcoeff, 0, Bcoeff, 0 | 
| 601 |             location = ctx->glGetUniformLocationARB(program, "Yoffset" ); | 
| 602 |             if (location >= 0) { | 
| 603 |                 ctx->glUniform3fARB(location, shader_params[0], shader_params[1], shader_params[2]); | 
| 604 |             } | 
| 605 |             location = ctx->glGetUniformLocationARB(program, "Rcoeff" ); | 
| 606 |             if (location >= 0) { | 
| 607 |                 ctx->glUniform3fARB(location, shader_params[4], shader_params[5], shader_params[6]); | 
| 608 |             } | 
| 609 |             location = ctx->glGetUniformLocationARB(program, "Gcoeff" ); | 
| 610 |             if (location >= 0) { | 
| 611 |                 ctx->glUniform3fARB(location, shader_params[8], shader_params[9], shader_params[10]); | 
| 612 |             } | 
| 613 |             location = ctx->glGetUniformLocationARB(program, "Bcoeff" ); | 
| 614 |             if (location >= 0) { | 
| 615 |                 ctx->glUniform3fARB(location, shader_params[12], shader_params[13], shader_params[14]); | 
| 616 |             } | 
| 617 |         } | 
| 618 | #endif // SDL_HAVE_YUV | 
| 619 |  | 
| 620 |         ctx->shader_params[shader] = shader_params; | 
| 621 |     } | 
| 622 | } | 
| 623 |  | 
| 624 | void GL_DestroyShaderContext(GL_ShaderContext *ctx) | 
| 625 | { | 
| 626 |     int i; | 
| 627 |  | 
| 628 |     for (i = 0; i < NUM_SHADERS; ++i) { | 
| 629 |         DestroyShaderProgram(ctx, &ctx->shaders[i]); | 
| 630 |     } | 
| 631 |     SDL_free(ctx); | 
| 632 | } | 
| 633 |  | 
| 634 | #endif // SDL_VIDEO_RENDER_OGL | 
| 635 |  |