src/render/opengles2/SDL_render_gles2.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 15 Feb 2011 13:59:59 -0800
changeset 5297 1800dc39b74c
parent 5276 8e421890cdb8
child 5332 ae8b6fb1feaf
permissions -rw-r--r--
Changed the concept of a render clip rect to a render viewport.
The render viewport is automatically re-centered when the window changes size, so applications that don't care will not have to handle recalculating their rendering coordinates.

Fixed API for drawing and filling multiple rectangles - the parameter should be an array of rects, not an array of pointers to rects.

Fixed API for updating window rects for consistency with other APIs - the order is pointer to array followed by count in array.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4     Copyright (C) 2010 itsnotabigtruck.
     5 
     6     This library is free software; you can redistribute it and/or
     7     modify it under the terms of the GNU Lesser General Public
     8     License as published by the Free Software Foundation; either
     9     version 2.1 of the License, or (at your option) any later version.
    10 
    11     This library is distributed in the hope that it will be useful,
    12     but WITHOUT ANY WARRANTY; without even the implied warranty of
    13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    14     Lesser General Public License for more details.
    15 
    16     You should have received a copy of the GNU Lesser General Public
    17     License along with this library; if not, write to the Free Software
    18     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    19 
    20     Sam Lantinga
    21     slouken@libsdl.org
    22 */
    23 #include "SDL_config.h"
    24 
    25 #if SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED
    26 
    27 #include "SDL_opengles2.h"
    28 #include "../SDL_sysrender.h"
    29 #include "SDL_shaders_gles2.h"
    30 
    31 /*************************************************************************************************
    32  * Bootstrap data                                                                                *
    33  *************************************************************************************************/
    34 
    35 static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, Uint32 flags);
    36 
    37 SDL_RenderDriver GLES2_RenderDriver = {
    38     GLES2_CreateRenderer,
    39     {
    40         "opengles2",
    41         (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
    42         1,
    43         {SDL_PIXELFORMAT_ABGR8888},
    44         0,
    45         0
    46     }
    47 };
    48 
    49 /*************************************************************************************************
    50  * Context structures                                                                            *
    51  *************************************************************************************************/
    52 
    53 typedef struct GLES2_TextureData
    54 {
    55     GLenum texture;
    56     GLenum texture_type;
    57     GLenum pixel_format;
    58     GLenum pixel_type;
    59     void *pixel_data;
    60     size_t pitch;
    61 } GLES2_TextureData;
    62 
    63 typedef struct GLES2_ShaderCacheEntry
    64 {
    65     GLuint id;
    66     GLES2_ShaderType type;
    67     const GLES2_ShaderInstance *instance;
    68     int references;
    69     struct GLES2_ShaderCacheEntry *prev;
    70     struct GLES2_ShaderCacheEntry *next;
    71 } GLES2_ShaderCacheEntry;
    72 
    73 typedef struct GLES2_ShaderCache
    74 {
    75     int count;
    76     GLES2_ShaderCacheEntry *head;
    77 } GLES2_ShaderCache;
    78 
    79 typedef struct GLES2_ProgramCacheEntry
    80 {
    81     GLuint id;
    82     SDL_BlendMode blend_mode;
    83     GLES2_ShaderCacheEntry *vertex_shader;
    84     GLES2_ShaderCacheEntry *fragment_shader;
    85     GLuint uniform_locations[16];
    86     struct GLES2_ProgramCacheEntry *prev;
    87     struct GLES2_ProgramCacheEntry *next;
    88 } GLES2_ProgramCacheEntry;
    89 
    90 typedef struct GLES2_ProgramCache
    91 {
    92     int count;
    93     GLES2_ProgramCacheEntry *head;
    94     GLES2_ProgramCacheEntry *tail;
    95 } GLES2_ProgramCache;
    96 
    97 typedef enum
    98 {
    99     GLES2_ATTRIBUTE_POSITION = 0,
   100     GLES2_ATTRIBUTE_TEXCOORD = 1
   101 } GLES2_Attribute;
   102 
   103 typedef enum
   104 {
   105     GLES2_UNIFORM_PROJECTION,
   106     GLES2_UNIFORM_TEXTURE,
   107     GLES2_UNIFORM_MODULATION,
   108     GLES2_UNIFORM_COLOR,
   109     GLES2_UNIFORM_COLORTABLE
   110 } GLES2_Uniform;
   111 
   112 typedef enum
   113 {
   114     GLES2_IMAGESOURCE_SOLID,
   115     GLES2_IMAGESOURCE_TEXTURE
   116 } GLES2_ImageSource;
   117 
   118 typedef struct GLES2_DriverContext
   119 {
   120     SDL_GLContext *context;
   121     int shader_format_count;
   122     GLenum *shader_formats;
   123     GLES2_ShaderCache shader_cache;
   124     GLES2_ProgramCache program_cache;
   125     GLES2_ProgramCacheEntry *current_program;
   126 } GLES2_DriverContext;
   127 
   128 #define GLES2_MAX_CACHED_PROGRAMS 8
   129 
   130 /*************************************************************************************************
   131  * Renderer state APIs                                                                           *
   132  *************************************************************************************************/
   133 
   134 static int GLES2_ActivateRenderer(SDL_Renderer *renderer);
   135 static void GLES2_WindowEvent(SDL_Renderer * renderer,
   136                               const SDL_WindowEvent *event);
   137 static int GLES2_UpdateViewport(SDL_Renderer * renderer);
   138 static void GLES2_DestroyRenderer(SDL_Renderer *renderer);
   139 
   140 static SDL_GLContext SDL_CurrentContext = NULL;
   141 
   142 static int
   143 GLES2_ActivateRenderer(SDL_Renderer * renderer)
   144 {
   145     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   146 
   147     if (SDL_CurrentContext != rdata->context) {
   148         /* Null out the current program to ensure we set it again */
   149         rdata->current_program = NULL;
   150 
   151         if (SDL_GL_MakeCurrent(renderer->window, rdata->context) < 0) {
   152             return -1;
   153         }
   154         SDL_CurrentContext = rdata->context;
   155 
   156         GLES2_UpdateViewport(renderer);
   157     }
   158     return 0;
   159 }
   160 
   161 static void
   162 GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   163 {
   164     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   165 
   166     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   167         /* Rebind the context to the window area */
   168         SDL_CurrentContext = NULL;
   169     }
   170 }
   171 
   172 static int
   173 GLES2_UpdateViewport(SDL_Renderer * renderer)
   174 {
   175     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   176 
   177     if (SDL_CurrentContext != rdata->context) {
   178         /* We'll update the viewport after we rebind the context */
   179         return 0;
   180     }
   181 
   182     glViewport(renderer->viewport.x, renderer->viewport.y,
   183                renderer->viewport.w, renderer->viewport.h);
   184     return 0;
   185 }
   186 
   187 static void
   188 GLES2_DestroyRenderer(SDL_Renderer *renderer)
   189 {
   190     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   191     GLES2_ProgramCacheEntry *entry;
   192     GLES2_ProgramCacheEntry *next;
   193 
   194     /* Deallocate everything */
   195     if (rdata) {
   196         GLES2_ActivateRenderer(renderer);
   197 
   198         entry = rdata->program_cache.head;
   199         while (entry) {
   200             glDeleteShader(entry->vertex_shader->id);
   201             glDeleteShader(entry->fragment_shader->id);
   202             SDL_free(entry->vertex_shader);
   203             SDL_free(entry->fragment_shader);
   204             glDeleteProgram(entry->id);
   205             next = entry->next;
   206             SDL_free(entry);
   207             entry = next;
   208         }
   209         if (rdata->context) {
   210             SDL_GL_DeleteContext(rdata->context);
   211         }
   212         if (rdata->shader_formats) {
   213             SDL_free(rdata->shader_formats);
   214         }
   215         SDL_free(rdata);
   216     }
   217     SDL_free(renderer);
   218 }
   219 
   220 /*************************************************************************************************
   221  * Texture APIs                                                                                  *
   222  *************************************************************************************************/
   223 
   224 static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture);
   225 static void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
   226 static int GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
   227                              void **pixels, int *pitch);
   228 static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture);
   229 static int GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
   230                                const void *pixels, int pitch);
   231 
   232 static int
   233 GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
   234 {
   235     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   236     GLES2_TextureData *tdata;
   237     GLenum format;
   238     GLenum type;
   239 
   240     GLES2_ActivateRenderer(renderer);
   241 
   242     /* Determine the corresponding GLES texture format params */
   243     switch (texture->format)
   244     {
   245     case SDL_PIXELFORMAT_ABGR8888:
   246         format = GL_RGBA;
   247         type = GL_UNSIGNED_BYTE;
   248         break;
   249     default:
   250         SDL_SetError("Texture format not supported");
   251         return -1;
   252     }
   253 
   254     /* Allocate a texture struct */
   255     tdata = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData));
   256     if (!tdata)
   257     {
   258         SDL_OutOfMemory();
   259         return -1;
   260     }
   261     tdata->texture = 0;
   262     tdata->texture_type = GL_TEXTURE_2D;
   263     tdata->pixel_format = format;
   264     tdata->pixel_type = type;
   265 
   266     /* Allocate a blob for image data */
   267     if (texture->access == SDL_TEXTUREACCESS_STREAMING)
   268     {
   269         tdata->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   270         tdata->pixel_data = SDL_malloc(tdata->pitch * texture->h);
   271         if (!tdata->pixel_data)
   272         {
   273             SDL_OutOfMemory();
   274             SDL_free(tdata);
   275             return -1;
   276         }
   277     }
   278 
   279     /* Allocate the texture */
   280     glGetError();
   281     glGenTextures(1, &tdata->texture);
   282     glActiveTexture(GL_TEXTURE0);
   283     glBindTexture(tdata->texture_type, tdata->texture);
   284     glTexParameteri(tdata->texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   285     glTexParameteri(tdata->texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   286     glTexParameteri(tdata->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   287     glTexParameteri(tdata->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   288     glTexImage2D(tdata->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);
   289     if (glGetError() != GL_NO_ERROR)
   290     {
   291         SDL_SetError("Texture creation failed");
   292         glDeleteTextures(1, &tdata->texture);
   293         SDL_free(tdata);
   294         return -1;
   295     }
   296     texture->driverdata = tdata;
   297     return 0;
   298 }
   299 
   300 static void
   301 GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
   302 {
   303     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   304 
   305     GLES2_ActivateRenderer(renderer);
   306 
   307     /* Destroy the texture */
   308     if (tdata)
   309     {
   310         glDeleteTextures(1, &tdata->texture);
   311         SDL_free(tdata->pixel_data);
   312         SDL_free(tdata);
   313         texture->driverdata = NULL;
   314     }
   315 }
   316 
   317 static int
   318 GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
   319                   void **pixels, int *pitch)
   320 {
   321     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   322 
   323     /* Retrieve the buffer/pitch for the specified region */
   324     *pixels = (Uint8 *)tdata->pixel_data +
   325               (tdata->pitch * rect->y) +
   326               (rect->x * SDL_BYTESPERPIXEL(texture->format));
   327     *pitch = tdata->pitch;
   328 
   329     return 0;
   330 }
   331 
   332 static void
   333 GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
   334 {
   335     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   336     SDL_Rect rect;
   337 
   338     /* We do whole texture updates, at least for now */
   339     rect.x = 0;
   340     rect.y = 0;
   341     rect.w = texture->w;
   342     rect.h = texture->h;
   343     GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
   344 }
   345 
   346 static int
   347 GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
   348                     const void *pixels, int pitch)
   349 {
   350     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   351     Uint8 *blob = NULL;
   352     Uint8 *src;
   353     int srcPitch;
   354     int y;
   355 
   356     GLES2_ActivateRenderer(renderer);
   357 
   358     /* Bail out if we're supposed to update an empty rectangle */
   359     if (rect->w <= 0 || rect->h <= 0)
   360         return 0;
   361 
   362     /* Reformat the texture data into a tightly packed array */
   363     srcPitch = rect->w * SDL_BYTESPERPIXEL(texture->format);
   364     src = (Uint8 *)pixels;
   365     if (pitch != srcPitch)
   366     {
   367         blob = (Uint8 *)SDL_malloc(srcPitch * rect->h);
   368         if (!blob)
   369         {
   370             SDL_OutOfMemory();
   371             return -1;
   372         }
   373         src = blob;
   374         for (y = 0; y < rect->h; ++y)
   375         {
   376             SDL_memcpy(src, pixels, srcPitch);
   377             src += srcPitch;
   378             pixels = (Uint8 *)pixels + pitch;
   379         }
   380         src = blob;
   381     }
   382 
   383     /* Create a texture subimage with the supplied data */
   384     glGetError();
   385     glActiveTexture(GL_TEXTURE0);
   386     glBindTexture(tdata->texture_type, tdata->texture);
   387     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   388     glTexSubImage2D(tdata->texture_type,
   389                     0,
   390                     rect->x,
   391                     rect->y,
   392                     rect->w,
   393                     rect->h,
   394                     tdata->pixel_format,
   395                     tdata->pixel_type,
   396                     src);
   397     if (blob) {
   398         SDL_free(blob);
   399     }
   400 
   401     if (glGetError() != GL_NO_ERROR)
   402     {
   403         SDL_SetError("Failed to update texture");
   404         return -1;
   405     }
   406     return 0;
   407 }
   408 
   409 /*************************************************************************************************
   410  * Shader management functions                                                                   *
   411  *************************************************************************************************/
   412 
   413 static GLES2_ShaderCacheEntry *GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type,
   414                                                  SDL_BlendMode blendMode);
   415 static void GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry);
   416 static GLES2_ProgramCacheEntry *GLES2_CacheProgram(SDL_Renderer *renderer,
   417                                                    GLES2_ShaderCacheEntry *vertex,
   418                                                    GLES2_ShaderCacheEntry *fragment,
   419                                                    SDL_BlendMode blendMode);
   420 static int GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source,
   421                                SDL_BlendMode blendMode);
   422 static int GLES2_SetOrthographicProjection(SDL_Renderer *renderer);
   423 
   424 static GLES2_ProgramCacheEntry *
   425 GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
   426                    GLES2_ShaderCacheEntry *fragment, SDL_BlendMode blendMode)
   427 {
   428     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   429     GLES2_ProgramCacheEntry *entry;
   430     GLES2_ShaderCacheEntry *shaderEntry;
   431     GLint linkSuccessful;
   432 
   433     /* Check if we've already cached this program */
   434     entry = rdata->program_cache.head;
   435     while (entry)
   436     {
   437         if (entry->vertex_shader == vertex && entry->fragment_shader == fragment)
   438             break;
   439         entry = entry->next;
   440     }
   441     if (entry)
   442     {
   443         if (rdata->program_cache.count > 1)
   444         {
   445             if (entry->next)
   446                 entry->next->prev = entry->prev;
   447             if (entry->prev)
   448                 entry->prev->next = entry->next;
   449             entry->prev = NULL;
   450             entry->next = rdata->program_cache.head;
   451             rdata->program_cache.head->prev = entry;
   452             rdata->program_cache.head = entry;
   453         }
   454         return entry;
   455     }
   456 
   457     /* Create a program cache entry */
   458     entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry));
   459     if (!entry)
   460     {
   461         SDL_OutOfMemory();
   462         return NULL;
   463     }
   464     entry->vertex_shader = vertex;
   465     entry->fragment_shader = fragment;
   466     entry->blend_mode = blendMode;
   467     
   468     /* Create the program and link it */
   469     glGetError();
   470     entry->id = glCreateProgram();
   471     glAttachShader(entry->id, vertex->id);
   472     glAttachShader(entry->id, fragment->id);
   473     glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_POSITION, "a_position");
   474     glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord");
   475     glLinkProgram(entry->id);
   476     glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful);
   477     if (glGetError() != GL_NO_ERROR || !linkSuccessful)
   478     {
   479         SDL_SetError("Failed to link shader program");
   480         glDeleteProgram(entry->id);
   481         SDL_free(entry);
   482         return NULL;
   483     }
   484     
   485     /* Predetermine locations of uniform variables */
   486     entry->uniform_locations[GLES2_UNIFORM_PROJECTION] =
   487         glGetUniformLocation(entry->id, "u_projection");
   488     entry->uniform_locations[GLES2_UNIFORM_TEXTURE] =
   489         glGetUniformLocation(entry->id, "u_texture");
   490     entry->uniform_locations[GLES2_UNIFORM_MODULATION] =
   491         glGetUniformLocation(entry->id, "u_modulation");
   492     entry->uniform_locations[GLES2_UNIFORM_COLOR] =
   493         glGetUniformLocation(entry->id, "u_color");
   494     entry->uniform_locations[GLES2_UNIFORM_COLORTABLE] =
   495         glGetUniformLocation(entry->id, "u_colorTable");
   496 
   497     /* Cache the linked program */
   498     if (rdata->program_cache.head)
   499     {
   500         entry->next = rdata->program_cache.head;
   501         rdata->program_cache.head->prev = entry;
   502     }
   503     else
   504     {
   505         rdata->program_cache.tail = entry;
   506     }
   507     rdata->program_cache.head = entry;
   508     ++rdata->program_cache.count;
   509 
   510     /* Increment the refcount of the shaders we're using */
   511     ++vertex->references;
   512     ++fragment->references;
   513 
   514     /* Evict the last entry from the cache if we exceed the limit */
   515     if (rdata->program_cache.count > GLES2_MAX_CACHED_PROGRAMS)
   516     {
   517         shaderEntry = rdata->program_cache.tail->vertex_shader;
   518         if (--shaderEntry->references <= 0)
   519             GLES2_EvictShader(renderer, shaderEntry);
   520         shaderEntry = rdata->program_cache.tail->fragment_shader;
   521         if (--shaderEntry->references <= 0)
   522             GLES2_EvictShader(renderer, shaderEntry);
   523         glDeleteProgram(rdata->program_cache.tail->id);
   524         rdata->program_cache.tail = rdata->program_cache.tail->prev;
   525         SDL_free(rdata->program_cache.tail->next);
   526         rdata->program_cache.tail->next = NULL;
   527         --rdata->program_cache.count;
   528     }
   529     return entry;
   530 }
   531 
   532 static GLES2_ShaderCacheEntry *
   533 GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode blendMode)
   534 {
   535     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   536     const GLES2_Shader *shader;
   537     const GLES2_ShaderInstance *instance = NULL;
   538     GLES2_ShaderCacheEntry *entry = NULL;
   539     GLint compileSuccessful = GL_FALSE;
   540     int i, j;
   541 
   542     /* Find the corresponding shader */
   543     shader = GLES2_GetShader(type, blendMode);
   544     if (!shader)
   545     {
   546         SDL_SetError("No shader matching the requested characteristics was found");
   547         return NULL;
   548     }
   549     
   550     /* Find a matching shader instance that's supported on this hardware */
   551     for (i = 0; i < shader->instance_count && !instance; ++i)
   552     {
   553         for (j = 0; j < rdata->shader_format_count && !instance; ++j)
   554         {
   555             if (!shader->instances)
   556                 continue;
   557             if (!shader->instances[i])
   558                 continue;
   559             if (shader->instances[i]->format != rdata->shader_formats[j])
   560                 continue;
   561             instance = shader->instances[i];
   562         }
   563     }
   564     if (!instance)
   565     {
   566         SDL_SetError("The specified shader cannot be loaded on the current platform");
   567         return NULL;
   568     }
   569 
   570     /* Check if we've already cached this shader */
   571     entry = rdata->shader_cache.head;
   572     while (entry)
   573     {
   574         if (entry->instance == instance)
   575             break;
   576         entry = entry->next;
   577     }
   578     if (entry)
   579         return entry;
   580 
   581     /* Create a shader cache entry */
   582     entry = (GLES2_ShaderCacheEntry *)SDL_calloc(1, sizeof(GLES2_ShaderCacheEntry));
   583     if (!entry)
   584     {
   585         SDL_OutOfMemory();
   586         return NULL;
   587     }
   588     entry->type = type;
   589     entry->instance = instance;
   590 
   591     /* Compile or load the selected shader instance */
   592     glGetError();
   593     entry->id = glCreateShader(instance->type);
   594     if (instance->format == (GLenum)-1)
   595     {
   596         glShaderSource(entry->id, 1, (const char **)&instance->data, NULL);
   597         glCompileShader(entry->id);
   598         glGetShaderiv(entry->id, GL_COMPILE_STATUS, &compileSuccessful);
   599     }
   600     else
   601     {
   602         glShaderBinary(1, &entry->id, instance->format, instance->data, instance->length);
   603         compileSuccessful = GL_TRUE;
   604     }
   605     if (glGetError() != GL_NO_ERROR || !compileSuccessful)
   606     {
   607         char *info = NULL;
   608         int length;
   609 
   610         glGetShaderiv(entry->id, GL_INFO_LOG_LENGTH, &length);
   611         if (length > 0) {
   612             info = SDL_stack_alloc(char, length);
   613             if (info) {
   614                 glGetShaderInfoLog(entry->id, length, &length, info);
   615             }
   616         }
   617         if (info) {
   618             SDL_SetError("Failed to load the shader: %s", info);
   619             SDL_stack_free(info);
   620         } else {
   621             SDL_SetError("Failed to load the shader");
   622         }
   623         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 (rdata->shader_cache.head)
   630     {
   631         entry->next = rdata->shader_cache.head;
   632         rdata->shader_cache.head->prev = entry;
   633     }
   634     rdata->shader_cache.head = entry;
   635     ++rdata->shader_cache.count;
   636     return entry;
   637 }
   638 
   639 static void
   640 GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry)
   641 {
   642     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   643 
   644     /* Unlink the shader from the cache */
   645     if (entry->next)
   646         entry->next->prev = entry->prev;
   647     if (entry->prev)
   648         entry->prev->next = entry->next;
   649     if (rdata->shader_cache.head == entry)
   650         rdata->shader_cache.head = entry->next;
   651     --rdata->shader_cache.count;
   652 
   653     /* Deallocate the shader */
   654     glDeleteShader(entry->id);
   655     SDL_free(entry);
   656 }
   657 
   658 static int
   659 GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendMode blendMode)
   660 {
   661     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   662     GLES2_ShaderCacheEntry *vertex = NULL;
   663     GLES2_ShaderCacheEntry *fragment = NULL;
   664     GLES2_ShaderType vtype, ftype;
   665     GLES2_ProgramCacheEntry *program;
   666 
   667     /* Select an appropriate shader pair for the specified modes */
   668     vtype = GLES2_SHADER_VERTEX_DEFAULT;
   669     switch (source)
   670     {
   671     case GLES2_IMAGESOURCE_SOLID:
   672         ftype = GLES2_SHADER_FRAGMENT_SOLID_SRC;
   673         break;
   674     case GLES2_IMAGESOURCE_TEXTURE:
   675         ftype = GLES2_SHADER_FRAGMENT_TEXTURE_SRC;
   676         break;
   677     }
   678 
   679     /* Load the requested shaders */
   680     vertex = GLES2_CacheShader(renderer, vtype, blendMode);
   681     if (!vertex)
   682         goto fault;
   683     fragment = GLES2_CacheShader(renderer, ftype, blendMode);
   684     if (!fragment)
   685         goto fault;
   686 
   687     /* Check if we need to change programs at all */
   688     if (rdata->current_program &&
   689         rdata->current_program->vertex_shader == vertex &&
   690         rdata->current_program->fragment_shader == fragment)
   691         return 0;
   692 
   693     /* Generate a matching program */
   694     program = GLES2_CacheProgram(renderer, vertex, fragment, blendMode);
   695     if (!program)
   696         goto fault;
   697 
   698     /* Select that program in OpenGL */
   699     glGetError();
   700     glUseProgram(program->id);
   701     if (glGetError() != GL_NO_ERROR)
   702     {
   703         SDL_SetError("Failed to select program");
   704         goto fault;
   705     }
   706 
   707     /* Set the current program */
   708     rdata->current_program = program;
   709 
   710     /* Activate an orthographic projection */
   711     if (GLES2_SetOrthographicProjection(renderer) < 0)
   712         goto fault;
   713 
   714     /* Clean up and return */
   715     return 0;
   716 fault:
   717     if (vertex && vertex->references <= 0)
   718         GLES2_EvictShader(renderer, vertex);
   719     if (fragment && fragment->references <= 0)
   720         GLES2_EvictShader(renderer, fragment);
   721     rdata->current_program = NULL;
   722     return -1;
   723 }
   724 
   725 static int
   726 GLES2_SetOrthographicProjection(SDL_Renderer *renderer)
   727 {
   728     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   729     GLfloat projection[4][4];
   730     GLuint locProjection;
   731 
   732     /* Prepare an orthographic projection */
   733     projection[0][0] = 2.0f / renderer->viewport.w;
   734     projection[0][1] = 0.0f;
   735     projection[0][2] = 0.0f;
   736     projection[0][3] = 0.0f;
   737     projection[1][0] = 0.0f;
   738     projection[1][1] = -2.0f / renderer->viewport.h;
   739     projection[1][2] = 0.0f;
   740     projection[1][3] = 0.0f;
   741     projection[2][0] = 0.0f;
   742     projection[2][1] = 0.0f;
   743     projection[2][2] = 1.0f;
   744     projection[2][3] = 0.0f;
   745     projection[3][0] = -1.0f;
   746     projection[3][1] = 1.0f;
   747     projection[3][2] = 0.0f;
   748     projection[3][3] = 1.0f;
   749 
   750     /* Set the projection matrix */
   751     locProjection = rdata->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION];
   752     glGetError();
   753     glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection);
   754     if (glGetError() != GL_NO_ERROR)
   755     {
   756         SDL_SetError("Failed to set orthographic projection");
   757         return -1;
   758     }
   759     return 0;
   760 }
   761 
   762 /*************************************************************************************************
   763  * Rendering functions                                                                           *
   764  *************************************************************************************************/
   765 
   766 static const float inv255f = 1.0f / 255.0f;
   767 
   768 static int GLES2_RenderClear(SDL_Renderer *renderer);
   769 static int GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count);
   770 static int GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points, int count);
   771 static int GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect *rects, int count);
   772 static int GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
   773                             const SDL_Rect *dstrect);
   774 static void GLES2_RenderPresent(SDL_Renderer *renderer);
   775 
   776 static int
   777 GLES2_RenderClear(SDL_Renderer *renderer)
   778 {
   779     float r = (float)renderer->r * inv255f;
   780     float g = (float)renderer->g * inv255f;
   781     float b = (float)renderer->b * inv255f;
   782     float a = (float)renderer->a * inv255f;
   783 
   784     GLES2_ActivateRenderer(renderer);
   785 
   786     /* Clear the backbuffer with the selected color */
   787     glClearColor(r, g, b, a);
   788     glClear(GL_COLOR_BUFFER_BIT);
   789     return 0;
   790 }
   791 
   792 static void
   793 GLES2_SetBlendMode(int blendMode)
   794 {
   795     switch (blendMode)
   796     {
   797     case SDL_BLENDMODE_NONE:
   798     default:
   799         glDisable(GL_BLEND);
   800         break;
   801     case SDL_BLENDMODE_BLEND:
   802         glEnable(GL_BLEND);
   803         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   804         break;
   805     case SDL_BLENDMODE_ADD:
   806         glEnable(GL_BLEND);
   807         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   808         break;
   809     case SDL_BLENDMODE_MOD:
   810         glEnable(GL_BLEND);
   811         glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   812         break;
   813     }
   814 }
   815 
   816 static int
   817 GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count)
   818 {
   819     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   820     GLfloat *vertices;
   821     SDL_BlendMode blendMode;
   822     int alpha;
   823     GLuint locColor;
   824     int idx;
   825 
   826     GLES2_ActivateRenderer(renderer);
   827 
   828     blendMode = renderer->blendMode;
   829     alpha = renderer->a;
   830 
   831     /* Activate an appropriate shader and set the projection matrix */
   832     if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0)
   833         return -1;
   834 
   835     /* Select the color to draw with */
   836     locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR];
   837     glGetError();
   838     glUniform4f(locColor,
   839                 renderer->r * inv255f,
   840                 renderer->g * inv255f,
   841                 renderer->b * inv255f,
   842                 alpha * inv255f);
   843 
   844     /* Configure the correct blend mode */
   845     GLES2_SetBlendMode(blendMode);
   846 
   847     /* Emit the specified vertices as points */
   848     vertices = SDL_stack_alloc(GLfloat, count * 2);
   849     for (idx = 0; idx < count; ++idx)
   850     {
   851         GLfloat x = (GLfloat)points[idx].x + 0.5f;
   852         GLfloat y = (GLfloat)points[idx].y + 0.5f;
   853 
   854         vertices[idx * 2] = x;
   855         vertices[(idx * 2) + 1] = y;
   856     }
   857     glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
   858     glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
   859     glDrawArrays(GL_POINTS, 0, count);
   860     glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
   861     SDL_stack_free(vertices);
   862     if (glGetError() != GL_NO_ERROR)
   863     {
   864         SDL_SetError("Failed to render lines");
   865         return -1;
   866     }
   867     return 0;
   868 }
   869 
   870 static int
   871 GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points, int count)
   872 {
   873     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   874     GLfloat *vertices;
   875     SDL_BlendMode blendMode;
   876     int alpha;
   877     GLuint locColor;
   878     int idx;
   879 
   880     GLES2_ActivateRenderer(renderer);
   881 
   882     blendMode = renderer->blendMode;
   883     alpha = renderer->a;
   884 
   885     /* Activate an appropriate shader and set the projection matrix */
   886     if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0)
   887         return -1;
   888 
   889     /* Select the color to draw with */
   890     locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR];
   891     glGetError();
   892     glUniform4f(locColor,
   893                 renderer->r * inv255f,
   894                 renderer->g * inv255f,
   895                 renderer->b * inv255f,
   896                 alpha * inv255f);
   897 
   898     /* Configure the correct blend mode */
   899     GLES2_SetBlendMode(blendMode);
   900 
   901     /* Emit a line strip including the specified vertices */
   902     vertices = SDL_stack_alloc(GLfloat, count * 2);
   903     for (idx = 0; idx < count; ++idx)
   904     {
   905         GLfloat x = (GLfloat)points[idx].x + 0.5f;
   906         GLfloat y = (GLfloat)points[idx].y + 0.5f;
   907 
   908         vertices[idx * 2] = x;
   909         vertices[(idx * 2) + 1] = y;
   910     }
   911     glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
   912     glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
   913     glDrawArrays(GL_LINE_STRIP, 0, count);
   914     glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
   915     SDL_stack_free(vertices);
   916     if (glGetError() != GL_NO_ERROR)
   917     {
   918         SDL_SetError("Failed to render lines");
   919         return -1;
   920     }
   921     return 0;
   922 }
   923 
   924 static int
   925 GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect *rects, int count)
   926 {
   927     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   928     GLfloat vertices[8];
   929     SDL_BlendMode blendMode;
   930     int alpha;
   931     GLuint locColor;
   932     int idx;
   933 
   934     GLES2_ActivateRenderer(renderer);
   935 
   936     blendMode = renderer->blendMode;
   937     alpha = renderer->a;
   938 
   939     /* Activate an appropriate shader and set the projection matrix */
   940     if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0)
   941         return -1;
   942 
   943     /* Select the color to draw with */
   944     locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR];
   945     glGetError();
   946     glUniform4f(locColor,
   947                 renderer->r * inv255f,
   948                 renderer->g * inv255f,
   949                 renderer->b * inv255f,
   950                 alpha * inv255f);
   951 
   952     /* Configure the correct blend mode */
   953     GLES2_SetBlendMode(blendMode);
   954 
   955     /* Emit a line loop for each rectangle */
   956     glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
   957     for (idx = 0; idx < count; ++idx) {
   958         const SDL_Rect *rect = &rects[idx];
   959 
   960         GLfloat xMin = (GLfloat)rect->x;
   961         GLfloat xMax = (GLfloat)(rect->x + rect->w);
   962         GLfloat yMin = (GLfloat)rect->y;
   963         GLfloat yMax = (GLfloat)(rect->y + rect->h);
   964 
   965         vertices[0] = xMin;
   966         vertices[1] = yMin;
   967         vertices[2] = xMax;
   968         vertices[3] = yMin;
   969         vertices[4] = xMin;
   970         vertices[5] = yMax;
   971         vertices[6] = xMax;
   972         vertices[7] = yMax;
   973         glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
   974         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   975     }
   976     glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
   977     if (glGetError() != GL_NO_ERROR)
   978     {
   979         SDL_SetError("Failed to render lines");
   980         return -1;
   981     }
   982     return 0;
   983 }
   984 
   985 static int
   986 GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
   987                  const SDL_Rect *dstrect)
   988 {
   989     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   990     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   991     GLES2_ImageSource sourceType;
   992     SDL_BlendMode blendMode;
   993     int alpha;
   994     GLfloat vertices[8];
   995     GLfloat texCoords[8];
   996     GLuint locTexture;
   997     GLuint locModulation;
   998     GLuint locColorTable;
   999 
  1000     GLES2_ActivateRenderer(renderer);
  1001 
  1002     /* Activate an appropriate shader and set the projection matrix */
  1003     blendMode = texture->blendMode;
  1004     alpha = texture->a;
  1005     sourceType = GLES2_IMAGESOURCE_TEXTURE;
  1006     if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0)
  1007         return -1;
  1008 
  1009     /* Select the target texture */
  1010     locTexture = rdata->current_program->uniform_locations[GLES2_UNIFORM_TEXTURE];
  1011     glGetError();
  1012     glActiveTexture(GL_TEXTURE0);
  1013     glBindTexture(tdata->texture_type, tdata->texture);
  1014     glUniform1i(locTexture, 0);
  1015 
  1016     /* Configure texture blending */
  1017     GLES2_SetBlendMode(blendMode);
  1018 
  1019     /* Configure color modulation */
  1020     locModulation = rdata->current_program->uniform_locations[GLES2_UNIFORM_MODULATION];
  1021     glUniform4f(locModulation,
  1022                 texture->r * inv255f,
  1023                 texture->g * inv255f,
  1024                 texture->b * inv255f,
  1025                 alpha * inv255f);
  1026 
  1027     /* Emit the textured quad */
  1028     glEnableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
  1029     glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
  1030     vertices[0] = (GLfloat)dstrect->x;
  1031     vertices[1] = (GLfloat)dstrect->y;
  1032     vertices[2] = (GLfloat)(dstrect->x + dstrect->w);
  1033     vertices[3] = (GLfloat)dstrect->y;
  1034     vertices[4] = (GLfloat)dstrect->x;
  1035     vertices[5] = (GLfloat)(dstrect->y + dstrect->h);
  1036     vertices[6] = (GLfloat)(dstrect->x + dstrect->w);
  1037     vertices[7] = (GLfloat)(dstrect->y + dstrect->h);
  1038     glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
  1039     texCoords[0] = srcrect->x / (GLfloat)texture->w;
  1040     texCoords[1] = srcrect->y / (GLfloat)texture->h;
  1041     texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
  1042     texCoords[3] = srcrect->y / (GLfloat)texture->h;
  1043     texCoords[4] = srcrect->x / (GLfloat)texture->w;
  1044     texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
  1045     texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
  1046     texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
  1047     glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
  1048     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  1049     glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
  1050     glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
  1051     if (glGetError() != GL_NO_ERROR)
  1052     {
  1053         SDL_SetError("Failed to render texture");
  1054         return -1;
  1055     }
  1056     return 0;
  1057 }
  1058 
  1059 static void
  1060 GLES2_RenderPresent(SDL_Renderer *renderer)
  1061 {
  1062     GLES2_ActivateRenderer(renderer);
  1063 
  1064     /* Tell the video driver to swap buffers */
  1065     SDL_GL_SwapWindow(renderer->window);
  1066 }
  1067 
  1068 /*************************************************************************************************
  1069  * Renderer instantiation                                                                        *
  1070  *************************************************************************************************/
  1071 
  1072 #define GL_NVIDIA_PLATFORM_BINARY_NV 0x890B
  1073 
  1074 static SDL_Renderer *
  1075 GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
  1076 {
  1077     SDL_Renderer *renderer;
  1078     GLES2_DriverContext *rdata;
  1079     GLint nFormats;
  1080 #ifndef ZUNE_HD
  1081     GLboolean hasCompiler;
  1082 #endif
  1083 
  1084     /* Create the renderer struct */
  1085     renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(SDL_Renderer));
  1086     if (!renderer) {
  1087         SDL_OutOfMemory();
  1088         return NULL;
  1089     }
  1090 
  1091     rdata = (GLES2_DriverContext *)SDL_calloc(1, sizeof(GLES2_DriverContext));
  1092     if (!rdata) {
  1093         GLES2_DestroyRenderer(renderer);
  1094         SDL_OutOfMemory();
  1095         return NULL;
  1096     }
  1097     renderer->info = GLES2_RenderDriver.info;
  1098     renderer->info.flags = SDL_RENDERER_ACCELERATED;
  1099     renderer->driverdata = rdata;
  1100 
  1101     /* Create an OpenGL ES 2.0 context */
  1102     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
  1103     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
  1104 
  1105     rdata->context = SDL_GL_CreateContext(window);
  1106     if (!rdata->context)
  1107     {
  1108         GLES2_DestroyRenderer(renderer);
  1109         return NULL;
  1110     }
  1111     if (SDL_GL_MakeCurrent(window, rdata->context) < 0) {
  1112         GLES2_DestroyRenderer(renderer);
  1113         return NULL;
  1114     }
  1115 
  1116     if (flags & SDL_RENDERER_PRESENTVSYNC) {
  1117         SDL_GL_SetSwapInterval(1);
  1118     } else {
  1119         SDL_GL_SetSwapInterval(0);
  1120     }
  1121     if (SDL_GL_GetSwapInterval() > 0) {
  1122         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  1123     }
  1124 
  1125     /* Determine supported shader formats */
  1126     /* HACK: glGetInteger is broken on the Zune HD's compositor, so we just hardcode this */
  1127     glGetError();
  1128 #ifdef ZUNE_HD
  1129     nFormats = 1;
  1130 #else /* !ZUNE_HD */
  1131     glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats);
  1132     glGetBooleanv(GL_SHADER_COMPILER, &hasCompiler);
  1133     if (hasCompiler)
  1134         ++nFormats;
  1135 #endif /* ZUNE_HD */
  1136     rdata->shader_formats = (GLenum *)SDL_calloc(nFormats, sizeof(GLenum));
  1137     if (!rdata->shader_formats)
  1138     {
  1139         GLES2_DestroyRenderer(renderer);
  1140         SDL_OutOfMemory();
  1141         return NULL;
  1142     }
  1143     rdata->shader_format_count = nFormats;
  1144 #ifdef ZUNE_HD
  1145     rdata->shader_formats[0] = GL_NVIDIA_PLATFORM_BINARY_NV;
  1146 #else /* !ZUNE_HD */
  1147     glGetIntegerv(GL_SHADER_BINARY_FORMATS, (GLint *)rdata->shader_formats);
  1148     if (glGetError() != GL_NO_ERROR)
  1149     {
  1150         GLES2_DestroyRenderer(renderer);
  1151         SDL_SetError("Failed to query supported shader formats");
  1152         return NULL;
  1153     }
  1154     if (hasCompiler)
  1155         rdata->shader_formats[nFormats - 1] = (GLenum)-1;
  1156 #endif /* ZUNE_HD */
  1157 
  1158     /* Populate the function pointers for the module */
  1159     renderer->WindowEvent         = &GLES2_WindowEvent;
  1160     renderer->CreateTexture       = &GLES2_CreateTexture;
  1161     renderer->UpdateTexture       = &GLES2_UpdateTexture;
  1162     renderer->LockTexture         = &GLES2_LockTexture;
  1163     renderer->UnlockTexture       = &GLES2_UnlockTexture;
  1164     renderer->UpdateViewport      = &GLES2_UpdateViewport;
  1165     renderer->RenderClear         = &GLES2_RenderClear;
  1166     renderer->RenderDrawPoints    = &GLES2_RenderDrawPoints;
  1167     renderer->RenderDrawLines     = &GLES2_RenderDrawLines;
  1168     renderer->RenderFillRects     = &GLES2_RenderFillRects;
  1169     renderer->RenderCopy          = &GLES2_RenderCopy;
  1170     renderer->RenderPresent       = &GLES2_RenderPresent;
  1171     renderer->DestroyTexture      = &GLES2_DestroyTexture;
  1172     renderer->DestroyRenderer     = &GLES2_DestroyRenderer;
  1173     return renderer;
  1174 }
  1175 
  1176 #endif /* SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED */
  1177 
  1178 /* vi: set ts=4 sw=4 expandtab: */