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