From 2a04bfa8bb3e202ff979c8058e1e8e62ba5f56a3 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Wed, 5 Oct 2022 22:14:16 -0400 Subject: [PATCH] Texture support! --- src/pc/gfx/gfx_vulkan.cpp | 497 +++++++++++++++++++++++++++++++++++++- 1 file changed, 486 insertions(+), 11 deletions(-) diff --git a/src/pc/gfx/gfx_vulkan.cpp b/src/pc/gfx/gfx_vulkan.cpp index 6b0acaa..eb51104 100644 --- a/src/pc/gfx/gfx_vulkan.cpp +++ b/src/pc/gfx/gfx_vulkan.cpp @@ -50,12 +50,38 @@ struct ShaderProgramVulkan { VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; uint8_t num_inputs; bool used_textures[2]; + + VkDescriptorSetLayout set_layout = VK_NULL_HANDLE; + std::unordered_map cached_sets; }; std::unordered_map cached_shaders; static ShaderProgramVulkan* last_program = nullptr; +struct TextureVulkan { + VkImage image = VK_NULL_HANDLE; + VkDeviceMemory memory = VK_NULL_HANDLE; + VkImageView view = VK_NULL_HANDLE; + VkSampler sampler = VK_NULL_HANDLE; +}; + +static std::vector cached_textures; + +static int last_tile = 0; +static std::array bound_textures; + +static VkDescriptorPool descriptor_pool; + +static int get_texture_hash() { + int hash = 0; + for(int i = 0; i < bound_textures.size(); i++) { + hash += bound_textures[i]; + } + + return hash; +} + VKAPI_ATTR VkBool32 VKAPI_CALL gfx_vulkan_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, @@ -107,8 +133,10 @@ static std::string gfx_vulkan_create_vertex_shader(const CCFeatures features) { src += "layout(location = 0) in vec4 position;\n"; int next_input = 1; + int next_output = 0; if(uses_textures) { src += "layout(location = " + std::to_string(next_input++) + ") in vec2 uv;\n"; + src += "layout(location = " + std::to_string(next_output++) + ") out vec2 out_uv;\n"; } /*if(needs_screenpos) { @@ -123,18 +151,99 @@ static std::string gfx_vulkan_create_vertex_shader(const CCFeatures features) { for(int i = 0; i < features.num_inputs; i++) { int size = uses_alpha ? 4 : 3; src += "layout(location = " + std::to_string(next_input++) + ") in vec" + std::to_string(size) + " input" + std::to_string(i + 1) + ";\n"; + src += "layout(location = " + std::to_string(next_output++) + ") out vec" + std::to_string(size) + " output" + std::to_string(i + 1) + ";\n"; } src += "void main() {\n"; src += "gl_Position = position;\n"; + if(uses_textures) { + src += "out_uv = uv;\n"; + } + + for(int i = 0; i < features.num_inputs; i++) { + src += "output" + std::to_string(i + 1) + " = input" + std::to_string(i + 1) + ";\n"; + } + src += "}"; return src; } -static std::string gfx_vulkan_create_fragment_shader(const CCFeatures features) { + +static const char *shader_item_to_str(uint32_t item, bool with_alpha, bool only_alpha, bool inputs_have_alpha, bool hint_single_element) { + if (!only_alpha) { + switch (item) { + case SHADER_0: + return with_alpha ? "vec4(0.0, 0.0, 0.0, 0.0)" : "vec3(0.0, 0.0, 0.0)"; + case SHADER_INPUT_1: + return with_alpha || !inputs_have_alpha ? "input1" : "input1.rgb"; + case SHADER_INPUT_2: + return with_alpha || !inputs_have_alpha ? "input2" : "input2.rgb"; + case SHADER_INPUT_3: + return with_alpha || !inputs_have_alpha ? "input3" : "input3.rgb"; + case SHADER_INPUT_4: + return with_alpha || !inputs_have_alpha ? "input4" : "input4.rgb"; + case SHADER_TEXEL0: + return with_alpha ? "tex_val_0" : "tex_val_0.rgb"; + case SHADER_TEXEL0A: + return hint_single_element ? "tex_val_0.a" : + (with_alpha ? "vec4(tex_val_0.a, tex_val_0.a, tex_val_0.a, tex_val_0.a)" : "vec3(tex_val_0.a, tex_val_0.a, tex_val_0.a)"); + case SHADER_TEXEL1: + return with_alpha ? "tex_val_1" : "tex_val_1.rgb"; + } + } else { + switch (item) { + case SHADER_0: + return "0.0"; + case SHADER_INPUT_1: + return "input1.a"; + case SHADER_INPUT_2: + return "input2.a"; + case SHADER_INPUT_3: + return "input3.a"; + case SHADER_INPUT_4: + return "input4.a"; + case SHADER_TEXEL0: + return "tex_val_0.a"; + case SHADER_TEXEL0A: + return "tex_val_0.a"; + case SHADER_TEXEL1: + return "tex_val_1.a"; + } + } +} + +static void append_formula(std::string& buf, uint8_t c[2][4], bool do_single, bool do_multiply, bool do_mix, bool with_alpha, bool only_alpha, bool opt_alpha) { + if (do_single) { + buf += shader_item_to_str(c[only_alpha][3], with_alpha, only_alpha, opt_alpha, false); + } else if (do_multiply) { + buf += shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false); + buf += " * "; + buf += shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true); + } else if (do_mix) { + buf += "mix("; + buf += shader_item_to_str(c[only_alpha][1], with_alpha, only_alpha, opt_alpha, false); + buf += ", "; + buf += shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false); + buf += ", "; + buf += shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true); + buf += ")"; + } else { + buf += "("; + buf += shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false); + buf += " - "; + buf += shader_item_to_str(c[only_alpha][1], with_alpha, only_alpha, opt_alpha, false); + buf += ") * "; + buf += shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true); + buf += " + "; + buf += shader_item_to_str(c[only_alpha][3], with_alpha, only_alpha, opt_alpha, false); + } +} + + +static std::string gfx_vulkan_create_fragment_shader(CCFeatures features) { std::string src = "#version 460 core\n"; const bool uses_textures = features.used_textures[0] || features.used_textures[1]; @@ -144,28 +253,70 @@ static std::string gfx_vulkan_create_fragment_shader(const CCFeatures features) src += "layout(location = 0) out vec4 out_color;\n"; - /*int next_input = 0; + int next_input = 0; if(uses_textures) { src += "layout(location = " + std::to_string(next_input++) + ") in vec2 uv;\n"; } - if(needs_screenpos) { + /*if(needs_screenpos) { src += "layout(location = " + std::to_string(next_input++) + ") in vec4 screen_pos;\n"; } if(uses_fog) { src += "layout(location = " + std::to_string(next_input++) + ") in vec4 fog;\n"; - } + }*/ // extra inputs? for(int i = 0; i < features.num_inputs; i++) { int size = uses_alpha ? 4 : 3; src += "layout(location = " + std::to_string(next_input++) + ") in vec" + std::to_string(size) + " input" + std::to_string(i + 1) + ";\n"; - }*/ + } + + if(features.used_textures[0]) { + src += "layout(binding = 0) uniform sampler2D texture0;\n"; + } + + if(features.used_textures[1]) { + src += "layout(binding = 1) uniform sampler2D texture1;\n"; + } src += "void main() {\n"; - src += "out_color = vec4(1, 1, 0, 1);\n"; + if(features.used_textures[0]) { + src += "vec4 tex_val_0 = texture(texture0, uv);\n"; + } + + if(features.used_textures[1]) { + src += "vec4 tex_val_1 = texture(texture1, uv);\n"; + } + + if(uses_alpha) { + src += "vec4 texel = "; + } else { + src += "vec3 texel = "; + } + + if(!features.color_alpha_same && features.opt_alpha) { + src += "vec4("; + + append_formula(src, features.c, features.do_single[0], features.do_multiply[0], features.do_mix[0], false, false, true); + + src += ", "; + + append_formula(src, features.c, features.do_single[1], features.do_multiply[1], features.do_mix[1], true, true, true); + + src += ")"; + } else { + append_formula(src,features.c, features.do_single[0], features.do_multiply[0], features.do_mix[0], features.opt_alpha, false, features.opt_alpha); + } + + src += ";\n"; + + if(uses_alpha) { + src += "out_color = texel;\n"; + } else { + src += "out_color = vec4(texel, 1.0);\n"; + } src += "}"; @@ -214,7 +365,7 @@ static VkShaderModule gfx_vulkan_compile_glsl(const std::string& shader_src, con return gfx_vulkan_create_shader_module(SpirV.data(), SpirV.size() * sizeof(uint32_t)); } -static std::pair gfx_vulkan_create_pipeline(const CCFeatures features) { +static std::tuple gfx_vulkan_create_pipeline(const CCFeatures features) { const std::string vertex_src = gfx_vulkan_create_vertex_shader(features); const std::string fragment_src = gfx_vulkan_create_fragment_shader(features); @@ -343,11 +494,42 @@ static std::pair gfx_vulkan_create_pipeline(const VkPipelineDynamicStateCreateInfo dynamic_state = {}; dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + std::vector bindings; + + if(features.used_textures[0]) { + VkDescriptorSetLayoutBinding textureBinding = {}; + textureBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + textureBinding.descriptorCount = 1; + textureBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + textureBinding.binding = 0; + + bindings.push_back(textureBinding); + } + + if(features.used_textures[0]) { + VkDescriptorSetLayoutBinding textureBinding = {}; + textureBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + textureBinding.descriptorCount = 1; + textureBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + textureBinding.binding = 1; + + bindings.push_back(textureBinding); + } + + VkDescriptorSetLayoutCreateInfo layoutInfo = {}; + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.bindingCount = bindings.size(); + layoutInfo.pBindings = bindings.data(); + + VkDescriptorSetLayout set_layout; + vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &set_layout); + VkPipelineLayoutCreateInfo pipeline_layout_create_info = {}; pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_create_info.pSetLayouts = &set_layout; + pipeline_layout_create_info.setLayoutCount = 1; VkPipelineLayout layout = VK_NULL_HANDLE; - vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, &layout); VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; @@ -380,7 +562,7 @@ static std::pair gfx_vulkan_create_pipeline(const nullptr, &pipeline); - return {pipeline, layout}; + return {pipeline, layout, set_layout}; } // FIXME: reorganize @@ -392,9 +574,10 @@ static struct ShaderProgram *gfx_vulkan_renderer_create_and_load_new_shader(uint CCFeatures cc_features; gfx_cc_get_features(shader_id, &cc_features); - auto [pipeline, layout] = gfx_vulkan_create_pipeline(cc_features); + auto [pipeline, layout, set_layout] = gfx_vulkan_create_pipeline(cc_features); shader->pipeline = pipeline; shader->pipeline_layout = layout; + shader->set_layout = set_layout; cached_shaders[shader_id] = shader; @@ -420,7 +603,8 @@ static void gfx_vulkan_renderer_shader_get_info(struct ShaderProgram *prg, uint8 } static uint32_t gfx_vulkan_renderer_new_texture(void) { - return 0; + cached_textures.resize(cached_textures.size() + 1); + return cached_textures.size() - 1; } static uint32_t gfx_vulkan_find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags properties) { @@ -848,6 +1032,81 @@ static void gfx_vulkan_create_framebuffers() { } } +static void gfx_vulkan_create_descriptor_pools() { + VkDescriptorPoolSize pool_size = {}; + pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + pool_size.descriptorCount = 500; + + const std::array pool_sizes = { pool_size }; + + VkDescriptorPoolCreateInfo pool_create_info = {}; + pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_create_info.poolSizeCount = pool_sizes.size(); + pool_create_info.pPoolSizes = pool_sizes.data(); + pool_create_info.maxSets = 500; + + vkCreateDescriptorPool(device, &pool_create_info, nullptr, &descriptor_pool); +} + +static void gfx_vulkan_cache_descriptor() { + ShaderProgramVulkan* vulkan = last_program; + + VkDescriptorSet set; + + VkDescriptorSetAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocateInfo.descriptorPool = descriptor_pool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &vulkan->set_layout; + + vkAllocateDescriptorSets(device, &allocateInfo, &set); + + std::vector writes; + + VkDescriptorImageInfo imageInfo1 = {}; + imageInfo1.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + if(vulkan->used_textures[0]) { + imageInfo1.imageView = cached_textures[bound_textures[0]].view; + imageInfo1.sampler = cached_textures[bound_textures[0]].sampler; + + VkWriteDescriptorSet descriptorWrite2 = {}; + descriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite2.dstSet = set; + descriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrite2.descriptorCount = 1; + descriptorWrite2.pImageInfo = &imageInfo1; + descriptorWrite2.dstBinding = 0; + writes.push_back(descriptorWrite2); + + } + + VkDescriptorImageInfo imageInfo2 = {}; + imageInfo2.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + + if(vulkan->used_textures[1]) { + imageInfo2.imageView = cached_textures[bound_textures[1]].view; + imageInfo2.sampler = cached_textures[bound_textures[1]].sampler; + + VkWriteDescriptorSet descriptorWrite2 = {}; + descriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite2.dstSet = set; + descriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrite2.descriptorCount = 1; + descriptorWrite2.pImageInfo = &imageInfo2; + descriptorWrite2.dstBinding = 1; + + writes.push_back(descriptorWrite2); + } + + vkUpdateDescriptorSets(device, writes.size(), writes.data(), 0, nullptr); + + vulkan->cached_sets[get_texture_hash()] = set; + + printf("Cached hash of %d\n", get_texture_hash()); +} + static void* mapped_data = nullptr; static void gfx_vulkan_create_buffers() { @@ -890,6 +1149,7 @@ static void gfx_vulkan_renderer_init(void) { gfx_vulkan_create_depth(); gfx_vulkan_create_framebuffers(); gfx_vulkan_create_buffers(); + gfx_vulkan_create_descriptor_pools(); } static void gfx_vulkan_renderer_on_resize(void) { @@ -949,9 +1209,218 @@ static void gfx_vulkan_renderer_start_frame(void) { /* draw commands */ static void gfx_vulkan_renderer_select_texture(int tile, uint32_t texture_id) { + last_tile = tile; + bound_textures[last_tile] = texture_id; + + printf("selecting texture %d in slot %d\n", texture_id, tile); +} + +static VkCommandBuffer gfx_vulkan_begin_singletime_commands() { + VkCommandBufferAllocateInfo allocate_info = {}; + allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocate_info.commandPool = command_pool; + allocate_info.commandBufferCount = 1; + + VkCommandBuffer commandbuffer; + vkAllocateCommandBuffers(device, &allocate_info, &commandbuffer); + + VkCommandBufferBeginInfo begin_info = {}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(commandbuffer, &begin_info); + + return commandbuffer; +} + +static void gfx_vulkan_end_singletime_commands(VkCommandBuffer commandbuffer) { + vkEndCommandBuffer(commandbuffer); + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandbuffer; + + vkQueueSubmit(graphics_queue, 1, &submitInfo, VK_NULL_HANDLE); + vkQueueWaitIdle(graphics_queue); + + vkFreeCommandBuffers(device, command_pool, 1, &commandbuffer); +} + +void gfx_vulkan_transition_layout(VkCommandBuffer commandBuffer, VkImage image, VkFormat format, + VkImageAspectFlags aspect, VkImageSubresourceRange range, + VkImageLayout oldLayout, VkImageLayout newLayout, + VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) { + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange = range; + barrier.subresourceRange.aspectMask = aspect; + + switch (oldLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + barrier.srcAccessMask = 0; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + case VK_IMAGE_LAYOUT_GENERAL: + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + break; + default: + break; + } + + switch (newLayout) { + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + case VK_IMAGE_LAYOUT_GENERAL: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + default: + break; + } + + vkCmdPipelineBarrier(commandBuffer, src_stage_mask, dst_stage_mask, 0, 0, + nullptr, 0, nullptr, 1, &barrier); } static void gfx_vulkan_renderer_upload_texture(const uint8_t *rgba32_buf, int width, int height) { + TextureVulkan& vulkan = cached_textures[bound_textures[last_tile]]; + + printf("Uploaded texture for %d\n", bound_textures[last_tile]); + + VkImageCreateInfo image_create_info = {}; + image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_create_info.imageType = VK_IMAGE_TYPE_2D; + image_create_info.extent.width = width; + image_create_info.extent.height = height; + image_create_info.extent.depth = 1; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; + image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + + vkCreateImage(device, &image_create_info, nullptr, &vulkan.image); + + VkMemoryRequirements memory_requirements; + vkGetImageMemoryRequirements(device, vulkan.image, &memory_requirements); + + VkMemoryAllocateInfo allocate_info = {}; + allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocate_info.allocationSize = memory_requirements.size; + allocate_info.memoryTypeIndex = gfx_vulkan_find_memory_type(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkAllocateMemory(device, &allocate_info, nullptr, &vulkan.memory); + + vkBindImageMemory(device, vulkan.image, vulkan.memory, 0); + + const int data_size = 4 * width * height; + + // copy image data + VkBuffer staging_buffer; + VkDeviceMemory staging_memory; + + VkBufferCreateInfo buffer_create_info = {}; + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.size = data_size; + buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(device, &buffer_create_info, nullptr, &staging_buffer); + + // allocate staging memory + vkGetBufferMemoryRequirements(device, staging_buffer, &memory_requirements); + + allocate_info = {}; + allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocate_info.allocationSize = memory_requirements.size; + allocate_info.memoryTypeIndex = + gfx_vulkan_find_memory_type(memory_requirements.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + vkAllocateMemory(device, &allocate_info, nullptr, &staging_memory); + + vkBindBufferMemory(device, staging_buffer, staging_memory, 0); + + // copy to staging buffer + void* data = nullptr; + vkMapMemory(device, staging_memory, 0, data_size, 0, &data); + memcpy(data, rgba32_buf, data_size); + vkUnmapMemory(device, staging_memory); + + // copy staging buffer to image + VkCommandBuffer commandbuffer = gfx_vulkan_begin_singletime_commands(); + + VkImageSubresourceRange range = {}; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + + gfx_vulkan_transition_layout(commandbuffer, vulkan.image, image_create_info.format, VK_IMAGE_ASPECT_COLOR_BIT, + range, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + region.imageExtent = {(uint32_t)width, + (uint32_t)height, 1}; + + vkCmdCopyBufferToImage(commandbuffer, staging_buffer, vulkan.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + gfx_vulkan_transition_layout(commandbuffer, vulkan.image, image_create_info.format, VK_IMAGE_ASPECT_COLOR_BIT, + range, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + gfx_vulkan_end_singletime_commands(commandbuffer); + + range = {}; + range.levelCount = 1; + range.layerCount = 1; + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + VkImageViewCreateInfo viewInfo = {}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = vulkan.image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = image_create_info.format; + viewInfo.subresourceRange = range; + + vkCreateImageView(device, &viewInfo, nullptr, &vulkan.view); + + VkSamplerCreateInfo samplerInfo = {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.maxLod = 1.0f; + + vkCreateSampler(device, &samplerInfo, nullptr, &vulkan.sampler); } static void gfx_vulkan_renderer_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) { @@ -988,6 +1457,12 @@ static void gfx_vulkan_renderer_load_shader(struct ShaderProgram *new_prg) { static void gfx_vulkan_renderer_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) { vkCmdBindPipeline(current_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, last_program->pipeline); + if(!last_program->cached_sets.count(get_texture_hash())) { + gfx_vulkan_cache_descriptor(); + } + + vkCmdBindDescriptorSets(current_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, last_program->pipeline_layout, 0, 1, &last_program->cached_sets[get_texture_hash()], 0, nullptr); + memcpy((uint8_t *)mapped_data + buf_vbo_offset, buf_vbo, buf_vbo_len * sizeof(float)); VkDeviceSize offsets[] = {static_cast(buf_vbo_offset)};