src/render/opengl/SDL_render_gl.c
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Mon, 22 Apr 2013 18:15:08 -0700
changeset 7091 ff07fad908f8
parent 7037 3fedf1f25b94
child 7141 e276777b4247
permissions -rw-r--r--
SDL_GL_DeleteContext would leave an invalid current_glctx.

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