From f9b918ff403782986f2a6712e6e2a462767a0457 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 11 Jan 2022 16:15:45 -0500 Subject: [PATCH] opengles2: Use client-side arrays on everything but Emscripten. Turns out they're much faster! Fixes #5206. --- src/render/opengles2/SDL_render_gles2.c | 39 ++++++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index c38ee9723..2df9d5463 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);