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