src/render/opengl/SDL_render_gl.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 04 Feb 2019 18:55:39 -0500
changeset 12592 10722106b650
parent 12503 806492103856
child 12621 6a60a1e87d10
permissions -rw-r--r--
render: Fix OpenGL draw state cache for various points of texture binding.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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 {
   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 #define SDL_PROC(ret,func,params) \
   238     do { \
   239         data->func = SDL_GL_GetProcAddress(#func); \
   240         if ( ! data->func ) { \
   241             return 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 0;
   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         *internalFormat = GL_RGBA8;
   409         *format = GL_BGRA;
   410         *type = GL_UNSIGNED_INT_8_8_8_8_REV;
   411         break;
   412     case SDL_PIXELFORMAT_YV12:
   413     case SDL_PIXELFORMAT_IYUV:
   414     case SDL_PIXELFORMAT_NV12:
   415     case SDL_PIXELFORMAT_NV21:
   416         *internalFormat = GL_LUMINANCE;
   417         *format = GL_LUMINANCE;
   418         *type = GL_UNSIGNED_BYTE;
   419         break;
   420 #ifdef __MACOSX__
   421     case SDL_PIXELFORMAT_UYVY:
   422         *internalFormat = GL_RGB8;
   423         *format = GL_YCBCR_422_APPLE;
   424         *type = GL_UNSIGNED_SHORT_8_8_APPLE;
   425         break;
   426 #endif
   427     default:
   428         return SDL_FALSE;
   429     }
   430     return SDL_TRUE;
   431 }
   432 
   433 static int
   434 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   435 {
   436     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   437     const GLenum textype = renderdata->textype;
   438     GL_TextureData *data;
   439     GLint internalFormat;
   440     GLenum format, type;
   441     int texture_w, texture_h;
   442     GLenum scaleMode;
   443 
   444     GL_ActivateRenderer(renderer);
   445 
   446     renderdata->drawstate.texture = NULL;  /* we trash this state. */
   447 
   448     if (texture->access == SDL_TEXTUREACCESS_TARGET &&
   449         !renderdata->GL_EXT_framebuffer_object_supported) {
   450         return SDL_SetError("Render targets not supported by OpenGL");
   451     }
   452 
   453     if (!convert_format(renderdata, texture->format, &internalFormat,
   454                         &format, &type)) {
   455         return SDL_SetError("Texture format %s not supported by OpenGL",
   456                             SDL_GetPixelFormatName(texture->format));
   457     }
   458 
   459     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   460     if (!data) {
   461         return SDL_OutOfMemory();
   462     }
   463 
   464     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   465         size_t size;
   466         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   467         size = texture->h * data->pitch;
   468         if (texture->format == SDL_PIXELFORMAT_YV12 ||
   469             texture->format == SDL_PIXELFORMAT_IYUV) {
   470             /* Need to add size for the U and V planes */
   471             size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
   472         }
   473         if (texture->format == SDL_PIXELFORMAT_NV12 ||
   474             texture->format == SDL_PIXELFORMAT_NV21) {
   475             /* Need to add size for the U/V plane */
   476             size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
   477         }
   478         data->pixels = SDL_calloc(1, size);
   479         if (!data->pixels) {
   480             SDL_free(data);
   481             return SDL_OutOfMemory();
   482         }
   483     }
   484 
   485     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   486         data->fbo = GL_GetFBO(renderdata, texture->w, texture->h);
   487     } else {
   488         data->fbo = NULL;
   489     }
   490 
   491     GL_CheckError("", renderer);
   492     renderdata->glGenTextures(1, &data->texture);
   493     if (GL_CheckError("glGenTextures()", renderer) < 0) {
   494         if (data->pixels) {
   495             SDL_free(data->pixels);
   496         }
   497         SDL_free(data);
   498         return -1;
   499     }
   500     texture->driverdata = data;
   501 
   502     if (renderdata->GL_ARB_texture_non_power_of_two_supported) {
   503         texture_w = texture->w;
   504         texture_h = texture->h;
   505         data->texw = 1.0f;
   506         data->texh = 1.0f;
   507     } else if (renderdata->GL_ARB_texture_rectangle_supported) {
   508         texture_w = texture->w;
   509         texture_h = texture->h;
   510         data->texw = (GLfloat) texture_w;
   511         data->texh = (GLfloat) texture_h;
   512     } else {
   513         texture_w = power_of_2(texture->w);
   514         texture_h = power_of_2(texture->h);
   515         data->texw = (GLfloat) (texture->w) / texture_w;
   516         data->texh = (GLfloat) texture->h / texture_h;
   517     }
   518 
   519     data->format = format;
   520     data->formattype = type;
   521     scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
   522     renderdata->glEnable(textype);
   523     renderdata->glBindTexture(textype, data->texture);
   524     renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, scaleMode);
   525     renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, scaleMode);
   526     /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE
   527        and setting it causes an INVALID_ENUM error in the latest NVidia drivers.
   528     */
   529     if (textype != GL_TEXTURE_RECTANGLE_ARB) {
   530         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
   531                                     GL_CLAMP_TO_EDGE);
   532         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
   533                                     GL_CLAMP_TO_EDGE);
   534     }
   535 #ifdef __MACOSX__
   536 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
   537 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
   538 #endif
   539 #ifndef STORAGE_CACHED_APPLE
   540 #define STORAGE_CACHED_APPLE                0x85BE
   541 #endif
   542 #ifndef STORAGE_SHARED_APPLE
   543 #define STORAGE_SHARED_APPLE                0x85BF
   544 #endif
   545     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   546         renderdata->glTexParameteri(textype, GL_TEXTURE_STORAGE_HINT_APPLE,
   547                                     GL_STORAGE_SHARED_APPLE);
   548     } else {
   549         renderdata->glTexParameteri(textype, GL_TEXTURE_STORAGE_HINT_APPLE,
   550                                     GL_STORAGE_CACHED_APPLE);
   551     }
   552     if (texture->access == SDL_TEXTUREACCESS_STREAMING
   553         && texture->format == SDL_PIXELFORMAT_ARGB8888
   554         && (texture->w % 8) == 0) {
   555         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
   556         renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   557         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   558                           (data->pitch / SDL_BYTESPERPIXEL(texture->format)));
   559         renderdata->glTexImage2D(textype, 0, internalFormat, texture_w,
   560                                  texture_h, 0, format, type, data->pixels);
   561         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
   562     }
   563     else
   564 #endif
   565     {
   566         renderdata->glTexImage2D(textype, 0, internalFormat, texture_w,
   567                                  texture_h, 0, format, type, NULL);
   568     }
   569     renderdata->glDisable(textype);
   570     if (GL_CheckError("glTexImage2D()", renderer) < 0) {
   571         return -1;
   572     }
   573 
   574     if (texture->format == SDL_PIXELFORMAT_YV12 ||
   575         texture->format == SDL_PIXELFORMAT_IYUV) {
   576         data->yuv = SDL_TRUE;
   577 
   578         renderdata->glGenTextures(1, &data->utexture);
   579         renderdata->glGenTextures(1, &data->vtexture);
   580         renderdata->glEnable(textype);
   581 
   582         renderdata->glBindTexture(textype, data->utexture);
   583         renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
   584                                     scaleMode);
   585         renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
   586                                     scaleMode);
   587         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
   588                                     GL_CLAMP_TO_EDGE);
   589         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
   590                                     GL_CLAMP_TO_EDGE);
   591         renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w+1)/2,
   592                                  (texture_h+1)/2, 0, format, type, NULL);
   593 
   594         renderdata->glBindTexture(textype, data->vtexture);
   595         renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
   596                                     scaleMode);
   597         renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
   598                                     scaleMode);
   599         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
   600                                     GL_CLAMP_TO_EDGE);
   601         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
   602                                     GL_CLAMP_TO_EDGE);
   603         renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w+1)/2,
   604                                  (texture_h+1)/2, 0, format, type, NULL);
   605 
   606         renderdata->glDisable(textype);
   607     }
   608 
   609     if (texture->format == SDL_PIXELFORMAT_NV12 ||
   610         texture->format == SDL_PIXELFORMAT_NV21) {
   611         data->nv12 = SDL_TRUE;
   612 
   613         renderdata->glGenTextures(1, &data->utexture);
   614         renderdata->glEnable(textype);
   615 
   616         renderdata->glBindTexture(textype, data->utexture);
   617         renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
   618                                     scaleMode);
   619         renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
   620                                     scaleMode);
   621         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
   622                                     GL_CLAMP_TO_EDGE);
   623         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
   624                                     GL_CLAMP_TO_EDGE);
   625         renderdata->glTexImage2D(textype, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2,
   626                                  (texture_h+1)/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
   627         renderdata->glDisable(textype);
   628     }
   629 
   630     return GL_CheckError("", renderer);
   631 }
   632 
   633 static int
   634 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   635                  const SDL_Rect * rect, const void *pixels, int pitch)
   636 {
   637     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   638     const GLenum textype = renderdata->textype;
   639     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   640     const int texturebpp = SDL_BYTESPERPIXEL(texture->format);
   641 
   642     SDL_assert(texturebpp != 0);  /* otherwise, division by zero later. */
   643 
   644     GL_ActivateRenderer(renderer);
   645 
   646     renderdata->drawstate.texture = NULL;  /* we trash this state. */
   647 
   648     renderdata->glEnable(textype);
   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     renderdata->glDisable(textype);
   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->glEnable(textype);
   712     renderdata->glBindTexture(textype, data->texture);
   713     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   714     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch);
   715     renderdata->glTexSubImage2D(textype, 0, rect->x, rect->y, rect->w,
   716                                 rect->h, data->format, data->formattype,
   717                                 Yplane);
   718 
   719     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
   720     renderdata->glBindTexture(textype, data->utexture);
   721     renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
   722                                 (rect->w + 1)/2, (rect->h + 1)/2,
   723                                 data->format, data->formattype, Uplane);
   724 
   725     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
   726     renderdata->glBindTexture(textype, data->vtexture);
   727     renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
   728                                 (rect->w + 1)/2, (rect->h + 1)/2,
   729                                 data->format, data->formattype, Vplane);
   730     renderdata->glDisable(textype);
   731 
   732     return GL_CheckError("glTexSubImage2D()", renderer);
   733 }
   734 
   735 static int
   736 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   737                const SDL_Rect * rect, void **pixels, int *pitch)
   738 {
   739     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   740 
   741     data->locked_rect = *rect;
   742     *pixels =
   743         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   744                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   745     *pitch = data->pitch;
   746     return 0;
   747 }
   748 
   749 static void
   750 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   751 {
   752     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   753     const SDL_Rect *rect;
   754     void *pixels;
   755 
   756     rect = &data->locked_rect;
   757     pixels =
   758         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   759                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   760     GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
   761 }
   762 
   763 static int
   764 GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   765 {
   766     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   767     GL_TextureData *texturedata;
   768     GLenum status;
   769 
   770     GL_ActivateRenderer(renderer);
   771 
   772     if (!data->GL_EXT_framebuffer_object_supported) {
   773         return SDL_SetError("Render targets not supported by OpenGL");
   774     }
   775 
   776     if (texture == NULL) {
   777         data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
   778         return 0;
   779     }
   780 
   781     texturedata = (GL_TextureData *) texture->driverdata;
   782     data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
   783     /* TODO: check if texture pixel format allows this operation */
   784     data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, data->textype, texturedata->texture, 0);
   785     /* Check FBO status */
   786     status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
   787     if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
   788         return SDL_SetError("glFramebufferTexture2DEXT() failed");
   789     }
   790     return 0;
   791 }
   792 
   793 /* !!! FIXME: all these Queue* calls set up the vertex buffer the way the immediate mode
   794    !!! FIXME:  renderer wants it, but this might want to operate differently if we move to
   795    !!! FIXME:  VBOs at some point. */
   796 static int
   797 GL_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
   798 {
   799     return 0;  /* nothing to do in this backend. */
   800 }
   801 
   802 static int
   803 GL_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
   804 {
   805     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   806     size_t i;
   807 
   808     if (!verts) {
   809         return -1;
   810     }
   811 
   812     cmd->data.draw.count = count;
   813     for (i = 0; i < count; i++) {
   814         *(verts++) = 0.5f + points[i].x;
   815         *(verts++) = 0.5f + points[i].y;
   816     }
   817 
   818     return 0;
   819 }
   820 
   821 static int
   822 GL_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
   823 {
   824     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 4 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   825     size_t i;
   826 
   827     if (!verts) {
   828         return -1;
   829     }
   830 
   831     cmd->data.draw.count = count;
   832     for (i = 0; i < count; i++) {
   833         const SDL_FRect *rect = &rects[i];
   834         *(verts++) = rect->x;
   835         *(verts++) = rect->y;
   836         *(verts++) = rect->x + rect->w;
   837         *(verts++) = rect->y + rect->h;
   838     }
   839 
   840     return 0;
   841 }
   842 
   843 static int
   844 GL_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
   845              const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   846 {
   847     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
   848     GLfloat minx, miny, maxx, maxy;
   849     GLfloat minu, maxu, minv, maxv;
   850     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 8 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   851 
   852     if (!verts) {
   853         return -1;
   854     }
   855 
   856     cmd->data.draw.count = 1;
   857 
   858     minx = dstrect->x;
   859     miny = dstrect->y;
   860     maxx = dstrect->x + dstrect->w;
   861     maxy = dstrect->y + dstrect->h;
   862 
   863     minu = (GLfloat) srcrect->x / texture->w;
   864     minu *= texturedata->texw;
   865     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   866     maxu *= texturedata->texw;
   867     minv = (GLfloat) srcrect->y / texture->h;
   868     minv *= texturedata->texh;
   869     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   870     maxv *= texturedata->texh;
   871 
   872     cmd->data.draw.count = 1;
   873     *(verts++) = minx;
   874     *(verts++) = miny;
   875     *(verts++) = maxx;
   876     *(verts++) = maxy;
   877     *(verts++) = minu;
   878     *(verts++) = maxu;
   879     *(verts++) = minv;
   880     *(verts++) = maxv;
   881     return 0;
   882 }
   883 
   884 static int
   885 GL_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
   886                const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   887                const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
   888 {
   889     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
   890     GLfloat minx, miny, maxx, maxy;
   891     GLfloat centerx, centery;
   892     GLfloat minu, maxu, minv, maxv;
   893     GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 11 * sizeof (GLfloat), 0, &cmd->data.draw.first);
   894 
   895     if (!verts) {
   896         return -1;
   897     }
   898 
   899     centerx = center->x;
   900     centery = center->y;
   901 
   902     if (flip & SDL_FLIP_HORIZONTAL) {
   903         minx =  dstrect->w - centerx;
   904         maxx = -centerx;
   905     }
   906     else {
   907         minx = -centerx;
   908         maxx =  dstrect->w - centerx;
   909     }
   910 
   911     if (flip & SDL_FLIP_VERTICAL) {
   912         miny =  dstrect->h - centery;
   913         maxy = -centery;
   914     }
   915     else {
   916         miny = -centery;
   917         maxy =  dstrect->h - centery;
   918     }
   919 
   920     minu = (GLfloat) srcrect->x / texture->w;
   921     minu *= texturedata->texw;
   922     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   923     maxu *= texturedata->texw;
   924     minv = (GLfloat) srcrect->y / texture->h;
   925     minv *= texturedata->texh;
   926     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   927     maxv *= texturedata->texh;
   928 
   929     cmd->data.draw.count = 1;
   930     *(verts++) = minx;
   931     *(verts++) = miny;
   932     *(verts++) = maxx;
   933     *(verts++) = maxy;
   934     *(verts++) = minu;
   935     *(verts++) = maxu;
   936     *(verts++) = minv;
   937     *(verts++) = maxv;
   938     *(verts++) = (GLfloat) dstrect->x + centerx;
   939     *(verts++) = (GLfloat) dstrect->y + centery;
   940     *(verts++) = (GLfloat) angle;
   941     return 0;
   942 }
   943 
   944 static void
   945 SetDrawState(GL_RenderData *data, const SDL_RenderCommand *cmd, const GL_Shader shader)
   946 {
   947     const SDL_BlendMode blend = cmd->data.draw.blend;
   948 
   949     if (data->drawstate.viewport_dirty) {
   950         const SDL_bool istarget = data->drawstate.target != NULL;
   951         const SDL_Rect *viewport = &data->drawstate.viewport;
   952         data->glMatrixMode(GL_PROJECTION);
   953         data->glLoadIdentity();
   954         data->glViewport(viewport->x,
   955                          istarget ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
   956                          viewport->w, viewport->h);
   957         if (viewport->w && viewport->h) {
   958             data->glOrtho((GLdouble) 0, (GLdouble) viewport->w,
   959                           (GLdouble) istarget ? 0 : viewport->h,
   960                           (GLdouble) istarget ? viewport->h : 0,
   961                           0.0, 1.0);
   962         }
   963         data->glMatrixMode(GL_MODELVIEW);
   964         data->drawstate.viewport_dirty = SDL_FALSE;
   965     }
   966 
   967     if (data->drawstate.cliprect_enabled_dirty) {
   968         if (!data->drawstate.cliprect_enabled) {
   969             data->glDisable(GL_SCISSOR_TEST);
   970         } else {
   971             data->glEnable(GL_SCISSOR_TEST);
   972         }
   973         data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
   974     }
   975 
   976     if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
   977         const SDL_Rect *viewport = &data->drawstate.viewport;
   978         const SDL_Rect *rect = &data->drawstate.cliprect;
   979         data->glScissor(viewport->x + rect->x,
   980                         data->drawstate.target ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
   981                         rect->w, rect->h);
   982         data->drawstate.cliprect_dirty = SDL_FALSE;
   983     }
   984 
   985     if (blend != data->drawstate.blend) {
   986         if (blend == SDL_BLENDMODE_NONE) {
   987             data->glDisable(GL_BLEND);
   988         } else {
   989             data->glEnable(GL_BLEND);
   990             data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
   991                                       GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
   992                                       GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
   993                                       GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
   994             data->glBlendEquation(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)));
   995         }
   996         data->drawstate.blend = blend;
   997     }
   998 
   999     if (data->shaders && (shader != data->drawstate.shader)) {
  1000         GL_SelectShader(data->shaders, shader);
  1001         data->drawstate.shader = shader;
  1002     }
  1003 
  1004     if ((cmd->data.draw.texture != NULL) != data->drawstate.texturing) {
  1005         if (cmd->data.draw.texture == NULL) {
  1006             data->glDisable(data->textype);
  1007             data->drawstate.texturing = SDL_FALSE;
  1008         } else {
  1009             data->glEnable(data->textype);
  1010             data->drawstate.texturing = SDL_TRUE;
  1011         }
  1012     }
  1013 }
  1014 
  1015 static void
  1016 SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd)
  1017 {
  1018     SDL_Texture *texture = cmd->data.draw.texture;
  1019     const GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1020     GL_Shader shader = SHADER_RGB;
  1021 
  1022     if (data->shaders) {
  1023         if (texturedata->yuv || texturedata->nv12) {
  1024             switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
  1025                 case SDL_YUV_CONVERSION_JPEG:
  1026                     if (texturedata->yuv) {
  1027                         shader = SHADER_YUV_JPEG;
  1028                     } else if (texture->format == SDL_PIXELFORMAT_NV12) {
  1029                         shader = SHADER_NV12_JPEG;
  1030                     } else {
  1031                         shader = SHADER_NV21_JPEG;
  1032                     }
  1033                     break;
  1034                 case SDL_YUV_CONVERSION_BT601:
  1035                     if (texturedata->yuv) {
  1036                         shader = SHADER_YUV_BT601;
  1037                     } else if (texture->format == SDL_PIXELFORMAT_NV12) {
  1038                         shader = SHADER_NV12_BT601;
  1039                     } else {
  1040                         shader = SHADER_NV21_BT601;
  1041                     }
  1042                     break;
  1043                 case SDL_YUV_CONVERSION_BT709:
  1044                     if (texturedata->yuv) {
  1045                         shader = SHADER_YUV_BT709;
  1046                     } else if (texture->format == SDL_PIXELFORMAT_NV12) {
  1047                         shader = SHADER_NV12_BT709;
  1048                     } else {
  1049                         shader = SHADER_NV21_BT709;
  1050                     }
  1051                     break;
  1052                 default:
  1053                     SDL_assert(!"unsupported YUV conversion mode");
  1054                     break;
  1055             }
  1056         }
  1057     }
  1058 
  1059     SetDrawState(data, cmd, shader);
  1060 
  1061     if (texture != data->drawstate.texture) {
  1062         const GLenum textype = data->textype;
  1063         if (texturedata->yuv) {
  1064             data->glActiveTextureARB(GL_TEXTURE2_ARB);
  1065             data->glBindTexture(textype, texturedata->vtexture);
  1066 
  1067             data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1068             data->glBindTexture(textype, texturedata->utexture);
  1069         }
  1070         if (texturedata->nv12) {
  1071             data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1072             data->glBindTexture(textype, texturedata->utexture);
  1073         }
  1074         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1075         data->glBindTexture(textype, texturedata->texture);
  1076 
  1077         data->drawstate.texture = texture;
  1078     }
  1079 }
  1080 
  1081 static int
  1082 GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
  1083 {
  1084     /* !!! FIXME: it'd be nice to use a vertex buffer instead of immediate mode... */
  1085     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1086     size_t i;
  1087 
  1088     if (GL_ActivateRenderer(renderer) < 0) {
  1089         return -1;
  1090     }
  1091 
  1092     data->drawstate.target = renderer->target;
  1093     if (!data->drawstate.target) {
  1094         SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh);
  1095     }
  1096 
  1097 
  1098     while (cmd) {
  1099         switch (cmd->command) {
  1100             case SDL_RENDERCMD_SETDRAWCOLOR: {
  1101                 const Uint8 r = cmd->data.color.r;
  1102                 const Uint8 g = cmd->data.color.g;
  1103                 const Uint8 b = cmd->data.color.b;
  1104                 const Uint8 a = cmd->data.color.a;
  1105                 const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
  1106                 if (color != data->drawstate.color) {
  1107                     data->glColor4f((GLfloat) r * inv255f,
  1108                                     (GLfloat) g * inv255f,
  1109                                     (GLfloat) b * inv255f,
  1110                                     (GLfloat) a * inv255f);
  1111                     data->drawstate.color = color;
  1112                 }
  1113                 break;
  1114             }
  1115 
  1116             case SDL_RENDERCMD_SETVIEWPORT: {
  1117                 SDL_Rect *viewport = &data->drawstate.viewport;
  1118                 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
  1119                     SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
  1120                     data->drawstate.viewport_dirty = SDL_TRUE;
  1121                 }
  1122                 break;
  1123             }
  1124 
  1125             case SDL_RENDERCMD_SETCLIPRECT: {
  1126                 const SDL_Rect *rect = &cmd->data.cliprect.rect;
  1127                 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
  1128                     data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
  1129                     data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
  1130                 }
  1131                 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
  1132                     SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
  1133                     data->drawstate.cliprect_dirty = SDL_TRUE;
  1134                 }
  1135                 break;
  1136             }
  1137 
  1138             case SDL_RENDERCMD_CLEAR: {
  1139                 const Uint8 r = cmd->data.color.r;
  1140                 const Uint8 g = cmd->data.color.g;
  1141                 const Uint8 b = cmd->data.color.b;
  1142                 const Uint8 a = cmd->data.color.a;
  1143                 const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
  1144                 if (color != data->drawstate.clear_color) {
  1145                     const GLfloat fr = ((GLfloat) r) * inv255f;
  1146                     const GLfloat fg = ((GLfloat) g) * inv255f;
  1147                     const GLfloat fb = ((GLfloat) b) * inv255f;
  1148                     const GLfloat fa = ((GLfloat) a) * inv255f;
  1149                     data->glClearColor(fr, fg, fb, fa);
  1150                     data->drawstate.clear_color = color;
  1151                 }
  1152 
  1153                 if (data->drawstate.cliprect_enabled) {
  1154                     data->glDisable(GL_SCISSOR_TEST);
  1155                     data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
  1156                 }
  1157 
  1158                 data->glClear(GL_COLOR_BUFFER_BIT);
  1159 
  1160                 break;
  1161             }
  1162 
  1163             case SDL_RENDERCMD_DRAW_POINTS: {
  1164                 const size_t count = cmd->data.draw.count;
  1165                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
  1166                 SetDrawState(data, cmd, SHADER_SOLID);
  1167                 data->glBegin(GL_POINTS);
  1168                 for (i = 0; i < count; i++, verts += 2) {
  1169                     data->glVertex2f(verts[0], verts[1]);
  1170                 }
  1171                 data->glEnd();
  1172                 break;
  1173             }
  1174 
  1175             case SDL_RENDERCMD_DRAW_LINES: {
  1176                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
  1177                 const size_t count = cmd->data.draw.count;
  1178                 SetDrawState(data, cmd, SHADER_SOLID);
  1179                 if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
  1180                     data->glBegin(GL_LINE_LOOP);
  1181                     /* GL_LINE_LOOP takes care of the final segment */
  1182                     for (i = 1; i < count; ++i, verts += 2) {
  1183                         data->glVertex2f(verts[0], verts[1]);
  1184                     }
  1185                     data->glEnd();
  1186                 } else {
  1187                     #if defined(__MACOSX__) || defined(__WIN32__)
  1188                     #else
  1189                     int x1, y1, x2, y2;
  1190                     #endif
  1191 
  1192                     data->glBegin(GL_LINE_STRIP);
  1193                     for (i = 0; i < count; ++i, verts += 2) {
  1194                         data->glVertex2f(verts[0], verts[1]);
  1195                     }
  1196                     data->glEnd();
  1197 
  1198                     /* The line is half open, so we need one more point to complete it.
  1199                      * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
  1200                      * If we have to, we can use vertical line and horizontal line textures
  1201                      * for vertical and horizontal lines, and then create custom textures
  1202                      * for diagonal lines and software render those.  It's terrible, but at
  1203                      * least it would be pixel perfect.
  1204                      */
  1205 
  1206                     data->glBegin(GL_POINTS);
  1207                     #if defined(__MACOSX__) || defined(__WIN32__)
  1208                     /* Mac OS X and Windows seem to always leave the last point open */
  1209                     data->glVertex2f(verts[(count-1)*2], verts[(count*2)-1]);
  1210                     #else
  1211                     /* Linux seems to leave the right-most or bottom-most point open */
  1212                     x1 = verts[0];
  1213                     y1 = verts[1];
  1214                     x2 = verts[(count-1)*2];
  1215                     y2 = verts[(count*2)-1];
  1216 
  1217                     if (x1 > x2) {
  1218                         data->glVertex2f(x1, y1);
  1219                     } else if (x2 > x1) {
  1220                         data->glVertex2f(x2, y2);
  1221                     }
  1222                     if (y1 > y2) {
  1223                         data->glVertex2f(x1, y1);
  1224                     } else if (y2 > y1) {
  1225                         data->glVertex2f(x2, y2);
  1226                     }
  1227                     #endif
  1228                     data->glEnd();
  1229                 }
  1230                 break;
  1231             }
  1232 
  1233             case SDL_RENDERCMD_FILL_RECTS: {
  1234                 const size_t count = cmd->data.draw.count;
  1235                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
  1236                 SetDrawState(data, cmd, SHADER_SOLID);
  1237                 for (i = 0; i < count; ++i, verts += 4) {
  1238                     data->glRectf(verts[0], verts[1], verts[2], verts[3]);
  1239                 }
  1240                 break;
  1241             }
  1242 
  1243             case SDL_RENDERCMD_COPY: {
  1244                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
  1245                 const GLfloat minx = verts[0];
  1246                 const GLfloat miny = verts[1];
  1247                 const GLfloat maxx = verts[2];
  1248                 const GLfloat maxy = verts[3];
  1249                 const GLfloat minu = verts[4];
  1250                 const GLfloat maxu = verts[5];
  1251                 const GLfloat minv = verts[6];
  1252                 const GLfloat maxv = verts[7];
  1253                 SetCopyState(data, cmd);
  1254                 data->glBegin(GL_TRIANGLE_STRIP);
  1255                 data->glTexCoord2f(minu, minv);
  1256                 data->glVertex2f(minx, miny);
  1257                 data->glTexCoord2f(maxu, minv);
  1258                 data->glVertex2f(maxx, miny);
  1259                 data->glTexCoord2f(minu, maxv);
  1260                 data->glVertex2f(minx, maxy);
  1261                 data->glTexCoord2f(maxu, maxv);
  1262                 data->glVertex2f(maxx, maxy);
  1263                 data->glEnd();
  1264                 break;
  1265             }
  1266 
  1267             case SDL_RENDERCMD_COPY_EX: {
  1268                 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
  1269                 const GLfloat minx = verts[0];
  1270                 const GLfloat miny = verts[1];
  1271                 const GLfloat maxx = verts[2];
  1272                 const GLfloat maxy = verts[3];
  1273                 const GLfloat minu = verts[4];
  1274                 const GLfloat maxu = verts[5];
  1275                 const GLfloat minv = verts[6];
  1276                 const GLfloat maxv = verts[7];
  1277                 const GLfloat translatex = verts[8];
  1278                 const GLfloat translatey = verts[9];
  1279                 const GLdouble angle = verts[10];
  1280                 SetCopyState(data, cmd);
  1281 
  1282                 /* Translate to flip, rotate, translate to position */
  1283                 data->glPushMatrix();
  1284                 data->glTranslatef(translatex, translatey, 0.0f);
  1285                 data->glRotated(angle, 0.0, 0.0, 1.0);
  1286                 data->glBegin(GL_TRIANGLE_STRIP);
  1287                 data->glTexCoord2f(minu, minv);
  1288                 data->glVertex2f(minx, miny);
  1289                 data->glTexCoord2f(maxu, minv);
  1290                 data->glVertex2f(maxx, miny);
  1291                 data->glTexCoord2f(minu, maxv);
  1292                 data->glVertex2f(minx, maxy);
  1293                 data->glTexCoord2f(maxu, maxv);
  1294                 data->glVertex2f(maxx, maxy);
  1295                 data->glEnd();
  1296                 data->glPopMatrix();
  1297                 break;
  1298             }
  1299 
  1300             case SDL_RENDERCMD_NO_OP:
  1301                 break;
  1302         }
  1303 
  1304         cmd = cmd->next;
  1305     }
  1306 
  1307     return GL_CheckError("", renderer);
  1308 }
  1309 
  1310 static int
  1311 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1312                     Uint32 pixel_format, void * pixels, int pitch)
  1313 {
  1314     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1315     Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ARGB8888;
  1316     void *temp_pixels;
  1317     int temp_pitch;
  1318     GLint internalFormat;
  1319     GLenum format, type;
  1320     Uint8 *src, *dst, *tmp;
  1321     int w, h, length, rows;
  1322     int status;
  1323 
  1324     GL_ActivateRenderer(renderer);
  1325 
  1326     if (!convert_format(data, temp_format, &internalFormat, &format, &type)) {
  1327         return SDL_SetError("Texture format %s not supported by OpenGL",
  1328                             SDL_GetPixelFormatName(temp_format));
  1329     }
  1330 
  1331     if (!rect->w || !rect->h) {
  1332         return 0;  /* nothing to do. */
  1333     }
  1334 
  1335     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1336     temp_pixels = SDL_malloc(rect->h * temp_pitch);
  1337     if (!temp_pixels) {
  1338         return SDL_OutOfMemory();
  1339     }
  1340 
  1341     SDL_GetRendererOutputSize(renderer, &w, &h);
  1342 
  1343     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
  1344     data->glPixelStorei(GL_PACK_ROW_LENGTH,
  1345                         (temp_pitch / SDL_BYTESPERPIXEL(temp_format)));
  1346 
  1347     data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
  1348                        rect->w, rect->h, format, type, temp_pixels);
  1349 
  1350     if (GL_CheckError("glReadPixels()", renderer) < 0) {
  1351         SDL_free(temp_pixels);
  1352         return -1;
  1353     }
  1354 
  1355     /* Flip the rows to be top-down if necessary */
  1356     if (!renderer->target) {
  1357         SDL_bool isstack;
  1358         length = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1359         src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
  1360         dst = (Uint8*)temp_pixels;
  1361         tmp = SDL_small_alloc(Uint8, length, &isstack);
  1362         rows = rect->h / 2;
  1363         while (rows--) {
  1364             SDL_memcpy(tmp, dst, length);
  1365             SDL_memcpy(dst, src, length);
  1366             SDL_memcpy(src, tmp, length);
  1367             dst += temp_pitch;
  1368             src -= temp_pitch;
  1369         }
  1370         SDL_small_free(tmp, isstack);
  1371     }
  1372 
  1373     status = SDL_ConvertPixels(rect->w, rect->h,
  1374                                temp_format, temp_pixels, temp_pitch,
  1375                                pixel_format, pixels, pitch);
  1376     SDL_free(temp_pixels);
  1377 
  1378     return status;
  1379 }
  1380 
  1381 static void
  1382 GL_RenderPresent(SDL_Renderer * renderer)
  1383 {
  1384     GL_ActivateRenderer(renderer);
  1385 
  1386     SDL_GL_SwapWindow(renderer->window);
  1387 }
  1388 
  1389 static void
  1390 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1391 {
  1392     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  1393     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1394 
  1395     GL_ActivateRenderer(renderer);
  1396 
  1397     if (renderdata->drawstate.texture == texture) {
  1398         renderdata->drawstate.texture = NULL;
  1399     }
  1400     if (renderdata->drawstate.target == texture) {
  1401         renderdata->drawstate.target = NULL;
  1402     }
  1403 
  1404     if (!data) {
  1405         return;
  1406     }
  1407     if (data->texture) {
  1408         renderdata->glDeleteTextures(1, &data->texture);
  1409     }
  1410     if (data->yuv) {
  1411         renderdata->glDeleteTextures(1, &data->utexture);
  1412         renderdata->glDeleteTextures(1, &data->vtexture);
  1413     }
  1414     SDL_free(data->pixels);
  1415     SDL_free(data);
  1416     texture->driverdata = NULL;
  1417 }
  1418 
  1419 static void
  1420 GL_DestroyRenderer(SDL_Renderer * renderer)
  1421 {
  1422     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1423 
  1424     if (data) {
  1425         if (data->context != NULL) {
  1426             /* make sure we delete the right resources! */
  1427             GL_ActivateRenderer(renderer);
  1428         }
  1429 
  1430         GL_ClearErrors(renderer);
  1431         if (data->GL_ARB_debug_output_supported) {
  1432             PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
  1433 
  1434             /* Uh oh, we don't have a safe way of removing ourselves from the callback chain, if it changed after we set our callback. */
  1435             /* For now, just always replace the callback with the original one */
  1436             glDebugMessageCallbackARBFunc(data->next_error_callback, data->next_error_userparam);
  1437         }
  1438         if (data->shaders) {
  1439             GL_DestroyShaderContext(data->shaders);
  1440         }
  1441         if (data->context) {
  1442             while (data->framebuffers) {
  1443                 GL_FBOList *nextnode = data->framebuffers->next;
  1444                 /* delete the framebuffer object */
  1445                 data->glDeleteFramebuffersEXT(1, &data->framebuffers->FBO);
  1446                 GL_CheckError("", renderer);
  1447                 SDL_free(data->framebuffers);
  1448                 data->framebuffers = nextnode;
  1449             }
  1450             SDL_GL_DeleteContext(data->context);
  1451         }
  1452         SDL_free(data);
  1453     }
  1454     SDL_free(renderer);
  1455 }
  1456 
  1457 static int
  1458 GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
  1459 {
  1460     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1461     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1462     const GLenum textype = data->textype;
  1463 
  1464     GL_ActivateRenderer(renderer);
  1465 
  1466     data->glEnable(textype);
  1467     if (texturedata->yuv) {
  1468         data->glActiveTextureARB(GL_TEXTURE2_ARB);
  1469         data->glBindTexture(textype, texturedata->vtexture);
  1470 
  1471         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1472         data->glBindTexture(textype, texturedata->utexture);
  1473 
  1474         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1475     }
  1476     data->glBindTexture(textype, texturedata->texture);
  1477 
  1478     data->drawstate.texturing = SDL_TRUE;
  1479     data->drawstate.texture = texture;
  1480 
  1481     if(texw) *texw = (float)texturedata->texw;
  1482     if(texh) *texh = (float)texturedata->texh;
  1483 
  1484     return 0;
  1485 }
  1486 
  1487 static int
  1488 GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
  1489 {
  1490     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1491     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1492     const GLenum textype = data->textype;
  1493 
  1494     GL_ActivateRenderer(renderer);
  1495 
  1496     if (texturedata->yuv) {
  1497         data->glActiveTextureARB(GL_TEXTURE2_ARB);
  1498         data->glDisable(textype);
  1499 
  1500         data->glActiveTextureARB(GL_TEXTURE1_ARB);
  1501         data->glDisable(textype);
  1502 
  1503         data->glActiveTextureARB(GL_TEXTURE0_ARB);
  1504     }
  1505 
  1506     data->glDisable(textype);
  1507 
  1508     data->drawstate.texturing = SDL_FALSE;
  1509     data->drawstate.texture = NULL;
  1510 
  1511     return 0;
  1512 }
  1513 
  1514 
  1515 SDL_Renderer *
  1516 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
  1517 {
  1518     SDL_Renderer *renderer;
  1519     GL_RenderData *data;
  1520     GLint value;
  1521     Uint32 window_flags;
  1522     int profile_mask = 0, major = 0, minor = 0;
  1523     SDL_bool changed_window = SDL_FALSE;
  1524 
  1525     SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
  1526     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
  1527     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
  1528     
  1529     window_flags = SDL_GetWindowFlags(window);
  1530     if (!(window_flags & SDL_WINDOW_OPENGL) ||
  1531         profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
  1532 
  1533         changed_window = SDL_TRUE;
  1534         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  1535         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
  1536         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
  1537 
  1538         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
  1539             goto error;
  1540         }
  1541     }
  1542 
  1543     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
  1544     if (!renderer) {
  1545         SDL_OutOfMemory();
  1546         goto error;
  1547     }
  1548 
  1549     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
  1550     if (!data) {
  1551         SDL_free(renderer);
  1552         SDL_OutOfMemory();
  1553         goto error;
  1554     }
  1555 
  1556     renderer->GetOutputSize = GL_GetOutputSize;
  1557     renderer->SupportsBlendMode = GL_SupportsBlendMode;
  1558     renderer->CreateTexture = GL_CreateTexture;
  1559     renderer->UpdateTexture = GL_UpdateTexture;
  1560     renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
  1561     renderer->LockTexture = GL_LockTexture;
  1562     renderer->UnlockTexture = GL_UnlockTexture;
  1563     renderer->SetRenderTarget = GL_SetRenderTarget;
  1564     renderer->QueueSetViewport = GL_QueueSetViewport;
  1565     renderer->QueueSetDrawColor = GL_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
  1566     renderer->QueueDrawPoints = GL_QueueDrawPoints;
  1567     renderer->QueueDrawLines = GL_QueueDrawPoints;  /* lines and points queue vertices the same way. */
  1568     renderer->QueueFillRects = GL_QueueFillRects;
  1569     renderer->QueueCopy = GL_QueueCopy;
  1570     renderer->QueueCopyEx = GL_QueueCopyEx;
  1571     renderer->RunCommandQueue = GL_RunCommandQueue;
  1572     renderer->RenderReadPixels = GL_RenderReadPixels;
  1573     renderer->RenderPresent = GL_RenderPresent;
  1574     renderer->DestroyTexture = GL_DestroyTexture;
  1575     renderer->DestroyRenderer = GL_DestroyRenderer;
  1576     renderer->GL_BindTexture = GL_BindTexture;
  1577     renderer->GL_UnbindTexture = GL_UnbindTexture;
  1578     renderer->info = GL_RenderDriver.info;
  1579     renderer->info.flags = SDL_RENDERER_ACCELERATED;
  1580     renderer->driverdata = data;
  1581     renderer->window = window;
  1582 
  1583     data->context = SDL_GL_CreateContext(window);
  1584     if (!data->context) {
  1585         SDL_free(renderer);
  1586         SDL_free(data);
  1587         goto error;
  1588     }
  1589     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
  1590         SDL_GL_DeleteContext(data->context);
  1591         SDL_free(renderer);
  1592         SDL_free(data);
  1593         goto error;
  1594     }
  1595 
  1596     if (GL_LoadFunctions(data) < 0) {
  1597         SDL_GL_DeleteContext(data->context);
  1598         SDL_free(renderer);
  1599         SDL_free(data);
  1600         goto error;
  1601     }
  1602 
  1603 #ifdef __MACOSX__
  1604     /* Enable multi-threaded rendering */
  1605     /* Disabled until Ryan finishes his VBO/PBO code...
  1606        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
  1607      */
  1608 #endif
  1609 
  1610     if (flags & SDL_RENDERER_PRESENTVSYNC) {
  1611         SDL_GL_SetSwapInterval(1);
  1612     } else {
  1613         SDL_GL_SetSwapInterval(0);
  1614     }
  1615     if (SDL_GL_GetSwapInterval() > 0) {
  1616         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  1617     }
  1618 
  1619     /* Check for debug output support */
  1620     if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
  1621         (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
  1622         data->debug_enabled = SDL_TRUE;
  1623     }
  1624     if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) {
  1625         PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
  1626 
  1627         data->GL_ARB_debug_output_supported = SDL_TRUE;
  1628         data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)(char *)&data->next_error_callback);
  1629         data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam);
  1630         glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer);
  1631 
  1632         /* Make sure our callback is called when errors actually happen */
  1633         data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
  1634     }
  1635 
  1636     data->textype = GL_TEXTURE_2D;
  1637     if (SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) {
  1638         data->GL_ARB_texture_non_power_of_two_supported = SDL_TRUE;
  1639     } else if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
  1640                SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
  1641         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
  1642         data->textype = GL_TEXTURE_RECTANGLE_ARB;
  1643     }
  1644     if (data->GL_ARB_texture_rectangle_supported) {
  1645         data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value);
  1646         renderer->info.max_texture_width = value;
  1647         renderer->info.max_texture_height = value;
  1648     } else {
  1649         data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
  1650         renderer->info.max_texture_width = value;
  1651         renderer->info.max_texture_height = value;
  1652     }
  1653 
  1654     /* Check for multitexture support */
  1655     if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
  1656         data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
  1657         if (data->glActiveTextureARB) {
  1658             data->GL_ARB_multitexture_supported = SDL_TRUE;
  1659             data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
  1660         }
  1661     }
  1662 
  1663     /* Check for shader support */
  1664     if (SDL_GetHintBoolean(SDL_HINT_RENDER_OPENGL_SHADERS, SDL_TRUE)) {
  1665         data->shaders = GL_CreateShaderContext();
  1666     }
  1667     SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
  1668                 data->shaders ? "ENABLED" : "DISABLED");
  1669 
  1670     /* We support YV12 textures using 3 textures and a shader */
  1671     if (data->shaders && data->num_texture_units >= 3) {
  1672         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
  1673         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
  1674         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
  1675         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
  1676     }
  1677 
  1678 #ifdef __MACOSX__
  1679     renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
  1680 #endif
  1681 
  1682     if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
  1683         data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
  1684         data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
  1685             SDL_GL_GetProcAddress("glGenFramebuffersEXT");
  1686         data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
  1687             SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
  1688         data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
  1689             SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
  1690         data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
  1691             SDL_GL_GetProcAddress("glBindFramebufferEXT");
  1692         data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
  1693             SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
  1694         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
  1695     }
  1696     data->framebuffers = NULL;
  1697 
  1698     /* Set up parameters for rendering */
  1699     data->glMatrixMode(GL_MODELVIEW);
  1700     data->glLoadIdentity();
  1701     data->glDisable(GL_DEPTH_TEST);
  1702     data->glDisable(GL_CULL_FACE);
  1703     data->glDisable(GL_SCISSOR_TEST);
  1704     data->glDisable(data->textype);
  1705     data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  1706     data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  1707     /* This ended up causing video discrepancies between OpenGL and Direct3D */
  1708     /* data->glEnable(GL_LINE_SMOOTH); */
  1709 
  1710     data->drawstate.blend = SDL_BLENDMODE_INVALID;
  1711     data->drawstate.shader = SHADER_INVALID;
  1712     data->drawstate.color = 0xFFFFFFFF;
  1713     data->drawstate.clear_color = 0xFFFFFFFF;
  1714 
  1715     return renderer;
  1716 
  1717 error:
  1718     if (changed_window) {
  1719         /* Uh oh, better try to put it back... */
  1720         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
  1721         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
  1722         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
  1723         SDL_RecreateWindow(window, window_flags);
  1724     }
  1725     return NULL;
  1726 }
  1727 
  1728 
  1729 SDL_RenderDriver GL_RenderDriver = {
  1730     GL_CreateRenderer,
  1731     {
  1732      "opengl",
  1733      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
  1734      1,
  1735      {SDL_PIXELFORMAT_ARGB8888},
  1736      0,
  1737      0}
  1738 };
  1739 
  1740 
  1741 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
  1742 
  1743 /* vi: set ts=4 sw=4 expandtab: */