263 lines
11 KiB
C++
263 lines
11 KiB
C++
#include "CommandCenter.hpp"
|
|
|
|
#include "PhysicalDeviceInfo.hpp"
|
|
#include "Pipeline.hpp"
|
|
#include "../Renderer.hpp"
|
|
#include "buffer/VertexData.hpp"
|
|
|
|
using namespace render::vk;
|
|
|
|
CommandCenter::CommandCenter(VkDevice device, Allocator& alloc, const std::vector<VkImageView> &views,
|
|
const Pipeline& pipe, const PhysicalDeviceInfo &info, const renderOptions &opt):
|
|
device(device), indexedBufferMemory(Allocator::GetNull()), uniformBuffersMemory(Allocator::GetNull()) {
|
|
{ // Graphics command pool
|
|
vkGetDeviceQueue(device, info.queueIndices.graphicsFamily.value(), 0, &graphicsQueue);
|
|
VkCommandPoolCreateInfo poolInfo{};
|
|
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
poolInfo.queueFamilyIndex = info.queueIndices.graphicsFamily.value();
|
|
poolInfo.flags = 0;
|
|
|
|
if (vkCreateCommandPool(device, &poolInfo, ALLOC, &graphicsPool) != VK_SUCCESS) {
|
|
FATAL("Failed to create graphics pool!");
|
|
}
|
|
}
|
|
{ // Vertex buffers (const)
|
|
size_t vertexSize = sizeof(buffer::vk::vertices[0]) * buffer::vk::vertices.size();
|
|
size_t indexSize = sizeof(buffer::vk::indices[0]) * buffer::vk::indices.size();
|
|
size_t stagingSize = std::max(vertexSize, indexSize);
|
|
Allocator::buffer_info stagingBuffer;
|
|
if(auto stagingMemory = alloc.createBuffer(stagingSize, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, stagingBuffer)) {
|
|
if(std::vector<Allocator::buffer_info> out; indexedBufferMemory = alloc.createBuffers({
|
|
{indexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT},
|
|
{vertexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT}
|
|
}, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, out)) {
|
|
indexBuffer = out[0];
|
|
vertexBuffer = out[1];
|
|
} else {
|
|
FATAL("Cannot allocate buffer memory");
|
|
}
|
|
|
|
stagingMemory->write(buffer::vk::vertices.data(), vertexSize);
|
|
alloc.copyBuffer(stagingBuffer, vertexBuffer, vertexSize);
|
|
stagingMemory->write(buffer::vk::indices.data(), indexSize);
|
|
alloc.copyBuffer(stagingBuffer, indexBuffer, indexSize);
|
|
|
|
vkDestroyBuffer(device, stagingBuffer.buffer, ALLOC); //TODO: move to buffer
|
|
} else {
|
|
FATAL("Cannot allocate staging memory");
|
|
}
|
|
}
|
|
|
|
allocate(alloc, views, pipe, info.swapDetails.capabilities.currentExtent, opt);
|
|
}
|
|
CommandCenter::~CommandCenter() {
|
|
if(!freed)
|
|
free();
|
|
|
|
vkDestroyBuffer(device, indexBuffer.buffer, ALLOC);
|
|
vkDestroyBuffer(device, vertexBuffer.buffer, ALLOC);
|
|
indexedBufferMemory.reset();
|
|
|
|
vkDestroyCommandPool(device, graphicsPool, ALLOC);
|
|
}
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
void CommandCenter::allocate(Allocator& alloc, const std::vector<VkImageView>& views, const Pipeline& pipe, VkExtent2D extent,
|
|
const renderOptions& opt)
|
|
{
|
|
assert(freed);
|
|
|
|
framebuffers.resize(views.size());
|
|
|
|
for (size_t i = 0; i < views.size(); i++) {
|
|
VkImageView attachments[] = { views[i] };
|
|
|
|
VkFramebufferCreateInfo framebufferInfo{};
|
|
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
framebufferInfo.renderPass = pipe.getRenderPass();
|
|
framebufferInfo.attachmentCount = 1;
|
|
framebufferInfo.pAttachments = attachments;
|
|
framebufferInfo.width = extent.width;
|
|
framebufferInfo.height = extent.height;
|
|
framebufferInfo.layers = 1;
|
|
|
|
if (vkCreateFramebuffer(device, &framebufferInfo, ALLOC, &framebuffers[i]) != VK_SUCCESS) {
|
|
FATAL("Failed to create framebuffer!");
|
|
}
|
|
}
|
|
|
|
{ // Uniform buffers
|
|
VkDeviceSize bufferSize = sizeof(buffer::vk::UniformBufferObject);
|
|
|
|
std::vector<Allocator::buffer_requirement> requirements;
|
|
requirements.resize(framebuffers.size(), Allocator::buffer_requirement{bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT});
|
|
uniformBuffersMemory = alloc.createBuffers(requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers);
|
|
if (!uniformBuffersMemory) {
|
|
FATAL("Failed to allocate UBO");
|
|
}
|
|
}
|
|
{ // Descriptor pool
|
|
VkDescriptorPoolSize poolSize{};
|
|
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
poolSize.descriptorCount = framebuffers.size();
|
|
|
|
VkDescriptorPoolCreateInfo poolInfo{};
|
|
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
|
poolInfo.poolSizeCount = 1;
|
|
poolInfo.pPoolSizes = &poolSize;
|
|
poolInfo.maxSets = framebuffers.size();
|
|
poolInfo.flags = 0; //VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT
|
|
|
|
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
|
|
FATAL("Failed to create descriptor pool!");
|
|
}
|
|
}
|
|
{ // Descriptor sets
|
|
std::vector<VkDescriptorSetLayout> layouts(framebuffers.size(), pipe.getDescriptorSet());
|
|
VkDescriptorSetAllocateInfo allocInfo{};
|
|
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
allocInfo.descriptorPool = descriptorPool;
|
|
allocInfo.descriptorSetCount = framebuffers.size();
|
|
allocInfo.pSetLayouts = layouts.data();
|
|
|
|
descriptorSets.resize(framebuffers.size());
|
|
if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {
|
|
FATAL("Failed to allocate descriptor sets!");
|
|
}
|
|
|
|
for (size_t i = 0; i < descriptorSets.size(); i++) {
|
|
VkDescriptorBufferInfo bufferInfo{};
|
|
bufferInfo.buffer = uniformBuffers[i].buffer;
|
|
bufferInfo.offset = 0;
|
|
bufferInfo.range = sizeof(buffer::vk::UniformBufferObject);
|
|
|
|
VkWriteDescriptorSet descriptorWrite{};
|
|
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
descriptorWrite.dstSet = descriptorSets[i];
|
|
descriptorWrite.dstBinding = 0;
|
|
descriptorWrite.dstArrayElement = 0;
|
|
|
|
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
descriptorWrite.descriptorCount = 1;
|
|
|
|
descriptorWrite.pBufferInfo = &bufferInfo;
|
|
descriptorWrite.pImageInfo = nullptr;
|
|
descriptorWrite.pTexelBufferView = nullptr;
|
|
|
|
vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
|
|
}
|
|
}
|
|
|
|
{
|
|
graphicsBuffers.resize(framebuffers.size());
|
|
VkCommandBufferAllocateInfo allocInfo{};
|
|
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
allocInfo.commandPool = graphicsPool;
|
|
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
allocInfo.commandBufferCount = (uint32_t) graphicsBuffers.size();
|
|
|
|
if (vkAllocateCommandBuffers(device, &allocInfo, graphicsBuffers.data()) != VK_SUCCESS) {
|
|
FATAL("Failed to allocate graphics buffers!");
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; i < graphicsBuffers.size(); i++) {
|
|
VkCommandBufferBeginInfo beginInfo{};
|
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
beginInfo.flags = 0;
|
|
beginInfo.pInheritanceInfo = nullptr;
|
|
|
|
if (vkBeginCommandBuffer(graphicsBuffers[i], &beginInfo) != VK_SUCCESS) {
|
|
FATAL("Failed to begin recording command buffer!");
|
|
}
|
|
|
|
VkRenderPassBeginInfo renderPassInfo{};
|
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
|
renderPassInfo.renderPass = pipe.getRenderPass();
|
|
renderPassInfo.framebuffer = framebuffers[i];
|
|
renderPassInfo.renderArea.offset = {0, 0};
|
|
renderPassInfo.renderArea.extent = extent;
|
|
|
|
VkClearValue clearColor = {opt.clear_color.x, opt.clear_color.y, opt.clear_color.z, opt.clear_color.a};
|
|
renderPassInfo.clearValueCount = 1; //TODO: clear depth
|
|
renderPassInfo.pClearValues = &clearColor;
|
|
|
|
vkCmdBeginRenderPass(graphicsBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
vkCmdBindPipeline(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getPipeline());
|
|
VkBuffer vertexBuffers[] = {vertexBuffer.buffer};
|
|
VkDeviceSize offsets[] = {0};
|
|
vkCmdBindVertexBuffers(graphicsBuffers[i], 0, 1, vertexBuffers, offsets);
|
|
vkCmdBindIndexBuffer(graphicsBuffers[i], indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
|
|
vkCmdBindDescriptorSets(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getLayout(), 0, 1, &descriptorSets[i], 0, nullptr);
|
|
vkCmdDrawIndexed(graphicsBuffers[i], static_cast<uint32_t>(buffer::vk::indices.size()), 1, 0, 0, 0);
|
|
vkCmdEndRenderPass(graphicsBuffers[i]);
|
|
|
|
if (vkEndCommandBuffer(graphicsBuffers[i]) != VK_SUCCESS) {
|
|
FATAL("Failed to record graphics buffer!");
|
|
}
|
|
}
|
|
|
|
proj = glm::perspective(glm::radians(45.0f), extent.width / (float) extent.height, 0.1f, 10.0f);
|
|
proj[1][1] *= -1;
|
|
|
|
freed = false;
|
|
}
|
|
void CommandCenter::free() {
|
|
assert(!freed);
|
|
vkFreeCommandBuffers(device, graphicsPool, static_cast<uint32_t>(graphicsBuffers.size()), graphicsBuffers.data());
|
|
|
|
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
|
|
|
for (size_t i = 0; i < uniformBuffers.size(); i++) {
|
|
vkDestroyBuffer(device, uniformBuffers[i].buffer, ALLOC);
|
|
}
|
|
uniformBuffersMemory.reset();
|
|
|
|
|
|
for (size_t i = 0; i < framebuffers.size(); i++) {
|
|
vkDestroyFramebuffer(device, framebuffers[i], nullptr);
|
|
}
|
|
|
|
freed = true;
|
|
}
|
|
|
|
#include <chrono>
|
|
#include <memory.h>
|
|
|
|
void CommandCenter::updateUBO(uint32_t idx) {
|
|
static auto startTime = std::chrono::high_resolution_clock::now();
|
|
|
|
auto currentTime = std::chrono::high_resolution_clock::now();
|
|
float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count();
|
|
buffer::vk::UniformBufferObject ubo{};
|
|
ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
|
ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
|
ubo.proj = proj;
|
|
|
|
memcpy(uniformBuffersMemory->ptr + uniformBuffers[idx].offset, &ubo, sizeof(ubo));
|
|
}
|
|
|
|
void CommandCenter::submitGraphics(uint32_t idx, VkSemaphore waitSemaphore, VkSemaphore signalSemaphore, VkFence submittedFence) {
|
|
assert(!freed);
|
|
|
|
VkSubmitInfo submitInfo{};
|
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
|
VkSemaphore waitSemaphores[] = {waitSemaphore};
|
|
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
|
submitInfo.waitSemaphoreCount = 1;
|
|
submitInfo.pWaitSemaphores = waitSemaphores;
|
|
submitInfo.pWaitDstStageMask = waitStages;
|
|
|
|
submitInfo.commandBufferCount = 1;
|
|
submitInfo.pCommandBuffers = &graphicsBuffers[idx];
|
|
|
|
VkSemaphore signalSemaphores[] = {signalSemaphore};
|
|
submitInfo.signalSemaphoreCount = 1;
|
|
submitInfo.pSignalSemaphores = signalSemaphores;
|
|
|
|
vkResetFences(device, 1, &submittedFence);
|
|
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, submittedFence) != VK_SUCCESS) {
|
|
FATAL("Failed to submit draw command buffer!");
|
|
}
|
|
}
|