From f3ff8bdc0e8c6c25c1725b82d6862b93a8df3c84 Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Tue, 19 Oct 2021 17:46:01 +0200 Subject: TextureCache: Fix blitting filter in Vulkan and correct viewport/scissor calculation when downscaling. --- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 24 ++++++++++--- .../renderer_vulkan/vk_texture_cache.cpp | 40 ++++++++++++++-------- 2 files changed, 44 insertions(+), 20 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 1ceffa718..a9334e101 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -60,10 +60,19 @@ struct DrawParams { VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) { const auto& src = regs.viewport_transform[index]; - const float x = (src.translate_x - src.scale_x) * scale; - const float width = src.scale_x * 2.0f * scale; - float y = (src.translate_y - src.scale_y) * scale; - float height = src.scale_y * 2.0f * scale; + const auto conv = [scale](float value) { + float new_value = value * scale; + if (scale < 1.0f) { + bool sign = std::signbit(new_value); + new_value = std::round(std::abs(new_value)); + new_value = sign ? -new_value : new_value; + } + return new_value; + }; + const float x = conv(src.translate_x - src.scale_x); + const float width = conv(src.scale_x * 2.0f); + float y = conv(src.translate_y - src.scale_y); + float height = conv(src.scale_y * 2.0f); if (regs.screen_y_control.y_negate) { y += height; height = -height; @@ -91,8 +100,13 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3 if (value == 0) { return 0U; } + const u32 upset = value * up_scale; + u32 acumm = 0; + if ((up_scale >> down_shift) == 0) { + acumm = upset & 0x1; + } const u32 converted_value = (value * up_scale) >> down_shift; - return std::max(converted_value, 1U); + return std::max(converted_value + acumm, 1U); }; if (src.enable) { scissor.offset.x = static_cast(scale_up(src.min_x)); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 02aac3b98..84ec803ba 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -593,7 +593,7 @@ struct RangedBarrierRange { void BlitScale(VKScheduler& scheduler, VkImage src_image, VkImage dst_image, const ImageInfo& info, VkImageAspectFlags aspect_mask, const Settings::ResolutionScalingInfo& resolution, - bool up_scaling = true) { + bool is_bilinear, bool up_scaling = true) { const bool is_2d = info.type == ImageType::e2D; const auto resources = info.resources; const VkExtent2D extent{ @@ -602,7 +602,7 @@ void BlitScale(VKScheduler& scheduler, VkImage src_image, VkImage dst_image, con }; const bool is_zeta = (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; const bool is_int_format = IsPixelFormatInteger(info.format); - const VkFilter vk_filter = (is_zeta || is_int_format) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; + const VkFilter vk_filter = is_bilinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([dst_image, src_image, extent, resources, aspect_mask, resolution, is_2d, @@ -1160,7 +1160,7 @@ bool Image::ScaleUp(bool ignore) { } current_image = *scaled_image; if (ignore) { - return true; + return true; } if (aspect_mask == 0) { @@ -1170,11 +1170,18 @@ bool Image::ScaleUp(bool ignore) { const PixelFormat format = StorageFormat(info.format); const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format; const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; + const bool is_color{aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT}; + const bool is_bilinear{is_color && !IsPixelFormatInteger(info.format)}; if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) { - BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution); + BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution, + device.IsFormatSupported(vk_format, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT, + OPTIMAL_FORMAT)); } else { using namespace VideoCommon; static constexpr auto BLIT_OPERATION = Tegra::Engines::Fermi2D::Operation::SrcCopy; + const auto operation = is_bilinear ? Tegra::Engines::Fermi2D::Filter::Bilinear + : Tegra::Engines::Fermi2D::Filter::Point; if (!scale_view) { const auto view_info = ImageViewInfo(ImageViewType::e2D, info.format); @@ -1201,9 +1208,8 @@ bool Image::ScaleUp(bool ignore) { } const auto color_view = scale_view->Handle(Shader::TextureType::Color2D); - runtime->blit_image_helper.BlitColor( - scale_framebuffer.get(), color_view, dst_region, src_region, - Tegra::Engines::Fermi2D::Filter::Bilinear, BLIT_OPERATION); + runtime->blit_image_helper.BlitColor(scale_framebuffer.get(), color_view, dst_region, + src_region, operation, BLIT_OPERATION); } else if (!runtime->device.IsBlitDepthStencilSupported() && aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { if (!scale_framebuffer) { @@ -1212,7 +1218,7 @@ bool Image::ScaleUp(bool ignore) { } runtime->blit_image_helper.BlitDepthStencil( scale_framebuffer.get(), scale_view->DepthView(), scale_view->StencilView(), - dst_region, src_region, Tegra::Engines::Fermi2D::Filter::Point, BLIT_OPERATION); + dst_region, src_region, operation, BLIT_OPERATION); } else { // TODO: Use helper blits where applicable flags &= ~ImageFlagBits::Rescaled; @@ -1233,8 +1239,8 @@ bool Image::ScaleDown(bool ignore) { return false; } if (ignore) { - current_image = *original_image; - return true; + current_image = *original_image; + return true; } const auto& device = runtime->device; const bool is_2d = info.type == ImageType::e2D; @@ -1247,11 +1253,16 @@ bool Image::ScaleDown(bool ignore) { const PixelFormat format = StorageFormat(info.format); const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format; const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; + const bool is_color{aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT}; + const bool is_bilinear{is_color && !IsPixelFormatInteger(info.format)}; if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) { - BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution, false); + BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution, + is_bilinear, false); } else { using namespace VideoCommon; static constexpr auto BLIT_OPERATION = Tegra::Engines::Fermi2D::Operation::SrcCopy; + const auto operation = is_bilinear ? Tegra::Engines::Fermi2D::Filter::Bilinear + : Tegra::Engines::Fermi2D::Filter::Point; if (!normal_view) { const auto view_info = ImageViewInfo(ImageViewType::e2D, info.format); @@ -1278,9 +1289,8 @@ bool Image::ScaleDown(bool ignore) { } const auto color_view = normal_view->Handle(Shader::TextureType::Color2D); - runtime->blit_image_helper.BlitColor( - normal_framebuffer.get(), color_view, dst_region, src_region, - Tegra::Engines::Fermi2D::Filter::Bilinear, BLIT_OPERATION); + runtime->blit_image_helper.BlitColor(normal_framebuffer.get(), color_view, dst_region, + src_region, operation, BLIT_OPERATION); } else if (!runtime->device.IsBlitDepthStencilSupported() && aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { if (!normal_framebuffer) { @@ -1289,7 +1299,7 @@ bool Image::ScaleDown(bool ignore) { } runtime->blit_image_helper.BlitDepthStencil( normal_framebuffer.get(), normal_view->DepthView(), normal_view->StencilView(), - dst_region, src_region, Tegra::Engines::Fermi2D::Filter::Point, BLIT_OPERATION); + dst_region, src_region, operation, BLIT_OPERATION); } else { // TODO: Use helper blits where applicable flags &= ~ImageFlagBits::Rescaled; -- cgit v1.2.3