mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-08-03 11:23:49 +00:00
413 lines
15 KiB
C++
413 lines
15 KiB
C++
#include "graphics/host_gpu/renderer/image/imageView.h"
|
|
|
|
#include "common/assert.h"
|
|
#include "graphics/host_gpu/graphicContext.h"
|
|
#include "graphics/host_gpu/renderer/image/image.h"
|
|
|
|
#include <mutex>
|
|
|
|
namespace Libs::Graphics {
|
|
|
|
namespace {
|
|
|
|
[[nodiscard]] bool IsComponentSwizzle(vk::ComponentSwizzle swizzle) {
|
|
switch (swizzle) {
|
|
case vk::ComponentSwizzle::eIdentity:
|
|
case vk::ComponentSwizzle::eZero:
|
|
case vk::ComponentSwizzle::eOne:
|
|
case vk::ComponentSwizzle::eR:
|
|
case vk::ComponentSwizzle::eG:
|
|
case vk::ComponentSwizzle::eB:
|
|
case vk::ComponentSwizzle::eA: return true;
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] bool IsCompatibleViewFormat(vk::Format image_format, vk::Format view_format) {
|
|
return ImageViewOps::FormatsCompatible(image_format, view_format);
|
|
}
|
|
|
|
[[nodiscard]] bool IsStencilViewFormat(vk::Format format) {
|
|
switch (format) {
|
|
case vk::Format::eS8Uint:
|
|
case vk::Format::eR8Uint:
|
|
case vk::Format::eR8Unorm: return true;
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] bool IsDepthViewFormat(vk::Format format) {
|
|
switch (format) {
|
|
case vk::Format::eD16Unorm:
|
|
case vk::Format::eR16Unorm:
|
|
case vk::Format::eD32Sfloat:
|
|
case vk::Format::eR32Sfloat:
|
|
case vk::Format::eR32Uint: return true;
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] bool IsValidViewType(const VulkanImage& image, const ImageViewInfo& info) {
|
|
switch (image.image_type) {
|
|
case vk::ImageType::e1D:
|
|
if (info.type != vk::ImageViewType::e1D && info.type != vk::ImageViewType::e1DArray) {
|
|
return false;
|
|
}
|
|
return info.type != vk::ImageViewType::e1D || info.layer_count == 1;
|
|
case vk::ImageType::e2D:
|
|
switch (info.type) {
|
|
case vk::ImageViewType::e2D: return info.layer_count == 1;
|
|
case vk::ImageViewType::e2DArray: return true;
|
|
case vk::ImageViewType::eCube:
|
|
return static_cast<bool>(image.flags &
|
|
vk::ImageCreateFlagBits::eCubeCompatible) &&
|
|
info.base_layer % 6 == 0 && info.layer_count == 6;
|
|
case vk::ImageViewType::eCubeArray:
|
|
return static_cast<bool>(image.flags &
|
|
vk::ImageCreateFlagBits::eCubeCompatible) &&
|
|
info.base_layer % 6 == 0 && info.layer_count % 6 == 0;
|
|
default: return false;
|
|
}
|
|
case vk::ImageType::e3D:
|
|
switch (info.type) {
|
|
case vk::ImageViewType::e3D: return info.base_layer == 0 && info.layer_count == 1;
|
|
case vk::ImageViewType::e2D:
|
|
return static_cast<bool>(image.flags &
|
|
vk::ImageCreateFlagBits::e2DArrayCompatible) &&
|
|
info.level_count == 1 && info.layer_count == 1;
|
|
case vk::ImageViewType::e2DArray:
|
|
return static_cast<bool>(image.flags &
|
|
vk::ImageCreateFlagBits::e2DArrayCompatible) &&
|
|
info.level_count == 1;
|
|
default: return false;
|
|
}
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] bool IsValidAspect(const VulkanImage& image, vk::ImageAspectFlags aspect) {
|
|
const auto depth_format = DepthAspectTransferFormat(image.format);
|
|
if (depth_format == vk::Format::eUndefined) {
|
|
return aspect == vk::ImageAspectFlagBits::eColor;
|
|
}
|
|
const auto supported = ImageViewOps::DepthAspectMask(image.format);
|
|
return static_cast<bool>(aspect) && !(aspect & ~supported);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace ImageViewOps {
|
|
|
|
namespace {
|
|
|
|
enum CompatibilityClass : uint32_t {
|
|
None = 0,
|
|
Bit8 = 1u << 0,
|
|
Bit16 = 1u << 1,
|
|
Bit24 = 1u << 2,
|
|
Bit32 = 1u << 3,
|
|
Bit48 = 1u << 4,
|
|
Bit64 = 1u << 5,
|
|
Bit96 = 1u << 6,
|
|
Bit128 = 1u << 7,
|
|
Bit192 = 1u << 8,
|
|
Bit256 = 1u << 9,
|
|
Bc1Rgb = 1u << 10,
|
|
Bc1Rgba = 1u << 11,
|
|
Bc2 = 1u << 12,
|
|
Bc3 = 1u << 13,
|
|
Bc4 = 1u << 14,
|
|
Bc5 = 1u << 15,
|
|
Bc6h = 1u << 16,
|
|
Bc7 = 1u << 17,
|
|
D16 = 1u << 18,
|
|
D16S8 = 1u << 19,
|
|
D24 = 1u << 20,
|
|
D24S8 = 1u << 21,
|
|
D32 = 1u << 22,
|
|
D32S8 = 1u << 23,
|
|
S8 = 1u << 24,
|
|
};
|
|
|
|
[[nodiscard]] uint32_t FormatClass(vk::Format format) noexcept {
|
|
switch (format) {
|
|
case vk::Format::eR4G4UnormPack8:
|
|
case vk::Format::eR8Sint:
|
|
case vk::Format::eR8Snorm:
|
|
case vk::Format::eR8Srgb:
|
|
case vk::Format::eR8Sscaled:
|
|
case vk::Format::eR8Uint:
|
|
case vk::Format::eR8Unorm:
|
|
case vk::Format::eR8Uscaled: return Bit8;
|
|
|
|
case vk::Format::eA1R5G5B5UnormPack16:
|
|
case vk::Format::eA4B4G4R4UnormPack16:
|
|
case vk::Format::eA4R4G4B4UnormPack16:
|
|
case vk::Format::eB4G4R4A4UnormPack16:
|
|
case vk::Format::eB5G5R5A1UnormPack16:
|
|
case vk::Format::eB5G6R5UnormPack16:
|
|
case vk::Format::eR10X6UnormPack16:
|
|
case vk::Format::eR12X4UnormPack16:
|
|
case vk::Format::eR16Sfloat:
|
|
case vk::Format::eR16Sint:
|
|
case vk::Format::eR16Snorm:
|
|
case vk::Format::eR16Sscaled:
|
|
case vk::Format::eR16Uint:
|
|
case vk::Format::eR16Unorm:
|
|
case vk::Format::eR16Uscaled:
|
|
case vk::Format::eR4G4B4A4UnormPack16:
|
|
case vk::Format::eR5G5B5A1UnormPack16:
|
|
case vk::Format::eR5G6B5UnormPack16:
|
|
case vk::Format::eR8G8Sint:
|
|
case vk::Format::eR8G8Snorm:
|
|
case vk::Format::eR8G8Srgb:
|
|
case vk::Format::eR8G8Sscaled:
|
|
case vk::Format::eR8G8Uint:
|
|
case vk::Format::eR8G8Unorm:
|
|
case vk::Format::eR8G8Uscaled: return Bit16;
|
|
|
|
case vk::Format::eB8G8R8Sint:
|
|
case vk::Format::eB8G8R8Snorm:
|
|
case vk::Format::eB8G8R8Srgb:
|
|
case vk::Format::eB8G8R8Sscaled:
|
|
case vk::Format::eB8G8R8Uint:
|
|
case vk::Format::eB8G8R8Unorm:
|
|
case vk::Format::eB8G8R8Uscaled:
|
|
case vk::Format::eR8G8B8Sint:
|
|
case vk::Format::eR8G8B8Snorm:
|
|
case vk::Format::eR8G8B8Srgb:
|
|
case vk::Format::eR8G8B8Sscaled:
|
|
case vk::Format::eR8G8B8Uint:
|
|
case vk::Format::eR8G8B8Unorm:
|
|
case vk::Format::eR8G8B8Uscaled: return Bit24;
|
|
|
|
case vk::Format::eA2B10G10R10SintPack32:
|
|
case vk::Format::eA2B10G10R10SnormPack32:
|
|
case vk::Format::eA2B10G10R10SscaledPack32:
|
|
case vk::Format::eA2B10G10R10UintPack32:
|
|
case vk::Format::eA2B10G10R10UnormPack32:
|
|
case vk::Format::eA2B10G10R10UscaledPack32:
|
|
case vk::Format::eA2R10G10B10SintPack32:
|
|
case vk::Format::eA2R10G10B10SnormPack32:
|
|
case vk::Format::eA2R10G10B10SscaledPack32:
|
|
case vk::Format::eA2R10G10B10UintPack32:
|
|
case vk::Format::eA2R10G10B10UnormPack32:
|
|
case vk::Format::eA2R10G10B10UscaledPack32:
|
|
case vk::Format::eA8B8G8R8SintPack32:
|
|
case vk::Format::eA8B8G8R8SnormPack32:
|
|
case vk::Format::eA8B8G8R8SrgbPack32:
|
|
case vk::Format::eA8B8G8R8SscaledPack32:
|
|
case vk::Format::eA8B8G8R8UintPack32:
|
|
case vk::Format::eA8B8G8R8UnormPack32:
|
|
case vk::Format::eA8B8G8R8UscaledPack32:
|
|
case vk::Format::eB10G11R11UfloatPack32:
|
|
case vk::Format::eB8G8R8A8Sint:
|
|
case vk::Format::eB8G8R8A8Snorm:
|
|
case vk::Format::eB8G8R8A8Srgb:
|
|
case vk::Format::eB8G8R8A8Sscaled:
|
|
case vk::Format::eB8G8R8A8Uint:
|
|
case vk::Format::eB8G8R8A8Unorm:
|
|
case vk::Format::eB8G8R8A8Uscaled:
|
|
case vk::Format::eE5B9G9R9UfloatPack32:
|
|
case vk::Format::eR10X6G10X6Unorm2Pack16:
|
|
case vk::Format::eR12X4G12X4Unorm2Pack16:
|
|
case vk::Format::eR16G16Sfloat:
|
|
case vk::Format::eR16G16Sint:
|
|
case vk::Format::eR16G16Snorm:
|
|
case vk::Format::eR16G16Sscaled:
|
|
case vk::Format::eR16G16Uint:
|
|
case vk::Format::eR16G16Unorm:
|
|
case vk::Format::eR16G16Uscaled:
|
|
case vk::Format::eR32Sfloat:
|
|
case vk::Format::eR32Sint:
|
|
case vk::Format::eR32Uint:
|
|
case vk::Format::eR8G8B8A8Sint:
|
|
case vk::Format::eR8G8B8A8Snorm:
|
|
case vk::Format::eR8G8B8A8Srgb:
|
|
case vk::Format::eR8G8B8A8Sscaled:
|
|
case vk::Format::eR8G8B8A8Uint:
|
|
case vk::Format::eR8G8B8A8Unorm:
|
|
case vk::Format::eR8G8B8A8Uscaled: return Bit32;
|
|
|
|
case vk::Format::eR16G16B16Sfloat:
|
|
case vk::Format::eR16G16B16Sint:
|
|
case vk::Format::eR16G16B16Snorm:
|
|
case vk::Format::eR16G16B16Sscaled:
|
|
case vk::Format::eR16G16B16Uint:
|
|
case vk::Format::eR16G16B16Unorm:
|
|
case vk::Format::eR16G16B16Uscaled: return Bit48;
|
|
|
|
case vk::Format::eR16G16B16A16Sfloat:
|
|
case vk::Format::eR16G16B16A16Sint:
|
|
case vk::Format::eR16G16B16A16Snorm:
|
|
case vk::Format::eR16G16B16A16Sscaled:
|
|
case vk::Format::eR16G16B16A16Uint:
|
|
case vk::Format::eR16G16B16A16Unorm:
|
|
case vk::Format::eR16G16B16A16Uscaled:
|
|
case vk::Format::eR32G32Sfloat:
|
|
case vk::Format::eR32G32Sint:
|
|
case vk::Format::eR32G32Uint:
|
|
case vk::Format::eR64Sfloat:
|
|
case vk::Format::eR64Sint:
|
|
case vk::Format::eR64Uint: return Bit64;
|
|
|
|
case vk::Format::eR32G32B32Sfloat:
|
|
case vk::Format::eR32G32B32Sint:
|
|
case vk::Format::eR32G32B32Uint: return Bit96;
|
|
|
|
case vk::Format::eR32G32B32A32Sfloat:
|
|
case vk::Format::eR32G32B32A32Sint:
|
|
case vk::Format::eR32G32B32A32Uint:
|
|
case vk::Format::eR64G64Sfloat:
|
|
case vk::Format::eR64G64Sint:
|
|
case vk::Format::eR64G64Uint: return Bit128;
|
|
|
|
case vk::Format::eR64G64B64Sfloat:
|
|
case vk::Format::eR64G64B64Sint:
|
|
case vk::Format::eR64G64B64Uint: return Bit192;
|
|
|
|
case vk::Format::eR64G64B64A64Sfloat:
|
|
case vk::Format::eR64G64B64A64Sint:
|
|
case vk::Format::eR64G64B64A64Uint: return Bit256;
|
|
|
|
case vk::Format::eBc1RgbSrgbBlock:
|
|
case vk::Format::eBc1RgbUnormBlock: return Bc1Rgb | Bit64;
|
|
case vk::Format::eBc1RgbaSrgbBlock:
|
|
case vk::Format::eBc1RgbaUnormBlock: return Bc1Rgba | Bit64;
|
|
case vk::Format::eBc2SrgbBlock:
|
|
case vk::Format::eBc2UnormBlock: return Bc2 | Bit128;
|
|
case vk::Format::eBc3SrgbBlock:
|
|
case vk::Format::eBc3UnormBlock: return Bc3 | Bit128;
|
|
case vk::Format::eBc4SnormBlock:
|
|
case vk::Format::eBc4UnormBlock: return Bc4 | Bit64;
|
|
case vk::Format::eBc5SnormBlock:
|
|
case vk::Format::eBc5UnormBlock: return Bc5 | Bit128;
|
|
case vk::Format::eBc6HSfloatBlock:
|
|
case vk::Format::eBc6HUfloatBlock: return Bc6h | Bit128;
|
|
case vk::Format::eBc7SrgbBlock:
|
|
case vk::Format::eBc7UnormBlock: return Bc7 | Bit128;
|
|
|
|
case vk::Format::eD16Unorm: return D16;
|
|
case vk::Format::eD16UnormS8Uint: return D16S8;
|
|
case vk::Format::eX8D24UnormPack32: return D24;
|
|
case vk::Format::eD24UnormS8Uint: return D24S8;
|
|
case vk::Format::eD32Sfloat: return D32;
|
|
case vk::Format::eD32SfloatS8Uint: return D32S8;
|
|
case vk::Format::eS8Uint: return S8;
|
|
default: return None;
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
vk::ImageAspectFlags DepthAspectMask(vk::Format format) {
|
|
switch (format) {
|
|
case vk::Format::eD16Unorm:
|
|
case vk::Format::eD32Sfloat: return vk::ImageAspectFlagBits::eDepth;
|
|
case vk::Format::eD16UnormS8Uint:
|
|
case vk::Format::eD24UnormS8Uint:
|
|
case vk::Format::eD32SfloatS8Uint:
|
|
return vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
|
|
default: EXIT("unsupported depth/stencil image format: %d\n", static_cast<int>(format));
|
|
}
|
|
}
|
|
|
|
bool FormatsCompatible(vk::Format base, vk::Format view) noexcept {
|
|
if (base == view) {
|
|
return true;
|
|
}
|
|
const auto base_class = FormatClass(base);
|
|
const auto view_class = FormatClass(view);
|
|
return view_class != None && (base_class & view_class) == view_class;
|
|
}
|
|
|
|
} // namespace ImageViewOps
|
|
|
|
vk::ImageView Image::FindView(const ImageViewInfo& view_info) {
|
|
const auto& image = backing;
|
|
auto normalized = view_info;
|
|
const bool is_storage = static_cast<bool>(normalized.usage & vk::ImageUsageFlagBits::eStorage);
|
|
normalized.aspect = FullAspectMask(image.format);
|
|
if (normalized.aspect & vk::ImageAspectFlagBits::eDepth &&
|
|
IsDepthViewFormat(normalized.format)) {
|
|
normalized.format = image.format;
|
|
normalized.aspect = vk::ImageAspectFlagBits::eDepth;
|
|
}
|
|
if (normalized.aspect & vk::ImageAspectFlagBits::eStencil &&
|
|
IsStencilViewFormat(normalized.format)) {
|
|
normalized.format = image.format;
|
|
normalized.aspect = vk::ImageAspectFlagBits::eStencil;
|
|
}
|
|
normalized.usage = is_storage ? vk::ImageUsageFlagBits::eStorage : vk::ImageUsageFlags {};
|
|
const bool format_compatible = normalized.format != vk::Format::eUndefined &&
|
|
IsCompatibleViewFormat(image.format, normalized.format);
|
|
const bool slice_view =
|
|
image.image_type == vk::ImageType::e3D && (normalized.type == vk::ImageViewType::e2D ||
|
|
normalized.type == vk::ImageViewType::e2DArray);
|
|
const bool levels_valid = normalized.level_count != 0 &&
|
|
normalized.base_level < image.mip_levels &&
|
|
normalized.level_count <= image.mip_levels - normalized.base_level;
|
|
const auto view_layers = slice_view && levels_valid
|
|
? std::max(image.extent.depth >> normalized.base_level, 1u)
|
|
: image.layers;
|
|
const bool ranges_valid = levels_valid && normalized.layer_count != 0 &&
|
|
normalized.base_layer < view_layers &&
|
|
normalized.layer_count <= view_layers - normalized.base_layer;
|
|
const bool mapping_valid =
|
|
IsComponentSwizzle(normalized.mapping.r) && IsComponentSwizzle(normalized.mapping.g) &&
|
|
IsComponentSwizzle(normalized.mapping.b) && IsComponentSwizzle(normalized.mapping.a);
|
|
if (image.image == nullptr || !format_compatible || !ranges_valid || !mapping_valid ||
|
|
!IsValidViewType(image, normalized) || !IsValidAspect(image, normalized.aspect)) {
|
|
EXIT("invalid image view: image_format=%d view_format=%d type=%d aspect=0x%x "
|
|
"mip=%u+%u layer=%u+%u usage=0x%x image_levels=%u image_layers=%u\n",
|
|
static_cast<int>(image.format), static_cast<int>(normalized.format),
|
|
static_cast<int>(normalized.type),
|
|
static_cast<vk::ImageAspectFlags::MaskType>(normalized.aspect), normalized.base_level,
|
|
normalized.level_count, normalized.base_layer, normalized.layer_count,
|
|
static_cast<vk::ImageUsageFlags::MaskType>(normalized.usage), image.mip_levels,
|
|
image.layers);
|
|
}
|
|
|
|
std::lock_guard lock(views.mutex);
|
|
for (const auto& cached: views.views) {
|
|
if (cached.info == normalized) {
|
|
return cached.view;
|
|
}
|
|
}
|
|
|
|
vk::ImageViewUsageCreateInfo usage {};
|
|
usage.sType = vk::StructureType::eImageViewUsageCreateInfo;
|
|
usage.usage = image.usage;
|
|
if (!is_storage) {
|
|
usage.usage &= ~vk::ImageUsageFlagBits::eStorage;
|
|
}
|
|
vk::ImageViewCreateInfo create {};
|
|
create.sType = vk::StructureType::eImageViewCreateInfo;
|
|
create.pNext = &usage;
|
|
create.image = image.image;
|
|
create.viewType = normalized.type;
|
|
create.format = normalized.format;
|
|
create.components = normalized.mapping;
|
|
create.subresourceRange.aspectMask = normalized.aspect;
|
|
create.subresourceRange.baseMipLevel = normalized.base_level;
|
|
create.subresourceRange.levelCount = normalized.level_count;
|
|
create.subresourceRange.baseArrayLayer = normalized.base_layer;
|
|
create.subresourceRange.layerCount = normalized.layer_count;
|
|
|
|
vk::ImageView view = nullptr;
|
|
const auto result = m_graphics->device.createImageView(&create, nullptr, &view);
|
|
if (result != vk::Result::eSuccess || view == nullptr) {
|
|
EXIT("failed to create image view: result=%d image_format=%d view_format=%d type=%d "
|
|
"aspect=0x%x mip=%u+%u layer=%u+%u usage=0x%x\n",
|
|
static_cast<int>(result), static_cast<int>(image.format),
|
|
static_cast<int>(view_info.format), static_cast<int>(view_info.type),
|
|
static_cast<vk::ImageAspectFlags::MaskType>(view_info.aspect), view_info.base_level,
|
|
view_info.level_count, view_info.base_layer, view_info.layer_count,
|
|
static_cast<vk::ImageUsageFlags::MaskType>(view_info.usage));
|
|
}
|
|
views.views.push_back({normalized, view});
|
|
return view;
|
|
}
|
|
|
|
} // namespace Libs::Graphics
|