diff --git a/../downloads/SDL2-2.0.8/src/render/SDL_render.c b/./sdl/src/render/SDL_render.c
index 8cd3a7b..6510f9d 100644
--- a/../downloads/SDL2-2.0.8/src/render/SDL_render.c
+++ b/./sdl/src/render/SDL_render.c
@@ -1196,12 +1196,13 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
         renderer->logical_w_backup = renderer->logical_w;
         renderer->logical_h_backup = renderer->logical_h;
     }
-    renderer->target = texture;
 
     if (renderer->SetRenderTarget(renderer, texture) < 0) {
         return -1;
     }
 
+    renderer->target = texture;
+
     if (texture) {
         renderer->viewport.x = 0;
         renderer->viewport.y = 0;
diff --git a/../downloads/SDL2-2.0.8/src/render/opengles2/SDL_render_gles2.c b/./sdl/src/render/opengles2/SDL_render_gles2.c
index 0cd388c..a2b2fe1 100644
--- a/../downloads/SDL2-2.0.8/src/render/opengles2/SDL_render_gles2.c
+++ b/./sdl/src/render/opengles2/SDL_render_gles2.c
@@ -39,7 +39,7 @@
 #ifdef __EMSCRIPTEN__
 #define SDL_GLES2_USE_VBOS 1
 #else
-#define SDL_GLES2_USE_VBOS 0
+#define SDL_GLES2_USE_VBOS 1
 #endif
 
 /* To prevent unnecessary window recreation,
@@ -101,6 +101,7 @@ typedef struct GLES2_TextureData
     GLenum texture_v;
     GLenum texture_u;
     GLES2_FBOList *fbo;
+    SDL_bool in_batch;
 } GLES2_TextureData;
 
 typedef struct GLES2_ShaderCacheEntry
@@ -126,8 +127,6 @@ typedef struct GLES2_ProgramCacheEntry
     GLES2_ShaderCacheEntry *vertex_shader;
     GLES2_ShaderCacheEntry *fragment_shader;
     GLuint uniform_locations[16];
-    Uint8 color_r, color_g, color_b, color_a;
-    Uint8 modulation_r, modulation_g, modulation_b, modulation_a;
     GLfloat projection[4][4];
     struct GLES2_ProgramCacheEntry *prev;
     struct GLES2_ProgramCacheEntry *next;
@@ -146,14 +145,13 @@ typedef enum
     GLES2_ATTRIBUTE_TEXCOORD = 1,
     GLES2_ATTRIBUTE_ANGLE = 2,
     GLES2_ATTRIBUTE_CENTER = 3,
+    GLES2_ATTRIBUTE_COLOR = 4,
 } GLES2_Attribute;
 
 typedef enum
 {
     GLES2_UNIFORM_PROJECTION,
     GLES2_UNIFORM_TEXTURE,
-    GLES2_UNIFORM_MODULATION,
-    GLES2_UNIFORM_COLOR,
     GLES2_UNIFORM_TEXTURE_U,
     GLES2_UNIFORM_TEXTURE_V
 } GLES2_Uniform;
@@ -171,6 +169,30 @@ typedef enum
     GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES
 } GLES2_ImageSource;
 
+typedef struct Vertex
+{
+    GLfloat pos[2];
+    GLfloat tex[2];
+    GLfloat angle;
+    GLfloat center[2];
+    GLfloat color[4];
+} Vertex;
+
+#ifndef MAX_VERTICES_COUNT
+#define MAX_VERTICES_COUNT 12000
+#endif
+
+#define GLES2_VERTEX_MAX_VERTICES MAX_VERTICES_COUNT
+
+typedef struct DrawCommand
+{
+    int size;
+    int offset;
+    GLenum primitive_type;
+    SDL_BlendMode blend_mode;
+    SDL_Texture* texture;
+} DrawCommand;
+
 typedef struct GLES2_DriverContext
 {
     SDL_GLContext *context;
@@ -195,10 +217,11 @@ typedef struct GLES2_DriverContext
     GLES2_ProgramCacheEntry *current_program;
     Uint8 clear_r, clear_g, clear_b, clear_a;
 
-#if SDL_GLES2_USE_VBOS
-    GLuint vertex_buffers[4];
-    GLsizeiptr vertex_buffer_size[4];
-#endif
+    GLuint VBO;
+    Vertex* vertices;
+    DrawCommand* draw_commands;
+    int draw_command_current_offset;
+    int vertices_current_offset;
 } GLES2_DriverContext;
 
 #define GLES2_MAX_CACHED_PROGRAMS 8
@@ -264,6 +287,12 @@ GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file,
 #define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, SDL_FILE, SDL_LINE, SDL_FUNCTION)
 #endif
 
+/*************************************************************************************************
+* Renderer batch draw APIs                                                                       *
+*************************************************************************************************/
+
+static void GLES2_CheckAndAddNewCommand(SDL_Renderer *renderer, SDL_Texture* texture, SDL_BlendMode blendMode, GLenum primitive_type, int count);
+static int GLES2_FlushVertices(SDL_Renderer *renderer);
 
 /*************************************************************************************************
  * Renderer state APIs                                                                           *
@@ -497,6 +526,14 @@ GLES2_DestroyRenderer(SDL_Renderer *renderer)
     if (data) {
         GLES2_ActivateRenderer(renderer);
 
+        if (data->vertices)
+        {
+            SDL_free(data->vertices);
+        }
+        if (data->draw_commands)
+        {
+            SDL_free(data->draw_commands);
+        }
         {
             GLES2_ShaderCacheEntry *entry;
             GLES2_ShaderCacheEntry *next;
@@ -625,6 +662,7 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     data->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21));
     data->texture_u = 0;
     data->texture_v = 0;
+    data->in_batch = SDL_FALSE;
     scaleMode = GetScaleQuality();
 
     /* Allocate a blob for image renderdata */
@@ -763,6 +801,9 @@ GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect
     GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
 
+    if (tdata->in_batch == SDL_TRUE)
+        GLES2_FlushVertices(renderer);
+
     GLES2_ActivateRenderer(renderer);
 
     /* Bail out if we're supposed to update an empty rectangle */
@@ -843,6 +884,9 @@ GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
     GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
 
+    if (tdata->in_batch == SDL_TRUE)
+        GLES2_FlushVertices(renderer);
+
     GLES2_ActivateRenderer(renderer);
 
     /* Bail out if we're supposed to update an empty rectangle */
@@ -919,6 +963,8 @@ GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
     GLES2_TextureData *texturedata = NULL;
     GLenum status;
 
+    GLES2_FlushVertices(renderer);
+
     if (texture == NULL) {
         data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer);
     } else {
@@ -941,6 +987,9 @@ GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
 
+    if (tdata->in_batch == SDL_TRUE)
+        GLES2_FlushVertices(renderer);
+
     GLES2_ActivateRenderer(renderer);
 
     /* Destroy the texture */
@@ -1019,6 +1068,7 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
     data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord");
     data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_ANGLE, "a_angle");
     data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_CENTER, "a_center");
+    data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_COLOR, "a_color");
     data->glLinkProgram(entry->id);
     data->glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful);
     if (!linkSuccessful) {
@@ -1037,21 +1087,12 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
         data->glGetUniformLocation(entry->id, "u_texture_u");
     entry->uniform_locations[GLES2_UNIFORM_TEXTURE] =
         data->glGetUniformLocation(entry->id, "u_texture");
-    entry->uniform_locations[GLES2_UNIFORM_MODULATION] =
-        data->glGetUniformLocation(entry->id, "u_modulation");
-    entry->uniform_locations[GLES2_UNIFORM_COLOR] =
-        data->glGetUniformLocation(entry->id, "u_color");
-
-    entry->modulation_r = entry->modulation_g = entry->modulation_b = entry->modulation_a = 255;
-    entry->color_r = entry->color_g = entry->color_b = entry->color_a = 255;
 
     data->glUseProgram(entry->id);
     data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V], 2);  /* always texture unit 2. */
     data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U], 1);  /* always texture unit 1. */
     data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0);  /* always texture unit 0. */
     data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection);
-    data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_MODULATION], 1.0f, 1.0f, 1.0f, 1.0f);
-    data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_COLOR], 1.0f, 1.0f, 1.0f, 1.0f);
 
     /* Cache the linked program */
     if (data->program_cache.head) {
@@ -1494,10 +1535,6 @@ static int
 GLES2_SetDrawingState(SDL_Renderer * renderer)
 {
     GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-    GLES2_ProgramCacheEntry *program;
-    Uint8 r, g, b, a;
-
-    GLES2_ActivateRenderer(renderer);
 
     GLES2_SetBlendMode(data, renderer->blendMode);
 
@@ -1508,58 +1545,6 @@ GLES2_SetDrawingState(SDL_Renderer * renderer)
         return -1;
     }
 
-    /* Select the color to draw with */
-    g = renderer->g;
-    a = renderer->a;
-
-    if (renderer->target &&
-         (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
-         renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
-        r = renderer->b;
-        b = renderer->r;
-     } else {
-        r = renderer->r;
-        b = renderer->b;
-     }
-
-    program = data->current_program;
-    if (!CompareColors(program->color_r, program->color_g, program->color_b, program->color_a, r, g, b, a)) {
-        /* Select the color to draw with */
-        data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_COLOR], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
-        program->color_r = r;
-        program->color_g = g;
-        program->color_b = b;
-        program->color_a = a;
-    }
-
-    return 0;
-}
-
-static int
-GLES2_UpdateVertexBuffer(SDL_Renderer *renderer, GLES2_Attribute attr,
-                         const void *vertexData, size_t dataSizeInBytes)
-{
-    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-
-#if !SDL_GLES2_USE_VBOS
-    data->glVertexAttribPointer(attr, attr == GLES2_ATTRIBUTE_ANGLE ? 1 : 2, GL_FLOAT, GL_FALSE, 0, vertexData);
-#else
-    if (!data->vertex_buffers[attr]) {
-        data->glGenBuffers(1, &data->vertex_buffers[attr]);
-    }
-
-    data->glBindBuffer(GL_ARRAY_BUFFER, data->vertex_buffers[attr]);
-
-    if (data->vertex_buffer_size[attr] < dataSizeInBytes) {
-        data->glBufferData(GL_ARRAY_BUFFER, dataSizeInBytes, vertexData, GL_STREAM_DRAW);
-        data->vertex_buffer_size[attr] = dataSizeInBytes;
-    } else {
-        data->glBufferSubData(GL_ARRAY_BUFFER, 0, dataSizeInBytes, vertexData);
-    }
-
-    data->glVertexAttribPointer(attr, attr == GLES2_ATTRIBUTE_ANGLE ? 1 : 2, GL_FLOAT, GL_FALSE, 0, 0);
-#endif
-
     return 0;
 }
 
@@ -1567,60 +1552,94 @@ static int
 GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
 {
     GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-    GLfloat *vertices;
+    Vertex *vertices = data->vertices;
+    int vertex_index = data->vertices_current_offset;
     int idx;
-
-    if (GLES2_SetDrawingState(renderer) < 0) {
+    GLfloat r = renderer->r * inv255f;
+    GLfloat g = renderer->g * inv255f;
+    GLfloat b = renderer->b * inv255f;
+    GLfloat a = renderer->a * inv255f;
+
+    //TODO: make loop and draw by parts
+    if (count > GLES2_VERTEX_MAX_VERTICES) {
+        SDL_SetError("Too many points for draw");
         return -1;
     }
+    if (data->vertices_current_offset + count > GLES2_VERTEX_MAX_VERTICES)
+        GLES2_FlushVertices(renderer);
 
-    /* Emit the specified vertices as points */
-    vertices = SDL_stack_alloc(GLfloat, count * 2);
+    GLES2_CheckAndAddNewCommand(renderer, NULL, renderer->blendMode, GL_POINTS, count);
     for (idx = 0; idx < count; ++idx) {
         GLfloat x = points[idx].x + 0.5f;
         GLfloat y = points[idx].y + 0.5f;
 
-        vertices[idx * 2] = x;
-        vertices[(idx * 2) + 1] = y;
+        vertices[vertex_index].pos[0] = x;
+        vertices[vertex_index].pos[1] = y;
+        vertices[vertex_index].angle = 0.0f;
+        vertices[vertex_index].color[0] = r;
+        vertices[vertex_index].color[1] = g;
+        vertices[vertex_index].color[2] = b;
+        vertices[vertex_index].color[3] = a;
+        ++vertex_index;
     }
-    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
-    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2 * sizeof(GLfloat));
-    data->glDrawArrays(GL_POINTS, 0, count);
-    SDL_stack_free(vertices);
-    return 0;
-}
+    data->vertices_current_offset += count;
 
+    return GL_CheckError("", renderer);
+}
 static int
 GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
 {
     GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-    GLfloat *vertices;
+    Vertex *vertices = data->vertices;
+    int vertex_index = data->vertices_current_offset;
     int idx;
-
-    if (GLES2_SetDrawingState(renderer) < 0) {
+    GLfloat r = renderer->r * inv255f;
+    GLfloat g = renderer->g * inv255f;
+    GLfloat b = renderer->b * inv255f;
+    GLfloat a = renderer->a * inv255f;
+    const int VERTICES_FOR_LINES = 2 * (count - 1);
+    //TODO: make loop and draw by parts
+    if (VERTICES_FOR_LINES > GLES2_VERTEX_MAX_VERTICES) {
+        SDL_SetError("Too many points for draw");
         return -1;
     }
-
-    /* Emit a line strip including the specified vertices */
-    vertices = SDL_stack_alloc(GLfloat, count * 2);
-    for (idx = 0; idx < count; ++idx) {
-        GLfloat x = points[idx].x + 0.5f;
-        GLfloat y = points[idx].y + 0.5f;
-
-        vertices[idx * 2] = x;
-        vertices[(idx * 2) + 1] = y;
-    }
-    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
-    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2 * sizeof(GLfloat));
-    data->glDrawArrays(GL_LINE_STRIP, 0, count);
-
+    if (data->vertices_current_offset + VERTICES_FOR_LINES > GLES2_VERTEX_MAX_VERTICES)
+        GLES2_FlushVertices(renderer);
+
+    //Rewrite for using GL_LINES (GL_LINE_STRIP is not suitable for batching)
+    GLES2_CheckAndAddNewCommand(renderer, NULL, renderer->blendMode, GL_LINES, VERTICES_FOR_LINES);
+    for (idx = 0; idx < count - 1; ++idx) {
+        const GLfloat x1 = points[idx].x + 0.5f;
+        const GLfloat y1 = points[idx].y + 0.5f;
+        const GLfloat x2 = points[idx + 1].x + 0.5f;
+        const GLfloat y2 = points[idx + 1].y + 0.5f;
+
+        vertices[vertex_index].pos[0] = x1;
+        vertices[vertex_index].pos[1] = y1;
+        vertices[vertex_index].angle = 0.0f;
+        vertices[vertex_index].color[0] = r;
+        vertices[vertex_index].color[1] = g;
+        vertices[vertex_index].color[2] = b;
+        vertices[vertex_index].color[3] = a;
+        ++vertex_index;
+
+        vertices[vertex_index].pos[0] = x2;
+        vertices[vertex_index].pos[1] = y2;
+        vertices[vertex_index].angle = 0.0f;
+        vertices[vertex_index].color[0] = r;
+        vertices[vertex_index].color[1] = g;
+        vertices[vertex_index].color[2] = b;
+        vertices[vertex_index].color[3] = a;
+        ++vertex_index;
+    }
+    data->vertices_current_offset += VERTICES_FOR_LINES;
+
+    //Why we need?
     /* We need to close the endpoint of the line */
-    if (count == 2 ||
-        points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
-        data->glDrawArrays(GL_POINTS, count-1, 1);
-    }
-    SDL_stack_free(vertices);
-
+    //if (count == 2 ||
+    //    points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) {
+    //    GLES2_RenderDrawPoints(renderer, &points[count - 1], 1);
+    //}
     return GL_CheckError("", renderer);
 }
 
@@ -1628,14 +1647,23 @@ static int
 GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
 {
     GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-    GLfloat vertices[8];
+    Vertex *vertices = data->vertices;
+    int vertex_index = data->vertices_current_offset;
     int idx;
-
-    if (GLES2_SetDrawingState(renderer) < 0) {
+    GLfloat r = renderer->r * inv255f;
+    GLfloat g = renderer->g * inv255f;
+    GLfloat b = renderer->b * inv255f;
+    GLfloat a = renderer->a * inv255f;
+    const int VERTICES_FOR_QUAD = 6;
+    //TODO: make loop and draw by parts
+    if (VERTICES_FOR_QUAD * count > GLES2_VERTEX_MAX_VERTICES) {
+        SDL_SetError("Too many points for draw");
         return -1;
     }
+    if ((data->vertices_current_offset + VERTICES_FOR_QUAD * count) > GLES2_VERTEX_MAX_VERTICES)
+        GLES2_FlushVertices(renderer);
 
-    /* Emit a line loop for each rectangle */
+    GLES2_CheckAndAddNewCommand(renderer, NULL, renderer->blendMode, GL_TRIANGLES, VERTICES_FOR_QUAD * count);
     for (idx = 0; idx < count; ++idx) {
         const SDL_FRect *rect = &rects[idx];
 
@@ -1644,29 +1672,79 @@ GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
         GLfloat yMin = rect->y;
         GLfloat yMax = (rect->y + rect->h);
 
-        vertices[0] = xMin;
-        vertices[1] = yMin;
-        vertices[2] = xMax;
-        vertices[3] = yMin;
-        vertices[4] = xMin;
-        vertices[5] = yMax;
-        vertices[6] = xMax;
-        vertices[7] = yMax;
-        /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
-        GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
-        data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-    }
+        // 0 == 5, 1, 2 == 3, 4; 0, 1, 2; 3, 4, 5;
+
+        //0
+        vertices[vertex_index].pos[0] = xMin;
+        vertices[vertex_index].pos[1] = yMin;
+        vertices[vertex_index].angle = 0.0f;
+        vertices[vertex_index].color[0] = r;
+        vertices[vertex_index].color[1] = g;
+        vertices[vertex_index].color[2] = b;
+        vertices[vertex_index].color[3] = a;
+        ++vertex_index;
+
+        //1
+        vertices[vertex_index].pos[0] = xMax;
+        vertices[vertex_index].pos[1] = yMin;
+        vertices[vertex_index].angle = 0.0f;
+        vertices[vertex_index].color[0] = r;
+        vertices[vertex_index].color[1] = g;
+        vertices[vertex_index].color[2] = b;
+        vertices[vertex_index].color[3] = a;
+        ++vertex_index;
+
+        //2
+        vertices[vertex_index].pos[0] = xMax;
+        vertices[vertex_index].pos[1] = yMax;
+        vertices[vertex_index].angle = 0.0f;
+        vertices[vertex_index].color[0] = r;
+        vertices[vertex_index].color[1] = g;
+        vertices[vertex_index].color[2] = b;
+        vertices[vertex_index].color[3] = a;
+        ++vertex_index;
+
+        //3
+        vertices[vertex_index].pos[0] = xMax;
+        vertices[vertex_index].pos[1] = yMax;
+        vertices[vertex_index].angle = 0.0f;
+        vertices[vertex_index].color[0] = r;
+        vertices[vertex_index].color[1] = g;
+        vertices[vertex_index].color[2] = b;
+        vertices[vertex_index].color[3] = a;
+        ++vertex_index;
+
+        //4
+        vertices[vertex_index].pos[0] = xMin;
+        vertices[vertex_index].pos[1] = yMax;
+        vertices[vertex_index].angle = 0.0f;
+        vertices[vertex_index].color[0] = r;
+        vertices[vertex_index].color[1] = g;
+        vertices[vertex_index].color[2] = b;
+        vertices[vertex_index].color[3] = a;
+        ++vertex_index;
+
+        //5
+        vertices[vertex_index].pos[0] = xMin;
+        vertices[vertex_index].pos[1] = yMin;
+        vertices[vertex_index].angle = 0.0f;
+        vertices[vertex_index].color[0] = r;
+        vertices[vertex_index].color[1] = g;
+        vertices[vertex_index].color[2] = b;
+        vertices[vertex_index].color[3] = a;
+        ++vertex_index;
+    }
+    data->vertices_current_offset += (VERTICES_FOR_QUAD * count);
+
     return GL_CheckError("", renderer);
 }
 
 static int
-GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture)
+GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture* texture)
 {
     GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
     GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
-    GLES2_ProgramCacheEntry *program;
-    Uint8 r, g, b, a;
 
     /* Activate an appropriate shader and set the projection matrix */
     if (renderer->target) {
@@ -1794,30 +1872,6 @@ GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture)
     }
     data->glBindTexture(tdata->texture_type, tdata->texture);
 
-    /* Configure color modulation */
-    g = texture->g;
-    a = texture->a;
-
-    if (renderer->target &&
-        (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
-         renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
-        r = texture->b;
-        b = texture->r;
-    } else {
-        r = texture->r;
-        b = texture->b;
-    }
-
-    program = data->current_program;
-
-    if (!CompareColors(program->modulation_r, program->modulation_g, program->modulation_b, program->modulation_a, r, g, b, a)) {
-        data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_MODULATION], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
-        program->modulation_r = r;
-        program->modulation_g = g;
-        program->modulation_b = b;
-        program->modulation_a = a;
-    }
-
     /* Configure texture blending */
     GLES2_SetBlendMode(data, texture->blendMode);
 
@@ -1829,40 +1883,8 @@ static int
 GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
                  const SDL_FRect *dstrect)
 {
-    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-    GLfloat vertices[8];
-    GLfloat texCoords[8];
-
-    GLES2_ActivateRenderer(renderer);
-
-    if (GLES2_SetupCopy(renderer, texture) < 0) {
-        return -1;
-    }
-
-    /* Emit the textured quad */
-    vertices[0] = dstrect->x;
-    vertices[1] = dstrect->y;
-    vertices[2] = (dstrect->x + dstrect->w);
-    vertices[3] = dstrect->y;
-    vertices[4] = dstrect->x;
-    vertices[5] = (dstrect->y + dstrect->h);
-    vertices[6] = (dstrect->x + dstrect->w);
-    vertices[7] = (dstrect->y + dstrect->h);
-    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
-    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
-    texCoords[0] = srcrect->x / (GLfloat)texture->w;
-    texCoords[1] = srcrect->y / (GLfloat)texture->h;
-    texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
-    texCoords[3] = srcrect->y / (GLfloat)texture->h;
-    texCoords[4] = srcrect->x / (GLfloat)texture->w;
-    texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
-    texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
-    texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
-    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);*/
-    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_TEXCOORD, texCoords, 8 * sizeof(GLfloat));
-    data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-    return GL_CheckError("", renderer);
+    SDL_FPoint center = { dstrect->w / 2, dstrect->h / 2 };
+    return GLES2_RenderCopyEx(renderer, texture, srcrect, dstrect, 0.0, &center, SDL_FLIP_NONE);
 }
 
 static int
@@ -1870,66 +1892,134 @@ GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect
                  const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
 {
     GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-    GLfloat vertices[8];
-    GLfloat texCoords[8];
-    GLfloat translate[8];
-    GLfloat fAngle[4];
+    GLES2_TextureData *texture_data = (GLES2_TextureData*)texture->driverdata;
     GLfloat tmp;
+    GLfloat r;
+    GLfloat g;
+    GLfloat b;
+    GLfloat a;
+    Vertex* vertices;
+    int vertex_index;
+    int vertex_index_start;
 
-    GLES2_ActivateRenderer(renderer);
-
-    if (GLES2_SetupCopy(renderer, texture) < 0) {
-        return -1;
+    g = texture->g;
+    a = texture->a;
+    if (renderer->target &&
+        (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
+            renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
+        r = texture->b;
+        b = texture->r;
+    }
+    else {
+        r = texture->r;
+        b = texture->b;
     }
+    r *= inv255f;
+    g *= inv255f;
+    b *= inv255f;
+    a *= inv255f;
+
+    vertices = data->vertices;
+
+    if (data->vertices_current_offset + 6 > GLES2_VERTEX_MAX_VERTICES)
+        GLES2_FlushVertices(renderer);
+
+    texture_data->in_batch = SDL_TRUE;
+    GLES2_CheckAndAddNewCommand(renderer, texture, texture->blendMode, GL_TRIANGLES, 6);
+    vertex_index_start = data->vertices_current_offset;
+    // 0 == 5, 1, 2 == 3, 4; 0, 1, 2; 3, 4, 5;
+    //0
+    vertex_index = vertex_index_start;
+    vertices[vertex_index].pos[0] = dstrect->x;
+    vertices[vertex_index].pos[1] = dstrect->y;
+    vertices[vertex_index].tex[0] = srcrect->x / (GLfloat)texture->w;
+    vertices[vertex_index].tex[1] = srcrect->y / (GLfloat)texture->h;
+    vertices[vertex_index].angle = (GLfloat)(360.0f - angle);
+    vertices[vertex_index].center[0] = (center->x + dstrect->x);
+    vertices[vertex_index].center[1] = (center->y + dstrect->y);
+    vertices[vertex_index].color[0] = r;
+    vertices[vertex_index].color[1] = g;
+    vertices[vertex_index].color[2] = b;
+    vertices[vertex_index].color[3] = a;
+    //1
+    ++vertex_index;
+    vertices[vertex_index].pos[0] = (dstrect->x + dstrect->w);
+    vertices[vertex_index].pos[1] = dstrect->y;
+    vertices[vertex_index].tex[0] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
+    vertices[vertex_index].tex[1] = srcrect->y / (GLfloat)texture->h;
+    vertices[vertex_index].angle = (GLfloat)(360.0f - angle);
+    vertices[vertex_index].center[0] = (center->x + dstrect->x);
+    vertices[vertex_index].center[1] = (center->y + dstrect->y);
+    vertices[vertex_index].color[0] = r;
+    vertices[vertex_index].color[1] = g;
+    vertices[vertex_index].color[2] = b;
+    vertices[vertex_index].color[3] = a;
+    //2
+    ++vertex_index;
+    vertices[vertex_index].pos[0] = (dstrect->x + dstrect->w);
+    vertices[vertex_index].pos[1] = (dstrect->y + dstrect->h);
+    vertices[vertex_index].tex[0] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
+    vertices[vertex_index].tex[1] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
+    vertices[vertex_index].angle = (GLfloat)(360.0f - angle);
+    vertices[vertex_index].center[0] = (center->x + dstrect->x);
+    vertices[vertex_index].center[1] = (center->y + dstrect->y);
+    vertices[vertex_index].color[0] = r;
+    vertices[vertex_index].color[1] = g;
+    vertices[vertex_index].color[2] = b;
+    vertices[vertex_index].color[3] = a;
+    //3
+    ++vertex_index;
+    vertices[vertex_index].pos[0] = (dstrect->x + dstrect->w);
+    vertices[vertex_index].pos[1] = (dstrect->y + dstrect->h);
+    vertices[vertex_index].tex[0] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
+    vertices[vertex_index].tex[1] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
+    vertices[vertex_index].angle = (GLfloat)(360.0f - angle);
+    vertices[vertex_index].center[0] = (center->x + dstrect->x);
+    vertices[vertex_index].center[1] = (center->y + dstrect->y);
+    vertices[vertex_index].color[0] = r;
+    vertices[vertex_index].color[1] = g;
+    vertices[vertex_index].color[2] = b;
+    vertices[vertex_index].color[3] = a;
+    //4
+    ++vertex_index;
+    vertices[vertex_index].pos[0] = dstrect->x;
+    vertices[vertex_index].pos[1] = (dstrect->y + dstrect->h);
+    vertices[vertex_index].tex[0] = srcrect->x / (GLfloat)texture->w;
+    vertices[vertex_index].tex[1] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
+    vertices[vertex_index].angle = (GLfloat)(360.0f - angle);
+    vertices[vertex_index].center[0] = (center->x + dstrect->x);
+    vertices[vertex_index].center[1] = (center->y + dstrect->y);
+    vertices[vertex_index].color[0] = r;
+    vertices[vertex_index].color[1] = g;
+    vertices[vertex_index].color[2] = b;
+    vertices[vertex_index].color[3] = a;
+
+    //5
+    ++vertex_index;
+    vertices[vertex_index].pos[0] = dstrect->x;
+    vertices[vertex_index].pos[1] = dstrect->y;
+    vertices[vertex_index].tex[0] = srcrect->x / (GLfloat)texture->w;
+    vertices[vertex_index].tex[1] = srcrect->y / (GLfloat)texture->h;
+    vertices[vertex_index].angle = (GLfloat)(360.0f - angle);
+    vertices[vertex_index].center[0] = (center->x + dstrect->x);
+    vertices[vertex_index].center[1] = (center->y + dstrect->y);
+    vertices[vertex_index].color[0] = r;
+    vertices[vertex_index].color[1] = g;
+    vertices[vertex_index].color[2] = b;
+    vertices[vertex_index].color[3] = a;
 
-    data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
-    data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
-    fAngle[0] = fAngle[1] = fAngle[2] = fAngle[3] = (GLfloat)(360.0f - angle);
-    /* Calculate the center of rotation */
-    translate[0] = translate[2] = translate[4] = translate[6] = (center->x + dstrect->x);
-    translate[1] = translate[3] = translate[5] = translate[7] = (center->y + dstrect->y);
-
-    /* Emit the textured quad */
-    vertices[0] = dstrect->x;
-    vertices[1] = dstrect->y;
-    vertices[2] = (dstrect->x + dstrect->w);
-    vertices[3] = dstrect->y;
-    vertices[4] = dstrect->x;
-    vertices[5] = (dstrect->y + dstrect->h);
-    vertices[6] = (dstrect->x + dstrect->w);
-    vertices[7] = (dstrect->y + dstrect->h);
     if (flip & SDL_FLIP_HORIZONTAL) {
-        tmp = vertices[0];
-        vertices[0] = vertices[4] = vertices[2];
-        vertices[2] = vertices[6] = tmp;
+        tmp = vertices[vertex_index_start + 0].pos[0];
+        vertices[vertex_index_start + 0].pos[0] = vertices[vertex_index_start + 4].pos[0] = vertices[vertex_index_start + 5].pos[0] = vertices[vertex_index_start + 1].pos[0];
+        vertices[vertex_index_start + 1].pos[0] = vertices[vertex_index_start + 2].pos[0] = vertices[vertex_index_start + 3].pos[0] = tmp;
     }
     if (flip & SDL_FLIP_VERTICAL) {
-        tmp = vertices[1];
-        vertices[1] = vertices[3] = vertices[5];
-        vertices[5] = vertices[7] = tmp;
-    }
-
-    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 1, GL_FLOAT, GL_FALSE, 0, &fAngle);
-    data->glVertexAttribPointer(GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, 0, translate);
-    data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
-
-    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_ANGLE, fAngle, 4 * sizeof(GLfloat));
-    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_CENTER, translate, 8 * sizeof(GLfloat));
-    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
-
-    texCoords[0] = srcrect->x / (GLfloat)texture->w;
-    texCoords[1] = srcrect->y / (GLfloat)texture->h;
-    texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
-    texCoords[3] = srcrect->y / (GLfloat)texture->h;
-    texCoords[4] = srcrect->x / (GLfloat)texture->w;
-    texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
-    texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
-    texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
-    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);*/
-    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_TEXCOORD, texCoords, 8 * sizeof(GLfloat));
-    data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-    data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
-    data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
+        tmp = vertices[0].pos[1];
+        vertices[vertex_index_start + 0].pos[1] = vertices[vertex_index_start + 1].pos[1] = vertices[vertex_index_start + 5].pos[1] = vertices[vertex_index_start + 2].pos[1];
+        vertices[vertex_index_start + 2].pos[1] = vertices[vertex_index_start + 3].pos[1] = vertices[vertex_index_start + 4].pos[1] = tmp;
+    }
+
+    data->vertices_current_offset += 6;
 
     return GL_CheckError("", renderer);
 }
@@ -1991,6 +2081,7 @@ static void
 GLES2_RenderPresent(SDL_Renderer *renderer)
 {
     GLES2_ActivateRenderer(renderer);
+    GLES2_FlushVertices(renderer);
 
     /* Tell the video driver to swap buffers */
     SDL_GL_SwapWindow(renderer->window);
@@ -2065,6 +2156,9 @@ GLES2_ResetState(SDL_Renderer *renderer)
                         (GLfloat) data->clear_a * inv255f);
 
     data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
+    data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_COLOR);
+    data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
+    data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
     data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
 
     GL_CheckError("", renderer);
@@ -2205,6 +2299,32 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
     data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer);
     data->window_framebuffer = (GLuint)window_framebuffer;
 
+    data->vertices = SDL_malloc(sizeof(Vertex) * GLES2_VERTEX_MAX_VERTICES);
+    if (!data->vertices)
+    {
+        GLES2_DestroyRenderer(renderer);
+        SDL_OutOfMemory();
+        goto error;
+    }
+
+    data->draw_commands = SDL_calloc(GLES2_VERTEX_MAX_VERTICES, sizeof(DrawCommand));
+    if (!data->draw_commands)
+    {
+        GLES2_DestroyRenderer(renderer);
+        SDL_OutOfMemory();
+        goto error;
+    }
+    data->draw_command_current_offset = -1;
+    data->vertices_current_offset = 0;
+#if SDL_GLES2_USE_VBOS
+    if (!data->VBO) {
+        data->glGenBuffers(1, &data->VBO);
+        data->glBindBuffer(GL_ARRAY_BUFFER, data->VBO);
+        data->glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * GLES2_VERTEX_MAX_VERTICES, data->vertices, GL_STREAM_DRAW);
+        data->glBindBuffer(GL_ARRAY_BUFFER, 0);
+    }
+#endif
+
     /* Populate the function pointers for the module */
     renderer->WindowEvent         = GLES2_WindowEvent;
     renderer->GetOutputSize       = GLES2_GetOutputSize;
@@ -2253,6 +2373,103 @@ error:
     return NULL;
 }
 
+static void GLES2_CheckAndAddNewCommand(SDL_Renderer *renderer, SDL_Texture* texture, SDL_BlendMode blendMode, GLenum primitive_type, int count)
+{
+    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
+    DrawCommand* draw_info = data->draw_commands;
+    int offset = 0;
+    int draw_info_index = data->draw_command_current_offset;
+    if (draw_info_index == -1 || draw_info[draw_info_index].texture != texture || draw_info[draw_info_index].blend_mode != blendMode || draw_info[draw_info_index].primitive_type != primitive_type) {
+        ++draw_info_index;
+        ++data->draw_command_current_offset;
+        if (draw_info_index)
+        {
+            offset = draw_info[draw_info_index - 1].offset + draw_info[draw_info_index - 1].size;
+        }
+        draw_info[draw_info_index].blend_mode = blendMode;
+        draw_info[draw_info_index].primitive_type = primitive_type;
+        draw_info[draw_info_index].size = count;
+        draw_info[draw_info_index].texture = texture;
+        //TODO make texture used (prevent delete before draw)
+        draw_info[draw_info_index].offset = offset;
+    }
+    else {
+        draw_info[draw_info_index].size += count;
+    }
+}
+
+static int GLES2_FlushVertices(SDL_Renderer *renderer)
+{
+    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
+    Vertex* vertices = data->vertices;
+    char* ptr = (char*)vertices;
+    DrawCommand* commands = data->draw_commands;
+    int commands_count = data->draw_command_current_offset + 1;
+    int vertices_count = data->vertices_current_offset;
+    GLenum type;
+    int size;
+    int offset;
+    SDL_Texture* texture;
+    GLES2_TextureData *texture_data;
+    SDL_BlendMode blendMode;
+    int result;
+    int i;
+    const size_t pos = offsetof(struct  Vertex, pos);
+    const size_t tex = offsetof(struct  Vertex, tex);
+    const size_t angle = offsetof(struct  Vertex, angle);
+    const size_t center = offsetof(struct  Vertex, center);
+    const size_t color = offsetof(struct  Vertex, color);
+
+    GLES2_ActivateRenderer(renderer);
+
+#if SDL_GLES2_USE_VBOS
+    data->glBindBuffer(GL_ARRAY_BUFFER, data->VBO);
+    data->glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * vertices_count, vertices);
+    ptr = 0;
+#endif
+
+    data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(ptr + pos));
+    data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(ptr + tex));
+    data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(ptr + angle));
+    data->glVertexAttribPointer(GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(ptr + center));
+    data->glVertexAttribPointer(GLES2_ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(ptr + color));
+
+    for (i = 0; i < commands_count; ++i)
+    {
+        type = commands[i].primitive_type;
+        texture = commands[i].texture;
+        blendMode = commands[i].blend_mode;
+        size = commands[i].size;
+        offset = commands[i].offset;
+        if (type == GL_TRIANGLES && texture) {
+            texture_data = (GLES2_TextureData*)texture->driverdata;
+            texture_data->in_batch = SDL_FALSE;
+            texture->blendMode = blendMode;
+            //data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
+            //data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
+            result = GLES2_SetupCopy(renderer, texture);
+        }
+        else
+        {
+            //data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
+            //data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
+            renderer->blendMode = blendMode;
+            result = GLES2_SetDrawingState(renderer);
+        }
+        if (result < 0)
+            continue;
+        data->glDrawArrays(type, offset, size);
+    }
+
+    //SDL_memset(vertices, 0, sizeof(Vertex) * GLES2_VERTEX_MAX_VERTICES);
+    data->draw_command_current_offset = -1;
+    data->vertices_current_offset = 0;
+#if SDL_GLES2_USE_VBOS
+    data->glBindBuffer(GL_ARRAY_BUFFER, 0);
+#endif
+    return GL_CheckError("", renderer);
+}
+
 #endif /* SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED */
 
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/../downloads/SDL2-2.0.8/src/render/opengles2/SDL_shaders_gles2.c b/./sdl/src/render/opengles2/SDL_shaders_gles2.c
index b0bcdff..138cc1c 100644
--- a/../downloads/SDL2-2.0.8/src/render/opengles2/SDL_shaders_gles2.c
+++ b/./sdl/src/render/opengles2/SDL_shaders_gles2.c
@@ -37,7 +37,9 @@ static const Uint8 GLES2_VertexSrc_Default_[] = " \
     attribute vec2 a_texCoord; \
     attribute float a_angle; \
     attribute vec2 a_center; \
+    attribute vec4 a_color; \
     varying vec2 v_texCoord; \
+    varying vec4 v_color; \
     \
     void main() \
     { \
@@ -49,29 +51,30 @@ static const Uint8 GLES2_VertexSrc_Default_[] = " \
         v_texCoord = a_texCoord; \
         gl_Position = u_projection * vec4(position, 0.0, 1.0);\
         gl_PointSize = 1.0; \
+        v_color = a_color; \
     } \
 ";
 
 static const Uint8 GLES2_FragmentSrc_SolidSrc_[] = " \
     precision mediump float; \
-    uniform vec4 u_color; \
+    varying vec4 v_color; \
     \
     void main() \
     { \
-        gl_FragColor = u_color; \
+        gl_FragColor = v_color; \
     } \
 ";
 
 static const Uint8 GLES2_FragmentSrc_TextureABGRSrc_[] = " \
     precision mediump float; \
     uniform sampler2D u_texture; \
-    uniform vec4 u_modulation; \
+    varying vec4 v_color; \
     varying vec2 v_texCoord; \
     \
     void main() \
     { \
         gl_FragColor = texture2D(u_texture, v_texCoord); \
-        gl_FragColor *= u_modulation; \
+        gl_FragColor *= v_color; \
     } \
 ";
 
@@ -79,7 +82,7 @@ static const Uint8 GLES2_FragmentSrc_TextureABGRSrc_[] = " \
 static const Uint8 GLES2_FragmentSrc_TextureARGBSrc_[] = " \
     precision mediump float; \
     uniform sampler2D u_texture; \
-    uniform vec4 u_modulation; \
+    varying vec4 v_color; \
     varying vec2 v_texCoord; \
     \
     void main() \
@@ -88,7 +91,7 @@ static const Uint8 GLES2_FragmentSrc_TextureARGBSrc_[] = " \
         gl_FragColor = abgr; \
         gl_FragColor.r = abgr.b; \
         gl_FragColor.b = abgr.r; \
-        gl_FragColor *= u_modulation; \
+        gl_FragColor *= v_color; \
     } \
 ";
 
@@ -96,7 +99,7 @@ static const Uint8 GLES2_FragmentSrc_TextureARGBSrc_[] = " \
 static const Uint8 GLES2_FragmentSrc_TextureRGBSrc_[] = " \
     precision mediump float; \
     uniform sampler2D u_texture; \
-    uniform vec4 u_modulation; \
+    varying vec4 v_color; \
     varying vec2 v_texCoord; \
     \
     void main() \
@@ -106,7 +109,7 @@ static const Uint8 GLES2_FragmentSrc_TextureRGBSrc_[] = " \
         gl_FragColor.r = abgr.b; \
         gl_FragColor.b = abgr.r; \
         gl_FragColor.a = 1.0; \
-        gl_FragColor *= u_modulation; \
+        gl_FragColor *= v_color; \
     } \
 ";
 
@@ -114,7 +117,7 @@ static const Uint8 GLES2_FragmentSrc_TextureRGBSrc_[] = " \
 static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
     precision mediump float; \
     uniform sampler2D u_texture; \
-    uniform vec4 u_modulation; \
+    varying vec4 v_color; \
     varying vec2 v_texCoord; \
     \
     void main() \
@@ -122,7 +125,7 @@ static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
         vec4 abgr = texture2D(u_texture, v_texCoord); \
         gl_FragColor = abgr; \
         gl_FragColor.a = 1.0; \
-        gl_FragColor *= u_modulation; \
+        gl_FragColor *= v_color; \
     } \
 ";
 
@@ -159,7 +162,7 @@ static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
 "uniform sampler2D u_texture;\n"                                \
 "uniform sampler2D u_texture_u;\n"                              \
 "uniform sampler2D u_texture_v;\n"                              \
-"uniform vec4 u_modulation;\n"                                  \
+"varying vec4 v_color;\n"                                  \
 "varying vec2 v_texCoord;\n"                                    \
 "\n"                                                            \
 
@@ -181,7 +184,7 @@ static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
 "\n"                                                            \
 "    // That was easy. :) \n"                                   \
 "    gl_FragColor = vec4(rgb, 1);\n"                            \
-"    gl_FragColor *= u_modulation;\n"                           \
+"    gl_FragColor *= v_color;\n"                           \
 "}"                                                             \
 
 #define NV12_SHADER_BODY                                        \
@@ -201,7 +204,7 @@ static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
 "\n"                                                            \
 "    // That was easy. :) \n"                                   \
 "    gl_FragColor = vec4(rgb, 1);\n"                            \
-"    gl_FragColor *= u_modulation;\n"                           \
+"    gl_FragColor *= v_color;\n"                           \
 "}"                                                             \
 
 #define NV21_SHADER_BODY                                        \
@@ -221,7 +224,7 @@ static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
 "\n"                                                            \
 "    // That was easy. :) \n"                                   \
 "    gl_FragColor = vec4(rgb, 1);\n"                            \
-"    gl_FragColor *= u_modulation;\n"                           \
+"    gl_FragColor *= v_color;\n"                           \
 "}"                                                             \
 
 /* YUV to ABGR conversion */
@@ -280,13 +283,13 @@ static const Uint8 GLES2_FragmentSrc_TextureExternalOESSrc_[] = " \
     #extension GL_OES_EGL_image_external : require\n\
     precision mediump float; \
     uniform samplerExternalOES u_texture; \
-    uniform vec4 u_modulation; \
+    varying vec4 v_color; \
     varying vec2 v_texCoord; \
     \
     void main() \
     { \
         gl_FragColor = texture2D(u_texture, v_texCoord); \
-        gl_FragColor *= u_modulation; \
+        gl_FragColor *= v_color; \
     } \
 ";
 
