sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_render_gl.c (62826B)


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