mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
mesh and spritebatch attributes reuse buffer bindings when possible.
This commit is contained in:
@@ -660,6 +660,58 @@ bool Mesh::getDrawRange(int &start, int &count) const
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mesh::updateVertexAttributes(Graphics *gfx)
|
||||
{
|
||||
VertexAttributes attributes;
|
||||
BufferBindings &buffers = bufferBindings;
|
||||
|
||||
int activebuffers = 0;
|
||||
|
||||
for (const auto &attrib : attachedAttributes)
|
||||
{
|
||||
if (!attrib.enabled)
|
||||
continue;
|
||||
|
||||
Buffer *buffer = attrib.buffer.get();
|
||||
int bindinglocation = attrib.bindingLocation;
|
||||
|
||||
// Query the index from the shader as a fallback to support old code that
|
||||
// hasn't set a binding location.
|
||||
if (bindinglocation < 0 && Shader::current)
|
||||
bindinglocation = Shader::current->getVertexAttributeIndex(attrib.name);
|
||||
|
||||
if (bindinglocation >= 0)
|
||||
{
|
||||
const auto &member = buffer->getDataMember(attrib.indexInBuffer);
|
||||
|
||||
uint16 offset = (uint16)member.offset;
|
||||
uint16 stride = (uint16)buffer->getArrayStride();
|
||||
size_t bufferoffset = (size_t)stride * attrib.startArrayIndex;
|
||||
|
||||
int bufferindex = activebuffers;
|
||||
|
||||
for (int i = 0; i < activebuffers; i++)
|
||||
{
|
||||
if (buffers.info[i].buffer == buffer && buffers.info[i].offset == bufferoffset
|
||||
&& attributes.bufferLayouts[i].stride == stride && attributes.getBufferStep(i) == attrib.step)
|
||||
{
|
||||
bufferindex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
attributes.set(bindinglocation, member.decl.format, offset, bufferindex);
|
||||
attributes.setBufferLayout(bufferindex, stride, attrib.step);
|
||||
|
||||
buffers.set(bufferindex, buffer, bufferoffset);
|
||||
|
||||
activebuffers = std::max(activebuffers, bufferindex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
attributesID = gfx->registerVertexAttributes(attributes);
|
||||
}
|
||||
|
||||
void Mesh::draw(Graphics *gfx, const love::Matrix4 &m)
|
||||
{
|
||||
drawInternal(gfx, m, 1, nullptr, 0);
|
||||
@@ -709,53 +761,22 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff
|
||||
|
||||
bool attributesIDneedsupdate = !attributesID.isValid();
|
||||
|
||||
VertexAttributes attributes;
|
||||
BufferBindings buffers;
|
||||
|
||||
int activebuffers = 0;
|
||||
|
||||
for (const auto &attrib : attachedAttributes)
|
||||
{
|
||||
if (!attrib.enabled)
|
||||
continue;
|
||||
|
||||
Buffer *buffer = attrib.buffer.get();
|
||||
int bindinglocation = attrib.bindingLocation;
|
||||
if (attrib.mesh.get())
|
||||
attrib.mesh->flush();
|
||||
|
||||
// Query the index from the shader as a fallback to support old code that
|
||||
// hasn't set a binding location.
|
||||
if (bindinglocation < 0 && Shader::current)
|
||||
{
|
||||
bindinglocation = Shader::current->getVertexAttributeIndex(attrib.name);
|
||||
if (attrib.bindingLocation < 0)
|
||||
attributesIDneedsupdate = true;
|
||||
}
|
||||
|
||||
if (bindinglocation >= 0)
|
||||
{
|
||||
if (attrib.mesh.get())
|
||||
attrib.mesh->flush();
|
||||
|
||||
const auto &member = buffer->getDataMember(attrib.indexInBuffer);
|
||||
|
||||
uint16 offset = (uint16) member.offset;
|
||||
uint16 stride = (uint16) buffer->getArrayStride();
|
||||
size_t bufferoffset = (size_t) stride * attrib.startArrayIndex;
|
||||
|
||||
attributes.set(bindinglocation, member.decl.format, offset, activebuffers);
|
||||
attributes.setBufferLayout(activebuffers, stride, attrib.step);
|
||||
|
||||
// TODO: Ideally we want to reuse buffers with the same stride+step.
|
||||
buffers.set(activebuffers, buffer, bufferoffset);
|
||||
activebuffers++;
|
||||
}
|
||||
}
|
||||
|
||||
// Not supported on all platforms or GL versions, I believe.
|
||||
if ((attributes.enableBits & ~(ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR)) == 0)
|
||||
throw love::Exception("Mesh must have an enabled VertexPosition or custom attribute to be drawn.");
|
||||
|
||||
if (attributesIDneedsupdate)
|
||||
attributesID = gfx->registerVertexAttributes(attributes);
|
||||
updateVertexAttributes(gfx);
|
||||
|
||||
Graphics::TempTransform transform(gfx, m);
|
||||
|
||||
@@ -782,7 +803,7 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff
|
||||
if (range.isValid())
|
||||
r.intersect(range);
|
||||
|
||||
Graphics::DrawIndexedCommand cmd(attributesID, &buffers, indexbuffer);
|
||||
Graphics::DrawIndexedCommand cmd(attributesID, &bufferBindings, indexbuffer);
|
||||
|
||||
cmd.primitiveType = primitiveType;
|
||||
cmd.indexType = indexDataType;
|
||||
@@ -805,7 +826,7 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff
|
||||
if (range.isValid())
|
||||
r.intersect(range);
|
||||
|
||||
Graphics::DrawCommand cmd(attributesID, &buffers);
|
||||
Graphics::DrawCommand cmd(attributesID, &bufferBindings);
|
||||
|
||||
cmd.primitiveType = primitiveType;
|
||||
cmd.vertexStart = (int) r.getOffset();
|
||||
|
||||
@@ -196,6 +196,8 @@ private:
|
||||
int getAttachedAttributeIndex(int bindingLocation) const;
|
||||
void finalizeAttribute(BufferAttribute &attrib) const;
|
||||
|
||||
void updateVertexAttributes(Graphics *gfx);
|
||||
|
||||
void drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buffer *indirectargs, int argsindex);
|
||||
|
||||
std::vector<Buffer::DataMember> vertexFormat;
|
||||
@@ -226,6 +228,8 @@ private:
|
||||
|
||||
StrongRef<Texture> texture;
|
||||
|
||||
BufferBindings bufferBindings;
|
||||
|
||||
}; // Mesh
|
||||
|
||||
} // graphics
|
||||
|
||||
@@ -321,6 +321,57 @@ bool SpriteBatch::getDrawRange(int &start, int &count) const
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpriteBatch::updateVertexAttributes(Graphics *gfx)
|
||||
{
|
||||
VertexAttributes attributes;
|
||||
BufferBindings &buffers = bufferBindings;
|
||||
|
||||
buffers.set(0, array_buf, 0);
|
||||
attributes.setCommonFormat(vertex_format, 0);
|
||||
|
||||
int activebuffers = 1;
|
||||
|
||||
for (const auto &it : attached_attributes)
|
||||
{
|
||||
Buffer *buffer = it.second.buffer.get();
|
||||
|
||||
int bindingindex = it.second.bindingIndex;
|
||||
|
||||
// If the attribute is one of the LOVE-defined ones, use the constant
|
||||
// attribute index for it, otherwise query the index from the shader.
|
||||
if (bindingindex < 0 && Shader::current)
|
||||
bindingindex = Shader::current->getVertexAttributeIndex(it.first);
|
||||
|
||||
if (bindingindex >= 0)
|
||||
{
|
||||
const auto &member = buffer->getDataMember(it.second.index);
|
||||
|
||||
uint16 offset = (uint16) buffer->getMemberOffset(it.second.index);
|
||||
uint16 stride = (uint16) buffer->getArrayStride();
|
||||
|
||||
int bufferindex = activebuffers;
|
||||
|
||||
for (int i = 1; i < activebuffers; i++)
|
||||
{
|
||||
if (buffers.info[i].buffer == buffer && attributes.bufferLayouts[i].stride == stride)
|
||||
{
|
||||
bufferindex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
attributes.set(bindingindex, member.decl.format, offset, bufferindex);
|
||||
attributes.setBufferLayout(bufferindex, stride);
|
||||
|
||||
buffers.set(bufferindex, buffer, 0);
|
||||
|
||||
activebuffers = std::max(activebuffers, bufferindex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
attributesID = gfx->registerVertexAttributes(attributes);
|
||||
}
|
||||
|
||||
void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
{
|
||||
if (next == 0)
|
||||
@@ -347,16 +398,6 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
|
||||
bool attributesIDneedsupdate = !attributesID.isValid();
|
||||
|
||||
VertexAttributes attributes;
|
||||
BufferBindings buffers;
|
||||
|
||||
{
|
||||
buffers.set(0, array_buf, 0);
|
||||
attributes.setCommonFormat(vertex_format, 0);
|
||||
}
|
||||
|
||||
int activebuffers = 1;
|
||||
|
||||
for (const auto &it : attached_attributes)
|
||||
{
|
||||
Buffer *buffer = it.second.buffer.get();
|
||||
@@ -366,37 +407,17 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
if (buffer->getArrayLength() < (size_t) next * 4)
|
||||
throw love::Exception("Buffer with attribute '%s' attached to this SpriteBatch has too few vertices", it.first.c_str());
|
||||
|
||||
int bindingindex = it.second.bindingIndex;
|
||||
|
||||
// If the attribute is one of the LOVE-defined ones, use the constant
|
||||
// attribute index for it, otherwise query the index from the shader.
|
||||
if (bindingindex < 0 && Shader::current)
|
||||
{
|
||||
bindingindex = Shader::current->getVertexAttributeIndex(it.first);
|
||||
if (it.second.bindingIndex < 0)
|
||||
attributesIDneedsupdate = true;
|
||||
}
|
||||
|
||||
if (bindingindex >= 0)
|
||||
{
|
||||
if (it.second.mesh.get())
|
||||
it.second.mesh->flush();
|
||||
|
||||
const auto &member = buffer->getDataMember(it.second.index);
|
||||
|
||||
uint16 offset = (uint16) buffer->getMemberOffset(it.second.index);
|
||||
uint16 stride = (uint16) buffer->getArrayStride();
|
||||
|
||||
attributes.set(bindingindex, member.decl.format, offset, activebuffers);
|
||||
attributes.setBufferLayout(activebuffers, stride);
|
||||
|
||||
// TODO: We should reuse buffer bindings with the same buffer+stride+step.
|
||||
buffers.set(activebuffers, buffer, 0);
|
||||
activebuffers++;
|
||||
}
|
||||
if (it.second.mesh.get())
|
||||
it.second.mesh->flush();
|
||||
}
|
||||
|
||||
if (attributesIDneedsupdate)
|
||||
attributesID = gfx->registerVertexAttributes(attributes);
|
||||
updateVertexAttributes(gfx);
|
||||
|
||||
Graphics::TempTransform transform(gfx, m);
|
||||
|
||||
@@ -411,7 +432,7 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
if (count > 0)
|
||||
{
|
||||
Texture *tex = gfx->getTextureOrDefaultForActiveShader(texture);
|
||||
gfx->drawQuads(start, count, attributesID, buffers, tex);
|
||||
gfx->drawQuads(start, count, attributesID, bufferBindings, tex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +108,8 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void updateVertexAttributes(Graphics *gfx);
|
||||
|
||||
struct AttachedAttribute
|
||||
{
|
||||
StrongRef<Buffer> buffer;
|
||||
@@ -138,6 +140,7 @@ private:
|
||||
size_t vertex_stride;
|
||||
|
||||
VertexAttributesID attributesID;
|
||||
BufferBindings bufferBindings;
|
||||
|
||||
StrongRef<love::graphics::Buffer> array_buf;
|
||||
uint8 *vertex_data;
|
||||
|
||||
Reference in New Issue
Block a user