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