mirror of
https://github.com/love2d/love.git
synced 2026-08-19 20:19:42 +02:00
metal: hook up emulated 'fan' mesh draw mode.
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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])
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user