mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
Add functions for indirect draws and compute dispatches.
Resolves #1879. - Add an 'indirectdraw' boolean field to the graphics feature support table returned by love.graphics.getSupported. This is almost always supported when compute shaders are supported, except on a few older phones. - Add an 'indirectarguments' boolean field to the settings table in love.graphics.newBuffer. - Add love.graphics.dispatchIndirect(shader, argumentsbuffer [, argumentsindex = 1]). The compute dispatch's threadgroup width, height, and depth values are fetched from the buffer (as 3 uints) instead of coming from function parameters. - Add love.graphics.drawIndirect(mesh, argumentsbuffer, argumentsindex, x, y, ....). Vertex or index count, instance count, and other related parameters for drawing the mesh are fetched from the buffer (as 4 or 5 uints depending on whether the mesh has an index buffer) instead of coming from function parameters. It's usually a good idea to keep parameters other than the instance count in sync with what the mesh should be using. - Add love.graphics.drawFromShaderIndirect(drawmode, argumentsbuffer [, argumentsindex = 1] [, maintexture = nil]) and drawFromShaderIndirect(indexbuffer, argumentsbuffer [, argumentsindex] [, maintexture = nil]). Vertex or index count, instance count, and other related parameters are fetched from the buffer as 4 or 5 uints, as above. For the dispatch indirect arguments buffer, it has to have 3 uint32 elements: { uint threadgroupsX, uint threadgroupsY, uint threadgroupsZ }. For non-indexed draws, the arguments buffer has to have 4 uint32 elements: { uint vertexCount, uint instanceCount, uint baseVertex, uint baseInstance }. Note that baseInstance should always be set to 0 as many drivers don't support non-zero values. For draws which use an index buffer, the arguments buffer has to have 5 uint32 elements: { uint indexCount, uint instanceCount, uint firstIndex, uint baseVertex, uint baseInstance }. As above, the baseInstance value should always be 0. A buffer can be created to have an array of those structures, which can be used with the argumentsindex parameter of the Indirect dispatch/draw functions.
This commit is contained in:
@@ -525,17 +525,38 @@ bool Mesh::getDrawRange(int &start, int &count) const
|
||||
|
||||
void Mesh::draw(Graphics *gfx, const love::Matrix4 &m)
|
||||
{
|
||||
drawInstanced(gfx, m, 1);
|
||||
drawInternal(gfx, m, 1, nullptr, 0);
|
||||
}
|
||||
|
||||
void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
|
||||
{
|
||||
if (vertexCount <= 0 || instancecount <= 0)
|
||||
drawInternal(gfx, m, instancecount, nullptr, 0);
|
||||
}
|
||||
|
||||
void Mesh::drawIndirect(Graphics *gfx, const Matrix4 &m, Buffer *indirectargs, int argsindex)
|
||||
{
|
||||
drawInternal(gfx, m, 0, indirectargs, argsindex);
|
||||
}
|
||||
|
||||
void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buffer *indirectargs, int argsindex)
|
||||
{
|
||||
if (vertexCount <= 0 || (instancecount <= 0 && indirectargs == nullptr))
|
||||
return;
|
||||
|
||||
if (instancecount > 1 && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING])
|
||||
throw love::Exception("Instancing is not supported on this system.");
|
||||
|
||||
if (indirectargs != nullptr)
|
||||
{
|
||||
if (primitiveType == PRIMITIVE_TRIANGLE_FAN)
|
||||
throw love::Exception("The fan draw mode is not supported in indirect draws.");
|
||||
|
||||
if (useIndexBuffer && indexBuffer != nullptr)
|
||||
gfx->validateIndirectArgsBuffer(Graphics::INDIRECT_ARGS_DRAW_INDICES, indirectargs, argsindex);
|
||||
else
|
||||
gfx->validateIndirectArgsBuffer(Graphics::INDIRECT_ARGS_DRAW_VERTICES, indirectargs, argsindex);
|
||||
}
|
||||
|
||||
// Some graphics backends don't natively support triangle fans. So we'd
|
||||
// have to emulate them with triangles plus an index buffer... which doesn't
|
||||
// work so well when there's already a custom index buffer.
|
||||
@@ -616,7 +637,7 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
|
||||
}
|
||||
}
|
||||
|
||||
if (indexbuffer != nullptr && indexcount > 0)
|
||||
if (indexbuffer != nullptr && (indexcount > 0 || indirectargs != nullptr))
|
||||
{
|
||||
Range r(0, indexcount);
|
||||
if (range.isValid())
|
||||
@@ -633,10 +654,13 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
|
||||
cmd.indexBufferOffset = r.getOffset() * indexbuffer->getArrayStride();
|
||||
cmd.indexCount = (int) r.getSize();
|
||||
|
||||
cmd.indirectBuffer = indirectargs;
|
||||
cmd.indirectBufferOffset = argsindex * (indirectargs != nullptr ? indirectargs->getArrayStride() : 0);
|
||||
|
||||
if (cmd.indexCount > 0)
|
||||
gfx->draw(cmd);
|
||||
}
|
||||
else if (vertexCount > 0)
|
||||
else if (vertexCount > 0 || indirectargs != nullptr)
|
||||
{
|
||||
Range r(0, vertexCount);
|
||||
if (range.isValid())
|
||||
@@ -651,6 +675,9 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
|
||||
cmd.texture = texture;
|
||||
cmd.cullMode = gfx->getMeshCullMode();
|
||||
|
||||
cmd.indirectBuffer = indirectargs;
|
||||
cmd.indirectBufferOffset = argsindex * (indirectargs != nullptr ? indirectargs->getArrayStride() : 0);
|
||||
|
||||
if (cmd.vertexCount > 0)
|
||||
gfx->draw(cmd);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user