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