Implement indirect draws

Bug: b/118619338
Test: dEQP-VK.draw.*
Change-Id: I282c0f1e8f44b0bec2318ab901ec511413bff11d
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/27888
Tested-by: Chris Forbes <chrisforbes@google.com>
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index 3156053..447075e 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -268,59 +268,15 @@
 	}
 }
 
-struct Draw : public CommandBuffer::Command
+struct DrawBase : public CommandBuffer::Command
 {
-	Draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance)
-		: vertexCount(vertexCount), instanceCount(instanceCount), firstVertex(firstVertex), firstInstance(firstInstance)
+	int bytesPerIndex(CommandBuffer::ExecutionState const& executionState)
 	{
+		return executionState.indexType == VK_INDEX_TYPE_UINT16 ? 2 : 4;
 	}
 
-	void play(CommandBuffer::ExecutionState& executionState) override
-	{
-		GraphicsPipeline* pipeline = static_cast<GraphicsPipeline*>(
-			executionState.pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS]);
-
-		sw::Context context = pipeline->getContext();
-		executionState.bindVertexInputs(context, firstVertex, firstInstance);
-
-		const auto& boundDescriptorSets = executionState.boundDescriptorSets[VK_PIPELINE_BIND_POINT_GRAPHICS];
-		for(int i = 0; i < vk::MAX_BOUND_DESCRIPTOR_SETS; i++)
-		{
-			context.descriptorSets[i] = reinterpret_cast<vk::DescriptorSet*>(boundDescriptorSets[i]);
-		}
-
-		context.pushConstants = executionState.pushConstants;
-
-		executionState.renderer->setContext(context);
-		executionState.renderer->setScissor(pipeline->getScissor());
-		executionState.renderer->setViewport(pipeline->getViewport());
-		executionState.renderer->setBlendConstant(pipeline->getBlendConstants());
-
-		executionState.bindAttachments();
-
-		const uint32_t primitiveCount = pipeline->computePrimitiveCount(vertexCount);
-		for(uint32_t instance = firstInstance; instance != firstInstance + instanceCount; instance++)
-		{
-			executionState.renderer->setInstanceID(instance);
-			executionState.renderer->draw(context.drawType, primitiveCount);
-			executionState.renderer->advanceInstanceAttributes();
-		}
-	}
-
-	uint32_t vertexCount;
-	uint32_t instanceCount;
-	uint32_t firstVertex;
-	uint32_t firstInstance;
-};
-
-struct DrawIndexed : public CommandBuffer::Command
-{
-	DrawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance)
-			: indexCount(indexCount), instanceCount(instanceCount), firstIndex(firstIndex), vertexOffset(vertexOffset), firstInstance(firstInstance)
-	{
-	}
-
-	void play(CommandBuffer::ExecutionState& executionState) override
+	void draw(CommandBuffer::ExecutionState& executionState, bool indexed,
+			uint32_t count, uint32_t instanceCount, uint32_t first, int32_t vertexOffset, uint32_t firstInstance)
 	{
 		GraphicsPipeline* pipeline = static_cast<GraphicsPipeline*>(
 				executionState.pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS]);
@@ -336,9 +292,16 @@
 		}
 
 		context.pushConstants = executionState.pushConstants;
+		auto drawType = context.drawType;
 
-		context.indexBuffer = Cast(executionState.indexBufferBinding.buffer)->getOffsetPointer(
-				executionState.indexBufferBinding.offset + firstIndex * (executionState.indexType == VK_INDEX_TYPE_UINT16 ? 2 : 4));
+		if (indexed)
+		{
+			context.indexBuffer = Cast(executionState.indexBufferBinding.buffer)->getOffsetPointer(
+					executionState.indexBufferBinding.offset + first * bytesPerIndex(executionState));
+
+			drawType = static_cast<sw::DrawType>(executionState.indexType == VK_INDEX_TYPE_UINT16
+					   ? (context.drawType | sw::DRAW_INDEXED16) : (context.drawType | sw::DRAW_INDEXED32));
+		}
 
 		executionState.renderer->setContext(context);
 		executionState.renderer->setScissor(pipeline->getScissor());
@@ -347,17 +310,45 @@
 
 		executionState.bindAttachments();
 
-		auto drawType = executionState.indexType == VK_INDEX_TYPE_UINT16
-				? (context.drawType | sw::DRAW_INDEXED16) : (context.drawType | sw::DRAW_INDEXED32);
-
-		const uint32_t primitiveCount = pipeline->computePrimitiveCount(indexCount);
+		const uint32_t primitiveCount = pipeline->computePrimitiveCount(count);
 		for(uint32_t instance = firstInstance; instance != firstInstance + instanceCount; instance++)
 		{
 			executionState.renderer->setInstanceID(instance);
-			executionState.renderer->draw(static_cast<sw::DrawType>(drawType), primitiveCount);
+			executionState.renderer->draw(drawType, primitiveCount);
 			executionState.renderer->advanceInstanceAttributes();
 		}
 	}
+};
+
+struct Draw : public DrawBase
+{
+	Draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance)
+		: vertexCount(vertexCount), instanceCount(instanceCount), firstVertex(firstVertex), firstInstance(firstInstance)
+	{
+	}
+
+	void play(CommandBuffer::ExecutionState& executionState) override
+	{
+		draw(executionState, false, vertexCount, instanceCount, 0, firstVertex, firstInstance);
+	}
+
+	uint32_t vertexCount;
+	uint32_t instanceCount;
+	uint32_t firstVertex;
+	uint32_t firstInstance;
+};
+
+struct DrawIndexed : public DrawBase
+{
+	DrawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance)
+			: indexCount(indexCount), instanceCount(instanceCount), firstIndex(firstIndex), vertexOffset(vertexOffset), firstInstance(firstInstance)
+	{
+	}
+
+	void play(CommandBuffer::ExecutionState& executionState) override
+	{
+		draw(executionState, true, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
+	}
 
 	uint32_t indexCount;
 	uint32_t instanceCount;
@@ -366,6 +357,50 @@
 	uint32_t firstInstance;
 };
 
+struct DrawIndirect : public DrawBase
+{
+	DrawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride)
+			: buffer(buffer), offset(offset), drawCount(drawCount), stride(stride)
+	{
+	}
+
+	void play(CommandBuffer::ExecutionState& executionState) override
+	{
+		for (auto drawId = 0u; drawId < drawCount; drawId++)
+		{
+			auto cmd = reinterpret_cast<VkDrawIndirectCommand const *>(Cast(buffer)->getOffsetPointer(offset + drawId * stride));
+			draw(executionState, false, cmd->vertexCount, cmd->instanceCount, 0, cmd->firstVertex, cmd->firstInstance);
+		}
+	}
+
+	VkBuffer buffer;
+	VkDeviceSize offset;
+	uint32_t drawCount;
+	uint32_t stride;
+};
+
+struct DrawIndexedIndirect : public DrawBase
+{
+	DrawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride)
+			: buffer(buffer), offset(offset), drawCount(drawCount), stride(stride)
+	{
+	}
+
+	void play(CommandBuffer::ExecutionState& executionState) override
+	{
+		for (auto drawId = 0u; drawId < drawCount; drawId++)
+		{
+			auto cmd = reinterpret_cast<VkDrawIndexedIndirectCommand const *>(Cast(buffer)->getOffsetPointer(offset + drawId * stride));
+			draw(executionState, true, cmd->indexCount, cmd->instanceCount, cmd->firstIndex, cmd->vertexOffset, cmd->firstInstance);
+		}
+	}
+
+	VkBuffer buffer;
+	VkDeviceSize offset;
+	uint32_t drawCount;
+	uint32_t stride;
+};
+
 struct ImageToImageCopy : public CommandBuffer::Command
 {
 	ImageToImageCopy(VkImage pSrcImage, VkImage pDstImage, const VkImageCopy& pRegion) :
@@ -1110,12 +1145,12 @@
 
 void CommandBuffer::drawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride)
 {
-	UNIMPLEMENTED("drawIndirect");
+	addCommand<DrawIndirect>(buffer, offset, drawCount, stride);
 }
 
 void CommandBuffer::drawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride)
 {
-	UNIMPLEMENTED("drawIndexedIndirect");
+	addCommand<DrawIndexedIndirect>(buffer, offset, drawCount, stride);
 }
 
 void CommandBuffer::submit(CommandBuffer::ExecutionState& executionState)