diff options
23 files changed, 669 insertions, 203 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b31a0328c..e836bf396 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -287,6 +287,18 @@ add_library(core STATIC hle/service/btm/btm.h hle/service/caps/caps.cpp hle/service/caps/caps.h + hle/service/caps/caps_a.cpp + hle/service/caps/caps_a.h + hle/service/caps/caps_c.cpp + hle/service/caps/caps_c.h + hle/service/caps/caps_u.cpp + hle/service/caps/caps_u.h + hle/service/caps/caps_sc.cpp + hle/service/caps/caps_sc.h + hle/service/caps/caps_ss.cpp + hle/service/caps/caps_ss.h + hle/service/caps/caps_su.cpp + hle/service/caps/caps_su.h hle/service/erpt/erpt.cpp hle/service/erpt/erpt.h hle/service/es/es.cpp diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp index 907f464ab..26c8a7081 100644 --- a/src/core/hle/service/caps/caps.cpp +++ b/src/core/hle/service/caps/caps.cpp @@ -2,168 +2,24 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <memory> - #include "core/hle/service/caps/caps.h" +#include "core/hle/service/caps/caps_a.h" +#include "core/hle/service/caps/caps_c.h" +#include "core/hle/service/caps/caps_sc.h" +#include "core/hle/service/caps/caps_ss.h" +#include "core/hle/service/caps/caps_su.h" +#include "core/hle/service/caps/caps_u.h" #include "core/hle/service/service.h" -#include "core/hle/service/sm/sm.h" namespace Service::Capture { -class CAPS_A final : public ServiceFramework<CAPS_A> { -public: - explicit CAPS_A() : ServiceFramework{"caps:a"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "GetAlbumFileCount"}, - {1, nullptr, "GetAlbumFileList"}, - {2, nullptr, "LoadAlbumFile"}, - {3, nullptr, "DeleteAlbumFile"}, - {4, nullptr, "StorageCopyAlbumFile"}, - {5, nullptr, "IsAlbumMounted"}, - {6, nullptr, "GetAlbumUsage"}, - {7, nullptr, "GetAlbumFileSize"}, - {8, nullptr, "LoadAlbumFileThumbnail"}, - {9, nullptr, "LoadAlbumScreenShotImage"}, - {10, nullptr, "LoadAlbumScreenShotThumbnailImage"}, - {11, nullptr, "GetAlbumEntryFromApplicationAlbumEntry"}, - {12, nullptr, "Unknown12"}, - {13, nullptr, "Unknown13"}, - {14, nullptr, "Unknown14"}, - {15, nullptr, "Unknown15"}, - {16, nullptr, "Unknown16"}, - {17, nullptr, "Unknown17"}, - {18, nullptr, "Unknown18"}, - {202, nullptr, "SaveEditedScreenShot"}, - {301, nullptr, "GetLastThumbnail"}, - {401, nullptr, "GetAutoSavingStorage"}, - {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"}, - {1001, nullptr, "Unknown1001"}, - {1002, nullptr, "Unknown1002"}, - {1003, nullptr, "Unknown1003"}, - {8001, nullptr, "ForceAlbumUnmounted"}, - {8002, nullptr, "ResetAlbumMountStatus"}, - {8011, nullptr, "RefreshAlbumCache"}, - {8012, nullptr, "GetAlbumCache"}, - {8013, nullptr, "Unknown8013"}, - {8021, nullptr, "GetAlbumEntryFromApplicationAlbumEntryAruid"}, - {10011, nullptr, "SetInternalErrorConversionEnabled"}, - {50000, nullptr, "Unknown50000"}, - {60002, nullptr, "Unknown60002"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class CAPS_C final : public ServiceFramework<CAPS_C> { -public: - explicit CAPS_C() : ServiceFramework{"caps:c"} { - // clang-format off - static const FunctionInfo functions[] = { - {33, nullptr, "Unknown33"}, - {2001, nullptr, "Unknown2001"}, - {2002, nullptr, "Unknown2002"}, - {2011, nullptr, "Unknown2011"}, - {2012, nullptr, "Unknown2012"}, - {2013, nullptr, "Unknown2013"}, - {2014, nullptr, "Unknown2014"}, - {2101, nullptr, "Unknown2101"}, - {2102, nullptr, "Unknown2102"}, - {2201, nullptr, "Unknown2201"}, - {2301, nullptr, "Unknown2301"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class CAPS_SC final : public ServiceFramework<CAPS_SC> { -public: - explicit CAPS_SC() : ServiceFramework{"caps:sc"} { - // clang-format off - static const FunctionInfo functions[] = { - {1, nullptr, "Unknown1"}, - {2, nullptr, "Unknown2"}, - {1001, nullptr, "Unknown3"}, - {1002, nullptr, "Unknown4"}, - {1003, nullptr, "Unknown5"}, - {1011, nullptr, "Unknown6"}, - {1012, nullptr, "Unknown7"}, - {1201, nullptr, "Unknown8"}, - {1202, nullptr, "Unknown9"}, - {1203, nullptr, "Unknown10"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class CAPS_SS final : public ServiceFramework<CAPS_SS> { -public: - explicit CAPS_SS() : ServiceFramework{"caps:ss"} { - // clang-format off - static const FunctionInfo functions[] = { - {201, nullptr, "Unknown1"}, - {202, nullptr, "Unknown2"}, - {203, nullptr, "Unknown3"}, - {204, nullptr, "Unknown4"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class CAPS_SU final : public ServiceFramework<CAPS_SU> { -public: - explicit CAPS_SU() : ServiceFramework{"caps:su"} { - // clang-format off - static const FunctionInfo functions[] = { - {201, nullptr, "SaveScreenShot"}, - {203, nullptr, "SaveScreenShotEx0"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class CAPS_U final : public ServiceFramework<CAPS_U> { -public: - explicit CAPS_U() : ServiceFramework{"caps:u"} { - // clang-format off - static const FunctionInfo functions[] = { - {32, nullptr, "SetShimLibraryVersion"}, - {102, nullptr, "GetAlbumFileListByAruid"}, - {103, nullptr, "DeleteAlbumFileByAruid"}, - {104, nullptr, "GetAlbumFileSizeByAruid"}, - {105, nullptr, "DeleteAlbumFileByAruidForDebug"}, - {110, nullptr, "LoadAlbumScreenShotImageByAruid"}, - {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"}, - {130, nullptr, "PrecheckToCreateContentsByAruid"}, - {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, - {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, - {142, nullptr, "GetAlbumFileList3AaeAruid"}, - {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, - {60002, nullptr, "OpenAccessorSessionForApplication"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - void InstallInterfaces(SM::ServiceManager& sm) { std::make_shared<CAPS_A>()->InstallAsService(sm); std::make_shared<CAPS_C>()->InstallAsService(sm); + std::make_shared<CAPS_U>()->InstallAsService(sm); std::make_shared<CAPS_SC>()->InstallAsService(sm); std::make_shared<CAPS_SS>()->InstallAsService(sm); std::make_shared<CAPS_SU>()->InstallAsService(sm); - std::make_shared<CAPS_U>()->InstallAsService(sm); } } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h index 471185dfa..fc70a4c27 100644 --- a/src/core/hle/service/caps/caps.h +++ b/src/core/hle/service/caps/caps.h @@ -4,12 +4,83 @@ #pragma once +#include "core/hle/service/service.h" + namespace Service::SM { class ServiceManager; } namespace Service::Capture { +enum AlbumImageOrientation { + Orientation0 = 0, + Orientation1 = 1, + Orientation2 = 2, + Orientation3 = 3, +}; + +enum AlbumReportOption { + Disable = 0, + Enable = 1, +}; + +enum ContentType : u8 { + Screenshot = 0, + Movie = 1, + ExtraMovie = 3, +}; + +enum AlbumStorage : u8 { + NAND = 0, + SD = 1, +}; + +struct AlbumFileDateTime { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 uid; +}; + +struct AlbumEntry { + u64 size; + u64 application_id; + AlbumFileDateTime datetime; + AlbumStorage storage; + ContentType content; + u8 padding[6]; +}; + +struct AlbumFileEntry { + u64 size; + u64 hash; + AlbumFileDateTime datetime; + AlbumStorage storage; + ContentType content; + u8 padding[5]; + u8 unknown; +}; + +struct ApplicationAlbumEntry { + u64 size; + u64 hash; + AlbumFileDateTime datetime; + AlbumStorage storage; + ContentType content; + u8 padding[5]; + u8 unknown; +}; + +struct ApplicationAlbumFileEntry { + ApplicationAlbumEntry entry; + AlbumFileDateTime datetime; + u64 unknown; +}; + +/// Registers all Capture services with the specified service manager. void InstallInterfaces(SM::ServiceManager& sm); } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp new file mode 100644 index 000000000..88a3fdc05 --- /dev/null +++ b/src/core/hle/service/caps/caps_a.cpp @@ -0,0 +1,78 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/caps/caps_a.h" + +namespace Service::Capture { + +class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> { +public: + explicit IAlbumAccessorSession() : ServiceFramework{"IAlbumAccessorSession"} { + // clang-format off + static const FunctionInfo functions[] = { + {2001, nullptr, "OpenAlbumMovieReadStream"}, + {2002, nullptr, "CloseAlbumMovieReadStream"}, + {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"}, + {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"}, + {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"}, + {2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"}, + {2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"}, + {2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +CAPS_A::CAPS_A() : ServiceFramework("caps:a") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetAlbumFileCount"}, + {1, nullptr, "GetAlbumFileList"}, + {2, nullptr, "LoadAlbumFile"}, + {3, nullptr, "DeleteAlbumFile"}, + {4, nullptr, "StorageCopyAlbumFile"}, + {5, nullptr, "IsAlbumMounted"}, + {6, nullptr, "GetAlbumUsage"}, + {7, nullptr, "GetAlbumFileSize"}, + {8, nullptr, "LoadAlbumFileThumbnail"}, + {9, nullptr, "LoadAlbumScreenShotImage"}, + {10, nullptr, "LoadAlbumScreenShotThumbnailImage"}, + {11, nullptr, "GetAlbumEntryFromApplicationAlbumEntry"}, + {12, nullptr, "LoadAlbumScreenShotImageEx"}, + {13, nullptr, "LoadAlbumScreenShotThumbnailImageEx"}, + {14, nullptr, "LoadAlbumScreenShotImageEx0"}, + {15, nullptr, "GetAlbumUsage3"}, + {16, nullptr, "GetAlbumMountResult"}, + {17, nullptr, "GetAlbumUsage16"}, + {18, nullptr, "Unknown18"}, + {100, nullptr, "GetAlbumFileCountEx0"}, + {101, nullptr, "GetAlbumFileListEx0"}, + {202, nullptr, "SaveEditedScreenShot"}, + {301, nullptr, "GetLastThumbnail"}, + {302, nullptr, "GetLastOverlayMovieThumbnail"}, + {401, nullptr, "GetAutoSavingStorage"}, + {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"}, + {1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"}, + {1002, nullptr, "LoadAlbumScreenShotImageEx1"}, + {1003, nullptr, "LoadAlbumScreenShotThumbnailImageEx1"}, + {8001, nullptr, "ForceAlbumUnmounted"}, + {8002, nullptr, "ResetAlbumMountStatus"}, + {8011, nullptr, "RefreshAlbumCache"}, + {8012, nullptr, "GetAlbumCache"}, + {8013, nullptr, "GetAlbumCacheEx"}, + {8021, nullptr, "GetAlbumEntryFromApplicationAlbumEntryAruid"}, + {10011, nullptr, "SetInternalErrorConversionEnabled"}, + {50000, nullptr, "LoadMakerNoteInfoForDebug"}, + {60002, nullptr, "OpenAccessorSession"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_A::~CAPS_A() = default; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_a.h b/src/core/hle/service/caps/caps_a.h new file mode 100644 index 000000000..8de832491 --- /dev/null +++ b/src/core/hle/service/caps/caps_a.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_A final : public ServiceFramework<CAPS_A> { +public: + explicit CAPS_A(); + ~CAPS_A() override; +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_c.cpp b/src/core/hle/service/caps/caps_c.cpp new file mode 100644 index 000000000..ea6452ffa --- /dev/null +++ b/src/core/hle/service/caps/caps_c.cpp @@ -0,0 +1,75 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/caps/caps_c.h" + +namespace Service::Capture { + +class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> { +public: + explicit IAlbumControlSession() : ServiceFramework{"IAlbumControlSession"} { + // clang-format off + static const FunctionInfo functions[] = { + {2001, nullptr, "OpenAlbumMovieReadStream"}, + {2002, nullptr, "CloseAlbumMovieReadStream"}, + {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"}, + {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"}, + {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"}, + {2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"}, + {2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"}, + {2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"}, + {2401, nullptr, "OpenAlbumMovieWriteStream"}, + {2402, nullptr, "FinishAlbumMovieWriteStream"}, + {2403, nullptr, "CommitAlbumMovieWriteStream"}, + {2404, nullptr, "DiscardAlbumMovieWriteStream"}, + {2405, nullptr, "DiscardAlbumMovieWriteStreamNoDelete"}, + {2406, nullptr, "CommitAlbumMovieWriteStreamEx"}, + {2411, nullptr, "StartAlbumMovieWriteStreamDataSection"}, + {2412, nullptr, "EndAlbumMovieWriteStreamDataSection"}, + {2413, nullptr, "StartAlbumMovieWriteStreamMetaSection"}, + {2414, nullptr, "EndAlbumMovieWriteStreamMetaSection"}, + {2421, nullptr, "ReadDataFromAlbumMovieWriteStream"}, + {2422, nullptr, "WriteDataToAlbumMovieWriteStream"}, + {2424, nullptr, "WriteMetaToAlbumMovieWriteStream"}, + {2431, nullptr, "GetAlbumMovieWriteStreamBrokenReason"}, + {2433, nullptr, "GetAlbumMovieWriteStreamDataSize"}, + {2434, nullptr, "SetAlbumMovieWriteStreamDataSize"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +CAPS_C::CAPS_C() : ServiceFramework("caps:c") { + // clang-format off + static const FunctionInfo functions[] = { + {1, nullptr, "CaptureRawImage"}, + {2, nullptr, "CaptureRawImageWithTimeout"}, + {33, nullptr, "Unknown33"}, + {1001, nullptr, "RequestTakingScreenShot"}, + {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, + {1011, nullptr, "NotifyTakingScreenShotRefused"}, + {2001, nullptr, "NotifyAlbumStorageIsAvailable"}, + {2002, nullptr, "NotifyAlbumStorageIsUnavailable"}, + {2011, nullptr, "RegisterAppletResourceUserId"}, + {2012, nullptr, "UnregisterAppletResourceUserId"}, + {2013, nullptr, "GetApplicationIdFromAruid"}, + {2014, nullptr, "CheckApplicationIdRegistered"}, + {2101, nullptr, "GenerateCurrentAlbumFileId"}, + {2102, nullptr, "GenerateApplicationAlbumEntry"}, + {2201, nullptr, "SaveAlbumScreenShotFile"}, + {2202, nullptr, "SaveAlbumScreenShotFileEx"}, + {2301, nullptr, "SetOverlayScreenShotThumbnailData"}, + {2302, nullptr, "SetOverlayMovieThumbnailData"}, + {60001, nullptr, "OpenControlSession"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_C::~CAPS_C() = default; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_c.h b/src/core/hle/service/caps/caps_c.h new file mode 100644 index 000000000..d07cdb441 --- /dev/null +++ b/src/core/hle/service/caps/caps_c.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_C final : public ServiceFramework<CAPS_C> { +public: + explicit CAPS_C(); + ~CAPS_C() override; +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_sc.cpp b/src/core/hle/service/caps/caps_sc.cpp new file mode 100644 index 000000000..d01a8a58e --- /dev/null +++ b/src/core/hle/service/caps/caps_sc.cpp @@ -0,0 +1,40 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/caps/caps_sc.h" + +namespace Service::Capture { + +CAPS_SC::CAPS_SC() : ServiceFramework("caps:sc") { + // clang-format off + static const FunctionInfo functions[] = { + {1, nullptr, "CaptureRawImage"}, + {2, nullptr, "CaptureRawImageWithTimeout"}, + {3, nullptr, "AttachSharedBuffer"}, + {5, nullptr, "CaptureRawImageToAttachedSharedBuffer"}, + {210, nullptr, "Unknown210"}, + {1001, nullptr, "RequestTakingScreenShot"}, + {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, + {1003, nullptr, "RequestTakingScreenShotEx"}, + {1004, nullptr, "RequestTakingScreenShotEx1"}, + {1009, nullptr, "CancelTakingScreenShot"}, + {1010, nullptr, "SetTakingScreenShotCancelState"}, + {1011, nullptr, "NotifyTakingScreenShotRefused"}, + {1012, nullptr, "NotifyTakingScreenShotFailed"}, + {1101, nullptr, "SetupOverlayMovieThumbnail"}, + {1106, nullptr, "Unknown1106"}, + {1107, nullptr, "Unknown1107"}, + {1201, nullptr, "OpenRawScreenShotReadStream"}, + {1202, nullptr, "CloseRawScreenShotReadStream"}, + {1203, nullptr, "ReadRawScreenShotReadStream"}, + {1204, nullptr, "Unknown1204"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_SC::~CAPS_SC() = default; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_sc.h b/src/core/hle/service/caps/caps_sc.h new file mode 100644 index 000000000..9ba372f7a --- /dev/null +++ b/src/core/hle/service/caps/caps_sc.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_SC final : public ServiceFramework<CAPS_SC> { +public: + explicit CAPS_SC(); + ~CAPS_SC() override; +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp new file mode 100644 index 000000000..eaa3a7494 --- /dev/null +++ b/src/core/hle/service/caps/caps_ss.cpp @@ -0,0 +1,26 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/caps/caps_ss.h" + +namespace Service::Capture { + +CAPS_SS::CAPS_SS() : ServiceFramework("caps:ss") { + // clang-format off + static const FunctionInfo functions[] = { + {201, nullptr, "SaveScreenShot"}, + {202, nullptr, "SaveEditedScreenShot"}, + {203, nullptr, "SaveScreenShotEx0"}, + {204, nullptr, "SaveEditedScreenShotEx0"}, + {206, nullptr, "Unknown206"}, + {208, nullptr, "SaveScreenShotOfMovieEx1"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_SS::~CAPS_SS() = default; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_ss.h b/src/core/hle/service/caps/caps_ss.h new file mode 100644 index 000000000..e258a6925 --- /dev/null +++ b/src/core/hle/service/caps/caps_ss.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_SS final : public ServiceFramework<CAPS_SS> { +public: + explicit CAPS_SS(); + ~CAPS_SS() override; +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp new file mode 100644 index 000000000..2b4c2d808 --- /dev/null +++ b/src/core/hle/service/caps/caps_su.cpp @@ -0,0 +1,22 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/caps/caps_su.h" + +namespace Service::Capture { + +CAPS_SU::CAPS_SU() : ServiceFramework("caps:su") { + // clang-format off + static const FunctionInfo functions[] = { + {201, nullptr, "SaveScreenShot"}, + {203, nullptr, "SaveScreenShotEx0"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_SU::~CAPS_SU() = default; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h new file mode 100644 index 000000000..cb11f7c9a --- /dev/null +++ b/src/core/hle/service/caps/caps_su.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_SU final : public ServiceFramework<CAPS_SU> { +public: + explicit CAPS_SU(); + ~CAPS_SU() override; +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp new file mode 100644 index 000000000..78bab6ed8 --- /dev/null +++ b/src/core/hle/service/caps/caps_u.cpp @@ -0,0 +1,76 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/caps/caps.h" +#include "core/hle/service/caps/caps_u.h" + +namespace Service::Capture { + +class IAlbumAccessorApplicationSession final + : public ServiceFramework<IAlbumAccessorApplicationSession> { +public: + explicit IAlbumAccessorApplicationSession() + : ServiceFramework{"IAlbumAccessorApplicationSession"} { + // clang-format off + static const FunctionInfo functions[] = { + {2001, nullptr, "OpenAlbumMovieReadStream"}, + {2002, nullptr, "CloseAlbumMovieReadStream"}, + {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"}, + {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"}, + {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +CAPS_U::CAPS_U() : ServiceFramework("caps:u") { + // clang-format off + static const FunctionInfo functions[] = { + {31, nullptr, "GetShimLibraryVersion"}, + {32, nullptr, "SetShimLibraryVersion"}, + {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"}, + {103, nullptr, "DeleteAlbumContentsFileForApplication"}, + {104, nullptr, "GetAlbumContentsFileSizeForApplication"}, + {105, nullptr, "DeleteAlbumFileByAruidForDebug"}, + {110, nullptr, "LoadAlbumContentsFileScreenShotImageForApplication"}, + {120, nullptr, "LoadAlbumContentsFileThumbnailImageForApplication"}, + {130, nullptr, "PrecheckToCreateContentsForApplication"}, + {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, + {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, + {142, nullptr, "GetAlbumFileList3AaeAruid"}, + {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, + {60002, nullptr, "OpenAccessorSessionForApplication"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_U::~CAPS_U() = default; + +void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) { + // Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an + // u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total + // output entries (which is copied to a s32 by official SW). + IPC::RequestParser rp{ctx}; + [[maybe_unused]] const auto application_album_file_entries = rp.PopRaw<std::array<u8, 0x30>>(); + const auto pid = rp.Pop<s32>(); + const auto content_type = rp.PopRaw<ContentType>(); + [[maybe_unused]] const auto start_datetime = rp.PopRaw<AlbumFileDateTime>(); + [[maybe_unused]] const auto end_datetime = rp.PopRaw<AlbumFileDateTime>(); + const auto applet_resource_user_id = rp.Pop<u64>(); + LOG_WARNING(Service_Capture, + "(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid, + content_type, applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<s32>(0); +} + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h new file mode 100644 index 000000000..e6e0716ff --- /dev/null +++ b/src/core/hle/service/caps/caps_u.h @@ -0,0 +1,24 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_U final : public ServiceFramework<CAPS_U> { +public: + explicit CAPS_U(); + ~CAPS_U() override; + +private: + void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx); +}; + +} // namespace Service::Capture diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 49dc5abe0..930b605af 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -231,18 +231,6 @@ enum class AtomicOp : u64 { Or = 6, Xor = 7, Exch = 8, -}; - -enum class GlobalAtomicOp : u64 { - Add = 0, - Min = 1, - Max = 2, - Inc = 3, - Dec = 4, - And = 5, - Or = 6, - Xor = 7, - Exch = 8, SafeAdd = 10, }; @@ -1001,7 +989,7 @@ union Instruction { } stg; union { - BitField<52, 4, GlobalAtomicOp> operation; + BitField<52, 4, AtomicOp> operation; BitField<49, 3, GlobalAtomicType> type; BitField<28, 20, s64> offset; } atom; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 8aa4a7ac9..c7d24cf14 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -2114,6 +2114,10 @@ private: template <const std::string_view& opname, Type type> Expression Atomic(Operation operation) { + if ((opname == Func::Min || opname == Func::Max) && type == Type::Int) { + UNIMPLEMENTED_MSG("Unimplemented Min & Max for atomic operations"); + return {}; + } return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(), Visit(operation[1]).As(type)), type}; @@ -2307,6 +2311,8 @@ private: ~Func() = delete; static constexpr std::string_view Add = "Add"; + static constexpr std::string_view Min = "Min"; + static constexpr std::string_view Max = "Max"; static constexpr std::string_view And = "And"; static constexpr std::string_view Or = "Or"; static constexpr std::string_view Xor = "Xor"; @@ -2457,7 +2463,21 @@ private: &GLSLDecompiler::AtomicImage<Func::Xor>, &GLSLDecompiler::AtomicImage<Func::Exchange>, + &GLSLDecompiler::Atomic<Func::Exchange, Type::Uint>, &GLSLDecompiler::Atomic<Func::Add, Type::Uint>, + &GLSLDecompiler::Atomic<Func::Min, Type::Uint>, + &GLSLDecompiler::Atomic<Func::Max, Type::Uint>, + &GLSLDecompiler::Atomic<Func::And, Type::Uint>, + &GLSLDecompiler::Atomic<Func::Or, Type::Uint>, + &GLSLDecompiler::Atomic<Func::Xor, Type::Uint>, + + &GLSLDecompiler::Atomic<Func::Exchange, Type::Int>, + &GLSLDecompiler::Atomic<Func::Add, Type::Int>, + &GLSLDecompiler::Atomic<Func::Min, Type::Int>, + &GLSLDecompiler::Atomic<Func::Max, Type::Int>, + &GLSLDecompiler::Atomic<Func::And, Type::Int>, + &GLSLDecompiler::Atomic<Func::Or, Type::Int>, + &GLSLDecompiler::Atomic<Func::Xor, Type::Int>, &GLSLDecompiler::Branch, &GLSLDecompiler::BranchIndirect, diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 51ecb5567..d67f08cf9 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -1941,7 +1941,11 @@ private: return {}; } - Expression AtomicAdd(Operation operation) { + template <Id (Module::*func)(Id, Id, Id, Id, Id), Type result_type, + Type value_type = result_type> + Expression Atomic(Operation operation) { + const Id type_def = GetTypeDefinition(result_type); + Id pointer; if (const auto smem = std::get_if<SmemNode>(&*operation[0])) { pointer = GetSharedMemoryPointer(*smem); @@ -1949,14 +1953,15 @@ private: pointer = GetGlobalMemoryPointer(*gmem); } else { UNREACHABLE(); - return {Constant(t_uint, 0), Type::Uint}; + return {Constant(type_def, 0), result_type}; } + const Id value = As(Visit(operation[1]), value_type); + const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); - const Id semantics = Constant(t_uint, 0U); + const Id semantics = Constant(type_def, 0); - const Id value = AsUint(Visit(operation[1])); - return {OpAtomicIAdd(t_uint, pointer, scope, semantics, value), Type::Uint}; + return {(this->*func)(type_def, pointer, scope, semantics, value), result_type}; } Expression Branch(Operation operation) { @@ -2545,7 +2550,21 @@ private: &SPIRVDecompiler::AtomicImageXor, &SPIRVDecompiler::AtomicImageExchange, - &SPIRVDecompiler::AtomicAdd, + &SPIRVDecompiler::Atomic<&Module::OpAtomicExchange, Type::Uint>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicIAdd, Type::Uint>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicUMin, Type::Uint>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicUMax, Type::Uint>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicAnd, Type::Uint>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicOr, Type::Uint>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicXor, Type::Uint>, + + &SPIRVDecompiler::Atomic<&Module::OpAtomicExchange, Type::Int>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicIAdd, Type::Int>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicSMin, Type::Int>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicSMax, Type::Int>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicAnd, Type::Int>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicOr, Type::Int>, + &SPIRVDecompiler::Atomic<&Module::OpAtomicXor, Type::Int>, &SPIRVDecompiler::Branch, &SPIRVDecompiler::BranchIndirect, diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp index 2fe787d6f..0f4c3103a 100644 --- a/src/video_core/shader/decode/arithmetic_integer.cpp +++ b/src/video_core/shader/decode/arithmetic_integer.cpp @@ -235,34 +235,30 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { case OpCode::Id::LEA_IMM: case OpCode::Id::LEA_RZ: case OpCode::Id::LEA_HI: { - const auto [op_a, op_b, op_c] = [&]() -> std::tuple<Node, Node, Node> { + auto [op_a, op_b, op_c] = [&]() -> std::tuple<Node, Node, Node> { switch (opcode->get().GetId()) { case OpCode::Id::LEA_R2: { return {GetRegister(instr.gpr20), GetRegister(instr.gpr39), Immediate(static_cast<u32>(instr.lea.r2.entry_a))}; } - case OpCode::Id::LEA_R1: { const bool neg = instr.lea.r1.neg != 0; return {GetOperandAbsNegInteger(GetRegister(instr.gpr8), false, neg, true), GetRegister(instr.gpr20), Immediate(static_cast<u32>(instr.lea.r1.entry_a))}; } - case OpCode::Id::LEA_IMM: { const bool neg = instr.lea.imm.neg != 0; return {Immediate(static_cast<u32>(instr.lea.imm.entry_a)), GetOperandAbsNegInteger(GetRegister(instr.gpr8), false, neg, true), Immediate(static_cast<u32>(instr.lea.imm.entry_b))}; } - case OpCode::Id::LEA_RZ: { const bool neg = instr.lea.rz.neg != 0; return {GetConstBuffer(instr.lea.rz.cb_index, instr.lea.rz.cb_offset), GetOperandAbsNegInteger(GetRegister(instr.gpr8), false, neg, true), Immediate(static_cast<u32>(instr.lea.rz.entry_a))}; } - case OpCode::Id::LEA_HI: default: UNIMPLEMENTED_MSG("Unhandled LEA subinstruction: {}", opcode->get().GetName()); @@ -275,12 +271,9 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { UNIMPLEMENTED_IF_MSG(instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex), "Unhandled LEA Predicate"); - const Node shifted_c = - Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, Immediate(1), op_c); - const Node mul_bc = Operation(OperationCode::IMul, NO_PRECISE, op_b, shifted_c); - const Node value = Operation(OperationCode::IAdd, NO_PRECISE, op_a, mul_bc); - - SetRegister(bb, instr.gpr0, value); + Node value = Operation(OperationCode::ILogicalShiftLeft, std::move(op_a), std::move(op_c)); + value = Operation(OperationCode::IAdd, std::move(op_b), std::move(value)); + SetRegister(bb, instr.gpr0, std::move(value)); break; } diff --git a/src/video_core/shader/decode/conversion.cpp b/src/video_core/shader/decode/conversion.cpp index 6ead42070..c72690b2b 100644 --- a/src/video_core/shader/decode/conversion.cpp +++ b/src/video_core/shader/decode/conversion.cpp @@ -138,18 +138,23 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { value = GetOperandAbsNegFloat(value, instr.conversion.abs_a, instr.conversion.negate_a); - value = [&]() { + value = [&] { + if (instr.conversion.src_size != instr.conversion.dst_size) { + // Rounding operations only matter when the source and destination conversion size + // is the same. + return value; + } switch (instr.conversion.f2f.GetRoundingMode()) { case Tegra::Shader::F2fRoundingOp::None: return value; case Tegra::Shader::F2fRoundingOp::Round: - return Operation(OperationCode::FRoundEven, PRECISE, value); + return Operation(OperationCode::FRoundEven, value); case Tegra::Shader::F2fRoundingOp::Floor: - return Operation(OperationCode::FFloor, PRECISE, value); + return Operation(OperationCode::FFloor, value); case Tegra::Shader::F2fRoundingOp::Ceil: - return Operation(OperationCode::FCeil, PRECISE, value); + return Operation(OperationCode::FCeil, value); case Tegra::Shader::F2fRoundingOp::Trunc: - return Operation(OperationCode::FTrunc, PRECISE, value); + return Operation(OperationCode::FTrunc, value); default: UNIMPLEMENTED_MSG("Unimplemented F2F rounding mode {}", static_cast<u32>(instr.conversion.f2f.rounding.Value())); diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp index b5fbc4d58..28a49addd 100644 --- a/src/video_core/shader/decode/memory.cpp +++ b/src/video_core/shader/decode/memory.cpp @@ -19,7 +19,6 @@ namespace VideoCommon::Shader { using Tegra::Shader::AtomicOp; using Tegra::Shader::AtomicType; using Tegra::Shader::Attribute; -using Tegra::Shader::GlobalAtomicOp; using Tegra::Shader::GlobalAtomicType; using Tegra::Shader::Instruction; using Tegra::Shader::OpCode; @@ -28,6 +27,28 @@ using Tegra::Shader::StoreType; namespace { +Node GetAtomOperation(AtomicOp op, bool is_signed, Node memory, Node data) { + const OperationCode operation_code = [op] { + switch (op) { + case AtomicOp::Add: + return OperationCode::AtomicIAdd; + case AtomicOp::Min: + return OperationCode::AtomicIMin; + case AtomicOp::Max: + return OperationCode::AtomicIMax; + case AtomicOp::And: + return OperationCode::AtomicIAnd; + case AtomicOp::Or: + return OperationCode::AtomicIOr; + case AtomicOp::Xor: + return OperationCode::AtomicIXor; + case AtomicOp::Exch: + return OperationCode::AtomicIExchange; + } + }(); + return SignedOperation(operation_code, is_signed, std::move(memory), std::move(data)); +} + bool IsUnaligned(Tegra::Shader::UniformType uniform_type) { return uniform_type == Tegra::Shader::UniformType::UnsignedByte || uniform_type == Tegra::Shader::UniformType::UnsignedShort; @@ -363,10 +384,13 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { break; } case OpCode::Id::ATOM: { - UNIMPLEMENTED_IF_MSG(instr.atom.operation != GlobalAtomicOp::Add, "operation={}", - static_cast<int>(instr.atom.operation.Value())); - UNIMPLEMENTED_IF_MSG(instr.atom.type != GlobalAtomicType::S32, "type={}", - static_cast<int>(instr.atom.type.Value())); + UNIMPLEMENTED_IF_MSG(instr.atom.operation == AtomicOp::Inc || + instr.atom.operation == AtomicOp::Dec || + instr.atom.operation == AtomicOp::SafeAdd, + "operation={}", static_cast<int>(instr.atom.operation.Value())); + UNIMPLEMENTED_IF_MSG(instr.atom.type == GlobalAtomicType::S64 || + instr.atom.type == GlobalAtomicType::U64, + "type={}", static_cast<int>(instr.atom.type.Value())); const auto [real_address, base_address, descriptor] = TrackGlobalMemory(bb, instr, true, true); @@ -375,25 +399,29 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { break; } + const bool is_signed = + instr.atoms.type == AtomicType::S32 || instr.atoms.type == AtomicType::S64; Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor); - Node value = Operation(OperationCode::AtomicAdd, std::move(gmem), GetRegister(instr.gpr20)); + Node value = GetAtomOperation(static_cast<AtomicOp>(instr.atom.operation), is_signed, gmem, + GetRegister(instr.gpr20)); SetRegister(bb, instr.gpr0, std::move(value)); break; } case OpCode::Id::ATOMS: { - UNIMPLEMENTED_IF_MSG(instr.atoms.operation != AtomicOp::Add, "operation={}", - static_cast<int>(instr.atoms.operation.Value())); - UNIMPLEMENTED_IF_MSG(instr.atoms.type != AtomicType::U32, "type={}", - static_cast<int>(instr.atoms.type.Value())); - + UNIMPLEMENTED_IF_MSG(instr.atoms.operation == AtomicOp::Inc || + instr.atoms.operation == AtomicOp::Dec, + "operation={}", static_cast<int>(instr.atoms.operation.Value())); + UNIMPLEMENTED_IF_MSG(instr.atoms.type == AtomicType::S64 || + instr.atoms.type == AtomicType::U64, + "type={}", static_cast<int>(instr.atoms.type.Value())); + const bool is_signed = + instr.atoms.type == AtomicType::S32 || instr.atoms.type == AtomicType::S64; const s32 offset = instr.atoms.GetImmediateOffset(); Node address = GetRegister(instr.gpr8); address = Operation(OperationCode::IAdd, std::move(address), Immediate(offset)); - - Node memory = GetSharedMemory(std::move(address)); - Node data = GetRegister(instr.gpr20); - - Node value = Operation(OperationCode::AtomicAdd, std::move(memory), std::move(data)); + Node value = + GetAtomOperation(static_cast<AtomicOp>(instr.atoms.operation), is_signed, + GetSharedMemory(std::move(address)), GetRegister(instr.gpr20)); SetRegister(bb, instr.gpr0, std::move(value)); break; } diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index a1828546e..5fcc9da60 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h @@ -162,7 +162,21 @@ enum class OperationCode { AtomicImageXor, /// (MetaImage, int[N] coords) -> void AtomicImageExchange, /// (MetaImage, int[N] coords) -> void - AtomicAdd, /// (memory, {u}int) -> {u}int + AtomicUExchange, /// (memory, uint) -> uint + AtomicUAdd, /// (memory, uint) -> uint + AtomicUMin, /// (memory, uint) -> uint + AtomicUMax, /// (memory, uint) -> uint + AtomicUAnd, /// (memory, uint) -> uint + AtomicUOr, /// (memory, uint) -> uint + AtomicUXor, /// (memory, uint) -> uint + + AtomicIExchange, /// (memory, int) -> int + AtomicIAdd, /// (memory, int) -> int + AtomicIMin, /// (memory, int) -> int + AtomicIMax, /// (memory, int) -> int + AtomicIAnd, /// (memory, int) -> int + AtomicIOr, /// (memory, int) -> int + AtomicIXor, /// (memory, int) -> int Branch, /// (uint branch_target) -> void BranchIndirect, /// (uint branch_target) -> void diff --git a/src/video_core/shader/node_helper.cpp b/src/video_core/shader/node_helper.cpp index 76c56abb5..7bf4ff387 100644 --- a/src/video_core/shader/node_helper.cpp +++ b/src/video_core/shader/node_helper.cpp @@ -86,6 +86,20 @@ OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed) return OperationCode::LogicalUNotEqual; case OperationCode::LogicalIGreaterEqual: return OperationCode::LogicalUGreaterEqual; + case OperationCode::AtomicIExchange: + return OperationCode::AtomicUExchange; + case OperationCode::AtomicIAdd: + return OperationCode::AtomicUAdd; + case OperationCode::AtomicIMin: + return OperationCode::AtomicUMin; + case OperationCode::AtomicIMax: + return OperationCode::AtomicUMax; + case OperationCode::AtomicIAnd: + return OperationCode::AtomicUAnd; + case OperationCode::AtomicIOr: + return OperationCode::AtomicUOr; + case OperationCode::AtomicIXor: + return OperationCode::AtomicUXor; case OperationCode::INegate: UNREACHABLE_MSG("Can't negate an unsigned integer"); return {}; |