Add texture handler
Added functionality to load images as textures and bind them to meshes.
This commit is contained in:
1 parent
0e040dd0d5
commit
4fcda01ba2
24 files changed
+897
-200
No files matched your search
@@ -115,9 +115,4 @@ size_t get_instances_count(uint16_t mesh_id)
|
||||
size_t get_vertex_offset(uint16_t mesh_id)
|
||||
{
|
||||
return g_meshes[mesh_id].vertex_data.buffer_offset;
|
||||
}
|
||||
|
||||
VkDrawIndexedIndirectCommand get_index_data_buffer(uint16_t mesh_id)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "mesh_controller.h"
|
||||
#include "vulkan_commons.h"
|
||||
#include "rse_vulkan_image.h"
|
||||
|
||||
#include "rse_math.h"
|
||||
|
||||
@@ -43,14 +44,14 @@ uint8_t rse_graphics_run(void)
|
||||
return -1;
|
||||
|
||||
// FIXME: Temporary array of vertices, for testing purposes
|
||||
struct rse_vertex_t 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}}};
|
||||
struct rse_vertex_t vertices2[] = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 1.0f}},
|
||||
{{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 0.0f}}};
|
||||
struct rse_vertex_t vertices[] = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
|
||||
{{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, 0.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}};
|
||||
struct rse_vertex_t vertices2[] = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
|
||||
{{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 0.0f}, {1.0f, 1.0f}}};
|
||||
|
||||
// FIXME: Temporary array of vertices, for testing purposes
|
||||
uint16_t indices[] = {0, 1, 2, 2, 3, 0};
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
#include "rse_vulkan_commands.h"
|
||||
|
||||
#include "vulkan_errors.h"
|
||||
#include "locale_vulkan.h"
|
||||
#include "utilities/logger.h"
|
||||
|
||||
VkCommandPool g_command_pool = VK_NULL_HANDLE;
|
||||
|
||||
/**
|
||||
* @brief Create Command Pools
|
||||
*
|
||||
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
||||
* VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED
|
||||
*/
|
||||
static uint8_t create_command_pools()
|
||||
{
|
||||
VkCommandPoolCreateInfo create_info;
|
||||
|
||||
create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
create_info.pNext = NULL;
|
||||
create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
create_info.queueFamilyIndex = g_vulkan_state.queue_family_indices[0]; /* TODO: Change when more families are needed */
|
||||
|
||||
if (VK_SUCCESS != vkCreateCommandPool(g_vulkan_state.device, &create_info, NULL, &g_command_pool)) {
|
||||
LOGF(vulkan_error_messages[VULKAN_COMMAND_POOL_CREATION_FAILED]);
|
||||
return VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
static uint8_t allocate_command_buffers()
|
||||
{
|
||||
VkCommandBufferAllocateInfo allocate_info;
|
||||
|
||||
/* Allocate memory for command buffers */
|
||||
allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocate_info.pNext = NULL;
|
||||
allocate_info.commandPool = g_command_pool;
|
||||
allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; /* TODO: When needed, add secondary command buffer */
|
||||
allocate_info.commandBufferCount = SWAP_BUFFER_COUNT;
|
||||
|
||||
if (VK_SUCCESS != vkAllocateCommandBuffers(g_vulkan_state.device,
|
||||
&allocate_info,
|
||||
g_vulkan_state.command_buffers)) {
|
||||
LOGF(vulkan_error_messages[VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED]);
|
||||
return VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED;
|
||||
}
|
||||
return VULKAN_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
VkCommandBuffer rse_begin_single_time_command()
|
||||
{
|
||||
VkCommandBuffer command_buffer = VK_NULL_HANDLE;
|
||||
VkCommandBufferBeginInfo begin_info = {};
|
||||
VkCommandBufferAllocateInfo alloc_info = {};
|
||||
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
alloc_info.pNext = NULL;
|
||||
alloc_info.commandPool = g_command_pool;
|
||||
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
alloc_info.commandBufferCount = 1;
|
||||
|
||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
begin_info.pNext = NULL;
|
||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
begin_info.pInheritanceInfo = NULL;
|
||||
|
||||
vkAllocateCommandBuffers(g_vulkan_state.device, &alloc_info, &command_buffer);
|
||||
vkBeginCommandBuffer(command_buffer, &begin_info);
|
||||
|
||||
return command_buffer;
|
||||
}
|
||||
|
||||
void rse_end_single_time_comands(VkCommandBuffer command_buffer)
|
||||
{
|
||||
VkSubmitInfo submit_info = {};
|
||||
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.pNext = NULL;
|
||||
submit_info.waitSemaphoreCount = 0;
|
||||
submit_info.pWaitSemaphores = NULL;
|
||||
submit_info.pWaitDstStageMask = NULL;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &command_buffer;
|
||||
submit_info.signalSemaphoreCount = 0;
|
||||
submit_info.pSignalSemaphores = NULL;
|
||||
|
||||
vkEndCommandBuffer(command_buffer);
|
||||
|
||||
vkQueueSubmit(g_vulkan_state.graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(g_vulkan_state.graphics_queue);
|
||||
|
||||
vkFreeCommandBuffers(g_vulkan_state.device, g_command_pool, 1, &command_buffer);
|
||||
}
|
||||
|
||||
uint8_t init_commands()
|
||||
{
|
||||
uint8_t status = VULKAN_ERROR_NO_ERROR;
|
||||
STATUS_CHECK(create_command_pools());
|
||||
STATUS_CHECK(allocate_command_buffers());
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void destroy_commands()
|
||||
{
|
||||
vkDestroyCommandPool(g_vulkan_state.device, g_command_pool, NULL);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file rse_vulkan_commands.h
|
||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||
* @brief Vukan Commands allocation and execution
|
||||
* @version 0.1
|
||||
* @date 2023-09-29
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RSE_VULKAN_COMMANDS_H
|
||||
#define RSE_VULKAN_COMMANDS_H
|
||||
|
||||
#include "vulkan_commons.h"
|
||||
#include "vk_mem_alloc.h"
|
||||
|
||||
uint8_t init_commands();
|
||||
void destroy_commands();
|
||||
|
||||
VkCommandBuffer rse_begin_single_time_command();
|
||||
void rse_end_single_time_comands(VkCommandBuffer command_buffer);
|
||||
|
||||
#endif /* RSE_VULKAN_COMMANDS_H */
|
||||
@@ -0,0 +1,332 @@
|
||||
#include "rse_vulkan_image.h"
|
||||
|
||||
#include "utilities/file_utils.h"
|
||||
#include "utilities/logger.h"
|
||||
#include "locale_vulkan.h"
|
||||
#include "vulkan_errors.h"
|
||||
#include "rse_vulkan_commands.h"
|
||||
#include "vulkan_buffers.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
#include "vma/vk_mem_alloc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define IMAGE_TAKEN 1U
|
||||
#define IMAGE_FREE 0U
|
||||
|
||||
/**
|
||||
* @brief Wrapper for Vulkan buffer. Holds allocation data;
|
||||
*
|
||||
*/
|
||||
struct rse_vulkan_image_t
|
||||
{
|
||||
uint8_t id_taken;
|
||||
size_t allocated_size;
|
||||
VkImage image;
|
||||
VkImageView image_view;
|
||||
VmaAllocation allocation;
|
||||
VmaAllocationInfo allocation_info;
|
||||
};
|
||||
|
||||
/* For now we will only have one image view per image */
|
||||
extern struct rse_vulkan_state_t g_vulkan_state;
|
||||
|
||||
struct rse_vulkan_image_t g_texture_images[RSE_MAX_IMAGE_COUNT];
|
||||
VkSampler g_sampler;
|
||||
|
||||
static uint8_t create_sampler()
|
||||
{
|
||||
VkSamplerCreateInfo create_info = {0};
|
||||
|
||||
create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
create_info.pNext = NULL;
|
||||
create_info.flags = 0U;
|
||||
create_info.magFilter = VK_FILTER_LINEAR;
|
||||
create_info.minFilter = VK_FILTER_LINEAR;
|
||||
create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
create_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
create_info.mipLodBias = 0.0f;
|
||||
create_info.anisotropyEnable = VK_FALSE; // TODO: Enable this
|
||||
create_info.maxAnisotropy = 1.0f;
|
||||
create_info.compareEnable = VK_FALSE;
|
||||
create_info.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
create_info.minLod = 0.0f;
|
||||
create_info.maxLod = 0.0f;
|
||||
create_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||
create_info.unnormalizedCoordinates = VK_FALSE;
|
||||
|
||||
if (VK_SUCCESS != vkCreateSampler(g_vulkan_state.device,
|
||||
&create_info,
|
||||
NULL,
|
||||
&g_sampler)) {
|
||||
LOGF("Failed to create image view");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return VULKAN_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static VkDeviceSize format_to_pixel_size(VkFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
return 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGE("Failed translate vulkan format to pixel width");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat format, unsigned char* pixels)
|
||||
{
|
||||
struct rse_vulkan_buffer_t staging_buffer = {0};
|
||||
VkDeviceSize staging_buffer_size = 0U;
|
||||
VkImageCreateInfo image_info = {0};
|
||||
VmaAllocationCreateInfo alloc_create_info = {0};
|
||||
VkImageSubresourceRange range = {0};
|
||||
VkImageMemoryBarrier image_barrier = {0};
|
||||
VkCommandBuffer command_buffer = {0};
|
||||
VkBufferImageCopy copy_region = {0};
|
||||
VkExtent3D image_extent = {0};
|
||||
VkImageViewCreateInfo image_view_create_info = {0};
|
||||
struct rse_vulkan_image_t* free_texture_image = NULL;
|
||||
size_t i = 0U;
|
||||
|
||||
while(free_texture_image == NULL || i > RSE_MAX_IMAGE_COUNT) {
|
||||
if(g_texture_images[i].id_taken == IMAGE_FREE) {
|
||||
free_texture_image = &g_texture_images[i];
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we found free image handle */
|
||||
if (free_texture_image == NULL) {
|
||||
LOGE("Failed to find free texture image handle");
|
||||
return 1;
|
||||
}
|
||||
|
||||
staging_buffer_size = width * height * format_to_pixel_size(format);
|
||||
|
||||
image_extent.width = width;
|
||||
image_extent.height = height;
|
||||
image_extent.depth = 1U;
|
||||
|
||||
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
image_info.pNext = NULL;
|
||||
image_info.flags = 0U;
|
||||
image_info.imageType = VK_IMAGE_TYPE_2D;
|
||||
image_info.format = format;
|
||||
image_info.extent = image_extent;
|
||||
image_info.mipLevels = 1U;
|
||||
image_info.arrayLayers = 1U;
|
||||
image_info.samples = VK_SAMPLE_COUNT_1_BIT; //TODO: Enable multisampling
|
||||
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
image_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; //TODO: Change if used by more than one queue family
|
||||
image_info.queueFamilyIndexCount = 0U;
|
||||
image_info.pQueueFamilyIndices = NULL;
|
||||
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
alloc_create_info.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
|
||||
alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO;
|
||||
alloc_create_info.requiredFlags = 0U;
|
||||
alloc_create_info.preferredFlags = 0U;
|
||||
alloc_create_info.memoryTypeBits = 0U;
|
||||
alloc_create_info.pool = NULL;
|
||||
alloc_create_info.pUserData = NULL;
|
||||
alloc_create_info.priority = 1.0f;
|
||||
|
||||
if (VK_SUCCESS != vmaCreateImage(g_vulkan_state.allocator,
|
||||
&image_info,
|
||||
&alloc_create_info,
|
||||
&free_texture_image->image,
|
||||
&free_texture_image->allocation,
|
||||
&free_texture_image->allocation_info)) {
|
||||
LOGF("Failed to create image");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Put image into correct layout to copy pixels from buffer to image memory */
|
||||
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
range.baseMipLevel = 0;
|
||||
range.levelCount = 1;
|
||||
range.baseArrayLayer = 0;
|
||||
range.layerCount = 1;
|
||||
|
||||
image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
image_barrier.pNext = NULL;
|
||||
image_barrier.srcAccessMask = 0U;
|
||||
image_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
image_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
image_barrier.srcQueueFamilyIndex = 0U;
|
||||
image_barrier.dstQueueFamilyIndex = 0U;
|
||||
image_barrier.image = free_texture_image->image;
|
||||
image_barrier.subresourceRange = range;
|
||||
|
||||
command_buffer = rse_begin_single_time_command();
|
||||
vkCmdPipelineBarrier(command_buffer,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
1,
|
||||
&image_barrier);
|
||||
rse_end_single_time_comands(command_buffer);
|
||||
|
||||
/* Copy pixel data to GPU memory */
|
||||
if (VK_SUCCESS != create_buffer(staging_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(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
|
||||
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
||||
}
|
||||
|
||||
memcpy(staging_buffer.allocation_info.pMappedData, pixels, staging_buffer_size);
|
||||
|
||||
copy_region.bufferOffset = 0U;
|
||||
copy_region.bufferRowLength = 0U;
|
||||
copy_region.bufferImageHeight = 0U;
|
||||
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_region.imageSubresource.mipLevel = 0U;
|
||||
copy_region.imageSubresource.baseArrayLayer = 0U;
|
||||
copy_region.imageSubresource.layerCount = 1U;
|
||||
copy_region.imageOffset.x = 0;
|
||||
copy_region.imageOffset.y = 0;
|
||||
copy_region.imageOffset.z = 0;
|
||||
copy_region.imageExtent = image_extent;
|
||||
|
||||
command_buffer = rse_begin_single_time_command();
|
||||
vkCmdCopyBufferToImage(command_buffer,
|
||||
staging_buffer.buffer,
|
||||
free_texture_image->image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1,
|
||||
©_region);
|
||||
rse_end_single_time_comands(command_buffer);
|
||||
destroy_buffer(&staging_buffer);
|
||||
|
||||
/* Change image layout for shaders to be able to read it */
|
||||
image_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
image_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
image_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
command_buffer = rse_begin_single_time_command();
|
||||
vkCmdPipelineBarrier(command_buffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
1,
|
||||
&image_barrier);
|
||||
rse_end_single_time_comands(command_buffer);
|
||||
|
||||
/* Fill image view */
|
||||
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
image_view_create_info.pNext = NULL;
|
||||
image_view_create_info.flags = 0U;
|
||||
image_view_create_info.image = free_texture_image->image;
|
||||
image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
image_view_create_info.format = format;
|
||||
// image_view_create_info.components = 0;
|
||||
image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
image_view_create_info.subresourceRange.baseMipLevel = 0;
|
||||
image_view_create_info.subresourceRange.levelCount = 1;
|
||||
image_view_create_info.subresourceRange.baseArrayLayer = 0;
|
||||
image_view_create_info.subresourceRange.layerCount = 1;
|
||||
|
||||
if (VK_SUCCESS != vkCreateImageView(g_vulkan_state.device,
|
||||
&image_view_create_info,
|
||||
NULL,
|
||||
&free_texture_image->image_view)) {
|
||||
LOGF("Failed to create image view");
|
||||
return 1;
|
||||
}
|
||||
|
||||
free_texture_image->id_taken = IMAGE_TAKEN;
|
||||
return VULKAN_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
uint8_t init_vulkan_images()
|
||||
{
|
||||
uint8_t status = VULKAN_ERROR_NO_ERROR;
|
||||
|
||||
// memset(g_texture_images, 0, sizeof(struct rse_vulkan_image_t) * RSE_MAX_IMAGE_COUNT);
|
||||
|
||||
STATUS_CHECK(create_sampler());
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void rse_load_texture(const char* file_path)
|
||||
{
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int channels = 0;
|
||||
stbi_uc* pixel_buffer = NULL;
|
||||
|
||||
|
||||
pixel_buffer = stbi_load(file_path, &width, &height, &channels, STBI_rgb_alpha);
|
||||
|
||||
if (pixel_buffer == NULL) {
|
||||
LOGE("Failed to load texture from file: %s", file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create actual Vulkan Image */
|
||||
create_vulkan_image(width,
|
||||
height,
|
||||
VK_FORMAT_R8G8B8A8_SRGB,
|
||||
pixel_buffer);
|
||||
|
||||
stbi_image_free(pixel_buffer);
|
||||
|
||||
}
|
||||
|
||||
void rse_destroy_textures()
|
||||
{
|
||||
size_t i = 0U;
|
||||
|
||||
vkDestroySampler(g_vulkan_state.device, g_sampler, NULL);
|
||||
|
||||
for (i = 0U; i < RSE_MAX_IMAGE_COUNT; ++i) {
|
||||
if (g_texture_images[i].id_taken == IMAGE_TAKEN) {
|
||||
vkDestroyImageView(g_vulkan_state.device, g_texture_images[i].image_view, NULL);
|
||||
vmaDestroyImage(g_vulkan_state.allocator, g_texture_images[i].image, g_texture_images[i].allocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VkImageView rse_get_image_view(size_t image_id)
|
||||
{
|
||||
return g_texture_images[image_id].image_view;
|
||||
}
|
||||
|
||||
VkSampler rse_get_texture_sampler()
|
||||
{
|
||||
return g_sampler;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file rse_vulkan_image.h
|
||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||
* @brief Library for loading and handling textures
|
||||
* @version 0.1
|
||||
* @date 2023-09-27
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RSE_TEXTURE_H
|
||||
#define RSE_TEXTURE_H
|
||||
|
||||
#include "utilities/file_utils.h"
|
||||
#include "vulkan_commons.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define RSE_MAX_IMAGE_COUNT 256
|
||||
|
||||
uint8_t init_vulkan_images(void);
|
||||
|
||||
void rse_load_texture(const char* path);
|
||||
|
||||
void rse_destroy_textures(void);
|
||||
|
||||
VkImageView rse_get_image_view(size_t image_id);
|
||||
|
||||
VkSampler rse_get_texture_sampler();
|
||||
|
||||
#endif /* RSE_TEXTURE_H */
|
||||
@@ -31,9 +31,11 @@
|
||||
#include "window.h"
|
||||
|
||||
#include "vulkan_commons.h"
|
||||
#include "rse_vulkan_commands.h"
|
||||
#include "vulkan_buffers.h"
|
||||
#include "vulkan_descriptors.h"
|
||||
#include "vulkan_pipeline.h"
|
||||
#include "rse_vulkan_image.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
@@ -564,12 +566,22 @@ uint8_t init_vulkan()
|
||||
|
||||
STATUS_CHECK(create_pipeline());
|
||||
|
||||
STATUS_CHECK(init_commands());
|
||||
|
||||
STATUS_CHECK(create_buffers());
|
||||
|
||||
|
||||
STATUS_CHECK(init_vulkan_images());
|
||||
|
||||
//FIXME: Images have to be add after vulkan initialization but before creating descriptors.
|
||||
// I have to fix it somehow to be able to add textures from anywhere in the code in some initialization step
|
||||
// at the beginnning.
|
||||
rse_load_texture("../../miotacz_piorunów.png");
|
||||
STATUS_CHECK(create_descriptors());
|
||||
|
||||
STATUS_CHECK(create_sync_objects());
|
||||
|
||||
|
||||
rse_init_time();
|
||||
return status;
|
||||
}
|
||||
@@ -657,6 +669,10 @@ void deinit_vulkan()
|
||||
vkDestroyFence(g_vulkan_state.device, g_in_flight_fences[i], NULL);
|
||||
}
|
||||
|
||||
rse_destroy_textures();
|
||||
|
||||
destroy_commands();
|
||||
|
||||
destroy_pipeline();
|
||||
|
||||
vmaDestroyAllocator(g_vulkan_state.allocator);
|
||||
|
||||
+48
-143
@@ -5,6 +5,7 @@
|
||||
#include "utilities/logger.h"
|
||||
#include "mesh_controller.h"
|
||||
#include "rse_math.h"
|
||||
#include "rse_vulkan_commands.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@@ -19,141 +20,28 @@ struct rse_vulkan_buffer_t g_index_buffer;
|
||||
struct rse_vulkan_buffer_t g_instance_buffers[MAX_MESH_NUMBER];
|
||||
struct rse_vulkan_buffer_t g_draw_indirect_command_buffer;
|
||||
|
||||
VkCommandPool g_command_pool = VK_NULL_HANDLE;
|
||||
|
||||
/**
|
||||
* @brief Helper function. Creates a buffer object
|
||||
*
|
||||
* @param size Size of the target buffer
|
||||
* @param buffer_usage Buffer usage flags
|
||||
* @param memory_usage memory usage flags (mostly VMA_MEMORY_USAGE_AUTO)
|
||||
* @param allocation_flags 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
|
||||
*/
|
||||
static uint8_t create_buffer(const VkDeviceSize size,
|
||||
VkBufferUsageFlags buffer_usage,
|
||||
VmaMemoryUsage memory_usage,
|
||||
const VmaAllocationCreateFlags allocation_flags,
|
||||
struct rse_vulkan_buffer_t* buffer)
|
||||
{
|
||||
VkBufferCreateInfo vertex_buffer_info = {};
|
||||
VmaAllocationCreateInfo create_info = {};
|
||||
|
||||
vertex_buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
vertex_buffer_info.pNext = NULL;
|
||||
vertex_buffer_info.flags = 0U;
|
||||
vertex_buffer_info.size = size;
|
||||
vertex_buffer_info.usage = buffer_usage;
|
||||
vertex_buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
vertex_buffer_info.queueFamilyIndexCount = 0U;
|
||||
vertex_buffer_info.pQueueFamilyIndices = NULL;
|
||||
|
||||
create_info.flags = allocation_flags;
|
||||
create_info.usage = memory_usage;
|
||||
create_info.memoryTypeBits = 0U;
|
||||
create_info.requiredFlags = 0U;
|
||||
create_info.preferredFlags = 0U;
|
||||
create_info.pool = VK_NULL_HANDLE;
|
||||
create_info.pUserData = VK_NULL_HANDLE;
|
||||
create_info.priority = 0.0f;
|
||||
|
||||
if (VK_SUCCESS != vmaCreateBuffer(g_vulkan_state.allocator,
|
||||
&vertex_buffer_info,
|
||||
&create_info,
|
||||
&buffer->buffer,
|
||||
&buffer->allocation,
|
||||
&buffer->allocation_info)) {
|
||||
LOGF(vulkan_error_messages[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:
|
||||
*/
|
||||
static uint8_t copy_buffer(VkBuffer src, VkBuffer dst, VkDeviceSize size, VkDeviceSize dest_offset)
|
||||
static void copy_buffer(VkBuffer src, VkBuffer dst, VkDeviceSize size, VkDeviceSize dest_offset)
|
||||
{
|
||||
/* Vulkan buffers can only be copied using command buffers */
|
||||
VkResult status = VK_FALSE;
|
||||
VkBufferCopy copy_region = {};
|
||||
VkSubmitInfo submit_info = {};
|
||||
VkCommandBuffer copy_command_buffer = NULL;
|
||||
VkCommandBufferBeginInfo begin_info = {};
|
||||
VkCommandBufferAllocateInfo alloc_info = {};
|
||||
VkCommandBuffer command_buffer = {0};
|
||||
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
alloc_info.pNext = NULL;
|
||||
alloc_info.commandPool = g_command_pool;
|
||||
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
alloc_info.commandBufferCount = 1;
|
||||
command_buffer = rse_begin_single_time_command();
|
||||
|
||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
begin_info.pNext = NULL;
|
||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
begin_info.pInheritanceInfo = NULL;
|
||||
|
||||
copy_region.srcOffset = 0;
|
||||
copy_region.srcOffset = 0U;
|
||||
copy_region.dstOffset = dest_offset;
|
||||
copy_region.size = size;
|
||||
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.pNext = NULL;
|
||||
submit_info.waitSemaphoreCount = 0;
|
||||
submit_info.pWaitSemaphores = NULL;
|
||||
submit_info.pWaitDstStageMask = NULL;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = ©_command_buffer;
|
||||
submit_info.signalSemaphoreCount = 0;
|
||||
submit_info.pSignalSemaphores = NULL;
|
||||
vkCmdCopyBuffer(command_buffer, src, dst, 1, ©_region);
|
||||
|
||||
// FIXME: Add result checks
|
||||
status = vkAllocateCommandBuffers(g_vulkan_state.device, &alloc_info, ©_command_buffer);
|
||||
status = vkBeginCommandBuffer(copy_command_buffer, &begin_info);
|
||||
vkCmdCopyBuffer(copy_command_buffer, src, dst, 1, ©_region);
|
||||
status = vkEndCommandBuffer(copy_command_buffer);
|
||||
status = vkQueueSubmit(g_vulkan_state.graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||
/* TODO: Use fences to wait instead of idle */
|
||||
status = vkQueueWaitIdle(g_vulkan_state.graphics_queue);
|
||||
vkFreeCommandBuffers(g_vulkan_state.device, g_command_pool, 1, ©_command_buffer);
|
||||
|
||||
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
|
||||
*/
|
||||
static uint8_t create_command_pools()
|
||||
{
|
||||
VkCommandPoolCreateInfo create_info;
|
||||
|
||||
create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
create_info.pNext = NULL;
|
||||
create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
create_info.queueFamilyIndex = g_vulkan_state.queue_family_indices[0]; /* TODO: Change when more families are needed */
|
||||
|
||||
if (VK_SUCCESS != vkCreateCommandPool(g_vulkan_state.device, &create_info, NULL, &g_command_pool)) {
|
||||
LOGF(vulkan_error_messages[VULKAN_COMMAND_POOL_CREATION_FAILED]);
|
||||
return VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED;
|
||||
}
|
||||
|
||||
return VULKAN_ERROR_NO_ERROR;
|
||||
rse_end_single_time_comands(command_buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -262,32 +150,52 @@ static uint8_t create_uniform_buffer()
|
||||
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
|
||||
*/
|
||||
static uint8_t allocate_command_buffers()
|
||||
uint8_t create_buffer(const VkDeviceSize size,
|
||||
VkBufferUsageFlags buffer_usage,
|
||||
VmaMemoryUsage memory_usage,
|
||||
const VmaAllocationCreateFlags allocation_flags,
|
||||
struct rse_vulkan_buffer_t* buffer)
|
||||
{
|
||||
VkCommandBufferAllocateInfo allocate_info;
|
||||
VkBufferCreateInfo vertex_buffer_info = {};
|
||||
VmaAllocationCreateInfo create_info = {};
|
||||
|
||||
/* Allocate memory for command buffers */
|
||||
allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocate_info.pNext = NULL;
|
||||
allocate_info.commandPool = g_command_pool;
|
||||
allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; /* TODO: When needed, add secondary command buffer */
|
||||
allocate_info.commandBufferCount = SWAP_BUFFER_COUNT;
|
||||
vertex_buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
vertex_buffer_info.pNext = NULL;
|
||||
vertex_buffer_info.flags = 0U;
|
||||
vertex_buffer_info.size = size;
|
||||
vertex_buffer_info.usage = buffer_usage;
|
||||
vertex_buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
vertex_buffer_info.queueFamilyIndexCount = 0U;
|
||||
vertex_buffer_info.pQueueFamilyIndices = NULL;
|
||||
|
||||
if (VK_SUCCESS != vkAllocateCommandBuffers(g_vulkan_state.device,
|
||||
&allocate_info,
|
||||
g_vulkan_state.command_buffers)) {
|
||||
LOGF(vulkan_error_messages[VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED]);
|
||||
return VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED;
|
||||
create_info.flags = allocation_flags;
|
||||
create_info.usage = memory_usage;
|
||||
create_info.memoryTypeBits = 0U;
|
||||
create_info.requiredFlags = 0U;
|
||||
create_info.preferredFlags = 0U;
|
||||
create_info.pool = VK_NULL_HANDLE;
|
||||
create_info.pUserData = VK_NULL_HANDLE;
|
||||
create_info.priority = 0.0f;
|
||||
|
||||
if (VK_SUCCESS != vmaCreateBuffer(g_vulkan_state.allocator,
|
||||
&vertex_buffer_info,
|
||||
&create_info,
|
||||
&buffer->buffer,
|
||||
&buffer->allocation,
|
||||
&buffer->allocation_info)) {
|
||||
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
|
||||
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
||||
}
|
||||
|
||||
return VULKAN_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
void destroy_buffer(struct rse_vulkan_buffer_t* buffer)
|
||||
{
|
||||
vmaDestroyBuffer(g_vulkan_state.allocator, buffer->buffer, buffer->allocation);
|
||||
}
|
||||
|
||||
|
||||
void update_uniform_buffers()
|
||||
{
|
||||
struct rse_uniform_buffer_object_t ubo = {};
|
||||
@@ -492,14 +400,12 @@ uint8_t record_command_buffer(uint32_t image_index)
|
||||
|
||||
uint8_t create_buffers()
|
||||
{
|
||||
uint8_t status = VULKAN_ERROR_NO_ERROR;\
|
||||
uint8_t status = VULKAN_ERROR_NO_ERROR;
|
||||
|
||||
STATUS_CHECK(create_command_pools());
|
||||
STATUS_CHECK(create_vertex_buffer());
|
||||
STATUS_CHECK(create_index_buffer());
|
||||
STATUS_CHECK(create_instance_buffers());
|
||||
STATUS_CHECK(create_uniform_buffer());
|
||||
STATUS_CHECK(allocate_command_buffers());
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -509,6 +415,7 @@ void reset_command_buffer()
|
||||
vkResetCommandBuffer(g_vulkan_state.command_buffers[g_vulkan_state.current_frame], /*VkCommandBufferResetFlagBits*/ 0);
|
||||
}
|
||||
|
||||
|
||||
void destroy_buffers()
|
||||
{
|
||||
size_t i = 0U;
|
||||
@@ -526,6 +433,4 @@ void destroy_buffers()
|
||||
for(i = 0; i < MAX_MESH_NUMBER; ++i) {
|
||||
vmaDestroyBuffer(g_vulkan_state.allocator, g_instance_buffers[i].buffer, g_instance_buffers[i].allocation);
|
||||
}
|
||||
|
||||
vkDestroyCommandPool(g_vulkan_state.device, g_command_pool, NULL);
|
||||
}
|
||||
@@ -78,4 +78,30 @@ void reset_command_buffer();
|
||||
*/
|
||||
void destroy_buffers();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper function. Creates a buffer object
|
||||
*
|
||||
* @param size Size of the target buffer
|
||||
* @param buffer_usage Buffer usage flags
|
||||
* @param memory_usage memory usage flags (mostly VMA_MEMORY_USAGE_AUTO)
|
||||
* @param allocation_flags 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 create_buffer(const VkDeviceSize size,
|
||||
VkBufferUsageFlags buffer_usage,
|
||||
VmaMemoryUsage memory_usage,
|
||||
const VmaAllocationCreateFlags allocation_flags,
|
||||
struct rse_vulkan_buffer_t* buffer);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destroy provided buffer
|
||||
*
|
||||
* @param buffer buffer to destroy
|
||||
*/
|
||||
void destroy_buffer(struct rse_vulkan_buffer_t* buffer);
|
||||
|
||||
#endif /* RSE_VULKAN_BUFFERS_H */
|
||||
@@ -30,6 +30,7 @@ struct rse_vertex_t
|
||||
{
|
||||
struct vec3_t pos;
|
||||
struct vec3_t color;
|
||||
struct vec3_t tex_coords;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "utilities/logger.h"
|
||||
#include "vulkan_errors.h"
|
||||
#include "vulkan_commons.h"
|
||||
#include "rse_vulkan_image.h"
|
||||
|
||||
#include "vulkan/vulkan.h"
|
||||
|
||||
@@ -20,15 +21,18 @@ static uint8_t create_descriptor_sets();
|
||||
*/
|
||||
uint8_t create_descriptor_pool()
|
||||
{
|
||||
VkDescriptorPoolSize pool_size = {};
|
||||
VkDescriptorPoolSize pool_sizes[2] = {};
|
||||
VkDescriptorPoolCreateInfo pool_info = {};
|
||||
|
||||
pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
pool_size.descriptorCount = (uint32_t)(SWAP_BUFFER_COUNT);
|
||||
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
pool_sizes[0].descriptorCount = (uint32_t)(SWAP_BUFFER_COUNT);
|
||||
|
||||
pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
pool_sizes[1].descriptorCount = (uint32_t)(SWAP_BUFFER_COUNT);
|
||||
|
||||
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
pool_info.poolSizeCount = 1;
|
||||
pool_info.pPoolSizes = &pool_size;
|
||||
pool_info.poolSizeCount = 2;
|
||||
pool_info.pPoolSizes = pool_sizes;
|
||||
|
||||
pool_info.maxSets = (uint32_t)(SWAP_BUFFER_COUNT);
|
||||
if (vkCreateDescriptorPool(g_vulkan_state.device, &pool_info, NULL, &gDescriptorPool) != VK_SUCCESS) {
|
||||
@@ -64,21 +68,34 @@ uint8_t create_descriptor_sets()
|
||||
|
||||
for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) {
|
||||
VkDescriptorBufferInfo buffer_info = {};
|
||||
VkWriteDescriptorSet descriptor_write = {};
|
||||
VkWriteDescriptorSet descriptor_writes[2] = {};
|
||||
VkDescriptorImageInfo image_info = {};
|
||||
|
||||
buffer_info.buffer = g_vulkan_state.uniform_buffers[i].buffer;
|
||||
buffer_info.offset = 0;
|
||||
buffer_info.range = sizeof(struct rse_uniform_buffer_object_t);
|
||||
|
||||
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptor_write.dstSet = g_vulkan_state.descriptor_sets[i];
|
||||
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;
|
||||
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
image_info.imageView = rse_get_image_view(0);
|
||||
image_info.sampler = rse_get_texture_sampler();
|
||||
|
||||
vkUpdateDescriptorSets(g_vulkan_state.device, 1, &descriptor_write, 0, NULL);
|
||||
descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptor_writes[0].dstSet = g_vulkan_state.descriptor_sets[i];
|
||||
descriptor_writes[0].dstBinding = 0;
|
||||
descriptor_writes[0].dstArrayElement = 0;
|
||||
descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
descriptor_writes[0].descriptorCount = 1;
|
||||
descriptor_writes[0].pBufferInfo = &buffer_info;
|
||||
|
||||
descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptor_writes[1].dstSet = g_vulkan_state.descriptor_sets[i];
|
||||
descriptor_writes[1].dstBinding = 1;
|
||||
descriptor_writes[1].dstArrayElement = 0;
|
||||
descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptor_writes[1].descriptorCount = 1;
|
||||
descriptor_writes[1].pImageInfo = &image_info;
|
||||
|
||||
vkUpdateDescriptorSets(g_vulkan_state.device, 2, descriptor_writes, 0, NULL);
|
||||
}
|
||||
|
||||
return VULKAN_ERROR_NO_ERROR;
|
||||
|
||||
@@ -72,7 +72,7 @@ static VkVertexInputBindingDescription get_binding_description()
|
||||
|
||||
static VkVertexInputAttributeDescription* get_attribute_descriptions()
|
||||
{
|
||||
static VkVertexInputAttributeDescription attributeDescriptions[2];
|
||||
static VkVertexInputAttributeDescription attributeDescriptions[3];
|
||||
|
||||
attributeDescriptions[0].binding = 0;
|
||||
attributeDescriptions[0].location = 0; /* inPosition in shader.vert */
|
||||
@@ -84,6 +84,11 @@ static VkVertexInputAttributeDescription* get_attribute_descriptions()
|
||||
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
attributeDescriptions[1].offset = offsetof(struct rse_vertex_t, color);
|
||||
|
||||
attributeDescriptions[2].binding = 0;
|
||||
attributeDescriptions[2].location = 2; /* inTexCoords in shader.vert */
|
||||
attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
|
||||
attributeDescriptions[2].offset = offsetof(struct rse_vertex_t, tex_coords);
|
||||
|
||||
return attributeDescriptions;
|
||||
}
|
||||
|
||||
@@ -258,7 +263,9 @@ uint8_t create_render_pass()
|
||||
uint8_t create_descriptor_set_layout()
|
||||
{
|
||||
VkDescriptorSetLayoutCreateInfo layout_info = {};
|
||||
VkDescriptorSetLayoutBinding bindings[2];
|
||||
VkDescriptorSetLayoutBinding ubo_layout_binding = {};
|
||||
VkDescriptorSetLayoutBinding sampler_layout_binding = {};
|
||||
|
||||
ubo_layout_binding.binding = 0;
|
||||
ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
@@ -266,11 +273,19 @@ uint8_t create_descriptor_set_layout()
|
||||
ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
ubo_layout_binding.pImmutableSamplers = NULL;
|
||||
|
||||
sampler_layout_binding.binding = 1;
|
||||
sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
sampler_layout_binding.descriptorCount = 1;
|
||||
sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
sampler_layout_binding.pImmutableSamplers = NULL;
|
||||
|
||||
bindings[0] = ubo_layout_binding;
|
||||
bindings[1] = sampler_layout_binding;
|
||||
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
layout_info.pNext = NULL;
|
||||
layout_info.flags = 0U;
|
||||
layout_info.bindingCount = 1U;
|
||||
layout_info.pBindings = &ubo_layout_binding;
|
||||
layout_info.bindingCount = 2U;
|
||||
layout_info.pBindings = bindings;
|
||||
|
||||
if (vkCreateDescriptorSetLayout(g_vulkan_state.device, &layout_info, NULL, &g_vulkan_state.descriptor_set_layout) != VK_SUCCESS) {
|
||||
LOGF(vulkan_error_messages[VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED]);
|
||||
@@ -440,22 +455,22 @@ void cleanup_swapchain()
|
||||
static uint8_t fill_shader_stages(VkPipelineShaderStageCreateInfo* shader_stages)
|
||||
{
|
||||
char* buffer;
|
||||
size_t buffer_size;
|
||||
long buffer_size;
|
||||
VkShaderModule vertex_shader_module;
|
||||
VkShaderModule fragments_shader_module;
|
||||
VkPipelineShaderStageCreateInfo vert_shader_stage_info = {};
|
||||
VkPipelineShaderStageCreateInfo frag_shader_stage_info = {};
|
||||
|
||||
read_file(g_shader_paths[VERTEX], &buffer_size, NULL);
|
||||
rse_read_file(g_shader_paths[VERTEX], &buffer_size, NULL);
|
||||
buffer = malloc(buffer_size);
|
||||
read_file(g_shader_paths[VERTEX], &buffer_size, buffer);
|
||||
rse_read_file(g_shader_paths[VERTEX], &buffer_size, buffer);
|
||||
|
||||
vertex_shader_module = create_shader_module(buffer, buffer_size);
|
||||
free(buffer);
|
||||
|
||||
read_file(g_shader_paths[FRAGMENTS], &buffer_size, NULL);
|
||||
rse_read_file(g_shader_paths[FRAGMENTS], &buffer_size, NULL);
|
||||
buffer = malloc(buffer_size);
|
||||
read_file(g_shader_paths[FRAGMENTS], &buffer_size, buffer);
|
||||
rse_read_file(g_shader_paths[FRAGMENTS], &buffer_size, buffer);
|
||||
|
||||
fragments_shader_module = create_shader_module(buffer, buffer_size);
|
||||
free(buffer);
|
||||
@@ -539,7 +554,7 @@ void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_i
|
||||
VkVertexInputBindingDescription vertex_binding_description = get_binding_description();
|
||||
VkVertexInputAttributeDescription* vertex_attribute_descriptions = get_attribute_descriptions();
|
||||
VkVertexInputBindingDescription* bindingDescriptions = malloc(sizeof(VkVertexInputBindingDescription) * 2);
|
||||
VkVertexInputAttributeDescription* attributeDescriptions = malloc(sizeof(VkVertexInputAttributeDescription) * 5);
|
||||
VkVertexInputAttributeDescription* attributeDescriptions = malloc(sizeof(VkVertexInputAttributeDescription) * 6);
|
||||
|
||||
bindingDescriptions[0] = vertex_binding_description;
|
||||
|
||||
@@ -547,22 +562,22 @@ void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_i
|
||||
bindingDescriptions[1].stride = sizeof(struct rse_instance_data_t); //TODO: change
|
||||
bindingDescriptions[1].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
|
||||
|
||||
memcpy(attributeDescriptions, vertex_attribute_descriptions, sizeof(VkVertexInputAttributeDescription) * 2);
|
||||
|
||||
attributeDescriptions[2].binding = 1;
|
||||
attributeDescriptions[2].location = 2;
|
||||
attributeDescriptions[2].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
attributeDescriptions[2].offset = offsetof(struct rse_instance_data_t, pos);
|
||||
memcpy(attributeDescriptions, vertex_attribute_descriptions, sizeof(VkVertexInputAttributeDescription) * 3);
|
||||
|
||||
attributeDescriptions[3].binding = 1;
|
||||
attributeDescriptions[3].location = 3;
|
||||
attributeDescriptions[3].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
attributeDescriptions[3].offset = offsetof(struct rse_instance_data_t, rot);
|
||||
attributeDescriptions[3].offset = offsetof(struct rse_instance_data_t, pos);
|
||||
|
||||
attributeDescriptions[4].binding = 1;
|
||||
attributeDescriptions[4].location = 4;
|
||||
attributeDescriptions[4].format = VK_FORMAT_R32_SFLOAT;
|
||||
attributeDescriptions[4].offset = offsetof(struct rse_instance_data_t, scale);
|
||||
attributeDescriptions[4].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
attributeDescriptions[4].offset = offsetof(struct rse_instance_data_t, rot);
|
||||
|
||||
attributeDescriptions[5].binding = 1;
|
||||
attributeDescriptions[5].location = 5;
|
||||
attributeDescriptions[5].format = VK_FORMAT_R32_SFLOAT;
|
||||
attributeDescriptions[5].offset = offsetof(struct rse_instance_data_t, scale);
|
||||
// ************************
|
||||
|
||||
vertex_input_info->sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
@@ -571,7 +586,7 @@ void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_i
|
||||
|
||||
vertex_input_info->vertexBindingDescriptionCount = 2U;
|
||||
vertex_input_info->pVertexBindingDescriptions = bindingDescriptions;
|
||||
vertex_input_info->vertexAttributeDescriptionCount = 5U;
|
||||
vertex_input_info->vertexAttributeDescriptionCount = 6U;
|
||||
vertex_input_info->pVertexAttributeDescriptions = attributeDescriptions;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user