src/render/opengl/SDL_render_gl.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 22 Mar 2020 14:32:47 -0400
changeset 13664 1c73cc1e4a3a
parent 13536 4ba421b1e88f
child 13696 ea20a7434b98
permissions -rw-r--r--
opengl: Don't enable/disable texturing except when actually rendering.

Otherwise our cached state goes out of sync when updating a texture. Since
these state changes aren't necessary, they were removed instead of updating
the cached state.

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