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