From 74c460fb67ca239d479807d16ca9c48cca3687ba Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Sun, 18 Oct 2020 10:41:42 +0100 Subject: [PATCH] Reduce glBufferSubData calls in legacy renderer This is part of effort to make more efficient use of the API for devices with poor drivers. This eliminates multiple calls to glBufferSubData per update. --- .../gles2/rasterizer_canvas_base_gles2.cpp | 32 ++++++++++++++----- drivers/gles2/rasterizer_storage_gles2.cpp | 7 ++-- .../gles3/rasterizer_canvas_base_gles3.cpp | 32 ++++++++++++++----- drivers/gles3/rasterizer_storage_gles3.cpp | 3 +- 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/drivers/gles2/rasterizer_canvas_base_gles2.cpp b/drivers/gles2/rasterizer_canvas_base_gles2.cpp index d7c85646a0b..ab78ec3b855 100644 --- a/drivers/gles2/rasterizer_canvas_base_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_base_gles2.cpp @@ -446,8 +446,21 @@ void RasterizerCanvasBaseGLES2::_draw_polygon(const int *p_indices, int p_index_ glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + // precalculate the buffer size ahead of time instead of making multiple glBufferSubData calls + uint32_t total_buffer_size = sizeof(Vector2) * p_vertex_count; + if (!p_singlecolor && p_colors) { + total_buffer_size += sizeof(Color) * p_vertex_count; + } + if (p_uvs) { + total_buffer_size += sizeof(Vector2) * p_vertex_count; + } + if (p_weights && p_bones) { + total_buffer_size += sizeof(float) * 4 * p_vertex_count; // weights + total_buffer_size += sizeof(int) * 4 * p_vertex_count; // bones + } + uint32_t buffer_ofs = 0; - storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices); + storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, total_buffer_size, p_vertices); glEnableVertexAttribArray(VS::ARRAY_VERTEX); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); @@ -461,14 +474,12 @@ void RasterizerCanvasBaseGLES2::_draw_polygon(const int *p_indices, int p_index_ glDisableVertexAttribArray(VS::ARRAY_COLOR); glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); } else { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); glEnableVertexAttribArray(VS::ARRAY_COLOR); glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Color) * p_vertex_count; } if (p_uvs) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Vector2) * p_vertex_count; @@ -477,12 +488,10 @@ void RasterizerCanvasBaseGLES2::_draw_polygon(const int *p_indices, int p_index_ } if (p_weights && p_bones) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights); glEnableVertexAttribArray(VS::ARRAY_WEIGHTS); glVertexAttribPointer(VS::ARRAY_WEIGHTS, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(float) * 4 * p_vertex_count; - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones); glEnableVertexAttribArray(VS::ARRAY_BONES); glVertexAttribPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, GL_FALSE, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(int) * 4 * p_vertex_count; @@ -516,8 +525,17 @@ void RasterizerCanvasBaseGLES2::_draw_generic(GLuint p_primitive, int p_vertex_c glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + // precalculate the buffer size ahead of time instead of making multiple glBufferSubData calls + uint32_t total_buffer_size = sizeof(Vector2) * p_vertex_count; + if (!p_singlecolor && p_colors) { + total_buffer_size += sizeof(Color) * p_vertex_count; + } + if (p_uvs) { + total_buffer_size += sizeof(Vector2) * p_vertex_count; + } + uint32_t buffer_ofs = 0; - storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices); + storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, total_buffer_size, p_vertices); glEnableVertexAttribArray(VS::ARRAY_VERTEX); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); @@ -531,14 +549,12 @@ void RasterizerCanvasBaseGLES2::_draw_generic(GLuint p_primitive, int p_vertex_c glDisableVertexAttribArray(VS::ARRAY_COLOR); glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); } else { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); glEnableVertexAttribArray(VS::ARRAY_COLOR); glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Color) * p_vertex_count; } if (p_uvs) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); } else { diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 55ae2d3f373..80b5b5a1c31 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -3788,14 +3788,17 @@ void RasterizerStorageGLES2::_update_skeleton_transform_buffer(const PoolVector< glBindBuffer(GL_ARRAY_BUFFER, resources.skeleton_transform_buffer); + uint32_t buffer_size = p_size * sizeof(float); + if (p_size > resources.skeleton_transform_buffer_size) { // new requested buffer is bigger, so resizing the GPU buffer resources.skeleton_transform_buffer_size = p_size; - glBufferData(GL_ARRAY_BUFFER, p_size * sizeof(float), p_data.read().ptr(), GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, buffer_size, p_data.read().ptr(), GL_DYNAMIC_DRAW); } else { - glBufferSubData(GL_ARRAY_BUFFER, 0, p_size * sizeof(float), p_data.read().ptr()); + // this may not be best, it could be better to use glBufferData in both cases. + buffer_orphan_and_upload(resources.skeleton_transform_buffer_size, 0, buffer_size, p_data.read().ptr()); } glBindBuffer(GL_ARRAY_BUFFER, 0); diff --git a/drivers/gles3/rasterizer_canvas_base_gles3.cpp b/drivers/gles3/rasterizer_canvas_base_gles3.cpp index e60e06be40f..eebe9e75405 100644 --- a/drivers/gles3/rasterizer_canvas_base_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_base_gles3.cpp @@ -348,8 +348,21 @@ void RasterizerCanvasBaseGLES3::_draw_polygon(const int *p_indices, int p_index_ glBindVertexArray(data.polygon_buffer_pointer_array); glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + // precalculate the buffer size ahead of time instead of making multiple glBufferSubData calls + uint32_t total_buffer_size = sizeof(Vector2) * p_vertex_count; + if (!p_singlecolor && p_colors) { + total_buffer_size += sizeof(Color) * p_vertex_count; + } + if (p_uvs) { + total_buffer_size += sizeof(Vector2) * p_vertex_count; + } + if (p_weights && p_bones) { + total_buffer_size += sizeof(int) * 4 * p_vertex_count; // bones + total_buffer_size += sizeof(float) * 4 * p_vertex_count; // weights + } + uint32_t buffer_ofs = 0; - storage->buffer_orphan_and_upload(data.polygon_buffer_size, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices); + storage->buffer_orphan_and_upload(data.polygon_buffer_size, buffer_ofs, total_buffer_size, p_vertices); glEnableVertexAttribArray(VS::ARRAY_VERTEX); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); @@ -368,7 +381,6 @@ void RasterizerCanvasBaseGLES3::_draw_polygon(const int *p_indices, int p_index_ glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); } else { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); glEnableVertexAttribArray(VS::ARRAY_COLOR); glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Color) * p_vertex_count; @@ -380,7 +392,6 @@ void RasterizerCanvasBaseGLES3::_draw_polygon(const int *p_indices, int p_index_ if (p_uvs) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Vector2) * p_vertex_count; @@ -395,13 +406,11 @@ void RasterizerCanvasBaseGLES3::_draw_polygon(const int *p_indices, int p_index_ if (p_bones && p_weights) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones); glEnableVertexAttribArray(VS::ARRAY_BONES); //glVertexAttribPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, false, sizeof(int) * 4, ((uint8_t *)0) + buffer_ofs); glVertexAttribIPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(int) * 4 * p_vertex_count; - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights); glEnableVertexAttribArray(VS::ARRAY_WEIGHTS); glVertexAttribPointer(VS::ARRAY_WEIGHTS, 4, GL_FLOAT, false, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(float) * 4 * p_vertex_count; @@ -439,9 +448,18 @@ void RasterizerCanvasBaseGLES3::_draw_generic(GLuint p_primitive, int p_vertex_c glBindVertexArray(data.polygon_buffer_pointer_array); glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + // precalculate the buffer size ahead of time instead of making multiple glBufferSubData calls + uint32_t total_buffer_size = sizeof(Vector2) * p_vertex_count; + if (!p_singlecolor && p_colors) { + total_buffer_size += sizeof(Color) * p_vertex_count; + } + if (p_uvs) { + total_buffer_size += sizeof(Vector2) * p_vertex_count; + } + //vertex uint32_t buffer_ofs = 0; - storage->buffer_orphan_and_upload(data.polygon_buffer_size, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices); + storage->buffer_orphan_and_upload(data.polygon_buffer_size, buffer_ofs, total_buffer_size, p_vertices); glEnableVertexAttribArray(VS::ARRAY_VERTEX); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); @@ -457,7 +475,6 @@ void RasterizerCanvasBaseGLES3::_draw_generic(GLuint p_primitive, int p_vertex_c glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); } else { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); glEnableVertexAttribArray(VS::ARRAY_COLOR); glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Color) * p_vertex_count; @@ -465,7 +482,6 @@ void RasterizerCanvasBaseGLES3::_draw_generic(GLuint p_primitive, int p_vertex_c if (p_uvs) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Vector2) * p_vertex_count; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 71ee1c17b5b..77021631c6e 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -5085,7 +5085,8 @@ void RasterizerStorageGLES3::update_dirty_multimeshes() { if (multimesh->size && multimesh->dirty_data) { glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer); - glBufferSubData(GL_ARRAY_BUFFER, 0, multimesh->data.size() * sizeof(float), multimesh->data.ptr()); + uint32_t buffer_size = multimesh->data.size() * sizeof(float); + glBufferData(GL_ARRAY_BUFFER, buffer_size, multimesh->data.ptr(), GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); }