2020-01-14 00:36:03 +01:00
|
|
|
// Copyright 2019 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <array>
|
2020-12-30 06:25:23 +01:00
|
|
|
#include <span>
|
2020-01-14 00:36:03 +01:00
|
|
|
#include <vector>
|
|
|
|
|
2021-04-12 12:04:55 +02:00
|
|
|
#include "common/bit_cast.h"
|
2021-06-13 21:38:54 +02:00
|
|
|
#include "common/settings.h"
|
2021-04-12 12:04:55 +02:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
#include "video_core/engines/fermi_2d.h"
|
|
|
|
#include "video_core/renderer_vulkan/blit_image.h"
|
2020-01-14 00:36:03 +01:00
|
|
|
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
2021-02-13 22:49:24 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_compute_pass.h"
|
2020-12-26 05:19:46 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
2020-02-21 00:35:53 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
2020-01-14 00:36:03 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
2020-12-26 05:19:46 +01:00
|
|
|
#include "video_core/vulkan_common/vulkan_device.h"
|
2021-01-03 22:17:57 +01:00
|
|
|
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
2020-12-25 01:30:11 +01:00
|
|
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
2020-01-14 00:36:03 +01:00
|
|
|
|
|
|
|
namespace Vulkan {
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
using Tegra::Engines::Fermi2D;
|
2020-01-14 00:36:03 +01:00
|
|
|
using Tegra::Texture::SwizzleSource;
|
2020-12-30 06:25:23 +01:00
|
|
|
using Tegra::Texture::TextureMipmapFilter;
|
|
|
|
using VideoCommon::BufferImageCopy;
|
|
|
|
using VideoCommon::ImageInfo;
|
|
|
|
using VideoCommon::ImageType;
|
|
|
|
using VideoCommon::SubresourceRange;
|
|
|
|
using VideoCore::Surface::IsPixelFormatASTC;
|
2020-01-14 00:36:03 +01:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
constexpr std::array ATTACHMENT_REFERENCES{
|
|
|
|
VkAttachmentReference{0, VK_IMAGE_LAYOUT_GENERAL},
|
|
|
|
VkAttachmentReference{1, VK_IMAGE_LAYOUT_GENERAL},
|
|
|
|
VkAttachmentReference{2, VK_IMAGE_LAYOUT_GENERAL},
|
|
|
|
VkAttachmentReference{3, VK_IMAGE_LAYOUT_GENERAL},
|
|
|
|
VkAttachmentReference{4, VK_IMAGE_LAYOUT_GENERAL},
|
|
|
|
VkAttachmentReference{5, VK_IMAGE_LAYOUT_GENERAL},
|
|
|
|
VkAttachmentReference{6, VK_IMAGE_LAYOUT_GENERAL},
|
|
|
|
VkAttachmentReference{7, VK_IMAGE_LAYOUT_GENERAL},
|
|
|
|
VkAttachmentReference{8, VK_IMAGE_LAYOUT_GENERAL},
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
|
|
|
if (color == std::array<float, 4>{0, 0, 0, 0}) {
|
|
|
|
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
|
|
|
} else if (color == std::array<float, 4>{0, 0, 0, 1}) {
|
|
|
|
return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
|
|
|
|
} else if (color == std::array<float, 4>{1, 1, 1, 1}) {
|
|
|
|
return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
|
|
|
}
|
|
|
|
if (color[0] + color[1] + color[2] > 1.35f) {
|
|
|
|
// If color elements are brighter than roughly 0.5 average, use white border
|
|
|
|
return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
|
|
|
} else if (color[3] > 0.5f) {
|
|
|
|
return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
|
|
|
|
} else {
|
|
|
|
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] VkImageType ConvertImageType(const ImageType type) {
|
|
|
|
switch (type) {
|
|
|
|
case ImageType::e1D:
|
2020-03-27 05:33:21 +01:00
|
|
|
return VK_IMAGE_TYPE_1D;
|
2020-12-30 06:25:23 +01:00
|
|
|
case ImageType::e2D:
|
|
|
|
case ImageType::Linear:
|
2020-03-27 05:33:21 +01:00
|
|
|
return VK_IMAGE_TYPE_2D;
|
2020-12-30 06:25:23 +01:00
|
|
|
case ImageType::e3D:
|
2020-03-27 05:33:21 +01:00
|
|
|
return VK_IMAGE_TYPE_3D;
|
2020-12-30 06:25:23 +01:00
|
|
|
case ImageType::Buffer:
|
|
|
|
break;
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
UNREACHABLE_MSG("Invalid image type={}", type);
|
2020-01-14 00:36:03 +01:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkSampleCountFlagBits ConvertSampleCount(u32 num_samples) {
|
|
|
|
switch (num_samples) {
|
|
|
|
case 1:
|
|
|
|
return VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
case 2:
|
|
|
|
return VK_SAMPLE_COUNT_2_BIT;
|
|
|
|
case 4:
|
|
|
|
return VK_SAMPLE_COUNT_4_BIT;
|
|
|
|
case 8:
|
|
|
|
return VK_SAMPLE_COUNT_8_BIT;
|
|
|
|
case 16:
|
|
|
|
return VK_SAMPLE_COUNT_16_BIT;
|
|
|
|
default:
|
|
|
|
UNREACHABLE_MSG("Invalid number of samples={}", num_samples);
|
|
|
|
return VK_SAMPLE_COUNT_1_BIT;
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 01:37:17 +01:00
|
|
|
[[nodiscard]] VkImageUsageFlags ImageUsageFlags(const MaxwellToVK::FormatInfo& info,
|
|
|
|
PixelFormat format) {
|
2020-12-30 06:25:23 +01:00
|
|
|
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
|
|
|
VK_IMAGE_USAGE_SAMPLED_BIT;
|
2021-01-16 01:37:17 +01:00
|
|
|
if (info.attachable) {
|
|
|
|
switch (VideoCore::Surface::GetFormatType(format)) {
|
2020-12-30 06:25:23 +01:00
|
|
|
case VideoCore::Surface::SurfaceType::ColorTexture:
|
|
|
|
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
|
|
break;
|
|
|
|
case VideoCore::Surface::SurfaceType::Depth:
|
|
|
|
case VideoCore::Surface::SurfaceType::DepthStencil:
|
|
|
|
usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE_MSG("Invalid surface type");
|
|
|
|
}
|
|
|
|
}
|
2021-01-16 01:37:17 +01:00
|
|
|
if (info.storage) {
|
2020-12-30 06:25:23 +01:00
|
|
|
usage |= VK_IMAGE_USAGE_STORAGE_BIT;
|
|
|
|
}
|
2021-01-16 01:37:17 +01:00
|
|
|
return usage;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the preferred format for a VkImage
|
|
|
|
[[nodiscard]] PixelFormat StorageFormat(PixelFormat format) {
|
|
|
|
switch (format) {
|
|
|
|
case PixelFormat::A8B8G8R8_SRGB:
|
|
|
|
return PixelFormat::A8B8G8R8_UNORM;
|
|
|
|
default:
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info) {
|
|
|
|
const PixelFormat format = StorageFormat(info.format);
|
|
|
|
const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format);
|
|
|
|
VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
|
|
|
|
if (info.type == ImageType::e2D && info.resources.layers >= 6 &&
|
|
|
|
info.size.width == info.size.height) {
|
|
|
|
flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
|
|
|
}
|
|
|
|
if (info.type == ImageType::e3D) {
|
|
|
|
flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
|
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples);
|
|
|
|
return VkImageCreateInfo{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
2020-07-17 01:42:47 +02:00
|
|
|
.pNext = nullptr,
|
2020-12-30 06:25:23 +01:00
|
|
|
.flags = flags,
|
|
|
|
.imageType = ConvertImageType(info.type),
|
|
|
|
.format = format_info.format,
|
2021-01-16 01:37:17 +01:00
|
|
|
.extent{
|
|
|
|
.width = info.size.width >> samples_x,
|
|
|
|
.height = info.size.height >> samples_y,
|
|
|
|
.depth = info.size.depth,
|
|
|
|
},
|
2020-12-30 06:25:23 +01:00
|
|
|
.mipLevels = static_cast<u32>(info.resources.levels),
|
|
|
|
.arrayLayers = static_cast<u32>(info.resources.layers),
|
|
|
|
.samples = ConvertSampleCount(info.num_samples),
|
|
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
2021-01-16 01:37:17 +01:00
|
|
|
.usage = ImageUsageFlags(format_info, format),
|
2020-07-17 01:42:47 +02:00
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
.queueFamilyIndexCount = 0,
|
|
|
|
.pQueueFamilyIndices = nullptr,
|
2020-12-30 06:25:23 +01:00
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
2020-07-17 01:42:47 +02:00
|
|
|
};
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-26 05:10:53 +01:00
|
|
|
[[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info) {
|
2020-12-30 06:25:23 +01:00
|
|
|
if (info.type == ImageType::Buffer) {
|
|
|
|
return vk::Image{};
|
|
|
|
}
|
|
|
|
return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info));
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-26 05:10:53 +01:00
|
|
|
[[nodiscard]] vk::Buffer MakeBuffer(const Device& device, const ImageInfo& info) {
|
2020-12-30 06:25:23 +01:00
|
|
|
if (info.type != ImageType::Buffer) {
|
|
|
|
return vk::Buffer{};
|
|
|
|
}
|
|
|
|
const size_t bytes_per_block = VideoCore::Surface::BytesPerBlock(info.format);
|
|
|
|
return device.GetLogical().CreateBuffer(VkBufferCreateInfo{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
2020-07-17 01:42:47 +02:00
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
2020-12-30 06:25:23 +01:00
|
|
|
.size = info.size.width * bytes_per_block,
|
|
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
|
|
|
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
|
|
|
|
VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
|
2020-07-17 01:42:47 +02:00
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
.queueFamilyIndexCount = 0,
|
|
|
|
.pQueueFamilyIndices = nullptr,
|
2020-12-30 06:25:23 +01:00
|
|
|
});
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) {
|
|
|
|
switch (VideoCore::Surface::GetFormatType(format)) {
|
|
|
|
case VideoCore::Surface::SurfaceType::ColorTexture:
|
|
|
|
return VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
case VideoCore::Surface::SurfaceType::Depth:
|
|
|
|
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
case VideoCore::Surface::SurfaceType::DepthStencil:
|
|
|
|
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
|
|
default:
|
|
|
|
UNREACHABLE_MSG("Invalid surface type");
|
|
|
|
return VkImageAspectFlags{};
|
|
|
|
}
|
2020-05-30 04:32:41 +02:00
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkImageAspectFlags ImageViewAspectMask(const VideoCommon::ImageViewInfo& info) {
|
|
|
|
if (info.IsRenderTarget()) {
|
|
|
|
return ImageAspectMask(info.format);
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
const bool is_first = info.Swizzle()[0] == SwizzleSource::R;
|
|
|
|
switch (info.format) {
|
|
|
|
case PixelFormat::D24_UNORM_S8_UINT:
|
|
|
|
case PixelFormat::D32_FLOAT_S8_UINT:
|
|
|
|
return is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
|
|
case PixelFormat::S8_UINT_D24_UNORM:
|
|
|
|
return is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
case PixelFormat::D16_UNORM:
|
|
|
|
case PixelFormat::D32_FLOAT:
|
|
|
|
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
default:
|
|
|
|
return VK_IMAGE_ASPECT_COLOR_BIT;
|
2020-05-30 04:32:41 +02:00
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-26 05:10:53 +01:00
|
|
|
[[nodiscard]] VkAttachmentDescription AttachmentDescription(const Device& device,
|
2020-12-30 06:25:23 +01:00
|
|
|
const ImageView* image_view) {
|
2021-01-16 01:37:17 +01:00
|
|
|
using MaxwellToVK::SurfaceFormat;
|
|
|
|
const PixelFormat pixel_format = image_view->format;
|
2020-12-30 06:25:23 +01:00
|
|
|
return VkAttachmentDescription{
|
|
|
|
.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT,
|
2021-01-16 01:37:17 +01:00
|
|
|
.format = SurfaceFormat(device, FormatType::Optimal, true, pixel_format).format,
|
2020-12-30 06:25:23 +01:00
|
|
|
.samples = image_view->Samples(),
|
|
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
|
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
|
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
};
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkComponentSwizzle ComponentSwizzle(SwizzleSource swizzle) {
|
|
|
|
switch (swizzle) {
|
|
|
|
case SwizzleSource::Zero:
|
|
|
|
return VK_COMPONENT_SWIZZLE_ZERO;
|
|
|
|
case SwizzleSource::R:
|
|
|
|
return VK_COMPONENT_SWIZZLE_R;
|
|
|
|
case SwizzleSource::G:
|
|
|
|
return VK_COMPONENT_SWIZZLE_G;
|
|
|
|
case SwizzleSource::B:
|
|
|
|
return VK_COMPONENT_SWIZZLE_B;
|
|
|
|
case SwizzleSource::A:
|
|
|
|
return VK_COMPONENT_SWIZZLE_A;
|
|
|
|
case SwizzleSource::OneFloat:
|
|
|
|
case SwizzleSource::OneInt:
|
|
|
|
return VK_COMPONENT_SWIZZLE_ONE;
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
UNREACHABLE_MSG("Invalid swizzle={}", swizzle);
|
|
|
|
return VK_COMPONENT_SWIZZLE_ZERO;
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkImageViewType ImageViewType(VideoCommon::ImageViewType type) {
|
|
|
|
switch (type) {
|
|
|
|
case VideoCommon::ImageViewType::e1D:
|
|
|
|
return VK_IMAGE_VIEW_TYPE_1D;
|
|
|
|
case VideoCommon::ImageViewType::e2D:
|
|
|
|
return VK_IMAGE_VIEW_TYPE_2D;
|
|
|
|
case VideoCommon::ImageViewType::Cube:
|
|
|
|
return VK_IMAGE_VIEW_TYPE_CUBE;
|
|
|
|
case VideoCommon::ImageViewType::e3D:
|
|
|
|
return VK_IMAGE_VIEW_TYPE_3D;
|
|
|
|
case VideoCommon::ImageViewType::e1DArray:
|
|
|
|
return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
|
|
|
case VideoCommon::ImageViewType::e2DArray:
|
|
|
|
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
|
|
|
case VideoCommon::ImageViewType::CubeArray:
|
|
|
|
return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
|
|
|
case VideoCommon::ImageViewType::Rect:
|
|
|
|
LOG_WARNING(Render_Vulkan, "Unnormalized image view type not supported");
|
|
|
|
return VK_IMAGE_VIEW_TYPE_2D;
|
|
|
|
case VideoCommon::ImageViewType::Buffer:
|
|
|
|
UNREACHABLE_MSG("Texture buffers can't be image views");
|
|
|
|
return VK_IMAGE_VIEW_TYPE_1D;
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
UNREACHABLE_MSG("Invalid image view type={}", type);
|
|
|
|
return VK_IMAGE_VIEW_TYPE_2D;
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkImageSubresourceLayers MakeImageSubresourceLayers(
|
|
|
|
VideoCommon::SubresourceLayers subresource, VkImageAspectFlags aspect_mask) {
|
|
|
|
return VkImageSubresourceLayers{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.mipLevel = static_cast<u32>(subresource.base_level),
|
|
|
|
.baseArrayLayer = static_cast<u32>(subresource.base_layer),
|
|
|
|
.layerCount = static_cast<u32>(subresource.num_layers),
|
|
|
|
};
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkOffset3D MakeOffset3D(VideoCommon::Offset3D offset3d) {
|
|
|
|
return VkOffset3D{
|
|
|
|
.x = offset3d.x,
|
|
|
|
.y = offset3d.y,
|
|
|
|
.z = offset3d.z,
|
|
|
|
};
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkExtent3D MakeExtent3D(VideoCommon::Extent3D extent3d) {
|
|
|
|
return VkExtent3D{
|
|
|
|
.width = static_cast<u32>(extent3d.width),
|
|
|
|
.height = static_cast<u32>(extent3d.height),
|
|
|
|
.depth = static_cast<u32>(extent3d.depth),
|
|
|
|
};
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkImageCopy MakeImageCopy(const VideoCommon::ImageCopy& copy,
|
|
|
|
VkImageAspectFlags aspect_mask) noexcept {
|
|
|
|
return VkImageCopy{
|
|
|
|
.srcSubresource = MakeImageSubresourceLayers(copy.src_subresource, aspect_mask),
|
|
|
|
.srcOffset = MakeOffset3D(copy.src_offset),
|
|
|
|
.dstSubresource = MakeImageSubresourceLayers(copy.dst_subresource, aspect_mask),
|
|
|
|
.dstOffset = MakeOffset3D(copy.dst_offset),
|
|
|
|
.extent = MakeExtent3D(copy.extent),
|
|
|
|
};
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies(
|
|
|
|
std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) {
|
|
|
|
std::vector<VkBufferCopy> result(copies.size());
|
|
|
|
std::ranges::transform(
|
|
|
|
copies, result.begin(), [buffer_offset](const VideoCommon::BufferCopy& copy) {
|
|
|
|
return VkBufferCopy{
|
|
|
|
.srcOffset = static_cast<VkDeviceSize>(copy.src_offset + buffer_offset),
|
|
|
|
.dstOffset = static_cast<VkDeviceSize>(copy.dst_offset),
|
|
|
|
.size = static_cast<VkDeviceSize>(copy.size),
|
|
|
|
};
|
|
|
|
});
|
|
|
|
return result;
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] std::vector<VkBufferImageCopy> TransformBufferImageCopies(
|
|
|
|
std::span<const BufferImageCopy> copies, size_t buffer_offset, VkImageAspectFlags aspect_mask) {
|
|
|
|
struct Maker {
|
|
|
|
VkBufferImageCopy operator()(const BufferImageCopy& copy) const {
|
|
|
|
return VkBufferImageCopy{
|
|
|
|
.bufferOffset = copy.buffer_offset + buffer_offset,
|
|
|
|
.bufferRowLength = copy.buffer_row_length,
|
|
|
|
.bufferImageHeight = copy.buffer_image_height,
|
|
|
|
.imageSubresource =
|
|
|
|
{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.mipLevel = static_cast<u32>(copy.image_subresource.base_level),
|
|
|
|
.baseArrayLayer = static_cast<u32>(copy.image_subresource.base_layer),
|
|
|
|
.layerCount = static_cast<u32>(copy.image_subresource.num_layers),
|
|
|
|
},
|
|
|
|
.imageOffset =
|
|
|
|
{
|
|
|
|
.x = copy.image_offset.x,
|
|
|
|
.y = copy.image_offset.y,
|
|
|
|
.z = copy.image_offset.z,
|
|
|
|
},
|
|
|
|
.imageExtent =
|
|
|
|
{
|
|
|
|
.width = copy.image_extent.width,
|
|
|
|
.height = copy.image_extent.height,
|
|
|
|
.depth = copy.image_extent.depth,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
size_t buffer_offset;
|
|
|
|
VkImageAspectFlags aspect_mask;
|
|
|
|
};
|
|
|
|
if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
|
|
|
std::vector<VkBufferImageCopy> result(copies.size() * 2);
|
|
|
|
std::ranges::transform(copies, result.begin(),
|
|
|
|
Maker{buffer_offset, VK_IMAGE_ASPECT_DEPTH_BIT});
|
|
|
|
std::ranges::transform(copies, result.begin() + copies.size(),
|
|
|
|
Maker{buffer_offset, VK_IMAGE_ASPECT_STENCIL_BIT});
|
|
|
|
return result;
|
|
|
|
} else {
|
|
|
|
std::vector<VkBufferImageCopy> result(copies.size());
|
|
|
|
std::ranges::transform(copies, result.begin(), Maker{buffer_offset, aspect_mask});
|
|
|
|
return result;
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(VkImageAspectFlags aspect_mask,
|
|
|
|
const SubresourceRange& range) {
|
|
|
|
return VkImageSubresourceRange{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.baseMipLevel = static_cast<u32>(range.base.level),
|
|
|
|
.levelCount = static_cast<u32>(range.extent.levels),
|
|
|
|
.baseArrayLayer = static_cast<u32>(range.base.layer),
|
|
|
|
.layerCount = static_cast<u32>(range.extent.layers),
|
|
|
|
};
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(const ImageView* image_view) {
|
|
|
|
SubresourceRange range = image_view->range;
|
|
|
|
if (True(image_view->flags & VideoCommon::ImageViewFlagBits::Slice)) {
|
|
|
|
// Slice image views always affect a single layer, but their subresource range corresponds
|
|
|
|
// to the slice. Override the value to affect a single layer.
|
|
|
|
range.base.layer = 0;
|
|
|
|
range.extent.layers = 1;
|
|
|
|
}
|
|
|
|
return MakeSubresourceRange(ImageAspectMask(image_view->format), range);
|
|
|
|
}
|
2020-03-27 05:33:21 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] VkImageSubresourceLayers MakeSubresourceLayers(const ImageView* image_view) {
|
|
|
|
return VkImageSubresourceLayers{
|
|
|
|
.aspectMask = ImageAspectMask(image_view->format),
|
|
|
|
.mipLevel = static_cast<u32>(image_view->range.base.level),
|
|
|
|
.baseArrayLayer = static_cast<u32>(image_view->range.base.layer),
|
|
|
|
.layerCount = static_cast<u32>(image_view->range.extent.layers),
|
|
|
|
};
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2021-04-25 05:59:42 +02:00
|
|
|
[[nodiscard]] SwizzleSource ConvertGreenRed(SwizzleSource value) {
|
2020-12-30 06:25:23 +01:00
|
|
|
switch (value) {
|
|
|
|
case SwizzleSource::G:
|
|
|
|
return SwizzleSource::R;
|
|
|
|
default:
|
|
|
|
return value;
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-25 05:59:42 +02:00
|
|
|
[[nodiscard]] SwizzleSource SwapBlueRed(SwizzleSource value) {
|
|
|
|
switch (value) {
|
|
|
|
case SwizzleSource::R:
|
|
|
|
return SwizzleSource::B;
|
|
|
|
case SwizzleSource::B:
|
|
|
|
return SwizzleSource::R;
|
|
|
|
default:
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage image,
|
|
|
|
VkImageAspectFlags aspect_mask, bool is_initialized,
|
|
|
|
std::span<const VkBufferImageCopy> copies) {
|
2021-01-17 00:48:58 +01:00
|
|
|
static constexpr VkAccessFlags WRITE_ACCESS_FLAGS =
|
|
|
|
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
|
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
|
|
|
static constexpr VkAccessFlags READ_ACCESS_FLAGS = VK_ACCESS_SHADER_READ_BIT |
|
|
|
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
|
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
2020-12-30 06:25:23 +01:00
|
|
|
const VkImageMemoryBarrier read_barrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
2021-01-17 00:48:58 +01:00
|
|
|
.srcAccessMask = WRITE_ACCESS_FLAGS,
|
2020-12-30 06:25:23 +01:00
|
|
|
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = image,
|
2021-01-17 00:48:58 +01:00
|
|
|
.subresourceRange{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
|
|
|
},
|
2020-12-30 06:25:23 +01:00
|
|
|
};
|
|
|
|
const VkImageMemoryBarrier write_barrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
2021-01-17 00:48:58 +01:00
|
|
|
.dstAccessMask = WRITE_ACCESS_FLAGS | READ_ACCESS_FLAGS,
|
2020-12-30 06:25:23 +01:00
|
|
|
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = image,
|
2021-01-17 00:48:58 +01:00
|
|
|
.subresourceRange{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
|
|
|
},
|
2020-07-17 01:42:47 +02:00
|
|
|
};
|
2020-12-30 06:25:23 +01:00
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
|
|
|
read_barrier);
|
|
|
|
cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies);
|
|
|
|
// TODO: Move this to another API
|
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
|
|
|
|
write_barrier);
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2021-05-08 04:14:21 +02:00
|
|
|
[[nodiscard]] VkImageBlit MakeImageBlit(const Region2D& dst_region, const Region2D& src_region,
|
2020-12-30 06:25:23 +01:00
|
|
|
const VkImageSubresourceLayers& dst_layers,
|
|
|
|
const VkImageSubresourceLayers& src_layers) {
|
|
|
|
return VkImageBlit{
|
|
|
|
.srcSubresource = src_layers,
|
|
|
|
.srcOffsets =
|
|
|
|
{
|
|
|
|
{
|
2021-05-08 04:14:21 +02:00
|
|
|
.x = src_region.start.x,
|
|
|
|
.y = src_region.start.y,
|
2020-12-30 06:25:23 +01:00
|
|
|
.z = 0,
|
|
|
|
},
|
|
|
|
{
|
2021-05-08 04:14:21 +02:00
|
|
|
.x = src_region.end.x,
|
|
|
|
.y = src_region.end.y,
|
2020-12-30 06:25:23 +01:00
|
|
|
.z = 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.dstSubresource = dst_layers,
|
|
|
|
.dstOffsets =
|
|
|
|
{
|
|
|
|
{
|
2021-05-08 04:14:21 +02:00
|
|
|
.x = dst_region.start.x,
|
|
|
|
.y = dst_region.start.y,
|
2020-12-30 06:25:23 +01:00
|
|
|
.z = 0,
|
|
|
|
},
|
|
|
|
{
|
2021-05-08 04:14:21 +02:00
|
|
|
.x = dst_region.end.x,
|
|
|
|
.y = dst_region.end.y,
|
2020-12-30 06:25:23 +01:00
|
|
|
.z = 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2021-05-08 04:14:21 +02:00
|
|
|
[[nodiscard]] VkImageResolve MakeImageResolve(const Region2D& dst_region,
|
|
|
|
const Region2D& src_region,
|
2020-12-30 06:25:23 +01:00
|
|
|
const VkImageSubresourceLayers& dst_layers,
|
|
|
|
const VkImageSubresourceLayers& src_layers) {
|
|
|
|
return VkImageResolve{
|
|
|
|
.srcSubresource = src_layers,
|
|
|
|
.srcOffset =
|
|
|
|
{
|
2021-05-08 04:14:21 +02:00
|
|
|
.x = src_region.start.x,
|
|
|
|
.y = src_region.start.y,
|
2020-12-30 06:25:23 +01:00
|
|
|
.z = 0,
|
|
|
|
},
|
|
|
|
.dstSubresource = dst_layers,
|
|
|
|
.dstOffset =
|
|
|
|
{
|
2021-05-08 04:14:21 +02:00
|
|
|
.x = dst_region.start.x,
|
|
|
|
.y = dst_region.start.y,
|
2020-12-30 06:25:23 +01:00
|
|
|
.z = 0,
|
|
|
|
},
|
|
|
|
.extent =
|
|
|
|
{
|
2021-05-08 04:14:21 +02:00
|
|
|
.width = static_cast<u32>(dst_region.end.x - dst_region.start.x),
|
|
|
|
.height = static_cast<u32>(dst_region.end.y - dst_region.start.y),
|
2020-12-30 06:25:23 +01:00
|
|
|
.depth = 1,
|
|
|
|
},
|
|
|
|
};
|
2020-05-30 04:32:41 +02:00
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2021-04-25 05:59:42 +02:00
|
|
|
[[nodiscard]] bool IsFormatFlipped(PixelFormat format) {
|
|
|
|
switch (format) {
|
|
|
|
case PixelFormat::A1B5G5R5_UNORM:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
struct RangedBarrierRange {
|
|
|
|
u32 min_mip = std::numeric_limits<u32>::max();
|
|
|
|
u32 max_mip = std::numeric_limits<u32>::min();
|
|
|
|
u32 min_layer = std::numeric_limits<u32>::max();
|
|
|
|
u32 max_layer = std::numeric_limits<u32>::min();
|
|
|
|
|
|
|
|
void AddLayers(const VkImageSubresourceLayers& layers) {
|
|
|
|
min_mip = std::min(min_mip, layers.mipLevel);
|
|
|
|
max_mip = std::max(max_mip, layers.mipLevel + 1);
|
|
|
|
min_layer = std::min(min_layer, layers.baseArrayLayer);
|
|
|
|
max_layer = std::max(max_layer, layers.baseArrayLayer + layers.layerCount);
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
VkImageSubresourceRange SubresourceRange(VkImageAspectFlags aspect_mask) const noexcept {
|
|
|
|
return VkImageSubresourceRange{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.baseMipLevel = min_mip,
|
|
|
|
.levelCount = max_mip - min_mip,
|
|
|
|
.baseArrayLayer = min_layer,
|
|
|
|
.layerCount = max_layer - min_layer,
|
|
|
|
};
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
};
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
} // Anonymous namespace
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
void TextureCacheRuntime::Finish() {
|
|
|
|
scheduler.Finish();
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2021-01-17 00:48:58 +01:00
|
|
|
StagingBufferRef TextureCacheRuntime::UploadStagingBuffer(size_t size) {
|
|
|
|
return staging_buffer_pool.Request(size, MemoryUsage::Upload);
|
2021-01-04 01:05:59 +01:00
|
|
|
}
|
|
|
|
|
2021-01-17 00:48:58 +01:00
|
|
|
StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
|
|
|
|
return staging_buffer_pool.Request(size, MemoryUsage::Download);
|
2020-12-30 06:25:23 +01:00
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
|
2021-05-08 04:14:21 +02:00
|
|
|
const Region2D& dst_region, const Region2D& src_region,
|
2020-12-30 06:25:23 +01:00
|
|
|
Tegra::Engines::Fermi2D::Filter filter,
|
|
|
|
Tegra::Engines::Fermi2D::Operation operation) {
|
|
|
|
const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format);
|
|
|
|
const bool is_dst_msaa = dst.Samples() != VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
const bool is_src_msaa = src.Samples() != VK_SAMPLE_COUNT_1_BIT;
|
2021-07-18 23:56:06 +02:00
|
|
|
if (aspect_mask != ImageAspectMask(dst.format) {
|
|
|
|
UNIMPLEMENTED_MSG("Incompatible blit from format {} to {}", src.format, dst.format));
|
|
|
|
return;
|
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT && !is_src_msaa && !is_dst_msaa) {
|
|
|
|
blit_image_helper.BlitColor(dst_framebuffer, src, dst_region, src_region, filter,
|
|
|
|
operation);
|
|
|
|
return;
|
2020-05-30 04:32:41 +02:00
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
|
|
|
if (!device.IsBlitDepthStencilSupported()) {
|
|
|
|
UNIMPLEMENTED_IF(is_src_msaa || is_dst_msaa);
|
|
|
|
blit_image_helper.BlitDepthStencil(dst_framebuffer, src.DepthView(), src.StencilView(),
|
|
|
|
dst_region, src_region, filter, operation);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT(src.ImageFormat() == dst.ImageFormat());
|
|
|
|
ASSERT(!(is_dst_msaa && !is_src_msaa));
|
|
|
|
ASSERT(operation == Fermi2D::Operation::SrcCopy);
|
|
|
|
|
|
|
|
const VkImage dst_image = dst.ImageHandle();
|
|
|
|
const VkImage src_image = src.ImageHandle();
|
|
|
|
const VkImageSubresourceLayers dst_layers = MakeSubresourceLayers(&dst);
|
|
|
|
const VkImageSubresourceLayers src_layers = MakeSubresourceLayers(&src);
|
|
|
|
const bool is_resolve = is_src_msaa && !is_dst_msaa;
|
|
|
|
scheduler.RequestOutsideRenderPassOperationContext();
|
|
|
|
scheduler.Record([filter, dst_region, src_region, dst_image, src_image, dst_layers, src_layers,
|
|
|
|
aspect_mask, is_resolve](vk::CommandBuffer cmdbuf) {
|
|
|
|
const std::array read_barriers{
|
|
|
|
VkImageMemoryBarrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT |
|
|
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
|
|
|
VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
|
|
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = src_image,
|
|
|
|
.subresourceRange{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
|
|
|
},
|
2020-07-17 01:42:47 +02:00
|
|
|
},
|
2020-12-30 06:25:23 +01:00
|
|
|
VkImageMemoryBarrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT |
|
|
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
|
|
|
VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = dst_image,
|
|
|
|
.subresourceRange{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
VkImageMemoryBarrier write_barrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
|
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
|
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
|
|
|
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = dst_image,
|
|
|
|
.subresourceRange{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
2020-07-17 01:42:47 +02:00
|
|
|
},
|
2020-12-30 06:25:23 +01:00
|
|
|
};
|
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
|
|
0, nullptr, nullptr, read_barriers);
|
|
|
|
if (is_resolve) {
|
|
|
|
cmdbuf.ResolveImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image,
|
|
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
MakeImageResolve(dst_region, src_region, dst_layers, src_layers));
|
|
|
|
} else {
|
|
|
|
const bool is_linear = filter == Fermi2D::Filter::Bilinear;
|
|
|
|
const VkFilter vk_filter = is_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
|
|
|
cmdbuf.BlitImage(
|
|
|
|
src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
MakeImageBlit(dst_region, src_region, dst_layers, src_layers), vk_filter);
|
|
|
|
}
|
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
|
|
|
0, write_barrier);
|
2020-07-17 01:42:47 +02:00
|
|
|
});
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
|
|
|
|
switch (dst_view.format) {
|
|
|
|
case PixelFormat::R16_UNORM:
|
|
|
|
if (src_view.format == PixelFormat::D16_UNORM) {
|
|
|
|
return blit_image_helper.ConvertD16ToR16(dst, src_view);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PixelFormat::R32_FLOAT:
|
|
|
|
if (src_view.format == PixelFormat::D32_FLOAT) {
|
|
|
|
return blit_image_helper.ConvertD32ToR32(dst, src_view);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PixelFormat::D16_UNORM:
|
|
|
|
if (src_view.format == PixelFormat::R16_UNORM) {
|
|
|
|
return blit_image_helper.ConvertR16ToD16(dst, src_view);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PixelFormat::D32_FLOAT:
|
|
|
|
if (src_view.format == PixelFormat::R32_FLOAT) {
|
|
|
|
return blit_image_helper.ConvertR32ToD32(dst, src_view);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2020-05-30 04:32:41 +02:00
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
UNIMPLEMENTED_MSG("Unimplemented format copy from {} to {}", src_view.format, dst_view.format);
|
|
|
|
}
|
2020-05-30 04:32:41 +02:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
|
|
|
|
std::span<const VideoCommon::ImageCopy> copies) {
|
|
|
|
std::vector<VkImageCopy> vk_copies(copies.size());
|
|
|
|
const VkImageAspectFlags aspect_mask = dst.AspectMask();
|
|
|
|
ASSERT(aspect_mask == src.AspectMask());
|
|
|
|
|
|
|
|
std::ranges::transform(copies, vk_copies.begin(), [aspect_mask](const auto& copy) {
|
|
|
|
return MakeImageCopy(copy, aspect_mask);
|
|
|
|
});
|
|
|
|
const VkImage dst_image = dst.Handle();
|
|
|
|
const VkImage src_image = src.Handle();
|
|
|
|
scheduler.RequestOutsideRenderPassOperationContext();
|
|
|
|
scheduler.Record([dst_image, src_image, aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) {
|
|
|
|
RangedBarrierRange dst_range;
|
|
|
|
RangedBarrierRange src_range;
|
|
|
|
for (const VkImageCopy& copy : vk_copies) {
|
|
|
|
dst_range.AddLayers(copy.dstSubresource);
|
|
|
|
src_range.AddLayers(copy.srcSubresource);
|
|
|
|
}
|
|
|
|
const std::array read_barriers{
|
|
|
|
VkImageMemoryBarrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
|
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
|
|
|
VK_ACCESS_TRANSFER_WRITE_BIT,
|
2021-01-17 00:48:58 +01:00
|
|
|
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
2020-12-30 06:25:23 +01:00
|
|
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = src_image,
|
|
|
|
.subresourceRange = src_range.SubresourceRange(aspect_mask),
|
2020-07-17 01:42:47 +02:00
|
|
|
},
|
2020-12-30 06:25:23 +01:00
|
|
|
VkImageMemoryBarrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
2021-01-17 00:48:58 +01:00
|
|
|
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
2020-12-30 06:25:23 +01:00
|
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
2021-01-17 00:48:58 +01:00
|
|
|
VK_ACCESS_TRANSFER_WRITE_BIT,
|
2020-12-30 06:25:23 +01:00
|
|
|
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = dst_image,
|
|
|
|
.subresourceRange = dst_range.SubresourceRange(aspect_mask),
|
2020-07-17 01:42:47 +02:00
|
|
|
},
|
2020-12-30 06:25:23 +01:00
|
|
|
};
|
|
|
|
const VkImageMemoryBarrier write_barrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
|
|
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
|
|
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
|
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
|
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
|
|
|
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = dst_image,
|
|
|
|
.subresourceRange = dst_range.SubresourceRange(aspect_mask),
|
|
|
|
};
|
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
|
|
0, {}, {}, read_barriers);
|
|
|
|
cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image,
|
|
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_copies);
|
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
|
|
|
0, write_barrier);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-06-17 00:29:48 +02:00
|
|
|
u64 TextureCacheRuntime::GetDeviceLocalMemory() const {
|
|
|
|
return device.GetDeviceLocalMemory();
|
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_addr_,
|
|
|
|
VAddr cpu_addr_)
|
|
|
|
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime.scheduler},
|
|
|
|
image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)),
|
|
|
|
aspect_mask(ImageAspectMask(info.format)) {
|
|
|
|
if (image) {
|
2021-01-03 22:38:15 +01:00
|
|
|
commit = runtime.memory_allocator.Commit(image, MemoryUsage::DeviceLocal);
|
2020-05-30 04:32:41 +02:00
|
|
|
} else {
|
2021-01-03 22:38:15 +01:00
|
|
|
commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
|
2020-12-30 06:25:23 +01:00
|
|
|
}
|
|
|
|
if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
|
2021-06-13 21:38:54 +02:00
|
|
|
if (Settings::values.accelerate_astc.GetValue()) {
|
|
|
|
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
|
|
|
|
} else {
|
|
|
|
flags |= VideoCommon::ImageFlagBits::Converted;
|
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
}
|
|
|
|
if (runtime.device.HasDebuggingToolAttached()) {
|
|
|
|
if (image) {
|
|
|
|
image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
|
|
|
|
} else {
|
|
|
|
buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
|
|
|
|
}
|
2020-05-30 04:32:41 +02:00
|
|
|
}
|
2021-02-13 22:49:24 +01:00
|
|
|
static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.usage = VK_IMAGE_USAGE_STORAGE_BIT,
|
|
|
|
};
|
|
|
|
if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
|
2021-02-13 22:08:50 +01:00
|
|
|
const auto& device = runtime.device.GetLogical();
|
|
|
|
storage_image_views.reserve(info.resources.levels);
|
|
|
|
for (s32 level = 0; level < info.resources.levels; ++level) {
|
|
|
|
storage_image_views.push_back(device.CreateImageView(VkImageViewCreateInfo{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
|
|
.pNext = &storage_image_view_usage_create_info,
|
|
|
|
.flags = 0,
|
|
|
|
.image = *image,
|
|
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
|
|
|
|
.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32,
|
|
|
|
.components{
|
|
|
|
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
},
|
|
|
|
.subresourceRange{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.baseMipLevel = static_cast<u32>(level),
|
|
|
|
.levelCount = 1,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
|
|
|
},
|
|
|
|
}));
|
|
|
|
}
|
2021-02-13 22:49:24 +01:00
|
|
|
}
|
2020-05-30 04:32:41 +02:00
|
|
|
}
|
|
|
|
|
2021-06-20 17:07:17 +02:00
|
|
|
Image::~Image() = default;
|
|
|
|
|
2021-01-16 20:20:18 +01:00
|
|
|
void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) {
|
2020-12-30 06:25:23 +01:00
|
|
|
// TODO: Move this to another API
|
|
|
|
scheduler->RequestOutsideRenderPassOperationContext();
|
2021-01-16 20:20:18 +01:00
|
|
|
std::vector vk_copies = TransformBufferImageCopies(copies, map.offset, aspect_mask);
|
2021-01-17 00:48:58 +01:00
|
|
|
const VkBuffer src_buffer = map.buffer;
|
2020-12-30 06:25:23 +01:00
|
|
|
const VkImage vk_image = *image;
|
|
|
|
const VkImageAspectFlags vk_aspect_mask = aspect_mask;
|
|
|
|
const bool is_initialized = std::exchange(initialized, true);
|
|
|
|
scheduler->Record([src_buffer, vk_image, vk_aspect_mask, is_initialized,
|
|
|
|
vk_copies](vk::CommandBuffer cmdbuf) {
|
|
|
|
CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, is_initialized, vk_copies);
|
|
|
|
});
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2021-01-16 20:20:18 +01:00
|
|
|
void Image::UploadMemory(const StagingBufferRef& map,
|
2020-12-30 06:25:23 +01:00
|
|
|
std::span<const VideoCommon::BufferCopy> copies) {
|
|
|
|
// TODO: Move this to another API
|
|
|
|
scheduler->RequestOutsideRenderPassOperationContext();
|
2021-01-16 20:20:18 +01:00
|
|
|
std::vector vk_copies = TransformBufferCopies(copies, map.offset);
|
2021-01-17 00:48:58 +01:00
|
|
|
const VkBuffer src_buffer = map.buffer;
|
2020-12-30 06:25:23 +01:00
|
|
|
const VkBuffer dst_buffer = *buffer;
|
|
|
|
scheduler->Record([src_buffer, dst_buffer, vk_copies](vk::CommandBuffer cmdbuf) {
|
|
|
|
// TODO: Barriers
|
|
|
|
cmdbuf.CopyBuffer(src_buffer, dst_buffer, vk_copies);
|
|
|
|
});
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2021-01-16 20:20:18 +01:00
|
|
|
void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) {
|
|
|
|
std::vector vk_copies = TransformBufferImageCopies(copies, map.offset, aspect_mask);
|
2021-01-17 00:48:58 +01:00
|
|
|
scheduler->Record([buffer = map.buffer, image = *image, aspect_mask = aspect_mask,
|
2020-12-30 06:25:23 +01:00
|
|
|
vk_copies](vk::CommandBuffer cmdbuf) {
|
2021-01-17 00:48:58 +01:00
|
|
|
const VkImageMemoryBarrier read_barrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
|
|
|
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
|
|
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = image,
|
|
|
|
.subresourceRange{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
const VkImageMemoryBarrier image_write_barrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.srcAccessMask = 0,
|
|
|
|
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
|
|
|
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
|
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = image,
|
|
|
|
.subresourceRange{
|
|
|
|
.aspectMask = aspect_mask,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
const VkMemoryBarrier memory_write_barrier{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
|
|
|
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
|
|
|
};
|
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
|
|
0, read_barrier);
|
|
|
|
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, vk_copies);
|
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
|
|
|
0, memory_write_barrier, nullptr, image_write_barrier);
|
2020-12-30 06:25:23 +01:00
|
|
|
});
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
|
|
|
|
ImageId image_id_, Image& image)
|
|
|
|
: VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device},
|
|
|
|
image_handle{image.Handle()}, image_format{image.info.format}, samples{ConvertSampleCount(
|
|
|
|
image.info.num_samples)} {
|
|
|
|
const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info);
|
|
|
|
std::array<SwizzleSource, 4> swizzle{
|
|
|
|
SwizzleSource::R,
|
|
|
|
SwizzleSource::G,
|
|
|
|
SwizzleSource::B,
|
|
|
|
SwizzleSource::A,
|
|
|
|
};
|
|
|
|
if (!info.IsRenderTarget()) {
|
|
|
|
swizzle = info.Swizzle();
|
2021-04-25 05:59:42 +02:00
|
|
|
if (IsFormatFlipped(format)) {
|
|
|
|
std::ranges::transform(swizzle, swizzle.begin(), SwapBlueRed);
|
|
|
|
}
|
2020-12-30 06:25:23 +01:00
|
|
|
if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
|
|
|
|
std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed);
|
|
|
|
}
|
|
|
|
}
|
2021-01-16 01:37:17 +01:00
|
|
|
const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format);
|
|
|
|
const VkImageViewUsageCreateInfo image_view_usage{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.usage = ImageUsageFlags(format_info, format),
|
|
|
|
};
|
2020-12-30 06:25:23 +01:00
|
|
|
const VkImageViewCreateInfo create_info{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
2021-01-16 01:37:17 +01:00
|
|
|
.pNext = &image_view_usage,
|
2020-12-30 06:25:23 +01:00
|
|
|
.flags = 0,
|
|
|
|
.image = image.Handle(),
|
|
|
|
.viewType = VkImageViewType{},
|
2021-02-13 22:49:24 +01:00
|
|
|
.format = format_info.format,
|
2020-12-30 06:25:23 +01:00
|
|
|
.components{
|
|
|
|
.r = ComponentSwizzle(swizzle[0]),
|
|
|
|
.g = ComponentSwizzle(swizzle[1]),
|
|
|
|
.b = ComponentSwizzle(swizzle[2]),
|
|
|
|
.a = ComponentSwizzle(swizzle[3]),
|
|
|
|
},
|
|
|
|
.subresourceRange = MakeSubresourceRange(aspect_mask, info.range),
|
|
|
|
};
|
|
|
|
const auto create = [&](VideoCommon::ImageViewType view_type, std::optional<u32> num_layers) {
|
|
|
|
VkImageViewCreateInfo ci{create_info};
|
|
|
|
ci.viewType = ImageViewType(view_type);
|
|
|
|
if (num_layers) {
|
|
|
|
ci.subresourceRange.layerCount = *num_layers;
|
|
|
|
}
|
|
|
|
vk::ImageView handle = device->GetLogical().CreateImageView(ci);
|
|
|
|
if (device->HasDebuggingToolAttached()) {
|
|
|
|
handle.SetObjectNameEXT(VideoCommon::Name(*this, view_type).c_str());
|
|
|
|
}
|
|
|
|
image_views[static_cast<size_t>(view_type)] = std::move(handle);
|
|
|
|
};
|
|
|
|
switch (info.type) {
|
|
|
|
case VideoCommon::ImageViewType::e1D:
|
|
|
|
case VideoCommon::ImageViewType::e1DArray:
|
|
|
|
create(VideoCommon::ImageViewType::e1D, 1);
|
|
|
|
create(VideoCommon::ImageViewType::e1DArray, std::nullopt);
|
|
|
|
render_target = Handle(VideoCommon::ImageViewType::e1DArray);
|
|
|
|
break;
|
|
|
|
case VideoCommon::ImageViewType::e2D:
|
|
|
|
case VideoCommon::ImageViewType::e2DArray:
|
|
|
|
create(VideoCommon::ImageViewType::e2D, 1);
|
|
|
|
create(VideoCommon::ImageViewType::e2DArray, std::nullopt);
|
|
|
|
render_target = Handle(VideoCommon::ImageViewType::e2DArray);
|
|
|
|
break;
|
|
|
|
case VideoCommon::ImageViewType::e3D:
|
|
|
|
create(VideoCommon::ImageViewType::e3D, std::nullopt);
|
|
|
|
render_target = Handle(VideoCommon::ImageViewType::e3D);
|
|
|
|
break;
|
|
|
|
case VideoCommon::ImageViewType::Cube:
|
|
|
|
case VideoCommon::ImageViewType::CubeArray:
|
|
|
|
create(VideoCommon::ImageViewType::Cube, 6);
|
|
|
|
create(VideoCommon::ImageViewType::CubeArray, std::nullopt);
|
|
|
|
break;
|
|
|
|
case VideoCommon::ImageViewType::Rect:
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
break;
|
|
|
|
case VideoCommon::ImageViewType::Buffer:
|
|
|
|
buffer_view = device->GetLogical().CreateBufferView(VkBufferViewCreateInfo{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
|
|
|
.buffer = image.Buffer(),
|
2021-02-13 22:49:24 +01:00
|
|
|
.format = format_info.format,
|
2020-12-30 06:25:23 +01:00
|
|
|
.offset = 0, // TODO: Redesign buffer cache to support this
|
|
|
|
.range = image.guest_size_bytes,
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::NullImageParams& params)
|
|
|
|
: VideoCommon::ImageViewBase{params} {}
|
2020-01-14 00:36:03 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
VkImageView ImageView::DepthView() {
|
|
|
|
if (depth_view) {
|
|
|
|
return *depth_view;
|
|
|
|
}
|
|
|
|
depth_view = MakeDepthStencilView(VK_IMAGE_ASPECT_DEPTH_BIT);
|
|
|
|
return *depth_view;
|
|
|
|
}
|
2020-03-27 05:33:21 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
VkImageView ImageView::StencilView() {
|
|
|
|
if (stencil_view) {
|
|
|
|
return *stencil_view;
|
|
|
|
}
|
|
|
|
stencil_view = MakeDepthStencilView(VK_IMAGE_ASPECT_STENCIL_BIT);
|
|
|
|
return *stencil_view;
|
|
|
|
}
|
2020-03-27 05:33:21 +01:00
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) {
|
|
|
|
return device->GetLogical().CreateImageView({
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
|
|
|
.image = image_handle,
|
|
|
|
.viewType = ImageViewType(type),
|
2021-01-16 01:37:17 +01:00
|
|
|
.format = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format).format,
|
2020-12-30 06:25:23 +01:00
|
|
|
.components{
|
|
|
|
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
},
|
|
|
|
.subresourceRange = MakeSubresourceRange(aspect_mask, range),
|
2020-01-14 00:36:03 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) {
|
|
|
|
const auto& device = runtime.device;
|
|
|
|
const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported();
|
2021-04-12 12:04:55 +02:00
|
|
|
const auto color = tsc.BorderColor();
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
const VkSamplerCustomBorderColorCreateInfoEXT border_ci{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
|
|
|
|
.pNext = nullptr,
|
2021-04-12 12:04:55 +02:00
|
|
|
// TODO: Make use of std::bit_cast once libc++ supports it.
|
|
|
|
.customBorderColor = Common::BitCast<VkClearColorValue>(color),
|
2020-12-30 06:25:23 +01:00
|
|
|
.format = VK_FORMAT_UNDEFINED,
|
|
|
|
};
|
|
|
|
const void* pnext = nullptr;
|
|
|
|
if (arbitrary_borders) {
|
|
|
|
pnext = &border_ci;
|
|
|
|
}
|
|
|
|
const VkSamplerReductionModeCreateInfoEXT reduction_ci{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT,
|
|
|
|
.pNext = pnext,
|
|
|
|
.reductionMode = MaxwellToVK::SamplerReduction(tsc.reduction_filter),
|
|
|
|
};
|
|
|
|
if (runtime.device.IsExtSamplerFilterMinmaxSupported()) {
|
|
|
|
pnext = &reduction_ci;
|
|
|
|
} else if (reduction_ci.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT) {
|
|
|
|
LOG_WARNING(Render_Vulkan, "VK_EXT_sampler_filter_minmax is required");
|
|
|
|
}
|
|
|
|
// Some games have samplers with garbage. Sanitize them here.
|
|
|
|
const float max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f);
|
|
|
|
sampler = device.GetLogical().CreateSampler(VkSamplerCreateInfo{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
|
|
|
.pNext = pnext,
|
|
|
|
.flags = 0,
|
|
|
|
.magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter),
|
|
|
|
.minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter),
|
|
|
|
.mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter),
|
|
|
|
.addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter),
|
|
|
|
.addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter),
|
|
|
|
.addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter),
|
|
|
|
.mipLodBias = tsc.LodBias(),
|
|
|
|
.anisotropyEnable = static_cast<VkBool32>(max_anisotropy > 1.0f ? VK_TRUE : VK_FALSE),
|
|
|
|
.maxAnisotropy = max_anisotropy,
|
|
|
|
.compareEnable = tsc.depth_compare_enabled,
|
|
|
|
.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
|
|
|
|
.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
|
|
|
|
.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
|
|
|
|
.borderColor =
|
|
|
|
arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color),
|
|
|
|
.unnormalizedCoordinates = VK_FALSE,
|
2020-01-14 00:36:03 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
|
|
|
|
ImageView* depth_buffer, const VideoCommon::RenderTargets& key) {
|
|
|
|
std::vector<VkAttachmentDescription> descriptions;
|
|
|
|
std::vector<VkImageView> attachments;
|
|
|
|
RenderPassKey renderpass_key{};
|
|
|
|
s32 num_layers = 1;
|
|
|
|
|
|
|
|
for (size_t index = 0; index < NUM_RT; ++index) {
|
|
|
|
const ImageView* const color_buffer = color_buffers[index];
|
|
|
|
if (!color_buffer) {
|
|
|
|
renderpass_key.color_formats[index] = PixelFormat::Invalid;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
descriptions.push_back(AttachmentDescription(runtime.device, color_buffer));
|
|
|
|
attachments.push_back(color_buffer->RenderTarget());
|
|
|
|
renderpass_key.color_formats[index] = color_buffer->format;
|
|
|
|
num_layers = std::max(num_layers, color_buffer->range.extent.layers);
|
|
|
|
images[num_images] = color_buffer->ImageHandle();
|
|
|
|
image_ranges[num_images] = MakeSubresourceRange(color_buffer);
|
|
|
|
samples = color_buffer->Samples();
|
|
|
|
++num_images;
|
|
|
|
}
|
|
|
|
const size_t num_colors = attachments.size();
|
|
|
|
const VkAttachmentReference* depth_attachment =
|
|
|
|
depth_buffer ? &ATTACHMENT_REFERENCES[num_colors] : nullptr;
|
|
|
|
if (depth_buffer) {
|
|
|
|
descriptions.push_back(AttachmentDescription(runtime.device, depth_buffer));
|
|
|
|
attachments.push_back(depth_buffer->RenderTarget());
|
|
|
|
renderpass_key.depth_format = depth_buffer->format;
|
|
|
|
num_layers = std::max(num_layers, depth_buffer->range.extent.layers);
|
|
|
|
images[num_images] = depth_buffer->ImageHandle();
|
|
|
|
image_ranges[num_images] = MakeSubresourceRange(depth_buffer);
|
|
|
|
samples = depth_buffer->Samples();
|
|
|
|
++num_images;
|
|
|
|
} else {
|
|
|
|
renderpass_key.depth_format = PixelFormat::Invalid;
|
|
|
|
}
|
|
|
|
renderpass_key.samples = samples;
|
|
|
|
|
|
|
|
const auto& device = runtime.device.GetLogical();
|
|
|
|
const auto [cache_pair, is_new] = runtime.renderpass_cache.try_emplace(renderpass_key);
|
|
|
|
if (is_new) {
|
|
|
|
const VkSubpassDescription subpass{
|
|
|
|
.flags = 0,
|
|
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
|
|
.inputAttachmentCount = 0,
|
|
|
|
.pInputAttachments = nullptr,
|
|
|
|
.colorAttachmentCount = static_cast<u32>(num_colors),
|
|
|
|
.pColorAttachments = num_colors != 0 ? ATTACHMENT_REFERENCES.data() : nullptr,
|
|
|
|
.pResolveAttachments = nullptr,
|
|
|
|
.pDepthStencilAttachment = depth_attachment,
|
|
|
|
.preserveAttachmentCount = 0,
|
|
|
|
.pPreserveAttachments = nullptr,
|
|
|
|
};
|
|
|
|
cache_pair->second = device.CreateRenderPass(VkRenderPassCreateInfo{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
|
|
|
.attachmentCount = static_cast<u32>(descriptions.size()),
|
|
|
|
.pAttachments = descriptions.data(),
|
|
|
|
.subpassCount = 1,
|
|
|
|
.pSubpasses = &subpass,
|
|
|
|
.dependencyCount = 0,
|
|
|
|
.pDependencies = nullptr,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
renderpass = *cache_pair->second;
|
|
|
|
render_area = VkExtent2D{
|
|
|
|
.width = key.size.width,
|
|
|
|
.height = key.size.height,
|
|
|
|
};
|
|
|
|
num_color_buffers = static_cast<u32>(num_colors);
|
|
|
|
framebuffer = device.CreateFramebuffer(VkFramebufferCreateInfo{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
|
|
|
.renderPass = renderpass,
|
|
|
|
.attachmentCount = static_cast<u32>(attachments.size()),
|
|
|
|
.pAttachments = attachments.data(),
|
|
|
|
.width = key.size.width,
|
|
|
|
.height = key.size.height,
|
2021-01-17 00:48:58 +01:00
|
|
|
.layers = static_cast<u32>(std::max(num_layers, 1)),
|
2020-12-30 06:25:23 +01:00
|
|
|
});
|
|
|
|
if (runtime.device.HasDebuggingToolAttached()) {
|
|
|
|
framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str());
|
|
|
|
}
|
2020-01-14 00:36:03 +01:00
|
|
|
}
|
|
|
|
|
2021-02-13 22:49:24 +01:00
|
|
|
void TextureCacheRuntime::AccelerateImageUpload(
|
|
|
|
Image& image, const StagingBufferRef& map,
|
|
|
|
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
|
|
|
if (IsPixelFormatASTC(image.info.format)) {
|
|
|
|
return astc_decoder_pass.Assemble(image, map, swizzles);
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
2020-01-14 00:36:03 +01:00
|
|
|
} // namespace Vulkan
|