diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index eda2f90c7..5822e887b 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -33,8 +33,8 @@ bool CanBlitToSwapchain(const vk::PhysicalDevice physical_device, vk::Format for }; } -[[nodiscard]] vk::ImageBlit MakeImageBlit(s32 frame_width, s32 frame_height, s32 swapchain_width, - s32 swapchain_height) { +[[nodiscard]] vk::ImageBlit MakeImageBlit(s32 frame_width, s32 frame_height, s32 dst_width, + s32 dst_height, s32 offset_x, s32 offset_y) { return vk::ImageBlit{ .srcSubresource = MakeImageSubresourceLayers(), .srcOffsets = @@ -54,19 +54,44 @@ bool CanBlitToSwapchain(const vk::PhysicalDevice physical_device, vk::Format for .dstOffsets = std::array{ vk::Offset3D{ - .x = 0, - .y = 0, + .x = offset_x, + .y = offset_y, .z = 0, }, vk::Offset3D{ - .x = swapchain_width, - .y = swapchain_height, + .x = offset_x + dst_width, + .y = offset_y + dst_height, .z = 1, }, }, }; } +[[nodiscard]] vk::ImageBlit MakeImageBlitStretch(s32 frame_width, s32 frame_height, + s32 swapchain_width, s32 swapchain_height) { + return MakeImageBlit(frame_width, frame_height, swapchain_width, swapchain_height, 0, 0); +} + +[[nodiscard]] vk::ImageBlit MakeImageBlitFit(s32 frame_width, s32 frame_height, s32 swapchain_width, + s32 swapchain_height) { + float frame_aspect = static_cast(frame_width) / frame_height; + float swapchain_aspect = static_cast(swapchain_width) / swapchain_height; + + s32 dst_width = swapchain_width; + s32 dst_height = swapchain_height; + + if (frame_aspect > swapchain_aspect) { + dst_height = static_cast(swapchain_width / frame_aspect); + } else { + dst_width = static_cast(swapchain_height * frame_aspect); + } + + s32 offset_x = (swapchain_width - dst_width) / 2; + s32 offset_y = (swapchain_height - dst_height) / 2; + + return MakeImageBlit(frame_width, frame_height, dst_width, dst_height, offset_x, offset_y); +} + RendererVulkan::RendererVulkan(Frontend::WindowSDL& window_, AmdGpu::Liverpool* liverpool_) : window{window_}, liverpool{liverpool_}, instance{window, Config::getGpuId(), Config::vkValidationEnabled(), @@ -230,7 +255,7 @@ Frame* RendererVulkan::PrepareFrameInternal(VideoCore::Image& image, bool is_eop // Post-processing (Anti-aliasing, FSR etc) goes here. For now just blit to the frame image. cmdbuf.blitImage( image.image, image.last_state.layout, frame->image, vk::ImageLayout::eTransferDstOptimal, - MakeImageBlit(image.info.size.width, image.info.size.height, frame->width, frame->height), + MakeImageBlitFit(image.info.size.width, image.info.size.height, frame->width, frame->height), vk::Filter::eLinear); const vk::ImageMemoryBarrier post_barrier{ @@ -342,7 +367,7 @@ void RendererVulkan::Present(Frame* frame) { cmdbuf.blitImage(frame->image, vk::ImageLayout::eTransferSrcOptimal, swapchain_image, vk::ImageLayout::eTransferDstOptimal, - MakeImageBlit(frame->width, frame->height, extent.width, extent.height), + MakeImageBlitStretch(frame->width, frame->height, extent.width, extent.height), vk::Filter::eLinear); cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,