Browse Source

Cleaned up some index buffer code.

Alex Szpakowski 10 years ago
parent
commit
2dc8a8ea45

+ 1 - 1
src/modules/graphics/opengl/Font.cpp

@@ -532,7 +532,7 @@ void Font::drawVertices(const std::vector<DrawCommand> &drawcommands)
 		totalverts = std::max(cmd.startvertex + cmd.vertexcount, totalverts);
 		totalverts = std::max(cmd.startvertex + cmd.vertexcount, totalverts);
 
 
 	if ((size_t) totalverts / 4 > quadIndices.getSize())
 	if ((size_t) totalverts / 4 > quadIndices.getSize())
-		quadIndices = VertexIndex((size_t) totalverts / 4);
+		quadIndices = QuadIndices((size_t) totalverts / 4);
 
 
 	gl.prepareDraw();
 	gl.prepareDraw();
 
 

+ 1 - 1
src/modules/graphics/opengl/Font.h

@@ -236,7 +236,7 @@ private:
 	bool useSpacesAsTab;
 	bool useSpacesAsTab;
 
 
 	// Index buffer used for drawing quads with GL_TRIANGLES.
 	// Index buffer used for drawing quads with GL_TRIANGLES.
-	VertexIndex quadIndices;
+	QuadIndices quadIndices;
 
 
 	// ID which is incremented when the texture cache is invalidated.
 	// ID which is incremented when the texture cache is invalidated.
 	uint32 textureCacheID;
 	uint32 textureCacheID;

+ 73 - 110
src/modules/graphics/opengl/GLBuffer.cpp

@@ -198,164 +198,127 @@ void GLBuffer::unload()
 }
 }
 
 
 
 
-// VertexIndex
+// QuadIndices
 
 
-size_t VertexIndex::maxSize = 0;
-size_t VertexIndex::elementSize = 0;
-std::list<size_t> VertexIndex::sizeRefs;
-GLBuffer *VertexIndex::element_array = NULL;
+size_t QuadIndices::maxSize = 0;
+size_t QuadIndices::elementSize = 0;
+size_t QuadIndices::objectCount = 0;
+GLBuffer *QuadIndices::indexBuffer = nullptr;
 
 
-VertexIndex::VertexIndex(size_t size)
+QuadIndices::QuadIndices(size_t size)
 	: size(size)
 	: size(size)
 {
 {
 	// The upper limit is the maximum of GLuint divided by six (the number
 	// The upper limit is the maximum of GLuint divided by six (the number
 	// of indices per size) and divided by the size of GLuint. This guarantees
 	// of indices per size) and divided by the size of GLuint. This guarantees
 	// no overflows when calculating the array size in bytes.
 	// no overflows when calculating the array size in bytes.
-	// Memory issues will be handled by other exceptions.
 	if (size == 0 || size > ((GLuint) -1) / 6 / sizeof(GLuint))
 	if (size == 0 || size > ((GLuint) -1) / 6 / sizeof(GLuint))
-		throw love::Exception("Invalid size.");
+		throw love::Exception("Invalid number of quads.");
 
 
-	addSize(size);
+	// Create a new / larger buffer if needed.
+	if (indexBuffer == nullptr || size > maxSize)
+	{
+		GLBuffer *newbuffer = nullptr;
+
+		// Depending on the size, a switch to int and more memory is needed.
+		GLenum targettype = getType(size);
+		size_t elemsize = (targettype == GL_UNSIGNED_SHORT) ? sizeof(GLushort) : sizeof(GLuint);
+
+		size_t buffersize = elemsize * 6 * size;
+
+		// Create may throw out-of-memory exceptions.
+		// QuadIndices will propagate the exception and keep the old GLBuffer.
+		try
+		{
+			newbuffer = new GLBuffer(buffersize, nullptr, GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW);
+		}
+		catch (std::bad_alloc &)
+		{
+			throw love::Exception("Out of memory.");
+		}
+
+		// Allocation of the new GLBuffer succeeded.
+		// The old GLBuffer can now be deleted.
+		delete indexBuffer;
+		indexBuffer = newbuffer;
+		maxSize = size;
+		elementSize = elemsize;
+
+		switch (targettype)
+		{
+		case GL_UNSIGNED_SHORT:
+			fill<GLushort>();
+			break;
+		case GL_UNSIGNED_INT:
+			fill<GLuint>();
+			break;
+		}
+	}
+
+	objectCount++;
 }
 }
 
 
-VertexIndex::VertexIndex(const VertexIndex &other)
+QuadIndices::QuadIndices(const QuadIndices &other)
 	: size(other.size)
 	: size(other.size)
 {
 {
-	addSize(size);
+	objectCount++;
 }
 }
 
 
-VertexIndex &VertexIndex::operator = (const VertexIndex &other)
+QuadIndices &QuadIndices::operator = (const QuadIndices &other)
 {
 {
-	addSize(other.size);
-	removeSize(size);
 	size = other.size;
 	size = other.size;
 	return *this;
 	return *this;
 }
 }
 
 
-VertexIndex::~VertexIndex()
+QuadIndices::~QuadIndices()
 {
 {
-	removeSize(size);
+	--objectCount;
+
+	// Delete the buffer if we were the last living QuadIndices object.
+	if (objectCount <= 0)
+	{
+		delete indexBuffer;
+		indexBuffer = nullptr;
+	}
 }
 }
 
 
-size_t VertexIndex::getSize() const
+size_t QuadIndices::getSize() const
 {
 {
 	return size;
 	return size;
 }
 }
 
 
-size_t VertexIndex::getIndexCount(size_t elements) const
+size_t QuadIndices::getIndexCount(size_t elements) const
 {
 {
 	return elements * 6;
 	return elements * 6;
 }
 }
 
 
-GLenum VertexIndex::getType(size_t s) const
+GLenum QuadIndices::getType(size_t s) const
 {
 {
 	// Calculates if unsigned short is big enough to hold all the vertex indices.
 	// Calculates if unsigned short is big enough to hold all the vertex indices.
-	static const GLenum type_table[] = {GL_UNSIGNED_SHORT, GL_UNSIGNED_INT};
-	return type_table[s * 4 > std::numeric_limits<GLushort>::max()];
+	static const GLenum types[] = {GL_UNSIGNED_SHORT, GL_UNSIGNED_INT};
+	return types[s * 4 > std::numeric_limits<GLushort>::max()];
 	// if buffer-size > max(GLushort) then GL_UNSIGNED_INT else GL_UNSIGNED_SHORT
 	// if buffer-size > max(GLushort) then GL_UNSIGNED_INT else GL_UNSIGNED_SHORT
 }
 }
 
 
-size_t VertexIndex::getElementSize()
+size_t QuadIndices::getElementSize()
 {
 {
 	return elementSize;
 	return elementSize;
 }
 }
 
 
-GLBuffer *VertexIndex::getBuffer() const
+GLBuffer *QuadIndices::getBuffer() const
 {
 {
-	return element_array;
+	return indexBuffer;
 }
 }
 
 
-const void *VertexIndex::getPointer(size_t offset) const
+const void *QuadIndices::getPointer(size_t offset) const
 {
 {
-	return element_array->getPointer(offset);
-}
-
-void VertexIndex::addSize(size_t newSize)
-{
-	if (newSize <= maxSize)
-	{
-		// Current size is bigger. Append the size to list and sort.
-		sizeRefs.push_back(newSize);
-		sizeRefs.sort();
-		return;
-	}
-
-	// Try to resize before adding it to the list because resize may throw.
-	resize(newSize);
-	sizeRefs.push_back(newSize);
-}
-
-void VertexIndex::removeSize(size_t oldSize)
-{
-	// TODO: For debugging purposes, this should check if the size was actually found.
-	sizeRefs.erase(std::find(sizeRefs.begin(), sizeRefs.end(), oldSize));
-	if (sizeRefs.size() == 0)
-	{
-		resize(0);
-		return;
-	}
-
-	if (oldSize == maxSize)
-	{
-		// Shrink if there's a smaller size.
-		size_t newSize = sizeRefs.back();
-		if (newSize < maxSize)
-			resize(newSize);
-	}
-}
-
-void VertexIndex::resize(size_t size)
-{
-	if (size == 0)
-	{
-		delete element_array;
-		element_array = NULL;
-		maxSize = 0;
-		return;
-	}
-
-	GLBuffer *new_element_array;
-
-	// Depending on the size, a switch to int and more memory is needed.
-	GLenum target_type = getType(size);
-	size_t elem_size = (target_type == GL_UNSIGNED_SHORT) ? sizeof(GLushort) : sizeof(GLuint);
-
-	size_t array_size = elem_size * 6 * size;
-
-	// Create may throw out-of-memory exceptions.
-	// VertexIndex will propagate the exception and keep the old GLBuffer.
-	try
-	{
-		new_element_array = new GLBuffer(array_size, nullptr, GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW);
-	}
-	catch (std::bad_alloc &)
-	{
-		throw love::Exception("Out of memory.");
-	}
-
-	// Allocation of the new GLBuffer succeeded.
-	// The old GLBuffer can now be deleted.
-	delete element_array;
-	element_array = new_element_array;
-	maxSize = size;
-	elementSize = elem_size;
-
-	switch (target_type)
-	{
-	case GL_UNSIGNED_SHORT:
-		fill<GLushort>();
-		break;
-	case GL_UNSIGNED_INT:
-		fill<GLuint>();
-		break;
-	}
+	return indexBuffer->getPointer(offset);
 }
 }
 
 
 template <typename T>
 template <typename T>
-void VertexIndex::fill()
+void QuadIndices::fill()
 {
 {
-	GLBuffer::Bind bind(*element_array);
-	GLBuffer::Mapper mapper(*element_array);
+	GLBuffer::Bind bind(*indexBuffer);
+	GLBuffer::Mapper mapper(*indexBuffer);
 
 
 	T *indices = (T *) mapper.get();
 	T *indices = (T *) mapper.get();
 
 

+ 16 - 38
src/modules/graphics/opengl/GLBuffer.h

@@ -266,7 +266,7 @@ private:
 
 
 
 
 /**
 /**
- * VertexIndex manages one shared GLBuffer that stores the indices for an
+ * QuadIndices manages one shared GLBuffer that stores the indices for an
  * element array. Vertex arrays using the vertex structure (or anything else
  * element array. Vertex arrays using the vertex structure (or anything else
  * that can use the pattern below) can request a size and use it for the
  * that can use the pattern below) can request a size and use it for the
  * drawElements call.
  * drawElements call.
@@ -280,14 +280,14 @@ private:
  *  indices[i*6 + 5] = i*4 + 3;
  *  indices[i*6 + 5] = i*4 + 3;
  *
  *
  * There will always be a large enough GLBuffer around until all
  * There will always be a large enough GLBuffer around until all
- * VertexIndex instances have been deleted.
+ * QuadIndices instances have been deleted.
  *
  *
- * Q: Why have something like VertexIndex?
+ * Q: Why have something like QuadIndices?
  * A: The indices for the SpriteBatch do not change, only the array size
  * A: The indices for the SpriteBatch do not change, only the array size
  * varies. Using one GLBuffer for all element arrays removes this
  * varies. Using one GLBuffer for all element arrays removes this
  * duplicated data and saves some memory.
  * duplicated data and saves some memory.
  */
  */
-class VertexIndex
+class QuadIndices
 {
 {
 public:
 public:
 	/**
 	/**
@@ -297,16 +297,16 @@ public:
 	 *
 	 *
 	 * @param size The requested size in groups of 6 indices.
 	 * @param size The requested size in groups of 6 indices.
 	 */
 	 */
-	VertexIndex(size_t size);
+	QuadIndices(size_t size);
 
 
-	VertexIndex(const VertexIndex &other);
-	VertexIndex &operator = (const VertexIndex &other);
+	QuadIndices(const QuadIndices &other);
+	QuadIndices &operator = (const QuadIndices &other);
 
 
 	/**
 	/**
 	 * Removes an entry from the list of sizes and resizes the GLBuffer
 	 * Removes an entry from the list of sizes and resizes the GLBuffer
 	 * if needed.
 	 * if needed.
 	 */
 	 */
-	~VertexIndex();
+	~QuadIndices();
 
 
 	/**
 	/**
 	 * Returns the number of index groups.
 	 * Returns the number of index groups.
@@ -318,8 +318,8 @@ public:
 
 
 	/**
 	/**
 	 * Returns the number of indices that the passed element count will have.
 	 * Returns the number of indices that the passed element count will have.
-	 * Use VertexIndex::getSize to get the full index count for that
-	 * VertexIndex instance.
+	 * Use QuadIndices::getSize to get the full index count for that
+	 * QuadIndices instance.
 	 *
 	 *
 	 * @param elements The number of elements to calculate the index count for.
 	 * @param elements The number of elements to calculate the index count for.
 	 * @return The index count.
 	 * @return The index count.
@@ -369,30 +369,6 @@ public:
 
 
 private:
 private:
 
 
-	/**
-	 * Adds a new size to the size list, then sorts and resizes it if needed.
-	 *
-	 * @param newSize The new size to be added.
-	 */
-	void addSize(size_t newSize);
-
-	/**
-	 * Removes a size from the size list, then sorts and resizes it if needed.
-	 *
-	 * @param oldSize The old size to be removed.
-	 */
-	void removeSize(size_t oldSize);
-
-	/**
-	 * Resizes the GLBuffer to the requested size.
-	 * This function takes care of choosing the correct integer type and
-	 * allocating and deleting the GLBuffer instance. It also has some
-	 * fallback logic in case the memory ran out.
-	 *
-	 * @param size The requested GLBuffer size. Passing 0 deletes the GLBuffer without allocating a new one.
-	 */
-	void resize(size_t size);
-
 	/**
 	/**
 	 * Adds all indices to the array with the type T.
 	 * Adds all indices to the array with the type T.
 	 * There are no checks for the correct types or overflows. The calling
 	 * There are no checks for the correct types or overflows. The calling
@@ -405,12 +381,14 @@ private:
 
 
 	// The size in bytes of an element in the element array.
 	// The size in bytes of an element in the element array.
 	static size_t elementSize;
 	static size_t elementSize;
+
 	// The current GLBuffer size. 0 means no GLBuffer.
 	// The current GLBuffer size. 0 means no GLBuffer.
 	static size_t maxSize;
 	static size_t maxSize;
-	// The list of sizes. Needs to be kept sorted in ascending order.
-	static std::list<size_t> sizeRefs;
-	// The GLBuffer for the element array. Can be NULL.
-	static GLBuffer *element_array;
+
+	static size_t objectCount;
+
+	// The GLBuffer for the element array. Can be null.
+	static GLBuffer *indexBuffer;
 };
 };
 
 
 } // opengl
 } // opengl

+ 23 - 11
src/modules/graphics/opengl/Graphics.cpp

@@ -50,7 +50,8 @@ namespace opengl
 {
 {
 
 
 Graphics::Graphics()
 Graphics::Graphics()
-	: width(0)
+	: quadIndices(nullptr)
+	, width(0)
 	, height(0)
 	, height(0)
 	, created(false)
 	, created(false)
 	, active(true)
 	, active(true)
@@ -84,6 +85,9 @@ Graphics::~Graphics()
 		Shader::defaultShader = nullptr;
 		Shader::defaultShader = nullptr;
 	}
 	}
 
 
+	if (quadIndices)
+		delete quadIndices;
+
 	currentWindow->release();
 	currentWindow->release();
 }
 }
 
 
@@ -289,6 +293,14 @@ bool Graphics::setMode(int width, int height, bool &sRGB)
 
 
 	setDebug(enabledebug);
 	setDebug(enabledebug);
 
 
+	// Create a quad indices object owned by love.graphics, so at least one
+	// QuadIndices object is alive at all times while love.graphics is alive.
+	// This makes sure there aren't too many expensive destruction/creations of
+	// index buffer objects, since the shared index buffer used by QuadIndices
+	// objects is destroyed when the last object is destroyed.
+	if (quadIndices == nullptr)
+		quadIndices = new QuadIndices(20);
+
 	// Reload all volatile objects.
 	// Reload all volatile objects.
 	if (!Volatile::loadAll())
 	if (!Volatile::loadAll())
 		::printf("Could not reload all volatile objects.\n");
 		::printf("Could not reload all volatile objects.\n");
@@ -296,9 +308,9 @@ bool Graphics::setMode(int width, int height, bool &sRGB)
 	// Restore the graphics state.
 	// Restore the graphics state.
 	restoreState(states.back());
 	restoreState(states.back());
 
 
-	pixel_size_stack.clear();
-	pixel_size_stack.reserve(5);
-	pixel_size_stack.push_back(1);
+	pixelSizeStack.clear();
+	pixelSizeStack.reserve(5);
+	pixelSizeStack.push_back(1);
 
 
 	// We always need a default shader.
 	// We always need a default shader.
 	if (!Shader::defaultShader)
 	if (!Shader::defaultShader)
@@ -1089,19 +1101,19 @@ void Graphics::polyline(const float *coords, size_t count)
 	if (state.lineJoin == LINE_JOIN_NONE)
 	if (state.lineJoin == LINE_JOIN_NONE)
 	{
 	{
 		NoneJoinPolyline line;
 		NoneJoinPolyline line;
-		line.render(coords, count, state.lineWidth * .5f, float(pixel_size_stack.back()), state.lineStyle == LINE_SMOOTH);
+		line.render(coords, count, state.lineWidth * .5f, float(pixelSizeStack.back()), state.lineStyle == LINE_SMOOTH);
 		line.draw();
 		line.draw();
 	}
 	}
 	else if (state.lineJoin == LINE_JOIN_BEVEL)
 	else if (state.lineJoin == LINE_JOIN_BEVEL)
 	{
 	{
 		BevelJoinPolyline line;
 		BevelJoinPolyline line;
-		line.render(coords, count, state.lineWidth * .5f, float(pixel_size_stack.back()), state.lineStyle == LINE_SMOOTH);
+		line.render(coords, count, state.lineWidth * .5f, float(pixelSizeStack.back()), state.lineStyle == LINE_SMOOTH);
 		line.draw();
 		line.draw();
 	}
 	}
 	else // LINE_JOIN_MITER
 	else // LINE_JOIN_MITER
 	{
 	{
 		MiterJoinPolyline line;
 		MiterJoinPolyline line;
-		line.render(coords, count, state.lineWidth * .5f, float(pixel_size_stack.back()), state.lineStyle == LINE_SMOOTH);
+		line.render(coords, count, state.lineWidth * .5f, float(pixelSizeStack.back()), state.lineStyle == LINE_SMOOTH);
 		line.draw();
 		line.draw();
 	}
 	}
 }
 }
@@ -1424,7 +1436,7 @@ void Graphics::push(StackType type)
 
 
 	gl.pushTransform();
 	gl.pushTransform();
 
 
-	pixel_size_stack.push_back(pixel_size_stack.back());
+	pixelSizeStack.push_back(pixelSizeStack.back());
 
 
 	if (type == STACK_ALL)
 	if (type == STACK_ALL)
 		states.push_back(states.back());
 		states.push_back(states.back());
@@ -1438,7 +1450,7 @@ void Graphics::pop()
 		throw Exception("Minimum stack depth reached (more pops than pushes?)");
 		throw Exception("Minimum stack depth reached (more pops than pushes?)");
 
 
 	gl.popTransform();
 	gl.popTransform();
-	pixel_size_stack.pop_back();
+	pixelSizeStack.pop_back();
 
 
 	if (stackTypes.back() == STACK_ALL)
 	if (stackTypes.back() == STACK_ALL)
 	{
 	{
@@ -1461,7 +1473,7 @@ void Graphics::rotate(float r)
 void Graphics::scale(float x, float y)
 void Graphics::scale(float x, float y)
 {
 {
 	gl.getTransform().scale(x, y);
 	gl.getTransform().scale(x, y);
-	pixel_size_stack.back() *= 2. / (fabs(x) + fabs(y));
+	pixelSizeStack.back() *= 2. / (fabs(x) + fabs(y));
 }
 }
 
 
 void Graphics::translate(float x, float y)
 void Graphics::translate(float x, float y)
@@ -1477,7 +1489,7 @@ void Graphics::shear(float kx, float ky)
 void Graphics::origin()
 void Graphics::origin()
 {
 {
 	gl.getTransform().setIdentity();
 	gl.getTransform().setIdentity();
-	pixel_size_stack.back() = 1;
+	pixelSizeStack.back() = 1;
 }
 }
 
 
 Graphics::DisplayState::DisplayState()
 Graphics::DisplayState::DisplayState()

+ 3 - 1
src/modules/graphics/opengl/Graphics.h

@@ -511,7 +511,9 @@ private:
 
 
 	StrongRef<Font> defaultFont;
 	StrongRef<Font> defaultFont;
 
 
-	std::vector<double> pixel_size_stack; // stores current size of a pixel (needed for line drawing)
+	std::vector<double> pixelSizeStack; // stores current size of a pixel (needed for line drawing)
+
+	QuadIndices *quadIndices;
 
 
 	int width;
 	int width;
 	int height;
 	int height;

+ 1 - 1
src/modules/graphics/opengl/ParticleSystem.cpp

@@ -209,7 +209,7 @@ void ParticleSystem::setBufferSize(uint32 size)
 {
 {
 	if (size == 0 || size > MAX_PARTICLES)
 	if (size == 0 || size > MAX_PARTICLES)
 		throw love::Exception("Invalid buffer size");
 		throw love::Exception("Invalid buffer size");
-	quadIndices = VertexIndex(size);
+	quadIndices = QuadIndices(size);
 	deleteBuffers();
 	deleteBuffers();
 	createBuffers(size);
 	createBuffers(size);
 	reset();
 	reset();

+ 1 - 1
src/modules/graphics/opengl/ParticleSystem.h

@@ -577,7 +577,7 @@ protected:
 	Vertex *particleVerts;
 	Vertex *particleVerts;
 
 
 	// Vertex index buffer.
 	// Vertex index buffer.
-	VertexIndex quadIndices;
+	QuadIndices quadIndices;
 
 
 	// The texture to be drawn.
 	// The texture to be drawn.
 	StrongRef<Texture> texture;
 	StrongRef<Texture> texture;

+ 1 - 1
src/modules/graphics/opengl/SpriteBatch.cpp

@@ -189,7 +189,7 @@ void SpriteBatch::setBufferSize(int newsize)
 		void *new_data = new_array_buf->map();
 		void *new_data = new_array_buf->map();
 		memcpy(new_data, old_data, sizeof(Vertex) * 4 * std::min(newsize, size));
 		memcpy(new_data, old_data, sizeof(Vertex) * 4 * std::min(newsize, size));
 
 
-		quad_indices = VertexIndex(newsize);
+		quad_indices = QuadIndices(newsize);
 	}
 	}
 	catch (love::Exception &)
 	catch (love::Exception &)
 	{
 	{

+ 1 - 1
src/modules/graphics/opengl/SpriteBatch.h

@@ -127,7 +127,7 @@ private:
 	Color *color;
 	Color *color;
 
 
 	GLBuffer *array_buf;
 	GLBuffer *array_buf;
-	VertexIndex quad_indices;
+	QuadIndices quad_indices;
 
 
 	// The portion of the vertex buffer that's been modified while mapped.
 	// The portion of the vertex buffer that's been modified while mapped.
 	size_t buffer_used_offset;
 	size_t buffer_used_offset;