331 lines
14 KiB
C++
331 lines
14 KiB
C++
#include "CommandCenter.hpp"
|
|
|
|
#include "PhysicalDeviceInfo.hpp"
|
|
#include "Pipeline.hpp"
|
|
#include "Renderer.hpp"
|
|
#include "buffer/VertexData.hpp"
|
|
|
|
using namespace render::vk;
|
|
|
|
#define CONTENT_DIR "content/"
|
|
#define TEXTURES_DIR CONTENT_DIR "textures/"
|
|
|
|
CommandCenter::CommandCenter(VkDevice device, const PhysicalDeviceInfo &info, const renderOptions &opt): device(device) {
|
|
{ // 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 = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
|
|
if (vkCreateCommandPool(device, &poolInfo, ALLOC, &graphicsPool) != VK_SUCCESS) {
|
|
FATAL("Failed to create graphics pool!");
|
|
}
|
|
}
|
|
|
|
modelBuffer = ShortIndexedVertexBuffer::Create(buffer::vk::vertices, buffer::vk::indices);
|
|
if (!modelBuffer) {
|
|
FATAL("Cannot create vertex buffer");
|
|
}
|
|
sampleTexture = Texture::LoadFromFile(TEXTURES_DIR + opt.textures + "/terrain/Mapl.dds", {true, true, Texture::Wrap::MIRRORED_REPEAT, opt.anisotropy});
|
|
if (!sampleTexture) {
|
|
FATAL("Failed to create texture sampler!");
|
|
}
|
|
|
|
indicCubeBuffer = Indicator::Create(Indicator::CUBE.first, Indicator::CUBE.second);
|
|
if (!indicCubeBuffer) {
|
|
FATAL("Failed to create vertex buffer!");
|
|
}
|
|
|
|
skyCubeBuffer = Shape::Create(Shape::SKY_CUBE);
|
|
if (!skyCubeBuffer) {
|
|
FATAL("Failed to create vertex buffer!");
|
|
}
|
|
skyboxTexture = TextureCube::LoadFromFiles(TEXTURES_DIR + opt.textures + "/sky/Space_tray.cube", {});
|
|
if (!skyboxTexture) {
|
|
FATAL("Failed to create texture sampler!");
|
|
}
|
|
|
|
colorFormat = info.getSurfaceFormat().format;
|
|
colorSamples = info.samples;
|
|
LOG_D("Samples: " << colorSamples);
|
|
depthFormat = info.findDepthFormat();
|
|
}
|
|
CommandCenter::~CommandCenter() {
|
|
if(!freed)
|
|
free();
|
|
|
|
vkDestroyCommandPool(device, graphicsPool, ALLOC);
|
|
}
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeline& pipe, VkExtent2D extent) {
|
|
assert(freed);
|
|
|
|
if (colorSamples > 1) {
|
|
colorbuffer = Image::Create(Image::requirement({{extent.height, extent.width}, 1, (Image::Format)colorFormat},
|
|
Image::Layout::COLOR_ATTACHMENT, Image::Usage::COLOR_ATTACHMENT | Image::Usage::TRANSIENT_ATTACHMENT, // NOTE: VulkanTutorial#118
|
|
Image::Aspect::COLOR, colorSamples));
|
|
}
|
|
|
|
depthbuffer = Image::Create(Image::requirement({{extent.height, extent.width}, 1, (Image::Format)depthFormat},
|
|
Image::Layout::DEPTH_STENCIL_ATTACHMENT, Image::Usage::DEPTH_STENCIL_ATTACHMENT,
|
|
Image::Aspect::DEPTH, colorSamples));
|
|
|
|
framebuffers.resize(views.size());
|
|
|
|
for (size_t i = 0; i < views.size(); i++) {
|
|
std::vector<VkImageView> attachments;
|
|
if (colorSamples > 1) {
|
|
attachments = {colorbuffer->getView(), depthbuffer->getView(), views[i]};
|
|
} else {
|
|
attachments = {views[i], depthbuffer->getView()};
|
|
}
|
|
|
|
VkFramebufferCreateInfo framebufferInfo{};
|
|
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
framebufferInfo.renderPass = pipe.getRenderPass();
|
|
framebufferInfo.attachmentCount = attachments.size();
|
|
framebufferInfo.pAttachments = attachments.data();
|
|
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
|
|
std::vector<Buffer::requirement> requirements;
|
|
requirements.resize(framebuffers.size(), Buffer::requirement(sizeof(UniformBufferObject), Buffer::Usage::UNIFORM));
|
|
uniformBuffers.allocate(requirements, true);
|
|
if (!uniformBuffers) {
|
|
FATAL("Failed to allocate UBO");
|
|
}
|
|
}
|
|
{ // Descriptor pools
|
|
std::array<VkDescriptorPoolSize, 2> poolSizes{};
|
|
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
poolSizes[0].descriptorCount = framebuffers.size();
|
|
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
poolSizes[1].descriptorCount = framebuffers.size();
|
|
|
|
VkDescriptorPoolCreateInfo poolInfo{};
|
|
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
|
poolInfo.poolSizeCount = poolSizes.size();
|
|
poolInfo.pPoolSizes = poolSizes.data();
|
|
poolInfo.maxSets = framebuffers.size();
|
|
poolInfo.flags = 0; //VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT
|
|
|
|
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &voxelDescriptorPool) != VK_SUCCESS) {
|
|
FATAL("Failed to create descriptor pool!");
|
|
}
|
|
|
|
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &skyDescriptorPool) != VK_SUCCESS) {
|
|
FATAL("Failed to create descriptor pool!");
|
|
}
|
|
|
|
poolInfo.poolSizeCount = 1;
|
|
poolInfo.pPoolSizes = &poolSizes[0];
|
|
|
|
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &indicDescriptorPool) != VK_SUCCESS) {
|
|
FATAL("Failed to create descriptor pool!");
|
|
}
|
|
}
|
|
{ // Descriptor sets
|
|
VkDescriptorSetAllocateInfo allocInfo{};
|
|
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
allocInfo.descriptorSetCount = framebuffers.size();
|
|
|
|
auto allocSets = [&](VkDescriptorPool pool, VkDescriptorSetLayout layout, std::vector<VkDescriptorSet>& out) {
|
|
std::vector<VkDescriptorSetLayout> layouts(framebuffers.size(), layout);
|
|
allocInfo.descriptorPool = pool;
|
|
allocInfo.pSetLayouts = layouts.data();
|
|
|
|
out.resize(framebuffers.size());
|
|
if (vkAllocateDescriptorSets(device, &allocInfo, out.data()) != VK_SUCCESS) {
|
|
FATAL("Failed to allocate descriptor sets!");
|
|
}
|
|
};
|
|
allocSets(voxelDescriptorPool, pipe.getVoxelDescriptorSet(), voxelDescriptorSets);
|
|
allocSets(indicDescriptorPool, pipe.getIndicDescriptorSet(), indicDescriptorSets);
|
|
allocSets(skyDescriptorPool, pipe.getSkyDescriptorSet(), skyDescriptorSets);
|
|
|
|
for (size_t i = 0; i < voxelDescriptorSets.size(); i++) {
|
|
VkDescriptorBufferInfo bufferInfo{};
|
|
bufferInfo.buffer = uniformBuffers.at(i);
|
|
bufferInfo.offset = 0;
|
|
bufferInfo.range = sizeof(UniformBufferObject);
|
|
|
|
std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
|
|
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
descriptorWrites[0].dstSet = voxelDescriptorSets[i];
|
|
descriptorWrites[0].dstBinding = 0;
|
|
descriptorWrites[0].dstArrayElement = 0;
|
|
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
descriptorWrites[0].descriptorCount = 1;
|
|
descriptorWrites[0].pBufferInfo = &bufferInfo;
|
|
|
|
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
descriptorWrites[1].dstSet = voxelDescriptorSets[i];
|
|
descriptorWrites[1].dstBinding = 1;
|
|
descriptorWrites[1].dstArrayElement = 0;
|
|
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
descriptorWrites[1].descriptorCount = 1;
|
|
descriptorWrites[1].pImageInfo = &sampleTexture->getDescriptor();
|
|
|
|
vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
|
|
|
descriptorWrites[0].dstSet = skyDescriptorSets[i];
|
|
descriptorWrites[1].dstSet = skyDescriptorSets[i];
|
|
descriptorWrites[1].pImageInfo = &skyboxTexture->getDescriptor();
|
|
vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
|
|
|
descriptorWrites[0].dstSet = indicDescriptorSets[i];
|
|
vkUpdateDescriptorSets(device, 1, &descriptorWrites[0], 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!");
|
|
}
|
|
}
|
|
|
|
freed = false;
|
|
}
|
|
void CommandCenter::free() {
|
|
assert(!freed);
|
|
vkFreeCommandBuffers(device, graphicsPool, static_cast<uint32_t>(graphicsBuffers.size()), graphicsBuffers.data());
|
|
|
|
vkDestroyDescriptorPool(device, voxelDescriptorPool, ALLOC);
|
|
vkDestroyDescriptorPool(device, indicDescriptorPool, ALLOC);
|
|
vkDestroyDescriptorPool(device, skyDescriptorPool, ALLOC);
|
|
|
|
colorbuffer.reset();
|
|
depthbuffer.reset();
|
|
|
|
for (size_t i = 0; i < framebuffers.size(); i++) {
|
|
vkDestroyFramebuffer(device, framebuffers[i], ALLOC);
|
|
}
|
|
|
|
freed = true;
|
|
}
|
|
|
|
#include <chrono>
|
|
#include <memory.h>
|
|
|
|
void CommandCenter::startRecording(uint32_t idx, VkRenderPass renderPass, VkExtent2D extent, const glm::vec4& clear_color, glm::mat4 view, glm::mat4 proj) {
|
|
UniformBufferObject ubo{};
|
|
ubo.view = view;
|
|
ubo.proj = proj;
|
|
uniformBuffers.write(idx, data_view(&ubo, sizeof(ubo)));
|
|
|
|
VkCommandBufferBeginInfo beginInfo{};
|
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
//TODO: reuse
|
|
beginInfo.pInheritanceInfo = nullptr;
|
|
|
|
if (vkBeginCommandBuffer(graphicsBuffers[idx], &beginInfo) != VK_SUCCESS) {
|
|
FATAL("Failed to begin recording command buffer!");
|
|
}
|
|
|
|
VkRenderPassBeginInfo renderPassInfo{};
|
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
|
renderPassInfo.renderPass = renderPass;
|
|
renderPassInfo.framebuffer = framebuffers[idx];
|
|
renderPassInfo.renderArea.offset = {0, 0};
|
|
renderPassInfo.renderArea.extent = extent;
|
|
|
|
std::array<VkClearValue, 2> clearValues{};
|
|
clearValues[0].color = {clear_color.x, clear_color.y, clear_color.z, clear_color.a};
|
|
clearValues[1].depthStencil = {1.0f, 0};
|
|
renderPassInfo.clearValueCount = clearValues.size();
|
|
renderPassInfo.pClearValues = clearValues.data();
|
|
|
|
vkCmdBeginRenderPass(graphicsBuffers[idx], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
}
|
|
|
|
void CommandCenter::startWorldPass(uint32_t idx, const Subpass &worldPass) {
|
|
vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, worldPass.pipeline);
|
|
vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, worldPass.layout, 0, 1, &voxelDescriptorSets[idx], 0, nullptr);
|
|
|
|
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();
|
|
ModelPush push{};
|
|
push.model = glm::translate(glm::mat4(1.0f), glm::vec3(98.0f, -2.f, -2.f));
|
|
push.model = glm::rotate(push.model, time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
|
vkCmdPushConstants(graphicsBuffers[idx], worldPass.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push), &push);
|
|
}
|
|
void CommandCenter::recordModel(uint32_t i) {
|
|
VkBuffer vertexBuffers[] = {modelBuffer->getVertex()};
|
|
VkDeviceSize offsets[] = {0};
|
|
vkCmdBindVertexBuffers(graphicsBuffers[i], 0, 1, vertexBuffers, offsets);
|
|
vkCmdBindIndexBuffer(graphicsBuffers[i], modelBuffer->getIndex(), 0, VK_INDEX_TYPE_UINT16);
|
|
vkCmdDrawIndexed(graphicsBuffers[i], static_cast<uint32_t>(buffer::vk::indices.size()), 1, 0, 0, 0);
|
|
}
|
|
void CommandCenter::startEntityPass(uint32_t) { }
|
|
void CommandCenter::recordIndicator(uint32_t idx, const Subpass& indicPass, glm::mat4 model) {
|
|
vkCmdNextSubpass(graphicsBuffers[idx], VK_SUBPASS_CONTENTS_INLINE);
|
|
vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, indicPass.pipeline);
|
|
vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, indicPass.layout, 0, 1, &indicDescriptorSets[idx], 0, nullptr);
|
|
|
|
ModelPush push{model};
|
|
vkCmdPushConstants(graphicsBuffers[idx], indicPass.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push), &push);
|
|
|
|
VkBuffer vertexBuffers[] = {indicCubeBuffer->getRef()};
|
|
VkDeviceSize offsets[] = {0};
|
|
vkCmdBindVertexBuffers(graphicsBuffers[idx], 0, 1, vertexBuffers, offsets);
|
|
vkCmdDraw(graphicsBuffers[idx], indicCubeBuffer->size, 1, 0, 0);
|
|
}
|
|
void CommandCenter::recordPostprocess(uint32_t idx, const Subpass& skyPass, bool skybox, glm::mat4, glm::mat4) {
|
|
vkCmdNextSubpass(graphicsBuffers[idx], VK_SUBPASS_CONTENTS_INLINE);
|
|
if (skybox) {
|
|
vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, skyPass.pipeline);
|
|
vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, skyPass.layout, 0, 1, &skyDescriptorSets[idx], 0, nullptr);
|
|
VkBuffer vertexBuffers[] = {skyCubeBuffer->getRef()};
|
|
VkDeviceSize offsets[] = {0};
|
|
vkCmdBindVertexBuffers(graphicsBuffers[idx], 0, 1, vertexBuffers, offsets);
|
|
vkCmdDraw(graphicsBuffers[idx], skyCubeBuffer->size, 1, 0, 0);
|
|
}
|
|
vkCmdEndRenderPass(graphicsBuffers[idx]);
|
|
}
|
|
|
|
void CommandCenter::submitGraphics(uint32_t idx, VkSemaphore waitSemaphore, VkSemaphore signalSemaphore, VkFence submittedFence) {
|
|
assert(!freed);
|
|
|
|
if (vkEndCommandBuffer(graphicsBuffers[idx]) != VK_SUCCESS) {
|
|
FATAL("Failed to record graphics buffer!");
|
|
}
|
|
|
|
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!");
|
|
}
|
|
}
|