diff options
author | quou <quou@disroot.org> | 2024-12-23 21:30:13 +1100 |
---|---|---|
committer | quou <quou@disroot.org> | 2024-12-23 21:30:13 +1100 |
commit | 078b97e48b5ad5fcf3f5a16bb081ea0efb1f931b (patch) | |
tree | d04bfb2d25952b214a4df303823ff7c5d2743681 /video.cpp | |
parent | b293168cc158d65f1a5146f155921ff82119d1bc (diff) |
send textures to shaders
Diffstat (limited to 'video.cpp')
-rw-r--r-- | video.cpp | 351 |
1 files changed, 343 insertions, 8 deletions
@@ -8,6 +8,7 @@ #define max_rpos 64 #define max_pipelines 64 #define max_shaders 32 +#define max_samplers 16 extern "C" { #include "memory.h" @@ -27,7 +28,8 @@ extern "C" { #include "glad_vk.h" const char* device_exts[] = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME }; extern "C" { @@ -388,10 +390,18 @@ struct Shader_Vk : public Shader, public Late_Terminated { int find_attribute(const char* name); }; + struct Desc { + char name[24]; + int slot; + int stage; + }; + SProgram_Type type; VkShaderModule modules[shader_type_count]; char entrypoints[shader_type_count][24]; Vertex_Format vfd; + Desc* descs; + int desc_count; bool init(Device_Vk* dev, Pack_File* f); bool init_module( @@ -406,6 +416,8 @@ struct Shader_Vk : public Shader, public Late_Terminated { ); void destroy(Device_Vk* dev) override; + int find_descriptor(const char* name); + static VkShaderStageFlagBits stage(Shader_Type type) { switch (type) { case shader_type_vertex: @@ -519,6 +531,9 @@ struct Pso_Key { struct Pipeline_Vk { VkPipeline pip; VkPipelineLayout lay; + VkDescriptorPool dp; + VkDescriptorSet dset; + VkDescriptorSetLayout dlay; int age; void init(Device_Vk* dev, const Pso_Key& desc); @@ -576,6 +591,11 @@ struct Pipeline_Vk { Device_Vk* dev, const Pipeline& desc ); + void init_descriptors( + Device_Vk* dev, + const Pipeline& desc, + int count + ); void on_submit() { age = 0; @@ -594,6 +614,17 @@ struct Vertex_Format_Vk { static VkFormat format_from_svar_type(SVariable_Type type); }; +struct Sampler_Vk : public Late_Terminated { + VkSampler sampler; + + void init(Device_Vk* dev, const Sampler_State& s); + void destroy(Device_Vk* dev) override; + + static VkFilter get_filter(Filter_Mode mode); + static VkSamplerMipmapMode get_mipmap_mode(Filter_Mode mode); + static VkSamplerAddressMode get_mode(Address_Mode mode); +}; + template<> struct Hash_Function<Render_Pass> { @@ -639,6 +670,13 @@ struct Hash_Function<Vertex_Format_Id> { }; template<> +struct Hash_Function<Sampler_Id> { + size_t operator()(Sampler_Id id) const { + return id.index; + } +}; + +template<> struct std::hash<Render_Pass> { size_t operator()(const Render_Pass& rp) const { return (size_t)fnv1a64((uint8_t*)&rp, sizeof rp); @@ -717,10 +755,12 @@ struct Device_Vk : public Device { max_vertex_formats > vertex_formats; Hash_Map<Shader_Id, Shader_Vk, max_shaders> shaders; + Hash_Map<Sampler_Id, Sampler_Vk, max_samplers> samplers; uint32_t texture_count; uint32_t buffer_count; uint32_t vertex_format_count; uint32_t shader_count; + uint32_t sampler_count; Hash_Map<Render_Pass, Renderpass_Vk, max_rpos> rpo_cache; Hash_Map<Pso_Key, Pipeline_Vk, max_pipelines> pso_cache; @@ -734,6 +774,7 @@ struct Device_Vk : public Device { Vertex_Format_Id create_vf(Shader_Vk& shader); void destroy_vf(Vertex_Format_Id id); Shader_Id alloc_shader(); + Sampler_Id alloc_sampler(); void init_internal(); void deinit_internal(); @@ -874,6 +915,7 @@ bool Device_Vk::has_validation() { void Device_Vk::find_exts(const char** exts, int& count) { app->get_vk_exts(exts, count); + exts[count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; #ifdef DEBUG exts[count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; #endif @@ -1023,11 +1065,14 @@ VkPhysicalDevice get_phys_dev(Device_Vk* d, Swap_Cap* sc) { void Device_Vk::create_dev(Swap_Cap* swap_cap) { const float priority = 0.0f; VkDeviceQueueCreateInfo qi{}; + VkPhysicalDeviceCustomBorderColorFeaturesEXT border{}; VkDeviceCreateInfo di{}; VkPhysicalDeviceFeatures pdf{}; VkResult r; phys_dev = get_phys_dev(this, swap_cap); vkGetPhysicalDeviceMemoryProperties(phys_dev, &mem_props); + border.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; + border.customBorderColors = true; qi.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; qi.queueFamilyIndex = queue_index; qi.queueCount = 1; @@ -1039,7 +1084,7 @@ void Device_Vk::create_dev(Swap_Cap* swap_cap) { di.enabledExtensionCount = sizeof device_exts / sizeof *device_exts; di.ppEnabledExtensionNames = device_exts; - di.pNext = 0; + di.pNext = &border; r = vkCreateDevice( phys_dev, &di, @@ -1064,6 +1109,8 @@ void Device_Vk::init_internal() { vertex_format_count = 1; shaders.init(); shader_count = 1; + samplers.init(); + sampler_count = 1; rpo_cache.init(); pso_cache.init(); shader_loader.init(this); @@ -1545,6 +1592,7 @@ Texture& Device::get_texture(Texture_Id id) { Texture_Id Device_Vk::alloc_texture() { Texture_Vk tex{}; Texture_Id id(texture_count++); + tex.id = id; textures.set(id, tex); return id; } @@ -1552,6 +1600,7 @@ Texture_Id Device_Vk::alloc_texture() { Buffer_Id Device_Vk::alloc_buffer() { Buffer_Vk buf{}; Buffer_Id id(buffer_count++); + buf.id = id; buffers.set(id, buf); return id; } @@ -1577,11 +1626,17 @@ void Device_Vk::destroy_vf(Vertex_Format_Id id) { Shader_Id Device_Vk::alloc_shader() { Shader_Vk buf{}; Shader_Id id(shader_count++); - assert(id.index < max_shaders); shaders.set(id, buf); return id; } +Sampler_Id Device_Vk::alloc_sampler() { + Sampler_Vk s{}; + Sampler_Id id(sampler_count++); + samplers.set(id, s); + return id; +} + void Device::destroy_texture(Texture_Id id) { Device_Vk* dev = (Device_Vk*)this; dev->queue_destroy((Texture_Vk*)&dev->get_texture(id)); @@ -1615,6 +1670,16 @@ void Context::submit( VK_PIPELINE_BIND_POINT_GRAPHICS, pso.pip ); + vkCmdBindDescriptorSets( + ctx->cb, + VK_PIPELINE_BIND_POINT_GRAPHICS, + pso.lay, + 0, + 1, + &pso.dset, + 0, + 0 + ); for (binding = draw.verts; binding->id; binding++) { VkBuffer buf = ((Buffer_Vk*)&dev->get_buffer(binding->id))->buf; VkDeviceSize offset = (VkDeviceSize)binding->offset; @@ -2101,6 +2166,143 @@ void Pipeline_Vk::init_blending( info.pColorBlendState = &bi; } +void Pipeline_Vk::init_descriptors( + Device_Vk* dev, + const Pipeline& desc, + int count +) { + int sampler_count = 0, cbuffer_count = 0; + const Descriptor* d = desc.descriptors; + Shader_Vk& shader = *(Shader_Vk*)&dev->get_shader(desc.shader); + VkDescriptorPoolSize sizes[4]; + VkResult r; + int size_count = 0, i; + for (; d; d = d->next) { + switch (d->type) { + case Descriptor::Type::texture: + sampler_count++; + break; + default: + assert(0); + break; + } + } + if (sampler_count) { + int idx = size_count++; + sizes[idx] = { + .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = (uint32_t)sampler_count + }; + } + if (cbuffer_count) { + int idx = size_count++; + sizes[idx] = { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = (uint32_t)cbuffer_count + }; + } + { + VkDescriptorPoolCreateInfo di{}; + di.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + di.poolSizeCount = (uint32_t)size_count; + di.pPoolSizes = sizes; + di.maxSets = (uint32_t)count; + r = vkCreateDescriptorPool(dev->dev, &di, &dev->ac, &dp); + if (r != VK_SUCCESS) { + print_err("Failed to create a descriptor pool.\n"); + pbreak(r); + } + } + { + VkDescriptorSetLayoutBinding* descs = + (VkDescriptorSetLayoutBinding*)heap_alloc( + dev->heap, + count * sizeof *descs + ); + VkDescriptorSetLayoutCreateInfo di{}; + VkDescriptorSetAllocateInfo da{}; + memset(descs, 0, count * sizeof *descs); + Descriptor* src = desc.descriptors; + for (i = count - 1; i >= 0; i--) { + int j, stage; + auto& dst = descs[i]; + switch (src->type) { + case Descriptor::Type::texture: + dst.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + break; + default: + assert(0); + break; + } + dst.binding = src->slot; + dst.descriptorCount = 1; + dst.stageFlags = 0; + stage = shader.descriptor_stage(src->slot); + for (j = 0; j < shader_type_count; j++) { + if (stage & (1 << j)) { + dst.stageFlags |= Shader_Vk::stage((Shader_Type)j); + } + } + src = src->next; + } + di.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + di.bindingCount = (uint32_t)count; + di.pBindings = descs; + r = vkCreateDescriptorSetLayout( + dev->dev, + &di, + &dev->ac, + &dlay + ); + if (r != VK_SUCCESS) { + print_err("Failed to create descriptor set layout.\n"); + pbreak(r); + } + da.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + da.descriptorPool = dp; + da.descriptorSetCount = 1; + da.pSetLayouts = &dlay; + r = vkAllocateDescriptorSets( + dev->dev, + &da, + &dset + ); + /* todo this should be refactored to allow + * swapping the resources without recreating pipelines */ + src = desc.descriptors; + for (i = 0; i < count; i++) { + VkDescriptorImageInfo img{}; + VkWriteDescriptorSet wd{}; + wd.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + wd.dstSet = dset; + wd.dstBinding = src->slot; + wd.dstArrayElement = 0; + wd.descriptorCount = 1; + + switch (src->type) { + case Descriptor::Type::texture: { + Texture_Descriptor* td = (Texture_Descriptor*)src; + assert(td->texture); + assert(td->sampler); + Texture_Vk& t = *(Texture_Vk*)&dev->get_texture(td->texture); + Sampler_Vk& s = *(Sampler_Vk*)&dev->samplers[td->sampler]; + img.imageView = t.view; + img.sampler = s.sampler; + img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + wd.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + wd.pImageInfo = &img; + } break; + default: + assert(0); + break; + } + vkUpdateDescriptorSets(dev->dev, 1, &wd, 0, 0); + src = src->next; + } + heap_free(dev->heap, descs); + } +} + void Pipeline_Vk::init_layout( Device_Vk* dev, const Pipeline& desc @@ -2108,9 +2310,15 @@ void Pipeline_Vk::init_layout( VkResult r; VkPipelineLayoutCreateInfo li{}; (void)desc; + int desc_count = desc.count_descriptors(); + int set_count = desc_count? 1: 0; + if (set_count) { + init_descriptors(dev, desc, desc_count); + } li.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - li.setLayoutCount = 0; - li.pushConstantRangeCount = 0; /* todo */ + li.setLayoutCount = set_count; + li.pSetLayouts = &dlay; + li.pushConstantRangeCount = 0; r = vkCreatePipelineLayout( dev->dev, &li, @@ -2159,8 +2367,10 @@ void Pipeline_Vk::init(Device_Vk* dev, const Pso_Key& key) { } void Pipeline_Vk::destroy(Device_Vk* dev) { - vkDestroyPipeline(dev->dev, pip, &dev->ac); + vkDestroyDescriptorPool(dev->dev, dp, &dev->ac); + vkDestroyDescriptorSetLayout(dev->dev, dlay, &dev->ac); vkDestroyPipelineLayout(dev->dev, lay, &dev->ac); + vkDestroyPipeline(dev->dev, pip, &dev->ac); } int Vertex_Format_Vk::svariable_type_size(SVariable_Type type) { @@ -2365,6 +2575,7 @@ void Shader_Vk::destroy(Device_Vk* dev) { if (modules[i]) vkDestroyShaderModule(dev->dev, modules[i], &dev->ac); vfd.destroy(dev); + heap_free(dev->heap, descs); dev->destroy_vf(vf); dev->shaders.remove(id); } @@ -2385,6 +2596,25 @@ int Shader::attribute_index(const char* name) { return idx; } +int Shader::descriptor_index(const char* name) { + int idx; + Shader_Vk* sh = (Shader_Vk*)this; + idx = sh->find_descriptor(name); + if (idx < 0 || !sh->descs[idx].name[0]) return -1; + return idx; +} + +int Shader::descriptor_stage(int slot) { + Shader_Vk* sh = (Shader_Vk*)this; + int i; + for (i = 0; i < sh->desc_count; i++) { + if (sh->descs[i].slot == slot) { + return sh->descs[i].stage; + } + } + return 0; +} + void Buffer_Vk::init( Device_Vk* dev, int flags, @@ -2481,6 +2711,20 @@ Shader& Device::get_shader(Shader_Id id) { return ((Device_Vk*)this)->shaders[id]; } +Sampler_Id Device::create_sampler(const Sampler_State& state) { + Device_Vk* dev = (Device_Vk*)this; + Sampler_Id id = dev->alloc_sampler(); + Sampler_Vk& s = dev->samplers[id]; + s.init(dev, state); + return id; +} + +void Device::destroy_sampler(Sampler_Id id) { + Device_Vk* dev = (Device_Vk*)this; + Sampler_Vk& s = dev->samplers[id]; + dev->queue_destroy(&s); +} + void Shader_Loader::init(Device_Vk* d) { dev = d; } @@ -2509,6 +2753,20 @@ void Shader_Loader::unload(Asset* a) { dev->queue_destroy(sh); } +int Shader_Vk::find_descriptor(const char* name) { + int i; + int bucket = (int)(hash_string(name) % desc_count); + for (i = 0; i < desc_count; i++) { + Desc& desc = descs[bucket]; + if ( + !desc.name[0] || + !strcmp(desc.name, name) + ) return bucket; + bucket = (bucket + 1) % desc_count; + } + return -1; +} + bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) { char magic[4]; int binding_count, target_count, i; @@ -2522,8 +2780,9 @@ bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) { pack_read(f, &type, 4); pack_read(f, &binding_count, 4); pack_read(f, &target_count, 4); - vfd.binding_count = binding_count; + pack_read(f, &desc_count, 4); assert(binding_count); + vfd.binding_count = binding_count; if (!vfd.init(dev, f)) return false; vf = dev->create_vf(*this); @@ -2532,6 +2791,11 @@ bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) { 32 * target_count, seek_rel_cur ); + descs = (Desc*)heap_alloc( + dev->heap, + desc_count * sizeof *descs + ); + pack_read(f, descs, desc_count * sizeof *descs); for (i = 0; i < shader_type_count; i++) { int o, s; pack_read(f, &o, 4); @@ -2655,6 +2919,7 @@ Asset* Texture_Loader::load(Arena* a, Arena* s, Pack_File* f) { int w, h; size_t size; Texture_Format fmt; + (void)a; pack_read(f, magic, 4); pack_read(f, &w, 4); pack_read(f, &h, 4); @@ -2679,7 +2944,7 @@ Asset* Texture_Loader::load(Arena* a, Arena* s, Pack_File* f) { void Texture_Loader::unload(Asset* a) { Texture_Vk* tex = (Texture_Vk*)a; - tex->destroy(dev); + dev->destroy_texture(tex->id); } void Texture_Vk::destroy(Device_Vk* dev) { @@ -2691,3 +2956,73 @@ void Texture_Vk::destroy(Device_Vk* dev) { dev->textures.remove(id); } +VkFilter Sampler_Vk::get_filter(Filter_Mode mode) { + switch (mode) { + case Filter_Mode::point: return VK_FILTER_NEAREST; + case Filter_Mode::linear: return VK_FILTER_LINEAR; + } + assert(0); + return (VkFilter)0; +} + +VkSamplerMipmapMode Sampler_Vk::get_mipmap_mode( + Filter_Mode mode +) { + switch (mode) { + case Filter_Mode::point: + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + case Filter_Mode::linear: + return VK_SAMPLER_MIPMAP_MODE_LINEAR; + } + assert(0); + return (VkSamplerMipmapMode)0; +} + +VkSamplerAddressMode Sampler_Vk::get_mode( + Address_Mode mode +) { + switch (mode) { + case Address_Mode::repeat: + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + case Address_Mode::mirror: + return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + case Address_Mode::clamp: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + case Address_Mode::border: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + } + assert(0); + return (VkSamplerAddressMode)0; +} + +void Sampler_Vk::init(Device_Vk* dev, const Sampler_State& s) { + VkSamplerCreateInfo si{}; + VkSamplerCustomBorderColorCreateInfoEXT bi{}; + VkClearColorValue col{}; + VkResult r; + col.float32[0] = s.border[0]; + col.float32[1] = s.border[1]; + col.float32[2] = s.border[2]; + col.float32[3] = s.border[3]; + si.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + si.magFilter = get_filter(s.mag); + si.minFilter = get_filter(s.min); + si.mipmapMode = get_mipmap_mode(s.mip); + si.addressModeU = get_mode(s.address_u); + si.addressModeV = get_mode(s.address_v); + si.addressModeW = get_mode(s.address_w); + si.borderColor = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT; + si.pNext = &bi; + bi.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT; + bi.customBorderColor = col; + bi.format = VK_FORMAT_R32G32B32A32_SFLOAT; + r = vkCreateSampler(dev->dev, &si, &dev->ac, &sampler); + if (r != VK_SUCCESS) { + print_err("Failed to create a sampler.\n"); + pbreak(r); + } +} + +void Sampler_Vk::destroy(Device_Vk* dev) { + vkDestroySampler(dev->dev, sampler, &dev->ac); +} |