Browse Source

metal: fix quad drawing on older iOS devices

Alex Szpakowski 3 years ago
parent
commit
620dc42292
1 changed files with 64 additions and 16 deletions
  1. 64 16
      src/modules/graphics/metal/Graphics.mm

+ 64 - 16
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<MTLBuffer> ib = getMTLBuffer(quadIndexBuffer);
 
-	// TODO: support for iOS devices that don't support base vertex.
+	// Some older iOS devices don't support base vertex rendering.
+	if (families.apple[3] || families.mac[1] || families.macCatalyst[1])
+	{
+		setVertexBuffers(encoder, &buffers, renderBindings);
 
-	int basevertex = start * 4;
+		int basevertex = start * 4;
 
-	for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW)
+		for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW)
+		{
+			int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
+
+			[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
+								indexCount:quadcount * 6
+								 indexType:MTLIndexTypeUInt16
+							   indexBuffer:ib
+						 indexBufferOffset:0
+							 instanceCount:1
+								baseVertex:basevertex
+							  baseInstance:0];
+
+			++drawCalls;
+			basevertex += quadcount * 4;
+		}
+	}
+	else
 	{
-		int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
+		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);
 
-		[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
-							indexCount:quadcount * 6
-							 indexType:MTLIndexTypeUInt16
-						   indexBuffer:ib
-					 indexBufferOffset:0
-						 instanceCount:1
-							baseVertex:basevertex
-						  baseInstance:0];
+			int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
 
-		++drawCalls;
+			[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
+								indexCount:quadcount * 6
+								 indexType:MTLIndexTypeUInt16
+							   indexBuffer:ib
+						 indexBufferOffset:0];
 
-		basevertex += quadcount * 4;
+			++drawCalls;
+
+			if (count > MAX_QUADS_PER_DRAW)
+				advanceVertexOffsets(attributes, bufferscopy, quadcount * 4);
+		}
 	}
 }}