mirror of
https://github.com/love2d/love.git
synced 2026-08-17 19:23:38 +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:
@@ -1204,10 +1204,19 @@ void Graphics::draw(const DrawCommand &cmd)
|
||||
|
||||
setVertexBuffers(encoder, Shader::current, cmd.buffers, renderBindings);
|
||||
|
||||
[encoder drawPrimitives:getMTLPrimitiveType(cmd.primitiveType)
|
||||
vertexStart:cmd.vertexStart
|
||||
vertexCount:cmd.vertexCount
|
||||
instanceCount:cmd.instanceCount];
|
||||
if (cmd.indirectBuffer != nullptr)
|
||||
{
|
||||
[encoder drawPrimitives:getMTLPrimitiveType(cmd.primitiveType)
|
||||
indirectBuffer:getMTLBuffer(cmd.indirectBuffer)
|
||||
indirectBufferOffset:cmd.indirectBufferOffset];
|
||||
}
|
||||
else
|
||||
{
|
||||
[encoder drawPrimitives:getMTLPrimitiveType(cmd.primitiveType)
|
||||
vertexStart:cmd.vertexStart
|
||||
vertexCount:cmd.vertexCount
|
||||
instanceCount:cmd.instanceCount];
|
||||
}
|
||||
|
||||
++drawCalls;
|
||||
}}
|
||||
@@ -1229,12 +1238,24 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||
|
||||
auto indexType = cmd.indexType == INDEX_UINT32 ? MTLIndexTypeUInt32 : MTLIndexTypeUInt16;
|
||||
|
||||
[encoder drawIndexedPrimitives:getMTLPrimitiveType(cmd.primitiveType)
|
||||
indexCount:cmd.indexCount
|
||||
indexType:indexType
|
||||
indexBuffer:getMTLBuffer(cmd.indexBuffer)
|
||||
indexBufferOffset:cmd.indexBufferOffset
|
||||
instanceCount:cmd.instanceCount];
|
||||
if (cmd.indirectBuffer != nullptr)
|
||||
{
|
||||
[encoder drawIndexedPrimitives:getMTLPrimitiveType(cmd.primitiveType)
|
||||
indexType:indexType
|
||||
indexBuffer:getMTLBuffer(cmd.indexBuffer)
|
||||
indexBufferOffset:cmd.indexBufferOffset
|
||||
indirectBuffer:getMTLBuffer(cmd.indirectBuffer)
|
||||
indirectBufferOffset:cmd.indexBufferOffset];
|
||||
}
|
||||
else
|
||||
{
|
||||
[encoder drawIndexedPrimitives:getMTLPrimitiveType(cmd.primitiveType)
|
||||
indexCount:cmd.indexCount
|
||||
indexType:indexType
|
||||
indexBuffer:getMTLBuffer(cmd.indexBuffer)
|
||||
indexBufferOffset:cmd.indexBufferOffset
|
||||
instanceCount:cmd.instanceCount];
|
||||
}
|
||||
|
||||
++drawCalls;
|
||||
}}
|
||||
@@ -1330,10 +1351,9 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes &attribute
|
||||
}
|
||||
}}
|
||||
|
||||
bool Graphics::dispatch(int x, int y, int z)
|
||||
bool Graphics::dispatch(love::graphics::Shader *s, int x, int y, int z)
|
||||
{ @autoreleasepool {
|
||||
// Set by higher level code before calling dispatch(x, y, z).
|
||||
auto shader = (Shader *) Shader::current;
|
||||
auto shader = (Shader *) s;
|
||||
|
||||
int tX, tY, tZ;
|
||||
shader->getLocalThreadgroupSize(&tX, &tY, &tZ);
|
||||
@@ -1356,6 +1376,32 @@ bool Graphics::dispatch(int x, int y, int z)
|
||||
return true;
|
||||
}}
|
||||
|
||||
bool Graphics::dispatch(love::graphics::Shader *s, love::graphics::Buffer *indirectargs, size_t argsoffset)
|
||||
{
|
||||
auto shader = (Shader *) s;
|
||||
|
||||
int tX, tY, tZ;
|
||||
shader->getLocalThreadgroupSize(&tX, &tY, &tZ);
|
||||
|
||||
id<MTLComputePipelineState> pipeline = shader->getComputePipeline();
|
||||
if (pipeline == nil)
|
||||
return false;
|
||||
|
||||
id<MTLComputeCommandEncoder> computeEncoder = useComputeEncoder();
|
||||
|
||||
if (!applyShaderUniforms(computeEncoder, shader))
|
||||
return false;
|
||||
|
||||
// TODO: track this state?
|
||||
[computeEncoder setComputePipelineState:pipeline];
|
||||
|
||||
[computeEncoder dispatchThreadgroupsWithIndirectBuffer:getMTLBuffer(indirectargs)
|
||||
indirectBufferOffset:argsoffset
|
||||
threadsPerThreadgroup:MTLSizeMake(tX, tY, tZ)];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int /*pixelw*/, int /*pixelh*/, bool /*hasSRGBtexture*/)
|
||||
{ @autoreleasepool {
|
||||
endPass(false);
|
||||
@@ -2173,7 +2219,13 @@ void Graphics::initCapabilities()
|
||||
capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = true;
|
||||
capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = true;
|
||||
capabilities.features[FEATURE_MIPMAP_RANGE] = true;
|
||||
static_assert(FEATURE_MAX_ENUM == 18, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
|
||||
|
||||
if (families.mac[1] || families.macCatalyst[1] || families.apple[3])
|
||||
capabilities.features[FEATURE_INDIRECT_DRAW] = true;
|
||||
else
|
||||
capabilities.features[FEATURE_INDIRECT_DRAW] = false;
|
||||
|
||||
static_assert(FEATURE_MAX_ENUM == 19, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
|
||||
|
||||
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
|
||||
capabilities.limits[LIMIT_POINT_SIZE] = 511;
|
||||
|
||||
Reference in New Issue
Block a user