diff options
31 files changed, 374 insertions, 319 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1b2056885..01109785d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,136 +1 @@ -# Reporting Issues - -**The issue tracker is not a support forum.** Unless you can provide precise *technical information* regarding an issue, you *should not post in it*. If you need support, first read the [FAQ](https://github.com/yuzu-emu/yuzu/wiki/FAQ) and then either visit our [Discord server](https://discordapp.com/invite/u77vRWY), [our forum](https://community.citra-emu.org) or ask in a general emulation forum such as [/r/emulation](https://www.reddit.com/r/emulation/). If you post support questions, generic messages to the developers or vague reports without technical details, they will be closed and locked. - -If you believe you have a valid issue report, please post text or a screenshot from the log (the console window that opens alongside yuzu) and build version (hex string visible in the titlebar and zip filename), as well as your hardware and software information if applicable. - -# Contributing -yuzu is a brand new project, so we have a great opportunity to keep things clean and well organized early on. As such, coding style is very important when making commits. We run clang-format on our CI to check the code. Please use it to format your code when contributing. However, it doesn't cover all the rules below. Some of them aren't very strict rules since we want to be flexible and we understand that under certain circumstances some of them can be counterproductive. Just try to follow as many of them as possible. - -# Using clang format (version 6.0) -When generating the native build script for your toolset, cmake will try to find the correct version of clang format (or will download it on windows). Before running cmake, please install clang format version 6.0 for your platform as follows: - -* Windows: do nothing; cmake will download a pre built binary for MSVC and MINGW. MSVC users can additionally install a clang format Visual Studio extension to add features like format on save. -* OSX: run `brew install clang-format`. -* Linux: use your package manager to get an appropriate binary. - -If clang format is found, then cmake will add a custom build target that can be run at any time to run clang format against *all* source files and update the formatting in them. This should be used before making a pull request so that the reviewers can spend more time reviewing the code instead of having to worry about minor style violations. On MSVC, you can run clang format by building the clang-format project in the solution. On OSX, you can either use the Makefile target `make clang-format` or by building the clang-format target in XCode. For Makefile builds, you can use the clang-format target with `make clang-format` - -### General Rules -* A lot of code was taken from other projects (e.g. Citra, Dolphin, PPSSPP, Gekko). In general, when editing other people's code, follow the style of the module you're in (or better yet, fix the style if it drastically differs from our guide). -* Line width is typically 100 characters. Please do not use 80-characters. -* Don't ever introduce new external dependencies into Core -* Don't use any platform specific code in Core -* Use namespaces often -* Avoid the use of C-style casts and instead prefer C++-style `static_cast` and `reinterpret_cast`. Try to avoid using `dynamic_cast`. Never use `const_cast`. - -### Naming Rules -* Functions: `PascalCase` -* Variables: `lower_case_underscored`. Prefix with `g_` if global. -* Classes: `PascalCase` -* Files and Directories: `lower_case_underscored` -* Namespaces: `PascalCase`, `_` may also be used for clarity (e.g. `ARM_InitCore`) - -### Indentation/Whitespace Style -Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. - -### Comments -* For regular comments, use C++ style (`//`) comments, even for multi-line ones. -* For doc-comments (Doxygen comments), use `/// ` if it's a single line, else use the `/**` `*/` style featured in the example. Start the text on the second line, not the first containing `/**`. -* For items that are both defined and declared in two separate files, put the doc-comment only next to the associated declaration. (In a header file, usually.) Otherwise, put it next to the implementation. Never duplicate doc-comments in both places. - -```cpp -// Includes should be sorted lexicographically -// STD includes first -#include <map> -#include <memory> - -// then, library includes -#include <nihstro/shared_binary.h> - -// finally, yuzu includes -#include "common/math_util.h" -#include "common/vector_math.h" - -// each major module is separated -#include "video_core/pica.h" -#include "video_core/video_core.h" - -namespace Example { - -// Namespace contents are not indented - -// Declare globals at the top -int g_foo{}; // {} can be used to initialize types as 0, false, or nullptr -char* g_some_pointer{}; // Pointer * and reference & stick to the type name, and make sure to initialize as nullptr! - -/// A colorful enum. -enum SomeEnum { - ColorRed, ///< The color of fire. - ColorGreen, ///< The color of grass. - ColorBlue, ///< Not actually the color of water. -}; - -/** - * Very important struct that does a lot of stuff. - * Note that the asterisks are indented by one space to align to the first line. - */ -struct Position { - int x{}, y{}; // Always intitialize member variables! -}; - -// Use "typename" rather than "class" here -template <typename T> -void FooBar() { - const std::string some_string{ "prefer uniform initialization" }; - - int some_array[]{ - 5, - 25, - 7, - 42, - }; - - if (note == the_space_after_the_if) { - CallAfunction(); - } else { - // Use a space after the // when commenting - } - - // Place a single space after the for loop semicolons, prefer pre-increment - for (int i{}; i != 25; ++i) { - // This is how we write loops - } - - DoStuff(this, function, call, takes, up, multiple, - lines, like, this); - - if (this || condition_takes_up_multiple && - lines && like && this || everything || - alright || then) { - - // Leave a blank space before the if block body if the condition was continued across - // several lines. - } - - switch (var) { - // No indentation for case label - case 1: { - int case_var{ var + 3 }; - DoSomething(case_var); - break; - } - case 3: - DoSomething(var); - return; - - default: - // Yes, even break for the last case - break; - } - - std::vector<T> you_can_declare, a_few, variables, like_this; -} - -} -``` +**The Contributor's Guide has moved to [the Citra wiki](https://github.com/citra-emu/citra/wiki/Contributing).** diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 0a7142ada..0d6c85aed 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -18,7 +18,7 @@ #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/server_session.h" namespace IPC { diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index c114eaf99..704e82824 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -8,6 +8,7 @@ #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" #include "core/hle/kernel/thread.h" +#include "core/hle/result.h" namespace Kernel { diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 439fbdb35..4c18de69c 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -6,9 +6,9 @@ #include <memory> #include <string> -#include "common/common_types.h" #include "core/hle/kernel/object.h" -#include "core/hle/result.h" + +union ResultCode; namespace Kernel { diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 61ce7d7e4..5dd855db8 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -22,11 +22,16 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/memory.h" namespace Kernel { +SessionRequestHandler::SessionRequestHandler() = default; + +SessionRequestHandler::~SessionRequestHandler() = default; + void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) { server_session->SetHleHandler(shared_from_this()); connected_sessions.push_back(std::move(server_session)); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index e5c0610cd..cb1c5aff3 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -14,8 +14,6 @@ #include "common/swap.h" #include "core/hle/ipc.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/thread.h" namespace Service { class ServiceFrameworkBase; @@ -27,9 +25,13 @@ class Domain; class HandleTable; class HLERequestContext; class Process; +class ServerSession; +class Thread; class ReadableEvent; class WritableEvent; +enum class ThreadWakeupReason; + /** * Interface implemented by HLE Session handlers. * This can be provided to a ServerSession in order to hook into several relevant events @@ -37,7 +39,8 @@ class WritableEvent; */ class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { public: - virtual ~SessionRequestHandler() = default; + SessionRequestHandler(); + virtual ~SessionRequestHandler(); /** * Handles a sync request from the emulated application. diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1c2290651..67674cd47 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <array> #include <atomic> #include <memory> #include <mutex> diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index b710104ab..dcc57ae9f 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -14,7 +14,6 @@ #include "common/common_types.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/process_capability.h" -#include "core/hle/kernel/thread.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" @@ -27,6 +26,7 @@ namespace Kernel { class KernelCore; class ResourceLimit; +class Thread; struct AddressMapping { // Address and size must be page-aligned diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 80897f3a4..027434f92 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -6,6 +6,7 @@ #include <utility> #include "common/assert.h" +#include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index e068db2bf..e0e9d64c8 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -8,7 +8,6 @@ #include <string> #include <vector> -#include "common/common_types.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 530ee6af7..90580ed93 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -4,11 +4,11 @@ #include <algorithm> #include "common/assert.h" +#include "common/common_types.h" #include "common/logging/log.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" -#include "core/hle/kernel/timer.h" namespace Kernel { diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h index f4367ee28..d70b67893 100644 --- a/src/core/hle/kernel/wait_object.h +++ b/src/core/hle/kernel/wait_object.h @@ -6,7 +6,6 @@ #include <vector> #include <boost/smart_ptr/intrusive_ptr.hpp> -#include "common/common_types.h" #include "core/hle/kernel/object.h" namespace Kernel { diff --git a/src/core/hle/kernel/writable_event.h b/src/core/hle/kernel/writable_event.h index 8fa8d68ee..c9068dd3d 100644 --- a/src/core/hle/kernel/writable_event.h +++ b/src/core/hle/kernel/writable_event.h @@ -4,9 +4,7 @@ #pragma once -#include "common/common_types.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/wait_object.h" namespace Kernel { diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 7698ca819..a6064c63f 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -6,7 +6,7 @@ #include "common/assert.h" #include "core/core.h" #include "core/hle/kernel/readable_event.h" -#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index b0a8913c3..37424c379 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -7,7 +7,7 @@ #include <memory> #include <queue> #include "common/swap.h" -#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/object.h" #include "core/hle/kernel/writable_event.h" union ResultCode; diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index a7bed0040..2254fb46b 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -9,9 +9,9 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/lock.h" -#include "core/hle/service/hid/hid.h" #include "core/hle/service/nfp/nfp.h" #include "core/hle/service/nfp/nfp_user.h" diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 05af2d593..6a613aeab 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -166,7 +166,7 @@ Layer::~Layer() = default; Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { auto& kernel = Core::System::GetInstance().Kernel(); - vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Pulse, + vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, fmt::format("Display VSync Event {}", id)); } diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index b3e0aab11..8528925ec 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -19,6 +19,7 @@ #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvflinger/buffer_queue.h" @@ -513,10 +514,12 @@ private: void TransactParcel(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u32 id = rp.Pop<u32>(); - auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); - u32 flags = rp.Pop<u32>(); - LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); + const u32 id = rp.Pop<u32>(); + const auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); + const u32 flags = rp.Pop<u32>(); + + LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, + static_cast<u32>(transaction), flags); auto buffer_queue = nv_flinger->GetBufferQueue(id); @@ -604,9 +607,10 @@ private: void AdjustRefcount(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u32 id = rp.Pop<u32>(); - s32 addval = rp.PopRaw<s32>(); - u32 type = rp.Pop<u32>(); + const u32 id = rp.Pop<u32>(); + const s32 addval = rp.PopRaw<s32>(); + const u32 type = rp.Pop<u32>(); + LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, type); @@ -616,11 +620,12 @@ private: void GetNativeHandle(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u32 id = rp.Pop<u32>(); - u32 unknown = rp.Pop<u32>(); + const u32 id = rp.Pop<u32>(); + const u32 unknown = rp.Pop<u32>(); + LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); - auto buffer_queue = nv_flinger->GetBufferQueue(id); + const auto buffer_queue = nv_flinger->GetBufferQueue(id); // TODO(Subv): Find out what this actually is. IPC::ResponseBuilder rb{ctx, 2, 1}; @@ -685,11 +690,12 @@ public: private: void SetLayerZ(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 layer_id = rp.Pop<u64>(); - u64 z_value = rp.Pop<u64>(); + const u64 layer_id = rp.Pop<u64>(); + const u64 z_value = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}, z_value=0x{:016X}", layer_id, + z_value); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -697,8 +703,9 @@ private: void SetLayerVisibility(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u64 layer_id = rp.Pop<u64>(); - bool visibility = rp.Pop<bool>(); + const u64 layer_id = rp.Pop<u64>(); + const bool visibility = rp.Pop<bool>(); + LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, visibility); @@ -807,25 +814,27 @@ public: private: void CloseDisplay(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 display = rp.Pop<u64>(); + const u64 display = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. display=0x{:016X}", display); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void CreateManagedLayer(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u32 unknown = rp.Pop<u32>(); + const u32 unknown = rp.Pop<u32>(); rp.Skip(1, false); - u64 display = rp.Pop<u64>(); - u64 aruid = rp.Pop<u64>(); + const u64 display = rp.Pop<u64>(); + const u64 aruid = rp.Pop<u64>(); - u64 layer_id = nv_flinger->CreateLayer(display); + LOG_WARNING(Service_VI, + "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", + unknown, display, aruid); + + const u64 layer_id = nv_flinger->CreateLayer(display); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); @@ -833,11 +842,12 @@ private: } void AddToLayerStack(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u32 stack = rp.Pop<u32>(); - u64 layer_id = rp.Pop<u64>(); + const u32 stack = rp.Pop<u32>(); + const u64 layer_id = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. stack=0x{:08X}, layer_id=0x{:016X}", stack, + layer_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -845,8 +855,9 @@ private: void SetLayerVisibility(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u64 layer_id = rp.Pop<u64>(); - bool visibility = rp.Pop<bool>(); + const u64 layer_id = rp.Pop<u64>(); + const bool visibility = rp.Pop<bool>(); + LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, visibility); @@ -899,10 +910,23 @@ private: LOG_WARNING(Service_VI, "(STUBBED) called"); IPC::RequestParser rp{ctx}; - auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); - auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); + const auto name_buf = rp.PopRaw<std::array<char, 0x40>>(); + + OpenDisplayImpl(ctx, std::string_view{name_buf.data(), name_buf.size()}); + } - std::string name(name_buf.begin(), end); + void OpenDefaultDisplay(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_VI, "called"); + + OpenDisplayImpl(ctx, "Default"); + } + + void OpenDisplayImpl(Kernel::HLERequestContext& ctx, std::string_view name) { + const auto trim_pos = name.find('\0'); + + if (trim_pos != std::string_view::npos) { + name.remove_suffix(name.size() - trim_pos); + } ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); @@ -912,20 +936,29 @@ private: } void CloseDisplay(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 display_id = rp.Pop<u64>(); + const u64 display_id = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } - void GetDisplayResolution(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); + // This literally does nothing internally in the actual service itself, + // and just returns a successful result code regardless of the input. + void SetDisplayEnabled(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_VI, "called."); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void GetDisplayResolution(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u64 display_id = rp.Pop<u64>(); + const u64 display_id = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); IPC::ResponseBuilder rb{ctx, 6}; rb.Push(RESULT_SUCCESS); @@ -944,11 +977,12 @@ private: } void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u32 scaling_mode = rp.Pop<u32>(); - u64 unknown = rp.Pop<u64>(); + const u32 scaling_mode = rp.Pop<u32>(); + const u64 unknown = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. scaling_mode=0x{:08X}, unknown=0x{:016X}", + scaling_mode, unknown); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -968,19 +1002,19 @@ private: } void OpenLayer(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_VI, "called"); - IPC::RequestParser rp{ctx}; - auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); - auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); + const auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); + const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); + + const std::string display_name(name_buf.begin(), end); - std::string display_name(name_buf.begin(), end); + const u64 layer_id = rp.Pop<u64>(); + const u64 aruid = rp.Pop<u64>(); - u64 layer_id = rp.Pop<u64>(); - u64 aruid = rp.Pop<u64>(); + LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); - u64 display_id = nv_flinger->OpenDisplay(display_name); - u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); + const u64 display_id = nv_flinger->OpenDisplay(display_name); + const u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); NativeWindow native_window{buffer_queue_id}; IPC::ResponseBuilder rb{ctx, 4}; @@ -989,17 +1023,17 @@ private: } void CreateStrayLayer(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_VI, "called"); - IPC::RequestParser rp{ctx}; - u32 flags = rp.Pop<u32>(); + const u32 flags = rp.Pop<u32>(); rp.Pop<u32>(); // padding - u64 display_id = rp.Pop<u64>(); + const u64 display_id = rp.Pop<u64>(); + + LOG_DEBUG(Service_VI, "called. flags=0x{:08X}, display_id=0x{:016X}", flags, display_id); // TODO(Subv): What's the difference between a Stray and a Managed layer? - u64 layer_id = nv_flinger->CreateLayer(display_id); - u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); + const u64 layer_id = nv_flinger->CreateLayer(display_id); + const u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); NativeWindow native_window{buffer_queue_id}; IPC::ResponseBuilder rb{ctx, 6}; @@ -1009,22 +1043,22 @@ private: } void DestroyStrayLayer(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 layer_id = rp.Pop<u64>(); + const u64 layer_id = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 display_id = rp.Pop<u64>(); + const u64 display_id = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); - auto vsync_event = nv_flinger->GetVsyncEvent(display_id); + const auto vsync_event = nv_flinger->GetVsyncEvent(display_id); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); @@ -1093,9 +1127,9 @@ IApplicationDisplayService::IApplicationDisplayService( "GetIndirectDisplayTransactionService"}, {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"}, {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"}, - {1011, nullptr, "OpenDefaultDisplay"}, + {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"}, {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"}, - {1101, nullptr, "SetDisplayEnabled"}, + {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"}, {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"}, {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"}, {2021, nullptr, "CloseLayer"}, diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 2b29fc45f..089daf96f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -1014,8 +1014,11 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); Surface surface = res_cache.GetTextureSurface(texture, entry); if (surface != nullptr) { - state.texture_units[current_bindpoint].texture = surface->Texture().handle; - state.texture_units[current_bindpoint].target = surface->Target(); + const GLuint handle = + entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle; + const GLenum target = entry.IsArray() ? surface->TargetLayer() : surface->Target(); + state.texture_units[current_bindpoint].texture = handle; + state.texture_units[current_bindpoint].target = target; state.texture_units[current_bindpoint].swizzle.r = MaxwellToGL::SwizzleSource(texture.tic.x_source); state.texture_units[current_bindpoint].swizzle.g = diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 75b4fe88d..d3dcb9a46 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -44,6 +44,17 @@ struct FormatTuple { bool compressed; }; +static void ApplyTextureDefaults(GLenum target, u32 max_mip_level) { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, max_mip_level - 1); + if (max_mip_level == 1) { + glTexParameterf(target, GL_TEXTURE_LOD_BIAS, 1000.0); + } +} + void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) { auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()}; const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)}; @@ -530,6 +541,9 @@ CachedSurface::CachedSurface(const SurfaceParams& params) glActiveTexture(GL_TEXTURE0); const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type); + gl_internal_format = format_tuple.internal_format; + gl_is_compressed = format_tuple.compressed; + if (!format_tuple.compressed) { // Only pre-create the texture for non-compressed textures. switch (params.target) { @@ -558,15 +572,7 @@ CachedSurface::CachedSurface(const SurfaceParams& params) } } - glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL, - params.max_mip_level - 1); - if (params.max_mip_level == 1) { - glTexParameterf(SurfaceTargetToGL(params.target), GL_TEXTURE_LOD_BIAS, 1000.0); - } + ApplyTextureDefaults(SurfaceTargetToGL(params.target), params.max_mip_level); LabelGLObject(GL_TEXTURE, texture.handle, params.addr, SurfaceParams::SurfaceTargetName(params.target)); @@ -864,6 +870,31 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } +void CachedSurface::EnsureTextureView() { + if (texture_view.handle != 0) + return; + // Compressed texture are not being created with immutable storage + UNIMPLEMENTED_IF(gl_is_compressed); + + const GLenum target{TargetLayer()}; + + texture_view.Create(); + glTextureView(texture_view.handle, target, texture.handle, gl_internal_format, 0, + params.max_mip_level, 0, 1); + + OpenGLState cur_state = OpenGLState::GetCurState(); + const auto& old_tex = cur_state.texture_units[0]; + SCOPE_EXIT({ + cur_state.texture_units[0] = old_tex; + cur_state.Apply(); + }); + cur_state.texture_units[0].texture = texture_view.handle; + cur_state.texture_units[0].target = target; + cur_state.Apply(); + + ApplyTextureDefaults(target, params.max_mip_level); +} + MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64)); void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { if (params.type == SurfaceType::Fill) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index c710aa245..7223700c4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -293,10 +293,31 @@ public: return texture; } + const OGLTexture& TextureLayer() { + if (params.is_layered) { + return Texture(); + } + EnsureTextureView(); + return texture_view; + } + GLenum Target() const { return gl_target; } + GLenum TargetLayer() const { + using VideoCore::Surface::SurfaceTarget; + switch (params.target) { + case SurfaceTarget::Texture1D: + return GL_TEXTURE_1D_ARRAY; + case SurfaceTarget::Texture2D: + return GL_TEXTURE_2D_ARRAY; + case SurfaceTarget::TextureCubemap: + return GL_TEXTURE_CUBE_MAP_ARRAY; + } + return Target(); + } + const SurfaceParams& GetSurfaceParams() const { return params; } @@ -311,11 +332,16 @@ public: private: void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); + void EnsureTextureView(); + OGLTexture texture; + OGLTexture texture_view; std::vector<std::vector<u8>> gl_buffer; - SurfaceParams params; - GLenum gl_target; - std::size_t cached_size_in_bytes; + SurfaceParams params{}; + GLenum gl_target{}; + GLenum gl_internal_format{}; + bool gl_is_compressed{}; + std::size_t cached_size_in_bytes{}; }; class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index c4349ccc8..165d70e9c 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -470,6 +470,8 @@ void Config::ReadValues() { qt_config->value("enable_discord_presence", true).toBool(); UISettings::values.screenshot_resolution_factor = static_cast<u16>(qt_config->value("screenshot_resolution_factor", 0).toUInt()); + UISettings::values.select_user_on_boot = + qt_config->value("select_user_on_boot", false).toBool(); qt_config->beginGroup("UIGameList"); UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool(); @@ -680,7 +682,7 @@ void Config::SaveValues() { qt_config->setValue("title_id", QVariant::fromValue<u64>(elem.first)); qt_config->beginWriteArray("disabled"); for (std::size_t j = 0; j < elem.second.size(); ++j) { - qt_config->setArrayIndex(j); + qt_config->setArrayIndex(static_cast<int>(j)); qt_config->setValue("d", QString::fromStdString(elem.second[j])); } qt_config->endArray(); @@ -693,6 +695,7 @@ void Config::SaveValues() { qt_config->setValue("enable_discord_presence", UISettings::values.enable_discord_presence); qt_config->setValue("screenshot_resolution_factor", UISettings::values.screenshot_resolution_factor); + qt_config->setValue("select_user_on_boot", UISettings::values.select_user_on_boot); qt_config->beginGroup("UIGameList"); qt_config->setValue("show_unknown", UISettings::values.show_unknown); diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index 8706b80d2..ce833b6c8 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>461</width> - <height>659</height> + <width>382</width> + <height>241</height> </rect> </property> <property name="windowTitle"> @@ -15,51 +15,71 @@ </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QTabWidget" name="tabWidget"> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="ConfigureGeneral" name="generalTab"> - <attribute name="title"> - <string>General</string> - </attribute> - </widget> - <widget class="ConfigureGameList" name="gameListTab"> - <attribute name="title"> - <string>Game List</string> - </attribute> - </widget> - <widget class="ConfigureSystem" name="systemTab"> - <attribute name="title"> - <string>System</string> - </attribute> - </widget> - <widget class="ConfigureInputSimple" name="inputTab"> - <attribute name="title"> - <string>Input</string> - </attribute> - </widget> - <widget class="ConfigureGraphics" name="graphicsTab"> - <attribute name="title"> - <string>Graphics</string> - </attribute> - </widget> - <widget class="ConfigureAudio" name="audioTab"> - <attribute name="title"> - <string>Audio</string> - </attribute> - </widget> - <widget class="ConfigureDebug" name="debugTab"> - <attribute name="title"> - <string>Debug</string> - </attribute> - </widget> - <widget class="ConfigureWeb" name="webTab"> - <attribute name="title"> - <string>Web</string> - </attribute> - </widget> - </widget> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QListWidget" name="selectorList"> + <property name="minimumSize"> + <size> + <width>150</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>150</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="ConfigureGeneral" name="generalTab"> + <attribute name="title"> + <string>General</string> + </attribute> + </widget> + <widget class="ConfigureGameList" name="gameListTab"> + <attribute name="title"> + <string>Game List</string> + </attribute> + </widget> + <widget class="ConfigureSystem" name="systemTab"> + <attribute name="title"> + <string>System</string> + </attribute> + </widget> + <widget class="ConfigureInputSimple" name="inputTab"> + <attribute name="title"> + <string>Input</string> + </attribute> + </widget> + <widget class="ConfigureGraphics" name="graphicsTab"> + <attribute name="title"> + <string>Graphics</string> + </attribute> + </widget> + <widget class="ConfigureAudio" name="audioTab"> + <attribute name="title"> + <string>Audio</string> + </attribute> + </widget> + <widget class="ConfigureDebug" name="debugTab"> + <attribute name="title"> + <string>Debug</string> + </attribute> + </widget> + <widget class="ConfigureWeb" name="webTab"> + <attribute name="title"> + <string>Web</string> + </attribute> + </widget> + </widget> + </item> + </layout> </item> <item> <widget class="QDialogButtonBox" name="buttonBox"> @@ -78,12 +98,6 @@ <container>1</container> </customwidget> <customwidget> - <class>ConfigureGameList</class> - <extends>QWidget</extends> - <header>configuration/configure_gamelist.h</header> - <container>1</container> - </customwidget> - <customwidget> <class>ConfigureSystem</class> <extends>QWidget</extends> <header>configuration/configure_system.h</header> @@ -102,12 +116,6 @@ <container>1</container> </customwidget> <customwidget> - <class>ConfigureInputSimple</class> - <extends>QWidget</extends> - <header>configuration/configure_input_simple.h</header> - <container>1</container> - </customwidget> - <customwidget> <class>ConfigureGraphics</class> <extends>QWidget</extends> <header>configuration/configure_graphics.h</header> @@ -119,6 +127,18 @@ <header>configuration/configure_web.h</header> <container>1</container> </customwidget> + <customwidget> + <class>ConfigureGameList</class> + <extends>QWidget</extends> + <header>configuration/configure_gamelist.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>ConfigureInputSimple</class> + <extends>QWidget</extends> + <header>configuration/configure_input_simple.h</header> + <container>1</container> + </customwidget> </customwidgets> <resources/> <connections> diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 3905423e9..90d7c6372 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <QHash> +#include <QListWidgetItem> #include "core/settings.h" #include "ui_configure.h" #include "yuzu/configuration/config.h" @@ -13,6 +15,13 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry ui->setupUi(this); ui->generalTab->PopulateHotkeyList(registry); this->setConfiguration(); + this->PopulateSelectionList(); + connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, + &ConfigureDialog::UpdateVisibleTabs); + + adjustSize(); + + ui->selectorList->setCurrentRow(0); } ConfigureDialog::~ConfigureDialog() = default; @@ -30,3 +39,37 @@ void ConfigureDialog::applyConfiguration() { ui->webTab->applyConfiguration(); Settings::Apply(); } + +void ConfigureDialog::PopulateSelectionList() { + const std::array<std::pair<QString, QStringList>, 4> items{ + {{tr("General"), {tr("General"), tr("Web"), tr("Debug"), tr("Game List")}}, + {tr("System"), {tr("System"), tr("Audio")}}, + {tr("Graphics"), {tr("Graphics")}}, + {tr("Controls"), {tr("Input")}}}}; + + for (const auto& entry : items) { + auto* const item = new QListWidgetItem(entry.first); + item->setData(Qt::UserRole, entry.second); + + ui->selectorList->addItem(item); + } +} + +void ConfigureDialog::UpdateVisibleTabs() { + const auto items = ui->selectorList->selectedItems(); + if (items.isEmpty()) + return; + + const std::map<QString, QWidget*> widgets = { + {tr("General"), ui->generalTab}, {tr("System"), ui->systemTab}, + {tr("Input"), ui->inputTab}, {tr("Graphics"), ui->graphicsTab}, + {tr("Audio"), ui->audioTab}, {tr("Debug"), ui->debugTab}, + {tr("Web"), ui->webTab}, {tr("Game List"), ui->gameListTab}}; + + ui->tabWidget->clear(); + + const QStringList tabs = items[0]->data(Qt::UserRole).toStringList(); + + for (const auto& tab : tabs) + ui->tabWidget->addTab(widgets.find(tab)->second, tab); +} diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index f6df7b827..243d9fa09 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -24,6 +24,8 @@ public: private: void setConfiguration(); + void UpdateVisibleTabs(); + void PopulateSelectionList(); std::unique_ptr<Ui::ConfigureDialog> ui; }; diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 92a441308..4116b6cd7 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -30,6 +30,7 @@ ConfigureGeneral::~ConfigureGeneral() = default; void ConfigureGeneral::setConfiguration() { ui->toggle_deepscan->setChecked(UISettings::values.gamedir_deepscan); ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); + ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot); ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit); ui->enable_nfc->setChecked(Settings::values.enable_nfc); @@ -42,6 +43,7 @@ void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) { void ConfigureGeneral::applyConfiguration() { UISettings::values.gamedir_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(); UISettings::values.theme = ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index bf37446c6..dff0ad5d0 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -38,6 +38,13 @@ </property> </widget> </item> + <item> + <widget class="QCheckBox" name="toggle_user_on_boot"> + <property name="text"> + <string>Prompt for user on game boot</string> + </property> + </widget> + </item> </layout> </item> </layout> diff --git a/src/yuzu/configuration/configure_per_general.cpp b/src/yuzu/configuration/configure_per_general.cpp index dffaba5ed..e13d2eac8 100644 --- a/src/yuzu/configuration/configure_per_general.cpp +++ b/src/yuzu/configuration/configure_per_general.cpp @@ -120,7 +120,7 @@ void ConfigurePerGameGeneral::loadConfiguration() { QPixmap map; const auto bytes = control.second->ReadAllBytes(); - map.loadFromData(bytes.data(), bytes.size()); + map.loadFromData(bytes.data(), static_cast<u32>(bytes.size())); scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); @@ -130,7 +130,7 @@ void ConfigurePerGameGeneral::loadConfiguration() { scene->clear(); QPixmap map; - map.loadFromData(bytes.data(), bytes.size()); + map.loadFromData(bytes.data(), static_cast<u32>(bytes.size())); scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 01a0f94ab..1d5a2b51a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -687,10 +687,26 @@ bool GMainWindow::LoadROM(const QString& filename) { return true; } +void GMainWindow::SelectAndSetCurrentUser() { + QtProfileSelectionDialog dialog(this); + dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | + Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); + dialog.setWindowModality(Qt::WindowModal); + dialog.exec(); + + if (dialog.GetStatus()) { + Settings::values.current_user = static_cast<s32>(dialog.GetIndex()); + } +} + void GMainWindow::BootGame(const QString& filename) { LOG_INFO(Frontend, "yuzu starting..."); StoreRecentFile(filename); // Put the filename on top of the list + if (UISettings::values.select_user_on_boot) { + SelectAndSetCurrentUser(); + } + if (!LoadROM(filename)) return; @@ -827,31 +843,25 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); ASSERT(program_id != 0); - Service::Account::ProfileManager manager{}; - const auto user_ids = manager.GetAllUsers(); - QStringList list; - for (const auto& user_id : user_ids) { - if (user_id == Service::Account::UUID{}) - continue; - Service::Account::ProfileBase base; - if (!manager.GetProfileBase(user_id, base)) - continue; - - list.push_back(QString::fromStdString(Common::StringFromFixedZeroTerminatedBuffer( - reinterpret_cast<const char*>(base.username.data()), base.username.size()))); - } + const auto select_profile = [this]() -> s32 { + QtProfileSelectionDialog dialog(this); + dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | + Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); + dialog.setWindowModality(Qt::WindowModal); + dialog.exec(); - bool ok = false; - const auto index_string = - QInputDialog::getItem(this, tr("Select User"), - tr("Please select the user's save data you would like to open."), - list, Settings::values.current_user, false, &ok); - if (!ok) - return; + if (!dialog.GetStatus()) { + return -1; + } + + return dialog.GetIndex(); + }; - const auto index = list.indexOf(index_string); - ASSERT(index != -1 && index < 8); + const auto index = select_profile(); + if (index == -1) + return; + Service::Account::ProfileManager manager; const auto user_id = manager.GetUser(index); ASSERT(user_id); path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser, diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 4e37f6a2d..d560bf75b 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -128,6 +128,8 @@ private: void ShowTelemetryCallout(); void SetDiscordEnabled(bool state); + void SelectAndSetCurrentUser(); + /** * Stores the filename in the recently loaded files list. * The new filename is stored at the beginning of the recently loaded files list. diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h index 58ba240fd..82aaeedb0 100644 --- a/src/yuzu/ui_settings.h +++ b/src/yuzu/ui_settings.h @@ -40,6 +40,8 @@ struct Values { bool confirm_before_closing; bool first_start; + bool select_user_on_boot; + // Discord RPC bool enable_discord_presence; |