src/render/opengles/SDL_render_gles.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Wed, 29 Oct 2014 20:20:47 +0100
changeset 9201 21d9f9babb30
parent 8993 bc47cf4c679d
child 9530 ac0885050d79
permissions -rw-r--r--
Fixed bug 2647 - Memory leak in SDL_AddHintCallback function - SDL_hints.c

Nitz

Variable entry going out of scope leaks the storage it points to, at:

/* Need to add a hint entry for this watcher */
hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
if (!hint) {
return;
}

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