mirror of
https://github.com/love2d/love.git
synced 2026-08-12 16:40:57 +02:00
Cleaned up some index buffer code.
This commit is contained in:
@@ -532,7 +532,7 @@ void Font::drawVertices(const std::vector<DrawCommand> &drawcommands)
|
||||
totalverts = std::max(cmd.startvertex + cmd.vertexcount, totalverts);
|
||||
|
||||
if ((size_t) totalverts / 4 > quadIndices.getSize())
|
||||
quadIndices = VertexIndex((size_t) totalverts / 4);
|
||||
quadIndices = QuadIndices((size_t) totalverts / 4);
|
||||
|
||||
gl.prepareDraw();
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ private:
|
||||
bool useSpacesAsTab;
|
||||
|
||||
// Index buffer used for drawing quads with GL_TRIANGLES.
|
||||
VertexIndex quadIndices;
|
||||
QuadIndices quadIndices;
|
||||
|
||||
// ID which is incremented when the texture cache is invalidated.
|
||||
uint32 textureCacheID;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
// 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
|
||||
// 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))
|
||||
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)
|
||||
{
|
||||
addSize(size);
|
||||
objectCount++;
|
||||
}
|
||||
|
||||
VertexIndex &VertexIndex::operator = (const VertexIndex &other)
|
||||
QuadIndices &QuadIndices::operator = (const QuadIndices &other)
|
||||
{
|
||||
addSize(other.size);
|
||||
removeSize(size);
|
||||
size = other.size;
|
||||
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;
|
||||
}
|
||||
|
||||
size_t VertexIndex::getIndexCount(size_t elements) const
|
||||
size_t QuadIndices::getIndexCount(size_t elements) const
|
||||
{
|
||||
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.
|
||||
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
|
||||
}
|
||||
|
||||
size_t VertexIndex::getElementSize()
|
||||
size_t QuadIndices::getElementSize()
|
||||
{
|
||||
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>
|
||||
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();
|
||||
|
||||
|
||||
@@ -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
|
||||
* that can use the pattern below) can request a size and use it for the
|
||||
* drawElements call.
|
||||
@@ -280,14 +280,14 @@ private:
|
||||
* indices[i*6 + 5] = i*4 + 3;
|
||||
*
|
||||
* 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
|
||||
* varies. Using one GLBuffer for all element arrays removes this
|
||||
* duplicated data and saves some memory.
|
||||
*/
|
||||
class VertexIndex
|
||||
class QuadIndices
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -297,16 +297,16 @@ public:
|
||||
*
|
||||
* @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
|
||||
* if needed.
|
||||
*/
|
||||
~VertexIndex();
|
||||
~QuadIndices();
|
||||
|
||||
/**
|
||||
* Returns the number of index groups.
|
||||
@@ -318,8 +318,8 @@ public:
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return The index count.
|
||||
@@ -369,30 +369,6 @@ public:
|
||||
|
||||
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.
|
||||
* 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.
|
||||
static size_t elementSize;
|
||||
|
||||
// The current GLBuffer size. 0 means no GLBuffer.
|
||||
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
|
||||
|
||||
@@ -50,7 +50,8 @@ namespace opengl
|
||||
{
|
||||
|
||||
Graphics::Graphics()
|
||||
: width(0)
|
||||
: quadIndices(nullptr)
|
||||
, width(0)
|
||||
, height(0)
|
||||
, created(false)
|
||||
, active(true)
|
||||
@@ -84,6 +85,9 @@ Graphics::~Graphics()
|
||||
Shader::defaultShader = nullptr;
|
||||
}
|
||||
|
||||
if (quadIndices)
|
||||
delete quadIndices;
|
||||
|
||||
currentWindow->release();
|
||||
}
|
||||
|
||||
@@ -289,6 +293,14 @@ bool Graphics::setMode(int width, int height, bool &sRGB)
|
||||
|
||||
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.
|
||||
if (!Volatile::loadAll())
|
||||
::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.
|
||||
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.
|
||||
if (!Shader::defaultShader)
|
||||
@@ -1089,19 +1101,19 @@ void Graphics::polyline(const float *coords, size_t count)
|
||||
if (state.lineJoin == LINE_JOIN_NONE)
|
||||
{
|
||||
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();
|
||||
}
|
||||
else if (state.lineJoin == LINE_JOIN_BEVEL)
|
||||
{
|
||||
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();
|
||||
}
|
||||
else // LINE_JOIN_MITER
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1424,7 +1436,7 @@ void Graphics::push(StackType type)
|
||||
|
||||
gl.pushTransform();
|
||||
|
||||
pixel_size_stack.push_back(pixel_size_stack.back());
|
||||
pixelSizeStack.push_back(pixelSizeStack.back());
|
||||
|
||||
if (type == STACK_ALL)
|
||||
states.push_back(states.back());
|
||||
@@ -1438,7 +1450,7 @@ void Graphics::pop()
|
||||
throw Exception("Minimum stack depth reached (more pops than pushes?)");
|
||||
|
||||
gl.popTransform();
|
||||
pixel_size_stack.pop_back();
|
||||
pixelSizeStack.pop_back();
|
||||
|
||||
if (stackTypes.back() == STACK_ALL)
|
||||
{
|
||||
@@ -1461,7 +1473,7 @@ void Graphics::rotate(float r)
|
||||
void Graphics::scale(float x, float 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)
|
||||
@@ -1477,7 +1489,7 @@ void Graphics::shear(float kx, float ky)
|
||||
void Graphics::origin()
|
||||
{
|
||||
gl.getTransform().setIdentity();
|
||||
pixel_size_stack.back() = 1;
|
||||
pixelSizeStack.back() = 1;
|
||||
}
|
||||
|
||||
Graphics::DisplayState::DisplayState()
|
||||
|
||||
@@ -511,7 +511,9 @@ private:
|
||||
|
||||
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 height;
|
||||
|
||||
@@ -209,7 +209,7 @@ void ParticleSystem::setBufferSize(uint32 size)
|
||||
{
|
||||
if (size == 0 || size > MAX_PARTICLES)
|
||||
throw love::Exception("Invalid buffer size");
|
||||
quadIndices = VertexIndex(size);
|
||||
quadIndices = QuadIndices(size);
|
||||
deleteBuffers();
|
||||
createBuffers(size);
|
||||
reset();
|
||||
|
||||
@@ -577,7 +577,7 @@ protected:
|
||||
Vertex *particleVerts;
|
||||
|
||||
// Vertex index buffer.
|
||||
VertexIndex quadIndices;
|
||||
QuadIndices quadIndices;
|
||||
|
||||
// The texture to be drawn.
|
||||
StrongRef<Texture> texture;
|
||||
|
||||
@@ -189,7 +189,7 @@ void SpriteBatch::setBufferSize(int newsize)
|
||||
void *new_data = new_array_buf->map();
|
||||
memcpy(new_data, old_data, sizeof(Vertex) * 4 * std::min(newsize, size));
|
||||
|
||||
quad_indices = VertexIndex(newsize);
|
||||
quad_indices = QuadIndices(newsize);
|
||||
}
|
||||
catch (love::Exception &)
|
||||
{
|
||||
|
||||
@@ -127,7 +127,7 @@ private:
|
||||
Color *color;
|
||||
|
||||
GLBuffer *array_buf;
|
||||
VertexIndex quad_indices;
|
||||
QuadIndices quad_indices;
|
||||
|
||||
// The portion of the vertex buffer that's been modified while mapped.
|
||||
size_t buffer_used_offset;
|
||||
|
||||
Reference in New Issue
Block a user