1
0
Fork 0
Univerxel/src/client/render/vk/CommandCenter.cpp

346 lines
15 KiB
C++

#include "CommandCenter.hpp"
#include "PhysicalDeviceInfo.hpp"
#include "Pipeline.hpp"
#include "../Renderer.hpp"
#include "buffer/VertexData.hpp"
#include "texture.hpp"
using namespace render::vk;
#define CONTENT_DIR "content/"
#define TEXTURES_DIR CONTENT_DIR "textures/"
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()), sampleImageMemory(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();
if(std::vector<Allocator::buffer_info> out; indexedBufferMemory = alloc.createBuffers({
{indexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, buffer::vk::indices.data(), indexSize, 0},
{vertexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, buffer::vk::vertices.data(), vertexSize, 0}
}, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, out)) {
indexBuffer = out[0];
vertexBuffer = out[1];
} else {
FATAL("Cannot create vertex buffer");
}
}
{ // Texture sampler (const)
std::vector<unsigned char> data;
dds::header_info header;
if (dds::readDDS(TEXTURES_DIR "1024-realistic/terrain/Mapl.dds", data, header)) {
FATAL("Cannot read texture");
}
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = header.width;
imageInfo.extent.height = header.height;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = header.mipMapCount; //TODO:
imageInfo.arrayLayers = 1;
imageInfo.format = header.format;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.flags = 0;
sampleImageMemory = alloc.createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, sampleImage, data.data(), data.size());
if(!sampleImageMemory) {
FATAL("Cannot create texture image");
}
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = sampleImage.image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = header.format;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
if (vkCreateImageView(device, &viewInfo, nullptr, &sampleImageView) != VK_SUCCESS) {
FATAL("Failed to create texture image view!");
}
VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
if (info.features.samplerAnisotropy && opt.anisotropy > 0) {
samplerInfo.anisotropyEnable = VK_TRUE;
samplerInfo.maxAnisotropy = 1 << (opt.anisotropy-1);
} else {
samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.maxAnisotropy = 1.f;
}
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
samplerInfo.unnormalizedCoordinates = VK_FALSE;
samplerInfo.compareEnable = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.mipLodBias = 0.0f; //TODO:
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 0.0f;
if (vkCreateSampler(device, &samplerInfo, nullptr, &sampleSampler) != VK_SUCCESS) {
FATAL("Failed to create texture sampler!");
}
}
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();
vkDestroySampler(device, sampleSampler, ALLOC);
vkDestroyImageView(device, sampleImageView, ALLOC);
vkDestroyImage(device, sampleImage.image, ALLOC);
sampleImageMemory.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
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, &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);
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.imageView = sampleImageView;
imageInfo.sampler = sampleSampler;
std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[0].dstSet = descriptorSets[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 = descriptorSets[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 = &imageInfo;
vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 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!");
}
}