src/render/opengles2/SDL_render_gles2.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 08 Dec 2019 11:36:40 -0800
changeset 13321 37350f1e7902
parent 13208 4389d1796f6d
permissions -rw-r--r--
Fixed bug 4883 - Add approximation for display DPI on iOS

Aaron Barany

There appears to be no way to directly access the display DPI on iOS, so as an approximation the DPI for the iPhone 1 is used as a base value and is multiplied by the screen's scale. This should at least give a ballpark number for the various screen scales. (based on https://stackoverflow.com/questions/25756087/detecting-iphone-6-6-screen-sizes-in-point-values it appears that both 2x and 3x are used)

I have updated the patch to use a table of current devices and use a computation as a fallback. I have also updated the fallback computation to be more accurate.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_hints.h"
    27 #include "SDL_opengles2.h"
    28 #include "../SDL_sysrender.h"
    29 #include "../../video/SDL_blit.h"
    30 #include "SDL_shaders_gles2.h"
    31 
    32 /* To prevent unnecessary window recreation,
    33  * these should match the defaults selected in SDL_GL_ResetAttributes
    34  */
    35 #define RENDERER_CONTEXT_MAJOR 2
    36 #define RENDERER_CONTEXT_MINOR 0
    37 
    38 /* Used to re-create the window with OpenGL ES capability */
    39 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
    40 
    41 /*************************************************************************************************
    42  * Context structures                                                                            *
    43  *************************************************************************************************/
    44 
    45 typedef struct GLES2_FBOList GLES2_FBOList;
    46 
    47 struct GLES2_FBOList
    48 {
    49    Uint32 w, h;
    50    GLuint FBO;
    51    GLES2_FBOList *next;
    52 };
    53 
    54 typedef struct GLES2_TextureData
    55 {
    56     GLenum texture;
    57     GLenum texture_type;
    58     GLenum pixel_format;
    59     GLenum pixel_type;
    60     void *pixel_data;
    61     int pitch;
    62     /* YUV texture support */
    63     SDL_bool yuv;
    64     SDL_bool nv12;
    65     GLenum texture_v;
    66     GLenum texture_u;
    67     GLES2_FBOList *fbo;
    68 } GLES2_TextureData;
    69 
    70 typedef struct GLES2_ShaderCacheEntry
    71 {
    72     GLuint id;
    73     GLES2_ShaderType type;
    74     const GLES2_ShaderInstance *instance;
    75     int references;
    76     struct GLES2_ShaderCacheEntry *prev;
    77     struct GLES2_ShaderCacheEntry *next;
    78 } GLES2_ShaderCacheEntry;
    79 
    80 typedef struct GLES2_ShaderCache
    81 {
    82     int count;
    83     GLES2_ShaderCacheEntry *head;
    84 } GLES2_ShaderCache;
    85 
    86 typedef struct GLES2_ProgramCacheEntry
    87 {
    88     GLuint id;
    89     GLES2_ShaderCacheEntry *vertex_shader;
    90     GLES2_ShaderCacheEntry *fragment_shader;
    91     GLuint uniform_locations[16];
    92     Uint32 color;
    93     GLfloat projection[4][4];
    94     struct GLES2_ProgramCacheEntry *prev;
    95     struct GLES2_ProgramCacheEntry *next;
    96 } GLES2_ProgramCacheEntry;
    97 
    98 typedef struct GLES2_ProgramCache
    99 {
   100     int count;
   101     GLES2_ProgramCacheEntry *head;
   102     GLES2_ProgramCacheEntry *tail;
   103 } GLES2_ProgramCache;
   104 
   105 typedef enum
   106 {
   107     GLES2_ATTRIBUTE_POSITION = 0,
   108     GLES2_ATTRIBUTE_TEXCOORD = 1,
   109     GLES2_ATTRIBUTE_ANGLE = 2,
   110     GLES2_ATTRIBUTE_CENTER = 3,
   111 } GLES2_Attribute;
   112 
   113 typedef enum
   114 {
   115     GLES2_UNIFORM_PROJECTION,
   116     GLES2_UNIFORM_TEXTURE,
   117     GLES2_UNIFORM_COLOR,
   118     GLES2_UNIFORM_TEXTURE_U,
   119     GLES2_UNIFORM_TEXTURE_V
   120 } GLES2_Uniform;
   121 
   122 typedef enum
   123 {
   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
   134 } GLES2_ImageSource;
   135 
   136 typedef struct
   137 {
   138     SDL_Rect viewport;
   139     SDL_bool viewport_dirty;
   140     SDL_Texture *texture;
   141     SDL_Texture *target;
   142     SDL_BlendMode blend;
   143     SDL_bool cliprect_enabled_dirty;
   144     SDL_bool cliprect_enabled;
   145     SDL_bool cliprect_dirty;
   146     SDL_Rect cliprect;
   147     SDL_bool texturing;
   148     SDL_bool is_copy_ex;
   149     Uint32 color;
   150     Uint32 clear_color;
   151     int drawablew;
   152     int drawableh;
   153     GLES2_ProgramCacheEntry *program;
   154     GLfloat projection[4][4];
   155 } GLES2_DrawStateCache;
   156 
   157 typedef struct GLES2_RenderData
   158 {
   159     SDL_GLContext *context;
   160 
   161     SDL_bool debug_enabled;
   162 
   163 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
   164 #include "SDL_gles2funcs.h"
   165 #undef SDL_PROC
   166     GLES2_FBOList *framebuffers;
   167     GLuint window_framebuffer;
   168 
   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;
   174 
   175     GLuint vertex_buffers[8];
   176     size_t vertex_buffer_size[8];
   177     int current_vertex_buffer;
   178     GLES2_DrawStateCache drawstate;
   179 } GLES2_RenderData;
   180 
   181 #define GLES2_MAX_CACHED_PROGRAMS 8
   182 
   183 static const float inv255f = 1.0f / 255.0f;
   184 
   185 
   186 SDL_FORCE_INLINE const char*
   187 GL_TranslateError (GLenum error)
   188 {
   189 #define GL_ERROR_TRANSLATE(e) case e: return #e;
   190     switch (error) {
   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)
   196     default:
   197         return "UNKNOWN";
   198 }
   199 #undef GL_ERROR_TRANSLATE
   200 }
   201 
   202 SDL_FORCE_INLINE void
   203 GL_ClearErrors(SDL_Renderer *renderer)
   204 {
   205     GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
   206 
   207     if (!data->debug_enabled) {
   208         return;
   209     }
   210     while (data->glGetError() != GL_NO_ERROR) {
   211         /* continue; */
   212     }
   213 }
   214 
   215 SDL_FORCE_INLINE int
   216 GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function)
   217 {
   218     GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
   219     int ret = 0;
   220 
   221     if (!data->debug_enabled) {
   222         return 0;
   223     }
   224     /* check gl errors (can return multiple errors) */
   225     for (;;) {
   226         GLenum error = data->glGetError();
   227         if (error != GL_NO_ERROR) {
   228             if (prefix == NULL || prefix[0] == '\0') {
   229                 prefix = "generic";
   230             }
   231             SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error);
   232             ret = -1;
   233         } else {
   234             break;
   235         }
   236     }
   237     return ret;
   238 }
   239 
   240 #if 0
   241 #define GL_CheckError(prefix, renderer)
   242 #else
   243 #define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, SDL_FILE, SDL_LINE, SDL_FUNCTION)
   244 #endif
   245 
   246 
   247 /*************************************************************************************************
   248  * Renderer state APIs                                                                           *
   249  *************************************************************************************************/
   250 
   251 static int GLES2_LoadFunctions(GLES2_RenderData * data)
   252 {
   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__
   259 #endif
   260 
   261 #if defined __SDL_NOGETPROCADDR__
   262 #define SDL_PROC(ret,func,params) data->func=func;
   263 #else
   264 #define SDL_PROC(ret,func,params) \
   265     do { \
   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()); \
   269         } \
   270     } while ( 0 );
   271 #endif /* __SDL_NOGETPROCADDR__ */
   272 
   273 #include "SDL_gles2funcs.h"
   274 #undef SDL_PROC
   275     return 0;
   276 }
   277 
   278 static GLES2_FBOList *
   279 GLES2_GetFBO(GLES2_RenderData *data, Uint32 w, Uint32 h)
   280 {
   281    GLES2_FBOList *result = data->framebuffers;
   282    while ((result) && ((result->w != w) || (result->h != h)) ) {
   283        result = result->next;
   284    }
   285    if (result == NULL) {
   286        result = SDL_malloc(sizeof(GLES2_FBOList));
   287        result->w = w;
   288        result->h = h;
   289        data->glGenFramebuffers(1, &result->FBO);
   290        result->next = data->framebuffers;
   291        data->framebuffers = result;
   292    }
   293    return result;
   294 }
   295 
   296 static int
   297 GLES2_ActivateRenderer(SDL_Renderer * renderer)
   298 {
   299     GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
   300 
   301     if (SDL_GL_GetCurrentContext() != data->context) {
   302         /* Null out the current program to ensure we set it again */
   303         data->drawstate.program = NULL;
   304 
   305         if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
   306             return -1;
   307         }
   308     }
   309 
   310     GL_ClearErrors(renderer);
   311 
   312     return 0;
   313 }
   314 
   315 static void
   316 GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   317 {
   318     GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
   319 
   320     if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
   321         /* According to Apple documentation, we need to finish drawing NOW! */
   322         data->glFinish();
   323     }
   324 }
   325 
   326 static int
   327 GLES2_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
   328 {
   329     SDL_GL_GetDrawableSize(renderer->window, w, h);
   330     return 0;
   331 }
   332 
   333 static GLenum GetBlendFunc(SDL_BlendFactor factor)
   334 {
   335     switch (factor) {
   336     case SDL_BLENDFACTOR_ZERO:
   337         return GL_ZERO;
   338     case SDL_BLENDFACTOR_ONE:
   339         return GL_ONE;
   340     case SDL_BLENDFACTOR_SRC_COLOR:
   341         return GL_SRC_COLOR;
   342     case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
   343         return GL_ONE_MINUS_SRC_COLOR;
   344     case SDL_BLENDFACTOR_SRC_ALPHA:
   345         return GL_SRC_ALPHA;
   346     case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
   347         return GL_ONE_MINUS_SRC_ALPHA;
   348     case SDL_BLENDFACTOR_DST_COLOR:
   349         return GL_DST_COLOR;
   350     case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
   351         return GL_ONE_MINUS_DST_COLOR;
   352     case SDL_BLENDFACTOR_DST_ALPHA:
   353         return GL_DST_ALPHA;
   354     case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
   355         return GL_ONE_MINUS_DST_ALPHA;
   356     default:
   357         return GL_INVALID_ENUM;
   358     }
   359 }
   360 
   361 static GLenum GetBlendEquation(SDL_BlendOperation operation)
   362 {
   363     switch (operation) {
   364     case SDL_BLENDOPERATION_ADD:
   365         return GL_FUNC_ADD;
   366     case SDL_BLENDOPERATION_SUBTRACT:
   367         return GL_FUNC_SUBTRACT;
   368     case SDL_BLENDOPERATION_REV_SUBTRACT:
   369         return GL_FUNC_REVERSE_SUBTRACT;
   370     default:
   371         return GL_INVALID_ENUM;
   372     }
   373 }
   374 
   375 static SDL_bool
   376 GLES2_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
   377 {
   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);
   384 
   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) {
   391         return SDL_FALSE;
   392     }
   393     return SDL_TRUE;
   394 }
   395 
   396 
   397 static void
   398 GLES2_EvictShader(GLES2_RenderData *data, GLES2_ShaderCacheEntry *entry)
   399 {
   400     /* Unlink the shader from the cache */
   401     if (entry->next) {
   402         entry->next->prev = entry->prev;
   403     }
   404     if (entry->prev) {
   405         entry->prev->next = entry->next;
   406     }
   407     if (data->shader_cache.head == entry) {
   408         data->shader_cache.head = entry->next;
   409     }
   410     --data->shader_cache.count;
   411 
   412     /* Deallocate the shader */
   413     data->glDeleteShader(entry->id);
   414     SDL_free(entry);
   415 }
   416 
   417 static GLES2_ProgramCacheEntry *
   418 GLES2_CacheProgram(GLES2_RenderData *data, GLES2_ShaderCacheEntry *vertex,
   419                    GLES2_ShaderCacheEntry *fragment)
   420 {
   421     GLES2_ProgramCacheEntry *entry;
   422     GLES2_ShaderCacheEntry *shaderEntry;
   423     GLint linkSuccessful;
   424 
   425     /* Check if we've already cached this program */
   426     entry = data->program_cache.head;
   427     while (entry) {
   428         if (entry->vertex_shader == vertex && entry->fragment_shader == fragment) {
   429             break;
   430         }
   431         entry = entry->next;
   432     }
   433     if (entry) {
   434         if (data->program_cache.head != entry) {
   435             if (entry->next) {
   436                 entry->next->prev = entry->prev;
   437             }
   438             if (entry->prev) {
   439                 entry->prev->next = entry->next;
   440             }
   441             entry->prev = NULL;
   442             entry->next = data->program_cache.head;
   443             data->program_cache.head->prev = entry;
   444             data->program_cache.head = entry;
   445         }
   446         return entry;
   447     }
   448 
   449     /* Create a program cache entry */
   450     entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry));
   451     if (!entry) {
   452         SDL_OutOfMemory();
   453         return NULL;
   454     }
   455     entry->vertex_shader = vertex;
   456     entry->fragment_shader = fragment;
   457 
   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);
   470         SDL_free(entry);
   471         SDL_SetError("Failed to link shader program");
   472         return NULL;
   473     }
   474 
   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");
   486 
   487     entry->color = 0;
   488 
   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. */
   492     }
   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. */
   495     }
   496     if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE] != -1) {
   497         data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0);  /* always texture unit 0. */
   498     }
   499     if (entry->uniform_locations[GLES2_UNIFORM_PROJECTION] != -1) {
   500         data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection);
   501     }
   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);
   504     }
   505 
   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;
   510     } else {
   511         data->program_cache.tail = entry;
   512     }
   513     data->program_cache.head = entry;
   514     ++data->program_cache.count;
   515 
   516     /* Increment the refcount of the shaders we're using */
   517     ++vertex->references;
   518     ++fragment->references;
   519 
   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);
   525         }
   526         shaderEntry = data->program_cache.tail->fragment_shader;
   527         if (--shaderEntry->references <= 0) {
   528             GLES2_EvictShader(data, shaderEntry);
   529         }
   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;
   535         }
   536         --data->program_cache.count;
   537     }
   538     return entry;
   539 }
   540 
   541 static GLES2_ShaderCacheEntry *
   542 GLES2_CacheShader(GLES2_RenderData *data, GLES2_ShaderType type)
   543 {
   544     const GLES2_Shader *shader;
   545     const GLES2_ShaderInstance *instance = NULL;
   546     GLES2_ShaderCacheEntry *entry = NULL;
   547     GLint compileSuccessful = GL_FALSE;
   548     int i, j;
   549 
   550     /* Find the corresponding shader */
   551     shader = GLES2_GetShader(type);
   552     if (!shader) {
   553         SDL_SetError("No shader matching the requested characteristics was found");
   554         return NULL;
   555     }
   556 
   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]) {
   561                 continue;
   562             }
   563             if (shader->instances[i]->format != data->shader_formats[j]) {
   564                 continue;
   565             }
   566             instance = shader->instances[i];
   567         }
   568     }
   569     if (!instance) {
   570         SDL_SetError("The specified shader cannot be loaded on the current platform");
   571         return NULL;
   572     }
   573 
   574     /* Check if we've already cached this shader */
   575     entry = data->shader_cache.head;
   576     while (entry) {
   577         if (entry->instance == instance) {
   578             break;
   579         }
   580         entry = entry->next;
   581     }
   582     if (entry) {
   583         return entry;
   584     }
   585 
   586     /* Create a shader cache entry */
   587     entry = (GLES2_ShaderCacheEntry *)SDL_calloc(1, sizeof(GLES2_ShaderCacheEntry));
   588     if (!entry) {
   589         SDL_OutOfMemory();
   590         return NULL;
   591     }
   592     entry->type = type;
   593     entry->instance = instance;
   594 
   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);
   601     } else {
   602         data->glShaderBinary(1, &entry->id, instance->format, instance->data, instance->length);
   603         compileSuccessful = GL_TRUE;
   604     }
   605     if (!compileSuccessful) {
   606         SDL_bool isstack = SDL_FALSE;
   607         char *info = NULL;
   608         int length = 0;
   609 
   610         data->glGetShaderiv(entry->id, GL_INFO_LOG_LENGTH, &length);
   611         if (length > 0) {
   612             info = SDL_small_alloc(char, length, &isstack);
   613             if (info) {
   614                 data->glGetShaderInfoLog(entry->id, length, &length, info);
   615             }
   616         }
   617         if (info) {
   618             SDL_SetError("Failed to load the shader: %s", info);
   619             SDL_small_free(info, isstack);
   620         } else {
   621             SDL_SetError("Failed to load the shader");
   622         }
   623         data->glDeleteShader(entry->id);
   624         SDL_free(entry);
   625         return NULL;
   626     }
   627 
   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;
   632     }
   633     data->shader_cache.head = entry;
   634     ++data->shader_cache.count;
   635     return entry;
   636 }
   637 
   638 static int
   639 GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source, int w, int h)
   640 {
   641     GLES2_ShaderCacheEntry *vertex = NULL;
   642     GLES2_ShaderCacheEntry *fragment = NULL;
   643     GLES2_ShaderType vtype, ftype;
   644     GLES2_ProgramCacheEntry *program;
   645 
   646     /* Select an appropriate shader pair for the specified modes */
   647     vtype = GLES2_SHADER_VERTEX_DEFAULT;
   648     switch (source) {
   649     case GLES2_IMAGESOURCE_SOLID:
   650         ftype = GLES2_SHADER_FRAGMENT_SOLID_SRC;
   651         break;
   652     case GLES2_IMAGESOURCE_TEXTURE_ABGR:
   653         ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_SRC;
   654         break;
   655     case GLES2_IMAGESOURCE_TEXTURE_ARGB:
   656         ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_SRC;
   657         break;
   658     case GLES2_IMAGESOURCE_TEXTURE_RGB:
   659         ftype = GLES2_SHADER_FRAGMENT_TEXTURE_RGB_SRC;
   660         break;
   661     case GLES2_IMAGESOURCE_TEXTURE_BGR:
   662         ftype = GLES2_SHADER_FRAGMENT_TEXTURE_BGR_SRC;
   663         break;
   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;
   668             break;
   669         case SDL_YUV_CONVERSION_BT601:
   670             ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT601_SRC;
   671             break;
   672         case SDL_YUV_CONVERSION_BT709:
   673             ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT709_SRC;
   674             break;
   675         default:
   676             SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
   677             goto fault;
   678         }
   679         break;
   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;
   684             break;
   685         case SDL_YUV_CONVERSION_BT601:
   686             ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_BT601_SRC;
   687             break;
   688         case SDL_YUV_CONVERSION_BT709:
   689             ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_BT709_SRC;
   690             break;
   691         default:
   692             SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
   693             goto fault;
   694         }
   695         break;
   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;
   700             break;
   701         case SDL_YUV_CONVERSION_BT601:
   702             ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT601_SRC;
   703             break;
   704         case SDL_YUV_CONVERSION_BT709:
   705             ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT709_SRC;
   706             break;
   707         default:
   708             SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
   709             goto fault;
   710         }
   711         break;
   712     case GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES:
   713         ftype = GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES_SRC;
   714         break;
   715     default:
   716         goto fault;
   717     }
   718 
   719     /* Load the requested shaders */
   720     vertex = GLES2_CacheShader(data, vtype);
   721     if (!vertex) {
   722         goto fault;
   723     }
   724     fragment = GLES2_CacheShader(data, ftype);
   725     if (!fragment) {
   726         goto fault;
   727     }
   728 
   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) {
   733         return 0;
   734     }
   735 
   736     /* Generate a matching program */
   737     program = GLES2_CacheProgram(data, vertex, fragment);
   738     if (!program) {
   739         goto fault;
   740     }
   741 
   742     /* Select that program in OpenGL */
   743     data->glUseProgram(program->id);
   744 
   745     /* Set the current program */
   746     data->drawstate.program = program;
   747 
   748     /* Clean up and return */
   749     return 0;
   750 fault:
   751     if (vertex && vertex->references <= 0) {
   752         GLES2_EvictShader(data, vertex);
   753     }
   754     if (fragment && fragment->references <= 0) {
   755         GLES2_EvictShader(data, fragment);
   756     }
   757     data->drawstate.program = NULL;
   758     return -1;
   759 }
   760 
   761 static int
   762 GLES2_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
   763 {
   764     return 0;  /* nothing to do in this backend. */
   765 }
   766 
   767 static int
   768 GLES2_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
   769 {
   770     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   771     int i;
   772 
   773     if (!verts) {
   774         return -1;
   775     }
   776 
   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;
   781     }
   782 
   783     return 0;
   784 }
   785 
   786 static int
   787 GLES2_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
   788 {
   789     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 8 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   790     int i;
   791 
   792     if (!verts) {
   793         return -1;
   794     }
   795 
   796     cmd->data.draw.count = count;
   797 
   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;
   804         *(verts++) = minx;
   805         *(verts++) = miny;
   806         *(verts++) = maxx;
   807         *(verts++) = miny;
   808         *(verts++) = minx;
   809         *(verts++) = maxy;
   810         *(verts++) = maxx;
   811         *(verts++) = maxy;
   812     }
   813 
   814     return 0;
   815 }
   816 
   817 static int
   818 GLES2_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
   819                           const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   820 {
   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);
   824 
   825     if (!verts) {
   826         return -1;
   827     }
   828 
   829     cmd->data.draw.count = 1;
   830 
   831     minx = dstrect->x;
   832     miny = dstrect->y;
   833     maxx = dstrect->x + dstrect->w;
   834     maxy = dstrect->y + dstrect->h;
   835 
   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;
   840 
   841     *(verts++) = minx;
   842     *(verts++) = miny;
   843     *(verts++) = maxx;
   844     *(verts++) = miny;
   845     *(verts++) = minx;
   846     *(verts++) = maxy;
   847     *(verts++) = maxx;
   848     *(verts++) = maxy;
   849 
   850     *(verts++) = minu;
   851     *(verts++) = minv;
   852     *(verts++) = maxu;
   853     *(verts++) = minv;
   854     *(verts++) = minu;
   855     *(verts++) = maxv;
   856     *(verts++) = maxu;
   857     *(verts++) = maxv;
   858 
   859     return 0;
   860 }
   861 
   862 static int
   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)
   866 {
   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);
   876 
   877     if (!verts) {
   878         return -1;
   879     }
   880 
   881     if (flip & SDL_FLIP_HORIZONTAL) {
   882         minx = dstrect->x + dstrect->w;
   883         maxx = dstrect->x;
   884     } else {
   885         minx = dstrect->x;
   886         maxx = dstrect->x + dstrect->w;
   887     }
   888 
   889     if (flip & SDL_FLIP_VERTICAL) {
   890         miny = dstrect->y + dstrect->h;
   891         maxy = dstrect->y;
   892     } else {
   893         miny = dstrect->y;
   894         maxy = dstrect->y + dstrect->h;
   895     }
   896 
   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);
   901 
   902 
   903     cmd->data.draw.count = 1;
   904 
   905     *(verts++) = minx;
   906     *(verts++) = miny;
   907     *(verts++) = maxx;
   908     *(verts++) = miny;
   909     *(verts++) = minx;
   910     *(verts++) = maxy;
   911     *(verts++) = maxx;
   912     *(verts++) = maxy;
   913 
   914     *(verts++) = minu;
   915     *(verts++) = minv;
   916     *(verts++) = maxu;
   917     *(verts++) = minv;
   918     *(verts++) = minu;
   919     *(verts++) = maxv;
   920     *(verts++) = maxu;
   921     *(verts++) = maxv;
   922 
   923     *(verts++) = s;
   924     *(verts++) = c;
   925     *(verts++) = s;
   926     *(verts++) = c;
   927     *(verts++) = s;
   928     *(verts++) = c;
   929     *(verts++) = s;
   930     *(verts++) = c;
   931 
   932     *(verts++) = centerx;
   933     *(verts++) = centery;
   934     *(verts++) = centerx;
   935     *(verts++) = centery;
   936     *(verts++) = centerx;
   937     *(verts++) = centery;
   938     *(verts++) = centerx;
   939     *(verts++) = centery;
   940 
   941     return 0;
   942 }
   943 
   944 static int
   945 SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_ImageSource imgsrc)
   946 {
   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;
   952 
   953     SDL_assert((texture != NULL) == (imgsrc != GLES2_IMAGESOURCE_SOLID));
   954 
   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;
   964         }
   965         data->drawstate.viewport_dirty = SDL_FALSE;
   966     }
   967 
   968     if (data->drawstate.cliprect_enabled_dirty) {
   969         if (!data->drawstate.cliprect_enabled) {
   970             data->glDisable(GL_SCISSOR_TEST);
   971         } else {
   972             data->glEnable(GL_SCISSOR_TEST);
   973         }
   974         data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
   975     }
   976 
   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,
   982                         rect->w, rect->h);
   983         data->drawstate.cliprect_dirty = SDL_FALSE;
   984     }
   985 
   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;
   991             } else {
   992                 data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_TEXCOORD);
   993                 data->drawstate.texturing = SDL_TRUE;
   994             }
   995         }
   996 
   997         if (texture) {
   998             GLES2_TextureData *tdata = (GLES2_TextureData *) texture->driverdata;
   999             if (tdata->yuv) {
  1000                 data->glActiveTexture(GL_TEXTURE2);
  1001                 data->glBindTexture(tdata->texture_type, tdata->texture_v);
  1002 
  1003                 data->glActiveTexture(GL_TEXTURE1);
  1004                 data->glBindTexture(tdata->texture_type, tdata->texture_u);
  1005 
  1006                 data->glActiveTexture(GL_TEXTURE0);
  1007             } else if (tdata->nv12) {
  1008                 data->glActiveTexture(GL_TEXTURE1);
  1009                 data->glBindTexture(tdata->texture_type, tdata->texture_u);
  1010 
  1011                 data->glActiveTexture(GL_TEXTURE0);
  1012             }
  1013             data->glBindTexture(tdata->texture_type, tdata->texture);
  1014         }
  1015 
  1016         data->drawstate.texture = texture;
  1017     }
  1018 
  1019     if (texture) {
  1020         data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) (cmd->data.draw.first + (sizeof (GLfloat) * 8)));
  1021     }
  1022 
  1023     if (GLES2_SelectProgram(data, imgsrc, texture ? texture->w : 0, texture ? texture->h : 0) < 0) {
  1024         return -1;
  1025     }
  1026 
  1027     program = data->drawstate.program;
  1028 
  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));
  1033         }
  1034     }
  1035 
  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;
  1044         }
  1045     }
  1046 
  1047     if (blend != data->drawstate.blend) {
  1048         if (blend == SDL_BLENDMODE_NONE) {
  1049             data->glDisable(GL_BLEND);
  1050         } else {
  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)));
  1058         }
  1059         data->drawstate.blend = blend;
  1060     }
  1061 
  1062     /* all drawing commands use this */
  1063     data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) cmd->data.draw.first);
  1064 
  1065     if (is_copy_ex != was_copy_ex) {
  1066         if (is_copy_ex) {
  1067             data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_ANGLE);
  1068             data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_CENTER);
  1069         } else {
  1070             data->glDisableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_ANGLE);
  1071             data->glDisableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_CENTER);
  1072         }
  1073         data->drawstate.is_copy_ex = is_copy_ex;
  1074     }
  1075 
  1076     if (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)));
  1079     }
  1080 
  1081     return 0;
  1082 }
  1083 
  1084 static int
  1085 SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd)
  1086 {
  1087     GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
  1088     GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
  1089     SDL_Texture *texture = cmd->data.draw.texture;
  1090 
  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;
  1101                     break;
  1102                 case SDL_PIXELFORMAT_RGB888:
  1103                     sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
  1104                     break;
  1105                 }
  1106                 break;
  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;
  1112                     break;
  1113                 case SDL_PIXELFORMAT_BGR888:
  1114                     sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
  1115                     break;
  1116                 }
  1117                 break;
  1118             case SDL_PIXELFORMAT_RGB888:
  1119                 switch (renderer->target->format) {
  1120                 case SDL_PIXELFORMAT_ABGR8888:
  1121                     sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
  1122                     break;
  1123                 case SDL_PIXELFORMAT_ARGB8888:
  1124                     sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
  1125                     break;
  1126                 case SDL_PIXELFORMAT_BGR888:
  1127                     sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
  1128                     break;
  1129                 }
  1130                 break;
  1131             case SDL_PIXELFORMAT_BGR888:
  1132                 switch (renderer->target->format) {
  1133                 case SDL_PIXELFORMAT_ABGR8888:
  1134                     sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
  1135                     break;
  1136                 case SDL_PIXELFORMAT_ARGB8888:
  1137                     sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
  1138                     break;
  1139                 case SDL_PIXELFORMAT_RGB888:
  1140                     sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
  1141                     break;
  1142                 }
  1143                 break;
  1144             case SDL_PIXELFORMAT_IYUV:
  1145             case SDL_PIXELFORMAT_YV12:
  1146                 sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV;
  1147                 break;
  1148             case SDL_PIXELFORMAT_NV12:
  1149                 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12;
  1150                 break;
  1151             case SDL_PIXELFORMAT_NV21:
  1152                 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21;
  1153                 break;
  1154             case SDL_PIXELFORMAT_EXTERNAL_OES:
  1155                 sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
  1156                 break;
  1157             default:
  1158                 return SDL_SetError("Unsupported texture format");
  1159             }
  1160         } else {
  1161             sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;   /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */
  1162         }
  1163     } else {
  1164         switch (texture->format) {
  1165             case SDL_PIXELFORMAT_ARGB8888:
  1166                 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
  1167                 break;
  1168             case SDL_PIXELFORMAT_ABGR8888:
  1169                 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
  1170                 break;
  1171             case SDL_PIXELFORMAT_RGB888:
  1172                 sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
  1173                 break;
  1174             case SDL_PIXELFORMAT_BGR888:
  1175                 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
  1176                 break;
  1177             case SDL_PIXELFORMAT_IYUV:
  1178             case SDL_PIXELFORMAT_YV12:
  1179                 sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV;
  1180                 break;
  1181             case SDL_PIXELFORMAT_NV12:
  1182                 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12;
  1183                 break;
  1184             case SDL_PIXELFORMAT_NV21:
  1185                 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21;
  1186                 break;
  1187             case SDL_PIXELFORMAT_EXTERNAL_OES:
  1188                 sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
  1189                 break;
  1190             default:
  1191                 return SDL_SetError("Unsupported texture format");
  1192         }
  1193     }
  1194 
  1195     return SetDrawState(data, cmd, sourceType);
  1196 }
  1197 
  1198 static int
  1199 GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
  1200 {
  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];
  1205     size_t i;
  1206 
  1207     if (GLES2_ActivateRenderer(renderer) < 0) {
  1208         return -1;
  1209     }
  1210 
  1211     data->drawstate.target = renderer->target;
  1212     if (!data->drawstate.target) {
  1213         SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh);
  1214     }
  1215 
  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;
  1221     } else {
  1222         data->glBufferSubData(GL_ARRAY_BUFFER, 0, vertsize, vertices);
  1223     }
  1224 
  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;
  1229     }
  1230 
  1231     while (cmd) {
  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);
  1239                 break;
  1240             }
  1241 
  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;
  1247                 }
  1248                 break;
  1249             }
  1250 
  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;
  1256                 }
  1257 
  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;
  1261                 }
  1262                 break;
  1263             }
  1264 
  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;
  1278                 }
  1279 
  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;
  1283                 }
  1284 
  1285                 data->glClear(GL_COLOR_BUFFER_BIT);
  1286                 break;
  1287             }
  1288 
  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);
  1292                 }
  1293                 break;
  1294             }
  1295 
  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));
  1303                     } else {
  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);
  1307                     }
  1308                 }
  1309                 break;
  1310             }
  1311 
  1312             case SDL_RENDERCMD_FILL_RECTS: {
  1313                 const size_t count = cmd->data.draw.count;
  1314                 size_t offset = 0;
  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);
  1318                     }
  1319                 }
  1320                 break;
  1321             }
  1322 
  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);
  1327                 }
  1328                 break;
  1329             }
  1330 
  1331             case SDL_RENDERCMD_NO_OP:
  1332                 break;
  1333         }
  1334 
  1335         cmd = cmd->next;
  1336     }
  1337 
  1338     return GL_CheckError("", renderer);
  1339 }
  1340 
  1341 static void
  1342 GLES2_DestroyRenderer(SDL_Renderer *renderer)
  1343 {
  1344     GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
  1345 
  1346     /* Deallocate everything */
  1347     if (data) {
  1348         GLES2_ActivateRenderer(renderer);
  1349 
  1350         {
  1351             GLES2_ShaderCacheEntry *entry;
  1352             GLES2_ShaderCacheEntry *next;
  1353             entry = data->shader_cache.head;
  1354             while (entry) {
  1355                 data->glDeleteShader(entry->id);
  1356                 next = entry->next;
  1357                 SDL_free(entry);
  1358                 entry = next;
  1359             }
  1360         }
  1361         {
  1362             GLES2_ProgramCacheEntry *entry;
  1363             GLES2_ProgramCacheEntry *next;
  1364             entry = data->program_cache.head;
  1365             while (entry) {
  1366                 data->glDeleteProgram(entry->id);
  1367                 next = entry->next;
  1368                 SDL_free(entry);
  1369                 entry = next;
  1370             }
  1371         }
  1372 
  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;
  1380             }
  1381 
  1382             data->glDeleteBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
  1383             GL_CheckError("", renderer);
  1384 
  1385             SDL_GL_DeleteContext(data->context);
  1386         }
  1387 
  1388         SDL_free(data->shader_formats);
  1389         SDL_free(data);
  1390     }
  1391     SDL_free(renderer);
  1392 }
  1393 
  1394 static int
  1395 GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
  1396 {
  1397     GLES2_RenderData *renderdata = (GLES2_RenderData *)renderer->driverdata;
  1398     GLES2_TextureData *data;
  1399     GLenum format;
  1400     GLenum type;
  1401     GLenum scaleMode;
  1402 
  1403     GLES2_ActivateRenderer(renderer);
  1404 
  1405     renderdata->drawstate.texture = NULL;  /* we trash this state. */
  1406 
  1407     /* Determine the corresponding GLES texture format params */
  1408     switch (texture->format)
  1409     {
  1410     case SDL_PIXELFORMAT_ARGB8888:
  1411     case SDL_PIXELFORMAT_ABGR8888:
  1412     case SDL_PIXELFORMAT_RGB888:
  1413     case SDL_PIXELFORMAT_BGR888:
  1414         format = GL_RGBA;
  1415         type = GL_UNSIGNED_BYTE;
  1416         break;
  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;
  1423         break;
  1424 #ifdef GL_TEXTURE_EXTERNAL_OES
  1425     case SDL_PIXELFORMAT_EXTERNAL_OES:
  1426         format = GL_NONE;
  1427         type = GL_NONE;
  1428         break;
  1429 #endif
  1430     default:
  1431         return SDL_SetError("Texture format not supported");
  1432     }
  1433 
  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");
  1437     }
  1438 
  1439     /* Allocate a texture struct */
  1440     data = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData));
  1441     if (!data) {
  1442         return SDL_OutOfMemory();
  1443     }
  1444     data->texture = 0;
  1445 #ifdef GL_TEXTURE_EXTERNAL_OES
  1446     data->texture_type = (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES) ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
  1447 #else
  1448     data->texture_type = GL_TEXTURE_2D;
  1449 #endif
  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;
  1457 
  1458     /* Allocate a blob for image renderdata */
  1459     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
  1460         size_t size;
  1461         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
  1462         size = texture->h * data->pitch;
  1463         if (data->yuv) {
  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);
  1469         }
  1470         data->pixel_data = SDL_calloc(1, size);
  1471         if (!data->pixel_data) {
  1472             SDL_free(data);
  1473             return SDL_OutOfMemory();
  1474         }
  1475     }
  1476 
  1477     /* Allocate the texture */
  1478     GL_CheckError("", renderer);
  1479 
  1480     if (data->yuv) {
  1481         renderdata->glGenTextures(1, &data->texture_v);
  1482         if (GL_CheckError("glGenTexures()", renderer) < 0) {
  1483             return -1;
  1484         }
  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);
  1492 
  1493         renderdata->glGenTextures(1, &data->texture_u);
  1494         if (GL_CheckError("glGenTexures()", renderer) < 0) {
  1495             return -1;
  1496         }
  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) {
  1505             return -1;
  1506         }
  1507     } else if (data->nv12) {
  1508         renderdata->glGenTextures(1, &data->texture_u);
  1509         if (GL_CheckError("glGenTexures()", renderer) < 0) {
  1510             return -1;
  1511         }
  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) {
  1520             return -1;
  1521         }
  1522     }
  1523 
  1524     renderdata->glGenTextures(1, &data->texture);
  1525     if (GL_CheckError("glGenTexures()", renderer) < 0) {
  1526         return -1;
  1527     }
  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) {
  1538             return -1;
  1539         }
  1540     }
  1541 
  1542     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  1543        data->fbo = GLES2_GetFBO(renderer->driverdata, texture->w, texture->h);
  1544     } else {
  1545        data->fbo = NULL;
  1546     }
  1547 
  1548     return GL_CheckError("", renderer);
  1549 }
  1550 
  1551 static int
  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)
  1553 {
  1554     Uint8 *blob = NULL;
  1555     Uint8 *src;
  1556     int src_pitch;
  1557     int y;
  1558 
  1559     if ((width == 0) || (height == 0) || (bpp == 0)) {
  1560         return 0;  /* nothing to do */
  1561     }
  1562 
  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);
  1568         if (!blob) {
  1569             return SDL_OutOfMemory();
  1570         }
  1571         src = blob;
  1572         for (y = 0; y < height; ++y)
  1573         {
  1574             SDL_memcpy(src, pixels, src_pitch);
  1575             src += src_pitch;
  1576             pixels = (Uint8 *)pixels + pitch;
  1577         }
  1578         src = blob;
  1579     }
  1580 
  1581     data->glTexSubImage2D(target, 0, xoffset, yoffset, width, height, format, type, src);
  1582     if (blob) {
  1583         SDL_free(blob);
  1584     }
  1585     return 0;
  1586 }
  1587 
  1588 static int
  1589 GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
  1590                     const void *pixels, int pitch)
  1591 {
  1592     GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
  1593     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
  1594 
  1595     GLES2_ActivateRenderer(renderer);
  1596 
  1597     /* Bail out if we're supposed to update an empty rectangle */
  1598     if (rect->w <= 0 || rect->h <= 0) {
  1599         return 0;
  1600     }
  1601 
  1602     data->drawstate.texture = NULL;  /* we trash this state. */
  1603 
  1604     /* Create a texture subimage with the supplied data */
  1605     data->glBindTexture(tdata->texture_type, tdata->texture);
  1606     GLES2_TexSubImage2D(data, tdata->texture_type,
  1607                     rect->x,
  1608                     rect->y,
  1609                     rect->w,
  1610                     rect->h,
  1611                     tdata->pixel_format,
  1612                     tdata->pixel_type,
  1613                     pixels, pitch, SDL_BYTESPERPIXEL(texture->format));
  1614 
  1615     if (tdata->yuv) {
  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);
  1620         } else {
  1621             data->glBindTexture(tdata->texture_type, tdata->texture_u);
  1622         }
  1623         GLES2_TexSubImage2D(data, tdata->texture_type,
  1624                 rect->x / 2,
  1625                 rect->y / 2,
  1626                 (rect->w + 1) / 2,
  1627                 (rect->h + 1) / 2,
  1628                 tdata->pixel_format,
  1629                 tdata->pixel_type,
  1630                 pixels, (pitch + 1) / 2, 1);
  1631 
  1632 
  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);
  1637         } else {
  1638             data->glBindTexture(tdata->texture_type, tdata->texture_v);
  1639         }
  1640         GLES2_TexSubImage2D(data, tdata->texture_type,
  1641                 rect->x / 2,
  1642                 rect->y / 2,
  1643                 (rect->w + 1) / 2,
  1644                 (rect->h + 1) / 2,
  1645                 tdata->pixel_format,
  1646                 tdata->pixel_type,
  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,
  1653                 rect->x / 2,
  1654                 rect->y / 2,
  1655                 (rect->w + 1) / 2,
  1656                 (rect->h + 1) / 2,
  1657                 GL_LUMINANCE_ALPHA,
  1658                 GL_UNSIGNED_BYTE,
  1659                 pixels, 2 * ((pitch + 1) / 2), 2);
  1660     }
  1661 
  1662     return GL_CheckError("glTexSubImage2D()", renderer);
  1663 }
  1664 
  1665 static int
  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)
  1671 {
  1672     GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
  1673     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
  1674 
  1675     GLES2_ActivateRenderer(renderer);
  1676 
  1677     /* Bail out if we're supposed to update an empty rectangle */
  1678     if (rect->w <= 0 || rect->h <= 0) {
  1679         return 0;
  1680     }
  1681 
  1682     data->drawstate.texture = NULL;  /* we trash this state. */
  1683 
  1684     data->glBindTexture(tdata->texture_type, tdata->texture_v);
  1685     GLES2_TexSubImage2D(data, tdata->texture_type,
  1686                     rect->x / 2,
  1687                     rect->y / 2,
  1688                     (rect->w + 1) / 2,
  1689                     (rect->h + 1) / 2,
  1690                     tdata->pixel_format,
  1691                     tdata->pixel_type,
  1692                     Vplane, Vpitch, 1);
  1693 
  1694     data->glBindTexture(tdata->texture_type, tdata->texture_u);
  1695     GLES2_TexSubImage2D(data, tdata->texture_type,
  1696                     rect->x / 2,
  1697                     rect->y / 2,
  1698                     (rect->w + 1) / 2,
  1699                     (rect->h + 1) / 2,
  1700                     tdata->pixel_format,
  1701                     tdata->pixel_type,
  1702                     Uplane, Upitch, 1);
  1703 
  1704     data->glBindTexture(tdata->texture_type, tdata->texture);
  1705     GLES2_TexSubImage2D(data, tdata->texture_type,
  1706                     rect->x,
  1707                     rect->y,
  1708                     rect->w,
  1709                     rect->h,
  1710                     tdata->pixel_format,
  1711                     tdata->pixel_type,
  1712                     Yplane, Ypitch, 1);
  1713 
  1714     return GL_CheckError("glTexSubImage2D()", renderer);
  1715 }
  1716 
  1717 static int
  1718 GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
  1719                   void **pixels, int *pitch)
  1720 {
  1721     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
  1722 
  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;
  1728 
  1729     return 0;
  1730 }
  1731 
  1732 static void
  1733 GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
  1734 {
  1735     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
  1736     SDL_Rect rect;
  1737 
  1738     /* We do whole texture updates, at least for now */
  1739     rect.x = 0;
  1740     rect.y = 0;
  1741     rect.w = texture->w;
  1742     rect.h = texture->h;
  1743     GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
  1744 }
  1745 
  1746 static int
  1747 GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
  1748 {
  1749     GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
  1750     GLES2_TextureData *texturedata = NULL;
  1751     GLenum status;
  1752 
  1753     data->drawstate.viewport_dirty = SDL_TRUE;
  1754 
  1755     if (texture == NULL) {
  1756         data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer);
  1757     } else {
  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");
  1766         }
  1767     }
  1768     return 0;
  1769 }
  1770 
  1771 static void
  1772 GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
  1773 {
  1774     GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
  1775     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
  1776 
  1777     GLES2_ActivateRenderer(renderer);
  1778 
  1779     if (data->drawstate.texture == texture) {
  1780         data->drawstate.texture = NULL;
  1781     }
  1782     if (data->drawstate.target == texture) {
  1783         data->drawstate.target = NULL;
  1784     }
  1785 
  1786     /* Destroy the texture */
  1787     if (tdata) {
  1788         data->glDeleteTextures(1, &tdata->texture);
  1789         if (tdata->texture_v) {
  1790             data->glDeleteTextures(1, &tdata->texture_v);
  1791         }
  1792         if (tdata->texture_u) {
  1793             data->glDeleteTextures(1, &tdata->texture_u);
  1794         }
  1795         SDL_free(tdata->pixel_data);
  1796         SDL_free(tdata);
  1797         texture->driverdata = NULL;
  1798     }
  1799 }
  1800 
  1801 static int
  1802 GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1803                     Uint32 pixel_format, void * pixels, int pitch)
  1804 {
  1805     GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
  1806     Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888;
  1807     size_t buflen;
  1808     void *temp_pixels;
  1809     int temp_pitch;
  1810     Uint8 *src, *dst, *tmp;
  1811     int w, h, length, rows;
  1812     int status;
  1813 
  1814     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1815     buflen = rect->h * temp_pitch;
  1816     if (buflen == 0) {
  1817         return 0;  /* nothing to do. */
  1818     }
  1819 
  1820     temp_pixels = SDL_malloc(buflen);
  1821     if (!temp_pixels) {
  1822         return SDL_OutOfMemory();
  1823     }
  1824 
  1825     SDL_GetRendererOutputSize(renderer, &w, &h);
  1826 
  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) {
  1830         return -1;
  1831     }
  1832 
  1833     /* Flip the rows to be top-down if necessary */
  1834     if (!renderer->target) {
  1835         SDL_bool isstack;
  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);
  1840         rows = rect->h / 2;
  1841         while (rows--) {
  1842             SDL_memcpy(tmp, dst, length);
  1843             SDL_memcpy(dst, src, length);
  1844             SDL_memcpy(src, tmp, length);
  1845             dst += temp_pitch;
  1846             src -= temp_pitch;
  1847         }
  1848         SDL_small_free(tmp, isstack);
  1849     }
  1850 
  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);
  1855 
  1856     return status;
  1857 }
  1858 
  1859 static void
  1860 GLES2_RenderPresent(SDL_Renderer *renderer)
  1861 {
  1862     /* Tell the video driver to swap buffers */
  1863     SDL_GL_SwapWindow(renderer->window);
  1864 }
  1865 
  1866 
  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);
  1872 
  1873 static int GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
  1874 {
  1875     GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
  1876     GLES2_TextureData *texturedata = (GLES2_TextureData *)texture->driverdata;
  1877     GLES2_ActivateRenderer(renderer);
  1878 
  1879     data->glBindTexture(texturedata->texture_type, texturedata->texture);
  1880     data->drawstate.texture = texture;
  1881 
  1882     if (texw) {
  1883         *texw = 1.0;
  1884     }
  1885     if (texh) {
  1886         *texh = 1.0;
  1887     }
  1888 
  1889     return 0;
  1890 }
  1891 
  1892 static int GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
  1893 {
  1894     GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
  1895     GLES2_TextureData *texturedata = (GLES2_TextureData *)texture->driverdata;
  1896     GLES2_ActivateRenderer(renderer);
  1897 
  1898     data->glBindTexture(texturedata->texture_type, 0);
  1899     data->drawstate.texture = NULL;
  1900 
  1901     return 0;
  1902 }
  1903 
  1904 
  1905 /*************************************************************************************************
  1906  * Renderer instantiation                                                                        *
  1907  *************************************************************************************************/
  1908 
  1909 #ifdef ZUNE_HD
  1910 #define GL_NVIDIA_PLATFORM_BINARY_NV 0x890B
  1911 #endif
  1912 
  1913 
  1914 static SDL_Renderer *
  1915 GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
  1916 {
  1917     SDL_Renderer *renderer;
  1918     GLES2_RenderData *data;
  1919     GLint nFormats;
  1920 #ifndef ZUNE_HD
  1921     GLboolean hasCompiler;
  1922 #endif
  1923     Uint32 window_flags = 0; /* -Wconditional-uninitialized */
  1924     GLint window_framebuffer;
  1925     GLint value;
  1926     int profile_mask = 0, major = 0, minor = 0;
  1927     SDL_bool changed_window = SDL_FALSE;
  1928 
  1929     if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask) < 0) {
  1930         goto error;
  1931     }
  1932     if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major) < 0) {
  1933         goto error;
  1934     }
  1935     if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor) < 0) {
  1936         goto error;
  1937     }
  1938 
  1939     window_flags = SDL_GetWindowFlags(window);
  1940 
  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) {
  1944 
  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);
  1949 
  1950         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
  1951             goto error;
  1952         }
  1953     }
  1954 
  1955     /* Create the renderer struct */
  1956     renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(SDL_Renderer));
  1957     if (!renderer) {
  1958         SDL_OutOfMemory();
  1959         goto error;
  1960     }
  1961 
  1962     data = (GLES2_RenderData *)SDL_calloc(1, sizeof(GLES2_RenderData));
  1963     if (!data) {
  1964         SDL_free(renderer);
  1965         SDL_OutOfMemory();
  1966         goto error;
  1967     }
  1968     renderer->info = GLES2_RenderDriver.info;
  1969     renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
  1970     renderer->driverdata = data;
  1971     renderer->window = window;
  1972 
  1973     /* Create an OpenGL ES 2.0 context */
  1974     data->context = SDL_GL_CreateContext(window);
  1975     if (!data->context) {
  1976         SDL_free(renderer);
  1977         SDL_free(data);
  1978         goto error;
  1979     }
  1980     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
  1981         SDL_GL_DeleteContext(data->context);
  1982         SDL_free(renderer);
  1983         SDL_free(data);
  1984         goto error;
  1985     }
  1986 
  1987     if (GLES2_LoadFunctions(data) < 0) {
  1988         SDL_GL_DeleteContext(data->context);
  1989         SDL_free(renderer);
  1990         SDL_free(data);
  1991         goto error;
  1992     }
  1993 
  1994 #if __WINRT__
  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.
  1998      */
  1999     flags |= SDL_RENDERER_PRESENTVSYNC;
  2000 #endif
  2001 
  2002     if (flags & SDL_RENDERER_PRESENTVSYNC) {
  2003         SDL_GL_SetSwapInterval(1);
  2004     } else {
  2005         SDL_GL_SetSwapInterval(0);
  2006     }
  2007     if (SDL_GL_GetSwapInterval() > 0) {
  2008         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  2009     }
  2010 
  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;
  2015     }
  2016 
  2017     value = 0;
  2018     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
  2019     renderer->info.max_texture_width = value;
  2020     value = 0;
  2021     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
  2022     renderer->info.max_texture_height = value;
  2023 
  2024     /* Determine supported shader formats */
  2025     /* HACK: glGetInteger is broken on the Zune HD's compositor, so we just hardcode this */
  2026 #ifdef ZUNE_HD
  2027     nFormats = 1;
  2028 #else /* !ZUNE_HD */
  2029     data->glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats);
  2030     data->glGetBooleanv(GL_SHADER_COMPILER, &hasCompiler);
  2031     if (hasCompiler) {
  2032         ++nFormats;
  2033     }
  2034 #endif /* ZUNE_HD */
  2035     data->shader_formats = (GLenum *)SDL_calloc(nFormats, sizeof(GLenum));
  2036     if (!data->shader_formats) {
  2037         GLES2_DestroyRenderer(renderer);
  2038         SDL_OutOfMemory();
  2039         goto error;
  2040     }
  2041     data->shader_format_count = nFormats;
  2042 #ifdef ZUNE_HD
  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);
  2046     if (hasCompiler) {
  2047         data->shader_formats[nFormats - 1] = (GLenum)-1;
  2048     }
  2049 #endif /* ZUNE_HD */
  2050 
  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);
  2053 
  2054     data->framebuffers = NULL;
  2055     data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer);
  2056     data->window_framebuffer = (GLuint)window_framebuffer;
  2057 
  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;
  2082 
  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;
  2089 #endif
  2090 
  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);
  2095 
  2096     data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
  2097     data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
  2098 
  2099     data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  2100 
  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;
  2106 
  2107     GL_CheckError("", renderer);
  2108 
  2109     return renderer;
  2110 
  2111 error:
  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);
  2118     }
  2119     return NULL;
  2120 }
  2121 
  2122 SDL_RenderDriver GLES2_RenderDriver = {
  2123     GLES2_CreateRenderer,
  2124     {
  2125         "opengles2",
  2126         (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
  2127         4,
  2128         {
  2129         SDL_PIXELFORMAT_ARGB8888,
  2130         SDL_PIXELFORMAT_ABGR8888,
  2131         SDL_PIXELFORMAT_RGB888,
  2132         SDL_PIXELFORMAT_BGR888
  2133         },
  2134         0,
  2135         0
  2136     }
  2137 };
  2138 
  2139 #endif /* SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED */
  2140 
  2141 /* vi: set ts=4 sw=4 expandtab: */