diff options
26 files changed, 299 insertions, 89 deletions
diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake index 1e9810bba..2598b9b60 100644 --- a/CMakeModules/CopyYuzuQt5Deps.cmake +++ b/CMakeModules/CopyYuzuQt5Deps.cmake | |||
| @@ -6,9 +6,9 @@ function(copy_yuzu_Qt5_deps target_dir) | |||
| 6 | set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") | 6 | set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") |
| 7 | set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") | 7 | set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") |
| 8 | set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/") | 8 | set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/") |
| 9 | set(PLATFORMS ${DLL_DEST}platforms/) | 9 | set(PLATFORMS ${DLL_DEST}plugins/platforms/) |
| 10 | set(STYLES ${DLL_DEST}styles/) | 10 | set(STYLES ${DLL_DEST}plugins/styles/) |
| 11 | set(IMAGEFORMATS ${DLL_DEST}imageformats/) | 11 | set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/) |
| 12 | windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST} | 12 | windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST} |
| 13 | icudt*.dll | 13 | icudt*.dll |
| 14 | icuin*.dll | 14 | icuin*.dll |
| @@ -42,11 +42,15 @@ function(copy_yuzu_Qt5_deps target_dir) | |||
| 42 | icudtl.dat | 42 | icudtl.dat |
| 43 | ) | 43 | ) |
| 44 | endif () | 44 | endif () |
| 45 | |||
| 46 | windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*) | 45 | windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*) |
| 47 | windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*) | 46 | windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*) |
| 48 | windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} | 47 | windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} |
| 49 | qjpeg$<$<CONFIG:Debug>:d>.* | 48 | qjpeg$<$<CONFIG:Debug>:d>.* |
| 50 | qgif$<$<CONFIG:Debug>:d>.* | 49 | qgif$<$<CONFIG:Debug>:d>.* |
| 51 | ) | 50 | ) |
| 51 | # Create an empty qt.conf file. Qt will detect that this file exists, and use the folder that its in as the root folder. | ||
| 52 | # This way it'll look for plugins in the root/plugins/ folder | ||
| 53 | add_custom_command(TARGET yuzu POST_BUILD | ||
| 54 | COMMAND ${CMAKE_COMMAND} -E touch ${DLL_DEST}qt.conf | ||
| 55 | ) | ||
| 52 | endfunction(copy_yuzu_Qt5_deps) | 56 | endfunction(copy_yuzu_Qt5_deps) |
| @@ -2,6 +2,7 @@ yuzu emulator | |||
| 2 | ============= | 2 | ============= |
| 3 | [](https://travis-ci.com/yuzu-emu/yuzu) | 3 | [](https://travis-ci.com/yuzu-emu/yuzu) |
| 4 | [](https://dev.azure.com/yuzu-emu/yuzu/) | 4 | [](https://dev.azure.com/yuzu-emu/yuzu/) |
| 5 | [](https://discord.gg/XQV6dn9) | ||
| 5 | 6 | ||
| 6 | yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/). | 7 | yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/). |
| 7 | 8 | ||
| @@ -21,7 +22,7 @@ For development discussion, please join us on [Discord](https://discord.gg/XQV6d | |||
| 21 | 22 | ||
| 22 | Most of the development happens on GitHub. It's also where [our central repository](https://github.com/yuzu-emu/yuzu) is hosted. | 23 | Most of the development happens on GitHub. It's also where [our central repository](https://github.com/yuzu-emu/yuzu) is hosted. |
| 23 | 24 | ||
| 24 | If you want to contribute please take a look at the [Contributor's Guide](CONTRIBUTING.md) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information). You should also contact any of the developers on Discord in order to know about the current state of the emulator. | 25 | If you want to contribute please take a look at the [Contributor's Guide](https://github.com/yuzu-emu/yuzu/wiki/Contributing) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information). You should also contact any of the developers on Discord in order to know about the current state of the emulator. |
| 25 | 26 | ||
| 26 | ### Building | 27 | ### Building |
| 27 | 28 | ||
diff --git a/dist/license.md b/dist/license.md index b777ebb20..f1ff35c95 100644 --- a/dist/license.md +++ b/dist/license.md | |||
| @@ -2,8 +2,8 @@ The icons in this folder and its subfolders have the following licenses: | |||
| 2 | 2 | ||
| 3 | Icon Name | License | Origin/Author | 3 | Icon Name | License | Origin/Author |
| 4 | --- | --- | --- | 4 | --- | --- | --- |
| 5 | qt_themes/default/icons/16x16/checked.png | Free for non-commercial use | 5 | qt_themes/default/icons/16x16/checked.png | CC BY-ND 3.0 | https://icons8.com |
| 6 | qt_themes/default/icons/16x16/failed.png | Free for non-commercial use | 6 | qt_themes/default/icons/16x16/failed.png | CC BY-ND 3.0 | https://icons8.com |
| 7 | qt_themes/default/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com | 7 | qt_themes/default/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com |
| 8 | qt_themes/default/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com | 8 | qt_themes/default/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com |
| 9 | qt_themes/default/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com | 9 | qt_themes/default/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com |
| @@ -11,8 +11,6 @@ qt_themes/default/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com | |||
| 11 | qt_themes/default/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com | 11 | qt_themes/default/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com |
| 12 | qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team | 12 | qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team |
| 13 | qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com | 13 | qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com |
| 14 | qt_themes/qdarkstyle/icons/16x16/checked.png | Free for non-commercial use | ||
| 15 | qt_themes/qdarkstyle/icons/16x16/failed.png | Free for non-commercial use | ||
| 16 | qt_themes/qdarkstyle/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com | 14 | qt_themes/qdarkstyle/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com |
| 17 | qt_themes/qdarkstyle/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com | 15 | qt_themes/qdarkstyle/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com |
| 18 | qt_themes/qdarkstyle/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com | 16 | qt_themes/qdarkstyle/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com |
diff --git a/dist/qt_themes/default/icons/16x16/checked.png b/dist/qt_themes/default/icons/16x16/checked.png index c277e6b40..3e017b715 100644 --- a/dist/qt_themes/default/icons/16x16/checked.png +++ b/dist/qt_themes/default/icons/16x16/checked.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/default/icons/16x16/failed.png b/dist/qt_themes/default/icons/16x16/failed.png index ac10f174a..7c4047dd0 100644 --- a/dist/qt_themes/default/icons/16x16/failed.png +++ b/dist/qt_themes/default/icons/16x16/failed.png | |||
| Binary files differ | |||
diff --git a/license.txt b/license.txt index bf5aec0e6..86e7b3c1b 100644 --- a/license.txt +++ b/license.txt | |||
| @@ -343,8 +343,8 @@ The icons used in this project have the following licenses: | |||
| 343 | 343 | ||
| 344 | Icon Name | License | Origin/Author | 344 | Icon Name | License | Origin/Author |
| 345 | --- | --- | --- | 345 | --- | --- | --- |
| 346 | checked.png | Free for non-commercial use | 346 | checked.png | CC BY-ND 3.0 | https://icons8.com |
| 347 | failed.png | Free for non-commercial use | 347 | failed.png | CC BY-ND 3.0 | https://icons8.com |
| 348 | lock.png | CC BY-ND 3.0 | https://icons8.com | 348 | lock.png | CC BY-ND 3.0 | https://icons8.com |
| 349 | plus_folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com | 349 | plus_folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com |
| 350 | bad_folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com | 350 | bad_folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 218508126..d1bc9340d 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -166,7 +166,7 @@ struct System::Impl { | |||
| 166 | service_manager = std::make_shared<Service::SM::ServiceManager>(); | 166 | service_manager = std::make_shared<Service::SM::ServiceManager>(); |
| 167 | 167 | ||
| 168 | Service::Init(service_manager, system); | 168 | Service::Init(service_manager, system); |
| 169 | GDBStub::Init(); | 169 | GDBStub::DeferStart(); |
| 170 | 170 | ||
| 171 | renderer = VideoCore::CreateRenderer(emu_window, system); | 171 | renderer = VideoCore::CreateRenderer(emu_window, system); |
| 172 | if (!renderer->Init()) { | 172 | if (!renderer->Init()) { |
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index e8d8871a7..6d15aeed9 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -141,6 +141,7 @@ constexpr char target_xml[] = | |||
| 141 | )"; | 141 | )"; |
| 142 | 142 | ||
| 143 | int gdbserver_socket = -1; | 143 | int gdbserver_socket = -1; |
| 144 | bool defer_start = false; | ||
| 144 | 145 | ||
| 145 | u8 command_buffer[GDB_BUFFER_SIZE]; | 146 | u8 command_buffer[GDB_BUFFER_SIZE]; |
| 146 | u32 command_length; | 147 | u32 command_length; |
| @@ -1166,6 +1167,9 @@ static void RemoveBreakpoint() { | |||
| 1166 | 1167 | ||
| 1167 | void HandlePacket() { | 1168 | void HandlePacket() { |
| 1168 | if (!IsConnected()) { | 1169 | if (!IsConnected()) { |
| 1170 | if (defer_start) { | ||
| 1171 | ToggleServer(true); | ||
| 1172 | } | ||
| 1169 | return; | 1173 | return; |
| 1170 | } | 1174 | } |
| 1171 | 1175 | ||
| @@ -1256,6 +1260,10 @@ void ToggleServer(bool status) { | |||
| 1256 | } | 1260 | } |
| 1257 | } | 1261 | } |
| 1258 | 1262 | ||
| 1263 | void DeferStart() { | ||
| 1264 | defer_start = true; | ||
| 1265 | } | ||
| 1266 | |||
| 1259 | static void Init(u16 port) { | 1267 | static void Init(u16 port) { |
| 1260 | if (!server_enabled) { | 1268 | if (!server_enabled) { |
| 1261 | // Set the halt loop to false in case the user enabled the gdbstub mid-execution. | 1269 | // Set the halt loop to false in case the user enabled the gdbstub mid-execution. |
| @@ -1341,6 +1349,7 @@ void Shutdown() { | |||
| 1341 | if (!server_enabled) { | 1349 | if (!server_enabled) { |
| 1342 | return; | 1350 | return; |
| 1343 | } | 1351 | } |
| 1352 | defer_start = false; | ||
| 1344 | 1353 | ||
| 1345 | LOG_INFO(Debug_GDBStub, "Stopping GDB ..."); | 1354 | LOG_INFO(Debug_GDBStub, "Stopping GDB ..."); |
| 1346 | if (gdbserver_socket != -1) { | 1355 | if (gdbserver_socket != -1) { |
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index 5a36524b2..8fe3c320b 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h | |||
| @@ -43,6 +43,13 @@ void ToggleServer(bool status); | |||
| 43 | /// Start the gdbstub server. | 43 | /// Start the gdbstub server. |
| 44 | void Init(); | 44 | void Init(); |
| 45 | 45 | ||
| 46 | /** | ||
| 47 | * Defer initialization of the gdbstub to the first packet processing functions. | ||
| 48 | * This avoids a case where the gdbstub thread is frozen after initialization | ||
| 49 | * and fails to respond in time to packets. | ||
| 50 | */ | ||
| 51 | void DeferStart(); | ||
| 52 | |||
| 46 | /// Stop gdbstub server. | 53 | /// Stop gdbstub server. |
| 47 | void Shutdown(); | 54 | void Shutdown(); |
| 48 | 55 | ||
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index d1bf13c89..557608e76 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -52,6 +52,11 @@ enum class LaunchParameterKind : u32 { | |||
| 52 | AccountPreselectedUser = 2, | 52 | AccountPreselectedUser = 2, |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | enum class VrMode : u8 { | ||
| 56 | Disabled = 0, | ||
| 57 | Enabled = 1, | ||
| 58 | }; | ||
| 59 | |||
| 55 | constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; | 60 | constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; |
| 56 | 61 | ||
| 57 | struct LaunchParameterAccountPreselectedUser { | 62 | struct LaunchParameterAccountPreselectedUser { |
| @@ -605,11 +610,11 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system, | |||
| 605 | {30, nullptr, "GetHomeButtonReaderLockAccessor"}, | 610 | {30, nullptr, "GetHomeButtonReaderLockAccessor"}, |
| 606 | {31, nullptr, "GetReaderLockAccessorEx"}, | 611 | {31, nullptr, "GetReaderLockAccessorEx"}, |
| 607 | {40, nullptr, "GetCradleFwVersion"}, | 612 | {40, nullptr, "GetCradleFwVersion"}, |
| 608 | {50, nullptr, "IsVrModeEnabled"}, | 613 | {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, |
| 609 | {51, nullptr, "SetVrModeEnabled"}, | 614 | {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, |
| 610 | {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"}, | 615 | {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"}, |
| 611 | {53, nullptr, "BeginVrModeEx"}, | 616 | {53, nullptr, "BeginVrModeEx"}, |
| 612 | {54, nullptr, "EndVrModeEx"}, | 617 | {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"}, |
| 613 | {55, nullptr, "IsInControllerFirmwareUpdateSection"}, | 618 | {55, nullptr, "IsInControllerFirmwareUpdateSection"}, |
| 614 | {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, | 619 | {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, |
| 615 | {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, | 620 | {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, |
| @@ -672,6 +677,30 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { | |||
| 672 | rb.Push(static_cast<u8>(FocusState::InFocus)); | 677 | rb.Push(static_cast<u8>(FocusState::InFocus)); |
| 673 | } | 678 | } |
| 674 | 679 | ||
| 680 | void ICommonStateGetter::IsVrModeEnabled(Kernel::HLERequestContext& ctx) { | ||
| 681 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 682 | |||
| 683 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 684 | rb.Push(RESULT_SUCCESS); | ||
| 685 | rb.PushEnum(VrMode::Disabled); | ||
| 686 | } | ||
| 687 | |||
| 688 | void ICommonStateGetter::SetVrModeEnabled(Kernel::HLERequestContext& ctx) { | ||
| 689 | IPC::RequestParser rp{ctx}; | ||
| 690 | const auto is_vr_mode_enabled = rp.Pop<bool>(); | ||
| 691 | |||
| 692 | LOG_WARNING(Service_AM, "(STUBBED) called. is_vr_mode_enabled={}", is_vr_mode_enabled); | ||
| 693 | |||
| 694 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 695 | if (!is_vr_mode_enabled) { | ||
| 696 | rb.Push(RESULT_SUCCESS); | ||
| 697 | } else { | ||
| 698 | // TODO: Find better error code for this | ||
| 699 | UNIMPLEMENTED_MSG("is_vr_mode_enabled={}", is_vr_mode_enabled); | ||
| 700 | rb.Push(RESULT_UNKNOWN); | ||
| 701 | } | ||
| 702 | } | ||
| 703 | |||
| 675 | void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx) { | 704 | void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx) { |
| 676 | IPC::RequestParser rp{ctx}; | 705 | IPC::RequestParser rp{ctx}; |
| 677 | const auto is_lcd_backlight_off_enabled = rp.Pop<bool>(); | 706 | const auto is_lcd_backlight_off_enabled = rp.Pop<bool>(); |
| @@ -683,6 +712,13 @@ void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx | |||
| 683 | rb.Push(RESULT_SUCCESS); | 712 | rb.Push(RESULT_SUCCESS); |
| 684 | } | 713 | } |
| 685 | 714 | ||
| 715 | void ICommonStateGetter::EndVrModeEx(Kernel::HLERequestContext& ctx) { | ||
| 716 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 717 | |||
| 718 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 719 | rb.Push(RESULT_SUCCESS); | ||
| 720 | } | ||
| 721 | |||
| 686 | void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { | 722 | void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { |
| 687 | LOG_DEBUG(Service_AM, "called"); | 723 | LOG_DEBUG(Service_AM, "called"); |
| 688 | 724 | ||
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 0843de781..53cfce10f 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -182,7 +182,10 @@ private: | |||
| 182 | void GetOperationMode(Kernel::HLERequestContext& ctx); | 182 | void GetOperationMode(Kernel::HLERequestContext& ctx); |
| 183 | void GetPerformanceMode(Kernel::HLERequestContext& ctx); | 183 | void GetPerformanceMode(Kernel::HLERequestContext& ctx); |
| 184 | void GetBootMode(Kernel::HLERequestContext& ctx); | 184 | void GetBootMode(Kernel::HLERequestContext& ctx); |
| 185 | void IsVrModeEnabled(Kernel::HLERequestContext& ctx); | ||
| 186 | void SetVrModeEnabled(Kernel::HLERequestContext& ctx); | ||
| 185 | void SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx); | 187 | void SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx); |
| 188 | void EndVrModeEx(Kernel::HLERequestContext& ctx); | ||
| 186 | void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); | 189 | void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); |
| 187 | void SetCpuBoostMode(Kernel::HLERequestContext& ctx); | 190 | void SetCpuBoostMode(Kernel::HLERequestContext& ctx); |
| 188 | 191 | ||
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 12443c910..9f30e167d 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp | |||
| @@ -254,6 +254,12 @@ void WebBrowser::Execute() { | |||
| 254 | 254 | ||
| 255 | if (status != RESULT_SUCCESS) { | 255 | if (status != RESULT_SUCCESS) { |
| 256 | complete = true; | 256 | complete = true; |
| 257 | |||
| 258 | // This is a workaround in order not to softlock yuzu when an error happens during the | ||
| 259 | // webapplet init. In order to avoid an svcBreak, the status is set to RESULT_SUCCESS | ||
| 260 | Finalize(); | ||
| 261 | status = RESULT_SUCCESS; | ||
| 262 | |||
| 257 | return; | 263 | return; |
| 258 | } | 264 | } |
| 259 | 265 | ||
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index e6b56a9f9..d6ed5f304 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -235,7 +235,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { | |||
| 235 | {303, nullptr, "ActivateSevenSixAxisSensor"}, | 235 | {303, nullptr, "ActivateSevenSixAxisSensor"}, |
| 236 | {304, nullptr, "StartSevenSixAxisSensor"}, | 236 | {304, nullptr, "StartSevenSixAxisSensor"}, |
| 237 | {305, nullptr, "StopSevenSixAxisSensor"}, | 237 | {305, nullptr, "StopSevenSixAxisSensor"}, |
| 238 | {306, nullptr, "InitializeSevenSixAxisSensor"}, | 238 | {306, &Hid::InitializeSevenSixAxisSensor, "InitializeSevenSixAxisSensor"}, |
| 239 | {307, nullptr, "FinalizeSevenSixAxisSensor"}, | 239 | {307, nullptr, "FinalizeSevenSixAxisSensor"}, |
| 240 | {308, nullptr, "SetSevenSixAxisSensorFusionStrength"}, | 240 | {308, nullptr, "SetSevenSixAxisSensorFusionStrength"}, |
| 241 | {309, nullptr, "GetSevenSixAxisSensorFusionStrength"}, | 241 | {309, nullptr, "GetSevenSixAxisSensorFusionStrength"}, |
| @@ -853,6 +853,13 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { | |||
| 853 | rb.Push(RESULT_SUCCESS); | 853 | rb.Push(RESULT_SUCCESS); |
| 854 | } | 854 | } |
| 855 | 855 | ||
| 856 | void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) { | ||
| 857 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 858 | |||
| 859 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 860 | rb.Push(RESULT_SUCCESS); | ||
| 861 | } | ||
| 862 | |||
| 856 | class HidDbg final : public ServiceFramework<HidDbg> { | 863 | class HidDbg final : public ServiceFramework<HidDbg> { |
| 857 | public: | 864 | public: |
| 858 | explicit HidDbg() : ServiceFramework{"hid:dbg"} { | 865 | explicit HidDbg() : ServiceFramework{"hid:dbg"} { |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index ad20f147c..039c38b58 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -128,6 +128,7 @@ private: | |||
| 128 | void StopSixAxisSensor(Kernel::HLERequestContext& ctx); | 128 | void StopSixAxisSensor(Kernel::HLERequestContext& ctx); |
| 129 | void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); | 129 | void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); |
| 130 | void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); | 130 | void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); |
| 131 | void InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx); | ||
| 131 | 132 | ||
| 132 | std::shared_ptr<IAppletResource> applet_resource; | 133 | std::shared_ptr<IAppletResource> applet_resource; |
| 133 | Core::System& system; | 134 | Core::System& system; |
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index c45b285f8..9cca84b31 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp | |||
| @@ -44,7 +44,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 44 | 44 | ||
| 45 | IPC::ResponseBuilder rb{ctx, 3}; | 45 | IPC::ResponseBuilder rb{ctx, 3}; |
| 46 | rb.Push(RESULT_SUCCESS); | 46 | rb.Push(RESULT_SUCCESS); |
| 47 | rb.Push<u16>(0x500); | 47 | rb.Push<u16>(0x1000); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | Controller::Controller() : ServiceFramework("IpcController") { | 50 | Controller::Controller() : ServiceFramework("IpcController") { |
diff --git a/src/video_core/engines/const_buffer_engine_interface.h b/src/video_core/engines/const_buffer_engine_interface.h index 724ee0fd6..ebe139504 100644 --- a/src/video_core/engines/const_buffer_engine_interface.h +++ b/src/video_core/engines/const_buffer_engine_interface.h | |||
| @@ -18,10 +18,14 @@ struct SamplerDescriptor { | |||
| 18 | union { | 18 | union { |
| 19 | u32 raw = 0; | 19 | u32 raw = 0; |
| 20 | BitField<0, 2, Tegra::Shader::TextureType> texture_type; | 20 | BitField<0, 2, Tegra::Shader::TextureType> texture_type; |
| 21 | BitField<2, 3, Tegra::Texture::ComponentType> component_type; | 21 | BitField<2, 3, Tegra::Texture::ComponentType> r_type; |
| 22 | BitField<5, 1, u32> is_array; | 22 | BitField<5, 1, u32> is_array; |
| 23 | BitField<6, 1, u32> is_buffer; | 23 | BitField<6, 1, u32> is_buffer; |
| 24 | BitField<7, 1, u32> is_shadow; | 24 | BitField<7, 1, u32> is_shadow; |
| 25 | BitField<8, 3, Tegra::Texture::ComponentType> g_type; | ||
| 26 | BitField<11, 3, Tegra::Texture::ComponentType> b_type; | ||
| 27 | BitField<14, 3, Tegra::Texture::ComponentType> a_type; | ||
| 28 | BitField<17, 7, Tegra::Texture::TextureFormat> format; | ||
| 25 | }; | 29 | }; |
| 26 | 30 | ||
| 27 | bool operator==(const SamplerDescriptor& rhs) const noexcept { | 31 | bool operator==(const SamplerDescriptor& rhs) const noexcept { |
| @@ -36,9 +40,11 @@ struct SamplerDescriptor { | |||
| 36 | using Tegra::Shader::TextureType; | 40 | using Tegra::Shader::TextureType; |
| 37 | SamplerDescriptor result; | 41 | SamplerDescriptor result; |
| 38 | 42 | ||
| 39 | // This is going to be used to determine the shading language type. | 43 | result.format.Assign(tic.format.Value()); |
| 40 | // Because of that we don't care about all component types on color textures. | 44 | result.r_type.Assign(tic.r_type.Value()); |
| 41 | result.component_type.Assign(tic.r_type.Value()); | 45 | result.g_type.Assign(tic.g_type.Value()); |
| 46 | result.b_type.Assign(tic.b_type.Value()); | ||
| 47 | result.a_type.Assign(tic.a_type.Value()); | ||
| 42 | 48 | ||
| 43 | switch (tic.texture_type.Value()) { | 49 | switch (tic.texture_type.Value()) { |
| 44 | case Tegra::Texture::TextureType::Texture1D: | 50 | case Tegra::Texture::TextureType::Texture1D: |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index ce536e29b..ba63b44b4 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -98,6 +98,8 @@ void Maxwell3D::InitializeRegisterDefaults() { | |||
| 98 | regs.framebuffer_srgb = 1; | 98 | regs.framebuffer_srgb = 1; |
| 99 | regs.front_face = Maxwell3D::Regs::FrontFace::ClockWise; | 99 | regs.front_face = Maxwell3D::Regs::FrontFace::ClockWise; |
| 100 | 100 | ||
| 101 | shadow_state = regs; | ||
| 102 | |||
| 101 | mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true; | 103 | mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true; |
| 102 | mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true; | 104 | mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true; |
| 103 | mme_inline[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; | 105 | mme_inline[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; |
| @@ -160,8 +162,17 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { | |||
| 160 | ASSERT_MSG(method < Regs::NUM_REGS, | 162 | ASSERT_MSG(method < Regs::NUM_REGS, |
| 161 | "Invalid Maxwell3D register, increase the size of the Regs structure"); | 163 | "Invalid Maxwell3D register, increase the size of the Regs structure"); |
| 162 | 164 | ||
| 163 | if (regs.reg_array[method] != method_call.argument) { | 165 | u32 arg = method_call.argument; |
| 164 | regs.reg_array[method] = method_call.argument; | 166 | // Keep track of the register value in shadow_state when requested. |
| 167 | if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Track || | ||
| 168 | shadow_state.shadow_ram_control == Regs::ShadowRamControl::TrackWithFilter) { | ||
| 169 | shadow_state.reg_array[method] = arg; | ||
| 170 | } else if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Replay) { | ||
| 171 | arg = shadow_state.reg_array[method]; | ||
| 172 | } | ||
| 173 | |||
| 174 | if (regs.reg_array[method] != arg) { | ||
| 175 | regs.reg_array[method] = arg; | ||
| 165 | 176 | ||
| 166 | for (const auto& table : dirty.tables) { | 177 | for (const auto& table : dirty.tables) { |
| 167 | dirty.flags[table[method]] = true; | 178 | dirty.flags[table[method]] = true; |
| @@ -169,12 +180,16 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { | |||
| 169 | } | 180 | } |
| 170 | 181 | ||
| 171 | switch (method) { | 182 | switch (method) { |
| 183 | case MAXWELL3D_REG_INDEX(shadow_ram_control): { | ||
| 184 | shadow_state.shadow_ram_control = static_cast<Regs::ShadowRamControl>(method_call.argument); | ||
| 185 | break; | ||
| 186 | } | ||
| 172 | case MAXWELL3D_REG_INDEX(macros.data): { | 187 | case MAXWELL3D_REG_INDEX(macros.data): { |
| 173 | ProcessMacroUpload(method_call.argument); | 188 | ProcessMacroUpload(arg); |
| 174 | break; | 189 | break; |
| 175 | } | 190 | } |
| 176 | case MAXWELL3D_REG_INDEX(macros.bind): { | 191 | case MAXWELL3D_REG_INDEX(macros.bind): { |
| 177 | ProcessMacroBind(method_call.argument); | 192 | ProcessMacroBind(arg); |
| 178 | break; | 193 | break; |
| 179 | } | 194 | } |
| 180 | case MAXWELL3D_REG_INDEX(firmware[4]): { | 195 | case MAXWELL3D_REG_INDEX(firmware[4]): { |
| @@ -250,7 +265,7 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { | |||
| 250 | } | 265 | } |
| 251 | case MAXWELL3D_REG_INDEX(data_upload): { | 266 | case MAXWELL3D_REG_INDEX(data_upload): { |
| 252 | const bool is_last_call = method_call.IsLastCall(); | 267 | const bool is_last_call = method_call.IsLastCall(); |
| 253 | upload_state.ProcessData(method_call.argument, is_last_call); | 268 | upload_state.ProcessData(arg, is_last_call); |
| 254 | if (is_last_call) { | 269 | if (is_last_call) { |
| 255 | OnMemoryWrite(); | 270 | OnMemoryWrite(); |
| 256 | } | 271 | } |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 8a9e9992e..d24c9f657 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -531,6 +531,17 @@ public: | |||
| 531 | Fill = 0x1b02, | 531 | Fill = 0x1b02, |
| 532 | }; | 532 | }; |
| 533 | 533 | ||
| 534 | enum class ShadowRamControl : u32 { | ||
| 535 | // write value to shadow ram | ||
| 536 | Track = 0, | ||
| 537 | // write value to shadow ram ( with validation ??? ) | ||
| 538 | TrackWithFilter = 1, | ||
| 539 | // only write to real hw register | ||
| 540 | Passthrough = 2, | ||
| 541 | // write value from shadow ram to real hw register | ||
| 542 | Replay = 3, | ||
| 543 | }; | ||
| 544 | |||
| 534 | struct RenderTargetConfig { | 545 | struct RenderTargetConfig { |
| 535 | u32 address_high; | 546 | u32 address_high; |
| 536 | u32 address_low; | 547 | u32 address_low; |
| @@ -674,7 +685,9 @@ public: | |||
| 674 | u32 bind; | 685 | u32 bind; |
| 675 | } macros; | 686 | } macros; |
| 676 | 687 | ||
| 677 | INSERT_UNION_PADDING_WORDS(0x17); | 688 | ShadowRamControl shadow_ram_control; |
| 689 | |||
| 690 | INSERT_UNION_PADDING_WORDS(0x16); | ||
| 678 | 691 | ||
| 679 | Upload::Registers upload; | 692 | Upload::Registers upload; |
| 680 | struct { | 693 | struct { |
| @@ -1263,7 +1276,12 @@ public: | |||
| 1263 | }; | 1276 | }; |
| 1264 | std::array<u32, NUM_REGS> reg_array; | 1277 | std::array<u32, NUM_REGS> reg_array; |
| 1265 | }; | 1278 | }; |
| 1266 | } regs{}; | 1279 | }; |
| 1280 | |||
| 1281 | Regs regs{}; | ||
| 1282 | |||
| 1283 | /// Store temporary hw register values, used by some calls to restore state after a operation | ||
| 1284 | Regs shadow_state; | ||
| 1267 | 1285 | ||
| 1268 | static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), "Maxwell3D Regs has wrong size"); | 1286 | static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), "Maxwell3D Regs has wrong size"); |
| 1269 | static_assert(std::is_trivially_copyable_v<Regs>, "Maxwell3D Regs must be trivially copyable"); | 1287 | static_assert(std::is_trivially_copyable_v<Regs>, "Maxwell3D Regs must be trivially copyable"); |
| @@ -1458,6 +1476,7 @@ private: | |||
| 1458 | "Field " #field_name " has invalid position") | 1476 | "Field " #field_name " has invalid position") |
| 1459 | 1477 | ||
| 1460 | ASSERT_REG_POSITION(macros, 0x45); | 1478 | ASSERT_REG_POSITION(macros, 0x45); |
| 1479 | ASSERT_REG_POSITION(shadow_ram_control, 0x49); | ||
| 1461 | ASSERT_REG_POSITION(upload, 0x60); | 1480 | ASSERT_REG_POSITION(upload, 0x60); |
| 1462 | ASSERT_REG_POSITION(exec_upload, 0x6C); | 1481 | ASSERT_REG_POSITION(exec_upload, 0x6C); |
| 1463 | ASSERT_REG_POSITION(data_upload, 0x6D); | 1482 | ASSERT_REG_POSITION(data_upload, 0x6D); |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index eba42deb4..49dc5abe0 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -82,6 +82,10 @@ union Attribute { | |||
| 82 | Position = 7, | 82 | Position = 7, |
| 83 | Attribute_0 = 8, | 83 | Attribute_0 = 8, |
| 84 | Attribute_31 = 39, | 84 | Attribute_31 = 39, |
| 85 | FrontColor = 40, | ||
| 86 | FrontSecondaryColor = 41, | ||
| 87 | BackColor = 42, | ||
| 88 | BackSecondaryColor = 43, | ||
| 85 | ClipDistances0123 = 44, | 89 | ClipDistances0123 = 44, |
| 86 | ClipDistances4567 = 45, | 90 | ClipDistances4567 = 45, |
| 87 | PointCoord = 46, | 91 | PointCoord = 46, |
| @@ -89,6 +93,8 @@ union Attribute { | |||
| 89 | // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval | 93 | // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval |
| 90 | // shader. | 94 | // shader. |
| 91 | TessCoordInstanceIDVertexID = 47, | 95 | TessCoordInstanceIDVertexID = 47, |
| 96 | TexCoord_0 = 48, | ||
| 97 | TexCoord_7 = 55, | ||
| 92 | // This attribute contains a tuple of (Unk, Unk, Unk, gl_FrontFacing) when inside a fragment | 98 | // This attribute contains a tuple of (Unk, Unk, Unk, gl_FrontFacing) when inside a fragment |
| 93 | // shader. It is unknown what the other values contain. | 99 | // shader. It is unknown what the other values contain. |
| 94 | FrontFacing = 63, | 100 | FrontFacing = 63, |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 063f41327..826eee7df 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -933,13 +933,15 @@ void RasterizerOpenGL::SyncViewport() { | |||
| 933 | } | 933 | } |
| 934 | flags[Dirty::Viewport0 + i] = false; | 934 | flags[Dirty::Viewport0 + i] = false; |
| 935 | 935 | ||
| 936 | const Common::Rectangle<f32> rect{regs.viewport_transform[i].GetRect()}; | 936 | const auto& src = regs.viewport_transform[i]; |
| 937 | const Common::Rectangle<f32> rect{src.GetRect()}; | ||
| 937 | glViewportIndexedf(static_cast<GLuint>(i), rect.left, rect.bottom, rect.GetWidth(), | 938 | glViewportIndexedf(static_cast<GLuint>(i), rect.left, rect.bottom, rect.GetWidth(), |
| 938 | rect.GetHeight()); | 939 | rect.GetHeight()); |
| 939 | 940 | ||
| 940 | const auto& src = regs.viewports[i]; | 941 | const GLdouble reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne; |
| 941 | glDepthRangeIndexed(static_cast<GLuint>(i), static_cast<GLdouble>(src.depth_range_near), | 942 | const GLdouble near_depth = src.translate_z - src.scale_z * reduce_z; |
| 942 | static_cast<GLdouble>(src.depth_range_far)); | 943 | const GLdouble far_depth = src.translate_z + src.scale_z; |
| 944 | glDepthRangeIndexed(static_cast<GLuint>(i), near_depth, far_depth); | ||
| 943 | } | 945 | } |
| 944 | } | 946 | } |
| 945 | } | 947 | } |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 2c38f57fd..8aa4a7ac9 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -366,10 +366,19 @@ constexpr bool IsGenericAttribute(Attribute::Index index) { | |||
| 366 | return index >= Attribute::Index::Attribute_0 && index <= Attribute::Index::Attribute_31; | 366 | return index >= Attribute::Index::Attribute_0 && index <= Attribute::Index::Attribute_31; |
| 367 | } | 367 | } |
| 368 | 368 | ||
| 369 | constexpr bool IsLegacyTexCoord(Attribute::Index index) { | ||
| 370 | return static_cast<int>(index) >= static_cast<int>(Attribute::Index::TexCoord_0) && | ||
| 371 | static_cast<int>(index) <= static_cast<int>(Attribute::Index::TexCoord_7); | ||
| 372 | } | ||
| 373 | |||
| 369 | constexpr Attribute::Index ToGenericAttribute(u64 value) { | 374 | constexpr Attribute::Index ToGenericAttribute(u64 value) { |
| 370 | return static_cast<Attribute::Index>(value + static_cast<u64>(Attribute::Index::Attribute_0)); | 375 | return static_cast<Attribute::Index>(value + static_cast<u64>(Attribute::Index::Attribute_0)); |
| 371 | } | 376 | } |
| 372 | 377 | ||
| 378 | constexpr int GetLegacyTexCoordIndex(Attribute::Index index) { | ||
| 379 | return static_cast<int>(index) - static_cast<int>(Attribute::Index::TexCoord_0); | ||
| 380 | } | ||
| 381 | |||
| 373 | u32 GetGenericAttributeIndex(Attribute::Index index) { | 382 | u32 GetGenericAttributeIndex(Attribute::Index index) { |
| 374 | ASSERT(IsGenericAttribute(index)); | 383 | ASSERT(IsGenericAttribute(index)); |
| 375 | return static_cast<u32>(index) - static_cast<u32>(Attribute::Index::Attribute_0); | 384 | return static_cast<u32>(index) - static_cast<u32>(Attribute::Index::Attribute_0); |
| @@ -498,7 +507,7 @@ private: | |||
| 498 | if (!identifier.empty()) { | 507 | if (!identifier.empty()) { |
| 499 | code.AddLine("// {}", identifier); | 508 | code.AddLine("// {}", identifier); |
| 500 | } | 509 | } |
| 501 | code.AddLine("#version 440 core"); | 510 | code.AddLine("#version 440 {}", ir.UsesLegacyVaryings() ? "compatibility" : "core"); |
| 502 | code.AddLine("#extension GL_ARB_separate_shader_objects : enable"); | 511 | code.AddLine("#extension GL_ARB_separate_shader_objects : enable"); |
| 503 | if (device.HasShaderBallot()) { | 512 | if (device.HasShaderBallot()) { |
| 504 | code.AddLine("#extension GL_ARB_shader_ballot : require"); | 513 | code.AddLine("#extension GL_ARB_shader_ballot : require"); |
| @@ -561,6 +570,16 @@ private: | |||
| 561 | if (stage != ShaderType::Fragment) { | 570 | if (stage != ShaderType::Fragment) { |
| 562 | return; | 571 | return; |
| 563 | } | 572 | } |
| 573 | if (ir.UsesLegacyVaryings()) { | ||
| 574 | code.AddLine("in gl_PerFragment {{"); | ||
| 575 | ++code.scope; | ||
| 576 | code.AddLine("vec4 gl_TexCoord[8];"); | ||
| 577 | code.AddLine("vec4 gl_Color;"); | ||
| 578 | code.AddLine("vec4 gl_SecondaryColor;"); | ||
| 579 | --code.scope; | ||
| 580 | code.AddLine("}};"); | ||
| 581 | } | ||
| 582 | |||
| 564 | for (u32 rt = 0; rt < Maxwell::NumRenderTargets; ++rt) { | 583 | for (u32 rt = 0; rt < Maxwell::NumRenderTargets; ++rt) { |
| 565 | code.AddLine("layout (location = {}) out vec4 frag_color{};", rt, rt); | 584 | code.AddLine("layout (location = {}) out vec4 frag_color{};", rt, rt); |
| 566 | } | 585 | } |
| @@ -617,12 +636,12 @@ private: | |||
| 617 | code.AddLine("float gl_PointSize;"); | 636 | code.AddLine("float gl_PointSize;"); |
| 618 | } | 637 | } |
| 619 | 638 | ||
| 620 | if (ir.UsesInstanceId()) { | 639 | if (ir.UsesLegacyVaryings()) { |
| 621 | code.AddLine("int gl_InstanceID;"); | 640 | code.AddLine("vec4 gl_TexCoord[8];"); |
| 622 | } | 641 | code.AddLine("vec4 gl_FrontColor;"); |
| 623 | 642 | code.AddLine("vec4 gl_FrontSecondaryColor;"); | |
| 624 | if (ir.UsesVertexId()) { | 643 | code.AddLine("vec4 gl_BackColor;"); |
| 625 | code.AddLine("int gl_VertexID;"); | 644 | code.AddLine("vec4 gl_BackSecondaryColor;"); |
| 626 | } | 645 | } |
| 627 | 646 | ||
| 628 | --code.scope; | 647 | --code.scope; |
| @@ -1128,6 +1147,10 @@ private: | |||
| 1128 | default: | 1147 | default: |
| 1129 | UNREACHABLE(); | 1148 | UNREACHABLE(); |
| 1130 | } | 1149 | } |
| 1150 | case Attribute::Index::FrontColor: | ||
| 1151 | return {"gl_Color"s + GetSwizzle(element), Type::Float}; | ||
| 1152 | case Attribute::Index::FrontSecondaryColor: | ||
| 1153 | return {"gl_SecondaryColor"s + GetSwizzle(element), Type::Float}; | ||
| 1131 | case Attribute::Index::PointCoord: | 1154 | case Attribute::Index::PointCoord: |
| 1132 | switch (element) { | 1155 | switch (element) { |
| 1133 | case 0: | 1156 | case 0: |
| @@ -1168,6 +1191,12 @@ private: | |||
| 1168 | return {GeometryPass(GetGenericInputAttribute(attribute)) + GetSwizzle(element), | 1191 | return {GeometryPass(GetGenericInputAttribute(attribute)) + GetSwizzle(element), |
| 1169 | Type::Float}; | 1192 | Type::Float}; |
| 1170 | } | 1193 | } |
| 1194 | if (IsLegacyTexCoord(attribute)) { | ||
| 1195 | UNIMPLEMENTED_IF(stage == ShaderType::Geometry); | ||
| 1196 | return {fmt::format("gl_TexCoord[{}]{}", GetLegacyTexCoordIndex(attribute), | ||
| 1197 | GetSwizzle(element)), | ||
| 1198 | Type::Float}; | ||
| 1199 | } | ||
| 1171 | break; | 1200 | break; |
| 1172 | } | 1201 | } |
| 1173 | UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); | 1202 | UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); |
| @@ -1206,11 +1235,12 @@ private: | |||
| 1206 | } | 1235 | } |
| 1207 | 1236 | ||
| 1208 | std::optional<Expression> GetOutputAttribute(const AbufNode* abuf) { | 1237 | std::optional<Expression> GetOutputAttribute(const AbufNode* abuf) { |
| 1238 | const u32 element = abuf->GetElement(); | ||
| 1209 | switch (const auto attribute = abuf->GetIndex()) { | 1239 | switch (const auto attribute = abuf->GetIndex()) { |
| 1210 | case Attribute::Index::Position: | 1240 | case Attribute::Index::Position: |
| 1211 | return {{"gl_Position"s + GetSwizzle(abuf->GetElement()), Type::Float}}; | 1241 | return {{"gl_Position"s + GetSwizzle(element), Type::Float}}; |
| 1212 | case Attribute::Index::LayerViewportPointSize: | 1242 | case Attribute::Index::LayerViewportPointSize: |
| 1213 | switch (abuf->GetElement()) { | 1243 | switch (element) { |
| 1214 | case 0: | 1244 | case 0: |
| 1215 | UNIMPLEMENTED(); | 1245 | UNIMPLEMENTED(); |
| 1216 | return {}; | 1246 | return {}; |
| @@ -1228,13 +1258,26 @@ private: | |||
| 1228 | return {{"gl_PointSize", Type::Float}}; | 1258 | return {{"gl_PointSize", Type::Float}}; |
| 1229 | } | 1259 | } |
| 1230 | return {}; | 1260 | return {}; |
| 1261 | case Attribute::Index::FrontColor: | ||
| 1262 | return {{"gl_FrontColor"s + GetSwizzle(element), Type::Float}}; | ||
| 1263 | case Attribute::Index::FrontSecondaryColor: | ||
| 1264 | return {{"gl_FrontSecondaryColor"s + GetSwizzle(element), Type::Float}}; | ||
| 1265 | case Attribute::Index::BackColor: | ||
| 1266 | return {{"gl_BackColor"s + GetSwizzle(element), Type::Float}}; | ||
| 1267 | case Attribute::Index::BackSecondaryColor: | ||
| 1268 | return {{"gl_BackSecondaryColor"s + GetSwizzle(element), Type::Float}}; | ||
| 1231 | case Attribute::Index::ClipDistances0123: | 1269 | case Attribute::Index::ClipDistances0123: |
| 1232 | return {{fmt::format("gl_ClipDistance[{}]", abuf->GetElement()), Type::Float}}; | 1270 | return {{fmt::format("gl_ClipDistance[{}]", element), Type::Float}}; |
| 1233 | case Attribute::Index::ClipDistances4567: | 1271 | case Attribute::Index::ClipDistances4567: |
| 1234 | return {{fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), Type::Float}}; | 1272 | return {{fmt::format("gl_ClipDistance[{}]", element + 4), Type::Float}}; |
| 1235 | default: | 1273 | default: |
| 1236 | if (IsGenericAttribute(attribute)) { | 1274 | if (IsGenericAttribute(attribute)) { |
| 1237 | return {{GetGenericOutputAttribute(attribute, abuf->GetElement()), Type::Float}}; | 1275 | return {{GetGenericOutputAttribute(attribute, element), Type::Float}}; |
| 1276 | } | ||
| 1277 | if (IsLegacyTexCoord(attribute)) { | ||
| 1278 | return {{fmt::format("gl_TexCoord[{}]{}", GetLegacyTexCoordIndex(attribute), | ||
| 1279 | GetSwizzle(element)), | ||
| 1280 | Type::Float}}; | ||
| 1238 | } | 1281 | } |
| 1239 | UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute)); | 1282 | UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute)); |
| 1240 | return {}; | 1283 | return {}; |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index f93447610..7480cb7c3 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp | |||
| @@ -401,6 +401,26 @@ vk::Format VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttr | |||
| 401 | } | 401 | } |
| 402 | break; | 402 | break; |
| 403 | case Maxwell::VertexAttribute::Type::SignedScaled: | 403 | case Maxwell::VertexAttribute::Type::SignedScaled: |
| 404 | switch (size) { | ||
| 405 | case Maxwell::VertexAttribute::Size::Size_8: | ||
| 406 | return vk::Format::eR8Sscaled; | ||
| 407 | case Maxwell::VertexAttribute::Size::Size_8_8: | ||
| 408 | return vk::Format::eR8G8Sscaled; | ||
| 409 | case Maxwell::VertexAttribute::Size::Size_8_8_8: | ||
| 410 | return vk::Format::eR8G8B8Sscaled; | ||
| 411 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | ||
| 412 | return vk::Format::eR8G8B8A8Sscaled; | ||
| 413 | case Maxwell::VertexAttribute::Size::Size_16: | ||
| 414 | return vk::Format::eR16Sscaled; | ||
| 415 | case Maxwell::VertexAttribute::Size::Size_16_16: | ||
| 416 | return vk::Format::eR16G16Sscaled; | ||
| 417 | case Maxwell::VertexAttribute::Size::Size_16_16_16: | ||
| 418 | return vk::Format::eR16G16B16Sscaled; | ||
| 419 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: | ||
| 420 | return vk::Format::eR16G16B16A16Sscaled; | ||
| 421 | default: | ||
| 422 | break; | ||
| 423 | } | ||
| 404 | break; | 424 | break; |
| 405 | case Maxwell::VertexAttribute::Type::Float: | 425 | case Maxwell::VertexAttribute::Type::Float: |
| 406 | switch (size) { | 426 | switch (size) { |
diff --git a/src/video_core/shader/decode/xmad.cpp b/src/video_core/shader/decode/xmad.cpp index fbd7e9a17..6191ffba1 100644 --- a/src/video_core/shader/decode/xmad.cpp +++ b/src/video_core/shader/decode/xmad.cpp | |||
| @@ -31,7 +31,7 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) { | |||
| 31 | const bool is_signed_b = instr.xmad.sign_b == 1; | 31 | const bool is_signed_b = instr.xmad.sign_b == 1; |
| 32 | const bool is_signed_c = is_signed_a; | 32 | const bool is_signed_c = is_signed_a; |
| 33 | 33 | ||
| 34 | auto [is_merge, is_psl, is_high_b, mode, op_b, | 34 | auto [is_merge, is_psl, is_high_b, mode, op_b_binding, |
| 35 | op_c] = [&]() -> std::tuple<bool, bool, bool, Tegra::Shader::XmadMode, Node, Node> { | 35 | op_c] = [&]() -> std::tuple<bool, bool, bool, Tegra::Shader::XmadMode, Node, Node> { |
| 36 | switch (opcode->get().GetId()) { | 36 | switch (opcode->get().GetId()) { |
| 37 | case OpCode::Id::XMAD_CR: | 37 | case OpCode::Id::XMAD_CR: |
| @@ -67,9 +67,10 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) { | |||
| 67 | op_a = SignedOperation(OperationCode::IBitfieldExtract, is_signed_a, std::move(op_a), | 67 | op_a = SignedOperation(OperationCode::IBitfieldExtract, is_signed_a, std::move(op_a), |
| 68 | instr.xmad.high_a ? Immediate(16) : Immediate(0), Immediate(16)); | 68 | instr.xmad.high_a ? Immediate(16) : Immediate(0), Immediate(16)); |
| 69 | 69 | ||
| 70 | const Node original_b = op_b; | 70 | const Node original_b = op_b_binding; |
| 71 | op_b = SignedOperation(OperationCode::IBitfieldExtract, is_signed_b, std::move(op_b), | 71 | const Node op_b = |
| 72 | is_high_b ? Immediate(16) : Immediate(0), Immediate(16)); | 72 | SignedOperation(OperationCode::IBitfieldExtract, is_signed_b, std::move(op_b_binding), |
| 73 | is_high_b ? Immediate(16) : Immediate(0), Immediate(16)); | ||
| 73 | 74 | ||
| 74 | // we already check sign_a and sign_b is difference or not before so just use one in here. | 75 | // we already check sign_a and sign_b is difference or not before so just use one in here. |
| 75 | Node product = SignedOperation(OperationCode::IMul, is_signed_a, op_a, op_b); | 76 | Node product = SignedOperation(OperationCode::IMul, is_signed_a, op_a, op_b); |
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index 425927777..baf7188d2 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp | |||
| @@ -96,6 +96,7 @@ Node ShaderIR::GetPredicate(bool immediate) { | |||
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) { | 98 | Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) { |
| 99 | MarkAttributeUsage(index, element); | ||
| 99 | used_input_attributes.emplace(index); | 100 | used_input_attributes.emplace(index); |
| 100 | return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer)); | 101 | return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer)); |
| 101 | } | 102 | } |
| @@ -106,42 +107,8 @@ Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_addres | |||
| 106 | } | 107 | } |
| 107 | 108 | ||
| 108 | Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { | 109 | Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { |
| 109 | if (index == Attribute::Index::LayerViewportPointSize) { | 110 | MarkAttributeUsage(index, element); |
| 110 | switch (element) { | ||
| 111 | case 0: | ||
| 112 | UNIMPLEMENTED(); | ||
| 113 | break; | ||
| 114 | case 1: | ||
| 115 | uses_layer = true; | ||
| 116 | break; | ||
| 117 | case 2: | ||
| 118 | uses_viewport_index = true; | ||
| 119 | break; | ||
| 120 | case 3: | ||
| 121 | uses_point_size = true; | ||
| 122 | break; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | if (index == Attribute::Index::TessCoordInstanceIDVertexID) { | ||
| 126 | switch (element) { | ||
| 127 | case 2: | ||
| 128 | uses_instance_id = true; | ||
| 129 | break; | ||
| 130 | case 3: | ||
| 131 | uses_vertex_id = true; | ||
| 132 | break; | ||
| 133 | default: | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | if (index == Attribute::Index::ClipDistances0123 || | ||
| 138 | index == Attribute::Index::ClipDistances4567) { | ||
| 139 | const auto clip_index = | ||
| 140 | static_cast<u32>((index == Attribute::Index::ClipDistances4567 ? 1 : 0) + element); | ||
| 141 | used_clip_distances.at(clip_index) = true; | ||
| 142 | } | ||
| 143 | used_output_attributes.insert(index); | 111 | used_output_attributes.insert(index); |
| 144 | |||
| 145 | return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer)); | 112 | return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer)); |
| 146 | } | 113 | } |
| 147 | 114 | ||
| @@ -452,6 +419,54 @@ Node ShaderIR::BitfieldInsert(Node base, Node insert, u32 offset, u32 bits) { | |||
| 452 | Immediate(bits)); | 419 | Immediate(bits)); |
| 453 | } | 420 | } |
| 454 | 421 | ||
| 422 | void ShaderIR::MarkAttributeUsage(Attribute::Index index, u64 element) { | ||
| 423 | switch (index) { | ||
| 424 | case Attribute::Index::LayerViewportPointSize: | ||
| 425 | switch (element) { | ||
| 426 | case 0: | ||
| 427 | UNIMPLEMENTED(); | ||
| 428 | break; | ||
| 429 | case 1: | ||
| 430 | uses_layer = true; | ||
| 431 | break; | ||
| 432 | case 2: | ||
| 433 | uses_viewport_index = true; | ||
| 434 | break; | ||
| 435 | case 3: | ||
| 436 | uses_point_size = true; | ||
| 437 | break; | ||
| 438 | } | ||
| 439 | break; | ||
| 440 | case Attribute::Index::TessCoordInstanceIDVertexID: | ||
| 441 | switch (element) { | ||
| 442 | case 2: | ||
| 443 | uses_instance_id = true; | ||
| 444 | break; | ||
| 445 | case 3: | ||
| 446 | uses_vertex_id = true; | ||
| 447 | break; | ||
| 448 | } | ||
| 449 | break; | ||
| 450 | case Attribute::Index::ClipDistances0123: | ||
| 451 | case Attribute::Index::ClipDistances4567: { | ||
| 452 | const u64 clip_index = (index == Attribute::Index::ClipDistances4567 ? 4 : 0) + element; | ||
| 453 | used_clip_distances.at(clip_index) = true; | ||
| 454 | break; | ||
| 455 | } | ||
| 456 | case Attribute::Index::FrontColor: | ||
| 457 | case Attribute::Index::FrontSecondaryColor: | ||
| 458 | case Attribute::Index::BackColor: | ||
| 459 | case Attribute::Index::BackSecondaryColor: | ||
| 460 | uses_legacy_varyings = true; | ||
| 461 | break; | ||
| 462 | default: | ||
| 463 | if (index >= Attribute::Index::TexCoord_0 && index <= Attribute::Index::TexCoord_7) { | ||
| 464 | uses_legacy_varyings = true; | ||
| 465 | } | ||
| 466 | break; | ||
| 467 | } | ||
| 468 | } | ||
| 469 | |||
| 455 | std::size_t ShaderIR::DeclareAmend(Node new_amend) { | 470 | std::size_t ShaderIR::DeclareAmend(Node new_amend) { |
| 456 | const std::size_t id = amend_code.size(); | 471 | const std::size_t id = amend_code.size(); |
| 457 | amend_code.push_back(new_amend); | 472 | amend_code.push_back(new_amend); |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index dde036b40..80fc9b82c 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -137,6 +137,10 @@ public: | |||
| 137 | return uses_vertex_id; | 137 | return uses_vertex_id; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | bool UsesLegacyVaryings() const { | ||
| 141 | return uses_legacy_varyings; | ||
| 142 | } | ||
| 143 | |||
| 140 | bool UsesWarps() const { | 144 | bool UsesWarps() const { |
| 141 | return uses_warps; | 145 | return uses_warps; |
| 142 | } | 146 | } |
| @@ -343,6 +347,9 @@ private: | |||
| 343 | /// Inserts a sequence of bits from a node | 347 | /// Inserts a sequence of bits from a node |
| 344 | Node BitfieldInsert(Node base, Node insert, u32 offset, u32 bits); | 348 | Node BitfieldInsert(Node base, Node insert, u32 offset, u32 bits); |
| 345 | 349 | ||
| 350 | /// Marks the usage of a input or output attribute. | ||
| 351 | void MarkAttributeUsage(Tegra::Shader::Attribute::Index index, u64 element); | ||
| 352 | |||
| 346 | void WriteTexInstructionFloat(NodeBlock& bb, Tegra::Shader::Instruction instr, | 353 | void WriteTexInstructionFloat(NodeBlock& bb, Tegra::Shader::Instruction instr, |
| 347 | const Node4& components); | 354 | const Node4& components); |
| 348 | 355 | ||
| @@ -443,6 +450,7 @@ private: | |||
| 443 | bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes | 450 | bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes |
| 444 | bool uses_instance_id{}; | 451 | bool uses_instance_id{}; |
| 445 | bool uses_vertex_id{}; | 452 | bool uses_vertex_id{}; |
| 453 | bool uses_legacy_varyings{}; | ||
| 446 | bool uses_warps{}; | 454 | bool uses_warps{}; |
| 447 | bool uses_indexed_samplers{}; | 455 | bool uses_indexed_samplers{}; |
| 448 | 456 | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 47615adfe..d7e59d0cd 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1034,6 +1034,14 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 1034 | } | 1034 | } |
| 1035 | 1035 | ||
| 1036 | void GMainWindow::ShutdownGame() { | 1036 | void GMainWindow::ShutdownGame() { |
| 1037 | if (!emulation_running) { | ||
| 1038 | return; | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | if (ui.action_Fullscreen->isChecked()) { | ||
| 1042 | HideFullscreen(); | ||
| 1043 | } | ||
| 1044 | |||
| 1037 | AllowOSSleep(); | 1045 | AllowOSSleep(); |
| 1038 | 1046 | ||
| 1039 | discord_rpc->Pause(); | 1047 | discord_rpc->Pause(); |
| @@ -1716,11 +1724,6 @@ void GMainWindow::OnStartGame() { | |||
| 1716 | } | 1724 | } |
| 1717 | 1725 | ||
| 1718 | void GMainWindow::OnPauseGame() { | 1726 | void GMainWindow::OnPauseGame() { |
| 1719 | Core::System& system{Core::System::GetInstance()}; | ||
| 1720 | if (system.GetExitLock() && !ConfirmForceLockedExit()) { | ||
| 1721 | return; | ||
| 1722 | } | ||
| 1723 | |||
| 1724 | emu_thread->SetRunning(false); | 1727 | emu_thread->SetRunning(false); |
| 1725 | 1728 | ||
| 1726 | ui.action_Start->setEnabled(true); | 1729 | ui.action_Start->setEnabled(true); |
| @@ -1803,7 +1806,7 @@ void GMainWindow::ToggleWindowMode() { | |||
| 1803 | // Render in the main window... | 1806 | // Render in the main window... |
| 1804 | render_window->BackupGeometry(); | 1807 | render_window->BackupGeometry(); |
| 1805 | ui.horizontalLayout->addWidget(render_window); | 1808 | ui.horizontalLayout->addWidget(render_window); |
| 1806 | render_window->setFocusPolicy(Qt::ClickFocus); | 1809 | render_window->setFocusPolicy(Qt::StrongFocus); |
| 1807 | if (emulation_running) { | 1810 | if (emulation_running) { |
| 1808 | render_window->setVisible(true); | 1811 | render_window->setVisible(true); |
| 1809 | render_window->setFocus(); | 1812 | render_window->setFocus(); |