src/video/SDL_renderer_gles.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 19 Jan 2011 23:56:16 -0800
changeset 5053 b5b42be9333c
parent 5052 4cb4b18cbae3
child 5138 da10636e5eca
permissions -rw-r--r--
Fixed bug #1026

Vittorio Giovara 2010-07-16 19:09:28 PDT

i was reading SDL_renderer_gles and i noticed that every time we there
is some gl call the gl state is modified with a couple of
glEnableClientState()/glDisableClientState.
While this is completely fine for desktops systems, this is a major
performace kill on mobile devices, right where opengles is
implemented.
Normal practice in this case is to update the glstate once, keep it
always the same and disable/enable other states only in very special
occasions.

On the web there's plenty of documentation (on the top of my head
http://developer.apple.com/iphone/library/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/Performance/Performance.html#//apple_ref/doc/uid/TP40008793-CH105-SW5
) and i personally tried this.
I modified my code and got a 10 fps boost, then modified SDL_render_gles and
shifted from 40 fps to 50 fps alone -- considering that i started from ~30fps i
got an 80% performance increase with this technique.

I have attached a dif of my changes, hope that it will be included in
mainstream.
     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_SCALEMODE_NONE | SDL_SCALEMODE_FAST | SDL_SCALEMODE_SLOW), 6,
   116      {
   117       /* OpenGL ES 1.x supported formats list */
   118       SDL_PIXELFORMAT_RGBA4444,
   119       SDL_PIXELFORMAT_RGBA5551,
   120       SDL_PIXELFORMAT_RGB565,
   121       SDL_PIXELFORMAT_RGB24,
   122       SDL_PIXELFORMAT_BGR888,
   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     data->glEnableClientState(GL_VERTEX_ARRAY);
   328     data->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   329     
   330     return renderer;
   331 }
   332 
   333 static int
   334 GLES_ActivateRenderer(SDL_Renderer * renderer)
   335 {
   336 
   337     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   338     SDL_Window *window = renderer->window;
   339 
   340     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   341         return -1;
   342     }
   343     if (data->updateSize) {
   344         data->glMatrixMode(GL_PROJECTION);
   345         data->glLoadIdentity();
   346         data->glMatrixMode(GL_MODELVIEW);
   347         data->glLoadIdentity();
   348         data->glViewport(0, 0, window->w, window->h);
   349         data->glOrthof(0.0, (GLfloat) window->w, (GLfloat) window->h, 0.0,
   350                        0.0, 1.0);
   351         data->updateSize = SDL_FALSE;
   352     }
   353     return 0;
   354 }
   355 
   356 static int
   357 GLES_DisplayModeChanged(SDL_Renderer * renderer)
   358 {
   359     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   360 
   361     data->updateSize = SDL_TRUE;
   362     return 0;
   363 }
   364 
   365 static __inline__ int
   366 power_of_2(int input)
   367 {
   368     int value = 1;
   369 
   370     while (value < input) {
   371         value <<= 1;
   372     }
   373     return value;
   374 }
   375 
   376 static int
   377 GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   378 {
   379     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   380     GLES_TextureData *data;
   381     GLint internalFormat;
   382     GLenum format, type;
   383     int texture_w, texture_h;
   384     GLenum result;
   385 
   386     switch (texture->format) {
   387     case SDL_PIXELFORMAT_RGB24:
   388         internalFormat = GL_RGB;
   389         format = GL_RGB;
   390         type = GL_UNSIGNED_BYTE;
   391         break;
   392     case SDL_PIXELFORMAT_BGR888:
   393     case SDL_PIXELFORMAT_ABGR8888:
   394         internalFormat = GL_RGBA;
   395         format = GL_RGBA;
   396         type = GL_UNSIGNED_BYTE;
   397         break;
   398     case SDL_PIXELFORMAT_RGB565:
   399         internalFormat = GL_RGB;
   400         format = GL_RGB;
   401         type = GL_UNSIGNED_SHORT_5_6_5;
   402         break;
   403     case SDL_PIXELFORMAT_RGBA5551:
   404         internalFormat = GL_RGBA;
   405         format = GL_RGBA;
   406         type = GL_UNSIGNED_SHORT_5_5_5_1;
   407         break;
   408     case SDL_PIXELFORMAT_RGBA4444:
   409         internalFormat = GL_RGBA;
   410         format = GL_RGBA;
   411         type = GL_UNSIGNED_SHORT_4_4_4_4;
   412         break;
   413     default:
   414         SDL_SetError("Texture format %s not supported by OpenGL ES",
   415                      SDL_GetPixelFormatName(texture->format));
   416         return -1;
   417     }
   418 
   419     data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data));
   420     if (!data) {
   421         SDL_OutOfMemory();
   422         return -1;
   423     }
   424 
   425     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   426         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   427         data->pixels = SDL_malloc(texture->h * data->pitch);
   428         if (!data->pixels) {
   429             SDL_OutOfMemory();
   430             SDL_free(data);
   431             return -1;
   432         }
   433     }
   434 
   435     texture->driverdata = data;
   436 
   437     renderdata->glGetError();
   438     renderdata->glEnable(GL_TEXTURE_2D);
   439     renderdata->glGenTextures(1, &data->texture);
   440 
   441     data->type = GL_TEXTURE_2D;
   442     /* no NPOV textures allowed in OpenGL ES (yet) */
   443     texture_w = power_of_2(texture->w);
   444     texture_h = power_of_2(texture->h);
   445     data->texw = (GLfloat) texture->w / texture_w;
   446     data->texh = (GLfloat) texture->h / texture_h;
   447 
   448     data->format = format;
   449     data->formattype = type;
   450     renderdata->glBindTexture(data->type, data->texture);
   451     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   452                                 GL_NEAREST);
   453     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   454                                 GL_NEAREST);
   455     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   456                                 GL_CLAMP_TO_EDGE);
   457     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   458                                 GL_CLAMP_TO_EDGE);
   459 
   460     renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   461                              texture_h, 0, format, type, NULL);
   462     renderdata->glDisable(GL_TEXTURE_2D);
   463 
   464     result = renderdata->glGetError();
   465     if (result != GL_NO_ERROR) {
   466         GLES_SetError("glTexImage2D()", result);
   467         return -1;
   468     }
   469     return 0;
   470 }
   471 
   472 static int
   473 GLES_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   474                         void **pixels, int *pitch)
   475 {
   476     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   477 
   478     *pixels = data->pixels;
   479     *pitch = data->pitch;
   480     return 0;
   481 }
   482 
   483 static int
   484 GLES_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   485                        const SDL_Color * colors, int firstcolor, int ncolors)
   486 {
   487     SDL_SetError("OpenGL ES does not support paletted textures");
   488     return -1;
   489 }
   490 
   491 static int
   492 GLES_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   493                        SDL_Color * colors, int firstcolor, int ncolors)
   494 {
   495     SDL_SetError("OpenGL ES does not support paletted textures");
   496     return -1;
   497 }
   498 
   499 static void
   500 SetupTextureUpdate(GLES_RenderData * renderdata, SDL_Texture * texture,
   501                    int pitch)
   502 {
   503     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   504     renderdata->glBindTexture(data->type, data->texture);
   505     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   506 }
   507 
   508 static int
   509 GLES_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   510 {
   511     return 0;
   512 }
   513 
   514 static int
   515 GLES_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   516 {
   517     return 0;
   518 }
   519 
   520 static int
   521 GLES_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   522 {
   523     switch (texture->blendMode) {
   524     case SDL_BLENDMODE_NONE:
   525     case SDL_BLENDMODE_MASK:
   526     case SDL_BLENDMODE_BLEND:
   527     case SDL_BLENDMODE_ADD:
   528     case SDL_BLENDMODE_MOD:
   529         return 0;
   530     default:
   531         SDL_Unsupported();
   532         texture->blendMode = SDL_BLENDMODE_NONE;
   533         return -1;
   534     }
   535 }
   536 
   537 static int
   538 GLES_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   539 {
   540     switch (texture->scaleMode) {
   541     case SDL_SCALEMODE_NONE:
   542     case SDL_SCALEMODE_FAST:
   543     case SDL_SCALEMODE_SLOW:
   544         return 0;
   545     case SDL_SCALEMODE_BEST:
   546         SDL_Unsupported();
   547         texture->scaleMode = SDL_SCALEMODE_SLOW;
   548         return -1;
   549     default:
   550         SDL_Unsupported();
   551         texture->scaleMode = SDL_SCALEMODE_NONE;
   552         return -1;
   553     }
   554 }
   555 
   556 static int
   557 GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   558                    const SDL_Rect * rect, const void *pixels, int pitch)
   559 {
   560     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   561     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   562     GLenum result;
   563     int bpp = SDL_BYTESPERPIXEL(texture->format);
   564     void * temp_buffer;
   565     void * temp_ptr;
   566     int i;
   567 
   568     renderdata->glGetError();
   569     renderdata->glEnable(data->type);
   570     SetupTextureUpdate(renderdata, texture, pitch);
   571 
   572     if( rect->w * bpp == pitch ) {
   573          temp_buffer = (void *)pixels; /* No need to reformat */
   574     } else {
   575          /* Reformatting of mem area required */
   576          temp_buffer = SDL_malloc(rect->w * rect->h * bpp);
   577          temp_ptr = temp_buffer;
   578          for (i = 0; i < rect->h; i++) {
   579              SDL_memcpy(temp_ptr, pixels, rect->w * bpp);
   580              temp_ptr += rect->w * bpp;
   581              pixels += pitch;
   582          }
   583     }
   584 
   585     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   586                                 rect->h, data->format, data->formattype,
   587                                 temp_buffer);
   588 
   589     if( temp_buffer != pixels ) {
   590         SDL_free(temp_buffer);
   591     }
   592 
   593     renderdata->glDisable(data->type);
   594     result = renderdata->glGetError();
   595     if (result != GL_NO_ERROR) {
   596         GLES_SetError("glTexSubImage2D()", result);
   597         return -1;
   598     }
   599     return 0;
   600 }
   601 
   602 static int
   603 GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   604                  const SDL_Rect * rect, int markDirty, void **pixels,
   605                  int *pitch)
   606 {
   607     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   608 
   609     if (markDirty) {
   610         SDL_AddDirtyRect(&data->dirty, rect);
   611     }
   612 
   613     *pixels =
   614         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   615                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   616     *pitch = data->pitch;
   617     return 0;
   618 }
   619 
   620 static void
   621 GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   622 {
   623 }
   624 
   625 static void
   626 GLES_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   627                   int numrects, const SDL_Rect * rects)
   628 {
   629     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   630     int i;
   631 
   632     for (i = 0; i < numrects; ++i) {
   633         SDL_AddDirtyRect(&data->dirty, &rects[i]);
   634     }
   635 }
   636 
   637 static void
   638 GLES_SetBlendMode(GLES_RenderData * data, int blendMode, int isprimitive)
   639 {
   640     if (blendMode != data->blendMode) {
   641         switch (blendMode) {
   642         case SDL_BLENDMODE_NONE:
   643             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   644             data->glDisable(GL_BLEND);
   645             break;
   646         case SDL_BLENDMODE_MASK:
   647             if (isprimitive) {
   648                 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   649                 data->glDisable(GL_BLEND);
   650                 /* The same as SDL_BLENDMODE_NONE */
   651                 blendMode = SDL_BLENDMODE_NONE;
   652                 break;
   653             }
   654             /* fall through */
   655         case SDL_BLENDMODE_BLEND:
   656             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   657             data->glEnable(GL_BLEND);
   658             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   659             break;
   660         case SDL_BLENDMODE_ADD:
   661             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   662             data->glEnable(GL_BLEND);
   663             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   664             break;
   665         case SDL_BLENDMODE_MOD:
   666             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   667             data->glEnable(GL_BLEND);
   668             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   669             break;
   670         }
   671         data->blendMode = blendMode;
   672     }
   673 }
   674 
   675 static int
   676 GLES_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   677                       int count)
   678 {
   679     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   680     int i;
   681     GLshort *vertices;
   682 
   683     GLES_SetBlendMode(data, renderer->blendMode, 1);
   684 
   685     data->glColor4f((GLfloat) renderer->r * inv255f,
   686                     (GLfloat) renderer->g * inv255f,
   687                     (GLfloat) renderer->b * inv255f,
   688                     (GLfloat) renderer->a * inv255f);
   689 
   690     vertices = SDL_stack_alloc(GLshort, count*2);
   691     for (i = 0; i < count; ++i) {
   692         vertices[2*i+0] = (GLshort)points[i].x;
   693         vertices[2*i+1] = (GLshort)points[i].y;
   694     }
   695     data->glVertexPointer(2, GL_SHORT, 0, vertices);
   696     data->glDrawArrays(GL_POINTS, 0, count);
   697     SDL_stack_free(vertices);
   698 
   699     return 0;
   700 }
   701 
   702 static int
   703 GLES_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   704                      int count)
   705 {
   706     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   707     int i;
   708     GLshort *vertices;
   709 
   710     GLES_SetBlendMode(data, renderer->blendMode, 1);
   711 
   712     data->glColor4f((GLfloat) renderer->r * inv255f,
   713                     (GLfloat) renderer->g * inv255f,
   714                     (GLfloat) renderer->b * inv255f,
   715                     (GLfloat) renderer->a * inv255f);
   716 
   717     vertices = SDL_stack_alloc(GLshort, count*2);
   718     for (i = 0; i < count; ++i) {
   719         vertices[2*i+0] = (GLshort)points[i].x;
   720         vertices[2*i+1] = (GLshort)points[i].y;
   721     }
   722     data->glVertexPointer(2, GL_SHORT, 0, vertices);
   723     if (count > 2 && 
   724         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
   725         /* GL_LINE_LOOP takes care of the final segment */
   726         --count;
   727         data->glDrawArrays(GL_LINE_LOOP, 0, count);
   728     } else {
   729         data->glDrawArrays(GL_LINE_STRIP, 0, count);
   730     }
   731     SDL_stack_free(vertices);
   732 
   733     return 0;
   734 }
   735 
   736 static int
   737 GLES_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
   738                      int count)
   739 {
   740     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   741     int i;
   742 
   743     GLES_SetBlendMode(data, renderer->blendMode, 1);
   744 
   745     data->glColor4f((GLfloat) renderer->r * inv255f,
   746                     (GLfloat) renderer->g * inv255f,
   747                     (GLfloat) renderer->b * inv255f,
   748                     (GLfloat) renderer->a * inv255f);
   749 
   750     for (i = 0; i < count; ++i) {
   751         const SDL_Rect *rect = rects[i];
   752         GLshort minx = rect->x;
   753         GLshort maxx = rect->x + rect->w;
   754         GLshort miny = rect->y;
   755         GLshort maxy = rect->y + rect->h;
   756         GLshort vertices[8];
   757         vertices[0] = minx;
   758         vertices[1] = miny;
   759         vertices[2] = maxx;
   760         vertices[3] = miny;
   761         vertices[4] = minx;
   762         vertices[5] = maxy;
   763         vertices[6] = maxx;
   764         vertices[7] = maxy;
   765 
   766         data->glVertexPointer(2, GL_SHORT, 0, vertices);
   767         data->glDrawArrays(GL_LINE_LOOP, 0, 4);
   768     }
   769 
   770     return 0;
   771 }
   772 
   773 static int
   774 GLES_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
   775                      int count)
   776 {
   777     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   778     int i;
   779 
   780     GLES_SetBlendMode(data, renderer->blendMode, 1);
   781 
   782     data->glColor4f((GLfloat) renderer->r * inv255f,
   783                     (GLfloat) renderer->g * inv255f,
   784                     (GLfloat) renderer->b * inv255f,
   785                     (GLfloat) renderer->a * inv255f);
   786 
   787     for (i = 0; i < count; ++i) {
   788         const SDL_Rect *rect = rects[i];
   789         GLshort minx = rect->x;
   790         GLshort maxx = rect->x + rect->w;
   791         GLshort miny = rect->y;
   792         GLshort maxy = rect->y + rect->h;
   793         GLshort vertices[8];
   794         vertices[0] = minx;
   795         vertices[1] = miny;
   796         vertices[2] = maxx;
   797         vertices[3] = miny;
   798         vertices[4] = minx;
   799         vertices[5] = maxy;
   800         vertices[6] = maxx;
   801         vertices[7] = maxy;
   802 
   803         data->glVertexPointer(2, GL_SHORT, 0, vertices);
   804         data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   805     }
   806 
   807     return 0;
   808 }
   809 
   810 static int
   811 GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   812                 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   813 {
   814 
   815     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   816     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   817     int minx, miny, maxx, maxy;
   818     GLfloat minu, maxu, minv, maxv;
   819     int i;
   820     void *temp_buffer;          /* used for reformatting dirty rect pixels */
   821     void *temp_ptr;
   822 
   823     data->glEnable(GL_TEXTURE_2D);
   824 
   825     if (texturedata->dirty.list) {
   826         SDL_DirtyRect *dirty;
   827         void *pixels;
   828         int bpp = SDL_BYTESPERPIXEL(texture->format);
   829         int pitch = texturedata->pitch;
   830 
   831         SetupTextureUpdate(data, texture, pitch);
   832 
   833         data->glBindTexture(texturedata->type, texturedata->texture);
   834         for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
   835             SDL_Rect *rect = &dirty->rect;
   836             pixels =
   837                 (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch +
   838                           rect->x * bpp);
   839             /*      There is no GL_UNPACK_ROW_LENGTH in OpenGLES 
   840                we must do this reformatting ourselves(!)
   841 
   842                maybe it'd be a good idea to keep a temp buffer around
   843                for this purpose rather than allocating it each time
   844              */
   845             if( rect->x == 0 && rect->w * bpp == pitch ) {
   846                 temp_buffer = pixels; /* Updating whole texture, no need to reformat */
   847             } else {
   848                 temp_buffer = SDL_malloc(rect->w * rect->h * bpp);
   849                 temp_ptr = temp_buffer;
   850                 for (i = 0; i < rect->h; i++) {
   851                     SDL_memcpy(temp_ptr, pixels, rect->w * bpp);
   852                     temp_ptr += rect->w * bpp;
   853                     pixels += pitch;
   854                 }
   855             }
   856 
   857             data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y,
   858                                   rect->w, rect->h, texturedata->format,
   859                                   texturedata->formattype, temp_buffer);
   860 
   861             if( temp_buffer != pixels ) {
   862                 SDL_free(temp_buffer);
   863             }
   864         }
   865         SDL_ClearDirtyRects(&texturedata->dirty);
   866     }
   867 
   868     data->glBindTexture(texturedata->type, texturedata->texture);
   869 
   870     if (texture->modMode) {
   871         data->glColor4f((GLfloat) texture->r * inv255f,
   872                         (GLfloat) texture->g * inv255f,
   873                         (GLfloat) texture->b * inv255f,
   874                         (GLfloat) texture->a * inv255f);
   875     } else {
   876         data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
   877     }
   878 
   879     GLES_SetBlendMode(data, texture->blendMode, 0);
   880 
   881     switch (texture->scaleMode) {
   882     case SDL_SCALEMODE_NONE:
   883     case SDL_SCALEMODE_FAST:
   884         data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
   885                               GL_NEAREST);
   886         data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
   887                               GL_NEAREST);
   888         break;
   889     case SDL_SCALEMODE_SLOW:
   890     case SDL_SCALEMODE_BEST:
   891         data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
   892                               GL_LINEAR);
   893         data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
   894                               GL_LINEAR);
   895         break;
   896     }
   897 
   898     if (data->GL_OES_draw_texture_supported && data->useDrawTexture) {
   899         /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */
   900         SDL_Window *window = renderer->window;
   901         GLint cropRect[4];
   902         cropRect[0] = srcrect->x;
   903         cropRect[1] = srcrect->y + srcrect->h;
   904         cropRect[2] = srcrect->w;
   905         cropRect[3] = -srcrect->h;
   906         data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
   907                                cropRect);
   908         data->glDrawTexiOES(dstrect->x, window->h - dstrect->y - dstrect->h,
   909                             0, dstrect->w, dstrect->h);
   910     } else {
   911 
   912         minx = dstrect->x;
   913         miny = dstrect->y;
   914         maxx = dstrect->x + dstrect->w;
   915         maxy = dstrect->y + dstrect->h;
   916 
   917         minu = (GLfloat) srcrect->x / texture->w;
   918         minu *= texturedata->texw;
   919         maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   920         maxu *= texturedata->texw;
   921         minv = (GLfloat) srcrect->y / texture->h;
   922         minv *= texturedata->texh;
   923         maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   924         maxv *= texturedata->texh;
   925 
   926         GLshort vertices[8];
   927         GLfloat texCoords[8];
   928 
   929         vertices[0] = minx;
   930         vertices[1] = miny;
   931         vertices[2] = maxx;
   932         vertices[3] = miny;
   933         vertices[4] = minx;
   934         vertices[5] = maxy;
   935         vertices[6] = maxx;
   936         vertices[7] = maxy;
   937 
   938         texCoords[0] = minu;
   939         texCoords[1] = minv;
   940         texCoords[2] = maxu;
   941         texCoords[3] = minv;
   942         texCoords[4] = minu;
   943         texCoords[5] = maxv;
   944         texCoords[6] = maxu;
   945         texCoords[7] = maxv;
   946 
   947         data->glVertexPointer(2, GL_SHORT, 0, vertices);
   948         data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
   949         data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   950     }
   951 
   952     data->glDisable(GL_TEXTURE_2D);
   953 
   954     return 0;
   955 }
   956 
   957 static void
   958 GLES_RenderPresent(SDL_Renderer * renderer)
   959 {
   960     SDL_GL_SwapWindow(renderer->window);
   961 }
   962 
   963 static void
   964 GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   965 {
   966     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   967 
   968     if (!data) {
   969         return;
   970     }
   971     if (data->texture) {
   972         glDeleteTextures(1, &data->texture);
   973     }
   974     if (data->pixels) {
   975         SDL_free(data->pixels);
   976     }
   977     SDL_FreeDirtyRects(&data->dirty);
   978     SDL_free(data);
   979     texture->driverdata = NULL;
   980 }
   981 
   982 static void
   983 GLES_DestroyRenderer(SDL_Renderer * renderer)
   984 {
   985     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   986 
   987     if (data) {
   988         if (data->context) {
   989             SDL_GL_DeleteContext(data->context);
   990         }
   991         SDL_free(data);
   992     }
   993     SDL_free(renderer);
   994 }
   995 
   996 #endif /* SDL_VIDEO_RENDER_OGL_ES */
   997 
   998 /* vi: set ts=4 sw=4 expandtab: */