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