src/render/opengl/SDL_render_gl.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 07 Jan 2012 02:32:08 -0500
changeset 6171 7b9126fde949
parent 6138 4c64952a58fb
child 6182 eb6796f3e598
permissions -rwxr-xr-x
Fixed bug 1256 - Invalid window warning in GL_CreateRenderer

Martin Gerhardy 2011-07-27 02:26:06 PDT
the window reference is lost in the GL_CreateRenderer function. The attached
patch should fix this error.

#0 SDLSystem_LogOutputFunction (userdata=0x63b010, category=1,
priority=SDL_LOG_PRIORITY_ERROR, message=0x7fffffffcd00 "Invalid window") at
src/system/sdl/SDLSystem.cpp:8
#1 0x00007ffff7b1ddb3 in SDL_LogMessageV (category=1,
priority=SDL_LOG_PRIORITY_ERROR, fmt=<value optimized out>, ap=<value optimized
out>) at src/SDL_log.c:275
#2 0x00007ffff7b1df7c in SDL_LogError (category=<value optimized out>,
fmt=<value optimized out>) at src/SDL_log.c:212
#3 0x00007ffff7b1d582 in SDL_SetError (fmt=0x7ffff7baaff0 "") at
src/SDL_error.c:111
#4 0x00007ffff7b96f9e in SDL_GL_MakeCurrent (window=0x0, ctx=0xa62ce0) at
src/video/SDL_video.c:2484
#5 0x00007ffff7b4ba0c in GL_ActivateRenderer (renderer=0xa8f680) at
src/render/opengl/SDL_render_gl.c:195
#6 0x00007ffff7b4c59a in GL_ResetState (window=0x918010, flags=<value
optimized out>) at src/render/opengl/SDL_render_gl.c:214
#7 GL_CreateRenderer (window=0x918010, flags=<value optimized out>) at
src/render/opengl/SDL_render_gl.c:343
#8 0x00007ffff7b48053 in SDL_CreateRenderer (window=0x918010, index=<value
optimized out>, flags=2) at src/render/SDL_render.c:166
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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_config.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_opengl.h"
    28 #include "../SDL_sysrender.h"
    29 #include "SDL_shaders_gl.h"
    30 
    31 #ifdef __MACOSX__
    32 #include <OpenGL/OpenGL.h>
    33 #endif
    34 
    35 
    36 /* OpenGL renderer implementation */
    37 
    38 /* Details on optimizing the texture path on Mac OS X:
    39    http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/opengl_texturedata.html
    40 */
    41 
    42 /* Used to re-create the window with OpenGL capability */
    43 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
    44 
    45 static const float inv255f = 1.0f / 255.0f;
    46 
    47 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
    48 static void GL_WindowEvent(SDL_Renderer * renderer,
    49                            const SDL_WindowEvent *event);
    50 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    51 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    52                             const SDL_Rect * rect, const void *pixels,
    53                             int pitch);
    54 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    55                           const SDL_Rect * rect, void **pixels, int *pitch);
    56 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    57 static int GL_UpdateViewport(SDL_Renderer * renderer);
    58 static int GL_RenderClear(SDL_Renderer * renderer);
    59 static int GL_RenderDrawPoints(SDL_Renderer * renderer,
    60                                const SDL_Point * points, int count);
    61 static int GL_RenderDrawLines(SDL_Renderer * renderer,
    62                               const SDL_Point * points, int count);
    63 static int GL_RenderFillRects(SDL_Renderer * renderer,
    64                               const SDL_Rect * rects, int count);
    65 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    66                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    67 static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    68                                Uint32 pixel_format, void * pixels, int pitch);
    69 static void GL_RenderPresent(SDL_Renderer * renderer);
    70 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    71 static void GL_DestroyRenderer(SDL_Renderer * renderer);
    72 
    73 
    74 SDL_RenderDriver GL_RenderDriver = {
    75     GL_CreateRenderer,
    76     {
    77      "opengl",
    78      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
    79      1,
    80      {SDL_PIXELFORMAT_ARGB8888},
    81      0,
    82      0}
    83 };
    84 
    85 typedef struct
    86 {
    87     SDL_GLContext context;
    88     SDL_bool GL_ARB_texture_rectangle_supported;
    89     struct {
    90         GL_Shader shader;
    91         Uint32 color;
    92         int blendMode;
    93     } current;
    94 
    95     /* OpenGL functions */
    96 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
    97 #include "SDL_glfuncs.h"
    98 #undef SDL_PROC
    99 
   100     /* Multitexture support */
   101     SDL_bool GL_ARB_multitexture_supported;
   102     PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
   103     GLint num_texture_units;
   104 
   105     /* Shader support */
   106     GL_ShaderContext *shaders;
   107 
   108 } GL_RenderData;
   109 
   110 typedef struct
   111 {
   112     GLuint texture;
   113     GLenum type;
   114     GLfloat texw;
   115     GLfloat texh;
   116     GLenum format;
   117     GLenum formattype;
   118     void *pixels;
   119     int pitch;
   120     SDL_Rect locked_rect;
   121 
   122     /* YV12 texture support */
   123     SDL_bool yuv;
   124     GLuint utexture;
   125     GLuint vtexture;
   126 } GL_TextureData;
   127 
   128 
   129 static void
   130 GL_SetError(const char *prefix, GLenum result)
   131 {
   132     const char *error;
   133 
   134     switch (result) {
   135     case GL_NO_ERROR:
   136         error = "GL_NO_ERROR";
   137         break;
   138     case GL_INVALID_ENUM:
   139         error = "GL_INVALID_ENUM";
   140         break;
   141     case GL_INVALID_VALUE:
   142         error = "GL_INVALID_VALUE";
   143         break;
   144     case GL_INVALID_OPERATION:
   145         error = "GL_INVALID_OPERATION";
   146         break;
   147     case GL_STACK_OVERFLOW:
   148         error = "GL_STACK_OVERFLOW";
   149         break;
   150     case GL_STACK_UNDERFLOW:
   151         error = "GL_STACK_UNDERFLOW";
   152         break;
   153     case GL_OUT_OF_MEMORY:
   154         error = "GL_OUT_OF_MEMORY";
   155         break;
   156     case GL_TABLE_TOO_LARGE:
   157         error = "GL_TABLE_TOO_LARGE";
   158         break;
   159     default:
   160         error = "UNKNOWN";
   161         break;
   162     }
   163     SDL_SetError("%s: %s", prefix, error);
   164 }
   165 
   166 static int
   167 GL_LoadFunctions(GL_RenderData * data)
   168 {
   169 #ifdef __SDL_NOGETPROCADDR__
   170 #define SDL_PROC(ret,func,params) data->func=func;
   171 #else
   172 #define SDL_PROC(ret,func,params) \
   173     do { \
   174         data->func = SDL_GL_GetProcAddress(#func); \
   175         if ( ! data->func ) { \
   176             SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
   177             return -1; \
   178         } \
   179     } while ( 0 );
   180 #endif /* __SDL_NOGETPROCADDR__ */
   181 
   182 #include "SDL_glfuncs.h"
   183 #undef SDL_PROC
   184     return 0;
   185 }
   186 
   187 static SDL_GLContext SDL_CurrentContext = NULL;
   188 
   189 static int
   190 GL_ActivateRenderer(SDL_Renderer * renderer)
   191 {
   192     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   193 
   194     if (SDL_CurrentContext != data->context) {
   195         if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
   196             return -1;
   197         }
   198         SDL_CurrentContext = data->context;
   199 
   200         GL_UpdateViewport(renderer);
   201     }
   202     return 0;
   203 }
   204 
   205 /* This is called if we need to invalidate all of the SDL OpenGL state */
   206 static void
   207 GL_ResetState(SDL_Renderer *renderer)
   208 {
   209     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   210 
   211     if (SDL_CurrentContext == data->context) {
   212         GL_UpdateViewport(renderer);
   213     } else {
   214         GL_ActivateRenderer(renderer);
   215     }
   216 
   217     data->current.shader = SHADER_NONE;
   218     data->current.color = 0;
   219     data->current.blendMode = -1;
   220 
   221     data->glDisable(GL_DEPTH_TEST);
   222     data->glDisable(GL_CULL_FACE);
   223     /* This ended up causing video discrepancies between OpenGL and Direct3D */
   224     /*data->glEnable(GL_LINE_SMOOTH);*/
   225 
   226     data->glMatrixMode(GL_MODELVIEW);
   227     data->glLoadIdentity();
   228 }
   229 
   230 SDL_Renderer *
   231 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
   232 {
   233     SDL_Renderer *renderer;
   234     GL_RenderData *data;
   235     const char *hint;
   236     GLint value;
   237     Uint32 window_flags;
   238 
   239     window_flags = SDL_GetWindowFlags(window);
   240     if (!(window_flags & SDL_WINDOW_OPENGL)) {
   241         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
   242             return NULL;
   243         }
   244     }
   245 
   246     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   247     if (!renderer) {
   248         SDL_OutOfMemory();
   249         return NULL;
   250     }
   251 
   252     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
   253     if (!data) {
   254         GL_DestroyRenderer(renderer);
   255         SDL_OutOfMemory();
   256         return NULL;
   257     }
   258 
   259     renderer->WindowEvent = GL_WindowEvent;
   260     renderer->CreateTexture = GL_CreateTexture;
   261     renderer->UpdateTexture = GL_UpdateTexture;
   262     renderer->LockTexture = GL_LockTexture;
   263     renderer->UnlockTexture = GL_UnlockTexture;
   264     renderer->UpdateViewport = GL_UpdateViewport;
   265     renderer->RenderClear = GL_RenderClear;
   266     renderer->RenderDrawPoints = GL_RenderDrawPoints;
   267     renderer->RenderDrawLines = GL_RenderDrawLines;
   268     renderer->RenderFillRects = GL_RenderFillRects;
   269     renderer->RenderCopy = GL_RenderCopy;
   270     renderer->RenderReadPixels = GL_RenderReadPixels;
   271     renderer->RenderPresent = GL_RenderPresent;
   272     renderer->DestroyTexture = GL_DestroyTexture;
   273     renderer->DestroyRenderer = GL_DestroyRenderer;
   274     renderer->info = GL_RenderDriver.info;
   275     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   276     renderer->driverdata = data;
   277     renderer->window = window;
   278 
   279     data->context = SDL_GL_CreateContext(window);
   280     if (!data->context) {
   281         GL_DestroyRenderer(renderer);
   282         return NULL;
   283     }
   284     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   285         GL_DestroyRenderer(renderer);
   286         return NULL;
   287     }
   288 
   289     if (GL_LoadFunctions(data) < 0) {
   290         GL_DestroyRenderer(renderer);
   291         return NULL;
   292     }
   293 
   294 #ifdef __MACOSX__
   295     /* Enable multi-threaded rendering */
   296     /* Disabled until Ryan finishes his VBO/PBO code...
   297        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
   298      */
   299 #endif
   300 
   301     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   302         SDL_GL_SetSwapInterval(1);
   303     } else {
   304         SDL_GL_SetSwapInterval(0);
   305     }
   306     if (SDL_GL_GetSwapInterval() > 0) {
   307         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   308     }
   309 
   310     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   311     renderer->info.max_texture_width = value;
   312     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   313     renderer->info.max_texture_height = value;
   314 
   315     if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
   316         || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
   317         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
   318     }
   319 
   320     /* Check for multitexture support */
   321     if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
   322         data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
   323         if (data->glActiveTextureARB) {
   324             data->GL_ARB_multitexture_supported = SDL_TRUE;
   325             data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
   326         }
   327     }
   328 
   329     /* Check for shader support */
   330     hint = SDL_GetHint(SDL_HINT_RENDER_OPENGL_SHADERS);
   331     if (!hint || *hint != '0') {
   332         data->shaders = GL_CreateShaderContext();
   333     }
   334     SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
   335                 data->shaders ? "ENABLED" : "DISABLED");
   336 
   337     /* We support YV12 textures using 3 textures and a shader */
   338     if (data->shaders && data->num_texture_units >= 3) {
   339         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   340         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   341     }
   342 
   343     /* Set up parameters for rendering */
   344     GL_ResetState(renderer);
   345 
   346     return renderer;
   347 }
   348 
   349 static void
   350 GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   351 {
   352     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   353         /* Rebind the context to the window area and update matrices */
   354         SDL_CurrentContext = NULL;
   355     }
   356 }
   357 
   358 static __inline__ int
   359 power_of_2(int input)
   360 {
   361     int value = 1;
   362 
   363     while (value < input) {
   364         value <<= 1;
   365     }
   366     return value;
   367 }
   368 
   369 static __inline__ SDL_bool
   370 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
   371                GLint* internalFormat, GLenum* format, GLenum* type)
   372 {
   373     switch (pixel_format) {
   374     case SDL_PIXELFORMAT_ARGB8888:
   375         *internalFormat = GL_RGBA8;
   376         *format = GL_BGRA;
   377         *type = GL_UNSIGNED_INT_8_8_8_8_REV;
   378         break;
   379     case SDL_PIXELFORMAT_YV12:
   380     case SDL_PIXELFORMAT_IYUV:
   381         *internalFormat = GL_LUMINANCE;
   382         *format = GL_LUMINANCE;
   383         *type = GL_UNSIGNED_BYTE;
   384         break;
   385     default:
   386         return SDL_FALSE;
   387     }
   388     return SDL_TRUE;
   389 }
   390 
   391 static GLenum
   392 GetScaleQuality(void)
   393 {
   394     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   395 
   396     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   397         return GL_NEAREST;
   398     } else {
   399         return GL_LINEAR;
   400     }
   401 }
   402 
   403 static int
   404 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   405 {
   406     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   407     GL_TextureData *data;
   408     GLint internalFormat;
   409     GLenum format, type;
   410     int texture_w, texture_h;
   411     GLenum scaleMode;
   412     GLenum result;
   413 
   414     GL_ActivateRenderer(renderer);
   415 
   416     if (!convert_format(renderdata, texture->format, &internalFormat,
   417                         &format, &type)) {
   418         SDL_SetError("Texture format %s not supported by OpenGL",
   419                      SDL_GetPixelFormatName(texture->format));
   420         return -1;
   421     }
   422 
   423     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   424     if (!data) {
   425         SDL_OutOfMemory();
   426         return -1;
   427     }
   428 
   429     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   430         size_t size;
   431         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   432         size = texture->h * data->pitch;
   433         if (texture->format == SDL_PIXELFORMAT_YV12 ||
   434             texture->format == SDL_PIXELFORMAT_IYUV) {
   435             /* Need to add size for the U and V planes */
   436             size += (2 * (texture->h * data->pitch) / 4);
   437         }
   438         data->pixels = SDL_calloc(1, size);
   439         if (!data->pixels) {
   440             SDL_OutOfMemory();
   441             SDL_free(data);
   442             return -1;
   443         }
   444     }
   445 
   446     texture->driverdata = data;
   447 
   448     renderdata->glGetError();
   449     renderdata->glGenTextures(1, &data->texture);
   450     if (renderdata->GL_ARB_texture_rectangle_supported) {
   451         data->type = GL_TEXTURE_RECTANGLE_ARB;
   452         texture_w = texture->w;
   453         texture_h = texture->h;
   454         data->texw = (GLfloat) texture_w;
   455         data->texh = (GLfloat) texture_h;
   456     } else {
   457         data->type = GL_TEXTURE_2D;
   458         texture_w = power_of_2(texture->w);
   459         texture_h = power_of_2(texture->h);
   460         data->texw = (GLfloat) (texture->w) / texture_w;
   461         data->texh = (GLfloat) texture->h / texture_h;
   462     }
   463 
   464     data->format = format;
   465     data->formattype = type;
   466     scaleMode = GetScaleQuality();
   467     renderdata->glEnable(data->type);
   468     renderdata->glBindTexture(data->type, data->texture);
   469     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
   470     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
   471     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   472                                 GL_CLAMP_TO_EDGE);
   473     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   474                                 GL_CLAMP_TO_EDGE);
   475 #ifdef __MACOSX__
   476 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
   477 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
   478 #endif
   479 #ifndef STORAGE_CACHED_APPLE
   480 #define STORAGE_CACHED_APPLE                0x85BE
   481 #endif
   482 #ifndef STORAGE_SHARED_APPLE
   483 #define STORAGE_SHARED_APPLE                0x85BF
   484 #endif
   485     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   486         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   487                                     GL_STORAGE_SHARED_APPLE);
   488     } else {
   489         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   490                                     GL_STORAGE_CACHED_APPLE);
   491     }
   492     if (texture->access == SDL_TEXTUREACCESS_STREAMING
   493         && texture->format == SDL_PIXELFORMAT_ARGB8888
   494         && (texture->w % 8) == 0) {
   495         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
   496         renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   497         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   498                           (data->pitch / SDL_BYTESPERPIXEL(texture->format)));
   499         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   500                                  texture_h, 0, format, type, data->pixels);
   501         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
   502     }
   503     else
   504 #endif
   505     {
   506         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   507                                  texture_h, 0, format, type, NULL);
   508     }
   509     renderdata->glDisable(data->type);
   510     result = renderdata->glGetError();
   511     if (result != GL_NO_ERROR) {
   512         GL_SetError("glTexImage2D()", result);
   513         return -1;
   514     }
   515 
   516     if (texture->format == SDL_PIXELFORMAT_YV12 ||
   517         texture->format == SDL_PIXELFORMAT_IYUV) {
   518         data->yuv = SDL_TRUE;
   519 
   520         renderdata->glGenTextures(1, &data->utexture);
   521         renderdata->glGenTextures(1, &data->vtexture);
   522         renderdata->glEnable(data->type);
   523 
   524         renderdata->glBindTexture(data->type, data->utexture);
   525         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   526                                     scaleMode);
   527         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   528                                     scaleMode);
   529         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   530                                     GL_CLAMP_TO_EDGE);
   531         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   532                                     GL_CLAMP_TO_EDGE);
   533         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
   534                                  texture_h/2, 0, format, type, NULL);
   535 
   536         renderdata->glBindTexture(data->type, data->vtexture);
   537         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   538                                     scaleMode);
   539         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   540                                     scaleMode);
   541         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   542                                     GL_CLAMP_TO_EDGE);
   543         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   544                                     GL_CLAMP_TO_EDGE);
   545         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
   546                                  texture_h/2, 0, format, type, NULL);
   547 
   548         renderdata->glDisable(data->type);
   549     }
   550     return 0;
   551 }
   552 
   553 static int
   554 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   555                  const SDL_Rect * rect, const void *pixels, int pitch)
   556 {
   557     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   558     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   559     GLenum result;
   560 
   561     GL_ActivateRenderer(renderer);
   562 
   563     renderdata->glGetError();
   564     renderdata->glEnable(data->type);
   565     renderdata->glBindTexture(data->type, data->texture);
   566     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   567     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   568                               (pitch / SDL_BYTESPERPIXEL(texture->format)));
   569     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   570                                 rect->h, data->format, data->formattype,
   571                                 pixels);
   572     if (data->yuv) {
   573         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
   574 
   575         /* Skip to the correct offset into the next texture */
   576         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
   577         if (texture->format == SDL_PIXELFORMAT_YV12) {
   578             renderdata->glBindTexture(data->type, data->vtexture);
   579         } else {
   580             renderdata->glBindTexture(data->type, data->utexture);
   581         }
   582         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   583                                     rect->w/2, rect->h/2,
   584                                     data->format, data->formattype, pixels);
   585 
   586         /* Skip to the correct offset into the next texture */
   587         pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
   588         if (texture->format == SDL_PIXELFORMAT_YV12) {
   589             renderdata->glBindTexture(data->type, data->utexture);
   590         } else {
   591             renderdata->glBindTexture(data->type, data->vtexture);
   592         }
   593         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
   594                                     rect->w/2, rect->h/2,
   595                                     data->format, data->formattype, pixels);
   596     }
   597     renderdata->glDisable(data->type);
   598     result = renderdata->glGetError();
   599     if (result != GL_NO_ERROR) {
   600         GL_SetError("glTexSubImage2D()", result);
   601         return -1;
   602     }
   603     return 0;
   604 }
   605 
   606 static int
   607 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   608                const SDL_Rect * rect, void **pixels, int *pitch)
   609 {
   610     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   611 
   612     data->locked_rect = *rect;
   613     *pixels = 
   614         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   615                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   616     *pitch = data->pitch;
   617     return 0;
   618 }
   619 
   620 static void
   621 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   622 {
   623     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   624     const SDL_Rect *rect;
   625     void *pixels;
   626 
   627     rect = &data->locked_rect;
   628     pixels = 
   629         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   630                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   631     GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
   632 }
   633 
   634 static int
   635 GL_UpdateViewport(SDL_Renderer * renderer)
   636 {
   637     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   638 
   639     if (SDL_CurrentContext != data->context) {
   640         /* We'll update the viewport after we rebind the context */
   641         return 0;
   642     }
   643 
   644     data->glViewport(renderer->viewport.x, renderer->viewport.y,
   645                      renderer->viewport.w, renderer->viewport.h);
   646 
   647     data->glMatrixMode(GL_PROJECTION);
   648     data->glLoadIdentity();
   649     data->glOrtho((GLdouble) 0,
   650                   (GLdouble) renderer->viewport.w,
   651                   (GLdouble) renderer->viewport.h,
   652                   (GLdouble) 0, 0.0, 1.0);
   653     return 0;
   654 }
   655 
   656 static void
   657 GL_SetShader(GL_RenderData * data, GL_Shader shader)
   658 {
   659     if (data->shaders && shader != data->current.shader) {
   660         GL_SelectShader(data->shaders, shader);
   661         data->current.shader = shader;
   662     }
   663 }
   664 
   665 static void
   666 GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
   667 {
   668     Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
   669 
   670     if (color != data->current.color) {
   671         data->glColor4f((GLfloat) r * inv255f,
   672                         (GLfloat) g * inv255f,
   673                         (GLfloat) b * inv255f,
   674                         (GLfloat) a * inv255f);
   675         data->current.color = color;
   676     }
   677 }
   678 
   679 static void
   680 GL_SetBlendMode(GL_RenderData * data, int blendMode)
   681 {
   682     if (blendMode != data->current.blendMode) {
   683         switch (blendMode) {
   684         case SDL_BLENDMODE_NONE:
   685             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   686             data->glDisable(GL_BLEND);
   687             break;
   688         case SDL_BLENDMODE_BLEND:
   689             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   690             data->glEnable(GL_BLEND);
   691             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   692             break;
   693         case SDL_BLENDMODE_ADD:
   694             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   695             data->glEnable(GL_BLEND);
   696             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   697             break;
   698         case SDL_BLENDMODE_MOD:
   699             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   700             data->glEnable(GL_BLEND);
   701             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   702             break;
   703         }
   704         data->current.blendMode = blendMode;
   705     }
   706 }
   707 
   708 static void
   709 GL_SetDrawingState(SDL_Renderer * renderer)
   710 {
   711     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   712 
   713     GL_ActivateRenderer(renderer);
   714 
   715     GL_SetColor(data, renderer->r,
   716                       renderer->g,
   717                       renderer->b,
   718                       renderer->a);
   719 
   720     GL_SetBlendMode(data, renderer->blendMode);
   721 
   722     GL_SetShader(data, SHADER_SOLID);
   723 }
   724 
   725 static int
   726 GL_RenderClear(SDL_Renderer * renderer)
   727 {
   728     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   729 
   730     GL_ActivateRenderer(renderer);
   731 
   732     data->glClearColor((GLfloat) renderer->r * inv255f,
   733                        (GLfloat) renderer->g * inv255f,
   734                        (GLfloat) renderer->b * inv255f,
   735                        (GLfloat) renderer->a * inv255f);
   736 
   737     data->glClear(GL_COLOR_BUFFER_BIT);
   738 
   739     return 0;
   740 }
   741 
   742 static int
   743 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   744                     int count)
   745 {
   746     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   747     int i;
   748 
   749     GL_SetDrawingState(renderer);
   750 
   751     data->glBegin(GL_POINTS);
   752     for (i = 0; i < count; ++i) {
   753         data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   754     }
   755     data->glEnd();
   756 
   757     return 0;
   758 }
   759 
   760 static int
   761 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   762                    int count)
   763 {
   764     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   765     int i;
   766 
   767     GL_SetDrawingState(renderer);
   768 
   769     if (count > 2 && 
   770         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
   771         data->glBegin(GL_LINE_LOOP);
   772         /* GL_LINE_LOOP takes care of the final segment */
   773         --count;
   774         for (i = 0; i < count; ++i) {
   775             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   776         }
   777         data->glEnd();
   778     } else {
   779 #if defined(__APPLE__) || defined(__WIN32__)
   780 #else
   781         int x1, y1, x2, y2;
   782 #endif
   783 
   784         data->glBegin(GL_LINE_STRIP);
   785         for (i = 0; i < count; ++i) {
   786             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   787         }
   788         data->glEnd();
   789 
   790         /* The line is half open, so we need one more point to complete it.
   791          * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
   792          * If we have to, we can use vertical line and horizontal line textures
   793          * for vertical and horizontal lines, and then create custom textures
   794          * for diagonal lines and software render those.  It's terrible, but at
   795          * least it would be pixel perfect.
   796          */
   797         data->glBegin(GL_POINTS);
   798 #if defined(__APPLE__) || defined(__WIN32__)
   799         /* Mac OS X and Windows seem to always leave the second point open */
   800         data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
   801 #else
   802         /* Linux seems to leave the right-most or bottom-most point open */
   803         x1 = points[0].x;
   804         y1 = points[0].y;
   805         x2 = points[count-1].x;
   806         y2 = points[count-1].y;
   807 
   808         if (x1 > x2) {
   809             data->glVertex2f(0.5f + x1, 0.5f + y1);
   810         } else if (x2 > x1) {
   811             data->glVertex2f(0.5f + x2, 0.5f + y2);
   812         } else if (y1 > y2) {
   813             data->glVertex2f(0.5f + x1, 0.5f + y1);
   814         } else if (y2 > y1) {
   815             data->glVertex2f(0.5f + x2, 0.5f + y2);
   816         }
   817 #endif
   818         data->glEnd();
   819     }
   820 
   821     return 0;
   822 }
   823 
   824 static int
   825 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count)
   826 {
   827     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   828     int i;
   829 
   830     GL_SetDrawingState(renderer);
   831 
   832     for (i = 0; i < count; ++i) {
   833         const SDL_Rect *rect = &rects[i];
   834 
   835         data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
   836     }
   837 
   838     return 0;
   839 }
   840 
   841 static int
   842 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   843               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   844 {
   845     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   846     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
   847     int minx, miny, maxx, maxy;
   848     GLfloat minu, maxu, minv, maxv;
   849 
   850     GL_ActivateRenderer(renderer);
   851 
   852     data->glEnable(texturedata->type);
   853     if (texturedata->yuv) {
   854         data->glActiveTextureARB(GL_TEXTURE2_ARB);
   855         data->glBindTexture(texturedata->type, texturedata->vtexture);
   856 
   857         data->glActiveTextureARB(GL_TEXTURE1_ARB);
   858         data->glBindTexture(texturedata->type, texturedata->utexture);
   859 
   860         data->glActiveTextureARB(GL_TEXTURE0_ARB);
   861     }
   862     data->glBindTexture(texturedata->type, texturedata->texture);
   863 
   864     if (texture->modMode) {
   865         GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
   866     } else {
   867         GL_SetColor(data, 255, 255, 255, 255);
   868     }
   869 
   870     GL_SetBlendMode(data, texture->blendMode);
   871 
   872     if (texturedata->yuv) {
   873         GL_SetShader(data, SHADER_YV12);
   874     } else {
   875         GL_SetShader(data, SHADER_RGB);
   876     }
   877 
   878     minx = dstrect->x;
   879     miny = dstrect->y;
   880     maxx = dstrect->x + dstrect->w;
   881     maxy = dstrect->y + dstrect->h;
   882 
   883     minu = (GLfloat) srcrect->x / texture->w;
   884     minu *= texturedata->texw;
   885     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   886     maxu *= texturedata->texw;
   887     minv = (GLfloat) srcrect->y / texture->h;
   888     minv *= texturedata->texh;
   889     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   890     maxv *= texturedata->texh;
   891 
   892     data->glBegin(GL_TRIANGLE_STRIP);
   893     data->glTexCoord2f(minu, minv);
   894     data->glVertex2f((GLfloat) minx, (GLfloat) miny);
   895     data->glTexCoord2f(maxu, minv);
   896     data->glVertex2f((GLfloat) maxx, (GLfloat) miny);
   897     data->glTexCoord2f(minu, maxv);
   898     data->glVertex2f((GLfloat) minx, (GLfloat) maxy);
   899     data->glTexCoord2f(maxu, maxv);
   900     data->glVertex2f((GLfloat) maxx, (GLfloat) maxy);
   901     data->glEnd();
   902 
   903     data->glDisable(texturedata->type);
   904 
   905     return 0;
   906 }
   907 
   908 static int
   909 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   910                     Uint32 pixel_format, void * pixels, int pitch)
   911 {
   912     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   913     SDL_Window *window = renderer->window;
   914     Uint32 temp_format = SDL_PIXELFORMAT_ARGB8888;
   915     void *temp_pixels;
   916     int temp_pitch;
   917     GLint internalFormat;
   918     GLenum format, type;
   919     Uint8 *src, *dst, *tmp;
   920     int w, h, length, rows;
   921     int status;
   922 
   923     GL_ActivateRenderer(renderer);
   924 
   925     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
   926     temp_pixels = SDL_malloc(rect->h * temp_pitch);
   927     if (!temp_pixels) {
   928         SDL_OutOfMemory();
   929         return -1;
   930     }
   931 
   932     convert_format(data, temp_format, &internalFormat, &format, &type);
   933 
   934     SDL_GetWindowSize(window, &w, &h);
   935 
   936     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
   937     data->glPixelStorei(GL_PACK_ROW_LENGTH,
   938                         (temp_pitch / SDL_BYTESPERPIXEL(temp_format)));
   939 
   940     data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
   941                        format, type, temp_pixels);
   942 
   943     /* Flip the rows to be top-down */
   944     length = rect->w * SDL_BYTESPERPIXEL(temp_format);
   945     src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
   946     dst = (Uint8*)temp_pixels;
   947     tmp = SDL_stack_alloc(Uint8, length);
   948     rows = rect->h / 2;
   949     while (rows--) {
   950         SDL_memcpy(tmp, dst, length);
   951         SDL_memcpy(dst, src, length);
   952         SDL_memcpy(src, tmp, length);
   953         dst += temp_pitch;
   954         src -= temp_pitch;
   955     }
   956     SDL_stack_free(tmp);
   957 
   958     status = SDL_ConvertPixels(rect->w, rect->h,
   959                                temp_format, temp_pixels, temp_pitch,
   960                                pixel_format, pixels, pitch);
   961     SDL_free(temp_pixels);
   962 
   963     return status;
   964 }
   965 
   966 static void
   967 GL_RenderPresent(SDL_Renderer * renderer)
   968 {
   969     GL_ActivateRenderer(renderer);
   970 
   971     SDL_GL_SwapWindow(renderer->window);
   972 }
   973 
   974 static void
   975 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   976 {
   977     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   978     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   979 
   980     GL_ActivateRenderer(renderer);
   981 
   982     if (!data) {
   983         return;
   984     }
   985     if (data->texture) {
   986         renderdata->glDeleteTextures(1, &data->texture);
   987     }
   988     if (data->yuv) {
   989         renderdata->glDeleteTextures(1, &data->utexture);
   990         renderdata->glDeleteTextures(1, &data->vtexture);
   991     }
   992     if (data->pixels) {
   993         SDL_free(data->pixels);
   994     }
   995     SDL_free(data);
   996     texture->driverdata = NULL;
   997 }
   998 
   999 static void
  1000 GL_DestroyRenderer(SDL_Renderer * renderer)
  1001 {
  1002     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1003 
  1004     if (data) {
  1005         if (data->shaders) {
  1006             GL_DestroyShaderContext(data->shaders);
  1007         }
  1008         if (data->context) {
  1009             /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
  1010             SDL_GL_DeleteContext(data->context);
  1011         }
  1012         SDL_free(data);
  1013     }
  1014     SDL_free(renderer);
  1015 }
  1016 
  1017 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
  1018 
  1019 /* vi: set ts=4 sw=4 expandtab: */