diff options
Diffstat (limited to 'src/video_core/renderer_vulkan')
56 files changed, 1049 insertions, 910 deletions
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 2c3914459..3f2b139e0 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> @@ -9,6 +8,7 @@ #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" +#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h" #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" #include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h" #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" @@ -349,7 +349,7 @@ VkExtent2D GetConversionExtent(const ImageView& src_image_view) { } } // Anonymous namespace -BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, +BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, StateTracker& state_tracker_, DescriptorPool& descriptor_pool) : device{device_}, scheduler{scheduler_}, state_tracker{state_tracker_}, one_texture_set_layout(device.GetLogical().CreateDescriptorSetLayout( @@ -366,16 +366,14 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, PipelineLayoutCreateInfo(two_textures_set_layout.address()))), full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)), blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)), + blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)), convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), + convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)), linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)), - nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) { - if (device.IsExtShaderStencilExportSupported()) { - blit_depth_stencil_frag = BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV); - } -} + nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {} BlitImageHelper::~BlitImageHelper() = default; @@ -474,6 +472,13 @@ void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view); } +void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer, + ImageView& src_image_view) { + ConvertPipelineColorTargetEx(convert_s8d24_to_abgr8_pipeline, dst_framebuffer->RenderPass(), + convert_s8d24_to_abgr8_frag); + ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view); +} + void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, const ImageView& src_image_view) { const VkPipelineLayout layout = *one_texture_pipeline_layout; diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 85e7dca5b..5df679fb4 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -1,11 +1,8 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include <compare> - #include "video_core/engines/fermi_2d.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/texture_cache/types.h" @@ -19,7 +16,7 @@ class Device; class Framebuffer; class ImageView; class StateTracker; -class VKScheduler; +class Scheduler; struct BlitImagePipelineKey { constexpr auto operator<=>(const BlitImagePipelineKey&) const noexcept = default; @@ -30,7 +27,7 @@ struct BlitImagePipelineKey { class BlitImageHelper { public: - explicit BlitImageHelper(const Device& device, VKScheduler& scheduler, + explicit BlitImageHelper(const Device& device, Scheduler& scheduler, StateTracker& state_tracker, DescriptorPool& descriptor_pool); ~BlitImageHelper(); @@ -56,6 +53,8 @@ public: void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view); + void ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view); + private: void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, const ImageView& src_image_view); @@ -83,7 +82,7 @@ private: vk::ShaderModule& module); const Device& device; - VKScheduler& scheduler; + Scheduler& scheduler; StateTracker& state_tracker; vk::DescriptorSetLayout one_texture_set_layout; @@ -99,6 +98,7 @@ private: vk::ShaderModule convert_float_to_depth_frag; vk::ShaderModule convert_abgr8_to_d24s8_frag; vk::ShaderModule convert_d24s8_to_abgr8_frag; + vk::ShaderModule convert_s8d24_to_abgr8_frag; vk::Sampler linear_sampler; vk::Sampler nearest_sampler; @@ -112,6 +112,7 @@ private: vk::Pipeline convert_r16_to_d16_pipeline; vk::Pipeline convert_abgr8_to_d24s8_pipeline; vk::Pipeline convert_d24s8_to_abgr8_pipeline; + vk::Pipeline convert_s8d24_to_abgr8_pipeline; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index d70153df3..733b454de 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -1,12 +1,8 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <cstring> -#include <tuple> - -#include <boost/functional/hash.hpp> #include "common/bit_cast.h" #include "common/cityhash.h" diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index c9be37935..9d60756e5 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 751e4792b..e7104d377 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <iterator> @@ -26,7 +25,7 @@ VkFilter Filter(Tegra::Texture::TextureFilter filter) { case Tegra::Texture::TextureFilter::Linear: return VK_FILTER_LINEAR; } - UNREACHABLE_MSG("Invalid sampler filter={}", filter); + ASSERT_MSG(false, "Invalid sampler filter={}", filter); return {}; } @@ -43,7 +42,7 @@ VkSamplerMipmapMode MipmapMode(Tegra::Texture::TextureMipmapFilter mipmap_filter case Tegra::Texture::TextureMipmapFilter::Linear: return VK_SAMPLER_MIPMAP_MODE_LINEAR; } - UNREACHABLE_MSG("Invalid sampler mipmap mode={}", mipmap_filter); + ASSERT_MSG(false, "Invalid sampler mipmap mode={}", mipmap_filter); return {}; } @@ -71,7 +70,7 @@ VkSamplerAddressMode WrapMode(const Device& device, Tegra::Texture::WrapMode wra case Tegra::Texture::TextureFilter::Linear: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; } - UNREACHABLE(); + ASSERT(false); return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; case Tegra::Texture::WrapMode::MirrorOnceClampToEdge: return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; @@ -127,6 +126,7 @@ struct FormatTuple { {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1B5G5R5_UNORM (flipped with swizzle) + {VK_FORMAT_R5G5B5A1_UNORM_PACK16}, // A5B5G5R1_UNORM (specially swizzled) {VK_FORMAT_R8_UNORM, Attachable | Storage}, // R8_UNORM {VK_FORMAT_R8_SNORM, Attachable | Storage}, // R8_SNORM {VK_FORMAT_R8_SINT, Attachable | Storage}, // R8_SINT @@ -172,7 +172,7 @@ struct FormatTuple { {VK_FORMAT_R8G8_SINT, Attachable | Storage}, // R8G8_SINT {VK_FORMAT_R8G8_UINT, Attachable | Storage}, // R8G8_UINT {VK_FORMAT_R32G32_UINT, Attachable | Storage}, // R32G32_UINT - {VK_FORMAT_UNDEFINED}, // R16G16B16X16_FLOAT + {VK_FORMAT_R16G16B16A16_SFLOAT, Attachable | Storage}, // R16G16B16X16_FLOAT {VK_FORMAT_R32_UINT, Attachable | Storage}, // R32_UINT {VK_FORMAT_R32_SINT, Attachable | Storage}, // R32_SINT {VK_FORMAT_ASTC_8x8_UNORM_BLOCK}, // ASTC_2D_8X8_UNORM @@ -184,6 +184,7 @@ struct FormatTuple { {VK_FORMAT_BC3_SRGB_BLOCK}, // BC3_SRGB {VK_FORMAT_BC7_SRGB_BLOCK}, // BC7_SRGB {VK_FORMAT_R4G4B4A4_UNORM_PACK16, Attachable}, // A4B4G4R4_UNORM + {VK_FORMAT_R4G4_UNORM_PACK8}, // G4R4_UNORM {VK_FORMAT_ASTC_4x4_SRGB_BLOCK}, // ASTC_2D_4X4_SRGB {VK_FORMAT_ASTC_8x8_SRGB_BLOCK}, // ASTC_2D_8X8_SRGB {VK_FORMAT_ASTC_8x5_SRGB_BLOCK}, // ASTC_2D_8X5_SRGB @@ -194,6 +195,9 @@ struct FormatTuple { {VK_FORMAT_ASTC_10x8_SRGB_BLOCK}, // ASTC_2D_10X8_SRGB {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB + {VK_FORMAT_ASTC_10x6_UNORM_BLOCK}, // ASTC_2D_10X6_UNORM + {VK_FORMAT_ASTC_10x5_UNORM_BLOCK}, // ASTC_2D_10X5_UNORM + {VK_FORMAT_ASTC_10x5_SRGB_BLOCK}, // ASTC_2D_10X5_SRGB {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM @@ -315,193 +319,204 @@ VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const Device& device, } } -VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size) { - switch (type) { - case Maxwell::VertexAttribute::Type::UnsignedNorm: - switch (size) { - case Maxwell::VertexAttribute::Size::Size_8: - return VK_FORMAT_R8_UNORM; - case Maxwell::VertexAttribute::Size::Size_8_8: - return VK_FORMAT_R8G8_UNORM; - case Maxwell::VertexAttribute::Size::Size_8_8_8: - return VK_FORMAT_R8G8B8_UNORM; - case Maxwell::VertexAttribute::Size::Size_8_8_8_8: - return VK_FORMAT_R8G8B8A8_UNORM; - case Maxwell::VertexAttribute::Size::Size_16: - return VK_FORMAT_R16_UNORM; - case Maxwell::VertexAttribute::Size::Size_16_16: - return VK_FORMAT_R16G16_UNORM; - case Maxwell::VertexAttribute::Size::Size_16_16_16: - return VK_FORMAT_R16G16B16_UNORM; - case Maxwell::VertexAttribute::Size::Size_16_16_16_16: - return VK_FORMAT_R16G16B16A16_UNORM; - case Maxwell::VertexAttribute::Size::Size_10_10_10_2: - return VK_FORMAT_A2B10G10R10_UNORM_PACK32; - default: +VkFormat VertexFormat(const Device& device, Maxwell::VertexAttribute::Type type, + Maxwell::VertexAttribute::Size size) { + const VkFormat format{([&]() { + switch (type) { + case Maxwell::VertexAttribute::Type::UnsignedNorm: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_8: + return VK_FORMAT_R8_UNORM; + case Maxwell::VertexAttribute::Size::Size_8_8: + return VK_FORMAT_R8G8_UNORM; + case Maxwell::VertexAttribute::Size::Size_8_8_8: + return VK_FORMAT_R8G8B8_UNORM; + case Maxwell::VertexAttribute::Size::Size_8_8_8_8: + return VK_FORMAT_R8G8B8A8_UNORM; + case Maxwell::VertexAttribute::Size::Size_16: + return VK_FORMAT_R16_UNORM; + case Maxwell::VertexAttribute::Size::Size_16_16: + return VK_FORMAT_R16G16_UNORM; + case Maxwell::VertexAttribute::Size::Size_16_16_16: + return VK_FORMAT_R16G16B16_UNORM; + case Maxwell::VertexAttribute::Size::Size_16_16_16_16: + return VK_FORMAT_R16G16B16A16_UNORM; + case Maxwell::VertexAttribute::Size::Size_10_10_10_2: + return VK_FORMAT_A2B10G10R10_UNORM_PACK32; + default: + break; + } break; - } - break; - case Maxwell::VertexAttribute::Type::SignedNorm: - switch (size) { - case Maxwell::VertexAttribute::Size::Size_8: - return VK_FORMAT_R8_SNORM; - case Maxwell::VertexAttribute::Size::Size_8_8: - return VK_FORMAT_R8G8_SNORM; - case Maxwell::VertexAttribute::Size::Size_8_8_8: - return VK_FORMAT_R8G8B8_SNORM; - case Maxwell::VertexAttribute::Size::Size_8_8_8_8: - return VK_FORMAT_R8G8B8A8_SNORM; - case Maxwell::VertexAttribute::Size::Size_16: - return VK_FORMAT_R16_SNORM; - case Maxwell::VertexAttribute::Size::Size_16_16: - return VK_FORMAT_R16G16_SNORM; - case Maxwell::VertexAttribute::Size::Size_16_16_16: - return VK_FORMAT_R16G16B16_SNORM; - case Maxwell::VertexAttribute::Size::Size_16_16_16_16: - return VK_FORMAT_R16G16B16A16_SNORM; - case Maxwell::VertexAttribute::Size::Size_10_10_10_2: - return VK_FORMAT_A2B10G10R10_SNORM_PACK32; - default: + case Maxwell::VertexAttribute::Type::SignedNorm: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_8: + return VK_FORMAT_R8_SNORM; + case Maxwell::VertexAttribute::Size::Size_8_8: + return VK_FORMAT_R8G8_SNORM; + case Maxwell::VertexAttribute::Size::Size_8_8_8: + return VK_FORMAT_R8G8B8_SNORM; + case Maxwell::VertexAttribute::Size::Size_8_8_8_8: + return VK_FORMAT_R8G8B8A8_SNORM; + case Maxwell::VertexAttribute::Size::Size_16: + return VK_FORMAT_R16_SNORM; + case Maxwell::VertexAttribute::Size::Size_16_16: + return VK_FORMAT_R16G16_SNORM; + case Maxwell::VertexAttribute::Size::Size_16_16_16: + return VK_FORMAT_R16G16B16_SNORM; + case Maxwell::VertexAttribute::Size::Size_16_16_16_16: + return VK_FORMAT_R16G16B16A16_SNORM; + case Maxwell::VertexAttribute::Size::Size_10_10_10_2: + return VK_FORMAT_A2B10G10R10_SNORM_PACK32; + default: + break; + } break; - } - break; - case Maxwell::VertexAttribute::Type::UnsignedScaled: - switch (size) { - case Maxwell::VertexAttribute::Size::Size_8: - return VK_FORMAT_R8_USCALED; - case Maxwell::VertexAttribute::Size::Size_8_8: - return VK_FORMAT_R8G8_USCALED; - case Maxwell::VertexAttribute::Size::Size_8_8_8: - return VK_FORMAT_R8G8B8_USCALED; - case Maxwell::VertexAttribute::Size::Size_8_8_8_8: - return VK_FORMAT_R8G8B8A8_USCALED; - case Maxwell::VertexAttribute::Size::Size_16: - return VK_FORMAT_R16_USCALED; - case Maxwell::VertexAttribute::Size::Size_16_16: - return VK_FORMAT_R16G16_USCALED; - case Maxwell::VertexAttribute::Size::Size_16_16_16: - return VK_FORMAT_R16G16B16_USCALED; - case Maxwell::VertexAttribute::Size::Size_16_16_16_16: - return VK_FORMAT_R16G16B16A16_USCALED; - case Maxwell::VertexAttribute::Size::Size_10_10_10_2: - return VK_FORMAT_A2B10G10R10_USCALED_PACK32; - default: + case Maxwell::VertexAttribute::Type::UnsignedScaled: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_8: + return VK_FORMAT_R8_USCALED; + case Maxwell::VertexAttribute::Size::Size_8_8: + return VK_FORMAT_R8G8_USCALED; + case Maxwell::VertexAttribute::Size::Size_8_8_8: + return VK_FORMAT_R8G8B8_USCALED; + case Maxwell::VertexAttribute::Size::Size_8_8_8_8: + return VK_FORMAT_R8G8B8A8_USCALED; + case Maxwell::VertexAttribute::Size::Size_16: + return VK_FORMAT_R16_USCALED; + case Maxwell::VertexAttribute::Size::Size_16_16: + return VK_FORMAT_R16G16_USCALED; + case Maxwell::VertexAttribute::Size::Size_16_16_16: + return VK_FORMAT_R16G16B16_USCALED; + case Maxwell::VertexAttribute::Size::Size_16_16_16_16: + return VK_FORMAT_R16G16B16A16_USCALED; + case Maxwell::VertexAttribute::Size::Size_10_10_10_2: + return VK_FORMAT_A2B10G10R10_USCALED_PACK32; + default: + break; + } break; - } - break; - case Maxwell::VertexAttribute::Type::SignedScaled: - switch (size) { - case Maxwell::VertexAttribute::Size::Size_8: - return VK_FORMAT_R8_SSCALED; - case Maxwell::VertexAttribute::Size::Size_8_8: - return VK_FORMAT_R8G8_SSCALED; - case Maxwell::VertexAttribute::Size::Size_8_8_8: - return VK_FORMAT_R8G8B8_SSCALED; - case Maxwell::VertexAttribute::Size::Size_8_8_8_8: - return VK_FORMAT_R8G8B8A8_SSCALED; - case Maxwell::VertexAttribute::Size::Size_16: - return VK_FORMAT_R16_SSCALED; - case Maxwell::VertexAttribute::Size::Size_16_16: - return VK_FORMAT_R16G16_SSCALED; - case Maxwell::VertexAttribute::Size::Size_16_16_16: - return VK_FORMAT_R16G16B16_SSCALED; - case Maxwell::VertexAttribute::Size::Size_16_16_16_16: - return VK_FORMAT_R16G16B16A16_SSCALED; - case Maxwell::VertexAttribute::Size::Size_10_10_10_2: - return VK_FORMAT_A2B10G10R10_SSCALED_PACK32; - default: + case Maxwell::VertexAttribute::Type::SignedScaled: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_8: + return VK_FORMAT_R8_SSCALED; + case Maxwell::VertexAttribute::Size::Size_8_8: + return VK_FORMAT_R8G8_SSCALED; + case Maxwell::VertexAttribute::Size::Size_8_8_8: + return VK_FORMAT_R8G8B8_SSCALED; + case Maxwell::VertexAttribute::Size::Size_8_8_8_8: + return VK_FORMAT_R8G8B8A8_SSCALED; + case Maxwell::VertexAttribute::Size::Size_16: + return VK_FORMAT_R16_SSCALED; + case Maxwell::VertexAttribute::Size::Size_16_16: + return VK_FORMAT_R16G16_SSCALED; + case Maxwell::VertexAttribute::Size::Size_16_16_16: + return VK_FORMAT_R16G16B16_SSCALED; + case Maxwell::VertexAttribute::Size::Size_16_16_16_16: + return VK_FORMAT_R16G16B16A16_SSCALED; + case Maxwell::VertexAttribute::Size::Size_10_10_10_2: + return VK_FORMAT_A2B10G10R10_SSCALED_PACK32; + default: + break; + } break; - } - break; - case Maxwell::VertexAttribute::Type::UnsignedInt: - switch (size) { - case Maxwell::VertexAttribute::Size::Size_8: - return VK_FORMAT_R8_UINT; - case Maxwell::VertexAttribute::Size::Size_8_8: - return VK_FORMAT_R8G8_UINT; - case Maxwell::VertexAttribute::Size::Size_8_8_8: - return VK_FORMAT_R8G8B8_UINT; - case Maxwell::VertexAttribute::Size::Size_8_8_8_8: - return VK_FORMAT_R8G8B8A8_UINT; - case Maxwell::VertexAttribute::Size::Size_16: - return VK_FORMAT_R16_UINT; - case Maxwell::VertexAttribute::Size::Size_16_16: - return VK_FORMAT_R16G16_UINT; - case Maxwell::VertexAttribute::Size::Size_16_16_16: - return VK_FORMAT_R16G16B16_UINT; - case Maxwell::VertexAttribute::Size::Size_16_16_16_16: - return VK_FORMAT_R16G16B16A16_UINT; - case Maxwell::VertexAttribute::Size::Size_32: - return VK_FORMAT_R32_UINT; - case Maxwell::VertexAttribute::Size::Size_32_32: - return VK_FORMAT_R32G32_UINT; - case Maxwell::VertexAttribute::Size::Size_32_32_32: - return VK_FORMAT_R32G32B32_UINT; - case Maxwell::VertexAttribute::Size::Size_32_32_32_32: - return VK_FORMAT_R32G32B32A32_UINT; - case Maxwell::VertexAttribute::Size::Size_10_10_10_2: - return VK_FORMAT_A2B10G10R10_UINT_PACK32; - default: + case Maxwell::VertexAttribute::Type::UnsignedInt: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_8: + return VK_FORMAT_R8_UINT; + case Maxwell::VertexAttribute::Size::Size_8_8: + return VK_FORMAT_R8G8_UINT; + case Maxwell::VertexAttribute::Size::Size_8_8_8: + return VK_FORMAT_R8G8B8_UINT; + case Maxwell::VertexAttribute::Size::Size_8_8_8_8: + return VK_FORMAT_R8G8B8A8_UINT; + case Maxwell::VertexAttribute::Size::Size_16: + return VK_FORMAT_R16_UINT; + case Maxwell::VertexAttribute::Size::Size_16_16: + return VK_FORMAT_R16G16_UINT; + case Maxwell::VertexAttribute::Size::Size_16_16_16: + return VK_FORMAT_R16G16B16_UINT; + case Maxwell::VertexAttribute::Size::Size_16_16_16_16: + return VK_FORMAT_R16G16B16A16_UINT; + case Maxwell::VertexAttribute::Size::Size_32: + return VK_FORMAT_R32_UINT; + case Maxwell::VertexAttribute::Size::Size_32_32: + return VK_FORMAT_R32G32_UINT; + case Maxwell::VertexAttribute::Size::Size_32_32_32: + return VK_FORMAT_R32G32B32_UINT; + case Maxwell::VertexAttribute::Size::Size_32_32_32_32: + return VK_FORMAT_R32G32B32A32_UINT; + case Maxwell::VertexAttribute::Size::Size_10_10_10_2: + return VK_FORMAT_A2B10G10R10_UINT_PACK32; + default: + break; + } break; - } - break; - case Maxwell::VertexAttribute::Type::SignedInt: - switch (size) { - case Maxwell::VertexAttribute::Size::Size_8: - return VK_FORMAT_R8_SINT; - case Maxwell::VertexAttribute::Size::Size_8_8: - return VK_FORMAT_R8G8_SINT; - case Maxwell::VertexAttribute::Size::Size_8_8_8: - return VK_FORMAT_R8G8B8_SINT; - case Maxwell::VertexAttribute::Size::Size_8_8_8_8: - return VK_FORMAT_R8G8B8A8_SINT; - case Maxwell::VertexAttribute::Size::Size_16: - return VK_FORMAT_R16_SINT; - case Maxwell::VertexAttribute::Size::Size_16_16: - return VK_FORMAT_R16G16_SINT; - case Maxwell::VertexAttribute::Size::Size_16_16_16: - return VK_FORMAT_R16G16B16_SINT; - case Maxwell::VertexAttribute::Size::Size_16_16_16_16: - return VK_FORMAT_R16G16B16A16_SINT; - case Maxwell::VertexAttribute::Size::Size_32: - return VK_FORMAT_R32_SINT; - case Maxwell::VertexAttribute::Size::Size_32_32: - return VK_FORMAT_R32G32_SINT; - case Maxwell::VertexAttribute::Size::Size_32_32_32: - return VK_FORMAT_R32G32B32_SINT; - case Maxwell::VertexAttribute::Size::Size_32_32_32_32: - return VK_FORMAT_R32G32B32A32_SINT; - case Maxwell::VertexAttribute::Size::Size_10_10_10_2: - return VK_FORMAT_A2B10G10R10_SINT_PACK32; - default: + case Maxwell::VertexAttribute::Type::SignedInt: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_8: + return VK_FORMAT_R8_SINT; + case Maxwell::VertexAttribute::Size::Size_8_8: + return VK_FORMAT_R8G8_SINT; + case Maxwell::VertexAttribute::Size::Size_8_8_8: + return VK_FORMAT_R8G8B8_SINT; + case Maxwell::VertexAttribute::Size::Size_8_8_8_8: + return VK_FORMAT_R8G8B8A8_SINT; + case Maxwell::VertexAttribute::Size::Size_16: + return VK_FORMAT_R16_SINT; + case Maxwell::VertexAttribute::Size::Size_16_16: + return VK_FORMAT_R16G16_SINT; + case Maxwell::VertexAttribute::Size::Size_16_16_16: + return VK_FORMAT_R16G16B16_SINT; + case Maxwell::VertexAttribute::Size::Size_16_16_16_16: + return VK_FORMAT_R16G16B16A16_SINT; + case Maxwell::VertexAttribute::Size::Size_32: + return VK_FORMAT_R32_SINT; + case Maxwell::VertexAttribute::Size::Size_32_32: + return VK_FORMAT_R32G32_SINT; + case Maxwell::VertexAttribute::Size::Size_32_32_32: + return VK_FORMAT_R32G32B32_SINT; + case Maxwell::VertexAttribute::Size::Size_32_32_32_32: + return VK_FORMAT_R32G32B32A32_SINT; + case Maxwell::VertexAttribute::Size::Size_10_10_10_2: + return VK_FORMAT_A2B10G10R10_SINT_PACK32; + default: + break; + } break; - } - break; - case Maxwell::VertexAttribute::Type::Float: - switch (size) { - case Maxwell::VertexAttribute::Size::Size_16: - return VK_FORMAT_R16_SFLOAT; - case Maxwell::VertexAttribute::Size::Size_16_16: - return VK_FORMAT_R16G16_SFLOAT; - case Maxwell::VertexAttribute::Size::Size_16_16_16: - return VK_FORMAT_R16G16B16_SFLOAT; - case Maxwell::VertexAttribute::Size::Size_16_16_16_16: - return VK_FORMAT_R16G16B16A16_SFLOAT; - case Maxwell::VertexAttribute::Size::Size_32: - return VK_FORMAT_R32_SFLOAT; - case Maxwell::VertexAttribute::Size::Size_32_32: - return VK_FORMAT_R32G32_SFLOAT; - case Maxwell::VertexAttribute::Size::Size_32_32_32: - return VK_FORMAT_R32G32B32_SFLOAT; - case Maxwell::VertexAttribute::Size::Size_32_32_32_32: - return VK_FORMAT_R32G32B32A32_SFLOAT; - default: + case Maxwell::VertexAttribute::Type::Float: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_16: + return VK_FORMAT_R16_SFLOAT; + case Maxwell::VertexAttribute::Size::Size_16_16: + return VK_FORMAT_R16G16_SFLOAT; + case Maxwell::VertexAttribute::Size::Size_16_16_16: + return VK_FORMAT_R16G16B16_SFLOAT; + case Maxwell::VertexAttribute::Size::Size_16_16_16_16: + return VK_FORMAT_R16G16B16A16_SFLOAT; + case Maxwell::VertexAttribute::Size::Size_32: + return VK_FORMAT_R32_SFLOAT; + case Maxwell::VertexAttribute::Size::Size_32_32: + return VK_FORMAT_R32G32_SFLOAT; + case Maxwell::VertexAttribute::Size::Size_32_32_32: + return VK_FORMAT_R32G32B32_SFLOAT; + case Maxwell::VertexAttribute::Size::Size_32_32_32_32: + return VK_FORMAT_R32G32B32A32_SFLOAT; + case Maxwell::VertexAttribute::Size::Size_11_11_10: + return VK_FORMAT_B10G11R11_UFLOAT_PACK32; + default: + break; + } break; } - break; + return VK_FORMAT_UNDEFINED; + })()}; + + if (format == VK_FORMAT_UNDEFINED) { + UNIMPLEMENTED_MSG("Unimplemented vertex format of type={} and size={}", type, size); } - UNIMPLEMENTED_MSG("Unimplemented vertex format of type={} and size={}", type, size); - return {}; + + return device.GetSupportedFormat(format, VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT, + FormatType::Buffer); } VkCompareOp ComparisonOp(Maxwell::ComparisonOp comparison) { @@ -741,7 +756,7 @@ VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle) case Maxwell::ViewportSwizzle::NegativeW: return VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV; } - UNREACHABLE_MSG("Invalid swizzle={}", swizzle); + ASSERT_MSG(false, "Invalid swizzle={}", swizzle); return {}; } @@ -754,7 +769,7 @@ VkSamplerReductionMode SamplerReduction(Tegra::Texture::SamplerReduction reducti case Tegra::Texture::SamplerReduction::Max: return VK_SAMPLER_REDUCTION_MODE_MAX_EXT; } - UNREACHABLE_MSG("Invalid sampler mode={}", static_cast<int>(reduction)); + ASSERT_MSG(false, "Invalid sampler mode={}", static_cast<int>(reduction)); return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT; } @@ -777,7 +792,7 @@ VkSampleCountFlagBits MsaaMode(Tegra::Texture::MsaaMode msaa_mode) { case Tegra::Texture::MsaaMode::Msaa4x4: return VK_SAMPLE_COUNT_16_BIT; default: - UNREACHABLE_MSG("Invalid msaa_mode={}", static_cast<int>(msaa_mode)); + ASSERT_MSG(false, "Invalid msaa_mode={}", static_cast<int>(msaa_mode)); return VK_SAMPLE_COUNT_1_BIT; } } diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.h b/src/video_core/renderer_vulkan/maxwell_to_vk.h index 8a9616039..356d46292 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.h +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h @@ -1,10 +1,8 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include "common/common_types.h" #include "shader_recompiler/stage.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/surface.h" @@ -50,7 +48,8 @@ VkShaderStageFlagBits ShaderStage(Shader::Stage stage); VkPrimitiveTopology PrimitiveTopology(const Device& device, Maxwell::PrimitiveTopology topology); -VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size); +VkFormat VertexFormat(const Device& device, Maxwell::VertexAttribute::Type type, + Maxwell::VertexAttribute::Size size); VkCompareOp ComparisonOp(Maxwell::ComparisonOp comparison); diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 11c160570..b24f3424a 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -8,7 +7,6 @@ #include <boost/container/small_vector.hpp> -#include "common/assert.h" #include "common/common_types.h" #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/shader_info.h" @@ -16,7 +14,6 @@ #include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/texture_cache/texture_cache.h" #include "video_core/texture_cache/types.h" -#include "video_core/textures/texture.h" #include "video_core/vulkan_common/vulkan_device.h" namespace Vulkan { @@ -171,7 +168,7 @@ private: }; inline void PushImageDescriptors(TextureCache& texture_cache, - VKUpdateDescriptorQueue& update_descriptor_queue, + UpdateDescriptorQueue& update_descriptor_queue, const Shader::Info& info, RescalingPushConstant& rescaling, const VkSampler*& samplers, const VideoCommon::ImageViewInOut*& views) { diff --git a/src/video_core/renderer_vulkan/pipeline_statistics.cpp b/src/video_core/renderer_vulkan/pipeline_statistics.cpp index bfec931a6..fcd160a32 100644 --- a/src/video_core/renderer_vulkan/pipeline_statistics.cpp +++ b/src/video_core/renderer_vulkan/pipeline_statistics.cpp @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <string_view> @@ -57,7 +56,7 @@ void PipelineStatistics::Collect(VkPipeline pipeline) { stage_stats.basic_block_count = GetUint64(statistic); } } - std::lock_guard lock{mutex}; + std::scoped_lock lock{mutex}; collected_stats.push_back(stage_stats); } } @@ -66,7 +65,7 @@ void PipelineStatistics::Report() const { double num{}; Stats total; { - std::lock_guard lock{mutex}; + std::scoped_lock lock{mutex}; for (const Stats& stats : collected_stats) { total.code_size += stats.code_size; total.register_count += stats.register_count; diff --git a/src/video_core/renderer_vulkan/pipeline_statistics.h b/src/video_core/renderer_vulkan/pipeline_statistics.h index b61840107..197bb0936 100644 --- a/src/video_core/renderer_vulkan/pipeline_statistics.h +++ b/src/video_core/renderer_vulkan/pipeline_statistics.h @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 74822814d..d8131232a 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -1,6 +1,5 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> @@ -13,16 +12,15 @@ #include <fmt/format.h> #include "common/logging/log.h" +#include "common/scope_exit.h" #include "common/settings.h" #include "common/telemetry.h" -#include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" #include "core/telemetry_session.h" #include "video_core/gpu.h" #include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/vk_blit_screen.h" -#include "video_core/renderer_vulkan/vk_master_semaphore.h" #include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" @@ -104,13 +102,13 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), surface(CreateSurface(instance, render_window)), device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), - state_tracker(gpu), scheduler(device, state_tracker), + state_tracker(), scheduler(device, state_tracker), swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, render_window.GetFramebufferLayout().height, false), blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler, screen_info), - rasterizer(render_window, gpu, gpu.MemoryManager(), cpu_memory, screen_info, device, - memory_allocator, state_tracker, scheduler) { + rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator, + state_tracker, scheduler) { Report(); } catch (const vk::Exception& exception) { LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what()); @@ -129,6 +127,11 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { if (!render_window.IsShown()) { return; } + // Update screen info if the framebuffer size has changed. + if (screen_info.width != framebuffer->width || screen_info.height != framebuffer->height) { + screen_info.width = framebuffer->width; + screen_info.height = framebuffer->height; + } const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; const bool use_accelerated = rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); @@ -139,7 +142,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { const auto recreate_swapchain = [&] { if (!has_been_recreated) { has_been_recreated = true; - scheduler.WaitWorker(); + scheduler.Finish(); } const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); swapchain.Create(layout.width, layout.height, is_srgb); diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 6dc985109..e7bfecb20 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -1,12 +1,10 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include <memory> #include <string> -#include <vector> #include "common/dynamic_library.h" #include "video_core/renderer_base.h" @@ -67,14 +65,14 @@ private: vk::DebugUtilsMessenger debug_callback; vk::SurfaceKHR surface; - VKScreenInfo screen_info; + ScreenInfo screen_info; Device device; MemoryAllocator memory_allocator; StateTracker state_tracker; - VKScheduler scheduler; - VKSwapchain swapchain; - VKBlitScreen blit_screen; + Scheduler scheduler; + Swapchain swapchain; + BlitScreen blit_screen; RasterizerVulkan rasterizer; }; diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index c71a1f44d..cb7fa2078 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -1,12 +1,10 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> #include <cstring> #include <memory> -#include <tuple> #include <vector> #include "common/assert.h" @@ -28,7 +26,6 @@ #include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/vk_blit_screen.h" #include "video_core/renderer_vulkan/vk_fsr.h" -#include "video_core/renderer_vulkan/vk_master_semaphore.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_swapchain.h" @@ -96,10 +93,12 @@ std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { switch (framebuffer.pixel_format) { - case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: + case Service::android::PixelFormat::Rgba8888: return VK_FORMAT_A8B8G8R8_UNORM_PACK32; - case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: + case Service::android::PixelFormat::Rgb565: return VK_FORMAT_R5G6B5_UNORM_PACK16; + case Service::android::PixelFormat::Bgra8888: + return VK_FORMAT_B8G8R8A8_UNORM; default: UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", static_cast<u32>(framebuffer.pixel_format)); @@ -109,7 +108,7 @@ VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { } // Anonymous namespace -struct VKBlitScreen::BufferData { +struct BlitScreen::BufferData { struct { std::array<f32, 4 * 4> modelview_matrix; } uniform; @@ -119,10 +118,9 @@ struct VKBlitScreen::BufferData { // Unaligned image data goes here }; -VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, - Core::Frontend::EmuWindow& render_window_, const Device& device_, - MemoryAllocator& memory_allocator_, VKSwapchain& swapchain_, - VKScheduler& scheduler_, const VKScreenInfo& screen_info_) +BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWindow& render_window_, + const Device& device_, MemoryAllocator& memory_allocator_, + Swapchain& swapchain_, Scheduler& scheduler_, const ScreenInfo& screen_info_) : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_}, memory_allocator{memory_allocator_}, swapchain{swapchain_}, scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { @@ -132,21 +130,26 @@ VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, CreateDynamicResources(); } -VKBlitScreen::~VKBlitScreen() = default; +BlitScreen::~BlitScreen() = default; -void VKBlitScreen::Recreate() { +void BlitScreen::Recreate() { CreateDynamicResources(); } -VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, - const VkFramebuffer& host_framebuffer, - const Layout::FramebufferLayout layout, VkExtent2D render_area, - bool use_accelerated) { +VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, + const VkFramebuffer& host_framebuffer, + const Layout::FramebufferLayout layout, VkExtent2D render_area, + bool use_accelerated) { RefreshResources(framebuffer); // Finish any pending renderpass scheduler.RequestOutsideRenderPassOperationContext(); + if (const auto swapchain_images = swapchain.GetImageCount(); swapchain_images != image_count) { + image_count = swapchain_images; + Recreate(); + } + const std::size_t image_index = swapchain.GetImageIndex(); scheduler.Wait(resource_ticks[image_index]); @@ -171,11 +174,12 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, // TODO(Rodrigo): Read this from HLE constexpr u32 block_height_log2 = 4; const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); - const u64 size_bytes{Tegra::Texture::CalculateSize(true, bytes_per_pixel, + const u64 linear_size{GetSizeInBytes(framebuffer)}; + const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; Tegra::Texture::UnswizzleTexture( - mapped_span.subspan(image_offset, size_bytes), std::span(host_ptr, size_bytes), + mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); const VkBufferImageCopy copy{ @@ -420,20 +424,20 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, return *semaphores[image_index]; } -VkSemaphore VKBlitScreen::DrawToSwapchain(const Tegra::FramebufferConfig& framebuffer, - bool use_accelerated) { +VkSemaphore BlitScreen::DrawToSwapchain(const Tegra::FramebufferConfig& framebuffer, + bool use_accelerated) { const std::size_t image_index = swapchain.GetImageIndex(); const VkExtent2D render_area = swapchain.GetSize(); const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); return Draw(framebuffer, *framebuffers[image_index], layout, render_area, use_accelerated); } -vk::Framebuffer VKBlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) { +vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) { return CreateFramebuffer(image_view, extent, renderpass); } -vk::Framebuffer VKBlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent, - vk::RenderPass& rd) { +vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent, + vk::RenderPass& rd) { return device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{ .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, .pNext = nullptr, @@ -447,17 +451,17 @@ vk::Framebuffer VKBlitScreen::CreateFramebuffer(const VkImageView& image_view, V }); } -void VKBlitScreen::CreateStaticResources() { +void BlitScreen::CreateStaticResources() { CreateShaders(); + CreateSampler(); +} + +void BlitScreen::CreateDynamicResources() { CreateSemaphores(); CreateDescriptorPool(); CreateDescriptorSetLayout(); CreateDescriptorSets(); CreatePipelineLayout(); - CreateSampler(); -} - -void VKBlitScreen::CreateDynamicResources() { CreateRenderPass(); CreateFramebuffers(); CreateGraphicsPipeline(); @@ -467,7 +471,7 @@ void VKBlitScreen::CreateDynamicResources() { } } -void VKBlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { +void BlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { if (!fsr) { CreateFSR(); @@ -487,7 +491,7 @@ void VKBlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) CreateRawImages(framebuffer); } -void VKBlitScreen::CreateShaders() { +void BlitScreen::CreateShaders() { vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV); fxaa_vertex_shader = BuildShader(device, FXAA_VERT_SPV); fxaa_fragment_shader = BuildShader(device, FXAA_FRAG_SPV); @@ -501,12 +505,12 @@ void VKBlitScreen::CreateShaders() { } } -void VKBlitScreen::CreateSemaphores() { +void BlitScreen::CreateSemaphores() { semaphores.resize(image_count); std::ranges::generate(semaphores, [this] { return device.GetLogical().CreateSemaphore(); }); } -void VKBlitScreen::CreateDescriptorPool() { +void BlitScreen::CreateDescriptorPool() { const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, @@ -546,11 +550,11 @@ void VKBlitScreen::CreateDescriptorPool() { aa_descriptor_pool = device.GetLogical().CreateDescriptorPool(ci_aa); } -void VKBlitScreen::CreateRenderPass() { +void BlitScreen::CreateRenderPass() { renderpass = CreateRenderPassImpl(swapchain.GetImageViewFormat()); } -vk::RenderPass VKBlitScreen::CreateRenderPassImpl(VkFormat format, bool is_present) { +vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format, bool is_present) { const VkAttachmentDescription color_attachment{ .flags = 0, .format = format, @@ -606,7 +610,7 @@ vk::RenderPass VKBlitScreen::CreateRenderPassImpl(VkFormat format, bool is_prese return device.GetLogical().CreateRenderPass(renderpass_ci); } -void VKBlitScreen::CreateDescriptorSetLayout() { +void BlitScreen::CreateDescriptorSetLayout() { const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ { .binding = 0, @@ -661,7 +665,7 @@ void VKBlitScreen::CreateDescriptorSetLayout() { aa_descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci_aa); } -void VKBlitScreen::CreateDescriptorSets() { +void BlitScreen::CreateDescriptorSets() { const std::vector layouts(image_count, *descriptor_set_layout); const std::vector layouts_aa(image_count, *aa_descriptor_set_layout); @@ -685,7 +689,7 @@ void VKBlitScreen::CreateDescriptorSets() { aa_descriptor_sets = aa_descriptor_pool.Allocate(ai_aa); } -void VKBlitScreen::CreatePipelineLayout() { +void BlitScreen::CreatePipelineLayout() { const VkPipelineLayoutCreateInfo ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, @@ -708,7 +712,7 @@ void VKBlitScreen::CreatePipelineLayout() { aa_pipeline_layout = device.GetLogical().CreatePipelineLayout(ci_aa); } -void VKBlitScreen::CreateGraphicsPipeline() { +void BlitScreen::CreateGraphicsPipeline() { const std::array<VkPipelineShaderStageCreateInfo, 2> bilinear_shader_stages{{ { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, @@ -981,7 +985,7 @@ void VKBlitScreen::CreateGraphicsPipeline() { scaleforce_pipeline = device.GetLogical().CreateGraphicsPipeline(scaleforce_pipeline_ci); } -void VKBlitScreen::CreateSampler() { +void BlitScreen::CreateSampler() { const VkSamplerCreateInfo ci{ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .pNext = nullptr, @@ -1028,7 +1032,7 @@ void VKBlitScreen::CreateSampler() { nn_sampler = device.GetLogical().CreateSampler(ci_nn); } -void VKBlitScreen::CreateFramebuffers() { +void BlitScreen::CreateFramebuffers() { const VkExtent2D size{swapchain.GetSize()}; framebuffers.resize(image_count); @@ -1038,7 +1042,7 @@ void VKBlitScreen::CreateFramebuffers() { } } -void VKBlitScreen::ReleaseRawImages() { +void BlitScreen::ReleaseRawImages() { for (const u64 tick : resource_ticks) { scheduler.Wait(tick); } @@ -1053,7 +1057,7 @@ void VKBlitScreen::ReleaseRawImages() { buffer_commit = MemoryCommit{}; } -void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { +void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { const VkBufferCreateInfo ci{ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, @@ -1070,7 +1074,7 @@ void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuff buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload); } -void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { +void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { raw_images.resize(image_count); raw_image_views.resize(image_count); raw_buffer_commits.resize(image_count); @@ -1295,8 +1299,8 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) aa_pipeline = device.GetLogical().CreateGraphicsPipeline(fxaa_pipeline_ci); } -void VKBlitScreen::UpdateAADescriptorSet(std::size_t image_index, VkImageView image_view, - bool nn) const { +void BlitScreen::UpdateAADescriptorSet(std::size_t image_index, VkImageView image_view, + bool nn) const { const VkDescriptorImageInfo image_info{ .sampler = nn ? *nn_sampler : *sampler, .imageView = image_view, @@ -1332,8 +1336,8 @@ void VKBlitScreen::UpdateAADescriptorSet(std::size_t image_index, VkImageView im device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, sampler_write_2}, {}); } -void VKBlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view, - bool nn) const { +void BlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view, + bool nn) const { const VkDescriptorBufferInfo buffer_info{ .buffer = *buffer, .offset = offsetof(BufferData, uniform), @@ -1375,13 +1379,13 @@ void VKBlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView imag device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); } -void VKBlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const { +void BlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const { data.uniform.modelview_matrix = MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); } -void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, - const Layout::FramebufferLayout layout) const { +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; @@ -1390,9 +1394,9 @@ void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfi auto right = texcoords.right; switch (framebuffer_transform_flags) { - case Tegra::FramebufferConfig::TransformFlags::Unset: + case Service::android::BufferTransformFlags::Unset: break; - case Tegra::FramebufferConfig::TransformFlags::FlipV: + case Service::android::BufferTransformFlags::FlipV: // Flip the framebuffer vertically left = texcoords.right; right = texcoords.left; @@ -1403,11 +1407,15 @@ void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfi break; } - UNIMPLEMENTED_IF(framebuffer_crop_rect.top != 0); UNIMPLEMENTED_IF(framebuffer_crop_rect.left != 0); - f32 scale_u = 1.0f; - f32 scale_v = 1.0f; + f32 left_start{}; + if (framebuffer_crop_rect.Top() > 0) { + left_start = static_cast<f32>(framebuffer_crop_rect.Top()) / + static_cast<f32>(framebuffer_crop_rect.Bottom()); + } + f32 scale_u = static_cast<f32>(framebuffer.width) / static_cast<f32>(screen_info.width); + f32 scale_v = static_cast<f32>(framebuffer.height) / static_cast<f32>(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) { @@ -1426,13 +1434,16 @@ void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfi const auto y = static_cast<f32>(screen.top); const auto w = static_cast<f32>(screen.GetWidth()); const auto h = static_cast<f32>(screen.GetHeight()); - data.vertices[0] = ScreenRectVertex(x, y, texcoords.top * scale_u, left * scale_v); - data.vertices[1] = ScreenRectVertex(x + w, y, texcoords.bottom * scale_u, left * scale_v); - data.vertices[2] = ScreenRectVertex(x, y + h, texcoords.top * scale_u, right * scale_v); - data.vertices[3] = ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v); + 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); } -void VKBlitScreen::CreateFSR() { +void BlitScreen::CreateFSR() { const auto& layout = render_window.GetFramebufferLayout(); const VkExtent2D fsr_size{ .width = layout.screen.GetWidth(), @@ -1441,12 +1452,12 @@ void VKBlitScreen::CreateFSR() { fsr = std::make_unique<FSR>(device, memory_allocator, image_count, fsr_size); } -u64 VKBlitScreen::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const { +u64 BlitScreen::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const { return sizeof(BufferData) + GetSizeInBytes(framebuffer) * image_count; } -u64 VKBlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, - std::size_t image_index) const { +u64 BlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, + std::size_t image_index) const { constexpr auto first_image_offset = static_cast<u64>(sizeof(BufferData)); return first_image_offset + GetSizeInBytes(framebuffer) * image_index; } diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index bbca71af3..29e2ea925 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h @@ -1,6 +1,5 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -36,23 +35,22 @@ struct ScreenInfo; class Device; class FSR; class RasterizerVulkan; -class VKScheduler; -class VKSwapchain; +class Scheduler; +class Swapchain; -struct VKScreenInfo { +struct ScreenInfo { VkImageView image_view{}; u32 width{}; u32 height{}; bool is_srgb{}; }; -class VKBlitScreen { +class BlitScreen { public: - explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, - Core::Frontend::EmuWindow& render_window, const Device& device, - MemoryAllocator& memory_manager, VKSwapchain& swapchain, - VKScheduler& scheduler, const VKScreenInfo& screen_info); - ~VKBlitScreen(); + explicit BlitScreen(Core::Memory::Memory& cpu_memory, Core::Frontend::EmuWindow& render_window, + const Device& device, MemoryAllocator& memory_manager, Swapchain& swapchain, + Scheduler& scheduler, const ScreenInfo& screen_info); + ~BlitScreen(); void Recreate(); @@ -109,10 +107,10 @@ private: Core::Frontend::EmuWindow& render_window; const Device& device; MemoryAllocator& memory_allocator; - VKSwapchain& swapchain; - VKScheduler& scheduler; - const std::size_t image_count; - const VKScreenInfo& screen_info; + Swapchain& swapchain; + Scheduler& scheduler; + std::size_t image_count; + const ScreenInfo& screen_info; vk::ShaderModule vertex_shader; vk::ShaderModule fxaa_vertex_shader; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 5ffd93499..558b8db56 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> @@ -47,7 +46,7 @@ size_t BytesPerIndex(VkIndexType index_type) { case VK_INDEX_TYPE_UINT32: return 4; default: - UNREACHABLE_MSG("Invalid index type={}", index_type); + ASSERT_MSG(false, "Invalid index type={}", index_type); return 1; } } @@ -125,8 +124,8 @@ VkBufferView Buffer::View(u32 offset, u32 size, VideoCore::Surface::PixelFormat } BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& memory_allocator_, - VKScheduler& scheduler_, StagingBufferPool& staging_pool_, - VKUpdateDescriptorQueue& update_descriptor_queue_, + Scheduler& scheduler_, StagingBufferPool& staging_pool_, + UpdateDescriptorQueue& update_descriptor_queue_, DescriptorPool& descriptor_pool) : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, staging_pool{staging_pool_}, update_descriptor_queue{update_descriptor_queue_}, @@ -141,6 +140,18 @@ StagingBufferRef BufferCacheRuntime::DownloadStagingBuffer(size_t size) { return staging_pool.Request(size, MemoryUsage::Download); } +u64 BufferCacheRuntime::GetDeviceLocalMemory() const { + return device.GetDeviceLocalMemory(); +} + +u64 BufferCacheRuntime::GetDeviceMemoryUsage() const { + return device.GetDeviceMemoryUsage(); +} + +bool BufferCacheRuntime::CanReportMemoryUsage() const { + return device.CanReportMemoryUsage(); +} + void BufferCacheRuntime::Finish() { scheduler.Finish(); } @@ -355,7 +366,7 @@ void BufferCacheRuntime::ReserveQuadArrayLUT(u32 num_indices, bool wait_for_idle std::memcpy(staging_data, MakeQuadIndices<u32>(quad, first).data(), quad_size); break; default: - UNREACHABLE(); + ASSERT(false); break; } staging_data += quad_size; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 1ee0d8420..a15c8b39b 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -17,7 +16,7 @@ namespace Vulkan { class Device; class DescriptorPool; -class VKScheduler; +class Scheduler; class BufferCacheRuntime; @@ -59,12 +58,18 @@ class BufferCacheRuntime { public: explicit BufferCacheRuntime(const Device& device_, MemoryAllocator& memory_manager_, - VKScheduler& scheduler_, StagingBufferPool& staging_pool_, - VKUpdateDescriptorQueue& update_descriptor_queue_, + Scheduler& scheduler_, StagingBufferPool& staging_pool_, + UpdateDescriptorQueue& update_descriptor_queue_, DescriptorPool& descriptor_pool); void Finish(); + u64 GetDeviceLocalMemory() const; + + u64 GetDeviceMemoryUsage() const; + + bool CanReportMemoryUsage() const; + [[nodiscard]] StagingBufferRef UploadStagingBuffer(size_t size); [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size); @@ -119,9 +124,9 @@ private: const Device& device; MemoryAllocator& memory_allocator; - VKScheduler& scheduler; + Scheduler& scheduler; StagingBufferPool& staging_pool; - VKUpdateDescriptorQueue& update_descriptor_queue; + UpdateDescriptorQueue& update_descriptor_queue; vk::Buffer quad_array_lut; MemoryCommit quad_array_lut_commit; diff --git a/src/video_core/renderer_vulkan/vk_command_pool.cpp b/src/video_core/renderer_vulkan/vk_command_pool.cpp index d8e92ac0e..2f09de1c1 100644 --- a/src/video_core/renderer_vulkan/vk_command_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_command_pool.cpp @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <cstddef> diff --git a/src/video_core/renderer_vulkan/vk_command_pool.h b/src/video_core/renderer_vulkan/vk_command_pool.h index 61c26a22a..ec1647f01 100644 --- a/src/video_core/renderer_vulkan/vk_command_pool.h +++ b/src/video_core/renderer_vulkan/vk_command_pool.h @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 3e96c0f60..241d7573e 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -1,13 +1,11 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later -#include <cstring> +#include <array> #include <memory> #include <optional> #include <utility> -#include "common/alignment.h" #include "common/assert.h" #include "common/common_types.h" #include "common/div_ceil.h" @@ -22,15 +20,12 @@ #include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/texture_cache/accelerated_swizzle.h" #include "video_core/texture_cache/types.h" -#include "video_core/textures/astc.h" #include "video_core/textures/decoders.h" #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { -using Tegra::Texture::SWIZZLE_TABLE; - namespace { constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0; @@ -203,9 +198,9 @@ ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool, ComputePass::~ComputePass() = default; -Uint8Pass::Uint8Pass(const Device& device_, VKScheduler& scheduler_, - DescriptorPool& descriptor_pool, StagingBufferPool& staging_buffer_pool_, - VKUpdateDescriptorQueue& update_descriptor_queue_) +Uint8Pass::Uint8Pass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool, + StagingBufferPool& staging_buffer_pool_, + UpdateDescriptorQueue& update_descriptor_queue_) : ComputePass(device_, descriptor_pool, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS, INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO, {}, VULKAN_UINT8_COMP_SPV), @@ -244,10 +239,10 @@ std::pair<VkBuffer, VkDeviceSize> Uint8Pass::Assemble(u32 num_vertices, VkBuffer return {staging.buffer, staging.offset}; } -QuadIndexedPass::QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, +QuadIndexedPass::QuadIndexedPass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_, - VKUpdateDescriptorQueue& update_descriptor_queue_) + UpdateDescriptorQueue& update_descriptor_queue_) : ComputePass(device_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS, INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO, COMPUTE_PUSH_CONSTANT_RANGE<sizeof(u32) * 2>, VULKAN_QUAD_INDEXED_COMP_SPV), @@ -268,7 +263,7 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble( case Tegra::Engines::Maxwell3D::Regs::IndexFormat::UnsignedInt: return 2; } - UNREACHABLE(); + ASSERT(false); return 2; }(); const u32 input_size = num_vertices << index_shift; @@ -292,7 +287,7 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble( .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, .dstAccessMask = VK_ACCESS_INDEX_READ_BIT, }; - const std::array push_constants{base_vertex, index_shift}; + const std::array<u32, 2> push_constants{base_vertex, index_shift}; const VkDescriptorSet set = descriptor_allocator.Commit(); device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); @@ -306,10 +301,10 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble( return {staging.buffer, staging.offset}; } -ASTCDecoderPass::ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_, +ASTCDecoderPass::ASTCDecoderPass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_, - VKUpdateDescriptorQueue& update_descriptor_queue_, + UpdateDescriptorQueue& update_descriptor_queue_, MemoryAllocator& memory_allocator_) : ComputePass(device_, descriptor_pool_, ASTC_DESCRIPTOR_SET_BINDINGS, ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO, @@ -331,31 +326,32 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, const VkImageAspectFlags aspect_mask = image.AspectMask(); const VkImage vk_image = image.Handle(); const bool is_initialized = image.ExchangeInitialization(); - scheduler.Record( - [vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) { - const VkImageMemoryBarrier image_barrier{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = is_initialized ? VK_ACCESS_SHADER_WRITE_BIT : VkAccessFlags{}, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, - .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED, - .newLayout = VK_IMAGE_LAYOUT_GENERAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = vk_image, - .subresourceRange{ - .aspectMask = aspect_mask, - .baseMipLevel = 0, - .levelCount = VK_REMAINING_MIP_LEVELS, - .baseArrayLayer = 0, - .layerCount = VK_REMAINING_ARRAY_LAYERS, - }, - }; - cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT - : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier); - cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline); - }); + scheduler.Record([vk_pipeline, vk_image, aspect_mask, + is_initialized](vk::CommandBuffer cmdbuf) { + const VkImageMemoryBarrier image_barrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = static_cast<VkAccessFlags>(is_initialized ? VK_ACCESS_SHADER_WRITE_BIT + : VK_ACCESS_NONE), + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = vk_image, + .subresourceRange{ + .aspectMask = aspect_mask, + .baseMipLevel = 0, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }, + }; + cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT + : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier); + cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline); + }); for (const VideoCommon::SwizzleParameters& swizzle : swizzles) { const size_t input_offset = swizzle.buffer_offset + map.offset; const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 8U); diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h index c7b92cce0..dcc691a8e 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -21,8 +20,8 @@ namespace Vulkan { class Device; class StagingBufferPool; -class VKScheduler; -class VKUpdateDescriptorQueue; +class Scheduler; +class UpdateDescriptorQueue; class Image; struct StagingBufferRef; @@ -49,9 +48,9 @@ private: class Uint8Pass final : public ComputePass { public: - explicit Uint8Pass(const Device& device_, VKScheduler& scheduler_, + explicit Uint8Pass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_, - VKUpdateDescriptorQueue& update_descriptor_queue_); + UpdateDescriptorQueue& update_descriptor_queue_); ~Uint8Pass(); /// Assemble uint8 indices into an uint16 index buffer @@ -60,17 +59,17 @@ public: u32 src_offset); private: - VKScheduler& scheduler; + Scheduler& scheduler; StagingBufferPool& staging_buffer_pool; - VKUpdateDescriptorQueue& update_descriptor_queue; + UpdateDescriptorQueue& update_descriptor_queue; }; class QuadIndexedPass final : public ComputePass { public: - explicit QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, + explicit QuadIndexedPass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_, - VKUpdateDescriptorQueue& update_descriptor_queue_); + UpdateDescriptorQueue& update_descriptor_queue_); ~QuadIndexedPass(); std::pair<VkBuffer, VkDeviceSize> Assemble( @@ -78,17 +77,17 @@ public: u32 base_vertex, VkBuffer src_buffer, u32 src_offset); private: - VKScheduler& scheduler; + Scheduler& scheduler; StagingBufferPool& staging_buffer_pool; - VKUpdateDescriptorQueue& update_descriptor_queue; + UpdateDescriptorQueue& update_descriptor_queue; }; class ASTCDecoderPass final : public ComputePass { public: - explicit ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_, + explicit ASTCDecoderPass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_, - VKUpdateDescriptorQueue& update_descriptor_queue_, + UpdateDescriptorQueue& update_descriptor_queue_, MemoryAllocator& memory_allocator_); ~ASTCDecoderPass(); @@ -96,9 +95,9 @@ public: std::span<const VideoCommon::SwizzleParameters> swizzles); private: - VKScheduler& scheduler; + Scheduler& scheduler; StagingBufferPool& staging_buffer_pool; - VKUpdateDescriptorQueue& update_descriptor_queue; + UpdateDescriptorQueue& update_descriptor_queue; MemoryAllocator& memory_allocator; }; diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index de36bcdb7..7906e11a8 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <vector> @@ -26,7 +25,7 @@ using Shader::Backend::SPIRV::RESCALING_LAYOUT_WORDS_OFFSET; using Tegra::Texture::TexturePair; ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool, - VKUpdateDescriptorQueue& update_descriptor_queue_, + UpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* thread_worker, PipelineStatistics* pipeline_statistics, VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_, @@ -77,7 +76,7 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript if (pipeline_statistics) { pipeline_statistics->Collect(*pipeline); } - std::lock_guard lock{build_mutex}; + std::scoped_lock lock{build_mutex}; is_built = true; build_condvar.notify_one(); if (shader_notify) { @@ -92,7 +91,7 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript } void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, - Tegra::MemoryManager& gpu_memory, VKScheduler& scheduler, + Tegra::MemoryManager& gpu_memory, Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache) { update_descriptor_queue.Acquire(); @@ -127,8 +126,8 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, const u32 secondary_offset{desc.secondary_cbuf_offset + index_offset}; const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].Address() + secondary_offset}; - const u32 lhs_raw{gpu_memory.Read<u32>(addr)}; - const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)}; + const u32 lhs_raw{gpu_memory.Read<u32>(addr) << desc.shift_left}; + const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr) << desc.secondary_shift_left}; return TexturePair(lhs_raw | rhs_raw, via_header_index); } } diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index 8c4b0a301..9879735fe 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -11,7 +10,6 @@ #include "common/common_types.h" #include "common/thread_worker.h" #include "shader_recompiler/shader_info.h" -#include "video_core/memory_manager.h" #include "video_core/renderer_vulkan/vk_buffer_cache.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" @@ -26,12 +24,12 @@ namespace Vulkan { class Device; class PipelineStatistics; -class VKScheduler; +class Scheduler; class ComputePipeline { public: explicit ComputePipeline(const Device& device, DescriptorPool& descriptor_pool, - VKUpdateDescriptorQueue& update_descriptor_queue, + UpdateDescriptorQueue& update_descriptor_queue, Common::ThreadWorker* thread_worker, PipelineStatistics* pipeline_statistics, VideoCore::ShaderNotify* shader_notify, const Shader::Info& info, @@ -44,11 +42,11 @@ public: ComputePipeline(const ComputePipeline&) = delete; void Configure(Tegra::Engines::KeplerCompute& kepler_compute, Tegra::MemoryManager& gpu_memory, - VKScheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache); + Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache); private: const Device& device; - VKUpdateDescriptorQueue& update_descriptor_queue; + UpdateDescriptorQueue& update_descriptor_queue; Shader::Info info; VideoCommon::ComputeUniformBufferSizes uniform_buffer_sizes{}; diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp index d87da2a34..c7196b64e 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <mutex> @@ -122,7 +121,7 @@ vk::DescriptorSets DescriptorAllocator::AllocateDescriptors(size_t count) { throw vk::Exception(VK_ERROR_OUT_OF_POOL_MEMORY); } -DescriptorPool::DescriptorPool(const Device& device_, VKScheduler& scheduler) +DescriptorPool::DescriptorPool(const Device& device_, Scheduler& scheduler) : device{device_}, master_semaphore{scheduler.GetMasterSemaphore()} {} DescriptorPool::~DescriptorPool() = default; diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h index 59466aac5..bd6696b07 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -15,7 +14,7 @@ namespace Vulkan { class Device; -class VKScheduler; +class Scheduler; struct DescriptorBank; @@ -63,7 +62,7 @@ private: class DescriptorPool { public: - explicit DescriptorPool(const Device& device, VKScheduler& scheduler); + explicit DescriptorPool(const Device& device, Scheduler& scheduler); ~DescriptorPool(); DescriptorPool& operator=(const DescriptorPool&) = delete; diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp index 3bec48d14..0214b103a 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <memory> @@ -9,15 +8,11 @@ #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/vulkan_common/vulkan_device.h" -#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { -InnerFence::InnerFence(VKScheduler& scheduler_, u32 payload_, bool is_stubbed_) - : FenceBase{payload_, is_stubbed_}, scheduler{scheduler_} {} - -InnerFence::InnerFence(VKScheduler& scheduler_, GPUVAddr address_, u32 payload_, bool is_stubbed_) - : FenceBase{address_, payload_, is_stubbed_}, scheduler{scheduler_} {} +InnerFence::InnerFence(Scheduler& scheduler_, bool is_stubbed_) + : FenceBase{is_stubbed_}, scheduler{scheduler_} {} InnerFence::~InnerFence() = default; @@ -44,30 +39,25 @@ void InnerFence::Wait() { scheduler.Wait(wait_tick); } -VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, - TextureCache& texture_cache_, BufferCache& buffer_cache_, - VKQueryCache& query_cache_, const Device& device_, - VKScheduler& scheduler_) +FenceManager::FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, + TextureCache& texture_cache_, BufferCache& buffer_cache_, + QueryCache& query_cache_, const Device& device_, Scheduler& scheduler_) : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_}, scheduler{scheduler_} {} -Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) { - return std::make_shared<InnerFence>(scheduler, value, is_stubbed); -} - -Fence VKFenceManager::CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) { - return std::make_shared<InnerFence>(scheduler, addr, value, is_stubbed); +Fence FenceManager::CreateFence(bool is_stubbed) { + return std::make_shared<InnerFence>(scheduler, is_stubbed); } -void VKFenceManager::QueueFence(Fence& fence) { +void FenceManager::QueueFence(Fence& fence) { fence->Queue(); } -bool VKFenceManager::IsFenceSignaled(Fence& fence) const { +bool FenceManager::IsFenceSignaled(Fence& fence) const { return fence->IsSignaled(); } -void VKFenceManager::WaitFence(Fence& fence) { +void FenceManager::WaitFence(Fence& fence) { fence->Wait(); } diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h index 2f8322d29..7fe2afcd9 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.h +++ b/src/video_core/renderer_vulkan/vk_fence_manager.h @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -9,7 +8,6 @@ #include "video_core/fence_manager.h" #include "video_core/renderer_vulkan/vk_buffer_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" -#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { class System; @@ -22,13 +20,12 @@ class RasterizerInterface; namespace Vulkan { class Device; -class VKQueryCache; -class VKScheduler; +class QueryCache; +class Scheduler; class InnerFence : public VideoCommon::FenceBase { public: - explicit InnerFence(VKScheduler& scheduler_, u32 payload_, bool is_stubbed_); - explicit InnerFence(VKScheduler& scheduler_, GPUVAddr address_, u32 payload_, bool is_stubbed_); + explicit InnerFence(Scheduler& scheduler_, bool is_stubbed_); ~InnerFence(); void Queue(); @@ -38,30 +35,27 @@ public: void Wait(); private: - VKScheduler& scheduler; + Scheduler& scheduler; u64 wait_tick = 0; }; using Fence = std::shared_ptr<InnerFence>; -using GenericFenceManager = - VideoCommon::FenceManager<Fence, TextureCache, BufferCache, VKQueryCache>; +using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCache, BufferCache, QueryCache>; -class VKFenceManager final : public GenericFenceManager { +class FenceManager final : public GenericFenceManager { public: - explicit VKFenceManager(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu, - TextureCache& texture_cache, BufferCache& buffer_cache, - VKQueryCache& query_cache, const Device& device, - VKScheduler& scheduler); + explicit FenceManager(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu, + TextureCache& texture_cache, BufferCache& buffer_cache, + QueryCache& query_cache, const Device& device, Scheduler& scheduler); protected: - Fence CreateFence(u32 value, bool is_stubbed) override; - Fence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) override; + Fence CreateFence(bool is_stubbed) override; void QueueFence(Fence& fence) override; bool IsFenceSignaled(Fence& fence) const override; void WaitFence(Fence& fence) override; private: - VKScheduler& scheduler; + Scheduler& scheduler; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp index b630090e8..dd450169e 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.cpp +++ b/src/video_core/renderer_vulkan/vk_fsr.cpp @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <cmath> #include "common/bit_cast.h" @@ -173,7 +172,7 @@ FSR::FSR(const Device& device_, MemoryAllocator& memory_allocator_, size_t image CreatePipeline(); } -VkImageView FSR::Draw(VKScheduler& 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) { UpdateDescriptorSet(image_index, image_view); diff --git a/src/video_core/renderer_vulkan/vk_fsr.h b/src/video_core/renderer_vulkan/vk_fsr.h index 6bbec3d36..5d872861f 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.h +++ b/src/video_core/renderer_vulkan/vk_fsr.h @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -11,13 +10,13 @@ namespace Vulkan { class Device; -class VKScheduler; +class Scheduler; class FSR { public: explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, VkExtent2D output_size); - VkImageView Draw(VKScheduler& 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); private: diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index d514b71d0..f47786f48 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <span> @@ -216,15 +215,14 @@ ConfigureFuncPtr ConfigureFunc(const std::array<vk::ShaderModule, NUM_STAGES>& m } // Anonymous namespace GraphicsPipeline::GraphicsPipeline( - Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_, - VKScheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, + Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool, - VKUpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread, + UpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread, PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages, const std::array<const Shader::Info*, NUM_STAGES>& infos) - : key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, device{device_}, - texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, scheduler{scheduler_}, + : key{key_}, device{device_}, texture_cache{texture_cache_}, + buffer_cache{buffer_cache_}, scheduler{scheduler_}, update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} { if (shader_notify) { shader_notify->MarkShaderBuilding(); @@ -258,7 +256,7 @@ GraphicsPipeline::GraphicsPipeline( pipeline_statistics->Collect(*pipeline); } - std::lock_guard lock{build_mutex}; + std::scoped_lock lock{build_mutex}; is_built = true; build_condvar.notify_one(); if (shader_notify) { @@ -289,7 +287,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { buffer_cache.SetUniformBuffersState(enabled_uniform_buffer_masks, &uniform_buffer_sizes); - const auto& regs{maxwell3d.regs}; + const auto& regs{maxwell3d->regs}; const bool via_header_index{regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex}; const auto config_stage{[&](size_t stage) LAMBDA_FORCEINLINE { const Shader::Info& info{stage_infos[stage]}; @@ -303,7 +301,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { ++ssbo_index; } } - const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers}; + const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers}; const auto read_handle{[&](const auto& desc, u32 index) { ASSERT(cbufs[desc.cbuf_index].enabled); const u32 index_offset{index << desc.size_shift}; @@ -316,13 +314,14 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { const u32 second_offset{desc.secondary_cbuf_offset + index_offset}; const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address + second_offset}; - const u32 lhs_raw{gpu_memory.Read<u32>(addr)}; - const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)}; + const u32 lhs_raw{gpu_memory->Read<u32>(addr) << desc.shift_left}; + const u32 rhs_raw{gpu_memory->Read<u32>(separate_addr) + << desc.secondary_shift_left}; const u32 raw{lhs_raw | rhs_raw}; return TexturePair(raw, via_header_index); } } - return TexturePair(gpu_memory.Read<u32>(addr), via_header_index); + return TexturePair(gpu_memory->Read<u32>(addr), via_header_index); }}; const auto add_image{[&](const auto& desc, bool blacklist) LAMBDA_FORCEINLINE { for (u32 index = 0; index < desc.count; ++index) { @@ -560,7 +559,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { vertex_attributes.push_back({ .location = static_cast<u32>(index), .binding = attribute.buffer, - .format = MaxwellToVK::VertexFormat(attribute.Type(), attribute.Size()), + .format = MaxwellToVK::VertexFormat(device, attribute.Type(), attribute.Size()), .offset = attribute.offset, }); } diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index a0c1d8f07..85602592b 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -63,22 +62,23 @@ class Device; class PipelineStatistics; class RenderPassCache; class RescalingPushConstant; -class VKScheduler; -class VKUpdateDescriptorQueue; +class Scheduler; +class UpdateDescriptorQueue; class GraphicsPipeline { static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; public: - explicit GraphicsPipeline( - Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, - VKScheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, - VideoCore::ShaderNotify* shader_notify, const Device& device, - DescriptorPool& descriptor_pool, VKUpdateDescriptorQueue& update_descriptor_queue, - Common::ThreadWorker* worker_thread, PipelineStatistics* pipeline_statistics, - RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key, - std::array<vk::ShaderModule, NUM_STAGES> stages, - const std::array<const Shader::Info*, NUM_STAGES>& infos); + explicit GraphicsPipeline(Scheduler& scheduler, BufferCache& buffer_cache, + TextureCache& texture_cache, VideoCore::ShaderNotify* shader_notify, + const Device& device, DescriptorPool& descriptor_pool, + UpdateDescriptorQueue& update_descriptor_queue, + Common::ThreadWorker* worker_thread, + PipelineStatistics* pipeline_statistics, + RenderPassCache& render_pass_cache, + const GraphicsPipelineCacheKey& key, + std::array<vk::ShaderModule, NUM_STAGES> stages, + const std::array<const Shader::Info*, NUM_STAGES>& infos); GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete; GraphicsPipeline(GraphicsPipeline&&) noexcept = delete; @@ -110,6 +110,11 @@ public: return [](GraphicsPipeline* pl, bool is_indexed) { pl->ConfigureImpl<Spec>(is_indexed); }; } + void SetEngine(Tegra::Engines::Maxwell3D* maxwell3d_, Tegra::MemoryManager* gpu_memory_) { + maxwell3d = maxwell3d_; + gpu_memory = gpu_memory_; + } + private: template <typename Spec> void ConfigureImpl(bool is_indexed); @@ -121,13 +126,13 @@ private: void Validate(); const GraphicsPipelineCacheKey key; - Tegra::Engines::Maxwell3D& maxwell3d; - Tegra::MemoryManager& gpu_memory; + Tegra::Engines::Maxwell3D* maxwell3d; + Tegra::MemoryManager* gpu_memory; const Device& device; TextureCache& texture_cache; BufferCache& buffer_cache; - VKScheduler& scheduler; - VKUpdateDescriptorQueue& update_descriptor_queue; + Scheduler& scheduler; + UpdateDescriptorQueue& update_descriptor_queue; void (*configure_func)(GraphicsPipeline*, bool){}; diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index 6852c11b0..4e81d3d28 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <thread> diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 9be9c9bed..362ed579a 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index a633b73e5..732e7b6f2 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <cstddef> @@ -16,13 +15,11 @@ #include "common/microprofile.h" #include "common/thread_worker.h" #include "core/core.h" -#include "core/memory.h" #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/environment.h" #include "shader_recompiler/frontend/maxwell/control_flow.h" #include "shader_recompiler/frontend/maxwell/translate_program.h" #include "shader_recompiler/program_header.h" -#include "video_core/dirty_flags.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" @@ -56,7 +53,7 @@ using VideoCommon::FileEnvironment; using VideoCommon::GenericEnvironment; using VideoCommon::GraphicsEnvironment; -constexpr u32 CACHE_VERSION = 5; +constexpr u32 CACHE_VERSION = 6; template <typename Container> auto MakeSpan(Container& container) { @@ -177,7 +174,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program case Maxwell::TessellationPrimitive::Quads: return Shader::TessPrimitive::Quads; } - UNREACHABLE(); + ASSERT(false); return Shader::TessPrimitive::Triangles; }(); info.tess_spacing = [&] { @@ -190,7 +187,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program case Maxwell::TessellationSpacing::FractionalEven: return Shader::TessSpacing::FractionalEven; } - UNREACHABLE(); + ASSERT(false); return Shader::TessSpacing::Equal; }(); break; @@ -262,20 +259,18 @@ bool GraphicsPipelineCacheKey::operator==(const GraphicsPipelineCacheKey& rhs) c return std::memcmp(&rhs, this, Size()) == 0; } -PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::Engines::Maxwell3D& maxwell3d_, - Tegra::Engines::KeplerCompute& kepler_compute_, - Tegra::MemoryManager& gpu_memory_, const Device& device_, - VKScheduler& scheduler_, DescriptorPool& descriptor_pool_, - VKUpdateDescriptorQueue& update_descriptor_queue_, +PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device_, + Scheduler& scheduler_, DescriptorPool& descriptor_pool_, + UpdateDescriptorQueue& update_descriptor_queue_, RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_, TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_) - : VideoCommon::ShaderCache{rasterizer_, gpu_memory_, maxwell3d_, kepler_compute_}, - device{device_}, scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, - update_descriptor_queue{update_descriptor_queue_}, render_pass_cache{render_pass_cache_}, - buffer_cache{buffer_cache_}, texture_cache{texture_cache_}, shader_notify{shader_notify_}, + : VideoCommon::ShaderCache{rasterizer_}, device{device_}, scheduler{scheduler_}, + descriptor_pool{descriptor_pool_}, update_descriptor_queue{update_descriptor_queue_}, + render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_}, + texture_cache{texture_cache_}, shader_notify{shader_notify_}, use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()}, - workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "yuzu:PipelineBuilder"), - serialization_thread(1, "yuzu:PipelineSerialization") { + workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "VkPipelineBuilder"), + serialization_thread(1, "VkPipelineSerialization") { const auto& float_control{device.FloatControlProperties()}; const VkDriverIdKHR driver_id{device.GetDriverID()}; profile = Shader::Profile{ @@ -340,7 +335,7 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() { current_pipeline = nullptr; return nullptr; } - graphics_key.state.Refresh(maxwell3d, device.IsExtExtendedDynamicStateSupported(), + graphics_key.state.Refresh(*maxwell3d, device.IsExtExtendedDynamicStateSupported(), device.IsExtVertexInputDynamicStateSupported()); if (current_pipeline) { @@ -360,7 +355,7 @@ ComputePipeline* PipelineCache::CurrentComputePipeline() { if (!shader) { return nullptr; } - const auto& qmd{kepler_compute.launch_description}; + const auto& qmd{kepler_compute->launch_description}; const ComputePipelineCacheKey key{ .unique_hash = shader->unique_hash, .shared_memory_size = qmd.shared_alloc, @@ -406,7 +401,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable { ShaderPools pools; auto pipeline{CreateComputePipeline(pools, key, env, state.statistics.get(), false)}; - std::lock_guard lock{state.mutex}; + std::scoped_lock lock{state.mutex}; if (pipeline) { compute_cache.emplace(key, std::move(pipeline)); } @@ -436,8 +431,10 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs), state.statistics.get(), false)}; - std::lock_guard lock{state.mutex}; - graphics_cache.emplace(key, std::move(pipeline)); + std::scoped_lock lock{state.mutex}; + if (pipeline) { + graphics_cache.emplace(key, std::move(pipeline)); + } ++state.built; if (state.has_loaded) { callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); @@ -455,7 +452,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading state.has_loaded = true; lock.unlock(); - workers.WaitForRequests(); + workers.WaitForRequests(stop_loading); if (state.statistics) { state.statistics->Report(); @@ -487,13 +484,13 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const } // If something is using depth, we can assume that games are not rendering anything which // will be used one time. - if (maxwell3d.regs.zeta_enable) { + if (maxwell3d->regs.zeta_enable) { return nullptr; } // If games are using a small index count, we can assume these are full screen quads. // Usually these shaders are only used once for building textures so we can assume they // can't be built async - if (maxwell3d.regs.index_array.count <= 6 || maxwell3d.regs.vertex_buffer.count <= 6) { + if (maxwell3d->regs.index_array.count <= 6 || maxwell3d->regs.vertex_buffer.count <= 6) { return pipeline; } return nullptr; @@ -558,10 +555,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( previous_stage = &program; } Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; - return std::make_unique<GraphicsPipeline>( - maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, &shader_notify, device, - descriptor_pool, update_descriptor_queue, thread_worker, statistics, render_pass_cache, key, - std::move(modules), infos); + return std::make_unique<GraphicsPipeline>(scheduler, buffer_cache, texture_cache, + &shader_notify, device, descriptor_pool, + update_descriptor_queue, thread_worker, statistics, + render_pass_cache, key, std::move(modules), infos); } catch (const Shader::Exception& exception) { LOG_ERROR(Render_Vulkan, "{}", exception.what()); @@ -593,9 +590,9 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() { std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( const ComputePipelineCacheKey& key, const ShaderInfo* shader) { - const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()}; - const auto& qmd{kepler_compute.launch_description}; - ComputeEnvironment env{kepler_compute, gpu_memory, program_base, qmd.program_start}; + const GPUVAddr program_base{kepler_compute->regs.code_loc.Address()}; + const auto& qmd{kepler_compute->launch_description}; + ComputeEnvironment env{*kepler_compute, *gpu_memory, program_base, qmd.program_start}; env.SetCachedSize(shader->size_bytes); main_pools.ReleaseContents(); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 4c135b5dd..61f9e9366 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -1,17 +1,14 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include <array> #include <cstddef> #include <filesystem> -#include <iosfwd> #include <memory> #include <type_traits> #include <unordered_map> -#include <utility> #include <vector> #include "common/common_types.h" @@ -29,7 +26,6 @@ #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/shader_cache.h" -#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { class System; @@ -85,8 +81,8 @@ class Device; class PipelineStatistics; class RasterizerVulkan; class RenderPassCache; -class VKScheduler; -class VKUpdateDescriptorQueue; +class Scheduler; +class UpdateDescriptorQueue; using VideoCommon::ShaderInfo; @@ -104,11 +100,9 @@ struct ShaderPools { class PipelineCache : public VideoCommon::ShaderCache { public: - explicit PipelineCache(RasterizerVulkan& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d, - Tegra::Engines::KeplerCompute& kepler_compute, - Tegra::MemoryManager& gpu_memory, const Device& device, - VKScheduler& scheduler, DescriptorPool& descriptor_pool, - VKUpdateDescriptorQueue& update_descriptor_queue, + explicit PipelineCache(RasterizerVulkan& rasterizer, const Device& device, Scheduler& scheduler, + DescriptorPool& descriptor_pool, + UpdateDescriptorQueue& update_descriptor_queue, RenderPassCache& render_pass_cache, BufferCache& buffer_cache, TextureCache& texture_cache, VideoCore::ShaderNotify& shader_notify_); ~PipelineCache(); @@ -142,9 +136,9 @@ private: bool build_in_parallel); const Device& device; - VKScheduler& scheduler; + Scheduler& scheduler; DescriptorPool& descriptor_pool; - VKUpdateDescriptorQueue& update_descriptor_queue; + UpdateDescriptorQueue& update_descriptor_queue; RenderPassCache& render_pass_cache; BufferCache& buffer_cache; TextureCache& texture_cache; diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 259cba156..7cb02631c 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <cstddef> @@ -27,7 +26,7 @@ constexpr VkQueryType GetTarget(QueryType type) { } // Anonymous namespace -QueryPool::QueryPool(const Device& device_, VKScheduler& scheduler, QueryType type_) +QueryPool::QueryPool(const Device& device_, Scheduler& scheduler, QueryType type_) : ResourcePool{scheduler.GetMasterSemaphore(), GROW_STEP}, device{device_}, type{type_} {} QueryPool::~QueryPool() = default; @@ -66,15 +65,14 @@ void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) { usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false; } -VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer_, - Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_, - const Device& device_, VKScheduler& scheduler_) - : QueryCacheBase{rasterizer_, maxwell3d_, gpu_memory_}, device{device_}, scheduler{scheduler_}, +QueryCache::QueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_, + Scheduler& scheduler_) + : QueryCacheBase{rasterizer_}, device{device_}, scheduler{scheduler_}, query_pools{ QueryPool{device_, scheduler_, QueryType::SamplesPassed}, } {} -VKQueryCache::~VKQueryCache() { +QueryCache::~QueryCache() { // TODO(Rodrigo): This is a hack to destroy all HostCounter instances before the base class // destructor is called. The query cache should be redesigned to have a proper ownership model // instead of using shared pointers. @@ -85,15 +83,15 @@ VKQueryCache::~VKQueryCache() { } } -std::pair<VkQueryPool, u32> VKQueryCache::AllocateQuery(QueryType type) { +std::pair<VkQueryPool, u32> QueryCache::AllocateQuery(QueryType type) { return query_pools[static_cast<std::size_t>(type)].Commit(); } -void VKQueryCache::Reserve(QueryType type, std::pair<VkQueryPool, u32> query) { +void QueryCache::Reserve(QueryType type, std::pair<VkQueryPool, u32> query) { query_pools[static_cast<std::size_t>(type)].Reserve(query); } -HostCounter::HostCounter(VKQueryCache& cache_, std::shared_ptr<HostCounter> dependency_, +HostCounter::HostCounter(QueryCache& cache_, std::shared_ptr<HostCounter> dependency_, QueryType type_) : HostCounterBase{std::move(dependency_)}, cache{cache_}, type{type_}, query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} { diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h index 7190946b9..26762ee09 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.h +++ b/src/video_core/renderer_vulkan/vk_query_cache.h @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -23,14 +22,14 @@ namespace Vulkan { class CachedQuery; class Device; class HostCounter; -class VKQueryCache; -class VKScheduler; +class QueryCache; +class Scheduler; -using CounterStream = VideoCommon::CounterStreamBase<VKQueryCache, HostCounter>; +using CounterStream = VideoCommon::CounterStreamBase<QueryCache, HostCounter>; class QueryPool final : public ResourcePool { public: - explicit QueryPool(const Device& device, VKScheduler& scheduler, VideoCore::QueryType type); + explicit QueryPool(const Device& device, Scheduler& scheduler, VideoCore::QueryType type); ~QueryPool() override; std::pair<VkQueryPool, u32> Commit(); @@ -50,13 +49,12 @@ private: std::vector<bool> usage; }; -class VKQueryCache final - : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter> { +class QueryCache final + : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { public: - explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer_, - Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_, - const Device& device_, VKScheduler& scheduler_); - ~VKQueryCache(); + explicit QueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_, + Scheduler& scheduler_); + ~QueryCache(); std::pair<VkQueryPool, u32> AllocateQuery(VideoCore::QueryType type); @@ -66,19 +64,19 @@ public: return device; } - VKScheduler& GetScheduler() const noexcept { + Scheduler& GetScheduler() const noexcept { return scheduler; } private: const Device& device; - VKScheduler& scheduler; + Scheduler& scheduler; std::array<QueryPool, VideoCore::NumQueryTypes> query_pools; }; -class HostCounter final : public VideoCommon::HostCounterBase<VKQueryCache, HostCounter> { +class HostCounter final : public VideoCommon::HostCounterBase<QueryCache, HostCounter> { public: - explicit HostCounter(VKQueryCache& cache_, std::shared_ptr<HostCounter> dependency_, + explicit HostCounter(QueryCache& cache_, std::shared_ptr<HostCounter> dependency_, VideoCore::QueryType type_); ~HostCounter(); @@ -87,7 +85,7 @@ public: private: u64 BlockingQuery() const override; - VKQueryCache& cache; + QueryCache& cache; const VideoCore::QueryType type; const std::pair<VkQueryPool, u32> query; const u64 tick; @@ -95,7 +93,7 @@ private: class CachedQuery : public VideoCommon::CachedQueryBase<HostCounter> { public: - explicit CachedQuery(VKQueryCache&, VideoCore::QueryType, VAddr cpu_addr_, u8* host_ptr_) + explicit CachedQuery(QueryCache&, VideoCore::QueryType, VAddr cpu_addr_, u8* host_ptr_) : CachedQueryBase{cpu_addr_, host_ptr_} {} }; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 2227d9197..acfd5da7d 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1,20 +1,17 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> #include <memory> #include <mutex> -#include <vector> -#include "common/alignment.h" #include "common/assert.h" #include "common/logging/log.h" #include "common/microprofile.h" #include "common/scope_exit.h" #include "common/settings.h" -#include "core/core.h" +#include "video_core/control/channel_state.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_vulkan/blit_image.h" @@ -73,10 +70,17 @@ VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t in const float width = conv(src.scale_x * 2.0f); float y = conv(src.translate_y - src.scale_y); float height = conv(src.scale_y * 2.0f); - if (regs.screen_y_control.y_negate) { + bool y_negate = regs.screen_y_control.y_negate; + + if (!device.IsNvViewportSwizzleSupported()) { + y_negate = y_negate != (src.swizzle.y == Maxwell::ViewportSwizzle::NegativeY); + } + + if (y_negate) { y += height; height = -height; } + const float reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1.0f : 0.0f; VkViewport viewport{ .x = x, @@ -145,14 +149,11 @@ DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_instan } // Anonymous namespace RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, - Tegra::MemoryManager& gpu_memory_, - Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, + Core::Memory::Memory& cpu_memory_, ScreenInfo& screen_info_, const Device& device_, MemoryAllocator& memory_allocator_, - StateTracker& state_tracker_, VKScheduler& scheduler_) - : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, - gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()}, - screen_info{screen_info_}, device{device_}, memory_allocator{memory_allocator_}, - state_tracker{state_tracker_}, scheduler{scheduler_}, + StateTracker& state_tracker_, Scheduler& scheduler_) + : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, screen_info{screen_info_}, device{device_}, + memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), update_descriptor_queue(device, scheduler), blit_image(device, scheduler, state_tracker, descriptor_pool), @@ -162,14 +163,13 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra memory_allocator, staging_pool, blit_image, astc_decoder_pass, render_pass_cache}, - texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), + texture_cache(texture_cache_runtime, *this), buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool, update_descriptor_queue, descriptor_pool), - buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime), - pipeline_cache(*this, maxwell3d, kepler_compute, gpu_memory, device, scheduler, - descriptor_pool, update_descriptor_queue, render_pass_cache, buffer_cache, - texture_cache, gpu.ShaderNotify()), - query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, accelerate_dma{buffer_cache}, + buffer_cache(*this, cpu_memory_, buffer_cache_runtime), + pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue, + render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()), + query_cache{*this, device, scheduler}, accelerate_dma{buffer_cache}, fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler), wfi_event(device.GetLogical().CreateEvent()) { scheduler.SetQueryCache(query_cache); @@ -190,14 +190,16 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { return; } std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + // update engine as channel may be different. + pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); BeginTransformFeedback(); UpdateDynamicStates(); - const auto& regs{maxwell3d.regs}; - const u32 num_instances{maxwell3d.mme_draw.instance_count}; + const auto& regs{maxwell3d->regs}; + const u32 num_instances{maxwell3d->mme_draw.instance_count}; const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_instanced, is_indexed)}; scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { if (draw_params.is_indexed) { @@ -215,14 +217,14 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { void RasterizerVulkan::Clear() { MICROPROFILE_SCOPE(Vulkan_Clearing); - if (!maxwell3d.ShouldExecute()) { + if (!maxwell3d->ShouldExecute()) { return; } FlushWork(); query_cache.UpdateCounters(); - auto& regs = maxwell3d.regs; + auto& regs = maxwell3d->regs; const bool use_color = regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || regs.clear_buffers.A; const bool use_depth = regs.clear_buffers.Z; @@ -245,8 +247,15 @@ void RasterizerVulkan::Clear() { } UpdateViewportsState(regs); + VkRect2D default_scissor; + default_scissor.offset.x = 0; + default_scissor.offset.y = 0; + default_scissor.extent.width = std::numeric_limits<s32>::max(); + default_scissor.extent.height = std::numeric_limits<s32>::max(); + VkClearRect clear_rect{ - .rect = GetScissorState(regs, 0, up_scale, down_shift), + .rect = regs.clear_flags.scissor ? GetScissorState(regs, 0, up_scale, down_shift) + : default_scissor, .baseArrayLayer = regs.clear_buffers.layer, .layerCount = 1, }; @@ -336,9 +345,9 @@ void RasterizerVulkan::DispatchCompute() { return; } std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex}; - pipeline->Configure(kepler_compute, gpu_memory, scheduler, buffer_cache, texture_cache); + pipeline->Configure(*kepler_compute, *gpu_memory, scheduler, buffer_cache, texture_cache); - const auto& qmd{kepler_compute.launch_description}; + const auto& qmd{kepler_compute->launch_description}; const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z}; scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([dim](vk::CommandBuffer cmdbuf) { cmdbuf.Dispatch(dim[0], dim[1], dim[2]); }); @@ -419,7 +428,7 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) { } } -void RasterizerVulkan::SyncGuestHost() { +void RasterizerVulkan::InvalidateGPUCache() { pipeline_cache.SyncGuestHost(); { std::scoped_lock lock{buffer_cache.mutex}; @@ -439,40 +448,30 @@ void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) { pipeline_cache.OnCPUWrite(addr, size); } -void RasterizerVulkan::ModifyGPUMemory(GPUVAddr addr, u64 size) { +void RasterizerVulkan::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) { { std::scoped_lock lock{texture_cache.mutex}; - texture_cache.UnmapGPUMemory(addr, size); + texture_cache.UnmapGPUMemory(as_id, addr, size); } } -void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) { - if (!gpu.IsAsync()) { - gpu_memory.Write<u32>(addr, value); - return; - } - fence_manager.SignalSemaphore(addr, value); +void RasterizerVulkan::SignalFence(std::function<void()>&& func) { + fence_manager.SignalFence(std::move(func)); +} + +void RasterizerVulkan::SyncOperation(std::function<void()>&& func) { + fence_manager.SyncOperation(std::move(func)); } void RasterizerVulkan::SignalSyncPoint(u32 value) { - if (!gpu.IsAsync()) { - gpu.IncrementSyncPoint(value); - return; - } fence_manager.SignalSyncPoint(value); } void RasterizerVulkan::SignalReference() { - if (!gpu.IsAsync()) { - return; - } fence_manager.SignalOrdering(); } void RasterizerVulkan::ReleaseFences() { - if (!gpu.IsAsync()) { - return; - } fence_manager.WaitPendingFences(); } @@ -549,13 +548,13 @@ Tegra::Engines::AccelerateDMAInterface& RasterizerVulkan::AccessAccelerateDMA() } void RasterizerVulkan::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, - std::span<u8> memory) { - auto cpu_addr = gpu_memory.GpuToCpuAddress(address); + std::span<const u8> memory) { + auto cpu_addr = gpu_memory->GpuToCpuAddress(address); if (!cpu_addr) [[unlikely]] { - gpu_memory.WriteBlock(address, memory.data(), copy_size); + gpu_memory->WriteBlock(address, memory.data(), copy_size); return; } - gpu_memory.WriteBlockUnsafe(address, memory.data(), copy_size); + gpu_memory->WriteBlockUnsafe(address, memory.data(), copy_size); { std::unique_lock<std::mutex> lock{buffer_cache.mutex}; if (!buffer_cache.InlineMemory(*cpu_addr, copy_size, memory)) { @@ -624,7 +623,7 @@ bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 } void RasterizerVulkan::UpdateDynamicStates() { - auto& regs = maxwell3d.regs; + auto& regs = maxwell3d->regs; UpdateViewportsState(regs); UpdateScissorsState(regs); UpdateDepthBias(regs); @@ -648,7 +647,7 @@ void RasterizerVulkan::UpdateDynamicStates() { } void RasterizerVulkan::BeginTransformFeedback() { - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; if (regs.tfb_enabled == 0) { return; } @@ -664,7 +663,7 @@ void RasterizerVulkan::BeginTransformFeedback() { } void RasterizerVulkan::EndTransformFeedback() { - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; if (regs.tfb_enabled == 0) { return; } @@ -788,8 +787,8 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs) }); } else { // Front face defines both faces - scheduler.Record([ref = regs.stencil_back_func_ref, write_mask = regs.stencil_back_mask, - test_mask = regs.stencil_back_func_mask](vk::CommandBuffer cmdbuf) { + scheduler.Record([ref = regs.stencil_front_func_ref, write_mask = regs.stencil_front_mask, + test_mask = regs.stencil_front_func_mask](vk::CommandBuffer cmdbuf) { cmdbuf.SetStencilReference(VK_STENCIL_FACE_FRONT_AND_BACK, ref); cmdbuf.SetStencilWriteMask(VK_STENCIL_FACE_FRONT_AND_BACK, write_mask); cmdbuf.SetStencilCompareMask(VK_STENCIL_FACE_FRONT_AND_BACK, test_mask); @@ -914,7 +913,7 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& } void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) { - auto& dirty{maxwell3d.dirty.flags}; + auto& dirty{maxwell3d->dirty.flags}; if (!dirty[Dirty::VertexInput]) { return; } @@ -943,7 +942,7 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) .pNext = nullptr, .location = static_cast<u32>(index), .binding = binding, - .format = MaxwellToVK::VertexFormat(attribute.type, attribute.size), + .format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size), .offset = attribute.offset, }); } @@ -971,4 +970,41 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) }); } +void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) { + CreateChannel(channel); + { + std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + texture_cache.CreateChannel(channel); + buffer_cache.CreateChannel(channel); + } + pipeline_cache.CreateChannel(channel); + query_cache.CreateChannel(channel); + state_tracker.SetupTables(channel); +} + +void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) { + const s32 channel_id = channel.bind_id; + BindToChannel(channel_id); + { + std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + texture_cache.BindToChannel(channel_id); + buffer_cache.BindToChannel(channel_id); + } + pipeline_cache.BindToChannel(channel_id); + query_cache.BindToChannel(channel_id); + state_tracker.ChangeChannel(channel); + state_tracker.InvalidateState(); +} + +void RasterizerVulkan::ReleaseChannel(s32 channel_id) { + EraseChannel(channel_id); + { + std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + texture_cache.EraseChannel(channel_id); + buffer_cache.EraseChannel(channel_id); + } + pipeline_cache.EraseChannel(channel_id); + query_cache.EraseChannel(channel_id); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 5af2e275b..4cde3c983 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -1,30 +1,24 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include <array> -#include <bitset> -#include <memory> -#include <utility> -#include <vector> #include <boost/container/static_vector.hpp> #include "common/common_types.h" +#include "video_core/control/channel_state_cache.h" #include "video_core/engines/maxwell_dma.h" #include "video_core/rasterizer_accelerated.h" #include "video_core/rasterizer_interface.h" #include "video_core/renderer_vulkan/blit_image.h" -#include "video_core/renderer_vulkan/fixed_pipeline_state.h" #include "video_core/renderer_vulkan/vk_buffer_cache.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_fence_manager.h" #include "video_core/renderer_vulkan/vk_pipeline_cache.h" #include "video_core/renderer_vulkan/vk_query_cache.h" #include "video_core/renderer_vulkan/vk_render_pass_cache.h" -#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" @@ -45,7 +39,7 @@ class Maxwell3D; namespace Vulkan { -struct VKScreenInfo; +struct ScreenInfo; class StateTracker; @@ -61,13 +55,13 @@ private: BufferCache& buffer_cache; }; -class RasterizerVulkan final : public VideoCore::RasterizerAccelerated { +class RasterizerVulkan final : public VideoCore::RasterizerAccelerated, + protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { public: explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, - Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, - VKScreenInfo& screen_info_, const Device& device_, - MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, - VKScheduler& scheduler_); + Core::Memory::Memory& cpu_memory_, ScreenInfo& screen_info_, + const Device& device_, MemoryAllocator& memory_allocator_, + StateTracker& state_tracker_, Scheduler& scheduler_); ~RasterizerVulkan() override; void Draw(bool is_indexed, bool is_instanced) override; @@ -82,10 +76,11 @@ public: bool MustFlushRegion(VAddr addr, u64 size) override; void InvalidateRegion(VAddr addr, u64 size) override; void OnCPUWrite(VAddr addr, u64 size) override; - void SyncGuestHost() override; + void InvalidateGPUCache() override; void UnmapMemory(VAddr addr, u64 size) override; - void ModifyGPUMemory(GPUVAddr addr, u64 size) override; - void SignalSemaphore(GPUVAddr addr, u32 value) override; + void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; + void SignalFence(std::function<void()>&& func) override; + void SyncOperation(std::function<void()>&& func) override; void SignalSyncPoint(u32 value) override; void SignalReference() override; void ReleaseFences() override; @@ -100,12 +95,18 @@ public: const Tegra::Engines::Fermi2D::Config& copy_config) override; Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, - std::span<u8> memory) override; + std::span<const u8> memory) override; bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, u32 pixel_stride) override; void LoadDiskResources(u64 title_id, std::stop_token stop_loading, const VideoCore::DiskResourceLoadCallback& callback) override; + void InitializeChannel(Tegra::Control::ChannelState& channel) override; + + void BindChannel(Tegra::Control::ChannelState& channel) override; + + void ReleaseChannel(s32 channel_id) override; + private: static constexpr size_t MAX_TEXTURES = 192; static constexpr size_t MAX_IMAGES = 48; @@ -141,19 +142,16 @@ private: void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); Tegra::GPU& gpu; - Tegra::MemoryManager& gpu_memory; - Tegra::Engines::Maxwell3D& maxwell3d; - Tegra::Engines::KeplerCompute& kepler_compute; - VKScreenInfo& screen_info; + ScreenInfo& screen_info; const Device& device; MemoryAllocator& memory_allocator; StateTracker& state_tracker; - VKScheduler& scheduler; + Scheduler& scheduler; StagingBufferPool staging_pool; DescriptorPool descriptor_pool; - VKUpdateDescriptorQueue update_descriptor_queue; + UpdateDescriptorQueue update_descriptor_queue; BlitImageHelper blit_image; ASTCDecoderPass astc_decoder_pass; RenderPassCache render_pass_cache; @@ -163,9 +161,9 @@ private: BufferCacheRuntime buffer_cache_runtime; BufferCache buffer_cache; PipelineCache pipeline_cache; - VKQueryCache query_cache; + QueryCache query_cache; AccelerateDMA accelerate_dma; - VKFenceManager fence_manager; + FenceManager fence_manager; vk::Event wfi_event; diff --git a/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp b/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp index 451ffe019..ae9f1de64 100644 --- a/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <unordered_map> @@ -36,7 +35,7 @@ VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat RenderPassCache::RenderPassCache(const Device& device_) : device{&device_} {} VkRenderPass RenderPassCache::Get(const RenderPassKey& key) { - std::lock_guard lock{mutex}; + std::scoped_lock lock{mutex}; const auto [pair, is_new] = cache.try_emplace(key); if (!is_new) { return *pair->second; diff --git a/src/video_core/renderer_vulkan/vk_render_pass_cache.h b/src/video_core/renderer_vulkan/vk_render_pass_cache.h index eaa0ed775..dc21b7e69 100644 --- a/src/video_core/renderer_vulkan/vk_render_pass_cache.h +++ b/src/video_core/renderer_vulkan/vk_render_pass_cache.h @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_vulkan/vk_resource_pool.cpp b/src/video_core/renderer_vulkan/vk_resource_pool.cpp index 2dd514968..6c8ac22f4 100644 --- a/src/video_core/renderer_vulkan/vk_resource_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_pool.cpp @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <optional> diff --git a/src/video_core/renderer_vulkan/vk_resource_pool.h b/src/video_core/renderer_vulkan/vk_resource_pool.h index f0b80ad59..a39a3b881 100644 --- a/src/video_core/renderer_vulkan/vk_resource_pool.h +++ b/src/video_core/renderer_vulkan/vk_resource_pool.h @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 7d9d4f7ba..d96720b80 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -1,10 +1,8 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <memory> #include <mutex> -#include <optional> #include <thread> #include <utility> @@ -23,7 +21,7 @@ namespace Vulkan { MICROPROFILE_DECLARE(Vulkan_WaitForWorker); -void VKScheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf) { +void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf) { auto command = first; while (command != nullptr) { auto next = command->GetNext(); @@ -37,7 +35,7 @@ void VKScheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf) { last = nullptr; } -VKScheduler::VKScheduler(const Device& device_, StateTracker& state_tracker_) +Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_) : device{device_}, state_tracker{state_tracker_}, master_semaphore{std::make_unique<MasterSemaphore>(device)}, command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} { @@ -46,14 +44,14 @@ VKScheduler::VKScheduler(const Device& device_, StateTracker& state_tracker_) worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); }); } -VKScheduler::~VKScheduler() = default; +Scheduler::~Scheduler() = default; -void VKScheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { +void Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { SubmitExecution(signal_semaphore, wait_semaphore); AllocateNewContext(); } -void VKScheduler::Finish(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { +void Scheduler::Finish(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { const u64 presubmit_tick = CurrentTick(); SubmitExecution(signal_semaphore, wait_semaphore); WaitWorker(); @@ -61,7 +59,7 @@ void VKScheduler::Finish(VkSemaphore signal_semaphore, VkSemaphore wait_semaphor AllocateNewContext(); } -void VKScheduler::WaitWorker() { +void Scheduler::WaitWorker() { MICROPROFILE_SCOPE(Vulkan_WaitForWorker); DispatchWork(); @@ -69,19 +67,19 @@ void VKScheduler::WaitWorker() { wait_cv.wait(lock, [this] { return work_queue.empty(); }); } -void VKScheduler::DispatchWork() { +void Scheduler::DispatchWork() { if (chunk->Empty()) { return; } { - std::lock_guard lock{work_mutex}; + std::scoped_lock lock{work_mutex}; work_queue.push(std::move(chunk)); } work_cv.notify_one(); AcquireNewChunk(); } -void VKScheduler::RequestRenderpass(const Framebuffer* framebuffer) { +void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) { const VkRenderPass renderpass = framebuffer->RenderPass(); const VkFramebuffer framebuffer_handle = framebuffer->Handle(); const VkExtent2D render_area = framebuffer->RenderArea(); @@ -116,11 +114,11 @@ void VKScheduler::RequestRenderpass(const Framebuffer* framebuffer) { renderpass_image_ranges = framebuffer->ImageRanges(); } -void VKScheduler::RequestOutsideRenderPassOperationContext() { +void Scheduler::RequestOutsideRenderPassOperationContext() { EndRenderPass(); } -bool VKScheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) { +bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) { if (state.graphics_pipeline == pipeline) { return false; } @@ -128,7 +126,7 @@ bool VKScheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) { return true; } -bool VKScheduler::UpdateRescaling(bool is_rescaling) { +bool Scheduler::UpdateRescaling(bool is_rescaling) { if (state.rescaling_defined && is_rescaling == state.is_rescaling) { return false; } @@ -137,8 +135,8 @@ bool VKScheduler::UpdateRescaling(bool is_rescaling) { return true; } -void VKScheduler::WorkerThread(std::stop_token stop_token) { - Common::SetCurrentThreadName("yuzu:VulkanWorker"); +void Scheduler::WorkerThread(std::stop_token stop_token) { + Common::SetCurrentThreadName("VulkanWorker"); do { std::unique_ptr<CommandChunk> work; { @@ -158,12 +156,12 @@ void VKScheduler::WorkerThread(std::stop_token stop_token) { if (has_submit) { AllocateWorkerCommandBuffer(); } - std::lock_guard reserve_lock{reserve_mutex}; + std::scoped_lock reserve_lock{reserve_mutex}; chunk_reserve.push_back(std::move(work)); } while (!stop_token.stop_requested()); } -void VKScheduler::AllocateWorkerCommandBuffer() { +void Scheduler::AllocateWorkerCommandBuffer() { current_cmdbuf = vk::CommandBuffer(command_pool->Commit(), device.GetDispatchLoader()); current_cmdbuf.Begin({ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, @@ -173,7 +171,7 @@ void VKScheduler::AllocateWorkerCommandBuffer() { }); } -void VKScheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { +void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { EndPendingOperations(); InvalidateState(); @@ -227,25 +225,25 @@ void VKScheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait DispatchWork(); } -void VKScheduler::AllocateNewContext() { +void Scheduler::AllocateNewContext() { // Enable counters once again. These are disabled when a command buffer is finished. if (query_cache) { query_cache->UpdateCounters(); } } -void VKScheduler::InvalidateState() { +void Scheduler::InvalidateState() { state.graphics_pipeline = nullptr; state.rescaling_defined = false; state_tracker.InvalidateCommandBufferState(); } -void VKScheduler::EndPendingOperations() { +void Scheduler::EndPendingOperations() { query_cache->DisableStreams(); EndRenderPass(); } -void VKScheduler::EndRenderPass() { +void Scheduler::EndRenderPass() { if (!state.renderpass) { return; } @@ -282,8 +280,8 @@ void VKScheduler::EndRenderPass() { num_renderpass_images = 0; } -void VKScheduler::AcquireNewChunk() { - std::lock_guard lock{reserve_mutex}; +void Scheduler::AcquireNewChunk() { + std::scoped_lock lock{reserve_mutex}; if (chunk_reserve.empty()) { chunk = std::make_unique<CommandChunk>(); return; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index e69aa136b..c04aad08f 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -1,10 +1,8 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include <atomic> #include <condition_variable> #include <cstddef> #include <memory> @@ -24,14 +22,14 @@ class Device; class Framebuffer; class GraphicsPipeline; class StateTracker; -class VKQueryCache; +class QueryCache; /// The scheduler abstracts command buffer and fence management with an interface that's able to do /// OpenGL-like operations on Vulkan command buffers. -class VKScheduler { +class Scheduler { public: - explicit VKScheduler(const Device& device, StateTracker& state_tracker); - ~VKScheduler(); + explicit Scheduler(const Device& device, StateTracker& state_tracker); + ~Scheduler(); /// Sends the current execution context to the GPU. void Flush(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr); @@ -63,7 +61,7 @@ public: void InvalidateState(); /// Assigns the query cache. - void SetQueryCache(VKQueryCache& query_cache_) { + void SetQueryCache(QueryCache& query_cache_) { query_cache = &query_cache_; } @@ -214,7 +212,7 @@ private: std::unique_ptr<MasterSemaphore> master_semaphore; std::unique_ptr<CommandPool> command_pool; - VKQueryCache* query_cache = nullptr; + QueryCache* query_cache = nullptr; vk::CommandBuffer current_cmdbuf; diff --git a/src/video_core/renderer_vulkan/vk_shader_util.cpp b/src/video_core/renderer_vulkan/vk_shader_util.cpp index aaad4f292..7a0a2b154 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_util.cpp @@ -1,11 +1,8 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <cstring> -#include <memory> -#include "common/assert.h" #include "common/common_types.h" #include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/vulkan_common/vulkan_device.h" diff --git a/src/video_core/renderer_vulkan/vk_shader_util.h b/src/video_core/renderer_vulkan/vk_shader_util.h index 9517cbe84..2f7c9f25c 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.h +++ b/src/video_core/renderer_vulkan/vk_shader_util.h @@ -1,6 +1,5 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 5d5329abf..7fb256953 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <utility> @@ -27,20 +26,39 @@ using namespace Common::Literals; constexpr VkDeviceSize MAX_ALIGNMENT = 256; // Maximum size to put elements in the stream buffer constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB; -// Stream buffer size in bytes -constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB; -constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS; constexpr VkMemoryPropertyFlags HOST_FLAGS = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; constexpr VkMemoryPropertyFlags STREAM_FLAGS = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | HOST_FLAGS; -bool IsStreamHeap(VkMemoryHeap heap) noexcept { - return STREAM_BUFFER_SIZE < (heap.size * 2) / 3; +static bool IsStreamHeap(VkMemoryHeap heap, size_t staging_buffer_size) noexcept { + return staging_buffer_size < (heap.size * 2) / 3; +} + +static bool HasLargeDeviceLocalHostVisibleMemory(const VkPhysicalDeviceMemoryProperties& props) { + const auto flags{VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT}; + + for (u32 type_index = 0; type_index < props.memoryTypeCount; ++type_index) { + const auto& memory_type{props.memoryTypes[type_index]}; + + if ((memory_type.propertyFlags & flags) != flags) { + // Memory must be device local and host visible + continue; + } + + const auto& heap{props.memoryHeaps[memory_type.heapIndex]}; + if (heap.size >= 7168_MiB) { + // This is the right type of memory + return true; + } + } + + return false; } std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask, - VkMemoryPropertyFlags flags) noexcept { + VkMemoryPropertyFlags flags, + size_t staging_buffer_size) noexcept { for (u32 type_index = 0; type_index < props.memoryTypeCount; ++type_index) { if (((type_mask >> type_index) & 1) == 0) { // Memory type is incompatible @@ -51,7 +69,7 @@ std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& p // Memory type doesn't have the flags we want continue; } - if (!IsStreamHeap(props.memoryHeaps[memory_type.heapIndex])) { + if (!IsStreamHeap(props.memoryHeaps[memory_type.heapIndex], staging_buffer_size)) { // Memory heap is not suitable for streaming continue; } @@ -62,17 +80,17 @@ std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& p } u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask, - bool try_device_local) { + bool try_device_local, size_t staging_buffer_size) { std::optional<u32> type; if (try_device_local) { // Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this - type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS); + type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS, staging_buffer_size); if (type) { return *type; } } // Otherwise try without the DEVICE_LOCAL_BIT - type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS); + type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS, staging_buffer_size); if (type) { return *type; } @@ -80,20 +98,32 @@ u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_ throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); } -size_t Region(size_t iterator) noexcept { - return iterator / REGION_SIZE; +size_t Region(size_t iterator, size_t region_size) noexcept { + return iterator / region_size; } } // Anonymous namespace StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, - VKScheduler& scheduler_) + Scheduler& scheduler_) : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { + + const auto memory_properties{device.GetPhysical().GetMemoryProperties().memoryProperties}; + if (HasLargeDeviceLocalHostVisibleMemory(memory_properties)) { + // Possible on many integrated and newer discrete cards + staging_buffer_size = 1_GiB; + } else { + // Well-supported default size used by most Vulkan PC games + staging_buffer_size = 256_MiB; + } + + region_size = staging_buffer_size / StagingBufferPool::NUM_SYNCS; + const vk::Device& dev = device.GetLogical(); stream_buffer = dev.CreateBuffer(VkBufferCreateInfo{ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, - .size = STREAM_BUFFER_SIZE, + .size = staging_buffer_size, .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, @@ -118,19 +148,18 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem .image = nullptr, .buffer = *stream_buffer, }; - const auto memory_properties = device.GetPhysical().GetMemoryProperties(); VkMemoryAllocateInfo stream_memory_info{ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .pNext = make_dedicated ? &dedicated_info : nullptr, .allocationSize = requirements.size, - .memoryTypeIndex = - FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true), + .memoryTypeIndex = FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true, + staging_buffer_size), }; stream_memory = dev.TryAllocateMemory(stream_memory_info); if (!stream_memory) { LOG_INFO(Render_Vulkan, "Dynamic memory allocation failed, trying with system memory"); - stream_memory_info.memoryTypeIndex = - FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, false); + stream_memory_info.memoryTypeIndex = FindMemoryTypeIndex( + memory_properties, requirements.memoryTypeBits, false, staging_buffer_size); stream_memory = dev.AllocateMemory(stream_memory_info); } @@ -138,7 +167,7 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem stream_memory.SetObjectNameEXT("Stream Buffer Memory"); } stream_buffer.BindMemory(*stream_memory, 0); - stream_pointer = stream_memory.Map(0, STREAM_BUFFER_SIZE); + stream_pointer = stream_memory.Map(0, staging_buffer_size); } StagingBufferPool::~StagingBufferPool() = default; @@ -159,25 +188,25 @@ void StagingBufferPool::TickFrame() { } StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) { - if (AreRegionsActive(Region(free_iterator) + 1, - std::min(Region(iterator + size) + 1, NUM_SYNCS))) { + if (AreRegionsActive(Region(free_iterator, region_size) + 1, + std::min(Region(iterator + size, region_size) + 1, NUM_SYNCS))) { // Avoid waiting for the previous usages to be free return GetStagingBuffer(size, MemoryUsage::Upload); } const u64 current_tick = scheduler.CurrentTick(); - std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + Region(iterator), - current_tick); + std::fill(sync_ticks.begin() + Region(used_iterator, region_size), + sync_ticks.begin() + Region(iterator, region_size), current_tick); used_iterator = iterator; free_iterator = std::max(free_iterator, iterator + size); - if (iterator + size >= STREAM_BUFFER_SIZE) { - std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + NUM_SYNCS, - current_tick); + if (iterator + size >= staging_buffer_size) { + std::fill(sync_ticks.begin() + Region(used_iterator, region_size), + sync_ticks.begin() + NUM_SYNCS, current_tick); used_iterator = 0; iterator = 0; free_iterator = size; - if (AreRegionsActive(0, Region(size) + 1)) { + if (AreRegionsActive(0, Region(size, region_size) + 1)) { // Avoid waiting for the previous usages to be free return GetStagingBuffer(size, MemoryUsage::Upload); } @@ -264,7 +293,7 @@ StagingBufferPool::StagingBuffersCache& StagingBufferPool::GetCache(MemoryUsage case MemoryUsage::Download: return download_cache; default: - UNREACHABLE_MSG("Invalid memory usage={}", usage); + ASSERT_MSG(false, "Invalid memory usage={}", usage); return upload_cache; } } diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 69f7618de..90c67177f 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -15,7 +14,7 @@ namespace Vulkan { class Device; -class VKScheduler; +class Scheduler; struct StagingBufferRef { VkBuffer buffer; @@ -28,7 +27,7 @@ public: static constexpr size_t NUM_SYNCS = 16; explicit StagingBufferPool(const Device& device, MemoryAllocator& memory_allocator, - VKScheduler& scheduler); + Scheduler& scheduler); ~StagingBufferPool(); StagingBufferRef Request(size_t size, MemoryUsage usage); @@ -83,7 +82,7 @@ private: const Device& device; MemoryAllocator& memory_allocator; - VKScheduler& scheduler; + Scheduler& scheduler; vk::Buffer stream_buffer; vk::DeviceMemory stream_memory; @@ -94,6 +93,9 @@ private: size_t free_iterator = 0; std::array<u64, NUM_SYNCS> sync_ticks{}; + size_t staging_buffer_size = 0; + size_t region_size = 0; + StagingBuffersCache device_local_cache; StagingBuffersCache upload_cache; StagingBuffersCache download_cache; diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp index c00913f55..f234e1a31 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp +++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp @@ -1,17 +1,15 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> #include <cstddef> -#include <iterator> #include "common/common_types.h" #include "core/core.h" +#include "video_core/control/channel_state.h" #include "video_core/dirty_flags.h" #include "video_core/engines/maxwell_3d.h" -#include "video_core/gpu.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" #define OFF(field_name) MAXWELL3D_REG_INDEX(field_name) @@ -176,9 +174,8 @@ void SetupDirtyVertexBindings(Tables& tables) { } } // Anonymous namespace -StateTracker::StateTracker(Tegra::GPU& gpu) - : flags{gpu.Maxwell3D().dirty.flags}, invalidation_flags{MakeInvalidationFlags()} { - auto& tables{gpu.Maxwell3D().dirty.tables}; +void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) { + auto& tables{channel_state.maxwell_3d->dirty.tables}; SetupDirtyFlags(tables); SetupDirtyViewports(tables); SetupDirtyScissors(tables); @@ -201,4 +198,15 @@ StateTracker::StateTracker(Tegra::GPU& gpu) SetupDirtyVertexBindings(tables); } +void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) { + flags = &channel_state.maxwell_3d->dirty.flags; +} + +void StateTracker::InvalidateState() { + flags->set(); +} + +StateTracker::StateTracker() + : flags{&default_flags}, default_flags{}, invalidation_flags{MakeInvalidationFlags()} {} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h index 40a149832..2296dea60 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.h +++ b/src/video_core/renderer_vulkan/vk_state_tracker.h @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -8,10 +7,15 @@ #include <limits> #include "common/common_types.h" -#include "core/core.h" #include "video_core/dirty_flags.h" #include "video_core/engines/maxwell_3d.h" +namespace Tegra { +namespace Control { +struct ChannelState; +} +} // namespace Tegra + namespace Vulkan { namespace Dirty { @@ -55,19 +59,19 @@ class StateTracker { using Maxwell = Tegra::Engines::Maxwell3D::Regs; public: - explicit StateTracker(Tegra::GPU& gpu); + explicit StateTracker(); void InvalidateCommandBufferState() { - flags |= invalidation_flags; + (*flags) |= invalidation_flags; current_topology = INVALID_TOPOLOGY; } void InvalidateViewports() { - flags[Dirty::Viewports] = true; + (*flags)[Dirty::Viewports] = true; } void InvalidateScissors() { - flags[Dirty::Scissors] = true; + (*flags)[Dirty::Scissors] = true; } bool TouchViewports() { @@ -141,16 +145,23 @@ public: return has_changed; } + void SetupTables(Tegra::Control::ChannelState& channel_state); + + void ChangeChannel(Tegra::Control::ChannelState& channel_state); + + void InvalidateState(); + private: static constexpr auto INVALID_TOPOLOGY = static_cast<Maxwell::PrimitiveTopology>(~0u); bool Exchange(std::size_t id, bool new_value) const noexcept { - const bool is_dirty = flags[id]; - flags[id] = new_value; + const bool is_dirty = (*flags)[id]; + (*flags)[id] = new_value; return is_dirty; } - Tegra::Engines::Maxwell3D::DirtyState::Flags& flags; + Tegra::Engines::Maxwell3D::DirtyState::Flags* flags; + Tegra::Engines::Maxwell3D::DirtyState::Flags default_flags; Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags; Maxwell::PrimitiveTopology current_topology = INVALID_TOPOLOGY; }; diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 8972a6921..706d9ba74 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -1,17 +1,14 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> #include <limits> #include <vector> -#include "common/assert.h" #include "common/logging/log.h" #include "common/settings.h" #include "core/core.h" -#include "core/frontend/framebuffer_layout.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/vulkan_common/vulkan_device.h" @@ -36,12 +33,14 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats) } VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { - // Mailbox doesn't lock the application like fifo (vsync), prefer it + // Mailbox (triple buffering) doesn't lock the application like fifo (vsync), + // prefer it if vsync option is not selected const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); - if (found_mailbox != modes.end()) { + if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Borderless && + found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) { return VK_PRESENT_MODE_MAILBOX_KHR; } - if (Settings::values.disable_fps_limit.GetValue()) { + if (!Settings::values.use_speed_limit.GetValue()) { // FIFO present mode locks the framerate to the monitor's refresh rate, // Find an alternative to surpass this limitation if FPS is unlocked. const auto found_imm = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR); @@ -67,15 +66,15 @@ VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 wi } // Anonymous namespace -VKSwapchain::VKSwapchain(VkSurfaceKHR surface_, const Device& device_, VKScheduler& scheduler_, - u32 width, u32 height, bool srgb) +Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, u32 width, + u32 height, bool srgb) : surface{surface_}, device{device_}, scheduler{scheduler_} { Create(width, height, srgb); } -VKSwapchain::~VKSwapchain() = default; +Swapchain::~Swapchain() = default; -void VKSwapchain::Create(u32 width, u32 height, bool srgb) { +void Swapchain::Create(u32 width, u32 height, bool srgb) { is_outdated = false; is_suboptimal = false; @@ -96,7 +95,7 @@ void VKSwapchain::Create(u32 width, u32 height, bool srgb) { resource_ticks.resize(image_count); } -void VKSwapchain::AcquireNextImage() { +void Swapchain::AcquireNextImage() { const VkResult result = device.GetLogical().AcquireNextImageKHR( *swapchain, std::numeric_limits<u64>::max(), *present_semaphores[frame_index], VK_NULL_HANDLE, &image_index); @@ -117,7 +116,7 @@ void VKSwapchain::AcquireNextImage() { resource_ticks[image_index] = scheduler.CurrentTick(); } -void VKSwapchain::Present(VkSemaphore render_semaphore) { +void Swapchain::Present(VkSemaphore render_semaphore) { const auto present_queue{device.GetPresentQueue()}; const VkPresentInfoKHR present_info{ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, @@ -148,8 +147,8 @@ void VKSwapchain::Present(VkSemaphore render_semaphore) { } } -void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, - u32 height, bool srgb) { +void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height, + bool srgb) { const auto physical_device{device.GetPhysical()}; const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)}; @@ -158,8 +157,16 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, present_mode = ChooseSwapPresentMode(present_modes); u32 requested_image_count{capabilities.minImageCount + 1}; - if (capabilities.maxImageCount > 0 && requested_image_count > capabilities.maxImageCount) { - requested_image_count = capabilities.maxImageCount; + // Ensure Tripple buffering if possible. + if (capabilities.maxImageCount > 0) { + if (requested_image_count > capabilities.maxImageCount) { + requested_image_count = capabilities.maxImageCount; + } else { + requested_image_count = + std::max(requested_image_count, std::min(3U, capabilities.maxImageCount)); + } + } else { + requested_image_count = std::max(requested_image_count, 3U); } VkSwapchainCreateInfoKHR swapchain_ci{ .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, @@ -208,20 +215,20 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, extent = swapchain_ci.imageExtent; current_srgb = srgb; - current_fps_unlocked = Settings::values.disable_fps_limit.GetValue(); + current_fps_unlocked = !Settings::values.use_speed_limit.GetValue(); images = swapchain.GetImages(); image_count = static_cast<u32>(images.size()); image_view_format = srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; } -void VKSwapchain::CreateSemaphores() { +void Swapchain::CreateSemaphores() { present_semaphores.resize(image_count); std::ranges::generate(present_semaphores, [this] { return device.GetLogical().CreateSemaphore(); }); } -void VKSwapchain::CreateImageViews() { +void Swapchain::CreateImageViews() { VkImageViewCreateInfo ci{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = nullptr, @@ -253,7 +260,7 @@ void VKSwapchain::CreateImageViews() { } } -void VKSwapchain::Destroy() { +void Swapchain::Destroy() { frame_index = 0; present_semaphores.clear(); framebuffers.clear(); @@ -261,11 +268,11 @@ void VKSwapchain::Destroy() { swapchain.reset(); } -bool VKSwapchain::HasFpsUnlockChanged() const { - return current_fps_unlocked != Settings::values.disable_fps_limit.GetValue(); +bool Swapchain::HasFpsUnlockChanged() const { + return current_fps_unlocked != !Settings::values.use_speed_limit.GetValue(); } -bool VKSwapchain::NeedsPresentModeUpdate() const { +bool Swapchain::NeedsPresentModeUpdate() const { // Mailbox present mode is the ideal for all scenarios. If it is not available, // A different present mode is needed to support unlocked FPS above the monitor's refresh rate. return present_mode != VK_PRESENT_MODE_MAILBOX_KHR && HasFpsUnlockChanged(); diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index 61a6d959e..111b3902d 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -16,13 +15,13 @@ struct FramebufferLayout; namespace Vulkan { class Device; -class VKScheduler; +class Scheduler; -class VKSwapchain { +class Swapchain { public: - explicit VKSwapchain(VkSurfaceKHR surface, const Device& device, VKScheduler& scheduler, - u32 width, u32 height, bool srgb); - ~VKSwapchain(); + explicit Swapchain(VkSurfaceKHR surface, const Device& device, Scheduler& scheduler, u32 width, + u32 height, bool srgb); + ~Swapchain(); /// Creates (or recreates) the swapchain with a given size. void Create(u32 width, u32 height, bool srgb); @@ -95,7 +94,7 @@ private: const VkSurfaceKHR surface; const Device& device; - VKScheduler& scheduler; + Scheduler& scheduler; vk::SwapchainKHR swapchain; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 0ba56ff1e..305ad8aee 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> @@ -71,7 +70,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { case ImageType::Buffer: break; } - UNREACHABLE_MSG("Invalid image type={}", type); + ASSERT_MSG(false, "Invalid image type={}", type); return {}; } @@ -88,7 +87,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { case 16: return VK_SAMPLE_COUNT_16_BIT; default: - UNREACHABLE_MSG("Invalid number of samples={}", num_samples); + ASSERT_MSG(false, "Invalid number of samples={}", num_samples); return VK_SAMPLE_COUNT_1_BIT; } } @@ -108,7 +107,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; break; default: - UNREACHABLE_MSG("Invalid surface type"); + ASSERT_MSG(false, "Invalid surface type"); } } if (info.storage) { @@ -180,7 +179,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { case VideoCore::Surface::SurfaceType::DepthStencil: return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; default: - UNREACHABLE_MSG("Invalid surface type"); + ASSERT_MSG(false, "Invalid surface type"); return VkImageAspectFlags{}; } } @@ -222,7 +221,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { case SwizzleSource::OneInt: return VK_COMPONENT_SWIZZLE_ONE; } - UNREACHABLE_MSG("Invalid swizzle={}", swizzle); + ASSERT_MSG(false, "Invalid swizzle={}", swizzle); return VK_COMPONENT_SWIZZLE_ZERO; } @@ -231,6 +230,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { case Shader::TextureType::Color1D: return VK_IMAGE_VIEW_TYPE_1D; case Shader::TextureType::Color2D: + case Shader::TextureType::Color2DRect: return VK_IMAGE_VIEW_TYPE_2D; case Shader::TextureType::ColorCube: return VK_IMAGE_VIEW_TYPE_CUBE; @@ -243,10 +243,10 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { case Shader::TextureType::ColorArrayCube: return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; case Shader::TextureType::Buffer: - UNREACHABLE_MSG("Texture buffers can't be image views"); + ASSERT_MSG(false, "Texture buffers can't be image views"); return VK_IMAGE_VIEW_TYPE_1D; } - UNREACHABLE_MSG("Invalid image view type={}", type); + ASSERT_MSG(false, "Invalid image view type={}", type); return VK_IMAGE_VIEW_TYPE_2D; } @@ -255,6 +255,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { case VideoCommon::ImageViewType::e1D: return VK_IMAGE_VIEW_TYPE_1D; case VideoCommon::ImageViewType::e2D: + case VideoCommon::ImageViewType::Rect: return VK_IMAGE_VIEW_TYPE_2D; case VideoCommon::ImageViewType::Cube: return VK_IMAGE_VIEW_TYPE_CUBE; @@ -266,14 +267,11 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { return VK_IMAGE_VIEW_TYPE_2D_ARRAY; case VideoCommon::ImageViewType::CubeArray: return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; - case VideoCommon::ImageViewType::Rect: - UNIMPLEMENTED_MSG("Rect image view"); - return VK_IMAGE_VIEW_TYPE_2D; case VideoCommon::ImageViewType::Buffer: - UNREACHABLE_MSG("Texture buffers can't be image views"); + ASSERT_MSG(false, "Texture buffers can't be image views"); return VK_IMAGE_VIEW_TYPE_1D; } - UNREACHABLE_MSG("Invalid image view type={}", type); + ASSERT_MSG(false, "Invalid image view type={}", type); return VK_IMAGE_VIEW_TYPE_2D; } @@ -438,6 +436,32 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { } } +[[nodiscard]] SwizzleSource SwapGreenRed(SwizzleSource value) { + switch (value) { + case SwizzleSource::R: + return SwizzleSource::G; + case SwizzleSource::G: + return SwizzleSource::R; + default: + return value; + } +} + +[[nodiscard]] SwizzleSource SwapSpecial(SwizzleSource value) { + switch (value) { + case SwizzleSource::A: + return SwizzleSource::R; + case SwizzleSource::R: + return SwizzleSource::A; + case SwizzleSource::G: + return SwizzleSource::B; + case SwizzleSource::B: + return SwizzleSource::G; + default: + return value; + } +} + void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage image, VkImageAspectFlags aspect_mask, bool is_initialized, std::span<const VkBufferImageCopy> copies) { @@ -554,12 +578,25 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im }; } -[[nodiscard]] bool IsFormatFlipped(PixelFormat format) { +void TryTransformSwizzleIfNeeded(PixelFormat format, std::array<SwizzleSource, 4>& swizzle, + bool emulate_bgr565) { switch (format) { case PixelFormat::A1B5G5R5_UNORM: - return true; + std::ranges::transform(swizzle, swizzle.begin(), SwapBlueRed); + break; + case PixelFormat::B5G6R5_UNORM: + if (emulate_bgr565) { + std::ranges::transform(swizzle, swizzle.begin(), SwapBlueRed); + } + break; + case PixelFormat::A5B5G5R1_UNORM: + std::ranges::transform(swizzle, swizzle.begin(), SwapSpecial); + break; + case PixelFormat::G4R4_UNORM: + std::ranges::transform(swizzle, swizzle.begin(), SwapGreenRed); + break; default: - return false; + break; } } @@ -606,11 +643,11 @@ struct RangedBarrierRange { case Shader::ImageFormat::R32G32B32A32_UINT: return VK_FORMAT_R32G32B32A32_UINT; } - UNREACHABLE_MSG("Invalid image format={}", format); + ASSERT_MSG(false, "Invalid image format={}", format); return VK_FORMAT_R32_UINT; } -void BlitScale(VKScheduler& scheduler, VkImage src_image, VkImage dst_image, const ImageInfo& info, +void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const ImageInfo& info, VkImageAspectFlags aspect_mask, const Settings::ResolutionScalingInfo& resolution, bool up_scaling = true) { const bool is_2d = info.type == ImageType::e2D; @@ -750,7 +787,7 @@ void BlitScale(VKScheduler& scheduler, VkImage src_image, VkImage dst_image, con } } // Anonymous namespace -TextureCacheRuntime::TextureCacheRuntime(const Device& device_, VKScheduler& scheduler_, +TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& scheduler_, MemoryAllocator& memory_allocator_, StagingBufferPool& staging_buffer_pool_, BlitImageHelper& blit_image_helper_, @@ -779,11 +816,6 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) { !device.IsExtShaderStencilExportSupported()) { return true; } - if (VideoCore::Surface::GetFormatType(src.info.format) == - VideoCore::Surface::SurfaceType::DepthStencil && - !device.IsExtShaderStencilExportSupported()) { - return true; - } if (dst.info.format == PixelFormat::D32_FLOAT_S8_UINT || src.info.format == PixelFormat::D32_FLOAT_S8_UINT) { return true; @@ -1068,6 +1100,9 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view); } + if (src_view.format == PixelFormat::D24_UNORM_S8_UINT) { + return blit_image_helper.ConvertS8D24ToABGR8(dst, src_view); + } break; case PixelFormat::R32_FLOAT: if (src_view.format == PixelFormat::D32_FLOAT) { @@ -1189,6 +1224,14 @@ u64 TextureCacheRuntime::GetDeviceLocalMemory() const { return device.GetDeviceLocalMemory(); } +u64 TextureCacheRuntime::GetDeviceMemoryUsage() const { + return device.GetDeviceMemoryUsage(); +} + +bool TextureCacheRuntime::CanReportMemoryUsage() const { + return device.CanReportMemoryUsage(); +} + void TextureCacheRuntime::TickFrame() {} Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_, @@ -1203,6 +1246,7 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu } else { flags |= VideoCommon::ImageFlagBits::Converted; } + flags |= VideoCommon::ImageFlagBits::CostlyLoad; } if (runtime->device.HasDebuggingToolAttached()) { original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); @@ -1430,22 +1474,23 @@ bool Image::BlitScaleHelper(bool scale_up) { }; const VkExtent2D extent{ .width = std::max(scaled_width, info.size.width), - .height = std::max(scaled_height, info.size.width), + .height = std::max(scaled_height, info.size.height), }; auto* view_ptr = blit_view.get(); if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) { if (!blit_framebuffer) { - blit_framebuffer = std::make_unique<Framebuffer>(*runtime, view_ptr, nullptr, extent); + blit_framebuffer = + std::make_unique<Framebuffer>(*runtime, view_ptr, nullptr, extent, scale_up); } const auto color_view = blit_view->Handle(Shader::TextureType::Color2D); runtime->blit_image_helper.BlitColor(blit_framebuffer.get(), color_view, dst_region, src_region, operation, BLIT_OPERATION); - } else if (!runtime->device.IsBlitDepthStencilSupported() && - aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + } 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); + blit_framebuffer = + std::make_unique<Framebuffer>(*runtime, nullptr, view_ptr, extent, scale_up); } runtime->blit_image_helper.BlitDepthStencil(blit_framebuffer.get(), blit_view->DepthView(), blit_view->StencilView(), dst_region, @@ -1488,9 +1533,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI }; if (!info.IsRenderTarget()) { swizzle = info.Swizzle(); - if (IsFormatFlipped(format)) { - std::ranges::transform(swizzle, swizzle.begin(), SwapBlueRed); - } + TryTransformSwizzleIfNeeded(format, swizzle, device->MustEmulateBGR565()); if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed); } @@ -1537,6 +1580,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI break; case VideoCommon::ImageViewType::e2D: case VideoCommon::ImageViewType::e2DArray: + case VideoCommon::ImageViewType::Rect: create(TextureType::Color2D, 1); create(TextureType::ColorArray2D, std::nullopt); render_target = Handle(Shader::TextureType::ColorArray2D); @@ -1550,11 +1594,8 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI create(TextureType::ColorCube, 6); create(TextureType::ColorArrayCube, std::nullopt); break; - case VideoCommon::ImageViewType::Rect: - UNIMPLEMENTED(); - break; case VideoCommon::ImageViewType::Buffer: - UNREACHABLE(); + ASSERT(false); break; } } @@ -1576,6 +1617,9 @@ ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParam ImageView::~ImageView() = default; VkImageView ImageView::DepthView() { + if (!image_handle) { + return VK_NULL_HANDLE; + } if (depth_view) { return *depth_view; } @@ -1585,6 +1629,9 @@ VkImageView ImageView::DepthView() { } VkImageView ImageView::StencilView() { + if (!image_handle) { + return VK_NULL_HANDLE; + } if (stencil_view) { return *stencil_view; } @@ -1594,6 +1641,9 @@ VkImageView ImageView::StencilView() { } VkImageView ImageView::ColorView() { + if (!image_handle) { + return VK_NULL_HANDLE; + } if (color_view) { return *color_view; } @@ -1603,6 +1653,9 @@ VkImageView ImageView::ColorView() { VkImageView ImageView::StorageView(Shader::TextureType texture_type, Shader::ImageFormat image_format) { + if (!image_handle) { + return VK_NULL_HANDLE; + } if (image_format == Shader::ImageFormat::Typeless) { return Handle(texture_type); } @@ -1705,34 +1758,42 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM .width = key.size.width, .height = key.size.height, }} { - CreateFramebuffer(runtime, color_buffers, depth_buffer); + CreateFramebuffer(runtime, color_buffers, depth_buffer, key.is_rescaled); if (runtime.device.HasDebuggingToolAttached()) { framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str()); } } Framebuffer::Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer, - ImageView* depth_buffer, VkExtent2D extent) + ImageView* depth_buffer, VkExtent2D extent, bool is_rescaled) : render_area{extent} { std::array<ImageView*, NUM_RT> color_buffers{color_buffer}; - CreateFramebuffer(runtime, color_buffers, depth_buffer); + CreateFramebuffer(runtime, color_buffers, depth_buffer, is_rescaled); } Framebuffer::~Framebuffer() = default; void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers, - ImageView* depth_buffer) { + ImageView* depth_buffer, bool is_rescaled) { std::vector<VkImageView> attachments; RenderPassKey renderpass_key{}; s32 num_layers = 1; + const auto& resolution = runtime.resolution; + + u32 width = 0; + u32 height = 0; for (size_t index = 0; index < NUM_RT; ++index) { const ImageView* const color_buffer = color_buffers[index]; if (!color_buffer) { renderpass_key.color_formats[index] = PixelFormat::Invalid; continue; } + width = std::max(width, is_rescaled ? resolution.ScaleUp(color_buffer->size.width) + : color_buffer->size.width); + height = std::max(height, is_rescaled ? resolution.ScaleUp(color_buffer->size.height) + : color_buffer->size.height); attachments.push_back(color_buffer->RenderTarget()); renderpass_key.color_formats[index] = color_buffer->format; num_layers = std::max(num_layers, color_buffer->range.extent.layers); @@ -1743,6 +1804,10 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, } const size_t num_colors = attachments.size(); if (depth_buffer) { + width = std::max(width, is_rescaled ? resolution.ScaleUp(depth_buffer->size.width) + : depth_buffer->size.width); + height = std::max(height, is_rescaled ? resolution.ScaleUp(depth_buffer->size.height) + : depth_buffer->size.height); attachments.push_back(depth_buffer->RenderTarget()); renderpass_key.depth_format = depth_buffer->format; num_layers = std::max(num_layers, depth_buffer->range.extent.layers); @@ -1759,6 +1824,8 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, renderpass_key.samples = samples; renderpass = runtime.render_pass_cache.Get(renderpass_key); + render_area.width = std::min(render_area.width, width); + render_area.height = std::min(render_area.height, height); num_color_buffers = static_cast<u32>(num_colors); framebuffer = runtime.device.GetLogical().CreateFramebuffer({ @@ -1780,7 +1847,7 @@ void TextureCacheRuntime::AccelerateImageUpload( if (IsPixelFormatASTC(image.info.format)) { return astc_decoder_pass.Assemble(image, map, swizzles); } - UNREACHABLE(); + ASSERT(false); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index c81130dd2..0b7ac0df1 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -34,11 +33,11 @@ class ImageView; class Framebuffer; class RenderPassCache; class StagingBufferPool; -class VKScheduler; +class Scheduler; class TextureCacheRuntime { public: - explicit TextureCacheRuntime(const Device& device_, VKScheduler& scheduler_, + explicit TextureCacheRuntime(const Device& device_, Scheduler& scheduler_, MemoryAllocator& memory_allocator_, StagingBufferPool& staging_buffer_pool_, BlitImageHelper& blit_image_helper_, @@ -55,6 +54,10 @@ public: u64 GetDeviceLocalMemory() const; + u64 GetDeviceMemoryUsage() const; + + bool CanReportMemoryUsage() const; + void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, @@ -90,7 +93,7 @@ public: [[nodiscard]] VkBuffer GetTemporaryBuffer(size_t needed_size); const Device& device; - VKScheduler& scheduler; + Scheduler& scheduler; MemoryAllocator& memory_allocator; StagingBufferPool& staging_buffer_pool; BlitImageHelper& blit_image_helper; @@ -151,7 +154,7 @@ private: bool NeedsScaleHelper() const; - VKScheduler* scheduler{}; + Scheduler* scheduler{}; TextureCacheRuntime* runtime{}; vk::Image original_image; @@ -265,7 +268,7 @@ public: ImageView* depth_buffer, const VideoCommon::RenderTargets& key); explicit Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer, - ImageView* depth_buffer, VkExtent2D extent); + ImageView* depth_buffer, VkExtent2D extent, bool is_rescaled); ~Framebuffer(); @@ -276,7 +279,8 @@ public: Framebuffer& operator=(Framebuffer&&) = default; void CreateFramebuffer(TextureCacheRuntime& runtime, - std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer); + std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer, + bool is_rescaled = false); [[nodiscard]] VkFramebuffer Handle() const noexcept { return *framebuffer; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache_base.cpp b/src/video_core/renderer_vulkan/vk_texture_cache_base.cpp index 44e688342..7e1c3a863 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache_base.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache_base.cpp @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/texture_cache/texture_cache.h" diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp index 0df3a7fe9..4d4a6753b 100644 --- a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp +++ b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp @@ -1,11 +1,9 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <variant> #include <boost/container/static_vector.hpp> -#include "common/assert.h" #include "common/logging/log.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" @@ -14,18 +12,18 @@ namespace Vulkan { -VKUpdateDescriptorQueue::VKUpdateDescriptorQueue(const Device& device_, VKScheduler& scheduler_) +UpdateDescriptorQueue::UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_) : device{device_}, scheduler{scheduler_} { payload_cursor = payload.data(); } -VKUpdateDescriptorQueue::~VKUpdateDescriptorQueue() = default; +UpdateDescriptorQueue::~UpdateDescriptorQueue() = default; -void VKUpdateDescriptorQueue::TickFrame() { +void UpdateDescriptorQueue::TickFrame() { payload_cursor = payload.data(); } -void VKUpdateDescriptorQueue::Acquire() { +void UpdateDescriptorQueue::Acquire() { // Minimum number of entries required. // This is the maximum number of entries a single draw call migth use. static constexpr size_t MIN_ENTRIES = 0x400; diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h index d7de4c490..625bcc809 100644 --- a/src/video_core/renderer_vulkan/vk_update_descriptor.h +++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h @@ -1,18 +1,16 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include <array> -#include "common/common_types.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { class Device; -class VKScheduler; +class Scheduler; struct DescriptorUpdateEntry { struct Empty {}; @@ -30,10 +28,10 @@ struct DescriptorUpdateEntry { }; }; -class VKUpdateDescriptorQueue final { +class UpdateDescriptorQueue final { public: - explicit VKUpdateDescriptorQueue(const Device& device_, VKScheduler& scheduler_); - ~VKUpdateDescriptorQueue(); + explicit UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_); + ~UpdateDescriptorQueue(); void TickFrame(); @@ -73,7 +71,7 @@ public: private: const Device& device; - VKScheduler& scheduler; + Scheduler& scheduler; DescriptorUpdateEntry* payload_cursor = nullptr; const DescriptorUpdateEntry* upload_start = nullptr; |