Add support for multiple pipelines

This commit is contained in:
Bailey Harrison 2022-10-24 00:19:07 +01:00
parent d6522730ae
commit a24b951df1
4 changed files with 44 additions and 45 deletions

View File

@ -45,7 +45,7 @@ namespace engine::gfx {
}; };
// handles (incomplete types) // handles (incomplete types)
struct Pipeline;
struct VertexBuffer; struct VertexBuffer;
} }

View File

@ -20,13 +20,14 @@ namespace engine {
~GFXDevice(); ~GFXDevice();
// adds a vertex buffer draw call to the queue // 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. // Call once per frame. Executes all queued draw calls and renders to the screen.
void draw(); void draw();
// creates the equivalent of an OpenGL shader program & vertex attrib configuration // 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 // creates a vertex array for holding mesh data
gfx::VertexBuffer* createVertexBuffer(uint32_t size, const void* vertices, const void* indices); gfx::VertexBuffer* createVertexBuffer(uint32_t size, const void* vertices, const void* indices);

View File

@ -7,6 +7,7 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
static engine::gfx::Pipeline* pipeline;
static engine::gfx::VertexBuffer* buffer; static engine::gfx::VertexBuffer* buffer;
namespace engine { namespace engine {
@ -17,22 +18,16 @@ namespace engine {
m_gfx = std::make_unique<GFXDevice>(appName, appVersion, m_win->getHandle()); m_gfx = std::make_unique<GFXDevice>(appName, appVersion, m_win->getHandle());
engine::ResourceManager resMan{}; engine::ResourceManager resMan{};
struct Vertex { struct Vertex {
glm::vec2 pos; glm::vec2 pos;
glm::vec3 col; glm::vec3 col;
}; };
gfx::VertexFormat vertFormat{ gfx::VertexFormat vertFormat{
.stride = (uint32_t)sizeof(Vertex), .stride = (uint32_t)sizeof(Vertex),
}; };
vertFormat.attributeDescriptions.push_back({0, gfx::VertexAttribFormat::VEC2, 0}); vertFormat.attributeDescriptions.push_back({0, gfx::VertexAttribFormat::VEC2, 0});
vertFormat.attributeDescriptions.push_back({1, gfx::VertexAttribFormat::VEC3, offsetof(Vertex, col)}); vertFormat.attributeDescriptions.push_back({1, gfx::VertexAttribFormat::VEC3, offsetof(Vertex, col)});
pipeline = m_gfx->createPipeline(resMan.getFilePath("shader.vert.spv").string().c_str(), resMan.getFilePath("shader.frag.spv").string().c_str(), vertFormat);
m_gfx->createPipeline(resMan.getFilePath("shader.vert.spv").string().c_str(), resMan.getFilePath("shader.frag.spv").string().c_str(), vertFormat);
const std::vector<Vertex> vertices = { const std::vector<Vertex> vertices = {
{ { 0.0f, -0.5f}, {1.0f, 0.0f, 0.0f} }, { { 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()); buffer = m_gfx->createVertexBuffer(sizeof(Vertex) * vertices.size(), vertices.data(), indices.data());
const std::vector<Vertex> 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() Application::~Application()
{ {
m_gfx->destroyVertexBuffer(buffer); m_gfx->destroyVertexBuffer(buffer);
m_gfx->destroyPipeline(pipeline);
} }
void Application::gameLoop() void Application::gameLoop()
@ -86,7 +76,7 @@ namespace engine {
/* draw */ /* draw */
m_gfx->drawBuffer(buffer); m_gfx->drawBuffer(pipeline, buffer);
m_gfx->draw(); m_gfx->draw();

View File

@ -26,6 +26,7 @@
#include <filesystem> #include <filesystem>
#include <optional> #include <optional>
#include <queue> #include <queue>
#include <map>
namespace engine { namespace engine {
@ -65,11 +66,6 @@ namespace engine {
VkSemaphore releaseSemaphore = VK_NULL_HANDLE; // waits until rendering finishes 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 { enum class QueueFlags : uint32_t {
GRAPHICS = (1 << 0), GRAPHICS = (1 << 0),
TRANSFER = (1 << 1), TRANSFER = (1 << 1),
@ -84,6 +80,11 @@ namespace engine {
uint32_t size; uint32_t size;
}; };
struct gfx::Pipeline {
VkPipelineLayout layout = VK_NULL_HANDLE;
VkPipeline handle = VK_NULL_HANDLE;
};
// enum converters // enum converters
@ -595,9 +596,7 @@ namespace engine {
VkFence inFlightFence = VK_NULL_HANDLE; VkFence inFlightFence = VK_NULL_HANDLE;
Pipeline pipeline{}; std::map<const gfx::Pipeline*, std::queue<const gfx::VertexBuffer*>> drawQueues{};
std::queue<const gfx::VertexBuffer*> drawQueue{};
}; };
@ -995,11 +994,6 @@ namespace engine {
{ {
TRACE("Destroying GFXDevice..."); 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); vkDestroyFence(pimpl->device, pimpl->inFlightFence, nullptr);
vkDestroySemaphore(pimpl->device, pimpl->swapchain.releaseSemaphore, nullptr); vkDestroySemaphore(pimpl->device, pimpl->swapchain.releaseSemaphore, nullptr);
@ -1022,9 +1016,9 @@ namespace engine {
vkDestroyInstance(pimpl->instance, nullptr); 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() void GFXDevice::draw()
@ -1087,19 +1081,20 @@ namespace engine {
// run queued draw calls // run queued draw calls
vkCmdBindPipeline(pimpl->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pimpl->pipeline.handle);
VkDeviceSize offsets[] = { 0 }; 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); vkCmdEndRenderPass(pimpl->commandBuffer);
res = vkEndCommandBuffer(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; VkResult res;
gfx::Pipeline* pipeline = new gfx::Pipeline;
// get vertex attrib layout: // get vertex attrib layout:
VkVertexInputBindingDescription bindingDescription{ }; VkVertexInputBindingDescription bindingDescription{ };
bindingDescription.binding = 0; bindingDescription.binding = 0;
@ -1281,7 +1278,7 @@ namespace engine {
layoutInfo.pushConstantRangeCount = 0; layoutInfo.pushConstantRangeCount = 0;
layoutInfo.pPushConstantRanges = nullptr; layoutInfo.pPushConstantRanges = nullptr;
res = vkCreatePipelineLayout(pimpl->device, &layoutInfo, nullptr, &pimpl->pipeline.layout); res = vkCreatePipelineLayout(pimpl->device, &layoutInfo, nullptr, &pipeline->layout);
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
VkGraphicsPipelineCreateInfo createInfo{}; VkGraphicsPipelineCreateInfo createInfo{};
@ -1296,18 +1293,29 @@ namespace engine {
createInfo.pDepthStencilState = nullptr; createInfo.pDepthStencilState = nullptr;
createInfo.pColorBlendState = &colorBlending; createInfo.pColorBlendState = &colorBlending;
createInfo.pDynamicState = &dynamicState; createInfo.pDynamicState = &dynamicState;
createInfo.layout = pimpl->pipeline.layout; createInfo.layout = pipeline->layout;
createInfo.renderPass = pimpl->swapchain.renderpass; createInfo.renderPass = pimpl->swapchain.renderpass;
createInfo.subpass = 0; createInfo.subpass = 0;
createInfo.basePipelineHandle = VK_NULL_HANDLE; createInfo.basePipelineHandle = VK_NULL_HANDLE;
createInfo.basePipelineIndex = -1; 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); assert(res == VK_SUCCESS);
vkDestroyShaderModule(pimpl->device, fragShaderModule, nullptr); vkDestroyShaderModule(pimpl->device, fragShaderModule, nullptr);
vkDestroyShaderModule(pimpl->device, vertShaderModule, 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) gfx::VertexBuffer* GFXDevice::createVertexBuffer(uint32_t size, const void* vertices, const void* indices)