diff options
| author | 2021-10-16 20:33:58 -0500 | |
|---|---|---|
| committer | 2021-11-16 22:11:31 +0100 | |
| commit | 37cb0377ae30e2139f6fa381d04124e51fcccded (patch) | |
| tree | a1cd811a61535d8aa8790a9ac0400b0e79976499 | |
| parent | Texture Cache: Rescale conversions between depth and color (diff) | |
| download | yuzu-37cb0377ae30e2139f6fa381d04124e51fcccded.tar.gz yuzu-37cb0377ae30e2139f6fa381d04124e51fcccded.tar.xz yuzu-37cb0377ae30e2139f6fa381d04124e51fcccded.zip | |
vulkan: Implement FidelityFX Super Resolution
| -rw-r--r-- | src/common/settings.h | 1 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/host_shaders/CMakeLists.txt | 17 | ||||
| -rw-r--r-- | src/video_core/host_shaders/fidelityfx_fsr.comp | 114 | ||||
| -rw-r--r-- | src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu.comp | 13 | ||||
| -rw-r--r-- | src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas.comp | 13 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_blit_screen.cpp | 62 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_blit_screen.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_fsr.cpp | 375 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_fsr.h | 54 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics.ui | 5 |
11 files changed, 643 insertions, 17 deletions
diff --git a/src/common/settings.h b/src/common/settings.h index a09db0822..9da447ce0 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -64,6 +64,7 @@ enum class ScalingFilter : u32 { | |||
| 64 | Bilinear = 0, | 64 | Bilinear = 0, |
| 65 | Bicubic = 1, | 65 | Bicubic = 1, |
| 66 | ScaleForce = 2, | 66 | ScaleForce = 2, |
| 67 | Fsr = 3, | ||
| 67 | }; | 68 | }; |
| 68 | 69 | ||
| 69 | struct ResolutionScalingInfo { | 70 | struct ResolutionScalingInfo { |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 6aac7f305..91a30fef7 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -132,6 +132,8 @@ add_library(video_core STATIC | |||
| 132 | renderer_vulkan/vk_descriptor_pool.h | 132 | renderer_vulkan/vk_descriptor_pool.h |
| 133 | renderer_vulkan/vk_fence_manager.cpp | 133 | renderer_vulkan/vk_fence_manager.cpp |
| 134 | renderer_vulkan/vk_fence_manager.h | 134 | renderer_vulkan/vk_fence_manager.h |
| 135 | renderer_vulkan/vk_fsr.cpp | ||
| 136 | renderer_vulkan/vk_fsr.h | ||
| 135 | renderer_vulkan/vk_graphics_pipeline.cpp | 137 | renderer_vulkan/vk_graphics_pipeline.cpp |
| 136 | renderer_vulkan/vk_graphics_pipeline.h | 138 | renderer_vulkan/vk_graphics_pipeline.h |
| 137 | renderer_vulkan/vk_master_semaphore.cpp | 139 | renderer_vulkan/vk_master_semaphore.cpp |
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 664d6ce5d..32e2ab500 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt | |||
| @@ -1,3 +1,11 @@ | |||
| 1 | set(FIDELITYFX_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/externals/FidelityFX-FSR/ffx-fsr) | ||
| 2 | |||
| 3 | set(GLSL_INCLUDES | ||
| 4 | fidelityfx_fsr.comp | ||
| 5 | ${FIDELITYFX_INCLUDE_DIR}/ffx_a.h | ||
| 6 | ${FIDELITYFX_INCLUDE_DIR}/ffx_fsr1.h | ||
| 7 | ) | ||
| 8 | |||
| 1 | set(SHADER_FILES | 9 | set(SHADER_FILES |
| 2 | astc_decoder.comp | 10 | astc_decoder.comp |
| 3 | block_linear_unswizzle_2d.comp | 11 | block_linear_unswizzle_2d.comp |
| @@ -13,6 +21,8 @@ set(SHADER_FILES | |||
| 13 | present_bicubic.frag | 21 | present_bicubic.frag |
| 14 | vulkan_blit_color_float.frag | 22 | vulkan_blit_color_float.frag |
| 15 | vulkan_blit_depth_stencil.frag | 23 | vulkan_blit_depth_stencil.frag |
| 24 | vulkan_fidelityfx_fsr_easu.comp | ||
| 25 | vulkan_fidelityfx_fsr_rcas.comp | ||
| 16 | vulkan_present.frag | 26 | vulkan_present.frag |
| 17 | vulkan_present.vert | 27 | vulkan_present.vert |
| 18 | vulkan_quad_indexed.comp | 28 | vulkan_quad_indexed.comp |
| @@ -78,7 +88,7 @@ foreach(FILENAME IN ITEMS ${SHADER_FILES}) | |||
| 78 | OUTPUT | 88 | OUTPUT |
| 79 | ${SPIRV_HEADER_FILE} | 89 | ${SPIRV_HEADER_FILE} |
| 80 | COMMAND | 90 | COMMAND |
| 81 | ${GLSLANGVALIDATOR} -V ${QUIET_FLAG} ${GLSL_FLAGS} --variable-name ${SPIRV_VARIABLE_NAME} -o ${SPIRV_HEADER_FILE} ${SOURCE_FILE} | 91 | ${GLSLANGVALIDATOR} -V ${QUIET_FLAG} -I"${FIDELITYFX_INCLUDE_DIR}" ${GLSL_FLAGS} --variable-name ${SPIRV_VARIABLE_NAME} -o ${SPIRV_HEADER_FILE} ${SOURCE_FILE} |
| 82 | MAIN_DEPENDENCY | 92 | MAIN_DEPENDENCY |
| 83 | ${SOURCE_FILE} | 93 | ${SOURCE_FILE} |
| 84 | ) | 94 | ) |
| @@ -86,9 +96,12 @@ foreach(FILENAME IN ITEMS ${SHADER_FILES}) | |||
| 86 | endif() | 96 | endif() |
| 87 | endforeach() | 97 | endforeach() |
| 88 | 98 | ||
| 99 | set(SHADER_SOURCES ${SHADER_FILES}) | ||
| 100 | list(APPEND SHADER_SOURCES ${GLSL_INCLUDES}) | ||
| 101 | |||
| 89 | add_custom_target(host_shaders | 102 | add_custom_target(host_shaders |
| 90 | DEPENDS | 103 | DEPENDS |
| 91 | ${SHADER_HEADERS} | 104 | ${SHADER_HEADERS} |
| 92 | SOURCES | 105 | SOURCES |
| 93 | ${SHADER_FILES} | 106 | ${SHADER_SOURCES} |
| 94 | ) | 107 | ) |
diff --git a/src/video_core/host_shaders/fidelityfx_fsr.comp b/src/video_core/host_shaders/fidelityfx_fsr.comp new file mode 100644 index 000000000..cbb601580 --- /dev/null +++ b/src/video_core/host_shaders/fidelityfx_fsr.comp | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | //!#version 460 core | ||
| 6 | #extension GL_ARB_separate_shader_objects : enable | ||
| 7 | #extension GL_ARB_shading_language_420pack : enable | ||
| 8 | #extension GL_GOOGLE_include_directive : enable | ||
| 9 | #extension GL_EXT_shader_explicit_arithmetic_types : require | ||
| 10 | |||
| 11 | // FidelityFX Super Resolution Sample | ||
| 12 | // | ||
| 13 | // Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. | ||
| 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 15 | // of this software and associated documentation files(the "Software"), to deal | ||
| 16 | // in the Software without restriction, including without limitation the rights | ||
| 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell | ||
| 18 | // copies of the Software, and to permit persons to whom the Software is | ||
| 19 | // furnished to do so, subject to the following conditions : | ||
| 20 | // The above copyright notice and this permission notice shall be included in | ||
| 21 | // all copies or substantial portions of the Software. | ||
| 22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 23 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 24 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE | ||
| 25 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 26 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 27 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 28 | // THE SOFTWARE. | ||
| 29 | |||
| 30 | layout( push_constant ) uniform constants { | ||
| 31 | u32vec2 input_size; | ||
| 32 | }; | ||
| 33 | |||
| 34 | uvec4 Const0; | ||
| 35 | uvec4 Const1; | ||
| 36 | uvec4 Const2; | ||
| 37 | uvec4 Const3; | ||
| 38 | |||
| 39 | #define A_GPU 1 | ||
| 40 | #define A_GLSL 1 | ||
| 41 | #define A_HALF | ||
| 42 | |||
| 43 | #include "ffx_a.h" | ||
| 44 | |||
| 45 | f16vec4 LinearToSRGB(f16vec4 linear) { | ||
| 46 | bvec4 selector = greaterThan(linear, f16vec4(0.00313066844250063)); | ||
| 47 | f16vec4 low = linear * float16_t(12.92); | ||
| 48 | f16vec4 high = float16_t(1.055) * pow(linear, f16vec4(1 / 2.4)) - float16_t(0.055); | ||
| 49 | return mix(low, high, selector); | ||
| 50 | } | ||
| 51 | |||
| 52 | f16vec4 SRGBToLinear(f16vec4 srgb) { | ||
| 53 | bvec4 selector = greaterThan(srgb, f16vec4(0.0404482362771082)); | ||
| 54 | f16vec4 low = srgb * float16_t(1.0 / 12.92); | ||
| 55 | f16vec4 high = pow((srgb + float16_t(0.055)) * float16_t(1.0 / 1.055), f16vec4(2.4)); | ||
| 56 | return mix(low, high, selector); | ||
| 57 | } | ||
| 58 | |||
| 59 | #if USE_EASU | ||
| 60 | #define FSR_EASU_H 1 | ||
| 61 | f16vec4 FsrEasuRH(vec2 p) { f16vec4 res = f16vec4(textureGather(InputTexture, p, 0)); return res; } | ||
| 62 | f16vec4 FsrEasuGH(vec2 p) { f16vec4 res = f16vec4(textureGather(InputTexture, p, 1)); return res; } | ||
| 63 | f16vec4 FsrEasuBH(vec2 p) { f16vec4 res = f16vec4(textureGather(InputTexture, p, 2)); return res; } | ||
| 64 | #endif | ||
| 65 | #if USE_RCAS | ||
| 66 | #define FSR_RCAS_H 1 | ||
| 67 | f16vec4 FsrRcasLoadH(ASW2 p) { return f16vec4(texelFetch(InputTexture, ASU2(p), 0)); } | ||
| 68 | void FsrRcasInputH(inout float16_t r, inout float16_t g, inout float16_t b) {} | ||
| 69 | #endif | ||
| 70 | |||
| 71 | #include "ffx_fsr1.h" | ||
| 72 | |||
| 73 | void CurrFilter(u32vec2 pos) { | ||
| 74 | // For debugging | ||
| 75 | #if USE_BILINEAR | ||
| 76 | vec2 pp = (vec2(pos) * vec2_AU2(Const0.xy) + vec2_AU2(Const0.zw)) * vec2_AU2(Const1.xy) + vec2(0.5, -0.5) * vec2_AU2(Const1.zw); | ||
| 77 | imageStore(OutputTexture, ivec2(pos), textureLod(InputTexture, pp, 0.0)); | ||
| 78 | #endif | ||
| 79 | #if USE_EASU | ||
| 80 | f16vec3 c; | ||
| 81 | FsrEasuH(c, pos, Const0, Const1, Const2, Const3); | ||
| 82 | imageStore(OutputTexture, ivec2(pos), f16vec4(c, 1)); | ||
| 83 | #endif | ||
| 84 | #if USE_RCAS | ||
| 85 | f16vec3 c; | ||
| 86 | FsrRcasH(c.r, c.g, c.b, pos, Const0); | ||
| 87 | imageStore(OutputTexture, ivec2(pos), f16vec4(c, 1)); | ||
| 88 | #endif | ||
| 89 | |||
| 90 | } | ||
| 91 | |||
| 92 | layout(local_size_x=64) in; | ||
| 93 | void main() { | ||
| 94 | |||
| 95 | #if USE_EASU || USE_BILINEAR | ||
| 96 | vec2 ires = vec2(input_size); | ||
| 97 | vec2 tres = textureSize(InputTexture, 0); | ||
| 98 | vec2 ores = imageSize(OutputTexture); | ||
| 99 | FsrEasuCon(Const0, Const1, Const2, Const3, ires.x, ires.y, tres.x, tres.y, ores.x, ores.y); | ||
| 100 | #endif | ||
| 101 | #if USE_RCAS | ||
| 102 | FsrRcasCon(Const0, 0.25f); | ||
| 103 | #endif | ||
| 104 | |||
| 105 | // Do remapping of local xy in workgroup for a more PS-like swizzle pattern. | ||
| 106 | AU2 gxy = ARmp8x8(gl_LocalInvocationID.x) + AU2(gl_WorkGroupID.x << 4u, gl_WorkGroupID.y << 4u); | ||
| 107 | CurrFilter(gxy); | ||
| 108 | gxy.x += 8u; | ||
| 109 | CurrFilter(gxy); | ||
| 110 | gxy.y += 8u; | ||
| 111 | CurrFilter(gxy); | ||
| 112 | gxy.x -= 8u; | ||
| 113 | CurrFilter(gxy); | ||
| 114 | } | ||
diff --git a/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu.comp b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu.comp new file mode 100644 index 000000000..6525eeeb5 --- /dev/null +++ b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_easu.comp | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #version 460 core | ||
| 6 | #extension GL_GOOGLE_include_directive : enable | ||
| 7 | |||
| 8 | layout(set=0,binding=0) uniform sampler2D InputTexture; | ||
| 9 | layout(set=0,binding=1,rgba16f) uniform image2D OutputTexture; | ||
| 10 | |||
| 11 | #define USE_EASU 1 | ||
| 12 | |||
| 13 | #include "fidelityfx_fsr.comp" | ||
diff --git a/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas.comp b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas.comp new file mode 100644 index 000000000..9463ed842 --- /dev/null +++ b/src/video_core/host_shaders/vulkan_fidelityfx_fsr_rcas.comp | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #version 460 core | ||
| 6 | #extension GL_GOOGLE_include_directive : enable | ||
| 7 | |||
| 8 | layout(set=0,binding=0) uniform sampler2D InputTexture; | ||
| 9 | layout(set=0,binding=1,rgba16f) uniform image2D OutputTexture; | ||
| 10 | |||
| 11 | #define USE_RCAS 1 | ||
| 12 | |||
| 13 | #include "fidelityfx_fsr.comp" | ||
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index c91b24e3a..8ce60e874 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "video_core/host_shaders/vulkan_present_vert_spv.h" | 23 | #include "video_core/host_shaders/vulkan_present_vert_spv.h" |
| 24 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 24 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| 25 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 25 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 26 | #include "video_core/renderer_vulkan/vk_fsr.h" | ||
| 26 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | 27 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" |
| 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 28 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 28 | #include "video_core/renderer_vulkan/vk_shader_util.h" | 29 | #include "video_core/renderer_vulkan/vk_shader_util.h" |
| @@ -147,8 +148,12 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||
| 147 | scheduler.Wait(resource_ticks[image_index]); | 148 | scheduler.Wait(resource_ticks[image_index]); |
| 148 | resource_ticks[image_index] = scheduler.CurrentTick(); | 149 | resource_ticks[image_index] = scheduler.CurrentTick(); |
| 149 | 150 | ||
| 150 | UpdateDescriptorSet(image_index, | 151 | const VkImageView source_image_view = |
| 151 | use_accelerated ? screen_info.image_view : *raw_image_views[image_index]); | 152 | use_accelerated ? screen_info.image_view : *raw_image_views[image_index]; |
| 153 | |||
| 154 | if (!fsr) { | ||
| 155 | UpdateDescriptorSet(image_index, source_image_view); | ||
| 156 | } | ||
| 152 | 157 | ||
| 153 | BufferData data; | 158 | BufferData data; |
| 154 | SetUniformData(data, layout); | 159 | SetUniformData(data, layout); |
| @@ -225,9 +230,26 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||
| 225 | read_barrier); | 230 | read_barrier); |
| 226 | cmdbuf.CopyBufferToImage(*buffer, image, VK_IMAGE_LAYOUT_GENERAL, copy); | 231 | cmdbuf.CopyBufferToImage(*buffer, image, VK_IMAGE_LAYOUT_GENERAL, copy); |
| 227 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, | 232 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, |
| 228 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier); | 233 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | |
| 234 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 235 | 0, write_barrier); | ||
| 229 | }); | 236 | }); |
| 230 | } | 237 | } |
| 238 | |||
| 239 | if (fsr) { | ||
| 240 | auto crop_rect = framebuffer.crop_rect; | ||
| 241 | if (crop_rect.GetWidth() == 0) { | ||
| 242 | crop_rect.right = framebuffer.width; | ||
| 243 | } | ||
| 244 | if (crop_rect.GetHeight() == 0) { | ||
| 245 | crop_rect.bottom = framebuffer.height; | ||
| 246 | } | ||
| 247 | crop_rect = crop_rect.Scale(Settings::values.resolution_info.up_factor); | ||
| 248 | VkImageView fsr_image_view = | ||
| 249 | fsr->Draw(scheduler, image_index, source_image_view, crop_rect); | ||
| 250 | UpdateDescriptorSet(image_index, fsr_image_view); | ||
| 251 | } | ||
| 252 | |||
| 231 | scheduler.Record( | 253 | scheduler.Record( |
| 232 | [this, host_framebuffer, image_index, size = render_area](vk::CommandBuffer cmdbuf) { | 254 | [this, host_framebuffer, image_index, size = render_area](vk::CommandBuffer cmdbuf) { |
| 233 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; | 255 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; |
| @@ -325,6 +347,13 @@ void VKBlitScreen::CreateDynamicResources() { | |||
| 325 | CreateRenderPass(); | 347 | CreateRenderPass(); |
| 326 | CreateFramebuffers(); | 348 | CreateFramebuffers(); |
| 327 | CreateGraphicsPipeline(); | 349 | CreateGraphicsPipeline(); |
| 350 | fsr.reset(); | ||
| 351 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 352 | const auto& layout = render_window.GetFramebufferLayout(); | ||
| 353 | fsr = std::make_unique<FSR>( | ||
| 354 | device, memory_allocator, image_count, | ||
| 355 | VkExtent2D{.width = layout.screen.GetWidth(), .height = layout.screen.GetHeight()}); | ||
| 356 | } | ||
| 328 | } | 357 | } |
| 329 | 358 | ||
| 330 | void VKBlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { | 359 | void VKBlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -716,13 +745,14 @@ void VKBlitScreen::CreateGraphicsPipeline() { | |||
| 716 | } | 745 | } |
| 717 | 746 | ||
| 718 | void VKBlitScreen::CreateSampler() { | 747 | void VKBlitScreen::CreateSampler() { |
| 748 | bool linear = Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::Fsr; | ||
| 719 | const VkSamplerCreateInfo ci{ | 749 | const VkSamplerCreateInfo ci{ |
| 720 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | 750 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, |
| 721 | .pNext = nullptr, | 751 | .pNext = nullptr, |
| 722 | .flags = 0, | 752 | .flags = 0, |
| 723 | .magFilter = VK_FILTER_LINEAR, | 753 | .magFilter = linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, |
| 724 | .minFilter = VK_FILTER_LINEAR, | 754 | .minFilter = linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, |
| 725 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, | 755 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, |
| 726 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | 756 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, |
| 727 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | 757 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, |
| 728 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | 758 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, |
| @@ -905,17 +935,19 @@ void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfi | |||
| 905 | UNIMPLEMENTED_IF(framebuffer_crop_rect.top != 0); | 935 | UNIMPLEMENTED_IF(framebuffer_crop_rect.top != 0); |
| 906 | UNIMPLEMENTED_IF(framebuffer_crop_rect.left != 0); | 936 | UNIMPLEMENTED_IF(framebuffer_crop_rect.left != 0); |
| 907 | 937 | ||
| 908 | // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering | ||
| 909 | // (e.g. handheld mode) on a 1920x1080 framebuffer. | ||
| 910 | f32 scale_u = 1.0f; | 938 | f32 scale_u = 1.0f; |
| 911 | f32 scale_v = 1.0f; | 939 | f32 scale_v = 1.0f; |
| 912 | if (framebuffer_crop_rect.GetWidth() > 0) { | 940 | // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering |
| 913 | scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) / | 941 | // (e.g. handheld mode) on a 1920x1080 framebuffer. |
| 914 | static_cast<f32>(screen_info.width); | 942 | if (!fsr) { |
| 915 | } | 943 | if (framebuffer_crop_rect.GetWidth() > 0) { |
| 916 | if (framebuffer_crop_rect.GetHeight() > 0) { | 944 | scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) / |
| 917 | scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) / | 945 | static_cast<f32>(screen_info.width); |
| 918 | static_cast<f32>(screen_info.height); | 946 | } |
| 947 | if (framebuffer_crop_rect.GetHeight() > 0) { | ||
| 948 | scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) / | ||
| 949 | static_cast<f32>(screen_info.height); | ||
| 950 | } | ||
| 919 | } | 951 | } |
| 920 | 952 | ||
| 921 | const auto& screen = layout.screen; | 953 | const auto& screen = layout.screen; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index d3a16f0ba..337931468 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -38,6 +38,8 @@ class RasterizerVulkan; | |||
| 38 | class VKScheduler; | 38 | class VKScheduler; |
| 39 | class VKSwapchain; | 39 | class VKSwapchain; |
| 40 | 40 | ||
| 41 | class FSR; | ||
| 42 | |||
| 41 | struct VKScreenInfo { | 43 | struct VKScreenInfo { |
| 42 | VkImageView image_view{}; | 44 | VkImageView image_view{}; |
| 43 | u32 width{}; | 45 | u32 width{}; |
| @@ -132,6 +134,8 @@ private: | |||
| 132 | std::vector<MemoryCommit> raw_buffer_commits; | 134 | std::vector<MemoryCommit> raw_buffer_commits; |
| 133 | u32 raw_width = 0; | 135 | u32 raw_width = 0; |
| 134 | u32 raw_height = 0; | 136 | u32 raw_height = 0; |
| 137 | |||
| 138 | std::unique_ptr<FSR> fsr; | ||
| 135 | }; | 139 | }; |
| 136 | 140 | ||
| 137 | } // namespace Vulkan | 141 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp new file mode 100644 index 000000000..fd0a4aa42 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_fsr.cpp | |||
| @@ -0,0 +1,375 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/div_ceil.h" | ||
| 6 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_comp_spv.h" | ||
| 7 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_comp_spv.h" | ||
| 8 | #include "video_core/renderer_vulkan/vk_fsr.h" | ||
| 9 | #include "video_core/renderer_vulkan/vk_scheduler.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_shader_util.h" | ||
| 11 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 12 | |||
| 13 | namespace Vulkan { | ||
| 14 | |||
| 15 | FSR::FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, | ||
| 16 | VkExtent2D output_size) | ||
| 17 | : device{device}, memory_allocator{memory_allocator}, image_count{image_count}, | ||
| 18 | output_size{output_size} { | ||
| 19 | |||
| 20 | CreateImages(); | ||
| 21 | CreateSampler(); | ||
| 22 | CreateShaders(); | ||
| 23 | CreateDescriptorPool(); | ||
| 24 | CreateDescriptorSetLayout(); | ||
| 25 | CreateDescriptorSets(); | ||
| 26 | CreatePipelineLayout(); | ||
| 27 | CreatePipeline(); | ||
| 28 | } | ||
| 29 | |||
| 30 | VkImageView FSR::Draw(VKScheduler& scheduler, size_t image_index, VkImageView image_view, | ||
| 31 | const Common::Rectangle<int>& crop_rect) { | ||
| 32 | |||
| 33 | UpdateDescriptorSet(image_index, image_view); | ||
| 34 | |||
| 35 | scheduler.Record([this, image_index, crop_rect](vk::CommandBuffer cmdbuf) { | ||
| 36 | const VkImageMemoryBarrier base_barrier{ | ||
| 37 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 38 | .pNext = nullptr, | ||
| 39 | .srcAccessMask = 0, | ||
| 40 | .dstAccessMask = 0, | ||
| 41 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 42 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 43 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 44 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 45 | .image = {}, | ||
| 46 | .subresourceRange = | ||
| 47 | { | ||
| 48 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 49 | .baseMipLevel = 0, | ||
| 50 | .levelCount = 1, | ||
| 51 | .baseArrayLayer = 0, | ||
| 52 | .layerCount = 1, | ||
| 53 | }, | ||
| 54 | }; | ||
| 55 | |||
| 56 | // TODO: Support clear color | ||
| 57 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *easu_pipeline); | ||
| 58 | cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 59 | VkExtent2D{ | ||
| 60 | .width = static_cast<u32>(crop_rect.GetWidth()), | ||
| 61 | .height = static_cast<u32>(crop_rect.GetHeight()), | ||
| 62 | }); | ||
| 63 | |||
| 64 | { | ||
| 65 | VkImageMemoryBarrier fsr_write_barrier = base_barrier; | ||
| 66 | fsr_write_barrier.image = *images[image_index], | ||
| 67 | fsr_write_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||
| 68 | |||
| 69 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 70 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, fsr_write_barrier); | ||
| 71 | } | ||
| 72 | |||
| 73 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0, | ||
| 74 | descriptor_sets[image_index * 2], {}); | ||
| 75 | cmdbuf.Dispatch(Common::DivCeil(output_size.width, 16u), | ||
| 76 | Common::DivCeil(output_size.height, 16u), 1); | ||
| 77 | |||
| 78 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *rcas_pipeline); | ||
| 79 | cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, output_size); | ||
| 80 | |||
| 81 | { | ||
| 82 | std::array<VkImageMemoryBarrier, 2> barriers; | ||
| 83 | auto& fsr_read_barrier = barriers[0]; | ||
| 84 | auto& blit_write_barrier = barriers[1]; | ||
| 85 | |||
| 86 | fsr_read_barrier = base_barrier; | ||
| 87 | fsr_read_barrier.image = *images[image_index]; | ||
| 88 | fsr_read_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; | ||
| 89 | fsr_read_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| 90 | |||
| 91 | blit_write_barrier = base_barrier; | ||
| 92 | blit_write_barrier.image = *images[image_count + image_index]; | ||
| 93 | blit_write_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||
| 94 | blit_write_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; | ||
| 95 | |||
| 96 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 97 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, {}, {}, barriers); | ||
| 98 | } | ||
| 99 | |||
| 100 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0, | ||
| 101 | descriptor_sets[image_index * 2 + 1], {}); | ||
| 102 | cmdbuf.Dispatch(Common::DivCeil(output_size.width, 16u), | ||
| 103 | Common::DivCeil(output_size.height, 16u), 1); | ||
| 104 | |||
| 105 | { | ||
| 106 | std::array<VkImageMemoryBarrier, 1> barriers; | ||
| 107 | auto& blit_read_barrier = barriers[0]; | ||
| 108 | |||
| 109 | blit_read_barrier = base_barrier; | ||
| 110 | blit_read_barrier.image = *images[image_count + image_index]; | ||
| 111 | blit_read_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; | ||
| 112 | blit_read_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| 113 | |||
| 114 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 115 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, {}, {}, barriers); | ||
| 116 | } | ||
| 117 | }); | ||
| 118 | |||
| 119 | return *image_views[image_count + image_index]; | ||
| 120 | } | ||
| 121 | |||
| 122 | void FSR::CreateDescriptorPool() { | ||
| 123 | const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ | ||
| 124 | { | ||
| 125 | .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 126 | .descriptorCount = static_cast<u32>(image_count * 2), | ||
| 127 | }, | ||
| 128 | { | ||
| 129 | .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, | ||
| 130 | .descriptorCount = static_cast<u32>(image_count * 2), | ||
| 131 | }, | ||
| 132 | }}; | ||
| 133 | |||
| 134 | const VkDescriptorPoolCreateInfo ci{ | ||
| 135 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | ||
| 136 | .pNext = nullptr, | ||
| 137 | .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, | ||
| 138 | .maxSets = static_cast<u32>(image_count * 2), | ||
| 139 | .poolSizeCount = static_cast<u32>(pool_sizes.size()), | ||
| 140 | .pPoolSizes = pool_sizes.data(), | ||
| 141 | }; | ||
| 142 | descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); | ||
| 143 | } | ||
| 144 | |||
| 145 | void FSR::CreateDescriptorSetLayout() { | ||
| 146 | const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ | ||
| 147 | { | ||
| 148 | .binding = 0, | ||
| 149 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 150 | .descriptorCount = 1, | ||
| 151 | .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 152 | .pImmutableSamplers = sampler.address(), | ||
| 153 | }, | ||
| 154 | { | ||
| 155 | .binding = 1, | ||
| 156 | .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, | ||
| 157 | .descriptorCount = 1, | ||
| 158 | .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 159 | .pImmutableSamplers = sampler.address(), | ||
| 160 | }, | ||
| 161 | }}; | ||
| 162 | |||
| 163 | const VkDescriptorSetLayoutCreateInfo ci{ | ||
| 164 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | ||
| 165 | .pNext = nullptr, | ||
| 166 | .flags = 0, | ||
| 167 | .bindingCount = static_cast<u32>(layout_bindings.size()), | ||
| 168 | .pBindings = layout_bindings.data(), | ||
| 169 | }; | ||
| 170 | |||
| 171 | descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); | ||
| 172 | } | ||
| 173 | |||
| 174 | void FSR::CreateDescriptorSets() { | ||
| 175 | const u32 sets = static_cast<u32>(image_count * 2); | ||
| 176 | const std::vector layouts(sets, *descriptor_set_layout); | ||
| 177 | |||
| 178 | const VkDescriptorSetAllocateInfo ai{ | ||
| 179 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, | ||
| 180 | .pNext = nullptr, | ||
| 181 | .descriptorPool = *descriptor_pool, | ||
| 182 | .descriptorSetCount = sets, | ||
| 183 | .pSetLayouts = layouts.data(), | ||
| 184 | }; | ||
| 185 | |||
| 186 | descriptor_sets = descriptor_pool.Allocate(ai); | ||
| 187 | } | ||
| 188 | |||
| 189 | void FSR::CreateImages() { | ||
| 190 | images.resize(image_count * 2); | ||
| 191 | image_views.resize(image_count * 2); | ||
| 192 | buffer_commits.resize(image_count * 2); | ||
| 193 | |||
| 194 | for (size_t i = 0; i < image_count * 2; ++i) { | ||
| 195 | images[i] = device.GetLogical().CreateImage(VkImageCreateInfo{ | ||
| 196 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | ||
| 197 | .pNext = nullptr, | ||
| 198 | .flags = 0, | ||
| 199 | .imageType = VK_IMAGE_TYPE_2D, | ||
| 200 | .format = VK_FORMAT_R16G16B16A16_SFLOAT, | ||
| 201 | .extent = | ||
| 202 | { | ||
| 203 | .width = output_size.width, | ||
| 204 | .height = output_size.height, | ||
| 205 | .depth = 1, | ||
| 206 | }, | ||
| 207 | .mipLevels = 1, | ||
| 208 | .arrayLayers = 1, | ||
| 209 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 210 | .tiling = VK_IMAGE_TILING_OPTIMAL, | ||
| 211 | .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT | | ||
| 212 | VK_IMAGE_USAGE_SAMPLED_BIT, | ||
| 213 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 214 | .queueFamilyIndexCount = 0, | ||
| 215 | .pQueueFamilyIndices = nullptr, | ||
| 216 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 217 | }); | ||
| 218 | buffer_commits[i] = memory_allocator.Commit(images[i], MemoryUsage::DeviceLocal); | ||
| 219 | image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | ||
| 220 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | ||
| 221 | .pNext = nullptr, | ||
| 222 | .flags = 0, | ||
| 223 | .image = *images[i], | ||
| 224 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | ||
| 225 | .format = VK_FORMAT_R16G16B16A16_SFLOAT, | ||
| 226 | .components = | ||
| 227 | { | ||
| 228 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 229 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 230 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 231 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 232 | }, | ||
| 233 | .subresourceRange = | ||
| 234 | { | ||
| 235 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 236 | .baseMipLevel = 0, | ||
| 237 | .levelCount = 1, | ||
| 238 | .baseArrayLayer = 0, | ||
| 239 | .layerCount = 1, | ||
| 240 | }, | ||
| 241 | }); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | void FSR::CreatePipelineLayout() { | ||
| 246 | VkPushConstantRange push_const{ | ||
| 247 | .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 248 | .offset = 0, | ||
| 249 | .size = sizeof(std::array<u32, 2>), | ||
| 250 | }; | ||
| 251 | VkPipelineLayoutCreateInfo ci{ | ||
| 252 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | ||
| 253 | .pNext = nullptr, | ||
| 254 | .flags = 0, | ||
| 255 | .setLayoutCount = 1, | ||
| 256 | .pSetLayouts = descriptor_set_layout.address(), | ||
| 257 | .pushConstantRangeCount = 1, | ||
| 258 | .pPushConstantRanges = &push_const, | ||
| 259 | }; | ||
| 260 | |||
| 261 | pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); | ||
| 262 | } | ||
| 263 | |||
| 264 | void FSR::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view) const { | ||
| 265 | const auto fsr_image_view = *image_views[image_index]; | ||
| 266 | const auto blit_image_view = *image_views[image_count + image_index]; | ||
| 267 | |||
| 268 | const VkDescriptorImageInfo image_info{ | ||
| 269 | .imageView = image_view, | ||
| 270 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 271 | }; | ||
| 272 | const VkDescriptorImageInfo fsr_image_info{ | ||
| 273 | .imageView = fsr_image_view, | ||
| 274 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 275 | }; | ||
| 276 | const VkDescriptorImageInfo blit_image_info{ | ||
| 277 | .imageView = blit_image_view, | ||
| 278 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 279 | }; | ||
| 280 | |||
| 281 | VkWriteDescriptorSet sampler_write{ | ||
| 282 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 283 | .pNext = nullptr, | ||
| 284 | .dstSet = descriptor_sets[image_index * 2], | ||
| 285 | .dstBinding = 0, | ||
| 286 | .dstArrayElement = 0, | ||
| 287 | .descriptorCount = 1, | ||
| 288 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 289 | .pImageInfo = &image_info, | ||
| 290 | .pBufferInfo = nullptr, | ||
| 291 | .pTexelBufferView = nullptr, | ||
| 292 | }; | ||
| 293 | |||
| 294 | VkWriteDescriptorSet output_write{ | ||
| 295 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 296 | .pNext = nullptr, | ||
| 297 | .dstSet = descriptor_sets[image_index * 2], | ||
| 298 | .dstBinding = 1, | ||
| 299 | .dstArrayElement = 0, | ||
| 300 | .descriptorCount = 1, | ||
| 301 | .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, | ||
| 302 | .pImageInfo = &fsr_image_info, | ||
| 303 | .pBufferInfo = nullptr, | ||
| 304 | .pTexelBufferView = nullptr, | ||
| 305 | }; | ||
| 306 | |||
| 307 | device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, output_write}, {}); | ||
| 308 | |||
| 309 | sampler_write.dstSet = descriptor_sets[image_index * 2 + 1]; | ||
| 310 | sampler_write.pImageInfo = &fsr_image_info; | ||
| 311 | output_write.dstSet = descriptor_sets[image_index * 2 + 1]; | ||
| 312 | output_write.pImageInfo = &blit_image_info; | ||
| 313 | |||
| 314 | device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, output_write}, {}); | ||
| 315 | } | ||
| 316 | |||
| 317 | void FSR::CreateSampler() { | ||
| 318 | const VkSamplerCreateInfo ci{ | ||
| 319 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 320 | .pNext = nullptr, | ||
| 321 | .flags = 0, | ||
| 322 | .magFilter = VK_FILTER_LINEAR, | ||
| 323 | .minFilter = VK_FILTER_LINEAR, | ||
| 324 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, | ||
| 325 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, | ||
| 326 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, | ||
| 327 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, | ||
| 328 | .mipLodBias = 0.0f, | ||
| 329 | .anisotropyEnable = VK_FALSE, | ||
| 330 | .maxAnisotropy = 0.0f, | ||
| 331 | .compareEnable = VK_FALSE, | ||
| 332 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 333 | .minLod = 0.0f, | ||
| 334 | .maxLod = 0.0f, | ||
| 335 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, | ||
| 336 | .unnormalizedCoordinates = VK_FALSE, | ||
| 337 | }; | ||
| 338 | |||
| 339 | sampler = device.GetLogical().CreateSampler(ci); | ||
| 340 | } | ||
| 341 | |||
| 342 | void FSR::CreateShaders() { | ||
| 343 | easu_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_EASU_COMP_SPV); | ||
| 344 | rcas_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_EASU_COMP_SPV); | ||
| 345 | } | ||
| 346 | |||
| 347 | void FSR::CreatePipeline() { | ||
| 348 | VkPipelineShaderStageCreateInfo shader_stage{ | ||
| 349 | |||
| 350 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 351 | .pNext = nullptr, | ||
| 352 | .flags = 0, | ||
| 353 | .stage = VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 354 | .pName = "main", | ||
| 355 | .pSpecializationInfo = nullptr, | ||
| 356 | }; | ||
| 357 | |||
| 358 | VkComputePipelineCreateInfo pipeline_ci{ | ||
| 359 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, | ||
| 360 | .pNext = nullptr, | ||
| 361 | .flags = 0, | ||
| 362 | .layout = *pipeline_layout, | ||
| 363 | .basePipelineIndex = 0, | ||
| 364 | }; | ||
| 365 | |||
| 366 | shader_stage.module = *easu_shader; | ||
| 367 | pipeline_ci.stage = shader_stage; | ||
| 368 | easu_pipeline = device.GetLogical().CreateComputePipeline(pipeline_ci); | ||
| 369 | |||
| 370 | shader_stage.module = *rcas_shader; | ||
| 371 | pipeline_ci.stage = shader_stage; | ||
| 372 | rcas_pipeline = device.GetLogical().CreateComputePipeline(pipeline_ci); | ||
| 373 | } | ||
| 374 | |||
| 375 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_fsr.h b/src/video_core/renderer_vulkan/vk_fsr.h new file mode 100644 index 000000000..8391e2e58 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_fsr.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/math_util.h" | ||
| 8 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 9 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 10 | |||
| 11 | namespace Vulkan { | ||
| 12 | |||
| 13 | class Device; | ||
| 14 | class VKScheduler; | ||
| 15 | |||
| 16 | class FSR { | ||
| 17 | public: | ||
| 18 | explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, | ||
| 19 | VkExtent2D output_size); | ||
| 20 | VkImageView Draw(VKScheduler& scheduler, size_t image_index, VkImageView image_view, | ||
| 21 | const Common::Rectangle<int>& crop_rect); | ||
| 22 | |||
| 23 | private: | ||
| 24 | void CreateDescriptorPool(); | ||
| 25 | void CreateDescriptorSetLayout(); | ||
| 26 | void CreateDescriptorSets(); | ||
| 27 | void CreateImages(); | ||
| 28 | void CreateSampler(); | ||
| 29 | void CreateShaders(); | ||
| 30 | void CreatePipeline(); | ||
| 31 | void CreatePipelineLayout(); | ||
| 32 | |||
| 33 | void UpdateDescriptorSet(std::size_t image_index, VkImageView image_view) const; | ||
| 34 | |||
| 35 | const Device& device; | ||
| 36 | MemoryAllocator& memory_allocator; | ||
| 37 | size_t image_count; | ||
| 38 | VkExtent2D output_size; | ||
| 39 | |||
| 40 | vk::DescriptorPool descriptor_pool; | ||
| 41 | vk::DescriptorSetLayout descriptor_set_layout; | ||
| 42 | vk::DescriptorSets descriptor_sets; | ||
| 43 | vk::PipelineLayout pipeline_layout; | ||
| 44 | vk::ShaderModule easu_shader; | ||
| 45 | vk::ShaderModule rcas_shader; | ||
| 46 | vk::Pipeline easu_pipeline; | ||
| 47 | vk::Pipeline rcas_pipeline; | ||
| 48 | vk::Sampler sampler; | ||
| 49 | std::vector<vk::Image> images; | ||
| 50 | std::vector<vk::ImageView> image_views; | ||
| 51 | std::vector<MemoryCommit> buffer_commits; | ||
| 52 | }; | ||
| 53 | |||
| 54 | } // namespace Vulkan | ||
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index d5e0d4e89..014ca6683 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui | |||
| @@ -402,6 +402,11 @@ | |||
| 402 | <string>ScaleForce</string> | 402 | <string>ScaleForce</string> |
| 403 | </property> | 403 | </property> |
| 404 | </item> | 404 | </item> |
| 405 | <item> | ||
| 406 | <property name="text"> | ||
| 407 | <string>FidelityFX Super Resolution</string> | ||
| 408 | </property> | ||
| 409 | </item> | ||
| 405 | </widget> | 410 | </widget> |
| 406 | </item> | 411 | </item> |
| 407 | </layout> | 412 | </layout> |