opengles2: Use client-side arrays on everything but Emscripten. Turns out they're much faster! Fixes #5206.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c
index c38ee97..2df9d54 100644
--- a/src/render/opengles2/SDL_render_gles2.c
+++ b/src/render/opengles2/SDL_render_gles2.c
@@ -28,6 +28,16 @@
#include "../../video/SDL_blit.h"
#include "SDL_shaders_gles2.h"
+/* WebGL doesn't offer client-side arrays, so use Vertex Buffer Objects
+ on Emscripten, which converts GLES2 into WebGL calls.
+ In all other cases, attempt to use client-side arrays, as they tend to
+ be faster. */
+#if defined(__EMSCRIPTEN__)
+#define USE_VERTEX_BUFFER_OBJECTS 1
+#else
+#define USE_VERTEX_BUFFER_OBJECTS 0
+#endif
+
/* To prevent unnecessary window recreation,
* these should match the defaults selected in SDL_GL_ResetAttributes
*/
@@ -151,9 +161,12 @@ typedef struct GLES2_RenderData
GLES2_ProgramCache program_cache;
Uint8 clear_r, clear_g, clear_b, clear_a;
+#if USE_VERTEX_BUFFER_OBJECTS
GLuint vertex_buffers[8];
size_t vertex_buffer_size[8];
int current_vertex_buffer;
+#endif
+
GLES2_DrawStateCache drawstate;
} GLES2_RenderData;
@@ -844,7 +857,7 @@ GLES2_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture
}
static int
-SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_ImageSource imgsrc)
+SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_ImageSource imgsrc, void *vertices)
{
SDL_Texture *texture = cmd->data.draw.texture;
const SDL_BlendMode blend = cmd->data.draw.blend;
@@ -926,7 +939,7 @@ SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_I
}
if (texture) {
- SDL_Vertex *verts = (SDL_Vertex *) (cmd->data.draw.first);
+ SDL_Vertex *verts = (SDL_Vertex *) (((Uint8 *) vertices) + cmd->data.draw.first);
data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, (const GLvoid *)&verts->tex_coord);
}
@@ -960,7 +973,7 @@ SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_I
/* all drawing commands use this */
{
- SDL_VertexSolid *verts = (SDL_VertexSolid *) (cmd->data.draw.first);
+ SDL_VertexSolid *verts = (SDL_VertexSolid *) (((Uint8 *) vertices) + cmd->data.draw.first);
data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, stride, (const GLvoid *) &verts->position);
data->glVertexAttribPointer(GLES2_ATTRIBUTE_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE /* Normalized */, stride, (const GLvoid *) &verts->color);
}
@@ -969,7 +982,7 @@ SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_I
}
static int
-SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd)
+SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, void *vertices)
{
GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
@@ -1079,7 +1092,7 @@ SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd)
}
}
- return SetDrawState(data, cmd, sourceType);
+ return SetDrawState(data, cmd, sourceType, vertices);
}
static int
@@ -1087,8 +1100,11 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
{
GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
const SDL_bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || renderer->target->format == SDL_PIXELFORMAT_RGB888));
+
+#if USE_VERTEX_BUFFER_OBJECTS
const int vboidx = data->current_vertex_buffer;
const GLuint vbo = data->vertex_buffers[vboidx];
+#endif
if (GLES2_ActivateRenderer(renderer) < 0) {
return -1;
@@ -1106,6 +1122,7 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
}
}
+#if USE_VERTEX_BUFFER_OBJECTS
/* upload the new VBO data for this set of commands. */
data->glBindBuffer(GL_ARRAY_BUFFER, vbo);
if (data->vertex_buffer_size[vboidx] < vertsize) {
@@ -1120,6 +1137,8 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
if (data->current_vertex_buffer >= SDL_arraysize(data->vertex_buffers)) {
data->current_vertex_buffer = 0;
}
+ vertices = NULL; /* attrib pointers will be offsets into the VBO. */
+#endif
while (cmd) {
switch (cmd->command) {
@@ -1184,7 +1203,7 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
break;
case SDL_RENDERCMD_DRAW_LINES: {
- if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID) == 0) {
+ if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID, vertices) == 0) {
size_t count = cmd->data.draw.count;
if (count > 2) {
/* joined lines cannot be grouped */
@@ -1242,9 +1261,9 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
}
if (thistexture) {
- ret = SetCopyState(renderer, cmd);
+ ret = SetCopyState(renderer, cmd, vertices);
} else {
- ret = SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID);
+ ret = SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID, vertices);
}
if (ret == 0) {
@@ -1308,8 +1327,10 @@ GLES2_DestroyRenderer(SDL_Renderer *renderer)
data->framebuffers = nextnode;
}
+#if USE_VERTEX_BUFFER_OBJECTS
data->glDeleteBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
GL_CheckError("", renderer);
+#endif
SDL_GL_DeleteContext(data->context);
}
@@ -2071,8 +2092,10 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
renderer->info.max_texture_height = value;
+#if USE_VERTEX_BUFFER_OBJECTS
/* we keep a few of these and cycle through them, so data can live for a few frames. */
data->glGenBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
+#endif
data->framebuffers = NULL;
data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer);