From aff095523d42ecd8fa64199922fbce356823e1ba Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 26 Nov 2025 18:58:18 -0400 Subject: [PATCH] [vk, rasterizer] Update sample location handling for MSAA configurations --- .../renderer_vulkan/vk_graphics_pipeline.cpp | 12 ++++++--- .../renderer_vulkan/vk_rasterizer.cpp | 25 ++++++++++------- src/video_core/texture_cache/samples_helper.h | 27 +++++++++++++++++++ 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 7178a7fd0d..e12363bb86 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -797,13 +797,17 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { key.state.alpha_to_one_enabled != 0 ? VK_TRUE : VK_FALSE, }; - std::array default_sample_locations{}; + const auto [sample_grid_width, sample_grid_height] = + VideoCommon::SampleLocationGridSize(msaa_mode); + const u32 sample_count = static_cast(VideoCommon::NumSamples(msaa_mode)); + const u32 total_sample_locations = sample_count * sample_grid_width * sample_grid_height; + std::array default_sample_locations{}; VkSampleLocationsInfoEXT sample_locations_info{ .sType = VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT, .pNext = nullptr, .sampleLocationsPerPixel = vk_samples, - .sampleLocationGridSize = {1u, 1u}, - .sampleLocationsCount = static_cast(VideoCommon::NumSamples(msaa_mode)), + .sampleLocationGridSize = {sample_grid_width, sample_grid_height}, + .sampleLocationsCount = total_sample_locations, .pSampleLocations = default_sample_locations.data(), }; VkPipelineSampleLocationsStateCreateInfoEXT sample_locations_ci{ @@ -812,7 +816,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .sampleLocationsEnable = VK_FALSE, .sampleLocationsInfo = sample_locations_info, }; - if (device.IsExtSampleLocationsSupported() && sample_locations_info.sampleLocationsCount > 1 && + if (device.IsExtSampleLocationsSupported() && total_sample_locations > 0 && device.SupportsSampleLocationsFor(vk_samples)) { sample_locations_ci.sampleLocationsEnable = VK_TRUE; sample_locations_ci.pNext = std::exchange(multisample_ci.pNext, &sample_locations_ci); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 7a8138edcb..29f421a04e 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1384,39 +1384,44 @@ void RasterizerVulkan::UpdateSampleLocations(Tegra::Engines::Maxwell3D::Regs& re const auto msaa_mode = regs.anti_alias_samples_mode; const u32 sample_count = static_cast(VideoCommon::NumSamples(msaa_mode)); - if (sample_count <= 1) { - return; - } const VkSampleCountFlagBits vk_samples = MaxwellToVK::MsaaMode(msaa_mode); if (!device.SupportsSampleLocationsFor(vk_samples)) { return; } + const auto [grid_width, grid_height] = VideoCommon::SampleLocationGridSize(msaa_mode); + const u32 total_locations = sample_count * grid_width * grid_height; + if (total_locations == 0 || total_locations > VideoCommon::MaxSampleLocationSlots) { + LOG_WARNING(Render_Vulkan, "Unsupported sample-location grid configuration: samples={}, grid={}x{}", + sample_count, grid_width, grid_height); + return; + } + const auto& props = device.SampleLocationProperties(); - std::array locations{}; + std::array locations{}; constexpr float unit = 1.0f / 16.0f; const auto clamp_coord = [&](float coord) { return std::clamp(coord, props.sampleLocationCoordinateRange[0], props.sampleLocationCoordinateRange[1]); }; - for (u32 sample_index = 0; sample_index < sample_count; ++sample_index) { - const auto& packed = regs.multisample_sample_locations[sample_index / 4]; - const auto [raw_x, raw_y] = packed.Location(sample_index % 4); + for (u32 index = 0; index < total_locations; ++index) { + const auto& packed = regs.multisample_sample_locations[index / 4]; + const auto [raw_x, raw_y] = packed.Location(index % 4); const float offset_x = static_cast(static_cast(raw_x) - 8); const float offset_y = static_cast(static_cast(raw_y) - 8); const float x = clamp_coord(offset_x * unit); const float y = clamp_coord(offset_y * unit); - locations[sample_index] = VkSampleLocationEXT{.x = x, .y = y}; + locations[index] = VkSampleLocationEXT{.x = x, .y = y}; } VkSampleLocationsInfoEXT info{ .sType = VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT, .pNext = nullptr, .sampleLocationsPerPixel = vk_samples, - .sampleLocationGridSize = {1u, 1u}, - .sampleLocationsCount = sample_count, + .sampleLocationGridSize = {grid_width, grid_height}, + .sampleLocationsCount = total_locations, .pSampleLocations = nullptr, }; diff --git a/src/video_core/texture_cache/samples_helper.h b/src/video_core/texture_cache/samples_helper.h index 2ee2f83123..38549b09db 100644 --- a/src/video_core/texture_cache/samples_helper.h +++ b/src/video_core/texture_cache/samples_helper.h @@ -1,15 +1,22 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include #include #include "common/assert.h" +#include "common/common_types.h" #include "video_core/textures/texture.h" namespace VideoCommon { +constexpr inline std::size_t MaxSampleLocationSlots = 16; + [[nodiscard]] inline std::pair SamplesLog2(int num_samples) { switch (num_samples) { case 1: @@ -95,4 +102,24 @@ namespace VideoCommon { return 1; } +// NVN guarantees up to sixteen programmable sample slots shared across a repeating pixel grid +// (per the 0.7.0 addon release notes), so the grid dimensions shrink as MSAA increases. +[[nodiscard]] inline std::pair SampleLocationGridSize(Tegra::Texture::MsaaMode msaa_mode) { + const int samples = NumSamples(msaa_mode); + switch (samples) { + case 1: + return {4u, 4u}; + case 2: + return {4u, 2u}; + case 4: + return {2u, 2u}; + case 8: + return {2u, 1u}; + case 16: + return {1u, 1u}; + } + ASSERT_MSG(false, "Unsupported sample count for grid size={}", samples); + return {1u, 1u}; +} + } // namespace VideoCommon