Compare commits

..

69 Commits

Author SHA1 Message Date
8df7144ada Android #106 2023-10-20 00:57:27 +00:00
85a89ca3e3 Merge pull request #11822 from german77/no-name
service: mii: Create random mii with name
2023-10-19 16:54:05 -04:00
26776c0e60 service: mii: Create random mii with name 2023-10-19 13:35:02 -06:00
134ecca9b0 Merge pull request #11810 from liamwhite/clang-17
general: fix build failure on clang 17
2023-10-18 19:30:29 -04:00
c5f1ec8040 Merge pull request #11795 from Squall-Leonhart/D32FToOther
[Vulkan]Implement missing copy formats for D32, ARGB8_SRGB and BGRA8_Unorm/SRGB
2023-10-18 09:22:14 -04:00
765ea9b79d Merge pull request #11791 from german77/bufferx
service: hle: Allow to access read buffer A and X directly
2023-10-18 09:21:58 -04:00
c5bdc0054c general: fix build failure on clang 17 2023-10-17 22:44:21 -04:00
bd05ace08d Merge pull request #11774 from liamwhite/refcount-issue
fsmitm_romfsbuild: avoid unnecessary copies of vfs pointers
2023-10-17 11:49:11 -04:00
fa56518f20 Merge pull request #11747 from Kelebek1/image_alias_sample_names
Small things
2023-10-17 11:48:57 -04:00
b577d7a55f Merge pull request #11349 from vonchenplus/buffer_cache_crash
video_core: Fix moltenvk crash on macos
2023-10-17 11:48:44 -04:00
2244b613cf Merge pull request #11788 from Squall-Leonhart/IFREMOVED
[crash fix]brings back the removed if  statement in util.cpp and adds the  num_level test to it like previous discontinued PR
2023-10-17 14:36:36 +02:00
c73bb33ff1 service: hle: Allow to access read buffer A and X directly 2023-10-16 23:36:46 -06:00
bcce184e60 service: acc: Implement functions needed for profile select (#11653) 2023-10-17 05:12:55 +02:00
326ebbb2fa Changes based on hardware tests
Removes unnecessary d32f to bgra shader and blit functions,
update vk_texture_cache to use abgr shader for d32f to BGRA formats
updates  abgr to d32f shader to comply with hardware tests
2023-10-17 02:42:40 +11:00
07143ce15c Make Clang happy. 2023-10-17 00:26:19 +11:00
dbc73c6c6c Added missing BuildShader line
Adds `convert_abgr8_to_d32f_frag(BuildShader(device, CONVERT_ABGR8_TO_D32F_FRAG_SPV)),`
2023-10-17 00:15:31 +11:00
8becf13e8b Merge pull request #11786 from v1993/cuda-on-linux
host1x/codecs: enable CUDA on Linux
2023-10-15 22:23:00 -04:00
9e2ebb24df Merge pull request #11794 from german77/linemot
input_common: udp: Avoid crash when trying to map motion before client is ready
2023-10-15 22:22:45 -04:00
90c56f5dc1 added missing trailing line. 2023-10-16 06:07:26 +11:00
4b0291172e meant to add the unorms as well 2023-10-16 04:29:24 +11:00
12e4757cf3 use texelfetch instead of texturelod 2023-10-16 04:20:45 +11:00
144c0734f5 appease the format gods 2023-10-16 03:24:44 +11:00
f40f65f5d2 Another missing copy connected to Bravely Default II
adds blit_image_helper.ConvertABGR8ToD32F and fragment shader for performing ABGR and BGRA to D32F copies
2023-10-16 03:17:53 +11:00
03c3f936cf missed this line when editing the copypasta 2023-10-15 20:58:50 +11:00
66f41da365 moved line to appease the format gods 2023-10-15 20:54:25 +11:00
7a986d731b Implement missing formats for Bravely Default 2 2023-10-15 20:43:48 +11:00
eae0570a1c input_common: udp: Avoid crash when trying to map motion before client is ready 2023-10-15 02:13:51 -06:00
b57d98f847 brings back the removed If statement and adds the num_level test
This resolves the out of bounds read/writes in the linear swizzler, it brings back the scaled TOTK Recall bug however, pending further work in the block size calculation.

Recall is not glitched in the Dynamic FPS resolution mod to the degree that it is in the native yuzu scaler, this can be a workaround for the time being.


The recall effect is constructed from multiple 320x180 texture slices, it breaking may have a similar origin to https://github.com/Ryujinx/Ryujinx/pull/5640

but it may also be connected to the other deficiencies identified in the Yuzu size calculations, such as no apparent implementation of slice testing for end of slce depth as opposed to full aligned size as implemented in https://github.com/Ryujinx/Ryujinx/pull/5220
2023-10-15 02:09:28 +11:00
762ac5aa9f host1x/codecs: enable CUDA on Linux 2023-10-14 17:35:45 +03:00
1a4abd184f Merge pull request #11780 from Darkness4/master
qt: add network components when using discord
2023-10-14 09:58:33 -04:00
9524d7034c Merge pull request #11779 from flodavid/improve-player-config-click
yuzu: Improve behavior when clicking on controller box in Control configuration
2023-10-14 09:58:27 -04:00
36d18e457b Merge pull request #11778 from liamwhite/audren-shutdown-lock
audio: fix shutdown deadlock in audio renderer
2023-10-14 09:58:17 -04:00
db562bc08d Merge pull request #11775 from Kelebek1/draw_vertex_array
Implement vertex array first and subsequent draws
2023-10-14 09:58:11 -04:00
18672e6a78 Merge pull request #11159 from flodavid/master_bis
Enable to use controller to close a game
2023-10-14 09:58:03 -04:00
32ad99701d Implement vertex array first and subsequent draws 2023-10-14 12:09:35 +01:00
63c5340cc4 Revert "cmake: only add network component if qt used"
This reverts commit a94371f67b.
2023-10-14 08:46:05 +02:00
a94371f67b cmake: only add network component if qt used 2023-10-14 01:46:20 +02:00
22e4add562 qt: add missing target_link_libraries for discordrpc 2023-10-14 01:15:28 +02:00
b1a7bbd458 qt: add network components when using discord 2023-10-14 01:01:02 +02:00
27ab2a6e13 yuzu: Improve behavior when clicking on controller box in Control Configuration
When reducing the number of Connecter Controllers, keep the one clicked if it was not the last one of the list
2023-10-14 00:46:11 +02:00
68ea0a2b72 audio: fix shutdown deadlock in audio renderer 2023-10-13 16:34:31 -04:00
a8bd02acd8 Merge pull request #11772 from v1993/polyfill-thread-fixes
common/polyfill_thread: use std::forward where appropriate, qualify std::move calls
2023-10-13 15:15:25 -04:00
3e4edbe007 Merge pull request #11767 from t895/gradle-stuff
android: Update dependencies
2023-10-13 15:08:47 -04:00
4a9240599a Merge pull request #11773 from t895/manager-fix
android: Fix incorrect assumption for driver installation validation
2023-10-13 15:08:39 -04:00
053a16799e fsmitm_romfsbuild: avoid unnecessary copies of vfs pointers 2023-10-13 14:22:52 -04:00
82c845dc2f android: Fix incorrect assumption for driver installation validation
The driver was assumed to be installed at this point before I made a refactor. Now we just check if the copy operation was successful and delete the file if it fails.
2023-10-13 13:50:38 -04:00
3aa6d4d8ce android: Allow ANDROID_STL 2023-10-13 12:55:41 -04:00
9b961dddb4 android: Remove unnecessary flag to extract native libs in AndroidManifest.xml 2023-10-13 12:55:41 -04:00
224b6036a4 android: Update dependencies
Updates to androidx navigation, lifecycle, preference, fragment, recyclerview, and core
2023-10-13 12:55:41 -04:00
2c3281c66b externals: Update LLVM to 17.0.2
Matches android ndk
2023-10-13 12:55:41 -04:00
1591923f91 android: Update ndk to 26.1.10909125
The new ndk uses LLVM 17.0.2 so we can remove the LLVM download and libc++ options for the android builds
2023-10-13 12:55:41 -04:00
56e5d99684 Improvement in Directory Path Detection for Shortcuts (#11749)
* Improvement in Directory Path Detection for Shortcuts

This pull request updates how the directory path for shortcuts is determined. The main changes are:

1. Replaced the use of environment variables to determine the path of the desktop and applications menu with `QStandardPaths::writableLocation`. This change addresses an issue where the desktop path was not correctly identified when its location was customized, as shown in the attached screenshot.

2. Added conversion from `QString` to `std::string` using `toUtf8()`, which correctly handles non-ASCII characters in directory paths. This change ensures that directory paths containing Portuguese words like "Área de trabalho" are supported.

3. Replaced directory checking using `Common::FS::IsDir()` with `QDir::exists()`.

These changes should improve cross-platform compatibility and code robustness. Because it couldn't locate my desktop, which wasn't on the C drive, but on the F, and even though localization wouldn't work because it was setting it to find the 'Desktop' folder and in the computer's language it says 'Área de trabalho', that will fix for other languages too.

* Update main.cpp

* formatting

* Update src/yuzu/main.cpp

Co-authored-by: Tobias <thm.frey@gmail.com>

* Update src/yuzu/main.cpp

Co-authored-by: Tobias <thm.frey@gmail.com>

* Update main.cpp

* Update main.cpp

* Update main.cpp

desktopPath > desktop_Path
applicationsPath > applications_Path

* Update main.cpp

* formatting

* Update main.cpp

This code will attempt to use QStandardPaths to find the applications directory. If that fails, it will resort to using the ~/.local/share/applications directory, which is a common location for application shortcuts in Linux.

* Update main.cpp

* formatting

---------

Co-authored-by: Tobias <thm.frey@gmail.com>
2023-10-13 09:57:49 -06:00
ca75c9125d common/polyfill_thread: use std::forward where appropriate, qualify std::move calls 2023-10-13 18:51:11 +03:00
1a4874e178 Merge pull request #11769 from liamwhite/qt-ownership-issue
qt: ensure worker cancellation is complete before clearing
2023-10-13 09:29:13 -04:00
c00b63b9e1 Merge pull request #11766 from liamwhite/open-sesame
k_page_table: add missing page group open when locking memory
2023-10-13 09:29:05 -04:00
c8602e1b1f Merge pull request #11649 from t895/driver-manager
android: Driver manager
2023-10-13 09:28:53 -04:00
faa6c35e78 qt: ensure worker cancellation is complete before clearing 2023-10-12 21:07:49 -04:00
8b64878258 android: Update AGP to 8.1.2 2023-10-12 18:59:57 -04:00
a5fb9de6fa android: Add GPU driver management fragment
Implements a GPU driver manager that saves all drivers to the user data directory and asynchronously installs drivers when they're needed.
2023-10-12 17:17:21 -04:00
c4ec76edba k_page_table: add missing page group open when locking memory 2023-10-12 15:00:26 -04:00
d9456f0a11 fix style 2023-10-12 16:06:44 +02:00
48b67fc4a0 yuzu: Enable to use controller to restart a game
- Show the right confirm dialog if wanted
  - Create generic method to ask close confirmation
- Add "R + Plus + Minus" default shortcut to Restart emulation
2023-10-12 01:53:54 +02:00
6c246f2ac5 yuzu: Use new setting method for stop emulation 2023-10-12 01:51:53 +02:00
a34565727b yuzu: Enable to use controller to close a game
- Add General setting to choose if a confirm dialog is shown when stopping
- Show the right confirm dialog if wanted
  - Reuse dialog window that ask to close the game
- Add "L + Plus + Minus" default shortcut to Stop emulation
- Create generic question dialog based on TAS dialog
  - It allows controller interaction on most dialogs
2023-10-12 01:51:52 +02:00
98cac9410c Get out of render pass before query barriers, fix image names with samples > 1, remove image alias bit 2023-10-11 17:15:35 +01:00
26f9d1f122 android: Use application context for all FileUtil functions 2023-10-01 15:56:02 -04:00
e69eebb14a video_core: Fix d24r8/s8d24 convert shader build error in moltenvk 2023-09-07 18:01:36 +08:00
0145c89879 video_core: Add missing scissor update when viewport scale offset disable 2023-09-07 18:01:30 +08:00
cc4736fa58 video_core: set vertex buffer num to 16, because mvk have when using more than 16 2023-08-23 23:22:55 +08:00
63 changed files with 615 additions and 337 deletions

View File

@ -11,7 +11,6 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modul
include(DownloadExternals)
include(CMakeDependentOption)
include(CTest)
include(FetchContent)
# Set bundled sdl2/qt as dependent options.
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
@ -99,47 +98,8 @@ if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL)
DESTINATION "${vvl_lib_path}")
endif()
# On Android, fetch and compile libcxx before doing anything else
if (ANDROID)
set(CMAKE_SKIP_INSTALL_RULES ON)
set(LLVM_VERSION "15.0.6")
# Note: even though libcxx and libcxxabi have separate releases on the project page,
# the separated releases cannot be compiled. Only in-tree builds work. Therefore we
# must fetch the source release for the entire llvm tree.
FetchContent_Declare(llvm
URL "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz"
URL_HASH SHA256=9d53ad04dc60cb7b30e810faf64c5ab8157dadef46c8766f67f286238256ff92
TLS_VERIFY TRUE
)
FetchContent_MakeAvailable(llvm)
# libcxx has support for most of the range library, but it's gated behind a flag:
add_compile_definitions(_LIBCPP_ENABLE_EXPERIMENTAL)
# Disable standard header inclusion
set(ANDROID_STL "none")
# libcxxabi
set(LIBCXXABI_INCLUDE_TESTS OFF)
set(LIBCXXABI_ENABLE_SHARED FALSE)
set(LIBCXXABI_ENABLE_STATIC TRUE)
set(LIBCXXABI_LIBCXX_INCLUDES "${LIBCXX_TARGET_INCLUDE_DIRECTORY}" CACHE STRING "" FORCE)
add_subdirectory("${llvm_SOURCE_DIR}/libcxxabi" "${llvm_BINARY_DIR}/libcxxabi")
link_libraries(cxxabi_static)
# libcxx
set(LIBCXX_ABI_NAMESPACE "__ndk1" CACHE STRING "" FORCE)
set(LIBCXX_CXX_ABI "libcxxabi")
set(LIBCXX_INCLUDE_TESTS OFF)
set(LIBCXX_INCLUDE_BENCHMARKS OFF)
set(LIBCXX_INCLUDE_DOCS OFF)
set(LIBCXX_ENABLE_SHARED FALSE)
set(LIBCXX_ENABLE_STATIC TRUE)
set(LIBCXX_ENABLE_ASSERTIONS FALSE)
add_subdirectory("${llvm_SOURCE_DIR}/libcxx" "${llvm_BINARY_DIR}/libcxx")
set_target_properties(cxx-headers PROPERTIES INTERFACE_COMPILE_OPTIONS "-isystem${CMAKE_BINARY_DIR}/${LIBCXX_INSTALL_INCLUDE_DIR}")
link_libraries(cxx_static cxx-headers)
endif()
if (YUZU_USE_BUNDLED_VCPKG)
@ -329,7 +289,7 @@ find_package(Boost 1.79.0 REQUIRED context)
find_package(enet 1.3 MODULE)
find_package(fmt 9 REQUIRED)
find_package(inih 52 MODULE COMPONENTS INIReader)
find_package(LLVM 17 MODULE COMPONENTS Demangle)
find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle)
find_package(lz4 REQUIRED)
find_package(nlohmann_json 3.8 REQUIRED)
find_package(Opus 1.3 MODULE)
@ -400,6 +360,9 @@ function(set_yuzu_qt_components)
if (ENABLE_QT_TRANSLATION)
list(APPEND YUZU_QT_COMPONENTS2 LinguistTools)
endif()
if (USE_DISCORD_PRESENCE)
list(APPEND YUZU_QT_COMPONENTS2 Network)
endif()
set(YUZU_QT_COMPONENTS ${YUZU_QT_COMPONENTS2} PARENT_SCOPE)
endfunction(set_yuzu_qt_components)

View File

@ -1,6 +1,5 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [11649](https://github.com/yuzu-emu/yuzu//pull/11649) | [`a5fb9de6f`](https://github.com/yuzu-emu/yuzu//pull/11649/files) | android: Driver manager | [t895](https://github.com/t895/) | Yes |
End of merge log. You can find the original README.md below the break.

View File

@ -27,7 +27,7 @@ android {
namespace = "org.yuzu.yuzu_emu"
compileSdkVersion = "android-34"
ndkVersion = "25.2.9519653"
ndkVersion = "26.1.10909125"
buildFeatures {
viewBinding = true
@ -203,23 +203,23 @@ ktlint {
}
dependencies {
implementation("androidx.core:core-ktx:1.10.1")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.recyclerview:recyclerview:1.3.0")
implementation("androidx.recyclerview:recyclerview:1.3.1")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.fragment:fragment-ktx:1.6.0")
implementation("androidx.fragment:fragment-ktx:1.6.1")
implementation("androidx.documentfile:documentfile:1.0.1")
implementation("com.google.android.material:material:1.9.0")
implementation("androidx.preference:preference:1.2.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
implementation("androidx.preference:preference-ktx:1.2.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
implementation("io.coil-kt:coil:2.2.2")
implementation("androidx.core:core-splashscreen:1.0.1")
implementation("androidx.window:window:1.2.0-beta03")
implementation("org.ini4j:ini4j:0.5.4")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.navigation:navigation-fragment-ktx:2.6.0")
implementation("androidx.navigation:navigation-ui-ktx:2.6.0")
implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
implementation("androidx.navigation:navigation-ui-ktx:2.7.4")
implementation("info.debatty:java-string-similarity:2.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
}

View File

@ -28,7 +28,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:appCategory="game"
android:localeConfig="@xml/locales_config"
android:banner="@drawable/tv_banner"
android:extractNativeLibs="true"
android:fullBackupContent="@xml/data_extraction_rules"
android:dataExtractionRules="@xml/data_extraction_rules_api_31"
android:enableOnBackInvokedCallback="true">

View File

@ -26,6 +26,7 @@ import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import java.io.File
import java.io.IOException
class DriverManagerFragment : Fragment() {
@ -154,29 +155,29 @@ class DriverManagerFragment : Fragment() {
R.string.installing_driver,
false
) {
val driverPath =
"${GpuDriverHelper.driverStoragePath}/${FileUtil.getFilename(result)}"
val driverFile = File(driverPath)
// Ignore file exceptions when a user selects an invalid zip
try {
GpuDriverHelper.copyDriverToInternalStorage(result)
if (!GpuDriverHelper.copyDriverToInternalStorage(result)) {
throw IOException("Driver failed validation!")
}
} catch (_: IOException) {
if (driverFile.exists()) {
driverFile.delete()
}
return@newInstance getString(R.string.select_gpu_driver_error)
}
val driverData = GpuDriverHelper.customDriverData
if (driverData.name == null) {
return@newInstance getString(R.string.select_gpu_driver_error)
}
val driverData = GpuDriverHelper.getMetadataFromZip(driverFile)
val driverInList =
driverViewModel.driverList.value.firstOrNull { it.second == driverData }
if (driverInList != null) {
return@newInstance getString(R.string.driver_already_installed)
} else {
driverViewModel.addDriver(
Pair(
"${GpuDriverHelper.driverStoragePath}/${FileUtil.getFilename(result)}",
driverData
)
)
driverViewModel.addDriver(Pair(driverPath, driverData))
driverViewModel.setNewDriverInstalled(true)
}
return@newInstance Any()

View File

@ -3,8 +3,8 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.0.2" apply false
id("com.android.library") version "8.0.2" apply false
id("com.android.application") version "8.1.2" apply false
id("com.android.library") version "8.1.2" apply false
id("org.jetbrains.kotlin.android") version "1.8.21" apply false
}

View File

@ -204,6 +204,10 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
// paused and we'll desync, so just play silence.
if (system.IsPaused() || system.IsShuttingDown()) {
if (system.IsShuttingDown()) {
{
std::scoped_lock lk{release_mutex};
queued_buffers.store(0);
}
release_cv.notify_one();
}

View File

@ -15,12 +15,13 @@
#include <condition_variable>
#include <stop_token>
#include <thread>
#include <utility>
namespace Common {
template <typename Condvar, typename Lock, typename Pred>
void CondvarWait(Condvar& cv, std::unique_lock<Lock>& lk, std::stop_token token, Pred&& pred) {
cv.wait(lk, token, std::move(pred));
cv.wait(lk, token, std::forward<Pred>(pred));
}
template <typename Rep, typename Period>
@ -109,7 +110,7 @@ public:
// Insert the callback.
stop_state_callback ret = ++m_next_callback;
m_callbacks.emplace(ret, move(f));
m_callbacks.emplace(ret, std::move(f));
return ret;
}
@ -162,7 +163,7 @@ private:
friend class stop_source;
template <typename Callback>
friend class stop_callback;
stop_token(shared_ptr<polyfill::stop_state> stop_state) : m_stop_state(move(stop_state)) {}
stop_token(shared_ptr<polyfill::stop_state> stop_state) : m_stop_state(std::move(stop_state)) {}
private:
shared_ptr<polyfill::stop_state> m_stop_state;
@ -198,7 +199,7 @@ public:
private:
friend class jthread;
explicit stop_source(shared_ptr<polyfill::stop_state> stop_state)
: m_stop_state(move(stop_state)) {}
: m_stop_state(std::move(stop_state)) {}
private:
shared_ptr<polyfill::stop_state> m_stop_state;
@ -218,16 +219,16 @@ public:
C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
: m_stop_state(st.m_stop_state) {
if (m_stop_state) {
m_callback = m_stop_state->insert_callback(move(cb));
m_callback = m_stop_state->insert_callback(std::move(cb));
}
}
template <typename C>
requires constructible_from<Callback, C>
explicit stop_callback(stop_token&& st,
C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
: m_stop_state(move(st.m_stop_state)) {
: m_stop_state(std::move(st.m_stop_state)) {
if (m_stop_state) {
m_callback = m_stop_state->insert_callback(move(cb));
m_callback = m_stop_state->insert_callback(std::move(cb));
}
}
~stop_callback() {
@ -260,7 +261,7 @@ public:
typename = enable_if_t<!is_same_v<remove_cvref_t<F>, jthread>>>
explicit jthread(F&& f, Args&&... args)
: m_stop_state(make_shared<polyfill::stop_state>()),
m_thread(make_thread(move(f), move(args)...)) {}
m_thread(make_thread(std::forward<F>(f), std::forward<Args>(args)...)) {}
~jthread() {
if (joinable()) {
@ -317,9 +318,9 @@ private:
template <typename F, typename... Args>
thread make_thread(F&& f, Args&&... args) {
if constexpr (is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>) {
return thread(move(f), get_stop_token(), move(args)...);
return thread(std::forward<F>(f), get_stop_token(), std::forward<Args>(args)...);
} else {
return thread(move(f), move(args)...);
return thread(std::forward<F>(f), std::forward<Args>(args)...);
}
}

View File

@ -45,6 +45,7 @@ SWITCHABLE(CpuAccuracy, true);
SWITCHABLE(FullscreenMode, true);
SWITCHABLE(GpuAccuracy, true);
SWITCHABLE(Language, true);
SWITCHABLE(MemoryLayout, true);
SWITCHABLE(NvdecEmulation, false);
SWITCHABLE(Region, true);
SWITCHABLE(RendererBackend, true);
@ -61,6 +62,10 @@ SWITCHABLE(u32, false);
SWITCHABLE(u8, false);
SWITCHABLE(u8, true);
// Used in UISettings
// TODO see if we can move this to uisettings.cpp
SWITCHABLE(ConfirmStop, true);
#undef SETTING
#undef SWITCHABLE
#endif

View File

@ -67,6 +67,7 @@ SWITCHABLE(CpuAccuracy, true);
SWITCHABLE(FullscreenMode, true);
SWITCHABLE(GpuAccuracy, true);
SWITCHABLE(Language, true);
SWITCHABLE(MemoryLayout, true);
SWITCHABLE(NvdecEmulation, false);
SWITCHABLE(Region, true);
SWITCHABLE(RendererBackend, true);
@ -83,6 +84,10 @@ SWITCHABLE(u32, false);
SWITCHABLE(u8, false);
SWITCHABLE(u8, true);
// Used in UISettings
// TODO see if we can move this to uisettings.h
SWITCHABLE(ConfirmStop, true);
#undef SETTING
#undef SWITCHABLE
#endif

View File

@ -133,6 +133,8 @@ ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
ENUM(FullscreenMode, Borderless, Exclusive);
ENUM(NvdecEmulation, Off, Cpu, Gpu);

View File

@ -116,11 +116,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
}
}
if (concat.empty()) {
return nullptr;
}
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(dir->GetName(),
std::move(concat));
}
if (Common::FS::IsDir(path)) {

View File

@ -107,62 +107,56 @@ static u64 romfs_get_hash_table_count(u64 num_entries) {
void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir,
std::shared_ptr<RomFSBuildDirectoryContext> parent) {
std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs;
for (auto& child_romfs_file : romfs_dir->GetFiles()) {
const auto name = child_romfs_file->GetName();
const auto child = std::make_shared<RomFSBuildFileContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
child->path_len = child->cur_path_ofs + static_cast<u32>(name.size());
child->path = parent->path + "/" + name;
const auto entries = romfs_dir->GetEntries();
if (ext_dir != nullptr && ext_dir->GetFile(name + ".stub") != nullptr) {
continue;
}
for (const auto& kv : entries) {
if (kv.second == VfsEntryType::Directory) {
const auto child = std::make_shared<RomFSBuildDirectoryContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
child->path = parent->path + "/" + kv.first;
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
if (ext_dir != nullptr && ext_dir->GetFile(kv.first + ".stub") != nullptr) {
continue;
}
child->source = std::move(child_romfs_file);
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
if (AddDirectory(parent, child)) {
child_dirs.push_back(child);
}
} else {
const auto child = std::make_shared<RomFSBuildFileContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
child->path = parent->path + "/" + kv.first;
if (ext_dir != nullptr && ext_dir->GetFile(kv.first + ".stub") != nullptr) {
continue;
}
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
child->source = romfs_dir->GetFile(kv.first);
if (ext_dir != nullptr) {
if (const auto ips = ext_dir->GetFile(kv.first + ".ips")) {
if (auto patched = PatchIPS(child->source, ips)) {
child->source = std::move(patched);
}
if (ext_dir != nullptr) {
if (const auto ips = ext_dir->GetFile(name + ".ips")) {
if (auto patched = PatchIPS(child->source, ips)) {
child->source = std::move(patched);
}
}
child->size = child->source->GetSize();
AddFile(parent, child);
}
child->size = child->source->GetSize();
AddFile(parent, child);
}
for (auto& child : child_dirs) {
auto subdir_name = std::string_view(child->path).substr(child->cur_path_ofs);
auto child_romfs_dir = romfs_dir->GetSubdirectory(subdir_name);
auto child_ext_dir = ext_dir != nullptr ? ext_dir->GetSubdirectory(subdir_name) : nullptr;
for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) {
const auto name = child_romfs_dir->GetName();
const auto child = std::make_shared<RomFSBuildDirectoryContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
child->path_len = child->cur_path_ofs + static_cast<u32>(name.size());
child->path = parent->path + "/" + name;
if (ext_dir != nullptr && ext_dir->GetFile(name + ".stub") != nullptr) {
continue;
}
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
if (!AddDirectory(parent, child)) {
continue;
}
auto child_ext_dir = ext_dir != nullptr ? ext_dir->GetSubdirectory(name) : nullptr;
this->VisitDirectory(child_romfs_dir, child_ext_dir, child);
}
}
@ -293,7 +287,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
cur_entry.name_size = name_size;
out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source);
out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source));
std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry));
std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0,
Common::AlignUp(cur_entry.name_size, 4));

View File

@ -377,16 +377,16 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
auto romfs_dir = FindSubdirectoryCaseless(subdir, "romfs");
if (romfs_dir != nullptr)
layers.push_back(std::make_shared<CachedVfsDirectory>(romfs_dir));
layers.emplace_back(std::make_shared<CachedVfsDirectory>(std::move(romfs_dir)));
auto ext_dir = FindSubdirectoryCaseless(subdir, "romfs_ext");
if (ext_dir != nullptr)
layers_ext.push_back(std::make_shared<CachedVfsDirectory>(ext_dir));
layers_ext.emplace_back(std::make_shared<CachedVfsDirectory>(std::move(ext_dir)));
if (type == ContentRecordType::HtmlDocument) {
auto manual_dir = FindSubdirectoryCaseless(subdir, "manual_html");
if (manual_dir != nullptr)
layers.push_back(std::make_shared<CachedVfsDirectory>(manual_dir));
layers.emplace_back(std::make_shared<CachedVfsDirectory>(std::move(manual_dir)));
}
}
@ -400,7 +400,7 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
return;
}
layers.push_back(std::move(extracted));
layers.emplace_back(std::move(extracted));
auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
if (layered == nullptr) {

View File

@ -322,7 +322,8 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& open_di
return nullptr;
}
return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
auto name = concat.front()->GetName();
return ConcatenatedVfsFile::MakeConcatenatedFile(std::move(name), std::move(concat));
}
VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {

View File

@ -133,7 +133,7 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) {
out = out->GetSubdirectories().front();
}
return std::make_shared<CachedVfsDirectory>(out);
return std::make_shared<CachedVfsDirectory>(std::move(out));
}
VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
@ -141,8 +141,7 @@ VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
return nullptr;
RomFSBuildContext ctx{dir, ext};
auto file_map = ctx.Build();
return ConcatenatedVfsFile::MakeConcatenatedFile(0, file_map, dir->GetName());
return ConcatenatedVfsFile::MakeConcatenatedFile(0, dir->GetName(), ctx.Build());
}
} // namespace FileSys

View File

@ -6,13 +6,13 @@
namespace FileSys {
CachedVfsDirectory::CachedVfsDirectory(VirtualDir& source_dir)
CachedVfsDirectory::CachedVfsDirectory(VirtualDir&& source_dir)
: name(source_dir->GetName()), parent(source_dir->GetParentDirectory()) {
for (auto& dir : source_dir->GetSubdirectories()) {
dirs.emplace(dir->GetName(), std::make_shared<CachedVfsDirectory>(dir));
dirs.emplace(dir->GetName(), std::make_shared<CachedVfsDirectory>(std::move(dir)));
}
for (auto& file : source_dir->GetFiles()) {
files.emplace(file->GetName(), file);
files.emplace(file->GetName(), std::move(file));
}
}

View File

@ -11,7 +11,7 @@ namespace FileSys {
class CachedVfsDirectory : public ReadOnlyVfsDirectory {
public:
CachedVfsDirectory(VirtualDir& source_directory);
CachedVfsDirectory(VirtualDir&& source_directory);
~CachedVfsDirectory() override;
VirtualFile GetFile(std::string_view file_name) const override;

View File

@ -10,7 +10,7 @@
namespace FileSys {
ConcatenatedVfsFile::ConcatenatedVfsFile(ConcatenationMap&& concatenation_map_, std::string&& name_)
ConcatenatedVfsFile::ConcatenatedVfsFile(std::string&& name_, ConcatenationMap&& concatenation_map_)
: concatenation_map(std::move(concatenation_map_)), name(std::move(name_)) {
DEBUG_ASSERT(this->VerifyContinuity());
}
@ -30,8 +30,8 @@ bool ConcatenatedVfsFile::VerifyContinuity() const {
ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(const std::vector<VirtualFile>& files,
std::string&& name) {
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::string&& name,
std::vector<VirtualFile>&& files) {
// Fold trivial cases.
if (files.empty()) {
return nullptr;
@ -46,20 +46,21 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(const std::vector<VirtualF
u64 last_offset = 0;
for (auto& file : files) {
const auto size = file->GetSize();
concatenation_map.emplace_back(ConcatenationEntry{
.offset = last_offset,
.file = file,
.file = std::move(file),
});
last_offset += file->GetSize();
last_offset += size;
}
return VirtualFile(new ConcatenatedVfsFile(std::move(concatenation_map), std::move(name)));
return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map)));
}
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
const std::multimap<u64, VirtualFile>& files,
std::string&& name) {
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, std::string&& name,
std::multimap<u64, VirtualFile>&& files) {
// Fold trivial cases.
if (files.empty()) {
return nullptr;
@ -76,6 +77,8 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
// Iteration of a multimap is ordered, so offset will be strictly non-decreasing.
for (auto& [offset, file] : files) {
const auto size = file->GetSize();
if (offset > last_offset) {
concatenation_map.emplace_back(ConcatenationEntry{
.offset = last_offset,
@ -85,13 +88,13 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
concatenation_map.emplace_back(ConcatenationEntry{
.offset = offset,
.file = file,
.file = std::move(file),
});
last_offset = offset + file->GetSize();
last_offset = offset + size;
}
return VirtualFile(new ConcatenatedVfsFile(std::move(concatenation_map), std::move(name)));
return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map)));
}
std::string ConcatenatedVfsFile::GetName() const {

View File

@ -24,22 +24,20 @@ private:
};
using ConcatenationMap = std::vector<ConcatenationEntry>;
explicit ConcatenatedVfsFile(std::vector<ConcatenationEntry>&& concatenation_map,
std::string&& name);
explicit ConcatenatedVfsFile(std::string&& name,
std::vector<ConcatenationEntry>&& concatenation_map);
bool VerifyContinuity() const;
public:
~ConcatenatedVfsFile() override;
/// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
static VirtualFile MakeConcatenatedFile(const std::vector<VirtualFile>& files,
std::string&& name);
static VirtualFile MakeConcatenatedFile(std::string&& name, std::vector<VirtualFile>&& files);
/// Convenience function that turns a map of offsets to files into a concatenated file, filling
/// gaps with a given filler byte.
static VirtualFile MakeConcatenatedFile(u8 filler_byte,
const std::multimap<u64, VirtualFile>& files,
std::string&& name);
static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name,
std::multimap<u64, VirtualFile>&& files);
std::string GetName() const override;
std::size_t GetSize() const override;

View File

@ -38,7 +38,7 @@ VirtualDir LayeredVfsDirectory::GetDirectoryRelative(std::string_view path) cons
for (const auto& layer : dirs) {
auto dir = layer->GetDirectoryRelative(path);
if (dir != nullptr) {
out.push_back(std::move(dir));
out.emplace_back(std::move(dir));
}
}
@ -62,11 +62,11 @@ std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
std::set<std::string, std::less<>> out_names;
for (const auto& layer : dirs) {
for (const auto& file : layer->GetFiles()) {
for (auto& file : layer->GetFiles()) {
auto file_name = file->GetName();
if (!out_names.contains(file_name)) {
out_names.emplace(std::move(file_name));
out.push_back(file);
out.emplace_back(std::move(file));
}
}
}
@ -86,7 +86,7 @@ std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const {
std::vector<VirtualDir> out;
out.reserve(names.size());
for (const auto& subdir : names)
out.push_back(GetSubdirectory(subdir));
out.emplace_back(GetSubdirectory(subdir));
return out;
}

View File

@ -3405,6 +3405,11 @@ Result KPageTable::LockMemoryAndOpen(KPageGroup* out_pg, KPhysicalAddress* out_K
new_attr, KMemoryBlockDisableMergeAttribute::Locked,
KMemoryBlockDisableMergeAttribute::None);
// If we have an output page group, open.
if (out_pg) {
out_pg->Open();
}
R_SUCCEED();
}

View File

@ -49,7 +49,7 @@ public:
: ServiceFramework{system_, "IManagerForSystemService"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CheckAvailability"},
{0, &IManagerForSystemService::CheckAvailability, "CheckAvailability"},
{1, nullptr, "GetAccountId"},
{2, nullptr, "EnsureIdTokenCacheAsync"},
{3, nullptr, "LoadIdTokenCache"},
@ -78,6 +78,13 @@ public:
RegisterHandlers(functions);
}
private:
void CheckAvailability(HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
};
// 3.0.0+
@ -400,13 +407,13 @@ protected:
IPC::RequestParser rp{ctx};
const auto base = rp.PopRaw<ProfileBase>();
const auto user_data = ctx.ReadBuffer();
const auto image_data = ctx.ReadBuffer(1);
const auto image_data = ctx.ReadBufferA(0);
const auto user_data = ctx.ReadBufferX(0);
LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}",
Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(base.username.data()), base.username.size()),
base.timestamp, base.user_uuid.RawString());
LOG_INFO(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}",
Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(base.username.data()), base.username.size()),
base.timestamp, base.user_uuid.RawString());
if (user_data.size() < sizeof(UserData)) {
LOG_ERROR(Service_ACC, "UserData buffer too small!");
@ -837,6 +844,29 @@ void Module::Interface::InitializeApplicationInfoV2(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
void Module::Interface::BeginUserRegistration(HLERequestContext& ctx) {
const auto user_id = Common::UUID::MakeRandom();
profile_manager->CreateNewUser(user_id, "yuzu");
LOG_INFO(Service_ACC, "called, uuid={}", user_id.FormattedString());
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(user_id);
}
void Module::Interface::CompleteUserRegistration(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
LOG_INFO(Service_ACC, "called, uuid={}", user_id.FormattedString());
profile_manager->WriteUserSaveFile();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Module::Interface::GetProfileEditor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
@ -880,6 +910,17 @@ void Module::Interface::StoreSaveDataThumbnailApplication(HLERequestContext& ctx
StoreSaveDataThumbnail(ctx, uuid, tid);
}
void Module::Interface::GetBaasAccountManagerForSystemService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto uuid = rp.PopRaw<Common::UUID>();
LOG_INFO(Service_ACC, "called, uuid=0x{}", uuid.RawString());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IManagerForSystemService>(system, uuid);
}
void Module::Interface::StoreSaveDataThumbnailSystem(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto uuid = rp.PopRaw<Common::UUID>();

View File

@ -33,10 +33,13 @@ public:
void TrySelectUserWithoutInteraction(HLERequestContext& ctx);
void IsUserAccountSwitchLocked(HLERequestContext& ctx);
void InitializeApplicationInfoV2(HLERequestContext& ctx);
void BeginUserRegistration(HLERequestContext& ctx);
void CompleteUserRegistration(HLERequestContext& ctx);
void GetProfileEditor(HLERequestContext& ctx);
void ListQualifiedUsers(HLERequestContext& ctx);
void ListOpenContextStoredUsers(HLERequestContext& ctx);
void StoreSaveDataThumbnailApplication(HLERequestContext& ctx);
void GetBaasAccountManagerForSystemService(HLERequestContext& ctx);
void StoreSaveDataThumbnailSystem(HLERequestContext& ctx);
private:

View File

@ -23,7 +23,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager>
{99, nullptr, "DebugActivateOpenContextRetention"},
{100, nullptr, "GetUserRegistrationNotifier"},
{101, nullptr, "GetUserStateChangeNotifier"},
{102, nullptr, "GetBaasAccountManagerForSystemService"},
{102, &ACC_SU::GetBaasAccountManagerForSystemService, "GetBaasAccountManagerForSystemService"},
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
{104, nullptr, "GetProfileUpdateNotifier"},
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
@ -40,8 +40,8 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager>
{152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"},
{190, nullptr, "GetUserLastOpenedApplication"},
{191, nullptr, "ActivateOpenContextHolder"},
{200, nullptr, "BeginUserRegistration"},
{201, nullptr, "CompleteUserRegistration"},
{200, &ACC_SU::BeginUserRegistration, "BeginUserRegistration"},
{201, &ACC_SU::CompleteUserRegistration, "CompleteUserRegistration"},
{202, nullptr, "CancelUserRegistration"},
{203, nullptr, "DeleteUser"},
{204, nullptr, "SetUserPosition"},

View File

@ -96,9 +96,10 @@ public:
bool SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new,
const UserData& data_new);
void WriteUserSaveFile();
private:
void ParseUserSaveFile();
void WriteUserSaveFile();
std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile);
bool RemoveProfileAtIndex(std::size_t index);

View File

@ -210,8 +210,8 @@ IDisplayController::IDisplayController(Core::System& system_)
{21, nullptr, "ClearAppletTransitionBuffer"},
{22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"},
{23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"},
{24, nullptr, "AcquireLastForegroundCaptureSharedBuffer"},
{25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"},
{24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"},
{25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"},
{26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"},
{27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"},
{28, nullptr, "TakeScreenShotOfOwnLayerEx"},
@ -239,6 +239,22 @@ void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(1U);
rb.Push(0);
}
void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
@ -1557,7 +1573,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
{100, nullptr, "CreateGameMovieTrimmer"},
{101, nullptr, "ReserveResourceForMovieOperation"},
{102, nullptr, "UnreserveResourceForMovieOperation"},
{110, nullptr, "GetMainAppletAvailableUsers"},
{110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"},
{120, nullptr, "GetLaunchStorageInfoForDebug"},
{130, nullptr, "GetGpuErrorDetectedSystemEvent"},
{140, nullptr, "SetApplicationMemoryReservation"},
@ -1652,6 +1668,25 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext&
rb.PushRaw(applet_info);
}
void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) {
const Service::Account::ProfileManager manager{};
bool is_empty{true};
s32 user_count{-1};
LOG_INFO(Service_AM, "called");
if (manager.GetUserCount() > 0) {
is_empty = false;
user_count = static_cast<s32>(manager.GetUserCount());
ctx.WriteBuffer(manager.GetAllUsers());
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u8>(is_empty);
rb.Push(user_count);
}
void ILibraryAppletSelfAccessor::PushInShowAlbum() {
const Applets::CommonArguments arguments{
.arguments_version = Applets::CommonArgumentVersion::Version3,

View File

@ -124,6 +124,8 @@ public:
private:
void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
};
@ -345,6 +347,7 @@ private:
void GetLibraryAppletInfo(HLERequestContext& ctx);
void ExitProcessAndReturn(HLERequestContext& ctx);
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
void GetMainAppletAvailableUsers(HLERequestContext& ctx);
void PushInShowAlbum();
void PushInShowCabinetData();

View File

@ -23,6 +23,17 @@
#include "core/hle/service/ipc_helpers.h"
#include "core/memory.h"
namespace {
static thread_local std::array read_buffer_data_a{
Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(),
};
static thread_local std::array read_buffer_data_x{
Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(),
};
} // Anonymous namespace
namespace Service {
SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_)
@ -328,26 +339,57 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons
}
}
std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) const {
static thread_local std::array read_buffer_a{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
};
ASSERT_OR_EXECUTE_MSG(
BufferDescriptorA().size() > buffer_index, { return {}; },
"BufferDescriptorA invalid buffer_index {}", buffer_index);
auto& read_buffer = read_buffer_a[buffer_index];
return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(),
BufferDescriptorA()[buffer_index].Size(),
&read_buffer_data_a[buffer_index]);
}
std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) const {
static thread_local std::array read_buffer_x{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
};
ASSERT_OR_EXECUTE_MSG(
BufferDescriptorX().size() > buffer_index, { return {}; },
"BufferDescriptorX invalid buffer_index {}", buffer_index);
auto& read_buffer = read_buffer_x[buffer_index];
return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(),
BufferDescriptorX()[buffer_index].Size(),
&read_buffer_data_x[buffer_index]);
}
std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
static thread_local std::array read_buffer_a{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
};
static thread_local std::array read_buffer_data_a{
Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(),
};
static thread_local std::array read_buffer_x{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
};
static thread_local std::array read_buffer_data_x{
Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(),
};
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
BufferDescriptorA()[buffer_index].Size()};
const bool is_buffer_x{BufferDescriptorX().size() > buffer_index &&
BufferDescriptorX()[buffer_index].Size()};
if (is_buffer_a && is_buffer_x) {
LOG_WARNING(Input, "Both buffer descriptors are available a.size={}, x.size={}",
BufferDescriptorA()[buffer_index].Size(),
BufferDescriptorX()[buffer_index].Size());
}
if (is_buffer_a) {
ASSERT_OR_EXECUTE_MSG(
BufferDescriptorA().size() > buffer_index, { return {}; },

View File

@ -253,6 +253,12 @@ public:
return domain_message_header.has_value();
}
/// Helper function to get a span of a buffer using the buffer descriptor A
[[nodiscard]] std::span<const u8> ReadBufferA(std::size_t buffer_index = 0) const;
/// Helper function to get a span of a buffer using the buffer descriptor X
[[nodiscard]] std::span<const u8> ReadBufferX(std::size_t buffer_index = 0) const;
/// Helper function to get a span of a buffer using the appropriate buffer descriptor
[[nodiscard]] std::span<const u8> ReadBuffer(std::size_t buffer_index = 0) const;

View File

@ -41,6 +41,7 @@ void CoreData::BuildRandom(Age age, Gender gender, Race race) {
}
}
SetDefault();
SetGender(gender);
SetFavoriteColor(MiiUtil::GetRandomValue(FavoriteColor::Max));
SetRegionMove(0);

View File

@ -58,14 +58,8 @@ private:
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
const auto data1 = ctx.ReadBuffer(0);
const auto data2 = [&ctx] {
if (ctx.CanReadBuffer(1)) {
return ctx.ReadBuffer(1);
}
return std::span<const u8>{};
}();
const auto data1 = ctx.ReadBufferA(0);
const auto data2 = ctx.ReadBufferX(0);
LOG_DEBUG(Service_PREPO,
"called, type={:02X}, process_id={:016X}, data1_size={:016X}, data2_size={:016X}",
@ -85,14 +79,8 @@ private:
const auto user_id = rp.PopRaw<u128>();
const auto process_id = rp.PopRaw<u64>();
const auto data1 = ctx.ReadBuffer(0);
const auto data2 = [&ctx] {
if (ctx.CanReadBuffer(1)) {
return ctx.ReadBuffer(1);
}
return std::span<const u8>{};
}();
const auto data1 = ctx.ReadBufferA(0);
const auto data2 = ctx.ReadBufferX(0);
LOG_DEBUG(Service_PREPO,
"called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, "
@ -137,14 +125,8 @@ private:
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
const auto data1 = ctx.ReadBuffer(0);
const auto data2 = [&ctx] {
if (ctx.CanReadBuffer(1)) {
return ctx.ReadBuffer(1);
}
return std::span<const u8>{};
}();
const auto data1 = ctx.ReadBufferA(0);
const auto data2 = ctx.ReadBufferX(0);
LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}",
title_id, data1.size(), data2.size());
@ -161,14 +143,8 @@ private:
const auto user_id = rp.PopRaw<u128>();
const auto title_id = rp.PopRaw<u64>();
const auto data1 = ctx.ReadBuffer(0);
const auto data2 = [&ctx] {
if (ctx.CanReadBuffer(1)) {
return ctx.ReadBuffer(1);
}
return std::span<const u8>{};
}();
const auto data1 = ctx.ReadBufferA(0);
const auto data2 = ctx.ReadBufferX(0);
LOG_DEBUG(Service_PREPO,
"called, user_id={:016X}{:016X}, title_id={:016X}, data1_size={:016X}, "

View File

@ -338,6 +338,7 @@ void UDPClient::StartCommunication(std::size_t client, const std::string& host,
for (std::size_t index = 0; index < PADS_PER_CLIENT; ++index) {
const PadIdentifier identifier = GetPadIdentifier(client * PADS_PER_CLIENT + index);
PreSetController(identifier);
PreSetMotion(identifier, 0);
}
}

View File

@ -46,8 +46,8 @@ TEST_CASE("UniqueFunction", "[common]") {
Noisy noisy;
REQUIRE(noisy.state == "Default constructed");
Common::UniqueFunction<void> func = [noisy = std::move(noisy)] {
REQUIRE(noisy.state == "Move constructed");
Common::UniqueFunction<void> func = [noisy_inner = std::move(noisy)] {
REQUIRE(noisy_inner.state == "Move constructed");
};
REQUIRE(noisy.state == "Moved away");
func();
@ -101,7 +101,7 @@ TEST_CASE("UniqueFunction", "[common]") {
};
Foo object{&num_destroyed};
{
Common::UniqueFunction<void> func = [object = std::move(object)] {};
Common::UniqueFunction<void> func = [object_inner = std::move(object)] {};
REQUIRE(num_destroyed == 0);
}
REQUIRE(num_destroyed == 1);

View File

@ -62,7 +62,11 @@ using BufferId = SlotId;
using VideoCore::Surface::PixelFormat;
using namespace Common::Literals;
#ifdef __APPLE__
constexpr u32 NUM_VERTEX_BUFFERS = 16;
#else
constexpr u32 NUM_VERTEX_BUFFERS = 32;
#endif
constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;

View File

@ -48,8 +48,14 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
SetInlineIndexBuffer(regs.inline_index_4x8.index3);
break;
case MAXWELL3D_REG_INDEX(vertex_array_instance_first):
DrawArrayInstanced(regs.vertex_array_instance_first.topology.Value(),
regs.vertex_array_instance_first.start.Value(),
regs.vertex_array_instance_first.count.Value(), false);
break;
case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): {
LOG_WARNING(HW_GPU, "(STUBBED) called");
DrawArrayInstanced(regs.vertex_array_instance_subsequent.topology.Value(),
regs.vertex_array_instance_subsequent.start.Value(),
regs.vertex_array_instance_subsequent.count.Value(), true);
break;
}
case MAXWELL3D_REG_INDEX(draw_texture.src_y0): {
@ -84,6 +90,22 @@ void DrawManager::DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 ve
ProcessDraw(false, num_instances);
}
void DrawManager::DrawArrayInstanced(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
bool subsequent) {
draw_state.topology = topology;
draw_state.vertex_buffer.first = vertex_first;
draw_state.vertex_buffer.count = vertex_count;
if (!subsequent) {
draw_state.instance_count = 1;
}
draw_state.base_instance = draw_state.instance_count - 1;
draw_state.draw_mode = DrawMode::Instance;
draw_state.instance_count++;
ProcessDraw(false, 1);
}
void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count,
u32 base_index, u32 base_instance, u32 num_instances) {
const auto& regs{maxwell3d->regs};

View File

@ -66,6 +66,8 @@ public:
void DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
u32 base_instance, u32 num_instances);
void DrawArrayInstanced(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
bool subsequent);
void DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index,
u32 base_instance, u32 num_instances);

View File

@ -137,16 +137,6 @@ bool Codec::CreateGpuAvDevice() {
break;
}
if ((config->methods & HW_CONFIG_METHOD) != 0 && config->device_type == type) {
#if defined(__unix__)
// Some linux decoding backends are reported to crash with this config method
// TODO(ameerj): Properly support this method
if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) != 0) {
// skip zero-copy decoders, we don't currently support them
LOG_DEBUG(Service_NVDRV, "Skipping decoder {} with unsupported capability {}.",
av_hwdevice_get_type_name(type), config->methods);
continue;
}
#endif
LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
av_codec_ctx->pix_fmt = config->pix_fmt;
return true;

View File

@ -19,6 +19,7 @@ set(SHADER_FILES
block_linear_unswizzle_2d.comp
block_linear_unswizzle_3d.comp
convert_abgr8_to_d24s8.frag
convert_abgr8_to_d32f.frag
convert_d32f_to_abgr8.frag
convert_d24s8_to_abgr8.frag
convert_depth_to_float.frag

View File

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 450
layout(binding = 0) uniform sampler2D color_texture;
void main() {
ivec2 coord = ivec2(gl_FragCoord.xy);
vec4 color = texelFetch(color_texture, coord, 0).abgr;
float value = color.a * (color.r + color.g + color.b) / 3.0f;
gl_FragDepth = value;
}

View File

@ -3,16 +3,16 @@
#version 450
precision mediump int;
precision highp float;
layout(binding = 0) uniform sampler2D depth_tex;
layout(binding = 1) uniform isampler2D stencil_tex;
layout(binding = 1) uniform usampler2D stencil_tex;
layout(location = 0) out vec4 color;
void main() {
ivec2 coord = ivec2(gl_FragCoord.xy);
uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
highp uint depth_val =
uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0));
lowp uint stencil_val = textureLod(stencil_tex, coord, 0).r;

View File

@ -9,6 +9,6 @@ layout(location = 0) out vec4 color;
void main() {
ivec2 coord = ivec2(gl_FragCoord.xy);
float depth = textureLod(depth_tex, coord, 0).r;
float depth = texelFetch(depth_tex, coord, 0).r;
color = vec4(depth, depth, depth, 1.0);
}

View File

@ -3,16 +3,16 @@
#version 450
precision mediump int;
precision highp float;
layout(binding = 0) uniform sampler2D depth_tex;
layout(binding = 1) uniform isampler2D stencil_tex;
layout(binding = 1) uniform usampler2D stencil_tex;
layout(location = 0) out vec4 color;
void main() {
ivec2 coord = ivec2(gl_FragCoord.xy);
uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
highp uint depth_val =
uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0));
lowp uint stencil_val = textureLod(stencil_tex, coord, 0).r;

View File

@ -8,6 +8,7 @@
#include "common/settings.h"
#include "video_core/host_shaders/blit_color_float_frag_spv.h"
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
#include "video_core/host_shaders/convert_abgr8_to_d32f_frag_spv.h"
#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
#include "video_core/host_shaders/convert_d32f_to_abgr8_frag_spv.h"
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
@ -434,6 +435,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
convert_abgr8_to_d32f_frag(BuildShader(device, CONVERT_ABGR8_TO_D32F_FRAG_SPV)),
convert_d32f_to_abgr8_frag(BuildShader(device, CONVERT_D32F_TO_ABGR8_FRAG_SPV)),
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
@ -559,6 +561,13 @@ void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertABGR8ToD32F(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view) {
ConvertPipelineDepthTargetEx(convert_abgr8_to_d32f_pipeline, dst_framebuffer->RenderPass(),
convert_abgr8_to_d32f_frag);
Convert(*convert_abgr8_to_d32f_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertD32FToABGR8(const Framebuffer* dst_framebuffer,
ImageView& src_image_view) {
ConvertPipelineColorTargetEx(convert_d32f_to_abgr8_pipeline, dst_framebuffer->RenderPass(),

View File

@ -67,6 +67,8 @@ public:
void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
void ConvertABGR8ToD32F(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
void ConvertD32FToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
@ -130,6 +132,7 @@ private:
vk::ShaderModule convert_depth_to_float_frag;
vk::ShaderModule convert_float_to_depth_frag;
vk::ShaderModule convert_abgr8_to_d24s8_frag;
vk::ShaderModule convert_abgr8_to_d32f_frag;
vk::ShaderModule convert_d32f_to_abgr8_frag;
vk::ShaderModule convert_d24s8_to_abgr8_frag;
vk::ShaderModule convert_s8d24_to_abgr8_frag;
@ -149,6 +152,7 @@ private:
vk::Pipeline convert_d16_to_r16_pipeline;
vk::Pipeline convert_r16_to_d16_pipeline;
vk::Pipeline convert_abgr8_to_d24s8_pipeline;
vk::Pipeline convert_abgr8_to_d32f_pipeline;
vk::Pipeline convert_d32f_to_abgr8_pipeline;
vk::Pipeline convert_d24s8_to_abgr8_pipeline;
vk::Pipeline convert_s8d24_to_abgr8_pipeline;

View File

@ -1436,6 +1436,7 @@ void QueryCacheRuntime::Barriers(bool is_prebarrier) {
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
};
impl->scheduler.RequestOutsideRenderPassOperationContext();
if (is_prebarrier) {
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,

View File

@ -975,6 +975,19 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
if (!state_tracker.TouchScissors()) {
return;
}
if (!regs.viewport_scale_offset_enabled) {
const auto x = static_cast<float>(regs.surface_clip.x);
const auto y = static_cast<float>(regs.surface_clip.y);
const auto width = static_cast<float>(regs.surface_clip.width);
const auto height = static_cast<float>(regs.surface_clip.height);
VkRect2D scissor;
scissor.offset.x = static_cast<u32>(x);
scissor.offset.y = static_cast<u32>(y);
scissor.extent.width = static_cast<u32>(width != 0.0f ? width : 1.0f);
scissor.extent.height = static_cast<u32>(height != 0.0f ? height : 1.0f);
scheduler.Record([scissor](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissor); });
return;
}
u32 up_scale = 1;
u32 down_shift = 0;
if (texture_cache.IsRescaling()) {

View File

@ -19,7 +19,7 @@ VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat
VkSampleCountFlagBits samples) {
using MaxwellToVK::SurfaceFormat;
return {
.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT,
.flags = {},
.format = SurfaceFormat(device, FormatType::Optimal, true, format).format,
.samples = samples,
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,

View File

@ -1194,6 +1194,11 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
return blit_image_helper.ConvertD16ToR16(dst, src_view);
}
break;
case PixelFormat::A8B8G8R8_SRGB:
if (src_view.format == PixelFormat::D32_FLOAT) {
return blit_image_helper.ConvertD32FToABGR8(dst, src_view);
}
break;
case PixelFormat::A8B8G8R8_UNORM:
if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view);
@ -1205,6 +1210,16 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
return blit_image_helper.ConvertD32FToABGR8(dst, src_view);
}
break;
case PixelFormat::B8G8R8A8_SRGB:
if (src_view.format == PixelFormat::D32_FLOAT) {
return blit_image_helper.ConvertD32FToABGR8(dst, src_view);
}
break;
case PixelFormat::B8G8R8A8_UNORM:
if (src_view.format == PixelFormat::D32_FLOAT) {
return blit_image_helper.ConvertD32FToABGR8(dst, src_view);
}
break;
case PixelFormat::R32_FLOAT:
if (src_view.format == PixelFormat::D32_FLOAT) {
return blit_image_helper.ConvertD32ToR32(dst, src_view);
@ -1222,6 +1237,12 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
}
break;
case PixelFormat::D32_FLOAT:
if (src_view.format == PixelFormat::A8B8G8R8_UNORM ||
src_view.format == PixelFormat::B8G8R8A8_UNORM ||
src_view.format == PixelFormat::A8B8G8R8_SRGB ||
src_view.format == PixelFormat::B8G8R8A8_SRGB) {
return blit_image_helper.ConvertABGR8ToD32F(dst, src_view);
}
if (src_view.format == PixelFormat::R32_FLOAT) {
return blit_image_helper.ConvertR32ToD32(dst, src_view);
}
@ -2034,7 +2055,7 @@ void TextureCacheRuntime::TransitionImageLayout(Image& image) {
},
};
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([barrier = barrier](vk::CommandBuffer cmdbuf) {
scheduler.Record([barrier](vk::CommandBuffer cmdbuf) {
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, barrier);
});

View File

@ -10,19 +10,23 @@
#include "video_core/texture_cache/image_info.h"
#include "video_core/texture_cache/image_view_base.h"
#include "video_core/texture_cache/render_targets.h"
#include "video_core/texture_cache/samples_helper.h"
namespace VideoCommon {
std::string Name(const ImageBase& image) {
const GPUVAddr gpu_addr = image.gpu_addr;
const ImageInfo& info = image.info;
const u32 width = info.size.width;
const u32 height = info.size.height;
u32 width = info.size.width;
u32 height = info.size.height;
const u32 depth = info.size.depth;
const u32 num_layers = image.info.resources.layers;
const u32 num_levels = image.info.resources.levels;
std::string resource;
if (image.info.num_samples > 1) {
const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(image.info.num_samples);
width >>= samples_x;
height >>= samples_y;
resource += fmt::format(":{}xMSAA", image.info.num_samples);
}
if (num_layers > 1) {

View File

@ -24,7 +24,7 @@ namespace VideoCommon {
return {2, 2};
}
ASSERT_MSG(false, "Invalid number of samples={}", num_samples);
return {1, 1};
return {0, 0};
}
[[nodiscard]] inline int NumSamples(Tegra::Texture::MsaaMode msaa_mode) {

View File

@ -167,6 +167,13 @@ template <u32 GOB_EXTENT>
}
[[nodiscard]] constexpr Extent3D TileShift(const LevelInfo& info, u32 level) {
if (level == 0 && info.num_levels == 1) {
return Extent3D{
.width = info.block.width,
.height = info.block.height,
.depth = info.block.depth,
};
}
const Extent3D blocks = NumLevelBlocks(info, level);
return Extent3D{
.width = AdjustTileSize(info.block.width, GOB_SIZE_X, blocks.width),
@ -1293,9 +1300,9 @@ u32 MapSizeBytes(const ImageBase& image) {
static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2, 0, 1}, 0) ==
0x7f8000);
static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0, 1}, 0) == 0x4000);
static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0, 1}, 0) == 0x40000);
static_assert(CalculateLevelSize(LevelInfo{{128, 8, 1}, {0, 4, 0}, {1, 1}, 4, 0, 1}, 0) == 0x4000);
static_assert(CalculateLevelSize(LevelInfo{{128, 8, 1}, {0, 4, 0}, {1, 1}, 4, 0, 1}, 0) == 0x40000);
static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 0, 7) ==
0x2afc00);

View File

@ -384,7 +384,7 @@ if (USE_DISCORD_PRESENCE)
discord_impl.cpp
discord_impl.h
)
target_link_libraries(yuzu PRIVATE DiscordRPC::discord-rpc httplib::httplib)
target_link_libraries(yuzu PRIVATE DiscordRPC::discord-rpc httplib::httplib Qt${QT_MAJOR_VERSION}::Network)
target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE)
endif()

View File

@ -128,8 +128,8 @@ const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral("R+Plus+Minus"), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral("L+Plus+Minus"), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut, false}},

View File

@ -115,17 +115,9 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
for (std::size_t i = 0; i < player_tabs.size(); ++i) {
player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i]));
player_tabs[i]->layout()->addWidget(player_controllers[i]);
connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) {
connect(player_connected[i], &QCheckBox::clicked, [this, i](int checked) {
// Ensures that the controllers are always connected in sequential order
if (is_connected) {
for (std::size_t index = 0; index <= i; ++index) {
player_connected[index]->setChecked(is_connected);
}
} else {
for (std::size_t index = i; index < player_tabs.size(); ++index) {
player_connected[index]->setChecked(is_connected);
}
}
this->propagateMouseClickOnPlayers(i, checked, true);
});
connect(player_controllers[i], &ConfigureInputPlayer::RefreshInputDevices, this,
&ConfigureInput::UpdateAllInputDevices);
@ -183,6 +175,30 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
LoadConfiguration();
}
void ConfigureInput::propagateMouseClickOnPlayers(size_t player_index, bool checked, bool origin) {
// Origin has already been toggled
if (!origin) {
player_connected[player_index]->setChecked(checked);
}
if (checked) {
// Check all previous buttons when checked
if (player_index > 0) {
propagateMouseClickOnPlayers(player_index - 1, checked, false);
}
} else {
// Unchecked all following buttons when unchecked
if (player_index < player_tabs.size() - 1) {
// Reconnect current player if it was the last one checked
// (player number was reduced by more than one)
if (origin && player_connected[player_index + 1]->checkState() == Qt::Checked) {
player_connected[player_index]->setCheckState(Qt::Checked);
}
propagateMouseClickOnPlayers(player_index + 1, checked, false);
}
}
}
QList<QWidget*> ConfigureInput::GetSubTabs() const {
return {
ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4, ui->tabPlayer5,

View File

@ -56,6 +56,7 @@ private:
void UpdateDockedState(bool is_handheld);
void UpdateAllInputDevices();
void UpdateAllInputProfiles(std::size_t player_index);
void propagateMouseClickOnPlayers(size_t player_index, bool origin, bool checked);
/// Load configuration settings.
void LoadConfiguration();

View File

@ -157,6 +157,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", "");
INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", "");
INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", "");
INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", "");
INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", "");
INSERT(UISettings, controller_applet_disabled, "Disable controller applet", "");
@ -383,6 +384,13 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
translations->insert(
{Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
{PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}});
translations->insert(
{Settings::EnumMetadata<Settings::ConfirmStop>::Index(),
{
PAIR(ConfirmStop, Ask_Always, "Always ask (Default)"),
PAIR(ConfirmStop, Ask_Based_On_Game, "Only if game specifies not to stop"),
PAIR(ConfirmStop, Ask_Never, "Never ask"),
}});
#undef PAIR
#undef CTX_PAIR

View File

@ -826,12 +826,13 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) {
tree_view->setColumnHidden(COLUMN_SIZE, !UISettings::values.show_size);
tree_view->setColumnHidden(COLUMN_PLAY_TIME, !UISettings::values.show_play_time);
// Before deleting rows, cancel the worker so that it is not using them
emit ShouldCancelWorker();
// Delete any rows that might already exist if we're repopulating
item_model->removeRows(0, item_model->rowCount());
search_field->clear();
emit ShouldCancelWorker();
GameListWorker* worker =
new GameListWorker(vfs, provider, game_dirs, compatibility_list, play_time_manager, system);

View File

@ -293,7 +293,7 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) {
void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_path, bool deep_scan,
GameListDir* parent_dir) {
const auto callback = [this, target, parent_dir](const std::filesystem::path& path) -> bool {
if (stop_processing) {
if (stop_requested) {
// Breaks the callback loop.
return false;
}
@ -399,7 +399,6 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
}
void GameListWorker::run() {
stop_processing = false;
provider->ClearAllEntries();
for (UISettings::GameDir& game_dir : game_dirs) {
@ -427,9 +426,11 @@ void GameListWorker::run() {
}
emit Finished(watch_list);
processing_completed.Set();
}
void GameListWorker::Cancel() {
this->disconnect();
stop_processing = true;
stop_requested.store(true);
processing_completed.Wait();
}

View File

@ -12,6 +12,7 @@
#include <QRunnable>
#include <QString>
#include "common/thread.h"
#include "yuzu/compatibility_list.h"
#include "yuzu/play_time_manager.h"
@ -82,7 +83,9 @@ private:
const PlayTime::PlayTimeManager& play_time_manager;
QStringList watch_list;
std::atomic_bool stop_processing;
Common::Event processing_completed;
std::atomic_bool stop_requested = false;
Core::System& system;
};

View File

@ -67,6 +67,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#define QT_NO_OPENGL
#include <QClipboard>
#include <QDesktopServices>
#include <QDir>
#include <QFile>
#include <QFileDialog>
#include <QInputDialog>
@ -76,6 +77,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include <QPushButton>
#include <QScreen>
#include <QShortcut>
#include <QStandardPaths>
#include <QStatusBar>
#include <QString>
#include <QSysInfo>
@ -209,7 +211,7 @@ void GMainWindow::ShowTelemetryCallout() {
tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous "
"data is collected</a> to help improve yuzu. "
"<br/><br/>Would you like to share your usage data with us?");
if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) {
if (!question(this, tr("Telemetry"), telemetry_message)) {
Settings::values.enable_telemetry = false;
system->ApplySettings();
}
@ -2418,9 +2420,8 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT
}
}();
if (QMessageBox::question(this, tr("Remove Entry"), entry_question,
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No) != QMessageBox::Yes) {
if (!question(this, tr("Remove Entry"), entry_question, QMessageBox::Yes | QMessageBox::No,
QMessageBox::No)) {
return;
}
@ -2519,8 +2520,8 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ
}
}();
if (QMessageBox::question(this, tr("Remove File"), question, QMessageBox::Yes | QMessageBox::No,
QMessageBox::No) != QMessageBox::Yes) {
if (!GMainWindow::question(this, tr("Remove File"), question,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) {
return;
}
@ -2869,44 +2870,50 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
#endif // __linux__
std::filesystem::path target_directory{};
// Determine target directory for shortcut
#if defined(WIN32)
const char* home = std::getenv("USERPROFILE");
#else
const char* home = std::getenv("HOME");
#endif
const std::filesystem::path home_path = (home == nullptr ? "~" : home);
const char* xdg_data_home = std::getenv("XDG_DATA_HOME");
if (target == GameListShortcutTarget::Desktop) {
target_directory = home_path / "Desktop";
if (!Common::FS::IsDir(target_directory)) {
QMessageBox::critical(
this, tr("Create Shortcut"),
tr("Cannot create shortcut on desktop. Path \"%1\" does not exist.")
.arg(QString::fromStdString(target_directory.generic_string())),
QMessageBox::StandardButton::Ok);
return;
}
} else if (target == GameListShortcutTarget::Applications) {
target_directory = (xdg_data_home == nullptr ? home_path / ".local/share" : xdg_data_home) /
"applications";
if (!Common::FS::CreateDirs(target_directory)) {
QMessageBox::critical(
this, tr("Create Shortcut"),
tr("Cannot create shortcut in applications menu. Path \"%1\" "
"does not exist and cannot be created.")
.arg(QString::fromStdString(target_directory.generic_string())),
QMessageBox::StandardButton::Ok);
return;
switch (target) {
case GameListShortcutTarget::Desktop: {
const QString desktop_path =
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
target_directory = desktop_path.toUtf8().toStdString();
break;
}
case GameListShortcutTarget::Applications: {
const QString applications_path =
QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
if (applications_path.isEmpty()) {
const char* home = std::getenv("HOME");
if (home != nullptr) {
target_directory = std::filesystem::path(home) / ".local/share/applications";
}
} else {
target_directory = applications_path.toUtf8().toStdString();
}
break;
}
default:
return;
}
const QDir dir(QString::fromStdString(target_directory.generic_string()));
if (!dir.exists()) {
QMessageBox::critical(this, tr("Create Shortcut"),
tr("Cannot create shortcut. Path \"%1\" does not exist.")
.arg(QString::fromStdString(target_directory.generic_string())),
QMessageBox::StandardButton::Ok);
return;
}
const std::string game_file_name = std::filesystem::path(game_path).filename().string();
// Determine full paths for icon and shortcut
#if defined(__linux__) || defined(__FreeBSD__)
const char* home = std::getenv("HOME");
const std::filesystem::path home_path = (home == nullptr ? "~" : home);
const char* xdg_data_home = std::getenv("XDG_DATA_HOME");
std::filesystem::path system_icons_path =
(xdg_data_home == nullptr ? home_path / ".local/share/" : xdg_data_home) /
(xdg_data_home == nullptr ? home_path / ".local/share/"
: std::filesystem::path(xdg_data_home)) /
"icons/hicolor/256x256";
if (!Common::FS::CreateDirs(system_icons_path)) {
QMessageBox::critical(
@ -3401,10 +3408,13 @@ void GMainWindow::OnRestartGame() {
if (!system->IsPoweredOn()) {
return;
}
// Make a copy since ShutdownGame edits game_path
const auto current_game = QString(current_game_path);
ShutdownGame();
BootGame(current_game);
if (ConfirmShutdownGame()) {
// Make a copy since ShutdownGame edits game_path
const auto current_game = QString(current_game_path);
ShutdownGame();
BootGame(current_game);
}
}
void GMainWindow::OnPauseGame() {
@ -3426,18 +3436,39 @@ void GMainWindow::OnPauseContinueGame() {
}
void GMainWindow::OnStopGame() {
if (system->GetExitLocked() && !ConfirmForceLockedExit()) {
return;
if (ConfirmShutdownGame()) {
play_time_manager->Stop();
// Update game list to show new play time
game_list->PopulateAsync(UISettings::values.game_dirs);
if (OnShutdownBegin()) {
OnShutdownBeginDialog();
} else {
OnEmulationStopped();
}
}
}
play_time_manager->Stop();
// Update game list to show new play time
game_list->PopulateAsync(UISettings::values.game_dirs);
if (OnShutdownBegin()) {
OnShutdownBeginDialog();
bool GMainWindow::ConfirmShutdownGame() {
if (UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Always) {
if (system->GetExitLocked()) {
if (!ConfirmForceLockedExit()) {
return false;
}
} else {
if (!ConfirmChangeGame()) {
return false;
}
}
} else {
OnEmulationStopped();
if (UISettings::values.confirm_before_stopping.GetValue() ==
ConfirmStop::Ask_Based_On_Game &&
system->GetExitLocked()) {
if (!ConfirmForceLockedExit()) {
return false;
}
}
}
return true;
}
void GMainWindow::OnLoadComplete() {
@ -3817,22 +3848,11 @@ void GMainWindow::OnTasRecord() {
const bool is_recording = input_subsystem->GetTas()->Record();
if (!is_recording) {
is_tas_recording_dialog_active = true;
ControllerNavigation* controller_navigation =
new ControllerNavigation(system->HIDCore(), this);
// Use QMessageBox instead of question so we can link controller navigation
QMessageBox* box_dialog = new QMessageBox();
box_dialog->setWindowTitle(tr("TAS Recording"));
box_dialog->setText(tr("Overwrite file of player 1?"));
box_dialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
box_dialog->setDefaultButton(QMessageBox::Yes);
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
[box_dialog](Qt::Key key) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
QCoreApplication::postEvent(box_dialog, event);
});
int res = box_dialog->exec();
controller_navigation->UnloadController();
input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes);
bool answer = question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
input_subsystem->GetTas()->SaveRecording(answer);
is_tas_recording_dialog_active = false;
}
OnTasStateChanged();
@ -4073,6 +4093,29 @@ void GMainWindow::OnLoadAmiibo() {
LoadAmiibo(filename);
}
bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton) {
QMessageBox* box_dialog = new QMessageBox(parent);
box_dialog->setWindowTitle(title);
box_dialog->setText(text);
box_dialog->setStandardButtons(buttons);
box_dialog->setDefaultButton(defaultButton);
ControllerNavigation* controller_navigation =
new ControllerNavigation(system->HIDCore(), box_dialog);
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
[box_dialog](Qt::Key key) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
QCoreApplication::postEvent(box_dialog, event);
});
int res = box_dialog->exec();
controller_navigation->UnloadController();
return res == QMessageBox::Yes;
}
void GMainWindow::LoadAmiibo(const QString& filename) {
auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo();
const QString title = tr("Error loading Amiibo data");
@ -4806,8 +4849,7 @@ bool GMainWindow::ConfirmClose() {
return true;
}
const auto text = tr("Are you sure you want to close yuzu?");
const auto answer = QMessageBox::question(this, tr("yuzu"), text);
return answer != QMessageBox::No;
return question(this, tr("yuzu"), text);
}
void GMainWindow::closeEvent(QCloseEvent* event) {
@ -4900,11 +4942,11 @@ bool GMainWindow::ConfirmChangeGame() {
if (emu_thread == nullptr)
return true;
const auto answer = QMessageBox::question(
// Use custom question to link controller navigation
return question(
this, tr("yuzu"),
tr("Are you sure you want to stop the emulation? Any unsaved progress will be lost."),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
return answer != QMessageBox::No;
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
}
bool GMainWindow::ConfirmForceLockedExit() {
@ -4914,8 +4956,7 @@ bool GMainWindow::ConfirmForceLockedExit() {
const auto text = tr("The currently running application has requested yuzu to not exit.\n\n"
"Would you like to bypass this and exit anyway?");
const auto answer = QMessageBox::question(this, tr("yuzu"), text);
return answer != QMessageBox::No;
return question(this, tr("yuzu"), text);
}
void GMainWindow::RequestGameExit() {

View File

@ -7,6 +7,7 @@
#include <optional>
#include <QMainWindow>
#include <QMessageBox>
#include <QTimer>
#include <QTranslator>
@ -15,6 +16,7 @@
#include "input_common/drivers/tas_input.h"
#include "yuzu/compatibility_list.h"
#include "yuzu/hotkeys.h"
#include "yuzu/util/controller_navigation.h"
#ifdef __unix__
#include <QVariant>
@ -424,6 +426,11 @@ private:
bool CheckSystemArchiveDecryption();
bool CheckFirmwarePresence();
void ConfigureFilesystemProvider(const std::string& filepath);
/**
* Open (or not) the right confirm dialog based on current setting and game exit lock
* @returns true if the player confirmed or the settings do no require it
*/
bool ConfirmShutdownGame();
QString GetTasStateDescription() const;
bool CreateShortcut(const std::string& shortcut_path, const std::string& title,
@ -431,6 +438,17 @@ private:
const std::string& command, const std::string& arguments,
const std::string& categories, const std::string& keywords);
/**
* Mimic the behavior of QMessageBox::question but link controller navigation to the dialog
* The only difference is that it returns a boolean.
*
* @returns true if buttons contains QMessageBox::Yes and the user clicks on the "Yes" button.
*/
bool question(QWidget* parent, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons =
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
std::unique_ptr<Ui::MainWindow> ui;
std::unique_ptr<Core::System> system;

View File

@ -16,7 +16,9 @@
#include "common/settings_enums.h"
using Settings::Category;
using Settings::ConfirmStop;
using Settings::Setting;
using Settings::SwitchableSetting;
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
namespace Settings {
@ -94,6 +96,15 @@ struct Values {
Setting<bool> confirm_before_closing{
linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default,
true, true};
SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage,
ConfirmStop::Ask_Always,
"confirmStop",
Category::UiGeneral,
Settings::Specialization::Default,
true,
true};
Setting<bool> first_start{linkage, true, "firstStart", Category::Ui};
Setting<bool> pause_when_in_background{linkage,
false,