src/render/opengles2/SDL_render_gles2.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 09 Apr 2012 23:55:43 -0400
changeset 6305 601b0e251822
parent 6269 07e08cb58696
child 6320 6077a1310907
permissions -rwxr-xr-x
SDL_ExitProcess() was ignoring exit code parameter.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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 /* Used to re-create the window with OpenGL ES capability */
    31 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
    32 
    33 /*************************************************************************************************
    34  * Bootstrap data                                                                                *
    35  *************************************************************************************************/
    36 
    37 static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, Uint32 flags);
    38 
    39 SDL_RenderDriver GLES2_RenderDriver = {
    40     GLES2_CreateRenderer,
    41     {
    42         "opengles2",
    43         (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
    44         4,
    45         {SDL_PIXELFORMAT_ABGR8888,
    46         SDL_PIXELFORMAT_ARGB8888,
    47         SDL_PIXELFORMAT_RGB888,
    48         SDL_PIXELFORMAT_BGR888},
    49         0,
    50         0
    51     }
    52 };
    53 
    54 /*************************************************************************************************
    55  * Context structures                                                                            *
    56  *************************************************************************************************/
    57 
    58 typedef struct GLES2_FBOList GLES2_FBOList;
    59 
    60 struct GLES2_FBOList
    61 {
    62    Uint32 w, h;
    63    GLuint FBO;
    64    GLES2_FBOList *next;
    65 };
    66 
    67 typedef struct GLES2_TextureData
    68 {
    69     GLenum texture;
    70     GLenum texture_type;
    71     GLenum pixel_format;
    72     GLenum pixel_type;
    73     void *pixel_data;
    74     size_t pitch;
    75     GLES2_FBOList *fbo;
    76 } GLES2_TextureData;
    77 
    78 typedef struct GLES2_ShaderCacheEntry
    79 {
    80     GLuint id;
    81     GLES2_ShaderType type;
    82     const GLES2_ShaderInstance *instance;
    83     int references;
    84     struct GLES2_ShaderCacheEntry *prev;
    85     struct GLES2_ShaderCacheEntry *next;
    86 } GLES2_ShaderCacheEntry;
    87 
    88 typedef struct GLES2_ShaderCache
    89 {
    90     int count;
    91     GLES2_ShaderCacheEntry *head;
    92 } GLES2_ShaderCache;
    93 
    94 typedef struct GLES2_ProgramCacheEntry
    95 {
    96     GLuint id;
    97     SDL_BlendMode blend_mode;
    98     GLES2_ShaderCacheEntry *vertex_shader;
    99     GLES2_ShaderCacheEntry *fragment_shader;
   100     GLuint uniform_locations[16];
   101     struct GLES2_ProgramCacheEntry *prev;
   102     struct GLES2_ProgramCacheEntry *next;
   103 } GLES2_ProgramCacheEntry;
   104 
   105 typedef struct GLES2_ProgramCache
   106 {
   107     int count;
   108     GLES2_ProgramCacheEntry *head;
   109     GLES2_ProgramCacheEntry *tail;
   110 } GLES2_ProgramCache;
   111 
   112 typedef enum
   113 {
   114     GLES2_ATTRIBUTE_POSITION = 0,
   115     GLES2_ATTRIBUTE_TEXCOORD = 1
   116 } GLES2_Attribute;
   117 
   118 typedef enum
   119 {
   120     GLES2_UNIFORM_PROJECTION,
   121     GLES2_UNIFORM_TEXTURE,
   122     GLES2_UNIFORM_MODULATION,
   123     GLES2_UNIFORM_COLOR,
   124     GLES2_UNIFORM_COLORTABLE
   125 } GLES2_Uniform;
   126 
   127 typedef enum
   128 {
   129     GLES2_IMAGESOURCE_SOLID,
   130     GLES2_IMAGESOURCE_TEXTURE_ABGR,
   131     GLES2_IMAGESOURCE_TEXTURE_ARGB,
   132     GLES2_IMAGESOURCE_TEXTURE_RGB,
   133     GLES2_IMAGESOURCE_TEXTURE_BGR
   134 } GLES2_ImageSource;
   135 
   136 typedef struct GLES2_DriverContext
   137 {
   138     SDL_GLContext *context;
   139     struct {
   140         int blendMode;
   141         SDL_bool tex_coords;
   142     } current;
   143 
   144 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
   145 #include "SDL_gles2funcs.h"
   146 #undef SDL_PROC
   147     GLES2_FBOList *framebuffers;
   148     GLuint window_framebuffer;
   149 
   150     int shader_format_count;
   151     GLenum *shader_formats;
   152     GLES2_ShaderCache shader_cache;
   153     GLES2_ProgramCache program_cache;
   154     GLES2_ProgramCacheEntry *current_program;
   155 } GLES2_DriverContext;
   156 
   157 #define GLES2_MAX_CACHED_PROGRAMS 8
   158 
   159 /*************************************************************************************************
   160  * Renderer state APIs                                                                           *
   161  *************************************************************************************************/
   162 
   163 static int GLES2_ActivateRenderer(SDL_Renderer *renderer);
   164 static void GLES2_WindowEvent(SDL_Renderer * renderer,
   165                               const SDL_WindowEvent *event);
   166 static int GLES2_UpdateViewport(SDL_Renderer * renderer);
   167 static void GLES2_DestroyRenderer(SDL_Renderer *renderer);
   168 static int GLES2_SetOrthographicProjection(SDL_Renderer *renderer);
   169 
   170 
   171 static SDL_GLContext SDL_CurrentContext = NULL;
   172 
   173 static int GLES2_LoadFunctions(GLES2_DriverContext * data)
   174 {
   175 #if SDL_VIDEO_DRIVER_UIKIT
   176 #define __SDL_NOGETPROCADDR__
   177 #elif SDL_VIDEO_DRIVER_ANDROID
   178 #define __SDL_NOGETPROCADDR__
   179 #elif SDL_VIDEO_DRIVER_PANDORA
   180 #define __SDL_NOGETPROCADDR__
   181 #endif
   182 
   183 #if defined __SDL_NOGETPROCADDR__
   184 #define SDL_PROC(ret,func,params) data->func=func;
   185 #else
   186 #define SDL_PROC(ret,func,params) \
   187     do { \
   188         data->func = SDL_GL_GetProcAddress(#func); \
   189         if ( ! data->func ) { \
   190             SDL_SetError("Couldn't load GLES2 function %s: %s\n", #func, SDL_GetError()); \
   191             return -1; \
   192         } \
   193     } while ( 0 );
   194 #endif /* _SDL_NOGETPROCADDR_ */
   195 
   196 #include "SDL_gles2funcs.h"
   197 #undef SDL_PROC
   198     return 0;
   199 }
   200 
   201 GLES2_FBOList *
   202 GLES2_GetFBO(GLES2_DriverContext *data, Uint32 w, Uint32 h)
   203 {
   204    GLES2_FBOList *result = data->framebuffers;
   205    while ((result) && ((result->w != w) || (result->h != h)) )
   206    {
   207        result = result->next;
   208    }
   209    if (result == NULL)
   210    {
   211        result = SDL_malloc(sizeof(GLES2_FBOList));
   212        result->w = w;
   213        result->h = h;
   214        data->glGenFramebuffers(1, &result->FBO);
   215        result->next = data->framebuffers;
   216        data->framebuffers = result;
   217    }
   218    return result;
   219 }
   220 
   221 static int
   222 GLES2_ActivateRenderer(SDL_Renderer * renderer)
   223 {
   224     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   225 
   226     if (SDL_CurrentContext != rdata->context) {
   227         /* Null out the current program to ensure we set it again */
   228         rdata->current_program = NULL;
   229 
   230         if (SDL_GL_MakeCurrent(renderer->window, rdata->context) < 0) {
   231             return -1;
   232         }
   233         SDL_CurrentContext = rdata->context;
   234 
   235         GLES2_UpdateViewport(renderer);
   236     }
   237     return 0;
   238 }
   239 
   240 static void
   241 GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   242 {
   243     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   244 
   245     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
   246         event->event == SDL_WINDOWEVENT_SHOWN ||
   247         event->event == SDL_WINDOWEVENT_HIDDEN) {
   248         /* Rebind the context to the window area */
   249         SDL_CurrentContext = NULL;
   250     }
   251 
   252     if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
   253         /* According to Apple documentation, we need to finish drawing NOW! */
   254         rdata->glFinish();
   255     }
   256 }
   257 
   258 static int
   259 GLES2_UpdateViewport(SDL_Renderer * renderer)
   260 {
   261     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   262 
   263     if (SDL_CurrentContext != rdata->context) {
   264         /* We'll update the viewport after we rebind the context */
   265         return 0;
   266     }
   267 
   268     rdata->glViewport(renderer->viewport.x, renderer->viewport.y,
   269                renderer->viewport.w, renderer->viewport.h);
   270 
   271     if (rdata->current_program) {
   272         GLES2_SetOrthographicProjection(renderer);
   273     }
   274     return 0;
   275 }
   276 
   277 static void
   278 GLES2_DestroyRenderer(SDL_Renderer *renderer)
   279 {
   280     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   281 
   282     /* Deallocate everything */
   283     if (rdata) {
   284         GLES2_ActivateRenderer(renderer);
   285 
   286         {
   287             GLES2_ShaderCacheEntry *entry;
   288             GLES2_ShaderCacheEntry *next;
   289             entry = rdata->shader_cache.head;
   290             while (entry)
   291             {
   292                 rdata->glDeleteShader(entry->id);
   293                 next = entry->next;
   294                 SDL_free(entry);
   295                 entry = next;
   296             }
   297         }
   298         {
   299             GLES2_ProgramCacheEntry *entry;
   300             GLES2_ProgramCacheEntry *next;
   301             entry = rdata->program_cache.head;
   302             while (entry) {
   303                 rdata->glDeleteProgram(entry->id);
   304                 next = entry->next;
   305                 SDL_free(entry);
   306                 entry = next;
   307             }
   308         }
   309         if (rdata->context) {
   310             while (rdata->framebuffers) {
   311                 GLES2_FBOList *nextnode = rdata->framebuffers->next;
   312                 rdata->glDeleteFramebuffers(1, &rdata->framebuffers->FBO);
   313                 SDL_free(rdata->framebuffers);
   314                 rdata->framebuffers = nextnode;
   315             }
   316             SDL_GL_DeleteContext(rdata->context);
   317         }
   318         if (rdata->shader_formats) {
   319             SDL_free(rdata->shader_formats);
   320         }
   321         SDL_free(rdata);
   322     }
   323     SDL_free(renderer);
   324 }
   325 
   326 /*************************************************************************************************
   327  * Texture APIs                                                                                  *
   328  *************************************************************************************************/
   329 
   330 static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture);
   331 static void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
   332 static int GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
   333                              void **pixels, int *pitch);
   334 static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture);
   335 static int GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
   336                                const void *pixels, int pitch);
   337 static int GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
   338 
   339 static GLenum
   340 GetScaleQuality(void)
   341 {
   342     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   343 
   344     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   345         return GL_NEAREST;
   346     } else {
   347         return GL_LINEAR;
   348     }
   349 }
   350 
   351 static int
   352 GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
   353 {
   354     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   355     GLES2_TextureData *tdata;
   356     GLenum format;
   357     GLenum type;
   358     GLenum scaleMode;
   359 
   360     GLES2_ActivateRenderer(renderer);
   361 
   362     /* Determine the corresponding GLES texture format params */
   363     switch (texture->format)
   364     {
   365     case SDL_PIXELFORMAT_ABGR8888:
   366     case SDL_PIXELFORMAT_ARGB8888:
   367     case SDL_PIXELFORMAT_BGR888:
   368     case SDL_PIXELFORMAT_RGB888:
   369         format = GL_RGBA;
   370         type = GL_UNSIGNED_BYTE;
   371         break;
   372     default:
   373         SDL_SetError("Texture format not supported");
   374         return -1;
   375     }
   376 
   377     /* Allocate a texture struct */
   378     tdata = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData));
   379     if (!tdata)
   380     {
   381         SDL_OutOfMemory();
   382         return -1;
   383     }
   384     tdata->texture = 0;
   385     tdata->texture_type = GL_TEXTURE_2D;
   386     tdata->pixel_format = format;
   387     tdata->pixel_type = type;
   388     scaleMode = GetScaleQuality();
   389 
   390     /* Allocate a blob for image data */
   391     if (texture->access == SDL_TEXTUREACCESS_STREAMING)
   392     {
   393         tdata->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   394         tdata->pixel_data = SDL_calloc(1, tdata->pitch * texture->h);
   395         if (!tdata->pixel_data)
   396         {
   397             SDL_OutOfMemory();
   398             SDL_free(tdata);
   399             return -1;
   400         }
   401     }
   402 
   403     /* Allocate the texture */
   404     rdata->glGetError();
   405     rdata->glGenTextures(1, &tdata->texture);
   406     rdata->glActiveTexture(GL_TEXTURE0);
   407     rdata->glBindTexture(tdata->texture_type, tdata->texture);
   408     rdata->glTexParameteri(tdata->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
   409     rdata->glTexParameteri(tdata->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
   410     rdata->glTexParameteri(tdata->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   411     rdata->glTexParameteri(tdata->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   412     rdata->glTexImage2D(tdata->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);
   413     if (rdata->glGetError() != GL_NO_ERROR)
   414     {
   415         SDL_SetError("Texture creation failed");
   416         rdata->glDeleteTextures(1, &tdata->texture);
   417         SDL_free(tdata);
   418         return -1;
   419     }
   420     texture->driverdata = tdata;
   421 
   422     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   423        tdata->fbo = GLES2_GetFBO(renderer->driverdata, texture->w, texture->h);
   424     } else {
   425        tdata->fbo = NULL;
   426     }
   427 
   428     return 0;
   429 }
   430 
   431 static void
   432 GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
   433 {
   434     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   435     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   436 
   437     GLES2_ActivateRenderer(renderer);
   438 
   439     /* Destroy the texture */
   440     if (tdata)
   441     {
   442         rdata->glDeleteTextures(1, &tdata->texture);
   443         SDL_free(tdata->pixel_data);
   444         SDL_free(tdata);
   445         texture->driverdata = NULL;
   446     }
   447 }
   448 
   449 static int
   450 GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
   451                   void **pixels, int *pitch)
   452 {
   453     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   454 
   455     /* Retrieve the buffer/pitch for the specified region */
   456     *pixels = (Uint8 *)tdata->pixel_data +
   457               (tdata->pitch * rect->y) +
   458               (rect->x * SDL_BYTESPERPIXEL(texture->format));
   459     *pitch = tdata->pitch;
   460 
   461     return 0;
   462 }
   463 
   464 static void
   465 GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
   466 {
   467     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   468     SDL_Rect rect;
   469 
   470     /* We do whole texture updates, at least for now */
   471     rect.x = 0;
   472     rect.y = 0;
   473     rect.w = texture->w;
   474     rect.h = texture->h;
   475     GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
   476 }
   477 
   478 static int
   479 GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
   480                     const void *pixels, int pitch)
   481 {
   482     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   483     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   484     Uint8 *blob = NULL;
   485     Uint8 *src;
   486     int srcPitch;
   487     int y;
   488 
   489     GLES2_ActivateRenderer(renderer);
   490 
   491     /* Bail out if we're supposed to update an empty rectangle */
   492     if (rect->w <= 0 || rect->h <= 0)
   493         return 0;
   494 
   495     /* Reformat the texture data into a tightly packed array */
   496     srcPitch = rect->w * SDL_BYTESPERPIXEL(texture->format);
   497     src = (Uint8 *)pixels;
   498     if (pitch != srcPitch)
   499     {
   500         blob = (Uint8 *)SDL_malloc(srcPitch * rect->h);
   501         if (!blob)
   502         {
   503             SDL_OutOfMemory();
   504             return -1;
   505         }
   506         src = blob;
   507         for (y = 0; y < rect->h; ++y)
   508         {
   509             SDL_memcpy(src, pixels, srcPitch);
   510             src += srcPitch;
   511             pixels = (Uint8 *)pixels + pitch;
   512         }
   513         src = blob;
   514     }
   515 
   516     /* Create a texture subimage with the supplied data */
   517     rdata->glGetError();
   518     rdata->glActiveTexture(GL_TEXTURE0);
   519     rdata->glBindTexture(tdata->texture_type, tdata->texture);
   520     rdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   521     rdata->glTexSubImage2D(tdata->texture_type,
   522                     0,
   523                     rect->x,
   524                     rect->y,
   525                     rect->w,
   526                     rect->h,
   527                     tdata->pixel_format,
   528                     tdata->pixel_type,
   529                     src);
   530     if (blob) {
   531         SDL_free(blob);
   532     }
   533 
   534     if (rdata->glGetError() != GL_NO_ERROR)
   535     {
   536         SDL_SetError("Failed to update texture");
   537         return -1;
   538     }
   539     return 0;
   540 }
   541 
   542 static int
   543 GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   544 {
   545     GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
   546     GLES2_TextureData *texturedata = NULL;
   547     GLenum status;
   548 
   549     if (texture == NULL) {
   550         data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer);
   551     } else {
   552         texturedata = (GLES2_TextureData *) texture->driverdata;
   553         data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO);
   554         /* TODO: check if texture pixel format allows this operation */
   555         data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0);
   556         /* Check FBO status */
   557         status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER);
   558         if (status != GL_FRAMEBUFFER_COMPLETE) {
   559             SDL_SetError("glFramebufferTexture2D() failed");
   560             return -1;
   561         }
   562     }
   563     return 0;
   564 }
   565 
   566 /*************************************************************************************************
   567  * Shader management functions                                                                   *
   568  *************************************************************************************************/
   569 
   570 static GLES2_ShaderCacheEntry *GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type,
   571                                                  SDL_BlendMode blendMode);
   572 static void GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry);
   573 static GLES2_ProgramCacheEntry *GLES2_CacheProgram(SDL_Renderer *renderer,
   574                                                    GLES2_ShaderCacheEntry *vertex,
   575                                                    GLES2_ShaderCacheEntry *fragment,
   576                                                    SDL_BlendMode blendMode);
   577 static int GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source,
   578                                SDL_BlendMode blendMode);
   579 
   580 static GLES2_ProgramCacheEntry *
   581 GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
   582                    GLES2_ShaderCacheEntry *fragment, SDL_BlendMode blendMode)
   583 {
   584     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   585     GLES2_ProgramCacheEntry *entry;
   586     GLES2_ShaderCacheEntry *shaderEntry;
   587     GLint linkSuccessful;
   588 
   589     /* Check if we've already cached this program */
   590     entry = rdata->program_cache.head;
   591     while (entry)
   592     {
   593         if (entry->vertex_shader == vertex && entry->fragment_shader == fragment)
   594             break;
   595         entry = entry->next;
   596     }
   597     if (entry)
   598     {
   599         if (rdata->program_cache.head != entry)
   600         {
   601             if (entry->next)
   602                 entry->next->prev = entry->prev;
   603             if (entry->prev)
   604                 entry->prev->next = entry->next;
   605             entry->prev = NULL;
   606             entry->next = rdata->program_cache.head;
   607             rdata->program_cache.head->prev = entry;
   608             rdata->program_cache.head = entry;
   609         }
   610         return entry;
   611     }
   612 
   613     /* Create a program cache entry */
   614     entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry));
   615     if (!entry)
   616     {
   617         SDL_OutOfMemory();
   618         return NULL;
   619     }
   620     entry->vertex_shader = vertex;
   621     entry->fragment_shader = fragment;
   622     entry->blend_mode = blendMode;
   623 
   624     /* Create the program and link it */
   625     rdata->glGetError();
   626     entry->id = rdata->glCreateProgram();
   627     rdata->glAttachShader(entry->id, vertex->id);
   628     rdata->glAttachShader(entry->id, fragment->id);
   629     rdata->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_POSITION, "a_position");
   630     rdata->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord");
   631     rdata->glLinkProgram(entry->id);
   632     rdata->glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful);
   633     if (rdata->glGetError() != GL_NO_ERROR || !linkSuccessful)
   634     {
   635         SDL_SetError("Failed to link shader program");
   636         rdata->glDeleteProgram(entry->id);
   637         SDL_free(entry);
   638         return NULL;
   639     }
   640 
   641     /* Predetermine locations of uniform variables */
   642     entry->uniform_locations[GLES2_UNIFORM_PROJECTION] =
   643         rdata->glGetUniformLocation(entry->id, "u_projection");
   644     entry->uniform_locations[GLES2_UNIFORM_TEXTURE] =
   645         rdata->glGetUniformLocation(entry->id, "u_texture");
   646     entry->uniform_locations[GLES2_UNIFORM_MODULATION] =
   647         rdata->glGetUniformLocation(entry->id, "u_modulation");
   648     entry->uniform_locations[GLES2_UNIFORM_COLOR] =
   649         rdata->glGetUniformLocation(entry->id, "u_color");
   650     entry->uniform_locations[GLES2_UNIFORM_COLORTABLE] =
   651         rdata->glGetUniformLocation(entry->id, "u_colorTable");
   652 
   653     /* Cache the linked program */
   654     if (rdata->program_cache.head)
   655     {
   656         entry->next = rdata->program_cache.head;
   657         rdata->program_cache.head->prev = entry;
   658     }
   659     else
   660     {
   661         rdata->program_cache.tail = entry;
   662     }
   663     rdata->program_cache.head = entry;
   664     ++rdata->program_cache.count;
   665 
   666     /* Increment the refcount of the shaders we're using */
   667     ++vertex->references;
   668     ++fragment->references;
   669 
   670     /* Evict the last entry from the cache if we exceed the limit */
   671     if (rdata->program_cache.count > GLES2_MAX_CACHED_PROGRAMS)
   672     {
   673         shaderEntry = rdata->program_cache.tail->vertex_shader;
   674         if (--shaderEntry->references <= 0)
   675             GLES2_EvictShader(renderer, shaderEntry);
   676         shaderEntry = rdata->program_cache.tail->fragment_shader;
   677         if (--shaderEntry->references <= 0)
   678             GLES2_EvictShader(renderer, shaderEntry);
   679         rdata->glDeleteProgram(rdata->program_cache.tail->id);
   680         rdata->program_cache.tail = rdata->program_cache.tail->prev;
   681         SDL_free(rdata->program_cache.tail->next);
   682         rdata->program_cache.tail->next = NULL;
   683         --rdata->program_cache.count;
   684     }
   685     return entry;
   686 }
   687 
   688 static GLES2_ShaderCacheEntry *
   689 GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode blendMode)
   690 {
   691     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   692     const GLES2_Shader *shader;
   693     const GLES2_ShaderInstance *instance = NULL;
   694     GLES2_ShaderCacheEntry *entry = NULL;
   695     GLint compileSuccessful = GL_FALSE;
   696     int i, j;
   697 
   698     /* Find the corresponding shader */
   699     shader = GLES2_GetShader(type, blendMode);
   700     if (!shader)
   701     {
   702         SDL_SetError("No shader matching the requested characteristics was found");
   703         return NULL;
   704     }
   705 
   706     /* Find a matching shader instance that's supported on this hardware */
   707     for (i = 0; i < shader->instance_count && !instance; ++i)
   708     {
   709         for (j = 0; j < rdata->shader_format_count && !instance; ++j)
   710         {
   711             if (!shader->instances)
   712                 continue;
   713             if (!shader->instances[i])
   714                 continue;
   715             if (shader->instances[i]->format != rdata->shader_formats[j])
   716                 continue;
   717             instance = shader->instances[i];
   718         }
   719     }
   720     if (!instance)
   721     {
   722         SDL_SetError("The specified shader cannot be loaded on the current platform");
   723         return NULL;
   724     }
   725 
   726     /* Check if we've already cached this shader */
   727     entry = rdata->shader_cache.head;
   728     while (entry)
   729     {
   730         if (entry->instance == instance)
   731             break;
   732         entry = entry->next;
   733     }
   734     if (entry)
   735         return entry;
   736 
   737     /* Create a shader cache entry */
   738     entry = (GLES2_ShaderCacheEntry *)SDL_calloc(1, sizeof(GLES2_ShaderCacheEntry));
   739     if (!entry)
   740     {
   741         SDL_OutOfMemory();
   742         return NULL;
   743     }
   744     entry->type = type;
   745     entry->instance = instance;
   746 
   747     /* Compile or load the selected shader instance */
   748     rdata->glGetError();
   749     entry->id = rdata->glCreateShader(instance->type);
   750     if (instance->format == (GLenum)-1)
   751     {
   752         rdata->glShaderSource(entry->id, 1, (const char **)&instance->data, NULL);
   753         rdata->glCompileShader(entry->id);
   754         rdata->glGetShaderiv(entry->id, GL_COMPILE_STATUS, &compileSuccessful);
   755     }
   756     else
   757     {
   758         rdata->glShaderBinary(1, &entry->id, instance->format, instance->data, instance->length);
   759         compileSuccessful = GL_TRUE;
   760     }
   761     if (rdata->glGetError() != GL_NO_ERROR || !compileSuccessful)
   762     {
   763         char *info = NULL;
   764         int length = 0;
   765 
   766         rdata->glGetShaderiv(entry->id, GL_INFO_LOG_LENGTH, &length);
   767         if (length > 0) {
   768             info = SDL_stack_alloc(char, length);
   769             if (info) {
   770                 rdata->glGetShaderInfoLog(entry->id, length, &length, info);
   771             }
   772         }
   773         if (info) {
   774             SDL_SetError("Failed to load the shader: %s", info);
   775             SDL_stack_free(info);
   776         } else {
   777             SDL_SetError("Failed to load the shader");
   778         }
   779         rdata->glDeleteShader(entry->id);
   780         SDL_free(entry);
   781         return NULL;
   782     }
   783 
   784     /* Link the shader entry in at the front of the cache */
   785     if (rdata->shader_cache.head)
   786     {
   787         entry->next = rdata->shader_cache.head;
   788         rdata->shader_cache.head->prev = entry;
   789     }
   790     rdata->shader_cache.head = entry;
   791     ++rdata->shader_cache.count;
   792     return entry;
   793 }
   794 
   795 static void
   796 GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry)
   797 {
   798     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   799 
   800     /* Unlink the shader from the cache */
   801     if (entry->next)
   802         entry->next->prev = entry->prev;
   803     if (entry->prev)
   804         entry->prev->next = entry->next;
   805     if (rdata->shader_cache.head == entry)
   806         rdata->shader_cache.head = entry->next;
   807     --rdata->shader_cache.count;
   808 
   809     /* Deallocate the shader */
   810     rdata->glDeleteShader(entry->id);
   811     SDL_free(entry);
   812 }
   813 
   814 static int
   815 GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendMode blendMode)
   816 {
   817     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   818     GLES2_ShaderCacheEntry *vertex = NULL;
   819     GLES2_ShaderCacheEntry *fragment = NULL;
   820     GLES2_ShaderType vtype, ftype;
   821     GLES2_ProgramCacheEntry *program;
   822 
   823     /* Select an appropriate shader pair for the specified modes */
   824     vtype = GLES2_SHADER_VERTEX_DEFAULT;
   825     switch (source)
   826     {
   827     case GLES2_IMAGESOURCE_SOLID:
   828         ftype = GLES2_SHADER_FRAGMENT_SOLID_SRC;
   829         break;
   830     case GLES2_IMAGESOURCE_TEXTURE_ABGR:
   831         ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_SRC;
   832             break;
   833     case GLES2_IMAGESOURCE_TEXTURE_ARGB:
   834         ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_SRC;
   835         break;
   836     case GLES2_IMAGESOURCE_TEXTURE_RGB:
   837         ftype = GLES2_SHADER_FRAGMENT_TEXTURE_RGB_SRC;
   838         break;
   839     case GLES2_IMAGESOURCE_TEXTURE_BGR:
   840         ftype = GLES2_SHADER_FRAGMENT_TEXTURE_BGR_SRC;
   841         break;
   842     default:
   843         goto fault;
   844     }
   845 
   846     /* Load the requested shaders */
   847     vertex = GLES2_CacheShader(renderer, vtype, blendMode);
   848     if (!vertex)
   849         goto fault;
   850     fragment = GLES2_CacheShader(renderer, ftype, blendMode);
   851     if (!fragment)
   852         goto fault;
   853 
   854     /* Check if we need to change programs at all */
   855     if (rdata->current_program &&
   856         rdata->current_program->vertex_shader == vertex &&
   857         rdata->current_program->fragment_shader == fragment)
   858         return 0;
   859 
   860     /* Generate a matching program */
   861     program = GLES2_CacheProgram(renderer, vertex, fragment, blendMode);
   862     if (!program)
   863         goto fault;
   864 
   865     /* Select that program in OpenGL */
   866     rdata->glGetError();
   867     rdata->glUseProgram(program->id);
   868     if (rdata->glGetError() != GL_NO_ERROR)
   869     {
   870         SDL_SetError("Failed to select program");
   871         goto fault;
   872     }
   873 
   874     /* Set the current program */
   875     rdata->current_program = program;
   876 
   877     /* Activate an orthographic projection */
   878     if (GLES2_SetOrthographicProjection(renderer) < 0)
   879         goto fault;
   880 
   881     /* Clean up and return */
   882     return 0;
   883 fault:
   884     if (vertex && vertex->references <= 0)
   885         GLES2_EvictShader(renderer, vertex);
   886     if (fragment && fragment->references <= 0)
   887         GLES2_EvictShader(renderer, fragment);
   888     rdata->current_program = NULL;
   889     return -1;
   890 }
   891 
   892 static int
   893 GLES2_SetOrthographicProjection(SDL_Renderer *renderer)
   894 {
   895     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   896     GLfloat projection[4][4];
   897     GLuint locProjection;
   898 
   899     /* Prepare an orthographic projection */
   900     projection[0][0] = 2.0f / renderer->viewport.w;
   901     projection[0][1] = 0.0f;
   902     projection[0][2] = 0.0f;
   903     projection[0][3] = 0.0f;
   904     projection[1][0] = 0.0f;
   905     projection[1][1] = -2.0f / renderer->viewport.h;
   906     projection[1][2] = 0.0f;
   907     projection[1][3] = 0.0f;
   908     projection[2][0] = 0.0f;
   909     projection[2][1] = 0.0f;
   910     projection[2][2] = 1.0f;
   911     projection[2][3] = 0.0f;
   912     projection[3][0] = -1.0f;
   913     projection[3][1] = 1.0f;
   914     projection[3][2] = 0.0f;
   915     projection[3][3] = 1.0f;
   916 
   917     /* Set the projection matrix */
   918     locProjection = rdata->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION];
   919     rdata->glGetError();
   920     rdata->glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection);
   921     if (rdata->glGetError() != GL_NO_ERROR)
   922     {
   923         SDL_SetError("Failed to set orthographic projection");
   924         return -1;
   925     }
   926     return 0;
   927 }
   928 
   929 /*************************************************************************************************
   930  * Rendering functions                                                                           *
   931  *************************************************************************************************/
   932 
   933 static const float inv255f = 1.0f / 255.0f;
   934 
   935 static int GLES2_RenderClear(SDL_Renderer *renderer);
   936 static int GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count);
   937 static int GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points, int count);
   938 static int GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect *rects, int count);
   939 static int GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
   940                             const SDL_Rect *dstrect);
   941 static int GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   942                     Uint32 pixel_format, void * pixels, int pitch);
   943 static void GLES2_RenderPresent(SDL_Renderer *renderer);
   944 
   945 
   946 static int
   947 GLES2_RenderClear(SDL_Renderer * renderer)
   948 {
   949     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   950 
   951     GLES2_ActivateRenderer(renderer);
   952 
   953     rdata->glClearColor((GLfloat) renderer->r * inv255f,
   954                  (GLfloat) renderer->g * inv255f,
   955                  (GLfloat) renderer->b * inv255f,
   956                  (GLfloat) renderer->a * inv255f);
   957 
   958     rdata->glClear(GL_COLOR_BUFFER_BIT);
   959 
   960     return 0;
   961 }
   962 
   963 static void
   964 GLES2_SetBlendMode(GLES2_DriverContext *rdata, int blendMode)
   965 {
   966     if (blendMode != rdata->current.blendMode) {
   967         switch (blendMode) {
   968         default:
   969         case SDL_BLENDMODE_NONE:
   970             rdata->glDisable(GL_BLEND);
   971             break;
   972         case SDL_BLENDMODE_BLEND:
   973             rdata->glEnable(GL_BLEND);
   974             rdata->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   975             break;
   976         case SDL_BLENDMODE_ADD:
   977             rdata->glEnable(GL_BLEND);
   978             rdata->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   979             break;
   980         case SDL_BLENDMODE_MOD:
   981             rdata->glEnable(GL_BLEND);
   982             rdata->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   983             break;
   984         }
   985         rdata->current.blendMode = blendMode;
   986     }
   987 }
   988 
   989 static void
   990 GLES2_SetTexCoords(GLES2_DriverContext * rdata, SDL_bool enabled)
   991 {
   992     if (enabled != rdata->current.tex_coords) {
   993         if (enabled) {
   994             rdata->glEnableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
   995         } else {
   996             rdata->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
   997         }
   998         rdata->current.tex_coords = enabled;
   999     }
  1000 }
  1001 
  1002 static int
  1003 GLES2_SetDrawingState(SDL_Renderer * renderer)
  1004 {
  1005     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
  1006     int blendMode = renderer->blendMode;
  1007     GLuint locColor;
  1008 
  1009     rdata->glGetError();
  1010 
  1011     GLES2_ActivateRenderer(renderer);
  1012 
  1013     GLES2_SetBlendMode(rdata, blendMode);
  1014 
  1015     GLES2_SetTexCoords(rdata, SDL_FALSE);
  1016 
  1017     /* Activate an appropriate shader and set the projection matrix */
  1018     if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0)
  1019         return -1;
  1020 
  1021     /* Select the color to draw with */
  1022     locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR];
  1023     rdata->glUniform4f(locColor,
  1024                 renderer->r * inv255f,
  1025                 renderer->g * inv255f,
  1026                 renderer->b * inv255f,
  1027                 renderer->a * inv255f);
  1028     return 0;
  1029 }
  1030 
  1031 static int
  1032 GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count)
  1033 {
  1034     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
  1035     GLfloat *vertices;
  1036     int idx;
  1037 
  1038     if (GLES2_SetDrawingState(renderer) < 0) {
  1039         return -1;
  1040     }
  1041 
  1042     /* Emit the specified vertices as points */
  1043     vertices = SDL_stack_alloc(GLfloat, count * 2);
  1044     for (idx = 0; idx < count; ++idx)
  1045     {
  1046         GLfloat x = (GLfloat)points[idx].x + 0.5f;
  1047         GLfloat y = (GLfloat)points[idx].y + 0.5f;
  1048 
  1049         vertices[idx * 2] = x;
  1050         vertices[(idx * 2) + 1] = y;
  1051     }
  1052     rdata->glGetError();
  1053     rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
  1054     rdata->glDrawArrays(GL_POINTS, 0, count);
  1055     SDL_stack_free(vertices);
  1056     if (rdata->glGetError() != GL_NO_ERROR)
  1057     {
  1058         SDL_SetError("Failed to render lines");
  1059         return -1;
  1060     }
  1061     return 0;
  1062 }
  1063 
  1064 static int
  1065 GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points, int count)
  1066 {
  1067     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
  1068     GLfloat *vertices;
  1069     int idx;
  1070 
  1071     if (GLES2_SetDrawingState(renderer) < 0) {
  1072         return -1;
  1073     }
  1074 
  1075     /* Emit a line strip including the specified vertices */
  1076     vertices = SDL_stack_alloc(GLfloat, count * 2);
  1077     for (idx = 0; idx < count; ++idx)
  1078     {
  1079         GLfloat x = (GLfloat)points[idx].x + 0.5f;
  1080         GLfloat y = (GLfloat)points[idx].y + 0.5f;
  1081 
  1082         vertices[idx * 2] = x;
  1083         vertices[(idx * 2) + 1] = y;
  1084     }
  1085     rdata->glGetError();
  1086     rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
  1087     rdata->glDrawArrays(GL_LINE_STRIP, 0, count);
  1088 
  1089     /* We need to close the endpoint of the line */
  1090     if (count == 2 ||
  1091         points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
  1092         rdata->glDrawArrays(GL_POINTS, count-1, 1);
  1093     }
  1094     SDL_stack_free(vertices);
  1095     if (rdata->glGetError() != GL_NO_ERROR)
  1096     {
  1097         SDL_SetError("Failed to render lines");
  1098         return -1;
  1099     }
  1100     return 0;
  1101 }
  1102 
  1103 static int
  1104 GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect *rects, int count)
  1105 {
  1106     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
  1107     GLfloat vertices[8];
  1108     int idx;
  1109 
  1110     if (GLES2_SetDrawingState(renderer) < 0) {
  1111         return -1;
  1112     }
  1113 
  1114     /* Emit a line loop for each rectangle */
  1115     rdata->glGetError();
  1116     for (idx = 0; idx < count; ++idx) {
  1117         const SDL_Rect *rect = &rects[idx];
  1118 
  1119         GLfloat xMin = (GLfloat)rect->x;
  1120         GLfloat xMax = (GLfloat)(rect->x + rect->w);
  1121         GLfloat yMin = (GLfloat)rect->y;
  1122         GLfloat yMax = (GLfloat)(rect->y + rect->h);
  1123 
  1124         vertices[0] = xMin;
  1125         vertices[1] = yMin;
  1126         vertices[2] = xMax;
  1127         vertices[3] = yMin;
  1128         vertices[4] = xMin;
  1129         vertices[5] = yMax;
  1130         vertices[6] = xMax;
  1131         vertices[7] = yMax;
  1132         rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
  1133         rdata->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  1134     }
  1135     if (rdata->glGetError() != GL_NO_ERROR)
  1136     {
  1137         SDL_SetError("Failed to render lines");
  1138         return -1;
  1139     }
  1140     return 0;
  1141 }
  1142 
  1143 static int
  1144 GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
  1145                  const SDL_Rect *dstrect)
  1146 {
  1147     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
  1148     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
  1149     GLES2_ImageSource sourceType;
  1150     SDL_BlendMode blendMode;
  1151     GLfloat vertices[8];
  1152     GLfloat texCoords[8];
  1153     GLuint locTexture;
  1154     GLuint locModulation;
  1155 
  1156     GLES2_ActivateRenderer(renderer);
  1157 
  1158     /* Activate an appropriate shader and set the projection matrix */
  1159     blendMode = texture->blendMode;
  1160     if (renderer->target) {
  1161         /* Check if we need to do color mapping between the source and render target textures */
  1162         if (renderer->target->format != texture->format) {
  1163             switch (texture->format)
  1164             {
  1165             case SDL_PIXELFORMAT_ABGR8888:
  1166                 switch (renderer->target->format)
  1167                 {
  1168                     case SDL_PIXELFORMAT_ARGB8888:
  1169                     case SDL_PIXELFORMAT_RGB888:
  1170                         sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
  1171                         break;
  1172                     case SDL_PIXELFORMAT_BGR888:
  1173                         sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
  1174                         break;
  1175                 }
  1176                 break;
  1177             case SDL_PIXELFORMAT_ARGB8888:
  1178                 switch (renderer->target->format)
  1179                 {
  1180                     case SDL_PIXELFORMAT_ABGR8888:
  1181                     case SDL_PIXELFORMAT_BGR888:
  1182                         sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
  1183                         break;
  1184                     case SDL_PIXELFORMAT_RGB888:
  1185                         sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
  1186                         break;
  1187                 }
  1188                 break;
  1189             case SDL_PIXELFORMAT_BGR888:
  1190                 switch (renderer->target->format)
  1191                 {
  1192                     case SDL_PIXELFORMAT_ABGR8888:
  1193                         sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
  1194                         break;
  1195                     case SDL_PIXELFORMAT_ARGB8888:
  1196                         sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
  1197                         break;
  1198                     case SDL_PIXELFORMAT_RGB888:
  1199                         sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
  1200                         break;
  1201                 }
  1202                 break;
  1203             case SDL_PIXELFORMAT_RGB888:
  1204                 switch (renderer->target->format)
  1205                 {
  1206                     case SDL_PIXELFORMAT_ABGR8888:
  1207                         sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
  1208                         break;
  1209                     case SDL_PIXELFORMAT_ARGB8888:
  1210                         sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
  1211                         break;
  1212                     case SDL_PIXELFORMAT_BGR888:
  1213                         sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
  1214                         break;
  1215                 }
  1216                 break;
  1217             }
  1218         }
  1219         else sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;   // Texture formats match, use the non color mapping shader (even if the formats are not ABGR)
  1220     }
  1221     else {
  1222         switch (texture->format)
  1223         {
  1224             case SDL_PIXELFORMAT_ABGR8888:
  1225                 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
  1226                 break;
  1227             case SDL_PIXELFORMAT_ARGB8888:
  1228                 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
  1229                 break;
  1230             case SDL_PIXELFORMAT_BGR888:
  1231                 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
  1232                 break;
  1233             case SDL_PIXELFORMAT_RGB888:
  1234                 sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
  1235                 break;
  1236         }
  1237     }
  1238     if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0)
  1239         return -1;
  1240 
  1241     /* Select the target texture */
  1242     locTexture = rdata->current_program->uniform_locations[GLES2_UNIFORM_TEXTURE];
  1243     rdata->glGetError();
  1244     rdata->glActiveTexture(GL_TEXTURE0);
  1245     rdata->glBindTexture(tdata->texture_type, tdata->texture);
  1246     rdata->glUniform1i(locTexture, 0);
  1247 
  1248     /* Configure color modulation */
  1249     locModulation = rdata->current_program->uniform_locations[GLES2_UNIFORM_MODULATION];
  1250     rdata->glUniform4f(locModulation,
  1251                 texture->r * inv255f,
  1252                 texture->g * inv255f,
  1253                 texture->b * inv255f,
  1254                 texture->a * inv255f);
  1255 
  1256     /* Configure texture blending */
  1257     GLES2_SetBlendMode(rdata, blendMode);
  1258 
  1259     GLES2_SetTexCoords(rdata, SDL_TRUE);
  1260 
  1261     /* Emit the textured quad */
  1262     if (renderer->target) {
  1263         // Flip the texture vertically to compensate for the inversion it'll be subjected to later when it's rendered to the screen
  1264         vertices[0] = (GLfloat)dstrect->x;
  1265         vertices[1] = (GLfloat)renderer->viewport.h-dstrect->y;
  1266         vertices[2] = (GLfloat)(dstrect->x + dstrect->w);
  1267         vertices[3] = (GLfloat)renderer->viewport.h-dstrect->y;
  1268         vertices[4] = (GLfloat)dstrect->x;
  1269         vertices[5] = (GLfloat)renderer->viewport.h-(dstrect->y + dstrect->h);
  1270         vertices[6] = (GLfloat)(dstrect->x + dstrect->w);
  1271         vertices[7] = (GLfloat)renderer->viewport.h-(dstrect->y + dstrect->h);
  1272     }
  1273     else {
  1274         vertices[0] = (GLfloat)dstrect->x;
  1275         vertices[1] = (GLfloat)dstrect->y;
  1276         vertices[2] = (GLfloat)(dstrect->x + dstrect->w);
  1277         vertices[3] = (GLfloat)dstrect->y;
  1278         vertices[4] = (GLfloat)dstrect->x;
  1279         vertices[5] = (GLfloat)(dstrect->y + dstrect->h);
  1280         vertices[6] = (GLfloat)(dstrect->x + dstrect->w);
  1281         vertices[7] = (GLfloat)(dstrect->y + dstrect->h);
  1282     }
  1283     rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
  1284 
  1285     texCoords[0] = srcrect->x / (GLfloat)texture->w;
  1286     texCoords[1] = srcrect->y / (GLfloat)texture->h;
  1287     texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
  1288     texCoords[3] = srcrect->y / (GLfloat)texture->h;
  1289     texCoords[4] = srcrect->x / (GLfloat)texture->w;
  1290     texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
  1291     texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
  1292     texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
  1293     rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
  1294     rdata->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  1295     if (rdata->glGetError() != GL_NO_ERROR)
  1296     {
  1297         SDL_SetError("Failed to render texture");
  1298         return -1;
  1299     }
  1300     return 0;
  1301 }
  1302 
  1303 static int
  1304 GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1305                     Uint32 pixel_format, void * pixels, int pitch)
  1306 {
  1307     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
  1308     SDL_Window *window = renderer->window;
  1309     Uint32 temp_format = SDL_PIXELFORMAT_ABGR8888;
  1310     void *temp_pixels;
  1311     int temp_pitch;
  1312     Uint8 *src, *dst, *tmp;
  1313     int w, h, length, rows;
  1314     int status;
  1315 
  1316     GLES2_ActivateRenderer(renderer);
  1317 
  1318     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1319     temp_pixels = SDL_malloc(rect->h * temp_pitch);
  1320     if (!temp_pixels) {
  1321         SDL_OutOfMemory();
  1322         return -1;
  1323     }
  1324 
  1325     SDL_GetWindowSize(window, &w, &h);
  1326 
  1327     rdata->glPixelStorei(GL_PACK_ALIGNMENT, 1);
  1328 
  1329     rdata->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
  1330                        GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels);
  1331 
  1332     /* Flip the rows to be top-down */
  1333     length = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1334     src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
  1335     dst = (Uint8*)temp_pixels;
  1336     tmp = SDL_stack_alloc(Uint8, length);
  1337     rows = rect->h / 2;
  1338     while (rows--) {
  1339         SDL_memcpy(tmp, dst, length);
  1340         SDL_memcpy(dst, src, length);
  1341         SDL_memcpy(src, tmp, length);
  1342         dst += temp_pitch;
  1343         src -= temp_pitch;
  1344     }
  1345     SDL_stack_free(tmp);
  1346 
  1347     status = SDL_ConvertPixels(rect->w, rect->h,
  1348                                temp_format, temp_pixels, temp_pitch,
  1349                                pixel_format, pixels, pitch);
  1350     SDL_free(temp_pixels);
  1351 
  1352     return status;
  1353 }
  1354 
  1355 static void
  1356 GLES2_RenderPresent(SDL_Renderer *renderer)
  1357 {
  1358     GLES2_ActivateRenderer(renderer);
  1359 
  1360     /* Tell the video driver to swap buffers */
  1361     SDL_GL_SwapWindow(renderer->window);
  1362 }
  1363 
  1364 /*************************************************************************************************
  1365  * Renderer instantiation                                                                        *
  1366  *************************************************************************************************/
  1367 
  1368 #define GL_NVIDIA_PLATFORM_BINARY_NV 0x890B
  1369 
  1370 static void
  1371 GLES2_ResetState(SDL_Renderer *renderer)
  1372 {
  1373     GLES2_DriverContext *rdata = (GLES2_DriverContext *) renderer->driverdata;
  1374 
  1375     if (SDL_CurrentContext == rdata->context) {
  1376         GLES2_UpdateViewport(renderer);
  1377     } else {
  1378         GLES2_ActivateRenderer(renderer);
  1379     }
  1380 
  1381     rdata->current.blendMode = -1;
  1382     rdata->current.tex_coords = SDL_FALSE;
  1383 
  1384     rdata->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
  1385     rdata->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
  1386 }
  1387 
  1388 static SDL_Renderer *
  1389 GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
  1390 {
  1391     SDL_Renderer *renderer;
  1392     GLES2_DriverContext *rdata;
  1393     GLint nFormats;
  1394 #ifndef ZUNE_HD
  1395     GLboolean hasCompiler;
  1396 #endif
  1397     Uint32 windowFlags;
  1398     GLint window_framebuffer;
  1399 
  1400     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
  1401     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
  1402 
  1403     windowFlags = SDL_GetWindowFlags(window);
  1404     if (!(windowFlags & SDL_WINDOW_OPENGL)) {
  1405         if (SDL_RecreateWindow(window, windowFlags | SDL_WINDOW_OPENGL) < 0) {
  1406             /* Uh oh, better try to put it back... */
  1407             SDL_RecreateWindow(window, windowFlags);
  1408             return NULL;
  1409         }
  1410     }
  1411 
  1412     /* Create the renderer struct */
  1413     renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(SDL_Renderer));
  1414     if (!renderer) {
  1415         SDL_OutOfMemory();
  1416         return NULL;
  1417     }
  1418 
  1419     rdata = (GLES2_DriverContext *)SDL_calloc(1, sizeof(GLES2_DriverContext));
  1420     if (!rdata) {
  1421         GLES2_DestroyRenderer(renderer);
  1422         SDL_OutOfMemory();
  1423         return NULL;
  1424     }
  1425     renderer->info = GLES2_RenderDriver.info;
  1426     renderer->info.flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
  1427     renderer->driverdata = rdata;
  1428     renderer->window = window;
  1429 
  1430     /* Create an OpenGL ES 2.0 context */
  1431     rdata->context = SDL_GL_CreateContext(window);
  1432     if (!rdata->context)
  1433     {
  1434         GLES2_DestroyRenderer(renderer);
  1435         return NULL;
  1436     }
  1437     if (SDL_GL_MakeCurrent(window, rdata->context) < 0) {
  1438         GLES2_DestroyRenderer(renderer);
  1439         return NULL;
  1440     }
  1441 
  1442     if (GLES2_LoadFunctions(rdata) < 0) {
  1443         GLES2_DestroyRenderer(renderer);
  1444         return NULL;
  1445     }
  1446 
  1447     if (flags & SDL_RENDERER_PRESENTVSYNC) {
  1448         SDL_GL_SetSwapInterval(1);
  1449     } else {
  1450         SDL_GL_SetSwapInterval(0);
  1451     }
  1452     if (SDL_GL_GetSwapInterval() > 0) {
  1453         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  1454     }
  1455 
  1456     /* Determine supported shader formats */
  1457     /* HACK: glGetInteger is broken on the Zune HD's compositor, so we just hardcode this */
  1458     rdata->glGetError();
  1459 #ifdef ZUNE_HD
  1460     nFormats = 1;
  1461 #else /* !ZUNE_HD */
  1462     rdata->glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats);
  1463     rdata->glGetBooleanv(GL_SHADER_COMPILER, &hasCompiler);
  1464     if (hasCompiler)
  1465         ++nFormats;
  1466 #endif /* ZUNE_HD */
  1467     rdata->shader_formats = (GLenum *)SDL_calloc(nFormats, sizeof(GLenum));
  1468     if (!rdata->shader_formats)
  1469     {
  1470         GLES2_DestroyRenderer(renderer);
  1471         SDL_OutOfMemory();
  1472         return NULL;
  1473     }
  1474     rdata->shader_format_count = nFormats;
  1475 #ifdef ZUNE_HD
  1476     rdata->shader_formats[0] = GL_NVIDIA_PLATFORM_BINARY_NV;
  1477 #else /* !ZUNE_HD */
  1478     rdata->glGetIntegerv(GL_SHADER_BINARY_FORMATS, (GLint *)rdata->shader_formats);
  1479     if (rdata->glGetError() != GL_NO_ERROR)
  1480     {
  1481         GLES2_DestroyRenderer(renderer);
  1482         SDL_SetError("Failed to query supported shader formats");
  1483         return NULL;
  1484     }
  1485     if (hasCompiler)
  1486         rdata->shader_formats[nFormats - 1] = (GLenum)-1;
  1487 #endif /* ZUNE_HD */
  1488 
  1489     rdata->framebuffers = NULL;
  1490     rdata->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer);
  1491     rdata->window_framebuffer = (GLuint)window_framebuffer;
  1492 
  1493     /* Populate the function pointers for the module */
  1494     renderer->WindowEvent         = &GLES2_WindowEvent;
  1495     renderer->CreateTexture       = &GLES2_CreateTexture;
  1496     renderer->UpdateTexture       = &GLES2_UpdateTexture;
  1497     renderer->LockTexture         = &GLES2_LockTexture;
  1498     renderer->UnlockTexture       = &GLES2_UnlockTexture;
  1499     renderer->SetRenderTarget     = &GLES2_SetRenderTarget;
  1500     renderer->UpdateViewport      = &GLES2_UpdateViewport;
  1501     renderer->RenderClear         = &GLES2_RenderClear;
  1502     renderer->RenderDrawPoints    = &GLES2_RenderDrawPoints;
  1503     renderer->RenderDrawLines     = &GLES2_RenderDrawLines;
  1504     renderer->RenderFillRects     = &GLES2_RenderFillRects;
  1505     renderer->RenderCopy          = &GLES2_RenderCopy;
  1506     renderer->RenderReadPixels    = &GLES2_RenderReadPixels;
  1507     renderer->RenderPresent       = &GLES2_RenderPresent;
  1508     renderer->DestroyTexture      = &GLES2_DestroyTexture;
  1509     renderer->DestroyRenderer     = &GLES2_DestroyRenderer;
  1510 
  1511     GLES2_ResetState(renderer);
  1512 
  1513     return renderer;
  1514 }
  1515 
  1516 #endif /* SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED */
  1517 
  1518 /* vi: set ts=4 sw=4 expandtab: */