diff options
| author | 2021-10-19 17:46:01 +0200 | |
|---|---|---|
| committer | 2021-11-16 22:11:31 +0100 | |
| commit | f3ff8bdc0e8c6c25c1725b82d6862b93a8df3c84 (patch) | |
| tree | 8a0915c032125a6b8f6217227ede508100e815b9 /src | |
| parent | Texture Cache: fix memory managment and optimize scaled downloads, uploads. (diff) | |
| download | yuzu-f3ff8bdc0e8c6c25c1725b82d6862b93a8df3c84.tar.gz yuzu-f3ff8bdc0e8c6c25c1725b82d6862b93a8df3c84.tar.xz yuzu-f3ff8bdc0e8c6c25c1725b82d6862b93a8df3c84.zip | |
TextureCache: Fix blitting filter in Vulkan and correct viewport/scissor calculation when downscaling.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_rasterizer.cpp | 24 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.cpp | 40 |
2 files changed, 44 insertions, 20 deletions
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 { | |||
| 60 | 60 | ||
| 61 | VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) { | 61 | VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) { |
| 62 | const auto& src = regs.viewport_transform[index]; | 62 | const auto& src = regs.viewport_transform[index]; |
| 63 | const float x = (src.translate_x - src.scale_x) * scale; | 63 | const auto conv = [scale](float value) { |
| 64 | const float width = src.scale_x * 2.0f * scale; | 64 | float new_value = value * scale; |
| 65 | float y = (src.translate_y - src.scale_y) * scale; | 65 | if (scale < 1.0f) { |
| 66 | float height = src.scale_y * 2.0f * scale; | 66 | bool sign = std::signbit(new_value); |
| 67 | new_value = std::round(std::abs(new_value)); | ||
| 68 | new_value = sign ? -new_value : new_value; | ||
| 69 | } | ||
| 70 | return new_value; | ||
| 71 | }; | ||
| 72 | const float x = conv(src.translate_x - src.scale_x); | ||
| 73 | const float width = conv(src.scale_x * 2.0f); | ||
| 74 | float y = conv(src.translate_y - src.scale_y); | ||
| 75 | float height = conv(src.scale_y * 2.0f); | ||
| 67 | if (regs.screen_y_control.y_negate) { | 76 | if (regs.screen_y_control.y_negate) { |
| 68 | y += height; | 77 | y += height; |
| 69 | height = -height; | 78 | height = -height; |
| @@ -91,8 +100,13 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3 | |||
| 91 | if (value == 0) { | 100 | if (value == 0) { |
| 92 | return 0U; | 101 | return 0U; |
| 93 | } | 102 | } |
| 103 | const u32 upset = value * up_scale; | ||
| 104 | u32 acumm = 0; | ||
| 105 | if ((up_scale >> down_shift) == 0) { | ||
| 106 | acumm = upset & 0x1; | ||
| 107 | } | ||
| 94 | const u32 converted_value = (value * up_scale) >> down_shift; | 108 | const u32 converted_value = (value * up_scale) >> down_shift; |
| 95 | return std::max<u32>(converted_value, 1U); | 109 | return std::max<u32>(converted_value + acumm, 1U); |
| 96 | }; | 110 | }; |
| 97 | if (src.enable) { | 111 | if (src.enable) { |
| 98 | scissor.offset.x = static_cast<s32>(scale_up(src.min_x)); | 112 | scissor.offset.x = static_cast<s32>(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 { | |||
| 593 | 593 | ||
| 594 | void BlitScale(VKScheduler& scheduler, VkImage src_image, VkImage dst_image, const ImageInfo& info, | 594 | void BlitScale(VKScheduler& scheduler, VkImage src_image, VkImage dst_image, const ImageInfo& info, |
| 595 | VkImageAspectFlags aspect_mask, const Settings::ResolutionScalingInfo& resolution, | 595 | VkImageAspectFlags aspect_mask, const Settings::ResolutionScalingInfo& resolution, |
| 596 | bool up_scaling = true) { | 596 | bool is_bilinear, bool up_scaling = true) { |
| 597 | const bool is_2d = info.type == ImageType::e2D; | 597 | const bool is_2d = info.type == ImageType::e2D; |
| 598 | const auto resources = info.resources; | 598 | const auto resources = info.resources; |
| 599 | const VkExtent2D extent{ | 599 | const VkExtent2D extent{ |
| @@ -602,7 +602,7 @@ void BlitScale(VKScheduler& scheduler, VkImage src_image, VkImage dst_image, con | |||
| 602 | }; | 602 | }; |
| 603 | const bool is_zeta = (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; | 603 | const bool is_zeta = (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; |
| 604 | const bool is_int_format = IsPixelFormatInteger(info.format); | 604 | const bool is_int_format = IsPixelFormatInteger(info.format); |
| 605 | const VkFilter vk_filter = (is_zeta || is_int_format) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; | 605 | const VkFilter vk_filter = is_bilinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; |
| 606 | 606 | ||
| 607 | scheduler.RequestOutsideRenderPassOperationContext(); | 607 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 608 | scheduler.Record([dst_image, src_image, extent, resources, aspect_mask, resolution, is_2d, | 608 | scheduler.Record([dst_image, src_image, extent, resources, aspect_mask, resolution, is_2d, |
| @@ -1160,7 +1160,7 @@ bool Image::ScaleUp(bool ignore) { | |||
| 1160 | } | 1160 | } |
| 1161 | current_image = *scaled_image; | 1161 | current_image = *scaled_image; |
| 1162 | if (ignore) { | 1162 | if (ignore) { |
| 1163 | return true; | 1163 | return true; |
| 1164 | } | 1164 | } |
| 1165 | 1165 | ||
| 1166 | if (aspect_mask == 0) { | 1166 | if (aspect_mask == 0) { |
| @@ -1170,11 +1170,18 @@ bool Image::ScaleUp(bool ignore) { | |||
| 1170 | const PixelFormat format = StorageFormat(info.format); | 1170 | const PixelFormat format = StorageFormat(info.format); |
| 1171 | const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format; | 1171 | const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format; |
| 1172 | const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; | 1172 | const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; |
| 1173 | const bool is_color{aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT}; | ||
| 1174 | const bool is_bilinear{is_color && !IsPixelFormatInteger(info.format)}; | ||
| 1173 | if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) { | 1175 | if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) { |
| 1174 | BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution); | 1176 | BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution, |
| 1177 | device.IsFormatSupported(vk_format, | ||
| 1178 | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT, | ||
| 1179 | OPTIMAL_FORMAT)); | ||
| 1175 | } else { | 1180 | } else { |
| 1176 | using namespace VideoCommon; | 1181 | using namespace VideoCommon; |
| 1177 | static constexpr auto BLIT_OPERATION = Tegra::Engines::Fermi2D::Operation::SrcCopy; | 1182 | static constexpr auto BLIT_OPERATION = Tegra::Engines::Fermi2D::Operation::SrcCopy; |
| 1183 | const auto operation = is_bilinear ? Tegra::Engines::Fermi2D::Filter::Bilinear | ||
| 1184 | : Tegra::Engines::Fermi2D::Filter::Point; | ||
| 1178 | 1185 | ||
| 1179 | if (!scale_view) { | 1186 | if (!scale_view) { |
| 1180 | const auto view_info = ImageViewInfo(ImageViewType::e2D, info.format); | 1187 | const auto view_info = ImageViewInfo(ImageViewType::e2D, info.format); |
| @@ -1201,9 +1208,8 @@ bool Image::ScaleUp(bool ignore) { | |||
| 1201 | } | 1208 | } |
| 1202 | const auto color_view = scale_view->Handle(Shader::TextureType::Color2D); | 1209 | const auto color_view = scale_view->Handle(Shader::TextureType::Color2D); |
| 1203 | 1210 | ||
| 1204 | runtime->blit_image_helper.BlitColor( | 1211 | runtime->blit_image_helper.BlitColor(scale_framebuffer.get(), color_view, dst_region, |
| 1205 | scale_framebuffer.get(), color_view, dst_region, src_region, | 1212 | src_region, operation, BLIT_OPERATION); |
| 1206 | Tegra::Engines::Fermi2D::Filter::Bilinear, BLIT_OPERATION); | ||
| 1207 | } else if (!runtime->device.IsBlitDepthStencilSupported() && | 1213 | } else if (!runtime->device.IsBlitDepthStencilSupported() && |
| 1208 | aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | 1214 | aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { |
| 1209 | if (!scale_framebuffer) { | 1215 | if (!scale_framebuffer) { |
| @@ -1212,7 +1218,7 @@ bool Image::ScaleUp(bool ignore) { | |||
| 1212 | } | 1218 | } |
| 1213 | runtime->blit_image_helper.BlitDepthStencil( | 1219 | runtime->blit_image_helper.BlitDepthStencil( |
| 1214 | scale_framebuffer.get(), scale_view->DepthView(), scale_view->StencilView(), | 1220 | scale_framebuffer.get(), scale_view->DepthView(), scale_view->StencilView(), |
| 1215 | dst_region, src_region, Tegra::Engines::Fermi2D::Filter::Point, BLIT_OPERATION); | 1221 | dst_region, src_region, operation, BLIT_OPERATION); |
| 1216 | } else { | 1222 | } else { |
| 1217 | // TODO: Use helper blits where applicable | 1223 | // TODO: Use helper blits where applicable |
| 1218 | flags &= ~ImageFlagBits::Rescaled; | 1224 | flags &= ~ImageFlagBits::Rescaled; |
| @@ -1233,8 +1239,8 @@ bool Image::ScaleDown(bool ignore) { | |||
| 1233 | return false; | 1239 | return false; |
| 1234 | } | 1240 | } |
| 1235 | if (ignore) { | 1241 | if (ignore) { |
| 1236 | current_image = *original_image; | 1242 | current_image = *original_image; |
| 1237 | return true; | 1243 | return true; |
| 1238 | } | 1244 | } |
| 1239 | const auto& device = runtime->device; | 1245 | const auto& device = runtime->device; |
| 1240 | const bool is_2d = info.type == ImageType::e2D; | 1246 | const bool is_2d = info.type == ImageType::e2D; |
| @@ -1247,11 +1253,16 @@ bool Image::ScaleDown(bool ignore) { | |||
| 1247 | const PixelFormat format = StorageFormat(info.format); | 1253 | const PixelFormat format = StorageFormat(info.format); |
| 1248 | const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format; | 1254 | const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format; |
| 1249 | const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; | 1255 | const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; |
| 1256 | const bool is_color{aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT}; | ||
| 1257 | const bool is_bilinear{is_color && !IsPixelFormatInteger(info.format)}; | ||
| 1250 | if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) { | 1258 | if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) { |
| 1251 | BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution, false); | 1259 | BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution, |
| 1260 | is_bilinear, false); | ||
| 1252 | } else { | 1261 | } else { |
| 1253 | using namespace VideoCommon; | 1262 | using namespace VideoCommon; |
| 1254 | static constexpr auto BLIT_OPERATION = Tegra::Engines::Fermi2D::Operation::SrcCopy; | 1263 | static constexpr auto BLIT_OPERATION = Tegra::Engines::Fermi2D::Operation::SrcCopy; |
| 1264 | const auto operation = is_bilinear ? Tegra::Engines::Fermi2D::Filter::Bilinear | ||
| 1265 | : Tegra::Engines::Fermi2D::Filter::Point; | ||
| 1255 | 1266 | ||
| 1256 | if (!normal_view) { | 1267 | if (!normal_view) { |
| 1257 | const auto view_info = ImageViewInfo(ImageViewType::e2D, info.format); | 1268 | const auto view_info = ImageViewInfo(ImageViewType::e2D, info.format); |
| @@ -1278,9 +1289,8 @@ bool Image::ScaleDown(bool ignore) { | |||
| 1278 | } | 1289 | } |
| 1279 | const auto color_view = normal_view->Handle(Shader::TextureType::Color2D); | 1290 | const auto color_view = normal_view->Handle(Shader::TextureType::Color2D); |
| 1280 | 1291 | ||
| 1281 | runtime->blit_image_helper.BlitColor( | 1292 | runtime->blit_image_helper.BlitColor(normal_framebuffer.get(), color_view, dst_region, |
| 1282 | normal_framebuffer.get(), color_view, dst_region, src_region, | 1293 | src_region, operation, BLIT_OPERATION); |
| 1283 | Tegra::Engines::Fermi2D::Filter::Bilinear, BLIT_OPERATION); | ||
| 1284 | } else if (!runtime->device.IsBlitDepthStencilSupported() && | 1294 | } else if (!runtime->device.IsBlitDepthStencilSupported() && |
| 1285 | aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | 1295 | aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { |
| 1286 | if (!normal_framebuffer) { | 1296 | if (!normal_framebuffer) { |
| @@ -1289,7 +1299,7 @@ bool Image::ScaleDown(bool ignore) { | |||
| 1289 | } | 1299 | } |
| 1290 | runtime->blit_image_helper.BlitDepthStencil( | 1300 | runtime->blit_image_helper.BlitDepthStencil( |
| 1291 | normal_framebuffer.get(), normal_view->DepthView(), normal_view->StencilView(), | 1301 | normal_framebuffer.get(), normal_view->DepthView(), normal_view->StencilView(), |
| 1292 | dst_region, src_region, Tegra::Engines::Fermi2D::Filter::Point, BLIT_OPERATION); | 1302 | dst_region, src_region, operation, BLIT_OPERATION); |
| 1293 | } else { | 1303 | } else { |
| 1294 | // TODO: Use helper blits where applicable | 1304 | // TODO: Use helper blits where applicable |
| 1295 | flags &= ~ImageFlagBits::Rescaled; | 1305 | flags &= ~ImageFlagBits::Rescaled; |