Implement indexed draws

Adds support for vkBindIndexBuffer and vkDrawIndexed.
There is significant duplication currently between Draw::play and
DrawIndexed::play, but most of it is going to evaporate when we
solve the context stomping problems.

Bug: b/118619338
Change-Id: If8e9f7b1f11a3c763e73663733697fddd3e1fcac
Reviewed-on: https://swiftshader-review.googlesource.com/c/25508
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Device/Context.hpp b/src/Device/Context.hpp
index daa2420..245f516 100644
--- a/src/Device/Context.hpp
+++ b/src/Device/Context.hpp
@@ -197,7 +197,7 @@
 
 		vk::ImageView *texture[TOTAL_IMAGE_UNITS];
 		Stream input[MAX_VERTEX_INPUTS];
-		uint8_t *indexBuffer;
+		void *indexBuffer;
 
 		vk::ImageView *renderTarget[RENDERTARGETS];
 		unsigned int renderTargetLayer[RENDERTARGETS];
diff --git a/src/Device/PixelProcessor.cpp b/src/Device/PixelProcessor.cpp
index 0d43b81..db32be0 100644
--- a/src/Device/PixelProcessor.cpp
+++ b/src/Device/PixelProcessor.cpp
@@ -77,11 +77,6 @@
 		context->renderTargetLayer[index] = layer;
 	}
 
-	vk::ImageView* PixelProcessor::getRenderTarget(int index)
-	{
-		return context->renderTarget[index];
-	}
-
 	void PixelProcessor::setDepthBuffer(vk::ImageView *depthBuffer, unsigned int layer)
 	{
 		context->depthBuffer = depthBuffer;
diff --git a/src/Device/PixelProcessor.hpp b/src/Device/PixelProcessor.hpp
index 9a0d20f..90b3f81 100644
--- a/src/Device/PixelProcessor.hpp
+++ b/src/Device/PixelProcessor.hpp
@@ -146,7 +146,6 @@
 		virtual ~PixelProcessor();
 
 		void setRenderTarget(int index, vk::ImageView *renderTarget, unsigned int layer = 0);
-		vk::ImageView *getRenderTarget(int index);
 		void setDepthBuffer(vk::ImageView *depthBuffer, unsigned int layer = 0);
 		void setStencilBuffer(vk::ImageView *stencilBuffer, unsigned int layer = 0);
 
diff --git a/src/Device/Renderer.cpp b/src/Device/Renderer.cpp
index 7ad30dd..1f90929 100644
--- a/src/Device/Renderer.cpp
+++ b/src/Device/Renderer.cpp
@@ -211,7 +211,7 @@
 		sw::deallocate(mem);
 	}
 
-	void Renderer::draw(DrawType drawType, unsigned int indexOffset, unsigned int count, bool update)
+	void Renderer::draw(DrawType drawType, unsigned int count, bool update)
 	{
 		#ifndef NDEBUG
 			if(count < minPrimitives || count > maxPrimitives)
@@ -315,23 +315,15 @@
 
 		for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
 		{
-			draw->vertexStream[i] = context->input[i].resource;
 			data->input[i] = context->input[i].buffer;
 			data->stride[i] = context->input[i].stride;
-
-			if(draw->vertexStream[i])
-			{
-				draw->vertexStream[i]->lock(PUBLIC, PRIVATE);
-			}
 		}
 
 		if(context->indexBuffer)
 		{
-			data->indices = &context->indexBuffer[indexOffset];
+			data->indices = context->indexBuffer;
 		}
 
-		draw->indexBuffer = context->indexBuffer;
-
 		for(int sampler = 0; sampler < TOTAL_IMAGE_UNITS; sampler++)
 		{
 			draw->texture[sampler] = 0;
@@ -834,14 +826,6 @@
 					draw.queries = 0;
 				}
 
-				for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
-				{
-					if(draw.vertexStream[i])
-					{
-						draw.vertexStream[i]->unlock();
-					}
-				}
-
 				draw.vertexRoutine->unbind();
 				draw.setupRoutine->unbind();
 				draw.pixelRoutine->unbind();
@@ -1575,11 +1559,6 @@
 		}
 	}
 
-	void Renderer::setIndexBuffer(uint8_t *indexBuffer)
-	{
-		context->indexBuffer = indexBuffer;
-	}
-
 	void Renderer::setMultiSampleMask(unsigned int mask)
 	{
 		context->sampleMask = mask;
diff --git a/src/Device/Renderer.hpp b/src/Device/Renderer.hpp
index 013bc3d..598c81a 100644
--- a/src/Device/Renderer.hpp
+++ b/src/Device/Renderer.hpp
@@ -247,14 +247,13 @@
 		void *operator new(size_t size);
 		void operator delete(void * mem);
 
-		void draw(DrawType drawType, unsigned int indexOffset, unsigned int count, bool update = true);
+		void draw(DrawType drawType, unsigned int count, bool update = true);
 
 		void clear(void *value, VkFormat format, Surface *dest, const Rect &rect, unsigned int rgbaMask);
 		void blit(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil = false, bool sRGBconversion = true);
 		void blit3D(Surface *source, Surface *dest);
 
 		void setContext(const sw::Context& context);
-		void setIndexBuffer(uint8_t *indexBuffer);
 
 		void setMultiSampleMask(unsigned int mask);
 		void setTransparencyAntialiasing(TransparencyAntialiasing transparencyAntialiasing);
@@ -423,8 +422,6 @@
 		int (Renderer::*setupPrimitives)(int batch, int count);
 		SetupProcessor::State setupState;
 
-		Resource *vertexStream[MAX_VERTEX_INPUTS];
-		uint8_t *indexBuffer;
 		vk::ImageView *renderTarget[RENDERTARGETS];
 		vk::ImageView *depthBuffer;
 		vk::ImageView *stencilBuffer;
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index d1932bc..7b5fe9f 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -140,6 +140,25 @@
 	const VkDeviceSize offset;
 };
 
+struct IndexBufferBind : public CommandBuffer::Command
+{
+	IndexBufferBind(const VkBuffer buffer, const VkDeviceSize offset, const VkIndexType indexType) :
+		buffer(buffer), offset(offset), indexType(indexType)
+	{
+
+	}
+
+	void play(CommandBuffer::ExecutionState& executionState) override
+	{
+		executionState.indexBufferBinding = {buffer, offset};
+		executionState.indexType = indexType;
+	}
+
+	const VkBuffer buffer;
+	const VkDeviceSize offset;
+	const VkIndexType indexType;
+};
+
 struct Draw : public CommandBuffer::Command
 {
 	Draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance)
@@ -185,7 +204,7 @@
 		for(uint32_t instance = firstInstance; instance <= lastInstance; instance++)
 		{
 			executionState.renderer->setInstanceID(instance);
-			executionState.renderer->draw(context.drawType, 0, primitiveCount);
+			executionState.renderer->draw(context.drawType, primitiveCount);
 		}
 	}
 
@@ -195,6 +214,68 @@
 	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
+	{
+		GraphicsPipeline* pipeline = static_cast<GraphicsPipeline*>(
+				executionState.pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS]);
+
+		sw::Context context = pipeline->getContext();
+		for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; i++)
+		{
+			auto &attrib = context.input[i];
+			if (attrib.count)
+			{
+				const auto &vertexInput = executionState.vertexInputBindings[attrib.binding];
+				Buffer *buffer = Cast(vertexInput.buffer);
+				attrib.buffer = buffer ? buffer->getOffsetPointer(
+						attrib.offset + vertexInput.offset + attrib.stride * vertexOffset) : nullptr;
+			}
+		}
+
+		context.indexBuffer = Cast(executionState.indexBufferBinding.buffer)->getOffsetPointer(
+				executionState.indexBufferBinding.offset + firstIndex * (executionState.indexType == VK_INDEX_TYPE_UINT16 ? 2 : 4));
+
+		executionState.renderer->setContext(context);
+		executionState.renderer->setScissor(pipeline->getScissor());
+		executionState.renderer->setViewport(pipeline->getViewport());
+		executionState.renderer->setBlendConstant(pipeline->getBlendConstants());
+
+		for (auto i = 0u; i < executionState.renderPass->getCurrentSubpass().colorAttachmentCount; i++)
+		{
+			auto attachmentReference = executionState.renderPass->getCurrentSubpass().pColorAttachments[i];
+			if (attachmentReference.attachment != VK_ATTACHMENT_UNUSED)
+			{
+				auto attachment = executionState.renderPassFramebuffer->getAttachment(attachmentReference.attachment);
+				executionState.renderer->setRenderTarget(i, attachment, 0);
+			}
+		}
+
+		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 lastInstance = firstInstance + instanceCount - 1;
+		for(uint32_t instance = firstInstance; instance <= lastInstance; instance++)
+		{
+			executionState.renderer->setInstanceID(instance);
+			executionState.renderer->draw(static_cast<sw::DrawType>(drawType), primitiveCount);
+		}
+	}
+
+	uint32_t indexCount;
+	uint32_t instanceCount;
+	uint32_t firstIndex;
+	int32_t vertexOffset;
+	uint32_t firstInstance;
+};
+
 struct ImageToImageCopy : public CommandBuffer::Command
 {
 	ImageToImageCopy(VkImage pSrcImage, VkImage pDstImage, const VkImageCopy& pRegion) :
@@ -715,7 +796,7 @@
 
 void CommandBuffer::bindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType)
 {
-	UNIMPLEMENTED();
+	addCommand<IndexBufferBind>(buffer, offset, indexType);
 }
 
 void CommandBuffer::dispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ)
@@ -876,7 +957,7 @@
 
 void CommandBuffer::drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance)
 {
-	UNIMPLEMENTED();
+	addCommand<DrawIndexed>(indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
 }
 
 void CommandBuffer::drawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride)
diff --git a/src/Vulkan/VkCommandBuffer.hpp b/src/Vulkan/VkCommandBuffer.hpp
index 1a1548b..eb5f891 100644
--- a/src/Vulkan/VkCommandBuffer.hpp
+++ b/src/Vulkan/VkCommandBuffer.hpp
@@ -133,6 +133,8 @@
 			VkDeviceSize offset;
 		};
 		VertexInputBinding vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS] = {};
+		VertexInputBinding indexBufferBinding;
+		VkIndexType indexType;
 	};
 
 	void submit(CommandBuffer::ExecutionState& executionState);