Browse Source

[vk] Added linear filtering in texture blitting operations

eds-true-adreno-fixes
CamilleLaVey 4 weeks ago
committed by Caio Oliveira
parent
commit
e086078e41
No known key found for this signature in database GPG Key ID: AAAE6C7FD4186B0C
  1. 53
      src/video_core/renderer_vulkan/vk_texture_cache.cpp
  2. 1
      src/video_core/renderer_vulkan/vk_texture_cache.h

53
src/video_core/renderer_vulkan/vk_texture_cache.cpp

@ -705,7 +705,7 @@ void TryTransformSwizzleIfNeeded(PixelFormat format, std::array<SwizzleSource, 4
void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const ImageInfo& info,
VkImageAspectFlags aspect_mask, const Settings::ResolutionScalingInfo& resolution,
bool up_scaling = true) {
bool supports_linear_filter, bool up_scaling = true) {
const bool is_2d = info.type == ImageType::e2D;
const auto resources = info.resources;
const VkExtent2D extent{
@ -714,7 +714,8 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
};
// Depth and integer formats must use NEAREST filter for blits.
const bool is_color{aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT};
const bool is_bilinear{is_color && !IsPixelFormatInteger(info.format)};
const bool is_bilinear = supports_linear_filter && is_color &&
!IsPixelFormatInteger(info.format);
const VkFilter vk_filter = is_bilinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
scheduler.RequestOutsideRenderPassOperationContext();
@ -1081,12 +1082,17 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format);
const bool is_dst_msaa = dst.Samples() != VK_SAMPLE_COUNT_1_BIT;
const bool is_src_msaa = src.Samples() != VK_SAMPLE_COUNT_1_BIT;
const bool supports_linear_filter = SupportsLinearFilter(src.format);
const auto effective_filter =
(filter == Fermi2D::Filter::Bilinear && supports_linear_filter)
? Fermi2D::Filter::Bilinear
: Fermi2D::Filter::Point;
if (aspect_mask != ImageAspectMask(dst.format)) {
UNIMPLEMENTED_MSG("Incompatible blit from format {} to {}", src.format, dst.format);
return;
}
if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT && !is_src_msaa && !is_dst_msaa) {
blit_image_helper.BlitColor(dst_framebuffer, src, dst_region, src_region, filter,
blit_image_helper.BlitColor(dst_framebuffer, src, dst_region, src_region, effective_filter,
operation);
return;
}
@ -1109,7 +1115,7 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
if (!can_blit_depth_stencil) {
UNIMPLEMENTED_IF(is_src_msaa || is_dst_msaa);
blit_image_helper.BlitDepthStencil(dst_framebuffer, src, dst_region, src_region,
filter, operation);
effective_filter, operation);
return;
}
}
@ -1131,8 +1137,8 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
}
const bool is_resolve = is_src_msaa && !is_dst_msaa;
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([filter, dst_region, src_region, dst_image, src_image, dst_layers, src_layers,
aspect_mask, is_resolve](vk::CommandBuffer cmdbuf) {
scheduler.Record([effective_filter, dst_region, src_region, dst_image, src_image, dst_layers,
src_layers, aspect_mask, is_resolve](vk::CommandBuffer cmdbuf) {
const std::array read_barriers{
VkImageMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
@ -1203,7 +1209,7 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
MakeImageResolve(dst_region, src_region, dst_layers, src_layers));
} else {
const bool is_linear = filter == Fermi2D::Filter::Bilinear;
const bool is_linear = effective_filter == Fermi2D::Filter::Bilinear;
const VkFilter vk_filter = is_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
cmdbuf.BlitImage(
src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
@ -1394,6 +1400,20 @@ bool TextureCacheRuntime::IsFormatScalable(PixelFormat format) {
}
}
bool TextureCacheRuntime::SupportsLinearFilter(PixelFormat format) const {
if (IsPixelFormatInteger(format)) {
return false;
}
if (VideoCore::Surface::GetFormatType(format) != SurfaceType::ColorTexture) {
return false;
}
const auto vk_format =
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format).format;
constexpr VkFormatFeatureFlags linear_filter_feature =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
return device.IsFormatSupported(vk_format, linear_filter_feature, FormatType::Optimal);
}
void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
std::span<const VideoCommon::ImageCopy> copies) {
// As per the size-compatible formats section of vulkan, copy manually via ReinterpretImage
@ -1925,7 +1945,9 @@ bool Image::ScaleUp(bool ignore) {
if (NeedsScaleHelper()) {
return BlitScaleHelper(true);
} else {
BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution);
const bool supports_linear_filter = runtime->SupportsLinearFilter(info.format);
BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution,
supports_linear_filter);
}
return true;
}
@ -1950,7 +1972,9 @@ bool Image::ScaleDown(bool ignore) {
if (NeedsScaleHelper()) {
return BlitScaleHelper(false);
} else {
BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution, false);
const bool supports_linear_filter = runtime->SupportsLinearFilter(info.format);
BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution,
supports_linear_filter, false);
}
return true;
}
@ -1959,9 +1983,10 @@ bool Image::BlitScaleHelper(bool scale_up) {
using namespace VideoCommon;
static constexpr auto BLIT_OPERATION = Tegra::Engines::Fermi2D::Operation::SrcCopy;
const bool is_color{aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT};
const bool is_bilinear{is_color && !IsPixelFormatInteger(info.format)};
const auto operation = is_bilinear ? Tegra::Engines::Fermi2D::Filter::Bilinear
: Tegra::Engines::Fermi2D::Filter::Point;
const bool supports_linear_filter = runtime->SupportsLinearFilter(info.format);
const bool is_bilinear = is_color && supports_linear_filter;
const auto filter_mode = is_bilinear ? Tegra::Engines::Fermi2D::Filter::Bilinear
: Tegra::Engines::Fermi2D::Filter::Point;
const bool is_2d = info.type == ImageType::e2D;
const auto& resolution = runtime->resolution;
@ -2000,14 +2025,14 @@ bool Image::BlitScaleHelper(bool scale_up) {
}
runtime->blit_image_helper.BlitColor(blit_framebuffer.get(), *blit_view, dst_region,
src_region, operation, BLIT_OPERATION);
src_region, filter_mode, BLIT_OPERATION);
} else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
if (!blit_framebuffer) {
blit_framebuffer =
std::make_unique<Framebuffer>(*runtime, nullptr, view_ptr, extent, scale_up);
}
runtime->blit_image_helper.BlitDepthStencil(blit_framebuffer.get(), *blit_view,
dst_region, src_region, operation,
dst_region, src_region, filter_mode,
BLIT_OPERATION);
} else {
// TODO: Use helper blits where applicable

1
src/video_core/renderer_vulkan/vk_texture_cache.h

@ -117,6 +117,7 @@ public:
bool IsFormatDitherable(VideoCore::Surface::PixelFormat format);
bool IsFormatScalable(VideoCore::Surface::PixelFormat format);
bool SupportsLinearFilter(VideoCore::Surface::PixelFormat format) const;
VkFormat GetSupportedFormat(VkFormat requested_format, VkFormatFeatureFlags required_features) const;

Loading…
Cancel
Save