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)
struct Pipeline;
struct VertexBuffer;
}

View File

@ -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);

View File

@ -7,6 +7,7 @@
#include <glm/glm.hpp>
static engine::gfx::Pipeline* pipeline;
static engine::gfx::VertexBuffer* buffer;
namespace engine {
@ -17,22 +18,16 @@ namespace engine {
m_gfx = std::make_unique<GFXDevice>(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<Vertex> 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<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()
{
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();

View File

@ -26,6 +26,7 @@
#include <filesystem>
#include <optional>
#include <queue>
#include <map>
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<const gfx::VertexBuffer*> drawQueue{};
std::map<const gfx::Pipeline*, std::queue<const gfx::VertexBuffer*>> 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,18 +1081,19 @@ 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();
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);
pimpl->drawQueue.pop();
queue.pop();
}
}
pimpl->drawQueues.clear();
vkCmdEndRenderPass(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)