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_ES2 |
24 | |
25 | #include <SDL3/SDL_opengles2.h> |
26 | #include "SDL_shaders_gles2.h" |
27 | |
28 | /* *INDENT-OFF* */ // clang-format off |
29 | |
30 | /************************************************************************************************* |
31 | * Vertex/fragment shader source * |
32 | *************************************************************************************************/ |
33 | |
34 | static const char GLES2_Fragment_Include_Best_Texture_Precision[] = |
35 | "#ifdef GL_FRAGMENT_PRECISION_HIGH\n" |
36 | "#define SDL_TEXCOORD_PRECISION highp\n" |
37 | "#else\n" |
38 | "#define SDL_TEXCOORD_PRECISION mediump\n" |
39 | "#endif\n" |
40 | "\n" |
41 | "precision mediump float;\n" |
42 | "\n" |
43 | ; |
44 | |
45 | static const char GLES2_Fragment_Include_Medium_Texture_Precision[] = |
46 | "#define SDL_TEXCOORD_PRECISION mediump\n" |
47 | "precision mediump float;\n" |
48 | "\n" |
49 | ; |
50 | |
51 | static const char GLES2_Fragment_Include_High_Texture_Precision[] = |
52 | "#define SDL_TEXCOORD_PRECISION highp\n" |
53 | "precision mediump float;\n" |
54 | "\n" |
55 | ; |
56 | |
57 | static const char GLES2_Fragment_Include_Undef_Precision[] = |
58 | "#define mediump\n" |
59 | "#define highp\n" |
60 | "#define lowp\n" |
61 | "#define SDL_TEXCOORD_PRECISION\n" |
62 | "\n" |
63 | ; |
64 | |
65 | static const char GLES2_Vertex_Default[] = |
66 | "uniform mat4 u_projection;\n" |
67 | "attribute vec2 a_position;\n" |
68 | "attribute vec4 a_color;\n" |
69 | "attribute vec2 a_texCoord;\n" |
70 | "varying vec2 v_texCoord;\n" |
71 | "varying vec4 v_color;\n" |
72 | "\n" |
73 | "void main()\n" |
74 | "{\n" |
75 | " v_texCoord = a_texCoord;\n" |
76 | " gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n" |
77 | " gl_PointSize = 1.0;\n" |
78 | " v_color = a_color;\n" |
79 | "}\n" |
80 | ; |
81 | |
82 | static const char GLES2_Fragment_Solid[] = |
83 | "varying mediump vec4 v_color;\n" |
84 | "\n" |
85 | "void main()\n" |
86 | "{\n" |
87 | " gl_FragColor = v_color;\n" |
88 | "}\n" |
89 | ; |
90 | |
91 | #define RGB_SHADER_PROLOGUE \ |
92 | "uniform sampler2D u_texture;\n" \ |
93 | "varying mediump vec4 v_color;\n" \ |
94 | "varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \ |
95 | |
96 | #define RGB_PIXELART_SHADER_PROLOGUE \ |
97 | "uniform sampler2D u_texture;\n" \ |
98 | "uniform mediump vec4 u_texel_size;\n" \ |
99 | "varying mediump vec4 v_color;\n" \ |
100 | "varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \ |
101 | |
102 | #ifdef OPENGLES_300 // This is required for fwidth() and textureGrad() |
103 | #define RGB_PIXELART_GETCOLOR \ |
104 | " mediump vec2 boxSize = clamp(fwidth(v_texCoord) * u_texel_size.zw, 1e-5, 1.0);\n" \ |
105 | " mediump vec2 tx = v_texCoord * u_texel_size.zw - 0.5 * boxSize;\n" \ |
106 | " mediump vec2 txOffset = smoothstep(vec2(1.0) - boxSize, vec2(1.0), fract(tx));\n" \ |
107 | " mediump vec2 uv = (floor(tx) + 0.5 + txOffset) * u_texel_size.xy;\n" \ |
108 | " mediump vec4 color = textureGrad(u_texture, uv, dFdx(v_texCoord), dFdy(v_texCoord));\n" \ |
109 | " mediump vec4 color = texture2D(u_texture, uv);\n" |
110 | #else |
111 | #define RGB_PIXELART_GETCOLOR \ |
112 | " mediump vec4 color = texture2D(u_texture, v_texCoord);\n" |
113 | #endif |
114 | |
115 | static const char GLES2_Fragment_TextureABGR[] = |
116 | RGB_SHADER_PROLOGUE |
117 | "\n" |
118 | "void main()\n" |
119 | "{\n" |
120 | " mediump vec4 color = texture2D(u_texture, v_texCoord);\n" |
121 | " gl_FragColor = color;\n" |
122 | " gl_FragColor *= v_color;\n" |
123 | "}\n" |
124 | ; |
125 | |
126 | // ARGB to ABGR conversion |
127 | static const char GLES2_Fragment_TextureARGB[] = |
128 | RGB_SHADER_PROLOGUE |
129 | "\n" |
130 | "void main()\n" |
131 | "{\n" |
132 | " mediump vec4 color = texture2D(u_texture, v_texCoord);\n" |
133 | " gl_FragColor = color;\n" |
134 | " gl_FragColor.r = color.b;\n" |
135 | " gl_FragColor.b = color.r;\n" |
136 | " gl_FragColor *= v_color;\n" |
137 | "}\n" |
138 | ; |
139 | |
140 | // RGB to ABGR conversion |
141 | static const char GLES2_Fragment_TextureRGB[] = |
142 | RGB_SHADER_PROLOGUE |
143 | "\n" |
144 | "void main()\n" |
145 | "{\n" |
146 | " mediump vec4 color = texture2D(u_texture, v_texCoord);\n" |
147 | " gl_FragColor = color;\n" |
148 | " gl_FragColor.r = color.b;\n" |
149 | " gl_FragColor.b = color.r;\n" |
150 | " gl_FragColor.a = 1.0;\n" |
151 | " gl_FragColor *= v_color;\n" |
152 | "}\n" |
153 | ; |
154 | |
155 | // BGR to ABGR conversion |
156 | static const char GLES2_Fragment_TextureBGR[] = |
157 | RGB_SHADER_PROLOGUE |
158 | "\n" |
159 | "void main()\n" |
160 | "{\n" |
161 | " mediump vec4 color = texture2D(u_texture, v_texCoord);\n" |
162 | " gl_FragColor = color;\n" |
163 | " gl_FragColor.a = 1.0;\n" |
164 | " gl_FragColor *= v_color;\n" |
165 | "}\n" |
166 | ; |
167 | |
168 | static const char GLES2_Fragment_TextureABGR_PixelArt[] = |
169 | RGB_PIXELART_SHADER_PROLOGUE |
170 | "\n" |
171 | "void main()\n" |
172 | "{\n" |
173 | RGB_PIXELART_GETCOLOR |
174 | " gl_FragColor = color;\n" |
175 | " gl_FragColor *= v_color;\n" |
176 | "}\n" |
177 | ; |
178 | |
179 | // ARGB to ABGR conversion |
180 | static const char GLES2_Fragment_TextureARGB_PixelArt[] = |
181 | RGB_PIXELART_SHADER_PROLOGUE |
182 | "\n" |
183 | "void main()\n" |
184 | "{\n" |
185 | RGB_PIXELART_GETCOLOR |
186 | " gl_FragColor = color;\n" |
187 | " gl_FragColor.r = color.b;\n" |
188 | " gl_FragColor.b = color.r;\n" |
189 | " gl_FragColor *= v_color;\n" |
190 | "}\n" |
191 | ; |
192 | |
193 | // RGB to ABGR conversion |
194 | static const char GLES2_Fragment_TextureRGB_PixelArt[] = |
195 | RGB_PIXELART_SHADER_PROLOGUE |
196 | "\n" |
197 | "void main()\n" |
198 | "{\n" |
199 | RGB_PIXELART_GETCOLOR |
200 | " gl_FragColor = color;\n" |
201 | " gl_FragColor.r = color.b;\n" |
202 | " gl_FragColor.b = color.r;\n" |
203 | " gl_FragColor.a = 1.0;\n" |
204 | " gl_FragColor *= v_color;\n" |
205 | "}\n" |
206 | ; |
207 | |
208 | // BGR to ABGR conversion |
209 | static const char GLES2_Fragment_TextureBGR_PixelArt[] = |
210 | RGB_PIXELART_SHADER_PROLOGUE |
211 | "\n" |
212 | "void main()\n" |
213 | "{\n" |
214 | RGB_PIXELART_GETCOLOR |
215 | " gl_FragColor = color;\n" |
216 | " gl_FragColor.a = 1.0;\n" |
217 | " gl_FragColor *= v_color;\n" |
218 | "}\n" |
219 | ; |
220 | |
221 | #ifdef SDL_HAVE_YUV |
222 | |
223 | #define YUV_SHADER_PROLOGUE \ |
224 | "uniform sampler2D u_texture;\n" \ |
225 | "uniform sampler2D u_texture_u;\n" \ |
226 | "uniform sampler2D u_texture_v;\n" \ |
227 | "uniform vec3 u_offset;\n" \ |
228 | "uniform mat3 u_matrix;\n" \ |
229 | "varying mediump vec4 v_color;\n" \ |
230 | "varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \ |
231 | "\n" \ |
232 | |
233 | #define YUV_SHADER_BODY \ |
234 | "void main()\n" \ |
235 | "{\n" \ |
236 | " mediump vec3 yuv;\n" \ |
237 | " lowp vec3 rgb;\n" \ |
238 | "\n" \ |
239 | " // Get the YUV values \n" \ |
240 | " yuv.x = texture2D(u_texture, v_texCoord).r;\n" \ |
241 | " yuv.y = texture2D(u_texture_u, v_texCoord).r;\n" \ |
242 | " yuv.z = texture2D(u_texture_v, v_texCoord).r;\n" \ |
243 | "\n" \ |
244 | " // Do the color transform \n" \ |
245 | " yuv += u_offset;\n" \ |
246 | " rgb = yuv * u_matrix;\n" \ |
247 | "\n" \ |
248 | " // That was easy. :) \n" \ |
249 | " gl_FragColor = vec4(rgb, 1);\n" \ |
250 | " gl_FragColor *= v_color;\n" \ |
251 | "}" \ |
252 | |
253 | #define NV12_RA_SHADER_BODY \ |
254 | "void main()\n" \ |
255 | "{\n" \ |
256 | " mediump vec3 yuv;\n" \ |
257 | " lowp vec3 rgb;\n" \ |
258 | "\n" \ |
259 | " // Get the YUV values \n" \ |
260 | " yuv.x = texture2D(u_texture, v_texCoord).r;\n" \ |
261 | " yuv.yz = texture2D(u_texture_u, v_texCoord).ra;\n" \ |
262 | "\n" \ |
263 | " // Do the color transform \n" \ |
264 | " yuv += u_offset;\n" \ |
265 | " rgb = yuv * u_matrix;\n" \ |
266 | "\n" \ |
267 | " // That was easy. :) \n" \ |
268 | " gl_FragColor = vec4(rgb, 1);\n" \ |
269 | " gl_FragColor *= v_color;\n" \ |
270 | "}" \ |
271 | |
272 | #define NV12_RG_SHADER_BODY \ |
273 | "void main()\n" \ |
274 | "{\n" \ |
275 | " mediump vec3 yuv;\n" \ |
276 | " lowp vec3 rgb;\n" \ |
277 | "\n" \ |
278 | " // Get the YUV values \n" \ |
279 | " yuv.x = texture2D(u_texture, v_texCoord).r;\n" \ |
280 | " yuv.yz = texture2D(u_texture_u, v_texCoord).rg;\n" \ |
281 | "\n" \ |
282 | " // Do the color transform \n" \ |
283 | " yuv += u_offset;\n" \ |
284 | " rgb = yuv * u_matrix;\n" \ |
285 | "\n" \ |
286 | " // That was easy. :) \n" \ |
287 | " gl_FragColor = vec4(rgb, 1);\n" \ |
288 | " gl_FragColor *= v_color;\n" \ |
289 | "}" \ |
290 | |
291 | #define NV21_RA_SHADER_BODY \ |
292 | "void main()\n" \ |
293 | "{\n" \ |
294 | " mediump vec3 yuv;\n" \ |
295 | " lowp vec3 rgb;\n" \ |
296 | "\n" \ |
297 | " // Get the YUV values \n" \ |
298 | " yuv.x = texture2D(u_texture, v_texCoord).r;\n" \ |
299 | " yuv.yz = texture2D(u_texture_u, v_texCoord).ar;\n" \ |
300 | "\n" \ |
301 | " // Do the color transform \n" \ |
302 | " yuv += u_offset;\n" \ |
303 | " rgb = yuv * u_matrix;\n" \ |
304 | "\n" \ |
305 | " // That was easy. :) \n" \ |
306 | " gl_FragColor = vec4(rgb, 1);\n" \ |
307 | " gl_FragColor *= v_color;\n" \ |
308 | "}" \ |
309 | |
310 | #define NV21_RG_SHADER_BODY \ |
311 | "void main()\n" \ |
312 | "{\n" \ |
313 | " mediump vec3 yuv;\n" \ |
314 | " lowp vec3 rgb;\n" \ |
315 | "\n" \ |
316 | " // Get the YUV values \n" \ |
317 | " yuv.x = texture2D(u_texture, v_texCoord).r;\n" \ |
318 | " yuv.yz = texture2D(u_texture_u, v_texCoord).gr;\n" \ |
319 | "\n" \ |
320 | " // Do the color transform \n" \ |
321 | " yuv += u_offset;\n" \ |
322 | " rgb = yuv * u_matrix;\n" \ |
323 | "\n" \ |
324 | " // That was easy. :) \n" \ |
325 | " gl_FragColor = vec4(rgb, 1);\n" \ |
326 | " gl_FragColor *= v_color;\n" \ |
327 | "}" \ |
328 | |
329 | // YUV to ABGR conversion |
330 | static const char GLES2_Fragment_TextureYUV[] = |
331 | YUV_SHADER_PROLOGUE |
332 | YUV_SHADER_BODY |
333 | ; |
334 | |
335 | // NV12 to ABGR conversion |
336 | static const char GLES2_Fragment_TextureNV12_RA[] = |
337 | YUV_SHADER_PROLOGUE |
338 | NV12_RA_SHADER_BODY |
339 | ; |
340 | static const char GLES2_Fragment_TextureNV12_RG[] = |
341 | YUV_SHADER_PROLOGUE |
342 | NV12_RG_SHADER_BODY |
343 | ; |
344 | |
345 | // NV21 to ABGR conversion |
346 | static const char GLES2_Fragment_TextureNV21_RA[] = |
347 | YUV_SHADER_PROLOGUE |
348 | NV21_RA_SHADER_BODY |
349 | ; |
350 | static const char GLES2_Fragment_TextureNV21_RG[] = |
351 | YUV_SHADER_PROLOGUE |
352 | NV21_RG_SHADER_BODY |
353 | ; |
354 | #endif |
355 | |
356 | // Custom Android video format texture |
357 | static const char GLES2_Fragment_TextureExternalOES_Prologue[] = |
358 | "#extension GL_OES_EGL_image_external : require\n" |
359 | "\n" |
360 | ; |
361 | static const char GLES2_Fragment_TextureExternalOES[] = |
362 | "uniform samplerExternalOES u_texture;\n" |
363 | "varying mediump vec4 v_color;\n" |
364 | "varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" |
365 | "\n" |
366 | "void main()\n" |
367 | "{\n" |
368 | " gl_FragColor = texture2D(u_texture, v_texCoord);\n" |
369 | " gl_FragColor *= v_color;\n" |
370 | "}\n" |
371 | ; |
372 | |
373 | /* *INDENT-ON* */ // clang-format on |
374 | |
375 | /************************************************************************************************* |
376 | * Shader selector * |
377 | *************************************************************************************************/ |
378 | |
379 | const char *GLES2_GetShaderPrologue(GLES2_ShaderType type) |
380 | { |
381 | switch (type) { |
382 | case GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES: |
383 | return GLES2_Fragment_TextureExternalOES_Prologue; |
384 | default: |
385 | return "" ; |
386 | } |
387 | } |
388 | |
389 | const char *GLES2_GetShaderInclude(GLES2_ShaderIncludeType type) |
390 | { |
391 | switch (type) { |
392 | case GLES2_SHADER_FRAGMENT_INCLUDE_UNDEF_PRECISION: |
393 | return GLES2_Fragment_Include_Undef_Precision; |
394 | case GLES2_SHADER_FRAGMENT_INCLUDE_BEST_TEXCOORD_PRECISION: |
395 | return GLES2_Fragment_Include_Best_Texture_Precision; |
396 | case GLES2_SHADER_FRAGMENT_INCLUDE_MEDIUM_TEXCOORD_PRECISION: |
397 | return GLES2_Fragment_Include_Medium_Texture_Precision; |
398 | case GLES2_SHADER_FRAGMENT_INCLUDE_HIGH_TEXCOORD_PRECISION: |
399 | return GLES2_Fragment_Include_High_Texture_Precision; |
400 | default: |
401 | return "" ; |
402 | } |
403 | } |
404 | |
405 | GLES2_ShaderIncludeType GLES2_GetTexCoordPrecisionEnumFromHint(void) |
406 | { |
407 | const char *texcoord_hint = SDL_GetHint("SDL_RENDER_OPENGLES2_TEXCOORD_PRECISION" ); |
408 | GLES2_ShaderIncludeType value = GLES2_SHADER_FRAGMENT_INCLUDE_BEST_TEXCOORD_PRECISION; |
409 | if (texcoord_hint) { |
410 | if (SDL_strcmp(texcoord_hint, "undefined" ) == 0) { |
411 | return GLES2_SHADER_FRAGMENT_INCLUDE_UNDEF_PRECISION; |
412 | } |
413 | if (SDL_strcmp(texcoord_hint, "high" ) == 0) { |
414 | return GLES2_SHADER_FRAGMENT_INCLUDE_HIGH_TEXCOORD_PRECISION; |
415 | } |
416 | if (SDL_strcmp(texcoord_hint, "medium" ) == 0) { |
417 | return GLES2_SHADER_FRAGMENT_INCLUDE_MEDIUM_TEXCOORD_PRECISION; |
418 | } |
419 | } |
420 | return value; |
421 | } |
422 | |
423 | const char *GLES2_GetShader(GLES2_ShaderType type) |
424 | { |
425 | switch (type) { |
426 | case GLES2_SHADER_VERTEX_DEFAULT: |
427 | return GLES2_Vertex_Default; |
428 | case GLES2_SHADER_FRAGMENT_SOLID: |
429 | return GLES2_Fragment_Solid; |
430 | case GLES2_SHADER_FRAGMENT_TEXTURE_ABGR: |
431 | return GLES2_Fragment_TextureABGR; |
432 | case GLES2_SHADER_FRAGMENT_TEXTURE_ARGB: |
433 | return GLES2_Fragment_TextureARGB; |
434 | case GLES2_SHADER_FRAGMENT_TEXTURE_RGB: |
435 | return GLES2_Fragment_TextureRGB; |
436 | case GLES2_SHADER_FRAGMENT_TEXTURE_BGR: |
437 | return GLES2_Fragment_TextureBGR; |
438 | case GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_PIXELART: |
439 | return GLES2_Fragment_TextureABGR_PixelArt; |
440 | case GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_PIXELART: |
441 | return GLES2_Fragment_TextureARGB_PixelArt; |
442 | case GLES2_SHADER_FRAGMENT_TEXTURE_RGB_PIXELART: |
443 | return GLES2_Fragment_TextureRGB_PixelArt; |
444 | case GLES2_SHADER_FRAGMENT_TEXTURE_BGR_PIXELART: |
445 | return GLES2_Fragment_TextureBGR_PixelArt; |
446 | #ifdef SDL_HAVE_YUV |
447 | case GLES2_SHADER_FRAGMENT_TEXTURE_YUV: |
448 | return GLES2_Fragment_TextureYUV; |
449 | case GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA: |
450 | return GLES2_Fragment_TextureNV12_RA; |
451 | case GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG: |
452 | return GLES2_Fragment_TextureNV12_RG; |
453 | case GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RA: |
454 | return GLES2_Fragment_TextureNV21_RA; |
455 | case GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RG: |
456 | return GLES2_Fragment_TextureNV21_RG; |
457 | #endif |
458 | case GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES: |
459 | return GLES2_Fragment_TextureExternalOES; |
460 | default: |
461 | return NULL; |
462 | } |
463 | } |
464 | |
465 | #endif // SDL_VIDEO_RENDER_OGL_ES2 |
466 | |