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