TextureCache: Fix blitting filter in Vulkan and correct viewport/scissor calculation when downscaling.

This commit is contained in:
FernandoS27 2021-10-19 17:46:01 +02:00 committed by Fernando Sahmkow
parent 3b61de74e6
commit f3ff8bdc0e
2 changed files with 44 additions and 20 deletions

View File

@ -60,10 +60,19 @@ struct DrawParams {
VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) { VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) {
const auto& src = regs.viewport_transform[index]; const auto& src = regs.viewport_transform[index];
const float x = (src.translate_x - src.scale_x) * scale; const auto conv = [scale](float value) {
const float width = src.scale_x * 2.0f * scale; float new_value = value * scale;
float y = (src.translate_y - src.scale_y) * scale; if (scale < 1.0f) {
float height = src.scale_y * 2.0f * scale; 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) { if (regs.screen_y_control.y_negate) {
y += height; y += height;
height = -height; height = -height;
@ -91,8 +100,13 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3
if (value == 0) { if (value == 0) {
return 0U; 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; const u32 converted_value = (value * up_scale) >> down_shift;
return std::max<u32>(converted_value, 1U); return std::max<u32>(converted_value + acumm, 1U);
}; };
if (src.enable) { if (src.enable) {
scissor.offset.x = static_cast<s32>(scale_up(src.min_x)); scissor.offset.x = static_cast<s32>(scale_up(src.min_x));

View File

@ -593,7 +593,7 @@ struct RangedBarrierRange {
void BlitScale(VKScheduler& scheduler, VkImage src_image, VkImage dst_image, const ImageInfo& info, void BlitScale(VKScheduler& scheduler, VkImage src_image, VkImage dst_image, const ImageInfo& info,
VkImageAspectFlags aspect_mask, const Settings::ResolutionScalingInfo& resolution, 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 bool is_2d = info.type == ImageType::e2D;
const auto resources = info.resources; const auto resources = info.resources;
const VkExtent2D extent{ 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_zeta = (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
const bool is_int_format = IsPixelFormatInteger(info.format); 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.RequestOutsideRenderPassOperationContext();
scheduler.Record([dst_image, src_image, extent, resources, aspect_mask, resolution, is_2d, 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; current_image = *scaled_image;
if (ignore) { if (ignore) {
return true; return true;
} }
if (aspect_mask == 0) { if (aspect_mask == 0) {
@ -1170,11 +1170,18 @@ bool Image::ScaleUp(bool ignore) {
const PixelFormat format = StorageFormat(info.format); const PixelFormat format = StorageFormat(info.format);
const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).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 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)) { 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 { } else {
using namespace VideoCommon; using namespace VideoCommon;
static constexpr auto BLIT_OPERATION = Tegra::Engines::Fermi2D::Operation::SrcCopy; 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) { if (!scale_view) {
const auto view_info = ImageViewInfo(ImageViewType::e2D, info.format); 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); const auto color_view = scale_view->Handle(Shader::TextureType::Color2D);
runtime->blit_image_helper.BlitColor( runtime->blit_image_helper.BlitColor(scale_framebuffer.get(), color_view, dst_region,
scale_framebuffer.get(), color_view, dst_region, src_region, src_region, operation, BLIT_OPERATION);
Tegra::Engines::Fermi2D::Filter::Bilinear, BLIT_OPERATION);
} else if (!runtime->device.IsBlitDepthStencilSupported() && } else if (!runtime->device.IsBlitDepthStencilSupported() &&
aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
if (!scale_framebuffer) { if (!scale_framebuffer) {
@ -1212,7 +1218,7 @@ bool Image::ScaleUp(bool ignore) {
} }
runtime->blit_image_helper.BlitDepthStencil( runtime->blit_image_helper.BlitDepthStencil(
scale_framebuffer.get(), scale_view->DepthView(), scale_view->StencilView(), 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 { } else {
// TODO: Use helper blits where applicable // TODO: Use helper blits where applicable
flags &= ~ImageFlagBits::Rescaled; flags &= ~ImageFlagBits::Rescaled;
@ -1233,8 +1239,8 @@ bool Image::ScaleDown(bool ignore) {
return false; return false;
} }
if (ignore) { if (ignore) {
current_image = *original_image; current_image = *original_image;
return true; return true;
} }
const auto& device = runtime->device; const auto& device = runtime->device;
const bool is_2d = info.type == ImageType::e2D; const bool is_2d = info.type == ImageType::e2D;
@ -1247,11 +1253,16 @@ bool Image::ScaleDown(bool ignore) {
const PixelFormat format = StorageFormat(info.format); const PixelFormat format = StorageFormat(info.format);
const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).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 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)) { 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 { } else {
using namespace VideoCommon; using namespace VideoCommon;
static constexpr auto BLIT_OPERATION = Tegra::Engines::Fermi2D::Operation::SrcCopy; 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) { if (!normal_view) {
const auto view_info = ImageViewInfo(ImageViewType::e2D, info.format); 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); const auto color_view = normal_view->Handle(Shader::TextureType::Color2D);
runtime->blit_image_helper.BlitColor( runtime->blit_image_helper.BlitColor(normal_framebuffer.get(), color_view, dst_region,
normal_framebuffer.get(), color_view, dst_region, src_region, src_region, operation, BLIT_OPERATION);
Tegra::Engines::Fermi2D::Filter::Bilinear, BLIT_OPERATION);
} else if (!runtime->device.IsBlitDepthStencilSupported() && } else if (!runtime->device.IsBlitDepthStencilSupported() &&
aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
if (!normal_framebuffer) { if (!normal_framebuffer) {
@ -1289,7 +1299,7 @@ bool Image::ScaleDown(bool ignore) {
} }
runtime->blit_image_helper.BlitDepthStencil( runtime->blit_image_helper.BlitDepthStencil(
normal_framebuffer.get(), normal_view->DepthView(), normal_view->StencilView(), 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 { } else {
// TODO: Use helper blits where applicable // TODO: Use helper blits where applicable
flags &= ~ImageFlagBits::Rescaled; flags &= ~ImageFlagBits::Rescaled;