src/render/opengl/SDL_render_gl.c
author Cameron Gutman <cameron.gutman@gmail.com>
Wed, 31 Oct 2018 20:17:53 -0700
changeset 12377 84618d571795
parent 11958 d7582d7286aa
child 12381 dc9108cd4340
permissions -rw-r--r--
Fix crash when GL_LoadFunctions()/GLES2_LoadFunctions() fails
https://bugzilla.libsdl.org/show_bug.cgi?id=4350

We can't safely call GL_DestroyRenderer() until GL_LoadFunctions()
succeeds because we will be missing functions that we try to use
when activating the renderer for destruction if we have an GL context.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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_internal.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_assert.h"
    28 #include "SDL_opengl.h"
    29 #include "../SDL_sysrender.h"
    30 #include "SDL_shaders_gl.h"
    31 
    32 #ifdef __MACOSX__
    33 #include <OpenGL/OpenGL.h>
    34 #endif
    35 
    36 /* To prevent unnecessary window recreation, 
    37  * these should match the defaults selected in SDL_GL_ResetAttributes 
    38  */
    39 
    40 #define RENDERER_CONTEXT_MAJOR 2
    41 #define RENDERER_CONTEXT_MINOR 1
    42 
    43 /* OpenGL renderer implementation */
    44 
    45 /* Details on optimizing the texture path on Mac OS X:
    46    http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/opengl_texturedata.html
    47 */
    48 
    49 /* Used to re-create the window with OpenGL capability */
    50 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
    51 
    52 static const float inv255f = 1.0f / 255.0f;
    53 
    54 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
    55 static void GL_WindowEvent(SDL_Renderer * renderer,
    56                            const SDL_WindowEvent *event);
    57 static int GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
    58 static SDL_bool GL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
    59 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    60 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    61                             const SDL_Rect * rect, const void *pixels,
    62                             int pitch);
    63 static int GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
    64                                const SDL_Rect * rect,
    65                                const Uint8 *Yplane, int Ypitch,
    66                                const Uint8 *Uplane, int Upitch,
    67                                const Uint8 *Vplane, int Vpitch);
    68 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    69                           const SDL_Rect * rect, void **pixels, int *pitch);
    70 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    71 static int GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
    72 static int GL_UpdateViewport(SDL_Renderer * renderer);
    73 static int GL_UpdateClipRect(SDL_Renderer * renderer);
    74 static int GL_RenderClear(SDL_Renderer * renderer);
    75 static int GL_RenderDrawPoints(SDL_Renderer * renderer,
    76                                const SDL_FPoint * points, int count);
    77 static int GL_RenderDrawLines(SDL_Renderer * renderer,
    78                               const SDL_FPoint * points, int count);
    79 static int GL_RenderFillRects(SDL_Renderer * renderer,
    80                               const SDL_FRect * rects, int count);
    81 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    82                          const SDL_Rect * srcrect, const SDL_FRect * dstrect);
    83 static int GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
    84                          const SDL_Rect * srcrect, const SDL_FRect * dstrect,
    85                          const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
    86 static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    87                                Uint32 pixel_format, void * pixels, int pitch);
    88 static void GL_RenderPresent(SDL_Renderer * renderer);
    89 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    90 static void GL_DestroyRenderer(SDL_Renderer * renderer);
    91 static int GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
    92 static int GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
    93 
    94 SDL_RenderDriver GL_RenderDriver = {
    95     GL_CreateRenderer,
    96     {
    97      "opengl",
    98      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
    99      1,
   100      {SDL_PIXELFORMAT_ARGB8888},
   101      0,
   102      0}
   103 };
   104 
   105 typedef struct GL_FBOList GL_FBOList;
   106 
   107 struct GL_FBOList
   108 {
   109     Uint32 w, h;
   110     GLuint FBO;
   111     GL_FBOList *next;
   112 };
   113 
   114 typedef struct
   115 {
   116     SDL_GLContext context;
   117 
   118     SDL_bool debug_enabled;
   119     SDL_bool GL_ARB_debug_output_supported;
   120     int errors;
   121     char **error_messages;
   122     GLDEBUGPROCARB next_error_callback;
   123     GLvoid *next_error_userparam;
   124 
   125     SDL_bool GL_ARB_texture_non_power_of_two_supported;
   126     SDL_bool GL_ARB_texture_rectangle_supported;
   127     struct {
   128         GL_Shader shader;
   129         Uint32 color;
   130         SDL_BlendMode blendMode;
   131     } current;
   132 
   133     SDL_bool GL_EXT_framebuffer_object_supported;
   134     GL_FBOList *framebuffers;
   135 
   136     /* OpenGL functions */
   137 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
   138 #include "SDL_glfuncs.h"
   139 #undef SDL_PROC
   140 
   141     /* Multitexture support */
   142     SDL_bool GL_ARB_multitexture_supported;
   143     PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
   144     GLint num_texture_units;
   145 
   146     PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
   147     PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
   148     PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
   149     PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
   150     PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
   151 
   152     /* Shader support */
   153     GL_ShaderContext *shaders;
   154 
   155 } GL_RenderData;
   156 
   157 typedef struct
   158 {
   159     GLuint texture;
   160     GLenum type;
   161     GLfloat texw;
   162     GLfloat texh;
   163     GLenum format;
   164     GLenum formattype;
   165     void *pixels;
   166     int pitch;
   167     SDL_Rect locked_rect;
   168 
   169     /* YUV texture support */
   170     SDL_bool yuv;
   171     SDL_bool nv12;
   172     GLuint utexture;
   173     GLuint vtexture;
   174 
   175     GL_FBOList *fbo;
   176 } GL_TextureData;
   177 
   178 SDL_FORCE_INLINE const char*
   179 GL_TranslateError (GLenum error)
   180 {
   181 #define GL_ERROR_TRANSLATE(e) case e: return #e;
   182     switch (error) {
   183     GL_ERROR_TRANSLATE(GL_INVALID_ENUM)
   184     GL_ERROR_TRANSLATE(GL_INVALID_VALUE)
   185     GL_ERROR_TRANSLATE(GL_INVALID_OPERATION)
   186     GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY)
   187     GL_ERROR_TRANSLATE(GL_NO_ERROR)
   188     GL_ERROR_TRANSLATE(GL_STACK_OVERFLOW)
   189     GL_ERROR_TRANSLATE(GL_STACK_UNDERFLOW)
   190     GL_ERROR_TRANSLATE(GL_TABLE_TOO_LARGE)
   191     default:
   192         return "UNKNOWN";
   193 }
   194 #undef GL_ERROR_TRANSLATE
   195 }
   196 
   197 SDL_FORCE_INLINE void
   198 GL_ClearErrors(SDL_Renderer *renderer)
   199 {
   200     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   201 
   202     if (!data->debug_enabled)
   203     {
   204         return;
   205     }
   206     if (data->GL_ARB_debug_output_supported) {
   207         if (data->errors) {
   208             int i;
   209             for (i = 0; i < data->errors; ++i) {
   210                 SDL_free(data->error_messages[i]);
   211             }
   212             SDL_free(data->error_messages);
   213 
   214             data->errors = 0;
   215             data->error_messages = NULL;
   216         }
   217     } else {
   218         while (data->glGetError() != GL_NO_ERROR) {
   219             continue;
   220         }
   221     }
   222 }
   223 
   224 SDL_FORCE_INLINE int
   225 GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function)
   226 {
   227     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   228     int ret = 0;
   229 
   230     if (!data->debug_enabled)
   231     {
   232         return 0;
   233     }
   234     if (data->GL_ARB_debug_output_supported) {
   235         if (data->errors) {
   236             int i;
   237             for (i = 0; i < data->errors; ++i) {
   238                 SDL_SetError("%s: %s (%d): %s %s", prefix, file, line, function, data->error_messages[i]);
   239                 ret = -1;
   240             }
   241             GL_ClearErrors(renderer);
   242         }
   243     } else {
   244         /* check gl errors (can return multiple errors) */
   245         for (;;) {
   246             GLenum error = data->glGetError();
   247             if (error != GL_NO_ERROR) {
   248                 if (prefix == NULL || prefix[0] == '\0') {
   249                     prefix = "generic";
   250                 }
   251                 SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error);
   252                 ret = -1;
   253             } else {
   254                 break;
   255             }
   256         }
   257     }
   258     return ret;
   259 }
   260 
   261 #if 0
   262 #define GL_CheckError(prefix, renderer)
   263 #else
   264 #define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, SDL_FILE, SDL_LINE, SDL_FUNCTION)
   265 #endif
   266 
   267 static int
   268 GL_LoadFunctions(GL_RenderData * data)
   269 {
   270 #ifdef __SDL_NOGETPROCADDR__
   271 #define SDL_PROC(ret,func,params) data->func=func;
   272 #else
   273 #define SDL_PROC(ret,func,params) \
   274     do { \
   275         data->func = SDL_GL_GetProcAddress(#func); \
   276         if ( ! data->func ) { \
   277             return SDL_SetError("Couldn't load GL function %s: %s", #func, SDL_GetError()); \
   278         } \
   279     } while ( 0 );
   280 #endif /* __SDL_NOGETPROCADDR__ */
   281 
   282 #include "SDL_glfuncs.h"
   283 #undef SDL_PROC
   284     return 0;
   285 }
   286 
   287 static SDL_GLContext SDL_CurrentContext = NULL;
   288 
   289 static int
   290 GL_ActivateRenderer(SDL_Renderer * renderer)
   291 {
   292     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   293 
   294     if (SDL_CurrentContext != data->context ||
   295         SDL_GL_GetCurrentContext() != data->context) {
   296         if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
   297             return -1;
   298         }
   299         SDL_CurrentContext = data->context;
   300 
   301         GL_UpdateViewport(renderer);
   302     }
   303 
   304     GL_ClearErrors(renderer);
   305 
   306     return 0;
   307 }
   308 
   309 /* This is called if we need to invalidate all of the SDL OpenGL state */
   310 static void
   311 GL_ResetState(SDL_Renderer *renderer)
   312 {
   313     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   314 
   315     if (SDL_GL_GetCurrentContext() == data->context) {
   316         GL_UpdateViewport(renderer);
   317     } else {
   318         GL_ActivateRenderer(renderer);
   319     }
   320 
   321     data->current.shader = SHADER_NONE;
   322     data->current.color = 0xffffffff;
   323     data->current.blendMode = SDL_BLENDMODE_INVALID;
   324 
   325     data->glDisable(GL_DEPTH_TEST);
   326     data->glDisable(GL_CULL_FACE);
   327     /* This ended up causing video discrepancies between OpenGL and Direct3D */
   328     /* data->glEnable(GL_LINE_SMOOTH); */
   329 
   330     data->glMatrixMode(GL_MODELVIEW);
   331     data->glLoadIdentity();
   332 
   333     GL_CheckError("", renderer);
   334 }
   335 
   336 static void APIENTRY
   337 GL_HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam)
   338 {
   339     SDL_Renderer *renderer = (SDL_Renderer *) userParam;
   340     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   341 
   342     if (type == GL_DEBUG_TYPE_ERROR_ARB) {
   343         /* Record this error */
   344         int errors = data->errors + 1;
   345         char **error_messages = SDL_realloc(data->error_messages, errors * sizeof(*data->error_messages));
   346         if (error_messages) {
   347             data->errors = errors;
   348             data->error_messages = error_messages;
   349             data->error_messages[data->errors-1] = SDL_strdup(message);
   350         }
   351     }
   352 
   353     /* If there's another error callback, pass it along, otherwise log it */
   354     if (data->next_error_callback) {
   355         data->next_error_callback(source, type, id, severity, length, message, data->next_error_userparam);
   356     } else {
   357         if (type == GL_DEBUG_TYPE_ERROR_ARB) {
   358             SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", message);
   359         } else {
   360             SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "%s", message);
   361         }
   362     }
   363 }
   364 
   365 static GL_FBOList *
   366 GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h)
   367 {
   368     GL_FBOList *result = data->framebuffers;
   369 
   370     while (result && ((result->w != w) || (result->h != h))) {
   371         result = result->next;
   372     }
   373 
   374     if (!result) {
   375         result = SDL_malloc(sizeof(GL_FBOList));
   376         if (result) {
   377             result->w = w;
   378             result->h = h;
   379             data->glGenFramebuffersEXT(1, &result->FBO);
   380             result->next = data->framebuffers;
   381             data->framebuffers = result;
   382         }
   383     }
   384     return result;
   385 }
   386 
   387 SDL_Renderer *
   388 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
   389 {
   390     SDL_Renderer *renderer;
   391     GL_RenderData *data;
   392     GLint value;
   393     Uint32 window_flags;
   394     int profile_mask = 0, major = 0, minor = 0;
   395     SDL_bool changed_window = SDL_FALSE;
   396 
   397     SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
   398     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
   399     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
   400     
   401     window_flags = SDL_GetWindowFlags(window);
   402     if (!(window_flags & SDL_WINDOW_OPENGL) ||
   403         profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
   404 
   405         changed_window = SDL_TRUE;
   406         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
   407         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
   408         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
   409 
   410         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
   411             goto error;
   412         }
   413     }
   414 
   415     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   416     if (!renderer) {
   417         SDL_OutOfMemory();
   418         goto error;
   419     }
   420 
   421     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
   422     if (!data) {
   423         SDL_free(renderer);
   424         SDL_OutOfMemory();
   425         goto error;
   426     }
   427 
   428     renderer->WindowEvent = GL_WindowEvent;
   429     renderer->GetOutputSize = GL_GetOutputSize;
   430     renderer->SupportsBlendMode = GL_SupportsBlendMode;
   431     renderer->CreateTexture = GL_CreateTexture;
   432     renderer->UpdateTexture = GL_UpdateTexture;
   433     renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
   434     renderer->LockTexture = GL_LockTexture;
   435     renderer->UnlockTexture = GL_UnlockTexture;
   436     renderer->SetRenderTarget = GL_SetRenderTarget;
   437     renderer->UpdateViewport = GL_UpdateViewport;
   438     renderer->UpdateClipRect = GL_UpdateClipRect;
   439     renderer->RenderClear = GL_RenderClear;
   440     renderer->RenderDrawPoints = GL_RenderDrawPoints;
   441     renderer->RenderDrawLines = GL_RenderDrawLines;
   442     renderer->RenderFillRects = GL_RenderFillRects;
   443     renderer->RenderCopy = GL_RenderCopy;
   444     renderer->RenderCopyEx = GL_RenderCopyEx;
   445     renderer->RenderReadPixels = GL_RenderReadPixels;
   446     renderer->RenderPresent = GL_RenderPresent;
   447     renderer->DestroyTexture = GL_DestroyTexture;
   448     renderer->DestroyRenderer = GL_DestroyRenderer;
   449     renderer->GL_BindTexture = GL_BindTexture;
   450     renderer->GL_UnbindTexture = GL_UnbindTexture;
   451     renderer->info = GL_RenderDriver.info;
   452     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   453     renderer->driverdata = data;
   454     renderer->window = window;
   455 
   456     data->context = SDL_GL_CreateContext(window);
   457     if (!data->context) {
   458         SDL_free(renderer);
   459         SDL_free(data);
   460         goto error;
   461     }
   462     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   463         SDL_GL_DeleteContext(data->context);
   464         SDL_free(renderer);
   465         SDL_free(data);
   466         goto error;
   467     }
   468 
   469     if (GL_LoadFunctions(data) < 0) {
   470         SDL_GL_DeleteContext(data->context);
   471         SDL_free(renderer);
   472         SDL_free(data);
   473         goto error;
   474     }
   475 
   476 #ifdef __MACOSX__
   477     /* Enable multi-threaded rendering */
   478     /* Disabled until Ryan finishes his VBO/PBO code...
   479        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
   480      */
   481 #endif
   482 
   483     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   484         SDL_GL_SetSwapInterval(1);
   485     } else {
   486         SDL_GL_SetSwapInterval(0);
   487     }
   488     if (SDL_GL_GetSwapInterval() > 0) {
   489         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   490     }
   491 
   492     /* Check for debug output support */
   493     if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
   494         (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
   495         data->debug_enabled = SDL_TRUE;
   496     }
   497     if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) {
   498         PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
   499 
   500         data->GL_ARB_debug_output_supported = SDL_TRUE;
   501         data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)(char *)&data->next_error_callback);
   502         data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam);
   503         glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer);
   504 
   505         /* Make sure our callback is called when errors actually happen */
   506         data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
   507     }
   508 
   509     if (SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) {
   510         data->GL_ARB_texture_non_power_of_two_supported = SDL_TRUE;
   511     } else if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
   512                SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
   513         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
   514     }
   515     if (data->GL_ARB_texture_rectangle_supported) {
   516         data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value);
   517         renderer->info.max_texture_width = value;
   518         renderer->info.max_texture_height = value;
   519     } else {
   520         data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   521         renderer->info.max_texture_width = value;
   522         renderer->info.max_texture_height = value;
   523     }
   524 
   525     /* Check for multitexture support */
   526     if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
   527         data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
   528         if (data->glActiveTextureARB) {
   529             data->GL_ARB_multitexture_supported = SDL_TRUE;
   530             data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
   531         }
   532     }
   533 
   534     /* Check for shader support */
   535     if (SDL_GetHintBoolean(SDL_HINT_RENDER_OPENGL_SHADERS, SDL_TRUE)) {
   536         data->shaders = GL_CreateShaderContext();
   537     }
   538     SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
   539                 data->shaders ? "ENABLED" : "DISABLED");
   540 
   541     /* We support YV12 textures using 3 textures and a shader */
   542     if (data->shaders && data->num_texture_units >= 3) {
   543         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   544         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   545         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
   546         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
   547     }
   548 
   549 #ifdef __MACOSX__
   550     renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
   551 #endif
   552 
   553     if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
   554         data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
   555         data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
   556             SDL_GL_GetProcAddress("glGenFramebuffersEXT");
   557         data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
   558             SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
   559         data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
   560             SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
   561         data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
   562             SDL_GL_GetProcAddress("glBindFramebufferEXT");
   563         data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
   564             SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
   565         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
   566     }
   567     data->framebuffers = NULL;
   568 
   569     /* Set up parameters for rendering */
   570     GL_ResetState(renderer);
   571 
   572     return renderer;
   573 
   574 error:
   575     if (changed_window) {
   576         /* Uh oh, better try to put it back... */
   577         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
   578         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
   579         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
   580         SDL_RecreateWindow(window, window_flags);
   581     }
   582     return NULL;
   583 }
   584 
   585 static void
   586 GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   587 {
   588     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
   589         event->event == SDL_WINDOWEVENT_SHOWN ||
   590         event->event == SDL_WINDOWEVENT_HIDDEN) {
   591         /* Rebind the context to the window area and update matrices */
   592         SDL_CurrentContext = NULL;
   593     }
   594 }
   595 
   596 static int
   597 GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
   598 {
   599     SDL_GL_GetDrawableSize(renderer->window, w, h);
   600     return 0;
   601 }
   602 
   603 static GLenum GetBlendFunc(SDL_BlendFactor factor)
   604 {
   605     switch (factor) {
   606     case SDL_BLENDFACTOR_ZERO:
   607         return GL_ZERO;
   608     case SDL_BLENDFACTOR_ONE:
   609         return GL_ONE;
   610     case SDL_BLENDFACTOR_SRC_COLOR:
   611         return GL_SRC_COLOR;
   612     case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
   613         return GL_ONE_MINUS_SRC_COLOR;
   614     case SDL_BLENDFACTOR_SRC_ALPHA:
   615         return GL_SRC_ALPHA;
   616     case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
   617         return GL_ONE_MINUS_SRC_ALPHA;
   618     case SDL_BLENDFACTOR_DST_COLOR:
   619         return GL_DST_COLOR;
   620     case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
   621         return GL_ONE_MINUS_DST_COLOR;
   622     case SDL_BLENDFACTOR_DST_ALPHA:
   623         return GL_DST_ALPHA;
   624     case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
   625         return GL_ONE_MINUS_DST_ALPHA;
   626     default:
   627         return GL_INVALID_ENUM;
   628     }
   629 }
   630 
   631 static GLenum GetBlendEquation(SDL_BlendOperation operation)
   632 {
   633     switch (operation) {
   634     case SDL_BLENDOPERATION_ADD:
   635         return GL_FUNC_ADD;
   636     case SDL_BLENDOPERATION_SUBTRACT:
   637         return GL_FUNC_SUBTRACT;
   638     case SDL_BLENDOPERATION_REV_SUBTRACT:
   639         return GL_FUNC_REVERSE_SUBTRACT;
   640     default:
   641         return GL_INVALID_ENUM;
   642     }
   643 }
   644 
   645 static SDL_bool
   646 GL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
   647 {
   648     SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
   649     SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
   650     SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
   651     SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
   652     SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
   653     SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
   654 
   655     if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM ||
   656         GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM ||
   657         GetBlendEquation(colorOperation) == GL_INVALID_ENUM ||
   658         GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM ||
   659         GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM ||
   660         GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) {
   661         return SDL_FALSE;
   662     }
   663     if (colorOperation != alphaOperation) {
   664         return SDL_FALSE;
   665     }
   666     return SDL_TRUE;
   667 }
   668 
   669 SDL_FORCE_INLINE int
   670 power_of_2(int input)
   671 {
   672     int value = 1;
   673 
   674     while (value < input) {
   675         value <<= 1;
   676     }
   677     return value;
   678 }
   679 
   680 SDL_FORCE_INLINE SDL_bool
   681 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
   682                GLint* internalFormat, GLenum* format, GLenum* type)
   683 {
   684     switch (pixel_format) {
   685     case SDL_PIXELFORMAT_ARGB8888:
   686         *internalFormat = GL_RGBA8;
   687         *format = GL_BGRA;
   688         *type = GL_UNSIGNED_INT_8_8_8_8_REV;
   689         break;
   690     case SDL_PIXELFORMAT_YV12:
   691     case SDL_PIXELFORMAT_IYUV:
   692     case SDL_PIXELFORMAT_NV12:
   693     case SDL_PIXELFORMAT_NV21:
   694         *internalFormat = GL_LUMINANCE;
   695         *format = GL_LUMINANCE;
   696         *type = GL_UNSIGNED_BYTE;
   697         break;
   698 #ifdef __MACOSX__
   699     case SDL_PIXELFORMAT_UYVY:
   700         *internalFormat = GL_RGB8;
   701         *format = GL_YCBCR_422_APPLE;
   702         *type = GL_UNSIGNED_SHORT_8_8_APPLE;
   703         break;
   704 #endif
   705     default:
   706         return SDL_FALSE;
   707     }
   708     return SDL_TRUE;
   709 }
   710 
   711 static int
   712 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   713 {
   714     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   715     GL_TextureData *data;
   716     GLint internalFormat;
   717     GLenum format, type;
   718     int texture_w, texture_h;
   719     GLenum scaleMode;
   720 
   721     GL_ActivateRenderer(renderer);
   722 
   723     if (texture->access == SDL_TEXTUREACCESS_TARGET &&
   724         !renderdata->GL_EXT_framebuffer_object_supported) {
   725         return SDL_SetError("Render targets not supported by OpenGL");
   726     }
   727 
   728     if (!convert_format(renderdata, texture->format, &internalFormat,
   729                         &format, &type)) {
   730         return SDL_SetError("Texture format %s not supported by OpenGL",
   731                             SDL_GetPixelFormatName(texture->format));
   732     }
   733 
   734     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   735     if (!data) {
   736         return SDL_OutOfMemory();
   737     }
   738 
   739     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   740         size_t size;
   741         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   742         size = texture->h * data->pitch;
   743         if (texture->format == SDL_PIXELFORMAT_YV12 ||
   744             texture->format == SDL_PIXELFORMAT_IYUV) {
   745             /* Need to add size for the U and V planes */
   746             size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
   747         }
   748         if (texture->format == SDL_PIXELFORMAT_NV12 ||
   749             texture->format == SDL_PIXELFORMAT_NV21) {
   750             /* Need to add size for the U/V plane */
   751             size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
   752         }
   753         data->pixels = SDL_calloc(1, size);
   754         if (!data->pixels) {
   755             SDL_free(data);
   756             return SDL_OutOfMemory();
   757         }
   758     }
   759 
   760     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   761         data->fbo = GL_GetFBO(renderdata, texture->w, texture->h);
   762     } else {
   763         data->fbo = NULL;
   764     }
   765 
   766     GL_CheckError("", renderer);
   767     renderdata->glGenTextures(1, &data->texture);
   768     if (GL_CheckError("glGenTextures()", renderer) < 0) {
   769         if (data->pixels) {
   770             SDL_free(data->pixels);
   771         }
   772         SDL_free(data);
   773         return -1;
   774     }
   775     texture->driverdata = data;
   776 
   777     if (renderdata->GL_ARB_texture_non_power_of_two_supported) {
   778         data->type = GL_TEXTURE_2D;
   779         texture_w = texture->w;
   780         texture_h = texture->h;
   781         data->texw = 1.0f;
   782         data->texh = 1.0f;
   783     } else if (renderdata->GL_ARB_texture_rectangle_supported) {
   784         data->type = GL_TEXTURE_RECTANGLE_ARB;
   785         texture_w = texture->w;
   786         texture_h = texture->h;
   787         data->texw = (GLfloat) texture_w;
   788         data->texh = (GLfloat) texture_h;
   789     } else {
   790         data->type = GL_TEXTURE_2D;
   791         texture_w = power_of_2(texture->w);
   792         texture_h = power_of_2(texture->h);
   793         data->texw = (GLfloat) (texture->w) / texture_w;
   794         data->texh = (GLfloat) texture->h / texture_h;
   795     }
   796 
   797     data->format = format;
   798     data->formattype = type;
   799     scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
   800     renderdata->glEnable(data->type);
   801     renderdata->glBindTexture(data->type, data->texture);
   802     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
   803     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
   804     /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE
   805        and setting it causes an INVALID_ENUM error in the latest NVidia drivers.
   806     */
   807     if (data->type != GL_TEXTURE_RECTANGLE_ARB) {
   808         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   809                                     GL_CLAMP_TO_EDGE);
   810         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   811                                     GL_CLAMP_TO_EDGE);
   812     }
   813 #ifdef __MACOSX__
   814 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
   815 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
   816 #endif
   817 #ifndef STORAGE_CACHED_APPLE
   818 #define STORAGE_CACHED_APPLE                0x85BE
   819 #endif
   820 #ifndef STORAGE_SHARED_APPLE
   821 #define STORAGE_SHARED_APPLE                0x85BF
   822 #endif
   823     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   824         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   825                                     GL_STORAGE_SHARED_APPLE);
   826     } else {
   827         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   828                                     GL_STORAGE_CACHED_APPLE);
   829     }
   830     if (texture->access == SDL_TEXTUREACCESS_STREAMING
   831         && texture->format == SDL_PIXELFORMAT_ARGB8888
   832         && (texture->w % 8) == 0) {
   833         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
   834         renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   835         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   836                           (data->pitch / SDL_BYTESPERPIXEL(texture->format)));
   837         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   838                                  texture_h, 0, format, type, data->pixels);
   839         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
   840     }
   841     else
   842 #endif
   843     {
   844         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   845                                  texture_h, 0, format, type, NULL);
   846     }
   847     renderdata->glDisable(data->type);
   848     if (GL_CheckError("glTexImage2D()", renderer) < 0) {
   849         return -1;
   850     }
   851 
   852     if (texture->format == SDL_PIXELFORMAT_YV12 ||
   853         texture->format == SDL_PIXELFORMAT_IYUV) {
   854         data->yuv = SDL_TRUE;
   855 
   856         renderdata->glGenTextures(1, &data->utexture);
   857         renderdata->glGenTextures(1, &data->vtexture);
   858         renderdata->glEnable(data->type);
   859 
   860         renderdata->glBindTexture(data->type, data->utexture);
   861         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   862                                     scaleMode);
   863         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   864                                     scaleMode);
   865         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   866                                     GL_CLAMP_TO_EDGE);
   867         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   868                                     GL_CLAMP_TO_EDGE);
   869         renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2,
   870                                  (texture_h+1)/2, 0, format, type, NULL);
   871 
   872         renderdata->glBindTexture(data->type, data->vtexture);
   873         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   874                                     scaleMode);
   875         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   876                                     scaleMode);
   877         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   878                                     GL_CLAMP_TO_EDGE);
   879         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   880                                     GL_CLAMP_TO_EDGE);
   881         renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2,
   882                                  (texture_h+1)/2, 0, format, type, NULL);
   883 
   884         renderdata->glDisable(data->type);
   885     }
   886 
   887     if (texture->format == SDL_PIXELFORMAT_NV12 ||
   888         texture->format == SDL_PIXELFORMAT_NV21) {
   889         data->nv12 = SDL_TRUE;
   890 
   891         renderdata->glGenTextures(1, &data->utexture);
   892         renderdata->glEnable(data->type);
   893 
   894         renderdata->glBindTexture(data->type, data->utexture);
   895         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   896                                     scaleMode);
   897         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   898                                     scaleMode);
   899         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   900                                     GL_CLAMP_TO_EDGE);
   901         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   902                                     GL_CLAMP_TO_EDGE);
   903         renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2,
   904                                  (texture_h+1)/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
   905         renderdata->glDisable(data->type);
   906     }
   907 
   908     return GL_CheckError("", renderer);
   909 }
   910 
   911 static int
   912 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   913                  const SDL_Rect * rect, const void *pixels, int pitch)
   914 {
   915     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   916     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   917     const int texturebpp = SDL_BYTESPERPIXEL(texture->format);
   918 
   919     SDL_assert(texturebpp != 0);  /* otherwise, division by zero later. */
   920 
   921     GL_ActivateRenderer(renderer);
   922 
   923     renderdata->glEnable(data->type);
   924     renderdata->glBindTexture(data->type, data->texture);
   925     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   926     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / texturebpp));
   927     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   928                                 rect->h, data->format, data->formattype,
   929                                 pixels);
   930     if (data->yuv) {
   931         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, ((pitch + 1) / 2));
   932 
   933         /* Skip to the correct offset into the next texture */
   934         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
   935         if (texture->format == SDL_PIXELFORMAT_YV12) {
   936             renderdata->glBindTexture(data->type, data->vtexture);
   937         } else {
   938             renderdata->glBindTexture(data->type, data->utexture);
   939         }
   940         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   941                                     (rect->w+1)/2, (rect->h+1)/2,
   942                                     data->format, data->formattype, pixels);
   943 
   944         /* Skip to the correct offset into the next texture */
   945         pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
   946         if (texture->format == SDL_PIXELFORMAT_YV12) {
   947             renderdata->glBindTexture(data->type, data->utexture);
   948         } else {
   949             renderdata->glBindTexture(data->type, data->vtexture);
   950         }
   951         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   952                                     (rect->w+1)/2, (rect->h+1)/2,
   953                                     data->format, data->formattype, pixels);
   954     }
   955 
   956     if (data->nv12) {
   957         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, ((pitch + 1) / 2));
   958 
   959         /* Skip to the correct offset into the next texture */
   960         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
   961         renderdata->glBindTexture(data->type, data->utexture);
   962         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   963                                     (rect->w + 1)/2, (rect->h + 1)/2,
   964                                     GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
   965     }
   966     renderdata->glDisable(data->type);
   967 
   968     return GL_CheckError("glTexSubImage2D()", renderer);
   969 }
   970 
   971 static int
   972 GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
   973                     const SDL_Rect * rect,
   974                     const Uint8 *Yplane, int Ypitch,
   975                     const Uint8 *Uplane, int Upitch,
   976                     const Uint8 *Vplane, int Vpitch)
   977 {
   978     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   979     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   980 
   981     GL_ActivateRenderer(renderer);
   982 
   983     renderdata->glEnable(data->type);
   984     renderdata->glBindTexture(data->type, data->texture);
   985     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   986     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch);
   987     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   988                                 rect->h, data->format, data->formattype,
   989                                 Yplane);
   990 
   991     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
   992     renderdata->glBindTexture(data->type, data->utexture);
   993     renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   994                                 (rect->w + 1)/2, (rect->h + 1)/2,
   995                                 data->format, data->formattype, Uplane);
   996 
   997     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
   998     renderdata->glBindTexture(data->type, data->vtexture);
   999     renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
  1000                                 (rect->w + 1)/2, (rect->h + 1)/2,
  1001                                 data->format, data->formattype, Vplane);
  1002     renderdata->glDisable(data->type);
  1003 
  1004     return GL_CheckError("glTexSubImage2D()", renderer);
  1005 }
  1006 
  1007 static int
  1008 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1009                const SDL_Rect * rect, void **pixels, int *pitch)
  1010 {
  1011     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1012 
  1013     data->locked_rect = *rect;
  1014     *pixels =
  1015         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
  1016                   rect->x * SDL_BYTESPERPIXEL(texture->format));
  1017     *pitch = data->pitch;
  1018     return 0;
  1019 }
  1020 
  1021 static void
  1022 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1023 {
  1024     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1025     const SDL_Rect *rect;
  1026     void *pixels;
  1027 
  1028     rect = &data->locked_rect;
  1029     pixels =
  1030         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
  1031                   rect->x * SDL_BYTESPERPIXEL(texture->format));
  1032     GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
  1033 }
  1034 
  1035 static int
  1036 GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
  1037 {
  1038     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1039     GL_TextureData *texturedata;
  1040     GLenum status;
  1041 
  1042     GL_ActivateRenderer(renderer);
  1043 
  1044     if (!data->GL_EXT_framebuffer_object_supported) {
  1045         return SDL_SetError("Render targets not supported by OpenGL");
  1046     }
  1047 
  1048     if (texture == NULL) {
  1049         data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  1050         return 0;
  1051     }
  1052 
  1053     texturedata = (GL_TextureData *) texture->driverdata;
  1054     data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
  1055     /* TODO: check if texture pixel format allows this operation */
  1056     data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
  1057     /* Check FBO status */
  1058     status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  1059     if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
  1060         return SDL_SetError("glFramebufferTexture2DEXT() failed");
  1061     }
  1062     return 0;
  1063 }
  1064 
  1065 static int
  1066 GL_UpdateViewport(SDL_Renderer * renderer)
  1067 {
  1068     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1069 
  1070     if (SDL_CurrentContext != data->context) {
  1071         /* We'll update the viewport after we rebind the context */
  1072         return 0;
  1073     }
  1074 
  1075     if (renderer->target) {
  1076         data->glViewport(renderer->viewport.x, renderer->viewport.y,
  1077                          renderer->viewport.w, renderer->viewport.h);
  1078     } else {
  1079         int w, h;
  1080 
  1081         SDL_GL_GetDrawableSize(renderer->window, &w, &h);
  1082         data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h),
  1083                          renderer->viewport.w, renderer->viewport.h);
  1084     }
  1085 
  1086     data->glMatrixMode(GL_PROJECTION);
  1087     data->glLoadIdentity();
  1088     if (renderer->viewport.w && renderer->viewport.h) {
  1089         if (renderer->target) {
  1090             data->glOrtho((GLdouble) 0,
  1091                           (GLdouble) renderer->viewport.w,
  1092                           (GLdouble) 0,
  1093                           (GLdouble) renderer->viewport.h,
  1094                            0.0, 1.0);
  1095         } else {
  1096             data->glOrtho((GLdouble) 0,
  1097                           (GLdouble) renderer->viewport.w,
  1098                           (GLdouble) renderer->viewport.h,
  1099                           (GLdouble) 0,
  1100                            0.0, 1.0);
  1101         }
  1102     }
  1103     data->glMatrixMode(GL_MODELVIEW);
  1104 
  1105     return GL_CheckError("", renderer);
  1106 }
  1107 
  1108 static int
  1109 GL_UpdateClipRect(SDL_Renderer * renderer)
  1110 {
  1111     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1112 
  1113     if (renderer->clipping_enabled) {
  1114         const SDL_Rect *rect = &renderer->clip_rect;
  1115         data->glEnable(GL_SCISSOR_TEST);
  1116         if (renderer->target) {
  1117             data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h);
  1118         } else {
  1119             int w, h;
  1120 
  1121             SDL_GL_GetDrawableSize(renderer->window, &w, &h);
  1122             data->glScissor(renderer->viewport.x + rect->x, h - renderer->viewport.y - rect->y - rect->h, rect->w, rect->h);
  1123         }
  1124     } else {
  1125         data->glDisable(GL_SCISSOR_TEST);
  1126     }
  1127     return 0;
  1128 }
  1129 
  1130 static void
  1131 GL_SetShader(GL_RenderData * data, GL_Shader shader)
  1132 {
  1133     if (data->shaders && shader != data->current.shader) {
  1134         GL_SelectShader(data->shaders, shader);
  1135         data->current.shader = shader;
  1136     }
  1137 }
  1138 
  1139 static void
  1140 GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  1141 {
  1142     Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
  1143 
  1144     if (color != data->current.color) {
  1145         data->glColor4f((GLfloat) r * inv255f,
  1146                         (GLfloat) g * inv255f,
  1147                         (GLfloat) b * inv255f,
  1148                         (GLfloat) a * inv255f);
  1149         data->current.color = color;
  1150     }
  1151 }
  1152 
  1153 static void
  1154 GL_SetBlendMode(GL_RenderData * data, SDL_BlendMode blendMode)
  1155 {
  1156     if (blendMode != data->current.blendMode) {
  1157         if (blendMode == SDL_BLENDMODE_NONE) {
  1158             data->glDisable(GL_BLEND);
  1159         } else {
  1160             data->glEnable(GL_BLEND);
  1161             data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)),
  1162                                       GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)),
  1163                                       GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)),
  1164                                       GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode)));
  1165             data->glBlendEquation(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode)));
  1166         }
  1167         data->current.blendMode = blendMode;
  1168     }
  1169 }
  1170 
  1171 static void
  1172 GL_SetDrawingState(SDL_Renderer * renderer)
  1173 {
  1174     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1175 
  1176     GL_ActivateRenderer(renderer);
  1177 
  1178     GL_SetColor(data, renderer->r,
  1179                       renderer->g,
  1180                       renderer->b,
  1181                       renderer->a);
  1182 
  1183     GL_SetBlendMode(data, renderer->blendMode);
  1184 
  1185     GL_SetShader(data, SHADER_SOLID);
  1186 }
  1187 
  1188 static int
  1189 GL_RenderClear(SDL_Renderer * renderer)
  1190 {
  1191     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1192 
  1193     GL_ActivateRenderer(renderer);
  1194 
  1195     data->glClearColor((GLfloat) renderer->r * inv255f,
  1196                        (GLfloat) renderer->g * inv255f,
  1197                        (GLfloat) renderer->b * inv255f,
  1198                        (GLfloat) renderer->a * inv255f);
  1199 
  1200     if (renderer->clipping_enabled) {
  1201         data->glDisable(GL_SCISSOR_TEST);
  1202     }
  1203 
  1204     data->glClear(GL_COLOR_BUFFER_BIT);
  1205 
  1206     if (renderer->clipping_enabled) {
  1207         data->glEnable(GL_SCISSOR_TEST);
  1208     }
  1209 
  1210     return 0;
  1211 }
  1212 
  1213 static int
  1214 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
  1215                     int count)
  1216 {
  1217     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1218     int i;
  1219 
  1220     GL_SetDrawingState(renderer);
  1221 
  1222     data->glBegin(GL_POINTS);
  1223     for (i = 0; i < count; ++i) {
  1224         data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
  1225     }
  1226     data->glEnd();
  1227 
  1228     return 0;
  1229 }
  1230 
  1231 static int
  1232 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
  1233                    int count)
  1234 {
  1235     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1236     int i;
  1237 
  1238     GL_SetDrawingState(renderer);
  1239 
  1240     if (count > 2 &&
  1241         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
  1242         data->glBegin(GL_LINE_LOOP);
  1243         /* GL_LINE_LOOP takes care of the final segment */
  1244         --count;
  1245         for (i = 0; i < count; ++i) {
  1246             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
  1247         }
  1248         data->glEnd();
  1249     } else {
  1250 #if defined(__MACOSX__) || defined(__WIN32__)
  1251 #else
  1252         int x1, y1, x2, y2;
  1253 #endif
  1254 
  1255         data->glBegin(GL_LINE_STRIP);
  1256         for (i = 0; i < count; ++i) {
  1257             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
  1258         }
  1259         data->glEnd();
  1260 
  1261         /* The line is half open, so we need one more point to complete it.
  1262          * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
  1263          * If we have to, we can use vertical line and horizontal line textures
  1264          * for vertical and horizontal lines, and then create custom textures
  1265          * for diagonal lines and software render those.  It's terrible, but at
  1266          * least it would be pixel perfect.
  1267          */
  1268         data->glBegin(GL_POINTS);
  1269 #if defined(__MACOSX__) || defined(__WIN32__)
  1270         /* Mac OS X and Windows seem to always leave the last point open */
  1271         data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
  1272 #else
  1273         /* Linux seems to leave the right-most or bottom-most point open */
  1274         x1 = points[0].x;
  1275         y1 = points[0].y;
  1276         x2 = points[count-1].x;
  1277         y2 = points[count-1].y;
  1278 
  1279         if (x1 > x2) {
  1280             data->glVertex2f(0.5f + x1, 0.5f + y1);
  1281         } else if (x2 > x1) {
  1282             data->glVertex2f(0.5f + x2, 0.5f + y2);
  1283         }
  1284         if (y1 > y2) {
  1285             data->glVertex2f(0.5f + x1, 0.5f + y1);
  1286         } else if (y2 > y1) {
  1287             data->glVertex2f(0.5f + x2, 0.5f + y2);
  1288         }
  1289 #endif
  1290         data->glEnd();
  1291     }
  1292     return GL_CheckError("", renderer);
  1293 }
  1294 
  1295 static int
  1296 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
  1297 {
  1298     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1299     int i;
  1300 
  1301     GL_SetDrawingState(renderer);
  1302 
  1303     for (i = 0; i < count; ++i) {
  1304         const SDL_FRect *rect = &rects[i];
  1305 
  1306         data->glRectf(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
  1307     }
  1308     return GL_CheckError("", renderer);
  1309 }
  1310 
  1311 static int
  1312 GL_SetupCopy(SDL_Renderer * renderer, SDL_Texture * texture)
  1313 {
  1314     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1315     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1316 
  1317     data->glEnable(texturedata->type);
  1318     if (texturedata->yuv) {
  1319         data->glActiveTextureARB(GL_TEXTURE2_ARB);
  1320         data->glBindTexture(texturedata->type, texturedata->vtexture);
  1321 
  1322         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1323         data->glBindTexture(texturedata->type, texturedata->utexture);
  1324 
  1325         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1326     }
  1327     if (texturedata->nv12) {
  1328         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1329         data->glBindTexture(texturedata->type, texturedata->utexture);
  1330 
  1331         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1332     }
  1333     data->glBindTexture(texturedata->type, texturedata->texture);
  1334 
  1335     if (texture->modMode) {
  1336         GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
  1337     } else {
  1338         GL_SetColor(data, 255, 255, 255, 255);
  1339     }
  1340 
  1341     GL_SetBlendMode(data, texture->blendMode);
  1342 
  1343     if (texturedata->yuv || texturedata->nv12) {
  1344         switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
  1345         case SDL_YUV_CONVERSION_JPEG:
  1346             if (texturedata->yuv) {
  1347                 GL_SetShader(data, SHADER_YUV_JPEG);
  1348             } else if (texture->format == SDL_PIXELFORMAT_NV12) {
  1349                 GL_SetShader(data, SHADER_NV12_JPEG);
  1350             } else {
  1351                 GL_SetShader(data, SHADER_NV21_JPEG);
  1352             }
  1353             break;
  1354         case SDL_YUV_CONVERSION_BT601:
  1355             if (texturedata->yuv) {
  1356                 GL_SetShader(data, SHADER_YUV_BT601);
  1357             } else if (texture->format == SDL_PIXELFORMAT_NV12) {
  1358                 GL_SetShader(data, SHADER_NV12_BT601);
  1359             } else {
  1360                 GL_SetShader(data, SHADER_NV21_BT601);
  1361             }
  1362             break;
  1363         case SDL_YUV_CONVERSION_BT709:
  1364             if (texturedata->yuv) {
  1365                 GL_SetShader(data, SHADER_YUV_BT709);
  1366             } else if (texture->format == SDL_PIXELFORMAT_NV12) {
  1367                 GL_SetShader(data, SHADER_NV12_BT709);
  1368             } else {
  1369                 GL_SetShader(data, SHADER_NV21_BT709);
  1370             }
  1371             break;
  1372         default:
  1373             return SDL_SetError("Unsupported YUV conversion mode");
  1374         }
  1375     } else {
  1376         GL_SetShader(data, SHADER_RGB);
  1377     }
  1378     return 0;
  1379 }
  1380 
  1381 static int
  1382 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1383               const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  1384 {
  1385     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1386     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1387     GLfloat minx, miny, maxx, maxy;
  1388     GLfloat minu, maxu, minv, maxv;
  1389 
  1390     GL_ActivateRenderer(renderer);
  1391 
  1392     if (GL_SetupCopy(renderer, texture) < 0) {
  1393         return -1;
  1394     }
  1395 
  1396     minx = dstrect->x;
  1397     miny = dstrect->y;
  1398     maxx = dstrect->x + dstrect->w;
  1399     maxy = dstrect->y + dstrect->h;
  1400 
  1401     minu = (GLfloat) srcrect->x / texture->w;
  1402     minu *= texturedata->texw;
  1403     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
  1404     maxu *= texturedata->texw;
  1405     minv = (GLfloat) srcrect->y / texture->h;
  1406     minv *= texturedata->texh;
  1407     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
  1408     maxv *= texturedata->texh;
  1409 
  1410     data->glBegin(GL_TRIANGLE_STRIP);
  1411     data->glTexCoord2f(minu, minv);
  1412     data->glVertex2f(minx, miny);
  1413     data->glTexCoord2f(maxu, minv);
  1414     data->glVertex2f(maxx, miny);
  1415     data->glTexCoord2f(minu, maxv);
  1416     data->glVertex2f(minx, maxy);
  1417     data->glTexCoord2f(maxu, maxv);
  1418     data->glVertex2f(maxx, maxy);
  1419     data->glEnd();
  1420 
  1421     data->glDisable(texturedata->type);
  1422 
  1423     return GL_CheckError("", renderer);
  1424 }
  1425 
  1426 static int
  1427 GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1428               const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  1429               const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
  1430 {
  1431     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1432     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1433     GLfloat minx, miny, maxx, maxy;
  1434     GLfloat centerx, centery;
  1435     GLfloat minu, maxu, minv, maxv;
  1436 
  1437     GL_ActivateRenderer(renderer);
  1438 
  1439     if (GL_SetupCopy(renderer, texture) < 0) {
  1440         return -1;
  1441     }
  1442 
  1443     centerx = center->x;
  1444     centery = center->y;
  1445 
  1446     if (flip & SDL_FLIP_HORIZONTAL) {
  1447         minx =  dstrect->w - centerx;
  1448         maxx = -centerx;
  1449     }
  1450     else {
  1451         minx = -centerx;
  1452         maxx =  dstrect->w - centerx;
  1453     }
  1454 
  1455     if (flip & SDL_FLIP_VERTICAL) {
  1456         miny =  dstrect->h - centery;
  1457         maxy = -centery;
  1458     }
  1459     else {
  1460         miny = -centery;
  1461         maxy =  dstrect->h - centery;
  1462     }
  1463 
  1464     minu = (GLfloat) srcrect->x / texture->w;
  1465     minu *= texturedata->texw;
  1466     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
  1467     maxu *= texturedata->texw;
  1468     minv = (GLfloat) srcrect->y / texture->h;
  1469     minv *= texturedata->texh;
  1470     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
  1471     maxv *= texturedata->texh;
  1472 
  1473     /* Translate to flip, rotate, translate to position */
  1474     data->glPushMatrix();
  1475     data->glTranslatef((GLfloat)dstrect->x + centerx, (GLfloat)dstrect->y + centery, (GLfloat)0.0);
  1476     data->glRotated(angle, (GLdouble)0.0, (GLdouble)0.0, (GLdouble)1.0);
  1477 
  1478     data->glBegin(GL_TRIANGLE_STRIP);
  1479     data->glTexCoord2f(minu, minv);
  1480     data->glVertex2f(minx, miny);
  1481     data->glTexCoord2f(maxu, minv);
  1482     data->glVertex2f(maxx, miny);
  1483     data->glTexCoord2f(minu, maxv);
  1484     data->glVertex2f(minx, maxy);
  1485     data->glTexCoord2f(maxu, maxv);
  1486     data->glVertex2f(maxx, maxy);
  1487     data->glEnd();
  1488     data->glPopMatrix();
  1489 
  1490     data->glDisable(texturedata->type);
  1491 
  1492     return GL_CheckError("", renderer);
  1493 }
  1494 
  1495 static int
  1496 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1497                     Uint32 pixel_format, void * pixels, int pitch)
  1498 {
  1499     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1500     Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ARGB8888;
  1501     void *temp_pixels;
  1502     int temp_pitch;
  1503     GLint internalFormat;
  1504     GLenum format, type;
  1505     Uint8 *src, *dst, *tmp;
  1506     int w, h, length, rows;
  1507     int status;
  1508 
  1509     GL_ActivateRenderer(renderer);
  1510 
  1511     if (!convert_format(data, temp_format, &internalFormat, &format, &type)) {
  1512         return SDL_SetError("Texture format %s not supported by OpenGL",
  1513                             SDL_GetPixelFormatName(temp_format));
  1514     }
  1515 
  1516     if (!rect->w || !rect->h) {
  1517         return 0;  /* nothing to do. */
  1518     }
  1519 
  1520     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1521     temp_pixels = SDL_malloc(rect->h * temp_pitch);
  1522     if (!temp_pixels) {
  1523         return SDL_OutOfMemory();
  1524     }
  1525 
  1526     SDL_GetRendererOutputSize(renderer, &w, &h);
  1527 
  1528     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
  1529     data->glPixelStorei(GL_PACK_ROW_LENGTH,
  1530                         (temp_pitch / SDL_BYTESPERPIXEL(temp_format)));
  1531 
  1532     data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
  1533                        rect->w, rect->h, format, type, temp_pixels);
  1534 
  1535     if (GL_CheckError("glReadPixels()", renderer) < 0) {
  1536         SDL_free(temp_pixels);
  1537         return -1;
  1538     }
  1539 
  1540     /* Flip the rows to be top-down if necessary */
  1541     if (!renderer->target) {
  1542         length = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1543         src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
  1544         dst = (Uint8*)temp_pixels;
  1545         tmp = SDL_stack_alloc(Uint8, length);
  1546         rows = rect->h / 2;
  1547         while (rows--) {
  1548             SDL_memcpy(tmp, dst, length);
  1549             SDL_memcpy(dst, src, length);
  1550             SDL_memcpy(src, tmp, length);
  1551             dst += temp_pitch;
  1552             src -= temp_pitch;
  1553         }
  1554         SDL_stack_free(tmp);
  1555     }
  1556 
  1557     status = SDL_ConvertPixels(rect->w, rect->h,
  1558                                temp_format, temp_pixels, temp_pitch,
  1559                                pixel_format, pixels, pitch);
  1560     SDL_free(temp_pixels);
  1561 
  1562     return status;
  1563 }
  1564 
  1565 static void
  1566 GL_RenderPresent(SDL_Renderer * renderer)
  1567 {
  1568     GL_ActivateRenderer(renderer);
  1569 
  1570     SDL_GL_SwapWindow(renderer->window);
  1571 }
  1572 
  1573 static void
  1574 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1575 {
  1576     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  1577     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1578 
  1579     GL_ActivateRenderer(renderer);
  1580 
  1581     if (!data) {
  1582         return;
  1583     }
  1584     if (data->texture) {
  1585         renderdata->glDeleteTextures(1, &data->texture);
  1586     }
  1587     if (data->yuv) {
  1588         renderdata->glDeleteTextures(1, &data->utexture);
  1589         renderdata->glDeleteTextures(1, &data->vtexture);
  1590     }
  1591     SDL_free(data->pixels);
  1592     SDL_free(data);
  1593     texture->driverdata = NULL;
  1594 }
  1595 
  1596 static void
  1597 GL_DestroyRenderer(SDL_Renderer * renderer)
  1598 {
  1599     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1600 
  1601     if (data) {
  1602         if (data->context != NULL) {
  1603             /* make sure we delete the right resources! */
  1604             GL_ActivateRenderer(renderer);
  1605         }
  1606 
  1607         GL_ClearErrors(renderer);
  1608         if (data->GL_ARB_debug_output_supported) {
  1609             PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
  1610 
  1611             /* Uh oh, we don't have a safe way of removing ourselves from the callback chain, if it changed after we set our callback. */
  1612             /* For now, just always replace the callback with the original one */
  1613             glDebugMessageCallbackARBFunc(data->next_error_callback, data->next_error_userparam);
  1614         }
  1615         if (data->shaders) {
  1616             GL_DestroyShaderContext(data->shaders);
  1617         }
  1618         if (data->context) {
  1619             while (data->framebuffers) {
  1620                 GL_FBOList *nextnode = data->framebuffers->next;
  1621                 /* delete the framebuffer object */
  1622                 data->glDeleteFramebuffersEXT(1, &data->framebuffers->FBO);
  1623                 GL_CheckError("", renderer);
  1624                 SDL_free(data->framebuffers);
  1625                 data->framebuffers = nextnode;
  1626             }
  1627             SDL_GL_DeleteContext(data->context);
  1628         }
  1629         SDL_free(data);
  1630     }
  1631     SDL_free(renderer);
  1632 }
  1633 
  1634 static int
  1635 GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
  1636 {
  1637     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1638     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1639     GL_ActivateRenderer(renderer);
  1640 
  1641     data->glEnable(texturedata->type);
  1642     if (texturedata->yuv) {
  1643         data->glActiveTextureARB(GL_TEXTURE2_ARB);
  1644         data->glBindTexture(texturedata->type, texturedata->vtexture);
  1645 
  1646         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1647         data->glBindTexture(texturedata->type, texturedata->utexture);
  1648 
  1649         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1650     }
  1651     data->glBindTexture(texturedata->type, texturedata->texture);
  1652 
  1653     if(texw) *texw = (float)texturedata->texw;
  1654     if(texh) *texh = (float)texturedata->texh;
  1655 
  1656     return 0;
  1657 }
  1658 
  1659 static int
  1660 GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
  1661 {
  1662     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1663     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1664     GL_ActivateRenderer(renderer);
  1665 
  1666     if (texturedata->yuv) {
  1667         data->glActiveTextureARB(GL_TEXTURE2_ARB);
  1668         data->glDisable(texturedata->type);
  1669 
  1670         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1671         data->glDisable(texturedata->type);
  1672 
  1673         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1674     }
  1675 
  1676     data->glDisable(texturedata->type);
  1677 
  1678     return 0;
  1679 }
  1680 
  1681 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
  1682 
  1683 /* vi: set ts=4 sw=4 expandtab: */