Add uniform buffer / resource descriptor set

This commit is contained in:
Grayson Riffe 2025-02-20 02:50:15 -06:00
parent ae707f1f3d
commit 9738de012a
6 changed files with 155 additions and 71 deletions

View File

@ -7,7 +7,12 @@ layout(location = 1) in vec3 inColor;
// Outputs // Outputs
layout(location = 0) out vec3 fragColor; layout(location = 0) out vec3 fragColor;
// Uniforms
layout(binding = 0) uniform MVPMatrixUniformBufferObject {
mat4 mvp;
} mvpUBO;
void main() { void main() {
fragColor = inColor; fragColor = inColor;
gl_Position = vec4(inPosition, 0.0, 1.0); gl_Position = mvpUBO.mvp * vec4(inPosition, 0.0, 1.0);
} }

View File

@ -7,11 +7,21 @@
namespace nf::client::render { namespace nf::client::render {
Buffer::Buffer(BufferType type, const VkDevice& device, VideoMemoryAllocator& allocator, const VkCommandPool& commandPool, const VkQueue& queue, void* bufferData, size_t bufferSize) Buffer::Buffer(BufferType type, const VkDevice& device, VideoMemoryAllocator& allocator, const VkCommandPool& commandPool, const VkQueue& queue, void* bufferData, size_t bufferSize)
: Resource(device) : Resource(device)
, m_allocator(allocator)
, m_handle() , m_handle()
, m_memory() , m_memory()
, m_offset() , m_offset()
, m_allocator(allocator) , m_pointer()
{ {
if (type == BufferType::Uniform) {
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, m_handle);
m_allocator.allocateForBuffer(m_handle, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, m_memory, m_offset);
vkBindBufferMemory(m_device, m_handle, m_memory, m_offset);
vkMapMemory(m_device, m_memory, m_offset, bufferSize, 0, &m_pointer);
return;
}
VkBuffer stagingBuffer = nullptr; VkBuffer stagingBuffer = nullptr;
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, stagingBuffer); createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, stagingBuffer);
@ -50,6 +60,10 @@ namespace nf::client::render {
return m_handle; return m_handle;
} }
void* Buffer::getPointer() const {
return m_pointer;
}
void Buffer::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkBuffer& buffer) { void Buffer::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkBuffer& buffer) {
VkBufferCreateInfo bufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo bufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufferCI.size = size; bufferCI.size = size;

View File

@ -7,7 +7,8 @@
namespace nf::client::render { namespace nf::client::render {
enum class BufferType { enum class BufferType {
Vertex, Vertex,
Index Index,
Uniform
}; };
class Buffer : Resource { class Buffer : Resource {
@ -15,6 +16,7 @@ namespace nf::client::render {
Buffer(BufferType type, const VkDevice& device, VideoMemoryAllocator& allocator, const VkCommandPool& commandPool, const VkQueue& queue, void* bufferData, size_t bufferSize); Buffer(BufferType type, const VkDevice& device, VideoMemoryAllocator& allocator, const VkCommandPool& commandPool, const VkQueue& queue, void* bufferData, size_t bufferSize);
const VkBuffer& getHandle() const; const VkBuffer& getHandle() const;
void* getPointer() const;
~Buffer(); ~Buffer();
private: private:
@ -23,11 +25,11 @@ namespace nf::client::render {
void destroyBuffer(VkBuffer buffer, VkDeviceMemory bufferMemory, VkDeviceSize offset); void destroyBuffer(VkBuffer buffer, VkDeviceMemory bufferMemory, VkDeviceSize offset);
VideoMemoryAllocator& m_allocator;
VkBuffer m_handle; VkBuffer m_handle;
VkDeviceMemory m_memory; VkDeviceMemory m_memory;
VkDeviceSize m_offset; VkDeviceSize m_offset;
void* m_pointer;
VideoMemoryAllocator& m_allocator;
}; };
} }

View File

@ -30,12 +30,16 @@ namespace nf::client::render {
, m_swapchainImages() , m_swapchainImages()
, m_swapchainImageViews() , m_swapchainImageViews()
, m_swapchainFramebuffers() , m_swapchainFramebuffers()
, m_pipelineLayoutOutput() , m_pipelineOutputDescriptorSetLayout()
, m_pipelineOutputLayout()
, m_pipelineOutputDescriptorPool()
, m_pipelineOutputDescriptorSet()
, m_pipelineOutput() , m_pipelineOutput()
, m_commandPool() , m_commandPool()
, m_numFramesInFlight(2) , m_commandBuffer()
, m_frameExecutors() , m_semaphoreImageAvailable()
, m_currentFrameExecutor() , m_semaphoreRenderingDone()
, m_fenceFrameInFlight()
, m_allocator() , m_allocator()
, m_bufferVertex() , m_bufferVertex()
, m_bufferIndex() , m_bufferIndex()
@ -51,7 +55,7 @@ namespace nf::client::render {
createOutputRenderPass(); createOutputRenderPass();
createSwapchainFramebuffers(); createSwapchainFramebuffers();
createOutputPipeline(); createOutputPipeline();
createFrameExecutors(); createExecutionObjects();
m_allocator = std::make_unique<VideoMemoryAllocator>(m_device, m_physicalDevice); m_allocator = std::make_unique<VideoMemoryAllocator>(m_device, m_physicalDevice);
createBuffers(); createBuffers();
@ -379,7 +383,7 @@ namespace nf::client::render {
VkPipelineRasterizationStateCreateInfo rasterizationCI = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; VkPipelineRasterizationStateCreateInfo rasterizationCI = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
rasterizationCI.lineWidth = 1.0; rasterizationCI.lineWidth = 1.0;
rasterizationCI.cullMode = VK_CULL_MODE_BACK_BIT; rasterizationCI.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizationCI.frontFace = VK_FRONT_FACE_CLOCKWISE; rasterizationCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
// Specify multisample state // Specify multisample state
VkPipelineMultisampleStateCreateInfo multisampleStateCI = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; VkPipelineMultisampleStateCreateInfo multisampleStateCI = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
@ -392,12 +396,48 @@ namespace nf::client::render {
colorBlendStateCI.attachmentCount = 1; colorBlendStateCI.attachmentCount = 1;
colorBlendStateCI.pAttachments = &colorBlendAttachmentState; colorBlendStateCI.pAttachments = &colorBlendAttachmentState;
// Create descriptor set layout
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
VkDescriptorSetLayoutBinding mvpLayoutBinding = {};
mvpLayoutBinding.binding = 0;
mvpLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
mvpLayoutBinding.descriptorCount = 1;
mvpLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
descriptorSetLayoutCI.bindingCount = 1;
descriptorSetLayoutCI.pBindings = &mvpLayoutBinding;
if (vkCreateDescriptorSetLayout(m_device, &descriptorSetLayoutCI, nullptr, &m_pipelineOutputDescriptorSetLayout) != VK_SUCCESS)
NFError("Could not create descriptor set layout.");
// Create pipeline layout // Create pipeline layout
VkPipelineLayoutCreateInfo layoutCI = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; VkPipelineLayoutCreateInfo layoutCI = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
layoutCI.setLayoutCount = 1;
layoutCI.pSetLayouts = &m_pipelineOutputDescriptorSetLayout;
if (vkCreatePipelineLayout(m_device, &layoutCI, nullptr, &m_pipelineLayoutOutput) != VK_SUCCESS) if (vkCreatePipelineLayout(m_device, &layoutCI, nullptr, &m_pipelineOutputLayout) != VK_SUCCESS)
NFError("Could not create pipeline layout."); NFError("Could not create pipeline layout.");
// Create descriptor pool
VkDescriptorPoolCreateInfo descriptorPoolCI = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
VkDescriptorPoolSize descriptorPoolSize = {};
descriptorPoolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorPoolSize.descriptorCount = 1;
descriptorPoolCI.poolSizeCount = 1;
descriptorPoolCI.pPoolSizes = &descriptorPoolSize;
descriptorPoolCI.maxSets = 1;
if (vkCreateDescriptorPool(m_device, &descriptorPoolCI, nullptr, &m_pipelineOutputDescriptorPool) != VK_SUCCESS)
NFError("Could not create descriptor pool.");
// Allocate descriptor set
VkDescriptorSetAllocateInfo descriptorSetAI = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
descriptorSetAI.descriptorPool = m_pipelineOutputDescriptorPool;
descriptorSetAI.descriptorSetCount = 1;
descriptorSetAI.pSetLayouts = &m_pipelineOutputDescriptorSetLayout;
if (vkAllocateDescriptorSets(m_device, &descriptorSetAI, &m_pipelineOutputDescriptorSet) != VK_SUCCESS)
NFError("Could not allocate descriptor set.");
// And finally put it all together // And finally put it all together
VkGraphicsPipelineCreateInfo pipelineCI = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; VkGraphicsPipelineCreateInfo pipelineCI = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
pipelineCI.stageCount = 2; pipelineCI.stageCount = 2;
@ -409,14 +449,14 @@ namespace nf::client::render {
pipelineCI.pMultisampleState = &multisampleStateCI; pipelineCI.pMultisampleState = &multisampleStateCI;
pipelineCI.pColorBlendState = &colorBlendStateCI; pipelineCI.pColorBlendState = &colorBlendStateCI;
pipelineCI.pDynamicState = &dynamicStateCI; pipelineCI.pDynamicState = &dynamicStateCI;
pipelineCI.layout = m_pipelineLayoutOutput; pipelineCI.layout = m_pipelineOutputLayout;
pipelineCI.renderPass = m_renderPassOutput; pipelineCI.renderPass = m_renderPassOutput;
if (vkCreateGraphicsPipelines(m_device, nullptr, 1, &pipelineCI, nullptr, &m_pipelineOutput) != VK_SUCCESS) if (vkCreateGraphicsPipelines(m_device, nullptr, 1, &pipelineCI, nullptr, &m_pipelineOutput) != VK_SUCCESS)
NFError("Could not create graphics pipeline."); NFError("Could not create graphics pipeline.");
} }
void RenderEngine::createFrameExecutors() { void RenderEngine::createExecutionObjects() {
VkCommandPoolCreateInfo commandPoolCI = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; VkCommandPoolCreateInfo commandPoolCI = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
commandPoolCI.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; commandPoolCI.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
commandPoolCI.queueFamilyIndex = m_queueFIGraphics; commandPoolCI.queueFamilyIndex = m_queueFIGraphics;
@ -424,26 +464,23 @@ namespace nf::client::render {
if (vkCreateCommandPool(m_device, &commandPoolCI, nullptr, &m_commandPool) != VK_SUCCESS) if (vkCreateCommandPool(m_device, &commandPoolCI, nullptr, &m_commandPool) != VK_SUCCESS)
NFError("Could not create command pool."); NFError("Could not create command pool.");
m_frameExecutors.resize(m_numFramesInFlight);
for (int i = 0; i < m_frameExecutors.size(); i++) {
VkCommandBufferAllocateInfo commandBufferAI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; VkCommandBufferAllocateInfo commandBufferAI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
commandBufferAI.commandPool = m_commandPool; commandBufferAI.commandPool = m_commandPool;
commandBufferAI.commandBufferCount = 1; commandBufferAI.commandBufferCount = 1;
if (vkAllocateCommandBuffers(m_device, &commandBufferAI, &m_frameExecutors[i].commandBuffer) != VK_SUCCESS) if (vkAllocateCommandBuffers(m_device, &commandBufferAI, &m_commandBuffer) != VK_SUCCESS)
NFError("Could not create command buffer."); NFError("Could not create command buffer.");
VkSemaphoreCreateInfo semaphoreCI = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; VkSemaphoreCreateInfo semaphoreCI = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
if (vkCreateSemaphore(m_device, &semaphoreCI, nullptr, &m_frameExecutors[i].semaphoreImageAvailable) != VK_SUCCESS || if (vkCreateSemaphore(m_device, &semaphoreCI, nullptr, &m_semaphoreImageAvailable) != VK_SUCCESS ||
vkCreateSemaphore(m_device, &semaphoreCI, nullptr, &m_frameExecutors[i].semaphoreRenderFinished) != VK_SUCCESS) vkCreateSemaphore(m_device, &semaphoreCI, nullptr, &m_semaphoreRenderingDone) != VK_SUCCESS)
NFError("Could not create semaphore."); NFError("Could not create semaphore.");
VkFenceCreateInfo fenceCI = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; VkFenceCreateInfo fenceCI = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
fenceCI.flags = VK_FENCE_CREATE_SIGNALED_BIT; fenceCI.flags = VK_FENCE_CREATE_SIGNALED_BIT;
if (vkCreateFence(m_device, &fenceCI, nullptr, &m_frameExecutors[i].fenceFrameInFlight) != VK_SUCCESS) if (vkCreateFence(m_device, &fenceCI, nullptr, &m_fenceFrameInFlight) != VK_SUCCESS)
NFError("Could not create fence."); NFError("Could not create fence.");
} }
}
void RenderEngine::createBuffers() { void RenderEngine::createBuffers() {
std::vector<Vertex> triangleVertices = { std::vector<Vertex> triangleVertices = {
@ -462,18 +499,30 @@ namespace nf::client::render {
size_t triangleIndicesSize = sizeof(triangleIndices[0]) * triangleIndices.size(); size_t triangleIndicesSize = sizeof(triangleIndices[0]) * triangleIndices.size();
m_bufferIndex = std::make_unique<Buffer>(BufferType::Index, m_device, *m_allocator, m_commandPool, m_queueGraphics, triangleIndices.data(), triangleIndicesSize); m_bufferIndex = std::make_unique<Buffer>(BufferType::Index, m_device, *m_allocator, m_commandPool, m_queueGraphics, triangleIndices.data(), triangleIndicesSize);
size_t mvpUniformBufferSize = sizeof(glm::mat4);
m_bufferUniformMVP = std::make_unique<Buffer>(BufferType::Uniform, m_device, *m_allocator, nullptr, nullptr, nullptr, mvpUniformBufferSize);
// Add uniform buffer to descriptor set
VkWriteDescriptorSet descriptorSetWrite = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
VkDescriptorBufferInfo uniformDescriptorBI = {};
uniformDescriptorBI.buffer = m_bufferUniformMVP->getHandle();
uniformDescriptorBI.range = VK_WHOLE_SIZE;
descriptorSetWrite.dstSet = m_pipelineOutputDescriptorSet;
descriptorSetWrite.dstBinding = 0;
descriptorSetWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorSetWrite.descriptorCount = 1;
descriptorSetWrite.pBufferInfo = &uniformDescriptorBI;
vkUpdateDescriptorSets(m_device, 1, &descriptorSetWrite, 0, nullptr);
} }
void RenderEngine::doFrame() { void RenderEngine::doFrame() {
// Get current frame executor
auto& [commandBuffer, semaphoreImageAvailable, semaphoreRenderFinished, fenceFrameInFlight] = m_frameExecutors[m_currentFrameExecutor];
// First, wait for previous frame to complete // First, wait for previous frame to complete
vkWaitForFences(m_device, 1, &fenceFrameInFlight, VK_TRUE, UINT64_MAX); vkWaitForFences(m_device, 1, &m_fenceFrameInFlight, VK_TRUE, UINT64_MAX);
// Get next swapchain image and recreate if necessary // Get next swapchain image and recreate if necessary
uint32_t nextImageIndex = 0; uint32_t nextImageIndex = 0;
VkResult result = vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, semaphoreImageAvailable, nullptr, &nextImageIndex); VkResult result = vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, m_semaphoreImageAvailable, nullptr, &nextImageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR) {
recreateSwapchain(); recreateSwapchain();
return; return;
@ -482,12 +531,12 @@ namespace nf::client::render {
NFError("Could not aquire next swapchain image."); NFError("Could not aquire next swapchain image.");
// Reset fence for this frame // Reset fence for this frame
vkResetFences(m_device, 1, &fenceFrameInFlight); vkResetFences(m_device, 1, &m_fenceFrameInFlight);
// Begin recording // Begin recording
VkCommandBufferBeginInfo commandBufferBI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; VkCommandBufferBeginInfo commandBufferBI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
if (vkBeginCommandBuffer(commandBuffer, &commandBufferBI) != VK_SUCCESS) if (vkBeginCommandBuffer(m_commandBuffer, &commandBufferBI) != VK_SUCCESS)
NFError("Could not begin recording command buffer."); NFError("Could not begin recording command buffer.");
// Start the render pass // Start the render pass
@ -498,52 +547,65 @@ namespace nf::client::render {
renderPassBI.renderArea.extent = m_swapchainExtent; renderPassBI.renderArea.extent = m_swapchainExtent;
renderPassBI.clearValueCount = 1; renderPassBI.clearValueCount = 1;
renderPassBI.pClearValues = &black; renderPassBI.pClearValues = &black;
vkCmdBeginRenderPass(commandBuffer, &renderPassBI, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(m_commandBuffer, &renderPassBI, VK_SUBPASS_CONTENTS_INLINE);
// Bind output pipeline // Bind output pipeline
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineOutput); vkCmdBindPipeline(m_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineOutput);
// Set viewport and scissor // Set viewport and scissor
VkViewport viewport = {}; VkViewport viewport = {};
viewport.width = static_cast<float>(m_swapchainExtent.width), viewport.height = static_cast<float>(m_swapchainExtent.height); viewport.width = static_cast<float>(m_swapchainExtent.width), viewport.height = static_cast<float>(m_swapchainExtent.height);
viewport.maxDepth = 1.0; viewport.maxDepth = 1.0;
vkCmdSetViewport(commandBuffer, 0, 1, &viewport); vkCmdSetViewport(m_commandBuffer, 0, 1, &viewport);
VkRect2D scissor = { {}, m_swapchainExtent }; VkRect2D scissor = { {}, m_swapchainExtent };
vkCmdSetScissor(commandBuffer, 0, 1, &scissor); vkCmdSetScissor(m_commandBuffer, 0, 1, &scissor);
// Bind buffers // Bind buffers
VkDeviceSize bufferOffset = 0; VkDeviceSize bufferOffset = 0;
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_bufferVertex->getHandle(), &bufferOffset); vkCmdBindVertexBuffers(m_commandBuffer, 0, 1, &m_bufferVertex->getHandle(), &bufferOffset);
vkCmdBindIndexBuffer(commandBuffer, m_bufferIndex->getHandle(), 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(m_commandBuffer, m_bufferIndex->getHandle(), 0, VK_INDEX_TYPE_UINT32);
// Update uniform buffer
static auto startTime = std::chrono::high_resolution_clock::now();
auto currentTime = std::chrono::high_resolution_clock::now();
float time = std::chrono::duration<float>(currentTime - startTime).count();
glm::mat4 modelMatrix = glm::rotate(glm::mat4(1.0), time * glm::radians(20.0f), glm::vec3(0.0, 0.0, 1.0)),
viewMatrix = glm::lookAt(glm::vec3(1.0, 1.0, 2.0), glm::vec3(0.0), glm::vec3(0.0, 1.0, 0.0)),
projectionMatrix = glm::perspective(glm::radians(45.0f), static_cast<float>(m_swapchainExtent.width) / m_swapchainExtent.height, 0.1f, 10.0f);
projectionMatrix[1][1] *= -1;
glm::mat4 mvpMatrix = projectionMatrix * viewMatrix * modelMatrix;
memcpy(m_bufferUniformMVP->getPointer(), &mvpMatrix, sizeof(mvpMatrix));
vkCmdBindDescriptorSets(m_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineOutputLayout, 0, 1, &m_pipelineOutputDescriptorSet, 0, nullptr);
// Draw // Draw
vkCmdDrawIndexed(commandBuffer, 6, 1, 0, 0, 0); vkCmdDrawIndexed(m_commandBuffer, 6, 1, 0, 0, 0);
// End the render pass // End the render pass
vkCmdEndRenderPass(commandBuffer); vkCmdEndRenderPass(m_commandBuffer);
// Finish recording // Finish recording
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) if (vkEndCommandBuffer(m_commandBuffer) != VK_SUCCESS)
NFError("Could not end command buffer."); NFError("Could not end command buffer.");
// Submit to graphics queue // Submit to graphics queue
VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
submitInfo.waitSemaphoreCount = 1; submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &semaphoreImageAvailable; submitInfo.pWaitSemaphores = &m_semaphoreImageAvailable;
submitInfo.pWaitDstStageMask = &waitStage; submitInfo.pWaitDstStageMask = &waitStage;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer; submitInfo.pCommandBuffers = &m_commandBuffer;
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &semaphoreRenderFinished; submitInfo.pSignalSemaphores = &m_semaphoreRenderingDone;
if (vkQueueSubmit(m_queueGraphics, 1, &submitInfo, fenceFrameInFlight) != VK_SUCCESS) if (vkQueueSubmit(m_queueGraphics, 1, &submitInfo, m_fenceFrameInFlight) != VK_SUCCESS)
NFError("Could not submit to Vulkan queue."); NFError("Could not submit to Vulkan queue.");
// And present! // And present!
VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
presentInfo.waitSemaphoreCount = 1; presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = &semaphoreRenderFinished; presentInfo.pWaitSemaphores = &m_semaphoreRenderingDone;
presentInfo.swapchainCount = 1; presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &m_swapchain; presentInfo.pSwapchains = &m_swapchain;
presentInfo.pImageIndices = &nextImageIndex; presentInfo.pImageIndices = &nextImageIndex;
@ -553,9 +615,6 @@ namespace nf::client::render {
recreateSwapchain(); recreateSwapchain();
else if (result != VK_SUCCESS) else if (result != VK_SUCCESS)
NFError("Could not present image."); NFError("Could not present image.");
// Advance to next frame executor
m_currentFrameExecutor = (m_currentFrameExecutor + 1) % m_numFramesInFlight;
} }
void RenderEngine::setDisplay(DisplayConfig config) { void RenderEngine::setDisplay(DisplayConfig config) {
@ -593,19 +652,20 @@ namespace nf::client::render {
RenderEngine::~RenderEngine() { RenderEngine::~RenderEngine() {
waitIdle(); waitIdle();
m_bufferUniformMVP.reset();
m_bufferIndex.reset(); m_bufferIndex.reset();
m_bufferVertex.reset(); m_bufferVertex.reset();
for (int i = 0; i < m_frameExecutors.size(); i++) { vkDestroyFence(m_device, m_fenceFrameInFlight, nullptr);
vkDestroyFence(m_device, m_frameExecutors[i].fenceFrameInFlight, nullptr); vkDestroySemaphore(m_device, m_semaphoreRenderingDone, nullptr);
vkDestroySemaphore(m_device, m_frameExecutors[i].semaphoreRenderFinished, nullptr); vkDestroySemaphore(m_device, m_semaphoreImageAvailable, nullptr);
vkDestroySemaphore(m_device, m_frameExecutors[i].semaphoreImageAvailable, nullptr);
}
destroySwapchain(); destroySwapchain();
vkDestroyCommandPool(m_device, m_commandPool, nullptr); vkDestroyCommandPool(m_device, m_commandPool, nullptr);
vkDestroyPipeline(m_device, m_pipelineOutput, nullptr); vkDestroyPipeline(m_device, m_pipelineOutput, nullptr);
vkDestroyPipelineLayout(m_device, m_pipelineLayoutOutput, nullptr); vkDestroyDescriptorPool(m_device, m_pipelineOutputDescriptorPool, nullptr);
vkDestroyPipelineLayout(m_device, m_pipelineOutputLayout, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_pipelineOutputDescriptorSetLayout, nullptr);
vkDestroyRenderPass(m_device, m_renderPassOutput, nullptr); vkDestroyRenderPass(m_device, m_renderPassOutput, nullptr);
vkDestroyDevice(m_device, nullptr); vkDestroyDevice(m_device, nullptr);
vkDestroySurfaceKHR(m_instance, m_surface, nullptr); vkDestroySurfaceKHR(m_instance, m_surface, nullptr);

View File

@ -7,12 +7,6 @@
#include "Buffer.h" #include "Buffer.h"
namespace nf::client::render { namespace nf::client::render {
struct FrameExecutor {
VkCommandBuffer commandBuffer;
VkSemaphore semaphoreImageAvailable, semaphoreRenderFinished;
VkFence fenceFrameInFlight;
};
class RenderEngine { class RenderEngine {
public: public:
RenderEngine(std::shared_ptr<Window> window, DisplayConfig display); RenderEngine(std::shared_ptr<Window> window, DisplayConfig display);
@ -26,11 +20,12 @@ namespace nf::client::render {
void createSurface(); void createSurface();
void pickPhysicalDevice(); void pickPhysicalDevice();
void createDevice(); void createDevice();
void createSwapchain(); void createSwapchain();
void createOutputRenderPass(); void createOutputRenderPass();
void createSwapchainFramebuffers(); void createSwapchainFramebuffers();
void createOutputPipeline(); void createOutputPipeline();
void createFrameExecutors(); void createExecutionObjects();
void createBuffers(); void createBuffers();
@ -49,6 +44,7 @@ namespace nf::client::render {
uint32_t m_queueFIGraphics, m_queueFIPresent; uint32_t m_queueFIGraphics, m_queueFIPresent;
VkDevice m_device; VkDevice m_device;
VkQueue m_queueGraphics, m_queuePresent; VkQueue m_queueGraphics, m_queuePresent;
VkRenderPass m_renderPassOutput; VkRenderPass m_renderPassOutput;
// Swapchain // Swapchain
@ -60,17 +56,23 @@ namespace nf::client::render {
std::vector<VkFramebuffer> m_swapchainFramebuffers; std::vector<VkFramebuffer> m_swapchainFramebuffers;
// Pipelines // Pipelines
VkPipelineLayout m_pipelineLayoutOutput; VkDescriptorSetLayout m_pipelineOutputDescriptorSetLayout;
VkPipelineLayout m_pipelineOutputLayout;
VkDescriptorPool m_pipelineOutputDescriptorPool;
VkDescriptorSet m_pipelineOutputDescriptorSet;
VkPipeline m_pipelineOutput; VkPipeline m_pipelineOutput;
// Execution objects // Execution objects
VkCommandPool m_commandPool; VkCommandPool m_commandPool;
const uint32_t m_numFramesInFlight; VkCommandBuffer m_commandBuffer;
std::vector<FrameExecutor> m_frameExecutors; VkSemaphore m_semaphoreImageAvailable;
uint32_t m_currentFrameExecutor; VkSemaphore m_semaphoreRenderingDone;
VkFence m_fenceFrameInFlight;
// Temporary objects
std::unique_ptr<VideoMemoryAllocator> m_allocator; std::unique_ptr<VideoMemoryAllocator> m_allocator;
std::unique_ptr<Buffer> m_bufferVertex; std::unique_ptr<Buffer> m_bufferVertex;
std::unique_ptr<Buffer> m_bufferIndex; std::unique_ptr<Buffer> m_bufferIndex;
std::unique_ptr<Buffer> m_bufferUniformMVP;
}; };
} }

View File

@ -45,3 +45,4 @@
// GLM // GLM
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>