From 65d4a16afd7d84742751d3f9b3b0976738cac136 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 27 Oct 2023 23:48:55 -0400 Subject: renderer_vulkan: fix cropping for presentation --- .../service/nvnflinger/buffer_transform_flags.h | 2 + src/video_core/renderer_vulkan/vk_blit_screen.cpp | 101 +++++++++++---------- 2 files changed, 57 insertions(+), 46 deletions(-) diff --git a/src/core/hle/service/nvnflinger/buffer_transform_flags.h b/src/core/hle/service/nvnflinger/buffer_transform_flags.h index 67aa5dad6..ffe579718 100644 --- a/src/core/hle/service/nvnflinger/buffer_transform_flags.h +++ b/src/core/hle/service/nvnflinger/buffer_transform_flags.h @@ -3,6 +3,7 @@ #pragma once +#include "common/common_funcs.h" #include "common/common_types.h" namespace Service::android { @@ -21,5 +22,6 @@ enum class BufferTransformFlags : u32 { /// Rotate source image 270 degrees clockwise Rotate270 = 0x07, }; +DECLARE_ENUM_FLAG_OPERATORS(BufferTransformFlags); } // namespace Service::android diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 52fc142d1..459ab32c2 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -1395,63 +1395,72 @@ void BlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayou MakeOrthographicMatrix(static_cast(layout.width), static_cast(layout.height)); } -void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, - const Layout::FramebufferLayout layout) const { - const auto& framebuffer_transform_flags = framebuffer.transform_flags; - const auto& framebuffer_crop_rect = framebuffer.crop_rect; - - static constexpr Common::Rectangle texcoords{0.f, 0.f, 1.f, 1.f}; - auto left = texcoords.left; - auto right = texcoords.right; - - switch (framebuffer_transform_flags) { - case Service::android::BufferTransformFlags::Unset: - break; - case Service::android::BufferTransformFlags::FlipV: - // Flip the framebuffer vertically - left = texcoords.right; - right = texcoords.left; - break; - default: - UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", - static_cast(framebuffer_transform_flags)); - break; +static Common::Rectangle NormalizeCrop(Common::Rectangle crop, + const Tegra::FramebufferConfig& framebuffer) { + f32 left, top, right, bottom; + + if (!crop.IsEmpty()) { + // If crop rectangle is not empty, apply properties from rectangle. + left = static_cast(crop.left); + top = static_cast(crop.top); + right = static_cast(crop.right); + bottom = static_cast(crop.bottom); + } else { + // Otherwise, fall back to framebuffer dimensions. + left = 0; + top = 0; + right = static_cast(framebuffer.width); + bottom = static_cast(framebuffer.height); } - UNIMPLEMENTED_IF(framebuffer_crop_rect.left != 0); + // Apply transformation flags. + auto framebuffer_transform_flags = framebuffer.transform_flags; - f32 left_start{}; - if (framebuffer_crop_rect.Top() > 0) { - left_start = static_cast(framebuffer_crop_rect.Top()) / - static_cast(framebuffer_crop_rect.Bottom()); + if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipH)) { + // Switch left and right. + std::swap(left, right); } - f32 scale_u = static_cast(framebuffer.width) / static_cast(screen_info.width); - f32 scale_v = static_cast(framebuffer.height) / static_cast(screen_info.height); - // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering - // (e.g. handheld mode) on a 1920x1080 framebuffer. - if (!fsr) { - if (framebuffer_crop_rect.GetWidth() > 0) { - scale_u = static_cast(framebuffer_crop_rect.GetWidth()) / - static_cast(screen_info.width); - } - if (framebuffer_crop_rect.GetHeight() > 0) { - scale_v = static_cast(framebuffer_crop_rect.GetHeight()) / - static_cast(screen_info.height); - } + if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipV)) { + // Switch top and bottom. + std::swap(top, bottom); + } + + framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipH; + framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipV; + if (True(framebuffer_transform_flags)) { + UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", + static_cast(framebuffer_transform_flags)); } + return Common::Rectangle(left, top, right, bottom); +} + +void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, + const Layout::FramebufferLayout layout) const { + // Get the normalized crop rectangle. + const auto crop = NormalizeCrop(framebuffer.crop_rect, framebuffer); + + // Get the screen properties. + const f32 screen_width = static_cast(screen_info.width); + const f32 screen_height = static_cast(screen_info.height); + + // Apply the crop. + const f32 left = crop.left / screen_width; + const f32 top = crop.top / screen_height; + const f32 right = crop.right / screen_width; + const f32 bottom = crop.bottom / screen_height; + + // Map the coordinates to the screen. const auto& screen = layout.screen; const auto x = static_cast(screen.left); const auto y = static_cast(screen.top); const auto w = static_cast(screen.GetWidth()); const auto h = static_cast(screen.GetHeight()); - data.vertices[0] = ScreenRectVertex(x, y, texcoords.top * scale_u, left_start + left * scale_v); - data.vertices[1] = - ScreenRectVertex(x + w, y, texcoords.bottom * scale_u, left_start + left * scale_v); - data.vertices[2] = - ScreenRectVertex(x, y + h, texcoords.top * scale_u, left_start + right * scale_v); - data.vertices[3] = - ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, left_start + right * scale_v); + + data.vertices[0] = ScreenRectVertex(x, y, left, top); + data.vertices[1] = ScreenRectVertex(x + w, y, right, top); + data.vertices[2] = ScreenRectVertex(x, y + h, left, bottom); + data.vertices[3] = ScreenRectVertex(x + w, y + h, right, bottom); } void BlitScreen::CreateSMAA(VkExtent2D smaa_size) { -- cgit v1.2.3 From 6513a356f07e64aacd66e792cf88e4cedc62cbcb Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 28 Oct 2023 11:40:02 -0400 Subject: renderer_vulkan: fix FSR cropping --- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 130 ++++++++++++---------- src/video_core/renderer_vulkan/vk_fsr.cpp | 24 ++-- src/video_core/renderer_vulkan/vk_fsr.h | 2 +- 3 files changed, 86 insertions(+), 70 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 459ab32c2..66483a900 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -137,6 +137,56 @@ BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWin BlitScreen::~BlitScreen() = default; +static Common::Rectangle NormalizeCrop(const Tegra::FramebufferConfig& framebuffer, + const ScreenInfo& screen_info) { + f32 left, top, right, bottom; + + if (!framebuffer.crop_rect.IsEmpty()) { + // If crop rectangle is not empty, apply properties from rectangle. + left = static_cast(framebuffer.crop_rect.left); + top = static_cast(framebuffer.crop_rect.top); + right = static_cast(framebuffer.crop_rect.right); + bottom = static_cast(framebuffer.crop_rect.bottom); + } else { + // Otherwise, fall back to framebuffer dimensions. + left = 0; + top = 0; + right = static_cast(framebuffer.width); + bottom = static_cast(framebuffer.height); + } + + // Apply transformation flags. + auto framebuffer_transform_flags = framebuffer.transform_flags; + + if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipH)) { + // Switch left and right. + std::swap(left, right); + } + if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipV)) { + // Switch top and bottom. + std::swap(top, bottom); + } + + framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipH; + framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipV; + if (True(framebuffer_transform_flags)) { + UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", + static_cast(framebuffer_transform_flags)); + } + + // Get the screen properties. + const f32 screen_width = static_cast(screen_info.width); + const f32 screen_height = static_cast(screen_info.height); + + // Normalize coordinate space. + left /= screen_width; + top /= screen_height; + right /= screen_width; + bottom /= screen_height; + + return Common::Rectangle(left, top, right, bottom); +} + void BlitScreen::Recreate() { present_manager.WaitPresent(); scheduler.Finish(); @@ -354,17 +404,10 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, source_image_view = smaa->Draw(scheduler, image_index, source_image, source_image_view); } if (fsr) { - auto crop_rect = framebuffer.crop_rect; - if (crop_rect.GetWidth() == 0) { - crop_rect.right = framebuffer.width; - } - if (crop_rect.GetHeight() == 0) { - crop_rect.bottom = framebuffer.height; - } - crop_rect = crop_rect.Scale(Settings::values.resolution_info.up_factor); - VkExtent2D fsr_input_size{ - .width = Settings::values.resolution_info.ScaleUp(framebuffer.width), - .height = Settings::values.resolution_info.ScaleUp(framebuffer.height), + const auto crop_rect = NormalizeCrop(framebuffer, screen_info); + const VkExtent2D fsr_input_size{ + .width = Settings::values.resolution_info.ScaleUp(screen_info.width), + .height = Settings::values.resolution_info.ScaleUp(screen_info.height), }; VkImageView fsr_image_view = fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); @@ -1395,61 +1438,28 @@ void BlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayou MakeOrthographicMatrix(static_cast(layout.width), static_cast(layout.height)); } -static Common::Rectangle NormalizeCrop(Common::Rectangle crop, - const Tegra::FramebufferConfig& framebuffer) { +void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, + const Layout::FramebufferLayout layout) const { f32 left, top, right, bottom; - if (!crop.IsEmpty()) { - // If crop rectangle is not empty, apply properties from rectangle. - left = static_cast(crop.left); - top = static_cast(crop.top); - right = static_cast(crop.right); - bottom = static_cast(crop.bottom); - } else { - // Otherwise, fall back to framebuffer dimensions. + if (fsr) { + // FSR has already applied the crop, so we just want to render the image + // it has produced. left = 0; top = 0; - right = static_cast(framebuffer.width); - bottom = static_cast(framebuffer.height); - } - - // Apply transformation flags. - auto framebuffer_transform_flags = framebuffer.transform_flags; - - if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipH)) { - // Switch left and right. - std::swap(left, right); - } - if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipV)) { - // Switch top and bottom. - std::swap(top, bottom); - } - - framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipH; - framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipV; - if (True(framebuffer_transform_flags)) { - UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", - static_cast(framebuffer_transform_flags)); + right = 1; + bottom = 1; + } else { + // Get the normalized crop rectangle. + const auto crop = NormalizeCrop(framebuffer, screen_info); + + // Apply the crop. + left = crop.left; + top = crop.top; + right = crop.right; + bottom = crop.bottom; } - return Common::Rectangle(left, top, right, bottom); -} - -void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, - const Layout::FramebufferLayout layout) const { - // Get the normalized crop rectangle. - const auto crop = NormalizeCrop(framebuffer.crop_rect, framebuffer); - - // Get the screen properties. - const f32 screen_width = static_cast(screen_info.width); - const f32 screen_height = static_cast(screen_info.height); - - // Apply the crop. - const f32 left = crop.left / screen_width; - const f32 top = crop.top / screen_height; - const f32 right = crop.right / screen_width; - const f32 bottom = crop.bottom / screen_height; - // Map the coordinates to the screen. const auto& screen = layout.screen; const auto x = static_cast(screen.left); diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp index ce8f3f3c2..f7a05fbc0 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.cpp +++ b/src/video_core/renderer_vulkan/vk_fsr.cpp @@ -34,7 +34,7 @@ FSR::FSR(const Device& device_, MemoryAllocator& memory_allocator_, size_t image } VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view, - VkExtent2D input_image_extent, const Common::Rectangle& crop_rect) { + VkExtent2D input_image_extent, const Common::Rectangle& crop_rect) { UpdateDescriptorSet(image_index, image_view); @@ -61,15 +61,21 @@ VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImageView imag cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *easu_pipeline); + const f32 input_image_width = static_cast(input_image_extent.width); + const f32 input_image_height = static_cast(input_image_extent.height); + const f32 output_image_width = static_cast(output_size.width); + const f32 output_image_height = static_cast(output_size.height); + const f32 viewport_width = (crop_rect.right - crop_rect.left) * input_image_width; + const f32 viewport_x = crop_rect.left * input_image_width; + const f32 viewport_height = (crop_rect.bottom - crop_rect.top) * input_image_height; + const f32 viewport_y = crop_rect.top * input_image_height; + std::array push_constants; - FsrEasuConOffset( - push_constants.data() + 0, push_constants.data() + 4, push_constants.data() + 8, - push_constants.data() + 12, - - static_cast(crop_rect.GetWidth()), static_cast(crop_rect.GetHeight()), - static_cast(input_image_extent.width), static_cast(input_image_extent.height), - static_cast(output_size.width), static_cast(output_size.height), - static_cast(crop_rect.left), static_cast(crop_rect.top)); + FsrEasuConOffset(push_constants.data() + 0, push_constants.data() + 4, + push_constants.data() + 8, push_constants.data() + 12, + + viewport_width, viewport_height, input_image_width, input_image_height, + output_image_width, output_image_height, viewport_x, viewport_y); cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, push_constants); { diff --git a/src/video_core/renderer_vulkan/vk_fsr.h b/src/video_core/renderer_vulkan/vk_fsr.h index 8bb9fc23a..3505c1416 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.h +++ b/src/video_core/renderer_vulkan/vk_fsr.h @@ -17,7 +17,7 @@ public: explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, VkExtent2D output_size); VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view, - VkExtent2D input_image_extent, const Common::Rectangle& crop_rect); + VkExtent2D input_image_extent, const Common::Rectangle& crop_rect); private: void CreateDescriptorPool(); -- cgit v1.2.3