summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt12
-rw-r--r--src/core/hle/service/caps/caps.cpp158
-rw-r--r--src/core/hle/service/caps/caps.h71
-rw-r--r--src/core/hle/service/caps/caps_a.cpp78
-rw-r--r--src/core/hle/service/caps/caps_a.h21
-rw-r--r--src/core/hle/service/caps/caps_c.cpp75
-rw-r--r--src/core/hle/service/caps/caps_c.h21
-rw-r--r--src/core/hle/service/caps/caps_sc.cpp40
-rw-r--r--src/core/hle/service/caps/caps_sc.h21
-rw-r--r--src/core/hle/service/caps/caps_ss.cpp26
-rw-r--r--src/core/hle/service/caps/caps_ss.h21
-rw-r--r--src/core/hle/service/caps/caps_su.cpp22
-rw-r--r--src/core/hle/service/caps/caps_su.h21
-rw-r--r--src/core/hle/service/caps/caps_u.cpp76
-rw-r--r--src/core/hle/service/caps/caps_u.h24
-rw-r--r--src/video_core/engines/shader_bytecode.h14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp20
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp31
-rw-r--r--src/video_core/shader/decode/arithmetic_integer.cpp15
-rw-r--r--src/video_core/shader/decode/conversion.cpp15
-rw-r--r--src/video_core/shader/decode/memory.cpp60
-rw-r--r--src/video_core/shader/node.h16
-rw-r--r--src/video_core/shader/node_helper.cpp14
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 {};