src/video/SDL_renderer_gl.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 06 Jan 2010 06:12:01 +0000
changeset 3607 8b4c0320638e
parent 3599 0f958e527e5e
child 3685 64ce267332c6
permissions -rw-r--r--
Fixed GL_RenderWritePixels() - thanks Ryan!
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #if SDL_VIDEO_RENDER_OGL
    25 
    26 #include "SDL_video.h"
    27 #include "SDL_opengl.h"
    28 #include "SDL_sysvideo.h"
    29 #include "SDL_pixels_c.h"
    30 #include "SDL_rect_c.h"
    31 #include "SDL_yuv_sw_c.h"
    32 
    33 #ifdef __MACOSX__
    34 #include <OpenGL/OpenGL.h>
    35 #endif
    36 
    37 
    38 /* OpenGL renderer implementation */
    39 
    40 /* Details on optimizing the texture path on Mac OS X:
    41    http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/chapter_10_section_2.html
    42 */
    43 
    44 /* !!! FIXME: this should go in a higher level than the GL renderer. */
    45 static __inline__ int
    46 bytes_per_pixel(const Uint32 format)
    47 {
    48     if (!SDL_ISPIXELFORMAT_FOURCC(format)) {
    49         return SDL_BYTESPERPIXEL(format);
    50     }
    51 
    52     /* FOURCC format */
    53     switch (format) {
    54     case SDL_PIXELFORMAT_YV12:
    55     case SDL_PIXELFORMAT_IYUV:
    56     case SDL_PIXELFORMAT_YUY2:
    57     case SDL_PIXELFORMAT_UYVY:
    58     case SDL_PIXELFORMAT_YVYU:
    59         return 2;
    60     default:
    61         return 1;               /* shouldn't ever hit this. */
    62     }
    63 }
    64 
    65 
    66 static const float inv255f = 1.0f / 255.0f;
    67 
    68 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
    69 static int GL_ActivateRenderer(SDL_Renderer * renderer);
    70 static int GL_DisplayModeChanged(SDL_Renderer * renderer);
    71 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    72 static int GL_QueryTexturePixels(SDL_Renderer * renderer,
    73                                  SDL_Texture * texture, void **pixels,
    74                                  int *pitch);
    75 static int GL_SetTexturePalette(SDL_Renderer * renderer,
    76                                 SDL_Texture * texture,
    77                                 const SDL_Color * colors, int firstcolor,
    78                                 int ncolors);
    79 static int GL_GetTexturePalette(SDL_Renderer * renderer,
    80                                 SDL_Texture * texture, SDL_Color * colors,
    81                                 int firstcolor, int ncolors);
    82 static int GL_SetTextureColorMod(SDL_Renderer * renderer,
    83                                  SDL_Texture * texture);
    84 static int GL_SetTextureAlphaMod(SDL_Renderer * renderer,
    85                                  SDL_Texture * texture);
    86 static int GL_SetTextureBlendMode(SDL_Renderer * renderer,
    87                                   SDL_Texture * texture);
    88 static int GL_SetTextureScaleMode(SDL_Renderer * renderer,
    89                                   SDL_Texture * texture);
    90 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    91                             const SDL_Rect * rect, const void *pixels,
    92                             int pitch);
    93 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    94                           const SDL_Rect * rect, int markDirty, void **pixels,
    95                           int *pitch);
    96 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    97 static void GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    98                             int numrects, const SDL_Rect * rects);
    99 static int GL_RenderClear(SDL_Renderer * renderer);
   100 static int GL_RenderDrawPoints(SDL_Renderer * renderer,
   101                                const SDL_Point * points, int count);
   102 static int GL_RenderDrawLines(SDL_Renderer * renderer,
   103                               const SDL_Point * points, int count);
   104 static int GL_RenderDrawRects(SDL_Renderer * renderer,
   105                               const SDL_Rect ** rects, int count);
   106 static int GL_RenderFillRects(SDL_Renderer * renderer,
   107                               const SDL_Rect ** rects, int count);
   108 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   109                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
   110 static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   111                                Uint32 pixel_format, void * pixels, int pitch);
   112 static int GL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   113                                 Uint32 pixel_format, const void * pixels, int pitch);
   114 static void GL_RenderPresent(SDL_Renderer * renderer);
   115 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   116 static void GL_DestroyRenderer(SDL_Renderer * renderer);
   117 
   118 
   119 SDL_RenderDriver GL_RenderDriver = {
   120     GL_CreateRenderer,
   121     {
   122      "opengl",
   123      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD |
   124       SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
   125      (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
   126       SDL_TEXTUREMODULATE_ALPHA),
   127      (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK |
   128       SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD),
   129      (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST |
   130       SDL_TEXTURESCALEMODE_SLOW),
   131      15,
   132      {
   133       SDL_PIXELFORMAT_INDEX1LSB,
   134       SDL_PIXELFORMAT_INDEX1MSB,
   135       SDL_PIXELFORMAT_INDEX8,
   136       SDL_PIXELFORMAT_RGB332,
   137       SDL_PIXELFORMAT_RGB444,
   138       SDL_PIXELFORMAT_RGB555,
   139       SDL_PIXELFORMAT_ARGB4444,
   140       SDL_PIXELFORMAT_ARGB1555,
   141       SDL_PIXELFORMAT_RGB565,
   142       SDL_PIXELFORMAT_RGB24,
   143       SDL_PIXELFORMAT_BGR24,
   144       SDL_PIXELFORMAT_RGB888,
   145       SDL_PIXELFORMAT_BGR888,
   146       SDL_PIXELFORMAT_ARGB8888,
   147       SDL_PIXELFORMAT_ABGR8888,
   148       SDL_PIXELFORMAT_ARGB2101010},
   149      0,
   150      0}
   151 };
   152 
   153 typedef struct
   154 {
   155     SDL_GLContext context;
   156     SDL_bool updateSize;
   157     SDL_bool GL_ARB_texture_rectangle_supported;
   158     SDL_bool GL_EXT_paletted_texture_supported;
   159     SDL_bool GL_APPLE_ycbcr_422_supported;
   160     SDL_bool GL_MESA_ycbcr_texture_supported;
   161     SDL_bool GL_ARB_fragment_program_supported;
   162     int blendMode;
   163     int scaleMode;
   164 
   165     /* OpenGL functions */
   166 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
   167 #include "SDL_glfuncs.h"
   168 #undef SDL_PROC
   169 
   170     PFNGLCOLORTABLEEXTPROC glColorTableEXT;
   171     void (*glTextureRangeAPPLE) (GLenum target, GLsizei length,
   172                                  const GLvoid * pointer);
   173 
   174     PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
   175     PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
   176     PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB;
   177     PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
   178     PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
   179     PFNGLBINDPROGRAMARBPROC glBindProgramARB;
   180     PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
   181 
   182     /* (optional) fragment programs */
   183     GLuint fragment_program_mask;
   184     GLuint fragment_program_UYVY;
   185 } GL_RenderData;
   186 
   187 typedef struct
   188 {
   189     GLuint texture;
   190     GLuint shader;
   191     GLenum type;
   192     GLfloat texw;
   193     GLfloat texh;
   194     GLenum format;
   195     GLenum formattype;
   196     Uint8 *palette;
   197     void *pixels;
   198     int pitch;
   199     SDL_DirtyRectList dirty;
   200     int HACK_RYAN_FIXME;
   201 } GL_TextureData;
   202 
   203 
   204 static void
   205 GL_SetError(const char *prefix, GLenum result)
   206 {
   207     const char *error;
   208 
   209     switch (result) {
   210     case GL_NO_ERROR:
   211         error = "GL_NO_ERROR";
   212         break;
   213     case GL_INVALID_ENUM:
   214         error = "GL_INVALID_ENUM";
   215         break;
   216     case GL_INVALID_VALUE:
   217         error = "GL_INVALID_VALUE";
   218         break;
   219     case GL_INVALID_OPERATION:
   220         error = "GL_INVALID_OPERATION";
   221         break;
   222     case GL_STACK_OVERFLOW:
   223         error = "GL_STACK_OVERFLOW";
   224         break;
   225     case GL_STACK_UNDERFLOW:
   226         error = "GL_STACK_UNDERFLOW";
   227         break;
   228     case GL_OUT_OF_MEMORY:
   229         error = "GL_OUT_OF_MEMORY";
   230         break;
   231     case GL_TABLE_TOO_LARGE:
   232         error = "GL_TABLE_TOO_LARGE";
   233         break;
   234     default:
   235         error = "UNKNOWN";
   236         break;
   237     }
   238     SDL_SetError("%s: %s", prefix, error);
   239 }
   240 
   241 static int
   242 GL_LoadFunctions(GL_RenderData * data)
   243 {
   244 #if defined(__QNXNTO__) && (_NTO_VERSION < 630)
   245 #define __SDL_NOGETPROCADDR__
   246 #endif
   247 #ifdef __SDL_NOGETPROCADDR__
   248 #define SDL_PROC(ret,func,params) data->func=func;
   249 #else
   250 #define SDL_PROC(ret,func,params) \
   251     do { \
   252         data->func = SDL_GL_GetProcAddress(#func); \
   253         if ( ! data->func ) { \
   254             SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
   255             return -1; \
   256         } \
   257     } while ( 0 );
   258 #endif /* __SDL_NOGETPROCADDR__ */
   259 
   260 #include "SDL_glfuncs.h"
   261 #undef SDL_PROC
   262     return 0;
   263 }
   264 
   265 SDL_Renderer *
   266 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
   267 {
   268     SDL_Renderer *renderer;
   269     GL_RenderData *data;
   270     GLint value;
   271     int doublebuffer;
   272 
   273     /* Render directly to the window, unless we're compositing */
   274 #ifndef __MACOSX__
   275     if (flags & SDL_RENDERER_SINGLEBUFFER) {
   276         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
   277     }
   278 #endif
   279     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   280         if (SDL_RecreateWindow(window, window->flags | SDL_WINDOW_OPENGL) < 0) {
   281             return NULL;
   282         }
   283     }
   284 
   285     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   286     if (!renderer) {
   287         SDL_OutOfMemory();
   288         return NULL;
   289     }
   290 
   291     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
   292     if (!data) {
   293         GL_DestroyRenderer(renderer);
   294         SDL_OutOfMemory();
   295         return NULL;
   296     }
   297 
   298     renderer->ActivateRenderer = GL_ActivateRenderer;
   299     renderer->DisplayModeChanged = GL_DisplayModeChanged;
   300     renderer->CreateTexture = GL_CreateTexture;
   301     renderer->QueryTexturePixels = GL_QueryTexturePixels;
   302     renderer->SetTexturePalette = GL_SetTexturePalette;
   303     renderer->GetTexturePalette = GL_GetTexturePalette;
   304     renderer->SetTextureColorMod = GL_SetTextureColorMod;
   305     renderer->SetTextureAlphaMod = GL_SetTextureAlphaMod;
   306     renderer->SetTextureBlendMode = GL_SetTextureBlendMode;
   307     renderer->SetTextureScaleMode = GL_SetTextureScaleMode;
   308     renderer->UpdateTexture = GL_UpdateTexture;
   309     renderer->LockTexture = GL_LockTexture;
   310     renderer->UnlockTexture = GL_UnlockTexture;
   311     renderer->DirtyTexture = GL_DirtyTexture;
   312     renderer->RenderClear = GL_RenderClear;
   313     renderer->RenderDrawPoints = GL_RenderDrawPoints;
   314     renderer->RenderDrawLines = GL_RenderDrawLines;
   315     renderer->RenderDrawRects = GL_RenderDrawRects;
   316     renderer->RenderFillRects = GL_RenderFillRects;
   317     renderer->RenderCopy = GL_RenderCopy;
   318     renderer->RenderReadPixels = GL_RenderReadPixels;
   319     renderer->RenderWritePixels = GL_RenderWritePixels;
   320     renderer->RenderPresent = GL_RenderPresent;
   321     renderer->DestroyTexture = GL_DestroyTexture;
   322     renderer->DestroyRenderer = GL_DestroyRenderer;
   323     renderer->info = GL_RenderDriver.info;
   324     renderer->window = window->id;
   325     renderer->driverdata = data;
   326 
   327     renderer->info.flags =
   328         (SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED);
   329 
   330     if (GL_LoadFunctions(data) < 0) {
   331         GL_DestroyRenderer(renderer);
   332         return NULL;
   333     }
   334 
   335     data->context = SDL_GL_CreateContext(window->id);
   336     if (!data->context) {
   337         GL_DestroyRenderer(renderer);
   338         return NULL;
   339     }
   340     if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
   341         GL_DestroyRenderer(renderer);
   342         return NULL;
   343     }
   344 #ifdef __MACOSX__
   345     /* Enable multi-threaded rendering */
   346     /* Disabled until Ryan finishes his VBO/PBO code...
   347        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
   348      */
   349 #endif
   350 
   351     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   352         SDL_GL_SetSwapInterval(1);
   353     } else {
   354         SDL_GL_SetSwapInterval(0);
   355     }
   356     if (SDL_GL_GetSwapInterval() > 0) {
   357         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   358     }
   359 
   360     if (SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &doublebuffer) == 0) {
   361         if (!doublebuffer) {
   362             renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER;
   363         }
   364     }
   365 
   366     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   367     renderer->info.max_texture_width = value;
   368     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   369     renderer->info.max_texture_height = value;
   370 
   371     if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
   372         || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
   373         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
   374     }
   375     if (SDL_GL_ExtensionSupported("GL_EXT_paletted_texture")) {
   376         data->GL_EXT_paletted_texture_supported = SDL_TRUE;
   377         data->glColorTableEXT =
   378             (PFNGLCOLORTABLEEXTPROC) SDL_GL_GetProcAddress("glColorTableEXT");
   379     } else {
   380         /* Don't advertise support for 8-bit indexed texture format */
   381         Uint32 i, j;
   382         SDL_RendererInfo *info = &renderer->info;
   383         for (i = 0, j = 0; i < info->num_texture_formats; ++i) {
   384             if (info->texture_formats[i] != SDL_PIXELFORMAT_INDEX8) {
   385                 info->texture_formats[j++] = info->texture_formats[i];
   386             }
   387         }
   388         --info->num_texture_formats;
   389     }
   390     if (SDL_GL_ExtensionSupported("GL_APPLE_ycbcr_422")) {
   391         data->GL_APPLE_ycbcr_422_supported = SDL_TRUE;
   392     }
   393     if (SDL_GL_ExtensionSupported("GL_MESA_ycbcr_texture")) {
   394         data->GL_MESA_ycbcr_texture_supported = SDL_TRUE;
   395     }
   396     if (SDL_GL_ExtensionSupported("GL_APPLE_texture_range")) {
   397         data->glTextureRangeAPPLE =
   398             (void (*)(GLenum, GLsizei, const GLvoid *))
   399             SDL_GL_GetProcAddress("glTextureRangeAPPLE");
   400     }
   401 
   402     /* we might use fragment programs for YUV data, etc. */
   403     if (SDL_GL_ExtensionSupported("GL_ARB_fragment_program")) {
   404         /* !!! FIXME: this doesn't check for errors. */
   405         /* !!! FIXME: this should really reuse the glfuncs.h stuff. */
   406         data->glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)
   407             SDL_GL_GetProcAddress("glGetProgramivARB");
   408         data->glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC)
   409             SDL_GL_GetProcAddress("glGetProgramStringARB");
   410         data->glProgramLocalParameter4fvARB =
   411             (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)
   412             SDL_GL_GetProcAddress("glProgramLocalParameter4fvARB");
   413         data->glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)
   414             SDL_GL_GetProcAddress("glDeleteProgramsARB");
   415         data->glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)
   416             SDL_GL_GetProcAddress("glGenProgramsARB");
   417         data->glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)
   418             SDL_GL_GetProcAddress("glBindProgramARB");
   419         data->glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)
   420             SDL_GL_GetProcAddress("glProgramStringARB");
   421         data->GL_ARB_fragment_program_supported = SDL_TRUE;
   422     }
   423 
   424     /* Set up parameters for rendering */
   425     data->blendMode = -1;
   426     data->scaleMode = -1;
   427     data->glDisable(GL_DEPTH_TEST);
   428     data->glDisable(GL_CULL_FACE);
   429     /* This ended up causing video discrepancies between OpenGL and Direct3D */
   430     /*data->glEnable(GL_LINE_SMOOTH);*/
   431     if (data->GL_ARB_texture_rectangle_supported) {
   432         data->glEnable(GL_TEXTURE_RECTANGLE_ARB);
   433     } else {
   434         data->glEnable(GL_TEXTURE_2D);
   435     }
   436     data->updateSize = SDL_TRUE;
   437 
   438     return renderer;
   439 }
   440 
   441 static int
   442 GL_ActivateRenderer(SDL_Renderer * renderer)
   443 {
   444     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   445     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   446 
   447     if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
   448         return -1;
   449     }
   450     if (data->updateSize) {
   451         data->glMatrixMode(GL_PROJECTION);
   452         data->glLoadIdentity();
   453         data->glMatrixMode(GL_MODELVIEW);
   454         data->glLoadIdentity();
   455         data->glViewport(0, 0, window->w, window->h);
   456         data->glOrtho(0.0, (GLdouble) window->w,
   457                       (GLdouble) window->h, 0.0, 0.0, 1.0);
   458         data->updateSize = SDL_FALSE;
   459     }
   460     return 0;
   461 }
   462 
   463 static int
   464 GL_DisplayModeChanged(SDL_Renderer * renderer)
   465 {
   466     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   467 
   468     /* Rebind the context to the window area and update matrices */
   469     data->updateSize = SDL_TRUE;
   470     return GL_ActivateRenderer(renderer);
   471 }
   472 
   473 static __inline__ int
   474 power_of_2(int input)
   475 {
   476     int value = 1;
   477 
   478     while (value < input) {
   479         value <<= 1;
   480     }
   481     return value;
   482 }
   483 
   484 
   485 //#define DEBUG_PROGRAM_COMPILE 1
   486 
   487 static void
   488 set_shader_error(GL_RenderData * data, const char *prefix)
   489 {
   490     GLint pos = 0;
   491     const GLubyte *errstr;
   492     data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
   493     errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB);
   494     SDL_SetError("%s: shader compile error at position %d: %s",
   495            prefix, (int) pos, (const char *) errstr);
   496 }
   497 
   498 static GLuint
   499 compile_shader(GL_RenderData * data, GLenum shader_type, const char *_code)
   500 {
   501     const int have_texture_rects = data->GL_ARB_texture_rectangle_supported;
   502     const char *replacement = have_texture_rects ? "RECT" : "2D";
   503     const size_t replacementlen = SDL_strlen(replacement);
   504     const char *token = "%TEXTURETARGET%";
   505     const size_t tokenlen = SDL_strlen(token);
   506     char *code = NULL;
   507     char *ptr = NULL;
   508     GLuint program = 0;
   509 
   510     /*
   511      * The TEX instruction needs a different target depending on what we use.
   512      *  To handle this, we use "%TEXTURETARGET%" and replace the string before
   513      *  compiling the shader.
   514      */
   515     code = SDL_strdup(_code);
   516     if (code == NULL)
   517         return 0;
   518 
   519     for (ptr = SDL_strstr(code, token); ptr; ptr = SDL_strstr(ptr + 1, token)) {
   520         SDL_memcpy(ptr, replacement, replacementlen);
   521         SDL_memmove(ptr + replacementlen, ptr + tokenlen,
   522                     SDL_strlen(ptr + tokenlen) + 1);
   523     }
   524 
   525 #if DEBUG_PROGRAM_COMPILE
   526     printf("compiling shader:\n%s\n\n", code);
   527 #endif
   528 
   529     data->glGetError();         /* flush any existing error state. */
   530     data->glGenProgramsARB(1, &program);
   531     data->glBindProgramARB(shader_type, program);
   532     data->glProgramStringARB(shader_type, GL_PROGRAM_FORMAT_ASCII_ARB,
   533                              (GLsizei)SDL_strlen(code), code);
   534 
   535     SDL_free(code);
   536 
   537     if (data->glGetError() == GL_INVALID_OPERATION) {
   538 #if DEBUG_PROGRAM_COMPILE
   539         GLint pos = 0;
   540         const GLubyte *errstr;
   541         data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
   542         errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB);
   543         printf("program compile error at position %d: %s\n\n",
   544                (int) pos, (const char *) errstr);
   545 #endif
   546         data->glBindProgramARB(shader_type, 0);
   547         data->glDeleteProgramsARB(1, &program);
   548         return 0;
   549     }
   550 
   551     return program;
   552 }
   553 
   554 
   555 /*
   556  * Fragment program that implements mask semantics
   557  */
   558 static const char *fragment_program_mask_source_code = "!!ARBfp1.0\n"
   559 "OUTPUT output = result.color;\n"
   560 "TEMP value;\n"
   561 "TEX value, fragment.texcoord[0], texture[0], %TEXTURETARGET%;\n"
   562 "MUL value, fragment.color, value;\n"
   563 "SGE value.a, value.a, 0.001;\n"
   564 "MOV output, value;\n"
   565 "END";
   566 
   567 /*
   568  * Fragment program that renders from UYVY textures.
   569  * The UYVY to RGB equasion is:
   570  *   R = 1.164(Y-16) + 1.596(Cr-128)
   571  *   G = 1.164(Y-16) - 0.813(Cr-128) - 0.391(Cb-128)
   572  *   B = 1.164(Y-16) + 2.018(Cb-128)
   573  * Byte layout is Cb, Y1, Cr, Y2, stored in the R, G, B, A channels.
   574  * 4 bytes == 2 pixels: Y1/Cb/Cr, Y2/Cb/Cr
   575  *
   576  * !!! FIXME: this ignores blendmodes, etc.
   577  * !!! FIXME: this could be more efficient...use a dot product for green, etc.
   578  */
   579 static const char *fragment_program_UYVY_source_code = "!!ARBfp1.0\n"
   580     /* outputs... */
   581     "OUTPUT outcolor = result.color;\n"
   582     /* scratch registers... */
   583     "TEMP uyvy;\n" "TEMP luminance;\n" "TEMP work;\n"
   584     /* Halve the coordinates to grab the correct 32 bits for the fragment. */
   585     "MUL work, fragment.texcoord, { 0.5, 1.0, 1.0, 1.0 };\n"
   586     /* Sample the YUV texture. Cb, Y1, Cr, Y2, are stored in x, y, z, w. */
   587     "TEX uyvy, work, texture[0], %TEXTURETARGET%;\n"
   588     /* Do subtractions (128/255, 16/255, 128/255, 16/255) */
   589     "SUB uyvy, uyvy, { 0.501960784313726, 0.06274509803922, 0.501960784313726, 0.06274509803922 };\n"
   590     /* Choose the luminance component by texcoord. */
   591     /* !!! FIXME: laziness wins out for now... just average Y1 and Y2. */
   592     "ADD luminance, uyvy.yyyy, uyvy.wwww;\n"
   593     "MUL luminance, luminance, { 0.5, 0.5, 0.5, 0.5 };\n"
   594     /* Multiply luminance by its magic value. */
   595     "MUL luminance, luminance, { 1.164, 1.164, 1.164, 1.164 };\n"
   596     /* uyvy.xyzw becomes Cr/Cr/Cb/Cb, with multiplications. */
   597     "MUL uyvy, uyvy.zzxx, { 1.596, -0.813, 2.018, -0.391 };\n"
   598     /* Add luminance to Cr and Cb, store to RGB channels. */
   599     "ADD work.rgb, luminance, uyvy;\n"
   600     /* Do final addition for Green channel.  (!!! FIXME: this should be a DPH?) */
   601     "ADD work.g, work.g, uyvy.w;\n"
   602     /* Make sure alpha channel is fully opaque.  (!!! FIXME: blend modes!) */
   603     "MOV work.a, { 1.0 };\n"
   604     /* Store out the final fragment color... */
   605     "MOV outcolor, work;\n"
   606     /* ...and we're done! */
   607     "END\n";
   608 
   609 static __inline__ SDL_bool
   610 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
   611                GLint* internalFormat, GLenum* format, GLenum* type)
   612 {
   613     switch (pixel_format) {
   614     case SDL_PIXELFORMAT_INDEX1LSB:
   615     case SDL_PIXELFORMAT_INDEX1MSB:
   616         *internalFormat = GL_RGB;
   617         *format = GL_COLOR_INDEX;
   618         *type = GL_BITMAP;
   619         break;
   620     case SDL_PIXELFORMAT_INDEX8:
   621         if (!renderdata->GL_EXT_paletted_texture_supported) {
   622             return SDL_FALSE;
   623         }
   624         *internalFormat = GL_COLOR_INDEX8_EXT;
   625         *format = GL_COLOR_INDEX;
   626         *type = GL_UNSIGNED_BYTE;
   627         break;
   628     case SDL_PIXELFORMAT_RGB332:
   629         *internalFormat = GL_R3_G3_B2;
   630         *format = GL_RGB;
   631         *type = GL_UNSIGNED_BYTE_3_3_2;
   632         break;
   633     case SDL_PIXELFORMAT_RGB444:
   634         *internalFormat = GL_RGB4;
   635         *format = GL_RGB;
   636         *type = GL_UNSIGNED_SHORT_4_4_4_4;
   637         break;
   638     case SDL_PIXELFORMAT_RGB555:
   639         *internalFormat = GL_RGB5;
   640         *format = GL_RGB;
   641         *type = GL_UNSIGNED_SHORT_5_5_5_1;
   642         break;
   643     case SDL_PIXELFORMAT_ARGB4444:
   644         *internalFormat = GL_RGBA4;
   645         *format = GL_BGRA;
   646         *type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
   647         break;
   648     case SDL_PIXELFORMAT_ARGB1555:
   649         *internalFormat = GL_RGB5_A1;
   650         *format = GL_BGRA;
   651         *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
   652         break;
   653     case SDL_PIXELFORMAT_RGB565:
   654         *internalFormat = GL_RGB8;
   655         *format = GL_RGB;
   656         *type = GL_UNSIGNED_SHORT_5_6_5;
   657         break;
   658     case SDL_PIXELFORMAT_RGB24:
   659         *internalFormat = GL_RGB8;
   660         *format = GL_RGB;
   661         *type = GL_UNSIGNED_BYTE;
   662         break;
   663     case SDL_PIXELFORMAT_RGB888:
   664         *internalFormat = GL_RGB8;
   665         *format = GL_BGRA;
   666         *type = GL_UNSIGNED_BYTE;
   667         break;
   668     case SDL_PIXELFORMAT_BGR24:
   669         *internalFormat = GL_RGB8;
   670         *format = GL_BGR;
   671         *type = GL_UNSIGNED_BYTE;
   672         break;
   673     case SDL_PIXELFORMAT_BGR888:
   674         *internalFormat = GL_RGB8;
   675         *format = GL_RGBA;
   676         *type = GL_UNSIGNED_BYTE;
   677         break;
   678     case SDL_PIXELFORMAT_ARGB8888:
   679 #ifdef __MACOSX__
   680         *internalFormat = GL_RGBA;
   681         *format = GL_BGRA;
   682         *type = GL_UNSIGNED_INT_8_8_8_8_REV;
   683 #else
   684         *internalFormat = GL_RGBA8;
   685         *format = GL_BGRA;
   686         *type = GL_UNSIGNED_BYTE;
   687 #endif
   688         break;
   689     case SDL_PIXELFORMAT_ABGR8888:
   690         *internalFormat = GL_RGBA8;
   691         *format = GL_RGBA;
   692         *type = GL_UNSIGNED_BYTE;
   693         break;
   694     case SDL_PIXELFORMAT_ARGB2101010:
   695         *internalFormat = GL_RGB10_A2;
   696         *format = GL_BGRA;
   697         *type = GL_UNSIGNED_INT_2_10_10_10_REV;
   698         break;
   699     case SDL_PIXELFORMAT_UYVY:
   700         if (renderdata->GL_APPLE_ycbcr_422_supported) {
   701             *internalFormat = GL_RGB;
   702             *format = GL_YCBCR_422_APPLE;
   703 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   704             *type = GL_UNSIGNED_SHORT_8_8_APPLE;
   705 #else
   706             *type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
   707 #endif
   708         } else if (renderdata->GL_MESA_ycbcr_texture_supported) {
   709             *internalFormat = GL_YCBCR_MESA;
   710             *format = GL_YCBCR_MESA;
   711 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   712             *type = GL_UNSIGNED_SHORT_8_8_MESA;
   713 #else
   714             *type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
   715 #endif
   716         } else if (renderdata->GL_ARB_fragment_program_supported) {
   717             *internalFormat = GL_RGBA;
   718             *format = GL_RGBA;
   719             *type = GL_UNSIGNED_BYTE;
   720         } else {
   721             return SDL_FALSE;
   722         }
   723         break;
   724     case SDL_PIXELFORMAT_YUY2:
   725         if (renderdata->GL_APPLE_ycbcr_422_supported) {
   726             *internalFormat = GL_RGB;
   727             *format = GL_YCBCR_422_APPLE;
   728 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   729             *type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
   730 #else
   731             *type = GL_UNSIGNED_SHORT_8_8_APPLE;
   732 #endif
   733         } else if (renderdata->GL_MESA_ycbcr_texture_supported) {
   734             *internalFormat = GL_YCBCR_MESA;
   735             *format = GL_YCBCR_MESA;
   736 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   737             *type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
   738 #else
   739             *type = GL_UNSIGNED_SHORT_8_8_MESA;
   740 #endif
   741         } else {
   742             return SDL_FALSE;
   743         }
   744         break;
   745     default:
   746         return SDL_FALSE;
   747     }
   748     return SDL_TRUE;
   749 }
   750 
   751 static int
   752 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   753 {
   754     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   755     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   756     GL_TextureData *data;
   757     GLint internalFormat;
   758     GLenum format, type;
   759     int texture_w, texture_h;
   760     GLuint shader = 0;
   761     GLenum result;
   762 
   763     if (!convert_format(renderdata, texture->format, &internalFormat,
   764                         &format, &type)) {
   765         SDL_SetError("Unsupported texture format");
   766         return -1;
   767     }
   768     if (texture->format == SDL_PIXELFORMAT_UYVY &&
   769         !renderdata->GL_APPLE_ycbcr_422_supported &&
   770         !renderdata->GL_MESA_ycbcr_texture_supported &&
   771         renderdata->GL_ARB_fragment_program_supported) {
   772         if (renderdata->fragment_program_UYVY == 0) {
   773             renderdata->fragment_program_UYVY =
   774                 compile_shader(renderdata, GL_FRAGMENT_PROGRAM_ARB,
   775                                fragment_program_UYVY_source_code);
   776             if (renderdata->fragment_program_UYVY == 0) {
   777                 set_shader_error(renderdata, "UYVY");
   778                 return -1;
   779             }
   780         }
   781         shader = renderdata->fragment_program_UYVY;
   782     }
   783 
   784     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   785     if (!data) {
   786         SDL_OutOfMemory();
   787         return -1;
   788     }
   789 
   790     data->shader = shader;
   791 
   792     if (texture->format == SDL_PIXELFORMAT_INDEX8) {
   793         data->palette = (Uint8 *) SDL_malloc(3 * 256 * sizeof(Uint8));
   794         if (!data->palette) {
   795             SDL_OutOfMemory();
   796             SDL_free(data);
   797             return -1;
   798         }
   799         SDL_memset(data->palette, 0xFF, 3 * 256 * sizeof(Uint8));
   800     }
   801 
   802     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   803         data->pitch = texture->w * bytes_per_pixel(texture->format);
   804         data->pixels = SDL_malloc(texture->h * data->pitch);
   805         if (!data->pixels) {
   806             SDL_OutOfMemory();
   807             SDL_free(data);
   808             return -1;
   809         }
   810     }
   811 
   812     texture->driverdata = data;
   813 
   814     renderdata->glGetError();
   815     renderdata->glGenTextures(1, &data->texture);
   816     if (renderdata->GL_ARB_texture_rectangle_supported) {
   817         data->type = GL_TEXTURE_RECTANGLE_ARB;
   818         texture_w = texture->w;
   819         texture_h = texture->h;
   820         data->texw = (GLfloat) texture_w;
   821         data->texh = (GLfloat) texture_h;
   822     } else {
   823         data->type = GL_TEXTURE_2D;
   824         texture_w = power_of_2(texture->w);
   825         texture_h = power_of_2(texture->h);
   826         data->texw = (GLfloat) (texture->w) / texture_w;
   827         data->texh = (GLfloat) texture->h / texture_h;
   828     }
   829 
   830     /* YUV formats use RGBA but are really two bytes per pixel */
   831     if (internalFormat == GL_RGBA && bytes_per_pixel(texture->format) < 4) {
   832         data->HACK_RYAN_FIXME = 2;
   833     } else {
   834         data->HACK_RYAN_FIXME = 1;
   835     }
   836     texture_w /= data->HACK_RYAN_FIXME;
   837 
   838     data->format = format;
   839     data->formattype = type;
   840     renderdata->glEnable(data->type);
   841     renderdata->glBindTexture(data->type, data->texture);
   842     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   843                                 GL_NEAREST);
   844     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   845                                 GL_NEAREST);
   846     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   847                                 GL_CLAMP_TO_EDGE);
   848     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   849                                 GL_CLAMP_TO_EDGE);
   850 #ifdef __MACOSX__
   851 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
   852 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
   853 #endif
   854 #ifndef STORAGE_CACHED_APPLE
   855 #define STORAGE_CACHED_APPLE                0x85BE
   856 #endif
   857 #ifndef STORAGE_SHARED_APPLE
   858 #define STORAGE_SHARED_APPLE                0x85BF
   859 #endif
   860     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   861         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   862                                     GL_STORAGE_SHARED_APPLE);
   863     } else {
   864         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   865                                     GL_STORAGE_CACHED_APPLE);
   866     }
   867 /* This causes a crash in testoverlay for some reason.  Apple bug? */
   868 #if 0
   869     if (texture->access == SDL_TEXTUREACCESS_STREAMING
   870         && texture->format == SDL_PIXELFORMAT_ARGB8888) {
   871         /*
   872            if (renderdata->glTextureRangeAPPLE) {
   873            renderdata->glTextureRangeAPPLE(data->type,
   874            texture->h * data->pitch,
   875            data->pixels);
   876            }
   877          */
   878         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
   879         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   880                                  texture_h, 0, format, type, data->pixels);
   881     } else
   882 #endif
   883 #endif
   884     {
   885         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   886                                  texture_h, 0, format, type, NULL);
   887     }
   888     renderdata->glDisable(data->type);
   889     result = renderdata->glGetError();
   890     if (result != GL_NO_ERROR) {
   891         GL_SetError("glTexImage2D()", result);
   892         return -1;
   893     }
   894     return 0;
   895 }
   896 
   897 static int
   898 GL_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   899                       void **pixels, int *pitch)
   900 {
   901     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   902 
   903     *pixels = data->pixels;
   904     *pitch = data->pitch;
   905     return 0;
   906 }
   907 
   908 static int
   909 GL_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   910                      const SDL_Color * colors, int firstcolor, int ncolors)
   911 {
   912     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   913     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   914     Uint8 *palette;
   915 
   916     if (!data->palette) {
   917         SDL_SetError("Texture doesn't have a palette");
   918         return -1;
   919     }
   920     palette = data->palette + firstcolor * 3;
   921     while (ncolors--) {
   922         *palette++ = colors->r;
   923         *palette++ = colors->g;
   924         *palette++ = colors->b;
   925         ++colors;
   926     }
   927     renderdata->glEnable(data->type);
   928     renderdata->glBindTexture(data->type, data->texture);
   929     renderdata->glColorTableEXT(data->type, GL_RGB8, 256, GL_RGB,
   930                                 GL_UNSIGNED_BYTE, data->palette);
   931     return 0;
   932 }
   933 
   934 static int
   935 GL_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   936                      SDL_Color * colors, int firstcolor, int ncolors)
   937 {
   938     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   939     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   940     Uint8 *palette;
   941 
   942     if (!data->palette) {
   943         SDL_SetError("Texture doesn't have a palette");
   944         return -1;
   945     }
   946     palette = data->palette + firstcolor * 3;
   947     while (ncolors--) {
   948         colors->r = *palette++;
   949         colors->g = *palette++;
   950         colors->b = *palette++;
   951         colors->unused = SDL_ALPHA_OPAQUE;
   952         ++colors;
   953     }
   954     return 0;
   955 }
   956 
   957 static void
   958 SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture,
   959                    int pitch)
   960 {
   961     if (texture->format == SDL_PIXELFORMAT_INDEX1LSB) {
   962         renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
   963     } else if (texture->format == SDL_PIXELFORMAT_INDEX1MSB) {
   964         renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 0);
   965     }
   966     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   967     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   968                               (pitch / bytes_per_pixel(texture->format)) /
   969                               ((GL_TextureData *) texture->driverdata)->
   970                               HACK_RYAN_FIXME);
   971 }
   972 
   973 static int
   974 GL_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   975 {
   976     return 0;
   977 }
   978 
   979 static int
   980 GL_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   981 {
   982     return 0;
   983 }
   984 
   985 static int
   986 GL_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   987 {
   988     switch (texture->blendMode) {
   989     case SDL_BLENDMODE_NONE:
   990     case SDL_BLENDMODE_MASK:
   991     case SDL_BLENDMODE_BLEND:
   992     case SDL_BLENDMODE_ADD:
   993     case SDL_BLENDMODE_MOD:
   994         return 0;
   995     default:
   996         SDL_Unsupported();
   997         texture->blendMode = SDL_BLENDMODE_NONE;
   998         return -1;
   999     }
  1000 }
  1001 
  1002 static int
  1003 GL_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
  1004 {
  1005     switch (texture->scaleMode) {
  1006     case SDL_TEXTURESCALEMODE_NONE:
  1007     case SDL_TEXTURESCALEMODE_FAST:
  1008     case SDL_TEXTURESCALEMODE_SLOW:
  1009         return 0;
  1010     case SDL_TEXTURESCALEMODE_BEST:
  1011         SDL_Unsupported();
  1012         texture->scaleMode = SDL_TEXTURESCALEMODE_SLOW;
  1013         return -1;
  1014     default:
  1015         SDL_Unsupported();
  1016         texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
  1017         return -1;
  1018     }
  1019 }
  1020 
  1021 static int
  1022 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1023                  const SDL_Rect * rect, const void *pixels, int pitch)
  1024 {
  1025     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  1026     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1027     GLenum result;
  1028 
  1029     renderdata->glGetError();
  1030     SetupTextureUpdate(renderdata, texture, pitch);
  1031     renderdata->glEnable(data->type);
  1032     renderdata->glBindTexture(data->type, data->texture);
  1033     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
  1034                                 rect->h, data->format, data->formattype,
  1035                                 pixels);
  1036     renderdata->glDisable(data->type);
  1037     result = renderdata->glGetError();
  1038     if (result != GL_NO_ERROR) {
  1039         GL_SetError("glTexSubImage2D()", result);
  1040         return -1;
  1041     }
  1042     return 0;
  1043 }
  1044 
  1045 static int
  1046 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1047                const SDL_Rect * rect, int markDirty, void **pixels,
  1048                int *pitch)
  1049 {
  1050     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1051 
  1052     if (markDirty) {
  1053         SDL_AddDirtyRect(&data->dirty, rect);
  1054     }
  1055 
  1056     *pixels =
  1057         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
  1058                   rect->x * bytes_per_pixel(texture->format));
  1059     *pitch = data->pitch;
  1060     return 0;
  1061 }
  1062 
  1063 static void
  1064 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1065 {
  1066 }
  1067 
  1068 static void
  1069 GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
  1070                 const SDL_Rect * rects)
  1071 {
  1072     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1073     int i;
  1074 
  1075     for (i = 0; i < numrects; ++i) {
  1076         SDL_AddDirtyRect(&data->dirty, &rects[i]);
  1077     }
  1078 }
  1079 
  1080 static void
  1081 GL_SetBlendMode(GL_RenderData * data, int blendMode, int isprimitive)
  1082 {
  1083     if (blendMode != data->blendMode) {
  1084         switch (blendMode) {
  1085         case SDL_BLENDMODE_NONE:
  1086             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  1087             data->glDisable(GL_BLEND);
  1088             break;
  1089         case SDL_BLENDMODE_MASK:
  1090             if (isprimitive) {
  1091                 /* The same as SDL_BLENDMODE_NONE */
  1092                 blendMode = SDL_BLENDMODE_NONE;
  1093                 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  1094                 data->glDisable(GL_BLEND);
  1095             } else {
  1096                 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  1097                 data->glEnable(GL_BLEND);
  1098                 data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1099             }
  1100             break;
  1101         case SDL_BLENDMODE_BLEND:
  1102             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1103             data->glEnable(GL_BLEND);
  1104             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1105             break;
  1106         case SDL_BLENDMODE_ADD:
  1107             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1108             data->glEnable(GL_BLEND);
  1109             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  1110             break;
  1111         case SDL_BLENDMODE_MOD:
  1112             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1113             data->glEnable(GL_BLEND);
  1114             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
  1115             break;
  1116         }
  1117         data->blendMode = blendMode;
  1118     }
  1119 }
  1120 
  1121 static int
  1122 GL_RenderClear(SDL_Renderer * renderer)
  1123 {
  1124     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1125 
  1126     data->glClearColor((GLfloat) renderer->r * inv255f,
  1127                        (GLfloat) renderer->g * inv255f,
  1128                        (GLfloat) renderer->b * inv255f,
  1129                        (GLfloat) renderer->a * inv255f);
  1130 
  1131     data->glClear(GL_COLOR_BUFFER_BIT);
  1132 
  1133     return 0;
  1134 }
  1135 
  1136 static int
  1137 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
  1138                     int count)
  1139 {
  1140     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1141     int i;
  1142 
  1143     GL_SetBlendMode(data, renderer->blendMode, 1);
  1144 
  1145     data->glColor4f((GLfloat) renderer->r * inv255f,
  1146                     (GLfloat) renderer->g * inv255f,
  1147                     (GLfloat) renderer->b * inv255f,
  1148                     (GLfloat) renderer->a * inv255f);
  1149 
  1150     data->glBegin(GL_POINTS);
  1151     for (i = 0; i < count; ++i) {
  1152         data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
  1153     }
  1154     data->glEnd();
  1155 
  1156     return 0;
  1157 }
  1158 
  1159 static int
  1160 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
  1161                    int count)
  1162 {
  1163     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1164     int i;
  1165 
  1166     GL_SetBlendMode(data, renderer->blendMode, 1);
  1167 
  1168     data->glColor4f((GLfloat) renderer->r * inv255f,
  1169                     (GLfloat) renderer->g * inv255f,
  1170                     (GLfloat) renderer->b * inv255f,
  1171                     (GLfloat) renderer->a * inv255f);
  1172 
  1173     if (count > 2 && 
  1174         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
  1175         data->glBegin(GL_LINE_LOOP);
  1176         /* GL_LINE_LOOP takes care of the final segment */
  1177         --count;
  1178         for (i = 0; i < count; ++i) {
  1179             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
  1180         }
  1181         data->glEnd();
  1182     } else {
  1183         data->glBegin(GL_LINE_STRIP);
  1184         for (i = 0; i < count; ++i) {
  1185             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
  1186         }
  1187         data->glEnd();
  1188 
  1189         /* The line is half open, so we need one more point to complete it.
  1190          * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
  1191          * If we have to, we can use vertical line and horizontal line textures
  1192          * for vertical and horizontal lines, and then create custom textures
  1193          * for diagonal lines and software render those.  It's terrible, but at
  1194          * least it would be pixel perfect.
  1195          */
  1196         data->glBegin(GL_POINTS);
  1197 #if defined(__APPLE__) || defined(__WIN32__)
  1198         /* Mac OS X and Windows seem to always leave the second point open */
  1199         data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
  1200 #else
  1201         /* Linux seems to leave the right-most or bottom-most point open */
  1202         int x1 = points[0].x;
  1203         int y1 = points[0].y;
  1204         int x2 = points[count-1].x;
  1205         int y2 = points[count-1].y;
  1206 
  1207         if (x1 > x2) {
  1208             data->glVertex2f(0.5f + x1, 0.5f + y1);
  1209         } else if (x2 > x1) {
  1210             data->glVertex2f(0.5f + x2, 0.5f + y2);
  1211         } else if (y1 > y2) {
  1212             data->glVertex2f(0.5f + x1, 0.5f + y1);
  1213         } else if (y2 > y1) {
  1214             data->glVertex2f(0.5f + x2, 0.5f + y2);
  1215         }
  1216 #endif
  1217         data->glEnd();
  1218     }
  1219 
  1220     return 0;
  1221 }
  1222 
  1223 static int
  1224 GL_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
  1225 {
  1226     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1227     int i, x, y;
  1228 
  1229     GL_SetBlendMode(data, renderer->blendMode, 1);
  1230 
  1231     data->glColor4f((GLfloat) renderer->r * inv255f,
  1232                     (GLfloat) renderer->g * inv255f,
  1233                     (GLfloat) renderer->b * inv255f,
  1234                     (GLfloat) renderer->a * inv255f);
  1235 
  1236     data->glBegin(GL_LINE_LOOP);
  1237     for (i = 0; i < count; ++i) {
  1238         const SDL_Rect *rect = rects[i];
  1239 
  1240         x = rect->x;
  1241         y = rect->y;
  1242         data->glVertex2f(0.5f + x, 0.5f + y);
  1243 
  1244         x = rect->x+rect->w-1;
  1245         y = rect->y;
  1246         data->glVertex2f(0.5f + x, 0.5f + y);
  1247 
  1248         x = rect->x+rect->w-1;
  1249         y = rect->y+rect->h-1;
  1250         data->glVertex2f(0.5f + x, 0.5f + y);
  1251 
  1252         x = rect->x;
  1253         y = rect->y+rect->h-1;
  1254         data->glVertex2f(0.5f + x, 0.5f + y);
  1255     }
  1256     data->glEnd();
  1257 
  1258     return 0;
  1259 }
  1260 
  1261 static int
  1262 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
  1263 {
  1264     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1265     int i;
  1266 
  1267     GL_SetBlendMode(data, renderer->blendMode, 1);
  1268 
  1269     data->glColor4f((GLfloat) renderer->r * inv255f,
  1270                     (GLfloat) renderer->g * inv255f,
  1271                     (GLfloat) renderer->b * inv255f,
  1272                     (GLfloat) renderer->a * inv255f);
  1273 
  1274     for (i = 0; i < count; ++i) {
  1275         const SDL_Rect *rect = rects[i];
  1276 
  1277         data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
  1278     }
  1279 
  1280     return 0;
  1281 }
  1282 
  1283 static int
  1284 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1285               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
  1286 {
  1287     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1288     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1289     GLuint shader = 0;
  1290     int minx, miny, maxx, maxy;
  1291     GLfloat minu, maxu, minv, maxv;
  1292 
  1293     if (texturedata->dirty.list) {
  1294         SDL_DirtyRect *dirty;
  1295         void *pixels;
  1296         int bpp = bytes_per_pixel(texture->format);
  1297         int pitch = texturedata->pitch;
  1298 
  1299         SetupTextureUpdate(data, texture, pitch);
  1300         data->glEnable(texturedata->type);
  1301         data->glBindTexture(texturedata->type, texturedata->texture);
  1302         for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
  1303             SDL_Rect *rect = &dirty->rect;
  1304             pixels =
  1305                 (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch +
  1306                           rect->x * bpp);
  1307             data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y,
  1308                                   rect->w / texturedata->HACK_RYAN_FIXME,
  1309                                   rect->h, texturedata->format,
  1310                                   texturedata->formattype, pixels);
  1311         }
  1312         SDL_ClearDirtyRects(&texturedata->dirty);
  1313     }
  1314 
  1315     minx = dstrect->x;
  1316     miny = dstrect->y;
  1317     maxx = dstrect->x + dstrect->w;
  1318     maxy = dstrect->y + dstrect->h;
  1319 
  1320     minu = (GLfloat) srcrect->x / texture->w;
  1321     minu *= texturedata->texw;
  1322     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
  1323     maxu *= texturedata->texw;
  1324     minv = (GLfloat) srcrect->y / texture->h;
  1325     minv *= texturedata->texh;
  1326     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
  1327     maxv *= texturedata->texh;
  1328 
  1329     data->glEnable(texturedata->type);
  1330     data->glBindTexture(texturedata->type, texturedata->texture);
  1331 
  1332     if (texture->modMode) {
  1333         data->glColor4f((GLfloat) texture->r * inv255f,
  1334                         (GLfloat) texture->g * inv255f,
  1335                         (GLfloat) texture->b * inv255f,
  1336                         (GLfloat) texture->a * inv255f);
  1337     } else {
  1338         data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  1339     }
  1340 
  1341     GL_SetBlendMode(data, texture->blendMode, 0);
  1342 
  1343     /* Set up the shader for the copy, we have a special one for MASK */
  1344     shader = texturedata->shader;
  1345     if (texture->blendMode == SDL_BLENDMODE_MASK && !shader) {
  1346         if (data->fragment_program_mask == 0) {
  1347             data->fragment_program_mask =
  1348                 compile_shader(data, GL_FRAGMENT_PROGRAM_ARB,
  1349                                fragment_program_mask_source_code);
  1350             if (data->fragment_program_mask == 0) {
  1351                 /* That's okay, we'll just miss some of the blend semantics */
  1352                 data->fragment_program_mask = ~0;
  1353             }
  1354         }
  1355         if (data->fragment_program_mask != ~0) {
  1356             shader = data->fragment_program_mask;
  1357         }
  1358     }
  1359 
  1360     if (texture->scaleMode != data->scaleMode) {
  1361         switch (texture->scaleMode) {
  1362         case SDL_TEXTURESCALEMODE_NONE:
  1363         case SDL_TEXTURESCALEMODE_FAST:
  1364             data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
  1365                                   GL_NEAREST);
  1366             data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
  1367                                   GL_NEAREST);
  1368             break;
  1369         case SDL_TEXTURESCALEMODE_SLOW:
  1370         case SDL_TEXTURESCALEMODE_BEST:
  1371             data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
  1372                                   GL_LINEAR);
  1373             data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
  1374                                   GL_LINEAR);
  1375             break;
  1376         }
  1377         data->scaleMode = texture->scaleMode;
  1378     }
  1379 
  1380     if (shader) {
  1381         data->glEnable(GL_FRAGMENT_PROGRAM_ARB);
  1382         data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader);
  1383     }
  1384 
  1385     data->glBegin(GL_TRIANGLE_STRIP);
  1386     data->glTexCoord2f(minu, minv);
  1387     data->glVertex2f((GLfloat) minx, (GLfloat) miny);
  1388     data->glTexCoord2f(maxu, minv);
  1389     data->glVertex2f((GLfloat) maxx, (GLfloat) miny);
  1390     data->glTexCoord2f(minu, maxv);
  1391     data->glVertex2f((GLfloat) minx, (GLfloat) maxy);
  1392     data->glTexCoord2f(maxu, maxv);
  1393     data->glVertex2f((GLfloat) maxx, (GLfloat) maxy);
  1394     data->glEnd();
  1395 
  1396     if (shader) {
  1397         data->glDisable(GL_FRAGMENT_PROGRAM_ARB);
  1398     }
  1399 
  1400     data->glDisable(texturedata->type);
  1401 
  1402     return 0;
  1403 }
  1404 
  1405 static int
  1406 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1407                     Uint32 pixel_format, void * pixels, int pitch)
  1408 {
  1409     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1410     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
  1411     GLint internalFormat;
  1412     GLenum format, type;
  1413     Uint8 *src, *dst, *tmp;
  1414     int length, rows;
  1415 
  1416     if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) {
  1417         /* FIXME: Do a temp copy to a format that is supported */
  1418         SDL_SetError("Unsupported pixel format");
  1419         return -1;
  1420     }
  1421 
  1422     if (pixel_format == SDL_PIXELFORMAT_INDEX1LSB) {
  1423         data->glPixelStorei(GL_PACK_LSB_FIRST, 1);
  1424     } else if (pixel_format == SDL_PIXELFORMAT_INDEX1MSB) {
  1425         data->glPixelStorei(GL_PACK_LSB_FIRST, 0);
  1426     }
  1427     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
  1428     data->glPixelStorei(GL_PACK_ROW_LENGTH,
  1429                         (pitch / bytes_per_pixel(pixel_format)));
  1430 
  1431     data->glReadPixels(rect->x, (window->h-rect->y)-rect->h, rect->w, rect->h,
  1432                        format, type, pixels);
  1433 
  1434     /* Flip the rows to be top-down */
  1435     length = rect->w * bytes_per_pixel(pixel_format);
  1436     src = (Uint8*)pixels + (rect->h-1)*pitch;
  1437     dst = (Uint8*)pixels;
  1438     tmp = SDL_stack_alloc(Uint8, length);
  1439     rows = rect->h / 2;
  1440     while (rows--) {
  1441         SDL_memcpy(tmp, dst, length);
  1442         SDL_memcpy(dst, src, length);
  1443         SDL_memcpy(src, tmp, length);
  1444         dst += pitch;
  1445         src -= pitch;
  1446     }
  1447     SDL_stack_free(tmp);
  1448 
  1449     return 0;
  1450 }
  1451 
  1452 static int
  1453 GL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1454                      Uint32 pixel_format, const void * pixels, int pitch)
  1455 {
  1456     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1457     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
  1458     GLint internalFormat;
  1459     GLenum format, type;
  1460     Uint8 *src, *dst, *tmp;
  1461     int length, rows;
  1462 
  1463     if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) {
  1464         /* FIXME: Do a temp copy to a format that is supported */
  1465         SDL_SetError("Unsupported pixel format");
  1466         return -1;
  1467     }
  1468 
  1469     if (pixel_format == SDL_PIXELFORMAT_INDEX1LSB) {
  1470         data->glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
  1471     } else if (pixel_format == SDL_PIXELFORMAT_INDEX1MSB) {
  1472         data->glPixelStorei(GL_UNPACK_LSB_FIRST, 0);
  1473     }
  1474     data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  1475     data->glPixelStorei(GL_UNPACK_ROW_LENGTH,
  1476                         (pitch / bytes_per_pixel(pixel_format)));
  1477 
  1478     /* Flip the rows to be bottom-up */
  1479     length = rect->h * rect->w * pitch;
  1480     tmp = SDL_stack_alloc(Uint8, length);
  1481     src = (Uint8*)pixels + (rect->h-1)*pitch;
  1482     dst = (Uint8*)tmp;
  1483     rows = rect->h;
  1484     while (rows--) {
  1485         SDL_memcpy(dst, src, pitch);
  1486         dst += pitch;
  1487         src -= pitch;
  1488     }
  1489 
  1490     data->glRasterPos2i(rect->x, (window->h-rect->y));
  1491     data->glDrawPixels(rect->w, rect->h, format, type, tmp);
  1492     SDL_stack_free(tmp);
  1493 
  1494     return 0;
  1495 }
  1496 
  1497 static void
  1498 GL_RenderPresent(SDL_Renderer * renderer)
  1499 {
  1500     SDL_GL_SwapWindow(renderer->window);
  1501 }
  1502 
  1503 static void
  1504 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1505 {
  1506     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  1507     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1508 
  1509     if (!data) {
  1510         return;
  1511     }
  1512     if (data->texture) {
  1513         renderdata->glDeleteTextures(1, &data->texture);
  1514     }
  1515     if (data->palette) {
  1516         SDL_free(data->palette);
  1517     }
  1518     if (data->pixels) {
  1519         SDL_free(data->pixels);
  1520     }
  1521     SDL_FreeDirtyRects(&data->dirty);
  1522     SDL_free(data);
  1523     texture->driverdata = NULL;
  1524 }
  1525 
  1526 static void
  1527 GL_DestroyRenderer(SDL_Renderer * renderer)
  1528 {
  1529     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1530 
  1531     if (data) {
  1532         if (data->context) {
  1533             if (data->GL_ARB_fragment_program_supported) {
  1534                 data->glDisable(GL_FRAGMENT_PROGRAM_ARB);
  1535                 data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
  1536                 if (data->fragment_program_mask &&
  1537                     data->fragment_program_mask != ~0) {
  1538                     data->glDeleteProgramsARB(1,
  1539                                               &data->fragment_program_mask);
  1540                 }
  1541                 if (data->fragment_program_UYVY &&
  1542                     data->fragment_program_UYVY != ~0) {
  1543                     data->glDeleteProgramsARB(1,
  1544                                               &data->fragment_program_UYVY);
  1545                 }
  1546             }
  1547 
  1548             /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
  1549             SDL_GL_DeleteContext(data->context);
  1550         }
  1551         SDL_free(data);
  1552     }
  1553     SDL_free(renderer);
  1554 }
  1555 
  1556 #endif /* SDL_VIDEO_RENDER_OGL */
  1557 
  1558 /* vi: set ts=4 sw=4 expandtab: */