2023-11-05 10:36:01 +01:00
|
|
|
#include "Texture.h"
|
2023-11-15 17:42:57 +01:00
|
|
|
#include "Command.h"
|
2024-06-09 10:44:24 +02:00
|
|
|
#include "Enums.h"
|
2024-06-13 15:43:03 +02:00
|
|
|
#include "Graphics/Enums.h"
|
|
|
|
|
#include "Graphics/Initializer.h"
|
2024-08-13 22:44:04 +02:00
|
|
|
#include <fmt/format.h>
|
2020-04-01 02:17:49 +02:00
|
|
|
#include <math.h>
|
2024-06-13 15:43:03 +02:00
|
|
|
#include <vulkan/vulkan_core.h>
|
2020-04-01 02:17:49 +02:00
|
|
|
|
|
|
|
|
using namespace Seele;
|
|
|
|
|
using namespace Seele::Vulkan;
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
VkImageAspectFlags getAspectFromFormat(Gfx::SeFormat format) {
|
|
|
|
|
switch (format) {
|
2020-04-12 15:47:19 +02:00
|
|
|
case Gfx::SE_FORMAT_D16_UNORM:
|
|
|
|
|
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
|
case Gfx::SE_FORMAT_D32_SFLOAT:
|
|
|
|
|
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
|
case Gfx::SE_FORMAT_S8_UINT:
|
|
|
|
|
return VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
|
|
|
case Gfx::SE_FORMAT_D16_UNORM_S8_UINT:
|
|
|
|
|
case Gfx::SE_FORMAT_D24_UNORM_S8_UINT:
|
|
|
|
|
case Gfx::SE_FORMAT_D32_SFLOAT_S8_UINT:
|
|
|
|
|
case Gfx::SE_FORMAT_X8_D24_UNORM_PACK32:
|
|
|
|
|
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
|
|
|
default:
|
|
|
|
|
return VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
TextureHandle::TextureHandle(PGraphics graphics, VkImageViewType viewType, const TextureCreateInfo& createInfo, VkImage existingImage)
|
2024-08-13 22:44:04 +02:00
|
|
|
: CommandBoundResource(graphics, createInfo.name), image(existingImage), width(createInfo.width), height(createInfo.height),
|
|
|
|
|
depth(createInfo.depth), arrayCount(createInfo.elements), mipLevels(1), layerCount(createInfo.layers), samples(createInfo.samples),
|
2024-06-13 15:43:03 +02:00
|
|
|
format(createInfo.format), usage(createInfo.usage), layout(Gfx::SE_IMAGE_LAYOUT_UNDEFINED),
|
2024-06-13 22:47:51 +02:00
|
|
|
aspect(getAspectFromFormat(createInfo.format)), ownsImage(false), owner(createInfo.sourceData.owner) {
|
2024-08-13 22:44:04 +02:00
|
|
|
if (createInfo.useMip) {
|
|
|
|
|
mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(width, height)))) + 1;
|
|
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
if (existingImage == VK_NULL_HANDLE) {
|
2023-11-15 17:42:57 +01:00
|
|
|
VkImageType type = VK_IMAGE_TYPE_MAX_ENUM;
|
|
|
|
|
VkImageCreateFlags flags = 0;
|
2024-06-09 12:20:04 +02:00
|
|
|
switch (viewType) {
|
2020-04-12 15:47:19 +02:00
|
|
|
case VK_IMAGE_VIEW_TYPE_1D:
|
|
|
|
|
case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
|
2023-11-15 17:42:57 +01:00
|
|
|
type = VK_IMAGE_TYPE_1D;
|
2020-04-12 15:47:19 +02:00
|
|
|
break;
|
|
|
|
|
case VK_IMAGE_VIEW_TYPE_2D:
|
|
|
|
|
case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
|
2023-11-15 17:42:57 +01:00
|
|
|
type = VK_IMAGE_TYPE_2D;
|
2020-04-12 15:47:19 +02:00
|
|
|
break;
|
|
|
|
|
case VK_IMAGE_VIEW_TYPE_3D:
|
2023-11-15 17:42:57 +01:00
|
|
|
type = VK_IMAGE_TYPE_3D;
|
2020-04-12 15:47:19 +02:00
|
|
|
break;
|
|
|
|
|
case VK_IMAGE_VIEW_TYPE_CUBE:
|
|
|
|
|
case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
|
2023-11-15 17:42:57 +01:00
|
|
|
type = VK_IMAGE_TYPE_2D;
|
|
|
|
|
flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
2020-04-12 15:47:19 +02:00
|
|
|
layerCount = 6 * arrayCount;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
if ((usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) == 0) {
|
|
|
|
|
usage = usage | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
2023-12-10 22:27:59 +01:00
|
|
|
}
|
2023-11-15 17:42:57 +01:00
|
|
|
VkImageCreateInfo info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
|
|
|
.pNext = nullptr,
|
|
|
|
|
.flags = flags,
|
|
|
|
|
.imageType = type,
|
|
|
|
|
.format = cast(format),
|
2024-06-09 12:20:04 +02:00
|
|
|
.extent =
|
|
|
|
|
{
|
|
|
|
|
.width = width,
|
|
|
|
|
.height = height,
|
|
|
|
|
.depth = depth,
|
|
|
|
|
},
|
2023-11-15 17:42:57 +01:00
|
|
|
.mipLevels = mipLevels,
|
|
|
|
|
.arrayLayers = arrayCount * layerCount,
|
|
|
|
|
.samples = (VkSampleCountFlagBits)samples,
|
|
|
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
2023-12-10 22:27:59 +01:00
|
|
|
.usage = usage,
|
2023-11-15 17:42:57 +01:00
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
|
.initialLayout = cast(layout),
|
|
|
|
|
};
|
2024-01-17 17:57:59 +01:00
|
|
|
VmaAllocationCreateInfo allocInfo = {
|
|
|
|
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
|
|
|
|
};
|
2024-06-13 15:43:03 +02:00
|
|
|
VK_CHECK(vmaCreateImage(graphics->getAllocator(), &info, &allocInfo, &image, &allocation, nullptr));
|
2024-08-13 22:44:04 +02:00
|
|
|
VkDebugUtilsObjectNameInfoEXT nameInfo = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
|
|
|
.pNext = nullptr,
|
|
|
|
|
.objectType = VK_OBJECT_TYPE_IMAGE,
|
|
|
|
|
.objectHandle = (uint64)image,
|
|
|
|
|
.pObjectName = name.c_str(),
|
|
|
|
|
};
|
|
|
|
|
vkSetDebugUtilsObjectNameEXT(graphics->getDevice(), &nameInfo);
|
2024-06-13 15:43:03 +02:00
|
|
|
ownsImage = true;
|
2024-05-04 09:25:13 +02:00
|
|
|
}
|
|
|
|
|
const DataSource& sourceData = createInfo.sourceData;
|
2024-06-09 12:20:04 +02:00
|
|
|
if (sourceData.size > 0) {
|
|
|
|
|
changeLayout(Gfx::SE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_NONE, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
2024-07-13 16:22:56 +02:00
|
|
|
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
2024-05-04 09:25:13 +02:00
|
|
|
void* data;
|
|
|
|
|
VkBufferCreateInfo stagingInfo = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
|
|
|
.pNext = nullptr,
|
|
|
|
|
.flags = 0,
|
|
|
|
|
.size = sourceData.size,
|
|
|
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
|
};
|
|
|
|
|
VmaAllocationCreateInfo alloc = {
|
|
|
|
|
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT,
|
|
|
|
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
|
|
|
|
};
|
2024-08-13 22:44:04 +02:00
|
|
|
OBufferAllocation stagingAlloc =
|
|
|
|
|
new BufferAllocation(graphics, fmt::format("{}Staging", createInfo.name), stagingInfo, alloc, Gfx::QueueType::TRANSFER);
|
2024-05-15 15:27:13 +02:00
|
|
|
vmaMapMemory(graphics->getAllocator(), stagingAlloc->allocation, &data);
|
2024-05-04 09:25:13 +02:00
|
|
|
std::memcpy(data, sourceData.data, sourceData.size);
|
2024-05-15 15:27:13 +02:00
|
|
|
vmaUnmapMemory(graphics->getAllocator(), stagingAlloc->allocation);
|
2024-05-04 09:25:13 +02:00
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
PCommandPool commandPool = graphics->getQueueCommands(owner);
|
2024-05-04 09:25:13 +02:00
|
|
|
VkBufferImageCopy region = {
|
|
|
|
|
.bufferOffset = 0,
|
|
|
|
|
.bufferRowLength = 0,
|
|
|
|
|
.bufferImageHeight = 0,
|
2024-06-09 12:20:04 +02:00
|
|
|
.imageSubresource =
|
|
|
|
|
{
|
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
|
.mipLevel = 0,
|
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
|
.layerCount = arrayCount * layerCount,
|
|
|
|
|
},
|
|
|
|
|
.imageOffset =
|
|
|
|
|
{
|
|
|
|
|
.x = 0,
|
|
|
|
|
.y = 0,
|
|
|
|
|
.z = 0,
|
|
|
|
|
},
|
|
|
|
|
.imageExtent = {.width = width, .height = height, .depth = depth},
|
2024-05-04 09:25:13 +02:00
|
|
|
};
|
|
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
vkCmdCopyBufferToImage(commandPool->getCommands()->getHandle(), stagingAlloc->buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
|
1, ®ion);
|
2024-05-04 09:25:13 +02:00
|
|
|
|
2024-05-15 15:27:13 +02:00
|
|
|
commandPool->getCommands()->bindResource(PBufferAllocation(stagingAlloc));
|
2024-06-11 14:15:29 +02:00
|
|
|
generateMipmaps();
|
2024-05-04 09:25:13 +02:00
|
|
|
// When loading a texture from a file, we will almost always use it as a texture map for fragment shaders
|
2024-07-13 16:22:56 +02:00
|
|
|
changeLayout(Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
2024-06-09 12:20:04 +02:00
|
|
|
VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
2024-05-15 15:27:13 +02:00
|
|
|
graphics->getDestructionManager()->queueResourceForDestruction(std::move(stagingAlloc));
|
2020-10-14 01:49:43 +02:00
|
|
|
}
|
2023-11-15 17:42:57 +01:00
|
|
|
VkImageViewCreateInfo viewInfo = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
|
|
|
.pNext = nullptr,
|
|
|
|
|
.flags = 0,
|
2024-06-13 15:43:03 +02:00
|
|
|
.image = image,
|
2023-11-15 17:42:57 +01:00
|
|
|
.viewType = viewType,
|
|
|
|
|
.format = cast(format),
|
2024-06-09 12:20:04 +02:00
|
|
|
.subresourceRange =
|
|
|
|
|
{
|
|
|
|
|
.aspectMask = aspect,
|
|
|
|
|
.levelCount = mipLevels,
|
|
|
|
|
.layerCount = layerCount,
|
|
|
|
|
},
|
2023-11-15 17:42:57 +01:00
|
|
|
};
|
2024-06-09 12:20:04 +02:00
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
VK_CHECK(vkCreateImageView(graphics->getDevice(), &viewInfo, nullptr, &imageView));
|
2020-04-01 02:17:49 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
TextureHandle::~TextureHandle() {
|
|
|
|
|
vkDestroyImageView(graphics->getDevice(), imageView, nullptr);
|
|
|
|
|
if (ownsImage) {
|
|
|
|
|
vmaDestroyImage(graphics->getAllocator(), image, allocation);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-01 02:17:49 +02:00
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
void TextureHandle::pipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, VkAccessFlags dstAccess,
|
|
|
|
|
VkPipelineStageFlags dstStage) {
|
|
|
|
|
VkImageMemoryBarrier barrier = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
|
.pNext = nullptr,
|
|
|
|
|
.srcAccessMask = srcAccess,
|
|
|
|
|
.dstAccessMask = dstAccess,
|
|
|
|
|
.oldLayout = cast(layout),
|
|
|
|
|
.newLayout = cast(layout),
|
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
|
.image = image,
|
|
|
|
|
.subresourceRange =
|
|
|
|
|
{
|
|
|
|
|
.aspectMask = aspect,
|
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
|
.levelCount = mipLevels,
|
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
|
.layerCount = 1,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
PCommand command = graphics->getQueueCommands(owner)->getCommands();
|
|
|
|
|
vkCmdPipelineBarrier(command->getHandle(), srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
|
|
|
|
command->bindResource(PTextureHandle(this));
|
|
|
|
|
}
|
2024-05-15 15:27:13 +02:00
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
void TextureHandle::transferOwnership(Gfx::QueueType newOwner) {
|
|
|
|
|
Gfx::QueueFamilyMapping mapping = graphics->getFamilyMapping();
|
2024-06-13 22:47:51 +02:00
|
|
|
if (mapping.getQueueTypeFamilyIndex(newOwner) == mapping.getQueueTypeFamilyIndex(owner))
|
|
|
|
|
return;
|
2024-06-13 15:43:03 +02:00
|
|
|
VkImageMemoryBarrier barrier = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
|
.pNext = nullptr,
|
|
|
|
|
.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
|
|
|
|
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
|
|
|
|
.oldLayout = cast(layout),
|
|
|
|
|
.newLayout = cast(layout),
|
|
|
|
|
.srcQueueFamilyIndex = mapping.getQueueTypeFamilyIndex(owner),
|
|
|
|
|
.dstQueueFamilyIndex = mapping.getQueueTypeFamilyIndex(newOwner),
|
|
|
|
|
.image = image,
|
|
|
|
|
.subresourceRange =
|
|
|
|
|
{
|
|
|
|
|
.aspectMask = aspect,
|
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
|
.levelCount = mipLevels,
|
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
|
.layerCount = arrayCount,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
PCommandPool sourcePool = graphics->getQueueCommands(owner);
|
|
|
|
|
PCommandPool dstPool = graphics->getQueueCommands(newOwner);
|
|
|
|
|
assert(barrier.srcQueueFamilyIndex != barrier.dstQueueFamilyIndex);
|
|
|
|
|
vkCmdPipelineBarrier(sourcePool->getCommands()->getHandle(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0,
|
|
|
|
|
0, nullptr, 0, nullptr, 1, &barrier);
|
|
|
|
|
vkCmdPipelineBarrier(dstPool->getCommands()->getHandle(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0,
|
|
|
|
|
nullptr, 0, nullptr, 1, &barrier);
|
|
|
|
|
sourcePool->submitCommands();
|
|
|
|
|
owner = newOwner;
|
|
|
|
|
}
|
2020-10-03 11:00:10 +02:00
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
void TextureHandle::changeLayout(Gfx::SeImageLayout newLayout, VkAccessFlags srcAccess, VkPipelineStageFlags srcStage,
|
|
|
|
|
VkAccessFlags dstAccess, VkPipelineStageFlags dstStage) {
|
2023-11-15 17:42:57 +01:00
|
|
|
VkImageMemoryBarrier barrier = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
|
.pNext = nullptr,
|
2024-01-31 09:49:53 +01:00
|
|
|
.srcAccessMask = srcAccess,
|
|
|
|
|
.dstAccessMask = dstAccess,
|
2023-11-15 17:42:57 +01:00
|
|
|
.oldLayout = cast(layout),
|
|
|
|
|
.newLayout = cast(newLayout),
|
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
2024-06-13 15:43:03 +02:00
|
|
|
.image = image,
|
2024-06-09 12:20:04 +02:00
|
|
|
.subresourceRange =
|
|
|
|
|
{
|
|
|
|
|
.aspectMask = aspect,
|
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
|
.levelCount = mipLevels,
|
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
|
.layerCount = layerCount,
|
|
|
|
|
},
|
2023-11-15 17:42:57 +01:00
|
|
|
};
|
2024-06-13 15:43:03 +02:00
|
|
|
PCommandPool commandPool = graphics->getQueueCommands(owner);
|
2024-06-09 12:20:04 +02:00
|
|
|
vkCmdPipelineBarrier(commandPool->getCommands()->getHandle(), srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
2024-06-13 15:43:03 +02:00
|
|
|
commandPool->getCommands()->bindResource(PTextureHandle(this));
|
2020-06-02 11:46:18 +02:00
|
|
|
layout = newLayout;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
void TextureHandle::download(uint32 mipLevel, uint32 arrayLayer, uint32 face, Array<uint8>& buffer) {
|
2023-11-15 17:42:57 +01:00
|
|
|
uint64 imageSize = width * height * depth * Gfx::getFormatInfo(format).blockSize;
|
2023-02-13 14:56:13 +01:00
|
|
|
|
2024-01-17 17:57:59 +01:00
|
|
|
auto prevLayout = layout;
|
2024-06-09 12:20:04 +02:00
|
|
|
changeLayout(Gfx::SE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_MEMORY_WRITE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
|
|
|
|
VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
2024-01-17 17:57:59 +01:00
|
|
|
void* data;
|
2024-01-18 18:39:44 +01:00
|
|
|
// always create a staging buffer since we do buffer -> image copy and the image may be in any tiling format
|
2024-01-17 17:57:59 +01:00
|
|
|
VkBufferCreateInfo stagingInfo = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
|
|
|
.pNext = nullptr,
|
|
|
|
|
.flags = 0,
|
|
|
|
|
.size = imageSize,
|
2024-01-17 19:34:38 +01:00
|
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
2024-01-17 17:57:59 +01:00
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
|
};
|
|
|
|
|
VmaAllocationCreateInfo alloc = {
|
2024-01-18 18:39:44 +01:00
|
|
|
.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT,
|
2024-01-20 19:14:19 +01:00
|
|
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
2024-01-17 17:57:59 +01:00
|
|
|
};
|
2024-06-13 22:47:51 +02:00
|
|
|
OBufferAllocation stagingAlloc = new BufferAllocation(graphics, "DownloadBuffer", stagingInfo, alloc, owner);
|
2024-01-17 17:57:59 +01:00
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
PCommand cmdBuffer = graphics->getQueueCommands(owner)->getCommands();
|
2024-06-09 12:20:04 +02:00
|
|
|
// Gfx::FormatCompatibilityInfo formatInfo = Gfx::getFormatInfo(format);
|
2023-02-13 14:56:13 +01:00
|
|
|
VkBufferImageCopy region = {
|
|
|
|
|
.bufferOffset = 0,
|
|
|
|
|
.bufferRowLength = 0,
|
|
|
|
|
.bufferImageHeight = 0,
|
2024-06-09 12:20:04 +02:00
|
|
|
.imageSubresource =
|
|
|
|
|
{
|
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
|
.mipLevel = mipLevel,
|
|
|
|
|
.baseArrayLayer = arrayLayer * layerCount + face,
|
|
|
|
|
.layerCount = 1,
|
|
|
|
|
},
|
|
|
|
|
.imageOffset =
|
|
|
|
|
{
|
|
|
|
|
.x = 0,
|
|
|
|
|
.y = 0,
|
|
|
|
|
.z = 0,
|
|
|
|
|
},
|
|
|
|
|
.imageExtent = {.width = width, .height = height, .depth = depth},
|
2023-02-13 14:56:13 +01:00
|
|
|
};
|
2024-06-13 15:43:03 +02:00
|
|
|
vkCmdCopyImageToBuffer(cmdBuffer->getHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stagingAlloc->buffer, 1, ®ion);
|
2024-05-15 15:27:13 +02:00
|
|
|
cmdBuffer->bindResource(PBufferAllocation(stagingAlloc));
|
2024-06-09 12:20:04 +02:00
|
|
|
changeLayout(prevLayout, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_MEMORY_READ_BIT,
|
|
|
|
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
2024-05-15 15:27:13 +02:00
|
|
|
VK_CHECK(vmaMapMemory(graphics->getAllocator(), stagingAlloc->allocation, &data));
|
2024-01-17 17:57:59 +01:00
|
|
|
buffer.resize(imageSize);
|
2023-02-13 14:56:13 +01:00
|
|
|
std::memcpy(buffer.data(), data, buffer.size());
|
2024-05-15 15:27:13 +02:00
|
|
|
vmaUnmapMemory(graphics->getAllocator(), stagingAlloc->allocation);
|
|
|
|
|
graphics->getDestructionManager()->queueResourceForDestruction(std::move(stagingAlloc));
|
2023-02-13 14:56:13 +01:00
|
|
|
}
|
|
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
void TextureHandle::generateMipmaps() {
|
|
|
|
|
PCommandPool commandPool = graphics->getQueueCommands(owner);
|
2024-06-11 14:15:29 +02:00
|
|
|
VkImageMemoryBarrier barrier = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
|
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
|
|
|
|
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
2024-06-13 15:43:03 +02:00
|
|
|
.image = image,
|
2024-06-11 14:15:29 +02:00
|
|
|
.subresourceRange =
|
|
|
|
|
{
|
|
|
|
|
.aspectMask = aspect,
|
|
|
|
|
.levelCount = 1,
|
|
|
|
|
.baseArrayLayer = 0,
|
2024-07-05 12:02:46 +02:00
|
|
|
.layerCount = layerCount,
|
2024-06-11 14:15:29 +02:00
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
int32 mipWidth = width;
|
|
|
|
|
int32 mipHeight = height;
|
|
|
|
|
for (uint32 i = 1; i < mipLevels; ++i) {
|
|
|
|
|
barrier.subresourceRange.baseMipLevel = i - 1;
|
|
|
|
|
|
|
|
|
|
vkCmdPipelineBarrier(commandPool->getCommands()->getHandle(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
|
|
|
|
|
nullptr, 0, nullptr, 1, &barrier);
|
|
|
|
|
|
|
|
|
|
VkImageBlit blit = {
|
|
|
|
|
.srcSubresource =
|
|
|
|
|
{
|
|
|
|
|
.aspectMask = aspect,
|
|
|
|
|
.mipLevel = i - 1,
|
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
|
.layerCount = 1,
|
|
|
|
|
},
|
|
|
|
|
.srcOffsets =
|
|
|
|
|
{
|
|
|
|
|
{0, 0, 0},
|
|
|
|
|
{mipWidth, mipHeight, 1},
|
|
|
|
|
},
|
|
|
|
|
.dstSubresource = {.aspectMask = aspect, .mipLevel = i, .baseArrayLayer = 0, .layerCount = 1},
|
|
|
|
|
.dstOffsets =
|
|
|
|
|
{
|
|
|
|
|
{0, 0, 0},
|
|
|
|
|
{mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1},
|
|
|
|
|
},
|
|
|
|
|
};
|
2024-06-13 15:43:03 +02:00
|
|
|
vkCmdBlitImage(commandPool->getCommands()->getHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image,
|
|
|
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
|
|
|
|
|
aspect & VK_IMAGE_ASPECT_DEPTH_BIT ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
|
2024-06-11 14:15:29 +02:00
|
|
|
|
|
|
|
|
if (mipWidth > 1)
|
|
|
|
|
mipWidth /= 2;
|
|
|
|
|
if (mipHeight)
|
|
|
|
|
mipHeight /= 2;
|
|
|
|
|
}
|
|
|
|
|
barrier.subresourceRange.baseMipLevel = mipLevels - 1;
|
|
|
|
|
|
|
|
|
|
// just so that all levels are in the same layout and we can transition them as one
|
|
|
|
|
vkCmdPipelineBarrier(commandPool->getCommands()->getHandle(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
|
|
|
|
|
nullptr, 0, nullptr, 1, &barrier);
|
|
|
|
|
layout = Gfx::SE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
TextureBase::TextureBase(PGraphics graphics, VkImageViewType viewType, const TextureCreateInfo& createInfo, VkImage existingImage)
|
|
|
|
|
: handle(new TextureHandle(graphics, viewType, createInfo, existingImage)), graphics(graphics),
|
|
|
|
|
initialOwner(createInfo.sourceData.owner) {}
|
2024-06-09 12:20:04 +02:00
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
TextureBase::~TextureBase() { graphics->getDestructionManager()->queueResourceForDestruction(std::move(handle)); }
|
2020-04-01 02:17:49 +02:00
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
void TextureBase::pipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, VkAccessFlags dstAccess,
|
|
|
|
|
VkPipelineStageFlags dstStage) {
|
|
|
|
|
handle->pipelineBarrier(srcAccess, srcStage, dstAccess, dstStage);
|
2020-04-12 15:47:19 +02:00
|
|
|
}
|
2024-06-13 15:43:03 +02:00
|
|
|
void TextureBase::transferOwnership(Gfx::QueueType newOwner) { handle->transferOwnership(newOwner); }
|
|
|
|
|
void TextureBase::changeLayout(Gfx::SeImageLayout newLayout, VkAccessFlags srcAccess, VkPipelineStageFlags srcStage,
|
|
|
|
|
VkAccessFlags dstAccess, VkPipelineStageFlags dstStage) {
|
|
|
|
|
handle->changeLayout(newLayout, srcAccess, srcStage, dstAccess, dstStage);
|
|
|
|
|
}
|
|
|
|
|
void TextureBase::download(uint32 mipLevel, uint32 arrayLayer, uint32 face, Array<uint8>& buffer) {
|
|
|
|
|
handle->download(mipLevel, arrayLayer, face, buffer);
|
|
|
|
|
}
|
|
|
|
|
void TextureBase::generateMipmaps() { handle->generateMipmaps(); }
|
2020-04-12 15:47:19 +02:00
|
|
|
|
2020-06-02 11:46:18 +02:00
|
|
|
Texture2D::Texture2D(PGraphics graphics, const TextureCreateInfo& createInfo, VkImage existingImage)
|
2024-06-13 15:43:03 +02:00
|
|
|
: Gfx::Texture2D(graphics->getFamilyMapping()),
|
|
|
|
|
TextureBase(graphics, createInfo.elements > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, createInfo, existingImage) {}
|
2020-04-01 02:17:49 +02:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
Texture2D::~Texture2D() {}
|
2020-06-02 11:46:18 +02:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void Texture2D::changeLayout(Gfx::SeImageLayout newLayout, Gfx::SeAccessFlags srcAccess, Gfx::SePipelineStageFlags srcStage,
|
|
|
|
|
Gfx::SeAccessFlags dstAccess, Gfx::SePipelineStageFlags dstStage) {
|
2024-01-31 09:49:53 +01:00
|
|
|
TextureBase::changeLayout(newLayout, srcAccess, srcStage, dstAccess, dstStage);
|
2021-05-10 23:57:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void Texture2D::download(uint32 mipLevel, uint32 arrayLayer, uint32 face, Array<uint8>& buffer) {
|
2023-11-15 17:42:57 +01:00
|
|
|
TextureBase::download(mipLevel, arrayLayer, face, buffer);
|
2023-02-13 14:56:13 +01:00
|
|
|
}
|
|
|
|
|
|
2024-06-11 14:15:29 +02:00
|
|
|
void Texture2D::generateMipmaps() { TextureBase::generateMipmaps(); }
|
|
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
void Texture2D::executeOwnershipBarrier(Gfx::QueueType newOwner) { TextureBase::transferOwnership(newOwner); }
|
2021-05-10 23:57:55 +02:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void Texture2D::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, VkAccessFlags dstAccess,
|
|
|
|
|
VkPipelineStageFlags dstStage) {
|
2024-06-13 15:43:03 +02:00
|
|
|
TextureBase::pipelineBarrier(srcAccess, srcStage, dstAccess, dstStage);
|
2023-01-29 18:58:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Texture3D::Texture3D(PGraphics graphics, const TextureCreateInfo& createInfo, VkImage existingImage)
|
2024-06-13 15:43:03 +02:00
|
|
|
: Gfx::Texture3D(graphics->getFamilyMapping()), TextureBase(graphics, VK_IMAGE_VIEW_TYPE_3D, createInfo, existingImage) {}
|
2023-01-29 18:58:59 +01:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
Texture3D::~Texture3D() {}
|
2023-01-29 18:58:59 +01:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void Texture3D::changeLayout(Gfx::SeImageLayout newLayout, Gfx::SeAccessFlags srcAccess, Gfx::SePipelineStageFlags srcStage,
|
|
|
|
|
Gfx::SeAccessFlags dstAccess, Gfx::SePipelineStageFlags dstStage) {
|
2024-01-31 09:49:53 +01:00
|
|
|
TextureBase::changeLayout(newLayout, srcAccess, srcStage, dstAccess, dstStage);
|
2023-01-29 18:58:59 +01:00
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void Texture3D::download(uint32 mipLevel, uint32 arrayLayer, uint32 face, Array<uint8>& buffer) {
|
2023-11-15 17:42:57 +01:00
|
|
|
TextureBase::download(mipLevel, arrayLayer, face, buffer);
|
2023-02-13 14:56:13 +01:00
|
|
|
}
|
2024-06-11 14:15:29 +02:00
|
|
|
|
|
|
|
|
void Texture3D::generateMipmaps() { TextureBase::generateMipmaps(); }
|
|
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
void Texture3D::executeOwnershipBarrier(Gfx::QueueType newOwner) { TextureBase::transferOwnership(newOwner); }
|
2023-01-29 18:58:59 +01:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void Texture3D::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, VkAccessFlags dstAccess,
|
|
|
|
|
VkPipelineStageFlags dstStage) {
|
2024-06-13 15:43:03 +02:00
|
|
|
TextureBase::pipelineBarrier(srcAccess, srcStage, dstAccess, dstStage);
|
2023-01-29 18:58:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TextureCube::TextureCube(PGraphics graphics, const TextureCreateInfo& createInfo, VkImage existingImage)
|
2024-06-13 15:43:03 +02:00
|
|
|
: Gfx::TextureCube(graphics->getFamilyMapping()),
|
|
|
|
|
TextureBase(graphics, createInfo.elements > 1 ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE, createInfo, existingImage) {}
|
2023-01-29 18:58:59 +01:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
TextureCube::~TextureCube() {}
|
2023-01-29 18:58:59 +01:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void TextureCube::changeLayout(Gfx::SeImageLayout newLayout, Gfx::SeAccessFlags srcAccess, Gfx::SePipelineStageFlags srcStage,
|
|
|
|
|
Gfx::SeAccessFlags dstAccess, Gfx::SePipelineStageFlags dstStage) {
|
2024-01-31 09:49:53 +01:00
|
|
|
TextureBase::changeLayout(newLayout, srcAccess, srcStage, dstAccess, dstStage);
|
2023-01-29 18:58:59 +01:00
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void TextureCube::download(uint32 mipLevel, uint32 arrayLayer, uint32 face, Array<uint8>& buffer) {
|
2023-11-15 17:42:57 +01:00
|
|
|
TextureBase::download(mipLevel, arrayLayer, face, buffer);
|
2023-02-13 14:56:13 +01:00
|
|
|
}
|
2024-06-11 14:15:29 +02:00
|
|
|
|
|
|
|
|
void TextureCube::generateMipmaps() { TextureBase::generateMipmaps(); }
|
|
|
|
|
|
2024-06-13 15:43:03 +02:00
|
|
|
void TextureCube::executeOwnershipBarrier(Gfx::QueueType newOwner) { TextureBase::transferOwnership(newOwner); }
|
2023-01-29 18:58:59 +01:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void TextureCube::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, VkAccessFlags dstAccess,
|
|
|
|
|
VkPipelineStageFlags dstStage) {
|
2024-06-13 15:43:03 +02:00
|
|
|
TextureBase::pipelineBarrier(srcAccess, srcStage, dstAccess, dstStage);
|
2023-01-29 18:58:59 +01:00
|
|
|
}
|