Skip to content

Commit

Permalink
use location numbers for vertex input attributes, instead of name-bas…
Browse files Browse the repository at this point in the history
…ed binding.

- add 'location' named field to buffer and mesh vertex format tables, replaces 'name' field.
- location numbers are expected to match 'layout (location = #)' qualifiers in vertex inputs in shader code.
- deprecate vertex inputs in shader code that don't have layout location qualifiers.
- love's default vertex attributes use location 0 for position, 1 for texcoord, and 2 for color.
- add new variants of Mesh:attachAttribute, setAttributeEnabled, and isAttributeEnabled which take location numbers instead of names.

Improves draw performance in vulkan and metal backends.
  • Loading branch information
slime73 committed Sep 7, 2024
1 parent c7b4ebb commit 50ff1e4
Show file tree
Hide file tree
Showing 31 changed files with 682 additions and 257 deletions.
60 changes: 38 additions & 22 deletions src/modules/graphics/Buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,13 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
if (info.baseType == DATA_BASETYPE_BOOL)
throw love::Exception("Bool types are not supported in vertex buffers.");

if (decl.name.empty())
throw love::Exception("Vertex buffer attributes must have a name.");
if (decl.bindingLocation < 0 || decl.bindingLocation >= VertexAttributes::MAX)
{
if (decl.bindingLocation == -1 && !decl.name.empty())
legacyVertexBindings = true;
else
throw love::Exception("Vertex buffer attributes must have a valid binding location value within [0, %d).", VertexAttributes::MAX);
}
}

if (texelbuffer)
Expand Down Expand Up @@ -258,6 +263,17 @@ int Buffer::getDataMemberIndex(const std::string &name) const
return -1;
}

int Buffer::getDataMemberIndex(int bindingLocation) const
{
for (size_t i = 0; i < dataMembers.size(); i++)
{
if (dataMembers[i].decl.bindingLocation == bindingLocation)
return (int)i;
}

return -1;
}

void Buffer::clear(size_t offset, size_t size)
{
if (isImmutable())
Expand All @@ -280,53 +296,53 @@ std::vector<Buffer::DataDeclaration> Buffer::getCommonFormatDeclaration(CommonFo
return {};
case CommonFormat::XYf:
return {
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 }
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2, 0, ATTRIB_POS }
};
case CommonFormat::XYZf:
return {
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC3 }
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC3, 0, ATTRIB_POS }
};
case CommonFormat::RGBAub:
return {
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 }
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4, 0, ATTRIB_COLOR }
};
case CommonFormat::STf_RGBAub:
return {
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2 },
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2, 0, ATTRIB_TEXCOORD },
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4, 0, ATTRIB_COLOR },
};
case CommonFormat::STPf_RGBAub:
return {
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC3 },
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC3, 0, ATTRIB_TEXCOORD },
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4, 0, ATTRIB_COLOR },
};
case CommonFormat::XYf_STf:
return {
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2 },
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2, 0, ATTRIB_POS },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2, 0, ATTRIB_TEXCOORD },
};
case CommonFormat::XYf_STPf:
return {
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC3 },
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2, 0, ATTRIB_POS },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC3, 0, ATTRIB_TEXCOORD },
};
case CommonFormat::XYf_STf_RGBAub:
return {
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2 },
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 },
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2, 0, ATTRIB_POS },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2, 0, ATTRIB_TEXCOORD },
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4, 0, ATTRIB_COLOR },
};
case CommonFormat::XYf_STus_RGBAub:
return {
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_UNORM16_VEC2 },
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 },
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2, 0, ATTRIB_POS },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_UNORM16_VEC2, 0, ATTRIB_TEXCOORD },
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4, 0, ATTRIB_COLOR },
};
case CommonFormat::XYf_STPf_RGBAub:
return {
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2 },
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 },
{ getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2, 0, ATTRIB_POS },
{ getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2, 0, ATTRIB_TEXCOORD },
{ getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4, 0, ATTRIB_COLOR },
};
}

Expand Down
9 changes: 8 additions & 1 deletion src/modules/graphics/Buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ class Buffer : public love::Object, public Resource
std::string name;
DataFormat format;
int arrayLength;
int bindingLocation;

DataDeclaration(const std::string &name, DataFormat format, int arrayLength = 0)
DataDeclaration(const std::string &name, DataFormat format, int arrayLength = 0, int bindingLocation = -1)
: name(name)
, format(format)
, arrayLength(arrayLength)
, bindingLocation(bindingLocation)
{}
};

Expand Down Expand Up @@ -117,6 +119,7 @@ class Buffer : public love::Object, public Resource
const DataMember &getDataMember(int index) const { return dataMembers[index]; }
size_t getMemberOffset(int index) const { return dataMembers[index].offset; }
int getDataMemberIndex(const std::string &name) const;
int getDataMemberIndex(int bindingLocation) const;
const std::string &getDebugName() const { return debugName; }

void setImmutable(bool immutable) { this->immutable = immutable; };
Expand Down Expand Up @@ -154,6 +157,8 @@ class Buffer : public love::Object, public Resource
**/
virtual ptrdiff_t getTexelBufferHandle() const = 0;

bool hasLegacyVertexBindings() const { return legacyVertexBindings; }

static std::vector<DataDeclaration> getCommonFormatDeclaration(CommonFormat format);

class Mapper
Expand Down Expand Up @@ -198,6 +203,8 @@ class Buffer : public love::Object, public Resource
bool mapped;
MapType mappedType;
bool immutable;

bool legacyVertexBindings = false;

}; // Buffer

Expand Down
2 changes: 2 additions & 0 deletions src/modules/graphics/Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ Font::Font(love::font::Rasterizer *r, const SamplerState &s)
if (pixelFormat == PIXELFORMAT_LA8_UNORM && !gfx->isPixelFormatSupported(pixelFormat, PIXELFORMATUSAGEFLAGS_SAMPLE))
pixelFormat = PIXELFORMAT_RGBA8_UNORM;

vertexAttributesID = gfx->registerVertexAttributes(VertexAttributes(vertexFormat, 0));

loadVolatile();
++fontCount;
}
Expand Down
4 changes: 4 additions & 0 deletions src/modules/graphics/Font.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ class Font : public Object, public Volatile

uint32 getTextureCacheID() const;

VertexAttributesID getVertexAttributesID() const { return vertexAttributesID; }

// Implements Volatile.
bool loadVolatile() override;
void unloadVolatile() override;
Expand Down Expand Up @@ -204,6 +206,8 @@ class Font : public Object, public Volatile
// ID which is incremented when the texture cache is invalidated.
uint32 textureCacheID;

VertexAttributesID vertexAttributesID;

// 1 pixel of transparent padding between glyphs (so quads won't pick up
// other glyphs), plus one pixel of transparent padding that the quads will
// use, for edge antialiasing.
Expand Down
60 changes: 43 additions & 17 deletions src/modules/graphics/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,10 @@ Graphics::Graphics(const char *name)
states.reserve(10);
states.push_back(DisplayState());

noAttributesID = registerVertexAttributes(VertexAttributes());

if (!Shader::initialize())
throw love::Exception("Shader support failed to initialize!");
throw love::Exception("Shader support failed to initialize.");
}

Graphics::~Graphics()
Expand Down Expand Up @@ -1413,6 +1415,29 @@ void Graphics::updatePendingReadbacks()
}
}

VertexAttributesID Graphics::registerVertexAttributes(const VertexAttributes &attributes)
{
for (size_t i = 0; i < vertexAttributesDatabase.size(); i++)
{
if (attributes == vertexAttributesDatabase[i])
return { (int)i + 1 };
}

vertexAttributesDatabase.push_back(attributes);
return { (int)vertexAttributesDatabase.size() };
}

bool Graphics::findVertexAttributes(VertexAttributesID id, VertexAttributes &attributes)
{
int index = id.id - 1;

if (index < 0 || index >= (int)vertexAttributesDatabase.size())
return false;

attributes = vertexAttributesDatabase[index];
return true;
}

void Graphics::intersectScissor(const Rect &rect)
{
Rect currect = states.back().scissorRect;
Expand Down Expand Up @@ -2022,15 +2047,24 @@ void Graphics::flushBatchedDraws()
VertexAttributes attributes;
BufferBindings buffers;

VertexAttributesID attributesID = sbstate.attributesIDs[(int)sbstate.formats[0]][(int)sbstate.formats[1]];

if (!findVertexAttributes(attributesID, attributes))
{
for (int i = 0; i < 2; i++)
attributes.setCommonFormat(sbstate.formats[i], (uint8)i);

attributesID = registerVertexAttributes(attributes);
sbstate.attributesIDs[(int)sbstate.formats[0]][(int)sbstate.formats[1]] = attributesID;
}

size_t usedsizes[3] = {0, 0, 0};

for (int i = 0; i < 2; i++)
{
if (sbstate.formats[i] == CommonFormat::NONE)
continue;

attributes.setCommonFormat(sbstate.formats[i], (uint8) i);

usedsizes[i] = getFormatStride(sbstate.formats[i]) * sbstate.vertexCount;

size_t offset = sbstate.vb[i]->unmap(usedsizes[i]);
Expand All @@ -2053,7 +2087,7 @@ void Graphics::flushBatchedDraws()
{
usedsizes[2] = sizeof(uint16) * sbstate.indexCount;

DrawIndexedCommand cmd(&attributes, &buffers, sbstate.indexBuffer);
DrawIndexedCommand cmd(attributesID, &buffers, sbstate.indexBuffer);
cmd.primitiveType = sbstate.primitiveMode;
cmd.indexCount = sbstate.indexCount;
cmd.indexType = INDEX_UINT16;
Expand All @@ -2065,7 +2099,7 @@ void Graphics::flushBatchedDraws()
}
else
{
DrawCommand cmd(&attributes, &buffers);
DrawCommand cmd(attributesID, &buffers);
cmd.primitiveType = sbstate.primitiveMode;
cmd.vertexStart = 0;
cmd.vertexCount = sbstate.vertexCount;
Expand Down Expand Up @@ -2156,10 +2190,8 @@ void Graphics::drawFromShader(PrimitiveType primtype, int vertexcount, int insta

Shader::current->validateDrawState(primtype, maintexture);

VertexAttributes attributes;
BufferBindings buffers;

DrawCommand cmd(&attributes, &buffers);
DrawCommand cmd(noAttributesID, &buffers);

cmd.primitiveType = primtype;
cmd.vertexCount = vertexcount;
Expand Down Expand Up @@ -2190,10 +2222,8 @@ void Graphics::drawFromShader(Buffer *indexbuffer, int indexcount, int instancec

Shader::current->validateDrawState(PRIMITIVE_TRIANGLES, maintexture);

VertexAttributes attributes;
BufferBindings buffers;

DrawIndexedCommand cmd(&attributes, &buffers, indexbuffer);
DrawIndexedCommand cmd(noAttributesID, &buffers, indexbuffer);

cmd.primitiveType = PRIMITIVE_TRIANGLES;
cmd.indexCount = indexcount;
Expand Down Expand Up @@ -2221,10 +2251,8 @@ void Graphics::drawFromShaderIndirect(PrimitiveType primtype, Buffer *indirectar

Shader::current->validateDrawState(primtype, maintexture);

VertexAttributes attributes;
BufferBindings buffers;

DrawCommand cmd(&attributes, &buffers);
DrawCommand cmd(noAttributesID, &buffers);

cmd.primitiveType = primtype;
cmd.indirectBuffer = indirectargs;
Expand All @@ -2248,10 +2276,8 @@ void Graphics::drawFromShaderIndirect(Buffer *indexbuffer, Buffer *indirectargs,

Shader::current->validateDrawState(PRIMITIVE_TRIANGLES, maintexture);

VertexAttributes attributes;
BufferBindings buffers;

DrawIndexedCommand cmd(&attributes, &buffers, indexbuffer);
DrawIndexedCommand cmd(noAttributesID, &buffers, indexbuffer);

cmd.primitiveType = PRIMITIVE_TRIANGLES;
cmd.indexType = getIndexDataType(indexbuffer->getDataMember(0).decl.format);
Expand Down
Loading

0 comments on commit 50ff1e4

Please sign in to comment.