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