vkCmdDraw implementation

Piped all the information from the vertex buffers and
the pipeline to the renderer to perform a draw.

In order for the renderer and the context to have proper
lifetimes, they both reside in the Queue object for now.

Bug b/118619338

Change-Id: Ifa03acd13ceb065a856b50f2cffadd4ee6b9a163
Reviewed-on: https://swiftshader-review.googlesource.com/c/23111
Reviewed-by: Corentin Wallez <cwallez@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Device/Renderer.cpp b/src/Device/Renderer.cpp
index 12f3b81..3874889 100644
--- a/src/Device/Renderer.cpp
+++ b/src/Device/Renderer.cpp
@@ -2291,6 +2291,11 @@
 		}
 	#endif
 
+	void Renderer::setContext(const sw::Context& context)
+	{
+		*(this->context) = context;
+	}
+
 	void Renderer::setViewport(const VkViewport &viewport)
 	{
 		this->viewport = viewport;
diff --git a/src/Device/Renderer.hpp b/src/Device/Renderer.hpp
index 3e92954..b5e4077 100644
--- a/src/Device/Renderer.hpp
+++ b/src/Device/Renderer.hpp
@@ -256,6 +256,7 @@
 		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(Resource *indexBuffer);
 
 		void setMultiSampleMask(unsigned int mask);
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index d2a50af..6be7df8 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -13,9 +13,12 @@
 // limitations under the License.
 
 #include "VkCommandBuffer.hpp"
+#include "VkBuffer.hpp"
 #include "VkFramebuffer.hpp"
 #include "VkImage.hpp"
+#include "VkPipeline.hpp"
 #include "VkRenderpass.hpp"
+#include "Device/Renderer.hpp"
 
 #include <cstring>
 
@@ -123,7 +126,23 @@
 
 	void play(CommandBuffer::ExecutionState& executionState)
 	{
-		UNIMPLEMENTED();
+		GraphicsPipeline* pipeline = static_cast<GraphicsPipeline*>(
+			Cast(executionState.pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS]));
+
+		sw::Context context = pipeline->getContext();
+		for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; i++)
+		{
+			const auto& vertexInput = executionState.vertexInputBindings[i];
+			Buffer* buffer = Cast(vertexInput.buffer);
+			context.input[i].buffer = buffer ? buffer->map(vertexInput.offset) : nullptr;
+		}
+
+		executionState.renderer->setContext(context);
+		executionState.renderer->setScissor(pipeline->getScissor());
+		executionState.renderer->setViewport(pipeline->getViewport());
+		executionState.renderer->setBlendConstant(pipeline->getBlendConstants());
+
+		executionState.renderer->draw(context.drawType, 0, pipeline->computePrimitiveCount(vertexCount));
 	}
 
 	uint32_t vertexCount;
diff --git a/src/Vulkan/VkCommandBuffer.hpp b/src/Vulkan/VkCommandBuffer.hpp
index c90dd1d..3a256c4 100644
--- a/src/Vulkan/VkCommandBuffer.hpp
+++ b/src/Vulkan/VkCommandBuffer.hpp
@@ -20,6 +20,11 @@
 #include <memory>
 #include <vector>
 
+namespace sw
+{
+	class Renderer;
+}
+
 namespace vk
 {
 
@@ -112,6 +117,7 @@
 	// TODO(sugoi): Move ExecutionState out of CommandBuffer (possibly into Device)
 	struct ExecutionState
 	{
+		sw::Renderer* renderer = nullptr;
 		VkRenderPass renderpass = VK_NULL_HANDLE;
 		VkPipeline pipelines[VK_PIPELINE_BIND_POINT_RANGE_SIZE] = {};
 
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index 59ff864..ec472f7 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -383,6 +383,29 @@
 	fragmentRoutine = Cast(pCreateInfo->pStages[1].module)->compile(pAllocator);
 }
 
+uint32_t GraphicsPipeline::computePrimitiveCount(uint32_t vertexCount) const
+{
+	switch(context.drawType)
+	{
+	case sw::DRAW_POINTLIST:
+		return vertexCount;
+	case sw::DRAW_LINELIST:
+		return vertexCount / 2;
+	case sw::DRAW_LINESTRIP:
+		return vertexCount - 1;
+	case sw::DRAW_TRIANGLELIST:
+		return vertexCount / 3;
+	case sw::DRAW_TRIANGLESTRIP:
+		return vertexCount - 2;
+	case sw::DRAW_TRIANGLEFAN:
+		return vertexCount - 2;
+	default:
+		UNIMPLEMENTED();
+	}
+
+	return 0;
+}
+
 const sw::Context& GraphicsPipeline::getContext() const
 {
 	return context;
diff --git a/src/Vulkan/VkPipeline.hpp b/src/Vulkan/VkPipeline.hpp
index 77a3d21..a38a105 100644
--- a/src/Vulkan/VkPipeline.hpp
+++ b/src/Vulkan/VkPipeline.hpp
@@ -58,13 +58,14 @@
 
 	void compileShaders(const VkAllocationCallbacks* pAllocator, const VkGraphicsPipelineCreateInfo* pCreateInfo);
 
+	uint32_t computePrimitiveCount(uint32_t vertexCount) const;
 	const sw::Context& getContext() const;
 	const sw::Rect& getScissor() const;
 	const VkViewport& getViewport() const;
 	const sw::Color<float>& getBlendConstants() const;
 
 private:
-	rr::Routine* vertexRoutine;

+	rr::Routine* vertexRoutine;
 	rr::Routine* fragmentRoutine;
 	sw::Context context;
 	sw::Rect scissor;
diff --git a/src/Vulkan/VkQueue.cpp b/src/Vulkan/VkQueue.cpp
index b433815..57f8605 100644
--- a/src/Vulkan/VkQueue.cpp
+++ b/src/Vulkan/VkQueue.cpp
@@ -16,11 +16,12 @@
 #include "VkFence.hpp"
 #include "VkQueue.hpp"
 #include "VkSemaphore.hpp"
+#include "Device/Renderer.hpp"
 
 namespace vk
 {
 
-Queue::Queue(uint32_t pFamilyIndex, float pPriority) : familyIndex(pFamilyIndex), priority(pPriority)
+Queue::Queue(uint32_t pFamilyIndex, float pPriority) : context(), renderer(&context, sw::OpenGL, true), familyIndex(pFamilyIndex), priority(pPriority)
 {
 }
 
@@ -36,6 +37,7 @@
 
 		{
 			CommandBuffer::ExecutionState executionState;
+			executionState.renderer = &renderer;
 			for(uint32_t j = 0; j < submitInfo.commandBufferCount; j++)
 			{
 				vk::Cast(submitInfo.pCommandBuffers[j])->submit(executionState);
diff --git a/src/Vulkan/VkQueue.hpp b/src/Vulkan/VkQueue.hpp
index 739d7fd..f57ebdf 100644
--- a/src/Vulkan/VkQueue.hpp
+++ b/src/Vulkan/VkQueue.hpp
@@ -16,6 +16,7 @@
 #define VK_QUEUE_HPP_
 
 #include "VkObject.hpp"
+#include "Device/Renderer.hpp"
 #include <vulkan/vk_icd.h>
 
 namespace vk
@@ -37,6 +38,8 @@
 	void submit(uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);
 
 private:
+	sw::Context context;
+	sw::Renderer renderer;
 	uint32_t familyIndex = 0;
 	float    priority = 0.0f;
 };