5#ifdef VISUTWIN_HAS_VULKAN
13#include "spdlog/spdlog.h"
17 VulkanTexture::VulkanTexture(Texture* owner)
22 VulkanTexture::~VulkanTexture()
24 if (_vkDevice != VK_NULL_HANDLE) {
25 if (_sampler != VK_NULL_HANDLE)
26 vkDestroySampler(_vkDevice, _sampler,
nullptr);
27 if (_imageView != VK_NULL_HANDLE)
28 vkDestroyImageView(_vkDevice, _imageView,
nullptr);
30 if (_allocator != VK_NULL_HANDLE && _image != VK_NULL_HANDLE) {
31 vmaDestroyImage(_allocator, _image, _allocation);
35 void VulkanTexture::uploadImmediate(GraphicsDevice* device)
37 auto* vkDev =
static_cast<VulkanGraphicsDevice*
>(device);
38 _vkDevice = vkDev->device();
39 _allocator = vkDev->vmaAllocator();
41 uint32_t width = _owner->width();
42 uint32_t height = _owner->height();
43 VkFormat format = vulkanMapPixelFormat(_owner->pixelFormat());
46 VkImageCreateInfo imageInfo{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
47 imageInfo.imageType = VK_IMAGE_TYPE_2D;
48 imageInfo.format = format;
49 imageInfo.extent = {width, height, 1};
50 imageInfo.mipLevels = 1;
51 imageInfo.arrayLayers = 1;
52 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
53 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
54 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
55 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
57 VmaAllocationCreateInfo allocInfo{};
58 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
60 VkResult result = vmaCreateImage(_allocator, &imageInfo, &allocInfo,
61 &_image, &_allocation,
nullptr);
62 if (result != VK_SUCCESS) {
63 spdlog::error(
"VulkanTexture: failed to create VkImage ({}x{}, fmt={})",
64 width, height,
static_cast<int>(format));
69 VkImageViewCreateInfo viewInfo{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
70 viewInfo.image = _image;
71 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
72 viewInfo.format = format;
73 viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
74 vkCreateImageView(_vkDevice, &viewInfo,
nullptr, &_imageView);
80 if (_owner->hasLevels() && _owner->getLevel(0) !=
nullptr) {
81 size_t dataSize = _owner->getLevelDataSize(0, 0);
82 const void* data = _owner->getLevel(0);
85 VkBuffer stagingBuffer;
86 VmaAllocation stagingAlloc;
88 VkBufferCreateInfo stagingInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
89 stagingInfo.size = dataSize;
90 stagingInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
92 VmaAllocationCreateInfo stagingAllocInfo{};
93 stagingAllocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
95 vmaCreateBuffer(_allocator, &stagingInfo, &stagingAllocInfo,
96 &stagingBuffer, &stagingAlloc,
nullptr);
99 vmaMapMemory(_allocator, stagingAlloc, &mapped);
100 memcpy(mapped, data, dataSize);
101 vmaUnmapMemory(_allocator, stagingAlloc);
103 vulkanImmediateSubmit(vkDev, [&](VkCommandBuffer cmd) {
104 vulkanTransitionImageLayout(cmd, _image,
105 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
107 VkBufferImageCopy region{};
108 region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
109 region.imageExtent = {width, height, 1};
110 vkCmdCopyBufferToImage(cmd, stagingBuffer, _image,
111 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
113 vulkanTransitionImageLayout(cmd, _image,
114 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
115 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
118 vmaDestroyBuffer(_allocator, stagingBuffer, stagingAlloc);
121 vulkanImmediateSubmit(vkDev, [&](VkCommandBuffer cmd) {
122 vulkanTransitionImageLayout(cmd, _image,
123 VK_IMAGE_LAYOUT_UNDEFINED,
124 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
129 void VulkanTexture::propertyChanged(uint32_t flag)
135 void VulkanTexture::createSampler(VulkanGraphicsDevice* device)
137 VkSamplerCreateInfo samplerInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
138 samplerInfo.magFilter = vulkanMapFilterMode(_owner->magFilter());
139 samplerInfo.minFilter = vulkanMapFilterMode(_owner->minFilter());
140 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
141 samplerInfo.addressModeU = vulkanMapAddressMode(_owner->addressU());
142 samplerInfo.addressModeV = vulkanMapAddressMode(_owner->addressV());
143 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
144 samplerInfo.maxLod = VK_LOD_CLAMP_NONE;
145 samplerInfo.maxAnisotropy = 1.0f;
147 vkCreateSampler(device->device(), &samplerInfo,
nullptr, &_sampler);