Add texture handler

Added functionality to load images as textures and bind them to meshes.
This commit is contained in:
Piotr Krygier committed 2023-10-02 13:21:17 +02:00
1 parent 0e040dd0d5
commit 4fcda01ba2
24 files changed
+897 -200

No files matched your search

+1 -1
View File
@@ -28,7 +28,7 @@ set(CMAKE_C_STANDARD 23)# turn on the dynamic depends for ninja
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
add_subdirectory(red_scarf_engine)
+3
View File
@@ -0,0 +1,3 @@
set(STB_DIR "${PROJECT_SOURCE_DIR}/third_party/stb/")
set(stb_INCLUDE_DIR "${STB_DIR}/")
+4
View File
@@ -15,3 +15,7 @@ tag = v3.0.1
git_url = https://github.com/Snaipe/Criterion.git
tag = v2.4.2
custom_commands = cd Criterion && meson build && cd build && ninja
[stb]
git_url = https://github.com/nothings/stb.git
tag = master
+4
View File
@@ -1,6 +1,7 @@
find_package(Vulkan REQUIRED)
find_package(vma REQUIRED)
find_package(glfw3 REQUIRED)
find_package(stb REQUIRED)
find_package(Vulkan COMPONENTS glslc)
find_program(glslc_executable NAMES glslc HINTS ${Vulkan_GLSLC_EXECUTABLE}/..)
@@ -42,6 +43,7 @@ ${CMAKE_SOURCE_DIR}
${Vulkan_INCLUDE_DIR}
${vma_INCLUDE_DIR}
${glfw3_INCLUDE_DIR}
${stb_INCLUDE_DIR}
)
target_sources(rse_graphics PRIVATE
@@ -49,12 +51,14 @@ src/vma_port.cpp
src/window.c
src/vulkan_base.c
src/vulkan_pipeline.c
src/rse_vulkan_commands.c
src/vulkan_buffers.c
src/vulkan_descriptors.c
src/rse_graphics.c
src/rse_math.c
src/mesh_controller.c
src/vulkan_commons.c
src/rse_vulkan_image.c
)
target_link_libraries(rse_graphics PRIVATE
+5 -1
View File
@@ -1,8 +1,12 @@
#version 450
layout(binding = 1) uniform sampler2D texSampler;
layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(fragColor, 1.0);
outColor = texture(texSampler, fragTexCoord);
}
+6 -3
View File
@@ -8,12 +8,14 @@ layout(binding = 0) uniform UniformBufferObject {
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTexCoord;
layout(location = 2) in vec3 instancePosition;
layout(location = 3) in vec3 instanceRotation;
layout(location = 4) in float instanceScale;
layout(location = 3) in vec3 instancePosition;
layout(location = 4) in vec3 instanceRotation;
layout(location = 5) in float instanceScale;
layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTexCoord;
void main()
{
@@ -59,4 +61,5 @@ void main()
gl_Position = ubo.proj * ubo.view * ubo.model * pos;
fragColor = inColor;
fragTexCoord = inTexCoord;
}
-5
View File
@@ -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)
{
}
+9 -8
View File
@@ -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};
+115
View File
@@ -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);
}
+24
View File
@@ -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 */
+332
View File
@@ -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,
&copy_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;
}
+33
View File
@@ -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 */
+16
View File
@@ -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
View File
@@ -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 = &copy_command_buffer;
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = NULL;
vkCmdCopyBuffer(command_buffer, src, dst, 1, &copy_region);
// FIXME: Add result checks
status = vkAllocateCommandBuffers(g_vulkan_state.device, &alloc_info, &copy_command_buffer);
status = vkBeginCommandBuffer(copy_command_buffer, &begin_info);
vkCmdCopyBuffer(copy_command_buffer, src, dst, 1, &copy_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, &copy_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);
}
+26
View File
@@ -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 */
+1
View File
@@ -30,6 +30,7 @@ struct rse_vertex_t
{
struct vec3_t pos;
struct vec3_t color;
struct vec3_t tex_coords;
};
/**
+31 -14
View File
@@ -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;
+34 -19
View File
@@ -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;
}
+4 -2
View File
@@ -1,6 +1,7 @@
#include "graphics/rse_graphics.h"
#include "utilities/rse_task.h"
int main(int argc, char** argv)
{
rse_thread_t graphics_task;
@@ -10,7 +11,8 @@ int main(int argc, char** argv)
rse_graphics_init();
rse_create_task(&graphics_task, (thread_worker_t)rse_graphics_run, NULL);
rse_task_join(&graphics_task);
rse_task_exit(); //TODO: Figure out why program is so much faster if we don't join the graphics_task. WTF.
rse_task_exit();
}
+1 -1
View File
@@ -1,7 +1,7 @@
find_package(Criterion)
add_executable(tests
src/rse_math_tests.c)
src/rse_graphics_tests.c)
target_include_directories(tests PRIVATE
${criterion_INCLUDE_DIR}
+186
View File
@@ -0,0 +1,186 @@
#include "criterion/criterion.h"
#include "graphics/src/rse_math.h"
#include <stdio.h>
#include <math.h>
/*-----------------RSE MATH TEST------------------------*/
TestSuite(rse_math);
Test(rse_math, normalize)
{
float res_x = 0.8017f;
float res_y = 0.2672f;
float res_z = 0.5345f;
struct vec3_t test_vec = {3.0f, 1.0f, 2.0f};
struct vec3_t result = rse_math_normalize_vec3(&test_vec);
cr_expect_float_eq(result.x, res_x, 0.0001, "Expected %f, got %f", res_x, result.x);
cr_expect_float_eq(result.y, res_y, 0.0001, "Expected %f, got %f", res_y, result.y);
cr_expect_float_eq(result.z, res_z, 0.0001, "Expected %f, got %f", res_z, result.z);
}
Test(rse_math, cross)
{
float res_x = -3.0f;
float res_y = 6.0f;
float res_z = -3.0f;
struct vec3_t test_vec1 = {2.0f, 3.0f, 4.0f};
struct vec3_t test_vec2 = {5.0f, 6.0f, 7.0f};
struct vec3_t result = rse_math_cross_vec3(&test_vec1, &test_vec2);
cr_expect_float_eq(result.x, res_x, 0.0001, "Expected %f, got %f", res_x, result.x);
cr_expect_float_eq(result.y, res_y, 0.0001, "Expected %f, got %f", res_y, result.y);
cr_expect_float_eq(result.z, res_z, 0.0001, "Expected %f, got %f", res_z, result.z);
}
Test(rse_math, look_at)
{
struct vec3_t eye;
struct vec3_t center;
struct vec3_t up;
struct mat4_t result;
struct mat4_t expected;
eye.x = 0.0f;
eye.y = 0.0f;
eye.z = 5.0f;
center.x = 0.0f;
center.y = 0.0f;
center.z = 0.0f;
up.x = 0.0f;
up.y = 0.1f;
up.z = 0.0f;
expected.x_1 = 1.0f;
expected.y_1 = 0.0f;
expected.z_1 = 0.0f;
expected.w_1 = 0.0f;
expected.x_2 = 0.0f;
expected.y_2 = 1.0f;
expected.z_2 = 0.0f;
expected.w_2 = 0.0f;
expected.x_3 = 0.0f;
expected.y_3 = 0.0f;
expected.z_3 = 1.0f;
expected.w_3 = 0.0f;
expected.x_4 = 0.0f;
expected.y_4 = 0.0f;
expected.z_4 = -5.0f;
expected.w_4 = 1.0f;
result = rse_math_look_at(&eye, &center, &up);
cr_expect_float_eq(result.x_1, expected.x_1, 0.0001, "Expected x_1 %f, got %f", expected.x_1, result.x_1);
cr_expect_float_eq(result.y_1, expected.y_1, 0.0001, "Expected y_1 %f, got %f", expected.y_1, result.y_1);
cr_expect_float_eq(result.z_1, expected.z_1, 0.0001, "Expected z_1 %f, got %f", expected.z_1, result.z_1);
cr_expect_float_eq(result.w_1, expected.w_1, 0.0001, "Expected w_1 %f, got %f", expected.w_1, result.w_1);
cr_expect_float_eq(result.x_2, expected.x_2, 0.0001, "Expected x_2 %f, got %f", expected.x_2, result.x_2);
cr_expect_float_eq(result.y_2, expected.y_2, 0.0001, "Expected y_2 %f, got %f", expected.y_2, result.y_2);
cr_expect_float_eq(result.z_2, expected.z_2, 0.0001, "Expected z_2 %f, got %f", expected.z_2, result.z_2);
cr_expect_float_eq(result.w_2, expected.w_2, 0.0001, "Expected w_2 %f, got %f", expected.w_2, result.w_2);
cr_expect_float_eq(result.x_3, expected.x_3, 0.0001, "Expected x_3 %f, got %f", expected.x_3, result.x_3);
cr_expect_float_eq(result.y_3, expected.y_3, 0.0001, "Expected y_3 %f, got %f", expected.y_3, result.y_3);
cr_expect_float_eq(result.z_3, expected.z_3, 0.0001, "Expected z_3 %f, got %f", expected.z_3, result.z_3);
cr_expect_float_eq(result.w_3, expected.w_3, 0.0001, "Expected w_3 %f, got %f", expected.w_3, result.w_3);
cr_expect_float_eq(result.x_4, expected.x_4, 0.0001, "Expected x_4 %f, got %f", expected.x_4, result.x_4);
cr_expect_float_eq(result.y_4, expected.y_4, 0.0001, "Expected y_4 %f, got %f", expected.y_4, result.y_4);
cr_expect_float_eq(result.z_4, expected.z_4, 0.0001, "Expected z_4 %f, got %f", expected.z_4, result.z_4);
cr_expect_float_eq(result.w_4, expected.w_4, 0.0001, "Expected w_4 %f, got %f", expected.w_4, result.w_4);
}
Test(rse_math, radians)
{
float degrees;
float radians;
float expected_radians;
degrees = 45.0f;
expected_radians = 0.7853;
radians = rse_math_deg_to_radians(degrees);
cr_expect_float_eq(radians, expected_radians, 0.0001, "Expected %f, got %f", expected_radians, radians);
}
Test(rse_math, perspective)
{
float fovy;
float width;
float height;
float z_near;
float z_far;
struct mat4_t result;
struct mat4_t expected;
fovy = rse_math_deg_to_radians(45.0f);
width = 640.0f;
height = 480.0f;
z_near = 0.1f;
z_far = 20.0f;
expected.x_1 = -1.81066012;
expected.y_1 = 0;
expected.z_1 = 0;
expected.w_1 = 0;
expected.x_2 = 0;
expected.y_2 = 2.41421342;
expected.z_2 = 0;
expected.w_2 = 0;
expected.x_3 = 0;
expected.y_3 = 0;
expected.z_3 = -1.0100503;
expected.w_3 = -1;
expected.x_4 = 0;
expected.y_4 = 0;
expected.z_4 = -0.201005027;
expected.w_4 = 0;
result = rse_math_perspective(fovy, width / height, z_near, z_far);
cr_expect_float_eq(result.x_1, expected.x_1, 0.0001, "Expected x_1 %f, got %f", expected.x_1, result.x_1);
cr_expect_float_eq(result.y_1, expected.y_1, 0.0001, "Expected y_1 %f, got %f", expected.y_1, result.y_1);
cr_expect_float_eq(result.z_1, expected.z_1, 0.0001, "Expected z_1 %f, got %f", expected.z_1, result.z_1);
cr_expect_float_eq(result.w_1, expected.w_1, 0.0001, "Expected w_1 %f, got %f", expected.w_1, result.w_1);
cr_expect_float_eq(result.x_2, expected.x_2, 0.0001, "Expected x_2 %f, got %f", expected.x_2, result.x_2);
cr_expect_float_eq(result.y_2, expected.y_2, 0.0001, "Expected y_2 %f, got %f", expected.y_2, result.y_2);
cr_expect_float_eq(result.z_2, expected.z_2, 0.0001, "Expected z_2 %f, got %f", expected.z_2, result.z_2);
cr_expect_float_eq(result.w_2, expected.w_2, 0.0001, "Expected w_2 %f, got %f", expected.w_2, result.w_2);
cr_expect_float_eq(result.x_3, expected.x_3, 0.0001, "Expected x_3 %f, got %f", expected.x_3, result.x_3);
cr_expect_float_eq(result.y_3, expected.y_3, 0.0001, "Expected y_3 %f, got %f", expected.y_3, result.y_3);
cr_expect_float_eq(result.z_3, expected.z_3, 0.0001, "Expected z_3 %f, got %f", expected.z_3, result.z_3);
cr_expect_float_eq(result.w_3, expected.w_3, 0.0001, "Expected w_3 %f, got %f", expected.w_3, result.w_3);
cr_expect_float_eq(result.x_4, expected.x_4, 0.0001, "Expected x_4 %f, got %f", expected.x_4, result.x_4);
cr_expect_float_eq(result.y_4, expected.y_4, 0.0001, "Expected y_4 %f, got %f", expected.y_4, result.y_4);
cr_expect_float_eq(result.z_4, expected.z_4, 0.0001, "Expected z_4 %f, got %f", expected.z_4, result.z_4);
cr_expect_float_eq(result.w_4, expected.w_4, 0.0001, "Expected w_4 %f, got %f", expected.w_4, result.w_4);
}
/*-----------------RSE TEXTURES TEST------------------------*/
#include "graphics/src/rse_texture.h"
TestSuite(rse_textures);
Test(rse_textures, load_png_image)
{
rse_load_texture("../../miotacz_piorunów.png");
}
+3 -1
View File
@@ -11,7 +11,9 @@
* @param bytes_count Returned bytes count
* @param buffer Returned filled buffer
*/
void read_file(const char* file_path, long* bytes_count, char* buffer);
void rse_read_file(const char* file_path, long* bytes_count, char* buffer);
void rse_write_to_file(const char* file_name, long bytes_count, char* buffer);
#endif /* RSE_FILE_UTILS_H */
+11 -1
View File
@@ -3,7 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
void read_file(const char* file_name, long* bytes_count, char* buffer)
void rse_read_file(const char* file_name, long* bytes_count, char* buffer)
{
FILE* file;
@@ -20,3 +20,13 @@ void read_file(const char* file_name, long* bytes_count, char* buffer)
fread(buffer, *bytes_count, 1, file);
fclose(file);
}
void rse_write_to_file(const char* file_name, long bytes_count, char* buffer)
{
FILE* file;
file = fopen(file_name, "wb");
fwrite(buffer, bytes_count, 1, file);
fclose(file);
}
-1
View File
@@ -7,7 +7,6 @@ const char* log_levels[] = {
void _log_log(unsigned int level, const char* file, int line, const char* fmt, ...)
{
char buf[256];
va_list list;
va_start(list, fmt);