diff --git a/graphics/shaders/shader.frag b/graphics/shaders/shader.frag index f7514858..9784f2dc 100644 --- a/graphics/shaders/shader.frag +++ b/graphics/shaders/shader.frag @@ -1,12 +1,14 @@ #version 450 -layout(binding = 1) uniform sampler2D texSampler; +/* Each time texture count is changed this value also need to change. I have to fix it somehow. */ +layout(binding = 1) uniform sampler2D texSampler[1]; layout(location = 0) in vec3 fragColor; layout(location = 1) in vec2 fragTexCoord; +layout(location = 2) in flat uint instanceTextureId; layout(location = 0) out vec4 outColor; void main() { - outColor = texture(texSampler, fragTexCoord); + outColor = vec4(fragColor * texture(texSampler[instanceTextureId], fragTexCoord).rgb, 1.0); } \ No newline at end of file diff --git a/graphics/shaders/shader.vert b/graphics/shaders/shader.vert index 801de257..9fd5d594 100644 --- a/graphics/shaders/shader.vert +++ b/graphics/shaders/shader.vert @@ -13,9 +13,12 @@ layout(location = 2) in vec2 inTexCoord; layout(location = 3) in vec3 instancePosition; layout(location = 4) in vec3 instanceRotation; layout(location = 5) in float instanceScale; +layout(location = 6) in uint instanceTextureId; layout(location = 0) out vec3 fragColor; layout(location = 1) out vec2 fragTexCoord; +layout(location = 2) out uint outInstanceTextureId; + void main() { @@ -62,4 +65,5 @@ void main() fragColor = inColor; fragTexCoord = inTexCoord; + outInstanceTextureId = instanceTextureId; } \ No newline at end of file diff --git a/graphics/src/rse_graphics.c b/graphics/src/rse_graphics.c index f9ce3b4c..a40ed057 100644 --- a/graphics/src/rse_graphics.c +++ b/graphics/src/rse_graphics.c @@ -38,11 +38,14 @@ void rse_graphics_deinit() uint8_t rse_graphics_run(void) { + int8_t tex_id_2 = 0; window_init(); - if (0 != init_vulkan()) + if (0 != preinit_vulkan()) return -1; + tex_id_2 = rse_load_texture("../../test_image.png"); + // 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}, {1.0f, 0.0f}}, {{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 0.0f}}, @@ -60,22 +63,29 @@ uint8_t rse_graphics_run(void) create_mesh_instance(mesh_id, (struct rse_instance_data_t){ {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, rse_math_deg_to_radians(45.0f)}, - 1.0f + 1.0f, + tex_id_2 }); create_mesh_instance(mesh_id, (struct rse_instance_data_t){ {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, - 1.0f + 1.0f, + tex_id_2 }); mesh_id = create_mesh(vertices2, indices, 8, 6); create_mesh_instance(mesh_id, (struct rse_instance_data_t){ {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, rse_math_deg_to_radians(0.0f)}, - 1.0f + 1.0f, + tex_id_2 }); + + if (0 != init_vulkan()) + return -1; + window_loop(); deinit_vulkan(); diff --git a/graphics/src/rse_vulkan_image.c b/graphics/src/rse_vulkan_image.c index 80265465..de7d1df2 100644 --- a/graphics/src/rse_vulkan_image.c +++ b/graphics/src/rse_vulkan_image.c @@ -90,7 +90,7 @@ static VkDeviceSize format_to_pixel_size(VkFormat format) } -static uint8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat format, unsigned char* pixels) +static int8_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; @@ -116,7 +116,7 @@ static uint8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat for /* Check if we found free image handle */ if (free_texture_image == NULL) { LOGE("Failed to find free texture image handle"); - return 1; + return -1; } staging_buffer_size = width * height * format_to_pixel_size(format); @@ -157,7 +157,7 @@ static uint8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat for &free_texture_image->allocation, &free_texture_image->allocation_info)) { LOGF("Failed to create image"); - return 1; + return -1; } /* Put image into correct layout to copy pixels from buffer to image memory */ @@ -199,7 +199,7 @@ static uint8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat for | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, &staging_buffer)) { LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]); - return VULKAN_ERROR_BUFFER_CREATION_FAILED; + return -1; } memcpy(staging_buffer.allocation_info.pMappedData, pixels, staging_buffer_size); @@ -264,11 +264,11 @@ static uint8_t create_vulkan_image(uint32_t width, uint32_t height, VkFormat for NULL, &free_texture_image->image_view)) { LOGF("Failed to create image view"); - return 1; + return -1; } free_texture_image->id_taken = IMAGE_TAKEN; - return VULKAN_ERROR_NO_ERROR; + return i; } uint8_t init_vulkan_images() @@ -282,29 +282,33 @@ uint8_t init_vulkan_images() return status; } -void rse_load_texture(const char* file_path) +int8_t rse_load_texture(const char* file_path) { int width = 0; int height = 0; int channels = 0; stbi_uc* pixel_buffer = NULL; + int8_t ret; + 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; + return -1; } /* Create actual Vulkan Image */ - create_vulkan_image(width, + ret = create_vulkan_image(width, height, VK_FORMAT_R8G8B8A8_SRGB, pixel_buffer); stbi_image_free(pixel_buffer); + return ret; + } void rse_destroy_textures() @@ -321,6 +325,10 @@ void rse_destroy_textures() } } +int8_t image_exists(uint8_t image_id) { + return g_texture_images[image_id].id_taken == IMAGE_TAKEN; +} + VkImageView rse_get_image_view(size_t image_id) { return g_texture_images[image_id].image_view; @@ -329,4 +337,18 @@ VkImageView rse_get_image_view(size_t image_id) VkSampler rse_get_texture_sampler() { return g_sampler; +} + +size_t get_textures_count() +{ + size_t count = 0U; + size_t i = 0U; + + for (i = 0U; i < RSE_MAX_IMAGE_COUNT; ++i) { + if(g_texture_images[i].id_taken == IMAGE_TAKEN) { + count++; + } + } + + return count; } \ No newline at end of file diff --git a/graphics/src/rse_vulkan_image.h b/graphics/src/rse_vulkan_image.h index f5bc659f..29181de8 100644 --- a/graphics/src/rse_vulkan_image.h +++ b/graphics/src/rse_vulkan_image.h @@ -18,16 +18,61 @@ #include +/** + * @brief Maximum number of textures that can be loaded + * + */ #define RSE_MAX_IMAGE_COUNT 256 +/** + * @brief Initialize vulkan with image views and stuff + * + * @return uint8_t VULKAN_ERROR_NO_ERROR on success + */ uint8_t init_vulkan_images(void); -void rse_load_texture(const char* path); +/** + * @brief Loads image from file, for later to be uysed as a texture + * + * @param path Path to texture file + * @return int8_t -1 on error. Texture ID on success + */ +int8_t rse_load_texture(const char* path); +/** + * @brief Destroy all loaded textures. Usefull for closing application or just clearing. + * + */ void rse_destroy_textures(void); +/** + * @brief Returns image view for provided image id + * + * @param image_id image id + * @return VkImageView Found image view. + */ VkImageView rse_get_image_view(size_t image_id); +/** + * @brief Returns sampler + * + * @return VkSampler Sampler object + */ VkSampler rse_get_texture_sampler(); +/** + * @brief Checks if image exists for provided image ID. + * + * @param image_id Image ID + * @return int8_t 1 on success, 0 on failure + */ +int8_t image_exists(uint8_t image_id); + +/** + * @brief Returns number of loaded texture + * + * @return size_t Texture count + */ +size_t get_textures_count(); + #endif /* RSE_TEXTURE_H */ \ No newline at end of file diff --git a/graphics/src/vulkan_base.c b/graphics/src/vulkan_base.c index 457af1a2..d7b89934 100644 --- a/graphics/src/vulkan_base.c +++ b/graphics/src/vulkan_base.c @@ -550,7 +550,7 @@ uint8_t create_sync_objects() } -uint8_t init_vulkan() +uint8_t preinit_vulkan() { uint8_t status = VULKAN_ERROR_NO_ERROR; @@ -563,25 +563,21 @@ uint8_t init_vulkan() STATUS_CHECK(pick_physical_device()); STATUS_CHECK(create_device()); STATUS_CHECK(create_memory_allocator()); - - 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"); + return status; +} + +uint8_t init_vulkan() +{ + uint8_t status = VULKAN_ERROR_NO_ERROR; + + STATUS_CHECK(create_pipeline()); STATUS_CHECK(create_descriptors()); - STATUS_CHECK(create_sync_objects()); - rse_init_time(); return status; } diff --git a/graphics/src/vulkan_base.h b/graphics/src/vulkan_base.h index 7665ebbf..7b7d7ef4 100644 --- a/graphics/src/vulkan_base.h +++ b/graphics/src/vulkan_base.h @@ -19,7 +19,15 @@ #include "vulkan_commons.h" /** - * @brief Initialize Vulkan backend + * @brief Initialize Vulkan backend for buffers and stuff + * + * @param state + * @return uint8_t 0 on success. Status code on failure + */ +uint8_t preinit_vulkan(); + +/** + * @brief Initialize Vulkan backend with descriptors * * @param state * @return uint8_t 0 on success. Status code on failure diff --git a/graphics/src/vulkan_commons.h b/graphics/src/vulkan_commons.h index 3ffb72fb..63b0339a 100644 --- a/graphics/src/vulkan_commons.h +++ b/graphics/src/vulkan_commons.h @@ -78,6 +78,7 @@ struct rse_instance_data_t { struct vec3_t pos; struct vec3_t rot; float scale; + uint8_t texture_id; }; void rse_init_time(); diff --git a/graphics/src/vulkan_descriptors.c b/graphics/src/vulkan_descriptors.c index 51310650..5c1a0eb0 100644 --- a/graphics/src/vulkan_descriptors.c +++ b/graphics/src/vulkan_descriptors.c @@ -27,8 +27,8 @@ uint8_t create_descriptor_pool() 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_sizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLER; + pool_sizes[1].descriptorCount = (uint32_t)(SWAP_BUFFER_COUNT*get_textures_count()); pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.poolSizeCount = 2; @@ -69,15 +69,22 @@ uint8_t create_descriptor_sets() for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) { VkDescriptorBufferInfo buffer_info = {}; VkWriteDescriptorSet descriptor_writes[2] = {}; - VkDescriptorImageInfo image_info = {}; + VkDescriptorImageInfo image_infos[RSE_MAX_IMAGE_COUNT] = {}; + size_t image_iterator = 0U; + size_t image_info_iterator = 0U; buffer_info.buffer = g_vulkan_state.uniform_buffers[i].buffer; buffer_info.offset = 0; buffer_info.range = sizeof(struct rse_uniform_buffer_object_t); - 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(); + for (image_iterator = 0U; image_iterator < RSE_MAX_IMAGE_COUNT; ++image_iterator) { + if (image_exists(image_iterator)) { + image_infos[image_info_iterator].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_infos[image_info_iterator].imageView = rse_get_image_view(image_iterator); + image_infos[image_info_iterator].sampler = rse_get_texture_sampler(); + image_info_iterator++; + } + } descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_writes[0].dstSet = g_vulkan_state.descriptor_sets[i]; @@ -92,8 +99,8 @@ uint8_t create_descriptor_sets() 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; + descriptor_writes[1].descriptorCount = image_info_iterator; + descriptor_writes[1].pImageInfo = image_infos; vkUpdateDescriptorSets(g_vulkan_state.device, 2, descriptor_writes, 0, NULL); } diff --git a/graphics/src/vulkan_pipeline.c b/graphics/src/vulkan_pipeline.c index 8406521f..2b794008 100644 --- a/graphics/src/vulkan_pipeline.c +++ b/graphics/src/vulkan_pipeline.c @@ -5,6 +5,7 @@ #include "utilities/logger.h" #include "vulkan_errors.h" #include "mesh_controller.h" +#include "rse_vulkan_image.h" #include "vulkan/vulkan.h" @@ -72,24 +73,24 @@ static VkVertexInputBindingDescription get_binding_description() static VkVertexInputAttributeDescription* get_attribute_descriptions() { - static VkVertexInputAttributeDescription attributeDescriptions[3]; + static VkVertexInputAttributeDescription attribute_descriptions[3]; - attributeDescriptions[0].binding = 0; - attributeDescriptions[0].location = 0; /* inPosition in shader.vert */ - attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; - attributeDescriptions[0].offset = offsetof(struct rse_vertex_t, pos); + attribute_descriptions[0].binding = 0; + attribute_descriptions[0].location = 0; /* inPosition in shader.vert */ + attribute_descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; + attribute_descriptions[0].offset = offsetof(struct rse_vertex_t, pos); - attributeDescriptions[1].binding = 0; - attributeDescriptions[1].location = 1; /* inColor in shader.vert */ - attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; - attributeDescriptions[1].offset = offsetof(struct rse_vertex_t, color); + attribute_descriptions[1].binding = 0; + attribute_descriptions[1].location = 1; /* inColor in shader.vert */ + attribute_descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; + attribute_descriptions[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); + attribute_descriptions[2].binding = 0; + attribute_descriptions[2].location = 2; /* inTexCoords in shader.vert */ + attribute_descriptions[2].format = VK_FORMAT_R32G32_SFLOAT; + attribute_descriptions[2].offset = offsetof(struct rse_vertex_t, tex_coords); - return attributeDescriptions; + return attribute_descriptions; } /** @@ -266,6 +267,7 @@ uint8_t create_descriptor_set_layout() VkDescriptorSetLayoutBinding bindings[2]; VkDescriptorSetLayoutBinding ubo_layout_binding = {}; VkDescriptorSetLayoutBinding sampler_layout_binding = {}; + // VkDescriptorSetLayoutBinding textures_layout_binding = {}; ubo_layout_binding.binding = 0; ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; @@ -275,12 +277,13 @@ uint8_t create_descriptor_set_layout() sampler_layout_binding.binding = 1; sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - sampler_layout_binding.descriptorCount = 1; + sampler_layout_binding.descriptorCount = get_textures_count(); 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; @@ -549,45 +552,54 @@ void free_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_ */ void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info) { + const size_t binding_descriptions_count = 2; + const size_t attribute_descriptions_count = 7; /* This is clusterfuck with some magic numbers here and there and unneeded malloc and memcpy stuff. Change, * so you won't feel ashamed. */ 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) * 6); + VkVertexInputBindingDescription* binding_descriptions = malloc(sizeof(VkVertexInputBindingDescription) + * binding_descriptions_count); + VkVertexInputAttributeDescription* attribute_descriptions = malloc(sizeof(VkVertexInputAttributeDescription) + * attribute_descriptions_count); - bindingDescriptions[0] = vertex_binding_description; + binding_descriptions[0] = vertex_binding_description; - bindingDescriptions[1].binding = 1; - bindingDescriptions[1].stride = sizeof(struct rse_instance_data_t); //TODO: change - bindingDescriptions[1].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; + binding_descriptions[1].binding = 1; + binding_descriptions[1].stride = sizeof(struct rse_instance_data_t); //TODO: change + binding_descriptions[1].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; - memcpy(attributeDescriptions, vertex_attribute_descriptions, sizeof(VkVertexInputAttributeDescription) * 3); + memcpy(attribute_descriptions, 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, pos); + attribute_descriptions[3].binding = 1; + attribute_descriptions[3].location = 3; + attribute_descriptions[3].format = VK_FORMAT_R32G32B32_SFLOAT; + attribute_descriptions[3].offset = offsetof(struct rse_instance_data_t, pos); - attributeDescriptions[4].binding = 1; - attributeDescriptions[4].location = 4; - attributeDescriptions[4].format = VK_FORMAT_R32G32B32_SFLOAT; - attributeDescriptions[4].offset = offsetof(struct rse_instance_data_t, rot); + attribute_descriptions[4].binding = 1; + attribute_descriptions[4].location = 4; + attribute_descriptions[4].format = VK_FORMAT_R32G32B32_SFLOAT; + attribute_descriptions[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); + attribute_descriptions[5].binding = 1; + attribute_descriptions[5].location = 5; + attribute_descriptions[5].format = VK_FORMAT_R32_SFLOAT; + attribute_descriptions[5].offset = offsetof(struct rse_instance_data_t, scale); + + attribute_descriptions[6].binding = 1; + attribute_descriptions[6].location = 6; + attribute_descriptions[6].format = VK_FORMAT_R8_UINT; + attribute_descriptions[6].offset = offsetof(struct rse_instance_data_t, texture_id); // ************************ vertex_input_info->sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertex_input_info->pNext = NULL; vertex_input_info->flags = 0U; - vertex_input_info->vertexBindingDescriptionCount = 2U; - vertex_input_info->pVertexBindingDescriptions = bindingDescriptions; - vertex_input_info->vertexAttributeDescriptionCount = 6U; - vertex_input_info->pVertexAttributeDescriptions = attributeDescriptions; + vertex_input_info->vertexBindingDescriptionCount = binding_descriptions_count; + vertex_input_info->pVertexBindingDescriptions = binding_descriptions; + vertex_input_info->vertexAttributeDescriptionCount = attribute_descriptions_count; + vertex_input_info->pVertexAttributeDescriptions = attribute_descriptions; } /** diff --git a/test_image.png b/test_image.png new file mode 100644 index 00000000..e39a01ae Binary files /dev/null and b/test_image.png differ