summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/common/fs/path_util.h2
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp26
-rw-r--r--src/core/hle/kernel/hle_ipc.h23
-rw-r--r--src/core/hle/kernel/k_auto_object.h11
-rw-r--r--src/core/hle/kernel/k_auto_object_container.cpp4
-rw-r--r--src/core/hle/kernel/k_auto_object_container.h5
-rw-r--r--src/core/hle/kernel/k_client_port.cpp9
-rw-r--r--src/core/hle/kernel/k_client_port.h4
-rw-r--r--src/core/hle/kernel/k_client_session.h4
-rw-r--r--src/core/hle/kernel/k_readable_event.h4
-rw-r--r--src/core/hle/kernel/k_server_port.cpp4
-rw-r--r--src/core/hle/kernel/k_server_port.h2
-rw-r--r--src/core/hle/kernel/k_server_session.cpp63
-rw-r--r--src/core/hle/kernel/k_server_session.h17
-rw-r--r--src/core/hle/kernel/k_session.cpp5
-rw-r--r--src/core/hle/kernel/k_session.h5
-rw-r--r--src/core/hle/kernel/k_writable_event.cpp4
-rw-r--r--src/core/hle/kernel/kernel.cpp18
-rw-r--r--src/core/hle/service/ns/pl_u.cpp2
-rw-r--r--src/core/hle/service/service.cpp6
-rw-r--r--src/core/hle/service/service.h5
-rw-r--r--src/core/hle/service/sm/controller.cpp37
-rw-r--r--src/core/hle/service/sm/sm.cpp2
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h11
-rw-r--r--src/video_core/engines/maxwell_3d.cpp8
-rw-r--r--src/video_core/memory_manager.cpp3
-rw-r--r--src/video_core/rasterizer_interface.h3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h1
-rw-r--r--src/video_core/textures/decoders.cpp8
-rw-r--r--src/yuzu/configuration/configure_ui.cpp40
-rw-r--r--src/yuzu/game_list.cpp10
-rw-r--r--src/yuzu/game_list.h2
-rw-r--r--src/yuzu/main.cpp6
-rw-r--r--src/yuzu/main.h8
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp15
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h3
39 files changed, 245 insertions, 144 deletions
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h
index 14e8c35d7..f956ac9a2 100644
--- a/src/common/fs/path_util.h
+++ b/src/common/fs/path_util.h
@@ -209,7 +209,7 @@ void SetYuzuPath(YuzuPath yuzu_path, const std::filesystem::path& new_path);
#ifdef _WIN32
template <typename Path>
-[[nodiscard]] void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) {
+void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) {
if constexpr (IsChar<typename Path::value_type>) {
SetYuzuPath(yuzu_path, ToU8String(new_path));
} else {
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 2b5c30f7a..45aced99f 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -30,9 +30,31 @@
namespace Kernel {
-SessionRequestHandler::SessionRequestHandler() = default;
+SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_)
+ : kernel{kernel_}, service_thread{kernel.CreateServiceThread(service_name_)} {}
-SessionRequestHandler::~SessionRequestHandler() = default;
+SessionRequestHandler::~SessionRequestHandler() {
+ kernel.ReleaseServiceThread(service_thread);
+}
+
+SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {}
+
+SessionRequestManager::~SessionRequestManager() = default;
+
+bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& context) const {
+ if (IsDomain() && context.HasDomainMessageHeader()) {
+ const auto& message_header = context.GetDomainMessageHeader();
+ const auto object_id = message_header.object_id;
+
+ if (object_id > DomainHandlerCount()) {
+ LOG_CRITICAL(IPC, "object_id {} is too big!", object_id);
+ return false;
+ }
+ return DomainHandler(object_id - 1) != nullptr;
+ } else {
+ return session_handler != nullptr;
+ }
+}
void SessionRequestHandler::ClientConnected(KServerSession* session) {
session->SetSessionHandler(shared_from_this());
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index b47e363cc..a61870f8b 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -46,6 +46,7 @@ class KThread;
class KReadableEvent;
class KSession;
class KWritableEvent;
+class ServiceThread;
enum class ThreadWakeupReason;
@@ -56,7 +57,7 @@ enum class ThreadWakeupReason;
*/
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
public:
- SessionRequestHandler();
+ SessionRequestHandler(KernelCore& kernel, const char* service_name_);
virtual ~SessionRequestHandler();
/**
@@ -83,6 +84,14 @@ public:
* @param server_session ServerSession associated with the connection.
*/
void ClientDisconnected(KServerSession* session);
+
+ std::weak_ptr<ServiceThread> GetServiceThread() const {
+ return service_thread;
+ }
+
+protected:
+ KernelCore& kernel;
+ std::weak_ptr<ServiceThread> service_thread;
};
using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
@@ -94,7 +103,8 @@ using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
*/
class SessionRequestManager final {
public:
- SessionRequestManager() = default;
+ explicit SessionRequestManager(KernelCore& kernel);
+ ~SessionRequestManager();
bool IsDomain() const {
return is_domain;
@@ -142,10 +152,19 @@ public:
session_handler = std::move(handler);
}
+ std::weak_ptr<ServiceThread> GetServiceThread() const {
+ return session_handler->GetServiceThread();
+ }
+
+ bool HasSessionRequestHandler(const HLERequestContext& context) const;
+
private:
bool is_domain{};
SessionRequestHandlerPtr session_handler;
std::vector<SessionRequestHandlerPtr> domain_handlers;
+
+private:
+ KernelCore& kernel;
};
/**
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index bc18582be..88a052f65 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -7,10 +7,11 @@
#include <atomic>
#include <string>
+#include <boost/intrusive/rbtree.hpp>
+
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
-#include "common/intrusive_red_black_tree.h"
#include "core/hle/kernel/k_class_token.h"
namespace Kernel {
@@ -175,7 +176,7 @@ private:
class KAutoObjectWithListContainer;
-class KAutoObjectWithList : public KAutoObject {
+class KAutoObjectWithList : public KAutoObject, public boost::intrusive::set_base_hook<> {
public:
explicit KAutoObjectWithList(KernelCore& kernel_) : KAutoObject(kernel_) {}
@@ -192,6 +193,10 @@ public:
}
}
+ friend bool operator<(const KAutoObjectWithList& left, const KAutoObjectWithList& right) {
+ return &left < &right;
+ }
+
public:
virtual u64 GetId() const {
return reinterpret_cast<u64>(this);
@@ -203,8 +208,6 @@ public:
private:
friend class KAutoObjectWithListContainer;
-
- Common::IntrusiveRedBlackTreeNode list_node;
};
template <typename T>
diff --git a/src/core/hle/kernel/k_auto_object_container.cpp b/src/core/hle/kernel/k_auto_object_container.cpp
index fc0c28874..010006bb7 100644
--- a/src/core/hle/kernel/k_auto_object_container.cpp
+++ b/src/core/hle/kernel/k_auto_object_container.cpp
@@ -9,13 +9,13 @@ namespace Kernel {
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
KScopedLightLock lk(m_lock);
- m_object_list.insert(*obj);
+ m_object_list.insert_unique(*obj);
}
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
KScopedLightLock lk(m_lock);
- m_object_list.erase(m_object_list.iterator_to(*obj));
+ m_object_list.erase(*obj);
}
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
diff --git a/src/core/hle/kernel/k_auto_object_container.h b/src/core/hle/kernel/k_auto_object_container.h
index ff40cf5a7..459953450 100644
--- a/src/core/hle/kernel/k_auto_object_container.h
+++ b/src/core/hle/kernel/k_auto_object_container.h
@@ -6,6 +6,8 @@
#include <atomic>
+#include <boost/intrusive/rbtree.hpp>
+
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
@@ -23,8 +25,7 @@ class KAutoObjectWithListContainer {
YUZU_NON_MOVEABLE(KAutoObjectWithListContainer);
public:
- using ListType = Common::IntrusiveRedBlackTreeMemberTraits<
- &KAutoObjectWithList::list_node>::TreeType<KAutoObjectWithList>;
+ using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
public:
class ListAccessor : public KScopedLightLock {
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp
index 23d830d1f..50606bd91 100644
--- a/src/core/hle/kernel/k_client_port.cpp
+++ b/src/core/hle/kernel/k_client_port.cpp
@@ -16,11 +16,11 @@ namespace Kernel {
KClientPort::KClientPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
KClientPort::~KClientPort() = default;
-void KClientPort::Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_) {
+void KClientPort::Initialize(KPort* parent_port_, s32 max_sessions_, std::string&& name_) {
// Set member variables.
num_sessions = 0;
peak_sessions = 0;
- parent = parent_;
+ parent = parent_port_;
max_sessions = max_sessions_;
name = std::move(name_);
}
@@ -56,7 +56,8 @@ bool KClientPort::IsSignaled() const {
return num_sessions < max_sessions;
}
-ResultCode KClientPort::CreateSession(KClientSession** out) {
+ResultCode KClientPort::CreateSession(KClientSession** out,
+ std::shared_ptr<SessionRequestManager> session_manager) {
// Reserve a new session from the resource limit.
KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
LimitableResource::Sessions);
@@ -101,7 +102,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) {
}
// Initialize the session.
- session->Initialize(this, parent->GetName());
+ session->Initialize(this, parent->GetName(), session_manager);
// Commit the session reservation.
session_reservation.Commit();
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h
index f2fff3b01..54bb05e20 100644
--- a/src/core/hle/kernel/k_client_port.h
+++ b/src/core/hle/kernel/k_client_port.h
@@ -16,6 +16,7 @@ namespace Kernel {
class KClientSession;
class KernelCore;
class KPort;
+class SessionRequestManager;
class KClientPort final : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
@@ -52,7 +53,8 @@ public:
void Destroy() override;
bool IsSignaled() const override;
- ResultCode CreateSession(KClientSession** out);
+ ResultCode CreateSession(KClientSession** out,
+ std::shared_ptr<SessionRequestManager> session_manager = nullptr);
private:
std::atomic<s32> num_sessions{};
diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h
index b11d5b4e3..230e3b6b8 100644
--- a/src/core/hle/kernel/k_client_session.h
+++ b/src/core/hle/kernel/k_client_session.h
@@ -36,9 +36,9 @@ public:
explicit KClientSession(KernelCore& kernel_);
~KClientSession() override;
- void Initialize(KSession* parent_, std::string&& name_) {
+ void Initialize(KSession* parent_session_, std::string&& name_) {
// Set member variables.
- parent = parent_;
+ parent = parent_session_;
name = std::move(name_);
}
diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h
index b2850ac7b..149fa78dd 100644
--- a/src/core/hle/kernel/k_readable_event.h
+++ b/src/core/hle/kernel/k_readable_event.h
@@ -21,9 +21,9 @@ public:
explicit KReadableEvent(KernelCore& kernel_);
~KReadableEvent() override;
- void Initialize(KEvent* parent_, std::string&& name_) {
+ void Initialize(KEvent* parent_event_, std::string&& name_) {
is_signaled = false;
- parent = parent_;
+ parent = parent_event_;
name = std::move(name_);
}
diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp
index 8cbde177a..c5dc58387 100644
--- a/src/core/hle/kernel/k_server_port.cpp
+++ b/src/core/hle/kernel/k_server_port.cpp
@@ -17,9 +17,9 @@ namespace Kernel {
KServerPort::KServerPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
KServerPort::~KServerPort() = default;
-void KServerPort::Initialize(KPort* parent_, std::string&& name_) {
+void KServerPort::Initialize(KPort* parent_port_, std::string&& name_) {
// Set member variables.
- parent = parent_;
+ parent = parent_port_;
name = std::move(name_);
}
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h
index 55481d63f..67a36da40 100644
--- a/src/core/hle/kernel/k_server_port.h
+++ b/src/core/hle/kernel/k_server_port.h
@@ -29,7 +29,7 @@ public:
explicit KServerPort(KernelCore& kernel_);
~KServerPort() override;
- void Initialize(KPort* parent_, std::string&& name_);
+ void Initialize(KPort* parent_port_, std::string&& name_);
/// Whether or not this server port has an HLE handler available.
bool HasSessionRequestHandler() const {
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index dbf03b462..5c3c13ce6 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -8,13 +8,16 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/scope_exit.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_handle_table.h"
+#include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_server_port.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/k_thread.h"
@@ -23,18 +26,21 @@
namespace Kernel {
-KServerSession::KServerSession(KernelCore& kernel_)
- : KSynchronizationObject{kernel_}, manager{std::make_shared<SessionRequestManager>()} {}
+KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
-KServerSession::~KServerSession() {
- kernel.ReleaseServiceThread(service_thread);
-}
+KServerSession::~KServerSession() {}
-void KServerSession::Initialize(KSession* parent_, std::string&& name_) {
+void KServerSession::Initialize(KSession* parent_session_, std::string&& name_,
+ std::shared_ptr<SessionRequestManager> manager_) {
// Set member variables.
- parent = parent_;
+ parent = parent_session_;
name = std::move(name_);
- service_thread = kernel.CreateServiceThread(name);
+
+ if (manager_) {
+ manager = manager_;
+ } else {
+ manager = std::make_shared<SessionRequestManager>(kernel);
+ }
}
void KServerSession::Destroy() {
@@ -114,9 +120,25 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
- if (auto strong_ptr = service_thread.lock()) {
- strong_ptr->QueueSyncRequest(*parent, std::move(context));
- return ResultSuccess;
+ // In the event that something fails here, stub a result to prevent the game from crashing.
+ // This is a work-around in the event that somehow we process a service request after the
+ // session has been closed by the game. This has been observed to happen rarely in Pokemon
+ // Sword/Shield and is likely a result of us using host threads/scheduling for services.
+ // TODO(bunnei): Find a better solution here.
+ auto error_guard = SCOPE_GUARD({ CompleteSyncRequest(*context); });
+
+ // Ensure we have a session request handler
+ if (manager->HasSessionRequestHandler(*context)) {
+ if (auto strong_ptr = manager->GetServiceThread().lock()) {
+ strong_ptr->QueueSyncRequest(*parent, std::move(context));
+
+ // We succeeded.
+ error_guard.Cancel();
+ } else {
+ ASSERT_MSG(false, "strong_ptr is nullptr!");
+ }
+ } else {
+ ASSERT_MSG(false, "handler is invalid!");
}
return ResultSuccess;
@@ -124,13 +146,20 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor
ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) {
ResultCode result = ResultSuccess;
+
// If the session has been converted to a domain, handle the domain request
- if (IsDomain() && context.HasDomainMessageHeader()) {
- result = HandleDomainSyncRequest(context);
- // If there is no domain header, the regular session handler is used
- } else if (manager->HasSessionHandler()) {
- // If this ServerSession has an associated HLE handler, forward the request to it.
- result = manager->SessionHandler().HandleSyncRequest(*this, context);
+ if (manager->HasSessionRequestHandler(context)) {
+ if (IsDomain() && context.HasDomainMessageHeader()) {
+ result = HandleDomainSyncRequest(context);
+ // If there is no domain header, the regular session handler is used
+ } else if (manager->HasSessionHandler()) {
+ // If this ServerSession has an associated HLE handler, forward the request to it.
+ result = manager->SessionHandler().HandleSyncRequest(*this, context);
+ }
+ } else {
+ ASSERT_MSG(false, "Session handler is invalid, stubbing response!");
+ IPC::ResponseBuilder rb(context, 2);
+ rb.Push(ResultSuccess);
}
if (convert_to_domain) {
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h
index 27b757ad2..9efd400bc 100644
--- a/src/core/hle/kernel/k_server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -32,6 +32,7 @@ class HLERequestContext;
class KernelCore;
class KSession;
class SessionRequestHandler;
+class SessionRequestManager;
class KThread;
class KServerSession final : public KSynchronizationObject,
@@ -46,7 +47,8 @@ public:
void Destroy() override;
- void Initialize(KSession* parent_, std::string&& name_);
+ void Initialize(KSession* parent_session_, std::string&& name_,
+ std::shared_ptr<SessionRequestManager> manager_);
KSession* GetParent() {
return parent;
@@ -104,16 +106,6 @@ public:
return manager;
}
- /// Gets the session request manager, which forwards requests to the underlying service
- const std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() const {
- return manager;
- }
-
- /// Sets the session request manager, which forwards requests to the underlying service
- void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) {
- manager = std::move(manager_);
- }
-
private:
/// Queues a sync request from the emulated application.
ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory);
@@ -131,9 +123,6 @@ private:
/// When set to True, converts the session to a domain at the end of the command
bool convert_to_domain{};
- /// Thread to dispatch service requests
- std::weak_ptr<ServiceThread> service_thread;
-
/// KSession that owns this KServerSession
KSession* parent{};
};
diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp
index 025b8b555..940878e03 100644
--- a/src/core/hle/kernel/k_session.cpp
+++ b/src/core/hle/kernel/k_session.cpp
@@ -15,7 +15,8 @@ KSession::KSession(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
KSession::~KSession() = default;
-void KSession::Initialize(KClientPort* port_, const std::string& name_) {
+void KSession::Initialize(KClientPort* port_, const std::string& name_,
+ std::shared_ptr<SessionRequestManager> manager_) {
// Increment reference count.
// Because reference count is one on creation, this will result
// in a reference count of two. Thus, when both server and client are closed
@@ -27,7 +28,7 @@ void KSession::Initialize(KClientPort* port_, const std::string& name_) {
KAutoObject::Create(std::addressof(client));
// Initialize our sub sessions.
- server.Initialize(this, name_ + ":Server");
+ server.Initialize(this, name_ + ":Server", manager_);
client.Initialize(this, name_ + ":Client");
// Set state and name.
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h
index 4ddd080d2..62c328a68 100644
--- a/src/core/hle/kernel/k_session.h
+++ b/src/core/hle/kernel/k_session.h
@@ -13,6 +13,8 @@
namespace Kernel {
+class SessionRequestManager;
+
class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList> {
KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject);
@@ -20,7 +22,8 @@ public:
explicit KSession(KernelCore& kernel_);
~KSession() override;
- void Initialize(KClientPort* port_, const std::string& name_);
+ void Initialize(KClientPort* port_, const std::string& name_,
+ std::shared_ptr<SessionRequestManager> manager_ = nullptr);
void Finalize() override;
diff --git a/src/core/hle/kernel/k_writable_event.cpp b/src/core/hle/kernel/k_writable_event.cpp
index b7b83c151..bdb1db6d5 100644
--- a/src/core/hle/kernel/k_writable_event.cpp
+++ b/src/core/hle/kernel/k_writable_event.cpp
@@ -13,8 +13,8 @@ KWritableEvent::KWritableEvent(KernelCore& kernel_)
KWritableEvent::~KWritableEvent() = default;
-void KWritableEvent::Initialize(KEvent* parent_, std::string&& name_) {
- parent = parent_;
+void KWritableEvent::Initialize(KEvent* parent_event_, std::string&& name_) {
+ parent = parent_event_;
name = std::move(name_);
parent->GetReadableEvent().Open();
}
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0ffb78d51..2ceeaeb5f 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -63,8 +63,6 @@ struct KernelCore::Impl {
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
- service_thread_manager =
- std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
is_phantom_mode_for_singlecore = false;
InitializePhysicalCores();
@@ -96,7 +94,6 @@ struct KernelCore::Impl {
process_list.clear();
// Ensures all service threads gracefully shutdown
- service_thread_manager.reset();
service_threads.clear();
next_object_id = 0;
@@ -680,10 +677,6 @@ struct KernelCore::Impl {
// Threads used for services
std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
- // Service threads are managed by a worker thread, so that a calling service thread can queue up
- // the release of itself
- std::unique_ptr<Common::ThreadWorker> service_thread_manager;
-
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
@@ -986,17 +979,14 @@ void KernelCore::ExitSVCProfile() {
std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name);
- impl->service_thread_manager->QueueWork(
- [this, service_thread] { impl->service_threads.emplace(service_thread); });
+ impl->service_threads.emplace(service_thread);
return service_thread;
}
void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
- impl->service_thread_manager->QueueWork([this, service_thread] {
- if (auto strong_ptr = service_thread.lock()) {
- impl->service_threads.erase(strong_ptr);
- }
- });
+ if (auto strong_ptr = service_thread.lock()) {
+ impl->service_threads.erase(strong_ptr);
+ }
}
Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() {
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 6e5ba26a3..74cc45f1e 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -254,8 +254,6 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NS, "called");
// Create shared font memory object
- auto& kernel = system.Kernel();
-
std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(),
impl->shared_font->size());
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 7a15eeba0..4e1541630 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -93,8 +93,8 @@ namespace Service {
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
u32 max_sessions_, InvokerFn* handler_invoker_)
- : system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
- handler_invoker{handler_invoker_} {}
+ : SessionRequestHandler(system_.Kernel(), service_name_), system{system_},
+ service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
ServiceFrameworkBase::~ServiceFrameworkBase() {
// Wait for other threads to release access before destroying
@@ -111,7 +111,7 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
port_installed = true;
}
-Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
+Kernel::KClientPort& ServiceFrameworkBase::CreatePort() {
const auto guard = LockService();
ASSERT(!port_installed);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 4c048173b..ec757753c 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -23,6 +23,7 @@ namespace Kernel {
class HLERequestContext;
class KClientPort;
class KServerSession;
+class ServiceThread;
} // namespace Kernel
namespace Service {
@@ -41,7 +42,7 @@ class ServiceManager;
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
/// Arbitrary default number of maximum connections to an HLE service.
-static const u32 DefaultMaxSessions = 10;
+static const u32 DefaultMaxSessions = 64;
/**
* This is an non-templated base of ServiceFramework to reduce code bloat and compilation times, it
@@ -74,7 +75,7 @@ public:
void InvokeRequestTipc(Kernel::HLERequestContext& ctx);
/// Creates a port pair and registers it on the kernel's global port registry.
- Kernel::KClientPort& CreatePort(Kernel::KernelCore& kernel);
+ Kernel::KClientPort& CreatePort();
/// Handles a synchronization request for the service.
ResultCode HandleSyncRequest(Kernel::KServerSession& session,
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 5fa5e0512..8b9418e0f 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -28,42 +28,25 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
}
void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
- // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
- // and that we probably want to actually make an entirely new Session, but we still need to
- // verify this on hardware.
-
LOG_DEBUG(Service, "called");
- auto& kernel = system.Kernel();
- auto* session = ctx.Session()->GetParent();
- auto* port = session->GetParent()->GetParent();
+ auto& parent_session = *ctx.Session()->GetParent();
+ auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort();
+ auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager();
- // Reserve a new session from the process resource limit.
- Kernel::KScopedResourceReservation session_reservation(
- kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions);
- if (!session_reservation.Succeeded()) {
+ // Create a session.
+ Kernel::KClientSession* session{};
+ const ResultCode result = parent_port.CreateSession(std::addressof(session), session_manager);
+ if (result.IsError()) {
+ LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Kernel::ResultLimitReached);
+ rb.Push(result);
}
- // Create a new session.
- auto* clone = Kernel::KSession::Create(kernel);
- clone->Initialize(&port->GetClientPort(), session->GetName());
-
- // Commit the session reservation.
- session_reservation.Commit();
-
- // Enqueue the session with the named port.
- port->EnqueueSession(&clone->GetServerSession());
-
- // Set the session request manager.
- clone->GetServerSession().SetSessionRequestManager(
- session->GetServerSession().GetSessionRequestManager());
-
// We succeeded.
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(ResultSuccess);
- rb.PushMoveObjects(clone->GetClientSession());
+ rb.PushMoveObjects(session);
}
void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index d8b20a3f2..bffa9ffcb 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -46,7 +46,7 @@ Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core
self.sm_interface = sm;
self.controller_interface = std::make_unique<Controller>(system);
- return sm->CreatePort(system.Kernel());
+ return sm->CreatePort();
}
ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name,
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 9e6b87960..d371b842f 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -110,6 +110,8 @@ public:
void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size);
+ void DisableGraphicsUniformBuffer(size_t stage, u32 index);
+
void UpdateGraphicsBuffers(bool is_indexed);
void UpdateComputeBuffers();
@@ -419,10 +421,6 @@ template <class P>
void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr,
u32 size) {
const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
- if (!cpu_addr) {
- uniform_buffers[stage][index] = NULL_BINDING;
- return;
- }
const Binding binding{
.cpu_addr = *cpu_addr,
.size = size,
@@ -432,6 +430,11 @@ void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr
}
template <class P>
+void BufferCache<P>::DisableGraphicsUniformBuffer(size_t stage, u32 index) {
+ uniform_buffers[stage][index] = NULL_BINDING;
+}
+
+template <class P>
void BufferCache<P>::UpdateGraphicsBuffers(bool is_indexed) {
MICROPROFILE_SCOPE(GPU_PrepareBuffers);
do {
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 75517a4f7..aab6b8f7a 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -578,8 +578,12 @@ void Maxwell3D::ProcessCBBind(size_t stage_index) {
buffer.size = regs.const_buffer.cb_size;
const bool is_enabled = bind_data.valid.Value() != 0;
- const GPUVAddr gpu_addr = is_enabled ? regs.const_buffer.BufferAddress() : 0;
- const u32 size = is_enabled ? regs.const_buffer.cb_size : 0;
+ if (!is_enabled) {
+ rasterizer->DisableGraphicsUniformBuffer(stage_index, bind_data.index);
+ return;
+ }
+ const GPUVAddr gpu_addr = regs.const_buffer.BufferAddress();
+ const u32 size = regs.const_buffer.cb_size;
rasterizer->BindGraphicsUniformBuffer(stage_index, bind_data.index, gpu_addr, size);
}
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index eb58ac6b6..7124c755c 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -163,6 +163,9 @@ std::optional<GPUVAddr> MemoryManager::FindFreeRange(std::size_t size, std::size
}
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const {
+ if (gpu_addr == 0) {
+ return std::nullopt;
+ }
const auto page_entry{GetPageEntry(gpu_addr)};
if (!page_entry.IsValid()) {
return std::nullopt;
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 50491b758..f968b5b16 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -54,6 +54,9 @@ public:
virtual void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr,
u32 size) = 0;
+ /// Signal disabling of a uniform buffer
+ virtual void DisableGraphicsUniformBuffer(size_t stage, u32 index) = 0;
+
/// Signal a GPU based semaphore as a fence
virtual void SignalSemaphore(GPUVAddr addr, u32 value) = 0;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index a5dbb9adf..f87bb269b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -526,6 +526,10 @@ void RasterizerOpenGL::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAd
buffer_cache.BindGraphicsUniformBuffer(stage, index, gpu_addr, size);
}
+void RasterizerOpenGL::DisableGraphicsUniformBuffer(size_t stage, u32 index) {
+ buffer_cache.DisableGraphicsUniformBuffer(stage, index);
+}
+
void RasterizerOpenGL::FlushAll() {}
void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 3745cf637..76298517f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -72,6 +72,7 @@ public:
void ResetCounter(VideoCore::QueryType type) override;
void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override;
void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override;
+ void DisableGraphicsUniformBuffer(size_t stage, u32 index) override;
void FlushAll() override;
void FlushRegion(VAddr addr, u64 size) override;
bool MustFlushRegion(VAddr addr, u64 size) override;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index e9a0e7811..1c9120170 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -476,6 +476,10 @@ void RasterizerVulkan::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAd
buffer_cache.BindGraphicsUniformBuffer(stage, index, gpu_addr, size);
}
+void Vulkan::RasterizerVulkan::DisableGraphicsUniformBuffer(size_t stage, u32 index) {
+ buffer_cache.DisableGraphicsUniformBuffer(stage, index);
+}
+
void RasterizerVulkan::FlushAll() {}
void RasterizerVulkan::FlushRegion(VAddr addr, u64 size) {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 235afc6f3..cb8c5c279 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -64,6 +64,7 @@ public:
void ResetCounter(VideoCore::QueryType type) override;
void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override;
void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override;
+ void DisableGraphicsUniformBuffer(size_t stage, u32 index) override;
void FlushAll() override;
void FlushRegion(VAddr addr, u64 size) override;
bool MustFlushRegion(VAddr addr, u64 size) override;
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 3a463d5db..f1f523ad1 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -63,6 +63,14 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe
const u32 unswizzled_offset =
slice * pitch * height + line * pitch + column * bytes_per_pixel;
+ if (const auto offset = (TO_LINEAR ? unswizzled_offset : swizzled_offset);
+ offset >= input.size()) {
+ // TODO(Rodrigo): This is an out of bounds access that should never happen. To
+ // avoid crashing the emulator, break.
+ ASSERT_MSG(false, "offset {} exceeds input size {}!", offset, input.size());
+ break;
+ }
+
u8* const dst = &output[TO_LINEAR ? swizzled_offset : unswizzled_offset];
const u8* const src = &input[TO_LINEAR ? unswizzled_offset : swizzled_offset];
std::memcpy(dst, src, bytes_per_pixel);
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index 0a28c87c0..9674119e1 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -17,17 +17,30 @@
namespace {
constexpr std::array default_icon_sizes{
- std::make_pair(0, QT_TR_NOOP("None")),
- std::make_pair(32, QT_TR_NOOP("Small (32x32)")),
- std::make_pair(64, QT_TR_NOOP("Standard (64x64)")),
- std::make_pair(128, QT_TR_NOOP("Large (128x128)")),
- std::make_pair(256, QT_TR_NOOP("Full Size (256x256)")),
+ std::make_pair(0, QT_TRANSLATE_NOOP("ConfigureUI", "None")),
+ std::make_pair(32, QT_TRANSLATE_NOOP("ConfigureUI", "Small (32x32)")),
+ std::make_pair(64, QT_TRANSLATE_NOOP("ConfigureUI", "Standard (64x64)")),
+ std::make_pair(128, QT_TRANSLATE_NOOP("ConfigureUI", "Large (128x128)")),
+ std::make_pair(256, QT_TRANSLATE_NOOP("ConfigureUI", "Full Size (256x256)")),
};
+// clang-format off
constexpr std::array row_text_names{
- QT_TR_NOOP("Filename"), QT_TR_NOOP("Filetype"), QT_TR_NOOP("Title ID"),
- QT_TR_NOOP("Title Name"), QT_TR_NOOP("None"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Filename"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Filetype"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Title ID"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Title Name"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "None"),
};
+// clang-format on
+
+QString GetTranslatedIconSize(size_t index) {
+ return QCoreApplication::translate("ConfigureUI", default_icon_sizes[index].second);
+}
+
+QString GetTranslatedRowTextName(size_t index) {
+ return QCoreApplication::translate("ConfigureUI", row_text_names[index]);
+}
} // Anonymous namespace
ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureUi) {
@@ -121,11 +134,11 @@ void ConfigureUi::RetranslateUI() {
ui->retranslateUi(this);
for (int i = 0; i < ui->icon_size_combobox->count(); i++) {
- ui->icon_size_combobox->setItemText(i, tr(default_icon_sizes[i].second));
+ ui->icon_size_combobox->setItemText(i, GetTranslatedIconSize(static_cast<size_t>(i)));
}
for (int i = 0; i < ui->row_1_text_combobox->count(); i++) {
- const QString name = tr(row_text_names[i]);
+ const QString name = GetTranslatedRowTextName(static_cast<size_t>(i));
ui->row_1_text_combobox->setItemText(i, name);
ui->row_2_text_combobox->setItemText(i, name);
@@ -152,8 +165,9 @@ void ConfigureUi::InitializeLanguageComboBox() {
}
void ConfigureUi::InitializeIconSizeComboBox() {
- for (const auto& size : default_icon_sizes) {
- ui->icon_size_combobox->addItem(QString::fromUtf8(size.second), size.first);
+ for (size_t i = 0; i < default_icon_sizes.size(); i++) {
+ const auto size = default_icon_sizes[i].first;
+ ui->icon_size_combobox->addItem(GetTranslatedIconSize(i), size);
}
}
@@ -170,7 +184,7 @@ void ConfigureUi::UpdateFirstRowComboBox(bool init) {
ui->row_1_text_combobox->clear();
for (std::size_t i = 0; i < row_text_names.size(); i++) {
- const QString row_text_name = QString::fromUtf8(row_text_names[i]);
+ const QString row_text_name = GetTranslatedRowTextName(i);
ui->row_1_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
}
@@ -189,7 +203,7 @@ void ConfigureUi::UpdateSecondRowComboBox(bool init) {
ui->row_2_text_combobox->clear();
for (std::size_t i = 0; i < row_text_names.size(); ++i) {
- const QString row_text_name = QString::fromUtf8(row_text_names[i]);
+ const QString row_text_name = GetTranslatedRowTextName(i);
ui->row_2_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
}
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 9308cfef8..da956c99b 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -505,6 +505,10 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) {
QAction* favorite = context_menu.addAction(tr("Favorite"));
context_menu.addSeparator();
+ QAction* start_game = context_menu.addAction(tr("Start Game"));
+ QAction* start_game_global =
+ context_menu.addAction(tr("Start Game without Custom Configuration"));
+ context_menu.addSeparator();
QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location"));
QAction* open_transferable_shader_cache =
@@ -540,6 +544,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
});
+ connect(start_game, &QAction::triggered, [this, path]() {
+ emit BootGame(QString::fromStdString(path), 0, StartGameType::Normal);
+ });
+ connect(start_game_global, &QAction::triggered, [this, path]() {
+ emit BootGame(QString::fromStdString(path), 0, StartGameType::Global);
+ });
connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
});
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index ab6866735..b630e34ff 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -28,6 +28,7 @@ class GameListWorker;
class GameListSearchField;
class GameListDir;
class GMainWindow;
+enum class StartGameType;
namespace FileSys {
class ManualContentProvider;
@@ -82,6 +83,7 @@ public:
static const QStringList supported_file_extensions;
signals:
+ void BootGame(const QString& game_path, std::size_t program_index, StartGameType type);
void GameChosen(const QString& game_path);
void ShouldCancelWorker();
void OpenFolderRequested(u64 program_id, GameListOpenTarget target,
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index e683fb920..19339ff2d 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1094,6 +1094,7 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
}
void GMainWindow::ConnectWidgetEvents() {
+ connect(game_list, &GameList::BootGame, this, &GMainWindow::BootGame);
connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);
connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory);
connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
@@ -1320,7 +1321,7 @@ void GMainWindow::SelectAndSetCurrentUser() {
Settings::values.current_user = dialog.GetIndex();
}
-void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
+void GMainWindow::BootGame(const QString& filename, std::size_t program_index, StartGameType type) {
LOG_INFO(Frontend, "yuzu starting...");
StoreRecentFile(filename); // Put the filename on top of the list
@@ -1332,7 +1333,8 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
const auto loader = Loader::GetLoader(system, v_file, program_index);
- if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) {
+ if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success &&
+ type == StartGameType::Normal) {
// Load per game settings
const auto file_path = std::filesystem::path{filename.toStdU16String()};
const auto config_file_name = title_id == 0
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 490b6889f..11f152cbe 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -39,6 +39,11 @@ class GameListPlaceholder;
class QtSoftwareKeyboardDialog;
+enum class StartGameType {
+ Normal, // Can use custom configuration
+ Global, // Only uses global configuration
+};
+
namespace Core::Frontend {
struct ControllerParameters;
struct InlineAppearParameters;
@@ -181,7 +186,8 @@ private:
void AllowOSSleep();
bool LoadROM(const QString& filename, std::size_t program_index);
- void BootGame(const QString& filename, std::size_t program_index = 0);
+ void BootGame(const QString& filename, std::size_t program_index = 0,
+ StartGameType with_config = StartGameType::Normal);
void ShutdownGame();
void ShowTelemetryCallout();
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
index 3c49a300b..837a44be7 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -32,17 +32,17 @@
class SDLGLContext : public Core::Frontend::GraphicsContext {
public:
- explicit SDLGLContext() {
- // create a hidden window to make the shared context against
- window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0,
- SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
+ explicit SDLGLContext(SDL_Window* window_) : window{window_} {
context = SDL_GL_CreateContext(window);
}
~SDLGLContext() {
DoneCurrent();
SDL_GL_DeleteContext(context);
- SDL_DestroyWindow(window);
+ }
+
+ void SwapBuffers() override {
+ SDL_GL_SwapWindow(window);
}
void MakeCurrent() override {
@@ -114,9 +114,6 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
exit(1);
}
- dummy_window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0,
- SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
-
SetWindowIcon();
if (fullscreen) {
@@ -159,5 +156,5 @@ EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() {
}
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const {
- return std::make_unique<SDLGLContext>();
+ return std::make_unique<SDLGLContext>(render_window);
}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
index dba5c293c..9e694d985 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
@@ -20,9 +20,6 @@ public:
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
private:
- /// Fake hidden window for the core context
- SDL_Window* dummy_window{};
-
/// Whether the GPU and driver supports the OpenGL extension required
bool SupportsRequiredGLExtensions();