src/render/opengl/SDL_render_gl.c
author Gabriel Jacobo <gabomdq@gmail.com>
Fri, 01 Jun 2012 19:51:08 -0300
changeset 6320 6077a1310907
parent 6260 fd494c5f305b
child 6414 df50b0d6c1c3
permissions -rwxr-xr-x
RenderCopyEx,rotation and flipping for all hardware/software backends (#1308)
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
    24 
    25 #include "SDL_hints.h"
    26 #include "SDL_log.h"
    27 #include "SDL_opengl.h"
    28 #include "../SDL_sysrender.h"
    29 #include "SDL_shaders_gl.h"
    30 
    31 #ifdef __MACOSX__
    32 #include <OpenGL/OpenGL.h>
    33 #endif
    34 
    35 
    36 /* OpenGL renderer implementation */
    37 
    38 /* Details on optimizing the texture path on Mac OS X:
    39    http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/opengl_texturedata.html
    40 */
    41 
    42 /* Used to re-create the window with OpenGL capability */
    43 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
    44 
    45 static const float inv255f = 1.0f / 255.0f;
    46 
    47 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
    48 static void GL_WindowEvent(SDL_Renderer * renderer,
    49                            const SDL_WindowEvent *event);
    50 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    51 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    52                             const SDL_Rect * rect, const void *pixels,
    53                             int pitch);
    54 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    55                           const SDL_Rect * rect, void **pixels, int *pitch);
    56 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    57 static int GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
    58 static int GL_UpdateViewport(SDL_Renderer * renderer);
    59 static int GL_RenderClear(SDL_Renderer * renderer);
    60 static int GL_RenderDrawPoints(SDL_Renderer * renderer,
    61                                const SDL_Point * points, int count);
    62 static int GL_RenderDrawLines(SDL_Renderer * renderer,
    63                               const SDL_Point * points, int count);
    64 static int GL_RenderFillRects(SDL_Renderer * renderer,
    65                               const SDL_Rect * rects, int count);
    66 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    67                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    68 static int GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
    69                          const SDL_Rect * srcrect, const SDL_Rect * dstrect,
    70                          const double angle, const SDL_Point *center, const SDL_RendererFlip flip);
    71 static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    72                                Uint32 pixel_format, void * pixels, int pitch);
    73 static void GL_RenderPresent(SDL_Renderer * renderer);
    74 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    75 static void GL_DestroyRenderer(SDL_Renderer * renderer);
    76 
    77 
    78 SDL_RenderDriver GL_RenderDriver = {
    79     GL_CreateRenderer,
    80     {
    81      "opengl",
    82      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
    83      1,
    84      {SDL_PIXELFORMAT_ARGB8888},
    85      0,
    86      0}
    87 };
    88 
    89 typedef struct GL_FBOList GL_FBOList;
    90 
    91 struct GL_FBOList
    92 {
    93     Uint32 w, h;
    94     GLuint FBO;
    95     GL_FBOList *next;
    96 };
    97 
    98 typedef struct
    99 {
   100     SDL_GLContext context;
   101     SDL_bool GL_ARB_texture_rectangle_supported;
   102     struct {
   103         GL_Shader shader;
   104         Uint32 color;
   105         int blendMode;
   106     } current;
   107     
   108     SDL_bool GL_EXT_framebuffer_object_supported;
   109     GL_FBOList *framebuffers;
   110 
   111     /* OpenGL functions */
   112 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
   113 #include "SDL_glfuncs.h"
   114 #undef SDL_PROC
   115 
   116     /* Multitexture support */
   117     SDL_bool GL_ARB_multitexture_supported;
   118     PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
   119     GLint num_texture_units;
   120     
   121     PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
   122     PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
   123     PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
   124     PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
   125     PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
   126 
   127     /* Shader support */
   128     GL_ShaderContext *shaders;
   129 
   130 } GL_RenderData;
   131 
   132 typedef struct
   133 {
   134     GLuint texture;
   135     GLenum type;
   136     GLfloat texw;
   137     GLfloat texh;
   138     GLenum format;
   139     GLenum formattype;
   140     void *pixels;
   141     int pitch;
   142     SDL_Rect locked_rect;
   143 
   144     /* YV12 texture support */
   145     SDL_bool yuv;
   146     GLuint utexture;
   147     GLuint vtexture;
   148     
   149     GL_FBOList *fbo;
   150 } GL_TextureData;
   151 
   152 
   153 static void
   154 GL_SetError(const char *prefix, GLenum result)
   155 {
   156     const char *error;
   157 
   158     switch (result) {
   159     case GL_NO_ERROR:
   160         error = "GL_NO_ERROR";
   161         break;
   162     case GL_INVALID_ENUM:
   163         error = "GL_INVALID_ENUM";
   164         break;
   165     case GL_INVALID_VALUE:
   166         error = "GL_INVALID_VALUE";
   167         break;
   168     case GL_INVALID_OPERATION:
   169         error = "GL_INVALID_OPERATION";
   170         break;
   171     case GL_STACK_OVERFLOW:
   172         error = "GL_STACK_OVERFLOW";
   173         break;
   174     case GL_STACK_UNDERFLOW:
   175         error = "GL_STACK_UNDERFLOW";
   176         break;
   177     case GL_OUT_OF_MEMORY:
   178         error = "GL_OUT_OF_MEMORY";
   179         break;
   180     case GL_TABLE_TOO_LARGE:
   181         error = "GL_TABLE_TOO_LARGE";
   182         break;
   183     default:
   184         error = "UNKNOWN";
   185         break;
   186     }
   187     SDL_SetError("%s: %s", prefix, error);
   188 }
   189 
   190 static int
   191 GL_LoadFunctions(GL_RenderData * data)
   192 {
   193 #ifdef __SDL_NOGETPROCADDR__
   194 #define SDL_PROC(ret,func,params) data->func=func;
   195 #else
   196 #define SDL_PROC(ret,func,params) \
   197     do { \
   198         data->func = SDL_GL_GetProcAddress(#func); \
   199         if ( ! data->func ) { \
   200             SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
   201             return -1; \
   202         } \
   203     } while ( 0 );
   204 #endif /* __SDL_NOGETPROCADDR__ */
   205 
   206 #include "SDL_glfuncs.h"
   207 #undef SDL_PROC
   208     return 0;
   209 }
   210 
   211 static SDL_GLContext SDL_CurrentContext = NULL;
   212 
   213 static int
   214 GL_ActivateRenderer(SDL_Renderer * renderer)
   215 {
   216     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   217 
   218     if (SDL_CurrentContext != data->context) {
   219         if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
   220             return -1;
   221         }
   222         SDL_CurrentContext = data->context;
   223 
   224         GL_UpdateViewport(renderer);
   225     }
   226     return 0;
   227 }
   228 
   229 /* This is called if we need to invalidate all of the SDL OpenGL state */
   230 static void
   231 GL_ResetState(SDL_Renderer *renderer)
   232 {
   233     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   234 
   235     if (SDL_CurrentContext == data->context) {
   236         GL_UpdateViewport(renderer);
   237     } else {
   238         GL_ActivateRenderer(renderer);
   239     }
   240 
   241     data->current.shader = SHADER_NONE;
   242     data->current.color = 0;
   243     data->current.blendMode = -1;
   244 
   245     data->glDisable(GL_DEPTH_TEST);
   246     data->glDisable(GL_CULL_FACE);
   247     /* This ended up causing video discrepancies between OpenGL and Direct3D */
   248     /*data->glEnable(GL_LINE_SMOOTH);*/
   249 
   250     data->glMatrixMode(GL_MODELVIEW);
   251     data->glLoadIdentity();
   252 }
   253 
   254 
   255 GL_FBOList *
   256 GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h)
   257 {
   258     GL_FBOList *result = data->framebuffers;
   259 
   260     while (result && ((result->w != w) || (result->h != h))) {
   261         result = result->next;
   262     }
   263 
   264     if (!result) {
   265         result = SDL_malloc(sizeof(GL_FBOList));
   266         if (result) {
   267             result->w = w;
   268             result->h = h;
   269             data->glGenFramebuffersEXT(1, &result->FBO);
   270             result->next = data->framebuffers;
   271             data->framebuffers = result;
   272         }
   273     }
   274     return result;
   275 }
   276 
   277 SDL_Renderer *
   278 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
   279 {
   280     SDL_Renderer *renderer;
   281     GL_RenderData *data;
   282     const char *hint;
   283     GLint value;
   284     Uint32 window_flags;
   285 
   286     window_flags = SDL_GetWindowFlags(window);
   287     if (!(window_flags & SDL_WINDOW_OPENGL)) {
   288         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
   289             /* Uh oh, better try to put it back... */
   290             SDL_RecreateWindow(window, window_flags);
   291             return NULL;
   292         }
   293     }
   294 
   295     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   296     if (!renderer) {
   297         SDL_OutOfMemory();
   298         return NULL;
   299     }
   300 
   301     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
   302     if (!data) {
   303         GL_DestroyRenderer(renderer);
   304         SDL_OutOfMemory();
   305         return NULL;
   306     }
   307 
   308     renderer->WindowEvent = GL_WindowEvent;
   309     renderer->CreateTexture = GL_CreateTexture;
   310     renderer->UpdateTexture = GL_UpdateTexture;
   311     renderer->LockTexture = GL_LockTexture;
   312     renderer->UnlockTexture = GL_UnlockTexture;
   313     renderer->SetRenderTarget = GL_SetRenderTarget;
   314     renderer->UpdateViewport = GL_UpdateViewport;
   315     renderer->RenderClear = GL_RenderClear;
   316     renderer->RenderDrawPoints = GL_RenderDrawPoints;
   317     renderer->RenderDrawLines = GL_RenderDrawLines;
   318     renderer->RenderFillRects = GL_RenderFillRects;
   319     renderer->RenderCopy = GL_RenderCopy;
   320     renderer->RenderCopyEx = GL_RenderCopyEx;
   321     renderer->RenderReadPixels = GL_RenderReadPixels;
   322     renderer->RenderPresent = GL_RenderPresent;
   323     renderer->DestroyTexture = GL_DestroyTexture;
   324     renderer->DestroyRenderer = GL_DestroyRenderer;
   325     renderer->info = GL_RenderDriver.info;
   326     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   327     renderer->driverdata = data;
   328     renderer->window = window;
   329 
   330     data->context = SDL_GL_CreateContext(window);
   331     if (!data->context) {
   332         GL_DestroyRenderer(renderer);
   333         return NULL;
   334     }
   335     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   336         GL_DestroyRenderer(renderer);
   337         return NULL;
   338     }
   339 
   340     if (GL_LoadFunctions(data) < 0) {
   341         GL_DestroyRenderer(renderer);
   342         return NULL;
   343     }
   344 
   345 #ifdef __MACOSX__
   346     /* Enable multi-threaded rendering */
   347     /* Disabled until Ryan finishes his VBO/PBO code...
   348        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
   349      */
   350 #endif
   351 
   352     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   353         SDL_GL_SetSwapInterval(1);
   354     } else {
   355         SDL_GL_SetSwapInterval(0);
   356     }
   357     if (SDL_GL_GetSwapInterval() > 0) {
   358         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   359     }
   360 
   361     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   362     renderer->info.max_texture_width = value;
   363     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   364     renderer->info.max_texture_height = value;
   365 
   366     if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
   367         || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
   368         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
   369     }
   370 
   371     /* Check for multitexture support */
   372     if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
   373         data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
   374         if (data->glActiveTextureARB) {
   375             data->GL_ARB_multitexture_supported = SDL_TRUE;
   376             data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
   377         }
   378     }
   379 
   380     /* Check for shader support */
   381     hint = SDL_GetHint(SDL_HINT_RENDER_OPENGL_SHADERS);
   382     if (!hint || *hint != '0') {
   383         data->shaders = GL_CreateShaderContext();
   384     }
   385     SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
   386                 data->shaders ? "ENABLED" : "DISABLED");
   387 
   388     /* We support YV12 textures using 3 textures and a shader */
   389     if (data->shaders && data->num_texture_units >= 3) {
   390         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   391         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   392     }
   393     
   394     if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
   395         data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
   396         data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
   397             SDL_GL_GetProcAddress("glGenFramebuffersEXT");
   398         data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
   399             SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
   400         data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
   401             SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
   402         data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
   403             SDL_GL_GetProcAddress("glBindFramebufferEXT");
   404         data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
   405             SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
   406         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
   407     }
   408     data->framebuffers = NULL;
   409 
   410     /* Set up parameters for rendering */
   411     GL_ResetState(renderer);
   412 
   413     return renderer;
   414 }
   415 
   416 static void
   417 GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   418 {
   419     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
   420         event->event == SDL_WINDOWEVENT_SHOWN ||
   421         event->event == SDL_WINDOWEVENT_HIDDEN) {
   422         /* Rebind the context to the window area and update matrices */
   423         SDL_CurrentContext = NULL;
   424     }
   425 }
   426 
   427 static __inline__ int
   428 power_of_2(int input)
   429 {
   430     int value = 1;
   431 
   432     while (value < input) {
   433         value <<= 1;
   434     }
   435     return value;
   436 }
   437 
   438 static __inline__ SDL_bool
   439 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
   440                GLint* internalFormat, GLenum* format, GLenum* type)
   441 {
   442     switch (pixel_format) {
   443     case SDL_PIXELFORMAT_ARGB8888:
   444         *internalFormat = GL_RGBA8;
   445         *format = GL_BGRA;
   446         *type = GL_UNSIGNED_INT_8_8_8_8_REV;
   447         break;
   448     case SDL_PIXELFORMAT_YV12:
   449     case SDL_PIXELFORMAT_IYUV:
   450         *internalFormat = GL_LUMINANCE;
   451         *format = GL_LUMINANCE;
   452         *type = GL_UNSIGNED_BYTE;
   453         break;
   454     default:
   455         return SDL_FALSE;
   456     }
   457     return SDL_TRUE;
   458 }
   459 
   460 static GLenum
   461 GetScaleQuality(void)
   462 {
   463     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   464 
   465     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   466         return GL_NEAREST;
   467     } else {
   468         return GL_LINEAR;
   469     }
   470 }
   471 
   472 static int
   473 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   474 {
   475     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   476     GL_TextureData *data;
   477     GLint internalFormat;
   478     GLenum format, type;
   479     int texture_w, texture_h;
   480     GLenum scaleMode;
   481     GLenum result;
   482 
   483     GL_ActivateRenderer(renderer);
   484 
   485     if (!convert_format(renderdata, texture->format, &internalFormat,
   486                         &format, &type)) {
   487         SDL_SetError("Texture format %s not supported by OpenGL",
   488                      SDL_GetPixelFormatName(texture->format));
   489         return -1;
   490     }
   491 
   492     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   493     if (!data) {
   494         SDL_OutOfMemory();
   495         return -1;
   496     }
   497 
   498     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   499         size_t size;
   500         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   501         size = texture->h * data->pitch;
   502         if (texture->format == SDL_PIXELFORMAT_YV12 ||
   503             texture->format == SDL_PIXELFORMAT_IYUV) {
   504             /* Need to add size for the U and V planes */
   505             size += (2 * (texture->h * data->pitch) / 4);
   506         }
   507         data->pixels = SDL_calloc(1, size);
   508         if (!data->pixels) {
   509             SDL_OutOfMemory();
   510             SDL_free(data);
   511             return -1;
   512         }
   513     }
   514 
   515     texture->driverdata = data;
   516     
   517     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   518         data->fbo = GL_GetFBO(renderdata, texture->w, texture->h);
   519     } else {
   520         data->fbo = NULL;
   521     }
   522 
   523     renderdata->glGetError();
   524     renderdata->glGenTextures(1, &data->texture);
   525     if ((renderdata->GL_ARB_texture_rectangle_supported)
   526         /*&& texture->access != SDL_TEXTUREACCESS_TARGET*/){
   527         data->type = GL_TEXTURE_RECTANGLE_ARB;
   528         texture_w = texture->w;
   529         texture_h = texture->h;
   530         data->texw = (GLfloat) texture_w;
   531         data->texh = (GLfloat) texture_h;
   532     } else {
   533         data->type = GL_TEXTURE_2D;
   534         texture_w = power_of_2(texture->w);
   535         texture_h = power_of_2(texture->h);
   536         data->texw = (GLfloat) (texture->w) / texture_w;
   537         data->texh = (GLfloat) texture->h / texture_h;
   538     }
   539 
   540     data->format = format;
   541     data->formattype = type;
   542     scaleMode = GetScaleQuality();
   543     renderdata->glEnable(data->type);
   544     renderdata->glBindTexture(data->type, data->texture);
   545     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
   546     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
   547     /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE
   548        and setting it causes an INVALID_ENUM error in the latest NVidia drivers.
   549     */
   550     if (data->type != GL_TEXTURE_RECTANGLE_ARB) {
   551         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   552                                     GL_CLAMP_TO_EDGE);
   553         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   554                                     GL_CLAMP_TO_EDGE);
   555     }
   556 #ifdef __MACOSX__
   557 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
   558 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
   559 #endif
   560 #ifndef STORAGE_CACHED_APPLE
   561 #define STORAGE_CACHED_APPLE                0x85BE
   562 #endif
   563 #ifndef STORAGE_SHARED_APPLE
   564 #define STORAGE_SHARED_APPLE                0x85BF
   565 #endif
   566     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   567         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   568                                     GL_STORAGE_SHARED_APPLE);
   569     } else {
   570         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   571                                     GL_STORAGE_CACHED_APPLE);
   572     }
   573     if (texture->access == SDL_TEXTUREACCESS_STREAMING
   574         && texture->format == SDL_PIXELFORMAT_ARGB8888
   575         && (texture->w % 8) == 0) {
   576         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
   577         renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   578         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   579                           (data->pitch / SDL_BYTESPERPIXEL(texture->format)));
   580         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   581                                  texture_h, 0, format, type, data->pixels);
   582         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
   583     }
   584     else
   585 #endif
   586     {
   587         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   588                                  texture_h, 0, format, type, NULL);
   589     }
   590     renderdata->glDisable(data->type);
   591     result = renderdata->glGetError();
   592     if (result != GL_NO_ERROR) {
   593         GL_SetError("glTexImage2D()", result);
   594         return -1;
   595     }
   596 
   597     if (texture->format == SDL_PIXELFORMAT_YV12 ||
   598         texture->format == SDL_PIXELFORMAT_IYUV) {
   599         data->yuv = SDL_TRUE;
   600 
   601         renderdata->glGenTextures(1, &data->utexture);
   602         renderdata->glGenTextures(1, &data->vtexture);
   603         renderdata->glEnable(data->type);
   604 
   605         renderdata->glBindTexture(data->type, data->utexture);
   606         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   607                                     scaleMode);
   608         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   609                                     scaleMode);
   610         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   611                                     GL_CLAMP_TO_EDGE);
   612         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   613                                     GL_CLAMP_TO_EDGE);
   614         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
   615                                  texture_h/2, 0, format, type, NULL);
   616 
   617         renderdata->glBindTexture(data->type, data->vtexture);
   618         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   619                                     scaleMode);
   620         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   621                                     scaleMode);
   622         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   623                                     GL_CLAMP_TO_EDGE);
   624         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   625                                     GL_CLAMP_TO_EDGE);
   626         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
   627                                  texture_h/2, 0, format, type, NULL);
   628 
   629         renderdata->glDisable(data->type);
   630     }
   631     return 0;
   632 }
   633 
   634 static int
   635 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   636                  const SDL_Rect * rect, const void *pixels, int pitch)
   637 {
   638     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   639     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   640     GLenum result;
   641 
   642     GL_ActivateRenderer(renderer);
   643 
   644     renderdata->glGetError();
   645     renderdata->glEnable(data->type);
   646     renderdata->glBindTexture(data->type, data->texture);
   647     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   648     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   649                               (pitch / SDL_BYTESPERPIXEL(texture->format)));
   650     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   651                                 rect->h, data->format, data->formattype,
   652                                 pixels);
   653     if (data->yuv) {
   654         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
   655 
   656         /* Skip to the correct offset into the next texture */
   657         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
   658         if (texture->format == SDL_PIXELFORMAT_YV12) {
   659             renderdata->glBindTexture(data->type, data->vtexture);
   660         } else {
   661             renderdata->glBindTexture(data->type, data->utexture);
   662         }
   663         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   664                                     rect->w/2, rect->h/2,
   665                                     data->format, data->formattype, pixels);
   666 
   667         /* Skip to the correct offset into the next texture */
   668         pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
   669         if (texture->format == SDL_PIXELFORMAT_YV12) {
   670             renderdata->glBindTexture(data->type, data->utexture);
   671         } else {
   672             renderdata->glBindTexture(data->type, data->vtexture);
   673         }
   674         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   675                                     rect->w/2, rect->h/2,
   676                                     data->format, data->formattype, pixels);
   677     }
   678     renderdata->glDisable(data->type);
   679     result = renderdata->glGetError();
   680     if (result != GL_NO_ERROR) {
   681         GL_SetError("glTexSubImage2D()", result);
   682         return -1;
   683     }
   684     return 0;
   685 }
   686 
   687 static int
   688 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   689                const SDL_Rect * rect, void **pixels, int *pitch)
   690 {
   691     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   692 
   693     data->locked_rect = *rect;
   694     *pixels = 
   695         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   696                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   697     *pitch = data->pitch;
   698     return 0;
   699 }
   700 
   701 static void
   702 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   703 {
   704     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   705     const SDL_Rect *rect;
   706     void *pixels;
   707 
   708     rect = &data->locked_rect;
   709     pixels = 
   710         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   711                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   712     GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
   713 }
   714 
   715 static int
   716 GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   717 {
   718     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;    
   719     GL_TextureData *texturedata;
   720     GLenum status;
   721 
   722     GL_ActivateRenderer(renderer);
   723     
   724     if (texture == NULL) {
   725         data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
   726         return 0;
   727     }
   728 
   729     texturedata = (GL_TextureData *) texture->driverdata;
   730     data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
   731     /* TODO: check if texture pixel format allows this operation */
   732     data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
   733     /* Check FBO status */
   734     status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
   735     if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
   736         SDL_SetError("glFramebufferTexture2DEXT() failed");
   737         return -1;
   738     }
   739     return 0;
   740 }
   741 
   742 static int
   743 GL_UpdateViewport(SDL_Renderer * renderer)
   744 {
   745     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   746 
   747     if (SDL_CurrentContext != data->context) {
   748         /* We'll update the viewport after we rebind the context */
   749         return 0;
   750     }
   751 
   752     data->glViewport(renderer->viewport.x, renderer->viewport.y,
   753                      renderer->viewport.w, renderer->viewport.h);
   754 
   755     data->glMatrixMode(GL_PROJECTION);
   756     data->glLoadIdentity();
   757     if (renderer->target) {
   758         data->glOrtho((GLdouble) 0,
   759                       (GLdouble) renderer->viewport.w,
   760                       (GLdouble) 0,
   761                       (GLdouble) renderer->viewport.h,
   762                        0.0, 1.0);
   763     } else {
   764         data->glOrtho((GLdouble) 0,
   765                       (GLdouble) renderer->viewport.w,
   766                       (GLdouble) renderer->viewport.h,
   767                       (GLdouble) 0,
   768                        0.0, 1.0);
   769     }
   770     return 0;
   771 }
   772 
   773 static void
   774 GL_SetShader(GL_RenderData * data, GL_Shader shader)
   775 {
   776     if (data->shaders && shader != data->current.shader) {
   777         GL_SelectShader(data->shaders, shader);
   778         data->current.shader = shader;
   779     }
   780 }
   781 
   782 static void
   783 GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
   784 {
   785     Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
   786 
   787     if (color != data->current.color) {
   788         data->glColor4f((GLfloat) r * inv255f,
   789                         (GLfloat) g * inv255f,
   790                         (GLfloat) b * inv255f,
   791                         (GLfloat) a * inv255f);
   792         data->current.color = color;
   793     }
   794 }
   795 
   796 static void
   797 GL_SetBlendMode(GL_RenderData * data, int blendMode)
   798 {
   799     if (blendMode != data->current.blendMode) {
   800         switch (blendMode) {
   801         case SDL_BLENDMODE_NONE:
   802             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   803             data->glDisable(GL_BLEND);
   804             break;
   805         case SDL_BLENDMODE_BLEND:
   806             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   807             data->glEnable(GL_BLEND);
   808             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   809             break;
   810         case SDL_BLENDMODE_ADD:
   811             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   812             data->glEnable(GL_BLEND);
   813             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   814             break;
   815         case SDL_BLENDMODE_MOD:
   816             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   817             data->glEnable(GL_BLEND);
   818             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   819             break;
   820         }
   821         data->current.blendMode = blendMode;
   822     }
   823 }
   824 
   825 static void
   826 GL_SetDrawingState(SDL_Renderer * renderer)
   827 {
   828     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   829 
   830     GL_ActivateRenderer(renderer);
   831 
   832     GL_SetColor(data, renderer->r,
   833                       renderer->g,
   834                       renderer->b,
   835                       renderer->a);
   836 
   837     GL_SetBlendMode(data, renderer->blendMode);
   838 
   839     GL_SetShader(data, SHADER_SOLID);
   840 }
   841 
   842 static int
   843 GL_RenderClear(SDL_Renderer * renderer)
   844 {
   845     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   846 
   847     GL_ActivateRenderer(renderer);
   848 
   849     data->glClearColor((GLfloat) renderer->r * inv255f,
   850                        (GLfloat) renderer->g * inv255f,
   851                        (GLfloat) renderer->b * inv255f,
   852                        (GLfloat) renderer->a * inv255f);
   853 
   854     data->glClear(GL_COLOR_BUFFER_BIT);
   855 
   856     return 0;
   857 }
   858 
   859 static int
   860 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   861                     int count)
   862 {
   863     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   864     int i;
   865 
   866     GL_SetDrawingState(renderer);
   867 
   868     data->glBegin(GL_POINTS);
   869     for (i = 0; i < count; ++i) {
   870         data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   871     }
   872     data->glEnd();
   873 
   874     return 0;
   875 }
   876 
   877 static int
   878 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   879                    int count)
   880 {
   881     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   882     int i;
   883 
   884     GL_SetDrawingState(renderer);
   885 
   886     if (count > 2 && 
   887         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
   888         data->glBegin(GL_LINE_LOOP);
   889         /* GL_LINE_LOOP takes care of the final segment */
   890         --count;
   891         for (i = 0; i < count; ++i) {
   892             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   893         }
   894         data->glEnd();
   895     } else {
   896 #if defined(__APPLE__) || defined(__WIN32__)
   897 #else
   898         int x1, y1, x2, y2;
   899 #endif
   900 
   901         data->glBegin(GL_LINE_STRIP);
   902         for (i = 0; i < count; ++i) {
   903             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   904         }
   905         data->glEnd();
   906 
   907         /* The line is half open, so we need one more point to complete it.
   908          * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
   909          * If we have to, we can use vertical line and horizontal line textures
   910          * for vertical and horizontal lines, and then create custom textures
   911          * for diagonal lines and software render those.  It's terrible, but at
   912          * least it would be pixel perfect.
   913          */
   914         data->glBegin(GL_POINTS);
   915 #if defined(__APPLE__) || defined(__WIN32__)
   916         /* Mac OS X and Windows seem to always leave the second point open */
   917         data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
   918 #else
   919         /* Linux seems to leave the right-most or bottom-most point open */
   920         x1 = points[0].x;
   921         y1 = points[0].y;
   922         x2 = points[count-1].x;
   923         y2 = points[count-1].y;
   924 
   925         if (x1 > x2) {
   926             data->glVertex2f(0.5f + x1, 0.5f + y1);
   927         } else if (x2 > x1) {
   928             data->glVertex2f(0.5f + x2, 0.5f + y2);
   929         } else if (y1 > y2) {
   930             data->glVertex2f(0.5f + x1, 0.5f + y1);
   931         } else if (y2 > y1) {
   932             data->glVertex2f(0.5f + x2, 0.5f + y2);
   933         }
   934 #endif
   935         data->glEnd();
   936     }
   937 
   938     return 0;
   939 }
   940 
   941 static int
   942 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count)
   943 {
   944     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   945     int i;
   946 
   947     GL_SetDrawingState(renderer);
   948 
   949     for (i = 0; i < count; ++i) {
   950         const SDL_Rect *rect = &rects[i];
   951 
   952         data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
   953     }
   954 
   955     return 0;
   956 }
   957 
   958 static int
   959 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   960               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   961 {
   962     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   963     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
   964     int minx, miny, maxx, maxy;
   965     GLfloat minu, maxu, minv, maxv;
   966 
   967     GL_ActivateRenderer(renderer);
   968 
   969     data->glEnable(texturedata->type);
   970     if (texturedata->yuv) {
   971         data->glActiveTextureARB(GL_TEXTURE2_ARB);
   972         data->glBindTexture(texturedata->type, texturedata->vtexture);
   973 
   974         data->glActiveTextureARB(GL_TEXTURE1_ARB);
   975         data->glBindTexture(texturedata->type, texturedata->utexture);
   976 
   977         data->glActiveTextureARB(GL_TEXTURE0_ARB);
   978     }
   979     data->glBindTexture(texturedata->type, texturedata->texture);
   980 
   981     if (texture->modMode) {
   982         GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
   983     } else {
   984         GL_SetColor(data, 255, 255, 255, 255);
   985     }
   986 
   987     GL_SetBlendMode(data, texture->blendMode);
   988 
   989     if (texturedata->yuv) {
   990         GL_SetShader(data, SHADER_YV12);
   991     } else {
   992         GL_SetShader(data, SHADER_RGB);
   993     }
   994 
   995     minx = dstrect->x;
   996     miny = dstrect->y;
   997     maxx = dstrect->x + dstrect->w;
   998     maxy = dstrect->y + dstrect->h;
   999 
  1000     minu = (GLfloat) srcrect->x / texture->w;
  1001     minu *= texturedata->texw;
  1002     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
  1003     maxu *= texturedata->texw;
  1004     minv = (GLfloat) srcrect->y / texture->h;
  1005     minv *= texturedata->texh;
  1006     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
  1007     maxv *= texturedata->texh;
  1008 
  1009     data->glBegin(GL_TRIANGLE_STRIP);
  1010     data->glTexCoord2f(minu, minv);
  1011     data->glVertex2f((GLfloat) minx, (GLfloat) miny);
  1012     data->glTexCoord2f(maxu, minv);
  1013     data->glVertex2f((GLfloat) maxx, (GLfloat) miny);
  1014     data->glTexCoord2f(minu, maxv);
  1015     data->glVertex2f((GLfloat) minx, (GLfloat) maxy);
  1016     data->glTexCoord2f(maxu, maxv);
  1017     data->glVertex2f((GLfloat) maxx, (GLfloat) maxy);
  1018     data->glEnd();
  1019 
  1020     data->glDisable(texturedata->type);
  1021 
  1022     return 0;
  1023 }
  1024 
  1025 static int
  1026 GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1027               const SDL_Rect * srcrect, const SDL_Rect * dstrect,
  1028               const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
  1029 {
  1030     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1031     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1032     GLfloat minx, miny, maxx, maxy;
  1033     GLfloat centerx, centery;
  1034     GLfloat minu, maxu, minv, maxv;
  1035     GL_ActivateRenderer(renderer);
  1036 
  1037     data->glEnable(texturedata->type);
  1038     if (texturedata->yuv) {
  1039         data->glActiveTextureARB(GL_TEXTURE2_ARB);
  1040         data->glBindTexture(texturedata->type, texturedata->vtexture);
  1041 
  1042         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1043         data->glBindTexture(texturedata->type, texturedata->utexture);
  1044 
  1045         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1046     }
  1047     data->glBindTexture(texturedata->type, texturedata->texture);
  1048 
  1049     if (texture->modMode) {
  1050         GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
  1051     } else {
  1052         GL_SetColor(data, 255, 255, 255, 255);
  1053     }
  1054 
  1055     GL_SetBlendMode(data, texture->blendMode);
  1056 
  1057     if (texturedata->yuv) {
  1058         GL_SetShader(data, SHADER_YV12);
  1059     } else {
  1060         GL_SetShader(data, SHADER_RGB);
  1061     }
  1062 
  1063     centerx = (GLfloat)center->x;
  1064     centery = (GLfloat)center->y;
  1065 
  1066     if (flip & SDL_FLIP_HORIZONTAL) {
  1067         minx = (GLfloat) dstrect->w - centerx;
  1068         maxx = -centerx;
  1069     }
  1070     else {
  1071         minx = -centerx;
  1072         maxx = (GLfloat) dstrect->w - centerx;
  1073     }
  1074 
  1075     if (flip & SDL_FLIP_VERTICAL) {
  1076         miny = (GLfloat) dstrect->h - centery;
  1077         maxy = -centery;
  1078     }
  1079     else {
  1080         miny = -centery;
  1081         maxy = (GLfloat) dstrect->h - centery;
  1082     }
  1083 
  1084     minu = (GLfloat) srcrect->x / texture->w;
  1085     minu *= texturedata->texw;
  1086     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
  1087     maxu *= texturedata->texw;
  1088     minv = (GLfloat) srcrect->y / texture->h;
  1089     minv *= texturedata->texh;
  1090     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
  1091     maxv *= texturedata->texh;
  1092 
  1093     // Translate to flip, rotate, translate to position
  1094     data->glPushMatrix();
  1095     data->glTranslatef((GLfloat)dstrect->x + centerx, (GLfloat)dstrect->y + centery, (GLfloat)0.0);    
  1096     data->glRotated(angle, (GLdouble)0.0, (GLdouble)0.0, (GLdouble)1.0);
  1097     
  1098     data->glBegin(GL_TRIANGLE_STRIP);
  1099     data->glTexCoord2f(minu, minv);
  1100     data->glVertex2f(minx, miny);
  1101     data->glTexCoord2f(maxu, minv);
  1102     data->glVertex2f(maxx, miny);
  1103     data->glTexCoord2f(minu, maxv);
  1104     data->glVertex2f(minx, maxy);
  1105     data->glTexCoord2f(maxu, maxv);
  1106     data->glVertex2f(maxx, maxy);
  1107     data->glEnd();
  1108     data->glPopMatrix();
  1109     
  1110     data->glDisable(texturedata->type);
  1111 
  1112     return 0;
  1113 }
  1114 
  1115 static int
  1116 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1117                     Uint32 pixel_format, void * pixels, int pitch)
  1118 {
  1119     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1120     SDL_Window *window = renderer->window;
  1121     Uint32 temp_format = SDL_PIXELFORMAT_ARGB8888;
  1122     void *temp_pixels;
  1123     int temp_pitch;
  1124     GLint internalFormat;
  1125     GLenum format, type;
  1126     Uint8 *src, *dst, *tmp;
  1127     int w, h, length, rows;
  1128     int status;
  1129 
  1130     GL_ActivateRenderer(renderer);
  1131 
  1132     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1133     temp_pixels = SDL_malloc(rect->h * temp_pitch);
  1134     if (!temp_pixels) {
  1135         SDL_OutOfMemory();
  1136         return -1;
  1137     }
  1138 
  1139     convert_format(data, temp_format, &internalFormat, &format, &type);
  1140 
  1141     SDL_GetWindowSize(window, &w, &h);
  1142 
  1143     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
  1144     data->glPixelStorei(GL_PACK_ROW_LENGTH,
  1145                         (temp_pitch / SDL_BYTESPERPIXEL(temp_format)));
  1146 
  1147     data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
  1148                        format, type, temp_pixels);
  1149 
  1150     /* Flip the rows to be top-down */
  1151     length = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1152     src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
  1153     dst = (Uint8*)temp_pixels;
  1154     tmp = SDL_stack_alloc(Uint8, length);
  1155     rows = rect->h / 2;
  1156     while (rows--) {
  1157         SDL_memcpy(tmp, dst, length);
  1158         SDL_memcpy(dst, src, length);
  1159         SDL_memcpy(src, tmp, length);
  1160         dst += temp_pitch;
  1161         src -= temp_pitch;
  1162     }
  1163     SDL_stack_free(tmp);
  1164 
  1165     status = SDL_ConvertPixels(rect->w, rect->h,
  1166                                temp_format, temp_pixels, temp_pitch,
  1167                                pixel_format, pixels, pitch);
  1168     SDL_free(temp_pixels);
  1169 
  1170     return status;
  1171 }
  1172 
  1173 static void
  1174 GL_RenderPresent(SDL_Renderer * renderer)
  1175 {
  1176     GL_ActivateRenderer(renderer);
  1177 
  1178     SDL_GL_SwapWindow(renderer->window);
  1179 }
  1180 
  1181 static void
  1182 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1183 {
  1184     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  1185     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1186 
  1187     GL_ActivateRenderer(renderer);
  1188 
  1189     if (!data) {
  1190         return;
  1191     }
  1192     if (data->texture) {
  1193         renderdata->glDeleteTextures(1, &data->texture);
  1194     }
  1195     if (data->yuv) {
  1196         renderdata->glDeleteTextures(1, &data->utexture);
  1197         renderdata->glDeleteTextures(1, &data->vtexture);
  1198     }
  1199     if (data->pixels) {
  1200         SDL_free(data->pixels);
  1201     }
  1202     SDL_free(data);
  1203     texture->driverdata = NULL;
  1204 }
  1205 
  1206 static void
  1207 GL_DestroyRenderer(SDL_Renderer * renderer)
  1208 {
  1209     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1210 
  1211     if (data) {
  1212         if (data->shaders) {
  1213             GL_DestroyShaderContext(data->shaders);
  1214         }
  1215         if (data->context) {
  1216             while (data->framebuffers) {
  1217                 GL_FBOList *nextnode = data->framebuffers->next;
  1218                 /* delete the framebuffer object */
  1219                 data->glDeleteFramebuffersEXT(1, &data->framebuffers->FBO);
  1220                 SDL_free(data->framebuffers);
  1221                 data->framebuffers = nextnode;
  1222             }            
  1223             /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
  1224             SDL_GL_DeleteContext(data->context);
  1225         }
  1226         SDL_free(data);
  1227     }
  1228     SDL_free(renderer);
  1229 }
  1230 
  1231 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
  1232 
  1233 /* vi: set ts=4 sw=4 expandtab: */