2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../../SDL_internal.h"
23 #if SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED
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"
32 /* To prevent unnecessary window recreation,
33 * these should match the defaults selected in SDL_GL_ResetAttributes
35 #define RENDERER_CONTEXT_MAJOR 2
36 #define RENDERER_CONTEXT_MINOR 0
38 /* Used to re-create the window with OpenGL ES capability */
39 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
41 /*************************************************************************************************
42 * Context structures *
43 *************************************************************************************************/
45 typedef struct GLES2_FBOList GLES2_FBOList;
54 typedef struct GLES2_TextureData
62 /* YUV texture support */
70 typedef struct GLES2_ShaderCacheEntry
73 GLES2_ShaderType type;
74 const GLES2_ShaderInstance *instance;
76 struct GLES2_ShaderCacheEntry *prev;
77 struct GLES2_ShaderCacheEntry *next;
78 } GLES2_ShaderCacheEntry;
80 typedef struct GLES2_ShaderCache
83 GLES2_ShaderCacheEntry *head;
86 typedef struct GLES2_ProgramCacheEntry
89 GLES2_ShaderCacheEntry *vertex_shader;
90 GLES2_ShaderCacheEntry *fragment_shader;
91 GLuint uniform_locations[16];
93 GLfloat projection[4][4];
94 struct GLES2_ProgramCacheEntry *prev;
95 struct GLES2_ProgramCacheEntry *next;
96 } GLES2_ProgramCacheEntry;
98 typedef struct GLES2_ProgramCache
101 GLES2_ProgramCacheEntry *head;
102 GLES2_ProgramCacheEntry *tail;
103 } GLES2_ProgramCache;
107 GLES2_ATTRIBUTE_POSITION = 0,
108 GLES2_ATTRIBUTE_TEXCOORD = 1,
109 GLES2_ATTRIBUTE_ANGLE = 2,
110 GLES2_ATTRIBUTE_CENTER = 3,
115 GLES2_UNIFORM_PROJECTION,
116 GLES2_UNIFORM_TEXTURE,
118 GLES2_UNIFORM_TEXTURE_U,
119 GLES2_UNIFORM_TEXTURE_V
124 GLES2_IMAGESOURCE_INVALID,
125 GLES2_IMAGESOURCE_SOLID,
126 GLES2_IMAGESOURCE_TEXTURE_ABGR,
127 GLES2_IMAGESOURCE_TEXTURE_ARGB,
128 GLES2_IMAGESOURCE_TEXTURE_RGB,
129 GLES2_IMAGESOURCE_TEXTURE_BGR,
130 GLES2_IMAGESOURCE_TEXTURE_YUV,
131 GLES2_IMAGESOURCE_TEXTURE_NV12,
132 GLES2_IMAGESOURCE_TEXTURE_NV21,
133 GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES
139 SDL_bool viewport_dirty;
140 SDL_Texture *texture;
143 SDL_bool cliprect_enabled_dirty;
144 SDL_bool cliprect_enabled;
145 SDL_bool cliprect_dirty;
153 GLES2_ProgramCacheEntry *program;
154 GLfloat projection[4][4];
155 } GLES2_DrawStateCache;
157 typedef struct GLES2_RenderData
159 SDL_GLContext *context;
161 SDL_bool debug_enabled;
163 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
164 #include "SDL_gles2funcs.h"
166 GLES2_FBOList *framebuffers;
167 GLuint window_framebuffer;
169 int shader_format_count;
170 GLenum *shader_formats;
171 GLES2_ShaderCache shader_cache;
172 GLES2_ProgramCache program_cache;
173 Uint8 clear_r, clear_g, clear_b, clear_a;
175 GLuint vertex_buffers[8];
176 size_t vertex_buffer_size[8];
177 int current_vertex_buffer;
178 GLES2_DrawStateCache drawstate;
181 #define GLES2_MAX_CACHED_PROGRAMS 8
183 static const float inv255f = 1.0f / 255.0f;
186 SDL_FORCE_INLINE const char*
187 GL_TranslateError (GLenum error)
189 #define GL_ERROR_TRANSLATE(e) case e: return #e;
191 GL_ERROR_TRANSLATE(GL_INVALID_ENUM)
192 GL_ERROR_TRANSLATE(GL_INVALID_VALUE)
193 GL_ERROR_TRANSLATE(GL_INVALID_OPERATION)
194 GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY)
195 GL_ERROR_TRANSLATE(GL_NO_ERROR)
199 #undef GL_ERROR_TRANSLATE
202 SDL_FORCE_INLINE void
203 GL_ClearErrors(SDL_Renderer *renderer)
205 GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
207 if (!data->debug_enabled) {
210 while (data->glGetError() != GL_NO_ERROR) {
216 GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function)
218 GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
221 if (!data->debug_enabled) {
224 /* check gl errors (can return multiple errors) */
226 GLenum error = data->glGetError();
227 if (error != GL_NO_ERROR) {
228 if (prefix == NULL || prefix[0] == '\0') {
231 SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error);
241 #define GL_CheckError(prefix, renderer)
243 #define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, SDL_FILE, SDL_LINE, SDL_FUNCTION)
247 /*************************************************************************************************
248 * Renderer state APIs *
249 *************************************************************************************************/
251 static int GLES2_LoadFunctions(GLES2_RenderData * data)
253 #if SDL_VIDEO_DRIVER_UIKIT
254 #define __SDL_NOGETPROCADDR__
255 #elif SDL_VIDEO_DRIVER_ANDROID
256 #define __SDL_NOGETPROCADDR__
257 #elif SDL_VIDEO_DRIVER_PANDORA
258 #define __SDL_NOGETPROCADDR__
261 #if defined __SDL_NOGETPROCADDR__
262 #define SDL_PROC(ret,func,params) data->func=func;
264 #define SDL_PROC(ret,func,params) \
266 data->func = SDL_GL_GetProcAddress(#func); \
267 if ( ! data->func ) { \
268 return SDL_SetError("Couldn't load GLES2 function %s: %s", #func, SDL_GetError()); \
271 #endif /* __SDL_NOGETPROCADDR__ */
273 #include "SDL_gles2funcs.h"
278 static GLES2_FBOList *
279 GLES2_GetFBO(GLES2_RenderData *data, Uint32 w, Uint32 h)
281 GLES2_FBOList *result = data->framebuffers;
282 while ((result) && ((result->w != w) || (result->h != h)) ) {
283 result = result->next;
285 if (result == NULL) {
286 result = SDL_malloc(sizeof(GLES2_FBOList));
289 data->glGenFramebuffers(1, &result->FBO);
290 result->next = data->framebuffers;
291 data->framebuffers = result;
297 GLES2_ActivateRenderer(SDL_Renderer * renderer)
299 GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
301 if (SDL_GL_GetCurrentContext() != data->context) {
302 /* Null out the current program to ensure we set it again */
303 data->drawstate.program = NULL;
305 if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
310 GL_ClearErrors(renderer);
316 GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
318 GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
320 if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
321 /* According to Apple documentation, we need to finish drawing NOW! */
327 GLES2_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
329 SDL_GL_GetDrawableSize(renderer->window, w, h);
333 static GLenum GetBlendFunc(SDL_BlendFactor factor)
336 case SDL_BLENDFACTOR_ZERO:
338 case SDL_BLENDFACTOR_ONE:
340 case SDL_BLENDFACTOR_SRC_COLOR:
342 case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
343 return GL_ONE_MINUS_SRC_COLOR;
344 case SDL_BLENDFACTOR_SRC_ALPHA:
346 case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
347 return GL_ONE_MINUS_SRC_ALPHA;
348 case SDL_BLENDFACTOR_DST_COLOR:
350 case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
351 return GL_ONE_MINUS_DST_COLOR;
352 case SDL_BLENDFACTOR_DST_ALPHA:
354 case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
355 return GL_ONE_MINUS_DST_ALPHA;
357 return GL_INVALID_ENUM;
361 static GLenum GetBlendEquation(SDL_BlendOperation operation)
364 case SDL_BLENDOPERATION_ADD:
366 case SDL_BLENDOPERATION_SUBTRACT:
367 return GL_FUNC_SUBTRACT;
368 case SDL_BLENDOPERATION_REV_SUBTRACT:
369 return GL_FUNC_REVERSE_SUBTRACT;
371 return GL_INVALID_ENUM;
376 GLES2_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
378 SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
379 SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
380 SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
381 SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
382 SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
383 SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
385 if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM ||
386 GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM ||
387 GetBlendEquation(colorOperation) == GL_INVALID_ENUM ||
388 GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM ||
389 GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM ||
390 GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) {
398 GLES2_EvictShader(GLES2_RenderData *data, GLES2_ShaderCacheEntry *entry)
400 /* Unlink the shader from the cache */
402 entry->next->prev = entry->prev;
405 entry->prev->next = entry->next;
407 if (data->shader_cache.head == entry) {
408 data->shader_cache.head = entry->next;
410 --data->shader_cache.count;
412 /* Deallocate the shader */
413 data->glDeleteShader(entry->id);
417 static GLES2_ProgramCacheEntry *
418 GLES2_CacheProgram(GLES2_RenderData *data, GLES2_ShaderCacheEntry *vertex,
419 GLES2_ShaderCacheEntry *fragment)
421 GLES2_ProgramCacheEntry *entry;
422 GLES2_ShaderCacheEntry *shaderEntry;
423 GLint linkSuccessful;
425 /* Check if we've already cached this program */
426 entry = data->program_cache.head;
428 if (entry->vertex_shader == vertex && entry->fragment_shader == fragment) {
434 if (data->program_cache.head != entry) {
436 entry->next->prev = entry->prev;
439 entry->prev->next = entry->next;
442 entry->next = data->program_cache.head;
443 data->program_cache.head->prev = entry;
444 data->program_cache.head = entry;
449 /* Create a program cache entry */
450 entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry));
455 entry->vertex_shader = vertex;
456 entry->fragment_shader = fragment;
458 /* Create the program and link it */
459 entry->id = data->glCreateProgram();
460 data->glAttachShader(entry->id, vertex->id);
461 data->glAttachShader(entry->id, fragment->id);
462 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_POSITION, "a_position");
463 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord");
464 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_ANGLE, "a_angle");
465 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_CENTER, "a_center");
466 data->glLinkProgram(entry->id);
467 data->glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful);
468 if (!linkSuccessful) {
469 data->glDeleteProgram(entry->id);
471 SDL_SetError("Failed to link shader program");
475 /* Predetermine locations of uniform variables */
476 entry->uniform_locations[GLES2_UNIFORM_PROJECTION] =
477 data->glGetUniformLocation(entry->id, "u_projection");
478 entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V] =
479 data->glGetUniformLocation(entry->id, "u_texture_v");
480 entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U] =
481 data->glGetUniformLocation(entry->id, "u_texture_u");
482 entry->uniform_locations[GLES2_UNIFORM_TEXTURE] =
483 data->glGetUniformLocation(entry->id, "u_texture");
484 entry->uniform_locations[GLES2_UNIFORM_COLOR] =
485 data->glGetUniformLocation(entry->id, "u_color");
489 data->glUseProgram(entry->id);
490 if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V] != -1) {
491 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V], 2); /* always texture unit 2. */
493 if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U] != -1) {
494 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U], 1); /* always texture unit 1. */
496 if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE] != -1) {
497 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0); /* always texture unit 0. */
499 if (entry->uniform_locations[GLES2_UNIFORM_PROJECTION] != -1) {
500 data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection);
502 if (entry->uniform_locations[GLES2_UNIFORM_COLOR] != -1) {
503 data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_COLOR], 0.0f, 0.0f, 0.0f, 0.0f);
506 /* Cache the linked program */
507 if (data->program_cache.head) {
508 entry->next = data->program_cache.head;
509 data->program_cache.head->prev = entry;
511 data->program_cache.tail = entry;
513 data->program_cache.head = entry;
514 ++data->program_cache.count;
516 /* Increment the refcount of the shaders we're using */
517 ++vertex->references;
518 ++fragment->references;
520 /* Evict the last entry from the cache if we exceed the limit */
521 if (data->program_cache.count > GLES2_MAX_CACHED_PROGRAMS) {
522 shaderEntry = data->program_cache.tail->vertex_shader;
523 if (--shaderEntry->references <= 0) {
524 GLES2_EvictShader(data, shaderEntry);
526 shaderEntry = data->program_cache.tail->fragment_shader;
527 if (--shaderEntry->references <= 0) {
528 GLES2_EvictShader(data, shaderEntry);
530 data->glDeleteProgram(data->program_cache.tail->id);
531 data->program_cache.tail = data->program_cache.tail->prev;
532 if (data->program_cache.tail != NULL) {
533 SDL_free(data->program_cache.tail->next);
534 data->program_cache.tail->next = NULL;
536 --data->program_cache.count;
541 static GLES2_ShaderCacheEntry *
542 GLES2_CacheShader(GLES2_RenderData *data, GLES2_ShaderType type)
544 const GLES2_Shader *shader;
545 const GLES2_ShaderInstance *instance = NULL;
546 GLES2_ShaderCacheEntry *entry = NULL;
547 GLint compileSuccessful = GL_FALSE;
550 /* Find the corresponding shader */
551 shader = GLES2_GetShader(type);
553 SDL_SetError("No shader matching the requested characteristics was found");
557 /* Find a matching shader instance that's supported on this hardware */
558 for (i = 0; i < shader->instance_count && !instance; ++i) {
559 for (j = 0; j < data->shader_format_count && !instance; ++j) {
560 if (!shader->instances[i]) {
563 if (shader->instances[i]->format != data->shader_formats[j]) {
566 instance = shader->instances[i];
570 SDL_SetError("The specified shader cannot be loaded on the current platform");
574 /* Check if we've already cached this shader */
575 entry = data->shader_cache.head;
577 if (entry->instance == instance) {
586 /* Create a shader cache entry */
587 entry = (GLES2_ShaderCacheEntry *)SDL_calloc(1, sizeof(GLES2_ShaderCacheEntry));
593 entry->instance = instance;
595 /* Compile or load the selected shader instance */
596 entry->id = data->glCreateShader(instance->type);
597 if (instance->format == (GLenum)-1) {
598 data->glShaderSource(entry->id, 1, (const char **)(char *)&instance->data, NULL);
599 data->glCompileShader(entry->id);
600 data->glGetShaderiv(entry->id, GL_COMPILE_STATUS, &compileSuccessful);
602 data->glShaderBinary(1, &entry->id, instance->format, instance->data, instance->length);
603 compileSuccessful = GL_TRUE;
605 if (!compileSuccessful) {
606 SDL_bool isstack = SDL_FALSE;
610 data->glGetShaderiv(entry->id, GL_INFO_LOG_LENGTH, &length);
612 info = SDL_small_alloc(char, length, &isstack);
614 data->glGetShaderInfoLog(entry->id, length, &length, info);
618 SDL_SetError("Failed to load the shader: %s", info);
619 SDL_small_free(info, isstack);
621 SDL_SetError("Failed to load the shader");
623 data->glDeleteShader(entry->id);
628 /* Link the shader entry in at the front of the cache */
629 if (data->shader_cache.head) {
630 entry->next = data->shader_cache.head;
631 data->shader_cache.head->prev = entry;
633 data->shader_cache.head = entry;
634 ++data->shader_cache.count;
639 GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source, int w, int h)
641 GLES2_ShaderCacheEntry *vertex = NULL;
642 GLES2_ShaderCacheEntry *fragment = NULL;
643 GLES2_ShaderType vtype, ftype;
644 GLES2_ProgramCacheEntry *program;
646 /* Select an appropriate shader pair for the specified modes */
647 vtype = GLES2_SHADER_VERTEX_DEFAULT;
649 case GLES2_IMAGESOURCE_SOLID:
650 ftype = GLES2_SHADER_FRAGMENT_SOLID_SRC;
652 case GLES2_IMAGESOURCE_TEXTURE_ABGR:
653 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_SRC;
655 case GLES2_IMAGESOURCE_TEXTURE_ARGB:
656 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_SRC;
658 case GLES2_IMAGESOURCE_TEXTURE_RGB:
659 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_RGB_SRC;
661 case GLES2_IMAGESOURCE_TEXTURE_BGR:
662 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_BGR_SRC;
664 case GLES2_IMAGESOURCE_TEXTURE_YUV:
665 switch (SDL_GetYUVConversionModeForResolution(w, h)) {
666 case SDL_YUV_CONVERSION_JPEG:
667 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_JPEG_SRC;
669 case SDL_YUV_CONVERSION_BT601:
670 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT601_SRC;
672 case SDL_YUV_CONVERSION_BT709:
673 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT709_SRC;
676 SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
680 case GLES2_IMAGESOURCE_TEXTURE_NV12:
681 switch (SDL_GetYUVConversionModeForResolution(w, h)) {
682 case SDL_YUV_CONVERSION_JPEG:
683 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_JPEG_SRC;
685 case SDL_YUV_CONVERSION_BT601:
686 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_BT601_SRC;
688 case SDL_YUV_CONVERSION_BT709:
689 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_BT709_SRC;
692 SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
696 case GLES2_IMAGESOURCE_TEXTURE_NV21:
697 switch (SDL_GetYUVConversionModeForResolution(w, h)) {
698 case SDL_YUV_CONVERSION_JPEG:
699 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_JPEG_SRC;
701 case SDL_YUV_CONVERSION_BT601:
702 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT601_SRC;
704 case SDL_YUV_CONVERSION_BT709:
705 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT709_SRC;
708 SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
712 case GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES:
713 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES_SRC;
719 /* Load the requested shaders */
720 vertex = GLES2_CacheShader(data, vtype);
724 fragment = GLES2_CacheShader(data, ftype);
729 /* Check if we need to change programs at all */
730 if (data->drawstate.program &&
731 data->drawstate.program->vertex_shader == vertex &&
732 data->drawstate.program->fragment_shader == fragment) {
736 /* Generate a matching program */
737 program = GLES2_CacheProgram(data, vertex, fragment);
742 /* Select that program in OpenGL */
743 data->glUseProgram(program->id);
745 /* Set the current program */
746 data->drawstate.program = program;
748 /* Clean up and return */
751 if (vertex && vertex->references <= 0) {
752 GLES2_EvictShader(data, vertex);
754 if (fragment && fragment->references <= 0) {
755 GLES2_EvictShader(data, fragment);
757 data->drawstate.program = NULL;
762 GLES2_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
764 return 0; /* nothing to do in this backend. */
768 GLES2_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
770 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
777 cmd->data.draw.count = count;
778 for (i = 0; i < count; i++) {
779 *(verts++) = 0.5f + points[i].x;
780 *(verts++) = 0.5f + points[i].y;
787 GLES2_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
789 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 8 * sizeof (GLfloat), 0, &cmd->data.draw.first);
796 cmd->data.draw.count = count;
798 for (i = 0; i < count; i++) {
799 const SDL_FRect *rect = &rects[i];
800 const GLfloat minx = rect->x;
801 const GLfloat maxx = rect->x + rect->w;
802 const GLfloat miny = rect->y;
803 const GLfloat maxy = rect->y + rect->h;
818 GLES2_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
819 const SDL_Rect * srcrect, const SDL_FRect * dstrect)
821 GLfloat minx, miny, maxx, maxy;
822 GLfloat minu, maxu, minv, maxv;
823 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 16 * sizeof (GLfloat), 0, &cmd->data.draw.first);
829 cmd->data.draw.count = 1;
833 maxx = dstrect->x + dstrect->w;
834 maxy = dstrect->y + dstrect->h;
836 minu = (GLfloat) srcrect->x / texture->w;
837 maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
838 minv = (GLfloat) srcrect->y / texture->h;
839 maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
863 GLES2_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
864 const SDL_Rect * srcquad, const SDL_FRect * dstrect,
865 const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
867 /* render expects cos value - 1 (see GLES2_VertexSrc_Default_) */
868 const float radian_angle = (float)(M_PI * (360.0 - angle) / 180.0);
869 const GLfloat s = (GLfloat) SDL_sin(radian_angle);
870 const GLfloat c = (GLfloat) SDL_cos(radian_angle) - 1.0f;
871 const GLfloat centerx = center->x + dstrect->x;
872 const GLfloat centery = center->y + dstrect->y;
873 GLfloat minx, miny, maxx, maxy;
874 GLfloat minu, maxu, minv, maxv;
875 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 32 * sizeof (GLfloat), 0, &cmd->data.draw.first);
881 if (flip & SDL_FLIP_HORIZONTAL) {
882 minx = dstrect->x + dstrect->w;
886 maxx = dstrect->x + dstrect->w;
889 if (flip & SDL_FLIP_VERTICAL) {
890 miny = dstrect->y + dstrect->h;
894 maxy = dstrect->y + dstrect->h;
897 minu = ((GLfloat) srcquad->x) / ((GLfloat) texture->w);
898 maxu = ((GLfloat) (srcquad->x + srcquad->w)) / ((GLfloat) texture->w);
899 minv = ((GLfloat) srcquad->y) / ((GLfloat) texture->h);
900 maxv = ((GLfloat) (srcquad->y + srcquad->h)) / ((GLfloat) texture->h);
903 cmd->data.draw.count = 1;
932 *(verts++) = centerx;
933 *(verts++) = centery;
934 *(verts++) = centerx;
935 *(verts++) = centery;
936 *(verts++) = centerx;
937 *(verts++) = centery;
938 *(verts++) = centerx;
939 *(verts++) = centery;
945 SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_ImageSource imgsrc)
947 const SDL_bool was_copy_ex = data->drawstate.is_copy_ex;
948 const SDL_bool is_copy_ex = (cmd->command == SDL_RENDERCMD_COPY_EX);
949 SDL_Texture *texture = cmd->data.draw.texture;
950 const SDL_BlendMode blend = cmd->data.draw.blend;
951 GLES2_ProgramCacheEntry *program;
953 SDL_assert((texture != NULL) == (imgsrc != GLES2_IMAGESOURCE_SOLID));
955 if (data->drawstate.viewport_dirty) {
956 const SDL_Rect *viewport = &data->drawstate.viewport;
957 data->glViewport(viewport->x,
958 data->drawstate.target ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
959 viewport->w, viewport->h);
960 if (viewport->w && viewport->h) {
961 data->drawstate.projection[0][0] = 2.0f / viewport->w;
962 data->drawstate.projection[1][1] = (data->drawstate.target ? 2.0f : -2.0f) / viewport->h;
963 data->drawstate.projection[3][1] = data->drawstate.target ? -1.0f : 1.0f;
965 data->drawstate.viewport_dirty = SDL_FALSE;
968 if (data->drawstate.cliprect_enabled_dirty) {
969 if (!data->drawstate.cliprect_enabled) {
970 data->glDisable(GL_SCISSOR_TEST);
972 data->glEnable(GL_SCISSOR_TEST);
974 data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
977 if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
978 const SDL_Rect *viewport = &data->drawstate.viewport;
979 const SDL_Rect *rect = &data->drawstate.cliprect;
980 data->glScissor(viewport->x + rect->x,
981 data->drawstate.target ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
983 data->drawstate.cliprect_dirty = SDL_FALSE;
986 if (texture != data->drawstate.texture) {
987 if ((texture != NULL) != data->drawstate.texturing) {
988 if (texture == NULL) {
989 data->glDisableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_TEXCOORD);
990 data->drawstate.texturing = SDL_FALSE;
992 data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_TEXCOORD);
993 data->drawstate.texturing = SDL_TRUE;
998 GLES2_TextureData *tdata = (GLES2_TextureData *) texture->driverdata;
1000 data->glActiveTexture(GL_TEXTURE2);
1001 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1003 data->glActiveTexture(GL_TEXTURE1);
1004 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1006 data->glActiveTexture(GL_TEXTURE0);
1007 } else if (tdata->nv12) {
1008 data->glActiveTexture(GL_TEXTURE1);
1009 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1011 data->glActiveTexture(GL_TEXTURE0);
1013 data->glBindTexture(tdata->texture_type, tdata->texture);
1016 data->drawstate.texture = texture;
1020 data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) (cmd->data.draw.first + (sizeof (GLfloat) * 8)));
1023 if (GLES2_SelectProgram(data, imgsrc, texture ? texture->w : 0, texture ? texture->h : 0) < 0) {
1027 program = data->drawstate.program;
1029 if (program->uniform_locations[GLES2_UNIFORM_PROJECTION] != -1) {
1030 if (SDL_memcmp(program->projection, data->drawstate.projection, sizeof (data->drawstate.projection)) != 0) {
1031 data->glUniformMatrix4fv(program->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)data->drawstate.projection);
1032 SDL_memcpy(program->projection, data->drawstate.projection, sizeof (data->drawstate.projection));
1036 if (program->uniform_locations[GLES2_UNIFORM_COLOR] != -1) {
1037 if (data->drawstate.color != program->color) {
1038 const Uint8 r = (data->drawstate.color >> 16) & 0xFF;
1039 const Uint8 g = (data->drawstate.color >> 8) & 0xFF;
1040 const Uint8 b = (data->drawstate.color >> 0) & 0xFF;
1041 const Uint8 a = (data->drawstate.color >> 24) & 0xFF;
1042 data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_COLOR], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
1043 program->color = data->drawstate.color;
1047 if (blend != data->drawstate.blend) {
1048 if (blend == SDL_BLENDMODE_NONE) {
1049 data->glDisable(GL_BLEND);
1051 data->glEnable(GL_BLEND);
1052 data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
1053 GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
1054 GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
1055 GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
1056 data->glBlendEquationSeparate(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)),
1057 GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
1059 data->drawstate.blend = blend;
1062 /* all drawing commands use this */
1063 data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) cmd->data.draw.first);
1065 if (is_copy_ex != was_copy_ex) {
1067 data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_ANGLE);
1068 data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_CENTER);
1070 data->glDisableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_ANGLE);
1071 data->glDisableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_CENTER);
1073 data->drawstate.is_copy_ex = is_copy_ex;
1077 data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) (cmd->data.draw.first + (sizeof (GLfloat) * 16)));
1078 data->glVertexAttribPointer(GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) (cmd->data.draw.first + (sizeof (GLfloat) * 24)));
1085 SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd)
1087 GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
1088 GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
1089 SDL_Texture *texture = cmd->data.draw.texture;
1091 /* Pick an appropriate shader */
1092 if (renderer->target) {
1093 /* Check if we need to do color mapping between the source and render target textures */
1094 if (renderer->target->format != texture->format) {
1095 switch (texture->format) {
1096 case SDL_PIXELFORMAT_ARGB8888:
1097 switch (renderer->target->format) {
1098 case SDL_PIXELFORMAT_ABGR8888:
1099 case SDL_PIXELFORMAT_BGR888:
1100 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1102 case SDL_PIXELFORMAT_RGB888:
1103 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
1107 case SDL_PIXELFORMAT_ABGR8888:
1108 switch (renderer->target->format) {
1109 case SDL_PIXELFORMAT_ARGB8888:
1110 case SDL_PIXELFORMAT_RGB888:
1111 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1113 case SDL_PIXELFORMAT_BGR888:
1114 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
1118 case SDL_PIXELFORMAT_RGB888:
1119 switch (renderer->target->format) {
1120 case SDL_PIXELFORMAT_ABGR8888:
1121 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1123 case SDL_PIXELFORMAT_ARGB8888:
1124 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
1126 case SDL_PIXELFORMAT_BGR888:
1127 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1131 case SDL_PIXELFORMAT_BGR888:
1132 switch (renderer->target->format) {
1133 case SDL_PIXELFORMAT_ABGR8888:
1134 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
1136 case SDL_PIXELFORMAT_ARGB8888:
1137 sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
1139 case SDL_PIXELFORMAT_RGB888:
1140 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1144 case SDL_PIXELFORMAT_IYUV:
1145 case SDL_PIXELFORMAT_YV12:
1146 sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV;
1148 case SDL_PIXELFORMAT_NV12:
1149 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12;
1151 case SDL_PIXELFORMAT_NV21:
1152 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21;
1154 case SDL_PIXELFORMAT_EXTERNAL_OES:
1155 sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
1158 return SDL_SetError("Unsupported texture format");
1161 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */
1164 switch (texture->format) {
1165 case SDL_PIXELFORMAT_ARGB8888:
1166 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
1168 case SDL_PIXELFORMAT_ABGR8888:
1169 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
1171 case SDL_PIXELFORMAT_RGB888:
1172 sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
1174 case SDL_PIXELFORMAT_BGR888:
1175 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
1177 case SDL_PIXELFORMAT_IYUV:
1178 case SDL_PIXELFORMAT_YV12:
1179 sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV;
1181 case SDL_PIXELFORMAT_NV12:
1182 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12;
1184 case SDL_PIXELFORMAT_NV21:
1185 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21;
1187 case SDL_PIXELFORMAT_EXTERNAL_OES:
1188 sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
1191 return SDL_SetError("Unsupported texture format");
1195 return SetDrawState(data, cmd, sourceType);
1199 GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
1201 GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
1202 const SDL_bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || renderer->target->format == SDL_PIXELFORMAT_RGB888));
1203 const int vboidx = data->current_vertex_buffer;
1204 const GLuint vbo = data->vertex_buffers[vboidx];
1207 if (GLES2_ActivateRenderer(renderer) < 0) {
1211 data->drawstate.target = renderer->target;
1212 if (!data->drawstate.target) {
1213 SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh);
1216 /* upload the new VBO data for this set of commands. */
1217 data->glBindBuffer(GL_ARRAY_BUFFER, vbo);
1218 if (data->vertex_buffer_size[vboidx] < vertsize) {
1219 data->glBufferData(GL_ARRAY_BUFFER, vertsize, vertices, GL_STREAM_DRAW);
1220 data->vertex_buffer_size[vboidx] = vertsize;
1222 data->glBufferSubData(GL_ARRAY_BUFFER, 0, vertsize, vertices);
1225 /* cycle through a few VBOs so the GL has some time with the data before we replace it. */
1226 data->current_vertex_buffer++;
1227 if (data->current_vertex_buffer >= SDL_arraysize(data->vertex_buffers)) {
1228 data->current_vertex_buffer = 0;
1232 switch (cmd->command) {
1233 case SDL_RENDERCMD_SETDRAWCOLOR: {
1234 const Uint8 r = colorswap ? cmd->data.color.b : cmd->data.color.r;
1235 const Uint8 g = cmd->data.color.g;
1236 const Uint8 b = colorswap ? cmd->data.color.r : cmd->data.color.b;
1237 const Uint8 a = cmd->data.color.a;
1238 data->drawstate.color = ((a << 24) | (r << 16) | (g << 8) | b);
1242 case SDL_RENDERCMD_SETVIEWPORT: {
1243 SDL_Rect *viewport = &data->drawstate.viewport;
1244 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
1245 SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
1246 data->drawstate.viewport_dirty = SDL_TRUE;
1251 case SDL_RENDERCMD_SETCLIPRECT: {
1252 const SDL_Rect *rect = &cmd->data.cliprect.rect;
1253 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
1254 data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
1255 data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
1258 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
1259 SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
1260 data->drawstate.cliprect_dirty = SDL_TRUE;
1265 case SDL_RENDERCMD_CLEAR: {
1266 const Uint8 r = colorswap ? cmd->data.color.b : cmd->data.color.r;
1267 const Uint8 g = cmd->data.color.g;
1268 const Uint8 b = colorswap ? cmd->data.color.r : cmd->data.color.b;
1269 const Uint8 a = cmd->data.color.a;
1270 const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
1271 if (color != data->drawstate.clear_color) {
1272 const GLfloat fr = ((GLfloat) r) * inv255f;
1273 const GLfloat fg = ((GLfloat) g) * inv255f;
1274 const GLfloat fb = ((GLfloat) b) * inv255f;
1275 const GLfloat fa = ((GLfloat) a) * inv255f;
1276 data->glClearColor(fr, fg, fb, fa);
1277 data->drawstate.clear_color = color;
1280 if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) {
1281 data->glDisable(GL_SCISSOR_TEST);
1282 data->drawstate.cliprect_enabled_dirty = data->drawstate.cliprect_enabled;
1285 data->glClear(GL_COLOR_BUFFER_BIT);
1289 case SDL_RENDERCMD_DRAW_POINTS: {
1290 if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID) == 0) {
1291 data->glDrawArrays(GL_POINTS, 0, (GLsizei) cmd->data.draw.count);
1296 case SDL_RENDERCMD_DRAW_LINES: {
1297 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
1298 const size_t count = cmd->data.draw.count;
1299 if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID) == 0) {
1300 if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
1301 /* GL_LINE_LOOP takes care of the final segment */
1302 data->glDrawArrays(GL_LINE_LOOP, 0, (GLsizei) (count - 1));
1304 data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count);
1305 /* We need to close the endpoint of the line */
1306 data->glDrawArrays(GL_POINTS, (GLsizei) (count - 1), 1);
1312 case SDL_RENDERCMD_FILL_RECTS: {
1313 const size_t count = cmd->data.draw.count;
1315 if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID) == 0) {
1316 for (i = 0; i < count; ++i, offset += 4) {
1317 data->glDrawArrays(GL_TRIANGLE_STRIP, (GLsizei) offset, 4);
1323 case SDL_RENDERCMD_COPY:
1324 case SDL_RENDERCMD_COPY_EX: {
1325 if (SetCopyState(renderer, cmd) == 0) {
1326 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1331 case SDL_RENDERCMD_NO_OP:
1338 return GL_CheckError("", renderer);
1342 GLES2_DestroyRenderer(SDL_Renderer *renderer)
1344 GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
1346 /* Deallocate everything */
1348 GLES2_ActivateRenderer(renderer);
1351 GLES2_ShaderCacheEntry *entry;
1352 GLES2_ShaderCacheEntry *next;
1353 entry = data->shader_cache.head;
1355 data->glDeleteShader(entry->id);
1362 GLES2_ProgramCacheEntry *entry;
1363 GLES2_ProgramCacheEntry *next;
1364 entry = data->program_cache.head;
1366 data->glDeleteProgram(entry->id);
1373 if (data->context) {
1374 while (data->framebuffers) {
1375 GLES2_FBOList *nextnode = data->framebuffers->next;
1376 data->glDeleteFramebuffers(1, &data->framebuffers->FBO);
1377 GL_CheckError("", renderer);
1378 SDL_free(data->framebuffers);
1379 data->framebuffers = nextnode;
1382 data->glDeleteBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
1383 GL_CheckError("", renderer);
1385 SDL_GL_DeleteContext(data->context);
1388 SDL_free(data->shader_formats);
1395 GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
1397 GLES2_RenderData *renderdata = (GLES2_RenderData *)renderer->driverdata;
1398 GLES2_TextureData *data;
1403 GLES2_ActivateRenderer(renderer);
1405 renderdata->drawstate.texture = NULL; /* we trash this state. */
1407 /* Determine the corresponding GLES texture format params */
1408 switch (texture->format)
1410 case SDL_PIXELFORMAT_ARGB8888:
1411 case SDL_PIXELFORMAT_ABGR8888:
1412 case SDL_PIXELFORMAT_RGB888:
1413 case SDL_PIXELFORMAT_BGR888:
1415 type = GL_UNSIGNED_BYTE;
1417 case SDL_PIXELFORMAT_IYUV:
1418 case SDL_PIXELFORMAT_YV12:
1419 case SDL_PIXELFORMAT_NV12:
1420 case SDL_PIXELFORMAT_NV21:
1421 format = GL_LUMINANCE;
1422 type = GL_UNSIGNED_BYTE;
1424 #ifdef GL_TEXTURE_EXTERNAL_OES
1425 case SDL_PIXELFORMAT_EXTERNAL_OES:
1431 return SDL_SetError("Texture format not supported");
1434 if (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES &&
1435 texture->access != SDL_TEXTUREACCESS_STATIC) {
1436 return SDL_SetError("Unsupported texture access for SDL_PIXELFORMAT_EXTERNAL_OES");
1439 /* Allocate a texture struct */
1440 data = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData));
1442 return SDL_OutOfMemory();
1445 #ifdef GL_TEXTURE_EXTERNAL_OES
1446 data->texture_type = (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES) ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
1448 data->texture_type = GL_TEXTURE_2D;
1450 data->pixel_format = format;
1451 data->pixel_type = type;
1452 data->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12));
1453 data->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21));
1454 data->texture_u = 0;
1455 data->texture_v = 0;
1456 scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
1458 /* Allocate a blob for image renderdata */
1459 if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
1461 data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
1462 size = texture->h * data->pitch;
1464 /* Need to add size for the U and V planes */
1465 size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
1466 } else if (data->nv12) {
1467 /* Need to add size for the U/V plane */
1468 size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
1470 data->pixel_data = SDL_calloc(1, size);
1471 if (!data->pixel_data) {
1473 return SDL_OutOfMemory();
1477 /* Allocate the texture */
1478 GL_CheckError("", renderer);
1481 renderdata->glGenTextures(1, &data->texture_v);
1482 if (GL_CheckError("glGenTexures()", renderer) < 0) {
1485 renderdata->glActiveTexture(GL_TEXTURE2);
1486 renderdata->glBindTexture(data->texture_type, data->texture_v);
1487 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1488 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1489 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1490 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1491 renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
1493 renderdata->glGenTextures(1, &data->texture_u);
1494 if (GL_CheckError("glGenTexures()", renderer) < 0) {
1497 renderdata->glActiveTexture(GL_TEXTURE1);
1498 renderdata->glBindTexture(data->texture_type, data->texture_u);
1499 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1500 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1501 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1502 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1503 renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
1504 if (GL_CheckError("glTexImage2D()", renderer) < 0) {
1507 } else if (data->nv12) {
1508 renderdata->glGenTextures(1, &data->texture_u);
1509 if (GL_CheckError("glGenTexures()", renderer) < 0) {
1512 renderdata->glActiveTexture(GL_TEXTURE1);
1513 renderdata->glBindTexture(data->texture_type, data->texture_u);
1514 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1515 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1516 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1517 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1518 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);
1519 if (GL_CheckError("glTexImage2D()", renderer) < 0) {
1524 renderdata->glGenTextures(1, &data->texture);
1525 if (GL_CheckError("glGenTexures()", renderer) < 0) {
1528 texture->driverdata = data;
1529 renderdata->glActiveTexture(GL_TEXTURE0);
1530 renderdata->glBindTexture(data->texture_type, data->texture);
1531 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1532 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1533 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1534 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1535 if (texture->format != SDL_PIXELFORMAT_EXTERNAL_OES) {
1536 renderdata->glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);
1537 if (GL_CheckError("glTexImage2D()", renderer) < 0) {
1542 if (texture->access == SDL_TEXTUREACCESS_TARGET) {
1543 data->fbo = GLES2_GetFBO(renderer->driverdata, texture->w, texture->h);
1548 return GL_CheckError("", renderer);
1552 GLES2_TexSubImage2D(GLES2_RenderData *data, GLenum target, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, GLint pitch, GLint bpp)
1559 if ((width == 0) || (height == 0) || (bpp == 0)) {
1560 return 0; /* nothing to do */
1563 /* Reformat the texture data into a tightly packed array */
1564 src_pitch = width * bpp;
1565 src = (Uint8 *)pixels;
1566 if (pitch != src_pitch) {
1567 blob = (Uint8 *)SDL_malloc(src_pitch * height);
1569 return SDL_OutOfMemory();
1572 for (y = 0; y < height; ++y)
1574 SDL_memcpy(src, pixels, src_pitch);
1576 pixels = (Uint8 *)pixels + pitch;
1581 data->glTexSubImage2D(target, 0, xoffset, yoffset, width, height, format, type, src);
1589 GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
1590 const void *pixels, int pitch)
1592 GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
1593 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
1595 GLES2_ActivateRenderer(renderer);
1597 /* Bail out if we're supposed to update an empty rectangle */
1598 if (rect->w <= 0 || rect->h <= 0) {
1602 data->drawstate.texture = NULL; /* we trash this state. */
1604 /* Create a texture subimage with the supplied data */
1605 data->glBindTexture(tdata->texture_type, tdata->texture);
1606 GLES2_TexSubImage2D(data, tdata->texture_type,
1611 tdata->pixel_format,
1613 pixels, pitch, SDL_BYTESPERPIXEL(texture->format));
1616 /* Skip to the correct offset into the next texture */
1617 pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
1618 if (texture->format == SDL_PIXELFORMAT_YV12) {
1619 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1621 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1623 GLES2_TexSubImage2D(data, tdata->texture_type,
1628 tdata->pixel_format,
1630 pixels, (pitch + 1) / 2, 1);
1633 /* Skip to the correct offset into the next texture */
1634 pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1)/2));
1635 if (texture->format == SDL_PIXELFORMAT_YV12) {
1636 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1638 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1640 GLES2_TexSubImage2D(data, tdata->texture_type,
1645 tdata->pixel_format,
1647 pixels, (pitch + 1) / 2, 1);
1648 } else if (tdata->nv12) {
1649 /* Skip to the correct offset into the next texture */
1650 pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
1651 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1652 GLES2_TexSubImage2D(data, tdata->texture_type,
1659 pixels, 2 * ((pitch + 1) / 2), 2);
1662 return GL_CheckError("glTexSubImage2D()", renderer);
1666 GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
1667 const SDL_Rect * rect,
1668 const Uint8 *Yplane, int Ypitch,
1669 const Uint8 *Uplane, int Upitch,
1670 const Uint8 *Vplane, int Vpitch)
1672 GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
1673 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
1675 GLES2_ActivateRenderer(renderer);
1677 /* Bail out if we're supposed to update an empty rectangle */
1678 if (rect->w <= 0 || rect->h <= 0) {
1682 data->drawstate.texture = NULL; /* we trash this state. */
1684 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1685 GLES2_TexSubImage2D(data, tdata->texture_type,
1690 tdata->pixel_format,
1694 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1695 GLES2_TexSubImage2D(data, tdata->texture_type,
1700 tdata->pixel_format,
1704 data->glBindTexture(tdata->texture_type, tdata->texture);
1705 GLES2_TexSubImage2D(data, tdata->texture_type,
1710 tdata->pixel_format,
1714 return GL_CheckError("glTexSubImage2D()", renderer);
1718 GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
1719 void **pixels, int *pitch)
1721 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
1723 /* Retrieve the buffer/pitch for the specified region */
1724 *pixels = (Uint8 *)tdata->pixel_data +
1725 (tdata->pitch * rect->y) +
1726 (rect->x * SDL_BYTESPERPIXEL(texture->format));
1727 *pitch = tdata->pitch;
1733 GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
1735 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
1738 /* We do whole texture updates, at least for now */
1741 rect.w = texture->w;
1742 rect.h = texture->h;
1743 GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
1747 GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
1749 GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
1750 GLES2_TextureData *texturedata = NULL;
1753 data->drawstate.viewport_dirty = SDL_TRUE;
1755 if (texture == NULL) {
1756 data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer);
1758 texturedata = (GLES2_TextureData *) texture->driverdata;
1759 data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO);
1760 /* TODO: check if texture pixel format allows this operation */
1761 data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0);
1762 /* Check FBO status */
1763 status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER);
1764 if (status != GL_FRAMEBUFFER_COMPLETE) {
1765 return SDL_SetError("glFramebufferTexture2D() failed");
1772 GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
1774 GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
1775 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
1777 GLES2_ActivateRenderer(renderer);
1779 if (data->drawstate.texture == texture) {
1780 data->drawstate.texture = NULL;
1782 if (data->drawstate.target == texture) {
1783 data->drawstate.target = NULL;
1786 /* Destroy the texture */
1788 data->glDeleteTextures(1, &tdata->texture);
1789 if (tdata->texture_v) {
1790 data->glDeleteTextures(1, &tdata->texture_v);
1792 if (tdata->texture_u) {
1793 data->glDeleteTextures(1, &tdata->texture_u);
1795 SDL_free(tdata->pixel_data);
1797 texture->driverdata = NULL;
1802 GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1803 Uint32 pixel_format, void * pixels, int pitch)
1805 GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
1806 Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888;
1810 Uint8 *src, *dst, *tmp;
1811 int w, h, length, rows;
1814 temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
1815 buflen = rect->h * temp_pitch;
1817 return 0; /* nothing to do. */
1820 temp_pixels = SDL_malloc(buflen);
1822 return SDL_OutOfMemory();
1825 SDL_GetRendererOutputSize(renderer, &w, &h);
1827 data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
1828 rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels);
1829 if (GL_CheckError("glReadPixels()", renderer) < 0) {
1833 /* Flip the rows to be top-down if necessary */
1834 if (!renderer->target) {
1836 length = rect->w * SDL_BYTESPERPIXEL(temp_format);
1837 src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
1838 dst = (Uint8*)temp_pixels;
1839 tmp = SDL_small_alloc(Uint8, length, &isstack);
1842 SDL_memcpy(tmp, dst, length);
1843 SDL_memcpy(dst, src, length);
1844 SDL_memcpy(src, tmp, length);
1848 SDL_small_free(tmp, isstack);
1851 status = SDL_ConvertPixels(rect->w, rect->h,
1852 temp_format, temp_pixels, temp_pitch,
1853 pixel_format, pixels, pitch);
1854 SDL_free(temp_pixels);
1860 GLES2_RenderPresent(SDL_Renderer *renderer)
1862 /* Tell the video driver to swap buffers */
1863 SDL_GL_SwapWindow(renderer->window);
1867 /*************************************************************************************************
1868 * Bind/unbinding of textures
1869 *************************************************************************************************/
1870 static int GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
1871 static int GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
1873 static int GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
1875 GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
1876 GLES2_TextureData *texturedata = (GLES2_TextureData *)texture->driverdata;
1877 GLES2_ActivateRenderer(renderer);
1879 data->glBindTexture(texturedata->texture_type, texturedata->texture);
1880 data->drawstate.texture = texture;
1892 static int GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
1894 GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
1895 GLES2_TextureData *texturedata = (GLES2_TextureData *)texture->driverdata;
1896 GLES2_ActivateRenderer(renderer);
1898 data->glBindTexture(texturedata->texture_type, 0);
1899 data->drawstate.texture = NULL;
1905 /*************************************************************************************************
1906 * Renderer instantiation *
1907 *************************************************************************************************/
1910 #define GL_NVIDIA_PLATFORM_BINARY_NV 0x890B
1914 static SDL_Renderer *
1915 GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
1917 SDL_Renderer *renderer;
1918 GLES2_RenderData *data;
1921 GLboolean hasCompiler;
1923 Uint32 window_flags = 0; /* -Wconditional-uninitialized */
1924 GLint window_framebuffer;
1926 int profile_mask = 0, major = 0, minor = 0;
1927 SDL_bool changed_window = SDL_FALSE;
1929 if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask) < 0) {
1932 if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major) < 0) {
1935 if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor) < 0) {
1939 window_flags = SDL_GetWindowFlags(window);
1941 /* OpenGL ES 3.0 is a superset of OpenGL ES 2.0 */
1942 if (!(window_flags & SDL_WINDOW_OPENGL) ||
1943 profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major < RENDERER_CONTEXT_MAJOR) {
1945 changed_window = SDL_TRUE;
1946 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
1947 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
1948 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
1950 if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
1955 /* Create the renderer struct */
1956 renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(SDL_Renderer));
1962 data = (GLES2_RenderData *)SDL_calloc(1, sizeof(GLES2_RenderData));
1968 renderer->info = GLES2_RenderDriver.info;
1969 renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
1970 renderer->driverdata = data;
1971 renderer->window = window;
1973 /* Create an OpenGL ES 2.0 context */
1974 data->context = SDL_GL_CreateContext(window);
1975 if (!data->context) {
1980 if (SDL_GL_MakeCurrent(window, data->context) < 0) {
1981 SDL_GL_DeleteContext(data->context);
1987 if (GLES2_LoadFunctions(data) < 0) {
1988 SDL_GL_DeleteContext(data->context);
1995 /* DLudwig, 2013-11-29: ANGLE for WinRT doesn't seem to work unless VSync
1996 * is turned on. Not doing so will freeze the screen's contents to that
1997 * of the first drawn frame.
1999 flags |= SDL_RENDERER_PRESENTVSYNC;
2002 if (flags & SDL_RENDERER_PRESENTVSYNC) {
2003 SDL_GL_SetSwapInterval(1);
2005 SDL_GL_SetSwapInterval(0);
2007 if (SDL_GL_GetSwapInterval() > 0) {
2008 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
2011 /* Check for debug output support */
2012 if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
2013 (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
2014 data->debug_enabled = SDL_TRUE;
2018 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
2019 renderer->info.max_texture_width = value;
2021 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
2022 renderer->info.max_texture_height = value;
2024 /* Determine supported shader formats */
2025 /* HACK: glGetInteger is broken on the Zune HD's compositor, so we just hardcode this */
2028 #else /* !ZUNE_HD */
2029 data->glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats);
2030 data->glGetBooleanv(GL_SHADER_COMPILER, &hasCompiler);
2034 #endif /* ZUNE_HD */
2035 data->shader_formats = (GLenum *)SDL_calloc(nFormats, sizeof(GLenum));
2036 if (!data->shader_formats) {
2037 GLES2_DestroyRenderer(renderer);
2041 data->shader_format_count = nFormats;
2043 data->shader_formats[0] = GL_NVIDIA_PLATFORM_BINARY_NV;
2044 #else /* !ZUNE_HD */
2045 data->glGetIntegerv(GL_SHADER_BINARY_FORMATS, (GLint *)data->shader_formats);
2047 data->shader_formats[nFormats - 1] = (GLenum)-1;
2049 #endif /* ZUNE_HD */
2051 /* we keep a few of these and cycle through them, so data can live for a few frames. */
2052 data->glGenBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
2054 data->framebuffers = NULL;
2055 data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer);
2056 data->window_framebuffer = (GLuint)window_framebuffer;
2058 /* Populate the function pointers for the module */
2059 renderer->WindowEvent = GLES2_WindowEvent;
2060 renderer->GetOutputSize = GLES2_GetOutputSize;
2061 renderer->SupportsBlendMode = GLES2_SupportsBlendMode;
2062 renderer->CreateTexture = GLES2_CreateTexture;
2063 renderer->UpdateTexture = GLES2_UpdateTexture;
2064 renderer->UpdateTextureYUV = GLES2_UpdateTextureYUV;
2065 renderer->LockTexture = GLES2_LockTexture;
2066 renderer->UnlockTexture = GLES2_UnlockTexture;
2067 renderer->SetRenderTarget = GLES2_SetRenderTarget;
2068 renderer->QueueSetViewport = GLES2_QueueSetViewport;
2069 renderer->QueueSetDrawColor = GLES2_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
2070 renderer->QueueDrawPoints = GLES2_QueueDrawPoints;
2071 renderer->QueueDrawLines = GLES2_QueueDrawPoints; /* lines and points queue vertices the same way. */
2072 renderer->QueueFillRects = GLES2_QueueFillRects;
2073 renderer->QueueCopy = GLES2_QueueCopy;
2074 renderer->QueueCopyEx = GLES2_QueueCopyEx;
2075 renderer->RunCommandQueue = GLES2_RunCommandQueue;
2076 renderer->RenderReadPixels = GLES2_RenderReadPixels;
2077 renderer->RenderPresent = GLES2_RenderPresent;
2078 renderer->DestroyTexture = GLES2_DestroyTexture;
2079 renderer->DestroyRenderer = GLES2_DestroyRenderer;
2080 renderer->GL_BindTexture = GLES2_BindTexture;
2081 renderer->GL_UnbindTexture = GLES2_UnbindTexture;
2083 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
2084 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
2085 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
2086 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
2087 #ifdef GL_TEXTURE_EXTERNAL_OES
2088 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_EXTERNAL_OES;
2091 /* Set up parameters for rendering */
2092 data->glActiveTexture(GL_TEXTURE0);
2093 data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
2094 data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2096 data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
2097 data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
2099 data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
2101 data->drawstate.blend = SDL_BLENDMODE_INVALID;
2102 data->drawstate.color = 0xFFFFFFFF;
2103 data->drawstate.clear_color = 0xFFFFFFFF;
2104 data->drawstate.projection[3][0] = -1.0f;
2105 data->drawstate.projection[3][3] = 1.0f;
2107 GL_CheckError("", renderer);
2112 if (changed_window) {
2113 /* Uh oh, better try to put it back... */
2114 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
2115 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
2116 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
2117 SDL_RecreateWindow(window, window_flags);
2122 SDL_RenderDriver GLES2_RenderDriver = {
2123 GLES2_CreateRenderer,
2126 (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
2129 SDL_PIXELFORMAT_ARGB8888,
2130 SDL_PIXELFORMAT_ABGR8888,
2131 SDL_PIXELFORMAT_RGB888,
2132 SDL_PIXELFORMAT_BGR888
2139 #endif /* SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED */
2141 /* vi: set ts=4 sw=4 expandtab: */