src/render/opengl/SDL_render_gl.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 19 May 2013 22:28:10 -0700
changeset 7194 987fb567bba9
parent 7191 75360622e65f
child 7196 fe0848afab9f
permissions -rw-r--r--
Fixed bug 1837 - Use error extension instead of glGetError()

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