Compare commits

..

87 Commits

Author SHA1 Message Date
ReinUsesLisp
dec1cbaf7f cmake: Add missing shader hash file entries 2019-06-06 20:11:48 -03:00
ReinUsesLisp
769a50661a shader/node: Minor changes
Reflect std::shared_ptr nature of Node on initializers and remove
constant members in nodes.

Add some commentaries.
2019-06-06 20:03:33 -03:00
ReinUsesLisp
e1b3be7ced shader: Move Node declarations out of the shader IR header
Analysis passes do not have a good reason to depend on shader_ir.h to
work on top of nodes. This splits node-related declarations to their own
file and leaves the IR in shader_ir.h
2019-06-06 20:02:37 -03:00
Zach Hilman
04ac7a637a Merge pull request #2552 from ReinUsesLisp/shader-shared-ptr
shader: Use shared_ptr to store nodes and move initialization to file
2019-06-06 18:25:24 -04:00
Zach Hilman
adb8a9152b Merge pull request #2549 from lioncash/header
kernel/process: Remove unused boost header include
2019-06-06 14:31:46 -04:00
Zach Hilman
7322c8bd7c Merge pull request #2550 from lioncash/frontend
yuzu/CMakeLists: Pass compilation flags that make it more difficult to cause bugs in Qt code
2019-06-06 14:31:22 -04:00
bunnei
03d9bbaa90 Merge pull request #2551 from lioncash/dtor
service/ns: Add missing override specifiers
2019-06-06 10:37:28 -04:00
ReinUsesLisp
bf4dfb3ad4 shader: Use shared_ptr to store nodes and move initialization to file
Instead of having a vector of unique_ptr stored in a vector and
returning star pointers to this, use shared_ptr. While changing
initialization code, move it to a separate file when possible.

This is a first step to allow code analysis and node generation beyond
the ShaderIR class.
2019-06-05 20:41:52 -03:00
bunnei
a20ba09bfd Merge pull request #2520 from ReinUsesLisp/vulkan-refresh
vk_device,vk_shader_decompiler: Miscellaneous changes
2019-06-05 18:10:00 -04:00
bunnei
55c5029171 Merge pull request #2540 from ReinUsesLisp/remove-guest-position
gl_shader_decompiler: Remove guest "position" varying
2019-06-05 18:07:23 -04:00
bunnei
e4fea833d4 Merge pull request #2419 from DarkLordZach/srv-lr-iface
lr: Add command handler skeletons for Open*LocationResolver
2019-06-05 18:05:50 -04:00
bunnei
8d7a012297 Merge pull request #2521 from lioncash/naming
yuzu/configuration: Make function naming consistent
2019-06-05 18:03:05 -04:00
bunnei
0bcc305797 Merge pull request #2512 from ReinUsesLisp/comp-indexing
gl_shader_decompiler: Pessimize uniform buffer access on AMD's prorpietary driver
2019-06-05 18:02:30 -04:00
Lioncash
8304aaf282 service/ns: Add missing override specifiers 2019-06-05 16:20:24 -04:00
Lioncash
d7d5bffa18 yuzu/CMakeLists: Disable implicit QString->QUrl conversions
Enforces the use of the proper URL resolution functions. e.g.

url = some_local_path_string;

should actually be:

url = QUrl::fromLocalPath(some_local_path_string);

etc.

This makes it harder to cause bugs when operating with both strings and
URLs at the same time.
2019-06-05 16:05:40 -04:00
Zach Hilman
799302bc9d Merge pull request #2526 from lioncash/global
core/telemetry_session: Remove usages of the global system accessor
2019-06-05 15:57:48 -04:00
Zach Hilman
81e09bb121 Merge pull request #2545 from lioncash/timing
core/core_timing_util: Use std::chrono types for specifying time units
2019-06-05 15:52:37 -04:00
Zach Hilman
6aff1005ef Merge pull request #2541 from lioncash/input
input_common/sdl/sdl_impl: Minor cleanup
2019-06-05 15:51:03 -04:00
Lioncash
5b93290183 yuzu/CMakeLists: Disable unsafe overloads of QProcess' start() function
Other overloads of start() are considerably much safer to use if we ever
need this in the future and need to pass arguments to the program, given
it contains separate parameters for the program path and the arguments
themselves, whereas this unsafe overload contains both as a single
string.

Given the alternatives are much safer, we can disable this.
2019-06-05 15:49:23 -04:00
Lioncash
b5e1e87922 yuzu/CMakeLists: Disable implicit type narrowing in connect() calls
Prevents hard-to-diagnose bugs from potentially occurring and requires
any type narrowing to be explicitly performed by our code.
2019-06-05 15:47:35 -04:00
Lioncash
e1d755bdda yuzu/configuration: Make function naming consistent 2019-06-05 15:40:33 -04:00
Zach Hilman
2beaaa35c5 Merge pull request #2510 from SciresM/desired_language
Implement/Fix IApplicationFunctions::GetDesiredLanguage
2019-06-05 15:39:33 -04:00
Zach Hilman
1eb979221f Merge pull request #2527 from lioncash/index
yuzu/{profile_select, software_keyboard}: Tidy up interface
2019-06-05 15:30:51 -04:00
Zach Hilman
dd4fe0dab1 Merge pull request #2534 from ReinUsesLisp/shader-cleanup
gl_shader_cache: Minor style changes
2019-06-05 15:28:34 -04:00
Zach Hilman
433ca686a8 Merge pull request #2531 from ReinUsesLisp/qt-warnings
qt: Silence name collision warnings
2019-06-05 15:27:12 -04:00
Zach Hilman
6ce5f3e1bf Merge pull request #2515 from lioncash/narrowing
yuzu/configuration/configure_graphics: Eliminate type narrowing in a connect call
2019-06-05 15:26:13 -04:00
Zach Hilman
dfc40a3f9e Merge pull request #2532 from ShalokShalom/patch-2
Remove outdated info about compability
2019-06-05 15:04:57 -04:00
Zach Hilman
4f7a1f6c8c Merge pull request #2536 from lioncash/cache
game_list_worker: Use QFile over our own IOFile instance or std streams for the game list cache
2019-06-05 15:03:59 -04:00
Lioncash
19dcb50692 kernel/process: Remove unused boost header include
Boost headers typically include a lot of other headers, so removing this
can prevent a bit of unnecessary compiler churn when building.
2019-06-05 14:03:29 -04:00
Rodrigo Locatti
2ba4aa8a3b Merge pull request #2529 from lioncash/boot
yuzu/bootmanager: Minor interface tidying
2019-06-04 21:35:56 -03:00
Lioncash
2548661c08 core/core_timing_util: Amend casing of cyclesTo* functions
Makes the casing consistent with all of our general function naming
conventions.
2019-06-04 20:31:46 -04:00
Lioncash
42f5fd0ab3 core/core_timing_util: Use std::chrono types for specifying time units
Makes the interface more type-safe and consistent in terms of return
values.
2019-06-04 20:31:24 -04:00
Lioncash
79189c7e3e core/core_timing_utils: Simplify overload set
Removes unused overloads, simplifying the overall interface,
deduplicating some code.
2019-06-04 19:44:05 -04:00
Mat M
55f8111543 Merge pull request #2525 from FearlessTobi/remove-unused-settings
yuzu: Remove unused birthday setting
2019-06-04 13:39:24 -04:00
Hexagon12
b35953e4fd Merge pull request #2543 from FernandoS27/exit-flow
shader_bytecode: Mark EXIT as flow instruction
2019-06-04 19:52:59 +03:00
Fernando Sahmkow
a32c52b1d8 shader_bytecode: Mark EXIT as flow instruction 2019-06-04 12:18:35 -04:00
Lioncash
5ccf2a7b82 input_common/sdl/sdl_impl: Correct logging string in SDLState constructor
If this path was ever taken, a runtime exception would occur due to the
lack of a formatting specifier to insert the error code into the format
string.
2019-06-03 16:56:47 -04:00
Lioncash
cfac942e63 input_common/sdl/sdl_impl: Move documentation comments to header where applicable
Places the documentation comments with the rest of SDLState's member
function documentation.
2019-06-03 16:56:47 -04:00
Lioncash
b9b23c98ff input_common/sdl/sdl_impl: Amend names for axes for SDLAnalogPoller
Adds another underscore to clearly indicate the axis names.
2019-06-03 16:56:47 -04:00
Lioncash
50048d9f5a input_common/sdl/sdl_impl: Mark variables const where applicable
Make it explicit that these aren't modified elsewhere (either through
functions by reference, or by other operations).
2019-06-03 16:56:47 -04:00
Lioncash
ca7ca2919c input_common/sdl/sdl_impl: Mark SDLEventToButtonParamPackage() as static
Its prototype declared at the top of the translation unit contains the
static qualifier, so the function itself should also contain it to make
it a proper internally linked function.
2019-06-03 16:56:47 -04:00
Lioncash
b73ea457cc input_common/sdl/sdl_impl: Convert reinterpret_cast into a static_cast
It's valid to static_cast a void pointer back into its proper type.
2019-06-03 16:56:46 -04:00
Lioncash
2c679cda51 input_common/sdl/sdl_impl: Use insert_or_assign() where applicable
Same behavior, but without a potential need to unnecessarily default
construct a value.
2019-06-03 16:56:46 -04:00
Lioncash
b46e615551 input_common/sdl/sdl_impl: Simplify SDL_Joystick deleter handling
The deleter can just be set in the constructor and maintained throughout
the lifetime of the object.

If a contained pointer is null, then the deleter won't execute, so this
is safe to do. We don't need to swap it out with a version of a deleter
that does nothing.
2019-06-03 16:56:46 -04:00
Lioncash
7ea07c6063 input_common/sdl/sdl_impl: Resolve two sign conversion warnings
Silences the final two warnings in SDL code.
2019-06-03 16:56:46 -04:00
Lioncash
cf0d01a5d7 input_common/sdl: Remove unused header includes and forward declarations
Gets rid of a few unnecessary inclusion dependencies. It also uncovered
a few indirect inclusion dependencies being relied upon.
2019-06-03 16:56:42 -04:00
Lioncash
00f0827a26 input_common/sdl/sdl_impl: Use nested namespace specifiers where applicable 2019-06-03 15:49:04 -04:00
Lioncash
77ce85f51d yuzu/bootmanager: Log out screenshot destination path
We can make this message more meaningful by indicating the location the
screenshot has been saved to. We can also log out whenever a screenshot
could not be saved (e.g. due to filesystem permissions or some other
reason).
2019-06-03 15:34:32 -04:00
Lioncash
e32bf646cf yuzu/bootmanager: Treat the resolution factor as a u32
Treating it as a u16 can result in a sign-conversion warning when
performing arithmetic with it, as u16 promotes to an int when aritmetic
is performed on it, not unsigned int.

This also makes the interface more uniform, as the layout interface now
operates on u32 across the board.
2019-06-03 15:34:31 -04:00
Lioncash
536c9cf006 yuzu/bootmanager: Default EmuThread's destructor in the cpp file
This class contains non-trivial members, so we should default the
destructor's definition within the cpp file.
2019-06-03 15:34:31 -04:00
Lioncash
0a650ec99e yuzu/bootmanager: unsigned -> u32
Same thing (for platforms we support), less reading.
2019-06-03 15:34:31 -04:00
Lioncash
2575403acf yuzu/bootmanager: Change false literal to 0 for setSwapInterval()
This function is defined as taking an int, not a bool.
2019-06-03 15:31:52 -04:00
Lioncash
cfb59aad3f yuzu/bootmanager: Remove pointer downcast in GRenderWindow's constructor
We can just pass a pointer to GMainWindow directly and make it a
requirement of the interface. This makes the interface a little safer,
since this would technically otherwise allow any random QWidget to be
the parent of a render window, downcasting it to GMainWindow (which is
undefined behavior).
2019-06-03 15:31:52 -04:00
Lioncash
49e3a6e924 yuzu/bootmanager: Remove unnecessary pointer casts
We can just invoke these functions by qualifying the object name before
the function.
2019-06-03 15:31:51 -04:00
ReinUsesLisp
0935c2d97b gl_shader_decompiler: Remove guest "position" varying
"position" was being written but not read anywhere besides geometry
shaders, where it had the same value as gl_Position.

This commit replaces "position" with gl_Position, reducing the
complexity of our code and the emitted GLSL code.
2019-06-03 01:01:34 -03:00
Lioncash
e70f16fff7 input_common/sdl/sdl_impl: Silence sign conversion warnings
Makes the conversions explicit, as opposed to implicit.
2019-05-31 04:47:02 -03:00
Lioncash
1edf018319 common/math_util: Provide a template deduction guide for Common::Rectangle
Allows for things such as:

auto rect = Common::Rectangle{0, 0, 0, 0};

as opposed to being required to explicitly write out the underlying
type, such as:

auto rect = Common::Rectangle<int>{0, 0, 0, 0};

The only requirement for the deduction is that all constructor arguments
be the same type.
2019-05-31 04:44:02 -03:00
ReinUsesLisp
e72b9044a0 gl_shader_cache: Store a system class and drop global accessors 2019-05-30 14:01:40 -03:00
ReinUsesLisp
ad321564ed gl_shader_cache: Add commentaries explaining the intention in shaders creation 2019-05-30 13:58:38 -03:00
ReinUsesLisp
838b6d2ff8 gl_shader_cache: Flip if condition in GetStageProgram to reduce indentation 2019-05-30 13:56:03 -03:00
ShalokShalom
e9772a2539 Remove outdated info about compability 2019-05-30 05:38:27 +02:00
ReinUsesLisp
3f11d1c821 qt: Silence name collision warnings 2019-05-29 21:35:05 -03:00
fearlessTobi
d9c1b94f03 yuzu: Remove unused birthday setting
Fixes #2522.
2019-05-29 23:31:55 +02:00
Lioncash
cfc9d92b38 yuzu/software_keyboard: Remove unnecessary GetStatus() member function
Like with the profile selection dialog, we can just use the result of
QDialog's exec() function to determine whether or not a dialog was
accepted.
2019-05-29 00:56:45 -04:00
Lioncash
802dd3cc95 profile_select: Remove unnecessary GetStatus() member function
This behavior is already provided by the built-in exec() function. We
just need to check the return value of it.
2019-05-29 00:56:41 -04:00
Lioncash
139301c5a1 profile_select: Return int instead of u32 for GetIndex()
Qt uses a signed value to represent indices. We should follow this
convention where applicable to avoid unnecessary sign-conversion
warnings, as well as making it easier to interoperate with other aspects
of Qt.

While we're at it, we can also make a sign-conversion explicit.
2019-05-29 00:29:09 -04:00
Lioncash
8bbe930fac core/core: Remove unnecessary includes
The contents of these includes aren't used anywhere in this translation
unit.
2019-05-29 00:00:27 -04:00
Lioncash
c6f05b586f yuzu_cmd/yuzu: Correct formatting specifier
Amends the formatting specifier to obey libfmt. Prevents the application
from terminating due to a formatting issue in the error case.
2019-05-28 22:28:46 -04:00
Lioncash
84a8fb9264 core/loader: Remove LoadKernelSystemMode
This is a hold-over from Citra and doesn't apply to yuzu.
2019-05-28 22:28:44 -04:00
Lioncash
b1a4ab2ccc core/telemetry_session: Remove unnecessary web service nulling out in destructor
This will automatically occur when the backend instance goes out of
scope at the end of the destructor's execution.
2019-05-28 22:28:18 -04:00
Lioncash
215fd82738 core/telemetry_session: Remove usages of the global system accessor
Makes the dependency explicit in the TelemetrySession's interface
instead of making it a hidden dependency.

This also revealed a hidden issue with the way the telemetry session was
being initialized. It was attempting to retrieve the app loader and log
out title-specific information. However, this isn't always guaranteed to
be possible.

During the initialization phase, everything is being constructed. It
doesn't mean an actual title has been selected. This is what the Load()
function is for. This potentially results in dead code paths involving
the app loader. Instead, we explicitly add this information when we know
the app loader instance is available.
2019-05-28 22:28:15 -04:00
Lioncash
05af9d915c core/telemetry_session: Explicitly delete copy and move constructors
NonCopyable is misleading here. It also makes the class non-moveable as
well, so we can be explicit about this.
2019-05-28 21:07:38 -04:00
Lioncash
2fb3b9b951 core/telemetry_session: Remove unused include 2019-05-28 20:56:22 -04:00
Zach Hilman
52b80d231c ncm: Implement LR OpenAddOnContentLocationResolver (2)
Returns an object of type IAddOnContentLocationResolver for the provided StorageId.
2019-05-26 20:37:13 -04:00
Zach Hilman
e0920ef4ba ncm: Implement LR OpenRegisteredLocationResolver (1)
Returns an object of type IRegisteredLocationResolver for the StorageId.
2019-05-26 18:24:48 -04:00
Zach Hilman
33ac193bf6 ncm: Implement LR OpenLocationResolver (0)
Returns an object of type ILocationResolver with the provided StorageId.
2019-05-26 18:24:48 -04:00
ReinUsesLisp
f424b46036 vk_device: Let formats array type be deduced 2019-05-26 03:09:06 -03:00
ReinUsesLisp
a4c5e3e339 vk_shader_decompiler: Misc fixes
Fix missing OpSelectionMerge instruction. This caused devices loses on
most hardware, Intel didn't care.

Fix [-1;1] -> [0;1] depth conversions.

Conditionally use VK_EXT_scalar_block_layout. This allows us to use
non-std140 layouts on UBOs.

Update external Vulkan headers.
2019-05-26 01:48:04 -03:00
ReinUsesLisp
dec3c981d0 vk_device: Enable features when available and misc changes
Keeps track of native ASTC support, VK_EXT_scalar_block_layout
availability and SSBO range.

Check for independentBlend and vertexPipelineStorageAndAtomics as a
required feature. Always enable it.

Use vk::to_string format to log Vulkan enums.

Style changes.
2019-05-26 01:41:34 -03:00
Lioncash
d623e38d18 yuzu/configuration/configure_graphics: Eliminate type narrowing in a connect call
A checkbox is able to be tri-state, giving it three possible activity
types, so in the connect call here, it would actually be truncating an
int into a bool.

Instead, we can just listen on the toggled() signal, which passes along
a bool, not an int.
2019-05-24 22:24:40 -04:00
ReinUsesLisp
d8827b07b5 gl_shader_decompiler: Use an if based cbuf indexing for broken drivers
The following code is broken on AMD's proprietary GLSL compiler:
```glsl
uint idx = ...;
vec4 values = ...;
float some_value = values[idx & 3];
```

It index the wrong components, to fix this the following pessimized code
is emitted when that bug is present:
```glsl
uint idx = ...;
vec4 values = ...;
float some_value;
if ((idx & 3) == 0) some_value = values.x;
if ((idx & 3) == 1) some_value = values.y;
if ((idx & 3) == 2) some_value = values.z;
if ((idx & 3) == 3) some_value = values.w;
```
2019-05-24 02:47:56 -03:00
ReinUsesLisp
46177901b8 gl_device: Add test to detect broken component indexing
Component indexing on AMD's proprietary driver is broken. This commit adds
a test to detect when we are on a driver that can't successfully manage
component indexing.

It dispatches a dummy draw with just one vertex shader that writes to an
indexed SSBO from the GPU with data sent through uniforms, it then reads
that data from the CPU and compares the expected output.
2019-05-24 02:47:56 -03:00
Michael Scire
016f2eab73 Fix bitmask logic inversion 2019-05-23 02:37:13 -07:00
Michael Scire
2ed896075e fix introduced clang-format errors 2019-05-23 01:39:22 -07:00
Michael Scire
d81b58f320 Address review comments 2019-05-23 01:28:27 -07:00
Michael Scire
7fba9c7224 clang-format fixes 2019-05-23 01:14:11 -07:00
Michael Scire
7dbf4c1ae5 Implement IApplicationFunctions::GetDesiredLanguage 2019-05-23 00:55:56 -07:00
126 changed files with 2919 additions and 2001 deletions

View File

@@ -82,6 +82,9 @@ set(HASH_FILES
"${VIDEO_CORE}/shader/decode/video.cpp"
"${VIDEO_CORE}/shader/decode/xmad.cpp"
"${VIDEO_CORE}/shader/decode.cpp"
"${VIDEO_CORE}/shader/node.h"
"${VIDEO_CORE}/shader/node_helper.cpp"
"${VIDEO_CORE}/shader/node_helper.h"
"${VIDEO_CORE}/shader/shader_ir.cpp"
"${VIDEO_CORE}/shader/shader_ir.h"
"${VIDEO_CORE}/shader/track.cpp"

View File

@@ -7,7 +7,7 @@ yuzu is an experimental open-source emulator for the Nintendo Switch from the cr
It is written in C++ with portability in mind, with builds actively maintained for Windows, Linux and macOS. The emulator is currently only useful for homebrew development and research purposes.
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu cannot play any commercial games without major problems. yuzu can boot some games, to varying degrees of success.
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. yuzu can boot some games, to varying degrees of success.
yuzu is licensed under the GPLv2 (or any later version). Refer to the license.txt file included.

View File

@@ -57,7 +57,9 @@ Stream::State Stream::GetState() const {
s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
return Core::Timing::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
const auto us =
std::chrono::microseconds((static_cast<u64>(num_samples) * 1000000) / sample_rate);
return Core::Timing::usToCycles(us);
}
static void VolumeAdjustSamples(std::vector<s16>& samples) {

View File

@@ -56,6 +56,9 @@ add_custom_command(OUTPUT scm_rev.cpp
"${VIDEO_CORE}/shader/decode/video.cpp"
"${VIDEO_CORE}/shader/decode/xmad.cpp"
"${VIDEO_CORE}/shader/decode.cpp"
"${VIDEO_CORE}/shader/node.h"
"${VIDEO_CORE}/shader/node_helper.cpp"
"${VIDEO_CORE}/shader/node_helper.h"
"${VIDEO_CORE}/shader/shader_ir.cpp"
"${VIDEO_CORE}/shader/shader_ir.h"
"${VIDEO_CORE}/shader/track.cpp"

View File

@@ -41,4 +41,7 @@ struct Rectangle {
}
};
template <typename T>
Rectangle(T, T, T, T)->Rectangle<T>;
} // namespace Common

View File

@@ -328,6 +328,9 @@ add_library(core STATIC
hle/service/nim/nim.h
hle/service/npns/npns.cpp
hle/service/npns/npns.h
hle/service/ns/errors.h
hle/service/ns/language.cpp
hle/service/ns/language.h
hle/service/ns/ns.cpp
hle/service/ns/ns.h
hle/service/ns/pl_u.cpp

View File

@@ -18,11 +18,6 @@
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/kernel.h"
@@ -37,9 +32,6 @@
#include "core/settings.h"
#include "core/telemetry_session.h"
#include "file_sys/cheat_engine.h"
#include "frontend/applets/profile_select.h"
#include "frontend/applets/software_keyboard.h"
#include "frontend/applets/web_browser.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
@@ -144,20 +136,10 @@ struct System::Impl {
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
const std::string& filepath) {
app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return ResultStatus::ErrorGetLoader;
}
std::pair<std::optional<u32>, Loader::ResultStatus> system_mode =
app_loader->LoadKernelSystemMode();
if (system_mode.second != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
static_cast<int>(system_mode.second));
return ResultStatus::ErrorSystemMode;
}
ResultStatus init_result{Init(system, emu_window)};
if (init_result != ResultStatus::Success) {
@@ -167,6 +149,7 @@ struct System::Impl {
return init_result;
}
telemetry_session->AddInitialInfo(*app_loader);
auto main_process = Kernel::Process::Create(system, "main");
const auto [load_result, load_parameters] = app_loader->Load(*main_process);
if (load_result != Loader::ResultStatus::Success) {

View File

@@ -98,7 +98,6 @@ public:
Success, ///< Succeeded
ErrorNotInitialized, ///< Error trying to use core prior to initialization
ErrorGetLoader, ///< Error finding the correct application loader
ErrorSystemMode, ///< Error determining the system mode
ErrorSystemFiles, ///< Error in finding system files
ErrorSharedFont, ///< Error in finding shared font
ErrorVideoCore, ///< Error in the video core

View File

@@ -13,52 +13,40 @@ namespace Core::Timing {
constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE;
s64 usToCycles(s64 us) {
if (static_cast<u64>(us / 1000000) > MAX_VALUE_TO_MULTIPLY) {
s64 msToCycles(std::chrono::milliseconds ms) {
if (static_cast<u64>(ms.count() / 1000) > MAX_VALUE_TO_MULTIPLY) {
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (static_cast<u64>(us) > MAX_VALUE_TO_MULTIPLY) {
if (static_cast<u64>(ms.count()) > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (us / 1000000);
return BASE_CLOCK_RATE * (ms.count() / 1000);
}
return (BASE_CLOCK_RATE * us) / 1000000;
return (BASE_CLOCK_RATE * ms.count()) / 1000;
}
s64 usToCycles(u64 us) {
if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) {
s64 usToCycles(std::chrono::microseconds us) {
if (static_cast<u64>(us.count() / 1000000) > MAX_VALUE_TO_MULTIPLY) {
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (us > MAX_VALUE_TO_MULTIPLY) {
if (static_cast<u64>(us.count()) > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * static_cast<s64>(us / 1000000);
return BASE_CLOCK_RATE * (us.count() / 1000000);
}
return (BASE_CLOCK_RATE * static_cast<s64>(us)) / 1000000;
return (BASE_CLOCK_RATE * us.count()) / 1000000;
}
s64 nsToCycles(s64 ns) {
if (static_cast<u64>(ns / 1000000000) > MAX_VALUE_TO_MULTIPLY) {
s64 nsToCycles(std::chrono::nanoseconds ns) {
if (static_cast<u64>(ns.count() / 1000000000) > MAX_VALUE_TO_MULTIPLY) {
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (static_cast<u64>(ns) > MAX_VALUE_TO_MULTIPLY) {
if (static_cast<u64>(ns.count()) > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (ns / 1000000000);
return BASE_CLOCK_RATE * (ns.count() / 1000000000);
}
return (BASE_CLOCK_RATE * ns) / 1000000000;
}
s64 nsToCycles(u64 ns) {
if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) {
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (ns > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (static_cast<s64>(ns) / 1000000000);
}
return (BASE_CLOCK_RATE * static_cast<s64>(ns)) / 1000000000;
return (BASE_CLOCK_RATE * ns.count()) / 1000000000;
}
u64 CpuCyclesToClockCycles(u64 ticks) {

View File

@@ -4,6 +4,7 @@
#pragma once
#include <chrono>
#include "common/common_types.h"
namespace Core::Timing {
@@ -13,53 +14,20 @@ namespace Core::Timing {
constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch clock speed is 1020MHz un/docked
constexpr u64 CNTFREQ = 19200000; // Value from fusee.
inline s64 msToCycles(int ms) {
// since ms is int there is no way to overflow
return BASE_CLOCK_RATE * static_cast<s64>(ms) / 1000;
s64 msToCycles(std::chrono::milliseconds ms);
s64 usToCycles(std::chrono::microseconds us);
s64 nsToCycles(std::chrono::nanoseconds ns);
inline std::chrono::milliseconds CyclesToMs(s64 cycles) {
return std::chrono::milliseconds(cycles * 1000 / BASE_CLOCK_RATE);
}
inline s64 msToCycles(float ms) {
return static_cast<s64>(BASE_CLOCK_RATE * (0.001f) * ms);
inline std::chrono::nanoseconds CyclesToNs(s64 cycles) {
return std::chrono::nanoseconds(cycles * 1000000000 / BASE_CLOCK_RATE);
}
inline s64 msToCycles(double ms) {
return static_cast<s64>(BASE_CLOCK_RATE * (0.001) * ms);
}
inline s64 usToCycles(float us) {
return static_cast<s64>(BASE_CLOCK_RATE * (0.000001f) * us);
}
inline s64 usToCycles(int us) {
return (BASE_CLOCK_RATE * static_cast<s64>(us) / 1000000);
}
s64 usToCycles(s64 us);
s64 usToCycles(u64 us);
inline s64 nsToCycles(float ns) {
return static_cast<s64>(BASE_CLOCK_RATE * (0.000000001f) * ns);
}
inline s64 nsToCycles(int ns) {
return BASE_CLOCK_RATE * static_cast<s64>(ns) / 1000000000;
}
s64 nsToCycles(s64 ns);
s64 nsToCycles(u64 ns);
inline u64 cyclesToNs(s64 cycles) {
return cycles * 1000000000 / BASE_CLOCK_RATE;
}
inline s64 cyclesToUs(s64 cycles) {
return cycles * 1000000 / BASE_CLOCK_RATE;
}
inline u64 cyclesToMs(s64 cycles) {
return cycles * 1000 / BASE_CLOCK_RATE;
inline std::chrono::microseconds CyclesToUs(s64 cycles) {
return std::chrono::microseconds(cycles * 1000000 / BASE_CLOCK_RATE);
}
u64 CpuCyclesToClockCycles(u64 ticks);

View File

@@ -87,6 +87,10 @@ u64 NACP::GetDefaultJournalSaveSize() const {
return raw.user_account_save_data_journal_size;
}
u32 NACP::GetSupportedLanguages() const {
return raw.supported_languages;
}
std::vector<u8> NACP::GetRawBytes() const {
std::vector<u8> out(sizeof(RawNACP));
std::memcpy(out.data(), &raw, sizeof(RawNACP));

View File

@@ -109,6 +109,7 @@ public:
std::string GetVersionString() const;
u64 GetDefaultNormalSaveSize() const;
u64 GetDefaultJournalSaveSize() const;
u32 GetSupportedLanguages() const;
std::vector<u8> GetRawBytes() const;
private:

View File

@@ -20,7 +20,7 @@ static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area,
static_cast<T>(std::round(scale * screen_aspect_ratio))};
}
FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height) {
FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
ASSERT(width > 0);
ASSERT(height > 0);
// The drawing code needs at least somewhat valid values for both screens
@@ -29,22 +29,23 @@ FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height) {
const float emulation_aspect_ratio{static_cast<float>(ScreenUndocked::Height) /
ScreenUndocked::Width};
Common::Rectangle<unsigned> screen_window_area{0, 0, width, height};
Common::Rectangle<unsigned> screen = MaxRectangle(screen_window_area, emulation_aspect_ratio);
const auto window_aspect_ratio = static_cast<float>(height) / width;
float window_aspect_ratio = static_cast<float>(height) / width;
const Common::Rectangle<u32> screen_window_area{0, 0, width, height};
Common::Rectangle<u32> screen = MaxRectangle(screen_window_area, emulation_aspect_ratio);
if (window_aspect_ratio < emulation_aspect_ratio) {
screen = screen.TranslateX((screen_window_area.GetWidth() - screen.GetWidth()) / 2);
} else {
screen = screen.TranslateY((height - screen.GetHeight()) / 2);
}
res.screen = screen;
return res;
}
FramebufferLayout FrameLayoutFromResolutionScale(u16 res_scale) {
int width, height;
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
u32 width, height;
if (Settings::values.use_docked_mode) {
width = ScreenDocked::WidthDocked * res_scale;

View File

@@ -8,15 +8,22 @@
namespace Layout {
enum ScreenUndocked : unsigned { Width = 1280, Height = 720 };
enum ScreenDocked : unsigned { WidthDocked = 1920, HeightDocked = 1080 };
enum ScreenUndocked : u32 {
Width = 1280,
Height = 720,
};
enum ScreenDocked : u32 {
WidthDocked = 1920,
HeightDocked = 1080,
};
/// Describes the layout of the window framebuffer
struct FramebufferLayout {
unsigned width{ScreenUndocked::Width};
unsigned height{ScreenUndocked::Height};
u32 width{ScreenUndocked::Width};
u32 height{ScreenUndocked::Height};
Common::Rectangle<unsigned> screen;
Common::Rectangle<u32> screen;
/**
* Returns the ration of pixel size of the screen, compared to the native size of the undocked
@@ -33,12 +40,12 @@ struct FramebufferLayout {
* @param height Window framebuffer height in pixels
* @return Newly created FramebufferLayout object with default screen regions initialized
*/
FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height);
FramebufferLayout DefaultFrameLayout(u32 width, u32 height);
/**
* Convenience method to get frame layout by resolution scale
* @param res_scale resolution scale factor
*/
FramebufferLayout FrameLayoutFromResolutionScale(u16 res_scale);
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale);
} // namespace Layout

View File

@@ -10,7 +10,6 @@
#include <list>
#include <string>
#include <vector>
#include <boost/container/static_vector.hpp>
#include "common/common_types.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/handle_table.h"

View File

@@ -75,9 +75,9 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
// This function might be called from any thread so we have to be cautious and use the
// thread-safe version of ScheduleEvent.
const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});
Core::System::GetInstance().CoreTiming().ScheduleEventThreadsafe(
Core::Timing::nsToCycles(nanoseconds), kernel.ThreadWakeupCallbackEventType(),
callback_handle);
cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle);
}
void Thread::CancelWakeupTimer() {

View File

@@ -8,6 +8,8 @@
#include <cstring>
#include "audio_core/audio_renderer.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/savedata_factory.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/kernel.h"
@@ -29,9 +31,11 @@
#include "core/hle/service/am/tcap.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvflinger/nvflinger.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/set/set.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/vi.h"
#include "core/settings.h"
@@ -1100,10 +1104,42 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
// TODO(bunnei): This should be configurable
LOG_DEBUG(Service_AM, "called");
// Get supported languages from NACP, if possible
// Default to 0 (all languages supported)
u32 supported_languages = 0;
FileSys::PatchManager pm{Core::System::GetInstance().CurrentProcess()->GetTitleID()};
const auto res = pm.GetControlMetadata();
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
}
// Call IApplicationManagerInterface implementation.
auto& service_manager = Core::System::GetInstance().ServiceManager();
auto ns_am2 = service_manager.GetService<Service::NS::NS>("ns:am2");
auto app_man = ns_am2->GetApplicationManagerInterface();
// Get desired application language
const auto res_lang = app_man->GetApplicationDesiredLanguage(supported_languages);
if (res_lang.Failed()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_lang.Code());
return;
}
// Convert to settings language code.
const auto res_code = app_man->ConvertApplicationLanguageToLanguageCode(*res_lang);
if (res_code.Failed()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_code.Code());
return;
}
LOG_DEBUG(Service_AM, "got desired_language={:016X}", *res_code);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(
static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index)));
rb.Push(*res_code);
}
void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {

View File

@@ -121,6 +121,21 @@ void Applet::Initialize() {
initialized = true;
}
AppletFrontendSet::AppletFrontendSet() = default;
AppletFrontendSet::AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer,
ProfileSelect profile_select,
SoftwareKeyboard software_keyboard, WebBrowser web_browser)
: error{std::move(error)}, photo_viewer{std::move(photo_viewer)}, profile_select{std::move(
profile_select)},
software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)} {}
AppletFrontendSet::~AppletFrontendSet() = default;
AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default;
AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default;
AppletManager::AppletManager() = default;
AppletManager::~AppletManager() = default;

View File

@@ -137,11 +137,28 @@ protected:
};
struct AppletFrontendSet {
std::unique_ptr<Core::Frontend::ErrorApplet> error;
std::unique_ptr<Core::Frontend::PhotoViewerApplet> photo_viewer;
std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_select;
std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser;
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
AppletFrontendSet();
AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, ProfileSelect profile_select,
SoftwareKeyboard software_keyboard, WebBrowser web_browser);
~AppletFrontendSet();
AppletFrontendSet(const AppletFrontendSet&) = delete;
AppletFrontendSet& operator=(const AppletFrontendSet&) = delete;
AppletFrontendSet(AppletFrontendSet&&) noexcept;
AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
ErrorApplet error;
PhotoViewer photo_viewer;
ProfileSelect profile_select;
SoftwareKeyboard software_keyboard;
WebBrowser web_browser;
};
class AppletManager {

View File

@@ -4,15 +4,89 @@
#include <memory>
#include "core/file_sys/romfs_factory.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/ncm/ncm.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
namespace Service::NCM {
class LocationResolver final : public ServiceFramework<LocationResolver> {
class ILocationResolver final : public ServiceFramework<ILocationResolver> {
public:
explicit LocationResolver() : ServiceFramework{"lr"} {
explicit ILocationResolver(FileSys::StorageId id)
: ServiceFramework{"ILocationResolver"}, storage(id) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "ResolveProgramPath"},
{1, nullptr, "RedirectProgramPath"},
{2, nullptr, "ResolveApplicationControlPath"},
{3, nullptr, "ResolveApplicationHtmlDocumentPath"},
{4, nullptr, "ResolveDataPath"},
{5, nullptr, "RedirectApplicationControlPath"},
{6, nullptr, "RedirectApplicationHtmlDocumentPath"},
{7, nullptr, "ResolveApplicationLegalInformationPath"},
{8, nullptr, "RedirectApplicationLegalInformationPath"},
{9, nullptr, "Refresh"},
{10, nullptr, "RedirectProgramPath2"},
{11, nullptr, "Refresh2"},
{12, nullptr, "DeleteProgramPath"},
{13, nullptr, "DeleteApplicationControlPath"},
{14, nullptr, "DeleteApplicationHtmlDocumentPath"},
{15, nullptr, "DeleteApplicationLegalInformationPath"},
{16, nullptr, ""},
{17, nullptr, ""},
{18, nullptr, ""},
{19, nullptr, ""},
};
// clang-format on
RegisterHandlers(functions);
}
private:
FileSys::StorageId storage;
};
class IRegisteredLocationResolver final : public ServiceFramework<IRegisteredLocationResolver> {
public:
explicit IRegisteredLocationResolver() : ServiceFramework{"IRegisteredLocationResolver"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "ResolveProgramPath"},
{1, nullptr, "RegisterProgramPath"},
{2, nullptr, "UnregisterProgramPath"},
{3, nullptr, "RedirectProgramPath"},
{4, nullptr, "ResolveHtmlDocumentPath"},
{5, nullptr, "RegisterHtmlDocumentPath"},
{6, nullptr, "UnregisterHtmlDocumentPath"},
{7, nullptr, "RedirectHtmlDocumentPath"},
{8, nullptr, ""},
};
// clang-format on
RegisterHandlers(functions);
}
};
class IAddOnContentLocationResolver final : public ServiceFramework<IAddOnContentLocationResolver> {
public:
explicit IAddOnContentLocationResolver() : ServiceFramework{"IAddOnContentLocationResolver"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "ResolveAddOnContentPath"},
{1, nullptr, "RegisterAddOnContentStorage"},
{2, nullptr, "UnregisterAllAddOnContentPath"},
};
// clang-format on
RegisterHandlers(functions);
}
};
class LR final : public ServiceFramework<LR> {
public:
explicit LR() : ServiceFramework{"lr"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "OpenLocationResolver"},
@@ -52,7 +126,7 @@ public:
};
void InstallInterfaces(SM::ServiceManager& sm) {
std::make_shared<LocationResolver>()->InstallAsService(sm);
std::make_shared<LR>()->InstallAsService(sm);
std::make_shared<NCM>()->InstallAsService(sm);
}

View File

@@ -0,0 +1,12 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
namespace Service::NS {
constexpr ResultCode ERR_APPLICATION_LANGUAGE_NOT_FOUND{ErrorModule::NS, 300};
}

View File

@@ -0,0 +1,392 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/service/ns/language.h"
#include "core/hle/service/set/set.h"
namespace Service::NS {
constexpr ApplicationLanguagePriorityList priority_list_american_english = {{
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_british_english = {{
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_japanese = {{
ApplicationLanguage::Japanese,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_french = {{
ApplicationLanguage::French,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_german = {{
ApplicationLanguage::German,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_latin_american_spanish = {{
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::Spanish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::Portuguese,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::Italian,
ApplicationLanguage::German,
ApplicationLanguage::Dutch,
ApplicationLanguage::Russian,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_spanish = {{
ApplicationLanguage::Spanish,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_italian = {{
ApplicationLanguage::Italian,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_dutch = {{
ApplicationLanguage::Dutch,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_canadian_french = {{
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::Spanish,
ApplicationLanguage::German,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_portuguese = {{
ApplicationLanguage::Portuguese,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_russian = {{
ApplicationLanguage::Russian,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_korean = {{
ApplicationLanguage::Korean,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
}};
constexpr ApplicationLanguagePriorityList priority_list_traditional_chinese = {{
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::Japanese,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_simplified_chinese = {{
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::Japanese,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::Korean,
}};
const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(
const ApplicationLanguage lang) {
switch (lang) {
case ApplicationLanguage::AmericanEnglish:
return &priority_list_american_english;
case ApplicationLanguage::BritishEnglish:
return &priority_list_british_english;
case ApplicationLanguage::Japanese:
return &priority_list_japanese;
case ApplicationLanguage::French:
return &priority_list_french;
case ApplicationLanguage::German:
return &priority_list_german;
case ApplicationLanguage::LatinAmericanSpanish:
return &priority_list_latin_american_spanish;
case ApplicationLanguage::Spanish:
return &priority_list_spanish;
case ApplicationLanguage::Italian:
return &priority_list_italian;
case ApplicationLanguage::Dutch:
return &priority_list_dutch;
case ApplicationLanguage::CanadianFrench:
return &priority_list_canadian_french;
case ApplicationLanguage::Portuguese:
return &priority_list_portuguese;
case ApplicationLanguage::Russian:
return &priority_list_russian;
case ApplicationLanguage::Korean:
return &priority_list_korean;
case ApplicationLanguage::TraditionalChinese:
return &priority_list_traditional_chinese;
case ApplicationLanguage::SimplifiedChinese:
return &priority_list_simplified_chinese;
default:
return nullptr;
}
}
std::optional<ApplicationLanguage> ConvertToApplicationLanguage(
const Set::LanguageCode language_code) {
switch (language_code) {
case Set::LanguageCode::EN_US:
return ApplicationLanguage::AmericanEnglish;
case Set::LanguageCode::EN_GB:
return ApplicationLanguage::BritishEnglish;
case Set::LanguageCode::JA:
return ApplicationLanguage::Japanese;
case Set::LanguageCode::FR:
return ApplicationLanguage::French;
case Set::LanguageCode::DE:
return ApplicationLanguage::German;
case Set::LanguageCode::ES_419:
return ApplicationLanguage::LatinAmericanSpanish;
case Set::LanguageCode::ES:
return ApplicationLanguage::Spanish;
case Set::LanguageCode::IT:
return ApplicationLanguage::Italian;
case Set::LanguageCode::NL:
return ApplicationLanguage::Dutch;
case Set::LanguageCode::FR_CA:
return ApplicationLanguage::CanadianFrench;
case Set::LanguageCode::PT:
return ApplicationLanguage::Portuguese;
case Set::LanguageCode::RU:
return ApplicationLanguage::Russian;
case Set::LanguageCode::KO:
return ApplicationLanguage::Korean;
case Set::LanguageCode::ZH_HANT:
return ApplicationLanguage::TraditionalChinese;
case Set::LanguageCode::ZH_HANS:
return ApplicationLanguage::SimplifiedChinese;
default:
return std::nullopt;
}
}
std::optional<Set::LanguageCode> ConvertToLanguageCode(const ApplicationLanguage lang) {
switch (lang) {
case ApplicationLanguage::AmericanEnglish:
return Set::LanguageCode::EN_US;
case ApplicationLanguage::BritishEnglish:
return Set::LanguageCode::EN_GB;
case ApplicationLanguage::Japanese:
return Set::LanguageCode::JA;
case ApplicationLanguage::French:
return Set::LanguageCode::FR;
case ApplicationLanguage::German:
return Set::LanguageCode::DE;
case ApplicationLanguage::LatinAmericanSpanish:
return Set::LanguageCode::ES_419;
case ApplicationLanguage::Spanish:
return Set::LanguageCode::ES;
case ApplicationLanguage::Italian:
return Set::LanguageCode::IT;
case ApplicationLanguage::Dutch:
return Set::LanguageCode::NL;
case ApplicationLanguage::CanadianFrench:
return Set::LanguageCode::FR_CA;
case ApplicationLanguage::Portuguese:
return Set::LanguageCode::PT;
case ApplicationLanguage::Russian:
return Set::LanguageCode::RU;
case ApplicationLanguage::Korean:
return Set::LanguageCode::KO;
case ApplicationLanguage::TraditionalChinese:
return Set::LanguageCode::ZH_HANT;
case ApplicationLanguage::SimplifiedChinese:
return Set::LanguageCode::ZH_HANS;
default:
return std::nullopt;
}
}
} // namespace Service::NS

View File

@@ -0,0 +1,45 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <optional>
#include <string>
#include "common/common_types.h"
namespace Service::Set {
enum class LanguageCode : u64;
}
namespace Service::NS {
/// This is nn::ns::detail::ApplicationLanguage
enum class ApplicationLanguage : u8 {
AmericanEnglish = 0,
BritishEnglish,
Japanese,
French,
German,
LatinAmericanSpanish,
Spanish,
Italian,
Dutch,
CanadianFrench,
Portuguese,
Russian,
Korean,
TraditionalChinese,
SimplifiedChinese,
Count
};
using ApplicationLanguagePriorityList =
const std::array<ApplicationLanguage, static_cast<std::size_t>(ApplicationLanguage::Count)>;
constexpr u32 GetSupportedLanguageFlag(const ApplicationLanguage lang) {
return 1U << static_cast<u32>(lang);
}
const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(ApplicationLanguage lang);
std::optional<ApplicationLanguage> ConvertToApplicationLanguage(Set::LanguageCode language_code);
std::optional<Set::LanguageCode> ConvertToLanguageCode(ApplicationLanguage lang);
} // namespace Service::NS

View File

@@ -7,445 +7,507 @@
#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/ns/errors.h"
#include "core/hle/service/ns/language.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/ns/pl_u.h"
#include "core/hle/service/set/set.h"
#include "core/settings.h"
namespace Service::NS {
class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
public:
explicit IAccountProxyInterface() : ServiceFramework{"IAccountProxyInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateUserAccount"},
};
// clang-format on
IAccountProxyInterface::IAccountProxyInterface() : ServiceFramework{"IAccountProxyInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateUserAccount"},
};
// clang-format on
RegisterHandlers(functions);
}
};
RegisterHandlers(functions);
}
class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
public:
explicit IApplicationManagerInterface() : ServiceFramework{"IApplicationManagerInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "ListApplicationRecord"},
{1, nullptr, "GenerateApplicationRecordCount"},
{2, nullptr, "GetApplicationRecordUpdateSystemEvent"},
{3, nullptr, "GetApplicationViewDeprecated"},
{4, nullptr, "DeleteApplicationEntity"},
{5, nullptr, "DeleteApplicationCompletely"},
{6, nullptr, "IsAnyApplicationEntityRedundant"},
{7, nullptr, "DeleteRedundantApplicationEntity"},
{8, nullptr, "IsApplicationEntityMovable"},
{9, nullptr, "MoveApplicationEntity"},
{11, nullptr, "CalculateApplicationOccupiedSize"},
{16, nullptr, "PushApplicationRecord"},
{17, nullptr, "ListApplicationRecordContentMeta"},
{19, nullptr, "LaunchApplicationOld"},
{21, nullptr, "GetApplicationContentPath"},
{22, nullptr, "TerminateApplication"},
{23, nullptr, "ResolveApplicationContentPath"},
{26, nullptr, "BeginInstallApplication"},
{27, nullptr, "DeleteApplicationRecord"},
{30, nullptr, "RequestApplicationUpdateInfo"},
{32, nullptr, "CancelApplicationDownload"},
{33, nullptr, "ResumeApplicationDownload"},
{35, nullptr, "UpdateVersionList"},
{36, nullptr, "PushLaunchVersion"},
{37, nullptr, "ListRequiredVersion"},
{38, nullptr, "CheckApplicationLaunchVersion"},
{39, nullptr, "CheckApplicationLaunchRights"},
{40, nullptr, "GetApplicationLogoData"},
{41, nullptr, "CalculateApplicationDownloadRequiredSize"},
{42, nullptr, "CleanupSdCard"},
{43, nullptr, "CheckSdCardMountStatus"},
{44, nullptr, "GetSdCardMountStatusChangedEvent"},
{45, nullptr, "GetGameCardAttachmentEvent"},
{46, nullptr, "GetGameCardAttachmentInfo"},
{47, nullptr, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"},
{49, nullptr, "GetSdCardRemovedEvent"},
{52, nullptr, "GetGameCardUpdateDetectionEvent"},
{53, nullptr, "DisableApplicationAutoDelete"},
{54, nullptr, "EnableApplicationAutoDelete"},
{55, nullptr, "GetApplicationDesiredLanguage"},
{56, nullptr, "SetApplicationTerminateResult"},
{57, nullptr, "ClearApplicationTerminateResult"},
{58, nullptr, "GetLastSdCardMountUnexpectedResult"},
{59, nullptr, "ConvertApplicationLanguageToLanguageCode"},
{60, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
{61, nullptr, "GetBackgroundDownloadStressTaskInfo"},
{62, nullptr, "GetGameCardStopper"},
{63, nullptr, "IsSystemProgramInstalled"},
{64, nullptr, "StartApplyDeltaTask"},
{65, nullptr, "GetRequestServerStopper"},
{66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
{67, nullptr, "CancelApplicationApplyDelta"},
{68, nullptr, "ResumeApplicationApplyDelta"},
{69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"},
{70, nullptr, "ResumeAll"},
{71, nullptr, "GetStorageSize"},
{80, nullptr, "RequestDownloadApplication"},
{81, nullptr, "RequestDownloadAddOnContent"},
{82, nullptr, "DownloadApplication"},
{83, nullptr, "CheckApplicationResumeRights"},
{84, nullptr, "GetDynamicCommitEvent"},
{85, nullptr, "RequestUpdateApplication2"},
{86, nullptr, "EnableApplicationCrashReport"},
{87, nullptr, "IsApplicationCrashReportEnabled"},
{90, nullptr, "BoostSystemMemoryResourceLimit"},
{91, nullptr, "DeprecatedLaunchApplication"},
{92, nullptr, "GetRunningApplicationProgramId"},
{93, nullptr, "GetMainApplicationProgramIndex"},
{94, nullptr, "LaunchApplication"},
{95, nullptr, "GetApplicationLaunchInfo"},
{96, nullptr, "AcquireApplicationLaunchInfo"},
{97, nullptr, "GetMainApplicationProgramIndex2"},
{98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{100, nullptr, "ResetToFactorySettings"},
{101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
{102, nullptr, "ResetToFactorySettingsForRefurbishment"},
{200, nullptr, "CalculateUserSaveDataStatistics"},
{201, nullptr, "DeleteUserSaveDataAll"},
{210, nullptr, "DeleteUserSystemSaveData"},
{211, nullptr, "DeleteSaveData"},
{220, nullptr, "UnregisterNetworkServiceAccount"},
{221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"},
{300, nullptr, "GetApplicationShellEvent"},
{301, nullptr, "PopApplicationShellEventInfo"},
{302, nullptr, "LaunchLibraryApplet"},
{303, nullptr, "TerminateLibraryApplet"},
{304, nullptr, "LaunchSystemApplet"},
{305, nullptr, "TerminateSystemApplet"},
{306, nullptr, "LaunchOverlayApplet"},
{307, nullptr, "TerminateOverlayApplet"},
{400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
{401, nullptr, "InvalidateAllApplicationControlCache"},
{402, nullptr, "RequestDownloadApplicationControlData"},
{403, nullptr, "GetMaxApplicationControlCacheCount"},
{404, nullptr, "InvalidateApplicationControlCache"},
{405, nullptr, "ListApplicationControlCacheEntryInfo"},
{406, nullptr, "GetApplicationControlProperty"},
{502, nullptr, "RequestCheckGameCardRegistration"},
{503, nullptr, "RequestGameCardRegistrationGoldPoint"},
{504, nullptr, "RequestRegisterGameCard"},
{505, nullptr, "GetGameCardMountFailureEvent"},
{506, nullptr, "IsGameCardInserted"},
{507, nullptr, "EnsureGameCardAccess"},
{508, nullptr, "GetLastGameCardMountFailureResult"},
{509, nullptr, "ListApplicationIdOnGameCard"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{602, nullptr, "ListAvailableAddOnContent"},
{603, nullptr, "GetOwnedApplicationContentMetaStatus"},
{604, nullptr, "RegisterContentsExternalKey"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{606, nullptr, "GetContentMetaStorage"},
{607, nullptr, "ListAvailableAddOnContent"},
{700, nullptr, "PushDownloadTaskList"},
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
{703, nullptr, "RequestEnsureDownloadTask"},
{704, nullptr, "ListDownloadTaskStatus"},
{705, nullptr, "RequestDownloadTaskListData"},
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
{900, nullptr, "GetApplicationRecord"},
{901, nullptr, "GetApplicationRecordProperty"},
{902, nullptr, "EnableApplicationAutoUpdate"},
{903, nullptr, "DisableApplicationAutoUpdate"},
{904, nullptr, "TouchApplication"},
{905, nullptr, "RequestApplicationUpdate"},
{906, nullptr, "IsApplicationUpdateRequested"},
{907, nullptr, "WithdrawApplicationUpdateRequest"},
{908, nullptr, "ListApplicationRecordInstalledContentMeta"},
{909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"},
{910, nullptr, "HasApplicationRecord"},
{911, nullptr, "SetPreInstalledApplication"},
{912, nullptr, "ClearPreInstalledApplicationFlag"},
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
{1001, nullptr, "CorruptApplicationForDebug"},
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
{1003, nullptr, "RequestVerifyApplication"},
{1004, nullptr, "CorruptContentForDebug"},
{1200, nullptr, "NeedsUpdateVulnerability"},
{1300, nullptr, "IsAnyApplicationEntityInstalled"},
{1301, nullptr, "DeleteApplicationContentEntities"},
{1302, nullptr, "CleanupUnrecordedApplicationEntity"},
{1303, nullptr, "CleanupAddOnContentsWithNoRights"},
{1304, nullptr, "DeleteApplicationContentEntity"},
{1305, nullptr, "TryDeleteRunningApplicationEntity"},
{1306, nullptr, "TryDeleteRunningApplicationCompletely"},
{1307, nullptr, "TryDeleteRunningApplicationContentEntities"},
{1308, nullptr, "DeleteApplicationCompletelyForDebug"},
{1309, nullptr, "CleanupUnavailableAddOnContents"},
{1400, nullptr, "PrepareShutdown"},
{1500, nullptr, "FormatSdCard"},
{1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
{1502, nullptr, "GetLastSdCardFormatUnexpectedResult"},
{1504, nullptr, "InsertSdCard"},
{1505, nullptr, "RemoveSdCard"},
{1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
{1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
{1700, nullptr, "ListApplicationDownloadingContentMeta"},
{1701, nullptr, "GetApplicationView"},
{1702, nullptr, "GetApplicationDownloadTaskStatus"},
{1703, nullptr, "GetApplicationViewDownloadErrorContext"},
{1800, nullptr, "IsNotificationSetupCompleted"},
{1801, nullptr, "GetLastNotificationInfoCount"},
{1802, nullptr, "ListLastNotificationInfo"},
{1803, nullptr, "ListNotificationTask"},
{1900, nullptr, "IsActiveAccount"},
{1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"},
{1902, nullptr, "GetApplicationTicketInfo"},
{2000, nullptr, "GetSystemDeliveryInfo"},
{2001, nullptr, "SelectLatestSystemDeliveryInfo"},
{2002, nullptr, "VerifyDeliveryProtocolVersion"},
{2003, nullptr, "GetApplicationDeliveryInfo"},
{2004, nullptr, "HasAllContentsToDeliver"},
{2005, nullptr, "CompareApplicationDeliveryInfo"},
{2006, nullptr, "CanDeliverApplication"},
{2007, nullptr, "ListContentMetaKeyToDeliverApplication"},
{2008, nullptr, "NeedsSystemUpdateToDeliverApplication"},
{2009, nullptr, "EstimateRequiredSize"},
{2010, nullptr, "RequestReceiveApplication"},
{2011, nullptr, "CommitReceiveApplication"},
{2012, nullptr, "GetReceiveApplicationProgress"},
{2013, nullptr, "RequestSendApplication"},
{2014, nullptr, "GetSendApplicationProgress"},
{2015, nullptr, "CompareSystemDeliveryInfo"},
{2016, nullptr, "ListNotCommittedContentMeta"},
{2017, nullptr, "CreateDownloadTask"},
{2018, nullptr, "GetApplicationDeliveryInfoHash"},
{2050, nullptr, "GetApplicationRightsOnClient"},
{2100, nullptr, "GetApplicationTerminateResult"},
{2101, nullptr, "GetRawApplicationTerminateResult"},
{2150, nullptr, "CreateRightsEnvironment"},
{2151, nullptr, "DestroyRightsEnvironment"},
{2152, nullptr, "ActivateRightsEnvironment"},
{2153, nullptr, "DeactivateRightsEnvironment"},
{2154, nullptr, "ForceActivateRightsContextForExit"},
{2160, nullptr, "AddTargetApplicationToRightsEnvironment"},
{2161, nullptr, "SetUsersToRightsEnvironment"},
{2170, nullptr, "GetRightsEnvironmentStatus"},
{2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"},
{2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
{2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"},
{2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
{2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
{2199, nullptr, "GetRightsEnvironmentCountForDebug"},
{2200, nullptr, "GetGameCardApplicationCopyIdentifier"},
{2201, nullptr, "GetInstalledApplicationCopyIdentifier"},
{2250, nullptr, "RequestReportActiveELicence"},
{2300, nullptr, "ListEventLog"},
};
// clang-format on
IAccountProxyInterface::~IAccountProxyInterface() = default;
RegisterHandlers(functions);
}
IApplicationManagerInterface::IApplicationManagerInterface()
: ServiceFramework{"IApplicationManagerInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "ListApplicationRecord"},
{1, nullptr, "GenerateApplicationRecordCount"},
{2, nullptr, "GetApplicationRecordUpdateSystemEvent"},
{3, nullptr, "GetApplicationViewDeprecated"},
{4, nullptr, "DeleteApplicationEntity"},
{5, nullptr, "DeleteApplicationCompletely"},
{6, nullptr, "IsAnyApplicationEntityRedundant"},
{7, nullptr, "DeleteRedundantApplicationEntity"},
{8, nullptr, "IsApplicationEntityMovable"},
{9, nullptr, "MoveApplicationEntity"},
{11, nullptr, "CalculateApplicationOccupiedSize"},
{16, nullptr, "PushApplicationRecord"},
{17, nullptr, "ListApplicationRecordContentMeta"},
{19, nullptr, "LaunchApplicationOld"},
{21, nullptr, "GetApplicationContentPath"},
{22, nullptr, "TerminateApplication"},
{23, nullptr, "ResolveApplicationContentPath"},
{26, nullptr, "BeginInstallApplication"},
{27, nullptr, "DeleteApplicationRecord"},
{30, nullptr, "RequestApplicationUpdateInfo"},
{32, nullptr, "CancelApplicationDownload"},
{33, nullptr, "ResumeApplicationDownload"},
{35, nullptr, "UpdateVersionList"},
{36, nullptr, "PushLaunchVersion"},
{37, nullptr, "ListRequiredVersion"},
{38, nullptr, "CheckApplicationLaunchVersion"},
{39, nullptr, "CheckApplicationLaunchRights"},
{40, nullptr, "GetApplicationLogoData"},
{41, nullptr, "CalculateApplicationDownloadRequiredSize"},
{42, nullptr, "CleanupSdCard"},
{43, nullptr, "CheckSdCardMountStatus"},
{44, nullptr, "GetSdCardMountStatusChangedEvent"},
{45, nullptr, "GetGameCardAttachmentEvent"},
{46, nullptr, "GetGameCardAttachmentInfo"},
{47, nullptr, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"},
{49, nullptr, "GetSdCardRemovedEvent"},
{52, nullptr, "GetGameCardUpdateDetectionEvent"},
{53, nullptr, "DisableApplicationAutoDelete"},
{54, nullptr, "EnableApplicationAutoDelete"},
{55, &IApplicationManagerInterface::GetApplicationDesiredLanguage, "GetApplicationDesiredLanguage"},
{56, nullptr, "SetApplicationTerminateResult"},
{57, nullptr, "ClearApplicationTerminateResult"},
{58, nullptr, "GetLastSdCardMountUnexpectedResult"},
{59, &IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode, "ConvertApplicationLanguageToLanguageCode"},
{60, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
{61, nullptr, "GetBackgroundDownloadStressTaskInfo"},
{62, nullptr, "GetGameCardStopper"},
{63, nullptr, "IsSystemProgramInstalled"},
{64, nullptr, "StartApplyDeltaTask"},
{65, nullptr, "GetRequestServerStopper"},
{66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
{67, nullptr, "CancelApplicationApplyDelta"},
{68, nullptr, "ResumeApplicationApplyDelta"},
{69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"},
{70, nullptr, "ResumeAll"},
{71, nullptr, "GetStorageSize"},
{80, nullptr, "RequestDownloadApplication"},
{81, nullptr, "RequestDownloadAddOnContent"},
{82, nullptr, "DownloadApplication"},
{83, nullptr, "CheckApplicationResumeRights"},
{84, nullptr, "GetDynamicCommitEvent"},
{85, nullptr, "RequestUpdateApplication2"},
{86, nullptr, "EnableApplicationCrashReport"},
{87, nullptr, "IsApplicationCrashReportEnabled"},
{90, nullptr, "BoostSystemMemoryResourceLimit"},
{91, nullptr, "DeprecatedLaunchApplication"},
{92, nullptr, "GetRunningApplicationProgramId"},
{93, nullptr, "GetMainApplicationProgramIndex"},
{94, nullptr, "LaunchApplication"},
{95, nullptr, "GetApplicationLaunchInfo"},
{96, nullptr, "AcquireApplicationLaunchInfo"},
{97, nullptr, "GetMainApplicationProgramIndex2"},
{98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{100, nullptr, "ResetToFactorySettings"},
{101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
{102, nullptr, "ResetToFactorySettingsForRefurbishment"},
{200, nullptr, "CalculateUserSaveDataStatistics"},
{201, nullptr, "DeleteUserSaveDataAll"},
{210, nullptr, "DeleteUserSystemSaveData"},
{211, nullptr, "DeleteSaveData"},
{220, nullptr, "UnregisterNetworkServiceAccount"},
{221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"},
{300, nullptr, "GetApplicationShellEvent"},
{301, nullptr, "PopApplicationShellEventInfo"},
{302, nullptr, "LaunchLibraryApplet"},
{303, nullptr, "TerminateLibraryApplet"},
{304, nullptr, "LaunchSystemApplet"},
{305, nullptr, "TerminateSystemApplet"},
{306, nullptr, "LaunchOverlayApplet"},
{307, nullptr, "TerminateOverlayApplet"},
{400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
{401, nullptr, "InvalidateAllApplicationControlCache"},
{402, nullptr, "RequestDownloadApplicationControlData"},
{403, nullptr, "GetMaxApplicationControlCacheCount"},
{404, nullptr, "InvalidateApplicationControlCache"},
{405, nullptr, "ListApplicationControlCacheEntryInfo"},
{406, nullptr, "GetApplicationControlProperty"},
{502, nullptr, "RequestCheckGameCardRegistration"},
{503, nullptr, "RequestGameCardRegistrationGoldPoint"},
{504, nullptr, "RequestRegisterGameCard"},
{505, nullptr, "GetGameCardMountFailureEvent"},
{506, nullptr, "IsGameCardInserted"},
{507, nullptr, "EnsureGameCardAccess"},
{508, nullptr, "GetLastGameCardMountFailureResult"},
{509, nullptr, "ListApplicationIdOnGameCard"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{602, nullptr, "ListAvailableAddOnContent"},
{603, nullptr, "GetOwnedApplicationContentMetaStatus"},
{604, nullptr, "RegisterContentsExternalKey"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{606, nullptr, "GetContentMetaStorage"},
{607, nullptr, "ListAvailableAddOnContent"},
{700, nullptr, "PushDownloadTaskList"},
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
{703, nullptr, "RequestEnsureDownloadTask"},
{704, nullptr, "ListDownloadTaskStatus"},
{705, nullptr, "RequestDownloadTaskListData"},
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
{900, nullptr, "GetApplicationRecord"},
{901, nullptr, "GetApplicationRecordProperty"},
{902, nullptr, "EnableApplicationAutoUpdate"},
{903, nullptr, "DisableApplicationAutoUpdate"},
{904, nullptr, "TouchApplication"},
{905, nullptr, "RequestApplicationUpdate"},
{906, nullptr, "IsApplicationUpdateRequested"},
{907, nullptr, "WithdrawApplicationUpdateRequest"},
{908, nullptr, "ListApplicationRecordInstalledContentMeta"},
{909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"},
{910, nullptr, "HasApplicationRecord"},
{911, nullptr, "SetPreInstalledApplication"},
{912, nullptr, "ClearPreInstalledApplicationFlag"},
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
{1001, nullptr, "CorruptApplicationForDebug"},
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
{1003, nullptr, "RequestVerifyApplication"},
{1004, nullptr, "CorruptContentForDebug"},
{1200, nullptr, "NeedsUpdateVulnerability"},
{1300, nullptr, "IsAnyApplicationEntityInstalled"},
{1301, nullptr, "DeleteApplicationContentEntities"},
{1302, nullptr, "CleanupUnrecordedApplicationEntity"},
{1303, nullptr, "CleanupAddOnContentsWithNoRights"},
{1304, nullptr, "DeleteApplicationContentEntity"},
{1305, nullptr, "TryDeleteRunningApplicationEntity"},
{1306, nullptr, "TryDeleteRunningApplicationCompletely"},
{1307, nullptr, "TryDeleteRunningApplicationContentEntities"},
{1308, nullptr, "DeleteApplicationCompletelyForDebug"},
{1309, nullptr, "CleanupUnavailableAddOnContents"},
{1400, nullptr, "PrepareShutdown"},
{1500, nullptr, "FormatSdCard"},
{1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
{1502, nullptr, "GetLastSdCardFormatUnexpectedResult"},
{1504, nullptr, "InsertSdCard"},
{1505, nullptr, "RemoveSdCard"},
{1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
{1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
{1700, nullptr, "ListApplicationDownloadingContentMeta"},
{1701, nullptr, "GetApplicationView"},
{1702, nullptr, "GetApplicationDownloadTaskStatus"},
{1703, nullptr, "GetApplicationViewDownloadErrorContext"},
{1800, nullptr, "IsNotificationSetupCompleted"},
{1801, nullptr, "GetLastNotificationInfoCount"},
{1802, nullptr, "ListLastNotificationInfo"},
{1803, nullptr, "ListNotificationTask"},
{1900, nullptr, "IsActiveAccount"},
{1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"},
{1902, nullptr, "GetApplicationTicketInfo"},
{2000, nullptr, "GetSystemDeliveryInfo"},
{2001, nullptr, "SelectLatestSystemDeliveryInfo"},
{2002, nullptr, "VerifyDeliveryProtocolVersion"},
{2003, nullptr, "GetApplicationDeliveryInfo"},
{2004, nullptr, "HasAllContentsToDeliver"},
{2005, nullptr, "CompareApplicationDeliveryInfo"},
{2006, nullptr, "CanDeliverApplication"},
{2007, nullptr, "ListContentMetaKeyToDeliverApplication"},
{2008, nullptr, "NeedsSystemUpdateToDeliverApplication"},
{2009, nullptr, "EstimateRequiredSize"},
{2010, nullptr, "RequestReceiveApplication"},
{2011, nullptr, "CommitReceiveApplication"},
{2012, nullptr, "GetReceiveApplicationProgress"},
{2013, nullptr, "RequestSendApplication"},
{2014, nullptr, "GetSendApplicationProgress"},
{2015, nullptr, "CompareSystemDeliveryInfo"},
{2016, nullptr, "ListNotCommittedContentMeta"},
{2017, nullptr, "CreateDownloadTask"},
{2018, nullptr, "GetApplicationDeliveryInfoHash"},
{2050, nullptr, "GetApplicationRightsOnClient"},
{2100, nullptr, "GetApplicationTerminateResult"},
{2101, nullptr, "GetRawApplicationTerminateResult"},
{2150, nullptr, "CreateRightsEnvironment"},
{2151, nullptr, "DestroyRightsEnvironment"},
{2152, nullptr, "ActivateRightsEnvironment"},
{2153, nullptr, "DeactivateRightsEnvironment"},
{2154, nullptr, "ForceActivateRightsContextForExit"},
{2160, nullptr, "AddTargetApplicationToRightsEnvironment"},
{2161, nullptr, "SetUsersToRightsEnvironment"},
{2170, nullptr, "GetRightsEnvironmentStatus"},
{2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"},
{2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
{2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"},
{2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
{2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
{2199, nullptr, "GetRightsEnvironmentCountForDebug"},
{2200, nullptr, "GetGameCardApplicationCopyIdentifier"},
{2201, nullptr, "GetInstalledApplicationCopyIdentifier"},
{2250, nullptr, "RequestReportActiveELicence"},
{2300, nullptr, "ListEventLog"},
};
// clang-format on
void GetApplicationControlData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto flag = rp.PopRaw<u64>();
LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
RegisterHandlers(functions);
}
const auto title_id = rp.PopRaw<u64>();
IApplicationManagerInterface::~IApplicationManagerInterface() = default;
const auto size = ctx.GetWriteBufferSize();
void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto flag = rp.PopRaw<u64>();
LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
const FileSys::PatchManager pm{title_id};
const auto control = pm.GetControlMetadata();
const auto title_id = rp.PopRaw<u64>();
std::vector<u8> out;
const auto size = ctx.GetWriteBufferSize();
if (control.first != nullptr) {
if (size < 0x4000) {
LOG_ERROR(Service_NS,
"output buffer is too small! (actual={:016X}, expected_min=0x4000)",
size);
IPC::ResponseBuilder rb{ctx, 2};
// TODO(DarkLordZach): Find a better error code for this.
rb.Push(ResultCode(-1));
return;
}
const FileSys::PatchManager pm{title_id};
const auto control = pm.GetControlMetadata();
out.resize(0x4000);
const auto bytes = control.first->GetRawBytes();
std::memcpy(out.data(), bytes.data(), bytes.size());
} else {
LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
title_id);
out.resize(std::min<u64>(0x4000, size));
std::vector<u8> out;
if (control.first != nullptr) {
if (size < 0x4000) {
LOG_ERROR(Service_NS,
"output buffer is too small! (actual={:016X}, expected_min=0x4000)", size);
IPC::ResponseBuilder rb{ctx, 2};
// TODO(DarkLordZach): Find a better error code for this.
rb.Push(ResultCode(-1));
return;
}
if (control.second != nullptr) {
if (size < 0x4000 + control.second->GetSize()) {
LOG_ERROR(Service_NS,
"output buffer is too small! (actual={:016X}, expected_min={:016X})",
size, 0x4000 + control.second->GetSize());
IPC::ResponseBuilder rb{ctx, 2};
// TODO(DarkLordZach): Find a better error code for this.
rb.Push(ResultCode(-1));
return;
}
out.resize(0x4000);
const auto bytes = control.first->GetRawBytes();
std::memcpy(out.data(), bytes.data(), bytes.size());
} else {
LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
title_id);
out.resize(std::min<u64>(0x4000, size));
}
out.resize(0x4000 + control.second->GetSize());
control.second->Read(out.data() + 0x4000, control.second->GetSize());
} else {
LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
title_id);
if (control.second != nullptr) {
if (size < 0x4000 + control.second->GetSize()) {
LOG_ERROR(Service_NS,
"output buffer is too small! (actual={:016X}, expected_min={:016X})", size,
0x4000 + control.second->GetSize());
IPC::ResponseBuilder rb{ctx, 2};
// TODO(DarkLordZach): Find a better error code for this.
rb.Push(ResultCode(-1));
return;
}
ctx.WriteBuffer(out);
out.resize(0x4000 + control.second->GetSize());
control.second->Read(out.data() + 0x4000, control.second->GetSize());
} else {
LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
title_id);
}
ctx.WriteBuffer(out);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(out.size()));
}
void IApplicationManagerInterface::GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto supported_languages = rp.Pop<u32>();
const auto res = GetApplicationDesiredLanguage(supported_languages);
if (res.Succeeded()) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(out.size()));
rb.Push<u32>(*res);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
}
};
}
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
public:
explicit IApplicationVersionInterface() : ServiceFramework{"IApplicationVersionInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetLaunchRequiredVersion"},
{1, nullptr, "UpgradeLaunchRequiredVersion"},
{35, nullptr, "UpdateVersionList"},
{36, nullptr, "PushLaunchVersion"},
{37, nullptr, "ListRequiredVersion"},
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
{1000, nullptr, "PerformAutoUpdate"},
};
// clang-format on
ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
const u32 supported_languages) {
LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages);
RegisterHandlers(functions);
// Get language code from settings
const auto language_code = Set::GetLanguageCodeFromIndex(Settings::values.language_index);
// Convert to application language, get priority list
const auto application_language = ConvertToApplicationLanguage(language_code);
if (application_language == std::nullopt) {
return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
}
};
class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> {
public:
explicit IContentManagerInterface() : ServiceFramework{"IContentManagerInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{11, nullptr, "CalculateApplicationOccupiedSize"},
{43, nullptr, "CheckSdCardMountStatus"},
{47, nullptr, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{607, nullptr, "IsAnyApplicationRunning"},
};
// clang-format on
RegisterHandlers(functions);
const auto priority_list = GetApplicationLanguagePriorityList(*application_language);
if (!priority_list) {
return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
}
};
class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
public:
explicit IDocumentInterface() : ServiceFramework{"IDocumentInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{21, nullptr, "GetApplicationContentPath"},
{23, nullptr, "ResolveApplicationContentPath"},
{93, nullptr, "GetRunningApplicationProgramId"},
};
// clang-format on
RegisterHandlers(functions);
// Try to find a valid language.
for (const auto lang : *priority_list) {
const auto supported_flag = GetSupportedLanguageFlag(lang);
if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) {
return MakeResult(static_cast<u8>(lang));
}
}
};
class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
public:
explicit IDownloadTaskInterface() : ServiceFramework{"IDownloadTaskInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
{703, nullptr, "RequestEnsureDownloadTask"},
{704, nullptr, "ListDownloadTaskStatus"},
{705, nullptr, "RequestDownloadTaskListData"},
{706, nullptr, "TryCommitCurrentApplicationDownloadTask"},
{707, nullptr, "EnableAutoCommit"},
{708, nullptr, "DisableAutoCommit"},
{709, nullptr, "TriggerDynamicCommitEvent"},
};
// clang-format on
return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
}
RegisterHandlers(functions);
void IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto application_language = rp.Pop<u8>();
const auto res = ConvertApplicationLanguageToLanguageCode(application_language);
if (res.Succeeded()) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(*res);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
}
};
}
class IECommerceInterface final : public ServiceFramework<IECommerceInterface> {
public:
explicit IECommerceInterface() : ServiceFramework{"IECommerceInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestLinkDevice"},
{1, nullptr, "RequestCleanupAllPreInstalledApplications"},
{2, nullptr, "RequestCleanupPreInstalledApplication"},
{3, nullptr, "RequestSyncRights"},
{4, nullptr, "RequestUnlinkDevice"},
{5, nullptr, "RequestRevokeAllELicense"},
};
// clang-format on
RegisterHandlers(functions);
ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
u8 application_language) {
const auto language_code =
ConvertToLanguageCode(static_cast<ApplicationLanguage>(application_language));
if (language_code == std::nullopt) {
return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
}
};
class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> {
public:
explicit IFactoryResetInterface() : ServiceFramework{"IFactoryResetInterface"} {
// clang-format off
return MakeResult(static_cast<u64>(*language_code));
}
IApplicationVersionInterface::IApplicationVersionInterface()
: ServiceFramework{"IApplicationVersionInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetLaunchRequiredVersion"},
{1, nullptr, "UpgradeLaunchRequiredVersion"},
{35, nullptr, "UpdateVersionList"},
{36, nullptr, "PushLaunchVersion"},
{37, nullptr, "ListRequiredVersion"},
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
{1000, nullptr, "PerformAutoUpdate"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationVersionInterface::~IApplicationVersionInterface() = default;
IContentManagerInterface::IContentManagerInterface()
: ServiceFramework{"IContentManagerInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{11, nullptr, "CalculateApplicationOccupiedSize"},
{43, nullptr, "CheckSdCardMountStatus"},
{47, nullptr, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{607, nullptr, "IsAnyApplicationRunning"},
};
// clang-format on
RegisterHandlers(functions);
}
IContentManagerInterface::~IContentManagerInterface() = default;
IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{21, nullptr, "GetApplicationContentPath"},
{23, nullptr, "ResolveApplicationContentPath"},
{93, nullptr, "GetRunningApplicationProgramId"},
};
// clang-format on
RegisterHandlers(functions);
}
IDocumentInterface::~IDocumentInterface() = default;
IDownloadTaskInterface::IDownloadTaskInterface() : ServiceFramework{"IDownloadTaskInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
{703, nullptr, "RequestEnsureDownloadTask"},
{704, nullptr, "ListDownloadTaskStatus"},
{705, nullptr, "RequestDownloadTaskListData"},
{706, nullptr, "TryCommitCurrentApplicationDownloadTask"},
{707, nullptr, "EnableAutoCommit"},
{708, nullptr, "DisableAutoCommit"},
{709, nullptr, "TriggerDynamicCommitEvent"},
};
// clang-format on
RegisterHandlers(functions);
}
IDownloadTaskInterface::~IDownloadTaskInterface() = default;
IECommerceInterface::IECommerceInterface() : ServiceFramework{"IECommerceInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestLinkDevice"},
{1, nullptr, "RequestCleanupAllPreInstalledApplications"},
{2, nullptr, "RequestCleanupPreInstalledApplication"},
{3, nullptr, "RequestSyncRights"},
{4, nullptr, "RequestUnlinkDevice"},
{5, nullptr, "RequestRevokeAllELicense"},
};
// clang-format on
RegisterHandlers(functions);
}
IECommerceInterface::~IECommerceInterface() = default;
IFactoryResetInterface::IFactoryResetInterface::IFactoryResetInterface()
: ServiceFramework{"IFactoryResetInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{100, nullptr, "ResetToFactorySettings"},
{101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
{102, nullptr, "ResetToFactorySettingsForRefurbishment"},
};
// clang-format on
// clang-format on
RegisterHandlers(functions);
}
};
RegisterHandlers(functions);
}
class NS final : public ServiceFramework<NS> {
public:
explicit NS(const char* name) : ServiceFramework{name} {
// clang-format off
static const FunctionInfo functions[] = {
{7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
{7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
{7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
{7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
{7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"},
{7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
{7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"},
{7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
};
// clang-format on
IFactoryResetInterface::~IFactoryResetInterface() = default;
RegisterHandlers(functions);
}
NS::NS(const char* name) : ServiceFramework{name} {
// clang-format off
static const FunctionInfo functions[] = {
{7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
{7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
{7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
{7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
{7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"},
{7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
{7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"},
{7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
};
// clang-format on
private:
template <typename T>
void PushInterface(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NS, "called");
RegisterHandlers(functions);
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<T>();
}
};
NS::~NS() = default;
std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const {
return GetInterface<IApplicationManagerInterface>();
}
class NS_DEV final : public ServiceFramework<NS_DEV> {
public:

View File

@@ -8,6 +8,88 @@
namespace Service::NS {
class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
public:
explicit IAccountProxyInterface();
~IAccountProxyInterface() override;
};
class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
public:
explicit IApplicationManagerInterface();
~IApplicationManagerInterface() override;
ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages);
ResultVal<u64> ConvertApplicationLanguageToLanguageCode(u8 application_language);
private:
void GetApplicationControlData(Kernel::HLERequestContext& ctx);
void GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx);
void ConvertApplicationLanguageToLanguageCode(Kernel::HLERequestContext& ctx);
};
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
public:
explicit IApplicationVersionInterface();
~IApplicationVersionInterface() override;
};
class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> {
public:
explicit IContentManagerInterface();
~IContentManagerInterface() override;
};
class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
public:
explicit IDocumentInterface();
~IDocumentInterface() override;
};
class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
public:
explicit IDownloadTaskInterface();
~IDownloadTaskInterface() override;
};
class IECommerceInterface final : public ServiceFramework<IECommerceInterface> {
public:
explicit IECommerceInterface();
~IECommerceInterface() override;
};
class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> {
public:
explicit IFactoryResetInterface();
~IFactoryResetInterface() override;
};
class NS final : public ServiceFramework<NS> {
public:
explicit NS(const char* name);
~NS() override;
std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const;
private:
template <typename T>
void PushInterface(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<T>();
}
template <typename T>
std::shared_ptr<T> GetInterface() const {
static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>,
"Not a base of ServiceFrameworkBase");
return std::make_shared<T>();
}
};
/// Registers all NS services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);

View File

@@ -0,0 +1,42 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <optional>
#include <string>
#include "common/common_types.h"
#include "core/hle/service/set/set.h"
namespace Service::NS {
/// This is nn::ns::detail::ApplicationLanguage
enum class ApplicationLanguage : u8 {
AmericanEnglish = 0,
BritishEnglish,
Japanese,
French,
German,
LatinAmericanSpanish,
Spanish,
Italian,
Dutch,
CanadianFrench,
Portuguese,
Russian,
Korean,
TraditionalChinese,
SimplifiedChinese,
Count
};
using ApplicationLanguagePriorityList =
const std::array<ApplicationLanguage, static_cast<std::size_t>(ApplicationLanguage::Count)>;
constexpr u32 GetSupportedLanguageFlag(const ApplicationLanguage lang) {
return 1U << static_cast<u32>(lang);
}
const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(ApplicationLanguage lang);
std::optional<ApplicationLanguage> ConvertToApplicationLanguage(
Service::Set::LanguageCode language_code);
std::optional<Service::Set::LanguageCode> ConvertToLanguageCode(ApplicationLanguage lang);
} // namespace Service::NS

View File

@@ -185,7 +185,8 @@ u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& o
IoctlGetGpuTime params{};
std::memcpy(&params, input.data(), input.size());
params.gpu_time = Core::Timing::cyclesToNs(Core::System::GetInstance().CoreTiming().GetTicks());
const auto ns = Core::Timing::CyclesToNs(Core::System::GetInstance().CoreTiming().GetTicks());
params.gpu_time = static_cast<u64_le>(ns.count());
std::memcpy(output.data(), &params, output.size());
return 0;
}

View File

@@ -108,8 +108,9 @@ private:
LOG_DEBUG(Service_Time, "called");
const auto& core_timing = Core::System::GetInstance().CoreTiming();
const SteadyClockTimePoint steady_clock_time_point{
Core::Timing::cyclesToMs(core_timing.GetTicks()) / 1000};
const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000),
{}};
IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(steady_clock_time_point);
@@ -284,8 +285,8 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
}
const auto& core_timing = Core::System::GetInstance().CoreTiming();
const SteadyClockTimePoint steady_clock_time_point{
Core::Timing::cyclesToMs(core_timing.GetTicks()) / 1000, {}};
const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}};
CalendarTime calendar_time{};
calendar_time.year = tm->tm_year + 1900;

View File

@@ -153,17 +153,6 @@ public:
*/
virtual LoadResult Load(Kernel::Process& process) = 0;
/**
* Loads the system mode that this application needs.
* This function defaults to 2 (96MB allocated to the application) if it can't read the
* information.
* @returns A pair with the optional system mode, and and the status.
*/
virtual std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() {
// 96MB allocated to the application.
return std::make_pair(2, ResultStatus::Success);
}
/**
* Get the code (typically .code section) of the application
* @param buffer Reference to buffer to store data

View File

@@ -12,7 +12,6 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/loader/loader.h"
@@ -101,7 +100,30 @@ bool VerifyLogin(const std::string& username, const std::string& token) {
#endif
}
TelemetrySession::TelemetrySession() {
TelemetrySession::TelemetrySession() = default;
TelemetrySession::~TelemetrySession() {
// Log one-time session end information
const s64 shutdown_time{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count()};
AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time);
#ifdef ENABLE_WEB_SERVICE
auto backend = std::make_unique<WebService::TelemetryJson>(
Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
#else
auto backend = std::make_unique<Telemetry::NullVisitor>();
#endif
// Complete the session, submitting to the web service backend if necessary
field_collection.Accept(*backend);
if (Settings::values.enable_telemetry) {
backend->Complete();
}
}
void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
// Log one-time top-level information
AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId());
@@ -112,26 +134,28 @@ TelemetrySession::TelemetrySession() {
AddField(Telemetry::FieldType::Session, "Init_Time", init_time);
u64 program_id{};
const Loader::ResultStatus res{System::GetInstance().GetAppLoader().ReadProgramId(program_id)};
const Loader::ResultStatus res{app_loader.ReadProgramId(program_id)};
if (res == Loader::ResultStatus::Success) {
const std::string formatted_program_id{fmt::format("{:016X}", program_id)};
AddField(Telemetry::FieldType::Session, "ProgramId", formatted_program_id);
std::string name;
System::GetInstance().GetAppLoader().ReadTitle(name);
app_loader.ReadTitle(name);
if (name.empty()) {
auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata();
if (nacp != nullptr)
if (nacp != nullptr) {
name = nacp->GetApplicationName();
}
}
if (!name.empty())
if (!name.empty()) {
AddField(Telemetry::FieldType::Session, "ProgramName", name);
}
}
AddField(Telemetry::FieldType::Session, "ProgramFormat",
static_cast<u8>(System::GetInstance().GetAppLoader().GetFileType()));
static_cast<u8>(app_loader.GetFileType()));
// Log application information
Telemetry::AppendBuildInfo(field_collection);
@@ -162,27 +186,6 @@ TelemetrySession::TelemetrySession() {
Settings::values.use_docked_mode);
}
TelemetrySession::~TelemetrySession() {
// Log one-time session end information
const s64 shutdown_time{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count()};
AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time);
#ifdef ENABLE_WEB_SERVICE
auto backend = std::make_unique<WebService::TelemetryJson>(
Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
#else
auto backend = std::make_unique<Telemetry::NullVisitor>();
#endif
// Complete the session, submitting to web service if necessary
field_collection.Accept(*backend);
if (Settings::values.enable_telemetry)
backend->Complete();
backend = nullptr;
}
bool TelemetrySession::SubmitTestcase() {
#ifdef ENABLE_WEB_SERVICE
auto backend = std::make_unique<WebService::TelemetryJson>(

View File

@@ -4,10 +4,13 @@
#pragma once
#include <memory>
#include <string>
#include "common/telemetry.h"
namespace Loader {
class AppLoader;
}
namespace Core {
/**
@@ -15,11 +18,33 @@ namespace Core {
* session, logging any one-time fields. Interfaces with the telemetry backend used for submitting
* data to the web service. Submits session data on close.
*/
class TelemetrySession : NonCopyable {
class TelemetrySession {
public:
TelemetrySession();
explicit TelemetrySession();
~TelemetrySession();
TelemetrySession(const TelemetrySession&) = delete;
TelemetrySession& operator=(const TelemetrySession&) = delete;
TelemetrySession(TelemetrySession&&) = delete;
TelemetrySession& operator=(TelemetrySession&&) = delete;
/**
* Adds the initial telemetry info necessary when starting up a title.
*
* This includes information such as:
* - Telemetry ID
* - Initialization time
* - Title ID
* - Title name
* - Title file format
* - Miscellaneous settings values.
*
* @param app_loader The application loader to use to retrieve
* title-specific information.
*/
void AddInitialInfo(Loader::AppLoader& app_loader);
/**
* Wrapper around the Telemetry::FieldCollection::AddField method.
* @param type Type of the field to add.

View File

@@ -6,15 +6,8 @@
#include <memory>
#include <vector>
#include "core/frontend/input.h"
#include "input_common/main.h"
union SDL_Event;
namespace Common {
class ParamPackage;
} // namespace Common
namespace InputCommon::Polling {
class DevicePoller;
enum class DeviceType;

View File

@@ -6,7 +6,6 @@
#include <atomic>
#include <cmath>
#include <functional>
#include <iterator>
#include <mutex>
#include <string>
#include <thread>
@@ -15,7 +14,6 @@
#include <utility>
#include <vector>
#include <SDL.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/param_package.h"
@@ -23,12 +21,10 @@
#include "core/frontend/input.h"
#include "input_common/sdl/sdl_impl.h"
namespace InputCommon {
namespace SDL {
namespace InputCommon::SDL {
static std::string GetGUID(SDL_Joystick* joystick) {
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
char guid_str[33];
SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
return guid_str;
@@ -37,26 +33,27 @@ static std::string GetGUID(SDL_Joystick* joystick) {
/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
static int SDLEventWatcher(void* userdata, SDL_Event* event) {
SDLState* sdl_state = reinterpret_cast<SDLState*>(userdata);
static int SDLEventWatcher(void* user_data, SDL_Event* event) {
auto* const sdl_state = static_cast<SDLState*>(user_data);
// Don't handle the event if we are configuring
if (sdl_state->polling) {
sdl_state->event_queue.Push(*event);
} else {
sdl_state->HandleGameControllerEvent(*event);
}
return 0;
}
class SDLJoystick {
public:
SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose)
: guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, deleter} {}
SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick)
: guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {}
void SetButton(int button, bool value) {
std::lock_guard lock{mutex};
state.buttons[button] = value;
state.buttons.insert_or_assign(button, value);
}
bool GetButton(int button) const {
@@ -66,7 +63,7 @@ public:
void SetAxis(int axis, Sint16 value) {
std::lock_guard lock{mutex};
state.axes[axis] = value;
state.axes.insert_or_assign(axis, value);
}
float GetAxis(int axis) const {
@@ -93,7 +90,7 @@ public:
void SetHat(int hat, Uint8 direction) {
std::lock_guard lock{mutex};
state.hats[hat] = direction;
state.hats.insert_or_assign(hat, direction);
}
bool GetHatDirection(int hat, Uint8 direction) const {
@@ -118,10 +115,8 @@ public:
return sdl_joystick.get();
}
void SetSDLJoystick(SDL_Joystick* joystick,
decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) {
sdl_joystick =
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)>(joystick, deleter);
void SetSDLJoystick(SDL_Joystick* joystick) {
sdl_joystick.reset(joystick);
}
private:
@@ -136,59 +131,57 @@ private:
mutable std::mutex mutex;
};
/**
* Get the nth joystick with the corresponding GUID
*/
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
std::lock_guard lock{joystick_map_mutex};
const auto it = joystick_map.find(guid);
if (it != joystick_map.end()) {
while (it->second.size() <= port) {
auto joystick = std::make_shared<SDLJoystick>(guid, it->second.size(), nullptr,
[](SDL_Joystick*) {});
while (it->second.size() <= static_cast<std::size_t>(port)) {
auto joystick =
std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), nullptr);
it->second.emplace_back(std::move(joystick));
}
return it->second[port];
}
auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, [](SDL_Joystick*) {});
auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr);
return joystick_map[guid].emplace_back(std::move(joystick));
}
/**
* Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie
* it to a SDLJoystick with the same guid and that port
*/
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
const std::string guid = GetGUID(sdl_joystick);
std::lock_guard lock{joystick_map_mutex};
auto map_it = joystick_map.find(guid);
const auto map_it = joystick_map.find(guid);
if (map_it != joystick_map.end()) {
auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
[&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
return sdl_joystick == joystick->GetSDLJoystick();
});
const auto vec_it =
std::find_if(map_it->second.begin(), map_it->second.end(),
[&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
return sdl_joystick == joystick->GetSDLJoystick();
});
if (vec_it != map_it->second.end()) {
// This is the common case: There is already an existing SDL_Joystick maped to a
// SDLJoystick. return the SDLJoystick
return *vec_it;
}
// Search for a SDLJoystick without a mapped SDL_Joystick...
auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
[](const std::shared_ptr<SDLJoystick>& joystick) {
return !joystick->GetSDLJoystick();
});
const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
[](const std::shared_ptr<SDLJoystick>& joystick) {
return !joystick->GetSDLJoystick();
});
if (nullptr_it != map_it->second.end()) {
// ... and map it
(*nullptr_it)->SetSDLJoystick(sdl_joystick);
return *nullptr_it;
}
// There is no SDLJoystick without a mapped SDL_Joystick
// Create a new SDLJoystick
auto joystick = std::make_shared<SDLJoystick>(guid, map_it->second.size(), sdl_joystick);
const int port = static_cast<int>(map_it->second.size());
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick);
return map_it->second.emplace_back(std::move(joystick));
}
auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
return joystick_map[guid].emplace_back(std::move(joystick));
}
@@ -215,17 +208,19 @@ void SDLState::InitJoystick(int joystick_index) {
(*it)->SetSDLJoystick(sdl_joystick);
return;
}
auto joystick = std::make_shared<SDLJoystick>(guid, joystick_guid_list.size(), sdl_joystick);
const int port = static_cast<int>(joystick_guid_list.size());
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick);
joystick_guid_list.emplace_back(std::move(joystick));
}
void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
std::string guid = GetGUID(sdl_joystick);
const std::string guid = GetGUID(sdl_joystick);
std::shared_ptr<SDLJoystick> joystick;
{
std::lock_guard lock{joystick_map_mutex};
// This call to guid is safe since the joystick is guaranteed to be in the map
auto& joystick_guid_list = joystick_map[guid];
const auto& joystick_guid_list = joystick_map[guid];
const auto joystick_it =
std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
[&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
@@ -233,9 +228,10 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
});
joystick = *joystick_it;
}
// Destruct SDL_Joystick outside the lock guard because SDL can internally call event calback
// which locks the mutex again
joystick->SetSDLJoystick(nullptr, [](SDL_Joystick*) {});
// Destruct SDL_Joystick outside the lock guard because SDL can internally call the
// event callback which locks the mutex again.
joystick->SetSDLJoystick(nullptr);
}
void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
@@ -317,9 +313,10 @@ public:
trigger_if_greater(trigger_if_greater_) {}
bool GetStatus() const override {
float axis_value = joystick->GetAxis(axis);
if (trigger_if_greater)
const float axis_value = joystick->GetAxis(axis);
if (trigger_if_greater) {
return axis_value > threshold;
}
return axis_value < threshold;
}
@@ -444,7 +441,7 @@ public:
const int port = params.Get("port", 0);
const int axis_x = params.Get("axis_x", 0);
const int axis_y = params.Get("axis_y", 1);
float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
auto joystick = state.GetSDLJoystickByGUID(guid, port);
@@ -470,7 +467,7 @@ SDLState::SDLState() {
return;
}
if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
LOG_ERROR(Input, "Failed to set Hint for background events", SDL_GetError());
LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
}
SDL_AddEventWatch(&SDLEventWatcher, this);
@@ -507,12 +504,12 @@ SDLState::~SDLState() {
}
}
Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
Common::ParamPackage params({{"engine", "sdl"}});
switch (event.type) {
case SDL_JOYAXISMOTION: {
auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
params.Set("axis", event.jaxis.axis);
@@ -526,14 +523,14 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
break;
}
case SDL_JOYBUTTONUP: {
auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
params.Set("button", event.jbutton.button);
break;
}
case SDL_JOYHATMOTION: {
auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
params.Set("hat", event.jhat.hat);
@@ -607,8 +604,8 @@ public:
SDLPoller::Start();
// Reset stored axes
analog_xaxis = -1;
analog_yaxis = -1;
analog_x_axis = -1;
analog_y_axis = -1;
analog_axes_joystick = -1;
}
@@ -620,25 +617,25 @@ public:
}
// An analog device needs two axes, so we need to store the axis for later and wait for
// a second SDL event. The axes also must be from the same joystick.
int axis = event.jaxis.axis;
if (analog_xaxis == -1) {
analog_xaxis = axis;
const int axis = event.jaxis.axis;
if (analog_x_axis == -1) {
analog_x_axis = axis;
analog_axes_joystick = event.jaxis.which;
} else if (analog_yaxis == -1 && analog_xaxis != axis &&
} else if (analog_y_axis == -1 && analog_x_axis != axis &&
analog_axes_joystick == event.jaxis.which) {
analog_yaxis = axis;
analog_y_axis = axis;
}
}
Common::ParamPackage params;
if (analog_xaxis != -1 && analog_yaxis != -1) {
auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
if (analog_x_axis != -1 && analog_y_axis != -1) {
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
params.Set("engine", "sdl");
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
params.Set("axis_x", analog_xaxis);
params.Set("axis_y", analog_yaxis);
analog_xaxis = -1;
analog_yaxis = -1;
params.Set("axis_x", analog_x_axis);
params.Set("axis_y", analog_y_axis);
analog_x_axis = -1;
analog_y_axis = -1;
analog_axes_joystick = -1;
return params;
}
@@ -646,8 +643,8 @@ public:
}
private:
int analog_xaxis = -1;
int analog_yaxis = -1;
int analog_x_axis = -1;
int analog_y_axis = -1;
SDL_JoystickID analog_axes_joystick = -1;
};
} // namespace Polling
@@ -667,5 +664,4 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
return pollers;
}
} // namespace SDL
} // namespace InputCommon
} // namespace InputCommon::SDL

View File

@@ -6,7 +6,10 @@
#include <atomic>
#include <memory>
#include <mutex>
#include <thread>
#include <unordered_map>
#include "common/common_types.h"
#include "common/threadsafe_queue.h"
#include "input_common/sdl/sdl.h"
@@ -16,9 +19,9 @@ using SDL_JoystickID = s32;
namespace InputCommon::SDL {
class SDLJoystick;
class SDLButtonFactory;
class SDLAnalogFactory;
class SDLButtonFactory;
class SDLJoystick;
class SDLState : public State {
public:
@@ -31,7 +34,13 @@ public:
/// Handle SDL_Events for joysticks from SDL_PollEvent
void HandleGameControllerEvent(const SDL_Event& event);
/// Get the nth joystick with the corresponding GUID
std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);
/**
* Check how many identical joysticks (by guid) were connected before the one with sdl_id and so
* tie it to a SDLJoystick with the same guid and that port
*/
std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);
/// Get all DevicePoller that use the SDL backend for a specific device type

View File

@@ -102,6 +102,9 @@ add_library(video_core STATIC
shader/decode/xmad.cpp
shader/decode/other.cpp
shader/decode.cpp
shader/node_helper.cpp
shader/node_helper.h
shader/node.h
shader/shader_ir.cpp
shader/shader_ir.h
shader/track.cpp

View File

@@ -1663,6 +1663,7 @@ private:
INST("111000100100----", Id::BRA, Type::Flow, "BRA"),
INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"),
INST("111000110100---", Id::BRK, Type::Flow, "BRK"),
INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"),
INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"),
INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
INST("1110111101001---", Id::LD_S, Type::Memory, "LD_S"),
@@ -1686,7 +1687,6 @@ private:
INST("1101111100------", Id::TLD4S, Type::Texture, "TLD4S"),
INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"),
INST("1101111101011---", Id::TMML, Type::Texture, "TMML"),
INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"),
INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"),
INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"),

View File

@@ -75,7 +75,7 @@ void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPus
void ThreadManager::SubmitList(Tegra::CommandList&& entries) {
const u64 fence{PushCommand(SubmitListCommand(std::move(entries)))};
const s64 synchronization_ticks{Core::Timing::usToCycles(9000)};
const s64 synchronization_ticks{Core::Timing::usToCycles(std::chrono::microseconds{9000})};
system.CoreTiming().ScheduleEvent(synchronization_ticks, synchronization_event, fence);
}

View File

@@ -2,11 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include <cstddef>
#include <glad/glad.h>
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "video_core/renderer_opengl/gl_device.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
namespace OpenGL {
@@ -24,6 +27,7 @@ Device::Device() {
max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
has_variable_aoffi = TestVariableAoffi();
has_component_indexing_bug = TestComponentIndexingBug();
}
Device::Device(std::nullptr_t) {
@@ -31,6 +35,7 @@ Device::Device(std::nullptr_t) {
max_vertex_attributes = 16;
max_varyings = 15;
has_variable_aoffi = true;
has_component_indexing_bug = false;
}
bool Device::TestVariableAoffi() {
@@ -52,4 +57,53 @@ void main() {
return supported;
}
bool Device::TestComponentIndexingBug() {
constexpr char log_message[] = "Renderer_ComponentIndexingBug: {}";
const GLchar* COMPONENT_TEST = R"(#version 430 core
layout (std430, binding = 0) buffer OutputBuffer {
uint output_value;
};
layout (std140, binding = 0) uniform InputBuffer {
uvec4 input_value[4096];
};
layout (location = 0) uniform uint idx;
void main() {
output_value = input_value[idx >> 2][idx & 3];
})";
const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &COMPONENT_TEST)};
SCOPE_EXIT({ glDeleteProgram(shader); });
glUseProgram(shader);
OGLVertexArray vao;
vao.Create();
glBindVertexArray(vao.handle);
constexpr std::array<GLuint, 8> values{0, 0, 0, 0, 0x1236327, 0x985482, 0x872753, 0x2378432};
OGLBuffer ubo;
ubo.Create();
glNamedBufferData(ubo.handle, sizeof(values), values.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo.handle);
OGLBuffer ssbo;
ssbo.Create();
glNamedBufferStorage(ssbo.handle, sizeof(GLuint), nullptr, GL_CLIENT_STORAGE_BIT);
for (GLuint index = 4; index < 8; ++index) {
glInvalidateBufferData(ssbo.handle);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo.handle);
glProgramUniform1ui(shader, 0, index);
glDrawArrays(GL_POINTS, 0, 1);
GLuint result;
glGetNamedBufferSubData(ssbo.handle, 0, sizeof(result), &result);
if (result != values.at(index)) {
LOG_INFO(Render_OpenGL, log_message, true);
return true;
}
}
LOG_INFO(Render_OpenGL, log_message, false);
return false;
}
} // namespace OpenGL

View File

@@ -30,13 +30,19 @@ public:
return has_variable_aoffi;
}
bool HasComponentIndexingBug() const {
return has_component_indexing_bug;
}
private:
static bool TestVariableAoffi();
static bool TestComponentIndexingBug();
std::size_t uniform_buffer_alignment{};
u32 max_vertex_attributes{};
u32 max_varyings{};
bool has_variable_aoffi{};
bool has_component_indexing_bug{};
};
} // namespace OpenGL

View File

@@ -35,8 +35,8 @@ struct UnspecializedShader {
namespace {
/// Gets the address for the specified shader stage program
GPUVAddr GetShaderAddress(Maxwell::ShaderProgram program) {
const auto& gpu{Core::System::GetInstance().GPU().Maxwell3D()};
GPUVAddr GetShaderAddress(Core::System& system, Maxwell::ShaderProgram program) {
const auto& gpu{system.GPU().Maxwell3D()};
const auto& shader_config{gpu.regs.shader_config[static_cast<std::size_t>(program)]};
return gpu.regs.code_address.CodeAddress() + shader_config.offset;
}
@@ -350,7 +350,8 @@ ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode,
ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
Core::Frontend::EmuWindow& emu_window, const Device& device)
: RasterizerCache{rasterizer}, emu_window{emu_window}, device{device}, disk_cache{system} {}
: RasterizerCache{rasterizer}, system{system}, emu_window{emu_window}, device{device},
disk_cache{system} {}
void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) {
@@ -546,42 +547,45 @@ std::unordered_map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecia
}
Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
if (!Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.shaders) {
return last_shaders[static_cast<u32>(program)];
if (!system.GPU().Maxwell3D().dirty_flags.shaders) {
return last_shaders[static_cast<std::size_t>(program)];
}
auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()};
const GPUVAddr program_addr{GetShaderAddress(program)};
auto& memory_manager{system.GPU().MemoryManager()};
const GPUVAddr program_addr{GetShaderAddress(system, program)};
// Look up shader in the cache based on address
const auto& host_ptr{memory_manager.GetPointer(program_addr)};
const auto host_ptr{memory_manager.GetPointer(program_addr)};
Shader shader{TryGet(host_ptr)};
if (!shader) {
// No shader found - create a new one
ProgramCode program_code{GetShaderCode(memory_manager, program_addr, host_ptr)};
ProgramCode program_code_b;
if (program == Maxwell::ShaderProgram::VertexA) {
const GPUVAddr program_addr_b{GetShaderAddress(Maxwell::ShaderProgram::VertexB)};
program_code_b = GetShaderCode(memory_manager, program_addr_b,
memory_manager.GetPointer(program_addr_b));
}
const u64 unique_identifier = GetUniqueIdentifier(program, program_code, program_code_b);
const VAddr cpu_addr{*memory_manager.GpuToCpuAddress(program_addr)};
const auto found = precompiled_shaders.find(unique_identifier);
if (found != precompiled_shaders.end()) {
shader =
std::make_shared<CachedShader>(cpu_addr, unique_identifier, program, disk_cache,
precompiled_programs, found->second, host_ptr);
} else {
shader = std::make_shared<CachedShader>(
device, cpu_addr, unique_identifier, program, disk_cache, precompiled_programs,
std::move(program_code), std::move(program_code_b), host_ptr);
}
Register(shader);
if (shader) {
return last_shaders[static_cast<std::size_t>(program)] = shader;
}
return last_shaders[static_cast<u32>(program)] = shader;
// No shader found - create a new one
ProgramCode program_code{GetShaderCode(memory_manager, program_addr, host_ptr)};
ProgramCode program_code_b;
if (program == Maxwell::ShaderProgram::VertexA) {
const GPUVAddr program_addr_b{GetShaderAddress(system, Maxwell::ShaderProgram::VertexB)};
program_code_b = GetShaderCode(memory_manager, program_addr_b,
memory_manager.GetPointer(program_addr_b));
}
const u64 unique_identifier = GetUniqueIdentifier(program, program_code, program_code_b);
const VAddr cpu_addr{*memory_manager.GpuToCpuAddress(program_addr)};
const auto found = precompiled_shaders.find(unique_identifier);
if (found != precompiled_shaders.end()) {
// Create a shader from the cache
shader = std::make_shared<CachedShader>(cpu_addr, unique_identifier, program, disk_cache,
precompiled_programs, found->second, host_ptr);
} else {
// Create a shader from guest memory
shader = std::make_shared<CachedShader>(
device, cpu_addr, unique_identifier, program, disk_cache, precompiled_programs,
std::move(program_code), std::move(program_code_b), host_ptr);
}
Register(shader);
return last_shaders[static_cast<std::size_t>(program)] = shader;
}
} // namespace OpenGL

View File

@@ -137,6 +137,7 @@ private:
CachedProgram GeneratePrecompiledProgram(const ShaderDiskCacheDump& dump,
const std::set<GLenum>& supported_formats);
Core::System& system;
Core::Frontend::EmuWindow& emu_window;
const Device& device;
ShaderDiskCacheOpenGL disk_cache;

View File

@@ -45,7 +45,6 @@ struct TextureAoffi {};
using TextureArgument = std::pair<Type, Node>;
using TextureIR = std::variant<TextureAoffi, TextureArgument>;
enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 };
constexpr u32 MAX_CONSTBUFFER_ELEMENTS =
static_cast<u32>(RasterizerOpenGL::MaxConstbufferSize) / (4 * sizeof(float));
@@ -124,8 +123,8 @@ bool IsPrecise(Operation operand) {
return false;
}
bool IsPrecise(Node node) {
if (const auto operation = std::get_if<OperationNode>(node)) {
bool IsPrecise(const Node& node) {
if (const auto operation = std::get_if<OperationNode>(&*node)) {
return IsPrecise(*operation);
}
return false;
@@ -247,6 +246,12 @@ private:
code.AddLine("layout ({}, max_vertices = {}) out;", topology, max_vertices);
code.AddNewLine();
code.AddLine("in gl_PerVertex {{");
++code.scope;
code.AddLine("vec4 gl_Position;");
--code.scope;
code.AddLine("}} gl_in[];");
DeclareVertexRedeclarations();
}
@@ -349,7 +354,7 @@ private:
}
void DeclareInputAttribute(Attribute::Index index, bool skip_unused) {
const u32 generic_index{GetGenericAttributeIndex(index)};
const u32 location{GetGenericAttributeIndex(index)};
std::string name{GetInputAttribute(index)};
if (stage == ShaderStage::Geometry) {
@@ -358,19 +363,13 @@ private:
std::string suffix;
if (stage == ShaderStage::Fragment) {
const auto input_mode{header.ps.GetAttributeUse(generic_index)};
const auto input_mode{header.ps.GetAttributeUse(location)};
if (skip_unused && input_mode == AttributeUse::Unused) {
return;
}
suffix = GetInputFlags(input_mode);
}
u32 location = generic_index;
if (stage != ShaderStage::Vertex) {
// If inputs are varyings, add an offset
location += GENERIC_VARYING_START_LOCATION;
}
code.AddLine("layout (location = {}) {} in vec4 {};", location, suffix, name);
}
@@ -395,7 +394,7 @@ private:
}
void DeclareOutputAttribute(Attribute::Index index) {
const u32 location{GetGenericAttributeIndex(index) + GENERIC_VARYING_START_LOCATION};
const u32 location{GetGenericAttributeIndex(index)};
code.AddLine("layout (location = {}) out vec4 {};", location, GetOutputAttribute(index));
}
@@ -498,15 +497,15 @@ private:
}
void VisitBlock(const NodeBlock& bb) {
for (const Node node : bb) {
for (const auto& node : bb) {
if (const std::string expr = Visit(node); !expr.empty()) {
code.AddLine(expr);
}
}
}
std::string Visit(Node node) {
if (const auto operation = std::get_if<OperationNode>(node)) {
std::string Visit(const Node& node) {
if (const auto operation = std::get_if<OperationNode>(&*node)) {
const auto operation_index = static_cast<std::size_t>(operation->GetCode());
if (operation_index >= operation_decompilers.size()) {
UNREACHABLE_MSG("Out of bounds operation: {}", operation_index);
@@ -520,7 +519,7 @@ private:
return (this->*decompiler)(*operation);
}
if (const auto gpr = std::get_if<GprNode>(node)) {
if (const auto gpr = std::get_if<GprNode>(&*node)) {
const u32 index = gpr->GetIndex();
if (index == Register::ZeroIndex) {
return "0";
@@ -528,7 +527,7 @@ private:
return GetRegister(index);
}
if (const auto immediate = std::get_if<ImmediateNode>(node)) {
if (const auto immediate = std::get_if<ImmediateNode>(&*node)) {
const u32 value = immediate->GetValue();
if (value < 10) {
// For eyecandy avoid using hex numbers on single digits
@@ -537,7 +536,7 @@ private:
return fmt::format("utof(0x{:x}u)", immediate->GetValue());
}
if (const auto predicate = std::get_if<PredicateNode>(node)) {
if (const auto predicate = std::get_if<PredicateNode>(&*node)) {
const auto value = [&]() -> std::string {
switch (const auto index = predicate->GetIndex(); index) {
case Tegra::Shader::Pred::UnusedIndex:
@@ -554,7 +553,7 @@ private:
return value;
}
if (const auto abuf = std::get_if<AbufNode>(node)) {
if (const auto abuf = std::get_if<AbufNode>(&*node)) {
UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry,
"Physical attributes in geometry shaders are not implemented");
if (abuf->IsPhysicalBuffer()) {
@@ -564,9 +563,9 @@ private:
return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer());
}
if (const auto cbuf = std::get_if<CbufNode>(node)) {
if (const auto cbuf = std::get_if<CbufNode>(&*node)) {
const Node offset = cbuf->GetOffset();
if (const auto immediate = std::get_if<ImmediateNode>(offset)) {
if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) {
// Direct access
const u32 offset_imm = immediate->GetValue();
ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access");
@@ -577,30 +576,47 @@ private:
if (std::holds_alternative<OperationNode>(*offset)) {
// Indirect access
const std::string final_offset = code.GenerateTemporary();
code.AddLine("uint {} = (ftou({}) / 4);", final_offset, Visit(offset));
return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()),
final_offset, final_offset);
code.AddLine("uint {} = ftou({}) >> 2;", final_offset, Visit(offset));
if (!device.HasComponentIndexingBug()) {
return fmt::format("{}[{} >> 2][{} & 3]", GetConstBuffer(cbuf->GetIndex()),
final_offset, final_offset);
}
// AMD's proprietary GLSL compiler emits ill code for variable component access.
// To bypass this driver bug generate 4 ifs, one per each component.
const std::string pack = code.GenerateTemporary();
code.AddLine("vec4 {} = {}[{} >> 2];", pack, GetConstBuffer(cbuf->GetIndex()),
final_offset);
const std::string result = code.GenerateTemporary();
code.AddLine("float {};", result);
for (u32 swizzle = 0; swizzle < 4; ++swizzle) {
code.AddLine("if (({} & 3) == {}) {} = {}{};", final_offset, swizzle, result,
pack, GetSwizzle(swizzle));
}
return result;
}
UNREACHABLE_MSG("Unmanaged offset node type");
}
if (const auto gmem = std::get_if<GmemNode>(node)) {
if (const auto gmem = std::get_if<GmemNode>(&*node)) {
const std::string real = Visit(gmem->GetRealAddress());
const std::string base = Visit(gmem->GetBaseAddress());
const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base);
return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset);
}
if (const auto lmem = std::get_if<LmemNode>(node)) {
if (const auto lmem = std::get_if<LmemNode>(&*node)) {
return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress()));
}
if (const auto internal_flag = std::get_if<InternalFlagNode>(node)) {
if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) {
return GetInternalFlag(internal_flag->GetFlag());
}
if (const auto conditional = std::get_if<ConditionalNode>(node)) {
if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
// It's invalid to call conditional on nested nodes, use an operation instead
code.AddLine("if ({}) {{", Visit(conditional->GetCondition()));
++code.scope;
@@ -612,7 +628,7 @@ private:
return {};
}
if (const auto comment = std::get_if<CommentNode>(node)) {
if (const auto comment = std::get_if<CommentNode>(&*node)) {
return "// " + comment->GetText();
}
@@ -620,7 +636,7 @@ private:
return {};
}
std::string ReadAttribute(Attribute::Index attribute, u32 element, Node buffer = {}) {
std::string ReadAttribute(Attribute::Index attribute, u32 element, const Node& buffer = {}) {
const auto GeometryPass = [&](std::string_view name) {
if (stage == ShaderStage::Geometry && buffer) {
// TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games
@@ -633,10 +649,14 @@ private:
switch (attribute) {
case Attribute::Index::Position:
if (stage != ShaderStage::Fragment) {
return GeometryPass("position") + GetSwizzle(element);
} else {
switch (stage) {
case ShaderStage::Geometry:
return fmt::format("gl_in[ftou({})].gl_Position{}", Visit(buffer),
GetSwizzle(element));
case ShaderStage::Fragment:
return element == 3 ? "1.0f" : ("gl_FragCoord"s + GetSwizzle(element));
default:
UNREACHABLE();
}
case Attribute::Index::PointCoord:
switch (element) {
@@ -852,7 +872,7 @@ private:
std::string expr = ", ";
switch (type) {
case Type::Int:
if (const auto immediate = std::get_if<ImmediateNode>(operand)) {
if (const auto immediate = std::get_if<ImmediateNode>(&*operand)) {
// Inline the string as an immediate integer in GLSL (some extra arguments are
// required to be constant)
expr += std::to_string(static_cast<s32>(immediate->GetValue()));
@@ -884,7 +904,7 @@ private:
for (std::size_t index = 0; index < aoffi.size(); ++index) {
const auto operand{aoffi.at(index)};
if (const auto immediate = std::get_if<ImmediateNode>(operand)) {
if (const auto immediate = std::get_if<ImmediateNode>(&*operand)) {
// Inline the string as an immediate integer in GLSL (AOFFI arguments are required
// to be constant by the standard).
expr += std::to_string(static_cast<s32>(immediate->GetValue()));
@@ -905,23 +925,23 @@ private:
}
std::string Assign(Operation operation) {
const Node dest = operation[0];
const Node src = operation[1];
const Node& dest = operation[0];
const Node& src = operation[1];
std::string target;
if (const auto gpr = std::get_if<GprNode>(dest)) {
if (const auto gpr = std::get_if<GprNode>(&*dest)) {
if (gpr->GetIndex() == Register::ZeroIndex) {
// Writing to Register::ZeroIndex is a no op
return {};
}
target = GetRegister(gpr->GetIndex());
} else if (const auto abuf = std::get_if<AbufNode>(dest)) {
} else if (const auto abuf = std::get_if<AbufNode>(&*dest)) {
UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer());
target = [&]() -> std::string {
switch (const auto attribute = abuf->GetIndex(); abuf->GetIndex()) {
case Attribute::Index::Position:
return "position"s + GetSwizzle(abuf->GetElement());
return "gl_Position"s + GetSwizzle(abuf->GetElement());
case Attribute::Index::PointSize:
return "gl_PointSize";
case Attribute::Index::ClipDistances0123:
@@ -937,9 +957,9 @@ private:
return "0";
}
}();
} else if (const auto lmem = std::get_if<LmemNode>(dest)) {
} else if (const auto lmem = std::get_if<LmemNode>(&*dest)) {
target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress()));
} else if (const auto gmem = std::get_if<GmemNode>(dest)) {
} else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
const std::string real = Visit(gmem->GetRealAddress());
const std::string base = Visit(gmem->GetBaseAddress());
const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base);
@@ -1216,12 +1236,12 @@ private:
}
std::string LogicalAssign(Operation operation) {
const Node dest = operation[0];
const Node src = operation[1];
const Node& dest = operation[0];
const Node& src = operation[1];
std::string target;
if (const auto pred = std::get_if<PredicateNode>(dest)) {
if (const auto pred = std::get_if<PredicateNode>(&*dest)) {
ASSERT_MSG(!pred->IsNegated(), "Negating logical assignment");
const auto index = pred->GetIndex();
@@ -1232,7 +1252,7 @@ private:
return {};
}
target = GetPredicate(index);
} else if (const auto flag = std::get_if<InternalFlagNode>(dest)) {
} else if (const auto flag = std::get_if<InternalFlagNode>(&*dest)) {
target = GetInternalFlag(flag->GetFlag());
}
@@ -1409,7 +1429,7 @@ private:
}
std::string Branch(Operation operation) {
const auto target = std::get_if<ImmediateNode>(operation[0]);
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
UNIMPLEMENTED_IF(!target);
code.AddLine("jmp_to = 0x{:x}u;", target->GetValue());
@@ -1418,7 +1438,7 @@ private:
}
std::string PushFlowStack(Operation operation) {
const auto target = std::get_if<ImmediateNode>(operation[0]);
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
UNIMPLEMENTED_IF(!target);
code.AddLine("flow_stack[flow_stack_top++] = 0x{:x}u;", target->GetValue());
@@ -1506,9 +1526,7 @@ private:
// If a geometry shader is attached, it will always flip (it's the last stage before
// fragment). For more info about flipping, refer to gl_shader_gen.cpp.
code.AddLine("position.xy *= viewport_flip.xy;");
code.AddLine("gl_Position = position;");
code.AddLine("position.w = 1.0;");
code.AddLine("gl_Position.xy *= viewport_flip.xy;");
code.AddLine("EmitVertex();");
return {};
}
@@ -1746,8 +1764,7 @@ private:
}
u32 GetNumPhysicalVaryings() const {
return std::min<u32>(device.GetMaxVaryings() - GENERIC_VARYING_START_LOCATION,
Maxwell::NumVaryings);
return std::min<u32>(device.GetMaxVaryings(), Maxwell::NumVaryings);
}
const Device& device;

View File

@@ -23,8 +23,6 @@ ProgramResult GenerateVertexShader(const Device& device, const ShaderSetup& setu
out += GetCommonDeclarations();
out += R"(
layout (location = 0) out vec4 position;
layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config {
vec4 viewport_flip;
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
@@ -48,7 +46,6 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config {
out += R"(
void main() {
position = vec4(0.0, 0.0, 0.0, 0.0);
execute_vertex();
)";
@@ -59,19 +56,12 @@ void main() {
out += R"(
// Set Position Y direction
position.y *= utof(config_pack[2]);
gl_Position.y *= utof(config_pack[2]);
// Check if the flip stage is VertexB
// Config pack's second value is flip_stage
if (config_pack[1] == 1) {
// Viewport can be flipped, which is unsupported by glViewport
position.xy *= viewport_flip.xy;
}
gl_Position = position;
// TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0
// For now, this is here to bring order in lieu of proper emulation
if (config_pack[1] == 1) {
position.w = 1.0;
gl_Position.xy *= viewport_flip.xy;
}
})";
@@ -85,9 +75,6 @@ ProgramResult GenerateGeometryShader(const Device& device, const ShaderSetup& se
out += GetCommonDeclarations();
out += R"(
layout (location = 0) in vec4 gs_position[];
layout (location = 0) out vec4 position;
layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config {
vec4 viewport_flip;
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
@@ -124,8 +111,6 @@ layout (location = 5) out vec4 FragColor5;
layout (location = 6) out vec4 FragColor6;
layout (location = 7) out vec4 FragColor7;
layout (location = 0) in noperspective vec4 position;
layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config {
vec4 viewport_flip;
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding

View File

@@ -18,6 +18,7 @@ constexpr std::array<vk::Format, 3> Depth24UnormS8Uint = {
vk::Format::eD32SfloatS8Uint, vk::Format::eD16UnormS8Uint, {}};
constexpr std::array<vk::Format, 3> Depth16UnormS8Uint = {
vk::Format::eD24UnormS8Uint, vk::Format::eD32SfloatS8Uint, {}};
constexpr std::array<vk::Format, 2> Astc = {vk::Format::eA8B8G8R8UnormPack32, {}};
} // namespace Alternatives
@@ -51,15 +52,19 @@ VKDevice::VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice phy
: physical{physical}, format_properties{GetFormatProperties(dldi, physical)} {
SetupFamilies(dldi, surface);
SetupProperties(dldi);
SetupFeatures(dldi);
}
VKDevice::~VKDevice() = default;
bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance) {
const auto queue_cis = GetDeviceQueueCreateInfos();
vk::PhysicalDeviceFeatures device_features{};
vk::PhysicalDeviceFeatures device_features;
device_features.vertexPipelineStoresAndAtomics = true;
device_features.independentBlend = true;
device_features.textureCompressionASTC_LDR = is_optimal_astc_supported;
const std::vector<const char*> extensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
const auto queue_cis = GetDeviceQueueCreateInfos();
const std::vector<const char*> extensions = LoadExtensions(dldi);
const vk::DeviceCreateInfo device_ci({}, static_cast<u32>(queue_cis.size()), queue_cis.data(),
0, nullptr, static_cast<u32>(extensions.size()),
extensions.data(), &device_features);
@@ -90,7 +95,7 @@ vk::Format VKDevice::GetSupportedFormat(vk::Format wanted_format,
LOG_CRITICAL(Render_Vulkan,
"Format={} with usage={} and type={} has no defined alternatives and host "
"hardware does not support it",
static_cast<u32>(wanted_format), static_cast<u32>(wanted_usage),
vk::to_string(wanted_format), vk::to_string(wanted_usage),
static_cast<u32>(format_type));
UNREACHABLE();
return wanted_format;
@@ -118,6 +123,30 @@ vk::Format VKDevice::GetSupportedFormat(vk::Format wanted_format,
return wanted_format;
}
bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features,
const vk::DispatchLoaderDynamic& dldi) const {
if (!features.textureCompressionASTC_LDR) {
return false;
}
const auto format_feature_usage{
vk::FormatFeatureFlagBits::eSampledImage | vk::FormatFeatureFlagBits::eBlitSrc |
vk::FormatFeatureFlagBits::eBlitDst | vk::FormatFeatureFlagBits::eTransferSrc |
vk::FormatFeatureFlagBits::eTransferDst};
constexpr std::array<vk::Format, 9> astc_formats = {
vk::Format::eAstc4x4UnormBlock, vk::Format::eAstc4x4SrgbBlock,
vk::Format::eAstc8x8SrgbBlock, vk::Format::eAstc8x6SrgbBlock,
vk::Format::eAstc5x4SrgbBlock, vk::Format::eAstc5x5UnormBlock,
vk::Format::eAstc5x5SrgbBlock, vk::Format::eAstc10x8UnormBlock,
vk::Format::eAstc10x8SrgbBlock};
for (const auto format : astc_formats) {
const auto format_properties{physical.getFormatProperties(format, dldi)};
if (!(format_properties.optimalTilingFeatures & format_feature_usage)) {
return false;
}
}
return true;
}
bool VKDevice::IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage,
FormatType format_type) const {
const auto it = format_properties.find(wanted_format);
@@ -132,11 +161,9 @@ bool VKDevice::IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlag
bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical,
vk::SurfaceKHR surface) {
const std::string swapchain_extension = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
bool has_swapchain{};
for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) {
has_swapchain |= prop.extensionName == swapchain_extension;
has_swapchain |= prop.extensionName == std::string(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}
if (!has_swapchain) {
// The device doesn't support creating swapchains.
@@ -160,8 +187,14 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev
}
// TODO(Rodrigo): Check if the device matches all requeriments.
const vk::PhysicalDeviceProperties props = physical.getProperties(dldi);
if (props.limits.maxUniformBufferRange < 65536) {
const auto properties{physical.getProperties(dldi)};
const auto limits{properties.limits};
if (limits.maxUniformBufferRange < 65536) {
return false;
}
const vk::PhysicalDeviceFeatures features{physical.getFeatures(dldi)};
if (!features.vertexPipelineStoresAndAtomics || !features.independentBlend) {
return false;
}
@@ -169,6 +202,30 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev
return true;
}
std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynamic& dldi) {
std::vector<const char*> extensions;
extensions.reserve(2);
extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
const auto Test = [&](const vk::ExtensionProperties& extension,
std::optional<std::reference_wrapper<bool>> status, const char* name,
u32 revision) {
if (extension.extensionName != std::string(name)) {
return;
}
extensions.push_back(name);
if (status) {
status->get() = true;
}
};
for (const auto& extension : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) {
Test(extension, ext_scalar_block_layout, VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, 1);
}
return extensions;
}
void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceKHR surface) {
std::optional<u32> graphics_family_, present_family_;
@@ -196,10 +253,16 @@ void VKDevice::SetupProperties(const vk::DispatchLoaderDynamic& dldi) {
const vk::PhysicalDeviceProperties props = physical.getProperties(dldi);
device_type = props.deviceType;
uniform_buffer_alignment = static_cast<u64>(props.limits.minUniformBufferOffsetAlignment);
max_storage_buffer_range = static_cast<u64>(props.limits.maxStorageBufferRange);
}
void VKDevice::SetupFeatures(const vk::DispatchLoaderDynamic& dldi) {
const auto supported_features{physical.getFeatures(dldi)};
is_optimal_astc_supported = IsOptimalAstcSupported(supported_features, dldi);
}
std::vector<vk::DeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const {
static const float QUEUE_PRIORITY = 1.f;
static const float QUEUE_PRIORITY = 1.0f;
std::set<u32> unique_queue_families = {graphics_family, present_family};
std::vector<vk::DeviceQueueCreateInfo> queue_cis;
@@ -212,26 +275,43 @@ std::vector<vk::DeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() con
std::map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperties(
const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical) {
static constexpr std::array formats{vk::Format::eA8B8G8R8UnormPack32,
vk::Format::eB5G6R5UnormPack16,
vk::Format::eA2B10G10R10UnormPack32,
vk::Format::eR32G32B32A32Sfloat,
vk::Format::eR16G16Unorm,
vk::Format::eR16G16Snorm,
vk::Format::eR8G8B8A8Srgb,
vk::Format::eR8Unorm,
vk::Format::eB10G11R11UfloatPack32,
vk::Format::eR32Sfloat,
vk::Format::eR16Sfloat,
vk::Format::eR16G16B16A16Sfloat,
vk::Format::eD32Sfloat,
vk::Format::eD16Unorm,
vk::Format::eD16UnormS8Uint,
vk::Format::eD24UnormS8Uint,
vk::Format::eD32SfloatS8Uint,
vk::Format::eBc1RgbaUnormBlock,
vk::Format::eBc2UnormBlock,
vk::Format::eBc3UnormBlock,
vk::Format::eBc4UnormBlock,
vk::Format::eBc5UnormBlock,
vk::Format::eBc5SnormBlock,
vk::Format::eBc7UnormBlock,
vk::Format::eAstc4x4UnormBlock,
vk::Format::eAstc4x4SrgbBlock,
vk::Format::eAstc8x8SrgbBlock,
vk::Format::eAstc8x6SrgbBlock,
vk::Format::eAstc5x4SrgbBlock,
vk::Format::eAstc5x5UnormBlock,
vk::Format::eAstc5x5SrgbBlock,
vk::Format::eAstc10x8UnormBlock,
vk::Format::eAstc10x8SrgbBlock};
std::map<vk::Format, vk::FormatProperties> format_properties;
const auto AddFormatQuery = [&format_properties, &dldi, physical](vk::Format format) {
for (const auto format : formats) {
format_properties.emplace(format, physical.getFormatProperties(format, dldi));
};
AddFormatQuery(vk::Format::eA8B8G8R8UnormPack32);
AddFormatQuery(vk::Format::eB5G6R5UnormPack16);
AddFormatQuery(vk::Format::eA2B10G10R10UnormPack32);
AddFormatQuery(vk::Format::eR8G8B8A8Srgb);
AddFormatQuery(vk::Format::eR8Unorm);
AddFormatQuery(vk::Format::eD32Sfloat);
AddFormatQuery(vk::Format::eD16Unorm);
AddFormatQuery(vk::Format::eD16UnormS8Uint);
AddFormatQuery(vk::Format::eD24UnormS8Uint);
AddFormatQuery(vk::Format::eD32SfloatS8Uint);
AddFormatQuery(vk::Format::eBc1RgbaUnormBlock);
AddFormatQuery(vk::Format::eBc2UnormBlock);
AddFormatQuery(vk::Format::eBc3UnormBlock);
AddFormatQuery(vk::Format::eBc4UnormBlock);
}
return format_properties;
}

View File

@@ -11,7 +11,7 @@
namespace Vulkan {
/// Format usage descriptor
/// Format usage descriptor.
enum class FormatType { Linear, Optimal, Buffer };
/// Handles data specific to a physical device.
@@ -34,12 +34,12 @@ public:
vk::Format GetSupportedFormat(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage,
FormatType format_type) const;
/// Returns the dispatch loader with direct function pointers of the device
/// Returns the dispatch loader with direct function pointers of the device.
const vk::DispatchLoaderDynamic& GetDispatchLoader() const {
return dld;
}
/// Returns the logical device
/// Returns the logical device.
vk::Device GetLogical() const {
return logical.get();
}
@@ -69,30 +69,55 @@ public:
return present_family;
}
/// Returns if the device is integrated with the host CPU
/// Returns if the device is integrated with the host CPU.
bool IsIntegrated() const {
return device_type == vk::PhysicalDeviceType::eIntegratedGpu;
}
/// Returns uniform buffer alignment requeriment
/// Returns uniform buffer alignment requeriment.
u64 GetUniformBufferAlignment() const {
return uniform_buffer_alignment;
}
/// Returns the maximum range for storage buffers.
u64 GetMaxStorageBufferRange() const {
return max_storage_buffer_range;
}
/// Returns true if ASTC is natively supported.
bool IsOptimalAstcSupported() const {
return is_optimal_astc_supported;
}
/// Returns true if the device supports VK_EXT_scalar_block_layout.
bool IsExtScalarBlockLayoutSupported() const {
return ext_scalar_block_layout;
}
/// Checks if the physical device is suitable.
static bool IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical,
vk::SurfaceKHR surface);
private:
/// Loads extensions into a vector and stores available ones in this object.
std::vector<const char*> LoadExtensions(const vk::DispatchLoaderDynamic& dldi);
/// Sets up queue families.
void SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceKHR surface);
/// Sets up device properties.
void SetupProperties(const vk::DispatchLoaderDynamic& dldi);
/// Sets up device features.
void SetupFeatures(const vk::DispatchLoaderDynamic& dldi);
/// Returns a list of queue initialization descriptors.
std::vector<vk::DeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const;
/// Returns true if ASTC textures are natively supported.
bool IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features,
const vk::DispatchLoaderDynamic& dldi) const;
/// Returns true if a format is supported.
bool IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage,
FormatType format_type) const;
@@ -101,16 +126,19 @@ private:
static std::map<vk::Format, vk::FormatProperties> GetFormatProperties(
const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical);
const vk::PhysicalDevice physical; ///< Physical device
vk::DispatchLoaderDynamic dld; ///< Device function pointers
UniqueDevice logical; ///< Logical device
vk::Queue graphics_queue; ///< Main graphics queue
vk::Queue present_queue; ///< Main present queue
u32 graphics_family{}; ///< Main graphics queue family index
u32 present_family{}; ///< Main present queue family index
vk::PhysicalDeviceType device_type; ///< Physical device type
u64 uniform_buffer_alignment{}; ///< Uniform buffer alignment requeriment
std::map<vk::Format, vk::FormatProperties> format_properties; ///< Format properties dictionary
const vk::PhysicalDevice physical; ///< Physical device.
vk::DispatchLoaderDynamic dld; ///< Device function pointers.
UniqueDevice logical; ///< Logical device.
vk::Queue graphics_queue; ///< Main graphics queue.
vk::Queue present_queue; ///< Main present queue.
u32 graphics_family{}; ///< Main graphics queue family index.
u32 present_family{}; ///< Main present queue family index.
vk::PhysicalDeviceType device_type; ///< Physical device type.
u64 uniform_buffer_alignment{}; ///< Uniform buffer alignment requeriment.
u64 max_storage_buffer_range{}; ///< Max storage buffer size.
bool is_optimal_astc_supported{}; ///< Support for native ASTC.
bool ext_scalar_block_layout{}; ///< Support for VK_EXT_scalar_block_layout.
std::map<vk::Format, vk::FormatProperties> format_properties; ///< Format properties dictionary.
};
} // namespace Vulkan

View File

@@ -17,6 +17,7 @@
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/engines/shader_header.h"
#include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
#include "video_core/shader/shader_ir.h"
@@ -33,7 +34,8 @@ using ShaderStage = Tegra::Engines::Maxwell3D::Regs::ShaderStage;
using Operation = const OperationNode&;
// TODO(Rodrigo): Use rasterizer's value
constexpr u32 MAX_CONSTBUFFER_ELEMENTS = 0x1000;
constexpr u32 MAX_CONSTBUFFER_FLOATS = 0x4000;
constexpr u32 MAX_CONSTBUFFER_ELEMENTS = MAX_CONSTBUFFER_FLOATS / 4;
constexpr u32 STAGE_BINDING_STRIDE = 0x100;
enum class Type { Bool, Bool2, Float, Int, Uint, HalfFloat };
@@ -87,8 +89,8 @@ bool IsPrecise(Operation operand) {
class SPIRVDecompiler : public Sirit::Module {
public:
explicit SPIRVDecompiler(const ShaderIR& ir, ShaderStage stage)
: Module(0x00010300), ir{ir}, stage{stage}, header{ir.GetHeader()} {
explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderStage stage)
: Module(0x00010300), device{device}, ir{ir}, stage{stage}, header{ir.GetHeader()} {
AddCapability(spv::Capability::Shader);
AddExtension("SPV_KHR_storage_buffer_storage_class");
AddExtension("SPV_KHR_variable_pointers");
@@ -195,7 +197,9 @@ public:
entries.samplers.emplace_back(sampler);
}
for (const auto& attribute : ir.GetInputAttributes()) {
entries.attributes.insert(GetGenericAttributeLocation(attribute));
if (IsGenericAttribute(attribute)) {
entries.attributes.insert(GetGenericAttributeLocation(attribute));
}
}
entries.clip_distances = ir.GetClipDistances();
entries.shader_length = ir.GetLength();
@@ -210,7 +214,6 @@ private:
std::array<OperationDecompilerFn, static_cast<std::size_t>(OperationCode::Amount)>;
static constexpr auto INTERNAL_FLAGS_COUNT = static_cast<std::size_t>(InternalFlag::Amount);
static constexpr u32 CBUF_STRIDE = 16;
void AllocateBindings() {
const u32 binding_base = static_cast<u32>(stage) * STAGE_BINDING_STRIDE;
@@ -315,6 +318,7 @@ private:
constexpr std::array<const char*, INTERNAL_FLAGS_COUNT> names = {"zero", "sign", "carry",
"overflow"};
for (std::size_t flag = 0; flag < INTERNAL_FLAGS_COUNT; ++flag) {
const auto flag_code = static_cast<InternalFlag>(flag);
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
internal_flags[flag] = AddGlobalVariable(Name(id, names[flag]));
}
@@ -374,7 +378,9 @@ private:
u32 binding = const_buffers_base_binding;
for (const auto& entry : ir.GetConstantBuffers()) {
const auto [index, size] = entry;
const Id id = OpVariable(t_cbuf_ubo, spv::StorageClass::Uniform);
const Id type =
device.IsExtScalarBlockLayoutSupported() ? t_cbuf_scalar_ubo : t_cbuf_std140_ubo;
const Id id = OpVariable(type, spv::StorageClass::Uniform);
AddGlobalVariable(Name(id, fmt::format("cbuf_{}", index)));
Decorate(id, spv::Decoration::Binding, binding++);
@@ -475,13 +481,13 @@ private:
}
void VisitBasicBlock(const NodeBlock& bb) {
for (const Node node : bb) {
for (const auto& node : bb) {
static_cast<void>(Visit(node));
}
}
Id Visit(Node node) {
if (const auto operation = std::get_if<OperationNode>(node)) {
Id Visit(const Node& node) {
if (const auto operation = std::get_if<OperationNode>(&*node)) {
const auto operation_index = static_cast<std::size_t>(operation->GetCode());
const auto decompiler = operation_decompilers[operation_index];
if (decompiler == nullptr) {
@@ -489,17 +495,17 @@ private:
}
return (this->*decompiler)(*operation);
} else if (const auto gpr = std::get_if<GprNode>(node)) {
} else if (const auto gpr = std::get_if<GprNode>(&*node)) {
const u32 index = gpr->GetIndex();
if (index == Register::ZeroIndex) {
return Constant(t_float, 0.0f);
}
return Emit(OpLoad(t_float, registers.at(index)));
} else if (const auto immediate = std::get_if<ImmediateNode>(node)) {
} else if (const auto immediate = std::get_if<ImmediateNode>(&*node)) {
return BitcastTo<Type::Float>(Constant(t_uint, immediate->GetValue()));
} else if (const auto predicate = std::get_if<PredicateNode>(node)) {
} else if (const auto predicate = std::get_if<PredicateNode>(&*node)) {
const auto value = [&]() -> Id {
switch (const auto index = predicate->GetIndex(); index) {
case Tegra::Shader::Pred::UnusedIndex:
@@ -515,7 +521,7 @@ private:
}
return value;
} else if (const auto abuf = std::get_if<AbufNode>(node)) {
} else if (const auto abuf = std::get_if<AbufNode>(&*node)) {
const auto attribute = abuf->GetIndex();
const auto element = abuf->GetElement();
@@ -565,40 +571,42 @@ private:
}
UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute));
} else if (const auto cbuf = std::get_if<CbufNode>(node)) {
const Node offset = cbuf->GetOffset();
} else if (const auto cbuf = std::get_if<CbufNode>(&*node)) {
const Node& offset = cbuf->GetOffset();
const Id buffer_id = constant_buffers.at(cbuf->GetIndex());
Id buffer_index{};
Id buffer_element{};
if (const auto immediate = std::get_if<ImmediateNode>(offset)) {
// Direct access
const u32 offset_imm = immediate->GetValue();
ASSERT(offset_imm % 4 == 0);
buffer_index = Constant(t_uint, offset_imm / 16);
buffer_element = Constant(t_uint, (offset_imm / 4) % 4);
} else if (std::holds_alternative<OperationNode>(*offset)) {
// Indirect access
// TODO(Rodrigo): Use a uniform buffer stride of 4 and drop this slow math (which
// emits sub-optimal code on GLSL from my testing).
const Id offset_id = BitcastTo<Type::Uint>(Visit(offset));
const Id unsafe_offset = Emit(OpUDiv(t_uint, offset_id, Constant(t_uint, 4)));
const Id final_offset = Emit(
OpUMod(t_uint, unsafe_offset, Constant(t_uint, MAX_CONSTBUFFER_ELEMENTS - 1)));
buffer_index = Emit(OpUDiv(t_uint, final_offset, Constant(t_uint, 4)));
buffer_element = Emit(OpUMod(t_uint, final_offset, Constant(t_uint, 4)));
Id pointer{};
if (device.IsExtScalarBlockLayoutSupported()) {
const Id buffer_offset = Emit(OpShiftRightLogical(
t_uint, BitcastTo<Type::Uint>(Visit(offset)), Constant(t_uint, 2u)));
pointer = Emit(
OpAccessChain(t_cbuf_float, buffer_id, Constant(t_uint, 0u), buffer_offset));
} else {
UNREACHABLE_MSG("Unmanaged offset node type");
Id buffer_index{};
Id buffer_element{};
if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) {
// Direct access
const u32 offset_imm = immediate->GetValue();
ASSERT(offset_imm % 4 == 0);
buffer_index = Constant(t_uint, offset_imm / 16);
buffer_element = Constant(t_uint, (offset_imm / 4) % 4);
} else if (std::holds_alternative<OperationNode>(*offset)) {
// Indirect access
const Id offset_id = BitcastTo<Type::Uint>(Visit(offset));
const Id unsafe_offset = Emit(OpUDiv(t_uint, offset_id, Constant(t_uint, 4)));
const Id final_offset = Emit(OpUMod(
t_uint, unsafe_offset, Constant(t_uint, MAX_CONSTBUFFER_ELEMENTS - 1)));
buffer_index = Emit(OpUDiv(t_uint, final_offset, Constant(t_uint, 4)));
buffer_element = Emit(OpUMod(t_uint, final_offset, Constant(t_uint, 4)));
} else {
UNREACHABLE_MSG("Unmanaged offset node type");
}
pointer = Emit(OpAccessChain(t_cbuf_float, buffer_id, Constant(t_uint, 0),
buffer_index, buffer_element));
}
const Id pointer = Emit(OpAccessChain(t_cbuf_float, buffer_id, Constant(t_uint, 0),
buffer_index, buffer_element));
return Emit(OpLoad(t_float, pointer));
} else if (const auto gmem = std::get_if<GmemNode>(node)) {
} else if (const auto gmem = std::get_if<GmemNode>(&*node)) {
const Id gmem_buffer = global_buffers.at(gmem->GetDescriptor());
const Id real = BitcastTo<Type::Uint>(Visit(gmem->GetRealAddress()));
const Id base = BitcastTo<Type::Uint>(Visit(gmem->GetBaseAddress()));
@@ -608,11 +616,13 @@ private:
return Emit(OpLoad(t_float, Emit(OpAccessChain(t_gmem_float, gmem_buffer,
Constant(t_uint, 0u), offset))));
} else if (const auto conditional = std::get_if<ConditionalNode>(node)) {
} else if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
// It's invalid to call conditional on nested nodes, use an operation instead
const Id true_label = OpLabel();
const Id skip_label = OpLabel();
Emit(OpBranchConditional(Visit(conditional->GetCondition()), true_label, skip_label));
const Id condition = Visit(conditional->GetCondition());
Emit(OpSelectionMerge(skip_label, spv::SelectionControlMask::MaskNone));
Emit(OpBranchConditional(condition, true_label, skip_label));
Emit(true_label);
VisitBasicBlock(conditional->GetCode());
@@ -621,7 +631,7 @@ private:
Emit(skip_label);
return {};
} else if (const auto comment = std::get_if<CommentNode>(node)) {
} else if (const auto comment = std::get_if<CommentNode>(&*node)) {
Name(Emit(OpUndef(t_void)), comment->GetText());
return {};
}
@@ -689,18 +699,18 @@ private:
}
Id Assign(Operation operation) {
const Node dest = operation[0];
const Node src = operation[1];
const Node& dest = operation[0];
const Node& src = operation[1];
Id target{};
if (const auto gpr = std::get_if<GprNode>(dest)) {
if (const auto gpr = std::get_if<GprNode>(&*dest)) {
if (gpr->GetIndex() == Register::ZeroIndex) {
// Writing to Register::ZeroIndex is a no op
return {};
}
target = registers.at(gpr->GetIndex());
} else if (const auto abuf = std::get_if<AbufNode>(dest)) {
} else if (const auto abuf = std::get_if<AbufNode>(&*dest)) {
target = [&]() -> Id {
switch (const auto attribute = abuf->GetIndex(); attribute) {
case Attribute::Index::Position:
@@ -725,7 +735,7 @@ private:
}
}();
} else if (const auto lmem = std::get_if<LmemNode>(dest)) {
} else if (const auto lmem = std::get_if<LmemNode>(&*dest)) {
Id address = BitcastTo<Type::Uint>(Visit(lmem->GetAddress()));
address = Emit(OpUDiv(t_uint, address, Constant(t_uint, 4)));
target = Emit(OpAccessChain(t_prv_float, local_memory, {address}));
@@ -771,11 +781,11 @@ private:
}
Id LogicalAssign(Operation operation) {
const Node dest = operation[0];
const Node src = operation[1];
const Node& dest = operation[0];
const Node& src = operation[1];
Id target{};
if (const auto pred = std::get_if<PredicateNode>(dest)) {
if (const auto pred = std::get_if<PredicateNode>(&*dest)) {
ASSERT_MSG(!pred->IsNegated(), "Negating logical assignment");
const auto index = pred->GetIndex();
@@ -787,7 +797,7 @@ private:
}
target = predicates.at(index);
} else if (const auto flag = std::get_if<InternalFlagNode>(dest)) {
} else if (const auto flag = std::get_if<InternalFlagNode>(&*dest)) {
target = internal_flags.at(static_cast<u32>(flag->GetFlag()));
}
@@ -873,7 +883,7 @@ private:
} else {
u32 component_value = 0;
if (meta->component) {
const auto component = std::get_if<ImmediateNode>(meta->component);
const auto component = std::get_if<ImmediateNode>(&*meta->component);
ASSERT_MSG(component, "Component is not an immediate value");
component_value = component->GetValue();
}
@@ -930,7 +940,7 @@ private:
}
Id Branch(Operation operation) {
const auto target = std::get_if<ImmediateNode>(operation[0]);
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
UNIMPLEMENTED_IF(!target);
Emit(OpStore(jmp_to, Constant(t_uint, target->GetValue())));
@@ -939,7 +949,7 @@ private:
}
Id PushFlowStack(Operation operation) {
const auto target = std::get_if<ImmediateNode>(operation[0]);
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
ASSERT(target);
const Id current = Emit(OpLoad(t_uint, flow_stack_top));
@@ -968,11 +978,11 @@ private:
case ShaderStage::Vertex: {
// TODO(Rodrigo): We should use VK_EXT_depth_range_unrestricted instead, but it doesn't
// seem to be working on Nvidia's drivers and Intel (mesa and blob) doesn't support it.
const Id position = AccessElement(t_float4, per_vertex, position_index);
Id depth = Emit(OpLoad(t_float, AccessElement(t_out_float, position, 2)));
const Id z_pointer = AccessElement(t_out_float, per_vertex, position_index, 2u);
Id depth = Emit(OpLoad(t_float, z_pointer));
depth = Emit(OpFAdd(t_float, depth, Constant(t_float, 1.0f)));
depth = Emit(OpFMul(t_float, depth, Constant(t_float, 0.5f)));
Emit(OpStore(AccessElement(t_out_float, position, 2), depth));
Emit(OpStore(z_pointer, depth));
break;
}
case ShaderStage::Fragment: {
@@ -1311,6 +1321,7 @@ private:
&SPIRVDecompiler::WorkGroupId<2>,
};
const VKDevice& device;
const ShaderIR& ir;
const ShaderStage stage;
const Tegra::Shader::Header header;
@@ -1349,12 +1360,18 @@ private:
const Id t_out_float4 = Name(TypePointer(spv::StorageClass::Output, t_float4), "out_float4");
const Id t_cbuf_float = TypePointer(spv::StorageClass::Uniform, t_float);
const Id t_cbuf_array =
Decorate(Name(TypeArray(t_float4, Constant(t_uint, MAX_CONSTBUFFER_ELEMENTS)), "CbufArray"),
spv::Decoration::ArrayStride, CBUF_STRIDE);
const Id t_cbuf_struct = MemberDecorate(
Decorate(TypeStruct(t_cbuf_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0);
const Id t_cbuf_ubo = TypePointer(spv::StorageClass::Uniform, t_cbuf_struct);
const Id t_cbuf_std140 = Decorate(
Name(TypeArray(t_float4, Constant(t_uint, MAX_CONSTBUFFER_ELEMENTS)), "CbufStd140Array"),
spv::Decoration::ArrayStride, 16u);
const Id t_cbuf_scalar = Decorate(
Name(TypeArray(t_float, Constant(t_uint, MAX_CONSTBUFFER_FLOATS)), "CbufScalarArray"),
spv::Decoration::ArrayStride, 4u);
const Id t_cbuf_std140_struct = MemberDecorate(
Decorate(TypeStruct(t_cbuf_std140), spv::Decoration::Block), 0, spv::Decoration::Offset, 0);
const Id t_cbuf_scalar_struct = MemberDecorate(
Decorate(TypeStruct(t_cbuf_scalar), spv::Decoration::Block), 0, spv::Decoration::Offset, 0);
const Id t_cbuf_std140_ubo = TypePointer(spv::StorageClass::Uniform, t_cbuf_std140_struct);
const Id t_cbuf_scalar_ubo = TypePointer(spv::StorageClass::Uniform, t_cbuf_scalar_struct);
const Id t_gmem_float = TypePointer(spv::StorageClass::StorageBuffer, t_float);
const Id t_gmem_array =
@@ -1403,8 +1420,9 @@ private:
std::map<u32, Id> labels;
};
DecompilerResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage) {
auto decompiler = std::make_unique<SPIRVDecompiler>(ir, stage);
DecompilerResult Decompile(const VKDevice& device, const VideoCommon::Shader::ShaderIR& ir,
Maxwell::ShaderStage stage) {
auto decompiler = std::make_unique<SPIRVDecompiler>(device, ir, stage);
decompiler->Decompile();
return {std::move(decompiler), decompiler->GetShaderEntries()};
}

View File

@@ -20,10 +20,13 @@ namespace VideoCommon::Shader {
class ShaderIR;
}
namespace Vulkan {
class VKDevice;
}
namespace Vulkan::VKShader {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
using SamplerEntry = VideoCommon::Shader::Sampler;
constexpr u32 DESCRIPTOR_SET = 0;
@@ -75,6 +78,7 @@ struct ShaderEntries {
using DecompilerResult = std::pair<std::unique_ptr<Sirit::Module>, ShaderEntries>;
DecompilerResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage);
DecompilerResult Decompile(const VKDevice& device, const VideoCommon::Shader::ShaderIR& ir,
Maxwell::ShaderStage stage);
} // namespace Vulkan::VKShader

View File

@@ -11,6 +11,7 @@
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/engines/shader_header.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -8,6 +8,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -7,6 +7,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -4,6 +4,7 @@
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -10,6 +10,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {
@@ -169,7 +170,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
const Node it_offset = Immediate(i * 4);
const Node real_address =
Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset);
const Node gmem = StoreNode(GmemNode(real_address, base_address, descriptor));
const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
SetTemporal(bb, i, gmem);
}
@@ -262,7 +263,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
const Node it_offset = Immediate(i * 4);
const Node real_address =
Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset);
const Node gmem = StoreNode(GmemNode(real_address, base_address, descriptor));
const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
bb.push_back(Operation(OperationCode::Assign, gmem, GetTemporal(i + 1)));
}
@@ -298,9 +299,9 @@ std::tuple<Node, Node, GlobalMemoryBase> ShaderIR::TrackAndGetGlobalMemory(NodeB
const Node base_address{
TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()))};
const auto cbuf = std::get_if<CbufNode>(base_address);
const auto cbuf = std::get_if<CbufNode>(&*base_address);
ASSERT(cbuf != nullptr);
const auto cbuf_offset_imm = std::get_if<ImmediateNode>(cbuf->GetOffset());
const auto cbuf_offset_imm = std::get_if<ImmediateNode>(&*cbuf->GetOffset());
ASSERT(cbuf_offset_imm != nullptr);
const auto cbuf_offset = cbuf_offset_imm->GetValue();

View File

@@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -11,6 +11,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {
@@ -291,8 +292,8 @@ const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg,
const Node sampler_register = GetRegister(reg);
const Node base_sampler =
TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size()));
const auto cbuf = std::get_if<CbufNode>(base_sampler);
const auto cbuf_offset_imm = std::get_if<ImmediateNode>(cbuf->GetOffset());
const auto cbuf = std::get_if<CbufNode>(&*base_sampler);
const auto cbuf_offset_imm = std::get_if<ImmediateNode>(&*cbuf->GetOffset());
ASSERT(cbuf_offset_imm != nullptr);
const auto cbuf_offset = cbuf_offset_imm->GetValue();
const auto cbuf_index = cbuf->GetIndex();
@@ -388,8 +389,8 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
Node array, Node depth_compare, u32 bias_offset,
std::vector<Node> aoffi,
std::optional<Tegra::Shader::Register> bindless_reg) {
const bool is_array = array;
const bool is_shadow = depth_compare;
const auto is_array = static_cast<bool>(array);
const auto is_shadow = static_cast<bool>(depth_compare);
const bool is_bindless = bindless_reg.has_value();
UNIMPLEMENTED_IF_MSG((texture_type == TextureType::Texture3D && (is_array || is_shadow)) ||

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {

View File

@@ -0,0 +1,514 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <cstddef>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
namespace VideoCommon::Shader {
enum class OperationCode {
Assign, /// (float& dest, float src) -> void
Select, /// (MetaArithmetic, bool pred, float a, float b) -> float
FAdd, /// (MetaArithmetic, float a, float b) -> float
FMul, /// (MetaArithmetic, float a, float b) -> float
FDiv, /// (MetaArithmetic, float a, float b) -> float
FFma, /// (MetaArithmetic, float a, float b, float c) -> float
FNegate, /// (MetaArithmetic, float a) -> float
FAbsolute, /// (MetaArithmetic, float a) -> float
FClamp, /// (MetaArithmetic, float value, float min, float max) -> float
FMin, /// (MetaArithmetic, float a, float b) -> float
FMax, /// (MetaArithmetic, float a, float b) -> float
FCos, /// (MetaArithmetic, float a) -> float
FSin, /// (MetaArithmetic, float a) -> float
FExp2, /// (MetaArithmetic, float a) -> float
FLog2, /// (MetaArithmetic, float a) -> float
FInverseSqrt, /// (MetaArithmetic, float a) -> float
FSqrt, /// (MetaArithmetic, float a) -> float
FRoundEven, /// (MetaArithmetic, float a) -> float
FFloor, /// (MetaArithmetic, float a) -> float
FCeil, /// (MetaArithmetic, float a) -> float
FTrunc, /// (MetaArithmetic, float a) -> float
FCastInteger, /// (MetaArithmetic, int a) -> float
FCastUInteger, /// (MetaArithmetic, uint a) -> float
IAdd, /// (MetaArithmetic, int a, int b) -> int
IMul, /// (MetaArithmetic, int a, int b) -> int
IDiv, /// (MetaArithmetic, int a, int b) -> int
INegate, /// (MetaArithmetic, int a) -> int
IAbsolute, /// (MetaArithmetic, int a) -> int
IMin, /// (MetaArithmetic, int a, int b) -> int
IMax, /// (MetaArithmetic, int a, int b) -> int
ICastFloat, /// (MetaArithmetic, float a) -> int
ICastUnsigned, /// (MetaArithmetic, uint a) -> int
ILogicalShiftLeft, /// (MetaArithmetic, int a, uint b) -> int
ILogicalShiftRight, /// (MetaArithmetic, int a, uint b) -> int
IArithmeticShiftRight, /// (MetaArithmetic, int a, uint b) -> int
IBitwiseAnd, /// (MetaArithmetic, int a, int b) -> int
IBitwiseOr, /// (MetaArithmetic, int a, int b) -> int
IBitwiseXor, /// (MetaArithmetic, int a, int b) -> int
IBitwiseNot, /// (MetaArithmetic, int a) -> int
IBitfieldInsert, /// (MetaArithmetic, int base, int insert, int offset, int bits) -> int
IBitfieldExtract, /// (MetaArithmetic, int value, int offset, int offset) -> int
IBitCount, /// (MetaArithmetic, int) -> int
UAdd, /// (MetaArithmetic, uint a, uint b) -> uint
UMul, /// (MetaArithmetic, uint a, uint b) -> uint
UDiv, /// (MetaArithmetic, uint a, uint b) -> uint
UMin, /// (MetaArithmetic, uint a, uint b) -> uint
UMax, /// (MetaArithmetic, uint a, uint b) -> uint
UCastFloat, /// (MetaArithmetic, float a) -> uint
UCastSigned, /// (MetaArithmetic, int a) -> uint
ULogicalShiftLeft, /// (MetaArithmetic, uint a, uint b) -> uint
ULogicalShiftRight, /// (MetaArithmetic, uint a, uint b) -> uint
UArithmeticShiftRight, /// (MetaArithmetic, uint a, uint b) -> uint
UBitwiseAnd, /// (MetaArithmetic, uint a, uint b) -> uint
UBitwiseOr, /// (MetaArithmetic, uint a, uint b) -> uint
UBitwiseXor, /// (MetaArithmetic, uint a, uint b) -> uint
UBitwiseNot, /// (MetaArithmetic, uint a) -> uint
UBitfieldInsert, /// (MetaArithmetic, uint base, uint insert, int offset, int bits) -> uint
UBitfieldExtract, /// (MetaArithmetic, uint value, int offset, int offset) -> uint
UBitCount, /// (MetaArithmetic, uint) -> uint
HAdd, /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2
HMul, /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2
HFma, /// (MetaArithmetic, f16vec2 a, f16vec2 b, f16vec2 c) -> f16vec2
HAbsolute, /// (f16vec2 a) -> f16vec2
HNegate, /// (f16vec2 a, bool first, bool second) -> f16vec2
HClamp, /// (f16vec2 src, float min, float max) -> f16vec2
HUnpack, /// (Tegra::Shader::HalfType, T value) -> f16vec2
HMergeF32, /// (f16vec2 src) -> float
HMergeH0, /// (f16vec2 dest, f16vec2 src) -> f16vec2
HMergeH1, /// (f16vec2 dest, f16vec2 src) -> f16vec2
HPack2, /// (float a, float b) -> f16vec2
LogicalAssign, /// (bool& dst, bool src) -> void
LogicalAnd, /// (bool a, bool b) -> bool
LogicalOr, /// (bool a, bool b) -> bool
LogicalXor, /// (bool a, bool b) -> bool
LogicalNegate, /// (bool a) -> bool
LogicalPick2, /// (bool2 pair, uint index) -> bool
LogicalAll2, /// (bool2 a) -> bool
LogicalAny2, /// (bool2 a) -> bool
LogicalFLessThan, /// (float a, float b) -> bool
LogicalFEqual, /// (float a, float b) -> bool
LogicalFLessEqual, /// (float a, float b) -> bool
LogicalFGreaterThan, /// (float a, float b) -> bool
LogicalFNotEqual, /// (float a, float b) -> bool
LogicalFGreaterEqual, /// (float a, float b) -> bool
LogicalFIsNan, /// (float a) -> bool
LogicalILessThan, /// (int a, int b) -> bool
LogicalIEqual, /// (int a, int b) -> bool
LogicalILessEqual, /// (int a, int b) -> bool
LogicalIGreaterThan, /// (int a, int b) -> bool
LogicalINotEqual, /// (int a, int b) -> bool
LogicalIGreaterEqual, /// (int a, int b) -> bool
LogicalULessThan, /// (uint a, uint b) -> bool
LogicalUEqual, /// (uint a, uint b) -> bool
LogicalULessEqual, /// (uint a, uint b) -> bool
LogicalUGreaterThan, /// (uint a, uint b) -> bool
LogicalUNotEqual, /// (uint a, uint b) -> bool
LogicalUGreaterEqual, /// (uint a, uint b) -> bool
Logical2HLessThan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HLessEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HGreaterThan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HNotEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HGreaterEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HLessThanWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HLessEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HGreaterThanWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HNotEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HGreaterEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Texture, /// (MetaTexture, float[N] coords) -> float4
TextureLod, /// (MetaTexture, float[N] coords) -> float4
TextureGather, /// (MetaTexture, float[N] coords) -> float4
TextureQueryDimensions, /// (MetaTexture, float a) -> float4
TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4
TexelFetch, /// (MetaTexture, int[N], int) -> float4
Branch, /// (uint branch_target) -> void
PushFlowStack, /// (uint branch_target) -> void
PopFlowStack, /// () -> void
Exit, /// () -> void
Discard, /// () -> void
EmitVertex, /// () -> void
EndPrimitive, /// () -> void
YNegate, /// () -> float
LocalInvocationIdX, /// () -> uint
LocalInvocationIdY, /// () -> uint
LocalInvocationIdZ, /// () -> uint
WorkGroupIdX, /// () -> uint
WorkGroupIdY, /// () -> uint
WorkGroupIdZ, /// () -> uint
Amount,
};
enum class InternalFlag {
Zero = 0,
Sign = 1,
Carry = 2,
Overflow = 3,
Amount = 4,
};
class OperationNode;
class ConditionalNode;
class GprNode;
class ImmediateNode;
class InternalFlagNode;
class PredicateNode;
class AbufNode;
class CbufNode;
class LmemNode;
class GmemNode;
class CommentNode;
using NodeData =
std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode,
PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>;
using Node = std::shared_ptr<NodeData>;
using Node4 = std::array<Node, 4>;
using NodeBlock = std::vector<Node>;
class Sampler {
public:
/// This constructor is for bound samplers
explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type,
bool is_array, bool is_shadow)
: offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow},
is_bindless{false} {}
/// This constructor is for bindless samplers
explicit Sampler(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
Tegra::Shader::TextureType type, bool is_array, bool is_shadow)
: offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
is_array{is_array}, is_shadow{is_shadow}, is_bindless{true} {}
/// This constructor is for serialization/deserialization
explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type,
bool is_array, bool is_shadow, bool is_bindless)
: offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow},
is_bindless{is_bindless} {}
std::size_t GetOffset() const {
return offset;
}
std::size_t GetIndex() const {
return index;
}
Tegra::Shader::TextureType GetType() const {
return type;
}
bool IsArray() const {
return is_array;
}
bool IsShadow() const {
return is_shadow;
}
bool IsBindless() const {
return is_bindless;
}
std::pair<u32, u32> GetBindlessCBuf() const {
return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
}
bool operator<(const Sampler& rhs) const {
return std::tie(index, offset, type, is_array, is_shadow, is_bindless) <
std::tie(rhs.index, rhs.offset, rhs.type, rhs.is_array, rhs.is_shadow,
rhs.is_bindless);
}
private:
/// Offset in TSC memory from which to read the sampler object, as specified by the sampling
/// instruction.
std::size_t offset{};
std::size_t index{}; ///< Value used to index into the generated GLSL sampler array.
Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc)
bool is_array{}; ///< Whether the texture is being sampled as an array texture or not.
bool is_shadow{}; ///< Whether the texture is being sampled as a depth texture or not.
bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
};
struct GlobalMemoryBase {
u32 cbuf_index{};
u32 cbuf_offset{};
bool operator<(const GlobalMemoryBase& rhs) const {
return std::tie(cbuf_index, cbuf_offset) < std::tie(rhs.cbuf_index, rhs.cbuf_offset);
}
};
/// Parameters describing an arithmetic operation
struct MetaArithmetic {
bool precise{}; ///< Whether the operation can be constraint or not
};
/// Parameters describing a texture sampler
struct MetaTexture {
const Sampler& sampler;
Node array;
Node depth_compare;
std::vector<Node> aoffi;
Node bias;
Node lod;
Node component{};
u32 element{};
};
/// Parameters that modify an operation but are not part of any particular operand
using Meta = std::variant<MetaArithmetic, MetaTexture, Tegra::Shader::HalfType>;
/// Holds any kind of operation that can be done in the IR
class OperationNode final {
public:
explicit OperationNode(OperationCode code) : OperationNode(code, Meta{}) {}
explicit OperationNode(OperationCode code, Meta meta)
: OperationNode(code, meta, std::vector<Node>{}) {}
explicit OperationNode(OperationCode code, std::vector<Node> operands)
: OperationNode(code, Meta{}, std::move(operands)) {}
explicit OperationNode(OperationCode code, Meta meta, std::vector<Node> operands)
: code{code}, meta{std::move(meta)}, operands{std::move(operands)} {}
template <typename... Args>
explicit OperationNode(OperationCode code, Meta meta, Args&&... operands)
: code{code}, meta{std::move(meta)}, operands{operands...} {}
OperationCode GetCode() const {
return code;
}
const Meta& GetMeta() const {
return meta;
}
std::size_t GetOperandsCount() const {
return operands.size();
}
const Node& operator[](std::size_t operand_index) const {
return operands.at(operand_index);
}
private:
OperationCode code{};
Meta meta{};
std::vector<Node> operands;
};
/// Encloses inside any kind of node that returns a boolean conditionally-executed code
class ConditionalNode final {
public:
explicit ConditionalNode(Node condition, std::vector<Node>&& code)
: condition{std::move(condition)}, code{std::move(code)} {}
const Node& GetCondition() const {
return condition;
}
const std::vector<Node>& GetCode() const {
return code;
}
private:
Node condition; ///< Condition to be satisfied
std::vector<Node> code; ///< Code to execute
};
/// A general purpose register
class GprNode final {
public:
explicit constexpr GprNode(Tegra::Shader::Register index) : index{index} {}
u32 GetIndex() const {
return static_cast<u32>(index);
}
private:
Tegra::Shader::Register index{};
};
/// A 32-bits value that represents an immediate value
class ImmediateNode final {
public:
explicit constexpr ImmediateNode(u32 value) : value{value} {}
u32 GetValue() const {
return value;
}
private:
u32 value{};
};
/// One of Maxwell's internal flags
class InternalFlagNode final {
public:
explicit constexpr InternalFlagNode(InternalFlag flag) : flag{flag} {}
InternalFlag GetFlag() const {
return flag;
}
private:
InternalFlag flag{};
};
/// A predicate register, it can be negated without additional nodes
class PredicateNode final {
public:
explicit constexpr PredicateNode(Tegra::Shader::Pred index, bool negated)
: index{index}, negated{negated} {}
Tegra::Shader::Pred GetIndex() const {
return index;
}
bool IsNegated() const {
return negated;
}
private:
Tegra::Shader::Pred index{};
bool negated{};
};
/// Attribute buffer memory (known as attributes or varyings in GLSL terms)
class AbufNode final {
public:
// Initialize for standard attributes (index is explicit).
explicit AbufNode(Tegra::Shader::Attribute::Index index, u32 element, Node buffer = {})
: buffer{std::move(buffer)}, index{index}, element{element} {}
// Initialize for physical attributes (index is a variable value).
explicit AbufNode(Node physical_address, Node buffer = {})
: physical_address{std::move(physical_address)}, buffer{std::move(buffer)} {}
Tegra::Shader::Attribute::Index GetIndex() const {
return index;
}
u32 GetElement() const {
return element;
}
const Node& GetBuffer() const {
return buffer;
}
bool IsPhysicalBuffer() const {
return static_cast<bool>(physical_address);
}
const Node& GetPhysicalAddress() const {
return physical_address;
}
private:
Node physical_address;
Node buffer;
Tegra::Shader::Attribute::Index index{};
u32 element{};
};
/// Constant buffer node, usually mapped to uniform buffers in GLSL
class CbufNode final {
public:
explicit CbufNode(u32 index, Node offset) : index{index}, offset{std::move(offset)} {}
u32 GetIndex() const {
return index;
}
const Node& GetOffset() const {
return offset;
}
private:
u32 index{};
Node offset;
};
/// Local memory node
class LmemNode final {
public:
explicit LmemNode(Node address) : address{std::move(address)} {}
const Node& GetAddress() const {
return address;
}
private:
Node address;
};
/// Global memory node
class GmemNode final {
public:
explicit GmemNode(Node real_address, Node base_address, const GlobalMemoryBase& descriptor)
: real_address{std::move(real_address)}, base_address{std::move(base_address)},
descriptor{descriptor} {}
const Node& GetRealAddress() const {
return real_address;
}
const Node& GetBaseAddress() const {
return base_address;
}
const GlobalMemoryBase& GetDescriptor() const {
return descriptor;
}
private:
Node real_address;
Node base_address;
GlobalMemoryBase descriptor;
};
/// Commentary, can be dropped
class CommentNode final {
public:
explicit CommentNode(std::string text) : text{std::move(text)} {}
const std::string& GetText() const {
return text;
}
private:
std::string text;
};
} // namespace VideoCommon::Shader

View File

@@ -0,0 +1,99 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring>
#include <vector>
#include "common/common_types.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {
Node Conditional(Node condition, std::vector<Node> code) {
return MakeNode<ConditionalNode>(condition, std::move(code));
}
Node Comment(std::string text) {
return MakeNode<CommentNode>(std::move(text));
}
Node Immediate(u32 value) {
return MakeNode<ImmediateNode>(value);
}
Node Immediate(s32 value) {
return Immediate(static_cast<u32>(value));
}
Node Immediate(f32 value) {
u32 integral;
std::memcpy(&integral, &value, sizeof(u32));
return Immediate(integral);
}
OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed) {
if (is_signed) {
return operation_code;
}
switch (operation_code) {
case OperationCode::FCastInteger:
return OperationCode::FCastUInteger;
case OperationCode::IAdd:
return OperationCode::UAdd;
case OperationCode::IMul:
return OperationCode::UMul;
case OperationCode::IDiv:
return OperationCode::UDiv;
case OperationCode::IMin:
return OperationCode::UMin;
case OperationCode::IMax:
return OperationCode::UMax;
case OperationCode::ICastFloat:
return OperationCode::UCastFloat;
case OperationCode::ICastUnsigned:
return OperationCode::UCastSigned;
case OperationCode::ILogicalShiftLeft:
return OperationCode::ULogicalShiftLeft;
case OperationCode::ILogicalShiftRight:
return OperationCode::ULogicalShiftRight;
case OperationCode::IArithmeticShiftRight:
return OperationCode::UArithmeticShiftRight;
case OperationCode::IBitwiseAnd:
return OperationCode::UBitwiseAnd;
case OperationCode::IBitwiseOr:
return OperationCode::UBitwiseOr;
case OperationCode::IBitwiseXor:
return OperationCode::UBitwiseXor;
case OperationCode::IBitwiseNot:
return OperationCode::UBitwiseNot;
case OperationCode::IBitfieldInsert:
return OperationCode::UBitfieldInsert;
case OperationCode::IBitCount:
return OperationCode::UBitCount;
case OperationCode::LogicalILessThan:
return OperationCode::LogicalULessThan;
case OperationCode::LogicalIEqual:
return OperationCode::LogicalUEqual;
case OperationCode::LogicalILessEqual:
return OperationCode::LogicalULessEqual;
case OperationCode::LogicalIGreaterThan:
return OperationCode::LogicalUGreaterThan;
case OperationCode::LogicalINotEqual:
return OperationCode::LogicalUNotEqual;
case OperationCode::LogicalIGreaterEqual:
return OperationCode::LogicalUGreaterEqual;
case OperationCode::INegate:
UNREACHABLE_MSG("Can't negate an unsigned integer");
return {};
case OperationCode::IAbsolute:
UNREACHABLE_MSG("Can't apply absolute to an unsigned integer");
return {};
default:
UNREACHABLE_MSG("Unknown signed operation with code={}", static_cast<u32>(operation_code));
return {};
}
}
} // namespace VideoCommon::Shader

View File

@@ -0,0 +1,65 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include "common/common_types.h"
#include "video_core/shader/node.h"
namespace VideoCommon::Shader {
/// This arithmetic operation cannot be constraint
inline constexpr MetaArithmetic PRECISE = {true};
/// This arithmetic operation can be optimized away
inline constexpr MetaArithmetic NO_PRECISE = {false};
/// Creates a conditional node
Node Conditional(Node condition, std::vector<Node> code);
/// Creates a commentary node
Node Comment(std::string text);
/// Creates an u32 immediate
Node Immediate(u32 value);
/// Creates a s32 immediate
Node Immediate(s32 value);
/// Creates a f32 immediate
Node Immediate(f32 value);
/// Converts an signed operation code to an unsigned operation code
OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed);
template <typename T, typename... Args>
Node MakeNode(Args&&... args) {
static_assert(std::is_convertible_v<T, NodeData>);
return std::make_shared<NodeData>(T(std::forward<Args>(args)...));
}
template <typename... Args>
Node Operation(OperationCode code, Args&&... args) {
if constexpr (sizeof...(args) == 0) {
return MakeNode<OperationNode>(code);
} else if constexpr (std::is_convertible_v<std::tuple_element_t<0, std::tuple<Args...>>,
Meta>) {
return MakeNode<OperationNode>(code, std::forward<Args>(args)...);
} else {
return MakeNode<OperationNode>(code, Meta{}, std::forward<Args>(args)...);
}
}
template <typename... Args>
Node SignedOperation(OperationCode code, bool is_signed, Args&&... args) {
return Operation(SignedToUnsignedCode(code, is_signed), std::forward<Args>(args)...);
}
} // namespace VideoCommon::Shader

View File

@@ -9,6 +9,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {
@@ -28,30 +29,11 @@ ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset)
ShaderIR::~ShaderIR() = default;
Node ShaderIR::StoreNode(NodeData&& node_data) {
auto store = std::make_unique<NodeData>(node_data);
const Node node = store.get();
stored_nodes.push_back(std::move(store));
return node;
}
Node ShaderIR::Conditional(Node condition, std::vector<Node>&& code) {
return StoreNode(ConditionalNode(condition, std::move(code)));
}
Node ShaderIR::Comment(std::string text) {
return StoreNode(CommentNode(std::move(text)));
}
Node ShaderIR::Immediate(u32 value) {
return StoreNode(ImmediateNode(value));
}
Node ShaderIR::GetRegister(Register reg) {
if (reg != Register::ZeroIndex) {
used_registers.insert(static_cast<u32>(reg));
}
return StoreNode(GprNode(reg));
return MakeNode<GprNode>(reg);
}
Node ShaderIR::GetImmediate19(Instruction instr) {
@@ -69,7 +51,7 @@ Node ShaderIR::GetConstBuffer(u64 index_, u64 offset_) {
const auto [entry, is_new] = used_cbufs.try_emplace(index);
entry->second.MarkAsUsed(offset);
return StoreNode(CbufNode(index, Immediate(offset)));
return MakeNode<CbufNode>(index, Immediate(offset));
}
Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) {
@@ -80,7 +62,7 @@ Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) {
entry->second.MarkAsUsedIndirect();
const Node final_offset = Operation(OperationCode::UAdd, NO_PRECISE, node, Immediate(offset));
return StoreNode(CbufNode(index, final_offset));
return MakeNode<CbufNode>(index, final_offset);
}
Node ShaderIR::GetPredicate(u64 pred_, bool negated) {
@@ -89,7 +71,7 @@ Node ShaderIR::GetPredicate(u64 pred_, bool negated) {
used_predicates.insert(pred);
}
return StoreNode(PredicateNode(pred, negated));
return MakeNode<PredicateNode>(pred, negated);
}
Node ShaderIR::GetPredicate(bool immediate) {
@@ -98,12 +80,12 @@ Node ShaderIR::GetPredicate(bool immediate) {
Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) {
used_input_attributes.emplace(index);
return StoreNode(AbufNode(index, static_cast<u32>(element), buffer));
return MakeNode<AbufNode>(index, static_cast<u32>(element), buffer);
}
Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_address, Node buffer) {
uses_physical_attributes = true;
return StoreNode(AbufNode(GetRegister(physical_address), buffer));
return MakeNode<AbufNode>(GetRegister(physical_address), buffer);
}
Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) {
@@ -115,11 +97,11 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff
}
used_output_attributes.insert(index);
return StoreNode(AbufNode(index, static_cast<u32>(element), buffer));
return MakeNode<AbufNode>(index, static_cast<u32>(element), buffer);
}
Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) {
const Node node = StoreNode(InternalFlagNode(flag));
const Node node = MakeNode<InternalFlagNode>(flag);
if (negated) {
return Operation(OperationCode::LogicalNegate, node);
}
@@ -127,7 +109,7 @@ Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) {
}
Node ShaderIR::GetLocalMemory(Node address) {
return StoreNode(LmemNode(address));
return MakeNode<LmemNode>(address);
}
Node ShaderIR::GetTemporal(u32 id) {
@@ -393,68 +375,4 @@ Node ShaderIR::BitfieldExtract(Node value, u32 offset, u32 bits) {
Immediate(bits));
}
/*static*/ OperationCode ShaderIR::SignedToUnsignedCode(OperationCode operation_code,
bool is_signed) {
if (is_signed) {
return operation_code;
}
switch (operation_code) {
case OperationCode::FCastInteger:
return OperationCode::FCastUInteger;
case OperationCode::IAdd:
return OperationCode::UAdd;
case OperationCode::IMul:
return OperationCode::UMul;
case OperationCode::IDiv:
return OperationCode::UDiv;
case OperationCode::IMin:
return OperationCode::UMin;
case OperationCode::IMax:
return OperationCode::UMax;
case OperationCode::ICastFloat:
return OperationCode::UCastFloat;
case OperationCode::ICastUnsigned:
return OperationCode::UCastSigned;
case OperationCode::ILogicalShiftLeft:
return OperationCode::ULogicalShiftLeft;
case OperationCode::ILogicalShiftRight:
return OperationCode::ULogicalShiftRight;
case OperationCode::IArithmeticShiftRight:
return OperationCode::UArithmeticShiftRight;
case OperationCode::IBitwiseAnd:
return OperationCode::UBitwiseAnd;
case OperationCode::IBitwiseOr:
return OperationCode::UBitwiseOr;
case OperationCode::IBitwiseXor:
return OperationCode::UBitwiseXor;
case OperationCode::IBitwiseNot:
return OperationCode::UBitwiseNot;
case OperationCode::IBitfieldInsert:
return OperationCode::UBitfieldInsert;
case OperationCode::IBitCount:
return OperationCode::UBitCount;
case OperationCode::LogicalILessThan:
return OperationCode::LogicalULessThan;
case OperationCode::LogicalIEqual:
return OperationCode::LogicalUEqual;
case OperationCode::LogicalILessEqual:
return OperationCode::LogicalULessEqual;
case OperationCode::LogicalIGreaterThan:
return OperationCode::LogicalUGreaterThan;
case OperationCode::LogicalINotEqual:
return OperationCode::LogicalUNotEqual;
case OperationCode::LogicalIGreaterEqual:
return OperationCode::LogicalUGreaterEqual;
case OperationCode::INegate:
UNREACHABLE_MSG("Can't negate an unsigned integer");
return {};
case OperationCode::IAbsolute:
UNREACHABLE_MSG("Can't apply absolute to an unsigned integer");
return {};
default:
UNREACHABLE_MSG("Unknown signed operation with code={}", static_cast<u32>(operation_code));
return {};
}
}
} // namespace VideoCommon::Shader

View File

@@ -18,188 +18,14 @@
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/engines/shader_header.h"
#include "video_core/shader/node.h"
namespace VideoCommon::Shader {
class OperationNode;
class ConditionalNode;
class GprNode;
class ImmediateNode;
class InternalFlagNode;
class PredicateNode;
class AbufNode; ///< Attribute buffer
class CbufNode; ///< Constant buffer
class LmemNode; ///< Local memory
class GmemNode; ///< Global memory
class CommentNode;
using ProgramCode = std::vector<u64>;
using NodeData =
std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode,
PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>;
using Node = const NodeData*;
using Node4 = std::array<Node, 4>;
using NodeBlock = std::vector<Node>;
constexpr u32 MAX_PROGRAM_LENGTH = 0x1000;
enum class OperationCode {
Assign, /// (float& dest, float src) -> void
Select, /// (MetaArithmetic, bool pred, float a, float b) -> float
FAdd, /// (MetaArithmetic, float a, float b) -> float
FMul, /// (MetaArithmetic, float a, float b) -> float
FDiv, /// (MetaArithmetic, float a, float b) -> float
FFma, /// (MetaArithmetic, float a, float b, float c) -> float
FNegate, /// (MetaArithmetic, float a) -> float
FAbsolute, /// (MetaArithmetic, float a) -> float
FClamp, /// (MetaArithmetic, float value, float min, float max) -> float
FMin, /// (MetaArithmetic, float a, float b) -> float
FMax, /// (MetaArithmetic, float a, float b) -> float
FCos, /// (MetaArithmetic, float a) -> float
FSin, /// (MetaArithmetic, float a) -> float
FExp2, /// (MetaArithmetic, float a) -> float
FLog2, /// (MetaArithmetic, float a) -> float
FInverseSqrt, /// (MetaArithmetic, float a) -> float
FSqrt, /// (MetaArithmetic, float a) -> float
FRoundEven, /// (MetaArithmetic, float a) -> float
FFloor, /// (MetaArithmetic, float a) -> float
FCeil, /// (MetaArithmetic, float a) -> float
FTrunc, /// (MetaArithmetic, float a) -> float
FCastInteger, /// (MetaArithmetic, int a) -> float
FCastUInteger, /// (MetaArithmetic, uint a) -> float
IAdd, /// (MetaArithmetic, int a, int b) -> int
IMul, /// (MetaArithmetic, int a, int b) -> int
IDiv, /// (MetaArithmetic, int a, int b) -> int
INegate, /// (MetaArithmetic, int a) -> int
IAbsolute, /// (MetaArithmetic, int a) -> int
IMin, /// (MetaArithmetic, int a, int b) -> int
IMax, /// (MetaArithmetic, int a, int b) -> int
ICastFloat, /// (MetaArithmetic, float a) -> int
ICastUnsigned, /// (MetaArithmetic, uint a) -> int
ILogicalShiftLeft, /// (MetaArithmetic, int a, uint b) -> int
ILogicalShiftRight, /// (MetaArithmetic, int a, uint b) -> int
IArithmeticShiftRight, /// (MetaArithmetic, int a, uint b) -> int
IBitwiseAnd, /// (MetaArithmetic, int a, int b) -> int
IBitwiseOr, /// (MetaArithmetic, int a, int b) -> int
IBitwiseXor, /// (MetaArithmetic, int a, int b) -> int
IBitwiseNot, /// (MetaArithmetic, int a) -> int
IBitfieldInsert, /// (MetaArithmetic, int base, int insert, int offset, int bits) -> int
IBitfieldExtract, /// (MetaArithmetic, int value, int offset, int offset) -> int
IBitCount, /// (MetaArithmetic, int) -> int
UAdd, /// (MetaArithmetic, uint a, uint b) -> uint
UMul, /// (MetaArithmetic, uint a, uint b) -> uint
UDiv, /// (MetaArithmetic, uint a, uint b) -> uint
UMin, /// (MetaArithmetic, uint a, uint b) -> uint
UMax, /// (MetaArithmetic, uint a, uint b) -> uint
UCastFloat, /// (MetaArithmetic, float a) -> uint
UCastSigned, /// (MetaArithmetic, int a) -> uint
ULogicalShiftLeft, /// (MetaArithmetic, uint a, uint b) -> uint
ULogicalShiftRight, /// (MetaArithmetic, uint a, uint b) -> uint
UArithmeticShiftRight, /// (MetaArithmetic, uint a, uint b) -> uint
UBitwiseAnd, /// (MetaArithmetic, uint a, uint b) -> uint
UBitwiseOr, /// (MetaArithmetic, uint a, uint b) -> uint
UBitwiseXor, /// (MetaArithmetic, uint a, uint b) -> uint
UBitwiseNot, /// (MetaArithmetic, uint a) -> uint
UBitfieldInsert, /// (MetaArithmetic, uint base, uint insert, int offset, int bits) -> uint
UBitfieldExtract, /// (MetaArithmetic, uint value, int offset, int offset) -> uint
UBitCount, /// (MetaArithmetic, uint) -> uint
HAdd, /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2
HMul, /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2
HFma, /// (MetaArithmetic, f16vec2 a, f16vec2 b, f16vec2 c) -> f16vec2
HAbsolute, /// (f16vec2 a) -> f16vec2
HNegate, /// (f16vec2 a, bool first, bool second) -> f16vec2
HClamp, /// (f16vec2 src, float min, float max) -> f16vec2
HUnpack, /// (Tegra::Shader::HalfType, T value) -> f16vec2
HMergeF32, /// (f16vec2 src) -> float
HMergeH0, /// (f16vec2 dest, f16vec2 src) -> f16vec2
HMergeH1, /// (f16vec2 dest, f16vec2 src) -> f16vec2
HPack2, /// (float a, float b) -> f16vec2
LogicalAssign, /// (bool& dst, bool src) -> void
LogicalAnd, /// (bool a, bool b) -> bool
LogicalOr, /// (bool a, bool b) -> bool
LogicalXor, /// (bool a, bool b) -> bool
LogicalNegate, /// (bool a) -> bool
LogicalPick2, /// (bool2 pair, uint index) -> bool
LogicalAll2, /// (bool2 a) -> bool
LogicalAny2, /// (bool2 a) -> bool
LogicalFLessThan, /// (float a, float b) -> bool
LogicalFEqual, /// (float a, float b) -> bool
LogicalFLessEqual, /// (float a, float b) -> bool
LogicalFGreaterThan, /// (float a, float b) -> bool
LogicalFNotEqual, /// (float a, float b) -> bool
LogicalFGreaterEqual, /// (float a, float b) -> bool
LogicalFIsNan, /// (float a) -> bool
LogicalILessThan, /// (int a, int b) -> bool
LogicalIEqual, /// (int a, int b) -> bool
LogicalILessEqual, /// (int a, int b) -> bool
LogicalIGreaterThan, /// (int a, int b) -> bool
LogicalINotEqual, /// (int a, int b) -> bool
LogicalIGreaterEqual, /// (int a, int b) -> bool
LogicalULessThan, /// (uint a, uint b) -> bool
LogicalUEqual, /// (uint a, uint b) -> bool
LogicalULessEqual, /// (uint a, uint b) -> bool
LogicalUGreaterThan, /// (uint a, uint b) -> bool
LogicalUNotEqual, /// (uint a, uint b) -> bool
LogicalUGreaterEqual, /// (uint a, uint b) -> bool
Logical2HLessThan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HLessEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HGreaterThan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HNotEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HGreaterEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HLessThanWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HLessEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HGreaterThanWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HNotEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Logical2HGreaterEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
Texture, /// (MetaTexture, float[N] coords) -> float4
TextureLod, /// (MetaTexture, float[N] coords) -> float4
TextureGather, /// (MetaTexture, float[N] coords) -> float4
TextureQueryDimensions, /// (MetaTexture, float a) -> float4
TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4
TexelFetch, /// (MetaTexture, int[N], int) -> float4
Branch, /// (uint branch_target) -> void
PushFlowStack, /// (uint branch_target) -> void
PopFlowStack, /// () -> void
Exit, /// () -> void
Discard, /// () -> void
EmitVertex, /// () -> void
EndPrimitive, /// () -> void
YNegate, /// () -> float
LocalInvocationIdX, /// () -> uint
LocalInvocationIdY, /// () -> uint
LocalInvocationIdZ, /// () -> uint
WorkGroupIdX, /// () -> uint
WorkGroupIdY, /// () -> uint
WorkGroupIdZ, /// () -> uint
Amount,
};
enum class InternalFlag {
Zero = 0,
Sign = 1,
Carry = 2,
Overflow = 3,
Amount = 4,
};
/// Describes the behaviour of code path of a given entry point and a return point.
enum class ExitMethod {
Undetermined, ///< Internal value. Only occur when analyzing JMP loop.
@@ -208,71 +34,6 @@ enum class ExitMethod {
AlwaysEnd, ///< All code paths reach a END instruction.
};
class Sampler {
public:
// Use this constructor for bounded Samplers
explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type,
bool is_array, bool is_shadow)
: offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow},
is_bindless{false} {}
// Use this constructor for bindless Samplers
explicit Sampler(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
Tegra::Shader::TextureType type, bool is_array, bool is_shadow)
: offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
is_array{is_array}, is_shadow{is_shadow}, is_bindless{true} {}
// Use this only for serialization/deserialization
explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type,
bool is_array, bool is_shadow, bool is_bindless)
: offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow},
is_bindless{is_bindless} {}
std::size_t GetOffset() const {
return offset;
}
std::size_t GetIndex() const {
return index;
}
Tegra::Shader::TextureType GetType() const {
return type;
}
bool IsArray() const {
return is_array;
}
bool IsShadow() const {
return is_shadow;
}
bool IsBindless() const {
return is_bindless;
}
std::pair<u32, u32> GetBindlessCBuf() const {
return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
}
bool operator<(const Sampler& rhs) const {
return std::tie(index, offset, type, is_array, is_shadow, is_bindless) <
std::tie(rhs.index, rhs.offset, rhs.type, rhs.is_array, rhs.is_shadow,
rhs.is_bindless);
}
private:
/// Offset in TSC memory from which to read the sampler object, as specified by the sampling
/// instruction.
std::size_t offset{};
std::size_t index{}; ///< Value used to index into the generated GLSL sampler array.
Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc)
bool is_array{}; ///< Whether the texture is being sampled as an array texture or not.
bool is_shadow{}; ///< Whether the texture is being sampled as a depth texture or not.
bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
};
class ConstBuffer {
public:
explicit ConstBuffer(u32 max_offset, bool is_indirect)
@@ -305,268 +66,11 @@ private:
bool is_indirect{};
};
struct GlobalMemoryBase {
u32 cbuf_index{};
u32 cbuf_offset{};
bool operator<(const GlobalMemoryBase& rhs) const {
return std::tie(cbuf_index, cbuf_offset) < std::tie(rhs.cbuf_index, rhs.cbuf_offset);
}
};
struct GlobalMemoryUsage {
bool is_read{};
bool is_written{};
};
struct MetaArithmetic {
bool precise{};
};
struct MetaTexture {
const Sampler& sampler;
Node array{};
Node depth_compare{};
std::vector<Node> aoffi;
Node bias{};
Node lod{};
Node component{};
u32 element{};
};
constexpr MetaArithmetic PRECISE = {true};
constexpr MetaArithmetic NO_PRECISE = {false};
using Meta = std::variant<MetaArithmetic, MetaTexture, Tegra::Shader::HalfType>;
/// Holds any kind of operation that can be done in the IR
class OperationNode final {
public:
explicit OperationNode(OperationCode code) : code{code} {}
explicit OperationNode(OperationCode code, Meta&& meta) : code{code}, meta{std::move(meta)} {}
template <typename... T>
explicit OperationNode(OperationCode code, const T*... operands)
: OperationNode(code, {}, operands...) {}
template <typename... T>
explicit OperationNode(OperationCode code, Meta&& meta, const T*... operands_)
: code{code}, meta{std::move(meta)}, operands{operands_...} {}
explicit OperationNode(OperationCode code, Meta&& meta, std::vector<Node>&& operands)
: code{code}, meta{meta}, operands{std::move(operands)} {}
explicit OperationNode(OperationCode code, std::vector<Node>&& operands)
: code{code}, operands{std::move(operands)} {}
OperationCode GetCode() const {
return code;
}
const Meta& GetMeta() const {
return meta;
}
std::size_t GetOperandsCount() const {
return operands.size();
}
Node operator[](std::size_t operand_index) const {
return operands.at(operand_index);
}
private:
const OperationCode code;
const Meta meta;
std::vector<Node> operands;
};
/// Encloses inside any kind of node that returns a boolean conditionally-executed code
class ConditionalNode final {
public:
explicit ConditionalNode(Node condition, std::vector<Node>&& code)
: condition{condition}, code{std::move(code)} {}
Node GetCondition() const {
return condition;
}
const std::vector<Node>& GetCode() const {
return code;
}
private:
const Node condition; ///< Condition to be satisfied
std::vector<Node> code; ///< Code to execute
};
/// A general purpose register
class GprNode final {
public:
explicit constexpr GprNode(Tegra::Shader::Register index) : index{index} {}
u32 GetIndex() const {
return static_cast<u32>(index);
}
private:
const Tegra::Shader::Register index;
};
/// A 32-bits value that represents an immediate value
class ImmediateNode final {
public:
explicit constexpr ImmediateNode(u32 value) : value{value} {}
u32 GetValue() const {
return value;
}
private:
const u32 value;
};
/// One of Maxwell's internal flags
class InternalFlagNode final {
public:
explicit constexpr InternalFlagNode(InternalFlag flag) : flag{flag} {}
InternalFlag GetFlag() const {
return flag;
}
private:
const InternalFlag flag;
};
/// A predicate register, it can be negated without additional nodes
class PredicateNode final {
public:
explicit constexpr PredicateNode(Tegra::Shader::Pred index, bool negated)
: index{index}, negated{negated} {}
Tegra::Shader::Pred GetIndex() const {
return index;
}
bool IsNegated() const {
return negated;
}
private:
const Tegra::Shader::Pred index;
const bool negated;
};
/// Attribute buffer memory (known as attributes or varyings in GLSL terms)
class AbufNode final {
public:
// Initialize for standard attributes (index is explicit).
explicit constexpr AbufNode(Tegra::Shader::Attribute::Index index, u32 element,
Node buffer = {})
: buffer{buffer}, index{index}, element{element} {}
// Initialize for physical attributes (index is a variable value).
explicit constexpr AbufNode(Node physical_address, Node buffer = {})
: physical_address{physical_address}, buffer{buffer} {}
Tegra::Shader::Attribute::Index GetIndex() const {
return index;
}
u32 GetElement() const {
return element;
}
Node GetBuffer() const {
return buffer;
}
bool IsPhysicalBuffer() const {
return physical_address != nullptr;
}
Node GetPhysicalAddress() const {
return physical_address;
}
private:
Node physical_address{};
Node buffer{};
Tegra::Shader::Attribute::Index index{};
u32 element{};
};
/// Constant buffer node, usually mapped to uniform buffers in GLSL
class CbufNode final {
public:
explicit constexpr CbufNode(u32 index, Node offset) : index{index}, offset{offset} {}
u32 GetIndex() const {
return index;
}
Node GetOffset() const {
return offset;
}
private:
const u32 index;
const Node offset;
};
/// Local memory node
class LmemNode final {
public:
explicit constexpr LmemNode(Node address) : address{address} {}
Node GetAddress() const {
return address;
}
private:
const Node address;
};
/// Global memory node
class GmemNode final {
public:
explicit constexpr GmemNode(Node real_address, Node base_address,
const GlobalMemoryBase& descriptor)
: real_address{real_address}, base_address{base_address}, descriptor{descriptor} {}
Node GetRealAddress() const {
return real_address;
}
Node GetBaseAddress() const {
return base_address;
}
const GlobalMemoryBase& GetDescriptor() const {
return descriptor;
}
private:
const Node real_address;
const Node base_address;
const GlobalMemoryBase descriptor;
};
/// Commentary, can be dropped
class CommentNode final {
public:
explicit CommentNode(std::string text) : text{std::move(text)} {}
const std::string& GetText() const {
return text;
}
private:
std::string text;
};
class ShaderIR final {
public:
explicit ShaderIR(const ProgramCode& program_code, u32 main_offset);
@@ -663,26 +167,6 @@ private:
u32 DecodeXmad(NodeBlock& bb, u32 pc);
u32 DecodeOther(NodeBlock& bb, u32 pc);
/// Internalizes node's data and returns a managed pointer to a clone of that node
Node StoreNode(NodeData&& node_data);
/// Creates a conditional node
Node Conditional(Node condition, std::vector<Node>&& code);
/// Creates a commentary
Node Comment(std::string text);
/// Creates an u32 immediate
Node Immediate(u32 value);
/// Creates a s32 immediate
Node Immediate(s32 value) {
return Immediate(static_cast<u32>(value));
}
/// Creates a f32 immediate
Node Immediate(f32 value) {
u32 integral;
std::memcpy(&integral, &value, sizeof(u32));
return Immediate(integral);
}
/// Generates a node for a passed register.
Node GetRegister(Tegra::Shader::Register reg);
/// Generates a node representing a 19-bit immediate value
@@ -827,37 +311,6 @@ private:
std::tuple<Node, Node, GlobalMemoryBase> TrackAndGetGlobalMemory(
NodeBlock& bb, Tegra::Shader::Instruction instr, bool is_write);
template <typename... T>
Node Operation(OperationCode code, const T*... operands) {
return StoreNode(OperationNode(code, operands...));
}
template <typename... T>
Node Operation(OperationCode code, Meta&& meta, const T*... operands) {
return StoreNode(OperationNode(code, std::move(meta), operands...));
}
Node Operation(OperationCode code, std::vector<Node>&& operands) {
return StoreNode(OperationNode(code, std::move(operands)));
}
Node Operation(OperationCode code, Meta&& meta, std::vector<Node>&& operands) {
return StoreNode(OperationNode(code, std::move(meta), std::move(operands)));
}
template <typename... T>
Node SignedOperation(OperationCode code, bool is_signed, const T*... operands) {
return StoreNode(OperationNode(SignedToUnsignedCode(code, is_signed), operands...));
}
template <typename... T>
Node SignedOperation(OperationCode code, bool is_signed, Meta&& meta, const T*... operands) {
return StoreNode(
OperationNode(SignedToUnsignedCode(code, is_signed), std::move(meta), operands...));
}
static OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed);
const ProgramCode& program_code;
const u32 main_offset;
@@ -868,8 +321,6 @@ private:
std::map<u32, NodeBlock> basic_blocks;
NodeBlock global_code;
std::vector<std::unique_ptr<NodeData>> stored_nodes;
std::set<u32> used_registers;
std::set<Tegra::Shader::Pred> used_predicates;
std::set<Tegra::Shader::Attribute::Index> used_input_attributes;

View File

@@ -16,12 +16,12 @@ std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor,
OperationCode operation_code) {
for (; cursor >= 0; --cursor) {
const Node node = code.at(cursor);
if (const auto operation = std::get_if<OperationNode>(node)) {
if (const auto operation = std::get_if<OperationNode>(&*node)) {
if (operation->GetCode() == operation_code) {
return {node, cursor};
}
}
if (const auto conditional = std::get_if<ConditionalNode>(node)) {
if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
const auto& conditional_code = conditional->GetCode();
const auto [found, internal_cursor] = FindOperation(
conditional_code, static_cast<s64>(conditional_code.size() - 1), operation_code);
@@ -35,11 +35,11 @@ std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor,
} // namespace
Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const {
if (const auto cbuf = std::get_if<CbufNode>(tracked)) {
if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) {
// Cbuf found, but it has to be immediate
return std::holds_alternative<ImmediateNode>(*cbuf->GetOffset()) ? tracked : nullptr;
}
if (const auto gpr = std::get_if<GprNode>(tracked)) {
if (const auto gpr = std::get_if<GprNode>(&*tracked)) {
if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) {
return nullptr;
}
@@ -51,7 +51,7 @@ Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const
}
return TrackCbuf(source, code, new_cursor);
}
if (const auto operation = std::get_if<OperationNode>(tracked)) {
if (const auto operation = std::get_if<OperationNode>(&*tracked)) {
for (std::size_t i = 0; i < operation->GetOperandsCount(); ++i) {
if (const auto found = TrackCbuf((*operation)[i], code, cursor)) {
// Cbuf found in operand
@@ -60,7 +60,7 @@ Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const
}
return nullptr;
}
if (const auto conditional = std::get_if<ConditionalNode>(tracked)) {
if (const auto conditional = std::get_if<ConditionalNode>(&*tracked)) {
const auto& conditional_code = conditional->GetCode();
return TrackCbuf(tracked, conditional_code, static_cast<s64>(conditional_code.size()));
}
@@ -75,7 +75,7 @@ std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code,
if (!found) {
return {};
}
if (const auto immediate = std::get_if<ImmediateNode>(found)) {
if (const auto immediate = std::get_if<ImmediateNode>(&*found)) {
return immediate->GetValue();
}
return {};
@@ -88,11 +88,11 @@ std::pair<Node, s64> ShaderIR::TrackRegister(const GprNode* tracked, const NodeB
if (!found_node) {
return {};
}
const auto operation = std::get_if<OperationNode>(found_node);
const auto operation = std::get_if<OperationNode>(&*found_node);
ASSERT(operation);
const auto& target = (*operation)[0];
if (const auto gpr_target = std::get_if<GprNode>(target)) {
if (const auto gpr_target = std::get_if<GprNode>(&*target)) {
if (gpr_target->GetIndex() == tracked->GetIndex()) {
return {(*operation)[1], new_cursor};
}

View File

@@ -159,6 +159,15 @@ target_compile_definitions(yuzu PRIVATE
# Disable implicit conversions from/to C strings
-DQT_NO_CAST_FROM_ASCII
-DQT_NO_CAST_TO_ASCII
# Disable implicit type narrowing in signal/slot connect() calls.
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
# Disable unsafe overloads of QProcess' start() function.
-DQT_NO_PROCESS_COMBINED_ARGUMENT_START
# Disable implicit QString->QUrl conversions to enforce use of proper resolving functions.
-DQT_NO_URL_CAST_FROM_STRING
)
if (YUZU_ENABLE_COMPATIBILITY_REPORTING)

View File

@@ -122,21 +122,15 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
QtProfileSelectionDialog::~QtProfileSelectionDialog() = default;
void QtProfileSelectionDialog::accept() {
ok = true;
QDialog::accept();
}
void QtProfileSelectionDialog::reject() {
ok = false;
user_index = 0;
QDialog::reject();
}
bool QtProfileSelectionDialog::GetStatus() const {
return ok;
}
u32 QtProfileSelectionDialog::GetIndex() const {
int QtProfileSelectionDialog::GetIndex() const {
return user_index;
}

View File

@@ -30,15 +30,13 @@ public:
void accept() override;
void reject() override;
bool GetStatus() const;
u32 GetIndex() const;
int GetIndex() const;
private:
bool ok = false;
u32 user_index = 0;
void SelectUser(const QModelIndex& index);
int user_index = 0;
QVBoxLayout* layout;
QTreeView* tree_view;
QStandardItemModel* item_model;

View File

@@ -104,13 +104,11 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default;
void QtSoftwareKeyboardDialog::accept() {
ok = true;
text = line_edit->text().toStdU16String();
QDialog::accept();
}
void QtSoftwareKeyboardDialog::reject() {
ok = false;
text.clear();
QDialog::reject();
}
@@ -119,10 +117,6 @@ std::u16string QtSoftwareKeyboardDialog::GetText() const {
return text;
}
bool QtSoftwareKeyboardDialog::GetStatus() const {
return ok;
}
QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) {
connect(this, &QtSoftwareKeyboard::MainWindowGetText, &main_window,
&GMainWindow::SoftwareKeyboardGetText, Qt::QueuedConnection);

View File

@@ -36,10 +36,8 @@ public:
void reject() override;
std::u16string GetText() const;
bool GetStatus() const;
private:
bool ok = false;
std::u16string text;
QDialogButtonBox* buttons;

View File

@@ -26,6 +26,8 @@
EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {}
EmuThread::~EmuThread() = default;
void EmuThread::run() {
render_window->MakeCurrent();
@@ -185,7 +187,7 @@ private:
bool do_painting;
};
GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread)
: QWidget(parent), emu_thread(emu_thread) {
setWindowTitle(QStringLiteral("yuzu %1 | %2-%3")
.arg(QString::fromUtf8(Common::g_build_name),
@@ -194,8 +196,7 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
setAttribute(Qt::WA_AcceptTouchEvents);
InputCommon::Init();
connect(this, &GRenderWindow::FirstFrameDisplayed, static_cast<GMainWindow*>(parent),
&GMainWindow::OnLoadComplete);
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
}
GRenderWindow::~GRenderWindow() {
@@ -247,9 +248,9 @@ void GRenderWindow::PollEvents() {}
void GRenderWindow::OnFramebufferSizeChanged() {
// Screen changes potentially incur a change in screen DPI, hence we should update the
// framebuffer size
qreal pixelRatio = GetWindowPixelRatio();
unsigned width = child->QPaintDevice::width() * pixelRatio;
unsigned height = child->QPaintDevice::height() * pixelRatio;
const qreal pixel_ratio = GetWindowPixelRatio();
const u32 width = child->QPaintDevice::width() * pixel_ratio;
const u32 height = child->QPaintDevice::height() * pixel_ratio;
UpdateCurrentFramebufferLayout(width, height);
}
@@ -266,7 +267,7 @@ void GRenderWindow::ForwardKeyReleaseEvent(QKeyEvent* event) {
}
void GRenderWindow::BackupGeometry() {
geometry = ((QWidget*)this)->saveGeometry();
geometry = QWidget::saveGeometry();
}
void GRenderWindow::RestoreGeometry() {
@@ -283,10 +284,11 @@ void GRenderWindow::restoreGeometry(const QByteArray& geometry) {
QByteArray GRenderWindow::saveGeometry() {
// If we are a top-level widget, store the current geometry
// otherwise, store the last backup
if (parent() == nullptr)
return ((QWidget*)this)->saveGeometry();
else
return geometry;
if (parent() == nullptr) {
return QWidget::saveGeometry();
}
return geometry;
}
qreal GRenderWindow::GetWindowPixelRatio() const {
@@ -294,10 +296,10 @@ qreal GRenderWindow::GetWindowPixelRatio() const {
return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f;
}
std::pair<unsigned, unsigned> GRenderWindow::ScaleTouch(const QPointF pos) const {
std::pair<u32, u32> GRenderWindow::ScaleTouch(const QPointF pos) const {
const qreal pixel_ratio = GetWindowPixelRatio();
return {static_cast<unsigned>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})),
static_cast<unsigned>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))};
return {static_cast<u32>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})),
static_cast<u32>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))};
}
void GRenderWindow::closeEvent(QCloseEvent* event) {
@@ -353,7 +355,7 @@ void GRenderWindow::focusOutEvent(QFocusEvent* event) {
InputCommon::GetKeyboard()->ReleaseAllKeys();
}
void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) {
void GRenderWindow::OnClientAreaResized(u32 width, u32 height) {
NotifyClientAreaSizeChanged(std::make_pair(width, height));
}
@@ -394,7 +396,7 @@ void GRenderWindow::InitRenderTarget() {
context->setShareContext(shared_context.get());
context->setFormat(fmt);
context->create();
fmt.setSwapInterval(false);
fmt.setSwapInterval(0);
child = new GGLWidgetInternal(this, shared_context.get());
container = QWidget::createWindowContainer(child, this);
@@ -424,23 +426,29 @@ void GRenderWindow::InitRenderTarget() {
BackupGeometry();
}
void GRenderWindow::CaptureScreenshot(u16 res_scale, const QString& screenshot_path) {
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
auto& renderer = Core::System::GetInstance().Renderer();
if (!res_scale)
if (res_scale == 0) {
res_scale = VideoCore::GetResolutionScaleFactor(renderer);
}
const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)};
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
renderer.RequestScreenshot(screenshot_image.bits(),
[=] {
screenshot_image.mirrored(false, true).save(screenshot_path);
LOG_INFO(Frontend, "The screenshot is saved.");
},
layout);
renderer.RequestScreenshot(
screenshot_image.bits(),
[=] {
const std::string std_screenshot_path = screenshot_path.toStdString();
if (screenshot_image.mirrored(false, true).save(screenshot_path)) {
LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path);
} else {
LOG_ERROR(Frontend, "Failed to save screenshot to \"{}\"", std_screenshot_path);
}
},
layout);
}
void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) {
void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
setMinimumSize(minimal_size.first, minimal_size.second);
}

View File

@@ -27,11 +27,12 @@ namespace VideoCore {
enum class LoadCallbackStage;
}
class EmuThread : public QThread {
class EmuThread final : public QThread {
Q_OBJECT
public:
explicit EmuThread(GRenderWindow* render_window);
~EmuThread() override;
/**
* Start emulation (on new thread)
@@ -114,7 +115,7 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
Q_OBJECT
public:
GRenderWindow(QWidget* parent, EmuThread* emu_thread);
GRenderWindow(GMainWindow* parent, EmuThread* emu_thread);
~GRenderWindow() override;
// EmuWindow implementation
@@ -133,17 +134,17 @@ public:
QByteArray saveGeometry(); // overridden
qreal GetWindowPixelRatio() const;
std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const;
std::pair<u32, u32> ScaleTouch(QPointF pos) const;
void closeEvent(QCloseEvent* event) override;
bool event(QEvent* event) override;
void focusOutEvent(QFocusEvent* event) override;
void OnClientAreaResized(unsigned width, unsigned height);
void OnClientAreaResized(u32 width, u32 height);
void InitRenderTarget();
void CaptureScreenshot(u16 res_scale, const QString& screenshot_path);
void CaptureScreenshot(u32 res_scale, const QString& screenshot_path);
public slots:
void moveContext(); // overridden
@@ -162,7 +163,7 @@ private:
void TouchUpdateEvent(const QTouchEvent* event);
void TouchEndEvent();
void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) override;
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
QWidget* container = nullptr;
GGLWidgetInternal* child = nullptr;

View File

@@ -22,11 +22,11 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
}
connect(ui->volume_slider, &QSlider::valueChanged, this,
&ConfigureAudio::setVolumeIndicatorText);
&ConfigureAudio::SetVolumeIndicatorText);
this->setConfiguration();
SetConfiguration();
connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureAudio::updateAudioDevices);
&ConfigureAudio::UpdateAudioDevices);
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
ui->output_sink_combo_box->setEnabled(!is_powered_on);
@@ -35,20 +35,20 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
ConfigureAudio::~ConfigureAudio() = default;
void ConfigureAudio::setConfiguration() {
setOutputSinkFromSinkID();
void ConfigureAudio::SetConfiguration() {
SetOutputSinkFromSinkID();
// The device list cannot be pre-populated (nor listed) until the output sink is known.
updateAudioDevices(ui->output_sink_combo_box->currentIndex());
UpdateAudioDevices(ui->output_sink_combo_box->currentIndex());
setAudioDeviceFromDeviceID();
SetAudioDeviceFromDeviceID();
ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum());
setVolumeIndicatorText(ui->volume_slider->sliderPosition());
SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
}
void ConfigureAudio::setOutputSinkFromSinkID() {
void ConfigureAudio::SetOutputSinkFromSinkID() {
int new_sink_index = 0;
const QString sink_id = QString::fromStdString(Settings::values.sink_id);
@@ -62,7 +62,7 @@ void ConfigureAudio::setOutputSinkFromSinkID() {
ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
}
void ConfigureAudio::setAudioDeviceFromDeviceID() {
void ConfigureAudio::SetAudioDeviceFromDeviceID() {
int new_device_index = -1;
const QString device_id = QString::fromStdString(Settings::values.audio_device_id);
@@ -76,11 +76,11 @@ void ConfigureAudio::setAudioDeviceFromDeviceID() {
ui->audio_device_combo_box->setCurrentIndex(new_device_index);
}
void ConfigureAudio::setVolumeIndicatorText(int percentage) {
void ConfigureAudio::SetVolumeIndicatorText(int percentage) {
ui->volume_indicator->setText(tr("%1%", "Volume percentage (e.g. 50%)").arg(percentage));
}
void ConfigureAudio::applyConfiguration() {
void ConfigureAudio::ApplyConfiguration() {
Settings::values.sink_id =
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
.toStdString();
@@ -92,7 +92,7 @@ void ConfigureAudio::applyConfiguration() {
static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum();
}
void ConfigureAudio::updateAudioDevices(int sink_index) {
void ConfigureAudio::UpdateAudioDevices(int sink_index) {
ui->audio_device_combo_box->clear();
ui->audio_device_combo_box->addItem(QString::fromUtf8(AudioCore::auto_device_name));
@@ -102,6 +102,6 @@ void ConfigureAudio::updateAudioDevices(int sink_index) {
}
}
void ConfigureAudio::retranslateUi() {
void ConfigureAudio::RetranslateUI() {
ui->retranslateUi(this);
}

View File

@@ -18,16 +18,16 @@ public:
explicit ConfigureAudio(QWidget* parent = nullptr);
~ConfigureAudio() override;
void applyConfiguration();
void retranslateUi();
void ApplyConfiguration();
void RetranslateUI();
private:
void updateAudioDevices(int sink_index);
void UpdateAudioDevices(int sink_index);
void setConfiguration();
void setOutputSinkFromSinkID();
void setAudioDeviceFromDeviceID();
void setVolumeIndicatorText(int percentage);
void SetConfiguration();
void SetOutputSinkFromSinkID();
void SetAudioDeviceFromDeviceID();
void SetVolumeIndicatorText(int percentage);
std::unique_ptr<Ui::ConfigureAudio> ui;
};

View File

@@ -20,7 +20,7 @@
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_1">
<property name="text">
<string>Output Engine:</string>
</property>
@@ -44,7 +44,7 @@
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Audio Device:</string>
</property>
@@ -61,7 +61,7 @@
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Volume:</string>
</property>

View File

@@ -16,7 +16,8 @@
ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureDebug) {
ui->setupUi(this);
this->setConfiguration();
SetConfiguration();
connect(ui->open_log_button, &QPushButton::pressed, []() {
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
@@ -25,7 +26,7 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::Co
ConfigureDebug::~ConfigureDebug() = default;
void ConfigureDebug::setConfiguration() {
void ConfigureDebug::SetConfiguration() {
ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub);
ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub);
ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port);
@@ -37,7 +38,7 @@ void ConfigureDebug::setConfiguration() {
ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso);
}
void ConfigureDebug::applyConfiguration() {
void ConfigureDebug::ApplyConfiguration() {
Settings::values.use_gdbstub = ui->toggle_gdbstub->isChecked();
Settings::values.gdbstub_port = ui->gdbport_spinbox->value();
UISettings::values.show_console = ui->toggle_console->isChecked();

View File

@@ -18,10 +18,10 @@ public:
explicit ConfigureDebug(QWidget* parent = nullptr);
~ConfigureDebug() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void setConfiguration();
void SetConfiguration();
std::unique_ptr<Ui::ConfigureDebug> ui;
};

View File

@@ -45,7 +45,7 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="label_1">
<property name="text">
<string>Port:</string>
</property>
@@ -70,11 +70,11 @@
<property name="title">
<string>Logging</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Global Log Filter</string>
</property>
@@ -86,7 +86,7 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="toggle_console">
<property name="text">
@@ -111,11 +111,11 @@
<property name="title">
<string>Homebrew</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Arguments String</string>
</property>
@@ -134,7 +134,7 @@
<property name="title">
<string>Dump</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QCheckBox" name="dump_decompressed_nso">
<property name="whatsThis">

View File

@@ -15,11 +15,11 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
: QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) {
ui->setupUi(this);
ui->hotkeysTab->Populate(registry);
this->setConfiguration();
this->PopulateSelectionList();
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
SetConfiguration();
PopulateSelectionList();
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
&ConfigureDialog::UpdateVisibleTabs);
@@ -29,19 +29,19 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
ConfigureDialog::~ConfigureDialog() = default;
void ConfigureDialog::setConfiguration() {}
void ConfigureDialog::SetConfiguration() {}
void ConfigureDialog::applyConfiguration() {
ui->generalTab->applyConfiguration();
ui->gameListTab->applyConfiguration();
ui->systemTab->applyConfiguration();
ui->profileManagerTab->applyConfiguration();
ui->inputTab->applyConfiguration();
ui->hotkeysTab->applyConfiguration(registry);
ui->graphicsTab->applyConfiguration();
ui->audioTab->applyConfiguration();
ui->debugTab->applyConfiguration();
ui->webTab->applyConfiguration();
void ConfigureDialog::ApplyConfiguration() {
ui->generalTab->ApplyConfiguration();
ui->gameListTab->ApplyConfiguration();
ui->systemTab->ApplyConfiguration();
ui->profileManagerTab->ApplyConfiguration();
ui->inputTab->ApplyConfiguration();
ui->hotkeysTab->ApplyConfiguration(registry);
ui->graphicsTab->ApplyConfiguration();
ui->audioTab->ApplyConfiguration();
ui->debugTab->ApplyConfiguration();
ui->webTab->ApplyConfiguration();
Settings::Apply();
Settings::LogSettings();
}

View File

@@ -20,10 +20,10 @@ public:
explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry);
~ConfigureDialog() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void setConfiguration();
void SetConfiguration();
void UpdateVisibleTabs();
void PopulateSelectionList();

View File

@@ -12,20 +12,20 @@
#include "yuzu/ui_settings.h"
namespace {
constexpr std::array<std::pair<u32, const char*>, 5> default_icon_sizes{{
constexpr std::array default_icon_sizes{
std::make_pair(0, QT_TR_NOOP("None")),
std::make_pair(32, QT_TR_NOOP("Small (32x32)")),
std::make_pair(64, QT_TR_NOOP("Standard (64x64)")),
std::make_pair(128, QT_TR_NOOP("Large (128x128)")),
std::make_pair(256, QT_TR_NOOP("Full Size (256x256)")),
}};
};
constexpr std::array<const char*, 4> row_text_names{{
constexpr std::array row_text_names{
QT_TR_NOOP("Filename"),
QT_TR_NOOP("Filetype"),
QT_TR_NOOP("Title ID"),
QT_TR_NOOP("Title Name"),
}};
};
} // Anonymous namespace
ConfigureGameList::ConfigureGameList(QWidget* parent)
@@ -35,7 +35,7 @@ ConfigureGameList::ConfigureGameList(QWidget* parent)
InitializeIconSizeComboBox();
InitializeRowComboBoxes();
this->setConfiguration();
SetConfiguration();
// Force game list reload if any of the relevant settings are changed.
connect(ui->show_unknown, &QCheckBox::stateChanged, this,
@@ -50,7 +50,7 @@ ConfigureGameList::ConfigureGameList(QWidget* parent)
ConfigureGameList::~ConfigureGameList() = default;
void ConfigureGameList::applyConfiguration() {
void ConfigureGameList::ApplyConfiguration() {
UISettings::values.show_unknown = ui->show_unknown->isChecked();
UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
@@ -63,7 +63,7 @@ void ConfigureGameList::RequestGameListUpdate() {
UISettings::values.is_game_list_reload_pending.exchange(true);
}
void ConfigureGameList::setConfiguration() {
void ConfigureGameList::SetConfiguration() {
ui->show_unknown->setChecked(UISettings::values.show_unknown);
ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
ui->icon_size_combobox->setCurrentIndex(

View File

@@ -18,12 +18,12 @@ public:
explicit ConfigureGameList(QWidget* parent = nullptr);
~ConfigureGameList() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void RequestGameListUpdate();
void setConfiguration();
void SetConfiguration();
void changeEvent(QEvent*) override;
void RetranslateUI();

View File

@@ -18,7 +18,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
QString::fromUtf8(theme.second));
}
this->setConfiguration();
SetConfiguration();
connect(ui->toggle_deepscan, &QCheckBox::stateChanged, this,
[] { UISettings::values.is_game_list_reload_pending.exchange(true); });
@@ -28,7 +28,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
ConfigureGeneral::~ConfigureGeneral() = default;
void ConfigureGeneral::setConfiguration() {
void ConfigureGeneral::SetConfiguration() {
ui->toggle_deepscan->setChecked(UISettings::values.game_directory_deepscan);
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
@@ -36,7 +36,7 @@ void ConfigureGeneral::setConfiguration() {
ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit);
}
void ConfigureGeneral::applyConfiguration() {
void ConfigureGeneral::ApplyConfiguration() {
UISettings::values.game_directory_deepscan = ui->toggle_deepscan->isChecked();
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();

View File

@@ -20,10 +20,10 @@ public:
explicit ConfigureGeneral(QWidget* parent = nullptr);
~ConfigureGeneral() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void setConfiguration();
void SetConfiguration();
std::unique_ptr<Ui::ConfigureGeneral> ui;
};

Some files were not shown because too many files have changed in this diff Show More