From a45c1332a714b8dd4b7bbd5d96552120542d8cb7 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 11 Aug 2015 23:07:33 -0300 Subject: [PATCH] Cleaned up some Mesh and SpriteBatch code. --- src/modules/graphics/opengl/GLBuffer.cpp | 80 +++++++++++++++------ src/modules/graphics/opengl/GLBuffer.h | 31 ++++++-- src/modules/graphics/opengl/Mesh.cpp | 36 +++------- src/modules/graphics/opengl/Mesh.h | 5 -- src/modules/graphics/opengl/SpriteBatch.cpp | 16 ++--- src/modules/graphics/opengl/SpriteBatch.h | 4 -- 6 files changed, 96 insertions(+), 76 deletions(-) diff --git a/src/modules/graphics/opengl/GLBuffer.cpp b/src/modules/graphics/opengl/GLBuffer.cpp index b13ff89fe..416edee1e 100644 --- a/src/modules/graphics/opengl/GLBuffer.cpp +++ b/src/modules/graphics/opengl/GLBuffer.cpp @@ -34,7 +34,7 @@ namespace graphics namespace opengl { -GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage) +GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage, uint32 mapflags) : is_bound(false) , is_mapped(false) , size(size) @@ -42,6 +42,9 @@ GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage) , usage(usage) , vbo(0) , memory_map(nullptr) + , modified_offset(0) + , modified_size(0) + , map_flags(mapflags) { try { @@ -79,6 +82,9 @@ void *GLBuffer::map() is_mapped = true; + modified_offset = 0; + modified_size = 0; + return memory_map; } @@ -96,13 +102,21 @@ void GLBuffer::unmapStream() glBufferData(getTarget(), (GLsizeiptr) getSize(), memory_map, getUsage()); } -void GLBuffer::unmap(size_t usedOffset, size_t usedSize) +void GLBuffer::unmap() { if (!is_mapped) return; - usedOffset = std::min(usedOffset, getSize()); - usedSize = std::min(usedSize, getSize() - usedOffset); + if ((map_flags & MAP_EXPLICIT_RANGE_MODIFY) != 0) + { + modified_offset = std::min(modified_offset, getSize() - 1); + modified_size = std::min(modified_size, getSize() - modified_offset); + } + else + { + modified_offset = 0; + modified_size = getSize(); + } // VBO::bind is a no-op when the VBO is mapped, so we have to make sure it's // bound here. @@ -112,28 +126,52 @@ void GLBuffer::unmap(size_t usedOffset, size_t usedSize) is_bound = true; } - switch (getUsage()) + if (modified_size > 0) { - case GL_STATIC_DRAW: - unmapStatic(usedOffset, usedSize); - break; - case GL_STREAM_DRAW: - unmapStream(); - break; - case GL_DYNAMIC_DRAW: - default: - // It's probably more efficient to treat it like a streaming buffer if - // more than a third of its contents have been modified during the map(). - if (usedSize >= getSize() / 3) + switch (getUsage()) + { + case GL_STATIC_DRAW: + unmapStatic(modified_offset, modified_size); + break; + case GL_STREAM_DRAW: unmapStream(); - else - unmapStatic(usedOffset, usedSize); - break; + break; + case GL_DYNAMIC_DRAW: + default: + // It's probably more efficient to treat it like a streaming buffer if + // at least a third of its contents have been modified during the map(). + if (modified_size >= getSize() / 3) + unmapStream(); + else + unmapStatic(modified_offset, modified_size); + break; + } } + modified_offset = 0; + modified_size = 0; + is_mapped = false; } +void GLBuffer::setMappedRangeModified(size_t offset, size_t modifiedsize) +{ + if (!is_mapped || !(map_flags & MAP_EXPLICIT_RANGE_MODIFY)) + return; + + // We're being conservative right now by internally marking the whole range + // from the start of section a to the end of section b as modified if both + // a and b are marked as modified. + + size_t old_range_end = modified_offset + modified_offset; + + modified_offset = std::min(modified_offset, offset); + + size_t new_range_end = std::max(offset + modifiedsize, old_range_end); + + modified_size = new_range_end - modified_offset; +} + void GLBuffer::bind() { if (!is_mapped) @@ -155,7 +193,9 @@ void GLBuffer::fill(size_t offset, size_t size, const void *data) { memcpy(memory_map + offset, data, size); - if (!is_mapped) + if (is_mapped) + setMappedRangeModified(offset, size); + else glBufferSubData(getTarget(), (GLintptr) offset, (GLsizeiptr) size, data); } diff --git a/src/modules/graphics/opengl/GLBuffer.h b/src/modules/graphics/opengl/GLBuffer.h index 44a95e2da..940db89bf 100644 --- a/src/modules/graphics/opengl/GLBuffer.h +++ b/src/modules/graphics/opengl/GLBuffer.h @@ -47,6 +47,11 @@ class GLBuffer : public Volatile { public: + enum MapFlags + { + MAP_EXPLICIT_RANGE_MODIFY = 0x01, // see setMappedRangeModified. + }; + /** * Constructor. * @@ -54,7 +59,7 @@ public: * @param target The target GLBuffer object, e.g. GL_ARRAY_BUFFER. * @param usage Usage hint, e.g. GL_DYNAMIC_DRAW. */ - GLBuffer(size_t size, const void *data, GLenum target, GLenum usage); + GLBuffer(size_t size, const void *data, GLenum target, GLenum usage, uint32 mapflags = 0); /** * Destructor. @@ -118,12 +123,14 @@ public: * when used to draw elements. * * The GLBuffer must be bound to use this function. - * - * @param usedOffset The offset into the mapped buffer indicating the - * sub-range of data modified. Optional. - * @param usedSize The size of the sub-range of modified data. Optional. */ - void unmap(size_t usedOffset = 0, size_t usedSize = -1); + void unmap(); + + /** + * Marks a range of mapped data as modified. + * NOTE: GLBuffer::fill calls this internally for you. + **/ + void setMappedRangeModified(size_t offset, size_t size); /** * Bind the GLBuffer to its specified target. @@ -137,7 +144,7 @@ public: void unbind(); /** - * Fill a portion of the buffer with data. + * Fill a portion of the buffer with data and marks the range as modified. * * The GLBuffer must be bound to use this function. * @@ -155,6 +162,11 @@ public: */ const void *getPointer(size_t offset) const; + uint32 getMapFlags() const + { + return map_flags; + } + // Implements Volatile. bool loadVolatile() override; void unloadVolatile() override; @@ -262,6 +274,11 @@ private: // A pointer to mapped memory. char *memory_map; + size_t modified_offset; + size_t modified_size; + + uint32 map_flags; + }; // GLBuffer diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index 351daaa2b..cc0511344 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -63,8 +63,6 @@ Mesh::Mesh(const std::vector &vertexformat, const void *data, size , vbo(nullptr) , vertexCount(0) , vertexStride(0) - , vboUsedOffset(0) - , vboUsedSize(0) , ibo(nullptr) , elementCount(0) , elementDataType(0) @@ -81,7 +79,7 @@ Mesh::Mesh(const std::vector &vertexformat, const void *data, size if (vertexCount == 0) throw love::Exception("Data size is too small for specified vertex attribute formats."); - vbo = new GLBuffer(datasize, data, GL_ARRAY_BUFFER, getGLBufferUsage(usage)); + vbo = new GLBuffer(datasize, data, GL_ARRAY_BUFFER, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); vertexScratchBuffer = new char[vertexStride]; } @@ -91,8 +89,6 @@ Mesh::Mesh(const std::vector &vertexformat, int vertexcount, DrawM , vbo(nullptr) , vertexCount((size_t) vertexcount) , vertexStride(0) - , vboUsedOffset(0) - , vboUsedSize(0) , ibo(nullptr) , elementCount(0) , elementDataType(getGLDataTypeFromMax(vertexcount)) @@ -108,11 +104,12 @@ Mesh::Mesh(const std::vector &vertexformat, int vertexcount, DrawM size_t buffersize = vertexCount * vertexStride; - vbo = new GLBuffer(buffersize, nullptr, GL_ARRAY_BUFFER, getGLBufferUsage(usage)); + vbo = new GLBuffer(buffersize, nullptr, GL_ARRAY_BUFFER, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); // Initialize the buffer's contents to 0. GLBuffer::Bind bind(*vbo); memset(vbo->map(), 0, buffersize); + vbo->setMappedRangeModified(0, vbo->getSize()); vbo->unmap(); vertexScratchBuffer = new char[vertexStride]; @@ -198,8 +195,7 @@ void Mesh::setVertex(size_t vertindex, const void *data, size_t datasize) memcpy(bufferdata + offset, data, size); - vboUsedOffset = std::min(vboUsedOffset, offset); - vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset); + vbo->setMappedRangeModified(offset, size); } size_t Mesh::getVertex(size_t vertindex, void *data, size_t datasize) @@ -216,12 +212,6 @@ size_t Mesh::getVertex(size_t vertindex, void *data, size_t datasize) memcpy(data, bufferdata + offset, size); - if (vboUsedSize == 0) - { - vboUsedOffset = std::min(vboUsedOffset, offset); - vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset); - } - return size; } @@ -246,8 +236,7 @@ void Mesh::setVertexAttribute(size_t vertindex, int attribindex, const void *dat memcpy(bufferdata + offset, data, size); - vboUsedOffset = std::min(vboUsedOffset, offset); - vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset); + vbo->setMappedRangeModified(offset, size); } size_t Mesh::getVertexAttribute(size_t vertindex, int attribindex, void *data, size_t datasize) @@ -267,12 +256,6 @@ size_t Mesh::getVertexAttribute(size_t vertindex, int attribindex, void *data, s memcpy(data, bufferdata + offset, size); - if (vboUsedSize == 0) - { - vboUsedOffset = std::min(vboUsedOffset, offset); - vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset); - } - return size; } @@ -378,17 +361,15 @@ void Mesh::unmapVertexData() { // Assume the whole buffer was modified. GLBuffer::Bind bind(*vbo); + vbo->setMappedRangeModified(0, vbo->getSize()); vbo->unmap(); - - vboUsedOffset = vboUsedSize = 0; } void Mesh::flush() { { GLBuffer::Bind vbobind(*vbo); - vbo->unmap(vboUsedOffset, vboUsedSize); - vboUsedOffset = vboUsedSize = 0; + vbo->unmap(); } if (ibo != nullptr) @@ -575,8 +556,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo GLBuffer::Bind vbobind(*mesh->vbo); // Make sure the buffer isn't mapped (sends data to GPU if needed.) - mesh->vbo->unmap(mesh->vboUsedOffset, mesh->vboUsedSize); - mesh->vboUsedOffset = mesh->vboUsedSize = 0; + mesh->vbo->unmap(); size_t offset = mesh->getAttributeOffset(attrib.second.index); const void *gloffset = mesh->vbo->getPointer(offset); diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index ab608ea11..5482dec24 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -240,11 +240,6 @@ private: // avoid memory allocations when using Mesh::setVertex etc. char *vertexScratchBuffer; - // Tracks the range of the vertex buffer that has been used, to make unmap() - // calls as efficient as possible. - size_t vboUsedOffset; - size_t vboUsedSize; - // Element (vertex index) buffer, for the vertex map. GLBuffer *ibo; size_t elementCount; diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index 4998da016..6d2d12c33 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -48,8 +48,6 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, Mesh::Usage usage) , color(0) , array_buf(nullptr) , quad_indices(size) - , buffer_used_offset(0) - , buffer_used_size(0) { if (size <= 0) throw love::Exception("Invalid SpriteBatch size."); @@ -60,7 +58,7 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, Mesh::Usage usage) try { - array_buf = new GLBuffer(vertex_size, nullptr, GL_ARRAY_BUFFER, gl_usage); + array_buf = new GLBuffer(vertex_size, nullptr, GL_ARRAY_BUFFER, gl_usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); } catch (love::Exception &) { @@ -123,9 +121,7 @@ void SpriteBatch::clear() void SpriteBatch::flush() { GLBuffer::Bind bind(*array_buf); - array_buf->unmap(buffer_used_offset, buffer_used_size); - - buffer_used_offset = buffer_used_size = 0; + array_buf->unmap(); } void SpriteBatch::setTexture(Texture *newtexture) @@ -182,7 +178,7 @@ void SpriteBatch::setBufferSize(int newsize) try { - new_array_buf = new GLBuffer(vertex_size, nullptr, array_buf->getTarget(), array_buf->getUsage()); + new_array_buf = new GLBuffer(vertex_size, nullptr, array_buf->getTarget(), array_buf->getUsage(), array_buf->getMapFlags()); // Copy as much of the old data into the new GLBuffer as can fit. GLBuffer::Bind bind(*new_array_buf); @@ -231,8 +227,7 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float GLBuffer::Bind element_bind(*quad_indices.getBuffer()); // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.) - array_buf->unmap(buffer_used_offset, buffer_used_size); - buffer_used_offset = buffer_used_size = 0; + array_buf->unmap(); uint32 enabledattribs = ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD; @@ -270,9 +265,6 @@ void SpriteBatch::addv(const Vertex *v, const Matrix3 &m, int index) array_buf->map(); array_buf->fill(index * sprite_size, sprite_size, sprite); - - buffer_used_offset = std::min(buffer_used_offset, index * sprite_size); - buffer_used_size = std::max(buffer_used_size, (index + 1) * sprite_size - buffer_used_offset); } void SpriteBatch::setColorv(Vertex *v, const Color &color) diff --git a/src/modules/graphics/opengl/SpriteBatch.h b/src/modules/graphics/opengl/SpriteBatch.h index 11479cf7d..0db524c5f 100644 --- a/src/modules/graphics/opengl/SpriteBatch.h +++ b/src/modules/graphics/opengl/SpriteBatch.h @@ -129,10 +129,6 @@ private: GLBuffer *array_buf; QuadIndices quad_indices; - // The portion of the vertex buffer that's been modified while mapped. - size_t buffer_used_offset; - size_t buffer_used_size; - }; // SpriteBatch } // opengl