Browse Source

Cleaned up some Mesh and SpriteBatch code.

Alex Szpakowski 10 years ago
parent
commit
a45c1332a7

+ 60 - 20
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);
 }
 

+ 24 - 7
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
 
 

+ 8 - 28
src/modules/graphics/opengl/Mesh.cpp

@@ -63,8 +63,6 @@ Mesh::Mesh(const std::vector<AttribFormat> &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<AttribFormat> &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<AttribFormat> &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<AttribFormat> &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);

+ 0 - 5
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;

+ 4 - 12
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)

+ 0 - 4
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