void ImGuiVulkanUtil::updateTexture(ImTextureData* tex) {
if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) {
int texWidth = tex->Width;
int texHeight = tex->Height;
unsigned char* fontData = (unsigned char*)tex->Pixels;
if (!fontData) return;
vk::DeviceSize uploadSize = texWidth * texHeight * tex->BytesPerPixel;
vk::Format format = (tex->BytesPerPixel == 4) ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8Unorm;
if (tex->Status == ImTextureStatus_WantCreate) {
// Create optimized GPU image for texture storage
vk::Extent3D extent{static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight), 1};
fontImage = Image(*device, extent, format,
vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst,
vk::MemoryPropertyFlagBits::eDeviceLocal);
fontImageView = ImageView(*device, fontImage.getHandle(), format,
vk::ImageAspectFlagBits::eColor);
}
// Create staging buffer for efficient CPU-to-GPU data transfer
Buffer stagingBuffer(*device, uploadSize, vk::BufferUsageFlagBits::eTransferSrc,
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
// Copy data to staging buffer
void* data = stagingBuffer.map();
memcpy(data, fontData, uploadSize);
stagingBuffer.unmap();
// Transition image layout and copy data
transitionImageLayout(fontImage.getHandle(), format,
vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
copyBufferToImage(stagingBuffer.getHandle(), fontImage.getHandle(),
static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
transitionImageLayout(fontImage.getHandle(), format,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
// Store descriptor set handle as the ImTextureID
// In this implementation, we use a single descriptor set for the font atlas
tex->SetTexID((ImTextureID)(intptr_t)(VkDescriptorSet)*descriptorSet);
tex->SetStatus(ImTextureStatus_OK);
}
}