metal: hook up emulated 'fan' mesh draw mode.

This commit is contained in:
Alex Szpakowski
2022-01-22 12:59:09 -04:00
parent 3ecae61189
commit 62de8f62c7
6 changed files with 83 additions and 30 deletions
+6
View File
@@ -66,6 +66,12 @@ struct Range
return !(first > other.last || last < other.first); return !(first > other.last || last < other.first);
} }
void intersect(const Range &other)
{
first = std::max(first, other.first);
last = std::min(last, other.last);
}
void encapsulate(size_t index) void encapsulate(size_t index)
{ {
first = std::min(first, index); first = std::min(first, index);
+33 -2
View File
@@ -184,6 +184,7 @@ Graphics::Graphics()
, drawCalls(0) , drawCalls(0)
, drawCallsBatched(0) , drawCallsBatched(0)
, quadIndexBuffer(nullptr) , quadIndexBuffer(nullptr)
, fanIndexBuffer(nullptr)
, capabilities() , capabilities()
, cachedShaderStages() , cachedShaderStages()
{ {
@@ -202,7 +203,10 @@ Graphics::Graphics()
Graphics::~Graphics() Graphics::~Graphics()
{ {
delete quadIndexBuffer; if (quadIndexBuffer != nullptr)
quadIndexBuffer->release();
if (fanIndexBuffer != nullptr)
fanIndexBuffer->release();
// Clean up standard shaders before the active shader. If we do it after, // Clean up standard shaders before the active shader. If we do it after,
// the active shader may try to activate a standard shader when deactivating // the active shader may try to activate a standard shader when deactivating
@@ -239,7 +243,7 @@ void Graphics::createQuadIndexBuffer()
if (quadIndexBuffer != nullptr) if (quadIndexBuffer != nullptr)
return; return;
size_t size = sizeof(uint16) * (LOVE_UINT16_MAX / 4) * 6; size_t size = sizeof(uint16) * getIndexCount(TRIANGLEINDEX_QUADS, LOVE_UINT16_MAX);
Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, BUFFERDATAUSAGE_STATIC); Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, BUFFERDATAUSAGE_STATIC);
quadIndexBuffer = newBuffer(settings, DATAFORMAT_UINT16, nullptr, size, 0); quadIndexBuffer = newBuffer(settings, DATAFORMAT_UINT16, nullptr, size, 0);
@@ -250,6 +254,22 @@ void Graphics::createQuadIndexBuffer()
quadIndexBuffer->setImmutable(true); quadIndexBuffer->setImmutable(true);
} }
void Graphics::createFanIndexBuffer()
{
if (fanIndexBuffer != nullptr)
return;
size_t size = sizeof(uint16) * getIndexCount(TRIANGLEINDEX_FAN, LOVE_UINT16_MAX);
Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, BUFFERDATAUSAGE_STATIC);
fanIndexBuffer = newBuffer(settings, DATAFORMAT_UINT16, nullptr, size, 0);
Buffer::Mapper map(*fanIndexBuffer);
fillIndices(TRIANGLEINDEX_FAN, 0, LOVE_UINT16_MAX, (uint16 *) map.data);
fanIndexBuffer->setImmutable(true);
}
Quad *Graphics::newQuad(Quad::Viewport v, double sw, double sh) Quad *Graphics::newQuad(Quad::Viewport v, double sw, double sh)
{ {
return new Quad(v, sw, sh); return new Quad(v, sw, sh);
@@ -1617,6 +1637,17 @@ void Graphics::drawInstanced(Mesh *mesh, const Matrix4 &m, int instancecount)
void Graphics::drawShaderVertices(PrimitiveType primtype, int vertexcount, int instancecount, Texture *maintexture) void Graphics::drawShaderVertices(PrimitiveType primtype, int vertexcount, int instancecount, Texture *maintexture)
{ {
if (primtype == PRIMITIVE_TRIANGLE_FAN && vertexcount > LOVE_UINT16_MAX)
throw love::Exception("drawShaderVertices cannot draw more than %d vertices when the 'fan' draw mode is used.", LOVE_UINT16_MAX);
// Emulated triangle fan via an index buffer.
if (primtype == PRIMITIVE_TRIANGLE_FAN && getFanIndexBuffer())
{
int indexcount = getIndexCount(TRIANGLEINDEX_FAN, vertexcount);
drawShaderVertices(getFanIndexBuffer(), indexcount, instancecount, 0, maintexture);
return;
}
flushBatchedDraws(); flushBatchedDraws();
if (!capabilities.features[FEATURE_GLSL3]) if (!capabilities.features[FEATURE_GLSL3])
+3
View File
@@ -526,6 +526,7 @@ public:
virtual int getBackbufferMSAA() const = 0; virtual int getBackbufferMSAA() const = 0;
Buffer *getQuadIndexBuffer() const { return quadIndexBuffer; } Buffer *getQuadIndexBuffer() const { return quadIndexBuffer; }
Buffer *getFanIndexBuffer() const { return fanIndexBuffer; }
/** /**
* Sets the current constant color. * Sets the current constant color.
@@ -987,6 +988,7 @@ protected:
virtual void getAPIStats(int &shaderswitches) const = 0; virtual void getAPIStats(int &shaderswitches) const = 0;
void createQuadIndexBuffer(); void createQuadIndexBuffer();
void createFanIndexBuffer();
Texture *getTemporaryTexture(PixelFormat format, int w, int h, int samples); Texture *getTemporaryTexture(PixelFormat format, int w, int h, int samples);
@@ -1029,6 +1031,7 @@ protected:
int drawCallsBatched; int drawCallsBatched;
Buffer *quadIndexBuffer; Buffer *quadIndexBuffer;
Buffer *fanIndexBuffer;
Capabilities capabilities; Capabilities capabilities;
+36 -23
View File
@@ -501,22 +501,21 @@ void Mesh::setDrawRange(int start, int count)
if (start < 0 || count <= 0) if (start < 0 || count <= 0)
throw love::Exception("Invalid draw range."); throw love::Exception("Invalid draw range.");
rangeStart = start; drawRange = Range(start, count);
rangeCount = count;
} }
void Mesh::setDrawRange() void Mesh::setDrawRange()
{ {
rangeStart = rangeCount = -1; drawRange.invalidate();
} }
bool Mesh::getDrawRange(int &start, int &count) const bool Mesh::getDrawRange(int &start, int &count) const
{ {
if (rangeStart < 0 || rangeCount <= 0) if (!drawRange.isValid())
return false; return false;
start = rangeStart; start = (int) drawRange.getOffset();
count = rangeCount; count = (int) drawRange.getSize();
return true; return true;
} }
@@ -595,9 +594,30 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
Graphics::TempTransform transform(gfx, m); Graphics::TempTransform transform(gfx, m);
if (useIndexBuffer && indexBuffer != nullptr && indexCount > 0) Buffer *indexbuffer = useIndexBuffer ? indexBuffer : nullptr;
int indexcount = (int) indexCount;
Range range = drawRange;
// Emulated triangle fan via an index buffer.
if (primitiveType == PRIMITIVE_TRIANGLE_FAN && indexbuffer == nullptr && gfx->getFanIndexBuffer())
{ {
Graphics::DrawIndexedCommand cmd(&attributes, &buffers, indexBuffer); indexbuffer = gfx->getFanIndexBuffer();
indexcount = graphics::getIndexCount(TRIANGLEINDEX_FAN, vertexCount);
if (range.isValid())
{
int start = graphics::getIndexCount(TRIANGLEINDEX_FAN, (int) range.getOffset());
int count = graphics::getIndexCount(TRIANGLEINDEX_FAN, (int) range.getSize());
range = Range(start, count);
}
}
if (indexbuffer != nullptr && indexcount > 0)
{
Range r(0, indexcount);
if (range.isValid())
r.intersect(range);
Graphics::DrawIndexedCommand cmd(&attributes, &buffers, indexbuffer);
cmd.primitiveType = primitiveType; cmd.primitiveType = primitiveType;
cmd.indexType = indexDataType; cmd.indexType = indexDataType;
@@ -605,30 +625,23 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
cmd.texture = texture; cmd.texture = texture;
cmd.cullMode = gfx->getMeshCullMode(); cmd.cullMode = gfx->getMeshCullMode();
int start = std::min(std::max(0, rangeStart), (int) indexCount - 1); cmd.indexBufferOffset = r.getOffset() * indexbuffer->getArrayStride();
cmd.indexBufferOffset = start * getIndexDataSize(indexDataType); cmd.indexCount = (int) r.getSize();
cmd.indexCount = (int) indexCount;
if (rangeCount > 0)
cmd.indexCount = std::min(cmd.indexCount, rangeCount);
cmd.indexCount = std::min(cmd.indexCount, (int) indexCount - start);
if (cmd.indexCount > 0) if (cmd.indexCount > 0)
gfx->draw(cmd); gfx->draw(cmd);
} }
else if (vertexCount > 0) else if (vertexCount > 0)
{ {
Range r(0, vertexCount);
if (range.isValid())
r.intersect(range);
Graphics::DrawCommand cmd(&attributes, &buffers); Graphics::DrawCommand cmd(&attributes, &buffers);
cmd.primitiveType = primitiveType; cmd.primitiveType = primitiveType;
cmd.vertexStart = std::min(std::max(0, rangeStart), (int) vertexCount - 1); cmd.vertexStart = (int) r.getOffset();
cmd.vertexCount = (int) r.getSize();
cmd.vertexCount = (int) vertexCount;
if (rangeCount > 0)
cmd.vertexCount = std::min(cmd.vertexCount, rangeCount);
cmd.vertexCount = std::min(cmd.vertexCount, (int) vertexCount - cmd.vertexStart);
cmd.instanceCount = instancecount; cmd.instanceCount = instancecount;
cmd.texture = texture; cmd.texture = texture;
cmd.cullMode = gfx->getMeshCullMode(); cmd.cullMode = gfx->getMeshCullMode();
+1 -2
View File
@@ -207,8 +207,7 @@ private:
PrimitiveType primitiveType = PRIMITIVE_TRIANGLES; PrimitiveType primitiveType = PRIMITIVE_TRIANGLES;
int rangeStart = -1; Range drawRange = Range();
int rangeCount = -1;
StrongRef<Texture> texture; StrongRef<Texture> texture;
+4 -3
View File
@@ -118,7 +118,7 @@ static MTLPrimitiveType getMTLPrimitiveType(PrimitiveType prim)
{ {
case PRIMITIVE_TRIANGLES: return MTLPrimitiveTypeTriangle; case PRIMITIVE_TRIANGLES: return MTLPrimitiveTypeTriangle;
case PRIMITIVE_TRIANGLE_STRIP: return MTLPrimitiveTypeTriangleStrip; case PRIMITIVE_TRIANGLE_STRIP: return MTLPrimitiveTypeTriangleStrip;
case PRIMITIVE_TRIANGLE_FAN: return MTLPrimitiveTypeTriangle; // TODO: This needs to be emulated. case PRIMITIVE_TRIANGLE_FAN: return MTLPrimitiveTypeTriangle; // This is emulated with an index buffer.
case PRIMITIVE_POINTS: return MTLPrimitiveTypePoint; case PRIMITIVE_POINTS: return MTLPrimitiveTypePoint;
case PRIMITIVE_MAX_ENUM: return MTLPrimitiveTypeTriangle; case PRIMITIVE_MAX_ENUM: return MTLPrimitiveTypeTriangle;
} }
@@ -336,6 +336,7 @@ Graphics::Graphics()
} }
createQuadIndexBuffer(); createQuadIndexBuffer();
createFanIndexBuffer();
// We always need a default shader. // We always need a default shader.
for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++)
@@ -1476,7 +1477,7 @@ void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt sten
}} }}
void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil) void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
{ { @autoreleasepool {
flushBatchedDraws(); flushBatchedDraws();
// TODO // TODO
@@ -1497,7 +1498,7 @@ void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
passDesc.stencilAttachment.loadAction = MTLLoadActionDontCare; passDesc.stencilAttachment.loadAction = MTLLoadActionDontCare;
passDesc.depthAttachment.loadAction = MTLLoadActionDontCare; passDesc.depthAttachment.loadAction = MTLLoadActionDontCare;
} }
} }}
void Graphics::present(void *screenshotCallbackData) void Graphics::present(void *screenshotCallbackData)
{ @autoreleasepool { { @autoreleasepool {