summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/render/opengles2
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/render/opengles2')
-rw-r--r--contrib/SDL-3.2.8/src/render/opengles2/SDL_gles2funcs.h78
-rw-r--r--contrib/SDL-3.2.8/src/render/opengles2/SDL_render_gles2.c2226
-rw-r--r--contrib/SDL-3.2.8/src/render/opengles2/SDL_shaders_gles2.c387
-rw-r--r--contrib/SDL-3.2.8/src/render/opengles2/SDL_shaders_gles2.h65
4 files changed, 2756 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/render/opengles2/SDL_gles2funcs.h b/contrib/SDL-3.2.8/src/render/opengles2/SDL_gles2funcs.h
new file mode 100644
index 0000000..bbc47a4
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/opengles2/SDL_gles2funcs.h
@@ -0,0 +1,78 @@
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
22SDL_PROC(void, glActiveTexture, (GLenum))
23SDL_PROC(void, glAttachShader, (GLuint, GLuint))
24SDL_PROC(void, glBindAttribLocation, (GLuint, GLuint, const char *))
25SDL_PROC(void, glBindTexture, (GLenum, GLuint))
26SDL_PROC(void, glBlendEquationSeparate, (GLenum, GLenum))
27SDL_PROC(void, glBlendFuncSeparate, (GLenum, GLenum, GLenum, GLenum))
28SDL_PROC(void, glClear, (GLbitfield))
29SDL_PROC(void, glClearColor, (GLclampf, GLclampf, GLclampf, GLclampf))
30SDL_PROC(void, glCompileShader, (GLuint))
31SDL_PROC(GLuint, glCreateProgram, (void))
32SDL_PROC(GLuint, glCreateShader, (GLenum))
33SDL_PROC(void, glDeleteProgram, (GLuint))
34SDL_PROC(void, glDeleteShader, (GLuint))
35SDL_PROC(void, glDeleteTextures, (GLsizei, const GLuint *))
36SDL_PROC(void, glDisable, (GLenum))
37SDL_PROC(void, glDisableVertexAttribArray, (GLuint))
38SDL_PROC(void, glDrawArrays, (GLenum, GLint, GLsizei))
39SDL_PROC(void, glEnable, (GLenum))
40SDL_PROC(void, glEnableVertexAttribArray, (GLuint))
41SDL_PROC(void, glFinish, (void))
42SDL_PROC(void, glGenFramebuffers, (GLsizei, GLuint *))
43SDL_PROC(void, glGenTextures, (GLsizei, GLuint *))
44SDL_PROC(const GLubyte *, glGetString, (GLenum))
45SDL_PROC(GLenum, glGetError, (void))
46SDL_PROC(void, glGetIntegerv, (GLenum, GLint *))
47SDL_PROC(void, glGetProgramiv, (GLuint, GLenum, GLint *))
48SDL_PROC(void, glGetShaderInfoLog, (GLuint, GLsizei, GLsizei *, char *))
49SDL_PROC(void, glGetShaderiv, (GLuint, GLenum, GLint *))
50SDL_PROC(GLint, glGetUniformLocation, (GLuint, const char *))
51SDL_PROC(void, glLinkProgram, (GLuint))
52SDL_PROC(void, glPixelStorei, (GLenum, GLint))
53SDL_PROC(void, glReadPixels, (GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *))
54SDL_PROC(void, glScissor, (GLint, GLint, GLsizei, GLsizei))
55SDL_PROC(void, glShaderBinary, (GLsizei, const GLuint *, GLenum, const void *, GLsizei))
56SDL_PROC(void, glShaderSource, (GLuint, GLsizei, const GLchar *const *, const GLint *))
57SDL_PROC(void, glTexImage2D, (GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void *))
58SDL_PROC(void, glTexParameteri, (GLenum, GLenum, GLint))
59SDL_PROC(void, glTexSubImage2D, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *))
60SDL_PROC(void, glUniform1i, (GLint, GLint))
61SDL_PROC(void, glUniform3f, (GLint, GLfloat, GLfloat, GLfloat))
62SDL_PROC(void, glUniform4f, (GLint, GLfloat, GLfloat, GLfloat, GLfloat))
63SDL_PROC(void, glUniformMatrix3fv, (GLint, GLsizei, GLboolean, const GLfloat *))
64SDL_PROC(void, glUniformMatrix4fv, (GLint, GLsizei, GLboolean, const GLfloat *))
65SDL_PROC(void, glUseProgram, (GLuint))
66SDL_PROC(void, glVertexAttribPointer, (GLuint, GLint, GLenum, GLboolean, GLsizei, const void *))
67SDL_PROC(void, glViewport, (GLint, GLint, GLsizei, GLsizei))
68SDL_PROC(void, glBindFramebuffer, (GLenum, GLuint))
69SDL_PROC(void, glFramebufferTexture2D, (GLenum, GLenum, GLenum, GLuint, GLint))
70SDL_PROC(GLenum, glCheckFramebufferStatus, (GLenum))
71SDL_PROC(void, glDeleteFramebuffers, (GLsizei, const GLuint *))
72SDL_PROC(GLint, glGetAttribLocation, (GLuint, const GLchar *))
73SDL_PROC(void, glGetProgramInfoLog, (GLuint, GLsizei, GLsizei *, GLchar *))
74SDL_PROC(void, glGenBuffers, (GLsizei, GLuint *))
75SDL_PROC(void, glDeleteBuffers, (GLsizei, const GLuint *))
76SDL_PROC(void, glBindBuffer, (GLenum, GLuint))
77SDL_PROC(void, glBufferData, (GLenum, GLsizeiptr, const GLvoid *, GLenum))
78SDL_PROC(void, glBufferSubData, (GLenum, GLintptr, GLsizeiptr, const GLvoid *))
diff --git a/contrib/SDL-3.2.8/src/render/opengles2/SDL_render_gles2.c b/contrib/SDL-3.2.8/src/render/opengles2/SDL_render_gles2.c
new file mode 100644
index 0000000..0e142a7
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/opengles2/SDL_render_gles2.c
@@ -0,0 +1,2226 @@
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 "../../video/SDL_sysvideo.h" // For SDL_RecreateWindow
26#include <SDL3/SDL_opengles2.h>
27#include "../SDL_sysrender.h"
28#include "../../video/SDL_pixels_c.h"
29#include "SDL_shaders_gles2.h"
30
31/* WebGL doesn't offer client-side arrays, so use Vertex Buffer Objects
32 on Emscripten, which converts GLES2 into WebGL calls.
33 In all other cases, attempt to use client-side arrays, as they tend to
34 be dramatically faster when not batching, and about the same when
35 we are. */
36#ifdef SDL_PLATFORM_EMSCRIPTEN
37#define USE_VERTEX_BUFFER_OBJECTS 1
38#else
39#define USE_VERTEX_BUFFER_OBJECTS 0
40#endif
41
42/* To prevent unnecessary window recreation,
43 * these should match the defaults selected in SDL_GL_ResetAttributes
44 */
45#define RENDERER_CONTEXT_MAJOR 2
46#define RENDERER_CONTEXT_MINOR 0
47
48/*************************************************************************************************
49 * Context structures *
50 *************************************************************************************************/
51
52typedef struct GLES2_FBOList GLES2_FBOList;
53
54struct GLES2_FBOList
55{
56 Uint32 w, h;
57 GLuint FBO;
58 GLES2_FBOList *next;
59};
60
61typedef struct GLES2_TextureData
62{
63 GLuint texture;
64 bool texture_external;
65 GLenum texture_type;
66 GLenum pixel_format;
67 GLenum pixel_type;
68 void *pixel_data;
69 int pitch;
70#ifdef SDL_HAVE_YUV
71 // YUV texture support
72 bool yuv;
73 bool nv12;
74 GLuint texture_v;
75 GLuint texture_v_external;
76 GLuint texture_u;
77 GLuint texture_u_external;
78#endif
79 GLES2_FBOList *fbo;
80} GLES2_TextureData;
81
82typedef enum
83{
84 GLES2_ATTRIBUTE_POSITION = 0,
85 GLES2_ATTRIBUTE_COLOR = 1,
86 GLES2_ATTRIBUTE_TEXCOORD = 2,
87} GLES2_Attribute;
88
89typedef enum
90{
91 GLES2_UNIFORM_PROJECTION,
92 GLES2_UNIFORM_TEXTURE,
93 GLES2_UNIFORM_TEXTURE_U,
94 GLES2_UNIFORM_TEXTURE_V,
95 GLES2_UNIFORM_OFFSET,
96 GLES2_UNIFORM_MATRIX,
97 NUM_GLES2_UNIFORMS
98} GLES2_Uniform;
99
100static const char *GLES2_UniformNames[] = {
101 "u_projection",
102 "u_texture",
103 "u_texture_u",
104 "u_texture_v",
105 "u_offset",
106 "u_matrix"
107};
108SDL_COMPILE_TIME_ASSERT(GLES2_UniformNames, SDL_arraysize(GLES2_UniformNames) == NUM_GLES2_UNIFORMS);
109
110typedef struct GLES2_ProgramCacheEntry
111{
112 GLuint id;
113 GLuint vertex_shader;
114 GLuint fragment_shader;
115 GLuint uniform_locations[NUM_GLES2_UNIFORMS];
116 GLfloat projection[4][4];
117 const float *shader_params;
118 struct GLES2_ProgramCacheEntry *prev;
119 struct GLES2_ProgramCacheEntry *next;
120} GLES2_ProgramCacheEntry;
121
122typedef struct GLES2_ProgramCache
123{
124 int count;
125 GLES2_ProgramCacheEntry *head;
126 GLES2_ProgramCacheEntry *tail;
127} GLES2_ProgramCache;
128
129typedef enum
130{
131 GLES2_IMAGESOURCE_INVALID,
132 GLES2_IMAGESOURCE_SOLID,
133 GLES2_IMAGESOURCE_TEXTURE_ABGR,
134 GLES2_IMAGESOURCE_TEXTURE_ARGB,
135 GLES2_IMAGESOURCE_TEXTURE_RGB,
136 GLES2_IMAGESOURCE_TEXTURE_BGR,
137 GLES2_IMAGESOURCE_TEXTURE_YUV,
138 GLES2_IMAGESOURCE_TEXTURE_NV12,
139 GLES2_IMAGESOURCE_TEXTURE_NV21,
140 GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES
141} GLES2_ImageSource;
142
143typedef struct
144{
145 SDL_Rect viewport;
146 bool viewport_dirty;
147 SDL_Texture *texture;
148 SDL_Texture *target;
149 SDL_BlendMode blend;
150 bool cliprect_enabled_dirty;
151 bool cliprect_enabled;
152 bool cliprect_dirty;
153 SDL_Rect cliprect;
154 bool texturing;
155 bool texturing_dirty;
156 SDL_FColor clear_color;
157 bool clear_color_dirty;
158 int drawablew;
159 int drawableh;
160 GLES2_ProgramCacheEntry *program;
161 const float *shader_params;
162 GLfloat projection[4][4];
163} GLES2_DrawStateCache;
164
165typedef struct GLES2_RenderData
166{
167 SDL_GLContext context;
168
169 bool debug_enabled;
170
171 bool GL_EXT_blend_minmax_supported;
172
173#define SDL_PROC(ret, func, params) ret (APIENTRY *func) params;
174#include "SDL_gles2funcs.h"
175#undef SDL_PROC
176 GLES2_FBOList *framebuffers;
177 GLuint window_framebuffer;
178
179 GLuint shader_id_cache[GLES2_SHADER_COUNT];
180
181 GLES2_ProgramCache program_cache;
182 Uint8 clear_r, clear_g, clear_b, clear_a;
183
184#if USE_VERTEX_BUFFER_OBJECTS
185 GLuint vertex_buffers[8];
186 size_t vertex_buffer_size[8];
187 int current_vertex_buffer;
188#endif
189
190 GLES2_DrawStateCache drawstate;
191 GLES2_ShaderIncludeType texcoord_precision_hint;
192} GLES2_RenderData;
193
194#define GLES2_MAX_CACHED_PROGRAMS 8
195
196static const char *GL_TranslateError(GLenum error)
197{
198#define GL_ERROR_TRANSLATE(e) \
199 case e: \
200 return #e;
201 switch (error) {
202 GL_ERROR_TRANSLATE(GL_INVALID_ENUM)
203 GL_ERROR_TRANSLATE(GL_INVALID_VALUE)
204 GL_ERROR_TRANSLATE(GL_INVALID_OPERATION)
205 GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY)
206 GL_ERROR_TRANSLATE(GL_NO_ERROR)
207 default:
208 return "UNKNOWN";
209 }
210#undef GL_ERROR_TRANSLATE
211}
212
213static void GL_ClearErrors(SDL_Renderer *renderer)
214{
215 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
216
217 if (!data->debug_enabled) {
218 return;
219 }
220 while (data->glGetError() != GL_NO_ERROR) {
221 // continue;
222 }
223}
224
225static bool GL_CheckAllErrors(const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function)
226{
227 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
228 bool result = true;
229
230 if (!data->debug_enabled) {
231 return true;
232 }
233 // check gl errors (can return multiple errors)
234 for (;;) {
235 GLenum error = data->glGetError();
236 if (error != GL_NO_ERROR) {
237 if (!prefix || prefix[0] == '\0') {
238 prefix = "generic";
239 }
240 SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error);
241 result = false;
242 } else {
243 break;
244 }
245 }
246 return result;
247}
248
249#if 0
250#define GL_CheckError(prefix, renderer)
251#else
252#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, SDL_FILE, SDL_LINE, SDL_FUNCTION)
253#endif
254
255/*************************************************************************************************
256 * Renderer state APIs *
257 *************************************************************************************************/
258
259static bool GLES2_LoadFunctions(GLES2_RenderData *data)
260{
261#ifdef SDL_VIDEO_DRIVER_UIKIT
262#define __SDL_NOGETPROCADDR__
263#elif defined(SDL_VIDEO_DRIVER_ANDROID)
264#define __SDL_NOGETPROCADDR__
265#endif
266
267#if defined __SDL_NOGETPROCADDR__
268#define SDL_PROC(ret, func, params) data->func = func;
269#else
270#define SDL_PROC(ret, func, params) \
271 do { \
272 data->func = (ret (APIENTRY *) params)SDL_GL_GetProcAddress(#func); \
273 if (!data->func) { \
274 return SDL_SetError("Couldn't load GLES2 function %s: %s", #func, SDL_GetError()); \
275 } \
276 } while (0);
277#endif // __SDL_NOGETPROCADDR__
278
279#include "SDL_gles2funcs.h"
280#undef SDL_PROC
281 return true;
282}
283
284static GLES2_FBOList *GLES2_GetFBO(GLES2_RenderData *data, Uint32 w, Uint32 h)
285{
286 GLES2_FBOList *result = data->framebuffers;
287 while ((result) && ((result->w != w) || (result->h != h))) {
288 result = result->next;
289 }
290 if (!result) {
291 result = (GLES2_FBOList *)SDL_malloc(sizeof(GLES2_FBOList));
292 result->w = w;
293 result->h = h;
294 data->glGenFramebuffers(1, &result->FBO);
295 result->next = data->framebuffers;
296 data->framebuffers = result;
297 }
298 return result;
299}
300
301static bool GLES2_ActivateRenderer(SDL_Renderer *renderer)
302{
303 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
304
305 if (SDL_GL_GetCurrentContext() != data->context) {
306 // Null out the current program to ensure we set it again
307 data->drawstate.program = NULL;
308
309 if (!SDL_GL_MakeCurrent(renderer->window, data->context)) {
310 return false;
311 }
312 }
313
314 GL_ClearErrors(renderer);
315
316 return true;
317}
318
319static void GLES2_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
320{
321 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
322
323 if (event->type == SDL_EVENT_WINDOW_MINIMIZED) {
324 // According to Apple documentation, we need to finish drawing NOW!
325 data->glFinish();
326 }
327}
328
329static GLenum GetBlendFunc(SDL_BlendFactor factor)
330{
331 switch (factor) {
332 case SDL_BLENDFACTOR_ZERO:
333 return GL_ZERO;
334 case SDL_BLENDFACTOR_ONE:
335 return GL_ONE;
336 case SDL_BLENDFACTOR_SRC_COLOR:
337 return GL_SRC_COLOR;
338 case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
339 return GL_ONE_MINUS_SRC_COLOR;
340 case SDL_BLENDFACTOR_SRC_ALPHA:
341 return GL_SRC_ALPHA;
342 case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
343 return GL_ONE_MINUS_SRC_ALPHA;
344 case SDL_BLENDFACTOR_DST_COLOR:
345 return GL_DST_COLOR;
346 case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
347 return GL_ONE_MINUS_DST_COLOR;
348 case SDL_BLENDFACTOR_DST_ALPHA:
349 return GL_DST_ALPHA;
350 case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
351 return GL_ONE_MINUS_DST_ALPHA;
352 default:
353 return GL_INVALID_ENUM;
354 }
355}
356
357static GLenum GetBlendEquation(SDL_BlendOperation operation)
358{
359 switch (operation) {
360 case SDL_BLENDOPERATION_ADD:
361 return GL_FUNC_ADD;
362 case SDL_BLENDOPERATION_SUBTRACT:
363 return GL_FUNC_SUBTRACT;
364 case SDL_BLENDOPERATION_REV_SUBTRACT:
365 return GL_FUNC_REVERSE_SUBTRACT;
366 case SDL_BLENDOPERATION_MINIMUM:
367 return GL_MIN_EXT;
368 case SDL_BLENDOPERATION_MAXIMUM:
369 return GL_MAX_EXT;
370 default:
371 return GL_INVALID_ENUM;
372 }
373}
374
375static bool GLES2_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode)
376{
377 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
378
379 SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
380 SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
381 SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
382 SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
383 SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
384 SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
385
386 if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM ||
387 GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM ||
388 GetBlendEquation(colorOperation) == GL_INVALID_ENUM ||
389 GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM ||
390 GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM ||
391 GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) {
392 return false;
393 }
394
395 if (colorOperation == SDL_BLENDOPERATION_MINIMUM && !data->GL_EXT_blend_minmax_supported) {
396 return false;
397 }
398 if (colorOperation == SDL_BLENDOPERATION_MAXIMUM && !data->GL_EXT_blend_minmax_supported) {
399 return false;
400 }
401
402 return true;
403}
404
405static GLES2_ProgramCacheEntry *GLES2_CacheProgram(GLES2_RenderData *data, GLuint vertex, GLuint fragment)
406{
407 GLES2_ProgramCacheEntry *entry;
408 GLint linkSuccessful;
409 int i;
410
411 // Check if we've already cached this program
412 entry = data->program_cache.head;
413 while (entry) {
414 if (entry->vertex_shader == vertex && entry->fragment_shader == fragment) {
415 break;
416 }
417 entry = entry->next;
418 }
419 if (entry) {
420 if (data->program_cache.head != entry) {
421 if (entry->next) {
422 entry->next->prev = entry->prev;
423 }
424 if (entry->prev) {
425 entry->prev->next = entry->next;
426 }
427 entry->prev = NULL;
428 entry->next = data->program_cache.head;
429 data->program_cache.head->prev = entry;
430 data->program_cache.head = entry;
431 }
432 return entry;
433 }
434
435 // Create a program cache entry
436 entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry));
437 if (!entry) {
438 return NULL;
439 }
440 entry->vertex_shader = vertex;
441 entry->fragment_shader = fragment;
442
443 // Create the program and link it
444 entry->id = data->glCreateProgram();
445 data->glAttachShader(entry->id, vertex);
446 data->glAttachShader(entry->id, fragment);
447 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_POSITION, "a_position");
448 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_COLOR, "a_color");
449 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord");
450 data->glLinkProgram(entry->id);
451 data->glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful);
452 if (!linkSuccessful) {
453 data->glDeleteProgram(entry->id);
454 SDL_free(entry);
455 SDL_SetError("Failed to link shader program");
456 return NULL;
457 }
458
459 // Predetermine locations of uniform variables
460 for (i = 0; i < NUM_GLES2_UNIFORMS; ++i) {
461 entry->uniform_locations[i] = data->glGetUniformLocation(entry->id, GLES2_UniformNames[i]);
462 }
463
464 data->glUseProgram(entry->id);
465 if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V] != -1) {
466 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V], 2); // always texture unit 2.
467 }
468 if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U] != -1) {
469 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U], 1); // always texture unit 1.
470 }
471 if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE] != -1) {
472 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0); // always texture unit 0.
473 }
474 if (entry->uniform_locations[GLES2_UNIFORM_PROJECTION] != -1) {
475 data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection);
476 }
477
478 // Cache the linked program
479 if (data->program_cache.head) {
480 entry->next = data->program_cache.head;
481 data->program_cache.head->prev = entry;
482 } else {
483 data->program_cache.tail = entry;
484 }
485 data->program_cache.head = entry;
486 ++data->program_cache.count;
487
488 // Evict the last entry from the cache if we exceed the limit
489 if (data->program_cache.count > GLES2_MAX_CACHED_PROGRAMS) {
490 data->glDeleteProgram(data->program_cache.tail->id);
491 data->program_cache.tail = data->program_cache.tail->prev;
492 if (data->program_cache.tail) {
493 SDL_free(data->program_cache.tail->next);
494 data->program_cache.tail->next = NULL;
495 }
496 --data->program_cache.count;
497 }
498 return entry;
499}
500
501static GLuint GLES2_CacheShader(GLES2_RenderData *data, GLES2_ShaderType type, GLenum shader_type)
502{
503 GLuint id = 0;
504 GLint compileSuccessful = GL_FALSE;
505 int attempt, num_src;
506 const GLchar *shader_src_list[3];
507 const GLchar *shader_body = GLES2_GetShader(type);
508
509 if (!shader_body) {
510 SDL_SetError("No shader body src");
511 return true;
512 }
513
514 for (attempt = 0; attempt < 2 && !compileSuccessful; ++attempt) {
515 num_src = 0;
516
517 shader_src_list[num_src++] = GLES2_GetShaderPrologue(type);
518
519 if (shader_type == GL_FRAGMENT_SHADER) {
520 if (attempt == 0) {
521 shader_src_list[num_src++] = GLES2_GetShaderInclude(data->texcoord_precision_hint);
522 } else {
523 shader_src_list[num_src++] = GLES2_GetShaderInclude(GLES2_SHADER_FRAGMENT_INCLUDE_UNDEF_PRECISION);
524 }
525 }
526
527 shader_src_list[num_src++] = shader_body;
528
529 SDL_assert(num_src <= SDL_arraysize(shader_src_list));
530
531#ifdef DEBUG_PRINT_SHADERS
532 {
533 int i;
534 char *message = NULL;
535
536 SDL_asprintf(&message, "Compiling shader:\n");
537 for (i = 0; i < num_src; ++i) {
538 char *last_message = message;
539 SDL_asprintf(&message, "%s%s", last_message, shader_src_list[i]);
540 SDL_free(last_message);
541 }
542 SDL_Log("%s", message);
543 SDL_free(message);
544 }
545#endif
546
547 // Compile
548 id = data->glCreateShader(shader_type);
549 data->glShaderSource(id, num_src, shader_src_list, NULL);
550 data->glCompileShader(id);
551 data->glGetShaderiv(id, GL_COMPILE_STATUS, &compileSuccessful);
552 }
553
554 if (!compileSuccessful) {
555 char *info = NULL;
556 int length = 0;
557
558 data->glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
559 if (length > 0) {
560 info = (char *)SDL_malloc(length);
561 if (info) {
562 data->glGetShaderInfoLog(id, length, &length, info);
563 }
564 }
565 if (info) {
566 SDL_SetError("Failed to load the shader %d: %s", type, info);
567 SDL_free(info);
568 } else {
569 SDL_SetError("Failed to load the shader %d", type);
570 }
571 data->glDeleteShader(id);
572 return true;
573 }
574
575 // Cache
576 data->shader_id_cache[(Uint32)type] = id;
577
578 return id;
579}
580
581static bool GLES2_CacheShaders(GLES2_RenderData *data)
582{
583 int shader;
584
585 data->texcoord_precision_hint = GLES2_GetTexCoordPrecisionEnumFromHint();
586
587 for (shader = 0; shader < GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES; ++shader) {
588 GLenum shader_type;
589
590 if (shader == GLES2_SHADER_VERTEX_DEFAULT) {
591 shader_type = GL_VERTEX_SHADER;
592 } else {
593 shader_type = GL_FRAGMENT_SHADER;
594 }
595 if (!GLES2_CacheShader(data, (GLES2_ShaderType)shader, shader_type)) {
596 return false;
597 }
598 }
599 return true;
600}
601
602static bool GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source, SDL_Colorspace colorspace)
603{
604 GLuint vertex;
605 GLuint fragment;
606 GLES2_ShaderType vtype, ftype;
607 GLES2_ProgramCacheEntry *program;
608 const float *shader_params = NULL;
609
610 // Select an appropriate shader pair for the specified modes
611 vtype = GLES2_SHADER_VERTEX_DEFAULT;
612 switch (source) {
613 case GLES2_IMAGESOURCE_SOLID:
614 ftype = GLES2_SHADER_FRAGMENT_SOLID;
615 break;
616 case GLES2_IMAGESOURCE_TEXTURE_ABGR:
617 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ABGR;
618 break;
619 case GLES2_IMAGESOURCE_TEXTURE_ARGB:
620 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ARGB;
621 break;
622 case GLES2_IMAGESOURCE_TEXTURE_RGB:
623 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_RGB;
624 break;
625 case GLES2_IMAGESOURCE_TEXTURE_BGR:
626 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_BGR;
627 break;
628#ifdef SDL_HAVE_YUV
629 case GLES2_IMAGESOURCE_TEXTURE_YUV:
630 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV;
631 shader_params = SDL_GetYCbCRtoRGBConversionMatrix(colorspace, 0, 0, 8);
632 if (!shader_params) {
633 SDL_SetError("Unsupported YUV colorspace");
634 goto fault;
635 }
636 break;
637 case GLES2_IMAGESOURCE_TEXTURE_NV12:
638 if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", false)) {
639 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG;
640 } else {
641 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA;
642 }
643 shader_params = SDL_GetYCbCRtoRGBConversionMatrix(colorspace, 0, 0, 8);
644 if (!shader_params) {
645 SDL_SetError("Unsupported YUV colorspace");
646 goto fault;
647 }
648 break;
649 case GLES2_IMAGESOURCE_TEXTURE_NV21:
650 if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", false)) {
651 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RG;
652 } else {
653 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RA;
654 }
655 shader_params = SDL_GetYCbCRtoRGBConversionMatrix(colorspace, 0, 0, 8);
656 if (!shader_params) {
657 SDL_SetError("Unsupported YUV colorspace");
658 goto fault;
659 }
660 break;
661#endif // SDL_HAVE_YUV
662 case GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES:
663 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES;
664 break;
665 default:
666 goto fault;
667 }
668
669 // Load the requested shaders
670 vertex = data->shader_id_cache[(Uint32)vtype];
671 if (!vertex) {
672 vertex = GLES2_CacheShader(data, vtype, GL_VERTEX_SHADER);
673 if (!vertex) {
674 goto fault;
675 }
676 }
677
678 fragment = data->shader_id_cache[(Uint32)ftype];
679 if (!fragment) {
680 fragment = GLES2_CacheShader(data, ftype, GL_FRAGMENT_SHADER);
681 if (!fragment) {
682 goto fault;
683 }
684 }
685
686 // Check if we need to change programs at all
687 if (data->drawstate.program &&
688 data->drawstate.program->vertex_shader == vertex &&
689 data->drawstate.program->fragment_shader == fragment &&
690 data->drawstate.program->shader_params == shader_params) {
691 return true;
692 }
693
694 // Generate a matching program
695 program = GLES2_CacheProgram(data, vertex, fragment);
696 if (!program) {
697 goto fault;
698 }
699
700 // Select that program in OpenGL
701 data->glUseProgram(program->id);
702
703 if (shader_params && shader_params != program->shader_params) {
704 // YUV shader params are Yoffset, 0, Rcoeff, 0, Gcoeff, 0, Bcoeff, 0
705 if (program->uniform_locations[GLES2_UNIFORM_OFFSET] != -1) {
706 data->glUniform3f(program->uniform_locations[GLES2_UNIFORM_OFFSET], shader_params[0], shader_params[1], shader_params[2]);
707 }
708 if (program->uniform_locations[GLES2_UNIFORM_MATRIX] != -1) {
709 GLfloat matrix[3 * 3];
710
711 matrix[0 * 3 + 0] = shader_params[4];
712 matrix[0 * 3 + 1] = shader_params[5];
713 matrix[0 * 3 + 2] = shader_params[6];
714 matrix[1 * 3 + 0] = shader_params[8];
715 matrix[1 * 3 + 1] = shader_params[9];
716 matrix[1 * 3 + 2] = shader_params[10];
717 matrix[2 * 3 + 0] = shader_params[12];
718 matrix[2 * 3 + 1] = shader_params[13];
719 matrix[2 * 3 + 2] = shader_params[14];
720 data->glUniformMatrix3fv(program->uniform_locations[GLES2_UNIFORM_MATRIX], 1, GL_FALSE, matrix);
721 }
722 program->shader_params = shader_params;
723 }
724
725 // Set the current program
726 data->drawstate.program = program;
727
728 // Clean up and return
729 return true;
730fault:
731 data->drawstate.program = NULL;
732 return false;
733}
734
735static bool GLES2_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
736{
737 return true; // nothing to do in this backend.
738}
739
740static bool GLES2_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
741{
742 const bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_BGRA32 || renderer->target->format == SDL_PIXELFORMAT_BGRX32));
743 SDL_VertexSolid *verts = (SDL_VertexSolid *)SDL_AllocateRenderVertices(renderer, count * sizeof(*verts), 0, &cmd->data.draw.first);
744 int i;
745 SDL_FColor color = cmd->data.draw.color;
746 const float color_scale = cmd->data.draw.color_scale;
747
748 if (!verts) {
749 return false;
750 }
751
752 color.r *= color_scale;
753 color.g *= color_scale;
754 color.b *= color_scale;
755
756 if (colorswap) {
757 float r = color.r;
758 color.r = color.b;
759 color.b = r;
760 }
761
762 cmd->data.draw.count = count;
763 for (i = 0; i < count; i++) {
764 verts->position.x = 0.5f + points[i].x;
765 verts->position.y = 0.5f + points[i].y;
766 verts->color = color;
767 verts++;
768 }
769
770 return true;
771}
772
773static bool GLES2_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
774{
775 const bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_BGRA32 || renderer->target->format == SDL_PIXELFORMAT_BGRX32));
776 int i;
777 GLfloat prevx, prevy;
778 SDL_VertexSolid *verts = (SDL_VertexSolid *)SDL_AllocateRenderVertices(renderer, count * sizeof(*verts), 0, &cmd->data.draw.first);
779 SDL_FColor color = cmd->data.draw.color;
780 const float color_scale = cmd->data.draw.color_scale;
781
782 if (!verts) {
783 return false;
784 }
785
786 color.r *= color_scale;
787 color.g *= color_scale;
788 color.b *= color_scale;
789
790 if (colorswap) {
791 float r = color.r;
792 color.r = color.b;
793 color.b = r;
794 }
795
796 cmd->data.draw.count = count;
797
798 // 0.5f offset to hit the center of the pixel.
799 prevx = 0.5f + points->x;
800 prevy = 0.5f + points->y;
801 verts->position.x = prevx;
802 verts->position.y = prevy;
803 verts->color = color;
804 verts++;
805
806 /* bump the end of each line segment out a quarter of a pixel, to provoke
807 the diamond-exit rule. Without this, you won't just drop the last
808 pixel of the last line segment, but you might also drop pixels at the
809 edge of any given line segment along the way too. */
810 for (i = 1; i < count; i++) {
811 const GLfloat xstart = prevx;
812 const GLfloat ystart = prevy;
813 const GLfloat xend = points[i].x + 0.5f; // 0.5f to hit pixel center.
814 const GLfloat yend = points[i].y + 0.5f;
815 // bump a little in the direction we are moving in.
816 const GLfloat deltax = xend - xstart;
817 const GLfloat deltay = yend - ystart;
818 const GLfloat angle = SDL_atan2f(deltay, deltax);
819 prevx = xend + (SDL_cosf(angle) * 0.25f);
820 prevy = yend + (SDL_sinf(angle) * 0.25f);
821 verts->position.x = prevx;
822 verts->position.y = prevy;
823 verts->color = color;
824 verts++;
825 }
826
827 return true;
828}
829
830static bool GLES2_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
831 const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride,
832 int num_vertices, const void *indices, int num_indices, int size_indices,
833 float scale_x, float scale_y)
834{
835 int i;
836 const bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_BGRA32 || renderer->target->format == SDL_PIXELFORMAT_BGRX32));
837 int count = indices ? num_indices : num_vertices;
838 const float color_scale = cmd->data.draw.color_scale;
839
840 cmd->data.draw.count = count;
841 size_indices = indices ? size_indices : 0;
842
843 if (texture) {
844 SDL_Vertex *verts = (SDL_Vertex *)SDL_AllocateRenderVertices(renderer, count * sizeof(*verts), 0, &cmd->data.draw.first);
845 if (!verts) {
846 return false;
847 }
848
849 for (i = 0; i < count; i++) {
850 int j;
851 float *xy_;
852 SDL_FColor col_;
853 float *uv_;
854 if (size_indices == 4) {
855 j = ((const Uint32 *)indices)[i];
856 } else if (size_indices == 2) {
857 j = ((const Uint16 *)indices)[i];
858 } else if (size_indices == 1) {
859 j = ((const Uint8 *)indices)[i];
860 } else {
861 j = i;
862 }
863
864 xy_ = (float *)((char *)xy + j * xy_stride);
865 col_ = *(SDL_FColor *)((char *)color + j * color_stride);
866 uv_ = (float *)((char *)uv + j * uv_stride);
867
868 verts->position.x = xy_[0] * scale_x;
869 verts->position.y = xy_[1] * scale_y;
870
871 col_.r *= color_scale;
872 col_.g *= color_scale;
873 col_.b *= color_scale;
874
875 if (colorswap) {
876 float r = col_.r;
877 col_.r = col_.b;
878 col_.b = r;
879 }
880
881 verts->color = col_;
882 verts->tex_coord.x = uv_[0];
883 verts->tex_coord.y = uv_[1];
884 verts++;
885 }
886
887 } else {
888 SDL_VertexSolid *verts = (SDL_VertexSolid *)SDL_AllocateRenderVertices(renderer, count * sizeof(*verts), 0, &cmd->data.draw.first);
889 if (!verts) {
890 return false;
891 }
892
893 for (i = 0; i < count; i++) {
894 int j;
895 float *xy_;
896 SDL_FColor col_;
897
898 if (size_indices == 4) {
899 j = ((const Uint32 *)indices)[i];
900 } else if (size_indices == 2) {
901 j = ((const Uint16 *)indices)[i];
902 } else if (size_indices == 1) {
903 j = ((const Uint8 *)indices)[i];
904 } else {
905 j = i;
906 }
907
908 xy_ = (float *)((char *)xy + j * xy_stride);
909 col_ = *(SDL_FColor *)((char *)color + j * color_stride);
910
911 verts->position.x = xy_[0] * scale_x;
912 verts->position.y = xy_[1] * scale_y;
913
914 col_.r *= color_scale;
915 col_.g *= color_scale;
916 col_.b *= color_scale;
917
918 if (colorswap) {
919 float r = col_.r;
920 col_.r = col_.b;
921 col_.b = r;
922 }
923
924 verts->color = col_;
925 verts++;
926 }
927 }
928
929 return true;
930}
931
932static bool SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_ImageSource imgsrc, void *vertices)
933{
934 SDL_Texture *texture = cmd->data.draw.texture;
935 const SDL_BlendMode blend = cmd->data.draw.blend;
936 GLES2_ProgramCacheEntry *program;
937 int stride;
938
939 SDL_assert((texture != NULL) == (imgsrc != GLES2_IMAGESOURCE_SOLID));
940
941 if (data->drawstate.viewport_dirty) {
942 const SDL_Rect *viewport = &data->drawstate.viewport;
943 data->glViewport(viewport->x,
944 data->drawstate.target ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
945 viewport->w, viewport->h);
946 if (viewport->w && viewport->h) {
947 data->drawstate.projection[0][0] = 2.0f / viewport->w;
948 data->drawstate.projection[1][1] = (data->drawstate.target ? 2.0f : -2.0f) / viewport->h;
949 data->drawstate.projection[3][1] = data->drawstate.target ? -1.0f : 1.0f;
950 }
951 data->drawstate.viewport_dirty = false;
952 }
953
954 if (data->drawstate.cliprect_enabled_dirty) {
955 if (!data->drawstate.cliprect_enabled) {
956 data->glDisable(GL_SCISSOR_TEST);
957 } else {
958 data->glEnable(GL_SCISSOR_TEST);
959 }
960 data->drawstate.cliprect_enabled_dirty = false;
961 }
962
963 if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
964 const SDL_Rect *viewport = &data->drawstate.viewport;
965 const SDL_Rect *rect = &data->drawstate.cliprect;
966 data->glScissor(viewport->x + rect->x,
967 data->drawstate.target ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
968 rect->w, rect->h);
969 data->drawstate.cliprect_dirty = false;
970 }
971
972 if (data->drawstate.texturing_dirty || ((texture != NULL) != data->drawstate.texturing)) {
973 if (!texture) {
974 data->glDisableVertexAttribArray((GLenum)GLES2_ATTRIBUTE_TEXCOORD);
975 data->drawstate.texturing = false;
976 } else {
977 data->glEnableVertexAttribArray((GLenum)GLES2_ATTRIBUTE_TEXCOORD);
978 data->drawstate.texturing = true;
979 }
980 data->drawstate.texturing_dirty = false;
981 }
982
983 if (texture) {
984 stride = sizeof(SDL_Vertex);
985 } else {
986 stride = sizeof(SDL_VertexSolid);
987 }
988
989 if (texture) {
990 SDL_Vertex *verts = (SDL_Vertex *)(((Uint8 *)vertices) + cmd->data.draw.first);
991 data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, (const GLvoid *)&verts->tex_coord);
992 }
993
994 if (!GLES2_SelectProgram(data, imgsrc, texture ? texture->colorspace : SDL_COLORSPACE_SRGB)) {
995 return false;
996 }
997
998 program = data->drawstate.program;
999
1000 if (program->uniform_locations[GLES2_UNIFORM_PROJECTION] != -1) {
1001 if (SDL_memcmp(program->projection, data->drawstate.projection, sizeof(data->drawstate.projection)) != 0) {
1002 data->glUniformMatrix4fv(program->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)data->drawstate.projection);
1003 SDL_memcpy(program->projection, data->drawstate.projection, sizeof(data->drawstate.projection));
1004 }
1005 }
1006
1007 if (blend != data->drawstate.blend) {
1008 if (blend == SDL_BLENDMODE_NONE) {
1009 data->glDisable(GL_BLEND);
1010 } else {
1011 data->glEnable(GL_BLEND);
1012 data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
1013 GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
1014 GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
1015 GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
1016 data->glBlendEquationSeparate(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)),
1017 GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
1018 }
1019 data->drawstate.blend = blend;
1020 }
1021
1022 // all drawing commands use this
1023 {
1024 SDL_VertexSolid *verts = (SDL_VertexSolid *)(((Uint8 *)vertices) + cmd->data.draw.first);
1025 data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, stride, (const GLvoid *)&verts->position);
1026 data->glVertexAttribPointer(GLES2_ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_TRUE /* Normalized */, stride, (const GLvoid *)&verts->color);
1027 }
1028
1029 return true;
1030}
1031
1032static bool SetTextureAddressMode(GLES2_RenderData *data, GLenum textype, SDL_TextureAddressMode addressMode)
1033{
1034 switch (addressMode) {
1035 case SDL_TEXTURE_ADDRESS_CLAMP:
1036 data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1037 data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1038 break;
1039 case SDL_TEXTURE_ADDRESS_WRAP:
1040 data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_REPEAT);
1041 data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_REPEAT);
1042 break;
1043 default:
1044 return SDL_SetError("Unknown texture address mode: %d", addressMode);
1045 }
1046 return true;
1047}
1048
1049static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, void *vertices)
1050{
1051 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
1052 GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
1053 SDL_Texture *texture = cmd->data.draw.texture;
1054 int ret;
1055
1056 // Pick an appropriate shader
1057 if (renderer->target) {
1058 // Check if we need to do color mapping between the source and render target textures
1059 if (renderer->target->format != texture->format) {
1060 switch (texture->format) {
1061 case SDL_PIXELFORMAT_BGRA32:
1062 switch (renderer->target->format) {
1063 case SDL_PIXELFORMAT_RGBA32:
1064 case SDL_PIXELFORMAT_RGBX32:
1065 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1066 break;
1067 case SDL_PIXELFORMAT_BGRX32:
1068 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
1069 break;
1070 default:
1071 break;
1072 }
1073 break;
1074 case SDL_PIXELFORMAT_RGBA32:
1075 switch (renderer->target->format) {
1076 case SDL_PIXELFORMAT_BGRA32:
1077 case SDL_PIXELFORMAT_BGRX32:
1078 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1079 break;
1080 case SDL_PIXELFORMAT_RGBX32:
1081 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
1082 break;
1083 default:
1084 break;
1085 }
1086 break;
1087 case SDL_PIXELFORMAT_BGRX32:
1088 switch (renderer->target->format) {
1089 case SDL_PIXELFORMAT_RGBA32:
1090 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1091 break;
1092 case SDL_PIXELFORMAT_BGRA32:
1093 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
1094 break;
1095 case SDL_PIXELFORMAT_RGBX32:
1096 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1097 break;
1098 default:
1099 break;
1100 }
1101 break;
1102 case SDL_PIXELFORMAT_RGBX32:
1103 switch (renderer->target->format) {
1104 case SDL_PIXELFORMAT_RGBA32:
1105 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
1106 break;
1107 case SDL_PIXELFORMAT_BGRA32:
1108 sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
1109 break;
1110 case SDL_PIXELFORMAT_BGRX32:
1111 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1112 break;
1113 default:
1114 break;
1115 }
1116 break;
1117#ifdef SDL_HAVE_YUV
1118 case SDL_PIXELFORMAT_IYUV:
1119 case SDL_PIXELFORMAT_YV12:
1120 sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV;
1121 break;
1122 case SDL_PIXELFORMAT_NV12:
1123 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12;
1124 break;
1125 case SDL_PIXELFORMAT_NV21:
1126 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21;
1127 break;
1128#endif
1129 case SDL_PIXELFORMAT_EXTERNAL_OES:
1130 sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
1131 break;
1132 default:
1133 return SDL_SetError("Unsupported texture format");
1134 }
1135 } else {
1136 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; // Texture formats match, use the non color mapping shader (even if the formats are not ABGR)
1137 }
1138 } else {
1139 switch (texture->format) {
1140 case SDL_PIXELFORMAT_BGRA32:
1141 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1142 break;
1143 case SDL_PIXELFORMAT_RGBA32:
1144 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
1145 break;
1146 case SDL_PIXELFORMAT_BGRX32:
1147 sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
1148 break;
1149 case SDL_PIXELFORMAT_RGBX32:
1150 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
1151 break;
1152#ifdef SDL_HAVE_YUV
1153 case SDL_PIXELFORMAT_IYUV:
1154 case SDL_PIXELFORMAT_YV12:
1155 sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV;
1156 break;
1157 case SDL_PIXELFORMAT_NV12:
1158 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12;
1159 break;
1160 case SDL_PIXELFORMAT_NV21:
1161 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21;
1162 break;
1163#endif
1164 case SDL_PIXELFORMAT_EXTERNAL_OES:
1165 sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
1166 break;
1167 default:
1168 return SDL_SetError("Unsupported texture format");
1169 }
1170 }
1171
1172 ret = SetDrawState(data, cmd, sourceType, vertices);
1173
1174 if (texture != data->drawstate.texture) {
1175 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal;
1176#ifdef SDL_HAVE_YUV
1177 if (tdata->yuv) {
1178 data->glActiveTexture(GL_TEXTURE2);
1179 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1180
1181 if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) {
1182 return false;
1183 }
1184
1185 data->glActiveTexture(GL_TEXTURE1);
1186 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1187
1188 if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) {
1189 return false;
1190 }
1191
1192 data->glActiveTexture(GL_TEXTURE0);
1193 } else if (tdata->nv12) {
1194 data->glActiveTexture(GL_TEXTURE1);
1195 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1196
1197 if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) {
1198 return false;
1199 }
1200
1201 data->glActiveTexture(GL_TEXTURE0);
1202 }
1203#endif
1204 data->glBindTexture(tdata->texture_type, tdata->texture);
1205
1206 if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) {
1207 return false;
1208 }
1209
1210 data->drawstate.texture = texture;
1211 }
1212
1213 return ret;
1214}
1215
1216static void GLES2_InvalidateCachedState(SDL_Renderer *renderer)
1217{
1218 GLES2_DrawStateCache *cache = &((GLES2_RenderData *)renderer->internal)->drawstate;
1219 cache->viewport_dirty = true;
1220 cache->texture = NULL;
1221 cache->blend = SDL_BLENDMODE_INVALID;
1222 cache->cliprect_enabled_dirty = true;
1223 cache->cliprect_dirty = true;
1224 cache->texturing_dirty = true;
1225 cache->clear_color_dirty = true;
1226 cache->drawablew = 0;
1227 cache->drawableh = 0;
1228 cache->program = NULL;
1229}
1230
1231static bool GLES2_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
1232{
1233 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
1234 const bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_BGRA32 || renderer->target->format == SDL_PIXELFORMAT_BGRX32));
1235
1236#if USE_VERTEX_BUFFER_OBJECTS
1237 const int vboidx = data->current_vertex_buffer;
1238 const GLuint vbo = data->vertex_buffers[vboidx];
1239#endif
1240
1241 if (!GLES2_ActivateRenderer(renderer)) {
1242 return false;
1243 }
1244
1245 data->drawstate.target = renderer->target;
1246 if (!data->drawstate.target) {
1247 int w, h;
1248 SDL_GetWindowSizeInPixels(renderer->window, &w, &h);
1249 if ((w != data->drawstate.drawablew) || (h != data->drawstate.drawableh)) {
1250 data->drawstate.viewport_dirty = true; // if the window dimensions changed, invalidate the current viewport, etc.
1251 data->drawstate.cliprect_dirty = true;
1252 data->drawstate.drawablew = w;
1253 data->drawstate.drawableh = h;
1254 }
1255 }
1256
1257#if USE_VERTEX_BUFFER_OBJECTS
1258 // upload the new VBO data for this set of commands.
1259 data->glBindBuffer(GL_ARRAY_BUFFER, vbo);
1260 if (data->vertex_buffer_size[vboidx] < vertsize) {
1261 data->glBufferData(GL_ARRAY_BUFFER, vertsize, vertices, GL_STREAM_DRAW);
1262 data->vertex_buffer_size[vboidx] = vertsize;
1263 } else {
1264 data->glBufferSubData(GL_ARRAY_BUFFER, 0, vertsize, vertices);
1265 }
1266
1267 // cycle through a few VBOs so the GL has some time with the data before we replace it.
1268 data->current_vertex_buffer++;
1269 if (data->current_vertex_buffer >= SDL_arraysize(data->vertex_buffers)) {
1270 data->current_vertex_buffer = 0;
1271 }
1272 vertices = NULL; // attrib pointers will be offsets into the VBO.
1273#endif
1274
1275 while (cmd) {
1276 switch (cmd->command) {
1277 case SDL_RENDERCMD_SETDRAWCOLOR:
1278 {
1279 break;
1280 }
1281
1282 case SDL_RENDERCMD_SETVIEWPORT:
1283 {
1284 SDL_Rect *viewport = &data->drawstate.viewport;
1285 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) {
1286 SDL_copyp(viewport, &cmd->data.viewport.rect);
1287 data->drawstate.viewport_dirty = true;
1288 data->drawstate.cliprect_dirty = true;
1289 }
1290 break;
1291 }
1292
1293 case SDL_RENDERCMD_SETCLIPRECT:
1294 {
1295 const SDL_Rect *rect = &cmd->data.cliprect.rect;
1296 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
1297 data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
1298 data->drawstate.cliprect_enabled_dirty = true;
1299 }
1300
1301 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof(*rect)) != 0) {
1302 SDL_copyp(&data->drawstate.cliprect, rect);
1303 data->drawstate.cliprect_dirty = true;
1304 }
1305 break;
1306 }
1307
1308 case SDL_RENDERCMD_CLEAR:
1309 {
1310 const float r = (colorswap ? cmd->data.color.color.b : cmd->data.color.color.r) * cmd->data.color.color_scale;
1311 const float g = cmd->data.color.color.g * cmd->data.color.color_scale;
1312 const float b = (colorswap ? cmd->data.color.color.r : cmd->data.color.color.b) * cmd->data.color.color_scale;
1313 const float a = cmd->data.color.color.a;
1314 if (data->drawstate.clear_color_dirty ||
1315 (r != data->drawstate.clear_color.r) ||
1316 (g != data->drawstate.clear_color.g) ||
1317 (b != data->drawstate.clear_color.b) ||
1318 (a != data->drawstate.clear_color.a)) {
1319 data->glClearColor(r, g, b, a);
1320 data->drawstate.clear_color.r = r;
1321 data->drawstate.clear_color.g = g;
1322 data->drawstate.clear_color.b = b;
1323 data->drawstate.clear_color.a = a;
1324 data->drawstate.clear_color_dirty = false;
1325 }
1326
1327 if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) {
1328 data->glDisable(GL_SCISSOR_TEST);
1329 data->drawstate.cliprect_enabled_dirty = data->drawstate.cliprect_enabled;
1330 }
1331
1332 data->glClear(GL_COLOR_BUFFER_BIT);
1333 break;
1334 }
1335
1336 case SDL_RENDERCMD_FILL_RECTS: // unused
1337 break;
1338
1339 case SDL_RENDERCMD_COPY: // unused
1340 break;
1341
1342 case SDL_RENDERCMD_COPY_EX: // unused
1343 break;
1344
1345 case SDL_RENDERCMD_DRAW_LINES:
1346 {
1347 if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID, vertices)) {
1348 size_t count = cmd->data.draw.count;
1349 if (count > 2) {
1350 // joined lines cannot be grouped
1351 data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei)count);
1352 } else {
1353 // let's group non joined lines
1354 SDL_RenderCommand *finalcmd = cmd;
1355 SDL_RenderCommand *nextcmd = cmd->next;
1356 SDL_BlendMode thisblend = cmd->data.draw.blend;
1357
1358 while (nextcmd) {
1359 const SDL_RenderCommandType nextcmdtype = nextcmd->command;
1360 if (nextcmdtype != SDL_RENDERCMD_DRAW_LINES) {
1361 break; // can't go any further on this draw call, different render command up next.
1362 } else if (nextcmd->data.draw.count != 2) {
1363 break; // can't go any further on this draw call, those are joined lines
1364 } else if (nextcmd->data.draw.blend != thisblend) {
1365 break; // can't go any further on this draw call, different blendmode copy up next.
1366 } else {
1367 finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
1368 count += nextcmd->data.draw.count;
1369 }
1370 nextcmd = nextcmd->next;
1371 }
1372
1373 data->glDrawArrays(GL_LINES, 0, (GLsizei)count);
1374 cmd = finalcmd; // skip any copy commands we just combined in here.
1375 }
1376 }
1377 break;
1378 }
1379
1380 case SDL_RENDERCMD_DRAW_POINTS:
1381 case SDL_RENDERCMD_GEOMETRY:
1382 {
1383 /* as long as we have the same copy command in a row, with the
1384 same texture, we can combine them all into a single draw call. */
1385 SDL_Texture *thistexture = cmd->data.draw.texture;
1386 SDL_BlendMode thisblend = cmd->data.draw.blend;
1387 const SDL_RenderCommandType thiscmdtype = cmd->command;
1388 SDL_RenderCommand *finalcmd = cmd;
1389 SDL_RenderCommand *nextcmd = cmd->next;
1390 size_t count = cmd->data.draw.count;
1391 int ret;
1392 while (nextcmd) {
1393 const SDL_RenderCommandType nextcmdtype = nextcmd->command;
1394 if (nextcmdtype != thiscmdtype) {
1395 break; // can't go any further on this draw call, different render command up next.
1396 } else if (nextcmd->data.draw.texture != thistexture || nextcmd->data.draw.blend != thisblend) {
1397 break; // can't go any further on this draw call, different texture/blendmode copy up next.
1398 } else {
1399 finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
1400 count += nextcmd->data.draw.count;
1401 }
1402 nextcmd = nextcmd->next;
1403 }
1404
1405 if (thistexture) {
1406 ret = SetCopyState(renderer, cmd, vertices);
1407 } else {
1408 ret = SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID, vertices);
1409 }
1410
1411 if (ret) {
1412 int op = GL_TRIANGLES; // SDL_RENDERCMD_GEOMETRY
1413 if (thiscmdtype == SDL_RENDERCMD_DRAW_POINTS) {
1414 op = GL_POINTS;
1415 }
1416 data->glDrawArrays(op, 0, (GLsizei)count);
1417 }
1418
1419 cmd = finalcmd; // skip any copy commands we just combined in here.
1420 break;
1421 }
1422
1423 case SDL_RENDERCMD_NO_OP:
1424 break;
1425 }
1426
1427 cmd = cmd->next;
1428 }
1429
1430 return GL_CheckError("", renderer);
1431}
1432
1433static void GLES2_DestroyRenderer(SDL_Renderer *renderer)
1434{
1435 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
1436
1437 // Deallocate everything
1438 if (data) {
1439 GLES2_ActivateRenderer(renderer);
1440
1441 {
1442 int i;
1443 for (i = 0; i < GLES2_SHADER_COUNT; i++) {
1444 GLuint id = data->shader_id_cache[i];
1445 if (id) {
1446 data->glDeleteShader(id);
1447 }
1448 }
1449 }
1450 {
1451 GLES2_ProgramCacheEntry *entry;
1452 GLES2_ProgramCacheEntry *next;
1453 entry = data->program_cache.head;
1454 while (entry) {
1455 data->glDeleteProgram(entry->id);
1456 next = entry->next;
1457 SDL_free(entry);
1458 entry = next;
1459 }
1460 }
1461
1462 if (data->context) {
1463 while (data->framebuffers) {
1464 GLES2_FBOList *nextnode = data->framebuffers->next;
1465 data->glDeleteFramebuffers(1, &data->framebuffers->FBO);
1466 GL_CheckError("", renderer);
1467 SDL_free(data->framebuffers);
1468 data->framebuffers = nextnode;
1469 }
1470
1471#if USE_VERTEX_BUFFER_OBJECTS
1472 data->glDeleteBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
1473 GL_CheckError("", renderer);
1474#endif
1475
1476 SDL_GL_DestroyContext(data->context);
1477 }
1478
1479 SDL_free(data);
1480 }
1481}
1482
1483static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
1484{
1485 GLES2_RenderData *renderdata = (GLES2_RenderData *)renderer->internal;
1486 GLES2_TextureData *data;
1487 GLenum format;
1488 GLenum type;
1489 GLenum scaleMode;
1490
1491 GLES2_ActivateRenderer(renderer);
1492
1493 renderdata->drawstate.texture = NULL; // we trash this state.
1494
1495 // Determine the corresponding GLES texture format params
1496 switch (texture->format) {
1497 case SDL_PIXELFORMAT_BGRA32:
1498 case SDL_PIXELFORMAT_RGBA32:
1499 case SDL_PIXELFORMAT_BGRX32:
1500 case SDL_PIXELFORMAT_RGBX32:
1501 format = GL_RGBA;
1502 type = GL_UNSIGNED_BYTE;
1503 break;
1504#ifdef SDL_HAVE_YUV
1505 case SDL_PIXELFORMAT_IYUV:
1506 case SDL_PIXELFORMAT_YV12:
1507 case SDL_PIXELFORMAT_NV12:
1508 case SDL_PIXELFORMAT_NV21:
1509 format = GL_LUMINANCE;
1510 type = GL_UNSIGNED_BYTE;
1511 break;
1512#endif
1513#ifdef GL_TEXTURE_EXTERNAL_OES
1514 case SDL_PIXELFORMAT_EXTERNAL_OES:
1515 format = GL_NONE;
1516 type = GL_NONE;
1517 break;
1518#endif
1519 default:
1520 return SDL_SetError("Texture format not supported");
1521 }
1522
1523 if (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES &&
1524 texture->access != SDL_TEXTUREACCESS_STATIC) {
1525 return SDL_SetError("Unsupported texture access for SDL_PIXELFORMAT_EXTERNAL_OES");
1526 }
1527
1528 // Allocate a texture struct
1529 data = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData));
1530 if (!data) {
1531 return false;
1532 }
1533 data->texture = 0;
1534#ifdef GL_TEXTURE_EXTERNAL_OES
1535 data->texture_type = (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES) ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
1536#else
1537 data->texture_type = GL_TEXTURE_2D;
1538#endif
1539 data->pixel_format = format;
1540 data->pixel_type = type;
1541#ifdef SDL_HAVE_YUV
1542 data->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12));
1543 data->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21));
1544 data->texture_u = 0;
1545 data->texture_v = 0;
1546#endif
1547 scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? GL_NEAREST : GL_LINEAR;
1548
1549 // Allocate a blob for image renderdata
1550 if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
1551 size_t size;
1552 data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
1553 size = (size_t)texture->h * data->pitch;
1554#ifdef SDL_HAVE_YUV
1555 if (data->yuv) {
1556 // Need to add size for the U and V planes
1557 size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
1558 } else if (data->nv12) {
1559 // Need to add size for the U/V plane
1560 size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
1561 }
1562#endif
1563 data->pixel_data = SDL_calloc(1, size);
1564 if (!data->pixel_data) {
1565 SDL_free(data);
1566 return false;
1567 }
1568 }
1569
1570 // Allocate the texture
1571 GL_CheckError("", renderer);
1572
1573#ifdef SDL_HAVE_YUV
1574 if (data->yuv) {
1575 data->texture_v = (GLuint)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_V_NUMBER, 0);
1576 if (data->texture_v) {
1577 data->texture_v_external = true;
1578 } else {
1579 renderdata->glGenTextures(1, &data->texture_v);
1580 if (!GL_CheckError("glGenTexures()", renderer)) {
1581 return false;
1582 }
1583 }
1584 renderdata->glActiveTexture(GL_TEXTURE2);
1585 renderdata->glBindTexture(data->texture_type, data->texture_v);
1586 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1587 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1588 renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
1589 SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_V_NUMBER, data->texture_v);
1590
1591 data->texture_u = (GLuint)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_U_NUMBER, 0);
1592 if (data->texture_u) {
1593 data->texture_u_external = true;
1594 } else {
1595 renderdata->glGenTextures(1, &data->texture_u);
1596 if (!GL_CheckError("glGenTexures()", renderer)) {
1597 return false;
1598 }
1599 }
1600 renderdata->glActiveTexture(GL_TEXTURE1);
1601 renderdata->glBindTexture(data->texture_type, data->texture_u);
1602 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1603 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1604 renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
1605 if (!GL_CheckError("glTexImage2D()", renderer)) {
1606 return false;
1607 }
1608 SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_U_NUMBER, data->texture_u);
1609
1610 if (!SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8)) {
1611 return SDL_SetError("Unsupported YUV colorspace");
1612 }
1613 } else if (data->nv12) {
1614 data->texture_u = (GLuint)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_UV_NUMBER, 0);
1615 if (data->texture_u) {
1616 data->texture_u_external = true;
1617 } else {
1618 renderdata->glGenTextures(1, &data->texture_u);
1619 if (!GL_CheckError("glGenTexures()", renderer)) {
1620 return false;
1621 }
1622 }
1623 renderdata->glActiveTexture(GL_TEXTURE1);
1624 renderdata->glBindTexture(data->texture_type, data->texture_u);
1625 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1626 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1627 renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
1628 if (!GL_CheckError("glTexImage2D()", renderer)) {
1629 return false;
1630 }
1631 SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_UV_NUMBER, data->texture_u);
1632
1633 if (!SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8)) {
1634 return SDL_SetError("Unsupported YUV colorspace");
1635 }
1636 }
1637#endif
1638
1639 data->texture = (GLuint)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_NUMBER, 0);
1640 if (data->texture) {
1641 data->texture_external = true;
1642 } else {
1643 renderdata->glGenTextures(1, &data->texture);
1644 if (!GL_CheckError("glGenTexures()", renderer)) {
1645 return false;
1646 }
1647 }
1648 texture->internal = data;
1649 renderdata->glActiveTexture(GL_TEXTURE0);
1650 renderdata->glBindTexture(data->texture_type, data->texture);
1651 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1652 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1653 if (texture->format != SDL_PIXELFORMAT_EXTERNAL_OES) {
1654 renderdata->glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);
1655 if (!GL_CheckError("glTexImage2D()", renderer)) {
1656 return false;
1657 }
1658 }
1659 SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_NUMBER, data->texture);
1660 SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_TARGET_NUMBER, data->texture_type);
1661
1662 if (texture->access == SDL_TEXTUREACCESS_TARGET) {
1663 data->fbo = GLES2_GetFBO((GLES2_RenderData *)renderer->internal, texture->w, texture->h);
1664 } else {
1665 data->fbo = NULL;
1666 }
1667
1668 return GL_CheckError("", renderer);
1669}
1670
1671static bool GLES2_TexSubImage2D(GLES2_RenderData *data, GLenum target, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, GLint pitch, GLint bpp)
1672{
1673 Uint8 *blob = NULL;
1674 Uint8 *src;
1675 size_t src_pitch;
1676 int y;
1677
1678 if ((width == 0) || (height == 0) || (bpp == 0)) {
1679 return true; // nothing to do
1680 }
1681
1682 // Reformat the texture data into a tightly packed array
1683 src_pitch = (size_t)width * bpp;
1684 src = (Uint8 *)pixels;
1685 if ((size_t)pitch != src_pitch) {
1686 blob = (Uint8 *)SDL_malloc(src_pitch * height);
1687 if (!blob) {
1688 return false;
1689 }
1690 src = blob;
1691 for (y = 0; y < height; ++y) {
1692 SDL_memcpy(src, pixels, src_pitch);
1693 src += src_pitch;
1694 pixels = (Uint8 *)pixels + pitch;
1695 }
1696 src = blob;
1697 }
1698
1699 data->glTexSubImage2D(target, 0, xoffset, yoffset, width, height, format, type, src);
1700 if (blob) {
1701 SDL_free(blob);
1702 }
1703 return true;
1704}
1705
1706static bool GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
1707 const void *pixels, int pitch)
1708{
1709 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
1710 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal;
1711
1712 GLES2_ActivateRenderer(renderer);
1713
1714 // Bail out if we're supposed to update an empty rectangle
1715 if (rect->w <= 0 || rect->h <= 0) {
1716 return true;
1717 }
1718
1719 data->drawstate.texture = NULL; // we trash this state.
1720
1721 // Create a texture subimage with the supplied data
1722 data->glBindTexture(tdata->texture_type, tdata->texture);
1723 GLES2_TexSubImage2D(data, tdata->texture_type,
1724 rect->x,
1725 rect->y,
1726 rect->w,
1727 rect->h,
1728 tdata->pixel_format,
1729 tdata->pixel_type,
1730 pixels, pitch, SDL_BYTESPERPIXEL(texture->format));
1731
1732#ifdef SDL_HAVE_YUV
1733 if (tdata->yuv) {
1734 // Skip to the correct offset into the next texture
1735 pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
1736 if (texture->format == SDL_PIXELFORMAT_YV12) {
1737 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1738 } else {
1739 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1740 }
1741 GLES2_TexSubImage2D(data, tdata->texture_type,
1742 rect->x / 2,
1743 rect->y / 2,
1744 (rect->w + 1) / 2,
1745 (rect->h + 1) / 2,
1746 tdata->pixel_format,
1747 tdata->pixel_type,
1748 pixels, (pitch + 1) / 2, 1);
1749
1750 // Skip to the correct offset into the next texture
1751 pixels = (const void *)((const Uint8 *)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
1752 if (texture->format == SDL_PIXELFORMAT_YV12) {
1753 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1754 } else {
1755 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1756 }
1757 GLES2_TexSubImage2D(data, tdata->texture_type,
1758 rect->x / 2,
1759 rect->y / 2,
1760 (rect->w + 1) / 2,
1761 (rect->h + 1) / 2,
1762 tdata->pixel_format,
1763 tdata->pixel_type,
1764 pixels, (pitch + 1) / 2, 1);
1765 } else if (tdata->nv12) {
1766 // Skip to the correct offset into the next texture
1767 pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
1768 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1769 GLES2_TexSubImage2D(data, tdata->texture_type,
1770 rect->x / 2,
1771 rect->y / 2,
1772 (rect->w + 1) / 2,
1773 (rect->h + 1) / 2,
1774 GL_LUMINANCE_ALPHA,
1775 GL_UNSIGNED_BYTE,
1776 pixels, 2 * ((pitch + 1) / 2), 2);
1777 }
1778#endif
1779
1780 return GL_CheckError("glTexSubImage2D()", renderer);
1781}
1782
1783#ifdef SDL_HAVE_YUV
1784static bool GLES2_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture,
1785 const SDL_Rect *rect,
1786 const Uint8 *Yplane, int Ypitch,
1787 const Uint8 *Uplane, int Upitch,
1788 const Uint8 *Vplane, int Vpitch)
1789{
1790 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
1791 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal;
1792
1793 GLES2_ActivateRenderer(renderer);
1794
1795 // Bail out if we're supposed to update an empty rectangle
1796 if (rect->w <= 0 || rect->h <= 0) {
1797 return true;
1798 }
1799
1800 data->drawstate.texture = NULL; // we trash this state.
1801
1802 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1803 GLES2_TexSubImage2D(data, tdata->texture_type,
1804 rect->x / 2,
1805 rect->y / 2,
1806 (rect->w + 1) / 2,
1807 (rect->h + 1) / 2,
1808 tdata->pixel_format,
1809 tdata->pixel_type,
1810 Vplane, Vpitch, 1);
1811
1812 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1813 GLES2_TexSubImage2D(data, tdata->texture_type,
1814 rect->x / 2,
1815 rect->y / 2,
1816 (rect->w + 1) / 2,
1817 (rect->h + 1) / 2,
1818 tdata->pixel_format,
1819 tdata->pixel_type,
1820 Uplane, Upitch, 1);
1821
1822 data->glBindTexture(tdata->texture_type, tdata->texture);
1823 GLES2_TexSubImage2D(data, tdata->texture_type,
1824 rect->x,
1825 rect->y,
1826 rect->w,
1827 rect->h,
1828 tdata->pixel_format,
1829 tdata->pixel_type,
1830 Yplane, Ypitch, 1);
1831
1832 return GL_CheckError("glTexSubImage2D()", renderer);
1833}
1834
1835static bool GLES2_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture,
1836 const SDL_Rect *rect,
1837 const Uint8 *Yplane, int Ypitch,
1838 const Uint8 *UVplane, int UVpitch)
1839{
1840 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
1841 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal;
1842
1843 GLES2_ActivateRenderer(renderer);
1844
1845 // Bail out if we're supposed to update an empty rectangle
1846 if (rect->w <= 0 || rect->h <= 0) {
1847 return true;
1848 }
1849
1850 data->drawstate.texture = NULL; // we trash this state.
1851
1852 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1853 GLES2_TexSubImage2D(data, tdata->texture_type,
1854 rect->x / 2,
1855 rect->y / 2,
1856 (rect->w + 1) / 2,
1857 (rect->h + 1) / 2,
1858 GL_LUMINANCE_ALPHA,
1859 GL_UNSIGNED_BYTE,
1860 UVplane, UVpitch, 2);
1861
1862 data->glBindTexture(tdata->texture_type, tdata->texture);
1863 GLES2_TexSubImage2D(data, tdata->texture_type,
1864 rect->x,
1865 rect->y,
1866 rect->w,
1867 rect->h,
1868 tdata->pixel_format,
1869 tdata->pixel_type,
1870 Yplane, Ypitch, 1);
1871
1872 return GL_CheckError("glTexSubImage2D()", renderer);
1873}
1874#endif
1875
1876static bool GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
1877 void **pixels, int *pitch)
1878{
1879 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal;
1880
1881 // Retrieve the buffer/pitch for the specified region
1882 *pixels = (Uint8 *)tdata->pixel_data +
1883 (tdata->pitch * rect->y) +
1884 (rect->x * SDL_BYTESPERPIXEL(texture->format));
1885 *pitch = tdata->pitch;
1886
1887 return true;
1888}
1889
1890static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
1891{
1892 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal;
1893 SDL_Rect rect;
1894
1895 // We do whole texture updates, at least for now
1896 rect.x = 0;
1897 rect.y = 0;
1898 rect.w = texture->w;
1899 rect.h = texture->h;
1900 GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
1901}
1902
1903static void GLES2_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
1904{
1905 GLES2_RenderData *renderdata = (GLES2_RenderData *)renderer->internal;
1906 GLES2_TextureData *data = (GLES2_TextureData *)texture->internal;
1907 GLenum glScaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? GL_NEAREST : GL_LINEAR;
1908
1909#ifdef SDL_HAVE_YUV
1910 if (data->yuv) {
1911 renderdata->glActiveTexture(GL_TEXTURE2);
1912 renderdata->glBindTexture(data->texture_type, data->texture_v);
1913 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
1914 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
1915
1916 renderdata->glActiveTexture(GL_TEXTURE1);
1917 renderdata->glBindTexture(data->texture_type, data->texture_u);
1918 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
1919 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
1920 } else if (data->nv12) {
1921 renderdata->glActiveTexture(GL_TEXTURE1);
1922 renderdata->glBindTexture(data->texture_type, data->texture_u);
1923 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
1924 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
1925 }
1926#endif
1927
1928 renderdata->glActiveTexture(GL_TEXTURE0);
1929 renderdata->glBindTexture(data->texture_type, data->texture);
1930 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
1931 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
1932}
1933
1934static bool GLES2_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
1935{
1936 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
1937 GLES2_TextureData *texturedata = NULL;
1938 GLenum status;
1939
1940 data->drawstate.viewport_dirty = true;
1941
1942 if (!texture) {
1943 data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer);
1944 } else {
1945 texturedata = (GLES2_TextureData *)texture->internal;
1946 data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO);
1947 // TODO: check if texture pixel format allows this operation
1948 data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0);
1949 // Check FBO status
1950 status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER);
1951 if (status != GL_FRAMEBUFFER_COMPLETE) {
1952 return SDL_SetError("glFramebufferTexture2D() failed");
1953 }
1954 }
1955 return true;
1956}
1957
1958static void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
1959{
1960 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
1961 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal;
1962
1963 GLES2_ActivateRenderer(renderer);
1964
1965 if (data->drawstate.texture == texture) {
1966 data->drawstate.texture = NULL;
1967 }
1968 if (data->drawstate.target == texture) {
1969 data->drawstate.target = NULL;
1970 }
1971
1972 // Destroy the texture
1973 if (tdata) {
1974 if (tdata->texture && !tdata->texture_external) {
1975 data->glDeleteTextures(1, &tdata->texture);
1976 }
1977#ifdef SDL_HAVE_YUV
1978 if (tdata->texture_v && !tdata->texture_v_external) {
1979 data->glDeleteTextures(1, &tdata->texture_v);
1980 }
1981 if (tdata->texture_u && !tdata->texture_u_external) {
1982 data->glDeleteTextures(1, &tdata->texture_u);
1983 }
1984#endif
1985 SDL_free(tdata->pixel_data);
1986 SDL_free(tdata);
1987 texture->internal = NULL;
1988 }
1989}
1990
1991static SDL_Surface *GLES2_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
1992{
1993 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
1994 SDL_PixelFormat format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_RGBA32;
1995 SDL_Surface *surface;
1996
1997 surface = SDL_CreateSurface(rect->w, rect->h, format);
1998 if (!surface) {
1999 return NULL;
2000 }
2001
2002 int y = rect->y;
2003 if (!renderer->target) {
2004 int w, h;
2005 SDL_GetRenderOutputSize(renderer, &w, &h);
2006 y = (h - y) - rect->h;
2007 }
2008
2009 data->glReadPixels(rect->x, y, rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
2010 if (!GL_CheckError("glReadPixels()", renderer)) {
2011 SDL_DestroySurface(surface);
2012 return NULL;
2013 }
2014
2015 // Flip the rows to be top-down if necessary
2016 if (!renderer->target) {
2017 SDL_FlipSurface(surface, SDL_FLIP_VERTICAL);
2018 }
2019 return surface;
2020}
2021
2022static bool GLES2_RenderPresent(SDL_Renderer *renderer)
2023{
2024 // Tell the video driver to swap buffers
2025 return SDL_GL_SwapWindow(renderer->window);
2026}
2027
2028static bool GLES2_SetVSync(SDL_Renderer *renderer, const int vsync)
2029{
2030 int interval = 0;
2031
2032 if (!SDL_GL_SetSwapInterval(vsync)) {
2033 return false;
2034 }
2035
2036 if (!SDL_GL_GetSwapInterval(&interval)) {
2037 return false;
2038 }
2039
2040 if (interval != vsync) {
2041 return SDL_Unsupported();
2042 }
2043 return true;
2044}
2045
2046/*************************************************************************************************
2047 * Renderer instantiation *
2048 *************************************************************************************************/
2049
2050static bool GLES2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
2051{
2052 GLES2_RenderData *data = NULL;
2053 SDL_WindowFlags window_flags = 0; // -Wconditional-uninitialized
2054 GLint window_framebuffer;
2055 GLint value;
2056 int profile_mask = 0, major = 0, minor = 0;
2057 bool changed_window = false;
2058
2059 if (!SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask)) {
2060 goto error;
2061 }
2062 if (!SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major)) {
2063 goto error;
2064 }
2065 if (!SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor)) {
2066 goto error;
2067 }
2068
2069 SDL_SyncWindow(window);
2070 window_flags = SDL_GetWindowFlags(window);
2071
2072 // OpenGL ES 3.0 is a superset of OpenGL ES 2.0
2073 if (!(window_flags & SDL_WINDOW_OPENGL) ||
2074 profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major < RENDERER_CONTEXT_MAJOR) {
2075
2076 changed_window = true;
2077 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
2078 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
2079 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
2080
2081 if (!SDL_RecreateWindow(window, (window_flags & ~(SDL_WINDOW_VULKAN | SDL_WINDOW_METAL)) | SDL_WINDOW_OPENGL)) {
2082 goto error;
2083 }
2084 }
2085
2086 SDL_SetupRendererColorspace(renderer, create_props);
2087
2088 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
2089 SDL_SetError("Unsupported output colorspace");
2090 goto error;
2091 }
2092
2093 data = (GLES2_RenderData *)SDL_calloc(1, sizeof(GLES2_RenderData));
2094 if (!data) {
2095 goto error;
2096 }
2097 renderer->internal = data;
2098 GLES2_InvalidateCachedState(renderer);
2099 renderer->window = window;
2100
2101 renderer->name = GLES2_RenderDriver.name;
2102 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32);
2103 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32);
2104 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX32);
2105 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX32);
2106
2107 // Create an OpenGL ES 2.0 context
2108 data->context = SDL_GL_CreateContext(window);
2109 if (!data->context) {
2110 goto error;
2111 }
2112 if (!SDL_GL_MakeCurrent(window, data->context)) {
2113 goto error;
2114 }
2115
2116 if (!GLES2_LoadFunctions(data)) {
2117 goto error;
2118 }
2119
2120 if (!GLES2_CacheShaders(data)) {
2121 goto error;
2122 }
2123
2124 // Check for debug output support
2125 if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) &&
2126 (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
2127 data->debug_enabled = true;
2128 }
2129
2130 value = 0;
2131 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
2132 SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, value);
2133
2134#if USE_VERTEX_BUFFER_OBJECTS
2135 // we keep a few of these and cycle through them, so data can live for a few frames.
2136 data->glGenBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
2137#endif
2138
2139 data->framebuffers = NULL;
2140 data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer);
2141 data->window_framebuffer = (GLuint)window_framebuffer;
2142
2143 // Populate the function pointers for the module
2144 renderer->WindowEvent = GLES2_WindowEvent;
2145 renderer->SupportsBlendMode = GLES2_SupportsBlendMode;
2146 renderer->CreateTexture = GLES2_CreateTexture;
2147 renderer->UpdateTexture = GLES2_UpdateTexture;
2148#ifdef SDL_HAVE_YUV
2149 renderer->UpdateTextureYUV = GLES2_UpdateTextureYUV;
2150 renderer->UpdateTextureNV = GLES2_UpdateTextureNV;
2151#endif
2152 renderer->LockTexture = GLES2_LockTexture;
2153 renderer->UnlockTexture = GLES2_UnlockTexture;
2154 renderer->SetTextureScaleMode = GLES2_SetTextureScaleMode;
2155 renderer->SetRenderTarget = GLES2_SetRenderTarget;
2156 renderer->QueueSetViewport = GLES2_QueueNoOp;
2157 renderer->QueueSetDrawColor = GLES2_QueueNoOp;
2158 renderer->QueueDrawPoints = GLES2_QueueDrawPoints;
2159 renderer->QueueDrawLines = GLES2_QueueDrawLines;
2160 renderer->QueueGeometry = GLES2_QueueGeometry;
2161 renderer->InvalidateCachedState = GLES2_InvalidateCachedState;
2162 renderer->RunCommandQueue = GLES2_RunCommandQueue;
2163 renderer->RenderReadPixels = GLES2_RenderReadPixels;
2164 renderer->RenderPresent = GLES2_RenderPresent;
2165 renderer->DestroyTexture = GLES2_DestroyTexture;
2166 renderer->DestroyRenderer = GLES2_DestroyRenderer;
2167 renderer->SetVSync = GLES2_SetVSync;
2168#ifdef SDL_HAVE_YUV
2169 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12);
2170 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV);
2171 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12);
2172 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21);
2173#endif
2174#ifdef GL_TEXTURE_EXTERNAL_OES
2175 if (GLES2_CacheShader(data, GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES, GL_FRAGMENT_SHADER)) {
2176 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_EXTERNAL_OES);
2177 }
2178#endif
2179
2180 if (SDL_GL_ExtensionSupported("GL_EXT_blend_minmax")) {
2181 data->GL_EXT_blend_minmax_supported = true;
2182 }
2183
2184 // Set up parameters for rendering
2185 data->glDisable(GL_DEPTH_TEST);
2186 data->glDisable(GL_CULL_FACE);
2187 data->glActiveTexture(GL_TEXTURE0);
2188 data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
2189 data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2190
2191 data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
2192 data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_COLOR);
2193 data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
2194
2195 data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
2196
2197 data->drawstate.clear_color.r = 1.0f;
2198 data->drawstate.clear_color.g = 1.0f;
2199 data->drawstate.clear_color.b = 1.0f;
2200 data->drawstate.clear_color.a = 1.0f;
2201 data->drawstate.projection[3][0] = -1.0f;
2202 data->drawstate.projection[3][3] = 1.0f;
2203
2204 GL_CheckError("", renderer);
2205
2206 return true;
2207
2208error:
2209 if (changed_window) {
2210 // Uh oh, better try to put it back...
2211 char *error = SDL_strdup(SDL_GetError());
2212 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
2213 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
2214 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
2215 SDL_RecreateWindow(window, window_flags);
2216 SDL_SetError("%s", error);
2217 SDL_free(error);
2218 }
2219 return false;
2220}
2221
2222SDL_RenderDriver GLES2_RenderDriver = {
2223 GLES2_CreateRenderer, "opengles2"
2224};
2225
2226#endif // SDL_VIDEO_RENDER_OGL_ES2
diff --git a/contrib/SDL-3.2.8/src/render/opengles2/SDL_shaders_gles2.c b/contrib/SDL-3.2.8/src/render/opengles2/SDL_shaders_gles2.c
new file mode 100644
index 0000000..1387968
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/opengles2/SDL_shaders_gles2.c
@@ -0,0 +1,387 @@
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
34static 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
45static const char GLES2_Fragment_Include_Medium_Texture_Precision[] = \
46"#define SDL_TEXCOORD_PRECISION mediump\n" \
47"precision mediump float;\n" \
48"\n" \
49;
50
51static const char GLES2_Fragment_Include_High_Texture_Precision[] = \
52"#define SDL_TEXCOORD_PRECISION highp\n" \
53"precision mediump float;\n" \
54"\n" \
55;
56
57static 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
65static 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
82static 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
91static const char GLES2_Fragment_TextureABGR[] = \
92"uniform sampler2D u_texture;\n" \
93"varying mediump vec4 v_color;\n" \
94"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \
95"\n" \
96"void main()\n" \
97"{\n" \
98" gl_FragColor = texture2D(u_texture, v_texCoord);\n" \
99" gl_FragColor *= v_color;\n" \
100"}\n" \
101;
102
103// ARGB to ABGR conversion
104static const char GLES2_Fragment_TextureARGB[] = \
105"uniform sampler2D u_texture;\n" \
106"varying mediump vec4 v_color;\n" \
107"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \
108"\n" \
109"void main()\n" \
110"{\n" \
111" mediump vec4 abgr = texture2D(u_texture, v_texCoord);\n" \
112" gl_FragColor = abgr;\n" \
113" gl_FragColor.r = abgr.b;\n" \
114" gl_FragColor.b = abgr.r;\n" \
115" gl_FragColor *= v_color;\n" \
116"}\n" \
117;
118
119// RGB to ABGR conversion
120static const char GLES2_Fragment_TextureRGB[] = \
121"uniform sampler2D u_texture;\n" \
122"varying mediump vec4 v_color;\n" \
123"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \
124"\n" \
125"void main()\n" \
126"{\n" \
127" mediump vec4 abgr = texture2D(u_texture, v_texCoord);\n" \
128" gl_FragColor = abgr;\n" \
129" gl_FragColor.r = abgr.b;\n" \
130" gl_FragColor.b = abgr.r;\n" \
131" gl_FragColor.a = 1.0;\n" \
132" gl_FragColor *= v_color;\n" \
133"}\n" \
134;
135
136// BGR to ABGR conversion
137static const char GLES2_Fragment_TextureBGR[] = \
138"uniform sampler2D u_texture;\n" \
139"varying mediump vec4 v_color;\n" \
140"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \
141"\n" \
142"void main()\n" \
143"{\n" \
144" mediump vec4 abgr = texture2D(u_texture, v_texCoord);\n" \
145" gl_FragColor = abgr;\n" \
146" gl_FragColor.a = 1.0;\n" \
147" gl_FragColor *= v_color;\n" \
148"}\n" \
149;
150
151#ifdef SDL_HAVE_YUV
152
153#define YUV_SHADER_PROLOGUE \
154"uniform sampler2D u_texture;\n" \
155"uniform sampler2D u_texture_u;\n" \
156"uniform sampler2D u_texture_v;\n" \
157"uniform vec3 u_offset;\n" \
158"uniform mat3 u_matrix;\n" \
159"varying mediump vec4 v_color;\n" \
160"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \
161"\n" \
162
163#define YUV_SHADER_BODY \
164"void main()\n" \
165"{\n" \
166" mediump vec3 yuv;\n" \
167" lowp vec3 rgb;\n" \
168"\n" \
169" // Get the YUV values \n" \
170" yuv.x = texture2D(u_texture, v_texCoord).r;\n" \
171" yuv.y = texture2D(u_texture_u, v_texCoord).r;\n" \
172" yuv.z = texture2D(u_texture_v, v_texCoord).r;\n" \
173"\n" \
174" // Do the color transform \n" \
175" yuv += u_offset;\n" \
176" rgb = yuv * u_matrix;\n" \
177"\n" \
178" // That was easy. :) \n" \
179" gl_FragColor = vec4(rgb, 1);\n" \
180" gl_FragColor *= v_color;\n" \
181"}" \
182
183#define NV12_RA_SHADER_BODY \
184"void main()\n" \
185"{\n" \
186" mediump vec3 yuv;\n" \
187" lowp vec3 rgb;\n" \
188"\n" \
189" // Get the YUV values \n" \
190" yuv.x = texture2D(u_texture, v_texCoord).r;\n" \
191" yuv.yz = texture2D(u_texture_u, v_texCoord).ra;\n" \
192"\n" \
193" // Do the color transform \n" \
194" yuv += u_offset;\n" \
195" rgb = yuv * u_matrix;\n" \
196"\n" \
197" // That was easy. :) \n" \
198" gl_FragColor = vec4(rgb, 1);\n" \
199" gl_FragColor *= v_color;\n" \
200"}" \
201
202#define NV12_RG_SHADER_BODY \
203"void main()\n" \
204"{\n" \
205" mediump vec3 yuv;\n" \
206" lowp vec3 rgb;\n" \
207"\n" \
208" // Get the YUV values \n" \
209" yuv.x = texture2D(u_texture, v_texCoord).r;\n" \
210" yuv.yz = texture2D(u_texture_u, v_texCoord).rg;\n" \
211"\n" \
212" // Do the color transform \n" \
213" yuv += u_offset;\n" \
214" rgb = yuv * u_matrix;\n" \
215"\n" \
216" // That was easy. :) \n" \
217" gl_FragColor = vec4(rgb, 1);\n" \
218" gl_FragColor *= v_color;\n" \
219"}" \
220
221#define NV21_RA_SHADER_BODY \
222"void main()\n" \
223"{\n" \
224" mediump vec3 yuv;\n" \
225" lowp vec3 rgb;\n" \
226"\n" \
227" // Get the YUV values \n" \
228" yuv.x = texture2D(u_texture, v_texCoord).r;\n" \
229" yuv.yz = texture2D(u_texture_u, v_texCoord).ar;\n" \
230"\n" \
231" // Do the color transform \n" \
232" yuv += u_offset;\n" \
233" rgb = yuv * u_matrix;\n" \
234"\n" \
235" // That was easy. :) \n" \
236" gl_FragColor = vec4(rgb, 1);\n" \
237" gl_FragColor *= v_color;\n" \
238"}" \
239
240#define NV21_RG_SHADER_BODY \
241"void main()\n" \
242"{\n" \
243" mediump vec3 yuv;\n" \
244" lowp vec3 rgb;\n" \
245"\n" \
246" // Get the YUV values \n" \
247" yuv.x = texture2D(u_texture, v_texCoord).r;\n" \
248" yuv.yz = texture2D(u_texture_u, v_texCoord).gr;\n" \
249"\n" \
250" // Do the color transform \n" \
251" yuv += u_offset;\n" \
252" rgb = yuv * u_matrix;\n" \
253"\n" \
254" // That was easy. :) \n" \
255" gl_FragColor = vec4(rgb, 1);\n" \
256" gl_FragColor *= v_color;\n" \
257"}" \
258
259// YUV to ABGR conversion
260static const char GLES2_Fragment_TextureYUV[] = \
261 YUV_SHADER_PROLOGUE \
262 YUV_SHADER_BODY \
263;
264
265// NV12 to ABGR conversion
266static const char GLES2_Fragment_TextureNV12_RA[] = \
267 YUV_SHADER_PROLOGUE \
268 NV12_RA_SHADER_BODY \
269;
270static const char GLES2_Fragment_TextureNV12_RG[] = \
271 YUV_SHADER_PROLOGUE \
272 NV12_RG_SHADER_BODY \
273;
274
275// NV21 to ABGR conversion
276static const char GLES2_Fragment_TextureNV21_RA[] = \
277 YUV_SHADER_PROLOGUE \
278 NV21_RA_SHADER_BODY \
279;
280static const char GLES2_Fragment_TextureNV21_RG[] = \
281 YUV_SHADER_PROLOGUE \
282 NV21_RG_SHADER_BODY \
283;
284#endif
285
286// Custom Android video format texture
287static const char GLES2_Fragment_TextureExternalOES_Prologue[] = \
288"#extension GL_OES_EGL_image_external : require\n" \
289"\n" \
290;
291static const char GLES2_Fragment_TextureExternalOES[] = \
292"uniform samplerExternalOES u_texture;\n" \
293"varying mediump vec4 v_color;\n" \
294"varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;\n" \
295"\n" \
296"void main()\n" \
297"{\n" \
298" gl_FragColor = texture2D(u_texture, v_texCoord);\n" \
299" gl_FragColor *= v_color;\n" \
300"}\n" \
301;
302
303/* *INDENT-ON* */ // clang-format on
304
305/*************************************************************************************************
306 * Shader selector *
307 *************************************************************************************************/
308
309const char *GLES2_GetShaderPrologue(GLES2_ShaderType type)
310{
311 switch (type) {
312 case GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES:
313 return GLES2_Fragment_TextureExternalOES_Prologue;
314 default:
315 return "";
316 }
317}
318
319const char *GLES2_GetShaderInclude(GLES2_ShaderIncludeType type)
320{
321 switch (type) {
322 case GLES2_SHADER_FRAGMENT_INCLUDE_UNDEF_PRECISION:
323 return GLES2_Fragment_Include_Undef_Precision;
324 case GLES2_SHADER_FRAGMENT_INCLUDE_BEST_TEXCOORD_PRECISION:
325 return GLES2_Fragment_Include_Best_Texture_Precision;
326 case GLES2_SHADER_FRAGMENT_INCLUDE_MEDIUM_TEXCOORD_PRECISION:
327 return GLES2_Fragment_Include_Medium_Texture_Precision;
328 case GLES2_SHADER_FRAGMENT_INCLUDE_HIGH_TEXCOORD_PRECISION:
329 return GLES2_Fragment_Include_High_Texture_Precision;
330 default:
331 return "";
332 }
333}
334
335GLES2_ShaderIncludeType GLES2_GetTexCoordPrecisionEnumFromHint(void)
336{
337 const char *texcoord_hint = SDL_GetHint("SDL_RENDER_OPENGLES2_TEXCOORD_PRECISION");
338 GLES2_ShaderIncludeType value = GLES2_SHADER_FRAGMENT_INCLUDE_BEST_TEXCOORD_PRECISION;
339 if (texcoord_hint) {
340 if (SDL_strcmp(texcoord_hint, "undefined") == 0) {
341 return GLES2_SHADER_FRAGMENT_INCLUDE_UNDEF_PRECISION;
342 }
343 if (SDL_strcmp(texcoord_hint, "high") == 0) {
344 return GLES2_SHADER_FRAGMENT_INCLUDE_HIGH_TEXCOORD_PRECISION;
345 }
346 if (SDL_strcmp(texcoord_hint, "medium") == 0) {
347 return GLES2_SHADER_FRAGMENT_INCLUDE_MEDIUM_TEXCOORD_PRECISION;
348 }
349 }
350 return value;
351}
352
353const char *GLES2_GetShader(GLES2_ShaderType type)
354{
355 switch (type) {
356 case GLES2_SHADER_VERTEX_DEFAULT:
357 return GLES2_Vertex_Default;
358 case GLES2_SHADER_FRAGMENT_SOLID:
359 return GLES2_Fragment_Solid;
360 case GLES2_SHADER_FRAGMENT_TEXTURE_ABGR:
361 return GLES2_Fragment_TextureABGR;
362 case GLES2_SHADER_FRAGMENT_TEXTURE_ARGB:
363 return GLES2_Fragment_TextureARGB;
364 case GLES2_SHADER_FRAGMENT_TEXTURE_RGB:
365 return GLES2_Fragment_TextureRGB;
366 case GLES2_SHADER_FRAGMENT_TEXTURE_BGR:
367 return GLES2_Fragment_TextureBGR;
368#ifdef SDL_HAVE_YUV
369 case GLES2_SHADER_FRAGMENT_TEXTURE_YUV:
370 return GLES2_Fragment_TextureYUV;
371 case GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA:
372 return GLES2_Fragment_TextureNV12_RA;
373 case GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG:
374 return GLES2_Fragment_TextureNV12_RG;
375 case GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RA:
376 return GLES2_Fragment_TextureNV21_RA;
377 case GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RG:
378 return GLES2_Fragment_TextureNV21_RG;
379#endif
380 case GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES:
381 return GLES2_Fragment_TextureExternalOES;
382 default:
383 return NULL;
384 }
385}
386
387#endif // SDL_VIDEO_RENDER_OGL_ES2
diff --git a/contrib/SDL-3.2.8/src/render/opengles2/SDL_shaders_gles2.h b/contrib/SDL-3.2.8/src/render/opengles2/SDL_shaders_gles2.h
new file mode 100644
index 0000000..e71f8ce
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/opengles2/SDL_shaders_gles2.h
@@ -0,0 +1,65 @@
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#ifndef SDL_shaders_gles2_h_
24#define SDL_shaders_gles2_h_
25
26#ifdef SDL_VIDEO_RENDER_OGL_ES2
27
28typedef enum
29{
30 GLES2_SHADER_FRAGMENT_INCLUDE_NONE = 0,
31 GLES2_SHADER_FRAGMENT_INCLUDE_BEST_TEXCOORD_PRECISION,
32 GLES2_SHADER_FRAGMENT_INCLUDE_MEDIUM_TEXCOORD_PRECISION,
33 GLES2_SHADER_FRAGMENT_INCLUDE_HIGH_TEXCOORD_PRECISION,
34 GLES2_SHADER_FRAGMENT_INCLUDE_UNDEF_PRECISION,
35 GLES2_SHADER_FRAGMENT_INCLUDE_COUNT
36} GLES2_ShaderIncludeType;
37
38typedef enum
39{
40 GLES2_SHADER_VERTEX_DEFAULT = 0,
41 GLES2_SHADER_FRAGMENT_SOLID,
42 GLES2_SHADER_FRAGMENT_TEXTURE_ABGR,
43 GLES2_SHADER_FRAGMENT_TEXTURE_ARGB,
44 GLES2_SHADER_FRAGMENT_TEXTURE_BGR,
45 GLES2_SHADER_FRAGMENT_TEXTURE_RGB,
46#ifdef SDL_HAVE_YUV
47 GLES2_SHADER_FRAGMENT_TEXTURE_YUV,
48 GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA,
49 GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG,
50 GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RA,
51 GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RG,
52#endif
53 // Shaders beyond this point are optional and not cached at render creation
54 GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES,
55 GLES2_SHADER_COUNT
56} GLES2_ShaderType;
57
58extern const char *GLES2_GetShaderPrologue(GLES2_ShaderType type);
59extern const char *GLES2_GetShaderInclude(GLES2_ShaderIncludeType type);
60extern const char *GLES2_GetShader(GLES2_ShaderType type);
61extern GLES2_ShaderIncludeType GLES2_GetTexCoordPrecisionEnumFromHint(void);
62
63#endif // SDL_VIDEO_RENDER_OGL_ES2
64
65#endif // SDL_shaders_gles2_h_