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;
}