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