From c3476e8e194e184098a8bcb9be6cf5cc8772f780 Mon Sep 17 00:00:00 2001 From: emoose Date: Sun, 4 Aug 2019 03:55:57 +0100 Subject: [PATCH 1/2] [Kernel] Make XNotifyListener::notifications_ a std::vector, allowing multiple to use the same ID. Previously adding a notification that already exists would just overwrite the older notifications value, meaning the game would never see that older notification. This would break games like Project Sylpheed, which seems to require seeing XN_SYS_UI = true eventually followed by XN_SYS_UI = false for the game to realize all system UIs are closed. --- src/xenia/kernel/xnotifylistener.cc | 49 ++++++++++++++--------------- src/xenia/kernel/xnotifylistener.h | 3 +- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/xenia/kernel/xnotifylistener.cc b/src/xenia/kernel/xnotifylistener.cc index 747f53574..0770bd2d8 100644 --- a/src/xenia/kernel/xnotifylistener.cc +++ b/src/xenia/kernel/xnotifylistener.cc @@ -36,14 +36,7 @@ void XNotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) { } auto global_lock = global_critical_region_.Acquire(); - if (notifications_.count(id)) { - // Already exists. Overwrite. - notifications_[id] = data; - } else { - // New. - notification_count_++; - notifications_.insert({id, data}); - } + notifications_.push_back(std::pair(id, data)); wait_handle_->Set(); } @@ -51,14 +44,13 @@ bool XNotifyListener::DequeueNotification(XNotificationID* out_id, uint32_t* out_data) { auto global_lock = global_critical_region_.Acquire(); bool dequeued = false; - if (notification_count_) { + if (notifications_.size()) { dequeued = true; auto it = notifications_.begin(); *out_id = it->first; *out_data = it->second; notifications_.erase(it); - notification_count_--; - if (!notification_count_) { + if (!notifications_.size()) { wait_handle_->Reset(); } } @@ -69,17 +61,22 @@ bool XNotifyListener::DequeueNotification(XNotificationID id, uint32_t* out_data) { auto global_lock = global_critical_region_.Acquire(); bool dequeued = false; - if (notification_count_) { - auto it = notifications_.find(id); - if (it != notifications_.end()) { - dequeued = true; - *out_data = it->second; - notifications_.erase(it); - notification_count_--; - if (!notification_count_) { - wait_handle_->Reset(); - } + if (!notifications_.size()) { + return dequeued; + } + + for (auto it = notifications_.begin(); it != notifications_.end(); ++it) { + if (it->first != id) { + continue; } + + dequeued = true; + *out_data = it->second; + notifications_.erase(it); + if (!notifications_.size()) { + wait_handle_->Reset(); + } + break; } return dequeued; } @@ -88,8 +85,8 @@ bool XNotifyListener::Save(ByteStream* stream) { SaveObject(stream); stream->Write(mask_); - stream->Write(notification_count_); - if (notification_count_) { + stream->Write(notifications_.size()); + if (notifications_.size()) { for (auto pair : notifications_) { stream->Write(pair.first); stream->Write(pair.second); @@ -107,12 +104,12 @@ object_ref XNotifyListener::Restore(KernelState* kernel_state, notify->RestoreObject(stream); notify->Initialize(stream->Read()); - notify->notification_count_ = stream->Read(); - for (size_t i = 0; i < notify->notification_count_; i++) { + auto notification_count_ = stream->Read(); + for (size_t i = 0; i < notification_count_; i++) { std::pair pair; pair.first = stream->Read(); pair.second = stream->Read(); - notify->notifications_.insert(pair); + notify->notifications_.push_back(pair); } return object_ref(notify); diff --git a/src/xenia/kernel/xnotifylistener.h b/src/xenia/kernel/xnotifylistener.h index 83599dd0b..800fa047d 100644 --- a/src/xenia/kernel/xnotifylistener.h +++ b/src/xenia/kernel/xnotifylistener.h @@ -48,8 +48,7 @@ class XNotifyListener : public XObject { private: std::unique_ptr wait_handle_; xe::global_critical_region global_critical_region_; - std::unordered_map notifications_; - size_t notification_count_ = 0; + std::vector> notifications_; uint64_t mask_ = 0; }; From 313e81ec38258ef3f572388f91f896661ef3f24c Mon Sep 17 00:00:00 2001 From: emoose Date: Sun, 4 Aug 2019 03:57:06 +0100 Subject: [PATCH 2/2] [Kernel] Add XN_SYS_UI notifications to XamShow*UI exports --- src/xenia/kernel/xam/xam_ui.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/xenia/kernel/xam/xam_ui.cc b/src/xenia/kernel/xam/xam_ui.cc index a3871577b..e2e01d015 100644 --- a/src/xenia/kernel/xam/xam_ui.cc +++ b/src/xenia/kernel/xam/xam_ui.cc @@ -111,6 +111,9 @@ dword_result_t XamShowMessageBoxUI(dword_t user_index, lpwstring_t title_ptr, buttons.push_back(button); } + // Broadcast XN_SYS_UI = true + kernel_state()->BroadcastNotification(0x9, true); + uint32_t chosen_button; if (cvars::headless) { // Auto-pick the focused button. @@ -144,6 +147,9 @@ dword_result_t XamShowMessageBoxUI(dword_t user_index, lpwstring_t title_ptr, } *result_ptr = chosen_button; + // Broadcast XN_SYS_UI = false + kernel_state()->BroadcastNotification(0x9, false); + if (overlapped) { kernel_state()->CompleteOverlappedImmediate(overlapped, X_ERROR_SUCCESS); return X_ERROR_IO_PENDING; @@ -232,6 +238,9 @@ dword_result_t XamShowKeyboardUI(dword_t user_index, dword_t flags, return X_ERROR_INVALID_PARAMETER; } + // Broadcast XN_SYS_UI = true + kernel_state()->BroadcastNotification(0x9, true); + if (cvars::headless) { // Redirect default_text back into the buffer. std::memset(buffer, 0, buffer_length * 2); @@ -239,6 +248,9 @@ dword_result_t XamShowKeyboardUI(dword_t user_index, dword_t flags, xe::store_and_swap(buffer, default_text.value()); } + // Broadcast XN_SYS_UI = false + kernel_state()->BroadcastNotification(0x9, false); + if (overlapped) { kernel_state()->CompleteOverlappedImmediate(overlapped, X_ERROR_SUCCESS); return X_ERROR_IO_PENDING; @@ -269,6 +281,9 @@ dword_result_t XamShowKeyboardUI(dword_t user_index, dword_t flags, out_text = out_text.substr(0, buffer_length - 1); xe::store_and_swap(buffer, out_text); + // Broadcast XN_SYS_UI = false + kernel_state()->BroadcastNotification(0x9, false); + if (overlapped) { kernel_state()->CompleteOverlappedImmediate(overlapped, X_ERROR_SUCCESS); return X_ERROR_IO_PENDING; @@ -300,6 +315,10 @@ dword_result_t XamShowDeviceSelectorUI(dword_t user_index, dword_t content_type, break; } + // Broadcast XN_SYS_UI = true followed by XN_SYS_UI = false + kernel_state()->BroadcastNotification(0x9, true); + kernel_state()->BroadcastNotification(0x9, false); + if (overlapped) { kernel_state()->CompleteOverlappedImmediate(overlapped, X_ERROR_SUCCESS); return X_ERROR_IO_PENDING;