Hi, the real problem is at the bottom of this post because it’s close to the problem, and there are explanation of my problems in the comments in the codes.
Goal
I want to bind multiple textures using vkCmdBindDescriptorSets, because I want multiple textures (Fonts Texture and Icons Texture), and those codes are referenced from professional developers.
A screenshot to prove that I have a good hope asking for real help
Vulkan is the hardest backend
There is a missing feature in the original code from professional developers because it cannot render texture for Vulkan, but only for OpenGL, DirectX or something. So I want to make that texture possible with Vulkan, but it’s difficult for me, so please help, I spent a lot of time with this. Thank you very much.
// A function that works perfectly
void ImGui_ImplVulkan_UpdateFontsTexture(VkImageView fontView)
{
// Referenced from ImGui_ImplVulkan_CreateFontsTexture
ImGui_ImplVulkan_Data *bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
//bd->FontSampler = ;
bd->FontMemory = nullptr;
bd->FontImage = nullptr;
bd->FontView = fontView;
bd->UploadBufferMemory = nullptr;
bd->UploadBuffer = nullptr;
// Update the Descriptor Set:
{
VkDescriptorImageInfo desc_image[1] = {};
desc_image[0].sampler = bd->FontSampler;
desc_image[0].imageView = bd->FontView;
desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_desc[0].dstSet = bd->DescriptorSet;
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Store our identifier
ImGuiIO& io = ImGui::GetIO();
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontImage);
}
// A copy function of the above with modification but it doesn't work
void ImGui_ImplVulkan_UpdateIconsTexture(VkImageView iconsView)
{
ImGui_ImplVulkan_Data *bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
// Update the Descriptor Set:
{
VkDescriptorImageInfo desc_image[1] = {};
desc_image[0].sampler = bd->FontSampler;
//_/--------------------------------------------------\_
desc_image[0].imageView = iconsView; // <-- This is a modification.
// \--------------------------------------------------/
desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
//_/--------------------------------------------------\_
write_desc[0].dstSet = bd->DescriptorSet_icons; // <-- This is a modification.
// \--------------------------------------------------/
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
}
How I call the 2 functions above
ImGui_ImplVulkan_UpdateFontsTexture(_fontAtlasTexture->_vk._imageView);
...
_copyCmd->begin();
TextureCreateInfo CI = {};
CI.type = TextureCreateInfoType_UVGrid;
CI.extent = { 128, 128, 1 };
CI.color = 0xff0000ff;
_iconsTexture = new Texture(this, _copyCmd, CI);
_copyCmd->end();
ImGui_ImplVulkan_UpdateIconsTexture(_iconsTexture->_vk._imageView);
// ^ ^ ^ ^ I'm sure that my Texture class works because I tried it with
// the other working function ImGui_ImplVulkan_UpdateFontsTexture
// just for testing and there is no problem.
// But I want 2 different textures in my GUI, FontsTexture and IconsTexture.
How the device objects are created
Note that most of the codes below are correct, and referenced from professional developers, but the only modification I made is indicated in a comment.
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
VkResult err;
if (!bd->FontSampler)
{
VkSamplerCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
info.magFilter = VK_FILTER_LINEAR;
info.minFilter = VK_FILTER_LINEAR;
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->FontSampler);
check_vk_result(err);
}
if (!bd->DescriptorSetLayout)
{
VkSampler sampler[1] = {bd->FontSampler};
VkDescriptorSetLayoutBinding binding[1] = {};
binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
binding[0].descriptorCount = 1;
binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
binding[0].pImmutableSamplers = sampler;
VkDescriptorSetLayoutCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &bd->DescriptorSetLayout);
check_vk_result(err);
}
// Create Descriptor Set:
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &bd->DescriptorSetLayout;
err = vkAllocateDescriptorSets(v->Device, &alloc_info, &bd->DescriptorSet);
check_vk_result(err);
}
//_/--------------------------------------------------\_
// --> Create Descriptor Set (icons) <-- This is the modification I made,
// and it doesn't work.
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &bd->DescriptorSetLayout;
err = vkAllocateDescriptorSets(v->Device, &alloc_info, &bd->DescriptorSet_icons); // <-- Modification
check_vk_result(err);
}
// \--------------------------------------------------/
if (!bd->PipelineLayout)
{
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
VkPushConstantRange push_constants[1] = {};
push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
push_constants[0].offset = sizeof(float) * 0;
push_constants[0].size = sizeof(float) * 4;
VkDescriptorSetLayout set_layout[1] = { bd->DescriptorSetLayout };
VkPipelineLayoutCreateInfo layout_info = {};
layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
layout_info.setLayoutCount = 1;
layout_info.pSetLayouts = set_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = push_constants;
err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &bd->PipelineLayout);
check_vk_result(err);
}
ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, bd->RenderPass, v->MSAASamples, &bd->Pipeline, bd->Subpass);
return true;
}
How I bind the descriptor set (for icons) and the draw
// Bind descriptor set (This is a code I wrote, maybe not perfect?)
{
// Referenced from "gltfloading.cpp" > drawNode in "Vulkan C++ examples and demos" https://github.com/SaschaWillems/Vulkan
ImGui_ImplVulkan_Data *bd = ImGui_ImplVulkan_GetBackendData();
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->DescriptorSet_icons, 0, nullptr);
}
// Draw
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
This is the error I get:
[vulkan] Debug report from ObjectType: VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT
Validation Error: [ VUID-vkCmdBindDescriptorSets-firstSet-00360 ] Object 0: handle = 0x1ca5a560270, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x1893ae29 | vkCmdBindDescriptorSets(): Sum of firstSet (1) and descriptorSetCount (1) is greater than VkPipelineLayoutCreateInfo::setLayoutCount (1) when pipeline layout was created The Vulkan spec states: The sum of firstSet and descriptorSetCount must be less than or equal to VkPipelineLayoutCreateInfo::setLayoutCount provided when layout was created (https://vulkan.lunarg.com/doc/view/1.2.182.0/windows/1.2-extensions/vkspec.html#VUID-vkCmdBindDescriptorSets-firstSet-00360)
I don’t understand the error message, I want multiple Descriptor Sets for all textures, because there can be unlimited many textures, and I try to bind all the descriptor sets per Render Frame. The error message may doesn’t telling the real problem because maybe I’m in the wrong direction, maybe the solution has nothing to do with LayoutCount. Please help.