1
Fork 0

Texture support!

This commit is contained in:
Joshua Goins 2022-10-05 22:14:16 -04:00
parent 83371003d1
commit 2a04bfa8bb

View file

@ -50,12 +50,38 @@ struct ShaderProgramVulkan {
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
uint8_t num_inputs; uint8_t num_inputs;
bool used_textures[2]; bool used_textures[2];
VkDescriptorSetLayout set_layout = VK_NULL_HANDLE;
std::unordered_map<int, VkDescriptorSet> cached_sets;
}; };
std::unordered_map<uint32_t, ShaderProgramVulkan*> cached_shaders; std::unordered_map<uint32_t, ShaderProgramVulkan*> cached_shaders;
static ShaderProgramVulkan* last_program = nullptr; 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<TextureVulkan> cached_textures;
static int last_tile = 0;
static std::array<int, 2> 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 VKAPI_ATTR VkBool32 VKAPI_CALL
gfx_vulkan_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, gfx_vulkan_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType, 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"; src += "layout(location = 0) in vec4 position;\n";
int next_input = 1; int next_input = 1;
int next_output = 0;
if(uses_textures) { if(uses_textures) {
src += "layout(location = " + std::to_string(next_input++) + ") in vec2 uv;\n"; 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) { /*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++) { for(int i = 0; i < features.num_inputs; i++) {
int size = uses_alpha ? 4 : 3; 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_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 += "void main() {\n";
src += "gl_Position = position;\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 += "}"; src += "}";
return 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"; std::string src = "#version 460 core\n";
const bool uses_textures = features.used_textures[0] || features.used_textures[1]; 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"; src += "layout(location = 0) out vec4 out_color;\n";
/*int next_input = 0; int next_input = 0;
if(uses_textures) { if(uses_textures) {
src += "layout(location = " + std::to_string(next_input++) + ") in vec2 uv;\n"; 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"; src += "layout(location = " + std::to_string(next_input++) + ") in vec4 screen_pos;\n";
} }
if(uses_fog) { if(uses_fog) {
src += "layout(location = " + std::to_string(next_input++) + ") in vec4 fog;\n"; src += "layout(location = " + std::to_string(next_input++) + ") in vec4 fog;\n";
} }*/
// extra inputs? // extra inputs?
for(int i = 0; i < features.num_inputs; i++) { for(int i = 0; i < features.num_inputs; i++) {
int size = uses_alpha ? 4 : 3; 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_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 += "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 += "}"; 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)); return gfx_vulkan_create_shader_module(SpirV.data(), SpirV.size() * sizeof(uint32_t));
} }
static std::pair<VkPipeline, VkPipelineLayout> gfx_vulkan_create_pipeline(const CCFeatures features) { static std::tuple<VkPipeline, VkPipelineLayout, VkDescriptorSetLayout> gfx_vulkan_create_pipeline(const CCFeatures features) {
const std::string vertex_src = gfx_vulkan_create_vertex_shader(features); const std::string vertex_src = gfx_vulkan_create_vertex_shader(features);
const std::string fragment_src = gfx_vulkan_create_fragment_shader(features); const std::string fragment_src = gfx_vulkan_create_fragment_shader(features);
@ -343,11 +494,42 @@ static std::pair<VkPipeline, VkPipelineLayout> gfx_vulkan_create_pipeline(const
VkPipelineDynamicStateCreateInfo dynamic_state = {}; VkPipelineDynamicStateCreateInfo dynamic_state = {};
dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
std::vector<VkDescriptorSetLayoutBinding> 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 = {}; VkPipelineLayoutCreateInfo pipeline_layout_create_info = {};
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_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; VkPipelineLayout layout = VK_NULL_HANDLE;
vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, &layout); vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, &layout);
VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; VkPipelineDepthStencilStateCreateInfo depth_stencil = {};
@ -380,7 +562,7 @@ static std::pair<VkPipeline, VkPipelineLayout> gfx_vulkan_create_pipeline(const
nullptr, nullptr,
&pipeline); &pipeline);
return {pipeline, layout}; return {pipeline, layout, set_layout};
} }
// FIXME: reorganize // FIXME: reorganize
@ -392,9 +574,10 @@ static struct ShaderProgram *gfx_vulkan_renderer_create_and_load_new_shader(uint
CCFeatures cc_features; CCFeatures cc_features;
gfx_cc_get_features(shader_id, &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 = pipeline;
shader->pipeline_layout = layout; shader->pipeline_layout = layout;
shader->set_layout = set_layout;
cached_shaders[shader_id] = shader; 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) { 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) { 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<VkWriteDescriptorSet> 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* mapped_data = nullptr;
static void gfx_vulkan_create_buffers() { static void gfx_vulkan_create_buffers() {
@ -890,6 +1149,7 @@ static void gfx_vulkan_renderer_init(void) {
gfx_vulkan_create_depth(); gfx_vulkan_create_depth();
gfx_vulkan_create_framebuffers(); gfx_vulkan_create_framebuffers();
gfx_vulkan_create_buffers(); gfx_vulkan_create_buffers();
gfx_vulkan_create_descriptor_pools();
} }
static void gfx_vulkan_renderer_on_resize(void) { static void gfx_vulkan_renderer_on_resize(void) {
@ -949,9 +1209,218 @@ static void gfx_vulkan_renderer_start_frame(void) {
/* draw commands */ /* draw commands */
static void gfx_vulkan_renderer_select_texture(int tile, uint32_t texture_id) { 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) { 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, &region);
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) { 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) { 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); 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)); memcpy((uint8_t *)mapped_data + buf_vbo_offset, buf_vbo, buf_vbo_len * sizeof(float));
VkDeviceSize offsets[] = {static_cast<VkDeviceSize>(buf_vbo_offset)}; VkDeviceSize offsets[] = {static_cast<VkDeviceSize>(buf_vbo_offset)};