Basic commands required to draw a simple triangle test

This cl adds the code needed to record and submit the minimal
subset of commands required to run a simple triangle example.

The commands themselves are still unimplemented.

Bug b/116336664

Change-Id: Id0109980225a64a2bb3599a89a5495091926c635
Reviewed-on: https://swiftshader-review.googlesource.com/c/22168
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Corentin Wallez <cwallez@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index 220d232..45f9199 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -17,30 +17,169 @@
 namespace vk
 {
 
+class CommandBuffer::Command
+{
+public:
+	// FIXME (b/119421344): change the commandBuffer argument to a CommandBuffer state
+	virtual void play(CommandBuffer* commandBuffer) = 0;
+	virtual ~Command() {}
+};
+
+class BeginRenderPass : public CommandBuffer::Command
+{
+public:
+	BeginRenderPass(VkRenderPass pRenderPass, VkFramebuffer pFramebuffer, VkRect2D pRenderArea,
+	                uint32_t pClearValueCount, const VkClearValue* pClearValues) :
+		renderPass(pRenderPass), framebuffer(pFramebuffer), renderArea(pRenderArea),
+		clearValueCount(pClearValueCount)
+	{
+		// FIXME (b/119409619): use an allocator here so we can control all memory allocations
+		clearValues = new VkClearValue[clearValueCount];
+		memcpy(clearValues, pClearValues, clearValueCount * sizeof(VkClearValue));
+	}
+
+	~BeginRenderPass() override
+	{
+		delete clearValues;
+	}
+
+protected:
+	void play(CommandBuffer* commandBuffer)
+	{
+		UNIMPLEMENTED();
+	}
+
+private:
+	VkRenderPass renderPass;
+	VkFramebuffer framebuffer;
+	VkRect2D renderArea;
+	uint32_t clearValueCount;
+	VkClearValue* clearValues;
+};
+
+class EndRenderPass : public CommandBuffer::Command
+{
+public:
+	EndRenderPass()
+	{
+	}
+
+protected:
+	void play(CommandBuffer* commandBuffer)
+	{
+		UNIMPLEMENTED();
+	}
+
+private:
+};
+
+class PipelineBind : public CommandBuffer::Command
+{
+public:
+	PipelineBind(VkPipelineBindPoint pPipelineBindPoint, VkPipeline pPipeline) :
+		pipelineBindPoint(pPipelineBindPoint), pipeline(pPipeline)
+	{
+	}
+
+protected:
+	void play(CommandBuffer* commandBuffer)
+	{
+		UNIMPLEMENTED();
+	}
+
+private:
+	VkPipelineBindPoint pipelineBindPoint;
+	VkPipeline pipeline;
+};
+
+struct VertexBufferBind : public CommandBuffer::Command
+{
+	VertexBufferBind(uint32_t pBinding, const VkBuffer pBuffer, const VkDeviceSize pOffset) :
+		binding(pBinding), buffer(pBuffer), offset(pOffset)
+	{
+	}
+
+	void play(CommandBuffer* commandBuffer)
+	{
+		UNIMPLEMENTED();
+	}
+
+	uint32_t binding;
+	const VkBuffer buffer;
+	const VkDeviceSize offset;
+};
+
+struct Draw : public CommandBuffer::Command
+{
+	Draw(uint32_t pVertexCount) : vertexCount(pVertexCount)
+	{
+	}
+
+	void play(CommandBuffer* commandBuffer)
+	{
+		UNIMPLEMENTED();
+	}
+
+	uint32_t vertexCount;
+};
+
+struct ImageToBufferCopy : public CommandBuffer::Command
+{
+	ImageToBufferCopy(VkImage pSrcImage, VkBuffer pDstBuffer, const VkBufferImageCopy& pRegion) :
+		srcImage(pSrcImage), dstBuffer(pDstBuffer), region(pRegion)
+	{
+	}
+
+	void play(CommandBuffer* commandBuffer)
+	{
+		UNIMPLEMENTED();
+	}
+
+private:
+	VkImage srcImage;
+	VkBuffer dstBuffer;
+	const VkBufferImageCopy region;
+};
+
 CommandBuffer::CommandBuffer(VkCommandBufferLevel pLevel) : level(pLevel)
 {
+	// FIXME (b/119409619): replace this vector by an allocator so we can control all memory allocations
+	commands = new std::vector<std::unique_ptr<Command> >();
+
 	pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS] = VK_NULL_HANDLE;
 	pipelines[VK_PIPELINE_BIND_POINT_COMPUTE] = VK_NULL_HANDLE;
 }
 
 void CommandBuffer::destroy(const VkAllocationCallbacks* pAllocator)
 {
+	deleteCommands();
+}
+
+void CommandBuffer::deleteCommands()
+{
+	// FIXME (b/119409619): replace this vector by an allocator so we can control all memory allocations
+	delete commands;
 }
 
 VkResult CommandBuffer::begin(VkCommandBufferUsageFlags flags, const VkCommandBufferInheritanceInfo* pInheritanceInfo)
 {
+	ASSERT((state != RECORDING) && (state != PENDING));
+

+	if((flags != VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) || pInheritanceInfo)

+	{

+		UNIMPLEMENTED();

+	}

+

 	state = RECORDING;
 
-	UNIMPLEMENTED();
-
 	return VK_SUCCESS;
 }
 
 VkResult CommandBuffer::end()
 {
-	state = EXECUTABLE;
+	ASSERT(state == RECORDING);
 
-	UNIMPLEMENTED();
+	state = EXECUTABLE;
 
 	return VK_SUCCESS;
 }
@@ -49,18 +188,24 @@
 {
 	ASSERT(state != PENDING);
 
-	UNIMPLEMENTED();
+	deleteCommands();
 
-	// FIXME: put command buffer back to the initial state
 	state = INITIAL;
 
 	return VK_SUCCESS;
 }
 
 void CommandBuffer::beginRenderPass(VkRenderPass renderPass, VkFramebuffer framebuffer, VkRect2D renderArea,
-                                    uint32_t clearValueCount, const VkClearValue* pClearValues, VkSubpassContents contents)
+                                    uint32_t clearValueCount, const VkClearValue* clearValues, VkSubpassContents contents)
 {
-	UNIMPLEMENTED();
+	ASSERT(state == RECORDING);
+
+	if(contents != VK_SUBPASS_CONTENTS_INLINE)

+	{

+		UNIMPLEMENTED();

+	}
+
+	commands->push_back(std::make_unique<BeginRenderPass>(renderPass, framebuffer, renderArea, clearValueCount, clearValues));
 }
 
 void CommandBuffer::nextSubpass(VkSubpassContents contents)
@@ -70,7 +215,7 @@
 
 void CommandBuffer::endRenderPass()
 {
-	UNIMPLEMENTED();
+	commands->push_back(std::make_unique<EndRenderPass>());
 }
 
 void CommandBuffer::executeCommands(uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers)
@@ -100,7 +245,12 @@
 
 void CommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline)
 {
-	pipelines[pipelineBindPoint] = pipeline;
+	if(pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS)
+	{
+		UNIMPLEMENTED();
+	}
+
+	commands->push_back(std::make_unique<PipelineBind>(pipelineBindPoint, pipeline));
 }
 
 void CommandBuffer::bindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount,
@@ -108,8 +258,7 @@
 {
 	for(uint32_t i = firstBinding; i < (firstBinding + bindingCount); ++i)
 	{
-		vertexInputBindings[i].buffer = pBuffers[i];
-		vertexInputBindings[i].offset = pOffsets[i];
+		commands->push_back(std::make_unique<VertexBufferBind>(i, pBuffers[i], pOffsets[i]));
 	}
 }
 
@@ -276,7 +425,12 @@
 void CommandBuffer::copyImageToBuffer(VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer,
 	uint32_t regionCount, const VkBufferImageCopy* pRegions)
 {
-	UNIMPLEMENTED();
+	ASSERT(srcImageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+
+	for(uint32_t i = 0; i < regionCount; i++)
+	{
+		commands->push_back(std::make_unique<ImageToBufferCopy>(srcImage, dstBuffer, pRegions[i]));
+	}
 }
 
 void CommandBuffer::updateBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData)
@@ -333,7 +487,12 @@
 
 void CommandBuffer::draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance)
 {
-	UNIMPLEMENTED();
+	if(instanceCount > 1 || firstVertex != 0 || firstInstance != 0)

+	{

+		UNIMPLEMENTED();

+	}
+
+	commands->push_back(std::make_unique<Draw>(vertexCount));
 }
 
 void CommandBuffer::drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance)
@@ -356,7 +515,10 @@
 	// Perform recorded work
 	state = PENDING;
 
-	UNIMPLEMENTED();
+	for(auto& command : *commands)
+	{
+		command->play(this);
+	}
 
 	// After work is completed
 	state = EXECUTABLE;
diff --git a/src/Vulkan/VkCommandBuffer.hpp b/src/Vulkan/VkCommandBuffer.hpp
index abcf241..814c603 100644
--- a/src/Vulkan/VkCommandBuffer.hpp
+++ b/src/Vulkan/VkCommandBuffer.hpp
@@ -17,6 +17,8 @@
 
 #include "VkConfig.h"
 #include "VkObject.hpp"
+#include <memory>
+#include <vector>
 
 namespace vk
 {
@@ -109,7 +111,10 @@
 
 	void submit();
 
+	class Command;
 private:
+	void deleteCommands();
+
 	enum State { INITIAL, RECORDING, EXECUTABLE, PENDING, INVALID };
 	State state = INITIAL;
 	VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
@@ -121,6 +126,9 @@
 		VkDeviceSize offset;
 	};
 	VertexInputBindings vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS];
+
+	// FIXME (b/119409619): replace this vector by an allocator so we can control all memory allocations
+	std::vector<std::unique_ptr<Command>>* commands;
 };
 
 using DispatchableCommandBuffer = DispatchableObject<CommandBuffer, VkCommandBuffer>;
diff --git a/src/Vulkan/VkQueue.cpp b/src/Vulkan/VkQueue.cpp
index 537849c..f0978cf 100644
--- a/src/Vulkan/VkQueue.cpp
+++ b/src/Vulkan/VkQueue.cpp
@@ -12,7 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "VkCommandBuffer.hpp"
 #include "VkQueue.hpp"
+#include "VkSemaphore.hpp"
 
 namespace vk
 {
@@ -21,4 +23,31 @@
 {
 }
 
+void Queue::submit(uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence)
+{
+	if(fence != VK_NULL_HANDLE)
+	{
+		UNIMPLEMENTED();
+	}
+
+	for(uint32_t i = 0; i < submitCount; i++)
+	{
+		auto& submitInfo = pSubmits[i];
+		for(uint32_t j = 0; j < submitInfo.waitSemaphoreCount; j++)
+		{
+			vk::Cast(submitInfo.pWaitSemaphores[j])->wait(submitInfo.pWaitDstStageMask[j]);
+		}
+
+		for(uint32_t j = 0; j < submitInfo.commandBufferCount; j++)
+		{
+			vk::Cast(submitInfo.pCommandBuffers[j])->submit();
+		}
+
+		for(uint32_t j = 0; j < submitInfo.signalSemaphoreCount; j++)
+		{
+			vk::Cast(submitInfo.pSignalSemaphores[j])->signal();
+		}
+	}
+}
+
 } // namespace vk
\ No newline at end of file
diff --git a/src/Vulkan/VkQueue.hpp b/src/Vulkan/VkQueue.hpp
index 49e2604..739d7fd 100644
--- a/src/Vulkan/VkQueue.hpp
+++ b/src/Vulkan/VkQueue.hpp
@@ -34,6 +34,8 @@
 		return reinterpret_cast<VkQueue>(this);
 	}
 
+	void submit(uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);
+
 private:
 	uint32_t familyIndex = 0;
 	float    priority = 0.0f;
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 249afe4..9d23ec8 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -427,8 +427,11 @@
 
 VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence)
 {
-	TRACE("()");
-	UNIMPLEMENTED();
+	TRACE("(VkQueue queue = 0x%X, uint32_t submitCount = %d, const VkSubmitInfo* pSubmits = 0x%X, VkFence fence = 0x%X)",
+	      queue, submitCount, pSubmits, fence);
+
+	vk::Cast(queue)->submit(submitCount, pSubmits, fence);
+
 	return VK_SUCCESS;
 }