diff options
54 files changed, 662 insertions, 198 deletions
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh index 9b451d3ab..5070b92d1 100755 --- a/.ci/scripts/linux/docker.sh +++ b/.ci/scripts/linux/docker.sh | |||
| @@ -18,7 +18,8 @@ cmake .. \ | |||
| 18 | -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ | 18 | -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ |
| 19 | -DENABLE_QT_TRANSLATION=ON \ | 19 | -DENABLE_QT_TRANSLATION=ON \ |
| 20 | -DUSE_DISCORD_PRESENCE=ON \ | 20 | -DUSE_DISCORD_PRESENCE=ON \ |
| 21 | -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} | 21 | -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \ |
| 22 | -DYUZU_USE_BUNDLED_FFMPEG=ON | ||
| 22 | 23 | ||
| 23 | make -j$(nproc) | 24 | make -j$(nproc) |
| 24 | 25 | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt index 857550e71..92c9929cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -25,7 +25,7 @@ option(YUZU_USE_BUNDLED_BOOST "Download bundled Boost" OFF) | |||
| 25 | 25 | ||
| 26 | option(YUZU_USE_BUNDLED_LIBUSB "Compile bundled libusb" OFF) | 26 | option(YUZU_USE_BUNDLED_LIBUSB "Compile bundled libusb" OFF) |
| 27 | 27 | ||
| 28 | CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" ON "WIN32" OFF) | 28 | option(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" "${WIN32}") |
| 29 | 29 | ||
| 30 | option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) | 30 | option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) |
| 31 | 31 | ||
| @@ -496,7 +496,7 @@ endif() | |||
| 496 | # Ensure libusb is properly configured (based on dolphin libusb include) | 496 | # Ensure libusb is properly configured (based on dolphin libusb include) |
| 497 | if(NOT APPLE AND NOT YUZU_USE_BUNDLED_LIBUSB) | 497 | if(NOT APPLE AND NOT YUZU_USE_BUNDLED_LIBUSB) |
| 498 | include(FindPkgConfig) | 498 | include(FindPkgConfig) |
| 499 | if (PKG_CONFIG_FOUND) | 499 | if (PKG_CONFIG_FOUND AND NOT CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD") |
| 500 | pkg_check_modules(LIBUSB QUIET libusb-1.0>=1.0.24) | 500 | pkg_check_modules(LIBUSB QUIET libusb-1.0>=1.0.24) |
| 501 | else() | 501 | else() |
| 502 | find_package(LibUSB) | 502 | find_package(LibUSB) |
| @@ -604,6 +604,8 @@ if (YUZU_USE_BUNDLED_FFMPEG) | |||
| 604 | --disable-vdpau | 604 | --disable-vdpau |
| 605 | --enable-decoder=h264 | 605 | --enable-decoder=h264 |
| 606 | --enable-decoder=vp9 | 606 | --enable-decoder=vp9 |
| 607 | --cc="${CMAKE_C_COMPILER}" | ||
| 608 | --cxx="${CMAKE_CXX_COMPILER}" | ||
| 607 | WORKING_DIRECTORY | 609 | WORKING_DIRECTORY |
| 608 | ${FFmpeg_BUILD_DIR} | 610 | ${FFmpeg_BUILD_DIR} |
| 609 | ) | 611 | ) |
diff --git a/externals/libusb/CMakeLists.txt b/externals/libusb/CMakeLists.txt index 151ddc462..12bdc097a 100644 --- a/externals/libusb/CMakeLists.txt +++ b/externals/libusb/CMakeLists.txt | |||
| @@ -67,6 +67,8 @@ if (MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux") OR APPLE) | |||
| 67 | "${LIBUSB_MAKEFILE}" | 67 | "${LIBUSB_MAKEFILE}" |
| 68 | COMMAND | 68 | COMMAND |
| 69 | env | 69 | env |
| 70 | CC="${CMAKE_C_COMPILER}" | ||
| 71 | CXX="${CMAKE_CXX_COMPILER}" | ||
| 70 | CFLAGS="${LIBUSB_CFLAGS}" | 72 | CFLAGS="${LIBUSB_CFLAGS}" |
| 71 | sh "${LIBUSB_CONFIGURE}" | 73 | sh "${LIBUSB_CONFIGURE}" |
| 72 | ${LIBUSB_CONFIGURE_ARGS} | 74 | ${LIBUSB_CONFIGURE_ARGS} |
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 2a5a7596c..6661244cf 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | #include <windows.h> | 6 | #include <windows.h> |
| 7 | #include "common/dynamic_library.h" | 7 | #include "common/dynamic_library.h" |
| 8 | 8 | ||
| 9 | #elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv | 9 | #elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv |
| 10 | 10 | ||
| 11 | #ifndef _GNU_SOURCE | 11 | #ifndef _GNU_SOURCE |
| 12 | #define _GNU_SOURCE | 12 | #define _GNU_SOURCE |
| @@ -343,7 +343,7 @@ private: | |||
| 343 | std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset | 343 | std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset |
| 344 | }; | 344 | }; |
| 345 | 345 | ||
| 346 | #elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv | 346 | #elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv |
| 347 | 347 | ||
| 348 | class HostMemory::Impl { | 348 | class HostMemory::Impl { |
| 349 | public: | 349 | public: |
| @@ -357,7 +357,12 @@ public: | |||
| 357 | }); | 357 | }); |
| 358 | 358 | ||
| 359 | // Backing memory initialization | 359 | // Backing memory initialization |
| 360 | #if defined(__FreeBSD__) && __FreeBSD__ < 13 | ||
| 361 | // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 | ||
| 362 | fd = shm_open(SHM_ANON, O_RDWR, 0600); | ||
| 363 | #else | ||
| 360 | fd = memfd_create("HostMemory", 0); | 364 | fd = memfd_create("HostMemory", 0); |
| 365 | #endif | ||
| 361 | if (fd == -1) { | 366 | if (fd == -1) { |
| 362 | LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); | 367 | LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); |
| 363 | throw std::bad_alloc{}; | 368 | throw std::bad_alloc{}; |
diff --git a/src/common/settings.h b/src/common/settings.h index d8730f515..a88ee045d 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -42,6 +42,11 @@ enum class CPUAccuracy : u32 { | |||
| 42 | Unsafe = 2, | 42 | Unsafe = 2, |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | enum class FullscreenMode : u32 { | ||
| 46 | Borderless = 0, | ||
| 47 | Exclusive = 1, | ||
| 48 | }; | ||
| 49 | |||
| 45 | /** The BasicSetting class is a simple resource manager. It defines a label and default value | 50 | /** The BasicSetting class is a simple resource manager. It defines a label and default value |
| 46 | * alongside the actual value of the setting for simpler and less-error prone use with frontend | 51 | * alongside the actual value of the setting for simpler and less-error prone use with frontend |
| 47 | * configurations. Setting a default value and label is required, though subclasses may deviate from | 52 | * configurations. Setting a default value and label is required, though subclasses may deviate from |
| @@ -314,6 +319,7 @@ struct Values { | |||
| 314 | // Renderer | 319 | // Renderer |
| 315 | Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"}; | 320 | Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"}; |
| 316 | BasicSetting<bool> renderer_debug{false, "debug"}; | 321 | BasicSetting<bool> renderer_debug{false, "debug"}; |
| 322 | BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"}; | ||
| 317 | BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; | 323 | BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; |
| 318 | BasicSetting<bool> disable_shader_loop_safety_checks{false, | 324 | BasicSetting<bool> disable_shader_loop_safety_checks{false, |
| 319 | "disable_shader_loop_safety_checks"}; | 325 | "disable_shader_loop_safety_checks"}; |
| @@ -322,11 +328,11 @@ struct Values { | |||
| 322 | Setting<u16> resolution_factor{1, "resolution_factor"}; | 328 | Setting<u16> resolution_factor{1, "resolution_factor"}; |
| 323 | // *nix platforms may have issues with the borderless windowed fullscreen mode. | 329 | // *nix platforms may have issues with the borderless windowed fullscreen mode. |
| 324 | // Default to exclusive fullscreen on these platforms for now. | 330 | // Default to exclusive fullscreen on these platforms for now. |
| 325 | Setting<int> fullscreen_mode{ | 331 | Setting<FullscreenMode> fullscreen_mode{ |
| 326 | #ifdef _WIN32 | 332 | #ifdef _WIN32 |
| 327 | 0, | 333 | FullscreenMode::Borderless, |
| 328 | #else | 334 | #else |
| 329 | 1, | 335 | FullscreenMode::Exclusive, |
| 330 | #endif | 336 | #endif |
| 331 | "fullscreen_mode"}; | 337 | "fullscreen_mode"}; |
| 332 | Setting<int> aspect_ratio{0, "aspect_ratio"}; | 338 | Setting<int> aspect_ratio{0, "aspect_ratio"}; |
diff --git a/src/common/uuid.cpp b/src/common/uuid.cpp index 26db03fba..18303a1e3 100644 --- a/src/common/uuid.cpp +++ b/src/common/uuid.cpp | |||
| @@ -18,7 +18,7 @@ UUID UUID::Generate() { | |||
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | std::string UUID::Format() const { | 20 | std::string UUID::Format() const { |
| 21 | return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); | 21 | return fmt::format("{:016x}{:016x}", uuid[1], uuid[0]); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | std::string UUID::FormatSwitch() const { | 24 | std::string UUID::FormatSwitch() const { |
diff --git a/src/core/hle/api_version.h b/src/core/hle/api_version.h index 5e10a7ad9..43d5670a9 100644 --- a/src/core/hle/api_version.h +++ b/src/core/hle/api_version.h | |||
| @@ -12,9 +12,9 @@ namespace HLE::ApiVersion { | |||
| 12 | 12 | ||
| 13 | // Horizon OS version constants. | 13 | // Horizon OS version constants. |
| 14 | 14 | ||
| 15 | constexpr u8 HOS_VERSION_MAJOR = 11; | 15 | constexpr u8 HOS_VERSION_MAJOR = 12; |
| 16 | constexpr u8 HOS_VERSION_MINOR = 0; | 16 | constexpr u8 HOS_VERSION_MINOR = 1; |
| 17 | constexpr u8 HOS_VERSION_MICRO = 1; | 17 | constexpr u8 HOS_VERSION_MICRO = 0; |
| 18 | 18 | ||
| 19 | // NintendoSDK version constants. | 19 | // NintendoSDK version constants. |
| 20 | 20 | ||
| @@ -22,15 +22,15 @@ constexpr u8 SDK_REVISION_MAJOR = 1; | |||
| 22 | constexpr u8 SDK_REVISION_MINOR = 0; | 22 | constexpr u8 SDK_REVISION_MINOR = 0; |
| 23 | 23 | ||
| 24 | constexpr char PLATFORM_STRING[] = "NX"; | 24 | constexpr char PLATFORM_STRING[] = "NX"; |
| 25 | constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf"; | 25 | constexpr char VERSION_HASH[] = "76b10c2dab7d3aa73fc162f8dff1655e6a21caf4"; |
| 26 | constexpr char DISPLAY_VERSION[] = "11.0.1"; | 26 | constexpr char DISPLAY_VERSION[] = "12.1.0"; |
| 27 | constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0"; | 27 | constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 12.1.0-1.0"; |
| 28 | 28 | ||
| 29 | // Atmosphere version constants. | 29 | // Atmosphere version constants. |
| 30 | 30 | ||
| 31 | constexpr u8 ATMOSPHERE_RELEASE_VERSION_MAJOR = 0; | 31 | constexpr u8 ATMOSPHERE_RELEASE_VERSION_MAJOR = 0; |
| 32 | constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 19; | 32 | constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 19; |
| 33 | constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 4; | 33 | constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 5; |
| 34 | 34 | ||
| 35 | constexpr u32 GetTargetFirmware() { | 35 | constexpr u32 GetTargetFirmware() { |
| 36 | return u32{HOS_VERSION_MAJOR} << 24 | u32{HOS_VERSION_MINOR} << 16 | | 36 | return u32{HOS_VERSION_MAJOR} << 24 | u32{HOS_VERSION_MINOR} << 16 | |
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 2e969f2a8..882fc1492 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -292,7 +292,7 @@ public: | |||
| 292 | 292 | ||
| 293 | protected: | 293 | protected: |
| 294 | void Get(Kernel::HLERequestContext& ctx) { | 294 | void Get(Kernel::HLERequestContext& ctx) { |
| 295 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); | 295 | LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); |
| 296 | ProfileBase profile_base{}; | 296 | ProfileBase profile_base{}; |
| 297 | ProfileData data{}; | 297 | ProfileData data{}; |
| 298 | if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { | 298 | if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { |
| @@ -301,7 +301,7 @@ protected: | |||
| 301 | rb.Push(ResultSuccess); | 301 | rb.Push(ResultSuccess); |
| 302 | rb.PushRaw(profile_base); | 302 | rb.PushRaw(profile_base); |
| 303 | } else { | 303 | } else { |
| 304 | LOG_ERROR(Service_ACC, "Failed to get profile base and data for user={}", | 304 | LOG_ERROR(Service_ACC, "Failed to get profile base and data for user=0x{}", |
| 305 | user_id.Format()); | 305 | user_id.Format()); |
| 306 | IPC::ResponseBuilder rb{ctx, 2}; | 306 | IPC::ResponseBuilder rb{ctx, 2}; |
| 307 | rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code | 307 | rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code |
| @@ -309,14 +309,14 @@ protected: | |||
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | void GetBase(Kernel::HLERequestContext& ctx) { | 311 | void GetBase(Kernel::HLERequestContext& ctx) { |
| 312 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); | 312 | LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); |
| 313 | ProfileBase profile_base{}; | 313 | ProfileBase profile_base{}; |
| 314 | if (profile_manager.GetProfileBase(user_id, profile_base)) { | 314 | if (profile_manager.GetProfileBase(user_id, profile_base)) { |
| 315 | IPC::ResponseBuilder rb{ctx, 16}; | 315 | IPC::ResponseBuilder rb{ctx, 16}; |
| 316 | rb.Push(ResultSuccess); | 316 | rb.Push(ResultSuccess); |
| 317 | rb.PushRaw(profile_base); | 317 | rb.PushRaw(profile_base); |
| 318 | } else { | 318 | } else { |
| 319 | LOG_ERROR(Service_ACC, "Failed to get profile base for user={}", user_id.Format()); | 319 | LOG_ERROR(Service_ACC, "Failed to get profile base for user=0x{}", user_id.Format()); |
| 320 | IPC::ResponseBuilder rb{ctx, 2}; | 320 | IPC::ResponseBuilder rb{ctx, 2}; |
| 321 | rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code | 321 | rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code |
| 322 | } | 322 | } |
| @@ -372,7 +372,7 @@ protected: | |||
| 372 | 372 | ||
| 373 | const auto user_data = ctx.ReadBuffer(); | 373 | const auto user_data = ctx.ReadBuffer(); |
| 374 | 374 | ||
| 375 | LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}", | 375 | LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}", |
| 376 | Common::StringFromFixedZeroTerminatedBuffer( | 376 | Common::StringFromFixedZeroTerminatedBuffer( |
| 377 | reinterpret_cast<const char*>(base.username.data()), base.username.size()), | 377 | reinterpret_cast<const char*>(base.username.data()), base.username.size()), |
| 378 | base.timestamp, base.user_uuid.Format()); | 378 | base.timestamp, base.user_uuid.Format()); |
| @@ -405,7 +405,7 @@ protected: | |||
| 405 | const auto user_data = ctx.ReadBuffer(); | 405 | const auto user_data = ctx.ReadBuffer(); |
| 406 | const auto image_data = ctx.ReadBuffer(1); | 406 | const auto image_data = ctx.ReadBuffer(1); |
| 407 | 407 | ||
| 408 | LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}", | 408 | LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}", |
| 409 | Common::StringFromFixedZeroTerminatedBuffer( | 409 | Common::StringFromFixedZeroTerminatedBuffer( |
| 410 | reinterpret_cast<const char*>(base.username.data()), base.username.size()), | 410 | reinterpret_cast<const char*>(base.username.data()), base.username.size()), |
| 411 | base.timestamp, base.user_uuid.Format()); | 411 | base.timestamp, base.user_uuid.Format()); |
| @@ -662,7 +662,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { | |||
| 662 | void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { | 662 | void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { |
| 663 | IPC::RequestParser rp{ctx}; | 663 | IPC::RequestParser rp{ctx}; |
| 664 | Common::UUID user_id = rp.PopRaw<Common::UUID>(); | 664 | Common::UUID user_id = rp.PopRaw<Common::UUID>(); |
| 665 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); | 665 | LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); |
| 666 | 666 | ||
| 667 | IPC::ResponseBuilder rb{ctx, 3}; | 667 | IPC::ResponseBuilder rb{ctx, 3}; |
| 668 | rb.Push(ResultSuccess); | 668 | rb.Push(ResultSuccess); |
| @@ -693,7 +693,7 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { | |||
| 693 | void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { | 693 | void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { |
| 694 | IPC::RequestParser rp{ctx}; | 694 | IPC::RequestParser rp{ctx}; |
| 695 | Common::UUID user_id = rp.PopRaw<Common::UUID>(); | 695 | Common::UUID user_id = rp.PopRaw<Common::UUID>(); |
| 696 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); | 696 | LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); |
| 697 | 697 | ||
| 698 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 698 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 699 | rb.Push(ResultSuccess); | 699 | rb.Push(ResultSuccess); |
| @@ -802,7 +802,7 @@ void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) { | |||
| 802 | IPC::RequestParser rp{ctx}; | 802 | IPC::RequestParser rp{ctx}; |
| 803 | Common::UUID user_id = rp.PopRaw<Common::UUID>(); | 803 | Common::UUID user_id = rp.PopRaw<Common::UUID>(); |
| 804 | 804 | ||
| 805 | LOG_DEBUG(Service_ACC, "called, user_id={}", user_id.Format()); | 805 | LOG_DEBUG(Service_ACC, "called, user_id=0x{}", user_id.Format()); |
| 806 | 806 | ||
| 807 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 807 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 808 | rb.Push(ResultSuccess); | 808 | rb.Push(ResultSuccess); |
| @@ -844,7 +844,7 @@ void Module::Interface::StoreSaveDataThumbnailApplication(Kernel::HLERequestCont | |||
| 844 | IPC::RequestParser rp{ctx}; | 844 | IPC::RequestParser rp{ctx}; |
| 845 | const auto uuid = rp.PopRaw<Common::UUID>(); | 845 | const auto uuid = rp.PopRaw<Common::UUID>(); |
| 846 | 846 | ||
| 847 | LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}", uuid.Format()); | 847 | LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}", uuid.Format()); |
| 848 | 848 | ||
| 849 | // TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable | 849 | // TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable |
| 850 | // way of confirming things like the TID, we're going to assume a non zero value for the time | 850 | // way of confirming things like the TID, we're going to assume a non zero value for the time |
| @@ -858,7 +858,7 @@ void Module::Interface::StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& | |||
| 858 | const auto uuid = rp.PopRaw<Common::UUID>(); | 858 | const auto uuid = rp.PopRaw<Common::UUID>(); |
| 859 | const auto tid = rp.Pop<u64_le>(); | 859 | const auto tid = rp.Pop<u64_le>(); |
| 860 | 860 | ||
| 861 | LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}, tid={:016X}", uuid.Format(), tid); | 861 | LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}, tid={:016X}", uuid.Format(), tid); |
| 862 | StoreSaveDataThumbnail(ctx, uuid, tid); | 862 | StoreSaveDataThumbnail(ctx, uuid, tid); |
| 863 | } | 863 | } |
| 864 | 864 | ||
diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/applets/applet_software_keyboard.cpp index 7cae90609..673abb755 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp +++ b/src/core/hle/service/am/applets/applet_software_keyboard.cpp | |||
| @@ -377,7 +377,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) { | |||
| 377 | 377 | ||
| 378 | if (swkbd_config_common.use_utf8) { | 378 | if (swkbd_config_common.use_utf8) { |
| 379 | std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text); | 379 | std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text); |
| 380 | const u64 buffer_size = sizeof(u64) + utf8_submitted_text.size(); | 380 | const u64 buffer_size = utf8_submitted_text.size(); |
| 381 | 381 | ||
| 382 | LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size, | 382 | LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size, |
| 383 | utf8_submitted_text); | 383 | utf8_submitted_text); |
| @@ -386,7 +386,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) { | |||
| 386 | std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(), | 386 | std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(), |
| 387 | utf8_submitted_text.size()); | 387 | utf8_submitted_text.size()); |
| 388 | } else { | 388 | } else { |
| 389 | const u64 buffer_size = sizeof(u64) + current_text.size() * sizeof(char16_t); | 389 | const u64 buffer_size = current_text.size() * sizeof(char16_t); |
| 390 | 390 | ||
| 391 | LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size, | 391 | LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size, |
| 392 | Common::UTF16ToUTF8(current_text)); | 392 | Common::UTF16ToUTF8(current_text)); |
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index a3c939c0c..b58c152ce 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -158,7 +158,7 @@ private: | |||
| 158 | const auto local_play = rp.Pop<bool>(); | 158 | const auto local_play = rp.Pop<bool>(); |
| 159 | const auto uuid = rp.PopRaw<Common::UUID>(); | 159 | const auto uuid = rp.PopRaw<Common::UUID>(); |
| 160 | 160 | ||
| 161 | LOG_WARNING(Service_Friend, "(STUBBED) called local_play={} uuid={}", local_play, | 161 | LOG_WARNING(Service_Friend, "(STUBBED) called, local_play={}, uuid=0x{}", local_play, |
| 162 | uuid.Format()); | 162 | uuid.Format()); |
| 163 | 163 | ||
| 164 | IPC::ResponseBuilder rb{ctx, 2}; | 164 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -171,7 +171,7 @@ private: | |||
| 171 | const auto uuid = rp.PopRaw<Common::UUID>(); | 171 | const auto uuid = rp.PopRaw<Common::UUID>(); |
| 172 | [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>(); | 172 | [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>(); |
| 173 | const auto pid = rp.Pop<u64>(); | 173 | const auto pid = rp.Pop<u64>(); |
| 174 | LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset, | 174 | LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset, |
| 175 | uuid.Format(), pid); | 175 | uuid.Format(), pid); |
| 176 | 176 | ||
| 177 | IPC::ResponseBuilder rb{ctx, 3}; | 177 | IPC::ResponseBuilder rb{ctx, 3}; |
| @@ -289,7 +289,7 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx | |||
| 289 | IPC::RequestParser rp{ctx}; | 289 | IPC::RequestParser rp{ctx}; |
| 290 | auto uuid = rp.PopRaw<Common::UUID>(); | 290 | auto uuid = rp.PopRaw<Common::UUID>(); |
| 291 | 291 | ||
| 292 | LOG_DEBUG(Service_Friend, "called, uuid={}", uuid.Format()); | 292 | LOG_DEBUG(Service_Friend, "called, uuid=0x{}", uuid.Format()); |
| 293 | 293 | ||
| 294 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 294 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 295 | rb.Push(ResultSuccess); | 295 | rb.Push(ResultSuccess); |
diff --git a/src/core/hle/service/ns/language.cpp b/src/core/hle/service/ns/language.cpp index 29c4a820c..7d9e4a20b 100644 --- a/src/core/hle/service/ns/language.cpp +++ b/src/core/hle/service/ns/language.cpp | |||
| @@ -339,13 +339,16 @@ std::optional<ApplicationLanguage> ConvertToApplicationLanguage( | |||
| 339 | case Set::LanguageCode::FR_CA: | 339 | case Set::LanguageCode::FR_CA: |
| 340 | return ApplicationLanguage::CanadianFrench; | 340 | return ApplicationLanguage::CanadianFrench; |
| 341 | case Set::LanguageCode::PT: | 341 | case Set::LanguageCode::PT: |
| 342 | case Set::LanguageCode::PT_BR: | ||
| 342 | return ApplicationLanguage::Portuguese; | 343 | return ApplicationLanguage::Portuguese; |
| 343 | case Set::LanguageCode::RU: | 344 | case Set::LanguageCode::RU: |
| 344 | return ApplicationLanguage::Russian; | 345 | return ApplicationLanguage::Russian; |
| 345 | case Set::LanguageCode::KO: | 346 | case Set::LanguageCode::KO: |
| 346 | return ApplicationLanguage::Korean; | 347 | return ApplicationLanguage::Korean; |
| 348 | case Set::LanguageCode::ZH_TW: | ||
| 347 | case Set::LanguageCode::ZH_HANT: | 349 | case Set::LanguageCode::ZH_HANT: |
| 348 | return ApplicationLanguage::TraditionalChinese; | 350 | return ApplicationLanguage::TraditionalChinese; |
| 351 | case Set::LanguageCode::ZH_CN: | ||
| 349 | case Set::LanguageCode::ZH_HANS: | 352 | case Set::LanguageCode::ZH_HANS: |
| 350 | return ApplicationLanguage::SimplifiedChinese; | 353 | return ApplicationLanguage::SimplifiedChinese; |
| 351 | default: | 354 | default: |
diff --git a/src/core/hle/service/ns/ns_language.h b/src/core/hle/service/ns/ns_language.h deleted file mode 100644 index 59ac85a19..000000000 --- a/src/core/hle/service/ns/ns_language.h +++ /dev/null | |||
| @@ -1,42 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | #include <optional> | ||
| 7 | #include <string> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/service/set/set.h" | ||
| 10 | |||
| 11 | namespace Service::NS { | ||
| 12 | /// This is nn::ns::detail::ApplicationLanguage | ||
| 13 | enum class ApplicationLanguage : u8 { | ||
| 14 | AmericanEnglish = 0, | ||
| 15 | BritishEnglish, | ||
| 16 | Japanese, | ||
| 17 | French, | ||
| 18 | German, | ||
| 19 | LatinAmericanSpanish, | ||
| 20 | Spanish, | ||
| 21 | Italian, | ||
| 22 | Dutch, | ||
| 23 | CanadianFrench, | ||
| 24 | Portuguese, | ||
| 25 | Russian, | ||
| 26 | Korean, | ||
| 27 | TraditionalChinese, | ||
| 28 | SimplifiedChinese, | ||
| 29 | Count | ||
| 30 | }; | ||
| 31 | using ApplicationLanguagePriorityList = | ||
| 32 | const std::array<ApplicationLanguage, static_cast<std::size_t>(ApplicationLanguage::Count)>; | ||
| 33 | |||
| 34 | constexpr u32 GetSupportedLanguageFlag(const ApplicationLanguage lang) { | ||
| 35 | return 1U << static_cast<u32>(lang); | ||
| 36 | } | ||
| 37 | |||
| 38 | const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(ApplicationLanguage lang); | ||
| 39 | std::optional<ApplicationLanguage> ConvertToApplicationLanguage( | ||
| 40 | Service::Set::LanguageCode language_code); | ||
| 41 | std::optional<Service::Set::LanguageCode> ConvertToLanguageCode(ApplicationLanguage lang); | ||
| 42 | } // namespace Service::NS \ No newline at end of file | ||
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 522a604a5..f2e2e8306 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | namespace Service::Set { | 13 | namespace Service::Set { |
| 14 | namespace { | 14 | namespace { |
| 15 | constexpr std::array<LanguageCode, 17> available_language_codes = {{ | 15 | constexpr std::array<LanguageCode, 18> available_language_codes = {{ |
| 16 | LanguageCode::JA, | 16 | LanguageCode::JA, |
| 17 | LanguageCode::EN_US, | 17 | LanguageCode::EN_US, |
| 18 | LanguageCode::FR, | 18 | LanguageCode::FR, |
| @@ -30,6 +30,7 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{ | |||
| 30 | LanguageCode::ES_419, | 30 | LanguageCode::ES_419, |
| 31 | LanguageCode::ZH_HANS, | 31 | LanguageCode::ZH_HANS, |
| 32 | LanguageCode::ZH_HANT, | 32 | LanguageCode::ZH_HANT, |
| 33 | LanguageCode::PT_BR, | ||
| 33 | }}; | 34 | }}; |
| 34 | 35 | ||
| 35 | enum class KeyboardLayout : u64 { | 36 | enum class KeyboardLayout : u64 { |
| @@ -50,7 +51,7 @@ enum class KeyboardLayout : u64 { | |||
| 50 | ChineseTraditional = 14, | 51 | ChineseTraditional = 14, |
| 51 | }; | 52 | }; |
| 52 | 53 | ||
| 53 | constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 17> language_to_layout{{ | 54 | constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{ |
| 54 | {LanguageCode::JA, KeyboardLayout::Japanese}, | 55 | {LanguageCode::JA, KeyboardLayout::Japanese}, |
| 55 | {LanguageCode::EN_US, KeyboardLayout::EnglishUs}, | 56 | {LanguageCode::EN_US, KeyboardLayout::EnglishUs}, |
| 56 | {LanguageCode::FR, KeyboardLayout::French}, | 57 | {LanguageCode::FR, KeyboardLayout::French}, |
| @@ -68,10 +69,11 @@ constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 17> language_to_la | |||
| 68 | {LanguageCode::ES_419, KeyboardLayout::SpanishLatin}, | 69 | {LanguageCode::ES_419, KeyboardLayout::SpanishLatin}, |
| 69 | {LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified}, | 70 | {LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified}, |
| 70 | {LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional}, | 71 | {LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional}, |
| 72 | {LanguageCode::PT_BR, KeyboardLayout::Portuguese}, | ||
| 71 | }}; | 73 | }}; |
| 72 | 74 | ||
| 73 | constexpr std::size_t pre4_0_0_max_entries = 15; | 75 | constexpr std::size_t PRE_4_0_0_MAX_ENTRIES = 0xF; |
| 74 | constexpr std::size_t post4_0_0_max_entries = 17; | 76 | constexpr std::size_t POST_4_0_0_MAX_ENTRIES = 0x40; |
| 75 | 77 | ||
| 76 | constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625}; | 78 | constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625}; |
| 77 | 79 | ||
| @@ -81,9 +83,9 @@ void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t num_la | |||
| 81 | rb.Push(static_cast<u32>(num_language_codes)); | 83 | rb.Push(static_cast<u32>(num_language_codes)); |
| 82 | } | 84 | } |
| 83 | 85 | ||
| 84 | void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_size) { | 86 | void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_entries) { |
| 85 | const std::size_t requested_amount = ctx.GetWriteBufferSize() / sizeof(LanguageCode); | 87 | const std::size_t requested_amount = ctx.GetWriteBufferSize() / sizeof(LanguageCode); |
| 86 | const std::size_t copy_amount = std::min(requested_amount, max_size); | 88 | const std::size_t copy_amount = std::min(requested_amount, max_entries); |
| 87 | const std::size_t copy_size = copy_amount * sizeof(LanguageCode); | 89 | const std::size_t copy_size = copy_amount * sizeof(LanguageCode); |
| 88 | 90 | ||
| 89 | ctx.WriteBuffer(available_language_codes.data(), copy_size); | 91 | ctx.WriteBuffer(available_language_codes.data(), copy_size); |
| @@ -118,7 +120,7 @@ LanguageCode GetLanguageCodeFromIndex(std::size_t index) { | |||
| 118 | void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { | 120 | void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { |
| 119 | LOG_DEBUG(Service_SET, "called"); | 121 | LOG_DEBUG(Service_SET, "called"); |
| 120 | 122 | ||
| 121 | GetAvailableLanguageCodesImpl(ctx, pre4_0_0_max_entries); | 123 | GetAvailableLanguageCodesImpl(ctx, PRE_4_0_0_MAX_ENTRIES); |
| 122 | } | 124 | } |
| 123 | 125 | ||
| 124 | void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) { | 126 | void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) { |
| @@ -140,19 +142,19 @@ void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) { | |||
| 140 | void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { | 142 | void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { |
| 141 | LOG_DEBUG(Service_SET, "called"); | 143 | LOG_DEBUG(Service_SET, "called"); |
| 142 | 144 | ||
| 143 | GetAvailableLanguageCodesImpl(ctx, post4_0_0_max_entries); | 145 | GetAvailableLanguageCodesImpl(ctx, POST_4_0_0_MAX_ENTRIES); |
| 144 | } | 146 | } |
| 145 | 147 | ||
| 146 | void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { | 148 | void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { |
| 147 | LOG_DEBUG(Service_SET, "called"); | 149 | LOG_DEBUG(Service_SET, "called"); |
| 148 | 150 | ||
| 149 | PushResponseLanguageCode(ctx, pre4_0_0_max_entries); | 151 | PushResponseLanguageCode(ctx, PRE_4_0_0_MAX_ENTRIES); |
| 150 | } | 152 | } |
| 151 | 153 | ||
| 152 | void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { | 154 | void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { |
| 153 | LOG_DEBUG(Service_SET, "called"); | 155 | LOG_DEBUG(Service_SET, "called"); |
| 154 | 156 | ||
| 155 | PushResponseLanguageCode(ctx, post4_0_0_max_entries); | 157 | PushResponseLanguageCode(ctx, POST_4_0_0_MAX_ENTRIES); |
| 156 | } | 158 | } |
| 157 | 159 | ||
| 158 | void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) { | 160 | void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index d5bd7828d..acabebeaa 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h | |||
| @@ -31,6 +31,7 @@ enum class LanguageCode : u64 { | |||
| 31 | ES_419 = 0x00003931342D7365, | 31 | ES_419 = 0x00003931342D7365, |
| 32 | ZH_HANS = 0x00736E61482D687A, | 32 | ZH_HANS = 0x00736E61482D687A, |
| 33 | ZH_HANT = 0x00746E61482D687A, | 33 | ZH_HANT = 0x00746E61482D687A, |
| 34 | PT_BR = 0x00000052422D7470, | ||
| 34 | }; | 35 | }; |
| 35 | LanguageCode GetLanguageCodeFromIndex(std::size_t idx); | 36 | LanguageCode GetLanguageCodeFromIndex(std::size_t idx); |
| 36 | 37 | ||
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index 795194d41..334bb47aa 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h | |||
| @@ -57,6 +57,7 @@ public: | |||
| 57 | 57 | ||
| 58 | [[nodiscard]] IR::Inst* Inst() const; | 58 | [[nodiscard]] IR::Inst* Inst() const; |
| 59 | [[nodiscard]] IR::Inst* InstRecursive() const; | 59 | [[nodiscard]] IR::Inst* InstRecursive() const; |
| 60 | [[nodiscard]] IR::Inst* TryInstRecursive() const; | ||
| 60 | [[nodiscard]] IR::Value Resolve() const; | 61 | [[nodiscard]] IR::Value Resolve() const; |
| 61 | [[nodiscard]] IR::Reg Reg() const; | 62 | [[nodiscard]] IR::Reg Reg() const; |
| 62 | [[nodiscard]] IR::Pred Pred() const; | 63 | [[nodiscard]] IR::Pred Pred() const; |
| @@ -308,6 +309,13 @@ inline IR::Inst* Value::InstRecursive() const { | |||
| 308 | return inst; | 309 | return inst; |
| 309 | } | 310 | } |
| 310 | 311 | ||
| 312 | inline IR::Inst* Value::TryInstRecursive() const { | ||
| 313 | if (IsIdentity()) { | ||
| 314 | return inst->Arg(0).TryInstRecursive(); | ||
| 315 | } | ||
| 316 | return type == Type::Opaque ? inst : nullptr; | ||
| 317 | } | ||
| 318 | |||
| 311 | inline IR::Value Value::Resolve() const { | 319 | inline IR::Value Value::Resolve() const { |
| 312 | if (IsIdentity()) { | 320 | if (IsIdentity()) { |
| 313 | return inst->Arg(0).Resolve(); | 321 | return inst->Arg(0).Resolve(); |
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 5ead930f1..f69e1c9cc 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -111,6 +111,8 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 111 | case IR::Opcode::ConvertF16U16: | 111 | case IR::Opcode::ConvertF16U16: |
| 112 | case IR::Opcode::ConvertF16U32: | 112 | case IR::Opcode::ConvertF16U32: |
| 113 | case IR::Opcode::ConvertF16U64: | 113 | case IR::Opcode::ConvertF16U64: |
| 114 | case IR::Opcode::ConvertF16F32: | ||
| 115 | case IR::Opcode::ConvertF32F16: | ||
| 114 | case IR::Opcode::FPAbs16: | 116 | case IR::Opcode::FPAbs16: |
| 115 | case IR::Opcode::FPAdd16: | 117 | case IR::Opcode::FPAdd16: |
| 116 | case IR::Opcode::FPCeil16: | 118 | case IR::Opcode::FPCeil16: |
diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp index 8dd6d6c2c..d089fdd12 100644 --- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp +++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <functional> | ||
| 6 | #include <tuple> | 7 | #include <tuple> |
| 7 | #include <type_traits> | 8 | #include <type_traits> |
| 8 | 9 | ||
| @@ -88,6 +89,26 @@ bool FoldWhenAllImmediates(IR::Inst& inst, Func&& func) { | |||
| 88 | return true; | 89 | return true; |
| 89 | } | 90 | } |
| 90 | 91 | ||
| 92 | /// Return true when all values in a range are equal | ||
| 93 | template <typename Range> | ||
| 94 | bool AreEqual(const Range& range) { | ||
| 95 | auto resolver{[](const auto& value) { return value.Resolve(); }}; | ||
| 96 | auto equal{[](const IR::Value& lhs, const IR::Value& rhs) { | ||
| 97 | if (lhs == rhs) { | ||
| 98 | return true; | ||
| 99 | } | ||
| 100 | // Not equal, but try to match if they read the same constant buffer | ||
| 101 | if (!lhs.IsImmediate() && !rhs.IsImmediate() && | ||
| 102 | lhs.Inst()->GetOpcode() == IR::Opcode::GetCbufU32 && | ||
| 103 | rhs.Inst()->GetOpcode() == IR::Opcode::GetCbufU32 && | ||
| 104 | lhs.Inst()->Arg(0) == rhs.Inst()->Arg(0) && lhs.Inst()->Arg(1) == rhs.Inst()->Arg(1)) { | ||
| 105 | return true; | ||
| 106 | } | ||
| 107 | return false; | ||
| 108 | }}; | ||
| 109 | return std::ranges::adjacent_find(range, std::not_fn(equal), resolver) == std::end(range); | ||
| 110 | } | ||
| 111 | |||
| 91 | void FoldGetRegister(IR::Inst& inst) { | 112 | void FoldGetRegister(IR::Inst& inst) { |
| 92 | if (inst.Arg(0).Reg() == IR::Reg::RZ) { | 113 | if (inst.Arg(0).Reg() == IR::Reg::RZ) { |
| 93 | inst.ReplaceUsesWith(IR::Value{u32{0}}); | 114 | inst.ReplaceUsesWith(IR::Value{u32{0}}); |
| @@ -100,6 +121,157 @@ void FoldGetPred(IR::Inst& inst) { | |||
| 100 | } | 121 | } |
| 101 | } | 122 | } |
| 102 | 123 | ||
| 124 | /// Replaces the XMAD pattern generated by an integer FMA | ||
| 125 | bool FoldXmadMultiplyAdd(IR::Block& block, IR::Inst& inst) { | ||
| 126 | /* | ||
| 127 | * We are looking for this specific pattern: | ||
| 128 | * %6 = BitFieldUExtract %op_b, #0, #16 | ||
| 129 | * %7 = BitFieldUExtract %op_a', #16, #16 | ||
| 130 | * %8 = IMul32 %6, %7 | ||
| 131 | * %10 = BitFieldUExtract %op_a', #0, #16 | ||
| 132 | * %11 = BitFieldInsert %8, %10, #16, #16 | ||
| 133 | * %15 = BitFieldUExtract %op_b, #0, #16 | ||
| 134 | * %16 = BitFieldUExtract %op_a, #0, #16 | ||
| 135 | * %17 = IMul32 %15, %16 | ||
| 136 | * %18 = IAdd32 %17, %op_c | ||
| 137 | * %22 = BitFieldUExtract %op_b, #16, #16 | ||
| 138 | * %23 = BitFieldUExtract %11, #16, #16 | ||
| 139 | * %24 = IMul32 %22, %23 | ||
| 140 | * %25 = ShiftLeftLogical32 %24, #16 | ||
| 141 | * %26 = ShiftLeftLogical32 %11, #16 | ||
| 142 | * %27 = IAdd32 %26, %18 | ||
| 143 | * %result = IAdd32 %25, %27 | ||
| 144 | * | ||
| 145 | * And replace it with: | ||
| 146 | * %temp = IMul32 %op_a, %op_b | ||
| 147 | * %result = IAdd32 %temp, %op_c | ||
| 148 | * | ||
| 149 | * This optimization has been proven safe by Nvidia's compiler logic being reversed. | ||
| 150 | * (If Nvidia generates this code from 'fma(a, b, c)', we can do the same in the reverse order.) | ||
| 151 | */ | ||
| 152 | const IR::Value zero{0u}; | ||
| 153 | const IR::Value sixteen{16u}; | ||
| 154 | IR::Inst* const _25{inst.Arg(0).TryInstRecursive()}; | ||
| 155 | IR::Inst* const _27{inst.Arg(1).TryInstRecursive()}; | ||
| 156 | if (!_25 || !_27) { | ||
| 157 | return false; | ||
| 158 | } | ||
| 159 | if (_27->GetOpcode() != IR::Opcode::IAdd32) { | ||
| 160 | return false; | ||
| 161 | } | ||
| 162 | if (_25->GetOpcode() != IR::Opcode::ShiftLeftLogical32 || _25->Arg(1) != sixteen) { | ||
| 163 | return false; | ||
| 164 | } | ||
| 165 | IR::Inst* const _24{_25->Arg(0).TryInstRecursive()}; | ||
| 166 | if (!_24 || _24->GetOpcode() != IR::Opcode::IMul32) { | ||
| 167 | return false; | ||
| 168 | } | ||
| 169 | IR::Inst* const _22{_24->Arg(0).TryInstRecursive()}; | ||
| 170 | IR::Inst* const _23{_24->Arg(1).TryInstRecursive()}; | ||
| 171 | if (!_22 || !_23) { | ||
| 172 | return false; | ||
| 173 | } | ||
| 174 | if (_22->GetOpcode() != IR::Opcode::BitFieldUExtract) { | ||
| 175 | return false; | ||
| 176 | } | ||
| 177 | if (_23->GetOpcode() != IR::Opcode::BitFieldUExtract) { | ||
| 178 | return false; | ||
| 179 | } | ||
| 180 | if (_22->Arg(1) != sixteen || _22->Arg(2) != sixteen) { | ||
| 181 | return false; | ||
| 182 | } | ||
| 183 | if (_23->Arg(1) != sixteen || _23->Arg(2) != sixteen) { | ||
| 184 | return false; | ||
| 185 | } | ||
| 186 | IR::Inst* const _11{_23->Arg(0).TryInstRecursive()}; | ||
| 187 | if (!_11 || _11->GetOpcode() != IR::Opcode::BitFieldInsert) { | ||
| 188 | return false; | ||
| 189 | } | ||
| 190 | if (_11->Arg(2) != sixteen || _11->Arg(3) != sixteen) { | ||
| 191 | return false; | ||
| 192 | } | ||
| 193 | IR::Inst* const _8{_11->Arg(0).TryInstRecursive()}; | ||
| 194 | IR::Inst* const _10{_11->Arg(1).TryInstRecursive()}; | ||
| 195 | if (!_8 || !_10) { | ||
| 196 | return false; | ||
| 197 | } | ||
| 198 | if (_8->GetOpcode() != IR::Opcode::IMul32) { | ||
| 199 | return false; | ||
| 200 | } | ||
| 201 | if (_10->GetOpcode() != IR::Opcode::BitFieldUExtract) { | ||
| 202 | return false; | ||
| 203 | } | ||
| 204 | IR::Inst* const _6{_8->Arg(0).TryInstRecursive()}; | ||
| 205 | IR::Inst* const _7{_8->Arg(1).TryInstRecursive()}; | ||
| 206 | if (!_6 || !_7) { | ||
| 207 | return false; | ||
| 208 | } | ||
| 209 | if (_6->GetOpcode() != IR::Opcode::BitFieldUExtract) { | ||
| 210 | return false; | ||
| 211 | } | ||
| 212 | if (_7->GetOpcode() != IR::Opcode::BitFieldUExtract) { | ||
| 213 | return false; | ||
| 214 | } | ||
| 215 | if (_6->Arg(1) != zero || _6->Arg(2) != sixteen) { | ||
| 216 | return false; | ||
| 217 | } | ||
| 218 | if (_7->Arg(1) != sixteen || _7->Arg(2) != sixteen) { | ||
| 219 | return false; | ||
| 220 | } | ||
| 221 | IR::Inst* const _26{_27->Arg(0).TryInstRecursive()}; | ||
| 222 | IR::Inst* const _18{_27->Arg(1).TryInstRecursive()}; | ||
| 223 | if (!_26 || !_18) { | ||
| 224 | return false; | ||
| 225 | } | ||
| 226 | if (_26->GetOpcode() != IR::Opcode::ShiftLeftLogical32 || _26->Arg(1) != sixteen) { | ||
| 227 | return false; | ||
| 228 | } | ||
| 229 | if (_26->Arg(0).InstRecursive() != _11) { | ||
| 230 | return false; | ||
| 231 | } | ||
| 232 | if (_18->GetOpcode() != IR::Opcode::IAdd32) { | ||
| 233 | return false; | ||
| 234 | } | ||
| 235 | IR::Inst* const _17{_18->Arg(0).TryInstRecursive()}; | ||
| 236 | if (!_17 || _17->GetOpcode() != IR::Opcode::IMul32) { | ||
| 237 | return false; | ||
| 238 | } | ||
| 239 | IR::Inst* const _15{_17->Arg(0).TryInstRecursive()}; | ||
| 240 | IR::Inst* const _16{_17->Arg(1).TryInstRecursive()}; | ||
| 241 | if (!_15 || !_16) { | ||
| 242 | return false; | ||
| 243 | } | ||
| 244 | if (_15->GetOpcode() != IR::Opcode::BitFieldUExtract) { | ||
| 245 | return false; | ||
| 246 | } | ||
| 247 | if (_16->GetOpcode() != IR::Opcode::BitFieldUExtract) { | ||
| 248 | return false; | ||
| 249 | } | ||
| 250 | if (_15->Arg(1) != zero || _16->Arg(1) != zero || _10->Arg(1) != zero) { | ||
| 251 | return false; | ||
| 252 | } | ||
| 253 | if (_15->Arg(2) != sixteen || _16->Arg(2) != sixteen || _10->Arg(2) != sixteen) { | ||
| 254 | return false; | ||
| 255 | } | ||
| 256 | const std::array<IR::Value, 3> op_as{ | ||
| 257 | _7->Arg(0).Resolve(), | ||
| 258 | _16->Arg(0).Resolve(), | ||
| 259 | _10->Arg(0).Resolve(), | ||
| 260 | }; | ||
| 261 | const std::array<IR::Value, 3> op_bs{ | ||
| 262 | _22->Arg(0).Resolve(), | ||
| 263 | _6->Arg(0).Resolve(), | ||
| 264 | _15->Arg(0).Resolve(), | ||
| 265 | }; | ||
| 266 | const IR::U32 op_c{_18->Arg(1)}; | ||
| 267 | if (!AreEqual(op_as) || !AreEqual(op_bs)) { | ||
| 268 | return false; | ||
| 269 | } | ||
| 270 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | ||
| 271 | inst.ReplaceUsesWith(ir.IAdd(ir.IMul(IR::U32{op_as[0]}, IR::U32{op_bs[1]}), op_c)); | ||
| 272 | return true; | ||
| 273 | } | ||
| 274 | |||
| 103 | /// Replaces the pattern generated by two XMAD multiplications | 275 | /// Replaces the pattern generated by two XMAD multiplications |
| 104 | bool FoldXmadMultiply(IR::Block& block, IR::Inst& inst) { | 276 | bool FoldXmadMultiply(IR::Block& block, IR::Inst& inst) { |
| 105 | /* | 277 | /* |
| @@ -116,33 +288,31 @@ bool FoldXmadMultiply(IR::Block& block, IR::Inst& inst) { | |||
| 116 | * | 288 | * |
| 117 | * This optimization has been proven safe by LLVM and MSVC. | 289 | * This optimization has been proven safe by LLVM and MSVC. |
| 118 | */ | 290 | */ |
| 119 | const IR::Value lhs_arg{inst.Arg(0)}; | 291 | IR::Inst* const lhs_shl{inst.Arg(0).TryInstRecursive()}; |
| 120 | const IR::Value rhs_arg{inst.Arg(1)}; | 292 | IR::Inst* const rhs_mul{inst.Arg(1).TryInstRecursive()}; |
| 121 | if (lhs_arg.IsImmediate() || rhs_arg.IsImmediate()) { | 293 | if (!lhs_shl || !rhs_mul) { |
| 122 | return false; | 294 | return false; |
| 123 | } | 295 | } |
| 124 | IR::Inst* const lhs_shl{lhs_arg.InstRecursive()}; | ||
| 125 | if (lhs_shl->GetOpcode() != IR::Opcode::ShiftLeftLogical32 || | 296 | if (lhs_shl->GetOpcode() != IR::Opcode::ShiftLeftLogical32 || |
| 126 | lhs_shl->Arg(1) != IR::Value{16U}) { | 297 | lhs_shl->Arg(1) != IR::Value{16U}) { |
| 127 | return false; | 298 | return false; |
| 128 | } | 299 | } |
| 129 | if (lhs_shl->Arg(0).IsImmediate()) { | 300 | IR::Inst* const lhs_mul{lhs_shl->Arg(0).TryInstRecursive()}; |
| 301 | if (!lhs_mul) { | ||
| 130 | return false; | 302 | return false; |
| 131 | } | 303 | } |
| 132 | IR::Inst* const lhs_mul{lhs_shl->Arg(0).InstRecursive()}; | ||
| 133 | IR::Inst* const rhs_mul{rhs_arg.InstRecursive()}; | ||
| 134 | if (lhs_mul->GetOpcode() != IR::Opcode::IMul32 || rhs_mul->GetOpcode() != IR::Opcode::IMul32) { | 304 | if (lhs_mul->GetOpcode() != IR::Opcode::IMul32 || rhs_mul->GetOpcode() != IR::Opcode::IMul32) { |
| 135 | return false; | 305 | return false; |
| 136 | } | 306 | } |
| 137 | if (lhs_mul->Arg(1).Resolve() != rhs_mul->Arg(1).Resolve()) { | 307 | const IR::U32 factor_b{lhs_mul->Arg(1)}; |
| 308 | if (factor_b.Resolve() != rhs_mul->Arg(1).Resolve()) { | ||
| 138 | return false; | 309 | return false; |
| 139 | } | 310 | } |
| 140 | const IR::U32 factor_b{lhs_mul->Arg(1)}; | 311 | IR::Inst* const lhs_bfe{lhs_mul->Arg(0).TryInstRecursive()}; |
| 141 | if (lhs_mul->Arg(0).IsImmediate() || rhs_mul->Arg(0).IsImmediate()) { | 312 | IR::Inst* const rhs_bfe{rhs_mul->Arg(0).TryInstRecursive()}; |
| 313 | if (!lhs_bfe || !rhs_bfe) { | ||
| 142 | return false; | 314 | return false; |
| 143 | } | 315 | } |
| 144 | IR::Inst* const lhs_bfe{lhs_mul->Arg(0).InstRecursive()}; | ||
| 145 | IR::Inst* const rhs_bfe{rhs_mul->Arg(0).InstRecursive()}; | ||
| 146 | if (lhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract) { | 316 | if (lhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract) { |
| 147 | return false; | 317 | return false; |
| 148 | } | 318 | } |
| @@ -155,10 +325,10 @@ bool FoldXmadMultiply(IR::Block& block, IR::Inst& inst) { | |||
| 155 | if (rhs_bfe->Arg(1) != IR::Value{0U} || rhs_bfe->Arg(2) != IR::Value{16U}) { | 325 | if (rhs_bfe->Arg(1) != IR::Value{0U} || rhs_bfe->Arg(2) != IR::Value{16U}) { |
| 156 | return false; | 326 | return false; |
| 157 | } | 327 | } |
| 158 | if (lhs_bfe->Arg(0).Resolve() != rhs_bfe->Arg(0).Resolve()) { | 328 | const IR::U32 factor_a{lhs_bfe->Arg(0)}; |
| 329 | if (factor_a.Resolve() != rhs_bfe->Arg(0).Resolve()) { | ||
| 159 | return false; | 330 | return false; |
| 160 | } | 331 | } |
| 161 | const IR::U32 factor_a{lhs_bfe->Arg(0)}; | ||
| 162 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | 332 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; |
| 163 | inst.ReplaceUsesWith(ir.IMul(factor_a, factor_b)); | 333 | inst.ReplaceUsesWith(ir.IMul(factor_a, factor_b)); |
| 164 | return true; | 334 | return true; |
| @@ -181,6 +351,9 @@ void FoldAdd(IR::Block& block, IR::Inst& inst) { | |||
| 181 | if (FoldXmadMultiply(block, inst)) { | 351 | if (FoldXmadMultiply(block, inst)) { |
| 182 | return; | 352 | return; |
| 183 | } | 353 | } |
| 354 | if (FoldXmadMultiplyAdd(block, inst)) { | ||
| 355 | return; | ||
| 356 | } | ||
| 184 | } | 357 | } |
| 185 | } | 358 | } |
| 186 | 359 | ||
| @@ -476,6 +649,10 @@ void ConstantPropagation(IR::Block& block, IR::Inst& inst) { | |||
| 476 | return FoldInverseFunc(inst, IR::Opcode::UnpackHalf2x16); | 649 | return FoldInverseFunc(inst, IR::Opcode::UnpackHalf2x16); |
| 477 | case IR::Opcode::UnpackHalf2x16: | 650 | case IR::Opcode::UnpackHalf2x16: |
| 478 | return FoldInverseFunc(inst, IR::Opcode::PackHalf2x16); | 651 | return FoldInverseFunc(inst, IR::Opcode::PackHalf2x16); |
| 652 | case IR::Opcode::PackFloat2x16: | ||
| 653 | return FoldInverseFunc(inst, IR::Opcode::UnpackFloat2x16); | ||
| 654 | case IR::Opcode::UnpackFloat2x16: | ||
| 655 | return FoldInverseFunc(inst, IR::Opcode::PackFloat2x16); | ||
| 479 | case IR::Opcode::SelectU1: | 656 | case IR::Opcode::SelectU1: |
| 480 | case IR::Opcode::SelectU8: | 657 | case IR::Opcode::SelectU8: |
| 481 | case IR::Opcode::SelectU16: | 658 | case IR::Opcode::SelectU16: |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 007ecc13e..333f6f35f 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -106,6 +106,8 @@ add_library(video_core STATIC | |||
| 106 | renderer_vulkan/maxwell_to_vk.cpp | 106 | renderer_vulkan/maxwell_to_vk.cpp |
| 107 | renderer_vulkan/maxwell_to_vk.h | 107 | renderer_vulkan/maxwell_to_vk.h |
| 108 | renderer_vulkan/pipeline_helper.h | 108 | renderer_vulkan/pipeline_helper.h |
| 109 | renderer_vulkan/pipeline_statistics.cpp | ||
| 110 | renderer_vulkan/pipeline_statistics.h | ||
| 109 | renderer_vulkan/renderer_vulkan.h | 111 | renderer_vulkan/renderer_vulkan.h |
| 110 | renderer_vulkan/renderer_vulkan.cpp | 112 | renderer_vulkan/renderer_vulkan.cpp |
| 111 | renderer_vulkan/vk_blit_screen.cpp | 113 | renderer_vulkan/vk_blit_screen.cpp |
diff --git a/src/video_core/renderer_vulkan/pipeline_statistics.cpp b/src/video_core/renderer_vulkan/pipeline_statistics.cpp new file mode 100644 index 000000000..bfec931a6 --- /dev/null +++ b/src/video_core/renderer_vulkan/pipeline_statistics.cpp | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <string_view> | ||
| 6 | |||
| 7 | #include <fmt/format.h> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "video_core/renderer_vulkan/pipeline_statistics.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 14 | |||
| 15 | namespace Vulkan { | ||
| 16 | |||
| 17 | using namespace std::string_view_literals; | ||
| 18 | |||
| 19 | static u64 GetUint64(const VkPipelineExecutableStatisticKHR& statistic) { | ||
| 20 | switch (statistic.format) { | ||
| 21 | case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR: | ||
| 22 | return static_cast<u64>(statistic.value.i64); | ||
| 23 | case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR: | ||
| 24 | return statistic.value.u64; | ||
| 25 | case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR: | ||
| 26 | return static_cast<u64>(statistic.value.f64); | ||
| 27 | default: | ||
| 28 | return 0; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | PipelineStatistics::PipelineStatistics(const Device& device_) : device{device_} {} | ||
| 33 | |||
| 34 | void PipelineStatistics::Collect(VkPipeline pipeline) { | ||
| 35 | const auto& dev{device.GetLogical()}; | ||
| 36 | const std::vector properties{dev.GetPipelineExecutablePropertiesKHR(pipeline)}; | ||
| 37 | const u32 num_executables{static_cast<u32>(properties.size())}; | ||
| 38 | for (u32 executable = 0; executable < num_executables; ++executable) { | ||
| 39 | const auto statistics{dev.GetPipelineExecutableStatisticsKHR(pipeline, executable)}; | ||
| 40 | if (statistics.empty()) { | ||
| 41 | continue; | ||
| 42 | } | ||
| 43 | Stats stage_stats; | ||
| 44 | for (const auto& statistic : statistics) { | ||
| 45 | const char* const name{statistic.name}; | ||
| 46 | if (name == "Binary Size"sv || name == "Code size"sv || name == "Instruction Count"sv) { | ||
| 47 | stage_stats.code_size = GetUint64(statistic); | ||
| 48 | } else if (name == "Register Count"sv) { | ||
| 49 | stage_stats.register_count = GetUint64(statistic); | ||
| 50 | } else if (name == "SGPRs"sv || name == "numUsedSgprs"sv) { | ||
| 51 | stage_stats.sgpr_count = GetUint64(statistic); | ||
| 52 | } else if (name == "VGPRs"sv || name == "numUsedVgprs"sv) { | ||
| 53 | stage_stats.vgpr_count = GetUint64(statistic); | ||
| 54 | } else if (name == "Branches"sv) { | ||
| 55 | stage_stats.branches_count = GetUint64(statistic); | ||
| 56 | } else if (name == "Basic Block Count"sv) { | ||
| 57 | stage_stats.basic_block_count = GetUint64(statistic); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | std::lock_guard lock{mutex}; | ||
| 61 | collected_stats.push_back(stage_stats); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | void PipelineStatistics::Report() const { | ||
| 66 | double num{}; | ||
| 67 | Stats total; | ||
| 68 | { | ||
| 69 | std::lock_guard lock{mutex}; | ||
| 70 | for (const Stats& stats : collected_stats) { | ||
| 71 | total.code_size += stats.code_size; | ||
| 72 | total.register_count += stats.register_count; | ||
| 73 | total.sgpr_count += stats.sgpr_count; | ||
| 74 | total.vgpr_count += stats.vgpr_count; | ||
| 75 | total.branches_count += stats.branches_count; | ||
| 76 | total.basic_block_count += stats.basic_block_count; | ||
| 77 | } | ||
| 78 | num = static_cast<double>(collected_stats.size()); | ||
| 79 | } | ||
| 80 | std::string report; | ||
| 81 | const auto add = [&](const char* fmt, u64 value) { | ||
| 82 | if (value > 0) { | ||
| 83 | report += fmt::format(fmt::runtime(fmt), static_cast<double>(value) / num); | ||
| 84 | } | ||
| 85 | }; | ||
| 86 | add("Code size: {:9.03f}\n", total.code_size); | ||
| 87 | add("Register count: {:9.03f}\n", total.register_count); | ||
| 88 | add("SGPRs: {:9.03f}\n", total.sgpr_count); | ||
| 89 | add("VGPRs: {:9.03f}\n", total.vgpr_count); | ||
| 90 | add("Branches count: {:9.03f}\n", total.branches_count); | ||
| 91 | add("Basic blocks: {:9.03f}\n", total.basic_block_count); | ||
| 92 | |||
| 93 | LOG_INFO(Render_Vulkan, | ||
| 94 | "\nAverage pipeline statistics\n" | ||
| 95 | "==========================================\n" | ||
| 96 | "{}\n", | ||
| 97 | report); | ||
| 98 | } | ||
| 99 | |||
| 100 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/pipeline_statistics.h b/src/video_core/renderer_vulkan/pipeline_statistics.h new file mode 100644 index 000000000..b61840107 --- /dev/null +++ b/src/video_core/renderer_vulkan/pipeline_statistics.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <mutex> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 12 | |||
| 13 | namespace Vulkan { | ||
| 14 | |||
| 15 | class Device; | ||
| 16 | |||
| 17 | class PipelineStatistics { | ||
| 18 | public: | ||
| 19 | explicit PipelineStatistics(const Device& device_); | ||
| 20 | |||
| 21 | void Collect(VkPipeline pipeline); | ||
| 22 | |||
| 23 | void Report() const; | ||
| 24 | |||
| 25 | private: | ||
| 26 | struct Stats { | ||
| 27 | u64 code_size{}; | ||
| 28 | u64 register_count{}; | ||
| 29 | u64 sgpr_count{}; | ||
| 30 | u64 vgpr_count{}; | ||
| 31 | u64 branches_count{}; | ||
| 32 | u64 basic_block_count{}; | ||
| 33 | }; | ||
| 34 | |||
| 35 | const Device& device; | ||
| 36 | mutable std::mutex mutex; | ||
| 37 | std::vector<Stats> collected_stats; | ||
| 38 | }; | ||
| 39 | |||
| 40 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 70b84c7a6..44faf626a 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <boost/container/small_vector.hpp> | 8 | #include <boost/container/small_vector.hpp> |
| 9 | 9 | ||
| 10 | #include "video_core/renderer_vulkan/pipeline_helper.h" | 10 | #include "video_core/renderer_vulkan/pipeline_helper.h" |
| 11 | #include "video_core/renderer_vulkan/pipeline_statistics.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 12 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| 12 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" | 13 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" |
| 13 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 14 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| @@ -26,6 +27,7 @@ using Tegra::Texture::TexturePair; | |||
| 26 | ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool, | 27 | ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool, |
| 27 | VKUpdateDescriptorQueue& update_descriptor_queue_, | 28 | VKUpdateDescriptorQueue& update_descriptor_queue_, |
| 28 | Common::ThreadWorker* thread_worker, | 29 | Common::ThreadWorker* thread_worker, |
| 30 | PipelineStatistics* pipeline_statistics, | ||
| 29 | VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_, | 31 | VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_, |
| 30 | vk::ShaderModule spv_module_) | 32 | vk::ShaderModule spv_module_) |
| 31 | : device{device_}, update_descriptor_queue{update_descriptor_queue_}, info{info_}, | 33 | : device{device_}, update_descriptor_queue{update_descriptor_queue_}, info{info_}, |
| @@ -36,7 +38,7 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript | |||
| 36 | std::copy_n(info.constant_buffer_used_sizes.begin(), uniform_buffer_sizes.size(), | 38 | std::copy_n(info.constant_buffer_used_sizes.begin(), uniform_buffer_sizes.size(), |
| 37 | uniform_buffer_sizes.begin()); | 39 | uniform_buffer_sizes.begin()); |
| 38 | 40 | ||
| 39 | auto func{[this, &descriptor_pool, shader_notify] { | 41 | auto func{[this, &descriptor_pool, shader_notify, pipeline_statistics] { |
| 40 | DescriptorLayoutBuilder builder{device}; | 42 | DescriptorLayoutBuilder builder{device}; |
| 41 | builder.Add(info, VK_SHADER_STAGE_COMPUTE_BIT); | 43 | builder.Add(info, VK_SHADER_STAGE_COMPUTE_BIT); |
| 42 | 44 | ||
| @@ -50,10 +52,14 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript | |||
| 50 | .pNext = nullptr, | 52 | .pNext = nullptr, |
| 51 | .requiredSubgroupSize = GuestWarpSize, | 53 | .requiredSubgroupSize = GuestWarpSize, |
| 52 | }; | 54 | }; |
| 55 | VkPipelineCreateFlags flags{}; | ||
| 56 | if (device.IsKhrPipelineEexecutablePropertiesEnabled()) { | ||
| 57 | flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR; | ||
| 58 | } | ||
| 53 | pipeline = device.GetLogical().CreateComputePipeline({ | 59 | pipeline = device.GetLogical().CreateComputePipeline({ |
| 54 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, | 60 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, |
| 55 | .pNext = nullptr, | 61 | .pNext = nullptr, |
| 56 | .flags = 0, | 62 | .flags = flags, |
| 57 | .stage{ | 63 | .stage{ |
| 58 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | 64 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
| 59 | .pNext = device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, | 65 | .pNext = device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, |
| @@ -67,6 +73,9 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript | |||
| 67 | .basePipelineHandle = 0, | 73 | .basePipelineHandle = 0, |
| 68 | .basePipelineIndex = 0, | 74 | .basePipelineIndex = 0, |
| 69 | }); | 75 | }); |
| 76 | if (pipeline_statistics) { | ||
| 77 | pipeline_statistics->Collect(*pipeline); | ||
| 78 | } | ||
| 70 | std::lock_guard lock{build_mutex}; | 79 | std::lock_guard lock{build_mutex}; |
| 71 | is_built = true; | 80 | is_built = true; |
| 72 | build_condvar.notify_one(); | 81 | build_condvar.notify_one(); |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index 52fec04d3..8c4b0a301 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h | |||
| @@ -25,6 +25,7 @@ class ShaderNotify; | |||
| 25 | namespace Vulkan { | 25 | namespace Vulkan { |
| 26 | 26 | ||
| 27 | class Device; | 27 | class Device; |
| 28 | class PipelineStatistics; | ||
| 28 | class VKScheduler; | 29 | class VKScheduler; |
| 29 | 30 | ||
| 30 | class ComputePipeline { | 31 | class ComputePipeline { |
| @@ -32,6 +33,7 @@ public: | |||
| 32 | explicit ComputePipeline(const Device& device, DescriptorPool& descriptor_pool, | 33 | explicit ComputePipeline(const Device& device, DescriptorPool& descriptor_pool, |
| 33 | VKUpdateDescriptorQueue& update_descriptor_queue, | 34 | VKUpdateDescriptorQueue& update_descriptor_queue, |
| 34 | Common::ThreadWorker* thread_worker, | 35 | Common::ThreadWorker* thread_worker, |
| 36 | PipelineStatistics* pipeline_statistics, | ||
| 35 | VideoCore::ShaderNotify* shader_notify, const Shader::Info& info, | 37 | VideoCore::ShaderNotify* shader_notify, const Shader::Info& info, |
| 36 | vk::ShaderModule spv_module); | 38 | vk::ShaderModule spv_module); |
| 37 | 39 | ||
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 18482e1d0..7c0f91007 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "common/bit_field.h" | 11 | #include "common/bit_field.h" |
| 12 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 12 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 13 | #include "video_core/renderer_vulkan/pipeline_helper.h" | 13 | #include "video_core/renderer_vulkan/pipeline_helper.h" |
| 14 | #include "video_core/renderer_vulkan/pipeline_statistics.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 15 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| 15 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" | 16 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" |
| 16 | #include "video_core/renderer_vulkan/vk_render_pass_cache.h" | 17 | #include "video_core/renderer_vulkan/vk_render_pass_cache.h" |
| @@ -217,8 +218,8 @@ GraphicsPipeline::GraphicsPipeline( | |||
| 217 | VKScheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, | 218 | VKScheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, |
| 218 | VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool, | 219 | VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool, |
| 219 | VKUpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread, | 220 | VKUpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread, |
| 220 | RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key_, | 221 | PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, |
| 221 | std::array<vk::ShaderModule, NUM_STAGES> stages, | 222 | const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages, |
| 222 | const std::array<const Shader::Info*, NUM_STAGES>& infos) | 223 | const std::array<const Shader::Info*, NUM_STAGES>& infos) |
| 223 | : key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, device{device_}, | 224 | : key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, device{device_}, |
| 224 | texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, scheduler{scheduler_}, | 225 | texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, scheduler{scheduler_}, |
| @@ -235,7 +236,7 @@ GraphicsPipeline::GraphicsPipeline( | |||
| 235 | enabled_uniform_buffer_masks[stage] = info->constant_buffer_mask; | 236 | enabled_uniform_buffer_masks[stage] = info->constant_buffer_mask; |
| 236 | std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin()); | 237 | std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin()); |
| 237 | } | 238 | } |
| 238 | auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool] { | 239 | auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool, pipeline_statistics] { |
| 239 | DescriptorLayoutBuilder builder{MakeBuilder(device, stage_infos)}; | 240 | DescriptorLayoutBuilder builder{MakeBuilder(device, stage_infos)}; |
| 240 | uses_push_descriptor = builder.CanUsePushDescriptor(); | 241 | uses_push_descriptor = builder.CanUsePushDescriptor(); |
| 241 | descriptor_set_layout = builder.CreateDescriptorSetLayout(uses_push_descriptor); | 242 | descriptor_set_layout = builder.CreateDescriptorSetLayout(uses_push_descriptor); |
| @@ -250,6 +251,9 @@ GraphicsPipeline::GraphicsPipeline( | |||
| 250 | const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(key.state))}; | 251 | const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(key.state))}; |
| 251 | Validate(); | 252 | Validate(); |
| 252 | MakePipeline(render_pass); | 253 | MakePipeline(render_pass); |
| 254 | if (pipeline_statistics) { | ||
| 255 | pipeline_statistics->Collect(*pipeline); | ||
| 256 | } | ||
| 253 | 257 | ||
| 254 | std::lock_guard lock{build_mutex}; | 258 | std::lock_guard lock{build_mutex}; |
| 255 | is_built = true; | 259 | is_built = true; |
| @@ -782,10 +786,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 782 | } | 786 | } |
| 783 | */ | 787 | */ |
| 784 | } | 788 | } |
| 789 | VkPipelineCreateFlags flags{}; | ||
| 790 | if (device.IsKhrPipelineEexecutablePropertiesEnabled()) { | ||
| 791 | flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR; | ||
| 792 | } | ||
| 785 | pipeline = device.GetLogical().CreateGraphicsPipeline({ | 793 | pipeline = device.GetLogical().CreateGraphicsPipeline({ |
| 786 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | 794 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, |
| 787 | .pNext = nullptr, | 795 | .pNext = nullptr, |
| 788 | .flags = 0, | 796 | .flags = flags, |
| 789 | .stageCount = static_cast<u32>(shader_stages.size()), | 797 | .stageCount = static_cast<u32>(shader_stages.size()), |
| 790 | .pStages = shader_stages.data(), | 798 | .pStages = shader_stages.data(), |
| 791 | .pVertexInputState = &vertex_input_ci, | 799 | .pVertexInputState = &vertex_input_ci, |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 2bd48d697..1c780e944 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h | |||
| @@ -60,6 +60,7 @@ struct hash<Vulkan::GraphicsPipelineCacheKey> { | |||
| 60 | namespace Vulkan { | 60 | namespace Vulkan { |
| 61 | 61 | ||
| 62 | class Device; | 62 | class Device; |
| 63 | class PipelineStatistics; | ||
| 63 | class RenderPassCache; | 64 | class RenderPassCache; |
| 64 | class VKScheduler; | 65 | class VKScheduler; |
| 65 | class VKUpdateDescriptorQueue; | 66 | class VKUpdateDescriptorQueue; |
| @@ -73,8 +74,9 @@ public: | |||
| 73 | VKScheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, | 74 | VKScheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, |
| 74 | VideoCore::ShaderNotify* shader_notify, const Device& device, | 75 | VideoCore::ShaderNotify* shader_notify, const Device& device, |
| 75 | DescriptorPool& descriptor_pool, VKUpdateDescriptorQueue& update_descriptor_queue, | 76 | DescriptorPool& descriptor_pool, VKUpdateDescriptorQueue& update_descriptor_queue, |
| 76 | Common::ThreadWorker* worker_thread, RenderPassCache& render_pass_cache, | 77 | Common::ThreadWorker* worker_thread, PipelineStatistics* pipeline_statistics, |
| 77 | const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages, | 78 | RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key, |
| 79 | std::array<vk::ShaderModule, NUM_STAGES> stages, | ||
| 78 | const std::array<const Shader::Info*, NUM_STAGES>& infos); | 80 | const std::array<const Shader::Info*, NUM_STAGES>& infos); |
| 79 | 81 | ||
| 80 | GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete; | 82 | GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete; |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 57b163247..a37ca1fdf 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 29 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| 30 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 30 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 31 | #include "video_core/renderer_vulkan/pipeline_helper.h" | 31 | #include "video_core/renderer_vulkan/pipeline_helper.h" |
| 32 | #include "video_core/renderer_vulkan/pipeline_statistics.h" | ||
| 32 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" | 33 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" |
| 33 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 34 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 34 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 35 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| @@ -389,15 +390,19 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading | |||
| 389 | size_t total{}; | 390 | size_t total{}; |
| 390 | size_t built{}; | 391 | size_t built{}; |
| 391 | bool has_loaded{}; | 392 | bool has_loaded{}; |
| 393 | std::unique_ptr<PipelineStatistics> statistics; | ||
| 392 | } state; | 394 | } state; |
| 393 | 395 | ||
| 396 | if (device.IsKhrPipelineEexecutablePropertiesEnabled()) { | ||
| 397 | state.statistics = std::make_unique<PipelineStatistics>(device); | ||
| 398 | } | ||
| 394 | const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { | 399 | const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { |
| 395 | ComputePipelineCacheKey key; | 400 | ComputePipelineCacheKey key; |
| 396 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); | 401 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); |
| 397 | 402 | ||
| 398 | workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable { | 403 | workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable { |
| 399 | ShaderPools pools; | 404 | ShaderPools pools; |
| 400 | auto pipeline{CreateComputePipeline(pools, key, env, false)}; | 405 | auto pipeline{CreateComputePipeline(pools, key, env, state.statistics.get(), false)}; |
| 401 | std::lock_guard lock{state.mutex}; | 406 | std::lock_guard lock{state.mutex}; |
| 402 | if (pipeline) { | 407 | if (pipeline) { |
| 403 | compute_cache.emplace(key, std::move(pipeline)); | 408 | compute_cache.emplace(key, std::move(pipeline)); |
| @@ -425,7 +430,8 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading | |||
| 425 | for (auto& env : envs) { | 430 | for (auto& env : envs) { |
| 426 | env_ptrs.push_back(&env); | 431 | env_ptrs.push_back(&env); |
| 427 | } | 432 | } |
| 428 | auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs), false)}; | 433 | auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs), |
| 434 | state.statistics.get(), false)}; | ||
| 429 | 435 | ||
| 430 | std::lock_guard lock{state.mutex}; | 436 | std::lock_guard lock{state.mutex}; |
| 431 | graphics_cache.emplace(key, std::move(pipeline)); | 437 | graphics_cache.emplace(key, std::move(pipeline)); |
| @@ -445,6 +451,10 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading | |||
| 445 | lock.unlock(); | 451 | lock.unlock(); |
| 446 | 452 | ||
| 447 | workers.WaitForRequests(); | 453 | workers.WaitForRequests(); |
| 454 | |||
| 455 | if (state.statistics) { | ||
| 456 | state.statistics->Report(); | ||
| 457 | } | ||
| 448 | } | 458 | } |
| 449 | 459 | ||
| 450 | GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() { | 460 | GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() { |
| @@ -486,7 +496,8 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const | |||
| 486 | 496 | ||
| 487 | std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( | 497 | std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( |
| 488 | ShaderPools& pools, const GraphicsPipelineCacheKey& key, | 498 | ShaderPools& pools, const GraphicsPipelineCacheKey& key, |
| 489 | std::span<Shader::Environment* const> envs, bool build_in_parallel) try { | 499 | std::span<Shader::Environment* const> envs, PipelineStatistics* statistics, |
| 500 | bool build_in_parallel) try { | ||
| 490 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); | 501 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); |
| 491 | size_t env_index{0}; | 502 | size_t env_index{0}; |
| 492 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; | 503 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; |
| @@ -540,7 +551,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( | |||
| 540 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; | 551 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; |
| 541 | return std::make_unique<GraphicsPipeline>( | 552 | return std::make_unique<GraphicsPipeline>( |
| 542 | maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, &shader_notify, device, | 553 | maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, &shader_notify, device, |
| 543 | descriptor_pool, update_descriptor_queue, thread_worker, render_pass_cache, key, | 554 | descriptor_pool, update_descriptor_queue, thread_worker, statistics, render_pass_cache, key, |
| 544 | std::move(modules), infos); | 555 | std::move(modules), infos); |
| 545 | 556 | ||
| 546 | } catch (const Shader::Exception& exception) { | 557 | } catch (const Shader::Exception& exception) { |
| @@ -553,7 +564,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() { | |||
| 553 | GetGraphicsEnvironments(environments, graphics_key.unique_hashes); | 564 | GetGraphicsEnvironments(environments, graphics_key.unique_hashes); |
| 554 | 565 | ||
| 555 | main_pools.ReleaseContents(); | 566 | main_pools.ReleaseContents(); |
| 556 | auto pipeline{CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(), true)}; | 567 | auto pipeline{ |
| 568 | CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(), nullptr, true)}; | ||
| 557 | if (!pipeline || pipeline_cache_filename.empty()) { | 569 | if (!pipeline || pipeline_cache_filename.empty()) { |
| 558 | return pipeline; | 570 | return pipeline; |
| 559 | } | 571 | } |
| @@ -578,7 +590,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | |||
| 578 | env.SetCachedSize(shader->size_bytes); | 590 | env.SetCachedSize(shader->size_bytes); |
| 579 | 591 | ||
| 580 | main_pools.ReleaseContents(); | 592 | main_pools.ReleaseContents(); |
| 581 | auto pipeline{CreateComputePipeline(main_pools, key, env, true)}; | 593 | auto pipeline{CreateComputePipeline(main_pools, key, env, nullptr, true)}; |
| 582 | if (!pipeline || pipeline_cache_filename.empty()) { | 594 | if (!pipeline || pipeline_cache_filename.empty()) { |
| 583 | return pipeline; | 595 | return pipeline; |
| 584 | } | 596 | } |
| @@ -591,7 +603,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | |||
| 591 | 603 | ||
| 592 | std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | 604 | std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( |
| 593 | ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, | 605 | ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, |
| 594 | bool build_in_parallel) try { | 606 | PipelineStatistics* statistics, bool build_in_parallel) try { |
| 595 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); | 607 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); |
| 596 | 608 | ||
| 597 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; | 609 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; |
| @@ -605,8 +617,8 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | |||
| 605 | } | 617 | } |
| 606 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; | 618 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; |
| 607 | return std::make_unique<ComputePipeline>(device, descriptor_pool, update_descriptor_queue, | 619 | return std::make_unique<ComputePipeline>(device, descriptor_pool, update_descriptor_queue, |
| 608 | thread_worker, &shader_notify, program.info, | 620 | thread_worker, statistics, &shader_notify, |
| 609 | std::move(spv_module)); | 621 | program.info, std::move(spv_module)); |
| 610 | 622 | ||
| 611 | } catch (const Shader::Exception& exception) { | 623 | } catch (const Shader::Exception& exception) { |
| 612 | LOG_ERROR(Render_Vulkan, "{}", exception.what()); | 624 | LOG_ERROR(Render_Vulkan, "{}", exception.what()); |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index efe5a7ed8..4c135b5dd 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h | |||
| @@ -80,8 +80,9 @@ struct hash<Vulkan::ComputePipelineCacheKey> { | |||
| 80 | namespace Vulkan { | 80 | namespace Vulkan { |
| 81 | 81 | ||
| 82 | class ComputePipeline; | 82 | class ComputePipeline; |
| 83 | class Device; | ||
| 84 | class DescriptorPool; | 83 | class DescriptorPool; |
| 84 | class Device; | ||
| 85 | class PipelineStatistics; | ||
| 85 | class RasterizerVulkan; | 86 | class RasterizerVulkan; |
| 86 | class RenderPassCache; | 87 | class RenderPassCache; |
| 87 | class VKScheduler; | 88 | class VKScheduler; |
| @@ -128,7 +129,8 @@ private: | |||
| 128 | 129 | ||
| 129 | std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline( | 130 | std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline( |
| 130 | ShaderPools& pools, const GraphicsPipelineCacheKey& key, | 131 | ShaderPools& pools, const GraphicsPipelineCacheKey& key, |
| 131 | std::span<Shader::Environment* const> envs, bool build_in_parallel); | 132 | std::span<Shader::Environment* const> envs, PipelineStatistics* statistics, |
| 133 | bool build_in_parallel); | ||
| 132 | 134 | ||
| 133 | std::unique_ptr<ComputePipeline> CreateComputePipeline(const ComputePipelineCacheKey& key, | 135 | std::unique_ptr<ComputePipeline> CreateComputePipeline(const ComputePipelineCacheKey& key, |
| 134 | const ShaderInfo* shader); | 136 | const ShaderInfo* shader); |
| @@ -136,6 +138,7 @@ private: | |||
| 136 | std::unique_ptr<ComputePipeline> CreateComputePipeline(ShaderPools& pools, | 138 | std::unique_ptr<ComputePipeline> CreateComputePipeline(ShaderPools& pools, |
| 137 | const ComputePipelineCacheKey& key, | 139 | const ComputePipelineCacheKey& key, |
| 138 | Shader::Environment& env, | 140 | Shader::Environment& env, |
| 141 | PipelineStatistics* statistics, | ||
| 139 | bool build_in_parallel); | 142 | bool build_in_parallel); |
| 140 | 143 | ||
| 141 | const Device& device; | 144 | const Device& device; |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index c7a07fdd8..23cef2996 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -61,11 +61,16 @@ struct DrawParams { | |||
| 61 | VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index) { | 61 | VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index) { |
| 62 | const auto& src = regs.viewport_transform[index]; | 62 | const auto& src = regs.viewport_transform[index]; |
| 63 | const float width = src.scale_x * 2.0f; | 63 | const float width = src.scale_x * 2.0f; |
| 64 | const float height = src.scale_y * 2.0f; | 64 | float y = src.translate_y - src.scale_y; |
| 65 | float height = src.scale_y * 2.0f; | ||
| 66 | if (regs.screen_y_control.y_negate) { | ||
| 67 | y += height; | ||
| 68 | height = -height; | ||
| 69 | } | ||
| 65 | const float reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1.0f : 0.0f; | 70 | const float reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1.0f : 0.0f; |
| 66 | VkViewport viewport{ | 71 | VkViewport viewport{ |
| 67 | .x = src.translate_x - src.scale_x, | 72 | .x = src.translate_x - src.scale_x, |
| 68 | .y = src.translate_y - src.scale_y, | 73 | .y = y, |
| 69 | .width = width != 0.0f ? width : 1.0f, | 74 | .width = width != 0.0f ? width : 1.0f, |
| 70 | .height = height != 0.0f ? height : 1.0f, | 75 | .height = height != 0.0f ? height : 1.0f, |
| 71 | .minDepth = src.translate_z - src.scale_z * reduce_z, | 76 | .minDepth = src.translate_z - src.scale_z * reduce_z, |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 44afdc1cd..8e56a89e1 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -526,6 +526,17 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 526 | SetNext(next, workgroup_layout); | 526 | SetNext(next, workgroup_layout); |
| 527 | } | 527 | } |
| 528 | 528 | ||
| 529 | VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties; | ||
| 530 | if (khr_pipeline_executable_properties) { | ||
| 531 | LOG_INFO(Render_Vulkan, "Enabling shader feedback, expect slower shader build times"); | ||
| 532 | executable_properties = { | ||
| 533 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR, | ||
| 534 | .pNext = nullptr, | ||
| 535 | .pipelineExecutableInfo = VK_TRUE, | ||
| 536 | }; | ||
| 537 | SetNext(next, executable_properties); | ||
| 538 | } | ||
| 539 | |||
| 529 | if (!ext_depth_range_unrestricted) { | 540 | if (!ext_depth_range_unrestricted) { |
| 530 | LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted"); | 541 | LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted"); |
| 531 | } | 542 | } |
| @@ -824,6 +835,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) { | |||
| 824 | 835 | ||
| 825 | bool has_khr_shader_float16_int8{}; | 836 | bool has_khr_shader_float16_int8{}; |
| 826 | bool has_khr_workgroup_memory_explicit_layout{}; | 837 | bool has_khr_workgroup_memory_explicit_layout{}; |
| 838 | bool has_khr_pipeline_executable_properties{}; | ||
| 827 | bool has_ext_subgroup_size_control{}; | 839 | bool has_ext_subgroup_size_control{}; |
| 828 | bool has_ext_transform_feedback{}; | 840 | bool has_ext_transform_feedback{}; |
| 829 | bool has_ext_custom_border_color{}; | 841 | bool has_ext_custom_border_color{}; |
| @@ -878,6 +890,10 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) { | |||
| 878 | test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, | 890 | test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, |
| 879 | true); | 891 | true); |
| 880 | } | 892 | } |
| 893 | if (Settings::values.renderer_shader_feedback) { | ||
| 894 | test(has_khr_pipeline_executable_properties, | ||
| 895 | VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME, false); | ||
| 896 | } | ||
| 881 | } | 897 | } |
| 882 | VkPhysicalDeviceFeatures2KHR features{}; | 898 | VkPhysicalDeviceFeatures2KHR features{}; |
| 883 | features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; | 899 | features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; |
| @@ -1033,6 +1049,19 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) { | |||
| 1033 | khr_workgroup_memory_explicit_layout = true; | 1049 | khr_workgroup_memory_explicit_layout = true; |
| 1034 | } | 1050 | } |
| 1035 | } | 1051 | } |
| 1052 | if (has_khr_pipeline_executable_properties) { | ||
| 1053 | VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties; | ||
| 1054 | executable_properties.sType = | ||
| 1055 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR; | ||
| 1056 | executable_properties.pNext = nullptr; | ||
| 1057 | features.pNext = &executable_properties; | ||
| 1058 | physical.GetFeatures2KHR(features); | ||
| 1059 | |||
| 1060 | if (executable_properties.pipelineExecutableInfo) { | ||
| 1061 | extensions.push_back(VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME); | ||
| 1062 | khr_pipeline_executable_properties = true; | ||
| 1063 | } | ||
| 1064 | } | ||
| 1036 | if (khr_push_descriptor) { | 1065 | if (khr_push_descriptor) { |
| 1037 | VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor; | 1066 | VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor; |
| 1038 | push_descriptor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR; | 1067 | push_descriptor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR; |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index df394e384..c19f40746 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -214,6 +214,11 @@ public: | |||
| 214 | return khr_push_descriptor; | 214 | return khr_push_descriptor; |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | /// Returns true if VK_KHR_pipeline_executable_properties is enabled. | ||
| 218 | bool IsKhrPipelineEexecutablePropertiesEnabled() const { | ||
| 219 | return khr_pipeline_executable_properties; | ||
| 220 | } | ||
| 221 | |||
| 217 | /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout. | 222 | /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout. |
| 218 | bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const { | 223 | bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const { |
| 219 | return khr_workgroup_memory_explicit_layout; | 224 | return khr_workgroup_memory_explicit_layout; |
| @@ -378,6 +383,7 @@ private: | |||
| 378 | bool khr_spirv_1_4{}; ///< Support for VK_KHR_spirv_1_4. | 383 | bool khr_spirv_1_4{}; ///< Support for VK_KHR_spirv_1_4. |
| 379 | bool khr_workgroup_memory_explicit_layout{}; ///< Support for explicit workgroup layouts. | 384 | bool khr_workgroup_memory_explicit_layout{}; ///< Support for explicit workgroup layouts. |
| 380 | bool khr_push_descriptor{}; ///< Support for VK_KHR_push_descritor. | 385 | bool khr_push_descriptor{}; ///< Support for VK_KHR_push_descritor. |
| 386 | bool khr_pipeline_executable_properties{}; ///< Support for executable properties. | ||
| 381 | bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. | 387 | bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. |
| 382 | bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax. | 388 | bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax. |
| 383 | bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. | 389 | bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 70898004a..a9faa4807 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp | |||
| @@ -181,6 +181,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 181 | X(vkGetMemoryWin32HandleKHR); | 181 | X(vkGetMemoryWin32HandleKHR); |
| 182 | #endif | 182 | #endif |
| 183 | X(vkGetQueryPoolResults); | 183 | X(vkGetQueryPoolResults); |
| 184 | X(vkGetPipelineExecutablePropertiesKHR); | ||
| 185 | X(vkGetPipelineExecutableStatisticsKHR); | ||
| 184 | X(vkGetSemaphoreCounterValueKHR); | 186 | X(vkGetSemaphoreCounterValueKHR); |
| 185 | X(vkMapMemory); | 187 | X(vkMapMemory); |
| 186 | X(vkQueueSubmit); | 188 | X(vkQueueSubmit); |
| @@ -809,6 +811,42 @@ VkMemoryRequirements Device::GetImageMemoryRequirements(VkImage image) const noe | |||
| 809 | return requirements; | 811 | return requirements; |
| 810 | } | 812 | } |
| 811 | 813 | ||
| 814 | std::vector<VkPipelineExecutablePropertiesKHR> Device::GetPipelineExecutablePropertiesKHR( | ||
| 815 | VkPipeline pipeline) const { | ||
| 816 | const VkPipelineInfoKHR info{ | ||
| 817 | .sType = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR, | ||
| 818 | .pNext = nullptr, | ||
| 819 | .pipeline = pipeline, | ||
| 820 | }; | ||
| 821 | u32 num{}; | ||
| 822 | dld->vkGetPipelineExecutablePropertiesKHR(handle, &info, &num, nullptr); | ||
| 823 | std::vector<VkPipelineExecutablePropertiesKHR> properties(num); | ||
| 824 | for (auto& property : properties) { | ||
| 825 | property.sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR; | ||
| 826 | } | ||
| 827 | Check(dld->vkGetPipelineExecutablePropertiesKHR(handle, &info, &num, properties.data())); | ||
| 828 | return properties; | ||
| 829 | } | ||
| 830 | |||
| 831 | std::vector<VkPipelineExecutableStatisticKHR> Device::GetPipelineExecutableStatisticsKHR( | ||
| 832 | VkPipeline pipeline, u32 executable_index) const { | ||
| 833 | const VkPipelineExecutableInfoKHR executable_info{ | ||
| 834 | .sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR, | ||
| 835 | .pNext = nullptr, | ||
| 836 | .pipeline = pipeline, | ||
| 837 | .executableIndex = executable_index, | ||
| 838 | }; | ||
| 839 | u32 num{}; | ||
| 840 | dld->vkGetPipelineExecutableStatisticsKHR(handle, &executable_info, &num, nullptr); | ||
| 841 | std::vector<VkPipelineExecutableStatisticKHR> statistics(num); | ||
| 842 | for (auto& statistic : statistics) { | ||
| 843 | statistic.sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR; | ||
| 844 | } | ||
| 845 | Check(dld->vkGetPipelineExecutableStatisticsKHR(handle, &executable_info, &num, | ||
| 846 | statistics.data())); | ||
| 847 | return statistics; | ||
| 848 | } | ||
| 849 | |||
| 812 | void Device::UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes, | 850 | void Device::UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes, |
| 813 | Span<VkCopyDescriptorSet> copies) const noexcept { | 851 | Span<VkCopyDescriptorSet> copies) const noexcept { |
| 814 | dld->vkUpdateDescriptorSets(handle, writes.size(), writes.data(), copies.size(), copies.data()); | 852 | dld->vkUpdateDescriptorSets(handle, writes.size(), writes.data(), copies.size(), copies.data()); |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index d76bb4324..b7ae01c6c 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h | |||
| @@ -295,6 +295,8 @@ struct DeviceDispatch : InstanceDispatch { | |||
| 295 | #ifdef _WIN32 | 295 | #ifdef _WIN32 |
| 296 | PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR{}; | 296 | PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR{}; |
| 297 | #endif | 297 | #endif |
| 298 | PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR{}; | ||
| 299 | PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR{}; | ||
| 298 | PFN_vkGetQueryPoolResults vkGetQueryPoolResults{}; | 300 | PFN_vkGetQueryPoolResults vkGetQueryPoolResults{}; |
| 299 | PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR{}; | 301 | PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR{}; |
| 300 | PFN_vkMapMemory vkMapMemory{}; | 302 | PFN_vkMapMemory vkMapMemory{}; |
| @@ -879,6 +881,12 @@ public: | |||
| 879 | 881 | ||
| 880 | VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept; | 882 | VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept; |
| 881 | 883 | ||
| 884 | std::vector<VkPipelineExecutablePropertiesKHR> GetPipelineExecutablePropertiesKHR( | ||
| 885 | VkPipeline pipeline) const; | ||
| 886 | |||
| 887 | std::vector<VkPipelineExecutableStatisticKHR> GetPipelineExecutableStatisticsKHR( | ||
| 888 | VkPipeline pipeline, u32 executable_index) const; | ||
| 889 | |||
| 882 | void UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes, | 890 | void UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes, |
| 883 | Span<VkCopyDescriptorSet> copies) const noexcept; | 891 | Span<VkCopyDescriptorSet> copies) const noexcept; |
| 884 | 892 | ||
diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index b112dd7b0..652d99570 100644 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp | |||
| @@ -107,6 +107,7 @@ void QtNXWebEngineView::LoadLocalWebPage(const std::string& main_url, | |||
| 107 | is_local = true; | 107 | is_local = true; |
| 108 | 108 | ||
| 109 | LoadExtractedFonts(); | 109 | LoadExtractedFonts(); |
| 110 | FocusFirstLinkElement(); | ||
| 110 | SetUserAgent(UserAgent::WebApplet); | 111 | SetUserAgent(UserAgent::WebApplet); |
| 111 | SetFinished(false); | 112 | SetFinished(false); |
| 112 | SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); | 113 | SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); |
| @@ -121,6 +122,7 @@ void QtNXWebEngineView::LoadExternalWebPage(const std::string& main_url, | |||
| 121 | const std::string& additional_args) { | 122 | const std::string& additional_args) { |
| 122 | is_local = false; | 123 | is_local = false; |
| 123 | 124 | ||
| 125 | FocusFirstLinkElement(); | ||
| 124 | SetUserAgent(UserAgent::WebApplet); | 126 | SetUserAgent(UserAgent::WebApplet); |
| 125 | SetFinished(false); | 127 | SetFinished(false); |
| 126 | SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); | 128 | SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); |
| @@ -208,7 +210,7 @@ void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { | |||
| 208 | if (input_interpreter->IsButtonPressedOnce(button)) { | 210 | if (input_interpreter->IsButtonPressedOnce(button)) { |
| 209 | page()->runJavaScript( | 211 | page()->runJavaScript( |
| 210 | QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)), | 212 | QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)), |
| 211 | [&](const QVariant& variant) { | 213 | [this, button](const QVariant& variant) { |
| 212 | if (variant.toBool()) { | 214 | if (variant.toBool()) { |
| 213 | switch (button) { | 215 | switch (button) { |
| 214 | case HIDButton::A: | 216 | case HIDButton::A: |
| @@ -364,6 +366,17 @@ void QtNXWebEngineView::LoadExtractedFonts() { | |||
| 364 | Qt::QueuedConnection); | 366 | Qt::QueuedConnection); |
| 365 | } | 367 | } |
| 366 | 368 | ||
| 369 | void QtNXWebEngineView::FocusFirstLinkElement() { | ||
| 370 | QWebEngineScript focus_link_element; | ||
| 371 | |||
| 372 | focus_link_element.setName(QStringLiteral("focus_link_element.js")); | ||
| 373 | focus_link_element.setSourceCode(QString::fromStdString(FOCUS_LINK_ELEMENT_SCRIPT)); | ||
| 374 | focus_link_element.setWorldId(QWebEngineScript::MainWorld); | ||
| 375 | focus_link_element.setInjectionPoint(QWebEngineScript::Deferred); | ||
| 376 | focus_link_element.setRunsOnSubFrames(true); | ||
| 377 | default_profile->scripts()->insert(focus_link_element); | ||
| 378 | } | ||
| 379 | |||
| 367 | #endif | 380 | #endif |
| 368 | 381 | ||
| 369 | QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { | 382 | QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { |
diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h index 7ad07409f..7e9f703fc 100644 --- a/src/yuzu/applets/qt_web_browser.h +++ b/src/yuzu/applets/qt_web_browser.h | |||
| @@ -161,6 +161,9 @@ private: | |||
| 161 | /// Loads the extracted fonts using JavaScript. | 161 | /// Loads the extracted fonts using JavaScript. |
| 162 | void LoadExtractedFonts(); | 162 | void LoadExtractedFonts(); |
| 163 | 163 | ||
| 164 | /// Brings focus to the first available link element. | ||
| 165 | void FocusFirstLinkElement(); | ||
| 166 | |||
| 164 | InputCommon::InputSubsystem* input_subsystem; | 167 | InputCommon::InputSubsystem* input_subsystem; |
| 165 | 168 | ||
| 166 | std::unique_ptr<UrlRequestInterceptor> url_interceptor; | 169 | std::unique_ptr<UrlRequestInterceptor> url_interceptor; |
diff --git a/src/yuzu/applets/qt_web_browser_scripts.h b/src/yuzu/applets/qt_web_browser_scripts.h index 992837a85..c4ba8d40f 100644 --- a/src/yuzu/applets/qt_web_browser_scripts.h +++ b/src/yuzu/applets/qt_web_browser_scripts.h | |||
| @@ -73,6 +73,12 @@ constexpr char LOAD_NX_FONT[] = R"( | |||
| 73 | })(); | 73 | })(); |
| 74 | )"; | 74 | )"; |
| 75 | 75 | ||
| 76 | constexpr char FOCUS_LINK_ELEMENT_SCRIPT[] = R"( | ||
| 77 | if (document.getElementsByTagName("a").length > 0) { | ||
| 78 | document.getElementsByTagName("a")[0].focus(); | ||
| 79 | } | ||
| 80 | )"; | ||
| 81 | |||
| 76 | constexpr char GAMEPAD_SCRIPT[] = R"( | 82 | constexpr char GAMEPAD_SCRIPT[] = R"( |
| 77 | window.addEventListener("gamepadconnected", function(e) { | 83 | window.addEventListener("gamepadconnected", function(e) { |
| 78 | console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.", | 84 | console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.", |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 72027e773..f3b8787f5 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -825,6 +825,7 @@ void Config::ReadRendererValues() { | |||
| 825 | if (global) { | 825 | if (global) { |
| 826 | ReadBasicSetting(Settings::values.fps_cap); | 826 | ReadBasicSetting(Settings::values.fps_cap); |
| 827 | ReadBasicSetting(Settings::values.renderer_debug); | 827 | ReadBasicSetting(Settings::values.renderer_debug); |
| 828 | ReadBasicSetting(Settings::values.renderer_shader_feedback); | ||
| 828 | ReadBasicSetting(Settings::values.enable_nsight_aftermath); | 829 | ReadBasicSetting(Settings::values.enable_nsight_aftermath); |
| 829 | ReadBasicSetting(Settings::values.disable_shader_loop_safety_checks); | 830 | ReadBasicSetting(Settings::values.disable_shader_loop_safety_checks); |
| 830 | } | 831 | } |
| @@ -1332,7 +1333,10 @@ void Config::SaveRendererValues() { | |||
| 1332 | static_cast<u32>(Settings::values.renderer_backend.GetDefault()), | 1333 | static_cast<u32>(Settings::values.renderer_backend.GetDefault()), |
| 1333 | Settings::values.renderer_backend.UsingGlobal()); | 1334 | Settings::values.renderer_backend.UsingGlobal()); |
| 1334 | WriteGlobalSetting(Settings::values.vulkan_device); | 1335 | WriteGlobalSetting(Settings::values.vulkan_device); |
| 1335 | WriteGlobalSetting(Settings::values.fullscreen_mode); | 1336 | WriteSetting(QString::fromStdString(Settings::values.fullscreen_mode.GetLabel()), |
| 1337 | static_cast<u32>(Settings::values.fullscreen_mode.GetValue(global)), | ||
| 1338 | static_cast<u32>(Settings::values.fullscreen_mode.GetDefault()), | ||
| 1339 | Settings::values.fullscreen_mode.UsingGlobal()); | ||
| 1336 | WriteGlobalSetting(Settings::values.aspect_ratio); | 1340 | WriteGlobalSetting(Settings::values.aspect_ratio); |
| 1337 | WriteGlobalSetting(Settings::values.max_anisotropy); | 1341 | WriteGlobalSetting(Settings::values.max_anisotropy); |
| 1338 | WriteGlobalSetting(Settings::values.use_speed_limit); | 1342 | WriteGlobalSetting(Settings::values.use_speed_limit); |
| @@ -1360,6 +1364,7 @@ void Config::SaveRendererValues() { | |||
| 1360 | if (global) { | 1364 | if (global) { |
| 1361 | WriteBasicSetting(Settings::values.fps_cap); | 1365 | WriteBasicSetting(Settings::values.fps_cap); |
| 1362 | WriteBasicSetting(Settings::values.renderer_debug); | 1366 | WriteBasicSetting(Settings::values.renderer_debug); |
| 1367 | WriteBasicSetting(Settings::values.renderer_shader_feedback); | ||
| 1363 | WriteBasicSetting(Settings::values.enable_nsight_aftermath); | 1368 | WriteBasicSetting(Settings::values.enable_nsight_aftermath); |
| 1364 | WriteBasicSetting(Settings::values.disable_shader_loop_safety_checks); | 1369 | WriteBasicSetting(Settings::values.disable_shader_loop_safety_checks); |
| 1365 | } | 1370 | } |
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 4bbb9f1cd..c1d7feb9f 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h | |||
| @@ -181,5 +181,6 @@ private: | |||
| 181 | // These metatype declarations cannot be in common/settings.h because core is devoid of QT | 181 | // These metatype declarations cannot be in common/settings.h because core is devoid of QT |
| 182 | Q_DECLARE_METATYPE(Settings::CPUAccuracy); | 182 | Q_DECLARE_METATYPE(Settings::CPUAccuracy); |
| 183 | Q_DECLARE_METATYPE(Settings::GPUAccuracy); | 183 | Q_DECLARE_METATYPE(Settings::GPUAccuracy); |
| 184 | Q_DECLARE_METATYPE(Settings::FullscreenMode); | ||
| 184 | Q_DECLARE_METATYPE(Settings::RendererBackend); | 185 | Q_DECLARE_METATYPE(Settings::RendererBackend); |
| 185 | Q_DECLARE_METATYPE(Settings::ShaderBackend); | 186 | Q_DECLARE_METATYPE(Settings::ShaderBackend); |
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp index 096e42e94..251aab912 100644 --- a/src/yuzu/configuration/configuration_shared.cpp +++ b/src/yuzu/configuration/configuration_shared.cpp | |||
| @@ -25,20 +25,6 @@ void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting, | |||
| 25 | } | 25 | } |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting, | ||
| 29 | const QComboBox* combobox) { | ||
| 30 | if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) { | ||
| 31 | setting->SetValue(combobox->currentIndex()); | ||
| 32 | } else if (!Settings::IsConfiguringGlobal()) { | ||
| 33 | if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { | ||
| 34 | setting->SetGlobal(true); | ||
| 35 | } else { | ||
| 36 | setting->SetGlobal(false); | ||
| 37 | setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox, | 28 | void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox, |
| 43 | const Settings::Setting<bool>* setting) { | 29 | const Settings::Setting<bool>* setting) { |
| 44 | if (setting->UsingGlobal()) { | 30 | if (setting->UsingGlobal()) { |
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h index 1e0ef01ca..5423dbc92 100644 --- a/src/yuzu/configuration/configuration_shared.h +++ b/src/yuzu/configuration/configuration_shared.h | |||
| @@ -28,7 +28,20 @@ enum class CheckState { | |||
| 28 | // ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting | 28 | // ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting |
| 29 | void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox, | 29 | void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox, |
| 30 | const CheckState& tracker); | 30 | const CheckState& tracker); |
| 31 | void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox); | 31 | template <typename Type> |
| 32 | void ApplyPerGameSetting(Settings::Setting<Type>* setting, const QComboBox* combobox) { | ||
| 33 | if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) { | ||
| 34 | setting->SetValue(static_cast<Type>(combobox->currentIndex())); | ||
| 35 | } else if (!Settings::IsConfiguringGlobal()) { | ||
| 36 | if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { | ||
| 37 | setting->SetGlobal(true); | ||
| 38 | } else { | ||
| 39 | setting->SetGlobal(false); | ||
| 40 | setting->SetValue(static_cast<Type>(combobox->currentIndex() - | ||
| 41 | ConfigurationShared::USE_GLOBAL_OFFSET)); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 32 | 45 | ||
| 33 | // Sets a Qt UI element given a Settings::Setting | 46 | // Sets a Qt UI element given a Settings::Setting |
| 34 | void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting); | 47 | void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting); |
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp index 8d7171487..784b6484e 100644 --- a/src/yuzu/configuration/configure_cpu.cpp +++ b/src/yuzu/configuration/configure_cpu.cpp | |||
| @@ -65,6 +65,7 @@ void ConfigureCpu::UpdateGroup(int index) { | |||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void ConfigureCpu::ApplyConfiguration() { | 67 | void ConfigureCpu::ApplyConfiguration() { |
| 68 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpu_accuracy, ui->accuracy); | ||
| 68 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_unfuse_fma, | 69 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_unfuse_fma, |
| 69 | ui->cpuopt_unsafe_unfuse_fma, | 70 | ui->cpuopt_unsafe_unfuse_fma, |
| 70 | cpuopt_unsafe_unfuse_fma); | 71 | cpuopt_unsafe_unfuse_fma); |
| @@ -80,22 +81,6 @@ void ConfigureCpu::ApplyConfiguration() { | |||
| 80 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_fastmem_check, | 81 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_fastmem_check, |
| 81 | ui->cpuopt_unsafe_fastmem_check, | 82 | ui->cpuopt_unsafe_fastmem_check, |
| 82 | cpuopt_unsafe_fastmem_check); | 83 | cpuopt_unsafe_fastmem_check); |
| 83 | |||
| 84 | if (Settings::IsConfiguringGlobal()) { | ||
| 85 | // Guard if during game and set to game-specific value | ||
| 86 | if (Settings::values.cpu_accuracy.UsingGlobal()) { | ||
| 87 | Settings::values.cpu_accuracy.SetValue( | ||
| 88 | static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex())); | ||
| 89 | } | ||
| 90 | } else { | ||
| 91 | if (ui->accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { | ||
| 92 | Settings::values.cpu_accuracy.SetGlobal(true); | ||
| 93 | } else { | ||
| 94 | Settings::values.cpu_accuracy.SetGlobal(false); | ||
| 95 | Settings::values.cpu_accuracy.SetValue(static_cast<Settings::CPUAccuracy>( | ||
| 96 | ui->accuracy->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET)); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } | 84 | } |
| 100 | 85 | ||
| 101 | void ConfigureCpu::changeEvent(QEvent* event) { | 86 | void ConfigureCpu::changeEvent(QEvent* event) { |
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index f7e29dbd7..c0b240c1e 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp | |||
| @@ -43,6 +43,8 @@ void ConfigureDebug::SetConfiguration() { | |||
| 43 | ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue()); | 43 | ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue()); |
| 44 | ui->enable_graphics_debugging->setEnabled(runtime_lock); | 44 | ui->enable_graphics_debugging->setEnabled(runtime_lock); |
| 45 | ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue()); | 45 | ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue()); |
| 46 | ui->enable_shader_feedback->setEnabled(runtime_lock); | ||
| 47 | ui->enable_shader_feedback->setChecked(Settings::values.renderer_shader_feedback.GetValue()); | ||
| 46 | ui->enable_cpu_debugging->setEnabled(runtime_lock); | 48 | ui->enable_cpu_debugging->setEnabled(runtime_lock); |
| 47 | ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue()); | 49 | ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue()); |
| 48 | ui->enable_nsight_aftermath->setEnabled(runtime_lock); | 50 | ui->enable_nsight_aftermath->setEnabled(runtime_lock); |
| @@ -65,6 +67,7 @@ void ConfigureDebug::ApplyConfiguration() { | |||
| 65 | Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked(); | 67 | Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked(); |
| 66 | Settings::values.use_auto_stub = ui->use_auto_stub->isChecked(); | 68 | Settings::values.use_auto_stub = ui->use_auto_stub->isChecked(); |
| 67 | Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); | 69 | Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); |
| 70 | Settings::values.renderer_shader_feedback = ui->enable_shader_feedback->isChecked(); | ||
| 68 | Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); | 71 | Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); |
| 69 | Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked(); | 72 | Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked(); |
| 70 | Settings::values.disable_shader_loop_safety_checks = | 73 | Settings::values.disable_shader_loop_safety_checks = |
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index c8baf2921..3fe9ff7de 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui | |||
| @@ -111,8 +111,8 @@ | |||
| 111 | <property name="title"> | 111 | <property name="title"> |
| 112 | <string>Graphics</string> | 112 | <string>Graphics</string> |
| 113 | </property> | 113 | </property> |
| 114 | <layout class="QVBoxLayout" name="verticalLayout_6"> | 114 | <layout class="QGridLayout" name="gridLayout_3"> |
| 115 | <item> | 115 | <item row="0" column="0"> |
| 116 | <widget class="QCheckBox" name="enable_graphics_debugging"> | 116 | <widget class="QCheckBox" name="enable_graphics_debugging"> |
| 117 | <property name="enabled"> | 117 | <property name="enabled"> |
| 118 | <bool>true</bool> | 118 | <bool>true</bool> |
| @@ -125,7 +125,7 @@ | |||
| 125 | </property> | 125 | </property> |
| 126 | </widget> | 126 | </widget> |
| 127 | </item> | 127 | </item> |
| 128 | <item> | 128 | <item row="2" column="0"> |
| 129 | <widget class="QCheckBox" name="enable_nsight_aftermath"> | 129 | <widget class="QCheckBox" name="enable_nsight_aftermath"> |
| 130 | <property name="toolTip"> | 130 | <property name="toolTip"> |
| 131 | <string>When checked, it enables Nsight Aftermath crash dumps</string> | 131 | <string>When checked, it enables Nsight Aftermath crash dumps</string> |
| @@ -135,7 +135,7 @@ | |||
| 135 | </property> | 135 | </property> |
| 136 | </widget> | 136 | </widget> |
| 137 | </item> | 137 | </item> |
| 138 | <item> | 138 | <item row="0" column="1"> |
| 139 | <widget class="QCheckBox" name="disable_macro_jit"> | 139 | <widget class="QCheckBox" name="disable_macro_jit"> |
| 140 | <property name="enabled"> | 140 | <property name="enabled"> |
| 141 | <bool>true</bool> | 141 | <bool>true</bool> |
| @@ -148,7 +148,17 @@ | |||
| 148 | </property> | 148 | </property> |
| 149 | </widget> | 149 | </widget> |
| 150 | </item> | 150 | </item> |
| 151 | <item> | 151 | <item row="1" column="0"> |
| 152 | <widget class="QCheckBox" name="enable_shader_feedback"> | ||
| 153 | <property name="toolTip"> | ||
| 154 | <string>When checked, yuzu will log statistics about the compiled pipeline cache</string> | ||
| 155 | </property> | ||
| 156 | <property name="text"> | ||
| 157 | <string>Enable Shader Feedback</string> | ||
| 158 | </property> | ||
| 159 | </widget> | ||
| 160 | </item> | ||
| 161 | <item row="1" column="1"> | ||
| 152 | <widget class="QCheckBox" name="disable_loop_safety_checks"> | 162 | <widget class="QCheckBox" name="disable_loop_safety_checks"> |
| 153 | <property name="toolTip"> | 163 | <property name="toolTip"> |
| 154 | <string>When checked, it executes shaders without loop logic changes</string> | 164 | <string>When checked, it executes shaders without loop logic changes</string> |
| @@ -276,11 +286,14 @@ | |||
| 276 | <tabstop>open_log_button</tabstop> | 286 | <tabstop>open_log_button</tabstop> |
| 277 | <tabstop>homebrew_args_edit</tabstop> | 287 | <tabstop>homebrew_args_edit</tabstop> |
| 278 | <tabstop>enable_graphics_debugging</tabstop> | 288 | <tabstop>enable_graphics_debugging</tabstop> |
| 289 | <tabstop>enable_shader_feedback</tabstop> | ||
| 279 | <tabstop>enable_nsight_aftermath</tabstop> | 290 | <tabstop>enable_nsight_aftermath</tabstop> |
| 280 | <tabstop>disable_macro_jit</tabstop> | 291 | <tabstop>disable_macro_jit</tabstop> |
| 281 | <tabstop>disable_loop_safety_checks</tabstop> | 292 | <tabstop>disable_loop_safety_checks</tabstop> |
| 293 | <tabstop>fs_access_log</tabstop> | ||
| 282 | <tabstop>reporting_services</tabstop> | 294 | <tabstop>reporting_services</tabstop> |
| 283 | <tabstop>quest_flag</tabstop> | 295 | <tabstop>quest_flag</tabstop> |
| 296 | <tabstop>enable_cpu_debugging</tabstop> | ||
| 284 | <tabstop>use_debug_asserts</tabstop> | 297 | <tabstop>use_debug_asserts</tabstop> |
| 285 | <tabstop>use_auto_stub</tabstop> | 298 | <tabstop>use_auto_stub</tabstop> |
| 286 | </tabstops> | 299 | </tabstops> |
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 1bc477c96..37e896258 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -98,7 +98,8 @@ void ConfigureGraphics::SetConfiguration() { | |||
| 98 | 98 | ||
| 99 | if (Settings::IsConfiguringGlobal()) { | 99 | if (Settings::IsConfiguringGlobal()) { |
| 100 | ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); | 100 | ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); |
| 101 | ui->fullscreen_mode_combobox->setCurrentIndex(Settings::values.fullscreen_mode.GetValue()); | 101 | ui->fullscreen_mode_combobox->setCurrentIndex( |
| 102 | static_cast<int>(Settings::values.fullscreen_mode.GetValue())); | ||
| 102 | ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); | 103 | ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); |
| 103 | } else { | 104 | } else { |
| 104 | ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); | 105 | ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); |
| @@ -310,8 +311,9 @@ void ConfigureGraphics::SetupPerGameUI() { | |||
| 310 | 311 | ||
| 311 | ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label, | 312 | ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label, |
| 312 | Settings::values.aspect_ratio.GetValue(true)); | 313 | Settings::values.aspect_ratio.GetValue(true)); |
| 313 | ConfigurationShared::SetColoredComboBox(ui->fullscreen_mode_combobox, ui->fullscreen_mode_label, | 314 | ConfigurationShared::SetColoredComboBox( |
| 314 | Settings::values.fullscreen_mode.GetValue(true)); | 315 | ui->fullscreen_mode_combobox, ui->fullscreen_mode_label, |
| 316 | static_cast<int>(Settings::values.fullscreen_mode.GetValue(true))); | ||
| 315 | ConfigurationShared::InsertGlobalItem( | 317 | ConfigurationShared::InsertGlobalItem( |
| 316 | ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); | 318 | ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); |
| 317 | } | 319 | } |
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 38276feb1..a31b8e192 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp | |||
| @@ -48,11 +48,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { | |||
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | void ConfigureGraphicsAdvanced::ApplyConfiguration() { | 50 | void ConfigureGraphicsAdvanced::ApplyConfiguration() { |
| 51 | // Subtract 2 if configuring per-game (separator and "use global configuration" take 2 slots) | 51 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.gpu_accuracy, ui->gpu_accuracy); |
| 52 | const auto gpu_accuracy = static_cast<Settings::GPUAccuracy>( | ||
| 53 | ui->gpu_accuracy->currentIndex() - | ||
| 54 | ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET)); | ||
| 55 | |||
| 56 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, | 52 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, |
| 57 | ui->anisotropic_filtering_combobox); | 53 | ui->anisotropic_filtering_combobox); |
| 58 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); | 54 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); |
| @@ -63,20 +59,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { | |||
| 63 | use_caches_gc); | 59 | use_caches_gc); |
| 64 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, | 60 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, |
| 65 | ui->use_fast_gpu_time, use_fast_gpu_time); | 61 | ui->use_fast_gpu_time, use_fast_gpu_time); |
| 66 | |||
| 67 | if (Settings::IsConfiguringGlobal()) { | ||
| 68 | // Must guard in case of a during-game configuration when set to be game-specific. | ||
| 69 | if (Settings::values.gpu_accuracy.UsingGlobal()) { | ||
| 70 | Settings::values.gpu_accuracy.SetValue(gpu_accuracy); | ||
| 71 | } | ||
| 72 | } else { | ||
| 73 | if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { | ||
| 74 | Settings::values.gpu_accuracy.SetGlobal(true); | ||
| 75 | } else { | ||
| 76 | Settings::values.gpu_accuracy.SetGlobal(false); | ||
| 77 | Settings::values.gpu_accuracy.SetValue(gpu_accuracy); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | 62 | } |
| 81 | 63 | ||
| 82 | void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { | 64 | void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { |
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui index 53b95658b..27f552f59 100644 --- a/src/yuzu/configuration/configure_system.ui +++ b/src/yuzu/configuration/configure_system.ui | |||
| @@ -401,6 +401,11 @@ | |||
| 401 | <string>Traditional Chinese (æ£é«”䏿–‡)</string> | 401 | <string>Traditional Chinese (æ£é«”䏿–‡)</string> |
| 402 | </property> | 402 | </property> |
| 403 | </item> | 403 | </item> |
| 404 | <item> | ||
| 405 | <property name="text"> | ||
| 406 | <string>Brazilian Portuguese (português do Brasil)</string> | ||
| 407 | </property> | ||
| 408 | </item> | ||
| 404 | </widget> | 409 | </widget> |
| 405 | </item> | 410 | </item> |
| 406 | <item row="5" column="0"> | 411 | <item row="5" column="0"> |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e172d2ff4..9544f0fb0 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -2513,7 +2513,7 @@ void GMainWindow::ShowFullscreen() { | |||
| 2513 | ui.menubar->hide(); | 2513 | ui.menubar->hide(); |
| 2514 | statusBar()->hide(); | 2514 | statusBar()->hide(); |
| 2515 | 2515 | ||
| 2516 | if (Settings::values.fullscreen_mode.GetValue() == 1) { | 2516 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { |
| 2517 | showFullScreen(); | 2517 | showFullScreen(); |
| 2518 | return; | 2518 | return; |
| 2519 | } | 2519 | } |
| @@ -2528,7 +2528,7 @@ void GMainWindow::ShowFullscreen() { | |||
| 2528 | } else { | 2528 | } else { |
| 2529 | UISettings::values.renderwindow_geometry = render_window->saveGeometry(); | 2529 | UISettings::values.renderwindow_geometry = render_window->saveGeometry(); |
| 2530 | 2530 | ||
| 2531 | if (Settings::values.fullscreen_mode.GetValue() == 1) { | 2531 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { |
| 2532 | render_window->showFullScreen(); | 2532 | render_window->showFullScreen(); |
| 2533 | return; | 2533 | return; |
| 2534 | } | 2534 | } |
| @@ -2545,7 +2545,7 @@ void GMainWindow::ShowFullscreen() { | |||
| 2545 | 2545 | ||
| 2546 | void GMainWindow::HideFullscreen() { | 2546 | void GMainWindow::HideFullscreen() { |
| 2547 | if (ui.action_Single_Window_Mode->isChecked()) { | 2547 | if (ui.action_Single_Window_Mode->isChecked()) { |
| 2548 | if (Settings::values.fullscreen_mode.GetValue() == 1) { | 2548 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { |
| 2549 | showNormal(); | 2549 | showNormal(); |
| 2550 | restoreGeometry(UISettings::values.geometry); | 2550 | restoreGeometry(UISettings::values.geometry); |
| 2551 | } else { | 2551 | } else { |
| @@ -2559,7 +2559,7 @@ void GMainWindow::HideFullscreen() { | |||
| 2559 | statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); | 2559 | statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); |
| 2560 | ui.menubar->show(); | 2560 | ui.menubar->show(); |
| 2561 | } else { | 2561 | } else { |
| 2562 | if (Settings::values.fullscreen_mode.GetValue() == 1) { | 2562 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { |
| 2563 | render_window->showNormal(); | 2563 | render_window->showNormal(); |
| 2564 | render_window->restoreGeometry(UISettings::values.renderwindow_geometry); | 2564 | render_window->restoreGeometry(UISettings::values.renderwindow_geometry); |
| 2565 | } else { | 2565 | } else { |
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 5af1ee6a8..064ecaafa 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -444,6 +444,7 @@ void Config::ReadValues() { | |||
| 444 | // Renderer | 444 | // Renderer |
| 445 | ReadSetting("Renderer", Settings::values.renderer_backend); | 445 | ReadSetting("Renderer", Settings::values.renderer_backend); |
| 446 | ReadSetting("Renderer", Settings::values.renderer_debug); | 446 | ReadSetting("Renderer", Settings::values.renderer_debug); |
| 447 | ReadSetting("Renderer", Settings::values.renderer_shader_feedback); | ||
| 447 | ReadSetting("Renderer", Settings::values.enable_nsight_aftermath); | 448 | ReadSetting("Renderer", Settings::values.enable_nsight_aftermath); |
| 448 | ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks); | 449 | ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks); |
| 449 | ReadSetting("Renderer", Settings::values.vulkan_device); | 450 | ReadSetting("Renderer", Settings::values.vulkan_device); |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index e646e2d2f..e02eceb99 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -221,6 +221,10 @@ backend = | |||
| 221 | # 0 (default): Disabled, 1: Enabled | 221 | # 0 (default): Disabled, 1: Enabled |
| 222 | debug = | 222 | debug = |
| 223 | 223 | ||
| 224 | # Enable shader feedback. | ||
| 225 | # 0 (default): Disabled, 1: Enabled | ||
| 226 | renderer_shader_feedback = | ||
| 227 | |||
| 224 | # Enable Nsight Aftermath crash dumps | 228 | # Enable Nsight Aftermath crash dumps |
| 225 | # 0 (default): Disabled, 1: Enabled | 229 | # 0 (default): Disabled, 1: Enabled |
| 226 | nsight_aftermath = | 230 | nsight_aftermath = |
| @@ -363,7 +367,7 @@ custom_rtc = | |||
| 363 | # Sets the systems language index | 367 | # Sets the systems language index |
| 364 | # 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, | 368 | # 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, |
| 365 | # 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, | 369 | # 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, |
| 366 | # 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese | 370 | # 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese |
| 367 | language_index = | 371 | language_index = |
| 368 | 372 | ||
| 369 | # The system region that yuzu will use during emulation | 373 | # The system region that yuzu will use during emulation |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 353e51ea7..f643a4b0b 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -16,8 +16,8 @@ | |||
| 16 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | 16 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" |
| 17 | #include "yuzu_cmd/yuzu_icon.h" | 17 | #include "yuzu_cmd/yuzu_icon.h" |
| 18 | 18 | ||
| 19 | EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_) | 19 | EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_) |
| 20 | : input_subsystem{input_subsystem_} { | 20 | : input_subsystem{input_subsystem_}, system{system_} { |
| 21 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { | 21 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { |
| 22 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); | 22 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); |
| 23 | exit(1); | 23 | exit(1); |
| @@ -124,7 +124,7 @@ void EmuWindow_SDL2::OnResize() { | |||
| 124 | 124 | ||
| 125 | void EmuWindow_SDL2::Fullscreen() { | 125 | void EmuWindow_SDL2::Fullscreen() { |
| 126 | switch (Settings::values.fullscreen_mode.GetValue()) { | 126 | switch (Settings::values.fullscreen_mode.GetValue()) { |
| 127 | case 1: // Exclusive fullscreen | 127 | case Settings::FullscreenMode::Exclusive: |
| 128 | // Set window size to render size before entering fullscreen -- SDL does not resize to | 128 | // Set window size to render size before entering fullscreen -- SDL does not resize to |
| 129 | // display dimensions in this mode. | 129 | // display dimensions in this mode. |
| 130 | // TODO: Multiply the window size by resolution_factor (for both docked modes) | 130 | // TODO: Multiply the window size by resolution_factor (for both docked modes) |
| @@ -140,7 +140,7 @@ void EmuWindow_SDL2::Fullscreen() { | |||
| 140 | LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError()); | 140 | LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError()); |
| 141 | LOG_INFO(Frontend, "Attempting to use borderless fullscreen..."); | 141 | LOG_INFO(Frontend, "Attempting to use borderless fullscreen..."); |
| 142 | [[fallthrough]]; | 142 | [[fallthrough]]; |
| 143 | case 0: // Borderless window | 143 | case Settings::FullscreenMode::Borderless: |
| 144 | if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { | 144 | if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { |
| 145 | return; | 145 | return; |
| 146 | } | 146 | } |
| @@ -218,7 +218,7 @@ void EmuWindow_SDL2::WaitEvent() { | |||
| 218 | 218 | ||
| 219 | const u32 current_time = SDL_GetTicks(); | 219 | const u32 current_time = SDL_GetTicks(); |
| 220 | if (current_time > last_time + 2000) { | 220 | if (current_time > last_time + 2000) { |
| 221 | const auto results = Core::System::GetInstance().GetAndResetPerfStats(); | 221 | const auto results = system.GetAndResetPerfStats(); |
| 222 | const auto title = | 222 | const auto title = |
| 223 | fmt::format("yuzu {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname, | 223 | fmt::format("yuzu {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname, |
| 224 | Common::g_scm_branch, Common::g_scm_desc, results.average_game_fps, | 224 | Common::g_scm_branch, Common::g_scm_desc, results.average_game_fps, |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 1b9ab5b93..aa0d52ae4 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h | |||
| @@ -24,7 +24,7 @@ enum class MouseButton; | |||
| 24 | 24 | ||
| 25 | class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { | 25 | class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { |
| 26 | public: | 26 | public: |
| 27 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); | 27 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem, Core::System& system_); |
| 28 | ~EmuWindow_SDL2(); | 28 | ~EmuWindow_SDL2(); |
| 29 | 29 | ||
| 30 | /// Whether the window is still open, and a close request hasn't yet been sent | 30 | /// Whether the window is still open, and a close request hasn't yet been sent |
| @@ -87,4 +87,7 @@ protected: | |||
| 87 | 87 | ||
| 88 | /// Input subsystem to use with this window. | 88 | /// Input subsystem to use with this window. |
| 89 | InputCommon::InputSubsystem* input_subsystem; | 89 | InputCommon::InputSubsystem* input_subsystem; |
| 90 | |||
| 91 | /// yuzu core instance | ||
| 92 | Core::System& system; | ||
| 90 | }; | 93 | }; |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp index eadb41790..5b98c255b 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | |||
| @@ -76,8 +76,9 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | |||
| 76 | return unsupported_ext.empty(); | 76 | return unsupported_ext.empty(); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) | 79 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, |
| 80 | : EmuWindow_SDL2{input_subsystem} { | 80 | Core::System& system_, bool fullscreen) |
| 81 | : EmuWindow_SDL2{input_subsystem, system_} { | ||
| 81 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); | 82 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); |
| 82 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); | 83 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); |
| 83 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); | 84 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h index 9e694d985..d7f2c83d8 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h | |||
| @@ -8,13 +8,18 @@ | |||
| 8 | #include "core/frontend/emu_window.h" | 8 | #include "core/frontend/emu_window.h" |
| 9 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | 9 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" |
| 10 | 10 | ||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 11 | namespace InputCommon { | 15 | namespace InputCommon { |
| 12 | class InputSubsystem; | 16 | class InputSubsystem; |
| 13 | } | 17 | } |
| 14 | 18 | ||
| 15 | class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 { | 19 | class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 { |
| 16 | public: | 20 | public: |
| 17 | explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen); | 21 | explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, Core::System& system_, |
| 22 | bool fullscreen); | ||
| 18 | ~EmuWindow_SDL2_GL(); | 23 | ~EmuWindow_SDL2_GL(); |
| 19 | 24 | ||
| 20 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | 25 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index d1473dbab..cdda375d8 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp | |||
| @@ -24,8 +24,9 @@ | |||
| 24 | #include <SDL.h> | 24 | #include <SDL.h> |
| 25 | #include <SDL_syswm.h> | 25 | #include <SDL_syswm.h> |
| 26 | 26 | ||
| 27 | EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) | 27 | EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, |
| 28 | : EmuWindow_SDL2{input_subsystem} { | 28 | Core::System& system_, bool fullscreen) |
| 29 | : EmuWindow_SDL2{input_subsystem, system_} { | ||
| 29 | const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, | 30 | const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, |
| 30 | Common::g_scm_branch, Common::g_scm_desc); | 31 | Common::g_scm_branch, Common::g_scm_desc); |
| 31 | render_window = | 32 | render_window = |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h index de53844f0..3ea521b2a 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h | |||
| @@ -19,7 +19,8 @@ class InputSubsystem; | |||
| 19 | 19 | ||
| 20 | class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 { | 20 | class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 { |
| 21 | public: | 21 | public: |
| 22 | explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, bool fullscreen); | 22 | explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, Core::System& system, |
| 23 | bool fullscreen); | ||
| 23 | ~EmuWindow_SDL2_VK() override; | 24 | ~EmuWindow_SDL2_VK() override; |
| 24 | 25 | ||
| 25 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | 26 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 35ce23696..c10093820 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -172,10 +172,10 @@ int main(int argc, char** argv) { | |||
| 172 | std::unique_ptr<EmuWindow_SDL2> emu_window; | 172 | std::unique_ptr<EmuWindow_SDL2> emu_window; |
| 173 | switch (Settings::values.renderer_backend.GetValue()) { | 173 | switch (Settings::values.renderer_backend.GetValue()) { |
| 174 | case Settings::RendererBackend::OpenGL: | 174 | case Settings::RendererBackend::OpenGL: |
| 175 | emu_window = std::make_unique<EmuWindow_SDL2_GL>(&input_subsystem, fullscreen); | 175 | emu_window = std::make_unique<EmuWindow_SDL2_GL>(&input_subsystem, system, fullscreen); |
| 176 | break; | 176 | break; |
| 177 | case Settings::RendererBackend::Vulkan: | 177 | case Settings::RendererBackend::Vulkan: |
| 178 | emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem, fullscreen); | 178 | emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem, system, fullscreen); |
| 179 | break; | 179 | break; |
| 180 | } | 180 | } |
| 181 | 181 | ||