Texture support!
This commit is contained in:
parent
83371003d1
commit
2a04bfa8bb
1 changed files with 486 additions and 11 deletions
|
@ -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, ®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) {
|
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)};
|
||||||
|
|
Loading…
Add table
Reference in a new issue