Files
Np_Term/impl/vulkan_engine/vulkan/buffers.cpp

332 lines
13 KiB
C++

#include <vulkan/vulkan.h>
#include "vulkan_engine/asset/object/model.h"
#include "vulkan_engine/vulkan/graphics.h"
#include "vulkan_engine/vulkan/uniform_transformations.h"
namespace veng {
std::uint32_t Graphics::FindMemoryType(
std::uint32_t type_bits_filter, VkMemoryPropertyFlags required_properties) {
VkPhysicalDeviceMemoryProperties memory_properties;
vkGetPhysicalDeviceMemoryProperties(physical_device_, &memory_properties);
gsl::span<VkMemoryType> memory_types(memory_properties.memoryTypes,
memory_properties.memoryTypeCount);
for (std::uint32_t i = 0; i < memory_types.size(); i++) {
bool passes_filter = type_bits_filter & (1 << i);
bool has_property_flags =
memory_types[i].propertyFlags & required_properties;
if (passes_filter && has_property_flags) return i;
}
throw std::runtime_error("Cannot find memory type!");
}
BufferHandle Graphics::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
VkMemoryPropertyFlags properties) {
BufferHandle handle = {};
VkBufferCreateInfo buffer_info = {};
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buffer_info.size = size;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VkResult result =
vkCreateBuffer(logical_device_, &buffer_info, nullptr, &handle.buffer);
if (result != VK_SUCCESS)
throw std::runtime_error("Failed to create vertex buffer!");
VkMemoryRequirements memory_requirements;
vkGetBufferMemoryRequirements(logical_device_, handle.buffer,
&memory_requirements);
std::uint32_t chosen_memory_type =
FindMemoryType(memory_requirements.memoryTypeBits, properties);
VkMemoryAllocateInfo allocation_info = {};
allocation_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocation_info.allocationSize = memory_requirements.size;
allocation_info.memoryTypeIndex = chosen_memory_type;
VkResult allocation_result = vkAllocateMemory(
logical_device_, &allocation_info, nullptr, &handle.memory);
if (allocation_result != VK_SUCCESS)
throw std::runtime_error("Failed to allocate buffer memory!");
vkBindBufferMemory(logical_device_, handle.buffer, handle.memory, 0);
return handle;
}
BufferHandle Graphics::CreateVertexBuffer(gsl::span<Vertex> vertices) {
VkDeviceSize size = sizeof(Vertex) * vertices.size();
BufferHandle staging_handle = CreateBuffer(
size,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
void* data;
vkMapMemory(logical_device_, staging_handle.memory, 0, size, 0, &data);
std::memcpy(data, vertices.data(), size);
vkUnmapMemory(logical_device_, staging_handle.memory);
BufferHandle gpu_handle = CreateBuffer(
size,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkCommandBuffer transient_commands = BeginTransientCommandBuffer();
VkBufferCopy copy_info = {};
copy_info.srcOffset = 0;
copy_info.dstOffset = 0;
copy_info.size = size;
vkCmdCopyBuffer(transient_commands, staging_handle.buffer, gpu_handle.buffer,
1, &copy_info);
EndTransientCommandBuffer(transient_commands);
DestroyBuffer(staging_handle);
return gpu_handle;
}
BufferHandle Graphics::CreateIndexBuffer(gsl::span<std::uint32_t> indices) {
VkDeviceSize size = sizeof(std::uint32_t) * indices.size();
BufferHandle staging_handle =
CreateBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
void* data;
vkMapMemory(logical_device_, staging_handle.memory, 0, size, 0, &data);
std::memcpy(data, indices.data(), size);
vkUnmapMemory(logical_device_, staging_handle.memory);
BufferHandle gpu_handle = CreateBuffer(
size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkCommandBuffer transient_commands = BeginTransientCommandBuffer();
VkBufferCopy copy_info = {};
copy_info.srcOffset = 0;
copy_info.dstOffset = 0;
copy_info.size = size;
vkCmdCopyBuffer(transient_commands, staging_handle.buffer, gpu_handle.buffer,
1, &copy_info);
EndTransientCommandBuffer(transient_commands);
DestroyBuffer(staging_handle);
return gpu_handle;
}
void Graphics::DestroyBuffer(BufferHandle handle) {
vkDeviceWaitIdle(logical_device_);
vkDestroyBuffer(logical_device_, handle.buffer, nullptr);
vkFreeMemory(logical_device_, handle.memory, nullptr);
}
void Graphics::SetModelMatrix(glm::mat4 model) {
// for (Frame& frame : frames_)
vkCmdPushConstants(frames_[current_frame_].command_buffer, pipeline_layout_,
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &model);
}
void Graphics::SetViewProjection(glm::mat4 view, glm::mat4 projection) {
UniformTransformations transformations{view, projection};
for (Frame& frame : frames_)
std::memcpy(frame.uniform_buffer_location, &transformations,
sizeof(UniformTransformations));
}
void Graphics::RenderBuffer(BufferHandle handle, std::uint32_t vertex_count) {
VkDeviceSize offset = 0;
vkCmdBindDescriptorSets(frames_[current_frame_].command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_, 0,
1, &frames_[current_frame_].uniform_set, 0, nullptr);
vkCmdBindVertexBuffers(frames_[current_frame_].command_buffer, 0, 1,
&handle.buffer, &offset);
vkCmdDraw(frames_[current_frame_].command_buffer, vertex_count, 1, 0, 0);
}
void Graphics::RenderIndexedBuffer(BufferHandle vertex_buffer,
BufferHandle index_buffer,
std::uint32_t count) {
VkDeviceSize offset = 0;
vkCmdBindDescriptorSets(frames_[current_frame_].command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_, 0,
1, &frames_[current_frame_].uniform_set, 0, nullptr);
vkCmdBindVertexBuffers(frames_[current_frame_].command_buffer, 0, 1,
&vertex_buffer.buffer, &offset);
vkCmdBindIndexBuffer(frames_[current_frame_].command_buffer,
index_buffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(frames_[current_frame_].command_buffer, count, 1, 0, 0, 0);
SetModelMatrix(glm::mat4(1.f));
}
void Graphics::RenderModel(Model* model) {
if (!model->visible) return;
SetTexture(model->material.texture_handle);
SetModelMatrix(model->transform);
RenderIndexedBuffer(model->vertex_buffer, model->index_buffer,
model->indices.size());
}
VkCommandBuffer Graphics::BeginTransientCommandBuffer() {
VkCommandBufferAllocateInfo allocation_info = {};
allocation_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocation_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocation_info.commandPool = command_pool_;
allocation_info.commandBufferCount = 1;
VkCommandBuffer buffer;
vkAllocateCommandBuffers(logical_device_, &allocation_info, &buffer);
VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(buffer, &begin_info);
return buffer;
}
void Graphics::EndTransientCommandBuffer(VkCommandBuffer command_buffer) {
vkEndCommandBuffer(command_buffer);
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer;
vkQueueSubmit(graphics_queue_, 1, &submit_info, VK_NULL_HANDLE);
vkQueueWaitIdle(graphics_queue_);
vkFreeCommandBuffers(logical_device_, command_pool_, 1, &command_buffer);
}
void Graphics::CreateUniformBuffers() {
VkDeviceSize buffer_size = sizeof(UniformTransformations);
for (Frame& frame : frames_) {
frame.uniform_buffer =
CreateBuffer(buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vkMapMemory(logical_device_, frame.uniform_buffer.memory, 0, buffer_size, 0,
&frame.uniform_buffer_location);
}
}
void Graphics::CreateDescriptorSetLayouts() {
VkDescriptorSetLayoutBinding uniform_layout_binding = {};
uniform_layout_binding.binding = 0;
uniform_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uniform_layout_binding.descriptorCount = 1;
uniform_layout_binding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
VkDescriptorSetLayoutCreateInfo uniform_layout_info = {};
uniform_layout_info.sType =
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
uniform_layout_info.bindingCount = 1;
uniform_layout_info.pBindings = &uniform_layout_binding;
if (vkCreateDescriptorSetLayout(logical_device_, &uniform_layout_info,
nullptr,
&uniform_set_layout_) != VK_SUCCESS) {
std::exit(EXIT_FAILURE);
}
VkDescriptorSetLayoutBinding texture_layout_binding = {};
texture_layout_binding.binding = 0;
texture_layout_binding.descriptorType =
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
texture_layout_binding.descriptorCount = 1;
texture_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo texture_layout_info = {};
texture_layout_info.sType =
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
texture_layout_info.bindingCount = 1;
texture_layout_info.pBindings = &texture_layout_binding;
if (vkCreateDescriptorSetLayout(logical_device_, &texture_layout_info,
nullptr,
&texture_set_layout_) != VK_SUCCESS) {
std::exit(EXIT_FAILURE);
}
}
void Graphics::CreateDescriptorPools() {
VkDescriptorPoolSize uniform_pool_size = {};
uniform_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uniform_pool_size.descriptorCount = MAX_BUFFERED_FRAMES;
VkDescriptorPoolCreateInfo uniform_create_info = {};
uniform_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
uniform_create_info.poolSizeCount = 1;
uniform_create_info.pPoolSizes = &uniform_pool_size;
uniform_create_info.maxSets = MAX_BUFFERED_FRAMES;
if (vkCreateDescriptorPool(logical_device_, &uniform_create_info, nullptr,
&uniform_pool_) != VK_SUCCESS) {
std::exit(EXIT_FAILURE);
}
VkPhysicalDeviceProperties properties = {};
vkGetPhysicalDeviceProperties(physical_device_, &properties);
VkDescriptorPoolSize texture_pool_size = {};
texture_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
texture_pool_size.descriptorCount =
properties.limits.maxSamplerAllocationCount;
VkDescriptorPoolCreateInfo texture_create_info = {};
texture_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
texture_create_info.poolSizeCount = 1;
texture_create_info.pPoolSizes = &texture_pool_size;
texture_create_info.maxSets = properties.limits.maxSamplerAllocationCount;
texture_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
if (vkCreateDescriptorPool(logical_device_, &texture_create_info, nullptr,
&texture_pool_) != VK_SUCCESS) {
std::exit(EXIT_FAILURE);
}
}
void Graphics::CreateDescriptorSets() {
for (Frame& frame : frames_) {
VkDescriptorSetAllocateInfo set_info = {};
set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
set_info.descriptorPool = uniform_pool_;
set_info.descriptorSetCount = 1;
set_info.pSetLayouts = &uniform_set_layout_;
VkResult result = vkAllocateDescriptorSets(logical_device_, &set_info,
&frame.uniform_set);
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
VkDescriptorBufferInfo buffer_info = {};
buffer_info.buffer = frame.uniform_buffer.buffer;
buffer_info.offset = 0;
buffer_info.range = sizeof(UniformTransformations);
VkWriteDescriptorSet descriptor_write = {};
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write.dstSet = frame.uniform_set;
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.descriptorCount = 1;
descriptor_write.pBufferInfo = &buffer_info;
vkUpdateDescriptorSets(logical_device_, 1, &descriptor_write, 0, nullptr);
}
}
} // namespace veng