src/render/opengles/SDL_render_gles.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 14 Jun 2019 13:56:42 -0700
changeset 12860 0f52dd40abe5
parent 12665 4743da9c3eea
child 13037 d465f3a64af6
permissions -rw-r--r--
Worked around "Undefined symbol: ___isPlatformVersionAtLeast()" link error on Xcode 11 beta
     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     data->drawstate.viewport_dirty = SDL_TRUE;
   507 
   508     if (texture == NULL) {
   509         data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, data->window_framebuffer);
   510         return 0;
   511     }
   512 
   513     texturedata = (GLES_TextureData *) texture->driverdata;
   514     data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturedata->fbo->FBO);
   515     /* TODO: check if texture pixel format allows this operation */
   516     data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->type, texturedata->texture, 0);
   517     /* Check FBO status */
   518     status = data->glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
   519     if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
   520         return SDL_SetError("glFramebufferTexture2DOES() failed");
   521     }
   522     return 0;
   523 }
   524 
   525 
   526 static int
   527 GLES_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
   528 {
   529     return 0;  /* nothing to do in this backend. */
   530 }
   531 
   532 static int
   533 GLES_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
   534 {
   535     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   536     int i;
   537 
   538     if (!verts) {
   539         return -1;
   540     }
   541 
   542     cmd->data.draw.count = count;
   543     for (i = 0; i < count; i++) {
   544         *(verts++) = 0.5f + points[i].x;
   545         *(verts++) = 0.5f + points[i].y;
   546     }
   547 
   548     return 0;
   549 }
   550 
   551 static int
   552 GLES_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
   553 {
   554     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 8 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   555     int i;
   556 
   557     if (!verts) {
   558         return -1;
   559     }
   560 
   561     cmd->data.draw.count = count;
   562 
   563     for (i = 0; i < count; i++) {
   564         const SDL_FRect *rect = &rects[i];
   565         const GLfloat minx = rect->x;
   566         const GLfloat maxx = rect->x + rect->w;
   567         const GLfloat miny = rect->y;
   568         const GLfloat maxy = rect->y + rect->h;
   569         *(verts++) = minx;
   570         *(verts++) = miny;
   571         *(verts++) = maxx;
   572         *(verts++) = miny;
   573         *(verts++) = minx;
   574         *(verts++) = maxy;
   575         *(verts++) = maxx;
   576         *(verts++) = maxy;
   577     }
   578 
   579     return 0;
   580 }
   581 
   582 static int
   583 GLES_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
   584                           const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   585 {
   586     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   587     GLfloat minx, miny, maxx, maxy;
   588     GLfloat minu, maxu, minv, maxv;
   589     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 16 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   590 
   591     if (!verts) {
   592         return -1;
   593     }
   594 
   595     cmd->data.draw.count = 1;
   596 
   597     minx = dstrect->x;
   598     miny = dstrect->y;
   599     maxx = dstrect->x + dstrect->w;
   600     maxy = dstrect->y + dstrect->h;
   601 
   602     minu = (GLfloat) srcrect->x / texture->w;
   603     minu *= texturedata->texw;
   604     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   605     maxu *= texturedata->texw;
   606     minv = (GLfloat) srcrect->y / texture->h;
   607     minv *= texturedata->texh;
   608     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   609     maxv *= texturedata->texh;
   610 
   611     *(verts++) = minx;
   612     *(verts++) = miny;
   613     *(verts++) = maxx;
   614     *(verts++) = miny;
   615     *(verts++) = minx;
   616     *(verts++) = maxy;
   617     *(verts++) = maxx;
   618     *(verts++) = maxy;
   619 
   620     *(verts++) = minu;
   621     *(verts++) = minv;
   622     *(verts++) = maxu;
   623     *(verts++) = minv;
   624     *(verts++) = minu;
   625     *(verts++) = maxv;
   626     *(verts++) = maxu;
   627     *(verts++) = maxv;
   628 
   629     return 0;
   630 }
   631 
   632 static int
   633 GLES_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
   634                         const SDL_Rect * srcquad, const SDL_FRect * dstrect,
   635                         const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
   636 {
   637     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   638     GLfloat minx, miny, maxx, maxy;
   639     GLfloat centerx, centery;
   640     GLfloat minu, maxu, minv, maxv;
   641     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 19 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   642 
   643     if (!verts) {
   644         return -1;
   645     }
   646 
   647     centerx = center->x;
   648     centery = center->y;
   649 
   650     if (flip & SDL_FLIP_HORIZONTAL) {
   651         minx =  dstrect->w - centerx;
   652         maxx = -centerx;
   653     }
   654     else {
   655         minx = -centerx;
   656         maxx =  dstrect->w - centerx;
   657     }
   658 
   659     if (flip & SDL_FLIP_VERTICAL) {
   660         miny =  dstrect->h - centery;
   661         maxy = -centery;
   662     }
   663     else {
   664         miny = -centery;
   665         maxy =  dstrect->h - centery;
   666     }
   667 
   668     minu = (GLfloat) srcquad->x / texture->w;
   669     minu *= texturedata->texw;
   670     maxu = (GLfloat) (srcquad->x + srcquad->w) / texture->w;
   671     maxu *= texturedata->texw;
   672     minv = (GLfloat) srcquad->y / texture->h;
   673     minv *= texturedata->texh;
   674     maxv = (GLfloat) (srcquad->y + srcquad->h) / texture->h;
   675     maxv *= texturedata->texh;
   676 
   677     cmd->data.draw.count = 1;
   678 
   679     *(verts++) = minx;
   680     *(verts++) = miny;
   681     *(verts++) = maxx;
   682     *(verts++) = miny;
   683     *(verts++) = minx;
   684     *(verts++) = maxy;
   685     *(verts++) = maxx;
   686     *(verts++) = maxy;
   687 
   688     *(verts++) = minu;
   689     *(verts++) = minv;
   690     *(verts++) = maxu;
   691     *(verts++) = minv;
   692     *(verts++) = minu;
   693     *(verts++) = maxv;
   694     *(verts++) = maxu;
   695     *(verts++) = maxv;
   696 
   697     *(verts++) = (GLfloat) dstrect->x + centerx;
   698     *(verts++) = (GLfloat) dstrect->y + centery;
   699     *(verts++) = (GLfloat) angle;
   700 
   701     return 0;
   702 }
   703 
   704 static void
   705 SetDrawState(GLES_RenderData *data, const SDL_RenderCommand *cmd)
   706 {
   707     const SDL_BlendMode blend = cmd->data.draw.blend;
   708     const Uint8 r = cmd->data.draw.r;
   709     const Uint8 g = cmd->data.draw.g;
   710     const Uint8 b = cmd->data.draw.b;
   711     const Uint8 a = cmd->data.draw.a;
   712     const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
   713 
   714     if (color != data->drawstate.color) {
   715         const GLfloat fr = ((GLfloat) r) * inv255f;
   716         const GLfloat fg = ((GLfloat) g) * inv255f;
   717         const GLfloat fb = ((GLfloat) b) * inv255f;
   718         const GLfloat fa = ((GLfloat) a) * inv255f;
   719         data->glColor4f(fr, fg, fb, fa);
   720         data->drawstate.color = color;
   721     }
   722 
   723     if (data->drawstate.viewport_dirty) {
   724         const SDL_Rect *viewport = &data->drawstate.viewport;
   725         const SDL_bool istarget = (data->drawstate.target != NULL);
   726         data->glMatrixMode(GL_PROJECTION);
   727         data->glLoadIdentity();
   728         data->glViewport(viewport->x,
   729                          istarget ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
   730                          viewport->w, viewport->h);
   731         if (viewport->w && viewport->h) {
   732             data->glOrthof((GLfloat) 0, (GLfloat) viewport->w,
   733                            (GLfloat) (istarget ? 0 : viewport->h),
   734                            (GLfloat) (istarget ? viewport->h : 0),
   735                            0.0, 1.0);
   736         }
   737         data->glMatrixMode(GL_MODELVIEW);
   738         data->drawstate.viewport_dirty = SDL_FALSE;
   739     }
   740 
   741     if (data->drawstate.cliprect_enabled_dirty) {
   742         if (data->drawstate.cliprect_enabled) {
   743             data->glEnable(GL_SCISSOR_TEST);
   744         } else {
   745             data->glDisable(GL_SCISSOR_TEST);
   746         }
   747         data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
   748     }
   749 
   750     if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
   751         const SDL_Rect *viewport = &data->drawstate.viewport;
   752         const SDL_Rect *rect = &data->drawstate.cliprect;
   753         const SDL_bool istarget = (data->drawstate.target != NULL);
   754         data->glScissor(viewport->x + rect->x,
   755                         istarget ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
   756                         rect->w, rect->h);
   757         data->drawstate.cliprect_dirty = SDL_FALSE;
   758     }
   759 
   760     if (blend != data->drawstate.blend) {
   761         if (blend == SDL_BLENDMODE_NONE) {
   762             data->glDisable(GL_BLEND);
   763         } else {
   764             data->glEnable(GL_BLEND);
   765             if (data->GL_OES_blend_func_separate_supported) {
   766                 data->glBlendFuncSeparateOES(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
   767                                              GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
   768                                              GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
   769                                              GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
   770             } else {
   771                 data->glBlendFunc(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
   772                                   GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
   773             }
   774             if (data->GL_OES_blend_equation_separate_supported) {
   775                 data->glBlendEquationSeparateOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)),
   776                                                  GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
   777             } else if (data->GL_OES_blend_subtract_supported) {
   778                 data->glBlendEquationOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)));
   779             }
   780         }
   781         data->drawstate.blend = blend;
   782     }
   783 
   784     if ((cmd->data.draw.texture != NULL) != data->drawstate.texturing) {
   785         if (cmd->data.draw.texture == NULL) {
   786             data->glDisable(GL_TEXTURE_2D);
   787             data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   788             data->drawstate.texturing = SDL_FALSE;
   789         } else {
   790             data->glEnable(GL_TEXTURE_2D);
   791             data->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   792             data->drawstate.texturing = SDL_TRUE;
   793         }
   794     }
   795 }
   796 
   797 static void
   798 SetCopyState(GLES_RenderData *data, const SDL_RenderCommand *cmd)
   799 {
   800     SDL_Texture *texture = cmd->data.draw.texture;
   801     SetDrawState(data, cmd);
   802 
   803     if (texture != data->drawstate.texture) {
   804         GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   805         data->glBindTexture(GL_TEXTURE_2D, texturedata->texture);
   806         data->drawstate.texture = texture;
   807     }
   808 }
   809 
   810 static int
   811 GLES_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
   812 {
   813     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   814     size_t i;
   815 
   816     if (GLES_ActivateRenderer(renderer) < 0) {
   817         return -1;
   818     }
   819 
   820     data->drawstate.target = renderer->target;
   821 
   822     if (!renderer->target) {
   823         SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh);
   824     }
   825 
   826     while (cmd) {
   827         switch (cmd->command) {
   828             case SDL_RENDERCMD_SETDRAWCOLOR: {
   829                 break;  /* not used in this render backend. */
   830             }
   831 
   832             case SDL_RENDERCMD_SETVIEWPORT: {
   833                 SDL_Rect *viewport = &data->drawstate.viewport;
   834                 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
   835                     SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
   836                     data->drawstate.viewport_dirty = SDL_TRUE;
   837                 }
   838                 break;
   839             }
   840 
   841             case SDL_RENDERCMD_SETCLIPRECT: {
   842                 const SDL_Rect *rect = &cmd->data.cliprect.rect;
   843                 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
   844                     data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
   845                     data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
   846                 }
   847                 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
   848                     SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
   849                     data->drawstate.cliprect_dirty = SDL_TRUE;
   850                 }
   851                 break;
   852             }
   853 
   854             case SDL_RENDERCMD_CLEAR: {
   855                 const Uint8 r = cmd->data.color.r;
   856                 const Uint8 g = cmd->data.color.g;
   857                 const Uint8 b = cmd->data.color.b;
   858                 const Uint8 a = cmd->data.color.a;
   859                 const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
   860                 if (color != data->drawstate.clear_color) {
   861                     const GLfloat fr = ((GLfloat) r) * inv255f;
   862                     const GLfloat fg = ((GLfloat) g) * inv255f;
   863                     const GLfloat fb = ((GLfloat) b) * inv255f;
   864                     const GLfloat fa = ((GLfloat) a) * inv255f;
   865                     data->glClearColor(fr, fg, fb, fa);
   866                     data->drawstate.clear_color = color;
   867                 }
   868 
   869                 if (data->drawstate.cliprect_enabled) {
   870                     data->glDisable(GL_SCISSOR_TEST);
   871                     data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
   872                 }
   873 
   874                 data->glClear(GL_COLOR_BUFFER_BIT);
   875 
   876                 break;
   877             }
   878 
   879             case SDL_RENDERCMD_DRAW_POINTS: {
   880                 const size_t count = cmd->data.draw.count;
   881                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
   882                 SetDrawState(data, cmd);
   883                 data->glVertexPointer(2, GL_FLOAT, 0, verts);
   884                 data->glDrawArrays(GL_POINTS, 0, (GLsizei) count);
   885                 break;
   886             }
   887 
   888             case SDL_RENDERCMD_DRAW_LINES: {
   889                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
   890                 const size_t count = cmd->data.draw.count;
   891                 SetDrawState(data, cmd);
   892                 data->glVertexPointer(2, GL_FLOAT, 0, verts);
   893                 if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
   894                     /* GL_LINE_LOOP takes care of the final segment */
   895                     data->glDrawArrays(GL_LINE_LOOP, 0, (GLsizei) (count - 1));
   896                 } else {
   897                     data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count);
   898                     /* We need to close the endpoint of the line */
   899                     data->glDrawArrays(GL_POINTS, (GLsizei) (count - 1), 1);
   900                 }
   901                 break;
   902             }
   903 
   904             case SDL_RENDERCMD_FILL_RECTS: {
   905                 const size_t count = cmd->data.draw.count;
   906                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
   907                 GLsizei offset = 0;
   908                 SetDrawState(data, cmd);
   909                 data->glVertexPointer(2, GL_FLOAT, 0, verts);
   910                 for (i = 0; i < count; ++i, offset += 4) {
   911                     data->glDrawArrays(GL_TRIANGLE_STRIP, offset, 4);
   912                 }
   913                 break;
   914             }
   915 
   916             case SDL_RENDERCMD_COPY: {
   917                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
   918                 SetCopyState(data, cmd);
   919                 data->glVertexPointer(2, GL_FLOAT, 0, verts);
   920                 data->glTexCoordPointer(2, GL_FLOAT, 0, verts + 8);
   921                 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   922                 break;
   923             }
   924 
   925             case SDL_RENDERCMD_COPY_EX: {
   926                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
   927                 const GLfloat translatex = verts[16];
   928                 const GLfloat translatey = verts[17];
   929                 const GLfloat angle = verts[18];
   930                 SetCopyState(data, cmd);
   931                 data->glVertexPointer(2, GL_FLOAT, 0, verts);
   932                 data->glTexCoordPointer(2, GL_FLOAT, 0, verts + 8);
   933 
   934                 /* Translate to flip, rotate, translate to position */
   935                 data->glPushMatrix();
   936                 data->glTranslatef(translatex, translatey, 0.0f);
   937                 data->glRotatef(angle, 0.0, 0.0, 1.0);
   938                 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   939                 data->glPopMatrix();
   940                 break;
   941             }
   942 
   943             case SDL_RENDERCMD_NO_OP:
   944                 break;
   945         }
   946 
   947         cmd = cmd->next;
   948     }
   949 
   950     return 0;
   951 }
   952 
   953 static int
   954 GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   955                       Uint32 pixel_format, void * pixels, int pitch)
   956 {
   957     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   958     Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888;
   959     void *temp_pixels;
   960     int temp_pitch;
   961     Uint8 *src, *dst, *tmp;
   962     int w, h, length, rows;
   963     int status;
   964 
   965     GLES_ActivateRenderer(renderer);
   966 
   967     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
   968     temp_pixels = SDL_malloc(rect->h * temp_pitch);
   969     if (!temp_pixels) {
   970         return SDL_OutOfMemory();
   971     }
   972 
   973     SDL_GetRendererOutputSize(renderer, &w, &h);
   974 
   975     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
   976 
   977     data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
   978                        rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels);
   979 
   980     /* Flip the rows to be top-down if necessary */
   981     if (!renderer->target) {
   982         SDL_bool isstack;
   983         length = rect->w * SDL_BYTESPERPIXEL(temp_format);
   984         src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
   985         dst = (Uint8*)temp_pixels;
   986         tmp = SDL_small_alloc(Uint8, length, &isstack);
   987         rows = rect->h / 2;
   988         while (rows--) {
   989             SDL_memcpy(tmp, dst, length);
   990             SDL_memcpy(dst, src, length);
   991             SDL_memcpy(src, tmp, length);
   992             dst += temp_pitch;
   993             src -= temp_pitch;
   994         }
   995         SDL_small_free(tmp, isstack);
   996     }
   997 
   998     status = SDL_ConvertPixels(rect->w, rect->h,
   999                                temp_format, temp_pixels, temp_pitch,
  1000                                pixel_format, pixels, pitch);
  1001     SDL_free(temp_pixels);
  1002 
  1003     return status;
  1004 }
  1005 
  1006 static void
  1007 GLES_RenderPresent(SDL_Renderer * renderer)
  1008 {
  1009     GLES_ActivateRenderer(renderer);
  1010 
  1011     SDL_GL_SwapWindow(renderer->window);
  1012 }
  1013 
  1014 static void
  1015 GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1016 {
  1017     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
  1018 
  1019     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
  1020 
  1021     GLES_ActivateRenderer(renderer);
  1022 
  1023     if (renderdata->drawstate.texture == texture) {
  1024         renderdata->drawstate.texture = NULL;
  1025     }
  1026     if (renderdata->drawstate.target == texture) {
  1027         renderdata->drawstate.target = NULL;
  1028     }
  1029 
  1030     if (!data) {
  1031         return;
  1032     }
  1033     if (data->texture) {
  1034         renderdata->glDeleteTextures(1, &data->texture);
  1035     }
  1036     SDL_free(data->pixels);
  1037     SDL_free(data);
  1038     texture->driverdata = NULL;
  1039 }
  1040 
  1041 static void
  1042 GLES_DestroyRenderer(SDL_Renderer * renderer)
  1043 {
  1044     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
  1045 
  1046     if (data) {
  1047         if (data->context) {
  1048             while (data->framebuffers) {
  1049                GLES_FBOList *nextnode = data->framebuffers->next;
  1050                data->glDeleteFramebuffersOES(1, &data->framebuffers->FBO);
  1051                SDL_free(data->framebuffers);
  1052                data->framebuffers = nextnode;
  1053             }
  1054             SDL_GL_DeleteContext(data->context);
  1055         }
  1056         SDL_free(data);
  1057     }
  1058     SDL_free(renderer);
  1059 }
  1060 
  1061 static int GLES_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
  1062 {
  1063     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
  1064     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
  1065     GLES_ActivateRenderer(renderer);
  1066 
  1067     data->glEnable(GL_TEXTURE_2D);
  1068     data->glBindTexture(texturedata->type, texturedata->texture);
  1069 
  1070     data->drawstate.texture = texture;
  1071     data->drawstate.texturing = SDL_TRUE;
  1072 
  1073     if (texw) {
  1074         *texw = (float)texturedata->texw;
  1075     }
  1076     if (texh) {
  1077         *texh = (float)texturedata->texh;
  1078     }
  1079 
  1080     return 0;
  1081 }
  1082 
  1083 static int GLES_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
  1084 {
  1085     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
  1086     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
  1087     GLES_ActivateRenderer(renderer);
  1088     data->glDisable(texturedata->type);
  1089 
  1090     data->drawstate.texture = NULL;
  1091     data->drawstate.texturing = SDL_FALSE;
  1092 
  1093     return 0;
  1094 }
  1095 
  1096 static SDL_Renderer *
  1097 GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
  1098 {
  1099     SDL_Renderer *renderer;
  1100     GLES_RenderData *data;
  1101     GLint value;
  1102     Uint32 window_flags;
  1103     int profile_mask = 0, major = 0, minor = 0;
  1104     SDL_bool changed_window = SDL_FALSE;
  1105 
  1106     SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
  1107     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
  1108     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
  1109 
  1110     window_flags = SDL_GetWindowFlags(window);
  1111     if (!(window_flags & SDL_WINDOW_OPENGL) ||
  1112         profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
  1113 
  1114         changed_window = SDL_TRUE;
  1115         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
  1116         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
  1117         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
  1118 
  1119         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
  1120             goto error;
  1121         }
  1122     }
  1123 
  1124     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
  1125     if (!renderer) {
  1126         SDL_OutOfMemory();
  1127         goto error;
  1128     }
  1129 
  1130     data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data));
  1131     if (!data) {
  1132         GLES_DestroyRenderer(renderer);
  1133         SDL_OutOfMemory();
  1134         goto error;
  1135     }
  1136 
  1137     renderer->WindowEvent = GLES_WindowEvent;
  1138     renderer->GetOutputSize = GLES_GetOutputSize;
  1139     renderer->SupportsBlendMode = GLES_SupportsBlendMode;
  1140     renderer->CreateTexture = GLES_CreateTexture;
  1141     renderer->UpdateTexture = GLES_UpdateTexture;
  1142     renderer->LockTexture = GLES_LockTexture;
  1143     renderer->UnlockTexture = GLES_UnlockTexture;
  1144     renderer->SetRenderTarget = GLES_SetRenderTarget;
  1145     renderer->QueueSetViewport = GLES_QueueSetViewport;
  1146     renderer->QueueSetDrawColor = GLES_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
  1147     renderer->QueueDrawPoints = GLES_QueueDrawPoints;
  1148     renderer->QueueDrawLines = GLES_QueueDrawPoints;  /* lines and points queue vertices the same way. */
  1149     renderer->QueueFillRects = GLES_QueueFillRects;
  1150     renderer->QueueCopy = GLES_QueueCopy;
  1151     renderer->QueueCopyEx = GLES_QueueCopyEx;
  1152     renderer->RunCommandQueue = GLES_RunCommandQueue;
  1153     renderer->RenderReadPixels = GLES_RenderReadPixels;
  1154     renderer->RenderPresent = GLES_RenderPresent;
  1155     renderer->DestroyTexture = GLES_DestroyTexture;
  1156     renderer->DestroyRenderer = GLES_DestroyRenderer;
  1157     renderer->GL_BindTexture = GLES_BindTexture;
  1158     renderer->GL_UnbindTexture = GLES_UnbindTexture;
  1159     renderer->info = GLES_RenderDriver.info;
  1160     renderer->info.flags = SDL_RENDERER_ACCELERATED;
  1161     renderer->driverdata = data;
  1162     renderer->window = window;
  1163 
  1164     data->context = SDL_GL_CreateContext(window);
  1165     if (!data->context) {
  1166         GLES_DestroyRenderer(renderer);
  1167         goto error;
  1168     }
  1169     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
  1170         GLES_DestroyRenderer(renderer);
  1171         goto error;
  1172     }
  1173 
  1174     if (GLES_LoadFunctions(data) < 0) {
  1175         GLES_DestroyRenderer(renderer);
  1176         goto error;
  1177     }
  1178 
  1179     if (flags & SDL_RENDERER_PRESENTVSYNC) {
  1180         SDL_GL_SetSwapInterval(1);
  1181     } else {
  1182         SDL_GL_SetSwapInterval(0);
  1183     }
  1184     if (SDL_GL_GetSwapInterval() > 0) {
  1185         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  1186     }
  1187 
  1188     value = 0;
  1189     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
  1190     renderer->info.max_texture_width = value;
  1191     value = 0;
  1192     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
  1193     renderer->info.max_texture_height = value;
  1194 
  1195     /* Android does not report GL_OES_framebuffer_object but the functionality seems to be there anyway */
  1196     if (SDL_GL_ExtensionSupported("GL_OES_framebuffer_object") || data->glGenFramebuffersOES) {
  1197         data->GL_OES_framebuffer_object_supported = SDL_TRUE;
  1198         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
  1199 
  1200         value = 0;
  1201         data->glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &value);
  1202         data->window_framebuffer = (GLuint)value;
  1203     }
  1204     data->framebuffers = NULL;
  1205 
  1206     if (SDL_GL_ExtensionSupported("GL_OES_blend_func_separate")) {
  1207         data->GL_OES_blend_func_separate_supported = SDL_TRUE;
  1208     }
  1209     if (SDL_GL_ExtensionSupported("GL_OES_blend_equation_separate")) {
  1210         data->GL_OES_blend_equation_separate_supported = SDL_TRUE;
  1211     }
  1212     if (SDL_GL_ExtensionSupported("GL_OES_blend_subtract")) {
  1213         data->GL_OES_blend_subtract_supported = SDL_TRUE;
  1214     }
  1215 
  1216     /* Set up parameters for rendering */
  1217     data->glDisable(GL_DEPTH_TEST);
  1218     data->glDisable(GL_CULL_FACE);
  1219 
  1220     data->glMatrixMode(GL_MODELVIEW);
  1221     data->glLoadIdentity();
  1222 
  1223     data->glEnableClientState(GL_VERTEX_ARRAY);
  1224     data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  1225 
  1226     data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  1227 
  1228     data->drawstate.blend = SDL_BLENDMODE_INVALID;
  1229     data->drawstate.color = 0xFFFFFFFF;
  1230     data->drawstate.clear_color = 0xFFFFFFFF;
  1231 
  1232     return renderer;
  1233 
  1234 error:
  1235     if (changed_window) {
  1236         /* Uh oh, better try to put it back... */
  1237         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
  1238         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
  1239         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
  1240         SDL_RecreateWindow(window, window_flags);
  1241     }
  1242     return NULL;
  1243 }
  1244 
  1245 SDL_RenderDriver GLES_RenderDriver = {
  1246     GLES_CreateRenderer,
  1247     {
  1248      "opengles",
  1249      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
  1250      1,
  1251      {SDL_PIXELFORMAT_ABGR8888},
  1252      0,
  1253      0
  1254     }
  1255 };
  1256 
  1257 #endif /* SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED */
  1258 
  1259 /* vi: set ts=4 sw=4 expandtab: */