src/video/SDL_renderer_gles.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 14 Jul 2010 07:31:35 -0700
changeset 4525 3abf0b9cafad
parent 3697 f7b03b6838cb
child 4929 aa8888658021
permissions -rw-r--r--
pelya 2010-07-12 03:53:48 PDT

In function GLES_RenderCopy() in SDL_renderer_gles.c:819 there is one memcpy()
that can be avoided if we're updating whole texture.
Because of that the SDL 1.3 in compatibility mode is working even slower than
software rendering in SDL 1.2.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 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_ES
    25 
    26 #include "SDL_video.h"
    27 #include "SDL_opengles.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 #if defined(__QNXNTO__)
    34 /* Include QNX system header to check QNX version later */
    35 #include <sys/neutrino.h>
    36 #endif /* __QNXNTO__ */
    37 
    38 #if defined(SDL_VIDEO_DRIVER_QNXGF)  ||  \
    39     defined(SDL_VIDEO_DRIVER_PHOTON) ||  \
    40     defined(SDL_VIDEO_DRIVER_PANDORA)
    41 
    42 /* Empty function stub to get OpenGL ES 1.x support without  */
    43 /* OpenGL ES extension GL_OES_draw_texture supported         */
    44 GL_API void GL_APIENTRY
    45 glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height)
    46 {
    47     return;
    48 }
    49 
    50 #endif /* QNXGF || PHOTON || PANDORA */
    51 
    52 /* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */
    53 
    54 static const float inv255f = 1.0f / 255.0f;
    55 
    56 static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags);
    57 static int GLES_ActivateRenderer(SDL_Renderer * renderer);
    58 static int GLES_DisplayModeChanged(SDL_Renderer * renderer);
    59 static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    60 static int GLES_QueryTexturePixels(SDL_Renderer * renderer,
    61                                    SDL_Texture * texture, void **pixels,
    62                                    int *pitch);
    63 static int GLES_SetTexturePalette(SDL_Renderer * renderer,
    64                                   SDL_Texture * texture,
    65                                   const SDL_Color * colors, int firstcolor,
    66                                   int ncolors);
    67 static int GLES_GetTexturePalette(SDL_Renderer * renderer,
    68                                   SDL_Texture * texture, SDL_Color * colors,
    69                                   int firstcolor, int ncolors);
    70 static int GLES_SetTextureColorMod(SDL_Renderer * renderer,
    71                                    SDL_Texture * texture);
    72 static int GLES_SetTextureAlphaMod(SDL_Renderer * renderer,
    73                                    SDL_Texture * texture);
    74 static int GLES_SetTextureBlendMode(SDL_Renderer * renderer,
    75                                     SDL_Texture * texture);
    76 static int GLES_SetTextureScaleMode(SDL_Renderer * renderer,
    77                                     SDL_Texture * texture);
    78 static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    79                               const SDL_Rect * rect, const void *pixels,
    80                               int pitch);
    81 static int GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    82                             const SDL_Rect * rect, int markDirty,
    83                             void **pixels, int *pitch);
    84 static void GLES_UnlockTexture(SDL_Renderer * renderer,
    85                                SDL_Texture * texture);
    86 static void GLES_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    87                               int numrects, const SDL_Rect * rects);
    88 static int GLES_RenderDrawPoints(SDL_Renderer * renderer,
    89                                  const SDL_Point * points, int count);
    90 static int GLES_RenderDrawLines(SDL_Renderer * renderer,
    91                                 const SDL_Point * points, int count);
    92 static int GLES_RenderDrawRects(SDL_Renderer * renderer,
    93                                 const SDL_Rect ** rects, int count);
    94 static int GLES_RenderFillRects(SDL_Renderer * renderer,
    95                                 const SDL_Rect ** rects, int count);
    96 static int GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    97                            const SDL_Rect * srcrect,
    98                            const SDL_Rect * dstrect);
    99 static void GLES_RenderPresent(SDL_Renderer * renderer);
   100 static void GLES_DestroyTexture(SDL_Renderer * renderer,
   101                                 SDL_Texture * texture);
   102 static void GLES_DestroyRenderer(SDL_Renderer * renderer);
   103 
   104 
   105 SDL_RenderDriver GL_ES_RenderDriver = {
   106     GLES_CreateRenderer,
   107     {
   108      "opengl_es",
   109      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD |
   110       SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
   111      (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
   112       SDL_TEXTUREMODULATE_ALPHA),
   113      (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK |
   114       SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD),
   115      (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST |
   116       SDL_TEXTURESCALEMODE_SLOW), 5,
   117      {
   118       /* OpenGL ES 1.x supported formats list */
   119       SDL_PIXELFORMAT_ABGR4444,
   120       SDL_PIXELFORMAT_ABGR1555,
   121       SDL_PIXELFORMAT_BGR565,
   122       SDL_PIXELFORMAT_BGR24,
   123       SDL_PIXELFORMAT_ABGR8888},
   124      0,
   125      0}
   126 };
   127 
   128 typedef struct
   129 {
   130     SDL_GLContext context;
   131     SDL_bool updateSize;
   132     int blendMode;
   133 
   134 #ifndef APIENTRY
   135 #define APIENTRY
   136 #endif
   137 
   138     SDL_bool useDrawTexture;
   139     SDL_bool GL_OES_draw_texture_supported;
   140 
   141     /* OpenGL ES functions */
   142 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
   143 #include "SDL_glesfuncs.h"
   144 #undef SDL_PROC
   145 
   146 } GLES_RenderData;
   147 
   148 typedef struct
   149 {
   150     GLuint texture;
   151     GLenum type;
   152     GLfloat texw;
   153     GLfloat texh;
   154     GLenum format;
   155     GLenum formattype;
   156     void *pixels;
   157     int pitch;
   158     SDL_DirtyRectList dirty;
   159 } GLES_TextureData;
   160 
   161 static void
   162 GLES_SetError(const char *prefix, GLenum result)
   163 {
   164     const char *error;
   165 
   166     switch (result) {
   167     case GL_NO_ERROR:
   168         error = "GL_NO_ERROR";
   169         break;
   170     case GL_INVALID_ENUM:
   171         error = "GL_INVALID_ENUM";
   172         break;
   173     case GL_INVALID_VALUE:
   174         error = "GL_INVALID_VALUE";
   175         break;
   176     case GL_INVALID_OPERATION:
   177         error = "GL_INVALID_OPERATION";
   178         break;
   179     case GL_STACK_OVERFLOW:
   180         error = "GL_STACK_OVERFLOW";
   181         break;
   182     case GL_STACK_UNDERFLOW:
   183         error = "GL_STACK_UNDERFLOW";
   184         break;
   185     case GL_OUT_OF_MEMORY:
   186         error = "GL_OUT_OF_MEMORY";
   187         break;
   188     default:
   189         error = "UNKNOWN";
   190         break;
   191     }
   192     SDL_SetError("%s: %s", prefix, error);
   193 }
   194 
   195 static int
   196 GLES_LoadFunctions(GLES_RenderData * data)
   197 {
   198 
   199 #define SDL_PROC(ret,func,params) \
   200     data->func = func;
   201 #include "SDL_glesfuncs.h"
   202 #undef SDL_PROC
   203 
   204     return 0;
   205 }
   206 
   207 SDL_Renderer *
   208 GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
   209 {
   210 
   211     SDL_Renderer *renderer;
   212     GLES_RenderData *data;
   213     GLint value;
   214     int doublebuffer;
   215 
   216     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   217         if (SDL_RecreateWindow(window, window->flags | SDL_WINDOW_OPENGL) < 0) {
   218             return NULL;
   219         }
   220     }
   221 
   222     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   223     if (!renderer) {
   224         SDL_OutOfMemory();
   225         return NULL;
   226     }
   227 
   228     data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data));
   229     if (!data) {
   230         GLES_DestroyRenderer(renderer);
   231         SDL_OutOfMemory();
   232         return NULL;
   233     }
   234 
   235     renderer->ActivateRenderer = GLES_ActivateRenderer;
   236     renderer->DisplayModeChanged = GLES_DisplayModeChanged;
   237     renderer->CreateTexture = GLES_CreateTexture;
   238     renderer->QueryTexturePixels = GLES_QueryTexturePixels;
   239     renderer->SetTexturePalette = GLES_SetTexturePalette;
   240     renderer->GetTexturePalette = GLES_GetTexturePalette;
   241     renderer->SetTextureColorMod = GLES_SetTextureColorMod;
   242     renderer->SetTextureAlphaMod = GLES_SetTextureAlphaMod;
   243     renderer->SetTextureBlendMode = GLES_SetTextureBlendMode;
   244     renderer->SetTextureScaleMode = GLES_SetTextureScaleMode;
   245     renderer->UpdateTexture = GLES_UpdateTexture;
   246     renderer->LockTexture = GLES_LockTexture;
   247     renderer->UnlockTexture = GLES_UnlockTexture;
   248     renderer->DirtyTexture = GLES_DirtyTexture;
   249     renderer->RenderDrawPoints = GLES_RenderDrawPoints;
   250     renderer->RenderDrawLines = GLES_RenderDrawLines;
   251     renderer->RenderDrawRects = GLES_RenderDrawRects;
   252     renderer->RenderFillRects = GLES_RenderFillRects;
   253     renderer->RenderCopy = GLES_RenderCopy;
   254     renderer->RenderPresent = GLES_RenderPresent;
   255     renderer->DestroyTexture = GLES_DestroyTexture;
   256     renderer->DestroyRenderer = GLES_DestroyRenderer;
   257     renderer->info = GL_ES_RenderDriver.info;
   258     renderer->window = window;
   259     renderer->driverdata = data;
   260 
   261     renderer->info.flags =
   262         (SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED);
   263 
   264 #if defined(__QNXNTO__)
   265 #if _NTO_VERSION<=641
   266     /* QNX's OpenGL ES implementation is broken regarding             */
   267     /* packed textures support, affected versions 6.3.2, 6.4.0, 6.4.1 */
   268     renderer->info.num_texture_formats = 2;
   269     renderer->info.texture_formats[0] = SDL_PIXELFORMAT_ABGR8888;
   270     renderer->info.texture_formats[1] = SDL_PIXELFORMAT_BGR24;
   271 #endif /* _NTO_VERSION */
   272 #endif /* __QNXNTO__ */
   273 
   274     if (GLES_LoadFunctions(data) < 0) {
   275         GLES_DestroyRenderer(renderer);
   276         return NULL;
   277     }
   278 
   279     data->context = SDL_GL_CreateContext(window);
   280     if (!data->context) {
   281         GLES_DestroyRenderer(renderer);
   282         return NULL;
   283     }
   284     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   285         GLES_DestroyRenderer(renderer);
   286         return NULL;
   287     }
   288 
   289     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   290         SDL_GL_SetSwapInterval(1);
   291     } else {
   292         SDL_GL_SetSwapInterval(0);
   293     }
   294     if (SDL_GL_GetSwapInterval() > 0) {
   295         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   296     }
   297 
   298     if (SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &doublebuffer) == 0) {
   299         if (!doublebuffer) {
   300             renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER;
   301         }
   302     }
   303 #if SDL_VIDEO_DRIVER_PANDORA
   304     data->GL_OES_draw_texture_supported = SDL_FALSE;
   305     data->useDrawTexture = SDL_FALSE;
   306 #else
   307     if (SDL_GL_ExtensionSupported("GL_OES_draw_texture")) {
   308         data->GL_OES_draw_texture_supported = SDL_TRUE;
   309         data->useDrawTexture = SDL_TRUE;
   310     } else {
   311         data->GL_OES_draw_texture_supported = SDL_FALSE;
   312         data->useDrawTexture = SDL_FALSE;
   313     }
   314 #endif
   315 
   316     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   317     renderer->info.max_texture_width = value;
   318     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   319     renderer->info.max_texture_height = value;
   320 
   321     /* Set up parameters for rendering */
   322     data->blendMode = -1;
   323     data->glDisable(GL_DEPTH_TEST);
   324     data->glDisable(GL_CULL_FACE);
   325     data->updateSize = SDL_TRUE;
   326 
   327     return renderer;
   328 }
   329 
   330 static int
   331 GLES_ActivateRenderer(SDL_Renderer * renderer)
   332 {
   333 
   334     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   335     SDL_Window *window = renderer->window;
   336 
   337     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   338         return -1;
   339     }
   340     if (data->updateSize) {
   341         data->glMatrixMode(GL_PROJECTION);
   342         data->glLoadIdentity();
   343         data->glMatrixMode(GL_MODELVIEW);
   344         data->glLoadIdentity();
   345         data->glViewport(0, 0, window->w, window->h);
   346         data->glOrthof(0.0, (GLfloat) window->w, (GLfloat) window->h, 0.0,
   347                        0.0, 1.0);
   348         data->updateSize = SDL_FALSE;
   349     }
   350     return 0;
   351 }
   352 
   353 static int
   354 GLES_DisplayModeChanged(SDL_Renderer * renderer)
   355 {
   356     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   357 
   358     data->updateSize = SDL_TRUE;
   359     return 0;
   360 }
   361 
   362 static __inline__ int
   363 power_of_2(int input)
   364 {
   365     int value = 1;
   366 
   367     while (value < input) {
   368         value <<= 1;
   369     }
   370     return value;
   371 }
   372 
   373 static int
   374 GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   375 {
   376     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   377     GLES_TextureData *data;
   378     GLint internalFormat;
   379     GLenum format, type;
   380     int texture_w, texture_h;
   381     GLenum result;
   382 
   383     switch (texture->format) {
   384     case SDL_PIXELFORMAT_BGR24:
   385         internalFormat = GL_RGB;
   386         format = GL_RGB;
   387         type = GL_UNSIGNED_BYTE;
   388         break;
   389     case SDL_PIXELFORMAT_ABGR8888:
   390         internalFormat = GL_RGBA;
   391         format = GL_RGBA;
   392         type = GL_UNSIGNED_BYTE;
   393         break;
   394     case SDL_PIXELFORMAT_BGR565:
   395         internalFormat = GL_RGB;
   396         format = GL_RGB;
   397         type = GL_UNSIGNED_SHORT_5_6_5;
   398         break;
   399     case SDL_PIXELFORMAT_ABGR1555:
   400         internalFormat = GL_RGBA;
   401         format = GL_RGBA;
   402         type = GL_UNSIGNED_SHORT_5_5_5_1;
   403         break;
   404     case SDL_PIXELFORMAT_ABGR4444:
   405         internalFormat = GL_RGBA;
   406         format = GL_RGBA;
   407         type = GL_UNSIGNED_SHORT_4_4_4_4;
   408         break;
   409     default:
   410         SDL_SetError("Unsupported by OpenGL ES texture format");
   411         return -1;
   412     }
   413 
   414     data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data));
   415     if (!data) {
   416         SDL_OutOfMemory();
   417         return -1;
   418     }
   419 
   420     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   421         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   422         data->pixels = SDL_malloc(texture->h * data->pitch);
   423         if (!data->pixels) {
   424             SDL_OutOfMemory();
   425             SDL_free(data);
   426             return -1;
   427         }
   428     }
   429 
   430     texture->driverdata = data;
   431 
   432     renderdata->glGetError();
   433     renderdata->glEnable(GL_TEXTURE_2D);
   434     renderdata->glGenTextures(1, &data->texture);
   435 
   436     data->type = GL_TEXTURE_2D;
   437     /* no NPOV textures allowed in OpenGL ES (yet) */
   438     texture_w = power_of_2(texture->w);
   439     texture_h = power_of_2(texture->h);
   440     data->texw = (GLfloat) texture->w / texture_w;
   441     data->texh = (GLfloat) texture->h / texture_h;
   442 
   443     data->format = format;
   444     data->formattype = type;
   445     renderdata->glBindTexture(data->type, data->texture);
   446     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   447                                 GL_NEAREST);
   448     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   449                                 GL_NEAREST);
   450     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   451                                 GL_CLAMP_TO_EDGE);
   452     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   453                                 GL_CLAMP_TO_EDGE);
   454 
   455     renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   456                              texture_h, 0, format, type, NULL);
   457     renderdata->glDisable(GL_TEXTURE_2D);
   458 
   459     result = renderdata->glGetError();
   460     if (result != GL_NO_ERROR) {
   461         GLES_SetError("glTexImage2D()", result);
   462         return -1;
   463     }
   464     return 0;
   465 }
   466 
   467 static int
   468 GLES_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   469                         void **pixels, int *pitch)
   470 {
   471     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   472 
   473     *pixels = data->pixels;
   474     *pitch = data->pitch;
   475     return 0;
   476 }
   477 
   478 static int
   479 GLES_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   480                        const SDL_Color * colors, int firstcolor, int ncolors)
   481 {
   482     SDL_SetError("OpenGL ES does not support paletted textures");
   483     return -1;
   484 }
   485 
   486 static int
   487 GLES_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   488                        SDL_Color * colors, int firstcolor, int ncolors)
   489 {
   490     SDL_SetError("OpenGL ES does not support paletted textures");
   491     return -1;
   492 }
   493 
   494 static void
   495 SetupTextureUpdate(GLES_RenderData * renderdata, SDL_Texture * texture,
   496                    int pitch)
   497 {
   498     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   499     renderdata->glBindTexture(data->type, data->texture);
   500     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   501 }
   502 
   503 static int
   504 GLES_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   505 {
   506     return 0;
   507 }
   508 
   509 static int
   510 GLES_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   511 {
   512     return 0;
   513 }
   514 
   515 static int
   516 GLES_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   517 {
   518     switch (texture->blendMode) {
   519     case SDL_BLENDMODE_NONE:
   520     case SDL_BLENDMODE_MASK:
   521     case SDL_BLENDMODE_BLEND:
   522     case SDL_BLENDMODE_ADD:
   523     case SDL_BLENDMODE_MOD:
   524         return 0;
   525     default:
   526         SDL_Unsupported();
   527         texture->blendMode = SDL_BLENDMODE_NONE;
   528         return -1;
   529     }
   530 }
   531 
   532 static int
   533 GLES_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   534 {
   535     switch (texture->scaleMode) {
   536     case SDL_TEXTURESCALEMODE_NONE:
   537     case SDL_TEXTURESCALEMODE_FAST:
   538     case SDL_TEXTURESCALEMODE_SLOW:
   539         return 0;
   540     case SDL_TEXTURESCALEMODE_BEST:
   541         SDL_Unsupported();
   542         texture->scaleMode = SDL_TEXTURESCALEMODE_SLOW;
   543         return -1;
   544     default:
   545         SDL_Unsupported();
   546         texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
   547         return -1;
   548     }
   549 }
   550 
   551 static int
   552 GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   553                    const SDL_Rect * rect, const void *pixels, int pitch)
   554 {
   555     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   556     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   557     GLenum result;
   558 
   559     renderdata->glGetError();
   560     renderdata->glEnable(data->type);
   561     SetupTextureUpdate(renderdata, texture, pitch);
   562     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   563                                 rect->h, data->format, data->formattype,
   564                                 pixels);
   565     renderdata->glDisable(data->type);
   566     result = renderdata->glGetError();
   567     if (result != GL_NO_ERROR) {
   568         GLES_SetError("glTexSubImage2D()", result);
   569         return -1;
   570     }
   571     return 0;
   572 }
   573 
   574 static int
   575 GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   576                  const SDL_Rect * rect, int markDirty, void **pixels,
   577                  int *pitch)
   578 {
   579     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   580 
   581     if (markDirty) {
   582         SDL_AddDirtyRect(&data->dirty, rect);
   583     }
   584 
   585     *pixels =
   586         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   587                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   588     *pitch = data->pitch;
   589     return 0;
   590 }
   591 
   592 static void
   593 GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   594 {
   595 }
   596 
   597 static void
   598 GLES_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   599                   int numrects, const SDL_Rect * rects)
   600 {
   601     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   602     int i;
   603 
   604     for (i = 0; i < numrects; ++i) {
   605         SDL_AddDirtyRect(&data->dirty, &rects[i]);
   606     }
   607 }
   608 
   609 static void
   610 GLES_SetBlendMode(GLES_RenderData * data, int blendMode, int isprimitive)
   611 {
   612     if (blendMode != data->blendMode) {
   613         switch (blendMode) {
   614         case SDL_BLENDMODE_NONE:
   615             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   616             data->glDisable(GL_BLEND);
   617             break;
   618         case SDL_BLENDMODE_MASK:
   619             if (isprimitive) {
   620                 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   621                 data->glDisable(GL_BLEND);
   622                 /* The same as SDL_BLENDMODE_NONE */
   623                 blendMode = SDL_BLENDMODE_NONE;
   624                 break;
   625             }
   626             /* fall through */
   627         case SDL_BLENDMODE_BLEND:
   628             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   629             data->glEnable(GL_BLEND);
   630             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   631             break;
   632         case SDL_BLENDMODE_ADD:
   633             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   634             data->glEnable(GL_BLEND);
   635             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   636             break;
   637         case SDL_BLENDMODE_MOD:
   638             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   639             data->glEnable(GL_BLEND);
   640             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   641             break;
   642         }
   643         data->blendMode = blendMode;
   644     }
   645 }
   646 
   647 static int
   648 GLES_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   649                       int count)
   650 {
   651     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   652     int i;
   653     GLshort *vertices;
   654 
   655     GLES_SetBlendMode(data, renderer->blendMode, 1);
   656 
   657     data->glColor4f((GLfloat) renderer->r * inv255f,
   658                     (GLfloat) renderer->g * inv255f,
   659                     (GLfloat) renderer->b * inv255f,
   660                     (GLfloat) renderer->a * inv255f);
   661 
   662     vertices = SDL_stack_alloc(GLshort, count*2);
   663     for (i = 0; i < count; ++i) {
   664         vertices[2*i+0] = (GLshort)points[i].x;
   665         vertices[2*i+1] = (GLshort)points[i].y;
   666     }
   667     data->glVertexPointer(2, GL_SHORT, 0, vertices);
   668     data->glEnableClientState(GL_VERTEX_ARRAY);
   669     data->glDrawArrays(GL_POINTS, 0, count);
   670     data->glDisableClientState(GL_VERTEX_ARRAY);
   671     SDL_stack_free(vertices);
   672 
   673     return 0;
   674 }
   675 
   676 static int
   677 GLES_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   678                      int count)
   679 {
   680     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   681     int i;
   682     GLshort *vertices;
   683 
   684     GLES_SetBlendMode(data, renderer->blendMode, 1);
   685 
   686     data->glColor4f((GLfloat) renderer->r * inv255f,
   687                     (GLfloat) renderer->g * inv255f,
   688                     (GLfloat) renderer->b * inv255f,
   689                     (GLfloat) renderer->a * inv255f);
   690 
   691     vertices = SDL_stack_alloc(GLshort, count*2);
   692     for (i = 0; i < count; ++i) {
   693         vertices[2*i+0] = (GLshort)points[i].x;
   694         vertices[2*i+1] = (GLshort)points[i].y;
   695     }
   696     data->glVertexPointer(2, GL_SHORT, 0, vertices);
   697     data->glEnableClientState(GL_VERTEX_ARRAY);
   698     if (count > 2 && 
   699         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
   700         /* GL_LINE_LOOP takes care of the final segment */
   701         --count;
   702         data->glDrawArrays(GL_LINE_LOOP, 0, count);
   703     } else {
   704         data->glDrawArrays(GL_LINE_STRIP, 0, count);
   705     }
   706     data->glDisableClientState(GL_VERTEX_ARRAY);
   707     SDL_stack_free(vertices);
   708 
   709     return 0;
   710 }
   711 
   712 static int
   713 GLES_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
   714                      int count)
   715 {
   716     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   717     int i;
   718 
   719     GLES_SetBlendMode(data, renderer->blendMode, 1);
   720 
   721     data->glColor4f((GLfloat) renderer->r * inv255f,
   722                     (GLfloat) renderer->g * inv255f,
   723                     (GLfloat) renderer->b * inv255f,
   724                     (GLfloat) renderer->a * inv255f);
   725 
   726     data->glEnableClientState(GL_VERTEX_ARRAY);
   727     for (i = 0; i < count; ++i) {
   728         const SDL_Rect *rect = rects[i];
   729         GLshort minx = rect->x;
   730         GLshort maxx = rect->x + rect->w;
   731         GLshort miny = rect->y;
   732         GLshort maxy = rect->y + rect->h;
   733         GLshort vertices[8];
   734         vertices[0] = minx;
   735         vertices[1] = miny;
   736         vertices[2] = maxx;
   737         vertices[3] = miny;
   738         vertices[4] = minx;
   739         vertices[5] = maxy;
   740         vertices[6] = maxx;
   741         vertices[7] = maxy;
   742 
   743         data->glVertexPointer(2, GL_SHORT, 0, vertices);
   744         data->glDrawArrays(GL_LINE_LOOP, 0, 4);
   745     }
   746     data->glDisableClientState(GL_VERTEX_ARRAY);
   747 
   748     return 0;
   749 }
   750 
   751 static int
   752 GLES_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
   753                      int count)
   754 {
   755     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   756     int i;
   757 
   758     GLES_SetBlendMode(data, renderer->blendMode, 1);
   759 
   760     data->glColor4f((GLfloat) renderer->r * inv255f,
   761                     (GLfloat) renderer->g * inv255f,
   762                     (GLfloat) renderer->b * inv255f,
   763                     (GLfloat) renderer->a * inv255f);
   764 
   765     data->glEnableClientState(GL_VERTEX_ARRAY);
   766     for (i = 0; i < count; ++i) {
   767         const SDL_Rect *rect = rects[i];
   768         GLshort minx = rect->x;
   769         GLshort maxx = rect->x + rect->w;
   770         GLshort miny = rect->y;
   771         GLshort maxy = rect->y + rect->h;
   772         GLshort vertices[8];
   773         vertices[0] = minx;
   774         vertices[1] = miny;
   775         vertices[2] = maxx;
   776         vertices[3] = miny;
   777         vertices[4] = minx;
   778         vertices[5] = maxy;
   779         vertices[6] = maxx;
   780         vertices[7] = maxy;
   781 
   782         data->glVertexPointer(2, GL_SHORT, 0, vertices);
   783         data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   784     }
   785     data->glDisableClientState(GL_VERTEX_ARRAY);
   786 
   787     return 0;
   788 }
   789 
   790 static int
   791 GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   792                 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   793 {
   794 
   795     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   796     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   797     int minx, miny, maxx, maxy;
   798     GLfloat minu, maxu, minv, maxv;
   799     int i;
   800     void *temp_buffer;          /* used for reformatting dirty rect pixels */
   801     void *temp_ptr;
   802 
   803     data->glEnable(GL_TEXTURE_2D);
   804 
   805     if (texturedata->dirty.list) {
   806         SDL_DirtyRect *dirty;
   807         void *pixels;
   808         int bpp = SDL_BYTESPERPIXEL(texture->format);
   809         int pitch = texturedata->pitch;
   810 
   811         SetupTextureUpdate(data, texture, pitch);
   812 
   813         data->glBindTexture(texturedata->type, texturedata->texture);
   814         for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
   815             SDL_Rect *rect = &dirty->rect;
   816             pixels =
   817                 (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch +
   818                           rect->x * bpp);
   819             /*      There is no GL_UNPACK_ROW_LENGTH in OpenGLES 
   820                we must do this reformatting ourselves(!)
   821 
   822                maybe it'd be a good idea to keep a temp buffer around
   823                for this purpose rather than allocating it each time
   824              */
   825             if( rect->x == 0 && rect->w * bpp == pitch ) {
   826                 temp_buffer = pixels; /* Updating whole texture, no need to reformat */
   827             } else {
   828                 temp_buffer = SDL_malloc(rect->w * rect->h * bpp);
   829                 temp_ptr = temp_buffer;
   830                 for (i = 0; i < rect->h; i++) {
   831                     SDL_memcpy(temp_ptr, pixels, rect->w * bpp);
   832                     temp_ptr += rect->w * bpp;
   833                     pixels += pitch;
   834                 }
   835             }
   836 
   837             data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y,
   838                                   rect->w, rect->h, texturedata->format,
   839                                   texturedata->formattype, temp_buffer);
   840 
   841             if( temp_buffer != pixels ) {
   842                 SDL_free(temp_buffer);
   843             }
   844         }
   845         SDL_ClearDirtyRects(&texturedata->dirty);
   846     }
   847 
   848     data->glBindTexture(texturedata->type, texturedata->texture);
   849 
   850     if (texture->modMode) {
   851         data->glColor4f((GLfloat) texture->r * inv255f,
   852                         (GLfloat) texture->g * inv255f,
   853                         (GLfloat) texture->b * inv255f,
   854                         (GLfloat) texture->a * inv255f);
   855     } else {
   856         data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
   857     }
   858 
   859     GLES_SetBlendMode(data, texture->blendMode, 0);
   860 
   861     switch (texture->scaleMode) {
   862     case SDL_TEXTURESCALEMODE_NONE:
   863     case SDL_TEXTURESCALEMODE_FAST:
   864         data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
   865                               GL_NEAREST);
   866         data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
   867                               GL_NEAREST);
   868         break;
   869     case SDL_TEXTURESCALEMODE_SLOW:
   870     case SDL_TEXTURESCALEMODE_BEST:
   871         data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
   872                               GL_LINEAR);
   873         data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
   874                               GL_LINEAR);
   875         break;
   876     }
   877 
   878     if (data->GL_OES_draw_texture_supported && data->useDrawTexture) {
   879         /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */
   880         SDL_Window *window = renderer->window;
   881         GLint cropRect[4];
   882         cropRect[0] = srcrect->x;
   883         cropRect[1] = srcrect->y + srcrect->h;
   884         cropRect[2] = srcrect->w;
   885         cropRect[3] = -srcrect->h;
   886         data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
   887                                cropRect);
   888         data->glDrawTexiOES(dstrect->x, window->h - dstrect->y - dstrect->h,
   889                             0, dstrect->w, dstrect->h);
   890     } else {
   891 
   892         minx = dstrect->x;
   893         miny = dstrect->y;
   894         maxx = dstrect->x + dstrect->w;
   895         maxy = dstrect->y + dstrect->h;
   896 
   897         minu = (GLfloat) srcrect->x / texture->w;
   898         minu *= texturedata->texw;
   899         maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   900         maxu *= texturedata->texw;
   901         minv = (GLfloat) srcrect->y / texture->h;
   902         minv *= texturedata->texh;
   903         maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   904         maxv *= texturedata->texh;
   905 
   906         GLshort vertices[8];
   907         GLfloat texCoords[8];
   908 
   909         vertices[0] = minx;
   910         vertices[1] = miny;
   911         vertices[2] = maxx;
   912         vertices[3] = miny;
   913         vertices[4] = minx;
   914         vertices[5] = maxy;
   915         vertices[6] = maxx;
   916         vertices[7] = maxy;
   917 
   918         texCoords[0] = minu;
   919         texCoords[1] = minv;
   920         texCoords[2] = maxu;
   921         texCoords[3] = minv;
   922         texCoords[4] = minu;
   923         texCoords[5] = maxv;
   924         texCoords[6] = maxu;
   925         texCoords[7] = maxv;
   926 
   927         data->glVertexPointer(2, GL_SHORT, 0, vertices);
   928         data->glEnableClientState(GL_VERTEX_ARRAY);
   929         data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
   930         data->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   931         data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   932         data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   933         data->glDisableClientState(GL_VERTEX_ARRAY);
   934     }
   935 
   936     data->glDisable(GL_TEXTURE_2D);
   937 
   938     return 0;
   939 }
   940 
   941 static void
   942 GLES_RenderPresent(SDL_Renderer * renderer)
   943 {
   944     SDL_GL_SwapWindow(renderer->window);
   945 }
   946 
   947 static void
   948 GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   949 {
   950     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   951 
   952     if (!data) {
   953         return;
   954     }
   955     if (data->texture) {
   956         glDeleteTextures(1, &data->texture);
   957     }
   958     if (data->pixels) {
   959         SDL_free(data->pixels);
   960     }
   961     SDL_FreeDirtyRects(&data->dirty);
   962     SDL_free(data);
   963     texture->driverdata = NULL;
   964 }
   965 
   966 static void
   967 GLES_DestroyRenderer(SDL_Renderer * renderer)
   968 {
   969     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   970 
   971     if (data) {
   972         if (data->context) {
   973             SDL_GL_DeleteContext(data->context);
   974         }
   975         SDL_free(data);
   976     }
   977     SDL_free(renderer);
   978 }
   979 
   980 #endif /* SDL_VIDEO_RENDER_OGL_ES */
   981 
   982 /* vi: set ts=4 sw=4 expandtab: */