Add uniform buffer / resource descriptor set
This commit is contained in:
parent
ae707f1f3d
commit
9738de012a
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -45,3 +45,4 @@
|
|||||||
|
|
||||||
// GLM
|
// GLM
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user