[TEST] Unify paths on MSAA part 2

This commit is contained in:
CamilleLaVey
2026-08-22 20:13:10 -04:00
parent 8f18e82931
commit faf82ccdd7
2 changed files with 98 additions and 31 deletions
@@ -5,6 +5,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#include <algorithm> #include <algorithm>
#include <limits>
#include <array> #include <array>
#include <optional> #include <optional>
#include <span> #include <span>
@@ -53,9 +54,7 @@ using VideoCore::Surface::IsPixelFormatInteger;
using VideoCore::Surface::SurfaceType; using VideoCore::Surface::SurfaceType;
namespace { namespace {
// Master switch for the tiler MSAA resolve path: resolve attachments, resolve shadows and the constexpr bool ENABLE_MSAA_TILER_RESOLVE = true;
// MSAA store discard that pays for them. Turning it off restores plain MSAA store behaviour.
constexpr bool ENABLE_MSAA_TILER_RESOLVE = false;
constexpr bool ENABLE_MSAA_RESOLVE_CONSUME = true; constexpr bool ENABLE_MSAA_RESOLVE_CONSUME = true;
constexpr bool ENABLE_MSAA_COLOR_DISCARD = true; constexpr bool ENABLE_MSAA_COLOR_DISCARD = true;
constexpr bool ENABLE_MSAA_DEPTH_STENCIL_DISCARD = true; constexpr bool ENABLE_MSAA_DEPTH_STENCIL_DISCARD = true;
@@ -203,6 +202,18 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
}; };
} }
[[nodiscard]] VkImageCreateInfo MakeMsaaScratchImageCreateInfo(const Device& device,
const ImageInfo& info,
VkImageUsageFlags usage) {
ImageInfo temp_info = info;
temp_info.num_samples = 1;
VkImageCreateInfo image_ci = MakeImageCreateInfo(device, temp_info);
image_ci.format =
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true, info.format).format;
image_ci.usage = usage;
return image_ci;
}
[[nodiscard]] vk::Image MakeImage(const Device& device, const MemoryAllocator& allocator, [[nodiscard]] vk::Image MakeImage(const Device& device, const MemoryAllocator& allocator,
const ImageInfo& info, std::span<const VkFormat> view_formats, const ImageInfo& info, std::span<const VkFormat> view_formats,
std::optional<VkFormat> format_override = {}) { std::optional<VkFormat> format_override = {}) {
@@ -1805,9 +1816,54 @@ void TextureCacheRuntime::FlushDeferredClear() {
scheduler.FlushDeferredClear(); scheduler.FlushDeferredClear();
} }
VkImage TextureCacheRuntime::AcquireMsaaScratchImage(const VkImageCreateInfo& image_ci) {
const MsaaScratchKey key{
.format = image_ci.format,
.type = image_ci.imageType,
.width = image_ci.extent.width,
.height = image_ci.extent.height,
.depth = image_ci.extent.depth,
.levels = image_ci.mipLevels,
.layers = image_ci.arrayLayers,
.usage = image_ci.usage,
.flags = image_ci.flags,
};
for (MsaaScratchImage& scratch : msaa_scratch_images) {
if (scratch.key != key || !scheduler.IsFree(scratch.tick)) {
continue;
}
scratch.tick = (std::numeric_limits<u64>::max)();
scratch.unused_frames = 0;
return *scratch.image;
}
MsaaScratchImage scratch{
.key = key,
.image = memory_allocator.CreateImage(image_ci),
.tick = (std::numeric_limits<u64>::max)(),
.unused_frames = 0,
};
const VkImage handle = *scratch.image;
msaa_scratch_images.push_back(std::move(scratch));
return handle;
}
void TextureCacheRuntime::ReleaseMsaaScratchImage(VkImage image) {
for (MsaaScratchImage& scratch : msaa_scratch_images) {
if (*scratch.image == image) {
scratch.tick = scheduler.CurrentTick();
return;
}
}
}
void TextureCacheRuntime::TickFrame() { void TextureCacheRuntime::TickFrame() {
std::erase_if(pending_msaa_images, [this](const auto& pending) { static constexpr u32 MAX_UNUSED_SCRATCH_FRAMES = 60;
return scheduler.IsFree(pending.first); std::erase_if(msaa_scratch_images, [this](MsaaScratchImage& scratch) {
if (!scheduler.IsFree(scratch.tick)) {
scratch.unused_frames = 0;
return false;
}
return ++scratch.unused_frames > MAX_UNUSED_SCRATCH_FRAMES;
}); });
std::erase_if(pending_resolve_shadows, [this](const auto& pending) { std::erase_if(pending_resolve_shadows, [this](const auto& pending) {
return scheduler.IsFree(pending.first); return scheduler.IsFree(pending.first);
@@ -1944,20 +2000,13 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
upload_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; upload_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT;
} }
} }
ImageInfo temp_info = info; const VkImageCreateInfo image_ci = MakeMsaaScratchImageCreateInfo(
temp_info.num_samples = 1; runtime->device, info, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
const VkImage temp_vk_image = runtime->AcquireMsaaScratchImage(image_ci);
VkImageCreateInfo image_ci = MakeImageCreateInfo(runtime->device, temp_info);
image_ci.format =
MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format)
.format;
image_ci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
vk::Image temp_image = runtime->memory_allocator.CreateImage(image_ci);
scheduler->RequestOutsideRenderPassOperationContext(); scheduler->RequestOutsideRenderPassOperationContext();
auto vk_copies = TransformBufferImageCopies(copies, offset, upload_aspect_mask); auto vk_copies = TransformBufferImageCopies(copies, offset, upload_aspect_mask);
const VkBuffer src_buffer = buffer; const VkBuffer src_buffer = buffer;
const VkImage temp_vk_image = *temp_image;
const VkImageAspectFlags vk_aspect_mask = upload_aspect_mask; const VkImageAspectFlags vk_aspect_mask = upload_aspect_mask;
scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask, scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask,
@@ -1991,7 +2040,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
image_copies, false); image_copies, false);
} }
initialized = true; initialized = true;
runtime->pending_msaa_images.emplace_back(scheduler->CurrentTick(), std::move(temp_image)); runtime->ReleaseMsaaScratchImage(temp_vk_image);
if (is_rescaled) { if (is_rescaled) {
ScaleUp(); ScaleUp();
@@ -2048,26 +2097,20 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
if (info.num_samples > 1) { if (info.num_samples > 1) {
if (runtime->CanDownloadMsaa(info)) { if (runtime->CanDownloadMsaa(info)) {
ImageInfo temp_info = info;
temp_info.num_samples = 1;
VkImageCreateInfo image_ci = MakeImageCreateInfo(runtime->device, temp_info);
image_ci.format =
MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format)
.format;
const bool msaa_download_is_depth = const bool msaa_download_is_depth =
(aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
const bool msaa_download_copies_stencil = const bool msaa_download_copies_stencil =
msaa_download_is_depth && (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 && msaa_download_is_depth && (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 &&
runtime->device.IsExtShaderStencilExportSupported(); runtime->device.IsExtShaderStencilExportSupported();
image_ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; VkImageUsageFlags scratch_usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
if (msaa_download_is_depth) { if (msaa_download_is_depth) {
image_ci.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; scratch_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
} else { } else {
image_ci.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; scratch_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
} }
vk::Image temp_image = runtime->memory_allocator.CreateImage(image_ci); const VkImageCreateInfo image_ci =
const VkImage temp_vk_image = *temp_image; MakeMsaaScratchImageCreateInfo(runtime->device, info, scratch_usage);
const VkImage temp_vk_image = runtime->AcquireMsaaScratchImage(image_ci);
const VkImageAspectFlags temp_aspect_mask = aspect_mask; const VkImageAspectFlags temp_aspect_mask = aspect_mask;
const VkAccessFlags attachment_access = const VkAccessFlags attachment_access =
@@ -2191,8 +2234,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
0, memory_write_barrier, nullptr, image_write_barrier); 0, memory_write_barrier, nullptr, image_write_barrier);
}); });
runtime->pending_msaa_images.emplace_back(scheduler->CurrentTick(), runtime->ReleaseMsaaScratchImage(temp_vk_image);
std::move(temp_image));
} }
if (is_rescaled) { if (is_rescaled) {
ScaleUp(true); ScaleUp(true);
@@ -70,6 +70,10 @@ public:
bool CanDownloadMsaa(const VideoCommon::ImageInfo& info) const; bool CanDownloadMsaa(const VideoCommon::ImageInfo& info) const;
[[nodiscard]] VkImage AcquireMsaaScratchImage(const VkImageCreateInfo& image_ci);
void ReleaseMsaaScratchImage(VkImage image);
void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
const Region2D& dst_region, const Region2D& src_region, const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Filter filter,
@@ -162,7 +166,28 @@ public:
static constexpr size_t indexing_slots = 8 * sizeof(size_t); static constexpr size_t indexing_slots = 8 * sizeof(size_t);
std::array<vk::Buffer, indexing_slots> buffers{}; std::array<vk::Buffer, indexing_slots> buffers{};
std::vector<std::pair<u64, vk::Image>> pending_msaa_images; struct MsaaScratchKey {
VkFormat format;
VkImageType type;
u32 width;
u32 height;
u32 depth;
u32 levels;
u32 layers;
VkImageUsageFlags usage;
VkImageCreateFlags flags;
bool operator==(const MsaaScratchKey&) const noexcept = default;
};
struct MsaaScratchImage {
MsaaScratchKey key;
vk::Image image;
u64 tick;
u32 unused_frames;
};
std::vector<MsaaScratchImage> msaa_scratch_images;
ankerl::unordered_dense::map<VkImage, ResolveShadow> resolve_shadows; ankerl::unordered_dense::map<VkImage, ResolveShadow> resolve_shadows;
std::vector<std::pair<u64, ResolveShadow>> pending_resolve_shadows; std::vector<std::pair<u64, ResolveShadow>> pending_resolve_shadows;
}; };