From a24b951df18bc3fffb8774644421042645ea2edc Mon Sep 17 00:00:00 2001 From: bailwillharr Date: Mon, 24 Oct 2022 00:19:07 +0100 Subject: [PATCH] Add support for multiple pipelines --- include/gfx.hpp | 2 +- include/gfx_device.hpp | 5 +-- src/engine.cpp | 18 +++-------- src/gfx_device_vulkan.cpp | 64 ++++++++++++++++++++++----------------- 4 files changed, 44 insertions(+), 45 deletions(-) diff --git a/include/gfx.hpp b/include/gfx.hpp index c275dc1..94cbf30 100644 --- a/include/gfx.hpp +++ b/include/gfx.hpp @@ -45,7 +45,7 @@ namespace engine::gfx { }; // handles (incomplete types) - + struct Pipeline; struct VertexBuffer; } diff --git a/include/gfx_device.hpp b/include/gfx_device.hpp index a3646da..75833d2 100644 --- a/include/gfx_device.hpp +++ b/include/gfx_device.hpp @@ -20,13 +20,14 @@ namespace engine { ~GFXDevice(); // adds a vertex buffer draw call to the queue - void drawBuffer(const gfx::VertexBuffer* vb); + void drawBuffer(const gfx::Pipeline* pipeline, const gfx::VertexBuffer* vb); // Call once per frame. Executes all queued draw calls and renders to the screen. void draw(); // creates the equivalent of an OpenGL shader program & vertex attrib configuration - void createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat); + gfx::Pipeline* createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat); + void destroyPipeline(const gfx::Pipeline* pipeline); // creates a vertex array for holding mesh data gfx::VertexBuffer* createVertexBuffer(uint32_t size, const void* vertices, const void* indices); diff --git a/src/engine.cpp b/src/engine.cpp index 41b61a7..6fc83c2 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -7,6 +7,7 @@ #include +static engine::gfx::Pipeline* pipeline; static engine::gfx::VertexBuffer* buffer; namespace engine { @@ -17,22 +18,16 @@ namespace engine { m_gfx = std::make_unique(appName, appVersion, m_win->getHandle()); engine::ResourceManager resMan{}; - struct Vertex { glm::vec2 pos; glm::vec3 col; }; - gfx::VertexFormat vertFormat{ .stride = (uint32_t)sizeof(Vertex), }; - vertFormat.attributeDescriptions.push_back({0, gfx::VertexAttribFormat::VEC2, 0}); vertFormat.attributeDescriptions.push_back({1, gfx::VertexAttribFormat::VEC3, offsetof(Vertex, col)}); - - m_gfx->createPipeline(resMan.getFilePath("shader.vert.spv").string().c_str(), resMan.getFilePath("shader.frag.spv").string().c_str(), vertFormat); - - + pipeline = m_gfx->createPipeline(resMan.getFilePath("shader.vert.spv").string().c_str(), resMan.getFilePath("shader.frag.spv").string().c_str(), vertFormat); const std::vector vertices = { { { 0.0f, -0.5f}, {1.0f, 0.0f, 0.0f} }, @@ -44,17 +39,12 @@ namespace engine { }; buffer = m_gfx->createVertexBuffer(sizeof(Vertex) * vertices.size(), vertices.data(), indices.data()); - const std::vector vertices2 = { - { { 0.9f, -0.9f}, {1.0f, 0.0f, 0.0f} }, - { { 0.9f, -0.8f}, {1.0f, 0.0f, 0.0f} }, - { { 0.8f, -0.9f}, {1.0f, 0.0f, 0.0f} } - }; - } Application::~Application() { m_gfx->destroyVertexBuffer(buffer); + m_gfx->destroyPipeline(pipeline); } void Application::gameLoop() @@ -86,7 +76,7 @@ namespace engine { /* draw */ - m_gfx->drawBuffer(buffer); + m_gfx->drawBuffer(pipeline, buffer); m_gfx->draw(); diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index ee34ea0..6e9d446 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace engine { @@ -65,11 +66,6 @@ namespace engine { VkSemaphore releaseSemaphore = VK_NULL_HANDLE; // waits until rendering finishes }; - struct Pipeline { - VkPipelineLayout layout = VK_NULL_HANDLE; - VkPipeline handle = VK_NULL_HANDLE; - }; - enum class QueueFlags : uint32_t { GRAPHICS = (1 << 0), TRANSFER = (1 << 1), @@ -84,6 +80,11 @@ namespace engine { uint32_t size; }; + struct gfx::Pipeline { + VkPipelineLayout layout = VK_NULL_HANDLE; + VkPipeline handle = VK_NULL_HANDLE; + }; + // enum converters @@ -595,9 +596,7 @@ namespace engine { VkFence inFlightFence = VK_NULL_HANDLE; - Pipeline pipeline{}; - - std::queue drawQueue{}; + std::map> drawQueues{}; }; @@ -995,11 +994,6 @@ namespace engine { { TRACE("Destroying GFXDevice..."); - if (pimpl->pipeline.handle != VK_NULL_HANDLE) { - vkDestroyPipeline(pimpl->device, pimpl->pipeline.handle, nullptr); - vkDestroyPipelineLayout(pimpl->device, pimpl->pipeline.layout, nullptr); - } - vkDestroyFence(pimpl->device, pimpl->inFlightFence, nullptr); vkDestroySemaphore(pimpl->device, pimpl->swapchain.releaseSemaphore, nullptr); @@ -1022,9 +1016,9 @@ namespace engine { vkDestroyInstance(pimpl->instance, nullptr); } - void GFXDevice::drawBuffer(const gfx::VertexBuffer* vb) + void GFXDevice::drawBuffer(const gfx::Pipeline* pipeline, const gfx::VertexBuffer* vb) { - pimpl->drawQueue.push(vb); + pimpl->drawQueues[pipeline].push(vb); } void GFXDevice::draw() @@ -1087,19 +1081,20 @@ namespace engine { // run queued draw calls - vkCmdBindPipeline(pimpl->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pimpl->pipeline.handle); VkDeviceSize offsets[] = { 0 }; - while (pimpl->drawQueue.empty() == false) { - - const auto* buffer = pimpl->drawQueue.front(); - - vkCmdBindVertexBuffers(pimpl->commandBuffer, 0, 1, &buffer->buffer, offsets); - vkCmdDraw(pimpl->commandBuffer, buffer->size, 1, 0, 0); - - pimpl->drawQueue.pop(); + for (auto& [pipeline, queue] : pimpl->drawQueues) { + vkCmdBindPipeline(pimpl->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); + while (queue.empty() == false) { + const gfx::VertexBuffer* buffer = queue.front(); + vkCmdBindVertexBuffers(pimpl->commandBuffer, 0, 1, &buffer->buffer, offsets); + vkCmdDraw(pimpl->commandBuffer, buffer->size, 1, 0, 0); + queue.pop(); + } } + pimpl->drawQueues.clear(); + vkCmdEndRenderPass(pimpl->commandBuffer); res = vkEndCommandBuffer(pimpl->commandBuffer); @@ -1141,11 +1136,13 @@ namespace engine { } } - void GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat) + gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat) { VkResult res; + gfx::Pipeline* pipeline = new gfx::Pipeline; + // get vertex attrib layout: VkVertexInputBindingDescription bindingDescription{ }; bindingDescription.binding = 0; @@ -1281,7 +1278,7 @@ namespace engine { layoutInfo.pushConstantRangeCount = 0; layoutInfo.pPushConstantRanges = nullptr; - res = vkCreatePipelineLayout(pimpl->device, &layoutInfo, nullptr, &pimpl->pipeline.layout); + res = vkCreatePipelineLayout(pimpl->device, &layoutInfo, nullptr, &pipeline->layout); assert(res == VK_SUCCESS); VkGraphicsPipelineCreateInfo createInfo{}; @@ -1296,18 +1293,29 @@ namespace engine { createInfo.pDepthStencilState = nullptr; createInfo.pColorBlendState = &colorBlending; createInfo.pDynamicState = &dynamicState; - createInfo.layout = pimpl->pipeline.layout; + createInfo.layout = pipeline->layout; createInfo.renderPass = pimpl->swapchain.renderpass; createInfo.subpass = 0; createInfo.basePipelineHandle = VK_NULL_HANDLE; createInfo.basePipelineIndex = -1; - res = vkCreateGraphicsPipelines(pimpl->device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pimpl->pipeline.handle); + res = vkCreateGraphicsPipelines(pimpl->device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline->handle); assert(res == VK_SUCCESS); vkDestroyShaderModule(pimpl->device, fragShaderModule, nullptr); vkDestroyShaderModule(pimpl->device, vertShaderModule, nullptr); + return pipeline; + + } + + void GFXDevice::destroyPipeline(const gfx::Pipeline* pipeline) + { + + vkDestroyPipeline(pimpl->device, pipeline->handle, nullptr); + vkDestroyPipelineLayout(pimpl->device, pipeline->layout, nullptr); + + delete pipeline; } gfx::VertexBuffer* GFXDevice::createVertexBuffer(uint32_t size, const void* vertices, const void* indices)