From 7a18190c5c8b83930f77bedc02d7168b20dfddd6 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 3 Nov 2020 22:12:56 -0400 Subject: [PATCH] Restructure SpriteBatch internal vertex data --- src/modules/graphics/SpriteBatch.cpp | 84 +++++++++++++++++----------- src/modules/graphics/SpriteBatch.h | 8 ++- 2 files changed, 57 insertions(+), 35 deletions(-) diff --git a/src/modules/graphics/SpriteBatch.cpp b/src/modules/graphics/SpriteBatch.cpp index 677f69352..285564f3e 100644 --- a/src/modules/graphics/SpriteBatch.cpp +++ b/src/modules/graphics/SpriteBatch.cpp @@ -47,6 +47,9 @@ SpriteBatch::SpriteBatch(Graphics *gfx, Texture *texture, int size, BufferUsage , color(255, 255, 255, 255) , colorf(1.0f, 1.0f, 1.0f, 1.0f) , array_buf(nullptr) + , vertex_data(nullptr) + , modified_sprite_first(LOVE_INT32_MAX) + , modified_sprite_last(0) , range_start(-1) , range_count(-1) { @@ -64,14 +67,22 @@ SpriteBatch::SpriteBatch(Graphics *gfx, Texture *texture, int size, BufferUsage vertex_stride = getFormatStride(vertex_format); size_t vertex_size = vertex_stride * 4 * size; + + vertex_data = (uint8 *) malloc(vertex_size); + if (vertex_data == nullptr) + throw love::Exception("Out of memory."); + + memset(vertex_data, 0, vertex_size); + Buffer::Settings settings(Buffer::TYPEFLAG_VERTEX, Buffer::MAP_EXPLICIT_RANGE_MODIFY, usage); auto decl = Buffer::getCommonFormatDeclaration(vertex_format); - array_buf = gfx->newBuffer(settings, decl, nullptr, vertex_size, 0); + + array_buf.set(gfx->newBuffer(settings, decl, nullptr, vertex_size, 0), Acquire::NORETAIN); } SpriteBatch::~SpriteBatch() { - delete array_buf; + free(vertex_data); } int SpriteBatch::add(const Matrix4 &m, int index /*= -1*/) @@ -93,9 +104,10 @@ int SpriteBatch::add(Quad *quad, const Matrix4 &m, int index /*= -1*/) const Vector2 *quadpositions = quad->getVertexPositions(); const Vector2 *quadtexcoords = quad->getVertexTexCoords(); - // Always keep the buffer mapped when adding data (it'll be unmapped on draw.) - size_t offset = (index == -1 ? next : index) * vertex_stride * 4; - auto verts = (XYf_STf_RGBAub *) ((uint8 *) array_buf->map() + offset); + int spriteindex = (index == -1 ? next : index); + + size_t offset = spriteindex * vertex_stride * 4; + auto verts = (XYf_STf_RGBAub *) (vertex_data + offset); m.transformXY(verts, quadpositions, 4); @@ -106,7 +118,8 @@ int SpriteBatch::add(Quad *quad, const Matrix4 &m, int index /*= -1*/) verts[i].color = color; } - array_buf->setMappedRangeModified(offset, vertex_stride * 4); + modified_sprite_first = std::min(modified_sprite_first, spriteindex); + modified_sprite_last = std::max(modified_sprite_last, spriteindex); // Increment counter. if (index == -1) @@ -137,9 +150,10 @@ int SpriteBatch::addLayer(int layer, Quad *quad, const Matrix4 &m, int index) const Vector2 *quadpositions = quad->getVertexPositions(); const Vector2 *quadtexcoords = quad->getVertexTexCoords(); - // Always keep the buffer mapped when adding data (it'll be unmapped on draw.) - size_t offset = (index == -1 ? next : index) * vertex_stride * 4; - auto verts = (XYf_STPf_RGBAub *) ((uint8 *) array_buf->map() + offset); + int spriteindex = (index == -1 ? next : index); + + size_t offset = spriteindex * vertex_stride * 4; + auto verts = (XYf_STPf_RGBAub *) (vertex_data + offset); m.transformXY(verts, quadpositions, 4); @@ -151,7 +165,8 @@ int SpriteBatch::addLayer(int layer, Quad *quad, const Matrix4 &m, int index) verts[i].color = color; } - array_buf->setMappedRangeModified(offset, vertex_stride * 4); + modified_sprite_first = std::min(modified_sprite_first, spriteindex); + modified_sprite_last = std::max(modified_sprite_last, spriteindex); // Increment counter. if (index == -1) @@ -168,7 +183,20 @@ void SpriteBatch::clear() void SpriteBatch::flush() { - array_buf->unmap(); + if (modified_sprite_first <= modified_sprite_last) + { + size_t offset = modified_sprite_first * vertex_stride * 4; + size_t size = (modified_sprite_last - modified_sprite_first) * vertex_stride * 4; + + // TODO: switch this to fill() once it gets cleaned up. + memcpy(((uint8 *)array_buf->map() + offset), vertex_data + offset, size); + + array_buf->setMappedRangeModified(offset, size); + array_buf->unmap(); + + modified_sprite_first = LOVE_INT32_MAX; + modified_sprite_last = 0; + } } void SpriteBatch::setTexture(Texture *newtexture) @@ -213,33 +241,24 @@ void SpriteBatch::setBufferSize(int newsize) return; size_t vertex_size = vertex_stride * 4 * newsize; - love::graphics::Buffer *new_array_buf = nullptr; int new_next = std::min(next, newsize); - try - { - auto gfx = Module::getInstance(Module::M_GRAPHICS); - Buffer::Settings settings(array_buf->getTypeFlags(), array_buf->getMapFlags(), array_buf->getUsage()); - auto decl = Buffer::getCommonFormatDeclaration(vertex_format); - new_array_buf = gfx->newBuffer(settings, decl, nullptr, vertex_size, 0); + void *new_vertex_data = realloc(vertex_data, vertex_size); + if (new_vertex_data == nullptr) + throw love::Exception("Out of memory."); - // Copy as much of the old data into the new GLBuffer as can fit. - size_t copy_size = vertex_stride * 4 * new_next; - array_buf->copyTo(0, copy_size, new_array_buf, 0); - } - catch (love::Exception &) - { - delete new_array_buf; - throw; - } + auto gfx = Module::getInstance(Module::M_GRAPHICS); + Buffer::Settings settings(array_buf->getTypeFlags(), array_buf->getMapFlags(), array_buf->getUsage()); + auto decl = Buffer::getCommonFormatDeclaration(vertex_format); - // We don't need to unmap the old GLBuffer since we're deleting it. - delete array_buf; + array_buf.set(gfx->newBuffer(settings, decl, nullptr, vertex_size, 0), Acquire::NORETAIN); + + array_buf->fill(0, vertex_stride * 4 * new_next, new_vertex_data); + + vertex_data = (uint8 *) new_vertex_data; - array_buf = new_array_buf; size = newsize; - next = new_next; } @@ -319,8 +338,7 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) Shader::current->checkMainTexture(texture); } - // Make sure the buffer isn't mapped when we draw (sends data to GPU if needed.) - array_buf->unmap(); + flush(); // Upload any modified sprite data to the GPU. VertexAttributes attributes; BufferBindings buffers; diff --git a/src/modules/graphics/SpriteBatch.h b/src/modules/graphics/SpriteBatch.h index 40fbfd932..0266f257f 100644 --- a/src/modules/graphics/SpriteBatch.h +++ b/src/modules/graphics/SpriteBatch.h @@ -130,8 +130,12 @@ private: CommonFormat vertex_format; size_t vertex_stride; - - love::graphics::Buffer *array_buf; + + StrongRef array_buf; + uint8 *vertex_data; + + int modified_sprite_first; + int modified_sprite_last; std::unordered_map attached_attributes;