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