From 620dc42292a10d848f14e86dd2b93ee084aa8ff9 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 24 Dec 2021 19:13:48 -0400 Subject: [PATCH] metal: fix quad drawing on older iOS devices --- src/modules/graphics/metal/Graphics.mm | 84 ++++++++++++++++++++------ 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index 8a5be01e1..6df0d595d 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -1076,6 +1076,29 @@ void Graphics::draw(const DrawIndexedCommand &cmd) ++drawCalls; }} +static inline void advanceVertexOffsets(const VertexAttributes &attributes, BufferBindings &buffers, int vertexcount) +{ + // TODO: Figure out a better way to avoid touching the same buffer multiple + // times, if multiple attributes share the buffer. + uint32 touchedbuffers = 0; + + for (unsigned int i = 0; i < VertexAttributes::MAX; i++) + { + if (!attributes.isEnabled(i)) + continue; + + auto &attrib = attributes.attribs[i]; + + uint32 bufferbit = 1u << attrib.bufferIndex; + if ((touchedbuffers & bufferbit) == 0) + { + touchedbuffers |= bufferbit; + const auto &layout = attributes.bufferLayouts[attrib.bufferIndex]; + buffers.info[attrib.bufferIndex].offset += layout.stride * vertexcount; + } + } +} + void Graphics::drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, love::graphics::Texture *texture) { @autoreleasepool { const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX; @@ -1092,30 +1115,55 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes &attribute applyRenderState(encoder, attributes); applyShaderUniforms(encoder, Shader::current, texture); - setVertexBuffers(encoder, &buffers, renderBindings); - id ib = getMTLBuffer(quadIndexBuffer); - // TODO: support for iOS devices that don't support base vertex. - - int basevertex = start * 4; - - for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW) + // Some older iOS devices don't support base vertex rendering. + if (families.apple[3] || families.mac[1] || families.macCatalyst[1]) { - int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex); + setVertexBuffers(encoder, &buffers, renderBindings); - [encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle - indexCount:quadcount * 6 - indexType:MTLIndexTypeUInt16 - indexBuffer:ib - indexBufferOffset:0 - instanceCount:1 - baseVertex:basevertex - baseInstance:0]; + int basevertex = start * 4; - ++drawCalls; + for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW) + { + int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex); - basevertex += quadcount * 4; + [encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle + indexCount:quadcount * 6 + indexType:MTLIndexTypeUInt16 + indexBuffer:ib + indexBufferOffset:0 + instanceCount:1 + baseVertex:basevertex + baseInstance:0]; + + ++drawCalls; + basevertex += quadcount * 4; + } + } + else + { + BufferBindings bufferscopy = buffers; + if (start > 0) + advanceVertexOffsets(attributes, bufferscopy, start * 4); + + for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW) + { + setVertexBuffers(encoder, &bufferscopy, renderBindings); + + int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex); + + [encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle + indexCount:quadcount * 6 + indexType:MTLIndexTypeUInt16 + indexBuffer:ib + indexBufferOffset:0]; + + ++drawCalls; + + if (count > MAX_QUADS_PER_DRAW) + advanceVertexOffsets(attributes, bufferscopy, quadcount * 4); + } } }}