diff options
54 files changed, 847 insertions, 885 deletions
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index eb54cb123..6b1613510 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -774,6 +774,17 @@ void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) { | |||
| 774 | rb.Push(RESULT_SUCCESS); | 774 | rb.Push(RESULT_SUCCESS); |
| 775 | } | 775 | } |
| 776 | 776 | ||
| 777 | void Module::Interface::LoadOpenContext(Kernel::HLERequestContext& ctx) { | ||
| 778 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||
| 779 | |||
| 780 | // This is similar to GetBaasAccountManagerForApplication | ||
| 781 | // This command is used concurrently with ListOpenContextStoredUsers | ||
| 782 | // TODO: Find the differences between this and GetBaasAccountManagerForApplication | ||
| 783 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 784 | rb.Push(RESULT_SUCCESS); | ||
| 785 | rb.PushIpcInterface<IManagerForApplication>(profile_manager->GetLastOpenedUser()); | ||
| 786 | } | ||
| 787 | |||
| 777 | void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) { | 788 | void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) { |
| 778 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | 789 | LOG_WARNING(Service_ACC, "(STUBBED) called"); |
| 779 | 790 | ||
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index d4c6395c6..c611efd89 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h | |||
| @@ -34,6 +34,7 @@ public: | |||
| 34 | void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx); | 34 | void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx); |
| 35 | void GetProfileEditor(Kernel::HLERequestContext& ctx); | 35 | void GetProfileEditor(Kernel::HLERequestContext& ctx); |
| 36 | void ListQualifiedUsers(Kernel::HLERequestContext& ctx); | 36 | void ListQualifiedUsers(Kernel::HLERequestContext& ctx); |
| 37 | void LoadOpenContext(Kernel::HLERequestContext& ctx); | ||
| 37 | void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx); | 38 | void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx); |
| 38 | 39 | ||
| 39 | private: | 40 | private: |
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index cb44e06b7..75a24f8f5 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp | |||
| @@ -29,7 +29,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 29 | {110, nullptr, "StoreSaveDataThumbnail"}, | 29 | {110, nullptr, "StoreSaveDataThumbnail"}, |
| 30 | {111, nullptr, "ClearSaveDataThumbnail"}, | 30 | {111, nullptr, "ClearSaveDataThumbnail"}, |
| 31 | {120, nullptr, "CreateGuestLoginRequest"}, | 31 | {120, nullptr, "CreateGuestLoginRequest"}, |
| 32 | {130, nullptr, "LoadOpenContext"}, // 5.0.0+ | 32 | {130, &ACC_U0::LoadOpenContext, "LoadOpenContext"}, // 5.0.0+ |
| 33 | {131, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 6.0.0+ | 33 | {131, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 6.0.0+ |
| 34 | {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+ | 34 | {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+ |
| 35 | {141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ | 35 | {141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 86d17c6cb..c3f4829d7 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -567,7 +567,7 @@ struct Memory::Impl { | |||
| 567 | * @param page_table The page table to use to perform the mapping. | 567 | * @param page_table The page table to use to perform the mapping. |
| 568 | * @param base The base address to begin mapping at. | 568 | * @param base The base address to begin mapping at. |
| 569 | * @param size The total size of the range in bytes. | 569 | * @param size The total size of the range in bytes. |
| 570 | * @param memory The memory to map. | 570 | * @param target The target address to begin mapping from. |
| 571 | * @param type The page type to map the memory as. | 571 | * @param type The page type to map the memory as. |
| 572 | */ | 572 | */ |
| 573 | void MapPages(Common::PageTable& page_table, VAddr base, u64 size, PAddr target, | 573 | void MapPages(Common::PageTable& page_table, VAddr base, u64 size, PAddr target, |
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index c507c9891..89c148aba 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp | |||
| @@ -15,7 +15,9 @@ | |||
| 15 | #endif | 15 | #endif |
| 16 | 16 | ||
| 17 | #include "common/logging/log.h" | 17 | #include "common/logging/log.h" |
| 18 | #include "common/param_package.h" | ||
| 18 | #include "input_common/gcadapter/gc_adapter.h" | 19 | #include "input_common/gcadapter/gc_adapter.h" |
| 20 | #include "input_common/settings.h" | ||
| 19 | 21 | ||
| 20 | namespace GCAdapter { | 22 | namespace GCAdapter { |
| 21 | 23 | ||
| @@ -292,6 +294,92 @@ void Adapter::Reset() { | |||
| 292 | } | 294 | } |
| 293 | } | 295 | } |
| 294 | 296 | ||
| 297 | std::vector<Common::ParamPackage> Adapter::GetInputDevices() const { | ||
| 298 | std::vector<Common::ParamPackage> devices; | ||
| 299 | for (std::size_t port = 0; port < state.size(); ++port) { | ||
| 300 | if (!DeviceConnected(port)) { | ||
| 301 | continue; | ||
| 302 | } | ||
| 303 | std::string name = fmt::format("Gamecube Controller {}", port); | ||
| 304 | devices.emplace_back(Common::ParamPackage{ | ||
| 305 | {"class", "gcpad"}, | ||
| 306 | {"display", std::move(name)}, | ||
| 307 | {"port", std::to_string(port)}, | ||
| 308 | }); | ||
| 309 | } | ||
| 310 | return devices; | ||
| 311 | } | ||
| 312 | |||
| 313 | InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice( | ||
| 314 | const Common::ParamPackage& params) const { | ||
| 315 | // This list is missing ZL/ZR since those are not considered buttons. | ||
| 316 | // We will add those afterwards | ||
| 317 | // This list also excludes any button that can't be really mapped | ||
| 318 | static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 12> | ||
| 319 | switch_to_gcadapter_button = { | ||
| 320 | std::pair{Settings::NativeButton::A, PadButton::PAD_BUTTON_A}, | ||
| 321 | {Settings::NativeButton::B, PadButton::PAD_BUTTON_B}, | ||
| 322 | {Settings::NativeButton::X, PadButton::PAD_BUTTON_X}, | ||
| 323 | {Settings::NativeButton::Y, PadButton::PAD_BUTTON_Y}, | ||
| 324 | {Settings::NativeButton::Plus, PadButton::PAD_BUTTON_START}, | ||
| 325 | {Settings::NativeButton::DLeft, PadButton::PAD_BUTTON_LEFT}, | ||
| 326 | {Settings::NativeButton::DUp, PadButton::PAD_BUTTON_UP}, | ||
| 327 | {Settings::NativeButton::DRight, PadButton::PAD_BUTTON_RIGHT}, | ||
| 328 | {Settings::NativeButton::DDown, PadButton::PAD_BUTTON_DOWN}, | ||
| 329 | {Settings::NativeButton::SL, PadButton::PAD_TRIGGER_L}, | ||
| 330 | {Settings::NativeButton::SR, PadButton::PAD_TRIGGER_R}, | ||
| 331 | {Settings::NativeButton::R, PadButton::PAD_TRIGGER_Z}, | ||
| 332 | }; | ||
| 333 | if (!params.Has("port")) { | ||
| 334 | return {}; | ||
| 335 | } | ||
| 336 | |||
| 337 | InputCommon::ButtonMapping mapping{}; | ||
| 338 | for (const auto& [switch_button, gcadapter_button] : switch_to_gcadapter_button) { | ||
| 339 | Common::ParamPackage button_params({{"engine", "gcpad"}}); | ||
| 340 | button_params.Set("port", params.Get("port", 0)); | ||
| 341 | button_params.Set("button", static_cast<int>(gcadapter_button)); | ||
| 342 | mapping.insert_or_assign(switch_button, std::move(button_params)); | ||
| 343 | } | ||
| 344 | |||
| 345 | // Add the missing bindings for ZL/ZR | ||
| 346 | static constexpr std::array<std::pair<Settings::NativeButton::Values, PadAxes>, 2> | ||
| 347 | switch_to_gcadapter_axis = { | ||
| 348 | std::pair{Settings::NativeButton::ZL, PadAxes::TriggerLeft}, | ||
| 349 | {Settings::NativeButton::ZR, PadAxes::TriggerRight}, | ||
| 350 | }; | ||
| 351 | for (const auto& [switch_button, gcadapter_axis] : switch_to_gcadapter_axis) { | ||
| 352 | Common::ParamPackage button_params({{"engine", "gcpad"}}); | ||
| 353 | button_params.Set("port", params.Get("port", 0)); | ||
| 354 | button_params.Set("button", static_cast<int>(PadButton::PAD_STICK)); | ||
| 355 | button_params.Set("axis", static_cast<int>(gcadapter_axis)); | ||
| 356 | mapping.insert_or_assign(switch_button, std::move(button_params)); | ||
| 357 | } | ||
| 358 | return mapping; | ||
| 359 | } | ||
| 360 | |||
| 361 | InputCommon::AnalogMapping Adapter::GetAnalogMappingForDevice( | ||
| 362 | const Common::ParamPackage& params) const { | ||
| 363 | if (!params.Has("port")) { | ||
| 364 | return {}; | ||
| 365 | } | ||
| 366 | |||
| 367 | InputCommon::AnalogMapping mapping = {}; | ||
| 368 | Common::ParamPackage left_analog_params; | ||
| 369 | left_analog_params.Set("engine", "gcpad"); | ||
| 370 | left_analog_params.Set("port", params.Get("port", 0)); | ||
| 371 | left_analog_params.Set("axis_x", static_cast<int>(PadAxes::StickX)); | ||
| 372 | left_analog_params.Set("axis_y", static_cast<int>(PadAxes::StickY)); | ||
| 373 | mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params)); | ||
| 374 | Common::ParamPackage right_analog_params; | ||
| 375 | right_analog_params.Set("engine", "gcpad"); | ||
| 376 | right_analog_params.Set("port", params.Get("port", 0)); | ||
| 377 | right_analog_params.Set("axis_x", static_cast<int>(PadAxes::SubstickX)); | ||
| 378 | right_analog_params.Set("axis_y", static_cast<int>(PadAxes::SubstickY)); | ||
| 379 | mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params)); | ||
| 380 | return mapping; | ||
| 381 | } | ||
| 382 | |||
| 295 | bool Adapter::DeviceConnected(std::size_t port) const { | 383 | bool Adapter::DeviceConnected(std::size_t port) const { |
| 296 | return adapter_controllers_status[port] != ControllerTypes::None; | 384 | return adapter_controllers_status[port] != ControllerTypes::None; |
| 297 | } | 385 | } |
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index 20e97d283..75bf9fe74 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <unordered_map> | 10 | #include <unordered_map> |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "common/threadsafe_queue.h" | 12 | #include "common/threadsafe_queue.h" |
| 13 | #include "input_common/main.h" | ||
| 13 | 14 | ||
| 14 | struct libusb_context; | 15 | struct libusb_context; |
| 15 | struct libusb_device; | 16 | struct libusb_device; |
| @@ -75,6 +76,10 @@ public: | |||
| 75 | void BeginConfiguration(); | 76 | void BeginConfiguration(); |
| 76 | void EndConfiguration(); | 77 | void EndConfiguration(); |
| 77 | 78 | ||
| 79 | std::vector<Common::ParamPackage> GetInputDevices() const; | ||
| 80 | InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const; | ||
| 81 | InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const; | ||
| 82 | |||
| 78 | /// Returns true if there is a device connected to port | 83 | /// Returns true if there is a device connected to port |
| 79 | bool DeviceConnected(std::size_t port) const; | 84 | bool DeviceConnected(std::size_t port) const; |
| 80 | 85 | ||
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 062ec66b5..8da829132 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -22,7 +22,7 @@ namespace InputCommon { | |||
| 22 | 22 | ||
| 23 | struct InputSubsystem::Impl { | 23 | struct InputSubsystem::Impl { |
| 24 | void Initialize() { | 24 | void Initialize() { |
| 25 | auto gcadapter = std::make_shared<GCAdapter::Adapter>(); | 25 | gcadapter = std::make_shared<GCAdapter::Adapter>(); |
| 26 | gcbuttons = std::make_shared<GCButtonFactory>(gcadapter); | 26 | gcbuttons = std::make_shared<GCButtonFactory>(gcadapter); |
| 27 | Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons); | 27 | Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons); |
| 28 | gcanalog = std::make_shared<GCAnalogFactory>(gcadapter); | 28 | gcanalog = std::make_shared<GCAnalogFactory>(gcadapter); |
| @@ -82,6 +82,8 @@ struct InputSubsystem::Impl { | |||
| 82 | #endif | 82 | #endif |
| 83 | auto udp_devices = udp->GetInputDevices(); | 83 | auto udp_devices = udp->GetInputDevices(); |
| 84 | devices.insert(devices.end(), udp_devices.begin(), udp_devices.end()); | 84 | devices.insert(devices.end(), udp_devices.begin(), udp_devices.end()); |
| 85 | auto gcpad_devices = gcadapter->GetInputDevices(); | ||
| 86 | devices.insert(devices.end(), gcpad_devices.begin(), gcpad_devices.end()); | ||
| 85 | return devices; | 87 | return devices; |
| 86 | } | 88 | } |
| 87 | 89 | ||
| @@ -94,6 +96,9 @@ struct InputSubsystem::Impl { | |||
| 94 | // TODO consider returning the SDL key codes for the default keybindings | 96 | // TODO consider returning the SDL key codes for the default keybindings |
| 95 | return {}; | 97 | return {}; |
| 96 | } | 98 | } |
| 99 | if (params.Get("class", "") == "gcpad") { | ||
| 100 | return gcadapter->GetAnalogMappingForDevice(params); | ||
| 101 | } | ||
| 97 | #ifdef HAVE_SDL2 | 102 | #ifdef HAVE_SDL2 |
| 98 | if (params.Get("class", "") == "sdl") { | 103 | if (params.Get("class", "") == "sdl") { |
| 99 | return sdl->GetAnalogMappingForDevice(params); | 104 | return sdl->GetAnalogMappingForDevice(params); |
| @@ -111,6 +116,9 @@ struct InputSubsystem::Impl { | |||
| 111 | // TODO consider returning the SDL key codes for the default keybindings | 116 | // TODO consider returning the SDL key codes for the default keybindings |
| 112 | return {}; | 117 | return {}; |
| 113 | } | 118 | } |
| 119 | if (params.Get("class", "") == "gcpad") { | ||
| 120 | return gcadapter->GetButtonMappingForDevice(params); | ||
| 121 | } | ||
| 114 | #ifdef HAVE_SDL2 | 122 | #ifdef HAVE_SDL2 |
| 115 | if (params.Get("class", "") == "sdl") { | 123 | if (params.Get("class", "") == "sdl") { |
| 116 | return sdl->GetButtonMappingForDevice(params); | 124 | return sdl->GetButtonMappingForDevice(params); |
| @@ -141,6 +149,7 @@ struct InputSubsystem::Impl { | |||
| 141 | std::shared_ptr<UDPMotionFactory> udpmotion; | 149 | std::shared_ptr<UDPMotionFactory> udpmotion; |
| 142 | std::shared_ptr<UDPTouchFactory> udptouch; | 150 | std::shared_ptr<UDPTouchFactory> udptouch; |
| 143 | std::shared_ptr<CemuhookUDP::Client> udp; | 151 | std::shared_ptr<CemuhookUDP::Client> udp; |
| 152 | std::shared_ptr<GCAdapter::Adapter> gcadapter; | ||
| 144 | }; | 153 | }; |
| 145 | 154 | ||
| 146 | InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {} | 155 | InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {} |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index f52b55ef3..da9e9fdda 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -190,6 +190,8 @@ if (ENABLE_VULKAN) | |||
| 190 | renderer_vulkan/vk_blit_screen.h | 190 | renderer_vulkan/vk_blit_screen.h |
| 191 | renderer_vulkan/vk_buffer_cache.cpp | 191 | renderer_vulkan/vk_buffer_cache.cpp |
| 192 | renderer_vulkan/vk_buffer_cache.h | 192 | renderer_vulkan/vk_buffer_cache.h |
| 193 | renderer_vulkan/vk_command_pool.cpp | ||
| 194 | renderer_vulkan/vk_command_pool.h | ||
| 193 | renderer_vulkan/vk_compute_pass.cpp | 195 | renderer_vulkan/vk_compute_pass.cpp |
| 194 | renderer_vulkan/vk_compute_pass.h | 196 | renderer_vulkan/vk_compute_pass.h |
| 195 | renderer_vulkan/vk_compute_pipeline.cpp | 197 | renderer_vulkan/vk_compute_pipeline.cpp |
| @@ -204,6 +206,8 @@ if (ENABLE_VULKAN) | |||
| 204 | renderer_vulkan/vk_graphics_pipeline.h | 206 | renderer_vulkan/vk_graphics_pipeline.h |
| 205 | renderer_vulkan/vk_image.cpp | 207 | renderer_vulkan/vk_image.cpp |
| 206 | renderer_vulkan/vk_image.h | 208 | renderer_vulkan/vk_image.h |
| 209 | renderer_vulkan/vk_master_semaphore.cpp | ||
| 210 | renderer_vulkan/vk_master_semaphore.h | ||
| 207 | renderer_vulkan/vk_memory_manager.cpp | 211 | renderer_vulkan/vk_memory_manager.cpp |
| 208 | renderer_vulkan/vk_memory_manager.h | 212 | renderer_vulkan/vk_memory_manager.h |
| 209 | renderer_vulkan/vk_pipeline_cache.cpp | 213 | renderer_vulkan/vk_pipeline_cache.cpp |
| @@ -214,8 +218,8 @@ if (ENABLE_VULKAN) | |||
| 214 | renderer_vulkan/vk_rasterizer.h | 218 | renderer_vulkan/vk_rasterizer.h |
| 215 | renderer_vulkan/vk_renderpass_cache.cpp | 219 | renderer_vulkan/vk_renderpass_cache.cpp |
| 216 | renderer_vulkan/vk_renderpass_cache.h | 220 | renderer_vulkan/vk_renderpass_cache.h |
| 217 | renderer_vulkan/vk_resource_manager.cpp | 221 | renderer_vulkan/vk_resource_pool.cpp |
| 218 | renderer_vulkan/vk_resource_manager.h | 222 | renderer_vulkan/vk_resource_pool.h |
| 219 | renderer_vulkan/vk_sampler_cache.cpp | 223 | renderer_vulkan/vk_sampler_cache.cpp |
| 220 | renderer_vulkan/vk_sampler_cache.h | 224 | renderer_vulkan/vk_sampler_cache.h |
| 221 | renderer_vulkan/vk_scheduler.cpp | 225 | renderer_vulkan/vk_scheduler.cpp |
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h index d13a66bb6..fc54ca0ef 100644 --- a/src/video_core/query_cache.h +++ b/src/video_core/query_cache.h | |||
| @@ -91,8 +91,7 @@ private: | |||
| 91 | std::shared_ptr<HostCounter> last; | 91 | std::shared_ptr<HostCounter> last; |
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter, | 94 | template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter> |
| 95 | class QueryPool> | ||
| 96 | class QueryCacheBase { | 95 | class QueryCacheBase { |
| 97 | public: | 96 | public: |
| 98 | explicit QueryCacheBase(VideoCore::RasterizerInterface& rasterizer_, | 97 | explicit QueryCacheBase(VideoCore::RasterizerInterface& rasterizer_, |
| @@ -206,9 +205,6 @@ public: | |||
| 206 | committed_flushes.pop_front(); | 205 | committed_flushes.pop_front(); |
| 207 | } | 206 | } |
| 208 | 207 | ||
| 209 | protected: | ||
| 210 | std::array<QueryPool, VideoCore::NumQueryTypes> query_pools; | ||
| 211 | |||
| 212 | private: | 208 | private: |
| 213 | /// Flushes a memory range to guest memory and removes it from the cache. | 209 | /// Flushes a memory range to guest memory and removes it from the cache. |
| 214 | void FlushAndRemoveRegion(VAddr addr, std::size_t size) { | 210 | void FlushAndRemoveRegion(VAddr addr, std::size_t size) { |
diff --git a/src/video_core/renderer_opengl/gl_query_cache.cpp b/src/video_core/renderer_opengl/gl_query_cache.cpp index 2bb8ec2b8..1a3d9720e 100644 --- a/src/video_core/renderer_opengl/gl_query_cache.cpp +++ b/src/video_core/renderer_opengl/gl_query_cache.cpp | |||
| @@ -32,10 +32,8 @@ constexpr GLenum GetTarget(VideoCore::QueryType type) { | |||
| 32 | 32 | ||
| 33 | QueryCache::QueryCache(RasterizerOpenGL& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d, | 33 | QueryCache::QueryCache(RasterizerOpenGL& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d, |
| 34 | Tegra::MemoryManager& gpu_memory) | 34 | Tegra::MemoryManager& gpu_memory) |
| 35 | : VideoCommon::QueryCacheBase< | 35 | : VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter>( |
| 36 | QueryCache, CachedQuery, CounterStream, HostCounter, | 36 | rasterizer, maxwell3d, gpu_memory), |
| 37 | std::vector<OGLQuery>>{static_cast<VideoCore::RasterizerInterface&>(rasterizer), | ||
| 38 | maxwell3d, gpu_memory}, | ||
| 39 | gl_rasterizer{rasterizer} {} | 37 | gl_rasterizer{rasterizer} {} |
| 40 | 38 | ||
| 41 | QueryCache::~QueryCache() = default; | 39 | QueryCache::~QueryCache() = default; |
| @@ -91,6 +89,8 @@ u64 HostCounter::BlockingQuery() const { | |||
| 91 | CachedQuery::CachedQuery(QueryCache& cache, VideoCore::QueryType type, VAddr cpu_addr, u8* host_ptr) | 89 | CachedQuery::CachedQuery(QueryCache& cache, VideoCore::QueryType type, VAddr cpu_addr, u8* host_ptr) |
| 92 | : VideoCommon::CachedQueryBase<HostCounter>{cpu_addr, host_ptr}, cache{&cache}, type{type} {} | 90 | : VideoCommon::CachedQueryBase<HostCounter>{cpu_addr, host_ptr}, cache{&cache}, type{type} {} |
| 93 | 91 | ||
| 92 | CachedQuery::~CachedQuery() = default; | ||
| 93 | |||
| 94 | CachedQuery::CachedQuery(CachedQuery&& rhs) noexcept | 94 | CachedQuery::CachedQuery(CachedQuery&& rhs) noexcept |
| 95 | : VideoCommon::CachedQueryBase<HostCounter>(std::move(rhs)), cache{rhs.cache}, type{rhs.type} {} | 95 | : VideoCommon::CachedQueryBase<HostCounter>(std::move(rhs)), cache{rhs.cache}, type{rhs.type} {} |
| 96 | 96 | ||
diff --git a/src/video_core/renderer_opengl/gl_query_cache.h b/src/video_core/renderer_opengl/gl_query_cache.h index dd626b66b..82cac51ee 100644 --- a/src/video_core/renderer_opengl/gl_query_cache.h +++ b/src/video_core/renderer_opengl/gl_query_cache.h | |||
| @@ -26,8 +26,8 @@ class RasterizerOpenGL; | |||
| 26 | 26 | ||
| 27 | using CounterStream = VideoCommon::CounterStreamBase<QueryCache, HostCounter>; | 27 | using CounterStream = VideoCommon::CounterStreamBase<QueryCache, HostCounter>; |
| 28 | 28 | ||
| 29 | class QueryCache final : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, | 29 | class QueryCache final |
| 30 | HostCounter, std::vector<OGLQuery>> { | 30 | : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { |
| 31 | public: | 31 | public: |
| 32 | explicit QueryCache(RasterizerOpenGL& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d, | 32 | explicit QueryCache(RasterizerOpenGL& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d, |
| 33 | Tegra::MemoryManager& gpu_memory); | 33 | Tegra::MemoryManager& gpu_memory); |
| @@ -41,6 +41,7 @@ public: | |||
| 41 | 41 | ||
| 42 | private: | 42 | private: |
| 43 | RasterizerOpenGL& gl_rasterizer; | 43 | RasterizerOpenGL& gl_rasterizer; |
| 44 | std::array<std::vector<OGLQuery>, VideoCore::NumQueryTypes> query_pools; | ||
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | class HostCounter final : public VideoCommon::HostCounterBase<QueryCache, HostCounter> { | 47 | class HostCounter final : public VideoCommon::HostCounterBase<QueryCache, HostCounter> { |
| @@ -63,10 +64,12 @@ class CachedQuery final : public VideoCommon::CachedQueryBase<HostCounter> { | |||
| 63 | public: | 64 | public: |
| 64 | explicit CachedQuery(QueryCache& cache, VideoCore::QueryType type, VAddr cpu_addr, | 65 | explicit CachedQuery(QueryCache& cache, VideoCore::QueryType type, VAddr cpu_addr, |
| 65 | u8* host_ptr); | 66 | u8* host_ptr); |
| 66 | CachedQuery(CachedQuery&& rhs) noexcept; | 67 | ~CachedQuery() override; |
| 67 | CachedQuery(const CachedQuery&) = delete; | ||
| 68 | 68 | ||
| 69 | CachedQuery(CachedQuery&& rhs) noexcept; | ||
| 69 | CachedQuery& operator=(CachedQuery&& rhs) noexcept; | 70 | CachedQuery& operator=(CachedQuery&& rhs) noexcept; |
| 71 | |||
| 72 | CachedQuery(const CachedQuery&) = delete; | ||
| 70 | CachedQuery& operator=(const CachedQuery&) = delete; | 73 | CachedQuery& operator=(const CachedQuery&) = delete; |
| 71 | 74 | ||
| 72 | void Flush() override; | 75 | void Flush() override; |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index d38e797a4..715182b3b 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -25,9 +25,9 @@ | |||
| 25 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 25 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| 26 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 26 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 27 | #include "video_core/renderer_vulkan/vk_device.h" | 27 | #include "video_core/renderer_vulkan/vk_device.h" |
| 28 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | ||
| 28 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 29 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 29 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 30 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 30 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 31 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 31 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 32 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 32 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| 33 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 33 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| @@ -56,7 +56,7 @@ VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, | |||
| 56 | VkDebugUtilsMessageTypeFlagsEXT type, | 56 | VkDebugUtilsMessageTypeFlagsEXT type, |
| 57 | const VkDebugUtilsMessengerCallbackDataEXT* data, | 57 | const VkDebugUtilsMessengerCallbackDataEXT* data, |
| 58 | [[maybe_unused]] void* user_data) { | 58 | [[maybe_unused]] void* user_data) { |
| 59 | const char* message{data->pMessage}; | 59 | const char* const message{data->pMessage}; |
| 60 | 60 | ||
| 61 | if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { | 61 | if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { |
| 62 | LOG_CRITICAL(Render_Vulkan, "{}", message); | 62 | LOG_CRITICAL(Render_Vulkan, "{}", message); |
| @@ -269,11 +269,11 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 269 | scheduler->WaitWorker(); | 269 | scheduler->WaitWorker(); |
| 270 | 270 | ||
| 271 | swapchain->AcquireNextImage(); | 271 | swapchain->AcquireNextImage(); |
| 272 | const auto [fence, render_semaphore] = blit_screen->Draw(*framebuffer, use_accelerated); | 272 | const VkSemaphore render_semaphore = blit_screen->Draw(*framebuffer, use_accelerated); |
| 273 | 273 | ||
| 274 | scheduler->Flush(false, render_semaphore); | 274 | scheduler->Flush(render_semaphore); |
| 275 | 275 | ||
| 276 | if (swapchain->Present(render_semaphore, fence)) { | 276 | if (swapchain->Present(render_semaphore)) { |
| 277 | blit_screen->Recreate(); | 277 | blit_screen->Recreate(); |
| 278 | } | 278 | } |
| 279 | 279 | ||
| @@ -295,23 +295,21 @@ bool RendererVulkan::Init() { | |||
| 295 | 295 | ||
| 296 | memory_manager = std::make_unique<VKMemoryManager>(*device); | 296 | memory_manager = std::make_unique<VKMemoryManager>(*device); |
| 297 | 297 | ||
| 298 | resource_manager = std::make_unique<VKResourceManager>(*device); | 298 | state_tracker = std::make_unique<StateTracker>(gpu); |
| 299 | |||
| 300 | scheduler = std::make_unique<VKScheduler>(*device, *state_tracker); | ||
| 299 | 301 | ||
| 300 | const auto& framebuffer = render_window.GetFramebufferLayout(); | 302 | const auto& framebuffer = render_window.GetFramebufferLayout(); |
| 301 | swapchain = std::make_unique<VKSwapchain>(*surface, *device); | 303 | swapchain = std::make_unique<VKSwapchain>(*surface, *device, *scheduler); |
| 302 | swapchain->Create(framebuffer.width, framebuffer.height, false); | 304 | swapchain->Create(framebuffer.width, framebuffer.height, false); |
| 303 | 305 | ||
| 304 | state_tracker = std::make_unique<StateTracker>(gpu); | 306 | rasterizer = std::make_unique<RasterizerVulkan>(render_window, gpu, gpu.MemoryManager(), |
| 305 | 307 | cpu_memory, screen_info, *device, | |
| 306 | scheduler = std::make_unique<VKScheduler>(*device, *resource_manager, *state_tracker); | 308 | *memory_manager, *state_tracker, *scheduler); |
| 307 | |||
| 308 | rasterizer = std::make_unique<RasterizerVulkan>( | ||
| 309 | render_window, gpu, gpu.MemoryManager(), cpu_memory, screen_info, *device, | ||
| 310 | *resource_manager, *memory_manager, *state_tracker, *scheduler); | ||
| 311 | 309 | ||
| 312 | blit_screen = std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, | 310 | blit_screen = |
| 313 | *resource_manager, *memory_manager, *swapchain, | 311 | std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, |
| 314 | *scheduler, screen_info); | 312 | *memory_manager, *swapchain, *scheduler, screen_info); |
| 315 | 313 | ||
| 316 | return true; | 314 | return true; |
| 317 | } | 315 | } |
| @@ -329,7 +327,6 @@ void RendererVulkan::ShutDown() { | |||
| 329 | scheduler.reset(); | 327 | scheduler.reset(); |
| 330 | swapchain.reset(); | 328 | swapchain.reset(); |
| 331 | memory_manager.reset(); | 329 | memory_manager.reset(); |
| 332 | resource_manager.reset(); | ||
| 333 | device.reset(); | 330 | device.reset(); |
| 334 | } | 331 | } |
| 335 | 332 | ||
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 5085310d0..49a4141ec 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -30,9 +30,7 @@ namespace Vulkan { | |||
| 30 | class StateTracker; | 30 | class StateTracker; |
| 31 | class VKBlitScreen; | 31 | class VKBlitScreen; |
| 32 | class VKDevice; | 32 | class VKDevice; |
| 33 | class VKFence; | ||
| 34 | class VKMemoryManager; | 33 | class VKMemoryManager; |
| 35 | class VKResourceManager; | ||
| 36 | class VKSwapchain; | 34 | class VKSwapchain; |
| 37 | class VKScheduler; | 35 | class VKScheduler; |
| 38 | class VKImage; | 36 | class VKImage; |
| @@ -81,11 +79,10 @@ private: | |||
| 81 | 79 | ||
| 82 | vk::DebugCallback debug_callback; | 80 | vk::DebugCallback debug_callback; |
| 83 | std::unique_ptr<VKDevice> device; | 81 | std::unique_ptr<VKDevice> device; |
| 84 | std::unique_ptr<VKSwapchain> swapchain; | ||
| 85 | std::unique_ptr<VKMemoryManager> memory_manager; | 82 | std::unique_ptr<VKMemoryManager> memory_manager; |
| 86 | std::unique_ptr<VKResourceManager> resource_manager; | ||
| 87 | std::unique_ptr<StateTracker> state_tracker; | 83 | std::unique_ptr<StateTracker> state_tracker; |
| 88 | std::unique_ptr<VKScheduler> scheduler; | 84 | std::unique_ptr<VKScheduler> scheduler; |
| 85 | std::unique_ptr<VKSwapchain> swapchain; | ||
| 89 | std::unique_ptr<VKBlitScreen> blit_screen; | 86 | std::unique_ptr<VKBlitScreen> blit_screen; |
| 90 | }; | 87 | }; |
| 91 | 88 | ||
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 2bea7b24d..b5b60309e 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -12,11 +12,9 @@ | |||
| 12 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/math_util.h" | 14 | #include "common/math_util.h" |
| 15 | |||
| 16 | #include "core/core.h" | 15 | #include "core/core.h" |
| 17 | #include "core/frontend/emu_window.h" | 16 | #include "core/frontend/emu_window.h" |
| 18 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 19 | |||
| 20 | #include "video_core/gpu.h" | 18 | #include "video_core/gpu.h" |
| 21 | #include "video_core/morton.h" | 19 | #include "video_core/morton.h" |
| 22 | #include "video_core/rasterizer_interface.h" | 20 | #include "video_core/rasterizer_interface.h" |
| @@ -24,8 +22,8 @@ | |||
| 24 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 22 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 25 | #include "video_core/renderer_vulkan/vk_device.h" | 23 | #include "video_core/renderer_vulkan/vk_device.h" |
| 26 | #include "video_core/renderer_vulkan/vk_image.h" | 24 | #include "video_core/renderer_vulkan/vk_image.h" |
| 25 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | ||
| 27 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 26 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 28 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 29 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 30 | #include "video_core/renderer_vulkan/vk_shader_util.h" | 28 | #include "video_core/renderer_vulkan/vk_shader_util.h" |
| 31 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 29 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| @@ -213,16 +211,12 @@ struct VKBlitScreen::BufferData { | |||
| 213 | VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, | 211 | VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, |
| 214 | Core::Frontend::EmuWindow& render_window_, | 212 | Core::Frontend::EmuWindow& render_window_, |
| 215 | VideoCore::RasterizerInterface& rasterizer_, const VKDevice& device_, | 213 | VideoCore::RasterizerInterface& rasterizer_, const VKDevice& device_, |
| 216 | VKResourceManager& resource_manager_, VKMemoryManager& memory_manager_, | 214 | VKMemoryManager& memory_manager_, VKSwapchain& swapchain_, |
| 217 | VKSwapchain& swapchain_, VKScheduler& scheduler_, | 215 | VKScheduler& scheduler_, const VKScreenInfo& screen_info_) |
| 218 | const VKScreenInfo& screen_info_) | 216 | : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_}, |
| 219 | : cpu_memory{cpu_memory_}, render_window{render_window_}, | 217 | device{device_}, memory_manager{memory_manager_}, swapchain{swapchain_}, |
| 220 | rasterizer{rasterizer_}, device{device_}, resource_manager{resource_manager_}, | 218 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { |
| 221 | memory_manager{memory_manager_}, swapchain{swapchain_}, scheduler{scheduler_}, | 219 | resource_ticks.resize(image_count); |
| 222 | image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { | ||
| 223 | watches.resize(image_count); | ||
| 224 | std::generate(watches.begin(), watches.end(), | ||
| 225 | []() { return std::make_unique<VKFenceWatch>(); }); | ||
| 226 | 220 | ||
| 227 | CreateStaticResources(); | 221 | CreateStaticResources(); |
| 228 | CreateDynamicResources(); | 222 | CreateDynamicResources(); |
| @@ -234,15 +228,16 @@ void VKBlitScreen::Recreate() { | |||
| 234 | CreateDynamicResources(); | 228 | CreateDynamicResources(); |
| 235 | } | 229 | } |
| 236 | 230 | ||
| 237 | std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | 231 | VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool use_accelerated) { |
| 238 | bool use_accelerated) { | ||
| 239 | RefreshResources(framebuffer); | 232 | RefreshResources(framebuffer); |
| 240 | 233 | ||
| 241 | // Finish any pending renderpass | 234 | // Finish any pending renderpass |
| 242 | scheduler.RequestOutsideRenderPassOperationContext(); | 235 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 243 | 236 | ||
| 244 | const std::size_t image_index = swapchain.GetImageIndex(); | 237 | const std::size_t image_index = swapchain.GetImageIndex(); |
| 245 | watches[image_index]->Watch(scheduler.GetFence()); | 238 | |
| 239 | scheduler.Wait(resource_ticks[image_index]); | ||
| 240 | resource_ticks[image_index] = scheduler.CurrentTick(); | ||
| 246 | 241 | ||
| 247 | VKImage* blit_image = use_accelerated ? screen_info.image : raw_images[image_index].get(); | 242 | VKImage* blit_image = use_accelerated ? screen_info.image : raw_images[image_index].get(); |
| 248 | 243 | ||
| @@ -345,7 +340,7 @@ std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferCon | |||
| 345 | cmdbuf.EndRenderPass(); | 340 | cmdbuf.EndRenderPass(); |
| 346 | }); | 341 | }); |
| 347 | 342 | ||
| 348 | return {scheduler.GetFence(), *semaphores[image_index]}; | 343 | return *semaphores[image_index]; |
| 349 | } | 344 | } |
| 350 | 345 | ||
| 351 | void VKBlitScreen::CreateStaticResources() { | 346 | void VKBlitScreen::CreateStaticResources() { |
| @@ -713,7 +708,7 @@ void VKBlitScreen::CreateFramebuffers() { | |||
| 713 | 708 | ||
| 714 | void VKBlitScreen::ReleaseRawImages() { | 709 | void VKBlitScreen::ReleaseRawImages() { |
| 715 | for (std::size_t i = 0; i < raw_images.size(); ++i) { | 710 | for (std::size_t i = 0; i < raw_images.size(); ++i) { |
| 716 | watches[i]->Wait(); | 711 | scheduler.Wait(resource_ticks.at(i)); |
| 717 | } | 712 | } |
| 718 | raw_images.clear(); | 713 | raw_images.clear(); |
| 719 | raw_buffer_commits.clear(); | 714 | raw_buffer_commits.clear(); |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 838d38f69..8f2839214 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -5,10 +5,8 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <tuple> | ||
| 9 | 8 | ||
| 10 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 9 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 11 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 12 | #include "video_core/renderer_vulkan/wrapper.h" | 10 | #include "video_core/renderer_vulkan/wrapper.h" |
| 13 | 11 | ||
| 14 | namespace Core { | 12 | namespace Core { |
| @@ -34,9 +32,9 @@ class RasterizerInterface; | |||
| 34 | namespace Vulkan { | 32 | namespace Vulkan { |
| 35 | 33 | ||
| 36 | struct ScreenInfo; | 34 | struct ScreenInfo; |
| 35 | |||
| 37 | class RasterizerVulkan; | 36 | class RasterizerVulkan; |
| 38 | class VKDevice; | 37 | class VKDevice; |
| 39 | class VKFence; | ||
| 40 | class VKImage; | 38 | class VKImage; |
| 41 | class VKScheduler; | 39 | class VKScheduler; |
| 42 | class VKSwapchain; | 40 | class VKSwapchain; |
| @@ -46,15 +44,14 @@ public: | |||
| 46 | explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, | 44 | explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, |
| 47 | Core::Frontend::EmuWindow& render_window, | 45 | Core::Frontend::EmuWindow& render_window, |
| 48 | VideoCore::RasterizerInterface& rasterizer, const VKDevice& device, | 46 | VideoCore::RasterizerInterface& rasterizer, const VKDevice& device, |
| 49 | VKResourceManager& resource_manager, VKMemoryManager& memory_manager, | 47 | VKMemoryManager& memory_manager, VKSwapchain& swapchain, |
| 50 | VKSwapchain& swapchain, VKScheduler& scheduler, | 48 | VKScheduler& scheduler, const VKScreenInfo& screen_info); |
| 51 | const VKScreenInfo& screen_info); | ||
| 52 | ~VKBlitScreen(); | 49 | ~VKBlitScreen(); |
| 53 | 50 | ||
| 54 | void Recreate(); | 51 | void Recreate(); |
| 55 | 52 | ||
| 56 | std::tuple<VKFence&, VkSemaphore> Draw(const Tegra::FramebufferConfig& framebuffer, | 53 | [[nodiscard]] VkSemaphore Draw(const Tegra::FramebufferConfig& framebuffer, |
| 57 | bool use_accelerated); | 54 | bool use_accelerated); |
| 58 | 55 | ||
| 59 | private: | 56 | private: |
| 60 | struct BufferData; | 57 | struct BufferData; |
| @@ -90,7 +87,6 @@ private: | |||
| 90 | Core::Frontend::EmuWindow& render_window; | 87 | Core::Frontend::EmuWindow& render_window; |
| 91 | VideoCore::RasterizerInterface& rasterizer; | 88 | VideoCore::RasterizerInterface& rasterizer; |
| 92 | const VKDevice& device; | 89 | const VKDevice& device; |
| 93 | VKResourceManager& resource_manager; | ||
| 94 | VKMemoryManager& memory_manager; | 90 | VKMemoryManager& memory_manager; |
| 95 | VKSwapchain& swapchain; | 91 | VKSwapchain& swapchain; |
| 96 | VKScheduler& scheduler; | 92 | VKScheduler& scheduler; |
| @@ -111,7 +107,7 @@ private: | |||
| 111 | vk::Buffer buffer; | 107 | vk::Buffer buffer; |
| 112 | VKMemoryCommit buffer_commit; | 108 | VKMemoryCommit buffer_commit; |
| 113 | 109 | ||
| 114 | std::vector<std::unique_ptr<VKFenceWatch>> watches; | 110 | std::vector<u64> resource_ticks; |
| 115 | 111 | ||
| 116 | std::vector<vk::Semaphore> semaphores; | 112 | std::vector<vk::Semaphore> semaphores; |
| 117 | std::vector<std::unique_ptr<VKImage>> raw_images; | 113 | std::vector<std::unique_ptr<VKImage>> raw_images; |
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.cpp b/src/video_core/renderer_vulkan/vk_command_pool.cpp new file mode 100644 index 000000000..f1abd4b1a --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_command_pool.cpp | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstddef> | ||
| 6 | |||
| 7 | #include "video_core/renderer_vulkan/vk_command_pool.h" | ||
| 8 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 9 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 10 | |||
| 11 | namespace Vulkan { | ||
| 12 | |||
| 13 | constexpr size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; | ||
| 14 | |||
| 15 | CommandPool::CommandPool(MasterSemaphore& master_semaphore, const VKDevice& device) | ||
| 16 | : ResourcePool(master_semaphore, COMMAND_BUFFER_POOL_SIZE), device{device} {} | ||
| 17 | |||
| 18 | CommandPool::~CommandPool() = default; | ||
| 19 | |||
| 20 | void CommandPool::Allocate(size_t begin, size_t end) { | ||
| 21 | // Command buffers are going to be commited, recorded, executed every single usage cycle. | ||
| 22 | // They are also going to be reseted when commited. | ||
| 23 | Pool& pool = pools.emplace_back(); | ||
| 24 | pool.handle = device.GetLogical().CreateCommandPool({ | ||
| 25 | .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | ||
| 26 | .pNext = nullptr, | ||
| 27 | .flags = | ||
| 28 | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, | ||
| 29 | .queueFamilyIndex = device.GetGraphicsFamily(), | ||
| 30 | }); | ||
| 31 | pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE); | ||
| 32 | } | ||
| 33 | |||
| 34 | VkCommandBuffer CommandPool::Commit() { | ||
| 35 | const size_t index = CommitResource(); | ||
| 36 | const auto pool_index = index / COMMAND_BUFFER_POOL_SIZE; | ||
| 37 | const auto sub_index = index % COMMAND_BUFFER_POOL_SIZE; | ||
| 38 | return pools[pool_index].cmdbufs[sub_index]; | ||
| 39 | } | ||
| 40 | |||
| 41 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.h b/src/video_core/renderer_vulkan/vk_command_pool.h new file mode 100644 index 000000000..3aee239b9 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_command_pool.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstddef> | ||
| 6 | #include <vector> | ||
| 7 | |||
| 8 | #include "video_core/renderer_vulkan/vk_resource_pool.h" | ||
| 9 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 10 | |||
| 11 | namespace Vulkan { | ||
| 12 | |||
| 13 | class MasterSemaphore; | ||
| 14 | class VKDevice; | ||
| 15 | |||
| 16 | class CommandPool final : public ResourcePool { | ||
| 17 | public: | ||
| 18 | explicit CommandPool(MasterSemaphore& master_semaphore, const VKDevice& device); | ||
| 19 | virtual ~CommandPool(); | ||
| 20 | |||
| 21 | void Allocate(size_t begin, size_t end) override; | ||
| 22 | |||
| 23 | VkCommandBuffer Commit(); | ||
| 24 | |||
| 25 | private: | ||
| 26 | struct Pool { | ||
| 27 | vk::CommandPool handle; | ||
| 28 | vk::CommandBuffers cmdbufs; | ||
| 29 | }; | ||
| 30 | |||
| 31 | const VKDevice& device; | ||
| 32 | std::vector<Pool> pools; | ||
| 33 | }; | ||
| 34 | |||
| 35 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 182461ed9..9637c6059 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp | |||
| @@ -112,7 +112,8 @@ constexpr u8 quad_array[] = { | |||
| 112 | 0xf9, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x00, | 112 | 0xf9, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x00, |
| 113 | 0xf9, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x4e, 0x00, 0x00, 0x00, | 113 | 0xf9, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x4e, 0x00, 0x00, 0x00, |
| 114 | 0xf9, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x00, 0x00, | 114 | 0xf9, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x00, 0x00, |
| 115 | 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; | 115 | 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, |
| 116 | }; | ||
| 116 | 117 | ||
| 117 | VkDescriptorSetLayoutBinding BuildQuadArrayPassDescriptorSetLayoutBinding() { | 118 | VkDescriptorSetLayoutBinding BuildQuadArrayPassDescriptorSetLayoutBinding() { |
| 118 | return { | 119 | return { |
| @@ -218,7 +219,8 @@ constexpr u8 uint8_pass[] = { | |||
| 218 | 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | 219 | 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, |
| 219 | 0x24, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | 220 | 0x24, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, |
| 220 | 0xf9, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, | 221 | 0xf9, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, |
| 221 | 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; | 222 | 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, |
| 223 | }; | ||
| 222 | 224 | ||
| 223 | // Quad indexed SPIR-V module. Generated from the "shaders/" directory. | 225 | // Quad indexed SPIR-V module. Generated from the "shaders/" directory. |
| 224 | constexpr u8 QUAD_INDEXED_SPV[] = { | 226 | constexpr u8 QUAD_INDEXED_SPV[] = { |
| @@ -341,7 +343,8 @@ constexpr u8 QUAD_INDEXED_SPV[] = { | |||
| 341 | 0xf9, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x37, 0x00, 0x00, 0x00, | 343 | 0xf9, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x37, 0x00, 0x00, 0x00, |
| 342 | 0xf9, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00, 0x00, | 344 | 0xf9, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00, 0x00, |
| 343 | 0xf9, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00, | 345 | 0xf9, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00, |
| 344 | 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; | 346 | 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, |
| 347 | }; | ||
| 345 | 348 | ||
| 346 | std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() { | 349 | std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() { |
| 347 | return {{ | 350 | return {{ |
| @@ -448,12 +451,12 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto | |||
| 448 | 451 | ||
| 449 | VKComputePass::~VKComputePass() = default; | 452 | VKComputePass::~VKComputePass() = default; |
| 450 | 453 | ||
| 451 | VkDescriptorSet VKComputePass::CommitDescriptorSet(VKUpdateDescriptorQueue& update_descriptor_queue, | 454 | VkDescriptorSet VKComputePass::CommitDescriptorSet( |
| 452 | VKFence& fence) { | 455 | VKUpdateDescriptorQueue& update_descriptor_queue) { |
| 453 | if (!descriptor_template) { | 456 | if (!descriptor_template) { |
| 454 | return nullptr; | 457 | return nullptr; |
| 455 | } | 458 | } |
| 456 | const auto set = descriptor_allocator->Commit(fence); | 459 | const VkDescriptorSet set = descriptor_allocator->Commit(); |
| 457 | update_descriptor_queue.Send(*descriptor_template, set); | 460 | update_descriptor_queue.Send(*descriptor_template, set); |
| 458 | return set; | 461 | return set; |
| 459 | } | 462 | } |
| @@ -477,7 +480,7 @@ std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32 | |||
| 477 | 480 | ||
| 478 | update_descriptor_queue.Acquire(); | 481 | update_descriptor_queue.Acquire(); |
| 479 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); | 482 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); |
| 480 | const auto set = CommitDescriptorSet(update_descriptor_queue, scheduler.GetFence()); | 483 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); |
| 481 | 484 | ||
| 482 | scheduler.RequestOutsideRenderPassOperationContext(); | 485 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 483 | 486 | ||
| @@ -520,13 +523,13 @@ Uint8Pass::~Uint8Pass() = default; | |||
| 520 | 523 | ||
| 521 | std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer, | 524 | std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer, |
| 522 | u64 src_offset) { | 525 | u64 src_offset) { |
| 523 | const auto staging_size = static_cast<u32>(num_vertices * sizeof(u16)); | 526 | const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16)); |
| 524 | auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); | 527 | auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); |
| 525 | 528 | ||
| 526 | update_descriptor_queue.Acquire(); | 529 | update_descriptor_queue.Acquire(); |
| 527 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); | 530 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); |
| 528 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); | 531 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); |
| 529 | const auto set = CommitDescriptorSet(update_descriptor_queue, scheduler.GetFence()); | 532 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); |
| 530 | 533 | ||
| 531 | scheduler.RequestOutsideRenderPassOperationContext(); | 534 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 532 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, | 535 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, |
| @@ -589,7 +592,7 @@ std::pair<VkBuffer, u64> QuadIndexedPass::Assemble( | |||
| 589 | update_descriptor_queue.Acquire(); | 592 | update_descriptor_queue.Acquire(); |
| 590 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); | 593 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); |
| 591 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); | 594 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); |
| 592 | const auto set = CommitDescriptorSet(update_descriptor_queue, scheduler.GetFence()); | 595 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); |
| 593 | 596 | ||
| 594 | scheduler.RequestOutsideRenderPassOperationContext(); | 597 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 595 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, | 598 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h index 230b526bc..acc94f27e 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | namespace Vulkan { | 15 | namespace Vulkan { |
| 16 | 16 | ||
| 17 | class VKDevice; | 17 | class VKDevice; |
| 18 | class VKFence; | ||
| 19 | class VKScheduler; | 18 | class VKScheduler; |
| 20 | class VKStagingBufferPool; | 19 | class VKStagingBufferPool; |
| 21 | class VKUpdateDescriptorQueue; | 20 | class VKUpdateDescriptorQueue; |
| @@ -30,8 +29,7 @@ public: | |||
| 30 | ~VKComputePass(); | 29 | ~VKComputePass(); |
| 31 | 30 | ||
| 32 | protected: | 31 | protected: |
| 33 | VkDescriptorSet CommitDescriptorSet(VKUpdateDescriptorQueue& update_descriptor_queue, | 32 | VkDescriptorSet CommitDescriptorSet(VKUpdateDescriptorQueue& update_descriptor_queue); |
| 34 | VKFence& fence); | ||
| 35 | 33 | ||
| 36 | vk::DescriptorUpdateTemplateKHR descriptor_template; | 34 | vk::DescriptorUpdateTemplateKHR descriptor_template; |
| 37 | vk::PipelineLayout layout; | 35 | vk::PipelineLayout layout; |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index ed9d2991c..9be72dc9b 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | |||
| @@ -32,7 +32,7 @@ VkDescriptorSet VKComputePipeline::CommitDescriptorSet() { | |||
| 32 | if (!descriptor_template) { | 32 | if (!descriptor_template) { |
| 33 | return {}; | 33 | return {}; |
| 34 | } | 34 | } |
| 35 | const auto set = descriptor_allocator.Commit(scheduler.GetFence()); | 35 | const VkDescriptorSet set = descriptor_allocator.Commit(); |
| 36 | update_descriptor_queue.Send(*descriptor_template, set); | 36 | update_descriptor_queue.Send(*descriptor_template, set); |
| 37 | return set; | 37 | return set; |
| 38 | } | 38 | } |
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp index ac4a0884e..f38e089d5 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp | |||
| @@ -7,7 +7,8 @@ | |||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 8 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 9 | #include "video_core/renderer_vulkan/vk_device.h" | 9 | #include "video_core/renderer_vulkan/vk_device.h" |
| 10 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | 10 | #include "video_core/renderer_vulkan/vk_resource_pool.h" |
| 11 | #include "video_core/renderer_vulkan/vk_scheduler.h" | ||
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | 12 | #include "video_core/renderer_vulkan/wrapper.h" |
| 12 | 13 | ||
| 13 | namespace Vulkan { | 14 | namespace Vulkan { |
| @@ -15,14 +16,15 @@ namespace Vulkan { | |||
| 15 | // Prefer small grow rates to avoid saturating the descriptor pool with barely used pipelines. | 16 | // Prefer small grow rates to avoid saturating the descriptor pool with barely used pipelines. |
| 16 | constexpr std::size_t SETS_GROW_RATE = 0x20; | 17 | constexpr std::size_t SETS_GROW_RATE = 0x20; |
| 17 | 18 | ||
| 18 | DescriptorAllocator::DescriptorAllocator(VKDescriptorPool& descriptor_pool, | 19 | DescriptorAllocator::DescriptorAllocator(VKDescriptorPool& descriptor_pool_, |
| 19 | VkDescriptorSetLayout layout) | 20 | VkDescriptorSetLayout layout_) |
| 20 | : VKFencedPool{SETS_GROW_RATE}, descriptor_pool{descriptor_pool}, layout{layout} {} | 21 | : ResourcePool(descriptor_pool_.master_semaphore, SETS_GROW_RATE), |
| 22 | descriptor_pool{descriptor_pool_}, layout{layout_} {} | ||
| 21 | 23 | ||
| 22 | DescriptorAllocator::~DescriptorAllocator() = default; | 24 | DescriptorAllocator::~DescriptorAllocator() = default; |
| 23 | 25 | ||
| 24 | VkDescriptorSet DescriptorAllocator::Commit(VKFence& fence) { | 26 | VkDescriptorSet DescriptorAllocator::Commit() { |
| 25 | const std::size_t index = CommitResource(fence); | 27 | const std::size_t index = CommitResource(); |
| 26 | return descriptors_allocations[index / SETS_GROW_RATE][index % SETS_GROW_RATE]; | 28 | return descriptors_allocations[index / SETS_GROW_RATE][index % SETS_GROW_RATE]; |
| 27 | } | 29 | } |
| 28 | 30 | ||
| @@ -30,8 +32,9 @@ void DescriptorAllocator::Allocate(std::size_t begin, std::size_t end) { | |||
| 30 | descriptors_allocations.push_back(descriptor_pool.AllocateDescriptors(layout, end - begin)); | 32 | descriptors_allocations.push_back(descriptor_pool.AllocateDescriptors(layout, end - begin)); |
| 31 | } | 33 | } |
| 32 | 34 | ||
| 33 | VKDescriptorPool::VKDescriptorPool(const VKDevice& device) | 35 | VKDescriptorPool::VKDescriptorPool(const VKDevice& device_, VKScheduler& scheduler) |
| 34 | : device{device}, active_pool{AllocateNewPool()} {} | 36 | : device{device_}, master_semaphore{scheduler.GetMasterSemaphore()}, active_pool{ |
| 37 | AllocateNewPool()} {} | ||
| 35 | 38 | ||
| 36 | VKDescriptorPool::~VKDescriptorPool() = default; | 39 | VKDescriptorPool::~VKDescriptorPool() = default; |
| 37 | 40 | ||
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h index 9efa66bef..544f32a20 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h | |||
| @@ -6,21 +6,24 @@ | |||
| 6 | 6 | ||
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | 8 | ||
| 9 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | 9 | #include "video_core/renderer_vulkan/vk_resource_pool.h" |
| 10 | #include "video_core/renderer_vulkan/wrapper.h" | 10 | #include "video_core/renderer_vulkan/wrapper.h" |
| 11 | 11 | ||
| 12 | namespace Vulkan { | 12 | namespace Vulkan { |
| 13 | 13 | ||
| 14 | class VKDevice; | ||
| 14 | class VKDescriptorPool; | 15 | class VKDescriptorPool; |
| 16 | class VKScheduler; | ||
| 15 | 17 | ||
| 16 | class DescriptorAllocator final : public VKFencedPool { | 18 | class DescriptorAllocator final : public ResourcePool { |
| 17 | public: | 19 | public: |
| 18 | explicit DescriptorAllocator(VKDescriptorPool& descriptor_pool, VkDescriptorSetLayout layout); | 20 | explicit DescriptorAllocator(VKDescriptorPool& descriptor_pool, VkDescriptorSetLayout layout); |
| 19 | ~DescriptorAllocator() override; | 21 | ~DescriptorAllocator() override; |
| 20 | 22 | ||
| 23 | DescriptorAllocator& operator=(const DescriptorAllocator&) = delete; | ||
| 21 | DescriptorAllocator(const DescriptorAllocator&) = delete; | 24 | DescriptorAllocator(const DescriptorAllocator&) = delete; |
| 22 | 25 | ||
| 23 | VkDescriptorSet Commit(VKFence& fence); | 26 | VkDescriptorSet Commit(); |
| 24 | 27 | ||
| 25 | protected: | 28 | protected: |
| 26 | void Allocate(std::size_t begin, std::size_t end) override; | 29 | void Allocate(std::size_t begin, std::size_t end) override; |
| @@ -36,15 +39,19 @@ class VKDescriptorPool final { | |||
| 36 | friend DescriptorAllocator; | 39 | friend DescriptorAllocator; |
| 37 | 40 | ||
| 38 | public: | 41 | public: |
| 39 | explicit VKDescriptorPool(const VKDevice& device); | 42 | explicit VKDescriptorPool(const VKDevice& device, VKScheduler& scheduler); |
| 40 | ~VKDescriptorPool(); | 43 | ~VKDescriptorPool(); |
| 41 | 44 | ||
| 45 | VKDescriptorPool(const VKDescriptorPool&) = delete; | ||
| 46 | VKDescriptorPool& operator=(const VKDescriptorPool&) = delete; | ||
| 47 | |||
| 42 | private: | 48 | private: |
| 43 | vk::DescriptorPool* AllocateNewPool(); | 49 | vk::DescriptorPool* AllocateNewPool(); |
| 44 | 50 | ||
| 45 | vk::DescriptorSets AllocateDescriptors(VkDescriptorSetLayout layout, std::size_t count); | 51 | vk::DescriptorSets AllocateDescriptors(VkDescriptorSetLayout layout, std::size_t count); |
| 46 | 52 | ||
| 47 | const VKDevice& device; | 53 | const VKDevice& device; |
| 54 | MasterSemaphore& master_semaphore; | ||
| 48 | 55 | ||
| 49 | std::vector<vk::DescriptorPool> pools; | 56 | std::vector<vk::DescriptorPool> pools; |
| 50 | vk::DescriptorPool* active_pool; | 57 | vk::DescriptorPool* active_pool; |
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index 4205bd573..05e31f1de 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp | |||
| @@ -42,6 +42,7 @@ constexpr std::array REQUIRED_EXTENSIONS{ | |||
| 42 | VK_KHR_8BIT_STORAGE_EXTENSION_NAME, | 42 | VK_KHR_8BIT_STORAGE_EXTENSION_NAME, |
| 43 | VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, | 43 | VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, |
| 44 | VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, | 44 | VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, |
| 45 | VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, | ||
| 45 | VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, | 46 | VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, |
| 46 | VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, | 47 | VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, |
| 47 | VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, | 48 | VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, |
| @@ -250,6 +251,13 @@ bool VKDevice::Create() { | |||
| 250 | .inheritedQueries = false, | 251 | .inheritedQueries = false, |
| 251 | }; | 252 | }; |
| 252 | 253 | ||
| 254 | VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore{ | ||
| 255 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR, | ||
| 256 | .pNext = nullptr, | ||
| 257 | .timelineSemaphore = true, | ||
| 258 | }; | ||
| 259 | SetNext(next, timeline_semaphore); | ||
| 260 | |||
| 253 | VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage{ | 261 | VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage{ |
| 254 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, | 262 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, |
| 255 | .pNext = nullptr, | 263 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp index 55a8348fc..5babbdd0b 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp | |||
| @@ -29,8 +29,8 @@ void InnerFence::Queue() { | |||
| 29 | } | 29 | } |
| 30 | ASSERT(!event); | 30 | ASSERT(!event); |
| 31 | 31 | ||
| 32 | event = device.GetLogical().CreateNewEvent(); | 32 | event = device.GetLogical().CreateEvent(); |
| 33 | ticks = scheduler.Ticks(); | 33 | ticks = scheduler.CurrentTick(); |
| 34 | 34 | ||
| 35 | scheduler.RequestOutsideRenderPassOperationContext(); | 35 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 36 | scheduler.Record([event = *event](vk::CommandBuffer cmdbuf) { | 36 | scheduler.Record([event = *event](vk::CommandBuffer cmdbuf) { |
| @@ -52,7 +52,7 @@ void InnerFence::Wait() { | |||
| 52 | } | 52 | } |
| 53 | ASSERT(event); | 53 | ASSERT(event); |
| 54 | 54 | ||
| 55 | if (ticks >= scheduler.Ticks()) { | 55 | if (ticks >= scheduler.CurrentTick()) { |
| 56 | scheduler.Flush(); | 56 | scheduler.Flush(); |
| 57 | } | 57 | } |
| 58 | while (!IsEventSignalled()) { | 58 | while (!IsEventSignalled()) { |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 2e46c6278..a4b9e7ef5 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -93,7 +93,7 @@ VkDescriptorSet VKGraphicsPipeline::CommitDescriptorSet() { | |||
| 93 | if (!descriptor_template) { | 93 | if (!descriptor_template) { |
| 94 | return {}; | 94 | return {}; |
| 95 | } | 95 | } |
| 96 | const auto set = descriptor_allocator.Commit(scheduler.GetFence()); | 96 | const VkDescriptorSet set = descriptor_allocator.Commit(); |
| 97 | update_descriptor_queue.Send(*descriptor_template, set); | 97 | update_descriptor_queue.Send(*descriptor_template, set); |
| 98 | return set; | 98 | return set; |
| 99 | } | 99 | } |
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp new file mode 100644 index 000000000..ae26e558d --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <atomic> | ||
| 6 | #include <chrono> | ||
| 7 | |||
| 8 | #include "core/settings.h" | ||
| 9 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | ||
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 12 | |||
| 13 | namespace Vulkan { | ||
| 14 | |||
| 15 | using namespace std::chrono_literals; | ||
| 16 | |||
| 17 | MasterSemaphore::MasterSemaphore(const VKDevice& device) { | ||
| 18 | static constexpr VkSemaphoreTypeCreateInfoKHR semaphore_type_ci{ | ||
| 19 | .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR, | ||
| 20 | .pNext = nullptr, | ||
| 21 | .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE_KHR, | ||
| 22 | .initialValue = 0, | ||
| 23 | }; | ||
| 24 | static constexpr VkSemaphoreCreateInfo semaphore_ci{ | ||
| 25 | .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, | ||
| 26 | .pNext = &semaphore_type_ci, | ||
| 27 | .flags = 0, | ||
| 28 | }; | ||
| 29 | semaphore = device.GetLogical().CreateSemaphore(semaphore_ci); | ||
| 30 | |||
| 31 | if (!Settings::values.renderer_debug) { | ||
| 32 | return; | ||
| 33 | } | ||
| 34 | // Validation layers have a bug where they fail to track resource usage when using timeline | ||
| 35 | // semaphores and synchronizing with GetSemaphoreCounterValueKHR. To workaround this issue, have | ||
| 36 | // a separate thread waiting for each timeline semaphore value. | ||
| 37 | debug_thread = std::thread([this] { | ||
| 38 | u64 counter = 0; | ||
| 39 | while (!shutdown) { | ||
| 40 | if (semaphore.Wait(counter, 10'000'000)) { | ||
| 41 | ++counter; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | }); | ||
| 45 | } | ||
| 46 | |||
| 47 | MasterSemaphore::~MasterSemaphore() { | ||
| 48 | shutdown = true; | ||
| 49 | |||
| 50 | // This thread might not be started | ||
| 51 | if (debug_thread.joinable()) { | ||
| 52 | debug_thread.join(); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h new file mode 100644 index 000000000..0e93706d7 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | #include <thread> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 12 | |||
| 13 | namespace Vulkan { | ||
| 14 | |||
| 15 | class VKDevice; | ||
| 16 | |||
| 17 | class MasterSemaphore { | ||
| 18 | public: | ||
| 19 | explicit MasterSemaphore(const VKDevice& device); | ||
| 20 | ~MasterSemaphore(); | ||
| 21 | |||
| 22 | /// Returns the current logical tick. | ||
| 23 | [[nodiscard]] u64 CurrentTick() const noexcept { | ||
| 24 | return current_tick; | ||
| 25 | } | ||
| 26 | |||
| 27 | /// Returns the timeline semaphore handle. | ||
| 28 | [[nodiscard]] VkSemaphore Handle() const noexcept { | ||
| 29 | return *semaphore; | ||
| 30 | } | ||
| 31 | |||
| 32 | /// Returns true when a tick has been hit by the GPU. | ||
| 33 | [[nodiscard]] bool IsFree(u64 tick) { | ||
| 34 | return gpu_tick >= tick; | ||
| 35 | } | ||
| 36 | |||
| 37 | /// Advance to the logical tick. | ||
| 38 | void NextTick() noexcept { | ||
| 39 | ++current_tick; | ||
| 40 | } | ||
| 41 | |||
| 42 | /// Refresh the known GPU tick | ||
| 43 | void Refresh() { | ||
| 44 | gpu_tick = semaphore.GetCounter(); | ||
| 45 | } | ||
| 46 | |||
| 47 | /// Waits for a tick to be hit on the GPU | ||
| 48 | void Wait(u64 tick) { | ||
| 49 | // No need to wait if the GPU is ahead of the tick | ||
| 50 | if (IsFree(tick)) { | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | // Update the GPU tick and try again | ||
| 54 | Refresh(); | ||
| 55 | if (IsFree(tick)) { | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | // If none of the above is hit, fallback to a regular wait | ||
| 59 | semaphore.Wait(tick); | ||
| 60 | } | ||
| 61 | |||
| 62 | private: | ||
| 63 | vk::Semaphore semaphore; ///< Timeline semaphore. | ||
| 64 | std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick. | ||
| 65 | std::atomic<u64> current_tick{1}; ///< Current logical tick. | ||
| 66 | std::atomic<bool> shutdown{false}; ///< True when the object is being destroyed. | ||
| 67 | std::thread debug_thread; ///< Debug thread to workaround validation layer bugs. | ||
| 68 | }; | ||
| 69 | |||
| 70 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 1a31fd9f6..e558e6658 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h | |||
| @@ -38,7 +38,6 @@ class RasterizerVulkan; | |||
| 38 | class VKComputePipeline; | 38 | class VKComputePipeline; |
| 39 | class VKDescriptorPool; | 39 | class VKDescriptorPool; |
| 40 | class VKDevice; | 40 | class VKDevice; |
| 41 | class VKFence; | ||
| 42 | class VKScheduler; | 41 | class VKScheduler; |
| 43 | class VKUpdateDescriptorQueue; | 42 | class VKUpdateDescriptorQueue; |
| 44 | 43 | ||
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 5a97c959d..ee2d871e3 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp | |||
| @@ -9,35 +9,33 @@ | |||
| 9 | 9 | ||
| 10 | #include "video_core/renderer_vulkan/vk_device.h" | 10 | #include "video_core/renderer_vulkan/vk_device.h" |
| 11 | #include "video_core/renderer_vulkan/vk_query_cache.h" | 11 | #include "video_core/renderer_vulkan/vk_query_cache.h" |
| 12 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | 12 | #include "video_core/renderer_vulkan/vk_resource_pool.h" |
| 13 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 13 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | 14 | #include "video_core/renderer_vulkan/wrapper.h" |
| 15 | 15 | ||
| 16 | namespace Vulkan { | 16 | namespace Vulkan { |
| 17 | 17 | ||
| 18 | using VideoCore::QueryType; | ||
| 19 | |||
| 18 | namespace { | 20 | namespace { |
| 19 | 21 | ||
| 20 | constexpr std::array QUERY_TARGETS = {VK_QUERY_TYPE_OCCLUSION}; | 22 | constexpr std::array QUERY_TARGETS = {VK_QUERY_TYPE_OCCLUSION}; |
| 21 | 23 | ||
| 22 | constexpr VkQueryType GetTarget(VideoCore::QueryType type) { | 24 | constexpr VkQueryType GetTarget(QueryType type) { |
| 23 | return QUERY_TARGETS[static_cast<std::size_t>(type)]; | 25 | return QUERY_TARGETS[static_cast<std::size_t>(type)]; |
| 24 | } | 26 | } |
| 25 | 27 | ||
| 26 | } // Anonymous namespace | 28 | } // Anonymous namespace |
| 27 | 29 | ||
| 28 | QueryPool::QueryPool() : VKFencedPool{GROW_STEP} {} | 30 | QueryPool::QueryPool(const VKDevice& device_, VKScheduler& scheduler, QueryType type_) |
| 31 | : ResourcePool{scheduler.GetMasterSemaphore(), GROW_STEP}, device{device_}, type{type_} {} | ||
| 29 | 32 | ||
| 30 | QueryPool::~QueryPool() = default; | 33 | QueryPool::~QueryPool() = default; |
| 31 | 34 | ||
| 32 | void QueryPool::Initialize(const VKDevice& device_, VideoCore::QueryType type_) { | 35 | std::pair<VkQueryPool, u32> QueryPool::Commit() { |
| 33 | device = &device_; | ||
| 34 | type = type_; | ||
| 35 | } | ||
| 36 | |||
| 37 | std::pair<VkQueryPool, u32> QueryPool::Commit(VKFence& fence) { | ||
| 38 | std::size_t index; | 36 | std::size_t index; |
| 39 | do { | 37 | do { |
| 40 | index = CommitResource(fence); | 38 | index = CommitResource(); |
| 41 | } while (usage[index]); | 39 | } while (usage[index]); |
| 42 | usage[index] = true; | 40 | usage[index] = true; |
| 43 | 41 | ||
| @@ -47,7 +45,7 @@ std::pair<VkQueryPool, u32> QueryPool::Commit(VKFence& fence) { | |||
| 47 | void QueryPool::Allocate(std::size_t begin, std::size_t end) { | 45 | void QueryPool::Allocate(std::size_t begin, std::size_t end) { |
| 48 | usage.resize(end); | 46 | usage.resize(end); |
| 49 | 47 | ||
| 50 | pools.push_back(device->GetLogical().CreateQueryPool({ | 48 | pools.push_back(device.GetLogical().CreateQueryPool({ |
| 51 | .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, | 49 | .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, |
| 52 | .pNext = nullptr, | 50 | .pNext = nullptr, |
| 53 | .flags = 0, | 51 | .flags = 0, |
| @@ -71,28 +69,36 @@ void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) { | |||
| 71 | VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer, | 69 | VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer, |
| 72 | Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, | 70 | Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, |
| 73 | const VKDevice& device, VKScheduler& scheduler) | 71 | const VKDevice& device, VKScheduler& scheduler) |
| 74 | : VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter, | 72 | : VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, |
| 75 | QueryPool>{rasterizer, maxwell3d, gpu_memory}, | 73 | HostCounter>{rasterizer, maxwell3d, gpu_memory}, |
| 76 | device{device}, scheduler{scheduler} { | 74 | device{device}, scheduler{scheduler}, query_pools{ |
| 77 | for (std::size_t i = 0; i < static_cast<std::size_t>(VideoCore::NumQueryTypes); ++i) { | 75 | QueryPool{device, scheduler, |
| 78 | query_pools[i].Initialize(device, static_cast<VideoCore::QueryType>(i)); | 76 | QueryType::SamplesPassed}, |
| 77 | } {} | ||
| 78 | |||
| 79 | VKQueryCache::~VKQueryCache() { | ||
| 80 | // TODO(Rodrigo): This is a hack to destroy all HostCounter instances before the base class | ||
| 81 | // destructor is called. The query cache should be redesigned to have a proper ownership model | ||
| 82 | // instead of using shared pointers. | ||
| 83 | for (size_t query_type = 0; query_type < VideoCore::NumQueryTypes; ++query_type) { | ||
| 84 | auto& stream = Stream(static_cast<QueryType>(query_type)); | ||
| 85 | stream.Update(false); | ||
| 86 | stream.Reset(); | ||
| 79 | } | 87 | } |
| 80 | } | 88 | } |
| 81 | 89 | ||
| 82 | VKQueryCache::~VKQueryCache() = default; | 90 | std::pair<VkQueryPool, u32> VKQueryCache::AllocateQuery(QueryType type) { |
| 83 | 91 | return query_pools[static_cast<std::size_t>(type)].Commit(); | |
| 84 | std::pair<VkQueryPool, u32> VKQueryCache::AllocateQuery(VideoCore::QueryType type) { | ||
| 85 | return query_pools[static_cast<std::size_t>(type)].Commit(scheduler.GetFence()); | ||
| 86 | } | 92 | } |
| 87 | 93 | ||
| 88 | void VKQueryCache::Reserve(VideoCore::QueryType type, std::pair<VkQueryPool, u32> query) { | 94 | void VKQueryCache::Reserve(QueryType type, std::pair<VkQueryPool, u32> query) { |
| 89 | query_pools[static_cast<std::size_t>(type)].Reserve(query); | 95 | query_pools[static_cast<std::size_t>(type)].Reserve(query); |
| 90 | } | 96 | } |
| 91 | 97 | ||
| 92 | HostCounter::HostCounter(VKQueryCache& cache, std::shared_ptr<HostCounter> dependency, | 98 | HostCounter::HostCounter(VKQueryCache& cache, std::shared_ptr<HostCounter> dependency, |
| 93 | VideoCore::QueryType type) | 99 | QueryType type) |
| 94 | : VideoCommon::HostCounterBase<VKQueryCache, HostCounter>{std::move(dependency)}, cache{cache}, | 100 | : VideoCommon::HostCounterBase<VKQueryCache, HostCounter>{std::move(dependency)}, cache{cache}, |
| 95 | type{type}, query{cache.AllocateQuery(type)}, ticks{cache.Scheduler().Ticks()} { | 101 | type{type}, query{cache.AllocateQuery(type)}, tick{cache.Scheduler().CurrentTick()} { |
| 96 | const vk::Device* logical = &cache.Device().GetLogical(); | 102 | const vk::Device* logical = &cache.Device().GetLogical(); |
| 97 | cache.Scheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) { | 103 | cache.Scheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) { |
| 98 | logical->ResetQueryPoolEXT(query.first, query.second, 1); | 104 | logical->ResetQueryPoolEXT(query.first, query.second, 1); |
| @@ -110,7 +116,7 @@ void HostCounter::EndQuery() { | |||
| 110 | } | 116 | } |
| 111 | 117 | ||
| 112 | u64 HostCounter::BlockingQuery() const { | 118 | u64 HostCounter::BlockingQuery() const { |
| 113 | if (ticks >= cache.Scheduler().Ticks()) { | 119 | if (tick >= cache.Scheduler().CurrentTick()) { |
| 114 | cache.Scheduler().Flush(); | 120 | cache.Scheduler().Flush(); |
| 115 | } | 121 | } |
| 116 | u64 data; | 122 | u64 data; |
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h index 9be996e55..2e57fb75d 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.h +++ b/src/video_core/renderer_vulkan/vk_query_cache.h | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "video_core/query_cache.h" | 13 | #include "video_core/query_cache.h" |
| 14 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | 14 | #include "video_core/renderer_vulkan/vk_resource_pool.h" |
| 15 | #include "video_core/renderer_vulkan/wrapper.h" | 15 | #include "video_core/renderer_vulkan/wrapper.h" |
| 16 | 16 | ||
| 17 | namespace VideoCore { | 17 | namespace VideoCore { |
| @@ -28,14 +28,12 @@ class VKScheduler; | |||
| 28 | 28 | ||
| 29 | using CounterStream = VideoCommon::CounterStreamBase<VKQueryCache, HostCounter>; | 29 | using CounterStream = VideoCommon::CounterStreamBase<VKQueryCache, HostCounter>; |
| 30 | 30 | ||
| 31 | class QueryPool final : public VKFencedPool { | 31 | class QueryPool final : public ResourcePool { |
| 32 | public: | 32 | public: |
| 33 | explicit QueryPool(); | 33 | explicit QueryPool(const VKDevice& device, VKScheduler& scheduler, VideoCore::QueryType type); |
| 34 | ~QueryPool() override; | 34 | ~QueryPool() override; |
| 35 | 35 | ||
| 36 | void Initialize(const VKDevice& device, VideoCore::QueryType type); | 36 | std::pair<VkQueryPool, u32> Commit(); |
| 37 | |||
| 38 | std::pair<VkQueryPool, u32> Commit(VKFence& fence); | ||
| 39 | 37 | ||
| 40 | void Reserve(std::pair<VkQueryPool, u32> query); | 38 | void Reserve(std::pair<VkQueryPool, u32> query); |
| 41 | 39 | ||
| @@ -45,16 +43,15 @@ protected: | |||
| 45 | private: | 43 | private: |
| 46 | static constexpr std::size_t GROW_STEP = 512; | 44 | static constexpr std::size_t GROW_STEP = 512; |
| 47 | 45 | ||
| 48 | const VKDevice* device = nullptr; | 46 | const VKDevice& device; |
| 49 | VideoCore::QueryType type = {}; | 47 | const VideoCore::QueryType type; |
| 50 | 48 | ||
| 51 | std::vector<vk::QueryPool> pools; | 49 | std::vector<vk::QueryPool> pools; |
| 52 | std::vector<bool> usage; | 50 | std::vector<bool> usage; |
| 53 | }; | 51 | }; |
| 54 | 52 | ||
| 55 | class VKQueryCache final | 53 | class VKQueryCache final |
| 56 | : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter, | 54 | : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter> { |
| 57 | QueryPool> { | ||
| 58 | public: | 55 | public: |
| 59 | explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer, | 56 | explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer, |
| 60 | Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, | 57 | Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, |
| @@ -76,6 +73,7 @@ public: | |||
| 76 | private: | 73 | private: |
| 77 | const VKDevice& device; | 74 | const VKDevice& device; |
| 78 | VKScheduler& scheduler; | 75 | VKScheduler& scheduler; |
| 76 | std::array<QueryPool, VideoCore::NumQueryTypes> query_pools; | ||
| 79 | }; | 77 | }; |
| 80 | 78 | ||
| 81 | class HostCounter final : public VideoCommon::HostCounterBase<VKQueryCache, HostCounter> { | 79 | class HostCounter final : public VideoCommon::HostCounterBase<VKQueryCache, HostCounter> { |
| @@ -92,7 +90,7 @@ private: | |||
| 92 | VKQueryCache& cache; | 90 | VKQueryCache& cache; |
| 93 | const VideoCore::QueryType type; | 91 | const VideoCore::QueryType type; |
| 94 | const std::pair<VkQueryPool, u32> query; | 92 | const std::pair<VkQueryPool, u32> query; |
| 95 | const u64 ticks; | 93 | const u64 tick; |
| 96 | }; | 94 | }; |
| 97 | 95 | ||
| 98 | class CachedQuery : public VideoCommon::CachedQueryBase<HostCounter> { | 96 | class CachedQuery : public VideoCommon::CachedQueryBase<HostCounter> { |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index bafebe294..f3c2483c8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -31,7 +31,6 @@ | |||
| 31 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 31 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 32 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 32 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 33 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | 33 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" |
| 34 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 35 | #include "video_core/renderer_vulkan/vk_sampler_cache.h" | 34 | #include "video_core/renderer_vulkan/vk_sampler_cache.h" |
| 36 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 35 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 37 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 36 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| @@ -384,27 +383,25 @@ void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf) const { | |||
| 384 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu_, | 383 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu_, |
| 385 | Tegra::MemoryManager& gpu_memory_, | 384 | Tegra::MemoryManager& gpu_memory_, |
| 386 | Core::Memory::Memory& cpu_memory, VKScreenInfo& screen_info_, | 385 | Core::Memory::Memory& cpu_memory, VKScreenInfo& screen_info_, |
| 387 | const VKDevice& device_, VKResourceManager& resource_manager_, | 386 | const VKDevice& device_, VKMemoryManager& memory_manager_, |
| 388 | VKMemoryManager& memory_manager_, StateTracker& state_tracker_, | 387 | StateTracker& state_tracker_, VKScheduler& scheduler_) |
| 389 | VKScheduler& scheduler_) | ||
| 390 | : RasterizerAccelerated(cpu_memory), gpu(gpu_), gpu_memory(gpu_memory_), | 388 | : RasterizerAccelerated(cpu_memory), gpu(gpu_), gpu_memory(gpu_memory_), |
| 391 | maxwell3d(gpu.Maxwell3D()), kepler_compute(gpu.KeplerCompute()), screen_info(screen_info_), | 389 | maxwell3d(gpu.Maxwell3D()), kepler_compute(gpu.KeplerCompute()), screen_info(screen_info_), |
| 392 | device(device_), resource_manager(resource_manager_), memory_manager(memory_manager_), | 390 | device(device_), memory_manager(memory_manager_), state_tracker(state_tracker_), |
| 393 | state_tracker(state_tracker_), scheduler(scheduler_), | 391 | scheduler(scheduler_), staging_pool(device, memory_manager, scheduler), |
| 394 | staging_pool(device, memory_manager, scheduler), descriptor_pool(device), | 392 | descriptor_pool(device, scheduler_), update_descriptor_queue(device, scheduler), |
| 395 | update_descriptor_queue(device, scheduler), renderpass_cache(device), | 393 | renderpass_cache(device), |
| 396 | quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 394 | quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 397 | quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 395 | quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 398 | uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 396 | uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 399 | texture_cache(*this, maxwell3d, gpu_memory, device, resource_manager, memory_manager, | 397 | texture_cache(*this, maxwell3d, gpu_memory, device, memory_manager, scheduler, staging_pool), |
| 400 | scheduler, staging_pool), | ||
| 401 | pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, | 398 | pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, |
| 402 | descriptor_pool, update_descriptor_queue, renderpass_cache), | 399 | descriptor_pool, update_descriptor_queue, renderpass_cache), |
| 403 | buffer_cache(*this, gpu_memory, cpu_memory, device, memory_manager, scheduler, staging_pool), | 400 | buffer_cache(*this, gpu_memory, cpu_memory, device, memory_manager, scheduler, staging_pool), |
| 404 | sampler_cache(device), query_cache(*this, maxwell3d, gpu_memory, device, scheduler), | 401 | sampler_cache(device), query_cache(*this, maxwell3d, gpu_memory, device, scheduler), |
| 405 | fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, device, | 402 | fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, device, |
| 406 | scheduler), | 403 | scheduler), |
| 407 | wfi_event(device.GetLogical().CreateNewEvent()), async_shaders(emu_window) { | 404 | wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window) { |
| 408 | scheduler.SetQueryCache(query_cache); | 405 | scheduler.SetQueryCache(query_cache); |
| 409 | if (device.UseAsynchronousShaders()) { | 406 | if (device.UseAsynchronousShaders()) { |
| 410 | async_shaders.AllocateWorkers(); | 407 | async_shaders.AllocateWorkers(); |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 16251d0f6..b47c8fc13 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 25 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 26 | #include "video_core/renderer_vulkan/vk_query_cache.h" | 26 | #include "video_core/renderer_vulkan/vk_query_cache.h" |
| 27 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | 27 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" |
| 28 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 29 | #include "video_core/renderer_vulkan/vk_sampler_cache.h" | 28 | #include "video_core/renderer_vulkan/vk_sampler_cache.h" |
| 30 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 29 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 31 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 30 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| @@ -109,8 +108,8 @@ public: | |||
| 109 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu, | 108 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu, |
| 110 | Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, | 109 | Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, |
| 111 | VKScreenInfo& screen_info, const VKDevice& device, | 110 | VKScreenInfo& screen_info, const VKDevice& device, |
| 112 | VKResourceManager& resource_manager, VKMemoryManager& memory_manager, | 111 | VKMemoryManager& memory_manager, StateTracker& state_tracker, |
| 113 | StateTracker& state_tracker, VKScheduler& scheduler); | 112 | VKScheduler& scheduler); |
| 114 | ~RasterizerVulkan() override; | 113 | ~RasterizerVulkan() override; |
| 115 | 114 | ||
| 116 | void Draw(bool is_indexed, bool is_instanced) override; | 115 | void Draw(bool is_indexed, bool is_instanced) override; |
| @@ -286,7 +285,6 @@ private: | |||
| 286 | 285 | ||
| 287 | VKScreenInfo& screen_info; | 286 | VKScreenInfo& screen_info; |
| 288 | const VKDevice& device; | 287 | const VKDevice& device; |
| 289 | VKResourceManager& resource_manager; | ||
| 290 | VKMemoryManager& memory_manager; | 288 | VKMemoryManager& memory_manager; |
| 291 | StateTracker& state_tracker; | 289 | StateTracker& state_tracker; |
| 292 | VKScheduler& scheduler; | 290 | VKScheduler& scheduler; |
diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp deleted file mode 100644 index f19330a36..000000000 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ /dev/null | |||
| @@ -1,311 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <optional> | ||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 12 | |||
| 13 | namespace Vulkan { | ||
| 14 | |||
| 15 | namespace { | ||
| 16 | |||
| 17 | // TODO(Rodrigo): Fine tune these numbers. | ||
| 18 | constexpr std::size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; | ||
| 19 | constexpr std::size_t FENCES_GROW_STEP = 0x40; | ||
| 20 | |||
| 21 | constexpr VkFenceCreateInfo BuildFenceCreateInfo() { | ||
| 22 | return { | ||
| 23 | .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, | ||
| 24 | .pNext = nullptr, | ||
| 25 | .flags = 0, | ||
| 26 | }; | ||
| 27 | } | ||
| 28 | |||
| 29 | } // Anonymous namespace | ||
| 30 | |||
| 31 | class CommandBufferPool final : public VKFencedPool { | ||
| 32 | public: | ||
| 33 | explicit CommandBufferPool(const VKDevice& device) | ||
| 34 | : VKFencedPool(COMMAND_BUFFER_POOL_SIZE), device{device} {} | ||
| 35 | |||
| 36 | void Allocate(std::size_t begin, std::size_t end) override { | ||
| 37 | // Command buffers are going to be commited, recorded, executed every single usage cycle. | ||
| 38 | // They are also going to be reseted when commited. | ||
| 39 | Pool& pool = pools.emplace_back(); | ||
| 40 | pool.handle = device.GetLogical().CreateCommandPool({ | ||
| 41 | .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | ||
| 42 | .pNext = nullptr, | ||
| 43 | .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | | ||
| 44 | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, | ||
| 45 | .queueFamilyIndex = device.GetGraphicsFamily(), | ||
| 46 | }); | ||
| 47 | pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE); | ||
| 48 | } | ||
| 49 | |||
| 50 | VkCommandBuffer Commit(VKFence& fence) { | ||
| 51 | const std::size_t index = CommitResource(fence); | ||
| 52 | const auto pool_index = index / COMMAND_BUFFER_POOL_SIZE; | ||
| 53 | const auto sub_index = index % COMMAND_BUFFER_POOL_SIZE; | ||
| 54 | return pools[pool_index].cmdbufs[sub_index]; | ||
| 55 | } | ||
| 56 | |||
| 57 | private: | ||
| 58 | struct Pool { | ||
| 59 | vk::CommandPool handle; | ||
| 60 | vk::CommandBuffers cmdbufs; | ||
| 61 | }; | ||
| 62 | |||
| 63 | const VKDevice& device; | ||
| 64 | std::vector<Pool> pools; | ||
| 65 | }; | ||
| 66 | |||
| 67 | VKResource::VKResource() = default; | ||
| 68 | |||
| 69 | VKResource::~VKResource() = default; | ||
| 70 | |||
| 71 | VKFence::VKFence(const VKDevice& device) | ||
| 72 | : device{device}, handle{device.GetLogical().CreateFence(BuildFenceCreateInfo())} {} | ||
| 73 | |||
| 74 | VKFence::~VKFence() = default; | ||
| 75 | |||
| 76 | void VKFence::Wait() { | ||
| 77 | switch (const VkResult result = handle.Wait()) { | ||
| 78 | case VK_SUCCESS: | ||
| 79 | return; | ||
| 80 | case VK_ERROR_DEVICE_LOST: | ||
| 81 | device.ReportLoss(); | ||
| 82 | [[fallthrough]]; | ||
| 83 | default: | ||
| 84 | throw vk::Exception(result); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | void VKFence::Release() { | ||
| 89 | ASSERT(is_owned); | ||
| 90 | is_owned = false; | ||
| 91 | } | ||
| 92 | |||
| 93 | void VKFence::Commit() { | ||
| 94 | is_owned = true; | ||
| 95 | is_used = true; | ||
| 96 | } | ||
| 97 | |||
| 98 | bool VKFence::Tick(bool gpu_wait, bool owner_wait) { | ||
| 99 | if (!is_used) { | ||
| 100 | // If a fence is not used it's always free. | ||
| 101 | return true; | ||
| 102 | } | ||
| 103 | if (is_owned && !owner_wait) { | ||
| 104 | // The fence is still being owned (Release has not been called) and ownership wait has | ||
| 105 | // not been asked. | ||
| 106 | return false; | ||
| 107 | } | ||
| 108 | |||
| 109 | if (gpu_wait) { | ||
| 110 | // Wait for the fence if it has been requested. | ||
| 111 | (void)handle.Wait(); | ||
| 112 | } else { | ||
| 113 | if (handle.GetStatus() != VK_SUCCESS) { | ||
| 114 | // Vulkan fence is not ready, not much it can do here | ||
| 115 | return false; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | // Broadcast resources their free state. | ||
| 120 | for (auto* resource : protected_resources) { | ||
| 121 | resource->OnFenceRemoval(this); | ||
| 122 | } | ||
| 123 | protected_resources.clear(); | ||
| 124 | |||
| 125 | // Prepare fence for reusage. | ||
| 126 | handle.Reset(); | ||
| 127 | is_used = false; | ||
| 128 | return true; | ||
| 129 | } | ||
| 130 | |||
| 131 | void VKFence::Protect(VKResource* resource) { | ||
| 132 | protected_resources.push_back(resource); | ||
| 133 | } | ||
| 134 | |||
| 135 | void VKFence::Unprotect(VKResource* resource) { | ||
| 136 | const auto it = std::find(protected_resources.begin(), protected_resources.end(), resource); | ||
| 137 | ASSERT(it != protected_resources.end()); | ||
| 138 | |||
| 139 | resource->OnFenceRemoval(this); | ||
| 140 | protected_resources.erase(it); | ||
| 141 | } | ||
| 142 | |||
| 143 | void VKFence::RedirectProtection(VKResource* old_resource, VKResource* new_resource) noexcept { | ||
| 144 | std::replace(std::begin(protected_resources), std::end(protected_resources), old_resource, | ||
| 145 | new_resource); | ||
| 146 | } | ||
| 147 | |||
| 148 | VKFenceWatch::VKFenceWatch() = default; | ||
| 149 | |||
| 150 | VKFenceWatch::VKFenceWatch(VKFence& initial_fence) { | ||
| 151 | Watch(initial_fence); | ||
| 152 | } | ||
| 153 | |||
| 154 | VKFenceWatch::VKFenceWatch(VKFenceWatch&& rhs) noexcept { | ||
| 155 | fence = std::exchange(rhs.fence, nullptr); | ||
| 156 | if (fence) { | ||
| 157 | fence->RedirectProtection(&rhs, this); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | VKFenceWatch& VKFenceWatch::operator=(VKFenceWatch&& rhs) noexcept { | ||
| 162 | fence = std::exchange(rhs.fence, nullptr); | ||
| 163 | if (fence) { | ||
| 164 | fence->RedirectProtection(&rhs, this); | ||
| 165 | } | ||
| 166 | return *this; | ||
| 167 | } | ||
| 168 | |||
| 169 | VKFenceWatch::~VKFenceWatch() { | ||
| 170 | if (fence) { | ||
| 171 | fence->Unprotect(this); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | void VKFenceWatch::Wait() { | ||
| 176 | if (fence == nullptr) { | ||
| 177 | return; | ||
| 178 | } | ||
| 179 | fence->Wait(); | ||
| 180 | fence->Unprotect(this); | ||
| 181 | } | ||
| 182 | |||
| 183 | void VKFenceWatch::Watch(VKFence& new_fence) { | ||
| 184 | Wait(); | ||
| 185 | fence = &new_fence; | ||
| 186 | fence->Protect(this); | ||
| 187 | } | ||
| 188 | |||
| 189 | bool VKFenceWatch::TryWatch(VKFence& new_fence) { | ||
| 190 | if (fence) { | ||
| 191 | return false; | ||
| 192 | } | ||
| 193 | fence = &new_fence; | ||
| 194 | fence->Protect(this); | ||
| 195 | return true; | ||
| 196 | } | ||
| 197 | |||
| 198 | void VKFenceWatch::OnFenceRemoval(VKFence* signaling_fence) { | ||
| 199 | ASSERT_MSG(signaling_fence == fence, "Removing the wrong fence"); | ||
| 200 | fence = nullptr; | ||
| 201 | } | ||
| 202 | |||
| 203 | VKFencedPool::VKFencedPool(std::size_t grow_step) : grow_step{grow_step} {} | ||
| 204 | |||
| 205 | VKFencedPool::~VKFencedPool() = default; | ||
| 206 | |||
| 207 | std::size_t VKFencedPool::CommitResource(VKFence& fence) { | ||
| 208 | const auto Search = [&](std::size_t begin, std::size_t end) -> std::optional<std::size_t> { | ||
| 209 | for (std::size_t iterator = begin; iterator < end; ++iterator) { | ||
| 210 | if (watches[iterator]->TryWatch(fence)) { | ||
| 211 | // The resource is now being watched, a free resource was successfully found. | ||
| 212 | return iterator; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | return {}; | ||
| 216 | }; | ||
| 217 | // Try to find a free resource from the hinted position to the end. | ||
| 218 | auto found = Search(free_iterator, watches.size()); | ||
| 219 | if (!found) { | ||
| 220 | // Search from beginning to the hinted position. | ||
| 221 | found = Search(0, free_iterator); | ||
| 222 | if (!found) { | ||
| 223 | // Both searches failed, the pool is full; handle it. | ||
| 224 | const std::size_t free_resource = ManageOverflow(); | ||
| 225 | |||
| 226 | // Watch will wait for the resource to be free. | ||
| 227 | watches[free_resource]->Watch(fence); | ||
| 228 | found = free_resource; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | // Free iterator is hinted to the resource after the one that's been commited. | ||
| 232 | free_iterator = (*found + 1) % watches.size(); | ||
| 233 | return *found; | ||
| 234 | } | ||
| 235 | |||
| 236 | std::size_t VKFencedPool::ManageOverflow() { | ||
| 237 | const std::size_t old_capacity = watches.size(); | ||
| 238 | Grow(); | ||
| 239 | |||
| 240 | // The last entry is guaranted to be free, since it's the first element of the freshly | ||
| 241 | // allocated resources. | ||
| 242 | return old_capacity; | ||
| 243 | } | ||
| 244 | |||
| 245 | void VKFencedPool::Grow() { | ||
| 246 | const std::size_t old_capacity = watches.size(); | ||
| 247 | watches.resize(old_capacity + grow_step); | ||
| 248 | std::generate(watches.begin() + old_capacity, watches.end(), | ||
| 249 | []() { return std::make_unique<VKFenceWatch>(); }); | ||
| 250 | Allocate(old_capacity, old_capacity + grow_step); | ||
| 251 | } | ||
| 252 | |||
| 253 | VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} { | ||
| 254 | GrowFences(FENCES_GROW_STEP); | ||
| 255 | command_buffer_pool = std::make_unique<CommandBufferPool>(device); | ||
| 256 | } | ||
| 257 | |||
| 258 | VKResourceManager::~VKResourceManager() = default; | ||
| 259 | |||
| 260 | VKFence& VKResourceManager::CommitFence() { | ||
| 261 | const auto StepFences = [&](bool gpu_wait, bool owner_wait) -> VKFence* { | ||
| 262 | const auto Tick = [=](auto& fence) { return fence->Tick(gpu_wait, owner_wait); }; | ||
| 263 | const auto hinted = fences.begin() + fences_iterator; | ||
| 264 | |||
| 265 | auto it = std::find_if(hinted, fences.end(), Tick); | ||
| 266 | if (it == fences.end()) { | ||
| 267 | it = std::find_if(fences.begin(), hinted, Tick); | ||
| 268 | if (it == hinted) { | ||
| 269 | return nullptr; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | fences_iterator = std::distance(fences.begin(), it) + 1; | ||
| 273 | if (fences_iterator >= fences.size()) | ||
| 274 | fences_iterator = 0; | ||
| 275 | |||
| 276 | auto& fence = *it; | ||
| 277 | fence->Commit(); | ||
| 278 | return fence.get(); | ||
| 279 | }; | ||
| 280 | |||
| 281 | VKFence* found_fence = StepFences(false, false); | ||
| 282 | if (!found_fence) { | ||
| 283 | // Try again, this time waiting. | ||
| 284 | found_fence = StepFences(true, false); | ||
| 285 | |||
| 286 | if (!found_fence) { | ||
| 287 | // Allocate new fences and try again. | ||
| 288 | LOG_INFO(Render_Vulkan, "Allocating new fences {} -> {}", fences.size(), | ||
| 289 | fences.size() + FENCES_GROW_STEP); | ||
| 290 | |||
| 291 | GrowFences(FENCES_GROW_STEP); | ||
| 292 | found_fence = StepFences(true, false); | ||
| 293 | ASSERT(found_fence != nullptr); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | return *found_fence; | ||
| 297 | } | ||
| 298 | |||
| 299 | VkCommandBuffer VKResourceManager::CommitCommandBuffer(VKFence& fence) { | ||
| 300 | return command_buffer_pool->Commit(fence); | ||
| 301 | } | ||
| 302 | |||
| 303 | void VKResourceManager::GrowFences(std::size_t new_fences_count) { | ||
| 304 | const std::size_t previous_size = fences.size(); | ||
| 305 | fences.resize(previous_size + new_fences_count); | ||
| 306 | |||
| 307 | std::generate(fences.begin() + previous_size, fences.end(), | ||
| 308 | [this] { return std::make_unique<VKFence>(device); }); | ||
| 309 | } | ||
| 310 | |||
| 311 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h deleted file mode 100644 index f683d2276..000000000 --- a/src/video_core/renderer_vulkan/vk_resource_manager.h +++ /dev/null | |||
| @@ -1,196 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstddef> | ||
| 8 | #include <memory> | ||
| 9 | #include <vector> | ||
| 10 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 11 | |||
| 12 | namespace Vulkan { | ||
| 13 | |||
| 14 | class VKDevice; | ||
| 15 | class VKFence; | ||
| 16 | class VKResourceManager; | ||
| 17 | |||
| 18 | class CommandBufferPool; | ||
| 19 | |||
| 20 | /// Interface for a Vulkan resource | ||
| 21 | class VKResource { | ||
| 22 | public: | ||
| 23 | explicit VKResource(); | ||
| 24 | virtual ~VKResource(); | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Signals the object that an owning fence has been signaled. | ||
| 28 | * @param signaling_fence Fence that signals its usage end. | ||
| 29 | */ | ||
| 30 | virtual void OnFenceRemoval(VKFence* signaling_fence) = 0; | ||
| 31 | }; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * Fences take ownership of objects, protecting them from GPU-side or driver-side concurrent access. | ||
| 35 | * They must be commited from the resource manager. Their usage flow is: commit the fence from the | ||
| 36 | * resource manager, protect resources with it and use them, send the fence to an execution queue | ||
| 37 | * and Wait for it if needed and then call Release. Used resources will automatically be signaled | ||
| 38 | * when they are free to be reused. | ||
| 39 | * @brief Protects resources for concurrent usage and signals its release. | ||
| 40 | */ | ||
| 41 | class VKFence { | ||
| 42 | friend class VKResourceManager; | ||
| 43 | |||
| 44 | public: | ||
| 45 | explicit VKFence(const VKDevice& device); | ||
| 46 | ~VKFence(); | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Waits for the fence to be signaled. | ||
| 50 | * @warning You must have ownership of the fence and it has to be previously sent to a queue to | ||
| 51 | * call this function. | ||
| 52 | */ | ||
| 53 | void Wait(); | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Releases ownership of the fence. Pass after it has been sent to an execution queue. | ||
| 57 | * Unmanaged usage of the fence after the call will result in undefined behavior because it may | ||
| 58 | * be being used for something else. | ||
| 59 | */ | ||
| 60 | void Release(); | ||
| 61 | |||
| 62 | /// Protects a resource with this fence. | ||
| 63 | void Protect(VKResource* resource); | ||
| 64 | |||
| 65 | /// Removes protection for a resource. | ||
| 66 | void Unprotect(VKResource* resource); | ||
| 67 | |||
| 68 | /// Redirects one protected resource to a new address. | ||
| 69 | void RedirectProtection(VKResource* old_resource, VKResource* new_resource) noexcept; | ||
| 70 | |||
| 71 | /// Retreives the fence. | ||
| 72 | operator VkFence() const { | ||
| 73 | return *handle; | ||
| 74 | } | ||
| 75 | |||
| 76 | private: | ||
| 77 | /// Take ownership of the fence. | ||
| 78 | void Commit(); | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Updates the fence status. | ||
| 82 | * @warning Waiting for the owner might soft lock the execution. | ||
| 83 | * @param gpu_wait Wait for the fence to be signaled by the driver. | ||
| 84 | * @param owner_wait Wait for the owner to signal its freedom. | ||
| 85 | * @returns True if the fence is free. Waiting for gpu and owner will always return true. | ||
| 86 | */ | ||
| 87 | bool Tick(bool gpu_wait, bool owner_wait); | ||
| 88 | |||
| 89 | const VKDevice& device; ///< Device handler | ||
| 90 | vk::Fence handle; ///< Vulkan fence | ||
| 91 | std::vector<VKResource*> protected_resources; ///< List of resources protected by this fence | ||
| 92 | bool is_owned = false; ///< The fence has been commited but not released yet. | ||
| 93 | bool is_used = false; ///< The fence has been commited but it has not been checked to be free. | ||
| 94 | }; | ||
| 95 | |||
| 96 | /** | ||
| 97 | * A fence watch is used to keep track of the usage of a fence and protect a resource or set of | ||
| 98 | * resources without having to inherit VKResource from their handlers. | ||
| 99 | */ | ||
| 100 | class VKFenceWatch final : public VKResource { | ||
| 101 | public: | ||
| 102 | explicit VKFenceWatch(); | ||
| 103 | VKFenceWatch(VKFence& initial_fence); | ||
| 104 | VKFenceWatch(VKFenceWatch&&) noexcept; | ||
| 105 | VKFenceWatch(const VKFenceWatch&) = delete; | ||
| 106 | ~VKFenceWatch() override; | ||
| 107 | |||
| 108 | VKFenceWatch& operator=(VKFenceWatch&&) noexcept; | ||
| 109 | |||
| 110 | /// Waits for the fence to be released. | ||
| 111 | void Wait(); | ||
| 112 | |||
| 113 | /** | ||
| 114 | * Waits for a previous fence and watches a new one. | ||
| 115 | * @param new_fence New fence to wait to. | ||
| 116 | */ | ||
| 117 | void Watch(VKFence& new_fence); | ||
| 118 | |||
| 119 | /** | ||
| 120 | * Checks if it's currently being watched and starts watching it if it's available. | ||
| 121 | * @returns True if a watch has started, false if it's being watched. | ||
| 122 | */ | ||
| 123 | bool TryWatch(VKFence& new_fence); | ||
| 124 | |||
| 125 | void OnFenceRemoval(VKFence* signaling_fence) override; | ||
| 126 | |||
| 127 | /** | ||
| 128 | * Do not use it paired with Watch. Use TryWatch instead. | ||
| 129 | * Returns true when the watch is free. | ||
| 130 | */ | ||
| 131 | bool IsUsed() const { | ||
| 132 | return fence != nullptr; | ||
| 133 | } | ||
| 134 | |||
| 135 | private: | ||
| 136 | VKFence* fence{}; ///< Fence watching this resource. nullptr when the watch is free. | ||
| 137 | }; | ||
| 138 | |||
| 139 | /** | ||
| 140 | * Handles a pool of resources protected by fences. Manages resource overflow allocating more | ||
| 141 | * resources. | ||
| 142 | */ | ||
| 143 | class VKFencedPool { | ||
| 144 | public: | ||
| 145 | explicit VKFencedPool(std::size_t grow_step); | ||
| 146 | virtual ~VKFencedPool(); | ||
| 147 | |||
| 148 | protected: | ||
| 149 | /** | ||
| 150 | * Commits a free resource and protects it with a fence. It may allocate new resources. | ||
| 151 | * @param fence Fence that protects the commited resource. | ||
| 152 | * @returns Index of the resource commited. | ||
| 153 | */ | ||
| 154 | std::size_t CommitResource(VKFence& fence); | ||
| 155 | |||
| 156 | /// Called when a chunk of resources have to be allocated. | ||
| 157 | virtual void Allocate(std::size_t begin, std::size_t end) = 0; | ||
| 158 | |||
| 159 | private: | ||
| 160 | /// Manages pool overflow allocating new resources. | ||
| 161 | std::size_t ManageOverflow(); | ||
| 162 | |||
| 163 | /// Allocates a new page of resources. | ||
| 164 | void Grow(); | ||
| 165 | |||
| 166 | std::size_t grow_step = 0; ///< Number of new resources created after an overflow | ||
| 167 | std::size_t free_iterator = 0; ///< Hint to where the next free resources is likely to be found | ||
| 168 | std::vector<std::unique_ptr<VKFenceWatch>> watches; ///< Set of watched resources | ||
| 169 | }; | ||
| 170 | |||
| 171 | /** | ||
| 172 | * The resource manager handles all resources that can be protected with a fence avoiding | ||
| 173 | * driver-side or GPU-side concurrent usage. Usage is documented in VKFence. | ||
| 174 | */ | ||
| 175 | class VKResourceManager final { | ||
| 176 | public: | ||
| 177 | explicit VKResourceManager(const VKDevice& device); | ||
| 178 | ~VKResourceManager(); | ||
| 179 | |||
| 180 | /// Commits a fence. It has to be sent to a queue and released. | ||
| 181 | VKFence& CommitFence(); | ||
| 182 | |||
| 183 | /// Commits an unused command buffer and protects it with a fence. | ||
| 184 | VkCommandBuffer CommitCommandBuffer(VKFence& fence); | ||
| 185 | |||
| 186 | private: | ||
| 187 | /// Allocates new fences. | ||
| 188 | void GrowFences(std::size_t new_fences_count); | ||
| 189 | |||
| 190 | const VKDevice& device; ///< Device handler. | ||
| 191 | std::size_t fences_iterator = 0; ///< Index where a free fence is likely to be found. | ||
| 192 | std::vector<std::unique_ptr<VKFence>> fences; ///< Pool of fences. | ||
| 193 | std::unique_ptr<CommandBufferPool> command_buffer_pool; ///< Pool of command buffers. | ||
| 194 | }; | ||
| 195 | |||
| 196 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_resource_pool.cpp b/src/video_core/renderer_vulkan/vk_resource_pool.cpp new file mode 100644 index 000000000..ee274ac59 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_resource_pool.cpp | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <optional> | ||
| 6 | |||
| 7 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | ||
| 8 | #include "video_core/renderer_vulkan/vk_resource_pool.h" | ||
| 9 | |||
| 10 | namespace Vulkan { | ||
| 11 | |||
| 12 | ResourcePool::ResourcePool(MasterSemaphore& master_semaphore_, size_t grow_step_) | ||
| 13 | : master_semaphore{master_semaphore_}, grow_step{grow_step_} {} | ||
| 14 | |||
| 15 | ResourcePool::~ResourcePool() = default; | ||
| 16 | |||
| 17 | size_t ResourcePool::CommitResource() { | ||
| 18 | // Refresh semaphore to query updated results | ||
| 19 | master_semaphore.Refresh(); | ||
| 20 | |||
| 21 | const auto search = [this](size_t begin, size_t end) -> std::optional<size_t> { | ||
| 22 | for (size_t iterator = begin; iterator < end; ++iterator) { | ||
| 23 | if (master_semaphore.IsFree(ticks[iterator])) { | ||
| 24 | ticks[iterator] = master_semaphore.CurrentTick(); | ||
| 25 | return iterator; | ||
| 26 | } | ||
| 27 | } | ||
| 28 | return {}; | ||
| 29 | }; | ||
| 30 | // Try to find a free resource from the hinted position to the end. | ||
| 31 | auto found = search(free_iterator, ticks.size()); | ||
| 32 | if (!found) { | ||
| 33 | // Search from beginning to the hinted position. | ||
| 34 | found = search(0, free_iterator); | ||
| 35 | if (!found) { | ||
| 36 | // Both searches failed, the pool is full; handle it. | ||
| 37 | const size_t free_resource = ManageOverflow(); | ||
| 38 | |||
| 39 | ticks[free_resource] = master_semaphore.CurrentTick(); | ||
| 40 | found = free_resource; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | // Free iterator is hinted to the resource after the one that's been commited. | ||
| 44 | free_iterator = (*found + 1) % ticks.size(); | ||
| 45 | return *found; | ||
| 46 | } | ||
| 47 | |||
| 48 | size_t ResourcePool::ManageOverflow() { | ||
| 49 | const size_t old_capacity = ticks.size(); | ||
| 50 | Grow(); | ||
| 51 | |||
| 52 | // The last entry is guaranted to be free, since it's the first element of the freshly | ||
| 53 | // allocated resources. | ||
| 54 | return old_capacity; | ||
| 55 | } | ||
| 56 | |||
| 57 | void ResourcePool::Grow() { | ||
| 58 | const size_t old_capacity = ticks.size(); | ||
| 59 | ticks.resize(old_capacity + grow_step); | ||
| 60 | Allocate(old_capacity, old_capacity + grow_step); | ||
| 61 | } | ||
| 62 | |||
| 63 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_resource_pool.h b/src/video_core/renderer_vulkan/vk_resource_pool.h new file mode 100644 index 000000000..a018c7ec2 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_resource_pool.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Vulkan { | ||
| 12 | |||
| 13 | class MasterSemaphore; | ||
| 14 | |||
| 15 | /** | ||
| 16 | * Handles a pool of resources protected by fences. Manages resource overflow allocating more | ||
| 17 | * resources. | ||
| 18 | */ | ||
| 19 | class ResourcePool { | ||
| 20 | public: | ||
| 21 | explicit ResourcePool(MasterSemaphore& master_semaphore, size_t grow_step); | ||
| 22 | virtual ~ResourcePool(); | ||
| 23 | |||
| 24 | protected: | ||
| 25 | size_t CommitResource(); | ||
| 26 | |||
| 27 | /// Called when a chunk of resources have to be allocated. | ||
| 28 | virtual void Allocate(size_t begin, size_t end) = 0; | ||
| 29 | |||
| 30 | private: | ||
| 31 | /// Manages pool overflow allocating new resources. | ||
| 32 | size_t ManageOverflow(); | ||
| 33 | |||
| 34 | /// Allocates a new page of resources. | ||
| 35 | void Grow(); | ||
| 36 | |||
| 37 | MasterSemaphore& master_semaphore; | ||
| 38 | size_t grow_step = 0; ///< Number of new resources created after an overflow | ||
| 39 | size_t free_iterator = 0; ///< Hint to where the next free resources is likely to be found | ||
| 40 | std::vector<u64> ticks; ///< Ticks for each resource | ||
| 41 | }; | ||
| 42 | |||
| 43 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index dbbd0961a..1a483dc71 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp | |||
| @@ -10,9 +10,10 @@ | |||
| 10 | 10 | ||
| 11 | #include "common/microprofile.h" | 11 | #include "common/microprofile.h" |
| 12 | #include "common/thread.h" | 12 | #include "common/thread.h" |
| 13 | #include "video_core/renderer_vulkan/vk_command_pool.h" | ||
| 13 | #include "video_core/renderer_vulkan/vk_device.h" | 14 | #include "video_core/renderer_vulkan/vk_device.h" |
| 15 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_query_cache.h" | 16 | #include "video_core/renderer_vulkan/vk_query_cache.h" |
| 15 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 16 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 17 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 17 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 18 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| 18 | #include "video_core/renderer_vulkan/wrapper.h" | 19 | #include "video_core/renderer_vulkan/wrapper.h" |
| @@ -35,10 +36,10 @@ void VKScheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf) { | |||
| 35 | last = nullptr; | 36 | last = nullptr; |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | VKScheduler::VKScheduler(const VKDevice& device, VKResourceManager& resource_manager, | 39 | VKScheduler::VKScheduler(const VKDevice& device_, StateTracker& state_tracker_) |
| 39 | StateTracker& state_tracker) | 40 | : device{device_}, state_tracker{state_tracker_}, |
| 40 | : device{device}, resource_manager{resource_manager}, state_tracker{state_tracker}, | 41 | master_semaphore{std::make_unique<MasterSemaphore>(device)}, |
| 41 | next_fence{&resource_manager.CommitFence()} { | 42 | command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} { |
| 42 | AcquireNewChunk(); | 43 | AcquireNewChunk(); |
| 43 | AllocateNewContext(); | 44 | AllocateNewContext(); |
| 44 | worker_thread = std::thread(&VKScheduler::WorkerThread, this); | 45 | worker_thread = std::thread(&VKScheduler::WorkerThread, this); |
| @@ -50,20 +51,27 @@ VKScheduler::~VKScheduler() { | |||
| 50 | worker_thread.join(); | 51 | worker_thread.join(); |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | void VKScheduler::Flush(bool release_fence, VkSemaphore semaphore) { | 54 | u64 VKScheduler::CurrentTick() const noexcept { |
| 55 | return master_semaphore->CurrentTick(); | ||
| 56 | } | ||
| 57 | |||
| 58 | bool VKScheduler::IsFree(u64 tick) const noexcept { | ||
| 59 | return master_semaphore->IsFree(tick); | ||
| 60 | } | ||
| 61 | |||
| 62 | void VKScheduler::Wait(u64 tick) { | ||
| 63 | master_semaphore->Wait(tick); | ||
| 64 | } | ||
| 65 | |||
| 66 | void VKScheduler::Flush(VkSemaphore semaphore) { | ||
| 54 | SubmitExecution(semaphore); | 67 | SubmitExecution(semaphore); |
| 55 | if (release_fence) { | ||
| 56 | current_fence->Release(); | ||
| 57 | } | ||
| 58 | AllocateNewContext(); | 68 | AllocateNewContext(); |
| 59 | } | 69 | } |
| 60 | 70 | ||
| 61 | void VKScheduler::Finish(bool release_fence, VkSemaphore semaphore) { | 71 | void VKScheduler::Finish(VkSemaphore semaphore) { |
| 72 | const u64 presubmit_tick = CurrentTick(); | ||
| 62 | SubmitExecution(semaphore); | 73 | SubmitExecution(semaphore); |
| 63 | current_fence->Wait(); | 74 | Wait(presubmit_tick); |
| 64 | if (release_fence) { | ||
| 65 | current_fence->Release(); | ||
| 66 | } | ||
| 67 | AllocateNewContext(); | 75 | AllocateNewContext(); |
| 68 | } | 76 | } |
| 69 | 77 | ||
| @@ -160,18 +168,38 @@ void VKScheduler::SubmitExecution(VkSemaphore semaphore) { | |||
| 160 | 168 | ||
| 161 | current_cmdbuf.End(); | 169 | current_cmdbuf.End(); |
| 162 | 170 | ||
| 171 | const VkSemaphore timeline_semaphore = master_semaphore->Handle(); | ||
| 172 | const u32 num_signal_semaphores = semaphore ? 2U : 1U; | ||
| 173 | |||
| 174 | const u64 signal_value = master_semaphore->CurrentTick(); | ||
| 175 | const u64 wait_value = signal_value - 1; | ||
| 176 | const VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; | ||
| 177 | |||
| 178 | master_semaphore->NextTick(); | ||
| 179 | |||
| 180 | const std::array signal_values{signal_value, u64(0)}; | ||
| 181 | const std::array signal_semaphores{timeline_semaphore, semaphore}; | ||
| 182 | |||
| 183 | const VkTimelineSemaphoreSubmitInfoKHR timeline_si{ | ||
| 184 | .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR, | ||
| 185 | .pNext = nullptr, | ||
| 186 | .waitSemaphoreValueCount = 1, | ||
| 187 | .pWaitSemaphoreValues = &wait_value, | ||
| 188 | .signalSemaphoreValueCount = num_signal_semaphores, | ||
| 189 | .pSignalSemaphoreValues = signal_values.data(), | ||
| 190 | }; | ||
| 163 | const VkSubmitInfo submit_info{ | 191 | const VkSubmitInfo submit_info{ |
| 164 | .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | 192 | .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, |
| 165 | .pNext = nullptr, | 193 | .pNext = &timeline_si, |
| 166 | .waitSemaphoreCount = 0, | 194 | .waitSemaphoreCount = 1, |
| 167 | .pWaitSemaphores = nullptr, | 195 | .pWaitSemaphores = &timeline_semaphore, |
| 168 | .pWaitDstStageMask = nullptr, | 196 | .pWaitDstStageMask = &wait_stage_mask, |
| 169 | .commandBufferCount = 1, | 197 | .commandBufferCount = 1, |
| 170 | .pCommandBuffers = current_cmdbuf.address(), | 198 | .pCommandBuffers = current_cmdbuf.address(), |
| 171 | .signalSemaphoreCount = semaphore ? 1U : 0U, | 199 | .signalSemaphoreCount = num_signal_semaphores, |
| 172 | .pSignalSemaphores = &semaphore, | 200 | .pSignalSemaphores = signal_semaphores.data(), |
| 173 | }; | 201 | }; |
| 174 | switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info, *current_fence)) { | 202 | switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info)) { |
| 175 | case VK_SUCCESS: | 203 | case VK_SUCCESS: |
| 176 | break; | 204 | break; |
| 177 | case VK_ERROR_DEVICE_LOST: | 205 | case VK_ERROR_DEVICE_LOST: |
| @@ -183,14 +211,9 @@ void VKScheduler::SubmitExecution(VkSemaphore semaphore) { | |||
| 183 | } | 211 | } |
| 184 | 212 | ||
| 185 | void VKScheduler::AllocateNewContext() { | 213 | void VKScheduler::AllocateNewContext() { |
| 186 | ++ticks; | ||
| 187 | |||
| 188 | std::unique_lock lock{mutex}; | 214 | std::unique_lock lock{mutex}; |
| 189 | current_fence = next_fence; | ||
| 190 | next_fence = &resource_manager.CommitFence(); | ||
| 191 | 215 | ||
| 192 | current_cmdbuf = vk::CommandBuffer(resource_manager.CommitCommandBuffer(*current_fence), | 216 | current_cmdbuf = vk::CommandBuffer(command_pool->Commit(), device.GetDispatchLoader()); |
| 193 | device.GetDispatchLoader()); | ||
| 194 | current_cmdbuf.Begin({ | 217 | current_cmdbuf.Begin({ |
| 195 | .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | 218 | .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, |
| 196 | .pNext = nullptr, | 219 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 970a65566..7be8a19f0 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h | |||
| @@ -16,42 +16,33 @@ | |||
| 16 | 16 | ||
| 17 | namespace Vulkan { | 17 | namespace Vulkan { |
| 18 | 18 | ||
| 19 | class CommandPool; | ||
| 20 | class MasterSemaphore; | ||
| 19 | class StateTracker; | 21 | class StateTracker; |
| 20 | class VKDevice; | 22 | class VKDevice; |
| 21 | class VKFence; | ||
| 22 | class VKQueryCache; | 23 | class VKQueryCache; |
| 23 | class VKResourceManager; | ||
| 24 | |||
| 25 | class VKFenceView { | ||
| 26 | public: | ||
| 27 | VKFenceView() = default; | ||
| 28 | VKFenceView(VKFence* const& fence) : fence{fence} {} | ||
| 29 | |||
| 30 | VKFence* operator->() const noexcept { | ||
| 31 | return fence; | ||
| 32 | } | ||
| 33 | |||
| 34 | operator VKFence&() const noexcept { | ||
| 35 | return *fence; | ||
| 36 | } | ||
| 37 | |||
| 38 | private: | ||
| 39 | VKFence* const& fence; | ||
| 40 | }; | ||
| 41 | 24 | ||
| 42 | /// The scheduler abstracts command buffer and fence management with an interface that's able to do | 25 | /// The scheduler abstracts command buffer and fence management with an interface that's able to do |
| 43 | /// OpenGL-like operations on Vulkan command buffers. | 26 | /// OpenGL-like operations on Vulkan command buffers. |
| 44 | class VKScheduler { | 27 | class VKScheduler { |
| 45 | public: | 28 | public: |
| 46 | explicit VKScheduler(const VKDevice& device, VKResourceManager& resource_manager, | 29 | explicit VKScheduler(const VKDevice& device, StateTracker& state_tracker); |
| 47 | StateTracker& state_tracker); | ||
| 48 | ~VKScheduler(); | 30 | ~VKScheduler(); |
| 49 | 31 | ||
| 32 | /// Returns the current command buffer tick. | ||
| 33 | [[nodiscard]] u64 CurrentTick() const noexcept; | ||
| 34 | |||
| 35 | /// Returns true when a tick has been triggered by the GPU. | ||
| 36 | [[nodiscard]] bool IsFree(u64 tick) const noexcept; | ||
| 37 | |||
| 38 | /// Waits for the given tick to trigger on the GPU. | ||
| 39 | void Wait(u64 tick); | ||
| 40 | |||
| 50 | /// Sends the current execution context to the GPU. | 41 | /// Sends the current execution context to the GPU. |
| 51 | void Flush(bool release_fence = true, VkSemaphore semaphore = nullptr); | 42 | void Flush(VkSemaphore semaphore = nullptr); |
| 52 | 43 | ||
| 53 | /// Sends the current execution context to the GPU and waits for it to complete. | 44 | /// Sends the current execution context to the GPU and waits for it to complete. |
| 54 | void Finish(bool release_fence = true, VkSemaphore semaphore = nullptr); | 45 | void Finish(VkSemaphore semaphore = nullptr); |
| 55 | 46 | ||
| 56 | /// Waits for the worker thread to finish executing everything. After this function returns it's | 47 | /// Waits for the worker thread to finish executing everything. After this function returns it's |
| 57 | /// safe to touch worker resources. | 48 | /// safe to touch worker resources. |
| @@ -86,14 +77,9 @@ public: | |||
| 86 | (void)chunk->Record(command); | 77 | (void)chunk->Record(command); |
| 87 | } | 78 | } |
| 88 | 79 | ||
| 89 | /// Gets a reference to the current fence. | 80 | /// Returns the master timeline semaphore. |
| 90 | VKFenceView GetFence() const { | 81 | [[nodiscard]] MasterSemaphore& GetMasterSemaphore() const noexcept { |
| 91 | return current_fence; | 82 | return *master_semaphore; |
| 92 | } | ||
| 93 | |||
| 94 | /// Returns the current command buffer tick. | ||
| 95 | u64 Ticks() const { | ||
| 96 | return ticks; | ||
| 97 | } | 83 | } |
| 98 | 84 | ||
| 99 | private: | 85 | private: |
| @@ -171,6 +157,13 @@ private: | |||
| 171 | std::array<u8, 0x8000> data{}; | 157 | std::array<u8, 0x8000> data{}; |
| 172 | }; | 158 | }; |
| 173 | 159 | ||
| 160 | struct State { | ||
| 161 | VkRenderPass renderpass = nullptr; | ||
| 162 | VkFramebuffer framebuffer = nullptr; | ||
| 163 | VkExtent2D render_area = {0, 0}; | ||
| 164 | VkPipeline graphics_pipeline = nullptr; | ||
| 165 | }; | ||
| 166 | |||
| 174 | void WorkerThread(); | 167 | void WorkerThread(); |
| 175 | 168 | ||
| 176 | void SubmitExecution(VkSemaphore semaphore); | 169 | void SubmitExecution(VkSemaphore semaphore); |
| @@ -186,30 +179,23 @@ private: | |||
| 186 | void AcquireNewChunk(); | 179 | void AcquireNewChunk(); |
| 187 | 180 | ||
| 188 | const VKDevice& device; | 181 | const VKDevice& device; |
| 189 | VKResourceManager& resource_manager; | ||
| 190 | StateTracker& state_tracker; | 182 | StateTracker& state_tracker; |
| 191 | 183 | ||
| 184 | std::unique_ptr<MasterSemaphore> master_semaphore; | ||
| 185 | std::unique_ptr<CommandPool> command_pool; | ||
| 186 | |||
| 192 | VKQueryCache* query_cache = nullptr; | 187 | VKQueryCache* query_cache = nullptr; |
| 193 | 188 | ||
| 194 | vk::CommandBuffer current_cmdbuf; | 189 | vk::CommandBuffer current_cmdbuf; |
| 195 | VKFence* current_fence = nullptr; | ||
| 196 | VKFence* next_fence = nullptr; | ||
| 197 | |||
| 198 | struct State { | ||
| 199 | VkRenderPass renderpass = nullptr; | ||
| 200 | VkFramebuffer framebuffer = nullptr; | ||
| 201 | VkExtent2D render_area = {0, 0}; | ||
| 202 | VkPipeline graphics_pipeline = nullptr; | ||
| 203 | } state; | ||
| 204 | 190 | ||
| 205 | std::unique_ptr<CommandChunk> chunk; | 191 | std::unique_ptr<CommandChunk> chunk; |
| 206 | std::thread worker_thread; | 192 | std::thread worker_thread; |
| 207 | 193 | ||
| 194 | State state; | ||
| 208 | Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_queue; | 195 | Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_queue; |
| 209 | Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_reserve; | 196 | Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_reserve; |
| 210 | std::mutex mutex; | 197 | std::mutex mutex; |
| 211 | std::condition_variable cv; | 198 | std::condition_variable cv; |
| 212 | std::atomic<u64> ticks = 0; | ||
| 213 | bool quit = false; | 199 | bool quit = false; |
| 214 | }; | 200 | }; |
| 215 | 201 | ||
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 5eca0ab91..2fd3b7f39 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | |||
| @@ -10,36 +10,18 @@ | |||
| 10 | #include "common/bit_util.h" | 10 | #include "common/bit_util.h" |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "video_core/renderer_vulkan/vk_device.h" | 12 | #include "video_core/renderer_vulkan/vk_device.h" |
| 13 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 13 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 15 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 14 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 16 | #include "video_core/renderer_vulkan/wrapper.h" | 15 | #include "video_core/renderer_vulkan/wrapper.h" |
| 17 | 16 | ||
| 18 | namespace Vulkan { | 17 | namespace Vulkan { |
| 19 | 18 | ||
| 20 | VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer, VKFence& fence, | 19 | VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer_) |
| 21 | u64 last_epoch) | 20 | : buffer{std::move(buffer_)} {} |
| 22 | : buffer{std::move(buffer)}, watch{fence}, last_epoch{last_epoch} {} | ||
| 23 | 21 | ||
| 24 | VKStagingBufferPool::StagingBuffer::StagingBuffer(StagingBuffer&& rhs) noexcept { | 22 | VKStagingBufferPool::VKStagingBufferPool(const VKDevice& device_, VKMemoryManager& memory_manager_, |
| 25 | buffer = std::move(rhs.buffer); | 23 | VKScheduler& scheduler_) |
| 26 | watch = std::move(rhs.watch); | 24 | : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {} |
| 27 | last_epoch = rhs.last_epoch; | ||
| 28 | } | ||
| 29 | |||
| 30 | VKStagingBufferPool::StagingBuffer::~StagingBuffer() = default; | ||
| 31 | |||
| 32 | VKStagingBufferPool::StagingBuffer& VKStagingBufferPool::StagingBuffer::operator=( | ||
| 33 | StagingBuffer&& rhs) noexcept { | ||
| 34 | buffer = std::move(rhs.buffer); | ||
| 35 | watch = std::move(rhs.watch); | ||
| 36 | last_epoch = rhs.last_epoch; | ||
| 37 | return *this; | ||
| 38 | } | ||
| 39 | |||
| 40 | VKStagingBufferPool::VKStagingBufferPool(const VKDevice& device, VKMemoryManager& memory_manager, | ||
| 41 | VKScheduler& scheduler) | ||
| 42 | : device{device}, memory_manager{memory_manager}, scheduler{scheduler} {} | ||
| 43 | 25 | ||
| 44 | VKStagingBufferPool::~VKStagingBufferPool() = default; | 26 | VKStagingBufferPool::~VKStagingBufferPool() = default; |
| 45 | 27 | ||
| @@ -51,7 +33,6 @@ VKBuffer& VKStagingBufferPool::GetUnusedBuffer(std::size_t size, bool host_visib | |||
| 51 | } | 33 | } |
| 52 | 34 | ||
| 53 | void VKStagingBufferPool::TickFrame() { | 35 | void VKStagingBufferPool::TickFrame() { |
| 54 | ++epoch; | ||
| 55 | current_delete_level = (current_delete_level + 1) % NumLevels; | 36 | current_delete_level = (current_delete_level + 1) % NumLevels; |
| 56 | 37 | ||
| 57 | ReleaseCache(true); | 38 | ReleaseCache(true); |
| @@ -59,11 +40,12 @@ void VKStagingBufferPool::TickFrame() { | |||
| 59 | } | 40 | } |
| 60 | 41 | ||
| 61 | VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_visible) { | 42 | VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_visible) { |
| 62 | for (auto& entry : GetCache(host_visible)[Common::Log2Ceil64(size)].entries) { | 43 | for (StagingBuffer& entry : GetCache(host_visible)[Common::Log2Ceil64(size)].entries) { |
| 63 | if (entry.watch.TryWatch(scheduler.GetFence())) { | 44 | if (!scheduler.IsFree(entry.tick)) { |
| 64 | entry.last_epoch = epoch; | 45 | continue; |
| 65 | return &*entry.buffer; | ||
| 66 | } | 46 | } |
| 47 | entry.tick = scheduler.CurrentTick(); | ||
| 48 | return &*entry.buffer; | ||
| 67 | } | 49 | } |
| 68 | return nullptr; | 50 | return nullptr; |
| 69 | } | 51 | } |
| @@ -86,8 +68,10 @@ VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_v | |||
| 86 | }); | 68 | }); |
| 87 | buffer->commit = memory_manager.Commit(buffer->handle, host_visible); | 69 | buffer->commit = memory_manager.Commit(buffer->handle, host_visible); |
| 88 | 70 | ||
| 89 | auto& entries = GetCache(host_visible)[log2].entries; | 71 | std::vector<StagingBuffer>& entries = GetCache(host_visible)[log2].entries; |
| 90 | return *entries.emplace_back(std::move(buffer), scheduler.GetFence(), epoch).buffer; | 72 | StagingBuffer& entry = entries.emplace_back(std::move(buffer)); |
| 73 | entry.tick = scheduler.CurrentTick(); | ||
| 74 | return *entry.buffer; | ||
| 91 | } | 75 | } |
| 92 | 76 | ||
| 93 | VKStagingBufferPool::StagingBuffersCache& VKStagingBufferPool::GetCache(bool host_visible) { | 77 | VKStagingBufferPool::StagingBuffersCache& VKStagingBufferPool::GetCache(bool host_visible) { |
| @@ -109,9 +93,8 @@ u64 VKStagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, std::size_t lo | |||
| 109 | auto& entries = staging.entries; | 93 | auto& entries = staging.entries; |
| 110 | const std::size_t old_size = entries.size(); | 94 | const std::size_t old_size = entries.size(); |
| 111 | 95 | ||
| 112 | const auto is_deleteable = [this](const auto& entry) { | 96 | const auto is_deleteable = [this](const StagingBuffer& entry) { |
| 113 | static constexpr u64 epochs_to_destroy = 180; | 97 | return scheduler.IsFree(entry.tick); |
| 114 | return entry.last_epoch + epochs_to_destroy < epoch && !entry.watch.IsUsed(); | ||
| 115 | }; | 98 | }; |
| 116 | const std::size_t begin_offset = staging.delete_index; | 99 | const std::size_t begin_offset = staging.delete_index; |
| 117 | const std::size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size); | 100 | const std::size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size); |
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 3c4901437..2dd5049ac 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h | |||
| @@ -10,13 +10,11 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | 11 | ||
| 12 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 12 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 13 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | 13 | #include "video_core/renderer_vulkan/wrapper.h" |
| 15 | 14 | ||
| 16 | namespace Vulkan { | 15 | namespace Vulkan { |
| 17 | 16 | ||
| 18 | class VKDevice; | 17 | class VKDevice; |
| 19 | class VKFenceWatch; | ||
| 20 | class VKScheduler; | 18 | class VKScheduler; |
| 21 | 19 | ||
| 22 | struct VKBuffer final { | 20 | struct VKBuffer final { |
| @@ -36,16 +34,10 @@ public: | |||
| 36 | 34 | ||
| 37 | private: | 35 | private: |
| 38 | struct StagingBuffer final { | 36 | struct StagingBuffer final { |
| 39 | explicit StagingBuffer(std::unique_ptr<VKBuffer> buffer, VKFence& fence, u64 last_epoch); | 37 | explicit StagingBuffer(std::unique_ptr<VKBuffer> buffer); |
| 40 | StagingBuffer(StagingBuffer&& rhs) noexcept; | ||
| 41 | StagingBuffer(const StagingBuffer&) = delete; | ||
| 42 | ~StagingBuffer(); | ||
| 43 | |||
| 44 | StagingBuffer& operator=(StagingBuffer&& rhs) noexcept; | ||
| 45 | 38 | ||
| 46 | std::unique_ptr<VKBuffer> buffer; | 39 | std::unique_ptr<VKBuffer> buffer; |
| 47 | VKFenceWatch watch; | 40 | u64 tick = 0; |
| 48 | u64 last_epoch = 0; | ||
| 49 | }; | 41 | }; |
| 50 | 42 | ||
| 51 | struct StagingBuffers final { | 43 | struct StagingBuffers final { |
| @@ -73,8 +65,6 @@ private: | |||
| 73 | StagingBuffersCache host_staging_buffers; | 65 | StagingBuffersCache host_staging_buffers; |
| 74 | StagingBuffersCache device_staging_buffers; | 66 | StagingBuffersCache device_staging_buffers; |
| 75 | 67 | ||
| 76 | u64 epoch = 0; | ||
| 77 | |||
| 78 | std::size_t current_delete_level = 0; | 68 | std::size_t current_delete_level = 0; |
| 79 | }; | 69 | }; |
| 80 | 70 | ||
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp index 3c9171a5e..5218c875b 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include "common/alignment.h" | 11 | #include "common/alignment.h" |
| 12 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| 13 | #include "video_core/renderer_vulkan/vk_device.h" | 13 | #include "video_core/renderer_vulkan/vk_device.h" |
| 14 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 15 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 16 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" | 15 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" |
| 17 | #include "video_core/renderer_vulkan/wrapper.h" | 16 | #include "video_core/renderer_vulkan/wrapper.h" |
| @@ -111,7 +110,7 @@ void VKStreamBuffer::Unmap(u64 size) { | |||
| 111 | } | 110 | } |
| 112 | auto& watch = current_watches[current_watch_cursor++]; | 111 | auto& watch = current_watches[current_watch_cursor++]; |
| 113 | watch.upper_bound = offset; | 112 | watch.upper_bound = offset; |
| 114 | watch.fence.Watch(scheduler.GetFence()); | 113 | watch.tick = scheduler.CurrentTick(); |
| 115 | } | 114 | } |
| 116 | 115 | ||
| 117 | void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) { | 116 | void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) { |
| @@ -157,7 +156,7 @@ void VKStreamBuffer::WaitPendingOperations(u64 requested_upper_bound) { | |||
| 157 | while (requested_upper_bound < wait_bound && wait_cursor < *invalidation_mark) { | 156 | while (requested_upper_bound < wait_bound && wait_cursor < *invalidation_mark) { |
| 158 | auto& watch = previous_watches[wait_cursor]; | 157 | auto& watch = previous_watches[wait_cursor]; |
| 159 | wait_bound = watch.upper_bound; | 158 | wait_bound = watch.upper_bound; |
| 160 | watch.fence.Wait(); | 159 | scheduler.Wait(watch.tick); |
| 161 | ++wait_cursor; | 160 | ++wait_cursor; |
| 162 | } | 161 | } |
| 163 | } | 162 | } |
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h index 689f0d276..5e15ad78f 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.h +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | namespace Vulkan { | 14 | namespace Vulkan { |
| 15 | 15 | ||
| 16 | class VKDevice; | 16 | class VKDevice; |
| 17 | class VKFence; | ||
| 18 | class VKFenceWatch; | 17 | class VKFenceWatch; |
| 19 | class VKScheduler; | 18 | class VKScheduler; |
| 20 | 19 | ||
| @@ -44,8 +43,8 @@ public: | |||
| 44 | } | 43 | } |
| 45 | 44 | ||
| 46 | private: | 45 | private: |
| 47 | struct Watch final { | 46 | struct Watch { |
| 48 | VKFenceWatch fence; | 47 | u64 tick{}; |
| 49 | u64 upper_bound{}; | 48 | u64 upper_bound{}; |
| 50 | }; | 49 | }; |
| 51 | 50 | ||
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 6bfd2abae..9636a7c65 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | #include "core/core.h" | 12 | #include "core/core.h" |
| 13 | #include "core/frontend/framebuffer_layout.h" | 13 | #include "core/frontend/framebuffer_layout.h" |
| 14 | #include "video_core/renderer_vulkan/vk_device.h" | 14 | #include "video_core/renderer_vulkan/vk_device.h" |
| 15 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | 15 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 16 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 16 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| 17 | #include "video_core/renderer_vulkan/wrapper.h" | 17 | #include "video_core/renderer_vulkan/wrapper.h" |
| 18 | 18 | ||
| @@ -56,8 +56,8 @@ VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 wi | |||
| 56 | 56 | ||
| 57 | } // Anonymous namespace | 57 | } // Anonymous namespace |
| 58 | 58 | ||
| 59 | VKSwapchain::VKSwapchain(VkSurfaceKHR surface, const VKDevice& device) | 59 | VKSwapchain::VKSwapchain(VkSurfaceKHR surface_, const VKDevice& device_, VKScheduler& scheduler_) |
| 60 | : surface{surface}, device{device} {} | 60 | : surface{surface_}, device{device_}, scheduler{scheduler_} {} |
| 61 | 61 | ||
| 62 | VKSwapchain::~VKSwapchain() = default; | 62 | VKSwapchain::~VKSwapchain() = default; |
| 63 | 63 | ||
| @@ -75,21 +75,18 @@ void VKSwapchain::Create(u32 width, u32 height, bool srgb) { | |||
| 75 | CreateSemaphores(); | 75 | CreateSemaphores(); |
| 76 | CreateImageViews(); | 76 | CreateImageViews(); |
| 77 | 77 | ||
| 78 | fences.resize(image_count, nullptr); | 78 | resource_ticks.clear(); |
| 79 | resource_ticks.resize(image_count); | ||
| 79 | } | 80 | } |
| 80 | 81 | ||
| 81 | void VKSwapchain::AcquireNextImage() { | 82 | void VKSwapchain::AcquireNextImage() { |
| 82 | device.GetLogical().AcquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(), | 83 | device.GetLogical().AcquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(), |
| 83 | *present_semaphores[frame_index], {}, &image_index); | 84 | *present_semaphores[frame_index], {}, &image_index); |
| 84 | 85 | ||
| 85 | if (auto& fence = fences[image_index]; fence) { | 86 | scheduler.Wait(resource_ticks[image_index]); |
| 86 | fence->Wait(); | ||
| 87 | fence->Release(); | ||
| 88 | fence = nullptr; | ||
| 89 | } | ||
| 90 | } | 87 | } |
| 91 | 88 | ||
| 92 | bool VKSwapchain::Present(VkSemaphore render_semaphore, VKFence& fence) { | 89 | bool VKSwapchain::Present(VkSemaphore render_semaphore) { |
| 93 | const VkSemaphore present_semaphore{*present_semaphores[frame_index]}; | 90 | const VkSemaphore present_semaphore{*present_semaphores[frame_index]}; |
| 94 | const std::array<VkSemaphore, 2> semaphores{present_semaphore, render_semaphore}; | 91 | const std::array<VkSemaphore, 2> semaphores{present_semaphore, render_semaphore}; |
| 95 | const auto present_queue{device.GetPresentQueue()}; | 92 | const auto present_queue{device.GetPresentQueue()}; |
| @@ -123,8 +120,7 @@ bool VKSwapchain::Present(VkSemaphore render_semaphore, VKFence& fence) { | |||
| 123 | break; | 120 | break; |
| 124 | } | 121 | } |
| 125 | 122 | ||
| 126 | ASSERT(fences[image_index] == nullptr); | 123 | resource_ticks[image_index] = scheduler.CurrentTick(); |
| 127 | fences[image_index] = &fence; | ||
| 128 | frame_index = (frame_index + 1) % static_cast<u32>(image_count); | 124 | frame_index = (frame_index + 1) % static_cast<u32>(image_count); |
| 129 | return recreated; | 125 | return recreated; |
| 130 | } | 126 | } |
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index a35d61345..6b39befdf 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h | |||
| @@ -16,11 +16,11 @@ struct FramebufferLayout; | |||
| 16 | namespace Vulkan { | 16 | namespace Vulkan { |
| 17 | 17 | ||
| 18 | class VKDevice; | 18 | class VKDevice; |
| 19 | class VKFence; | 19 | class VKScheduler; |
| 20 | 20 | ||
| 21 | class VKSwapchain { | 21 | class VKSwapchain { |
| 22 | public: | 22 | public: |
| 23 | explicit VKSwapchain(VkSurfaceKHR surface, const VKDevice& device); | 23 | explicit VKSwapchain(VkSurfaceKHR surface, const VKDevice& device, VKScheduler& scheduler); |
| 24 | ~VKSwapchain(); | 24 | ~VKSwapchain(); |
| 25 | 25 | ||
| 26 | /// Creates (or recreates) the swapchain with a given size. | 26 | /// Creates (or recreates) the swapchain with a given size. |
| @@ -31,7 +31,7 @@ public: | |||
| 31 | 31 | ||
| 32 | /// Presents the rendered image to the swapchain. Returns true when the swapchains had to be | 32 | /// Presents the rendered image to the swapchain. Returns true when the swapchains had to be |
| 33 | /// recreated. Takes responsability for the ownership of fence. | 33 | /// recreated. Takes responsability for the ownership of fence. |
| 34 | bool Present(VkSemaphore render_semaphore, VKFence& fence); | 34 | bool Present(VkSemaphore render_semaphore); |
| 35 | 35 | ||
| 36 | /// Returns true when the framebuffer layout has changed. | 36 | /// Returns true when the framebuffer layout has changed. |
| 37 | bool HasFramebufferChanged(const Layout::FramebufferLayout& framebuffer) const; | 37 | bool HasFramebufferChanged(const Layout::FramebufferLayout& framebuffer) const; |
| @@ -74,6 +74,7 @@ private: | |||
| 74 | 74 | ||
| 75 | const VkSurfaceKHR surface; | 75 | const VkSurfaceKHR surface; |
| 76 | const VKDevice& device; | 76 | const VKDevice& device; |
| 77 | VKScheduler& scheduler; | ||
| 77 | 78 | ||
| 78 | vk::SwapchainKHR swapchain; | 79 | vk::SwapchainKHR swapchain; |
| 79 | 80 | ||
| @@ -81,7 +82,7 @@ private: | |||
| 81 | std::vector<VkImage> images; | 82 | std::vector<VkImage> images; |
| 82 | std::vector<vk::ImageView> image_views; | 83 | std::vector<vk::ImageView> image_views; |
| 83 | std::vector<vk::Framebuffer> framebuffers; | 84 | std::vector<vk::Framebuffer> framebuffers; |
| 84 | std::vector<VKFence*> fences; | 85 | std::vector<u64> resource_ticks; |
| 85 | std::vector<vk::Semaphore> present_semaphores; | 86 | std::vector<vk::Semaphore> present_semaphores; |
| 86 | 87 | ||
| 87 | u32 image_index{}; | 88 | u32 image_index{}; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 06182d909..f2c8f2ae1 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -188,13 +188,11 @@ u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source, Tegra::Texture::Swizzl | |||
| 188 | 188 | ||
| 189 | } // Anonymous namespace | 189 | } // Anonymous namespace |
| 190 | 190 | ||
| 191 | CachedSurface::CachedSurface(const VKDevice& device, VKResourceManager& resource_manager, | 191 | CachedSurface::CachedSurface(const VKDevice& device, VKMemoryManager& memory_manager, |
| 192 | VKMemoryManager& memory_manager, VKScheduler& scheduler, | 192 | VKScheduler& scheduler, VKStagingBufferPool& staging_pool, |
| 193 | VKStagingBufferPool& staging_pool, GPUVAddr gpu_addr, | 193 | GPUVAddr gpu_addr, const SurfaceParams& params) |
| 194 | const SurfaceParams& params) | ||
| 195 | : SurfaceBase<View>{gpu_addr, params, device.IsOptimalAstcSupported()}, device{device}, | 194 | : SurfaceBase<View>{gpu_addr, params, device.IsOptimalAstcSupported()}, device{device}, |
| 196 | resource_manager{resource_manager}, memory_manager{memory_manager}, scheduler{scheduler}, | 195 | memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{staging_pool} { |
| 197 | staging_pool{staging_pool} { | ||
| 198 | if (params.IsBuffer()) { | 196 | if (params.IsBuffer()) { |
| 199 | buffer = CreateBuffer(device, params, host_memory_size); | 197 | buffer = CreateBuffer(device, params, host_memory_size); |
| 200 | commit = memory_manager.Commit(buffer, false); | 198 | commit = memory_manager.Commit(buffer, false); |
| @@ -493,18 +491,17 @@ VkImageView CachedSurfaceView::GetAttachment() { | |||
| 493 | VKTextureCache::VKTextureCache(VideoCore::RasterizerInterface& rasterizer, | 491 | VKTextureCache::VKTextureCache(VideoCore::RasterizerInterface& rasterizer, |
| 494 | Tegra::Engines::Maxwell3D& maxwell3d, | 492 | Tegra::Engines::Maxwell3D& maxwell3d, |
| 495 | Tegra::MemoryManager& gpu_memory, const VKDevice& device_, | 493 | Tegra::MemoryManager& gpu_memory, const VKDevice& device_, |
| 496 | VKResourceManager& resource_manager_, | ||
| 497 | VKMemoryManager& memory_manager_, VKScheduler& scheduler_, | 494 | VKMemoryManager& memory_manager_, VKScheduler& scheduler_, |
| 498 | VKStagingBufferPool& staging_pool_) | 495 | VKStagingBufferPool& staging_pool_) |
| 499 | : TextureCache(rasterizer, maxwell3d, gpu_memory, device_.IsOptimalAstcSupported()), | 496 | : TextureCache(rasterizer, maxwell3d, gpu_memory, device_.IsOptimalAstcSupported()), |
| 500 | device{device_}, resource_manager{resource_manager_}, | 497 | device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ |
| 501 | memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{staging_pool_} {} | 498 | staging_pool_} {} |
| 502 | 499 | ||
| 503 | VKTextureCache::~VKTextureCache() = default; | 500 | VKTextureCache::~VKTextureCache() = default; |
| 504 | 501 | ||
| 505 | Surface VKTextureCache::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { | 502 | Surface VKTextureCache::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { |
| 506 | return std::make_shared<CachedSurface>(device, resource_manager, memory_manager, scheduler, | 503 | return std::make_shared<CachedSurface>(device, memory_manager, scheduler, staging_pool, |
| 507 | staging_pool, gpu_addr, params); | 504 | gpu_addr, params); |
| 508 | } | 505 | } |
| 509 | 506 | ||
| 510 | void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface, | 507 | void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface, |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index e47d02c41..39202feba 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -23,7 +23,6 @@ namespace Vulkan { | |||
| 23 | 23 | ||
| 24 | class RasterizerVulkan; | 24 | class RasterizerVulkan; |
| 25 | class VKDevice; | 25 | class VKDevice; |
| 26 | class VKResourceManager; | ||
| 27 | class VKScheduler; | 26 | class VKScheduler; |
| 28 | class VKStagingBufferPool; | 27 | class VKStagingBufferPool; |
| 29 | 28 | ||
| @@ -41,10 +40,9 @@ class CachedSurface final : public VideoCommon::SurfaceBase<View> { | |||
| 41 | friend CachedSurfaceView; | 40 | friend CachedSurfaceView; |
| 42 | 41 | ||
| 43 | public: | 42 | public: |
| 44 | explicit CachedSurface(const VKDevice& device, VKResourceManager& resource_manager, | 43 | explicit CachedSurface(const VKDevice& device, VKMemoryManager& memory_manager, |
| 45 | VKMemoryManager& memory_manager, VKScheduler& scheduler, | 44 | VKScheduler& scheduler, VKStagingBufferPool& staging_pool, |
| 46 | VKStagingBufferPool& staging_pool, GPUVAddr gpu_addr, | 45 | GPUVAddr gpu_addr, const SurfaceParams& params); |
| 47 | const SurfaceParams& params); | ||
| 48 | ~CachedSurface(); | 46 | ~CachedSurface(); |
| 49 | 47 | ||
| 50 | void UploadTexture(const std::vector<u8>& staging_buffer) override; | 48 | void UploadTexture(const std::vector<u8>& staging_buffer) override; |
| @@ -98,7 +96,6 @@ private: | |||
| 98 | VkImageSubresourceRange GetImageSubresourceRange() const; | 96 | VkImageSubresourceRange GetImageSubresourceRange() const; |
| 99 | 97 | ||
| 100 | const VKDevice& device; | 98 | const VKDevice& device; |
| 101 | VKResourceManager& resource_manager; | ||
| 102 | VKMemoryManager& memory_manager; | 99 | VKMemoryManager& memory_manager; |
| 103 | VKScheduler& scheduler; | 100 | VKScheduler& scheduler; |
| 104 | VKStagingBufferPool& staging_pool; | 101 | VKStagingBufferPool& staging_pool; |
| @@ -198,9 +195,8 @@ class VKTextureCache final : public TextureCacheBase { | |||
| 198 | public: | 195 | public: |
| 199 | explicit VKTextureCache(VideoCore::RasterizerInterface& rasterizer, | 196 | explicit VKTextureCache(VideoCore::RasterizerInterface& rasterizer, |
| 200 | Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, | 197 | Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, |
| 201 | const VKDevice& device, VKResourceManager& resource_manager, | 198 | const VKDevice& device, VKMemoryManager& memory_manager, |
| 202 | VKMemoryManager& memory_manager, VKScheduler& scheduler, | 199 | VKScheduler& scheduler, VKStagingBufferPool& staging_pool); |
| 203 | VKStagingBufferPool& staging_pool); | ||
| 204 | ~VKTextureCache(); | 200 | ~VKTextureCache(); |
| 205 | 201 | ||
| 206 | private: | 202 | private: |
| @@ -215,7 +211,6 @@ private: | |||
| 215 | void BufferCopy(Surface& src_surface, Surface& dst_surface) override; | 211 | void BufferCopy(Surface& src_surface, Surface& dst_surface) override; |
| 216 | 212 | ||
| 217 | const VKDevice& device; | 213 | const VKDevice& device; |
| 218 | VKResourceManager& resource_manager; | ||
| 219 | VKMemoryManager& memory_manager; | 214 | VKMemoryManager& memory_manager; |
| 220 | VKScheduler& scheduler; | 215 | VKScheduler& scheduler; |
| 221 | VKStagingBufferPool& staging_pool; | 216 | VKStagingBufferPool& staging_pool; |
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp index fe291a148..1fb14e190 100644 --- a/src/video_core/renderer_vulkan/wrapper.cpp +++ b/src/video_core/renderer_vulkan/wrapper.cpp | |||
| @@ -148,6 +148,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 148 | X(vkGetFenceStatus); | 148 | X(vkGetFenceStatus); |
| 149 | X(vkGetImageMemoryRequirements); | 149 | X(vkGetImageMemoryRequirements); |
| 150 | X(vkGetQueryPoolResults); | 150 | X(vkGetQueryPoolResults); |
| 151 | X(vkGetSemaphoreCounterValueKHR); | ||
| 151 | X(vkMapMemory); | 152 | X(vkMapMemory); |
| 152 | X(vkQueueSubmit); | 153 | X(vkQueueSubmit); |
| 153 | X(vkResetFences); | 154 | X(vkResetFences); |
| @@ -156,6 +157,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 156 | X(vkUpdateDescriptorSetWithTemplateKHR); | 157 | X(vkUpdateDescriptorSetWithTemplateKHR); |
| 157 | X(vkUpdateDescriptorSets); | 158 | X(vkUpdateDescriptorSets); |
| 158 | X(vkWaitForFences); | 159 | X(vkWaitForFences); |
| 160 | X(vkWaitSemaphoresKHR); | ||
| 159 | #undef X | 161 | #undef X |
| 160 | } | 162 | } |
| 161 | 163 | ||
| @@ -574,7 +576,10 @@ Semaphore Device::CreateSemaphore() const { | |||
| 574 | .pNext = nullptr, | 576 | .pNext = nullptr, |
| 575 | .flags = 0, | 577 | .flags = 0, |
| 576 | }; | 578 | }; |
| 579 | return CreateSemaphore(ci); | ||
| 580 | } | ||
| 577 | 581 | ||
| 582 | Semaphore Device::CreateSemaphore(const VkSemaphoreCreateInfo& ci) const { | ||
| 578 | VkSemaphore object; | 583 | VkSemaphore object; |
| 579 | Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object)); | 584 | Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object)); |
| 580 | return Semaphore(object, handle, *dld); | 585 | return Semaphore(object, handle, *dld); |
| @@ -660,7 +665,7 @@ ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) cons | |||
| 660 | return ShaderModule(object, handle, *dld); | 665 | return ShaderModule(object, handle, *dld); |
| 661 | } | 666 | } |
| 662 | 667 | ||
| 663 | Event Device::CreateNewEvent() const { | 668 | Event Device::CreateEvent() const { |
| 664 | static constexpr VkEventCreateInfo ci{ | 669 | static constexpr VkEventCreateInfo ci{ |
| 665 | .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, | 670 | .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, |
| 666 | .pNext = nullptr, | 671 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h index b9d3fedc1..234e01693 100644 --- a/src/video_core/renderer_vulkan/wrapper.h +++ b/src/video_core/renderer_vulkan/wrapper.h | |||
| @@ -267,6 +267,7 @@ struct DeviceDispatch : public InstanceDispatch { | |||
| 267 | PFN_vkGetFenceStatus vkGetFenceStatus; | 267 | PFN_vkGetFenceStatus vkGetFenceStatus; |
| 268 | PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; | 268 | PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; |
| 269 | PFN_vkGetQueryPoolResults vkGetQueryPoolResults; | 269 | PFN_vkGetQueryPoolResults vkGetQueryPoolResults; |
| 270 | PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; | ||
| 270 | PFN_vkMapMemory vkMapMemory; | 271 | PFN_vkMapMemory vkMapMemory; |
| 271 | PFN_vkQueueSubmit vkQueueSubmit; | 272 | PFN_vkQueueSubmit vkQueueSubmit; |
| 272 | PFN_vkResetFences vkResetFences; | 273 | PFN_vkResetFences vkResetFences; |
| @@ -275,6 +276,7 @@ struct DeviceDispatch : public InstanceDispatch { | |||
| 275 | PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; | 276 | PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; |
| 276 | PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; | 277 | PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; |
| 277 | PFN_vkWaitForFences vkWaitForFences; | 278 | PFN_vkWaitForFences vkWaitForFences; |
| 279 | PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; | ||
| 278 | }; | 280 | }; |
| 279 | 281 | ||
| 280 | /// Loads instance agnostic function pointers. | 282 | /// Loads instance agnostic function pointers. |
| @@ -550,7 +552,6 @@ using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>; | |||
| 550 | using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>; | 552 | using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>; |
| 551 | using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>; | 553 | using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>; |
| 552 | using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>; | 554 | using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>; |
| 553 | using Semaphore = Handle<VkSemaphore, VkDevice, DeviceDispatch>; | ||
| 554 | using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>; | 555 | using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>; |
| 555 | using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>; | 556 | using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>; |
| 556 | 557 | ||
| @@ -582,7 +583,8 @@ public: | |||
| 582 | /// Construct a queue handle. | 583 | /// Construct a queue handle. |
| 583 | constexpr Queue(VkQueue queue, const DeviceDispatch& dld) noexcept : queue{queue}, dld{&dld} {} | 584 | constexpr Queue(VkQueue queue, const DeviceDispatch& dld) noexcept : queue{queue}, dld{&dld} {} |
| 584 | 585 | ||
| 585 | VkResult Submit(Span<VkSubmitInfo> submit_infos, VkFence fence) const noexcept { | 586 | VkResult Submit(Span<VkSubmitInfo> submit_infos, |
| 587 | VkFence fence = VK_NULL_HANDLE) const noexcept { | ||
| 586 | return dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence); | 588 | return dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence); |
| 587 | } | 589 | } |
| 588 | 590 | ||
| @@ -674,6 +676,44 @@ public: | |||
| 674 | } | 676 | } |
| 675 | }; | 677 | }; |
| 676 | 678 | ||
| 679 | class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> { | ||
| 680 | using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle; | ||
| 681 | |||
| 682 | public: | ||
| 683 | [[nodiscard]] u64 GetCounter() const { | ||
| 684 | u64 value; | ||
| 685 | Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value)); | ||
| 686 | return value; | ||
| 687 | } | ||
| 688 | |||
| 689 | /** | ||
| 690 | * Waits for a timeline semaphore on the host. | ||
| 691 | * | ||
| 692 | * @param value Value to wait | ||
| 693 | * @param timeout Time in nanoseconds to timeout | ||
| 694 | * @return True on successful wait, false on timeout | ||
| 695 | */ | ||
| 696 | bool Wait(u64 value, u64 timeout = std::numeric_limits<u64>::max()) const { | ||
| 697 | const VkSemaphoreWaitInfoKHR wait_info{ | ||
| 698 | .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR, | ||
| 699 | .pNext = nullptr, | ||
| 700 | .flags = 0, | ||
| 701 | .semaphoreCount = 1, | ||
| 702 | .pSemaphores = &handle, | ||
| 703 | .pValues = &value, | ||
| 704 | }; | ||
| 705 | const VkResult result = dld->vkWaitSemaphoresKHR(owner, &wait_info, timeout); | ||
| 706 | switch (result) { | ||
| 707 | case VK_SUCCESS: | ||
| 708 | return true; | ||
| 709 | case VK_TIMEOUT: | ||
| 710 | return false; | ||
| 711 | default: | ||
| 712 | throw Exception(result); | ||
| 713 | } | ||
| 714 | } | ||
| 715 | }; | ||
| 716 | |||
| 677 | class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> { | 717 | class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> { |
| 678 | using Handle<VkDevice, NoOwner, DeviceDispatch>::Handle; | 718 | using Handle<VkDevice, NoOwner, DeviceDispatch>::Handle; |
| 679 | 719 | ||
| @@ -694,6 +734,8 @@ public: | |||
| 694 | 734 | ||
| 695 | Semaphore CreateSemaphore() const; | 735 | Semaphore CreateSemaphore() const; |
| 696 | 736 | ||
| 737 | Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const; | ||
| 738 | |||
| 697 | Fence CreateFence(const VkFenceCreateInfo& ci) const; | 739 | Fence CreateFence(const VkFenceCreateInfo& ci) const; |
| 698 | 740 | ||
| 699 | DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const; | 741 | DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const; |
| @@ -721,7 +763,7 @@ public: | |||
| 721 | 763 | ||
| 722 | ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const; | 764 | ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const; |
| 723 | 765 | ||
| 724 | Event CreateNewEvent() const; | 766 | Event CreateEvent() const; |
| 725 | 767 | ||
| 726 | SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const; | 768 | SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const; |
| 727 | 769 | ||
diff --git a/src/video_core/shader/async_shaders.h b/src/video_core/shader/async_shaders.h index 7cf8d994c..7a99e1dc5 100644 --- a/src/video_core/shader/async_shaders.h +++ b/src/video_core/shader/async_shaders.h | |||
| @@ -9,6 +9,17 @@ | |||
| 9 | #include <shared_mutex> | 9 | #include <shared_mutex> |
| 10 | #include <thread> | 10 | #include <thread> |
| 11 | 11 | ||
| 12 | // This header includes both Vulkan and OpenGL headers, this has to be fixed | ||
| 13 | // Unfortunately, including OpenGL will include Windows.h that defines macros that can cause issues. | ||
| 14 | // Forcefully include glad early and undefine macros | ||
| 15 | #include <glad/glad.h> | ||
| 16 | #ifdef CreateEvent | ||
| 17 | #undef CreateEvent | ||
| 18 | #endif | ||
| 19 | #ifdef CreateSemaphore | ||
| 20 | #undef CreateSemaphore | ||
| 21 | #endif | ||
| 22 | |||
| 12 | #include "common/common_types.h" | 23 | #include "common/common_types.h" |
| 13 | #include "video_core/renderer_opengl/gl_device.h" | 24 | #include "video_core/renderer_opengl/gl_device.h" |
| 14 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 25 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index 336397cdb..4c8971615 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp | |||
| @@ -547,13 +547,13 @@ bool TryQuery(CFGRebuildState& state) { | |||
| 547 | gather_labels(q2.ssy_stack, state.ssy_labels, block); | 547 | gather_labels(q2.ssy_stack, state.ssy_labels, block); |
| 548 | gather_labels(q2.pbk_stack, state.pbk_labels, block); | 548 | gather_labels(q2.pbk_stack, state.pbk_labels, block); |
| 549 | if (std::holds_alternative<SingleBranch>(*block.branch)) { | 549 | if (std::holds_alternative<SingleBranch>(*block.branch)) { |
| 550 | const auto branch = std::get_if<SingleBranch>(block.branch.get()); | 550 | auto* branch = std::get_if<SingleBranch>(block.branch.get()); |
| 551 | if (!branch->condition.IsUnconditional()) { | 551 | if (!branch->condition.IsUnconditional()) { |
| 552 | q2.address = block.end + 1; | 552 | q2.address = block.end + 1; |
| 553 | state.queries.push_back(q2); | 553 | state.queries.push_back(q2); |
| 554 | } | 554 | } |
| 555 | 555 | ||
| 556 | Query conditional_query{q2}; | 556 | auto& conditional_query = state.queries.emplace_back(q2); |
| 557 | if (branch->is_sync) { | 557 | if (branch->is_sync) { |
| 558 | if (branch->address == unassigned_branch) { | 558 | if (branch->address == unassigned_branch) { |
| 559 | branch->address = conditional_query.ssy_stack.top(); | 559 | branch->address = conditional_query.ssy_stack.top(); |
| @@ -567,21 +567,21 @@ bool TryQuery(CFGRebuildState& state) { | |||
| 567 | conditional_query.pbk_stack.pop(); | 567 | conditional_query.pbk_stack.pop(); |
| 568 | } | 568 | } |
| 569 | conditional_query.address = branch->address; | 569 | conditional_query.address = branch->address; |
| 570 | state.queries.push_back(std::move(conditional_query)); | ||
| 571 | return true; | 570 | return true; |
| 572 | } | 571 | } |
| 573 | const auto multi_branch = std::get_if<MultiBranch>(block.branch.get()); | 572 | |
| 573 | const auto* multi_branch = std::get_if<MultiBranch>(block.branch.get()); | ||
| 574 | for (const auto& branch_case : multi_branch->branches) { | 574 | for (const auto& branch_case : multi_branch->branches) { |
| 575 | Query conditional_query{q2}; | 575 | auto& conditional_query = state.queries.emplace_back(q2); |
| 576 | conditional_query.address = branch_case.address; | 576 | conditional_query.address = branch_case.address; |
| 577 | state.queries.push_back(std::move(conditional_query)); | ||
| 578 | } | 577 | } |
| 578 | |||
| 579 | return true; | 579 | return true; |
| 580 | } | 580 | } |
| 581 | 581 | ||
| 582 | void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) { | 582 | void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) { |
| 583 | const auto get_expr = ([&](const Condition& cond) -> Expr { | 583 | const auto get_expr = [](const Condition& cond) -> Expr { |
| 584 | Expr result{}; | 584 | Expr result; |
| 585 | if (cond.cc != ConditionCode::T) { | 585 | if (cond.cc != ConditionCode::T) { |
| 586 | result = MakeExpr<ExprCondCode>(cond.cc); | 586 | result = MakeExpr<ExprCondCode>(cond.cc); |
| 587 | } | 587 | } |
| @@ -594,10 +594,10 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) { | |||
| 594 | } | 594 | } |
| 595 | Expr extra = MakeExpr<ExprPredicate>(pred); | 595 | Expr extra = MakeExpr<ExprPredicate>(pred); |
| 596 | if (negate) { | 596 | if (negate) { |
| 597 | extra = MakeExpr<ExprNot>(extra); | 597 | extra = MakeExpr<ExprNot>(std::move(extra)); |
| 598 | } | 598 | } |
| 599 | if (result) { | 599 | if (result) { |
| 600 | return MakeExpr<ExprAnd>(extra, result); | 600 | return MakeExpr<ExprAnd>(std::move(extra), std::move(result)); |
| 601 | } | 601 | } |
| 602 | return extra; | 602 | return extra; |
| 603 | } | 603 | } |
| @@ -605,9 +605,10 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) { | |||
| 605 | return result; | 605 | return result; |
| 606 | } | 606 | } |
| 607 | return MakeExpr<ExprBoolean>(true); | 607 | return MakeExpr<ExprBoolean>(true); |
| 608 | }); | 608 | }; |
| 609 | |||
| 609 | if (std::holds_alternative<SingleBranch>(*branch_info)) { | 610 | if (std::holds_alternative<SingleBranch>(*branch_info)) { |
| 610 | const auto branch = std::get_if<SingleBranch>(branch_info.get()); | 611 | const auto* branch = std::get_if<SingleBranch>(branch_info.get()); |
| 611 | if (branch->address < 0) { | 612 | if (branch->address < 0) { |
| 612 | if (branch->kill) { | 613 | if (branch->kill) { |
| 613 | mm.InsertReturn(get_expr(branch->condition), true); | 614 | mm.InsertReturn(get_expr(branch->condition), true); |
| @@ -619,7 +620,7 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) { | |||
| 619 | mm.InsertGoto(get_expr(branch->condition), branch->address); | 620 | mm.InsertGoto(get_expr(branch->condition), branch->address); |
| 620 | return; | 621 | return; |
| 621 | } | 622 | } |
| 622 | const auto multi_branch = std::get_if<MultiBranch>(branch_info.get()); | 623 | const auto* multi_branch = std::get_if<MultiBranch>(branch_info.get()); |
| 623 | for (const auto& branch_case : multi_branch->branches) { | 624 | for (const auto& branch_case : multi_branch->branches) { |
| 624 | mm.InsertGoto(MakeExpr<ExprGprEqual>(multi_branch->gpr, branch_case.cmp_value), | 625 | mm.InsertGoto(MakeExpr<ExprGprEqual>(multi_branch->gpr, branch_case.cmp_value), |
| 625 | branch_case.address); | 626 | branch_case.address); |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 6a71d9644..a9738e298 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -56,7 +56,7 @@ bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* eve | |||
| 56 | case Qt::Key_Return: | 56 | case Qt::Key_Return: |
| 57 | case Qt::Key_Enter: { | 57 | case Qt::Key_Enter: { |
| 58 | if (gamelist->search_field->visible == 1) { | 58 | if (gamelist->search_field->visible == 1) { |
| 59 | QString file_path = gamelist->getLastFilterResultItem(); | 59 | const QString file_path = gamelist->GetLastFilterResultItem(); |
| 60 | 60 | ||
| 61 | // To avoid loading error dialog loops while confirming them using enter | 61 | // To avoid loading error dialog loops while confirming them using enter |
| 62 | // Also users usually want to run a different game after closing one | 62 | // Also users usually want to run a different game after closing one |
| @@ -83,22 +83,25 @@ void GameListSearchField::setFilterResult(int visible, int total) { | |||
| 83 | label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); | 83 | label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | QString GameList::getLastFilterResultItem() const { | 86 | QString GameList::GetLastFilterResultItem() const { |
| 87 | QStandardItem* folder; | ||
| 88 | QStandardItem* child; | ||
| 89 | QString file_path; | 87 | QString file_path; |
| 90 | const int folder_count = item_model->rowCount(); | 88 | const int folder_count = item_model->rowCount(); |
| 89 | |||
| 91 | for (int i = 0; i < folder_count; ++i) { | 90 | for (int i = 0; i < folder_count; ++i) { |
| 92 | folder = item_model->item(i, 0); | 91 | const QStandardItem* folder = item_model->item(i, 0); |
| 93 | const QModelIndex folder_index = folder->index(); | 92 | const QModelIndex folder_index = folder->index(); |
| 94 | const int children_count = folder->rowCount(); | 93 | const int children_count = folder->rowCount(); |
| 94 | |||
| 95 | for (int j = 0; j < children_count; ++j) { | 95 | for (int j = 0; j < children_count; ++j) { |
| 96 | if (!tree_view->isRowHidden(j, folder_index)) { | 96 | if (tree_view->isRowHidden(j, folder_index)) { |
| 97 | child = folder->child(j, 0); | 97 | continue; |
| 98 | file_path = child->data(GameListItemPath::FullPathRole).toString(); | ||
| 99 | } | 98 | } |
| 99 | |||
| 100 | const QStandardItem* child = folder->child(j, 0); | ||
| 101 | file_path = child->data(GameListItemPath::FullPathRole).toString(); | ||
| 100 | } | 102 | } |
| 101 | } | 103 | } |
| 104 | |||
| 102 | return file_path; | 105 | return file_path; |
| 103 | } | 106 | } |
| 104 | 107 | ||
| @@ -123,7 +126,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { | |||
| 123 | edit_filter->setPlaceholderText(tr("Enter pattern to filter")); | 126 | edit_filter->setPlaceholderText(tr("Enter pattern to filter")); |
| 124 | edit_filter->installEventFilter(key_release_eater); | 127 | edit_filter->installEventFilter(key_release_eater); |
| 125 | edit_filter->setClearButtonEnabled(true); | 128 | edit_filter->setClearButtonEnabled(true); |
| 126 | connect(edit_filter, &QLineEdit::textChanged, parent, &GameList::onTextChanged); | 129 | connect(edit_filter, &QLineEdit::textChanged, parent, &GameList::OnTextChanged); |
| 127 | label_filter_result = new QLabel; | 130 | label_filter_result = new QLabel; |
| 128 | button_filter_close = new QToolButton(this); | 131 | button_filter_close = new QToolButton(this); |
| 129 | button_filter_close->setText(QStringLiteral("X")); | 132 | button_filter_close->setText(QStringLiteral("X")); |
| @@ -133,7 +136,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { | |||
| 133 | "#000000; font-weight: bold; background: #F0F0F0; }" | 136 | "#000000; font-weight: bold; background: #F0F0F0; }" |
| 134 | "QToolButton:hover{ border: none; padding: 0px; color: " | 137 | "QToolButton:hover{ border: none; padding: 0px; color: " |
| 135 | "#EEEEEE; font-weight: bold; background: #E81123}")); | 138 | "#EEEEEE; font-weight: bold; background: #E81123}")); |
| 136 | connect(button_filter_close, &QToolButton::clicked, parent, &GameList::onFilterCloseClicked); | 139 | connect(button_filter_close, &QToolButton::clicked, parent, &GameList::OnFilterCloseClicked); |
| 137 | layout_filter->setSpacing(10); | 140 | layout_filter->setSpacing(10); |
| 138 | layout_filter->addWidget(label_filter); | 141 | layout_filter->addWidget(label_filter); |
| 139 | layout_filter->addWidget(edit_filter); | 142 | layout_filter->addWidget(edit_filter); |
| @@ -159,16 +162,22 @@ static bool ContainsAllWords(const QString& haystack, const QString& userinput) | |||
| 159 | } | 162 | } |
| 160 | 163 | ||
| 161 | // Syncs the expanded state of Game Directories with settings to persist across sessions | 164 | // Syncs the expanded state of Game Directories with settings to persist across sessions |
| 162 | void GameList::onItemExpanded(const QModelIndex& item) { | 165 | void GameList::OnItemExpanded(const QModelIndex& item) { |
| 163 | const auto type = item.data(GameListItem::TypeRole).value<GameListItemType>(); | 166 | const auto type = item.data(GameListItem::TypeRole).value<GameListItemType>(); |
| 164 | if (type == GameListItemType::CustomDir || type == GameListItemType::SdmcDir || | 167 | const bool is_dir = type == GameListItemType::CustomDir || type == GameListItemType::SdmcDir || |
| 165 | type == GameListItemType::UserNandDir || type == GameListItemType::SysNandDir) | 168 | type == GameListItemType::UserNandDir || |
| 166 | item.data(GameListDir::GameDirRole).value<UISettings::GameDir*>()->expanded = | 169 | type == GameListItemType::SysNandDir; |
| 167 | tree_view->isExpanded(item); | 170 | |
| 171 | if (!is_dir) { | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | |||
| 175 | auto* game_dir = item.data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); | ||
| 176 | game_dir->expanded = tree_view->isExpanded(item); | ||
| 168 | } | 177 | } |
| 169 | 178 | ||
| 170 | // Event in order to filter the gamelist after editing the searchfield | 179 | // Event in order to filter the gamelist after editing the searchfield |
| 171 | void GameList::onTextChanged(const QString& new_text) { | 180 | void GameList::OnTextChanged(const QString& new_text) { |
| 172 | const int folder_count = tree_view->model()->rowCount(); | 181 | const int folder_count = tree_view->model()->rowCount(); |
| 173 | QString edit_filter_text = new_text.toLower(); | 182 | QString edit_filter_text = new_text.toLower(); |
| 174 | QStandardItem* folder; | 183 | QStandardItem* folder; |
| @@ -224,7 +233,7 @@ void GameList::onTextChanged(const QString& new_text) { | |||
| 224 | } | 233 | } |
| 225 | } | 234 | } |
| 226 | 235 | ||
| 227 | void GameList::onUpdateThemedIcons() { | 236 | void GameList::OnUpdateThemedIcons() { |
| 228 | for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) { | 237 | for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) { |
| 229 | QStandardItem* child = item_model->invisibleRootItem()->child(i); | 238 | QStandardItem* child = item_model->invisibleRootItem()->child(i); |
| 230 | 239 | ||
| @@ -276,7 +285,7 @@ void GameList::onUpdateThemedIcons() { | |||
| 276 | } | 285 | } |
| 277 | } | 286 | } |
| 278 | 287 | ||
| 279 | void GameList::onFilterCloseClicked() { | 288 | void GameList::OnFilterCloseClicked() { |
| 280 | main_window->filterBarSetChecked(false); | 289 | main_window->filterBarSetChecked(false); |
| 281 | } | 290 | } |
| 282 | 291 | ||
| @@ -317,11 +326,11 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide | |||
| 317 | } | 326 | } |
| 318 | item_model->setSortRole(GameListItemPath::SortRole); | 327 | item_model->setSortRole(GameListItemPath::SortRole); |
| 319 | 328 | ||
| 320 | connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::onUpdateThemedIcons); | 329 | connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons); |
| 321 | connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry); | 330 | connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry); |
| 322 | connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu); | 331 | connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu); |
| 323 | connect(tree_view, &QTreeView::expanded, this, &GameList::onItemExpanded); | 332 | connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded); |
| 324 | connect(tree_view, &QTreeView::collapsed, this, &GameList::onItemExpanded); | 333 | connect(tree_view, &QTreeView::collapsed, this, &GameList::OnItemExpanded); |
| 325 | 334 | ||
| 326 | // We must register all custom types with the Qt Automoc system so that we are able to use | 335 | // We must register all custom types with the Qt Automoc system so that we are able to use |
| 327 | // it with signals/slots. In this case, QList falls under the umbrells of custom types. | 336 | // it with signals/slots. In this case, QList falls under the umbrells of custom types. |
| @@ -338,17 +347,17 @@ GameList::~GameList() { | |||
| 338 | emit ShouldCancelWorker(); | 347 | emit ShouldCancelWorker(); |
| 339 | } | 348 | } |
| 340 | 349 | ||
| 341 | void GameList::setFilterFocus() { | 350 | void GameList::SetFilterFocus() { |
| 342 | if (tree_view->model()->rowCount() > 0) { | 351 | if (tree_view->model()->rowCount() > 0) { |
| 343 | search_field->setFocus(); | 352 | search_field->setFocus(); |
| 344 | } | 353 | } |
| 345 | } | 354 | } |
| 346 | 355 | ||
| 347 | void GameList::setFilterVisible(bool visibility) { | 356 | void GameList::SetFilterVisible(bool visibility) { |
| 348 | search_field->setVisible(visibility); | 357 | search_field->setVisible(visibility); |
| 349 | } | 358 | } |
| 350 | 359 | ||
| 351 | void GameList::clearFilter() { | 360 | void GameList::ClearFilter() { |
| 352 | search_field->clear(); | 361 | search_field->clear(); |
| 353 | } | 362 | } |
| 354 | 363 | ||
| @@ -397,10 +406,11 @@ void GameList::ValidateEntry(const QModelIndex& item) { | |||
| 397 | } | 406 | } |
| 398 | } | 407 | } |
| 399 | 408 | ||
| 400 | bool GameList::isEmpty() const { | 409 | bool GameList::IsEmpty() const { |
| 401 | for (int i = 0; i < item_model->rowCount(); i++) { | 410 | for (int i = 0; i < item_model->rowCount(); i++) { |
| 402 | const QStandardItem* child = item_model->invisibleRootItem()->child(i); | 411 | const QStandardItem* child = item_model->invisibleRootItem()->child(i); |
| 403 | const auto type = static_cast<GameListItemType>(child->type()); | 412 | const auto type = static_cast<GameListItemType>(child->type()); |
| 413 | |||
| 404 | if (!child->hasChildren() && | 414 | if (!child->hasChildren() && |
| 405 | (type == GameListItemType::SdmcDir || type == GameListItemType::UserNandDir || | 415 | (type == GameListItemType::SdmcDir || type == GameListItemType::UserNandDir || |
| 406 | type == GameListItemType::SysNandDir)) { | 416 | type == GameListItemType::SysNandDir)) { |
| @@ -408,11 +418,12 @@ bool GameList::isEmpty() const { | |||
| 408 | i--; | 418 | i--; |
| 409 | } | 419 | } |
| 410 | } | 420 | } |
| 421 | |||
| 411 | return !item_model->invisibleRootItem()->hasChildren(); | 422 | return !item_model->invisibleRootItem()->hasChildren(); |
| 412 | } | 423 | } |
| 413 | 424 | ||
| 414 | void GameList::DonePopulating(QStringList watch_list) { | 425 | void GameList::DonePopulating(const QStringList& watch_list) { |
| 415 | emit ShowList(!isEmpty()); | 426 | emit ShowList(!IsEmpty()); |
| 416 | 427 | ||
| 417 | item_model->invisibleRootItem()->appendRow(new GameListAddDir()); | 428 | item_model->invisibleRootItem()->appendRow(new GameListAddDir()); |
| 418 | 429 | ||
| @@ -472,7 +483,7 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { | |||
| 472 | context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location)); | 483 | context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location)); |
| 473 | } | 484 | } |
| 474 | 485 | ||
| 475 | void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, std::string path) { | 486 | void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) { |
| 476 | QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location")); | 487 | QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location")); |
| 477 | QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location")); | 488 | QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location")); |
| 478 | QAction* open_transferable_shader_cache = | 489 | QAction* open_transferable_shader_cache = |
| @@ -690,12 +701,15 @@ void GameList::SaveInterfaceLayout() { | |||
| 690 | } | 701 | } |
| 691 | 702 | ||
| 692 | void GameList::LoadInterfaceLayout() { | 703 | void GameList::LoadInterfaceLayout() { |
| 693 | auto header = tree_view->header(); | 704 | auto* header = tree_view->header(); |
| 694 | if (!header->restoreState(UISettings::values.gamelist_header_state)) { | 705 | |
| 695 | // We are using the name column to display icons and titles | 706 | if (header->restoreState(UISettings::values.gamelist_header_state)) { |
| 696 | // so make it as large as possible as default. | 707 | return; |
| 697 | header->resizeSection(COLUMN_NAME, header->width()); | ||
| 698 | } | 708 | } |
| 709 | |||
| 710 | // We are using the name column to display icons and titles | ||
| 711 | // so make it as large as possible as default. | ||
| 712 | header->resizeSection(COLUMN_NAME, header->width()); | ||
| 699 | } | 713 | } |
| 700 | 714 | ||
| 701 | const QStringList GameList::supported_file_extensions = { | 715 | const QStringList GameList::supported_file_extensions = { |
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 78e2ba169..58059a3c4 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -67,11 +67,11 @@ public: | |||
| 67 | FileSys::ManualContentProvider* provider, GMainWindow* parent = nullptr); | 67 | FileSys::ManualContentProvider* provider, GMainWindow* parent = nullptr); |
| 68 | ~GameList() override; | 68 | ~GameList() override; |
| 69 | 69 | ||
| 70 | QString getLastFilterResultItem() const; | 70 | QString GetLastFilterResultItem() const; |
| 71 | void clearFilter(); | 71 | void ClearFilter(); |
| 72 | void setFilterFocus(); | 72 | void SetFilterFocus(); |
| 73 | void setFilterVisible(bool visibility); | 73 | void SetFilterVisible(bool visibility); |
| 74 | bool isEmpty() const; | 74 | bool IsEmpty() const; |
| 75 | 75 | ||
| 76 | void LoadCompatibilityList(); | 76 | void LoadCompatibilityList(); |
| 77 | void PopulateAsync(QVector<UISettings::GameDir>& game_dirs); | 77 | void PopulateAsync(QVector<UISettings::GameDir>& game_dirs); |
| @@ -82,7 +82,7 @@ public: | |||
| 82 | static const QStringList supported_file_extensions; | 82 | static const QStringList supported_file_extensions; |
| 83 | 83 | ||
| 84 | signals: | 84 | signals: |
| 85 | void GameChosen(QString game_path); | 85 | void GameChosen(const QString& game_path); |
| 86 | void ShouldCancelWorker(); | 86 | void ShouldCancelWorker(); |
| 87 | void OpenFolderRequested(u64 program_id, GameListOpenTarget target, | 87 | void OpenFolderRequested(u64 program_id, GameListOpenTarget target, |
| 88 | const std::string& game_path); | 88 | const std::string& game_path); |
| @@ -99,21 +99,21 @@ signals: | |||
| 99 | void ShowList(bool show); | 99 | void ShowList(bool show); |
| 100 | 100 | ||
| 101 | private slots: | 101 | private slots: |
| 102 | void onItemExpanded(const QModelIndex& item); | 102 | void OnItemExpanded(const QModelIndex& item); |
| 103 | void onTextChanged(const QString& new_text); | 103 | void OnTextChanged(const QString& new_text); |
| 104 | void onFilterCloseClicked(); | 104 | void OnFilterCloseClicked(); |
| 105 | void onUpdateThemedIcons(); | 105 | void OnUpdateThemedIcons(); |
| 106 | 106 | ||
| 107 | private: | 107 | private: |
| 108 | void AddDirEntry(GameListDir* entry_items); | 108 | void AddDirEntry(GameListDir* entry_items); |
| 109 | void AddEntry(const QList<QStandardItem*>& entry_items, GameListDir* parent); | 109 | void AddEntry(const QList<QStandardItem*>& entry_items, GameListDir* parent); |
| 110 | void ValidateEntry(const QModelIndex& item); | 110 | void ValidateEntry(const QModelIndex& item); |
| 111 | void DonePopulating(QStringList watch_list); | 111 | void DonePopulating(const QStringList& watch_list); |
| 112 | 112 | ||
| 113 | void RefreshGameDirectory(); | 113 | void RefreshGameDirectory(); |
| 114 | 114 | ||
| 115 | void PopupContextMenu(const QPoint& menu_location); | 115 | void PopupContextMenu(const QPoint& menu_location); |
| 116 | void AddGamePopup(QMenu& context_menu, u64 program_id, std::string path); | 116 | void AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path); |
| 117 | void AddCustomDirPopup(QMenu& context_menu, QModelIndex selected); | 117 | void AddCustomDirPopup(QMenu& context_menu, QModelIndex selected); |
| 118 | void AddPermDirPopup(QMenu& context_menu, QModelIndex selected); | 118 | void AddPermDirPopup(QMenu& context_menu, QModelIndex selected); |
| 119 | 119 | ||
diff --git a/src/yuzu/install_dialog.h b/src/yuzu/install_dialog.h index e4aba1b06..68e03fe4e 100644 --- a/src/yuzu/install_dialog.h +++ b/src/yuzu/install_dialog.h | |||
| @@ -20,9 +20,8 @@ public: | |||
| 20 | explicit InstallDialog(QWidget* parent, const QStringList& files); | 20 | explicit InstallDialog(QWidget* parent, const QStringList& files); |
| 21 | ~InstallDialog() override; | 21 | ~InstallDialog() override; |
| 22 | 22 | ||
| 23 | QStringList GetFiles() const; | 23 | [[nodiscard]] QStringList GetFiles() const; |
| 24 | bool ShouldOverwriteFiles() const; | 24 | [[nodiscard]] int GetMinimumWidth() const; |
| 25 | int GetMinimumWidth() const; | ||
| 26 | 25 | ||
| 27 | private: | 26 | private: |
| 28 | QListWidget* file_list; | 27 | QListWidget* file_list; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index bb3a08ac7..6a2a88dd8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -838,7 +838,7 @@ void GMainWindow::RestoreUIState() { | |||
| 838 | OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked()); | 838 | OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked()); |
| 839 | 839 | ||
| 840 | ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar); | 840 | ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar); |
| 841 | game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked()); | 841 | game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked()); |
| 842 | 842 | ||
| 843 | ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar); | 843 | ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar); |
| 844 | statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); | 844 | statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); |
| @@ -1199,11 +1199,12 @@ void GMainWindow::ShutdownGame() { | |||
| 1199 | render_window->hide(); | 1199 | render_window->hide(); |
| 1200 | loading_screen->hide(); | 1200 | loading_screen->hide(); |
| 1201 | loading_screen->Clear(); | 1201 | loading_screen->Clear(); |
| 1202 | if (game_list->isEmpty()) | 1202 | if (game_list->IsEmpty()) { |
| 1203 | game_list_placeholder->show(); | 1203 | game_list_placeholder->show(); |
| 1204 | else | 1204 | } else { |
| 1205 | game_list->show(); | 1205 | game_list->show(); |
| 1206 | game_list->setFilterFocus(); | 1206 | } |
| 1207 | game_list->SetFilterFocus(); | ||
| 1207 | 1208 | ||
| 1208 | setMouseTracking(false); | 1209 | setMouseTracking(false); |
| 1209 | ui.centralwidget->setMouseTracking(false); | 1210 | ui.centralwidget->setMouseTracking(false); |
| @@ -2361,11 +2362,11 @@ void GMainWindow::OnAbout() { | |||
| 2361 | } | 2362 | } |
| 2362 | 2363 | ||
| 2363 | void GMainWindow::OnToggleFilterBar() { | 2364 | void GMainWindow::OnToggleFilterBar() { |
| 2364 | game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked()); | 2365 | game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked()); |
| 2365 | if (ui.action_Show_Filter_Bar->isChecked()) { | 2366 | if (ui.action_Show_Filter_Bar->isChecked()) { |
| 2366 | game_list->setFilterFocus(); | 2367 | game_list->SetFilterFocus(); |
| 2367 | } else { | 2368 | } else { |
| 2368 | game_list->clearFilter(); | 2369 | game_list->ClearFilter(); |
| 2369 | } | 2370 | } |
| 2370 | } | 2371 | } |
| 2371 | 2372 | ||