src/render/opengles/SDL_render_gles.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 04 Feb 2019 23:24:10 -0500
changeset 12593 307b9da13612
parent 12531 af47ff0de5ab
child 12621 6a60a1e87d10
permissions -rw-r--r--
opengles1: keep cached texturing state correct.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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_internal.h"
    22 
    23 #if SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED
    24 
    25 #include "SDL_hints.h"
    26 #include "SDL_opengles.h"
    27 #include "../SDL_sysrender.h"
    28 
    29 /* To prevent unnecessary window recreation,
    30  * these should match the defaults selected in SDL_GL_ResetAttributes
    31  */
    32 
    33 #define RENDERER_CONTEXT_MAJOR 1
    34 #define RENDERER_CONTEXT_MINOR 1
    35 
    36 #if defined(SDL_VIDEO_DRIVER_PANDORA)
    37 
    38 /* Empty function stub to get OpenGL ES 1.x support without  */
    39 /* OpenGL ES extension GL_OES_draw_texture supported         */
    40 GL_API void GL_APIENTRY
    41 glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height)
    42 {
    43     return;
    44 }
    45 
    46 #endif /* SDL_VIDEO_DRIVER_PANDORA */
    47 
    48 /* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */
    49 
    50 /* Used to re-create the window with OpenGL ES capability */
    51 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
    52 
    53 static const float inv255f = 1.0f / 255.0f;
    54 
    55 typedef struct GLES_FBOList GLES_FBOList;
    56 
    57 struct GLES_FBOList
    58 {
    59    Uint32 w, h;
    60    GLuint FBO;
    61    GLES_FBOList *next;
    62 };
    63 
    64 typedef struct
    65 {
    66     SDL_Rect viewport;
    67     SDL_bool viewport_dirty;
    68     SDL_Texture *texture;
    69     SDL_Texture *target;
    70     int drawablew;
    71     int drawableh;
    72     SDL_BlendMode blend;
    73     SDL_bool cliprect_enabled_dirty;
    74     SDL_bool cliprect_enabled;
    75     SDL_bool cliprect_dirty;
    76     SDL_Rect cliprect;
    77     SDL_bool texturing;
    78     Uint32 color;
    79     Uint32 clear_color;
    80 } GLES_DrawStateCache;
    81 
    82 typedef struct
    83 {
    84     SDL_GLContext context;
    85 
    86 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
    87 #define SDL_PROC_OES SDL_PROC
    88 #include "SDL_glesfuncs.h"
    89 #undef SDL_PROC
    90 #undef SDL_PROC_OES
    91     SDL_bool GL_OES_framebuffer_object_supported;
    92     GLES_FBOList *framebuffers;
    93     GLuint window_framebuffer;
    94 
    95     SDL_bool GL_OES_blend_func_separate_supported;
    96     SDL_bool GL_OES_blend_equation_separate_supported;
    97     SDL_bool GL_OES_blend_subtract_supported;
    98 
    99     GLES_DrawStateCache drawstate;
   100 } GLES_RenderData;
   101 
   102 typedef struct
   103 {
   104     GLuint texture;
   105     GLenum type;
   106     GLfloat texw;
   107     GLfloat texh;
   108     GLenum format;
   109     GLenum formattype;
   110     void *pixels;
   111     int pitch;
   112     GLES_FBOList *fbo;
   113 } GLES_TextureData;
   114 
   115 static int
   116 GLES_SetError(const char *prefix, GLenum result)
   117 {
   118     const char *error;
   119 
   120     switch (result) {
   121     case GL_NO_ERROR:
   122         error = "GL_NO_ERROR";
   123         break;
   124     case GL_INVALID_ENUM:
   125         error = "GL_INVALID_ENUM";
   126         break;
   127     case GL_INVALID_VALUE:
   128         error = "GL_INVALID_VALUE";
   129         break;
   130     case GL_INVALID_OPERATION:
   131         error = "GL_INVALID_OPERATION";
   132         break;
   133     case GL_STACK_OVERFLOW:
   134         error = "GL_STACK_OVERFLOW";
   135         break;
   136     case GL_STACK_UNDERFLOW:
   137         error = "GL_STACK_UNDERFLOW";
   138         break;
   139     case GL_OUT_OF_MEMORY:
   140         error = "GL_OUT_OF_MEMORY";
   141         break;
   142     default:
   143         error = "UNKNOWN";
   144         break;
   145     }
   146     return SDL_SetError("%s: %s", prefix, error);
   147 }
   148 
   149 static int GLES_LoadFunctions(GLES_RenderData * data)
   150 {
   151 #if SDL_VIDEO_DRIVER_UIKIT
   152 #define __SDL_NOGETPROCADDR__
   153 #elif SDL_VIDEO_DRIVER_ANDROID
   154 #define __SDL_NOGETPROCADDR__
   155 #elif SDL_VIDEO_DRIVER_PANDORA
   156 #define __SDL_NOGETPROCADDR__
   157 #endif
   158 
   159 #ifdef __SDL_NOGETPROCADDR__
   160 #define SDL_PROC(ret,func,params) data->func=func;
   161 #define SDL_PROC_OES(ret,func,params) data->func=func;
   162 #else
   163 #define SDL_PROC(ret,func,params) \
   164     do { \
   165         data->func = SDL_GL_GetProcAddress(#func); \
   166         if ( ! data->func ) { \
   167             return SDL_SetError("Couldn't load GLES function %s: %s", #func, SDL_GetError()); \
   168         } \
   169     } while ( 0 );
   170 #define SDL_PROC_OES(ret,func,params) \
   171     do { \
   172         data->func = SDL_GL_GetProcAddress(#func); \
   173     } while ( 0 );
   174 #endif /* __SDL_NOGETPROCADDR__ */
   175 
   176 #include "SDL_glesfuncs.h"
   177 #undef SDL_PROC
   178 #undef SDL_PROC_OES
   179     return 0;
   180 }
   181 
   182 static GLES_FBOList *
   183 GLES_GetFBO(GLES_RenderData *data, Uint32 w, Uint32 h)
   184 {
   185    GLES_FBOList *result = data->framebuffers;
   186    while ((result) && ((result->w != w) || (result->h != h)) ) {
   187        result = result->next;
   188    }
   189    if (result == NULL) {
   190        result = SDL_malloc(sizeof(GLES_FBOList));
   191        result->w = w;
   192        result->h = h;
   193        data->glGenFramebuffersOES(1, &result->FBO);
   194        result->next = data->framebuffers;
   195        data->framebuffers = result;
   196    }
   197    return result;
   198 }
   199 
   200 
   201 static int
   202 GLES_ActivateRenderer(SDL_Renderer * renderer)
   203 {
   204     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   205 
   206     if (SDL_GL_GetCurrentContext() != data->context) {
   207         if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
   208             return -1;
   209         }
   210     }
   211 
   212     return 0;
   213 }
   214 
   215 static void
   216 GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   217 {
   218     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   219 
   220     if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
   221         /* According to Apple documentation, we need to finish drawing NOW! */
   222         data->glFinish();
   223     }
   224 }
   225 
   226 static int
   227 GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
   228 {
   229     SDL_GL_GetDrawableSize(renderer->window, w, h);
   230     return 0;
   231 }
   232 
   233 static GLenum GetBlendFunc(SDL_BlendFactor factor)
   234 {
   235     switch (factor) {
   236     case SDL_BLENDFACTOR_ZERO:
   237         return GL_ZERO;
   238     case SDL_BLENDFACTOR_ONE:
   239         return GL_ONE;
   240     case SDL_BLENDFACTOR_SRC_COLOR:
   241         return GL_SRC_COLOR;
   242     case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
   243         return GL_ONE_MINUS_SRC_COLOR;
   244     case SDL_BLENDFACTOR_SRC_ALPHA:
   245         return GL_SRC_ALPHA;
   246     case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
   247         return GL_ONE_MINUS_SRC_ALPHA;
   248     case SDL_BLENDFACTOR_DST_COLOR:
   249         return GL_DST_COLOR;
   250     case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
   251         return GL_ONE_MINUS_DST_COLOR;
   252     case SDL_BLENDFACTOR_DST_ALPHA:
   253         return GL_DST_ALPHA;
   254     case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
   255         return GL_ONE_MINUS_DST_ALPHA;
   256     default:
   257         return GL_INVALID_ENUM;
   258     }
   259 }
   260 
   261 static GLenum GetBlendEquation(SDL_BlendOperation operation)
   262 {
   263     switch (operation) {
   264     case SDL_BLENDOPERATION_ADD:
   265         return GL_FUNC_ADD_OES;
   266     case SDL_BLENDOPERATION_SUBTRACT:
   267         return GL_FUNC_SUBTRACT_OES;
   268     case SDL_BLENDOPERATION_REV_SUBTRACT:
   269         return GL_FUNC_REVERSE_SUBTRACT_OES;
   270     default:
   271         return GL_INVALID_ENUM;
   272     }
   273 }
   274 
   275 static SDL_bool
   276 GLES_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
   277 {
   278     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   279     SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
   280     SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
   281     SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
   282     SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
   283     SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
   284     SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
   285 
   286     if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM ||
   287         GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM ||
   288         GetBlendEquation(colorOperation) == GL_INVALID_ENUM ||
   289         GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM ||
   290         GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM ||
   291         GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) {
   292         return SDL_FALSE;
   293     }
   294     if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->GL_OES_blend_func_separate_supported) {
   295         return SDL_FALSE;
   296     }
   297     if (colorOperation != alphaOperation && !data->GL_OES_blend_equation_separate_supported) {
   298         return SDL_FALSE;
   299     }
   300     if (colorOperation != SDL_BLENDOPERATION_ADD && !data->GL_OES_blend_subtract_supported) {
   301         return SDL_FALSE;
   302     }
   303     return SDL_TRUE;
   304 }
   305 
   306 static SDL_INLINE int
   307 power_of_2(int input)
   308 {
   309     int value = 1;
   310 
   311     while (value < input) {
   312         value <<= 1;
   313     }
   314     return value;
   315 }
   316 
   317 static int
   318 GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   319 {
   320     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   321     GLES_TextureData *data;
   322     GLint internalFormat;
   323     GLenum format, type;
   324     int texture_w, texture_h;
   325     GLenum scaleMode;
   326     GLenum result;
   327 
   328     GLES_ActivateRenderer(renderer);
   329 
   330     switch (texture->format) {
   331     case SDL_PIXELFORMAT_ABGR8888:
   332         internalFormat = GL_RGBA;
   333         format = GL_RGBA;
   334         type = GL_UNSIGNED_BYTE;
   335         break;
   336     default:
   337         return SDL_SetError("Texture format not supported");
   338     }
   339 
   340     data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data));
   341     if (!data) {
   342         return SDL_OutOfMemory();
   343     }
   344 
   345     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   346         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   347         data->pixels = SDL_calloc(1, texture->h * data->pitch);
   348         if (!data->pixels) {
   349             SDL_free(data);
   350             return SDL_OutOfMemory();
   351         }
   352     }
   353 
   354 
   355     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   356         if (!renderdata->GL_OES_framebuffer_object_supported) {
   357             SDL_free(data);
   358             return SDL_SetError("GL_OES_framebuffer_object not supported");
   359         }
   360         data->fbo = GLES_GetFBO(renderer->driverdata, texture->w, texture->h);
   361     } else {
   362         data->fbo = NULL;
   363     }
   364 
   365 
   366     renderdata->glGetError();
   367     renderdata->glEnable(GL_TEXTURE_2D);
   368     renderdata->glGenTextures(1, &data->texture);
   369     result = renderdata->glGetError();
   370     if (result != GL_NO_ERROR) {
   371         SDL_free(data);
   372         return GLES_SetError("glGenTextures()", result);
   373     }
   374 
   375     data->type = GL_TEXTURE_2D;
   376     /* no NPOV textures allowed in OpenGL ES (yet) */
   377     texture_w = power_of_2(texture->w);
   378     texture_h = power_of_2(texture->h);
   379     data->texw = (GLfloat) texture->w / texture_w;
   380     data->texh = (GLfloat) texture->h / texture_h;
   381 
   382     data->format = format;
   383     data->formattype = type;
   384     scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
   385     renderdata->glBindTexture(data->type, data->texture);
   386     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
   387     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
   388     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   389     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   390 
   391     renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   392                              texture_h, 0, format, type, NULL);
   393     renderdata->glDisable(GL_TEXTURE_2D);
   394     renderdata->drawstate.texture = texture;
   395     renderdata->drawstate.texturing = SDL_FALSE;
   396 
   397     result = renderdata->glGetError();
   398     if (result != GL_NO_ERROR) {
   399         SDL_free(data);
   400         return GLES_SetError("glTexImage2D()", result);
   401     }
   402 
   403     texture->driverdata = data;
   404     return 0;
   405 }
   406 
   407 static int
   408 GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   409                    const SDL_Rect * rect, const void *pixels, int pitch)
   410 {
   411     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   412     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   413     Uint8 *blob = NULL;
   414     Uint8 *src;
   415     int srcPitch;
   416     int y;
   417 
   418     GLES_ActivateRenderer(renderer);
   419 
   420     /* Bail out if we're supposed to update an empty rectangle */
   421     if (rect->w <= 0 || rect->h <= 0) {
   422         return 0;
   423     }
   424 
   425     /* Reformat the texture data into a tightly packed array */
   426     srcPitch = rect->w * SDL_BYTESPERPIXEL(texture->format);
   427     src = (Uint8 *)pixels;
   428     if (pitch != srcPitch) {
   429         blob = (Uint8 *)SDL_malloc(srcPitch * rect->h);
   430         if (!blob) {
   431             return SDL_OutOfMemory();
   432         }
   433         src = blob;
   434         for (y = 0; y < rect->h; ++y) {
   435             SDL_memcpy(src, pixels, srcPitch);
   436             src += srcPitch;
   437             pixels = (Uint8 *)pixels + pitch;
   438         }
   439         src = blob;
   440     }
   441 
   442     /* Create a texture subimage with the supplied data */
   443     renderdata->glGetError();
   444     renderdata->glEnable(data->type);
   445     renderdata->glBindTexture(data->type, data->texture);
   446     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   447     renderdata->glTexSubImage2D(data->type,
   448                     0,
   449                     rect->x,
   450                     rect->y,
   451                     rect->w,
   452                     rect->h,
   453                     data->format,
   454                     data->formattype,
   455                     src);
   456     renderdata->glDisable(data->type);
   457     SDL_free(blob);
   458 
   459     renderdata->drawstate.texture = texture;
   460     renderdata->drawstate.texturing = SDL_FALSE;
   461 
   462     if (renderdata->glGetError() != GL_NO_ERROR) {
   463         return SDL_SetError("Failed to update texture");
   464     }
   465     return 0;
   466 }
   467 
   468 static int
   469 GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   470                  const SDL_Rect * rect, void **pixels, int *pitch)
   471 {
   472     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   473 
   474     *pixels =
   475         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   476                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   477     *pitch = data->pitch;
   478     return 0;
   479 }
   480 
   481 static void
   482 GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   483 {
   484     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   485     SDL_Rect rect;
   486 
   487     /* We do whole texture updates, at least for now */
   488     rect.x = 0;
   489     rect.y = 0;
   490     rect.w = texture->w;
   491     rect.h = texture->h;
   492     GLES_UpdateTexture(renderer, texture, &rect, data->pixels, data->pitch);
   493 }
   494 
   495 static int
   496 GLES_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   497 {
   498     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   499     GLES_TextureData *texturedata = NULL;
   500     GLenum status;
   501 
   502     if (!data->GL_OES_framebuffer_object_supported) {
   503         return SDL_SetError("Can't enable render target support in this renderer");
   504     }
   505 
   506     if (texture == NULL) {
   507         data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, data->window_framebuffer);
   508         return 0;
   509     }
   510 
   511     texturedata = (GLES_TextureData *) texture->driverdata;
   512     data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturedata->fbo->FBO);
   513     /* TODO: check if texture pixel format allows this operation */
   514     data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->type, texturedata->texture, 0);
   515     /* Check FBO status */
   516     status = data->glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
   517     if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
   518         return SDL_SetError("glFramebufferTexture2DOES() failed");
   519     }
   520     return 0;
   521 }
   522 
   523 
   524 static int
   525 GLES_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
   526 {
   527     return 0;  /* nothing to do in this backend. */
   528 }
   529 
   530 static int
   531 GLES_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
   532 {
   533     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   534     size_t i;
   535 
   536     if (!verts) {
   537         return -1;
   538     }
   539 
   540     cmd->data.draw.count = count;
   541     for (i = 0; i < count; i++) {
   542         *(verts++) = 0.5f + points[i].x;
   543         *(verts++) = 0.5f + points[i].y;
   544     }
   545 
   546     return 0;
   547 }
   548 
   549 static int
   550 GLES_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
   551 {
   552     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 8 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   553     size_t i;
   554 
   555     if (!verts) {
   556         return -1;
   557     }
   558 
   559     cmd->data.draw.count = count;
   560 
   561     for (i = 0; i < count; i++) {
   562         const SDL_FRect *rect = &rects[i];
   563         const GLfloat minx = rect->x;
   564         const GLfloat maxx = rect->x + rect->w;
   565         const GLfloat miny = rect->y;
   566         const GLfloat maxy = rect->y + rect->h;
   567         *(verts++) = minx;
   568         *(verts++) = miny;
   569         *(verts++) = maxx;
   570         *(verts++) = miny;
   571         *(verts++) = minx;
   572         *(verts++) = maxy;
   573         *(verts++) = maxx;
   574         *(verts++) = maxy;
   575     }
   576 
   577     return 0;
   578 }
   579 
   580 static int
   581 GLES_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
   582                           const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   583 {
   584     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   585     GLfloat minx, miny, maxx, maxy;
   586     GLfloat minu, maxu, minv, maxv;
   587     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 16 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   588 
   589     if (!verts) {
   590         return -1;
   591     }
   592 
   593     cmd->data.draw.count = 1;
   594 
   595     minx = dstrect->x;
   596     miny = dstrect->y;
   597     maxx = dstrect->x + dstrect->w;
   598     maxy = dstrect->y + dstrect->h;
   599 
   600     minu = (GLfloat) srcrect->x / texture->w;
   601     minu *= texturedata->texw;
   602     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   603     maxu *= texturedata->texw;
   604     minv = (GLfloat) srcrect->y / texture->h;
   605     minv *= texturedata->texh;
   606     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   607     maxv *= texturedata->texh;
   608 
   609     *(verts++) = minx;
   610     *(verts++) = miny;
   611     *(verts++) = maxx;
   612     *(verts++) = miny;
   613     *(verts++) = minx;
   614     *(verts++) = maxy;
   615     *(verts++) = maxx;
   616     *(verts++) = maxy;
   617 
   618     *(verts++) = minu;
   619     *(verts++) = minv;
   620     *(verts++) = maxu;
   621     *(verts++) = minv;
   622     *(verts++) = minu;
   623     *(verts++) = maxv;
   624     *(verts++) = maxu;
   625     *(verts++) = maxv;
   626 
   627     return 0;
   628 }
   629 
   630 static int
   631 GLES_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
   632                         const SDL_Rect * srcquad, const SDL_FRect * dstrect,
   633                         const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
   634 {
   635     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   636     GLfloat minx, miny, maxx, maxy;
   637     GLfloat centerx, centery;
   638     GLfloat minu, maxu, minv, maxv;
   639     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 19 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   640 
   641     if (!verts) {
   642         return -1;
   643     }
   644 
   645     centerx = center->x;
   646     centery = center->y;
   647 
   648     if (flip & SDL_FLIP_HORIZONTAL) {
   649         minx =  dstrect->w - centerx;
   650         maxx = -centerx;
   651     }
   652     else {
   653         minx = -centerx;
   654         maxx =  dstrect->w - centerx;
   655     }
   656 
   657     if (flip & SDL_FLIP_VERTICAL) {
   658         miny =  dstrect->h - centery;
   659         maxy = -centery;
   660     }
   661     else {
   662         miny = -centery;
   663         maxy =  dstrect->h - centery;
   664     }
   665 
   666     minu = (GLfloat) srcquad->x / texture->w;
   667     minu *= texturedata->texw;
   668     maxu = (GLfloat) (srcquad->x + srcquad->w) / texture->w;
   669     maxu *= texturedata->texw;
   670     minv = (GLfloat) srcquad->y / texture->h;
   671     minv *= texturedata->texh;
   672     maxv = (GLfloat) (srcquad->y + srcquad->h) / texture->h;
   673     maxv *= texturedata->texh;
   674 
   675     cmd->data.draw.count = 1;
   676 
   677     *(verts++) = minx;
   678     *(verts++) = miny;
   679     *(verts++) = maxx;
   680     *(verts++) = miny;
   681     *(verts++) = minx;
   682     *(verts++) = maxy;
   683     *(verts++) = maxx;
   684     *(verts++) = maxy;
   685 
   686     *(verts++) = minu;
   687     *(verts++) = minv;
   688     *(verts++) = maxu;
   689     *(verts++) = minv;
   690     *(verts++) = minu;
   691     *(verts++) = maxv;
   692     *(verts++) = maxu;
   693     *(verts++) = maxv;
   694 
   695     *(verts++) = (GLfloat) dstrect->x + centerx;
   696     *(verts++) = (GLfloat) dstrect->y + centery;
   697     *(verts++) = (GLfloat) angle;
   698 
   699     return 0;
   700 }
   701 
   702 static void
   703 SetDrawState(GLES_RenderData *data, const SDL_RenderCommand *cmd)
   704 {
   705     const SDL_BlendMode blend = cmd->data.draw.blend;
   706     const Uint8 r = cmd->data.draw.r;
   707     const Uint8 g = cmd->data.draw.g;
   708     const Uint8 b = cmd->data.draw.b;
   709     const Uint8 a = cmd->data.draw.a;
   710     const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
   711 
   712     if (color != data->drawstate.color) {
   713         const GLfloat fr = ((GLfloat) r) * inv255f;
   714         const GLfloat fg = ((GLfloat) g) * inv255f;
   715         const GLfloat fb = ((GLfloat) b) * inv255f;
   716         const GLfloat fa = ((GLfloat) a) * inv255f;
   717         data->glColor4f(fr, fg, fb, fa);
   718         data->drawstate.color = color;
   719     }
   720 
   721     if (data->drawstate.viewport_dirty) {
   722         const SDL_Rect *viewport = &data->drawstate.viewport;
   723         const SDL_bool istarget = (data->drawstate.target != NULL);
   724         data->glMatrixMode(GL_PROJECTION);
   725         data->glLoadIdentity();
   726         data->glViewport(viewport->x,
   727                          istarget ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
   728                          viewport->w, viewport->h);
   729         if (viewport->w && viewport->h) {
   730             data->glOrthof((GLfloat) 0, (GLfloat) viewport->w,
   731                            (GLfloat) (istarget ? 0 : viewport->h),
   732                            (GLfloat) (istarget ? viewport->h : 0),
   733                            0.0, 1.0);
   734         }
   735         data->glMatrixMode(GL_MODELVIEW);
   736         data->drawstate.viewport_dirty = SDL_FALSE;
   737     }
   738 
   739     if (data->drawstate.cliprect_enabled_dirty) {
   740         if (data->drawstate.cliprect_enabled) {
   741             data->glEnable(GL_SCISSOR_TEST);
   742         } else {
   743             data->glDisable(GL_SCISSOR_TEST);
   744         }
   745         data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
   746     }
   747 
   748     if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
   749         const SDL_Rect *viewport = &data->drawstate.viewport;
   750         const SDL_Rect *rect = &data->drawstate.cliprect;
   751         const SDL_bool istarget = (data->drawstate.target != NULL);
   752         data->glScissor(viewport->x + rect->x,
   753                         istarget ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
   754                         rect->w, rect->h);
   755         data->drawstate.cliprect_dirty = SDL_FALSE;
   756     }
   757 
   758     if (blend != data->drawstate.blend) {
   759         if (blend == SDL_BLENDMODE_NONE) {
   760             data->glDisable(GL_BLEND);
   761         } else {
   762             data->glEnable(GL_BLEND);
   763             if (data->GL_OES_blend_func_separate_supported) {
   764                 data->glBlendFuncSeparateOES(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
   765                                              GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
   766                                              GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
   767                                              GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
   768             } else {
   769                 data->glBlendFunc(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
   770                                   GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
   771             }
   772             if (data->GL_OES_blend_equation_separate_supported) {
   773                 data->glBlendEquationSeparateOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)),
   774                                                  GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
   775             } else if (data->GL_OES_blend_subtract_supported) {
   776                 data->glBlendEquationOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)));
   777             }
   778         }
   779         data->drawstate.blend = blend;
   780     }
   781 
   782     if ((cmd->data.draw.texture != NULL) != data->drawstate.texturing) {
   783         if (cmd->data.draw.texture == NULL) {
   784             data->glDisable(GL_TEXTURE_2D);
   785             data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   786             data->drawstate.texturing = SDL_FALSE;
   787         } else {
   788             data->glEnable(GL_TEXTURE_2D);
   789             data->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   790             data->drawstate.texturing = SDL_TRUE;
   791         }
   792     }
   793 }
   794 
   795 static void
   796 SetCopyState(GLES_RenderData *data, const SDL_RenderCommand *cmd)
   797 {
   798     SDL_Texture *texture = cmd->data.draw.texture;
   799     SetDrawState(data, cmd);
   800 
   801     if (texture != data->drawstate.texture) {
   802         GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   803         data->glBindTexture(GL_TEXTURE_2D, texturedata->texture);
   804         data->drawstate.texture = texture;
   805     }
   806 }
   807 
   808 static int
   809 GLES_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
   810 {
   811     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   812     size_t i;
   813 
   814     if (GLES_ActivateRenderer(renderer) < 0) {
   815         return -1;
   816     }
   817 
   818     data->drawstate.target = renderer->target;
   819 
   820     if (!renderer->target) {
   821         SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh);
   822     }
   823 
   824     while (cmd) {
   825         switch (cmd->command) {
   826             case SDL_RENDERCMD_SETDRAWCOLOR: {
   827                 break;  /* not used in this render backend. */
   828             }
   829 
   830             case SDL_RENDERCMD_SETVIEWPORT: {
   831                 SDL_Rect *viewport = &data->drawstate.viewport;
   832                 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
   833                     SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
   834                     data->drawstate.viewport_dirty = SDL_TRUE;
   835                 }
   836                 break;
   837             }
   838 
   839             case SDL_RENDERCMD_SETCLIPRECT: {
   840                 const SDL_Rect *rect = &cmd->data.cliprect.rect;
   841                 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
   842                     data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
   843                     data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
   844                 }
   845                 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
   846                     SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
   847                     data->drawstate.cliprect_dirty = SDL_TRUE;
   848                 }
   849                 break;
   850             }
   851 
   852             case SDL_RENDERCMD_CLEAR: {
   853                 const Uint8 r = cmd->data.color.r;
   854                 const Uint8 g = cmd->data.color.g;
   855                 const Uint8 b = cmd->data.color.b;
   856                 const Uint8 a = cmd->data.color.a;
   857                 const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
   858                 if (color != data->drawstate.clear_color) {
   859                     const GLfloat fr = ((GLfloat) r) * inv255f;
   860                     const GLfloat fg = ((GLfloat) g) * inv255f;
   861                     const GLfloat fb = ((GLfloat) b) * inv255f;
   862                     const GLfloat fa = ((GLfloat) a) * inv255f;
   863                     data->glClearColor(fr, fg, fb, fa);
   864                     data->drawstate.clear_color = color;
   865                 }
   866 
   867                 if (data->drawstate.cliprect_enabled) {
   868                     data->glDisable(GL_SCISSOR_TEST);
   869                     data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
   870                 }
   871 
   872                 data->glClear(GL_COLOR_BUFFER_BIT);
   873 
   874                 break;
   875             }
   876 
   877             case SDL_RENDERCMD_DRAW_POINTS: {
   878                 const size_t count = cmd->data.draw.count;
   879                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
   880                 SetDrawState(data, cmd);
   881                 data->glVertexPointer(2, GL_FLOAT, 0, verts);
   882                 data->glDrawArrays(GL_POINTS, 0, (GLsizei) count);
   883                 break;
   884             }
   885 
   886             case SDL_RENDERCMD_DRAW_LINES: {
   887                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
   888                 const size_t count = cmd->data.draw.count;
   889                 SetDrawState(data, cmd);
   890                 data->glVertexPointer(2, GL_FLOAT, 0, verts);
   891                 if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
   892                     /* GL_LINE_LOOP takes care of the final segment */
   893                     data->glDrawArrays(GL_LINE_LOOP, 0, (GLsizei) (count - 1));
   894                 } else {
   895                     data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count);
   896                     /* We need to close the endpoint of the line */
   897                     data->glDrawArrays(GL_POINTS, (GLsizei) (count - 1), 1);
   898                 }
   899                 break;
   900             }
   901 
   902             case SDL_RENDERCMD_FILL_RECTS: {
   903                 const size_t count = cmd->data.draw.count;
   904                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
   905                 GLsizei offset = 0;
   906                 SetDrawState(data, cmd);
   907                 data->glVertexPointer(2, GL_FLOAT, 0, verts);
   908                 for (i = 0; i < count; ++i, offset += 4) {
   909                     data->glDrawArrays(GL_TRIANGLE_STRIP, offset, 4);
   910                 }
   911                 break;
   912             }
   913 
   914             case SDL_RENDERCMD_COPY: {
   915                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
   916                 SetCopyState(data, cmd);
   917                 data->glVertexPointer(2, GL_FLOAT, 0, verts);
   918                 data->glTexCoordPointer(2, GL_FLOAT, 0, verts + 8);
   919                 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   920                 break;
   921             }
   922 
   923             case SDL_RENDERCMD_COPY_EX: {
   924                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
   925                 const GLfloat translatex = verts[16];
   926                 const GLfloat translatey = verts[17];
   927                 const GLfloat angle = verts[18];
   928                 SetCopyState(data, cmd);
   929                 data->glVertexPointer(2, GL_FLOAT, 0, verts);
   930                 data->glTexCoordPointer(2, GL_FLOAT, 0, verts + 8);
   931 
   932                 /* Translate to flip, rotate, translate to position */
   933                 data->glPushMatrix();
   934                 data->glTranslatef(translatex, translatey, 0.0f);
   935                 data->glRotatef(angle, 0.0, 0.0, 1.0);
   936                 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   937                 data->glPopMatrix();
   938                 break;
   939             }
   940 
   941             case SDL_RENDERCMD_NO_OP:
   942                 break;
   943         }
   944 
   945         cmd = cmd->next;
   946     }
   947 
   948     return 0;
   949 }
   950 
   951 static int
   952 GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   953                       Uint32 pixel_format, void * pixels, int pitch)
   954 {
   955     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   956     Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888;
   957     void *temp_pixels;
   958     int temp_pitch;
   959     Uint8 *src, *dst, *tmp;
   960     int w, h, length, rows;
   961     int status;
   962 
   963     GLES_ActivateRenderer(renderer);
   964 
   965     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
   966     temp_pixels = SDL_malloc(rect->h * temp_pitch);
   967     if (!temp_pixels) {
   968         return SDL_OutOfMemory();
   969     }
   970 
   971     SDL_GetRendererOutputSize(renderer, &w, &h);
   972 
   973     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
   974 
   975     data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
   976                        rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels);
   977 
   978     /* Flip the rows to be top-down if necessary */
   979     if (!renderer->target) {
   980         SDL_bool isstack;
   981         length = rect->w * SDL_BYTESPERPIXEL(temp_format);
   982         src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
   983         dst = (Uint8*)temp_pixels;
   984         tmp = SDL_small_alloc(Uint8, length, &isstack);
   985         rows = rect->h / 2;
   986         while (rows--) {
   987             SDL_memcpy(tmp, dst, length);
   988             SDL_memcpy(dst, src, length);
   989             SDL_memcpy(src, tmp, length);
   990             dst += temp_pitch;
   991             src -= temp_pitch;
   992         }
   993         SDL_small_free(tmp, isstack);
   994     }
   995 
   996     status = SDL_ConvertPixels(rect->w, rect->h,
   997                                temp_format, temp_pixels, temp_pitch,
   998                                pixel_format, pixels, pitch);
   999     SDL_free(temp_pixels);
  1000 
  1001     return status;
  1002 }
  1003 
  1004 static void
  1005 GLES_RenderPresent(SDL_Renderer * renderer)
  1006 {
  1007     GLES_ActivateRenderer(renderer);
  1008 
  1009     SDL_GL_SwapWindow(renderer->window);
  1010 }
  1011 
  1012 static void
  1013 GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1014 {
  1015     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
  1016 
  1017     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
  1018 
  1019     GLES_ActivateRenderer(renderer);
  1020 
  1021     if (renderdata->drawstate.texture == texture) {
  1022         renderdata->drawstate.texture = NULL;
  1023     }
  1024     if (renderdata->drawstate.target == texture) {
  1025         renderdata->drawstate.target = NULL;
  1026     }
  1027 
  1028     if (!data) {
  1029         return;
  1030     }
  1031     if (data->texture) {
  1032         renderdata->glDeleteTextures(1, &data->texture);
  1033     }
  1034     SDL_free(data->pixels);
  1035     SDL_free(data);
  1036     texture->driverdata = NULL;
  1037 }
  1038 
  1039 static void
  1040 GLES_DestroyRenderer(SDL_Renderer * renderer)
  1041 {
  1042     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
  1043 
  1044     if (data) {
  1045         if (data->context) {
  1046             while (data->framebuffers) {
  1047                GLES_FBOList *nextnode = data->framebuffers->next;
  1048                data->glDeleteFramebuffersOES(1, &data->framebuffers->FBO);
  1049                SDL_free(data->framebuffers);
  1050                data->framebuffers = nextnode;
  1051             }
  1052             SDL_GL_DeleteContext(data->context);
  1053         }
  1054         SDL_free(data);
  1055     }
  1056     SDL_free(renderer);
  1057 }
  1058 
  1059 static int GLES_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
  1060 {
  1061     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
  1062     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
  1063     GLES_ActivateRenderer(renderer);
  1064 
  1065     data->glEnable(GL_TEXTURE_2D);
  1066     data->glBindTexture(texturedata->type, texturedata->texture);
  1067 
  1068     data->drawstate.texture = texture;
  1069     data->drawstate.texturing = SDL_TRUE;
  1070 
  1071     if (texw) {
  1072         *texw = (float)texturedata->texw;
  1073     }
  1074     if (texh) {
  1075         *texh = (float)texturedata->texh;
  1076     }
  1077 
  1078     return 0;
  1079 }
  1080 
  1081 static int GLES_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
  1082 {
  1083     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
  1084     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
  1085     GLES_ActivateRenderer(renderer);
  1086     data->glDisable(texturedata->type);
  1087 
  1088     data->drawstate.texture = NULL;
  1089     data->drawstate.texturing = SDL_FALSE;
  1090 
  1091     return 0;
  1092 }
  1093 
  1094 static SDL_Renderer *
  1095 GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
  1096 {
  1097     SDL_Renderer *renderer;
  1098     GLES_RenderData *data;
  1099     GLint value;
  1100     Uint32 window_flags;
  1101     int profile_mask = 0, major = 0, minor = 0;
  1102     SDL_bool changed_window = SDL_FALSE;
  1103 
  1104     SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
  1105     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
  1106     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
  1107 
  1108     window_flags = SDL_GetWindowFlags(window);
  1109     if (!(window_flags & SDL_WINDOW_OPENGL) ||
  1110         profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
  1111 
  1112         changed_window = SDL_TRUE;
  1113         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
  1114         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
  1115         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
  1116 
  1117         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
  1118             goto error;
  1119         }
  1120     }
  1121 
  1122     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
  1123     if (!renderer) {
  1124         SDL_OutOfMemory();
  1125         goto error;
  1126     }
  1127 
  1128     data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data));
  1129     if (!data) {
  1130         GLES_DestroyRenderer(renderer);
  1131         SDL_OutOfMemory();
  1132         goto error;
  1133     }
  1134 
  1135     renderer->WindowEvent = GLES_WindowEvent;
  1136     renderer->GetOutputSize = GLES_GetOutputSize;
  1137     renderer->SupportsBlendMode = GLES_SupportsBlendMode;
  1138     renderer->CreateTexture = GLES_CreateTexture;
  1139     renderer->UpdateTexture = GLES_UpdateTexture;
  1140     renderer->LockTexture = GLES_LockTexture;
  1141     renderer->UnlockTexture = GLES_UnlockTexture;
  1142     renderer->SetRenderTarget = GLES_SetRenderTarget;
  1143     renderer->QueueSetViewport = GLES_QueueSetViewport;
  1144     renderer->QueueSetDrawColor = GLES_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
  1145     renderer->QueueDrawPoints = GLES_QueueDrawPoints;
  1146     renderer->QueueDrawLines = GLES_QueueDrawPoints;  /* lines and points queue vertices the same way. */
  1147     renderer->QueueFillRects = GLES_QueueFillRects;
  1148     renderer->QueueCopy = GLES_QueueCopy;
  1149     renderer->QueueCopyEx = GLES_QueueCopyEx;
  1150     renderer->RunCommandQueue = GLES_RunCommandQueue;
  1151     renderer->RenderReadPixels = GLES_RenderReadPixels;
  1152     renderer->RenderPresent = GLES_RenderPresent;
  1153     renderer->DestroyTexture = GLES_DestroyTexture;
  1154     renderer->DestroyRenderer = GLES_DestroyRenderer;
  1155     renderer->GL_BindTexture = GLES_BindTexture;
  1156     renderer->GL_UnbindTexture = GLES_UnbindTexture;
  1157     renderer->info = GLES_RenderDriver.info;
  1158     renderer->info.flags = SDL_RENDERER_ACCELERATED;
  1159     renderer->driverdata = data;
  1160     renderer->window = window;
  1161 
  1162     data->context = SDL_GL_CreateContext(window);
  1163     if (!data->context) {
  1164         GLES_DestroyRenderer(renderer);
  1165         goto error;
  1166     }
  1167     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
  1168         GLES_DestroyRenderer(renderer);
  1169         goto error;
  1170     }
  1171 
  1172     if (GLES_LoadFunctions(data) < 0) {
  1173         GLES_DestroyRenderer(renderer);
  1174         goto error;
  1175     }
  1176 
  1177     if (flags & SDL_RENDERER_PRESENTVSYNC) {
  1178         SDL_GL_SetSwapInterval(1);
  1179     } else {
  1180         SDL_GL_SetSwapInterval(0);
  1181     }
  1182     if (SDL_GL_GetSwapInterval() > 0) {
  1183         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  1184     }
  1185 
  1186     value = 0;
  1187     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
  1188     renderer->info.max_texture_width = value;
  1189     value = 0;
  1190     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
  1191     renderer->info.max_texture_height = value;
  1192 
  1193     /* Android does not report GL_OES_framebuffer_object but the functionality seems to be there anyway */
  1194     if (SDL_GL_ExtensionSupported("GL_OES_framebuffer_object") || data->glGenFramebuffersOES) {
  1195         data->GL_OES_framebuffer_object_supported = SDL_TRUE;
  1196         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
  1197 
  1198         value = 0;
  1199         data->glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &value);
  1200         data->window_framebuffer = (GLuint)value;
  1201     }
  1202     data->framebuffers = NULL;
  1203 
  1204     if (SDL_GL_ExtensionSupported("GL_OES_blend_func_separate")) {
  1205         data->GL_OES_blend_func_separate_supported = SDL_TRUE;
  1206     }
  1207     if (SDL_GL_ExtensionSupported("GL_OES_blend_equation_separate")) {
  1208         data->GL_OES_blend_equation_separate_supported = SDL_TRUE;
  1209     }
  1210     if (SDL_GL_ExtensionSupported("GL_OES_blend_subtract")) {
  1211         data->GL_OES_blend_subtract_supported = SDL_TRUE;
  1212     }
  1213 
  1214     /* Set up parameters for rendering */
  1215     data->glDisable(GL_DEPTH_TEST);
  1216     data->glDisable(GL_CULL_FACE);
  1217 
  1218     data->glMatrixMode(GL_MODELVIEW);
  1219     data->glLoadIdentity();
  1220 
  1221     data->glEnableClientState(GL_VERTEX_ARRAY);
  1222     data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  1223 
  1224     data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  1225 
  1226     data->drawstate.blend = SDL_BLENDMODE_INVALID;
  1227     data->drawstate.color = 0xFFFFFFFF;
  1228     data->drawstate.clear_color = 0xFFFFFFFF;
  1229 
  1230     return renderer;
  1231 
  1232 error:
  1233     if (changed_window) {
  1234         /* Uh oh, better try to put it back... */
  1235         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
  1236         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
  1237         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
  1238         SDL_RecreateWindow(window, window_flags);
  1239     }
  1240     return NULL;
  1241 }
  1242 
  1243 SDL_RenderDriver GLES_RenderDriver = {
  1244     GLES_CreateRenderer,
  1245     {
  1246      "opengles",
  1247      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
  1248      1,
  1249      {SDL_PIXELFORMAT_ABGR8888},
  1250      0,
  1251      0
  1252     }
  1253 };
  1254 
  1255 #endif /* SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED */
  1256 
  1257 /* vi: set ts=4 sw=4 expandtab: */