opengles2: Use client-side arrays on everything but Emscripten.

Turns out they're much faster!

Fixes #5206.
This commit is contained in:
Ryan C. Gordon 2022-01-11 16:15:45 -05:00
parent bb9ebad74b
commit f9b918ff40
1 changed files with 31 additions and 8 deletions

View File

@ -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);