renderer_vulkan: fix FSR cropping

This commit is contained in:
Liam 2023-10-28 11:40:02 -04:00
parent 65d4a16afd
commit 6513a356f0
3 changed files with 87 additions and 71 deletions

View File

@ -137,6 +137,56 @@ BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWin
BlitScreen::~BlitScreen() = default; BlitScreen::~BlitScreen() = default;
static Common::Rectangle<f32> 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<f32>(framebuffer.crop_rect.left);
top = static_cast<f32>(framebuffer.crop_rect.top);
right = static_cast<f32>(framebuffer.crop_rect.right);
bottom = static_cast<f32>(framebuffer.crop_rect.bottom);
} else {
// Otherwise, fall back to framebuffer dimensions.
left = 0;
top = 0;
right = static_cast<f32>(framebuffer.width);
bottom = static_cast<f32>(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<u32>(framebuffer_transform_flags));
}
// Get the screen properties.
const f32 screen_width = static_cast<f32>(screen_info.width);
const f32 screen_height = static_cast<f32>(screen_info.height);
// Normalize coordinate space.
left /= screen_width;
top /= screen_height;
right /= screen_width;
bottom /= screen_height;
return Common::Rectangle<f32>(left, top, right, bottom);
}
void BlitScreen::Recreate() { void BlitScreen::Recreate() {
present_manager.WaitPresent(); present_manager.WaitPresent();
scheduler.Finish(); 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); source_image_view = smaa->Draw(scheduler, image_index, source_image, source_image_view);
} }
if (fsr) { if (fsr) {
auto crop_rect = framebuffer.crop_rect; const auto crop_rect = NormalizeCrop(framebuffer, screen_info);
if (crop_rect.GetWidth() == 0) { const VkExtent2D fsr_input_size{
crop_rect.right = framebuffer.width; .width = Settings::values.resolution_info.ScaleUp(screen_info.width),
} .height = Settings::values.resolution_info.ScaleUp(screen_info.height),
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),
}; };
VkImageView fsr_image_view = VkImageView fsr_image_view =
fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect);
@ -1395,60 +1438,27 @@ void BlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayou
MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height));
} }
static Common::Rectangle<f32> NormalizeCrop(Common::Rectangle<int> 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<f32>(crop.left);
top = static_cast<f32>(crop.top);
right = static_cast<f32>(crop.right);
bottom = static_cast<f32>(crop.bottom);
} else {
// Otherwise, fall back to framebuffer dimensions.
left = 0;
top = 0;
right = static_cast<f32>(framebuffer.width);
bottom = static_cast<f32>(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<u32>(framebuffer_transform_flags));
}
return Common::Rectangle<f32>(left, top, right, bottom);
}
void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer,
const Layout::FramebufferLayout layout) const { const Layout::FramebufferLayout layout) const {
// Get the normalized crop rectangle. f32 left, top, right, bottom;
const auto crop = NormalizeCrop(framebuffer.crop_rect, framebuffer);
// Get the screen properties. if (fsr) {
const f32 screen_width = static_cast<f32>(screen_info.width); // FSR has already applied the crop, so we just want to render the image
const f32 screen_height = static_cast<f32>(screen_info.height); // it has produced.
left = 0;
top = 0;
right = 1;
bottom = 1;
} else {
// Get the normalized crop rectangle.
const auto crop = NormalizeCrop(framebuffer, screen_info);
// Apply the crop. // Apply the crop.
const f32 left = crop.left / screen_width; left = crop.left;
const f32 top = crop.top / screen_height; top = crop.top;
const f32 right = crop.right / screen_width; right = crop.right;
const f32 bottom = crop.bottom / screen_height; bottom = crop.bottom;
}
// Map the coordinates to the screen. // Map the coordinates to the screen.
const auto& screen = layout.screen; const auto& screen = layout.screen;

View File

@ -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, VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view,
VkExtent2D input_image_extent, const Common::Rectangle<int>& crop_rect) { VkExtent2D input_image_extent, const Common::Rectangle<f32>& crop_rect) {
UpdateDescriptorSet(image_index, image_view); 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); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *easu_pipeline);
std::array<u32, 4 * 4> push_constants; const f32 input_image_width = static_cast<f32>(input_image_extent.width);
FsrEasuConOffset( const f32 input_image_height = static_cast<f32>(input_image_extent.height);
push_constants.data() + 0, push_constants.data() + 4, push_constants.data() + 8, const f32 output_image_width = static_cast<f32>(output_size.width);
push_constants.data() + 12, const f32 output_image_height = static_cast<f32>(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;
static_cast<f32>(crop_rect.GetWidth()), static_cast<f32>(crop_rect.GetHeight()), std::array<u32, 4 * 4> push_constants;
static_cast<f32>(input_image_extent.width), static_cast<f32>(input_image_extent.height), FsrEasuConOffset(push_constants.data() + 0, push_constants.data() + 4,
static_cast<f32>(output_size.width), static_cast<f32>(output_size.height), push_constants.data() + 8, push_constants.data() + 12,
static_cast<f32>(crop_rect.left), static_cast<f32>(crop_rect.top));
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); cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, push_constants);
{ {

View File

@ -17,7 +17,7 @@ public:
explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count,
VkExtent2D output_size); VkExtent2D output_size);
VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view, VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view,
VkExtent2D input_image_extent, const Common::Rectangle<int>& crop_rect); VkExtent2D input_image_extent, const Common::Rectangle<f32>& crop_rect);
private: private:
void CreateDescriptorPool(); void CreateDescriptorPool();