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