如何在SpaiR/imgui-java中基于Vulkan渲染图像?
问题:imgui-java中Vulkan纹理渲染的类型不匹配问题
我基于LWJGL的Vulkan教程实现了Vulkan Java应用中的纹理创建,并且编写了与ImGui C++库ImGui_ImplVulkan_AddTexture逻辑完全一致的Java代码来生成DescriptorSet:
public TextureDescriptorSet(DescriptorPool descriptorPool, DescriptorSetLayout descriptorSetLayout, Texture texture, TextureSampler textureSampler, int binding) { try (MemoryStack stack = MemoryStack.stackPush()) { Device device = descriptorPool.getDevice(); LongBuffer pDescriptorSetLayout = stack.mallocLong(1); pDescriptorSetLayout.put(0, descriptorSetLayout.getVkDescriptorLayout()); VkDescriptorSetAllocateInfo allocInfo = VkDescriptorSetAllocateInfo.calloc(stack) .sType(VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO) .descriptorPool(descriptorPool.getVkDescriptorPool()) .pSetLayouts(pDescriptorSetLayout); allocInfo.descriptorSetCount(); LongBuffer pDescriptorSet = stack.mallocLong(1); vkCheck(vkAllocateDescriptorSets(device.getVkDevice(), allocInfo, pDescriptorSet), "Failed to create descriptor set"); vkDescriptorSet = pDescriptorSet.get(0); VkDescriptorImageInfo.Buffer imageInfo = VkDescriptorImageInfo.calloc(1, stack) .imageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) .imageView(texture.getImageView().getVkImageView()) .sampler(textureSampler.getVkSampler()); VkWriteDescriptorSet.Buffer descrBuffer = VkWriteDescriptorSet.calloc(1, stack); descrBuffer.get(0) .sType(VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET) .dstSet(vkDescriptorSet) .dstBinding(binding) .descriptorType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) .descriptorCount(1) .pImageInfo(imageInfo); vkUpdateDescriptorSets(device.getVkDevice(), descrBuffer, null); } }
上述代码对应ImGui C++中的实现:
ImTextureID ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout){ VkResult err; ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo; VkDescriptorSet 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 = &g_DescriptorSetLayout; err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); check_vk_result(err); } { VkDescriptorImageInfo desc_image[1] = {}; desc_image[0].sampler = sampler; desc_image[0].imageView = image_view; desc_image[0].imageLayout = image_layout; VkWriteDescriptorSet write_desc[1] = {}; write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write_desc[0].dstSet = descriptor_set; 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); } return (ImTextureID)descriptor_set; }
但imgui-java中的ImGui.image方法接收的textureID为int类型:
public static native void image(int textureID, float sizeX, float sizeY); /* ImGui::Image((ImTextureID)(intptr_t)textureID, ImVec2(sizeX, sizeY)); */
而Vulkan的DescriptorSet是long类型,强制转换为int后数值溢出,导致调用ImGui.imageButton时渲染出默认图像而非自定义纹理:
long img = guiRenderActivity.getTextureDescriptorSet().getVkDescriptorSet(); ImGui.imageButton((int) img, 500, 200);
解决方案
1. 修正imgui-java的原生方法绑定
底层C++代码是将intptr_t转换为ImTextureID,而Java中long对应64位系统的intptr_t。可以修改imgui-java的原生方法定义,将参数类型改为long:
public static native void image(long textureID, float sizeX, float sizeY); /* ImGui::Image((ImTextureID)(intptr_t)textureID, ImVec2(sizeX, sizeY)); */
重新编译imgui-java的绑定后,直接传入long类型的DescriptorSet即可,无需强制转换,避免溢出问题。
2. 建立纹理ID映射表
如果无法修改imgui-java源码,可以创建一个全局的映射表,将long类型的DescriptorSet映射为唯一的intID:
private static final Map<Long, Integer> TEXTURE_ID_MAP = new ConcurrentHashMap<>(); private static int nextTextureId = 1; // 避免0值(默认纹理) public static int registerTexture(long descriptorSet) { return TEXTURE_ID_MAP.computeIfAbsent(descriptorSet, k -> nextTextureId++); }
同时需要修改ImGui的Vulkan渲染后端,在绘制回调中根据intID查找对应的longDescriptorSet,替换到渲染命令中。这种方式需要对ImGui的Vulkan实现有一定修改能力。
3. 选择适配性更好的ImGui替代绑定
- LibGDX ImGui:基于LibGDX框架的ImGui绑定,对Vulkan的Java类型适配更完善,原生支持64位指针类型传递,避免类型溢出问题。
- Kotlin/Native ImGui:如果项目允许使用Kotlin,该绑定对原生类型的处理更灵活,直接支持将Vulkan对象作为纹理ID传递。
内容的提问来源于stack exchange,提问作者Blogger 2015
相关产品推荐
相关产品推荐

