src/render/opengl/SDL_render_gl.c
author Alex Szpakowski <slime73@gmail.com>
Thu, 10 Dec 2015 20:25:34 -0400
changeset 9958 687e118144c7
parent 9680 1d13a878b066
child 9977 f9cd179cf50e
permissions -rw-r--r--
SDL_GL_GetAttribute: If a GL context isn't active, only return failure when the specified attribute needs an active GL context to be queried.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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     const char *hint;
   394     GLint value;
   395     Uint32 window_flags;
   396     int profile_mask = 0, major = 0, minor = 0;
   397     SDL_bool changed_window = SDL_FALSE;
   398 
   399     SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
   400     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
   401     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
   402     
   403     window_flags = SDL_GetWindowFlags(window);
   404     if (!(window_flags & SDL_WINDOW_OPENGL) ||
   405         profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
   406 
   407         changed_window = SDL_TRUE;
   408         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
   409         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
   410         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
   411 
   412         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
   413             goto error;
   414         }
   415     }
   416 
   417     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   418     if (!renderer) {
   419         SDL_OutOfMemory();
   420         goto error;
   421     }
   422 
   423     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
   424     if (!data) {
   425         GL_DestroyRenderer(renderer);
   426         SDL_OutOfMemory();
   427         goto error;
   428     }
   429 
   430     renderer->WindowEvent = GL_WindowEvent;
   431     renderer->GetOutputSize = GL_GetOutputSize;
   432     renderer->CreateTexture = GL_CreateTexture;
   433     renderer->UpdateTexture = GL_UpdateTexture;
   434     renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
   435     renderer->LockTexture = GL_LockTexture;
   436     renderer->UnlockTexture = GL_UnlockTexture;
   437     renderer->SetRenderTarget = GL_SetRenderTarget;
   438     renderer->UpdateViewport = GL_UpdateViewport;
   439     renderer->UpdateClipRect = GL_UpdateClipRect;
   440     renderer->RenderClear = GL_RenderClear;
   441     renderer->RenderDrawPoints = GL_RenderDrawPoints;
   442     renderer->RenderDrawLines = GL_RenderDrawLines;
   443     renderer->RenderFillRects = GL_RenderFillRects;
   444     renderer->RenderCopy = GL_RenderCopy;
   445     renderer->RenderCopyEx = GL_RenderCopyEx;
   446     renderer->RenderReadPixels = GL_RenderReadPixels;
   447     renderer->RenderPresent = GL_RenderPresent;
   448     renderer->DestroyTexture = GL_DestroyTexture;
   449     renderer->DestroyRenderer = GL_DestroyRenderer;
   450     renderer->GL_BindTexture = GL_BindTexture;
   451     renderer->GL_UnbindTexture = GL_UnbindTexture;
   452     renderer->info = GL_RenderDriver.info;
   453     renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
   454     renderer->driverdata = data;
   455     renderer->window = window;
   456 
   457     data->context = SDL_GL_CreateContext(window);
   458     if (!data->context) {
   459         GL_DestroyRenderer(renderer);
   460         goto error;
   461     }
   462     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   463         GL_DestroyRenderer(renderer);
   464         goto error;
   465     }
   466 
   467     if (GL_LoadFunctions(data) < 0) {
   468         GL_DestroyRenderer(renderer);
   469         goto error;
   470     }
   471 
   472 #ifdef __MACOSX__
   473     /* Enable multi-threaded rendering */
   474     /* Disabled until Ryan finishes his VBO/PBO code...
   475        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
   476      */
   477 #endif
   478 
   479     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   480         SDL_GL_SetSwapInterval(1);
   481     } else {
   482         SDL_GL_SetSwapInterval(0);
   483     }
   484     if (SDL_GL_GetSwapInterval() > 0) {
   485         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   486     }
   487 
   488     /* Check for debug output support */
   489     if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
   490         (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
   491         data->debug_enabled = SDL_TRUE;
   492     }
   493     if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) {
   494         PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
   495 
   496         data->GL_ARB_debug_output_supported = SDL_TRUE;
   497         data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)&data->next_error_callback);
   498         data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam);
   499         glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer);
   500 
   501         /* Make sure our callback is called when errors actually happen */
   502         data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
   503     }
   504 
   505     if (SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) {
   506         data->GL_ARB_texture_non_power_of_two_supported = SDL_TRUE;
   507     } else if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
   508                SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
   509         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
   510     }
   511     if (data->GL_ARB_texture_rectangle_supported) {
   512         data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value);
   513         renderer->info.max_texture_width = value;
   514         renderer->info.max_texture_height = value;
   515     } else {
   516         data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   517         renderer->info.max_texture_width = value;
   518         renderer->info.max_texture_height = value;
   519     }
   520 
   521     /* Check for multitexture support */
   522     if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
   523         data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
   524         if (data->glActiveTextureARB) {
   525             data->GL_ARB_multitexture_supported = SDL_TRUE;
   526             data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
   527         }
   528     }
   529 
   530     /* Check for shader support */
   531     hint = SDL_GetHint(SDL_HINT_RENDER_OPENGL_SHADERS);
   532     if (!hint || *hint != '0') {
   533         data->shaders = GL_CreateShaderContext();
   534     }
   535     SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
   536                 data->shaders ? "ENABLED" : "DISABLED");
   537 
   538     /* We support YV12 textures using 3 textures and a shader */
   539     if (data->shaders && data->num_texture_units >= 3) {
   540         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   541         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   542         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
   543         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
   544     }
   545 
   546 #ifdef __MACOSX__
   547     renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
   548 #endif
   549 
   550     if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
   551         data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
   552         data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
   553             SDL_GL_GetProcAddress("glGenFramebuffersEXT");
   554         data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
   555             SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
   556         data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
   557             SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
   558         data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
   559             SDL_GL_GetProcAddress("glBindFramebufferEXT");
   560         data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
   561             SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
   562         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
   563     }
   564     data->framebuffers = NULL;
   565 
   566     /* Set up parameters for rendering */
   567     GL_ResetState(renderer);
   568 
   569     return renderer;
   570 
   571 error:
   572     if (changed_window) {
   573         /* Uh oh, better try to put it back... */
   574         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
   575         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
   576         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
   577         SDL_RecreateWindow(window, window_flags);
   578     }
   579     return NULL;
   580 }
   581 
   582 static void
   583 GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   584 {
   585     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
   586         event->event == SDL_WINDOWEVENT_SHOWN ||
   587         event->event == SDL_WINDOWEVENT_HIDDEN) {
   588         /* Rebind the context to the window area and update matrices */
   589         SDL_CurrentContext = NULL;
   590     }
   591 }
   592 
   593 static int
   594 GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
   595 {
   596     SDL_GL_GetDrawableSize(renderer->window, w, h);
   597 
   598     return 0;
   599 }
   600 
   601 SDL_FORCE_INLINE int
   602 power_of_2(int input)
   603 {
   604     int value = 1;
   605 
   606     while (value < input) {
   607         value <<= 1;
   608     }
   609     return value;
   610 }
   611 
   612 SDL_FORCE_INLINE SDL_bool
   613 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
   614                GLint* internalFormat, GLenum* format, GLenum* type)
   615 {
   616     switch (pixel_format) {
   617     case SDL_PIXELFORMAT_ARGB8888:
   618         *internalFormat = GL_RGBA8;
   619         *format = GL_BGRA;
   620         *type = GL_UNSIGNED_INT_8_8_8_8_REV;
   621         break;
   622     case SDL_PIXELFORMAT_YV12:
   623     case SDL_PIXELFORMAT_IYUV:
   624     case SDL_PIXELFORMAT_NV12:
   625     case SDL_PIXELFORMAT_NV21:
   626         *internalFormat = GL_LUMINANCE;
   627         *format = GL_LUMINANCE;
   628         *type = GL_UNSIGNED_BYTE;
   629         break;
   630 #ifdef __MACOSX__
   631     case SDL_PIXELFORMAT_UYVY:
   632         *internalFormat = GL_RGB8;
   633         *format = GL_YCBCR_422_APPLE;
   634         *type = GL_UNSIGNED_SHORT_8_8_APPLE;
   635         break;
   636 #endif
   637     default:
   638         return SDL_FALSE;
   639     }
   640     return SDL_TRUE;
   641 }
   642 
   643 static GLenum
   644 GetScaleQuality(void)
   645 {
   646     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   647 
   648     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   649         return GL_NEAREST;
   650     } else {
   651         return GL_LINEAR;
   652     }
   653 }
   654 
   655 static int
   656 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   657 {
   658     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   659     GL_TextureData *data;
   660     GLint internalFormat;
   661     GLenum format, type;
   662     int texture_w, texture_h;
   663     GLenum scaleMode;
   664 
   665     GL_ActivateRenderer(renderer);
   666 
   667     if (!convert_format(renderdata, texture->format, &internalFormat,
   668                         &format, &type)) {
   669         return SDL_SetError("Texture format %s not supported by OpenGL",
   670                             SDL_GetPixelFormatName(texture->format));
   671     }
   672 
   673     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   674     if (!data) {
   675         return SDL_OutOfMemory();
   676     }
   677 
   678     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   679         size_t size;
   680         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   681         size = texture->h * data->pitch;
   682         if (texture->format == SDL_PIXELFORMAT_YV12 ||
   683             texture->format == SDL_PIXELFORMAT_IYUV) {
   684             /* Need to add size for the U and V planes */
   685             size += (2 * (texture->h * data->pitch) / 4);
   686         }
   687         if (texture->format == SDL_PIXELFORMAT_NV12 ||
   688             texture->format == SDL_PIXELFORMAT_NV21) {
   689             /* Need to add size for the U/V plane */
   690             size += ((texture->h * data->pitch) / 2);
   691         }
   692         data->pixels = SDL_calloc(1, size);
   693         if (!data->pixels) {
   694             SDL_free(data);
   695             return SDL_OutOfMemory();
   696         }
   697     }
   698 
   699     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   700         data->fbo = GL_GetFBO(renderdata, texture->w, texture->h);
   701     } else {
   702         data->fbo = NULL;
   703     }
   704 
   705     GL_CheckError("", renderer);
   706     renderdata->glGenTextures(1, &data->texture);
   707     if (GL_CheckError("glGenTextures()", renderer) < 0) {
   708         if (data->pixels) {
   709             SDL_free(data->pixels);
   710         }
   711         SDL_free(data);
   712         return -1;
   713     }
   714     texture->driverdata = data;
   715 
   716     if (renderdata->GL_ARB_texture_non_power_of_two_supported) {
   717         data->type = GL_TEXTURE_2D;
   718         texture_w = texture->w;
   719         texture_h = texture->h;
   720         data->texw = 1.0f;
   721         data->texh = 1.0f;
   722     } else if (renderdata->GL_ARB_texture_rectangle_supported) {
   723         data->type = GL_TEXTURE_RECTANGLE_ARB;
   724         texture_w = texture->w;
   725         texture_h = texture->h;
   726         data->texw = (GLfloat) texture_w;
   727         data->texh = (GLfloat) texture_h;
   728     } else {
   729         data->type = GL_TEXTURE_2D;
   730         texture_w = power_of_2(texture->w);
   731         texture_h = power_of_2(texture->h);
   732         data->texw = (GLfloat) (texture->w) / texture_w;
   733         data->texh = (GLfloat) texture->h / texture_h;
   734     }
   735 
   736     data->format = format;
   737     data->formattype = type;
   738     scaleMode = GetScaleQuality();
   739     renderdata->glEnable(data->type);
   740     renderdata->glBindTexture(data->type, data->texture);
   741     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
   742     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
   743     /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE
   744        and setting it causes an INVALID_ENUM error in the latest NVidia drivers.
   745     */
   746     if (data->type != GL_TEXTURE_RECTANGLE_ARB) {
   747         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   748                                     GL_CLAMP_TO_EDGE);
   749         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   750                                     GL_CLAMP_TO_EDGE);
   751     }
   752 #ifdef __MACOSX__
   753 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
   754 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
   755 #endif
   756 #ifndef STORAGE_CACHED_APPLE
   757 #define STORAGE_CACHED_APPLE                0x85BE
   758 #endif
   759 #ifndef STORAGE_SHARED_APPLE
   760 #define STORAGE_SHARED_APPLE                0x85BF
   761 #endif
   762     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   763         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   764                                     GL_STORAGE_SHARED_APPLE);
   765     } else {
   766         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   767                                     GL_STORAGE_CACHED_APPLE);
   768     }
   769     if (texture->access == SDL_TEXTUREACCESS_STREAMING
   770         && texture->format == SDL_PIXELFORMAT_ARGB8888
   771         && (texture->w % 8) == 0) {
   772         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
   773         renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   774         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   775                           (data->pitch / SDL_BYTESPERPIXEL(texture->format)));
   776         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   777                                  texture_h, 0, format, type, data->pixels);
   778         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
   779     }
   780     else
   781 #endif
   782     {
   783         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   784                                  texture_h, 0, format, type, NULL);
   785     }
   786     renderdata->glDisable(data->type);
   787     if (GL_CheckError("glTexImage2D()", renderer) < 0) {
   788         return -1;
   789     }
   790 
   791     if (texture->format == SDL_PIXELFORMAT_YV12 ||
   792         texture->format == SDL_PIXELFORMAT_IYUV) {
   793         data->yuv = SDL_TRUE;
   794 
   795         renderdata->glGenTextures(1, &data->utexture);
   796         renderdata->glGenTextures(1, &data->vtexture);
   797         renderdata->glEnable(data->type);
   798 
   799         renderdata->glBindTexture(data->type, data->utexture);
   800         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   801                                     scaleMode);
   802         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   803                                     scaleMode);
   804         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   805                                     GL_CLAMP_TO_EDGE);
   806         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   807                                     GL_CLAMP_TO_EDGE);
   808         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
   809                                  texture_h/2, 0, format, type, NULL);
   810 
   811         renderdata->glBindTexture(data->type, data->vtexture);
   812         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   813                                     scaleMode);
   814         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   815                                     scaleMode);
   816         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   817                                     GL_CLAMP_TO_EDGE);
   818         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   819                                     GL_CLAMP_TO_EDGE);
   820         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
   821                                  texture_h/2, 0, format, type, NULL);
   822 
   823         renderdata->glDisable(data->type);
   824     }
   825 
   826     if (texture->format == SDL_PIXELFORMAT_NV12 ||
   827         texture->format == SDL_PIXELFORMAT_NV21) {
   828         data->nv12 = SDL_TRUE;
   829 
   830         renderdata->glGenTextures(1, &data->utexture);
   831         renderdata->glEnable(data->type);
   832 
   833         renderdata->glBindTexture(data->type, data->utexture);
   834         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   835                                     scaleMode);
   836         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   837                                     scaleMode);
   838         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   839                                     GL_CLAMP_TO_EDGE);
   840         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   841                                     GL_CLAMP_TO_EDGE);
   842         renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, texture_w/2,
   843                                  texture_h/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
   844         renderdata->glDisable(data->type);
   845     }
   846 
   847     return GL_CheckError("", renderer);
   848 }
   849 
   850 static int
   851 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   852                  const SDL_Rect * rect, const void *pixels, int pitch)
   853 {
   854     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   855     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   856     const int texturebpp = SDL_BYTESPERPIXEL(texture->format);
   857 
   858     SDL_assert(texturebpp != 0);  /* otherwise, division by zero later. */
   859 
   860     GL_ActivateRenderer(renderer);
   861 
   862     renderdata->glEnable(data->type);
   863     renderdata->glBindTexture(data->type, data->texture);
   864     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   865     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / texturebpp));
   866     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   867                                 rect->h, data->format, data->formattype,
   868                                 pixels);
   869     if (data->yuv) {
   870         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
   871 
   872         /* Skip to the correct offset into the next texture */
   873         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
   874         if (texture->format == SDL_PIXELFORMAT_YV12) {
   875             renderdata->glBindTexture(data->type, data->vtexture);
   876         } else {
   877             renderdata->glBindTexture(data->type, data->utexture);
   878         }
   879         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   880                                     rect->w/2, rect->h/2,
   881                                     data->format, data->formattype, pixels);
   882 
   883         /* Skip to the correct offset into the next texture */
   884         pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
   885         if (texture->format == SDL_PIXELFORMAT_YV12) {
   886             renderdata->glBindTexture(data->type, data->utexture);
   887         } else {
   888             renderdata->glBindTexture(data->type, data->vtexture);
   889         }
   890         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   891                                     rect->w/2, rect->h/2,
   892                                     data->format, data->formattype, pixels);
   893     }
   894 
   895     if (data->nv12) {
   896         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
   897 
   898         /* Skip to the correct offset into the next texture */
   899         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
   900         renderdata->glBindTexture(data->type, data->utexture);
   901         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   902                                     rect->w/2, rect->h/2,
   903                                     GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
   904     }
   905     renderdata->glDisable(data->type);
   906 
   907     return GL_CheckError("glTexSubImage2D()", renderer);
   908 }
   909 
   910 static int
   911 GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
   912                     const SDL_Rect * rect,
   913                     const Uint8 *Yplane, int Ypitch,
   914                     const Uint8 *Uplane, int Upitch,
   915                     const Uint8 *Vplane, int Vpitch)
   916 {
   917     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   918     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   919 
   920     GL_ActivateRenderer(renderer);
   921 
   922     renderdata->glEnable(data->type);
   923     renderdata->glBindTexture(data->type, data->texture);
   924     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   925     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch);
   926     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   927                                 rect->h, data->format, data->formattype,
   928                                 Yplane);
   929 
   930     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
   931     renderdata->glBindTexture(data->type, data->utexture);
   932     renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   933                                 rect->w/2, rect->h/2,
   934                                 data->format, data->formattype, Uplane);
   935 
   936     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
   937     renderdata->glBindTexture(data->type, data->vtexture);
   938     renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   939                                 rect->w/2, rect->h/2,
   940                                 data->format, data->formattype, Vplane);
   941     renderdata->glDisable(data->type);
   942 
   943     return GL_CheckError("glTexSubImage2D()", renderer);
   944 }
   945 
   946 static int
   947 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   948                const SDL_Rect * rect, void **pixels, int *pitch)
   949 {
   950     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   951 
   952     data->locked_rect = *rect;
   953     *pixels =
   954         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   955                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   956     *pitch = data->pitch;
   957     return 0;
   958 }
   959 
   960 static void
   961 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   962 {
   963     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   964     const SDL_Rect *rect;
   965     void *pixels;
   966 
   967     rect = &data->locked_rect;
   968     pixels =
   969         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   970                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   971     GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
   972 }
   973 
   974 static int
   975 GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   976 {
   977     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   978     GL_TextureData *texturedata;
   979     GLenum status;
   980 
   981     GL_ActivateRenderer(renderer);
   982 
   983     if (texture == NULL) {
   984         data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
   985         return 0;
   986     }
   987 
   988     texturedata = (GL_TextureData *) texture->driverdata;
   989     data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
   990     /* TODO: check if texture pixel format allows this operation */
   991     data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
   992     /* Check FBO status */
   993     status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
   994     if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
   995         return SDL_SetError("glFramebufferTexture2DEXT() failed");
   996     }
   997     return 0;
   998 }
   999 
  1000 static int
  1001 GL_UpdateViewport(SDL_Renderer * renderer)
  1002 {
  1003     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1004 
  1005     if (SDL_CurrentContext != data->context) {
  1006         /* We'll update the viewport after we rebind the context */
  1007         return 0;
  1008     }
  1009 
  1010     if (renderer->target) {
  1011         data->glViewport(renderer->viewport.x, renderer->viewport.y,
  1012                          renderer->viewport.w, renderer->viewport.h);
  1013     } else {
  1014         int w, h;
  1015 
  1016         SDL_GetRendererOutputSize(renderer, &w, &h);
  1017         data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h),
  1018                          renderer->viewport.w, renderer->viewport.h);
  1019     }
  1020 
  1021     data->glMatrixMode(GL_PROJECTION);
  1022     data->glLoadIdentity();
  1023     if (renderer->viewport.w && renderer->viewport.h) {
  1024         if (renderer->target) {
  1025             data->glOrtho((GLdouble) 0,
  1026                           (GLdouble) renderer->viewport.w,
  1027                           (GLdouble) 0,
  1028                           (GLdouble) renderer->viewport.h,
  1029                            0.0, 1.0);
  1030         } else {
  1031             data->glOrtho((GLdouble) 0,
  1032                           (GLdouble) renderer->viewport.w,
  1033                           (GLdouble) renderer->viewport.h,
  1034                           (GLdouble) 0,
  1035                            0.0, 1.0);
  1036         }
  1037     }
  1038     return GL_CheckError("", renderer);
  1039 }
  1040 
  1041 static int
  1042 GL_UpdateClipRect(SDL_Renderer * renderer)
  1043 {
  1044     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1045 
  1046     if (renderer->clipping_enabled) {
  1047         const SDL_Rect *rect = &renderer->clip_rect;
  1048         data->glEnable(GL_SCISSOR_TEST);
  1049         if (renderer->target) {
  1050             data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h);
  1051         } else {
  1052             int w, h;
  1053 
  1054             SDL_GetRendererOutputSize(renderer, &w, &h);
  1055             data->glScissor(renderer->viewport.x + rect->x, (h - renderer->viewport.y - renderer->viewport.h) + rect->y, rect->w, rect->h);
  1056         }
  1057     } else {
  1058         data->glDisable(GL_SCISSOR_TEST);
  1059     }
  1060     return 0;
  1061 }
  1062 
  1063 static void
  1064 GL_SetShader(GL_RenderData * data, GL_Shader shader)
  1065 {
  1066     if (data->shaders && shader != data->current.shader) {
  1067         GL_SelectShader(data->shaders, shader);
  1068         data->current.shader = shader;
  1069     }
  1070 }
  1071 
  1072 static void
  1073 GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  1074 {
  1075     Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
  1076 
  1077     if (color != data->current.color) {
  1078         data->glColor4f((GLfloat) r * inv255f,
  1079                         (GLfloat) g * inv255f,
  1080                         (GLfloat) b * inv255f,
  1081                         (GLfloat) a * inv255f);
  1082         data->current.color = color;
  1083     }
  1084 }
  1085 
  1086 static void
  1087 GL_SetBlendMode(GL_RenderData * data, int blendMode)
  1088 {
  1089     if (blendMode != data->current.blendMode) {
  1090         switch (blendMode) {
  1091         case SDL_BLENDMODE_NONE:
  1092             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  1093             data->glDisable(GL_BLEND);
  1094             break;
  1095         case SDL_BLENDMODE_BLEND:
  1096             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1097             data->glEnable(GL_BLEND);
  1098             data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  1099             break;
  1100         case SDL_BLENDMODE_ADD:
  1101             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1102             data->glEnable(GL_BLEND);
  1103             data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
  1104             break;
  1105         case SDL_BLENDMODE_MOD:
  1106             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1107             data->glEnable(GL_BLEND);
  1108             data->glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE);
  1109             break;
  1110         }
  1111         data->current.blendMode = blendMode;
  1112     }
  1113 }
  1114 
  1115 static void
  1116 GL_SetDrawingState(SDL_Renderer * renderer)
  1117 {
  1118     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1119 
  1120     GL_ActivateRenderer(renderer);
  1121 
  1122     GL_SetColor(data, renderer->r,
  1123                       renderer->g,
  1124                       renderer->b,
  1125                       renderer->a);
  1126 
  1127     GL_SetBlendMode(data, renderer->blendMode);
  1128 
  1129     GL_SetShader(data, SHADER_SOLID);
  1130 }
  1131 
  1132 static int
  1133 GL_RenderClear(SDL_Renderer * renderer)
  1134 {
  1135     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1136 
  1137     GL_ActivateRenderer(renderer);
  1138 
  1139     data->glClearColor((GLfloat) renderer->r * inv255f,
  1140                        (GLfloat) renderer->g * inv255f,
  1141                        (GLfloat) renderer->b * inv255f,
  1142                        (GLfloat) renderer->a * inv255f);
  1143 
  1144     data->glClear(GL_COLOR_BUFFER_BIT);
  1145 
  1146     return 0;
  1147 }
  1148 
  1149 static int
  1150 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
  1151                     int count)
  1152 {
  1153     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1154     int i;
  1155 
  1156     GL_SetDrawingState(renderer);
  1157 
  1158     data->glBegin(GL_POINTS);
  1159     for (i = 0; i < count; ++i) {
  1160         data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
  1161     }
  1162     data->glEnd();
  1163 
  1164     return 0;
  1165 }
  1166 
  1167 static int
  1168 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
  1169                    int count)
  1170 {
  1171     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1172     int i;
  1173 
  1174     GL_SetDrawingState(renderer);
  1175 
  1176     if (count > 2 &&
  1177         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
  1178         data->glBegin(GL_LINE_LOOP);
  1179         /* GL_LINE_LOOP takes care of the final segment */
  1180         --count;
  1181         for (i = 0; i < count; ++i) {
  1182             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
  1183         }
  1184         data->glEnd();
  1185     } else {
  1186 #if defined(__MACOSX__) || defined(__WIN32__)
  1187 #else
  1188         int x1, y1, x2, y2;
  1189 #endif
  1190 
  1191         data->glBegin(GL_LINE_STRIP);
  1192         for (i = 0; i < count; ++i) {
  1193             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
  1194         }
  1195         data->glEnd();
  1196 
  1197         /* The line is half open, so we need one more point to complete it.
  1198          * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
  1199          * If we have to, we can use vertical line and horizontal line textures
  1200          * for vertical and horizontal lines, and then create custom textures
  1201          * for diagonal lines and software render those.  It's terrible, but at
  1202          * least it would be pixel perfect.
  1203          */
  1204         data->glBegin(GL_POINTS);
  1205 #if defined(__MACOSX__) || defined(__WIN32__)
  1206         /* Mac OS X and Windows seem to always leave the last point open */
  1207         data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
  1208 #else
  1209         /* Linux seems to leave the right-most or bottom-most point open */
  1210         x1 = points[0].x;
  1211         y1 = points[0].y;
  1212         x2 = points[count-1].x;
  1213         y2 = points[count-1].y;
  1214 
  1215         if (x1 > x2) {
  1216             data->glVertex2f(0.5f + x1, 0.5f + y1);
  1217         } else if (x2 > x1) {
  1218             data->glVertex2f(0.5f + x2, 0.5f + y2);
  1219         }
  1220         if (y1 > y2) {
  1221             data->glVertex2f(0.5f + x1, 0.5f + y1);
  1222         } else if (y2 > y1) {
  1223             data->glVertex2f(0.5f + x2, 0.5f + y2);
  1224         }
  1225 #endif
  1226         data->glEnd();
  1227     }
  1228     return GL_CheckError("", renderer);
  1229 }
  1230 
  1231 static int
  1232 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
  1233 {
  1234     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1235     int i;
  1236 
  1237     GL_SetDrawingState(renderer);
  1238 
  1239     for (i = 0; i < count; ++i) {
  1240         const SDL_FRect *rect = &rects[i];
  1241 
  1242         data->glRectf(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
  1243     }
  1244     return GL_CheckError("", renderer);
  1245 }
  1246 
  1247 static int
  1248 GL_SetupCopy(SDL_Renderer * renderer, SDL_Texture * texture)
  1249 {
  1250     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1251     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1252 
  1253     data->glEnable(texturedata->type);
  1254     if (texturedata->yuv) {
  1255         data->glActiveTextureARB(GL_TEXTURE2_ARB);
  1256         data->glBindTexture(texturedata->type, texturedata->vtexture);
  1257 
  1258         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1259         data->glBindTexture(texturedata->type, texturedata->utexture);
  1260 
  1261         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1262     }
  1263     if (texturedata->nv12) {
  1264         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1265         data->glBindTexture(texturedata->type, texturedata->utexture);
  1266 
  1267         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1268     }
  1269     data->glBindTexture(texturedata->type, texturedata->texture);
  1270 
  1271     if (texture->modMode) {
  1272         GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
  1273     } else {
  1274         GL_SetColor(data, 255, 255, 255, 255);
  1275     }
  1276 
  1277     GL_SetBlendMode(data, texture->blendMode);
  1278 
  1279     if (texturedata->yuv) {
  1280         GL_SetShader(data, SHADER_YUV);
  1281     } else if (texturedata->nv12) {
  1282         if (texture->format == SDL_PIXELFORMAT_NV12) {
  1283             GL_SetShader(data, SHADER_NV12);
  1284         } else {
  1285             GL_SetShader(data, SHADER_NV21);
  1286         }
  1287     } else {
  1288         GL_SetShader(data, SHADER_RGB);
  1289     }
  1290     return 0;
  1291 }
  1292 
  1293 static int
  1294 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1295               const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  1296 {
  1297     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1298     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1299     GLfloat minx, miny, maxx, maxy;
  1300     GLfloat minu, maxu, minv, maxv;
  1301 
  1302     GL_ActivateRenderer(renderer);
  1303 
  1304     if (GL_SetupCopy(renderer, texture) < 0) {
  1305         return -1;
  1306     }
  1307 
  1308     minx = dstrect->x;
  1309     miny = dstrect->y;
  1310     maxx = dstrect->x + dstrect->w;
  1311     maxy = dstrect->y + dstrect->h;
  1312 
  1313     minu = (GLfloat) srcrect->x / texture->w;
  1314     minu *= texturedata->texw;
  1315     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
  1316     maxu *= texturedata->texw;
  1317     minv = (GLfloat) srcrect->y / texture->h;
  1318     minv *= texturedata->texh;
  1319     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
  1320     maxv *= texturedata->texh;
  1321 
  1322     data->glBegin(GL_TRIANGLE_STRIP);
  1323     data->glTexCoord2f(minu, minv);
  1324     data->glVertex2f(minx, miny);
  1325     data->glTexCoord2f(maxu, minv);
  1326     data->glVertex2f(maxx, miny);
  1327     data->glTexCoord2f(minu, maxv);
  1328     data->glVertex2f(minx, maxy);
  1329     data->glTexCoord2f(maxu, maxv);
  1330     data->glVertex2f(maxx, maxy);
  1331     data->glEnd();
  1332 
  1333     data->glDisable(texturedata->type);
  1334 
  1335     return GL_CheckError("", renderer);
  1336 }
  1337 
  1338 static int
  1339 GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1340               const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  1341               const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
  1342 {
  1343     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1344     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1345     GLfloat minx, miny, maxx, maxy;
  1346     GLfloat centerx, centery;
  1347     GLfloat minu, maxu, minv, maxv;
  1348 
  1349     GL_ActivateRenderer(renderer);
  1350 
  1351     if (GL_SetupCopy(renderer, texture) < 0) {
  1352         return -1;
  1353     }
  1354 
  1355     centerx = center->x;
  1356     centery = center->y;
  1357 
  1358     if (flip & SDL_FLIP_HORIZONTAL) {
  1359         minx =  dstrect->w - centerx;
  1360         maxx = -centerx;
  1361     }
  1362     else {
  1363         minx = -centerx;
  1364         maxx =  dstrect->w - centerx;
  1365     }
  1366 
  1367     if (flip & SDL_FLIP_VERTICAL) {
  1368         miny =  dstrect->h - centery;
  1369         maxy = -centery;
  1370     }
  1371     else {
  1372         miny = -centery;
  1373         maxy =  dstrect->h - centery;
  1374     }
  1375 
  1376     minu = (GLfloat) srcrect->x / texture->w;
  1377     minu *= texturedata->texw;
  1378     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
  1379     maxu *= texturedata->texw;
  1380     minv = (GLfloat) srcrect->y / texture->h;
  1381     minv *= texturedata->texh;
  1382     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
  1383     maxv *= texturedata->texh;
  1384 
  1385     /* Translate to flip, rotate, translate to position */
  1386     data->glPushMatrix();
  1387     data->glTranslatef((GLfloat)dstrect->x + centerx, (GLfloat)dstrect->y + centery, (GLfloat)0.0);
  1388     data->glRotated(angle, (GLdouble)0.0, (GLdouble)0.0, (GLdouble)1.0);
  1389 
  1390     data->glBegin(GL_TRIANGLE_STRIP);
  1391     data->glTexCoord2f(minu, minv);
  1392     data->glVertex2f(minx, miny);
  1393     data->glTexCoord2f(maxu, minv);
  1394     data->glVertex2f(maxx, miny);
  1395     data->glTexCoord2f(minu, maxv);
  1396     data->glVertex2f(minx, maxy);
  1397     data->glTexCoord2f(maxu, maxv);
  1398     data->glVertex2f(maxx, maxy);
  1399     data->glEnd();
  1400     data->glPopMatrix();
  1401 
  1402     data->glDisable(texturedata->type);
  1403 
  1404     return GL_CheckError("", renderer);
  1405 }
  1406 
  1407 static int
  1408 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1409                     Uint32 pixel_format, void * pixels, int pitch)
  1410 {
  1411     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1412     Uint32 temp_format = SDL_PIXELFORMAT_ARGB8888;
  1413     void *temp_pixels;
  1414     int temp_pitch;
  1415     GLint internalFormat;
  1416     GLenum format, type;
  1417     Uint8 *src, *dst, *tmp;
  1418     int w, h, length, rows;
  1419     int status;
  1420 
  1421     GL_ActivateRenderer(renderer);
  1422 
  1423     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1424     temp_pixels = SDL_malloc(rect->h * temp_pitch);
  1425     if (!temp_pixels) {
  1426         return SDL_OutOfMemory();
  1427     }
  1428 
  1429     convert_format(data, temp_format, &internalFormat, &format, &type);
  1430 
  1431     SDL_GetRendererOutputSize(renderer, &w, &h);
  1432 
  1433     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
  1434     data->glPixelStorei(GL_PACK_ROW_LENGTH,
  1435                         (temp_pitch / SDL_BYTESPERPIXEL(temp_format)));
  1436 
  1437     data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
  1438                        format, type, temp_pixels);
  1439 
  1440     if (GL_CheckError("glReadPixels()", renderer) < 0) {
  1441         SDL_free(temp_pixels);
  1442         return -1;
  1443     }
  1444 
  1445     /* Flip the rows to be top-down */
  1446     length = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1447     src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
  1448     dst = (Uint8*)temp_pixels;
  1449     tmp = SDL_stack_alloc(Uint8, length);
  1450     rows = rect->h / 2;
  1451     while (rows--) {
  1452         SDL_memcpy(tmp, dst, length);
  1453         SDL_memcpy(dst, src, length);
  1454         SDL_memcpy(src, tmp, length);
  1455         dst += temp_pitch;
  1456         src -= temp_pitch;
  1457     }
  1458     SDL_stack_free(tmp);
  1459 
  1460     status = SDL_ConvertPixels(rect->w, rect->h,
  1461                                temp_format, temp_pixels, temp_pitch,
  1462                                pixel_format, pixels, pitch);
  1463     SDL_free(temp_pixels);
  1464 
  1465     return status;
  1466 }
  1467 
  1468 static void
  1469 GL_RenderPresent(SDL_Renderer * renderer)
  1470 {
  1471     GL_ActivateRenderer(renderer);
  1472 
  1473     SDL_GL_SwapWindow(renderer->window);
  1474 }
  1475 
  1476 static void
  1477 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1478 {
  1479     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  1480     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1481 
  1482     GL_ActivateRenderer(renderer);
  1483 
  1484     if (!data) {
  1485         return;
  1486     }
  1487     if (data->texture) {
  1488         renderdata->glDeleteTextures(1, &data->texture);
  1489     }
  1490     if (data->yuv) {
  1491         renderdata->glDeleteTextures(1, &data->utexture);
  1492         renderdata->glDeleteTextures(1, &data->vtexture);
  1493     }
  1494     SDL_free(data->pixels);
  1495     SDL_free(data);
  1496     texture->driverdata = NULL;
  1497 }
  1498 
  1499 static void
  1500 GL_DestroyRenderer(SDL_Renderer * renderer)
  1501 {
  1502     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1503 
  1504     if (data) {
  1505         GL_ClearErrors(renderer);
  1506         if (data->GL_ARB_debug_output_supported) {
  1507             PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
  1508 
  1509             /* Uh oh, we don't have a safe way of removing ourselves from the callback chain, if it changed after we set our callback. */
  1510             /* For now, just always replace the callback with the original one */
  1511             glDebugMessageCallbackARBFunc(data->next_error_callback, data->next_error_userparam);
  1512         }
  1513         if (data->shaders) {
  1514             GL_DestroyShaderContext(data->shaders);
  1515         }
  1516         if (data->context) {
  1517             while (data->framebuffers) {
  1518                 GL_FBOList *nextnode = data->framebuffers->next;
  1519                 /* delete the framebuffer object */
  1520                 data->glDeleteFramebuffersEXT(1, &data->framebuffers->FBO);
  1521                 GL_CheckError("", renderer);
  1522                 SDL_free(data->framebuffers);
  1523                 data->framebuffers = nextnode;
  1524             }
  1525             SDL_GL_DeleteContext(data->context);
  1526         }
  1527         SDL_free(data);
  1528     }
  1529     SDL_free(renderer);
  1530 }
  1531 
  1532 static int
  1533 GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
  1534 {
  1535     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1536     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1537     GL_ActivateRenderer(renderer);
  1538 
  1539     data->glEnable(texturedata->type);
  1540     if (texturedata->yuv) {
  1541         data->glActiveTextureARB(GL_TEXTURE2_ARB);
  1542         data->glBindTexture(texturedata->type, texturedata->vtexture);
  1543 
  1544         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1545         data->glBindTexture(texturedata->type, texturedata->utexture);
  1546 
  1547         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1548     }
  1549     data->glBindTexture(texturedata->type, texturedata->texture);
  1550 
  1551     if(texw) *texw = (float)texturedata->texw;
  1552     if(texh) *texh = (float)texturedata->texh;
  1553 
  1554     return 0;
  1555 }
  1556 
  1557 static int
  1558 GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
  1559 {
  1560     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1561     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1562     GL_ActivateRenderer(renderer);
  1563 
  1564     if (texturedata->yuv) {
  1565         data->glActiveTextureARB(GL_TEXTURE2_ARB);
  1566         data->glDisable(texturedata->type);
  1567 
  1568         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1569         data->glDisable(texturedata->type);
  1570 
  1571         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1572     }
  1573 
  1574     data->glDisable(texturedata->type);
  1575 
  1576     return 0;
  1577 }
  1578 
  1579 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
  1580 
  1581 /* vi: set ts=4 sw=4 expandtab: */