fix(font-atlas): the atlas destroys its image

FontAtlas::Initialize creates an ImageVulkan and nothing ever called its
Destroy(): every atlas left its 1024x1024 image, memory and view behind.
The atlas now owns the image for its lifetime and is no longer copyable.
ImageVulkan's handles start as VK_NULL_HANDLE and Destroy() resets them,
so an atlas that was never initialised, or an image destroyed by hand
before the atlas goes, is a no-op in the destructor.

The owner waits for the GPU before the atlas goes and, in sets mode,
destroys the descriptor heap that holds the image's view before the atlas.
This commit is contained in:
Jorijn van der Graaf 2026-10-18 01:12:21 +02:00
commit b16f1e99d5
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
2 changed files with 18 additions and 3 deletions

View file

@ -56,8 +56,8 @@ export namespace Crafter {
std::uint16_t width;
std::uint16_t height;
std::uint8_t mipLevels;
VkImage image;
VkDeviceMemory imageMemory;
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory imageMemory = VK_NULL_HANDLE;
VulkanBuffer<PixelType, true> buffer;
// Transient host-visible staging for the compressed Update path. Same
// lifetime contract as Mesh::compressedStaging: the compressed Update
@ -66,7 +66,7 @@ export namespace Crafter {
// submit's frame has cleared instead of pinning it for the image's life.
// Between Updates the handle is null; the next Update's Resize re-creates it.
VulkanBuffer<std::byte, true> compressedStaging;
VkImageView imageView;
VkImageView imageView = VK_NULL_HANDLE;
VkDescriptorImageInfo descriptor;
// Pipeline stage that samples this image after upload. Set once at
// Create and reused by every Update so the upload barrier's dst (and
@ -378,6 +378,9 @@ export namespace Crafter {
vkDestroyImageView(Device::device, imageView, nullptr);
vkDestroyImage(Device::device, image, nullptr);
vkFreeMemory(Device::device, imageMemory, nullptr);
imageView = VK_NULL_HANDLE;
image = VK_NULL_HANDLE;
imageMemory = VK_NULL_HANDLE;
// Free any staging this image still owns: a streamed image's
// persistent `buffer`, or either staging buffer on an image
// destroyed before its first upload released them (issue #114).