Enables creation of multiple mesh objects in a single buffer. This is still WIP.
513 lines
20 KiB
C++
513 lines
20 KiB
C++
#include "vulkan_buffers.hpp"
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
#define GLM_FORCE_RADIANS
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
#include "vulkan_errors.hpp"
|
|
#include "locale_vulkan.hpp"
|
|
#include "utilities/logger.hpp"
|
|
#include "mesh_controller.hpp"
|
|
|
|
namespace rse::graphics::vulkanbase
|
|
{
|
|
|
|
#define MAX_VERTEX_BUFFER_SIZE 33554432 /* 32 MB*/
|
|
|
|
using namespace locale::vulkan;
|
|
|
|
// // FIXME: Temporary array of vertices, for testing purposes
|
|
// const std::vector<Vertex> vertices = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 1.0f}},
|
|
// {{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 1.0f}},
|
|
// {{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}},
|
|
// {{-0.5f, 0.5f, 0.0f}, {1.0f, 0.0f, 1.0f}}};
|
|
|
|
// // FIXME: Temporary array of vertices, for testing purposes
|
|
// std::vector<uint16_t> indices = {0, 1, 2, 2, 3, 0};
|
|
|
|
/* GPU visible buffer */
|
|
std::vector<Buffer> gVertexBuffers = {};
|
|
std::vector<Buffer> gIndexBuffers = {};
|
|
std::vector<Buffer> gInstanceBuffers = {};
|
|
/* CPU visible buffer. TODO: Do we need this global? */
|
|
|
|
VkCommandPool gCommandPool = VK_NULL_HANDLE;
|
|
|
|
|
|
static uint8_t createBuffer(VulkanState& vulkan_state, const VkDeviceSize size, VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage,
|
|
const VmaAllocationCreateFlags allocationFlags, Buffer& buffer);
|
|
static uint8_t copyBuffer(VulkanState& vulkan_state, VkBuffer src, VkBuffer dst, VkDeviceSize size, VkDeviceSize dest_offset = 0);
|
|
|
|
static uint8_t createCommandPools(VulkanState& vulkan_state);
|
|
static uint8_t createVertexBuffer(VulkanState& vulkan_state);
|
|
static uint8_t createIndexBuffer(VulkanState& vulkan_state);
|
|
static uint8_t createUniformBuffers(VulkanState& vulkan_state);
|
|
static uint8_t allocateCommandBuffers(VulkanState& vulkan_state);
|
|
|
|
/**
|
|
* @brief Helper function. Creates a buffer object
|
|
*
|
|
* @param size Size of the target buffer
|
|
* @param bufferUsage Buffer usage flags
|
|
* @param memoryUsage memory usage flags (mostly VMA_MEMORY_USAGE_AUTO)
|
|
* @param allocationFlags VMA allocation flags
|
|
* @param buffer Buffer, that will be allocated
|
|
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
|
* VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED
|
|
*/
|
|
uint8_t createBuffer(VulkanState& vulkan_state, const VkDeviceSize size, VkBufferUsageFlags bufferUsage,
|
|
VmaMemoryUsage memoryUsage, const VmaAllocationCreateFlags allocationFlags, Buffer& buffer)
|
|
{
|
|
VkBufferCreateInfo vertexBufferInfo;
|
|
VmaAllocationCreateInfo createInfo;
|
|
|
|
vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
vertexBufferInfo.pNext = nullptr;
|
|
vertexBufferInfo.flags = 0U;
|
|
vertexBufferInfo.size = size;
|
|
vertexBufferInfo.usage = bufferUsage;
|
|
vertexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
vertexBufferInfo.queueFamilyIndexCount = 0U;
|
|
vertexBufferInfo.pQueueFamilyIndices = nullptr;
|
|
|
|
/* Disalows random access to memory. TODO: Consider changing to VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT? */
|
|
createInfo.flags = allocationFlags;
|
|
createInfo.usage = memoryUsage;
|
|
createInfo.memoryTypeBits = 0U;
|
|
createInfo.requiredFlags = 0U;
|
|
createInfo.preferredFlags = 0U;
|
|
createInfo.pool = VK_NULL_HANDLE;
|
|
createInfo.pUserData = VK_NULL_HANDLE;
|
|
createInfo.priority = 0.0f;
|
|
|
|
if (VK_SUCCESS != vmaCreateBuffer(vulkan_state.allocator, &vertexBufferInfo, &createInfo, &buffer.buffer, &buffer.allocation,
|
|
&buffer.allocationInfo)) {
|
|
LOGF << vulkanErrorMesssages[VULKAN_BUFFER_CREATION_FAILED];
|
|
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
|
}
|
|
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @brief Copy one buffer's data to another
|
|
*
|
|
* @param src Source buffer
|
|
* @param dst Destination buffer
|
|
* @param size Size of buffer to copy
|
|
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
|
*/
|
|
uint8_t copyBuffer(VulkanState& vulkan_state, VkBuffer src, VkBuffer dst, VkDeviceSize size, VkDeviceSize dest_offset)
|
|
{
|
|
/* Vulkan buffers can only be copied using command buffers */
|
|
VkBufferCopy copyRegion;
|
|
VkSubmitInfo submitInfo;
|
|
VkCommandBuffer copyCommandBuffer;
|
|
VkCommandBufferBeginInfo beginInfo;
|
|
VkCommandBufferAllocateInfo allocInfo;
|
|
|
|
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
allocInfo.pNext = nullptr;
|
|
allocInfo.commandPool = gCommandPool;
|
|
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
allocInfo.commandBufferCount = 1;
|
|
|
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
beginInfo.pNext = nullptr;
|
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
beginInfo.pInheritanceInfo = nullptr;
|
|
|
|
copyRegion.srcOffset = 0;
|
|
copyRegion.dstOffset = dest_offset;
|
|
copyRegion.size = size;
|
|
|
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
submitInfo.pNext = nullptr;
|
|
submitInfo.waitSemaphoreCount = 0;
|
|
submitInfo.pWaitSemaphores = nullptr;
|
|
submitInfo.pWaitDstStageMask = nullptr;
|
|
submitInfo.commandBufferCount = 1;
|
|
submitInfo.pCommandBuffers = ©CommandBuffer;
|
|
submitInfo.signalSemaphoreCount = 0;
|
|
submitInfo.pSignalSemaphores = nullptr;
|
|
|
|
// FIXME: At result checks
|
|
VkResult status;
|
|
status = vkAllocateCommandBuffers(vulkan_state.device, &allocInfo, ©CommandBuffer);
|
|
status = vkBeginCommandBuffer(copyCommandBuffer, &beginInfo);
|
|
vkCmdCopyBuffer(copyCommandBuffer, src, dst, 1, ©Region);
|
|
status = vkEndCommandBuffer(copyCommandBuffer);
|
|
status = vkQueueSubmit(vulkan_state.graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
|
/* TODO: Use fences to wait instead of idle */
|
|
status = vkQueueWaitIdle(vulkan_state.graphicsQueue);
|
|
vkFreeCommandBuffers(vulkan_state.device, gCommandPool, 1, ©CommandBuffer);
|
|
|
|
if (status != VK_SUCCESS) {
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief Create Command Pools
|
|
*
|
|
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
|
* VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED
|
|
*/
|
|
uint8_t createCommandPools(VulkanState& vulkan_state)
|
|
{
|
|
VkCommandPoolCreateInfo createInfo;
|
|
|
|
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
createInfo.pNext = nullptr;
|
|
createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
createInfo.queueFamilyIndex = vulkan_state.queueFamilyIndices[0]; /* TODO: Change when more families are needed */
|
|
|
|
if (VK_SUCCESS != vkCreateCommandPool(vulkan_state.device, &createInfo, nullptr, &gCommandPool)) {
|
|
LOGF << vulkanErrorMesssages[VULKAN_COMMAND_POOL_CREATION_FAILED];
|
|
return VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED;
|
|
}
|
|
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Create a buffer holding all vertex data
|
|
*
|
|
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
|
* VULKAN_ERROR_BUFFER_CREATION_FAILED
|
|
* VULKAN_ERROR_VERTEX_BUFFER_MAPPING_FAILED
|
|
*/
|
|
uint8_t createVertexBuffer(VulkanState& vulkan_state)
|
|
{
|
|
VkDeviceSize bufferSize;
|
|
Buffer vertex_buffer;
|
|
|
|
bufferSize = MAX_VERTEX_BUFFER_SIZE;
|
|
|
|
/* Create Vertex Buffer*/
|
|
if (VK_SUCCESS != createBuffer(vulkan_state, bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0, /* Will not be mapped with vmaMapMemory */
|
|
vertex_buffer)) {
|
|
LOGF << vulkanErrorMesssages[VULKAN_BUFFER_CREATION_FAILED];
|
|
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
|
}
|
|
|
|
vertex_buffer.allocated_size = 0;
|
|
gVertexBuffers.push_back(std::move(vertex_buffer));
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @brief Create an index buffer, connected with vertex buffer
|
|
*
|
|
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
|
* VULKAN_ERROR_BUFFER_CREATION_FAILED
|
|
*/
|
|
uint8_t createIndexBuffer(VulkanState& vulkan_state)
|
|
{
|
|
VkDeviceSize bufferSize;
|
|
Buffer index_buffer;
|
|
|
|
bufferSize = MAX_VERTEX_BUFFER_SIZE;
|
|
|
|
/* Create Index Buffer*/
|
|
if (VK_SUCCESS != createBuffer(vulkan_state, bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0, /* Will not be mapped with vmaMapMemory */
|
|
index_buffer)) {
|
|
LOGF << vulkanErrorMesssages[VULKAN_BUFFER_CREATION_FAILED];
|
|
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
|
}
|
|
|
|
index_buffer.allocated_size = 0;
|
|
gIndexBuffers.push_back(std::move(index_buffer));
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
uint8_t createInstanceBuffer(VulkanState& vulkan_state)
|
|
{
|
|
VkDeviceSize bufferSize;
|
|
Buffer instance_buffer;
|
|
|
|
|
|
bufferSize = MAX_VERTEX_BUFFER_SIZE;
|
|
|
|
/* Create Instance Buffer*/
|
|
if (VK_SUCCESS != createBuffer(vulkan_state, bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0, /* Will not be mapped with vmaMapMemory */
|
|
instance_buffer)) {
|
|
LOGF << vulkanErrorMesssages[VULKAN_BUFFER_CREATION_FAILED];
|
|
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
|
}
|
|
|
|
instance_buffer.allocated_size = 0;
|
|
|
|
gInstanceBuffers.push_back(std::move(instance_buffer));
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief Create a Uniform Buffers
|
|
*
|
|
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
|
*/
|
|
uint8_t createUniformBuffers(VulkanState& vulkan_state)
|
|
{
|
|
VkDeviceSize bufferSize = sizeof(UniformBufferObject);
|
|
|
|
vulkan_state.uniformBuffers.resize(SWAP_BUFFER_COUNT);
|
|
|
|
for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) {
|
|
createBuffer(vulkan_state, bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
|
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
|
vulkan_state.uniformBuffers[i]);
|
|
}
|
|
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @brief Allocate Command Buffers
|
|
*
|
|
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
|
* VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED
|
|
*/
|
|
uint8_t allocateCommandBuffers(VulkanState& vulkan_state)
|
|
{
|
|
VkCommandBufferAllocateInfo allocateInfo;
|
|
|
|
/* Allocate memory for command buffers */
|
|
vulkan_state.pCommandBuffers.resize(SWAP_BUFFER_COUNT);
|
|
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
allocateInfo.pNext = nullptr;
|
|
allocateInfo.commandPool = gCommandPool;
|
|
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; /* TODO: When needed, add secondary command buffer */
|
|
allocateInfo.commandBufferCount = SWAP_BUFFER_COUNT;
|
|
|
|
if (VK_SUCCESS != vkAllocateCommandBuffers(vulkan_state.device,
|
|
&allocateInfo,
|
|
vulkan_state.pCommandBuffers.data())) {
|
|
LOGF << vulkanErrorMesssages[VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED];
|
|
return VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED;
|
|
}
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @brief Update uniform buffers
|
|
*
|
|
* @param currentImage Current image index
|
|
*/
|
|
void updateUniformBuffer(VulkanState& vulkan_state)
|
|
{
|
|
UniformBufferObject ubo{};
|
|
// ubo.model = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 0.0f, 0.0f)) * glm::rotate(glm::mat4(1.0f), glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f)) * glm::scale(glm::mat4(1.0f), glm::vec3(2, 1, 1));
|
|
ubo.model = glm::mat4(1.0f);
|
|
ubo.view = glm::lookAt(glm::vec3(0.0f, 0.0f, 5.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
|
|
ubo.proj = glm::perspective(glm::radians(45.0f),
|
|
vulkan_state.swapchainExtent.width / (float)vulkan_state.swapchainExtent.height,
|
|
0.1f,
|
|
20.0f);
|
|
ubo.proj[1][1] *= -1; /* GLM was developed for OpenGL, where Y coordinate of the clip is inverted */
|
|
memcpy(vulkan_state.uniformBuffers[vulkan_state.currentFrame].allocationInfo.pMappedData, &ubo, sizeof(ubo));
|
|
}
|
|
|
|
uint8_t update_mesh_buffers(VulkanState& vulkan_state,
|
|
const std::vector<rse::graphics::vulkanbase::Vertex>& vertices,
|
|
const std::vector<uint16_t>& indices)
|
|
{
|
|
// void* mapped_data;
|
|
Buffer staging_buffer;
|
|
auto vertices_size = sizeof(vertices[0]) * vertices.size();
|
|
auto indices_size = sizeof(indices[0]) * indices.size();
|
|
|
|
auto last_vertex_buffer = &gVertexBuffers[gVertexBuffers.size() - 1];
|
|
auto last_index_buffer = &gIndexBuffers[gIndexBuffers.size() - 1];
|
|
|
|
/* Creating staging buffer*/
|
|
if (VK_SUCCESS != createBuffer(vulkan_state,
|
|
MAX_VERTEX_BUFFER_SIZE,
|
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
|
VMA_ALLOCATION_CREATE_MAPPED_BIT
|
|
| VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
|
staging_buffer)) {
|
|
LOGF << vulkanErrorMesssages[VULKAN_BUFFER_CREATION_FAILED];
|
|
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
|
}
|
|
|
|
/* Fill staging buffer with vertex data */
|
|
memset(staging_buffer.allocationInfo.pMappedData, 0, MAX_VERTEX_BUFFER_SIZE);
|
|
memcpy(staging_buffer.allocationInfo.pMappedData, vertices.data(), vertices_size);
|
|
copyBuffer(vulkan_state,
|
|
staging_buffer.buffer,
|
|
last_vertex_buffer->buffer,
|
|
vertices_size,
|
|
last_vertex_buffer->allocated_size);
|
|
|
|
/* Fill staging buffer with index data */
|
|
memset(staging_buffer.allocationInfo.pMappedData, 0, MAX_VERTEX_BUFFER_SIZE);
|
|
memcpy(staging_buffer.allocationInfo.pMappedData, indices.data(), indices_size);
|
|
copyBuffer(vulkan_state,
|
|
staging_buffer.buffer,
|
|
last_index_buffer->buffer,
|
|
indices_size,
|
|
last_index_buffer->allocated_size);
|
|
|
|
vmaDestroyBuffer(vulkan_state.allocator, staging_buffer.buffer, staging_buffer.allocation);
|
|
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
uint8_t update_mesh_instances(VulkanState& vulkan_state,
|
|
rse::graphics::mesh::InstanceData& instance_data)
|
|
{
|
|
Buffer staging_buffer;
|
|
|
|
auto last_instance_buffer = &gInstanceBuffers[gInstanceBuffers.size() - 1];
|
|
auto instance_size = sizeof(instance_data);
|
|
|
|
/* Creating staging buffer*/
|
|
if (VK_SUCCESS != createBuffer(vulkan_state,
|
|
MAX_VERTEX_BUFFER_SIZE,
|
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
|
VMA_ALLOCATION_CREATE_MAPPED_BIT
|
|
| VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
|
staging_buffer)) {
|
|
LOGF << vulkanErrorMesssages[VULKAN_BUFFER_CREATION_FAILED];
|
|
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
|
}
|
|
|
|
memcpy(staging_buffer.allocationInfo.pMappedData, &instance_data, instance_size);
|
|
copyBuffer(vulkan_state,
|
|
staging_buffer.buffer,
|
|
last_instance_buffer->buffer,
|
|
instance_size,
|
|
last_instance_buffer->allocated_size);
|
|
|
|
vmaDestroyBuffer(vulkan_state.allocator, staging_buffer.buffer, staging_buffer.allocation);
|
|
|
|
last_instance_buffer->allocated_size += instance_size;
|
|
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @brief Records commands for provided command buffer
|
|
*
|
|
* @param commandBuffer Command buffer, that will hold commands
|
|
* @param imageIndex Image index
|
|
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
|
* VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED
|
|
*/
|
|
uint8_t recordCommandBuffer(VulkanState& vulkan_state, uint32_t imageIndex)
|
|
{
|
|
VkCommandBuffer commandBuffer = vulkan_state.pCommandBuffers[vulkan_state.currentFrame];
|
|
VkCommandBufferBeginInfo beginInfo{};
|
|
VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
|
VkRenderPassBeginInfo renderPassInfo{};
|
|
VkViewport viewport{};
|
|
VkRect2D scissor{};
|
|
VkDeviceSize offsets[] = {0};
|
|
|
|
auto indices = rse::graphics::mesh::get_mesh_indices(0);
|
|
auto instances = rse::graphics::mesh::get_instance_data_for_mesh(0);
|
|
|
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
beginInfo.flags = 0;
|
|
beginInfo.pInheritanceInfo = nullptr;
|
|
|
|
if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {
|
|
LOGF << vulkanErrorMesssages[VULKAN_RECORD_COMMAND_BEGIN_FAILED];
|
|
return VULKAN_ERROR_RECORD_COMMAND_BEGIN_FAILED;
|
|
}
|
|
|
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
|
renderPassInfo.renderPass = vulkan_state.renderPass;
|
|
renderPassInfo.framebuffer = vulkan_state.swapchainFramebuffers[imageIndex];
|
|
renderPassInfo.renderArea.offset = {0, 0};
|
|
renderPassInfo.renderArea.extent = vulkan_state.swapchainExtent;
|
|
renderPassInfo.clearValueCount = 1;
|
|
renderPassInfo.pClearValues = &clearColor;
|
|
|
|
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_state.graphicsPipeline);
|
|
|
|
viewport.x = 0.0f;
|
|
viewport.y = 0.0f;
|
|
viewport.width = static_cast<float>(vulkan_state.swapchainExtent.width);
|
|
viewport.height = static_cast<float>(vulkan_state.swapchainExtent.height);
|
|
viewport.minDepth = 0.0f;
|
|
viewport.maxDepth = 1.0f;
|
|
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
|
|
|
scissor.offset = {0, 0};
|
|
scissor.extent = vulkan_state.swapchainExtent;
|
|
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
|
|
|
for (size_t i = 0; i < gVertexBuffers.size(); ++i) {
|
|
VkBuffer vertexBuffers[] = {gVertexBuffers[i].buffer};
|
|
VkBuffer indexBuffer = {gIndexBuffers[i].buffer};
|
|
VkBuffer instanceBuffers[] = {gInstanceBuffers[i].buffer};
|
|
|
|
/* TODO: Figure out the offset */
|
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
|
|
vkCmdBindVertexBuffers(commandBuffer, 1, 1, instanceBuffers, offsets);
|
|
vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT16);
|
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_state.pipelineLayout, 0, 1,
|
|
&vulkan_state.descriptorSets[vulkan_state.currentFrame], 0, nullptr);
|
|
|
|
vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(indices.size()), instances.size(), 0, 0, 0);
|
|
}
|
|
|
|
vkCmdEndRenderPass(commandBuffer);
|
|
|
|
if (VK_SUCCESS != vkEndCommandBuffer(commandBuffer)) {
|
|
LOGF << vulkanErrorMesssages[VULKAN_RECORD_COMMAND_BUFFER_FAILED];
|
|
return VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED;
|
|
}
|
|
|
|
return VULKAN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
uint8_t create_buffers(VulkanState& vulkan_state)
|
|
{
|
|
uint8_t status = VULKAN_ERROR_NO_ERROR;\
|
|
|
|
STATUS_CHECK(createCommandPools(vulkan_state));
|
|
STATUS_CHECK(createVertexBuffer(vulkan_state));
|
|
STATUS_CHECK(createIndexBuffer(vulkan_state));
|
|
STATUS_CHECK(createInstanceBuffer(vulkan_state));
|
|
STATUS_CHECK(createUniformBuffers(vulkan_state));
|
|
STATUS_CHECK(allocateCommandBuffers(vulkan_state));
|
|
|
|
return status;
|
|
}
|
|
|
|
void reset_command_buffer(VulkanState& vulkan_state)
|
|
{
|
|
vkResetCommandBuffer(vulkan_state.pCommandBuffers[vulkan_state.currentFrame], /*VkCommandBufferResetFlagBits*/ 0);
|
|
}
|
|
|
|
void destroy_buffers(VulkanState& vulkan_state)
|
|
{
|
|
for (size_t i = 0; i < SWAP_BUFFER_COUNT; ++i) {
|
|
vmaDestroyBuffer(vulkan_state.allocator, vulkan_state.uniformBuffers[i].buffer, vulkan_state.uniformBuffers[i].allocation);
|
|
}
|
|
|
|
for (size_t i = 0; i < gVertexBuffers.size(); ++i) {
|
|
vmaDestroyBuffer(vulkan_state.allocator, gVertexBuffers[i].buffer, gVertexBuffers[i].allocation);
|
|
vmaDestroyBuffer(vulkan_state.allocator, gIndexBuffers[i].buffer, gIndexBuffers[i].allocation);
|
|
vmaDestroyBuffer(vulkan_state.allocator, gInstanceBuffers[i].buffer, gInstanceBuffers[i].allocation);
|
|
}
|
|
vkDestroyCommandPool(vulkan_state.device, gCommandPool, nullptr);
|
|
}
|
|
|
|
} |