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