From 583a9fd32032703853bb4343bc91a15fdb714b40 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Thu, 4 Dec 2025 02:44:06 -0400 Subject: [PATCH] [maxwell, vk] Allocate data transfer from Maxwell to VK using Sample Locations as channel for MSAA --- .../renderer_vulkan/vk_graphics_pipeline.cpp | 11 +++++-- .../renderer_vulkan/vk_rasterizer.cpp | 33 +++++++++++++++++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index d89a992281..170fba1897 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -862,8 +862,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { const bool alpha_to_one_supported = device.SupportsAlphaToOne(); const auto msaa_mode = key.state.msaa_mode.Value(); const VkSampleCountFlagBits vk_samples = MaxwellToVK::MsaaMode(msaa_mode); - const bool supports_sample_locations = - device.IsExtSampleLocationsSupported() && device.SupportsSampleLocationsFor(vk_samples); + const auto [grid_width, grid_height] = VideoCommon::SampleLocationGridSize(msaa_mode); + const auto& sample_location_props = device.SampleLocationProperties(); + const bool grid_within_limits = grid_width <= sample_location_props.maxSampleLocationGridSize.width && + grid_height <= sample_location_props.maxSampleLocationGridSize.height; + const bool supports_sample_locations = device.IsExtSampleLocationsSupported() && + device.SupportsSampleLocationsFor(vk_samples) && + sample_location_props.variableSampleLocations == VK_TRUE && + grid_within_limits; VkPipelineMultisampleStateCreateInfo multisample_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, @@ -888,7 +894,6 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { if (supports_sample_locations) { sample_locations_chain.emplace(); auto& chain = *sample_locations_chain; - const auto [grid_width, grid_height] = VideoCommon::SampleLocationGridSize(msaa_mode); const u32 samples_per_pixel = static_cast(VideoCommon::NumSamples(msaa_mode)); const u32 sample_locations_count = grid_width * grid_height * samples_per_pixel; chain.locations.fill(VkSampleLocationEXT{0.5f, 0.5f}); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 5cc4a80306..51afa06327 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -1713,9 +1714,22 @@ void RasterizerVulkan::UpdateSampleLocations(Maxwell& regs) { return; } + const auto& sample_props = device.SampleLocationProperties(); + if (sample_props.variableSampleLocations == VK_FALSE) { + return; + } + const auto [grid_width_u32, grid_height_u32] = VideoCommon::SampleLocationGridSize(msaa_mode); const u32 grid_width = grid_width_u32; const u32 grid_height = grid_height_u32; + if (grid_width > sample_props.maxSampleLocationGridSize.width || + grid_height > sample_props.maxSampleLocationGridSize.height) { + LOG_WARNING(Render_Vulkan, + "Sample location grid {}x{} exceeds device limit {}x{}, falling back to fixed pattern", + grid_width, grid_height, sample_props.maxSampleLocationGridSize.width, + sample_props.maxSampleLocationGridSize.height); + return; + } const u32 samples_per_pixel = static_cast(VideoCommon::NumSamples(msaa_mode)); const u32 grid_cells = grid_width * grid_height; const u32 sample_locations_count = grid_cells * samples_per_pixel; @@ -1723,15 +1737,30 @@ void RasterizerVulkan::UpdateSampleLocations(Maxwell& regs) { const auto raw_locations = DecodeSampleLocationRegisters(regs); std::array resolved{}; + const float coord_min = sample_props.sampleLocationCoordinateRange[0]; + const float coord_max = sample_props.sampleLocationCoordinateRange[1]; + const float host_unit = sample_props.sampleLocationSubPixelBits > 0 + ? 1.0f / static_cast(1u << sample_props.sampleLocationSubPixelBits) + : 0.0f; + const auto sanitize_coord = [&](float value) { + float clamped = std::clamp(value, coord_min, coord_max); + if (host_unit > 0.0f) { + clamped = coord_min + std::round((clamped - coord_min) / host_unit) * host_unit; + clamped = std::clamp(clamped, coord_min, coord_max); + } + return clamped; + }; for (u32 cell = 0; cell < grid_cells; ++cell) { const u32 slot_base = cell * samples_per_pixel; const u32 cell_x = cell % grid_width; const u32 cell_y = cell / grid_width; for (u32 sample = 0; sample < samples_per_pixel; ++sample) { const VkSampleLocationEXT raw = raw_locations[slot_base + sample]; + const float sample_x = static_cast(cell_x) + raw.x; + const float sample_y = static_cast(cell_y) + raw.y; resolved[slot_base + sample] = VkSampleLocationEXT{ - .x = static_cast(cell_x) + raw.x, - .y = static_cast(cell_y) + raw.y, + .x = sanitize_coord(sample_x), + .y = sanitize_coord(sample_y), }; } }