Compare commits
28 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbaa08d7f0 | ||
|
|
9c85cb354a | ||
|
|
fa5277ecdb | ||
|
|
172137f1a0 | ||
|
|
0cfcee95c7 | ||
|
|
eb8c8db899 | ||
|
|
37199c5f90 | ||
|
|
8c089f4e2a | ||
|
|
12dc4d0527 | ||
|
|
0c1b954e07 | ||
|
|
e4c3565ebe | ||
|
|
9af501b75d | ||
|
|
7f11710e0a | ||
|
|
ce859cf526 | ||
|
|
119d1692c9 | ||
|
|
fdf4909f97 | ||
|
|
4036e37bbe | ||
|
|
30b07878ba | ||
|
|
7610554b1e | ||
|
|
f9371f36a4 | ||
|
|
93f010c988 | ||
|
|
d02bf6dab1 | ||
|
|
99770653bb | ||
|
|
2afef2b609 | ||
|
|
11120b5b1e | ||
|
|
bf1750664c | ||
|
|
864523327f | ||
|
|
ea7a0d4652 |
@@ -103,12 +103,6 @@ else()
|
||||
-Wno-unused-parameter
|
||||
)
|
||||
|
||||
# TODO: Remove when we update to a GCC compiler that enables this
|
||||
# by default (i.e. GCC 10 or newer).
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
|
||||
add_compile_options(-fconcepts)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_compile_options("-mcx16")
|
||||
endif()
|
||||
|
||||
@@ -101,6 +101,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
||||
SUB(Service, GRC) \
|
||||
SUB(Service, HID) \
|
||||
SUB(Service, IRS) \
|
||||
SUB(Service, JIT) \
|
||||
SUB(Service, LBL) \
|
||||
SUB(Service, LDN) \
|
||||
SUB(Service, LDR) \
|
||||
|
||||
@@ -69,6 +69,7 @@ enum class Class : u8 {
|
||||
Service_GRC, ///< The game recording service
|
||||
Service_HID, ///< The HID (Human interface device) service
|
||||
Service_IRS, ///< The IRS service
|
||||
Service_JIT, ///< The JIT service
|
||||
Service_LBL, ///< The LBL (LCD backlight) service
|
||||
Service_LDN, ///< The LDN (Local domain network) service
|
||||
Service_LDR, ///< The loader service
|
||||
|
||||
@@ -458,6 +458,8 @@ add_library(core STATIC
|
||||
hle/service/hid/controllers/touchscreen.h
|
||||
hle/service/hid/controllers/xpad.cpp
|
||||
hle/service/hid/controllers/xpad.h
|
||||
hle/service/jit/jit.cpp
|
||||
hle/service/jit/jit.h
|
||||
hle/service/lbl/lbl.cpp
|
||||
hle/service/lbl/lbl.h
|
||||
hle/service/ldn/errors.h
|
||||
|
||||
@@ -70,11 +70,13 @@ public:
|
||||
}
|
||||
|
||||
void InterpreterFallback(u32 pc, std::size_t num_instructions) override {
|
||||
parent.LogBacktrace();
|
||||
UNIMPLEMENTED_MSG("This should never happen, pc = {:08X}, code = {:08X}", pc,
|
||||
MemoryReadCode(pc));
|
||||
}
|
||||
|
||||
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
|
||||
parent.LogBacktrace();
|
||||
LOG_CRITICAL(Core_ARM,
|
||||
"ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
|
||||
exception, pc, MemoryReadCode(pc), parent.IsInThumbMode());
|
||||
|
||||
@@ -81,6 +81,7 @@ public:
|
||||
}
|
||||
|
||||
void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
|
||||
parent.LogBacktrace();
|
||||
LOG_ERROR(Core_ARM,
|
||||
"Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
|
||||
num_instructions, MemoryReadCode(pc));
|
||||
@@ -118,6 +119,7 @@ public:
|
||||
return;
|
||||
case Dynarmic::A64::Exception::Breakpoint:
|
||||
default:
|
||||
parent.LogBacktrace();
|
||||
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
|
||||
static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
|
||||
}
|
||||
|
||||
@@ -387,15 +387,17 @@ std::vector<NcaID> RegisteredCache::AccumulateFiles() const {
|
||||
continue;
|
||||
|
||||
for (const auto& nca_dir : d2_dir->GetSubdirectories()) {
|
||||
if (!FollowsNcaIdFormat(nca_dir->GetName()))
|
||||
if (nca_dir == nullptr || !FollowsNcaIdFormat(nca_dir->GetName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ids.push_back(Common::HexStringToArray<0x10, true>(nca_dir->GetName().substr(0, 0x20)));
|
||||
}
|
||||
|
||||
for (const auto& nca_file : d2_dir->GetFiles()) {
|
||||
if (!FollowsNcaIdFormat(nca_file->GetName()))
|
||||
if (nca_file == nullptr || !FollowsNcaIdFormat(nca_file->GetName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ids.push_back(
|
||||
Common::HexStringToArray<0x10, true>(nca_file->GetName().substr(0, 0x20)));
|
||||
|
||||
@@ -132,7 +132,7 @@ void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
|
||||
}
|
||||
|
||||
void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
auto& raw_status = console.motion_values.raw_status;
|
||||
auto& emulated = console.motion_values.emulated;
|
||||
|
||||
@@ -151,6 +151,7 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
|
||||
emulated.UpdateOrientation(raw_status.delta_timestamp);
|
||||
|
||||
if (is_configuring) {
|
||||
lock.unlock();
|
||||
TriggerOnChange(ConsoleTriggerType::Motion);
|
||||
return;
|
||||
}
|
||||
@@ -166,6 +167,7 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
|
||||
// Find what is this value
|
||||
motion.verticalization_error = 0.0f;
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ConsoleTriggerType::Motion);
|
||||
}
|
||||
|
||||
@@ -173,11 +175,12 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st
|
||||
if (index >= console.touch_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
console.touch_values[index] = TransformToTouch(callback);
|
||||
|
||||
if (is_configuring) {
|
||||
lock.unlock();
|
||||
TriggerOnChange(ConsoleTriggerType::Touch);
|
||||
return;
|
||||
}
|
||||
@@ -189,26 +192,32 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st
|
||||
.pressed = console.touch_values[index].pressed.value,
|
||||
};
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ConsoleTriggerType::Touch);
|
||||
}
|
||||
|
||||
ConsoleMotionValues EmulatedConsole::GetMotionValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return console.motion_values;
|
||||
}
|
||||
|
||||
TouchValues EmulatedConsole::GetTouchValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return console.touch_values;
|
||||
}
|
||||
|
||||
ConsoleMotion EmulatedConsole::GetMotion() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return console.motion_state;
|
||||
}
|
||||
|
||||
TouchFingerState EmulatedConsole::GetTouch() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return console.touch_state;
|
||||
}
|
||||
|
||||
void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
for (const auto& poller_pair : callback_list) {
|
||||
const ConsoleUpdateCallback& poller = poller_pair.second;
|
||||
if (poller.on_change) {
|
||||
@@ -218,13 +227,13 @@ void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
|
||||
}
|
||||
|
||||
int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) {
|
||||
std::lock_guard lock{mutex};
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
callback_list.insert_or_assign(last_callback_key, update_callback);
|
||||
return last_callback_key++;
|
||||
}
|
||||
|
||||
void EmulatedConsole::DeleteCallback(int key) {
|
||||
std::lock_guard lock{mutex};
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
const auto& iterator = callback_list.find(key);
|
||||
if (iterator == callback_list.end()) {
|
||||
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
|
||||
|
||||
@@ -183,6 +183,7 @@ private:
|
||||
TouchDevices touch_devices;
|
||||
|
||||
mutable std::mutex mutex;
|
||||
mutable std::mutex callback_mutex;
|
||||
std::unordered_map<int, ConsoleUpdateCallback> callback_list;
|
||||
int last_callback_key = 0;
|
||||
|
||||
|
||||
@@ -353,14 +353,17 @@ void EmulatedController::DisableConfiguration() {
|
||||
}
|
||||
|
||||
void EmulatedController::EnableSystemButtons() {
|
||||
std::scoped_lock lock{mutex};
|
||||
system_buttons_enabled = true;
|
||||
}
|
||||
|
||||
void EmulatedController::DisableSystemButtons() {
|
||||
std::scoped_lock lock{mutex};
|
||||
system_buttons_enabled = false;
|
||||
}
|
||||
|
||||
void EmulatedController::ResetSystemButtons() {
|
||||
std::scoped_lock lock{mutex};
|
||||
controller.home_button_state.home.Assign(false);
|
||||
controller.capture_button_state.capture.Assign(false);
|
||||
}
|
||||
@@ -494,139 +497,141 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
||||
if (index >= controller.button_values.size()) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
bool value_changed = false;
|
||||
const auto new_status = TransformToButton(callback);
|
||||
auto& current_status = controller.button_values[index];
|
||||
std::unique_lock lock{mutex};
|
||||
bool value_changed = false;
|
||||
const auto new_status = TransformToButton(callback);
|
||||
auto& current_status = controller.button_values[index];
|
||||
|
||||
// Only read button values that have the same uuid or are pressed once
|
||||
if (current_status.uuid != uuid) {
|
||||
if (!new_status.value) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
current_status.toggle = new_status.toggle;
|
||||
current_status.uuid = uuid;
|
||||
|
||||
// Update button status with current
|
||||
if (!current_status.toggle) {
|
||||
current_status.locked = false;
|
||||
if (current_status.value != new_status.value) {
|
||||
current_status.value = new_status.value;
|
||||
value_changed = true;
|
||||
}
|
||||
} else {
|
||||
// Toggle button and lock status
|
||||
if (new_status.value && !current_status.locked) {
|
||||
current_status.locked = true;
|
||||
current_status.value = !current_status.value;
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
// Unlock button ready for next press
|
||||
if (!new_status.value && current_status.locked) {
|
||||
current_status.locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!value_changed) {
|
||||
// Only read button values that have the same uuid or are pressed once
|
||||
if (current_status.uuid != uuid) {
|
||||
if (!new_status.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_configuring) {
|
||||
controller.npad_button_state.raw = NpadButton::None;
|
||||
controller.debug_pad_button_state.raw = 0;
|
||||
TriggerOnChange(ControllerTriggerType::Button, false);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (index) {
|
||||
case Settings::NativeButton::A:
|
||||
controller.npad_button_state.a.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.a.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::B:
|
||||
controller.npad_button_state.b.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.b.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::X:
|
||||
controller.npad_button_state.x.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.x.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Y:
|
||||
controller.npad_button_state.y.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.y.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::LStick:
|
||||
controller.npad_button_state.stick_l.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::RStick:
|
||||
controller.npad_button_state.stick_r.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::L:
|
||||
controller.npad_button_state.l.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.l.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::R:
|
||||
controller.npad_button_state.r.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.r.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::ZL:
|
||||
controller.npad_button_state.zl.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.zl.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::ZR:
|
||||
controller.npad_button_state.zr.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.zr.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Plus:
|
||||
controller.npad_button_state.plus.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.plus.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Minus:
|
||||
controller.npad_button_state.minus.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.minus.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DLeft:
|
||||
controller.npad_button_state.left.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.d_left.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DUp:
|
||||
controller.npad_button_state.up.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.d_up.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DRight:
|
||||
controller.npad_button_state.right.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.d_right.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DDown:
|
||||
controller.npad_button_state.down.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.d_down.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::SL:
|
||||
controller.npad_button_state.left_sl.Assign(current_status.value);
|
||||
controller.npad_button_state.right_sl.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::SR:
|
||||
controller.npad_button_state.left_sr.Assign(current_status.value);
|
||||
controller.npad_button_state.right_sr.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Home:
|
||||
if (!system_buttons_enabled) {
|
||||
break;
|
||||
}
|
||||
controller.home_button_state.home.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Screenshot:
|
||||
if (!system_buttons_enabled) {
|
||||
break;
|
||||
}
|
||||
controller.capture_button_state.capture.Assign(current_status.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current_status.toggle = new_status.toggle;
|
||||
current_status.uuid = uuid;
|
||||
|
||||
// Update button status with current
|
||||
if (!current_status.toggle) {
|
||||
current_status.locked = false;
|
||||
if (current_status.value != new_status.value) {
|
||||
current_status.value = new_status.value;
|
||||
value_changed = true;
|
||||
}
|
||||
} else {
|
||||
// Toggle button and lock status
|
||||
if (new_status.value && !current_status.locked) {
|
||||
current_status.locked = true;
|
||||
current_status.value = !current_status.value;
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
// Unlock button ready for next press
|
||||
if (!new_status.value && current_status.locked) {
|
||||
current_status.locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!value_changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_configuring) {
|
||||
controller.npad_button_state.raw = NpadButton::None;
|
||||
controller.debug_pad_button_state.raw = 0;
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Button, false);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (index) {
|
||||
case Settings::NativeButton::A:
|
||||
controller.npad_button_state.a.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.a.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::B:
|
||||
controller.npad_button_state.b.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.b.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::X:
|
||||
controller.npad_button_state.x.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.x.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Y:
|
||||
controller.npad_button_state.y.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.y.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::LStick:
|
||||
controller.npad_button_state.stick_l.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::RStick:
|
||||
controller.npad_button_state.stick_r.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::L:
|
||||
controller.npad_button_state.l.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.l.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::R:
|
||||
controller.npad_button_state.r.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.r.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::ZL:
|
||||
controller.npad_button_state.zl.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.zl.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::ZR:
|
||||
controller.npad_button_state.zr.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.zr.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Plus:
|
||||
controller.npad_button_state.plus.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.plus.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Minus:
|
||||
controller.npad_button_state.minus.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.minus.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DLeft:
|
||||
controller.npad_button_state.left.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.d_left.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DUp:
|
||||
controller.npad_button_state.up.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.d_up.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DRight:
|
||||
controller.npad_button_state.right.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.d_right.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DDown:
|
||||
controller.npad_button_state.down.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.d_down.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::SL:
|
||||
controller.npad_button_state.left_sl.Assign(current_status.value);
|
||||
controller.npad_button_state.right_sl.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::SR:
|
||||
controller.npad_button_state.left_sr.Assign(current_status.value);
|
||||
controller.npad_button_state.right_sr.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Home:
|
||||
if (!system_buttons_enabled) {
|
||||
break;
|
||||
}
|
||||
controller.home_button_state.home.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Screenshot:
|
||||
if (!system_buttons_enabled) {
|
||||
break;
|
||||
}
|
||||
controller.capture_button_state.capture.Assign(current_status.value);
|
||||
break;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
if (!is_connected) {
|
||||
if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) {
|
||||
Connect();
|
||||
@@ -643,7 +648,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
|
||||
if (index >= controller.stick_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
const auto stick_value = TransformToStick(callback);
|
||||
|
||||
// Only read stick values that have the same uuid or are over the threshold to avoid flapping
|
||||
@@ -659,6 +664,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
|
||||
if (is_configuring) {
|
||||
controller.analog_stick_state.left = {};
|
||||
controller.analog_stick_state.right = {};
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Stick, false);
|
||||
return;
|
||||
}
|
||||
@@ -685,6 +691,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
|
||||
break;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Stick, true);
|
||||
}
|
||||
|
||||
@@ -693,7 +700,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
|
||||
if (index >= controller.trigger_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
const auto trigger_value = TransformToTrigger(callback);
|
||||
|
||||
// Only read trigger values that have the same uuid or are pressed once
|
||||
@@ -709,6 +716,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
|
||||
if (is_configuring) {
|
||||
controller.gc_trigger_state.left = 0;
|
||||
controller.gc_trigger_state.right = 0;
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Trigger, false);
|
||||
return;
|
||||
}
|
||||
@@ -727,6 +735,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
|
||||
break;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Trigger, true);
|
||||
}
|
||||
|
||||
@@ -735,7 +744,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
||||
if (index >= controller.motion_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
auto& raw_status = controller.motion_values[index].raw_status;
|
||||
auto& emulated = controller.motion_values[index].emulated;
|
||||
|
||||
@@ -756,6 +765,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
||||
force_update_motion = raw_status.force_update;
|
||||
|
||||
if (is_configuring) {
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Motion, false);
|
||||
return;
|
||||
}
|
||||
@@ -767,6 +777,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
||||
motion.orientation = emulated.GetOrientation();
|
||||
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Motion, true);
|
||||
}
|
||||
|
||||
@@ -775,10 +786,11 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
|
||||
if (index >= controller.battery_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
controller.battery_values[index] = TransformToBattery(callback);
|
||||
|
||||
if (is_configuring) {
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Battery, false);
|
||||
return;
|
||||
}
|
||||
@@ -835,6 +847,8 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Battery, true);
|
||||
}
|
||||
|
||||
@@ -932,6 +946,7 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
|
||||
}
|
||||
|
||||
bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||
switch (type) {
|
||||
case NpadStyleIndex::ProController:
|
||||
@@ -947,6 +962,7 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
|
||||
}
|
||||
|
||||
bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||
switch (type) {
|
||||
case NpadStyleIndex::ProController:
|
||||
@@ -982,40 +998,44 @@ void EmulatedController::Connect(bool use_temporary_value) {
|
||||
LOG_ERROR(Service_HID, "Controller type {} is not supported", type);
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
if (is_configuring) {
|
||||
tmp_is_connected = true;
|
||||
TriggerOnChange(ControllerTriggerType::Connected, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_connected) {
|
||||
return;
|
||||
}
|
||||
is_connected = true;
|
||||
std::unique_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
tmp_is_connected = true;
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Connected, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_connected) {
|
||||
return;
|
||||
}
|
||||
is_connected = true;
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Connected, true);
|
||||
}
|
||||
|
||||
void EmulatedController::Disconnect() {
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
if (is_configuring) {
|
||||
tmp_is_connected = false;
|
||||
TriggerOnChange(ControllerTriggerType::Disconnected, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_connected) {
|
||||
return;
|
||||
}
|
||||
is_connected = false;
|
||||
std::unique_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
tmp_is_connected = false;
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Disconnected, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_connected) {
|
||||
return;
|
||||
}
|
||||
is_connected = false;
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Disconnected, true);
|
||||
}
|
||||
|
||||
bool EmulatedController::IsConnected(bool get_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (get_temporary_value && is_configuring) {
|
||||
return tmp_is_connected;
|
||||
}
|
||||
@@ -1029,10 +1049,12 @@ bool EmulatedController::IsVibrationEnabled() const {
|
||||
}
|
||||
|
||||
NpadIdType EmulatedController::GetNpadIdType() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return npad_id_type;
|
||||
}
|
||||
|
||||
NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (get_temporary_value && is_configuring) {
|
||||
return tmp_npad_type;
|
||||
}
|
||||
@@ -1040,27 +1062,28 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c
|
||||
}
|
||||
|
||||
void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
if (is_configuring) {
|
||||
if (tmp_npad_type == npad_type_) {
|
||||
return;
|
||||
}
|
||||
tmp_npad_type = npad_type_;
|
||||
TriggerOnChange(ControllerTriggerType::Type, false);
|
||||
if (is_configuring) {
|
||||
if (tmp_npad_type == npad_type_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (npad_type == npad_type_) {
|
||||
return;
|
||||
}
|
||||
if (is_connected) {
|
||||
LOG_WARNING(Service_HID, "Controller {} type changed while it's connected",
|
||||
NpadIdTypeToIndex(npad_id_type));
|
||||
}
|
||||
npad_type = npad_type_;
|
||||
tmp_npad_type = npad_type_;
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Type, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (npad_type == npad_type_) {
|
||||
return;
|
||||
}
|
||||
if (is_connected) {
|
||||
LOG_WARNING(Service_HID, "Controller {} type changed while it's connected",
|
||||
NpadIdTypeToIndex(npad_id_type));
|
||||
}
|
||||
npad_type = npad_type_;
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Type, true);
|
||||
}
|
||||
|
||||
@@ -1088,30 +1111,37 @@ LedPattern EmulatedController::GetLedPattern() const {
|
||||
}
|
||||
|
||||
ButtonValues EmulatedController::GetButtonsValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.button_values;
|
||||
}
|
||||
|
||||
SticksValues EmulatedController::GetSticksValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.stick_values;
|
||||
}
|
||||
|
||||
TriggerValues EmulatedController::GetTriggersValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.trigger_values;
|
||||
}
|
||||
|
||||
ControllerMotionValues EmulatedController::GetMotionValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.motion_values;
|
||||
}
|
||||
|
||||
ColorValues EmulatedController::GetColorsValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.color_values;
|
||||
}
|
||||
|
||||
BatteryValues EmulatedController::GetBatteryValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.battery_values;
|
||||
}
|
||||
|
||||
HomeButtonState EmulatedController::GetHomeButtons() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
return {};
|
||||
}
|
||||
@@ -1119,6 +1149,7 @@ HomeButtonState EmulatedController::GetHomeButtons() const {
|
||||
}
|
||||
|
||||
CaptureButtonState EmulatedController::GetCaptureButtons() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
return {};
|
||||
}
|
||||
@@ -1126,6 +1157,7 @@ CaptureButtonState EmulatedController::GetCaptureButtons() const {
|
||||
}
|
||||
|
||||
NpadButtonState EmulatedController::GetNpadButtons() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
return {};
|
||||
}
|
||||
@@ -1133,6 +1165,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {
|
||||
}
|
||||
|
||||
DebugPadButton EmulatedController::GetDebugPadButtons() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
return {};
|
||||
}
|
||||
@@ -1140,20 +1173,27 @@ DebugPadButton EmulatedController::GetDebugPadButtons() const {
|
||||
}
|
||||
|
||||
AnalogSticks EmulatedController::GetSticks() const {
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
if (is_configuring) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Some drivers like stick from buttons need constant refreshing
|
||||
for (auto& device : stick_devices) {
|
||||
if (!device) {
|
||||
continue;
|
||||
}
|
||||
lock.unlock();
|
||||
device->SoftUpdate();
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
return controller.analog_stick_state;
|
||||
}
|
||||
|
||||
NpadGcTriggerState EmulatedController::GetTriggers() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
return {};
|
||||
}
|
||||
@@ -1161,26 +1201,35 @@ NpadGcTriggerState EmulatedController::GetTriggers() const {
|
||||
}
|
||||
|
||||
MotionState EmulatedController::GetMotions() const {
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
// Some drivers like mouse motion need constant refreshing
|
||||
if (force_update_motion) {
|
||||
for (auto& device : motion_devices) {
|
||||
if (!device) {
|
||||
continue;
|
||||
}
|
||||
lock.unlock();
|
||||
device->ForceUpdate();
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
return controller.motion_state;
|
||||
}
|
||||
|
||||
ControllerColors EmulatedController::GetColors() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.colors_state;
|
||||
}
|
||||
|
||||
BatteryLevelState EmulatedController::GetBattery() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.battery_state;
|
||||
}
|
||||
|
||||
void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
for (const auto& poller_pair : callback_list) {
|
||||
const ControllerUpdateCallback& poller = poller_pair.second;
|
||||
if (!is_npad_service_update && poller.is_npad_service) {
|
||||
@@ -1193,13 +1242,13 @@ void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npa
|
||||
}
|
||||
|
||||
int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) {
|
||||
std::lock_guard lock{mutex};
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
||||
return last_callback_key++;
|
||||
}
|
||||
|
||||
void EmulatedController::DeleteCallback(int key) {
|
||||
std::lock_guard lock{mutex};
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
const auto& iterator = callback_list.find(key);
|
||||
if (iterator == callback_list.end()) {
|
||||
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
|
||||
|
||||
@@ -400,7 +400,7 @@ private:
|
||||
*/
|
||||
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
|
||||
|
||||
NpadIdType npad_id_type;
|
||||
const NpadIdType npad_id_type;
|
||||
NpadStyleIndex npad_type{NpadStyleIndex::None};
|
||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
||||
bool is_connected{false};
|
||||
@@ -434,6 +434,7 @@ private:
|
||||
StickDevices tas_stick_devices;
|
||||
|
||||
mutable std::mutex mutex;
|
||||
mutable std::mutex callback_mutex;
|
||||
std::unordered_map<int, ControllerUpdateCallback> callback_list;
|
||||
int last_callback_key = 0;
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal
|
||||
if (index >= device_status.keyboard_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
bool value_changed = false;
|
||||
const auto new_status = TransformToButton(callback);
|
||||
auto& current_status = device_status.keyboard_values[index];
|
||||
@@ -201,6 +201,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal
|
||||
}
|
||||
|
||||
if (is_configuring) {
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Keyboard);
|
||||
return;
|
||||
}
|
||||
@@ -208,6 +209,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal
|
||||
// Index should be converted from NativeKeyboard to KeyboardKeyIndex
|
||||
UpdateKey(index, current_status.value);
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Keyboard);
|
||||
}
|
||||
|
||||
@@ -227,7 +229,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c
|
||||
if (index >= device_status.keyboard_moddifier_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
bool value_changed = false;
|
||||
const auto new_status = TransformToButton(callback);
|
||||
auto& current_status = device_status.keyboard_moddifier_values[index];
|
||||
@@ -259,6 +261,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c
|
||||
}
|
||||
|
||||
if (is_configuring) {
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
|
||||
return;
|
||||
}
|
||||
@@ -289,6 +292,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c
|
||||
break;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
|
||||
}
|
||||
|
||||
@@ -297,7 +301,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba
|
||||
if (index >= device_status.mouse_button_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
bool value_changed = false;
|
||||
const auto new_status = TransformToButton(callback);
|
||||
auto& current_status = device_status.mouse_button_values[index];
|
||||
@@ -329,6 +333,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba
|
||||
}
|
||||
|
||||
if (is_configuring) {
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
return;
|
||||
}
|
||||
@@ -351,6 +356,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba
|
||||
break;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
}
|
||||
|
||||
@@ -359,13 +365,14 @@ void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callba
|
||||
if (index >= device_status.mouse_analog_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
const auto analog_value = TransformToAnalog(callback);
|
||||
|
||||
device_status.mouse_analog_values[index] = analog_value;
|
||||
|
||||
if (is_configuring) {
|
||||
device_status.mouse_position_state = {};
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
return;
|
||||
}
|
||||
@@ -379,17 +386,19 @@ void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callba
|
||||
break;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
}
|
||||
|
||||
void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) {
|
||||
std::lock_guard lock{mutex};
|
||||
std::unique_lock lock{mutex};
|
||||
const auto touch_value = TransformToTouch(callback);
|
||||
|
||||
device_status.mouse_stick_value = touch_value;
|
||||
|
||||
if (is_configuring) {
|
||||
device_status.mouse_position_state = {};
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
return;
|
||||
}
|
||||
@@ -397,42 +406,52 @@ void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callbac
|
||||
device_status.mouse_position_state.x = touch_value.x.value;
|
||||
device_status.mouse_position_state.y = touch_value.y.value;
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
}
|
||||
|
||||
KeyboardValues EmulatedDevices::GetKeyboardValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.keyboard_values;
|
||||
}
|
||||
|
||||
KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.keyboard_moddifier_values;
|
||||
}
|
||||
|
||||
MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.mouse_button_values;
|
||||
}
|
||||
|
||||
KeyboardKey EmulatedDevices::GetKeyboard() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.keyboard_state;
|
||||
}
|
||||
|
||||
KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.keyboard_moddifier_state;
|
||||
}
|
||||
|
||||
MouseButton EmulatedDevices::GetMouseButtons() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.mouse_button_state;
|
||||
}
|
||||
|
||||
MousePosition EmulatedDevices::GetMousePosition() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.mouse_position_state;
|
||||
}
|
||||
|
||||
AnalogStickState EmulatedDevices::GetMouseWheel() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.mouse_wheel_state;
|
||||
}
|
||||
|
||||
void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
for (const auto& poller_pair : callback_list) {
|
||||
const InterfaceUpdateCallback& poller = poller_pair.second;
|
||||
if (poller.on_change) {
|
||||
@@ -442,13 +461,13 @@ void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
|
||||
}
|
||||
|
||||
int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
|
||||
std::lock_guard lock{mutex};
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
||||
return last_callback_key++;
|
||||
}
|
||||
|
||||
void EmulatedDevices::DeleteCallback(int key) {
|
||||
std::lock_guard lock{mutex};
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
const auto& iterator = callback_list.find(key);
|
||||
if (iterator == callback_list.end()) {
|
||||
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
|
||||
|
||||
@@ -200,6 +200,7 @@ private:
|
||||
MouseStickDevice mouse_stick_device;
|
||||
|
||||
mutable std::mutex mutex;
|
||||
mutable std::mutex callback_mutex;
|
||||
std::unordered_map<int, InterfaceUpdateCallback> callback_list;
|
||||
int last_callback_key = 0;
|
||||
|
||||
|
||||
@@ -24,8 +24,15 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_)
|
||||
: kernel{kernel_}, service_thread{kernel.CreateServiceThread(service_name_)} {}
|
||||
SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
|
||||
ServiceThreadType thread_type)
|
||||
: kernel{kernel_} {
|
||||
if (thread_type == ServiceThreadType::CreateNew) {
|
||||
service_thread = kernel.CreateServiceThread(service_name_);
|
||||
} else {
|
||||
service_thread = kernel.GetDefaultServiceThread();
|
||||
}
|
||||
}
|
||||
|
||||
SessionRequestHandler::~SessionRequestHandler() {
|
||||
kernel.ReleaseServiceThread(service_thread);
|
||||
|
||||
@@ -33,6 +33,11 @@ namespace Service {
|
||||
class ServiceFrameworkBase;
|
||||
}
|
||||
|
||||
enum class ServiceThreadType {
|
||||
Default,
|
||||
CreateNew,
|
||||
};
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class Domain;
|
||||
@@ -57,7 +62,8 @@ enum class ThreadWakeupReason;
|
||||
*/
|
||||
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
|
||||
public:
|
||||
SessionRequestHandler(KernelCore& kernel, const char* service_name_);
|
||||
SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
|
||||
ServiceThreadType thread_type);
|
||||
virtual ~SessionRequestHandler();
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,6 +61,7 @@ struct KernelCore::Impl {
|
||||
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
||||
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
|
||||
global_handle_table->Initialize(KHandleTable::MaxTableSize);
|
||||
default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
|
||||
|
||||
is_phantom_mode_for_singlecore = false;
|
||||
|
||||
@@ -677,6 +678,12 @@ struct KernelCore::Impl {
|
||||
|
||||
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
|
||||
if (auto strong_ptr = service_thread.lock()) {
|
||||
if (strong_ptr == default_service_thread.lock()) {
|
||||
// Nothing to do here, the service is using default_service_thread, which will be
|
||||
// released on shutdown.
|
||||
return;
|
||||
}
|
||||
|
||||
service_threads_manager.QueueWork(
|
||||
[this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); });
|
||||
}
|
||||
@@ -739,7 +746,8 @@ struct KernelCore::Impl {
|
||||
std::unique_ptr<KMemoryLayout> memory_layout;
|
||||
|
||||
// Threads used for services
|
||||
std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
|
||||
std::unordered_set<std::shared_ptr<ServiceThread>> service_threads;
|
||||
std::weak_ptr<ServiceThread> default_service_thread;
|
||||
Common::ThreadWorker service_threads_manager;
|
||||
|
||||
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
|
||||
@@ -1065,6 +1073,10 @@ std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::
|
||||
return impl->CreateServiceThread(*this, name);
|
||||
}
|
||||
|
||||
std::weak_ptr<Kernel::ServiceThread> KernelCore::GetDefaultServiceThread() const {
|
||||
return impl->default_service_thread;
|
||||
}
|
||||
|
||||
void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
|
||||
impl->ReleaseServiceThread(service_thread);
|
||||
}
|
||||
|
||||
@@ -271,15 +271,25 @@ public:
|
||||
void ExitSVCProfile();
|
||||
|
||||
/**
|
||||
* Creates an HLE service thread, which are used to execute service routines asynchronously.
|
||||
* While these are allocated per ServerSession, these need to be owned and managed outside
|
||||
* of ServerSession to avoid a circular dependency.
|
||||
* Creates a host thread to execute HLE service requests, which are used to execute service
|
||||
* routines asynchronously. While these are allocated per ServerSession, these need to be owned
|
||||
* and managed outside of ServerSession to avoid a circular dependency. In general, most
|
||||
* services can just use the default service thread, and not need their own host service thread.
|
||||
* See GetDefaultServiceThread.
|
||||
* @param name String name for the ServerSession creating this thread, used for debug
|
||||
* purposes.
|
||||
* @returns The a weak pointer newly created service thread.
|
||||
*/
|
||||
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
|
||||
|
||||
/**
|
||||
* Gets the default host service thread, which executes HLE service requests. Unless service
|
||||
* requests need to block on the host, the default service thread should be used in favor of
|
||||
* creating a new service thread.
|
||||
* @returns The a weak pointer for the default service thread.
|
||||
*/
|
||||
std::weak_ptr<Kernel::ServiceThread> GetDefaultServiceThread() const;
|
||||
|
||||
/**
|
||||
* Releases a HLE service thread, instructing KernelCore to free it. This should be called when
|
||||
* the ServerSession associated with the thread is destroyed.
|
||||
|
||||
@@ -1337,7 +1337,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
{200, nullptr, "GetLastApplicationExitReason"},
|
||||
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
|
||||
{1000, nullptr, "CreateMovieMaker"},
|
||||
{1001, nullptr, "PrepareForJit"},
|
||||
{1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -1787,6 +1787,13 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERe
|
||||
rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IApplicationFunctions::PrepareForJit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
|
||||
Core::System& system) {
|
||||
auto message_queue = std::make_shared<AppletMessageQueue>(system);
|
||||
|
||||
@@ -336,6 +336,7 @@ private:
|
||||
void TryPopFromFriendInvitationStorageChannel(Kernel::HLERequestContext& ctx);
|
||||
void GetNotificationStorageChannelEvent(Kernel::HLERequestContext& ctx);
|
||||
void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx);
|
||||
void PrepareForJit(Kernel::HLERequestContext& ctx);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
|
||||
@@ -41,9 +41,10 @@ public:
|
||||
explicit IAudioOut(Core::System& system_, AudoutParams audio_params_,
|
||||
AudioCore::AudioOut& audio_core_, std::string&& device_name_,
|
||||
std::string&& unique_name)
|
||||
: ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_},
|
||||
device_name{std::move(device_name_)}, audio_params{audio_params_},
|
||||
main_memory{system.Memory()}, service_context{system_, "IAudioOut"} {
|
||||
: ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew},
|
||||
audio_core{audio_core_}, device_name{std::move(device_name_)},
|
||||
audio_params{audio_params_}, main_memory{system.Memory()}, service_context{system_,
|
||||
"IAudioOut"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
|
||||
|
||||
@@ -24,7 +24,8 @@ public:
|
||||
explicit IAudioRenderer(Core::System& system_,
|
||||
const AudioCommon::AudioRendererParameter& audren_params,
|
||||
const std::size_t instance_number)
|
||||
: ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"} {
|
||||
: ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew},
|
||||
service_context{system_, "IAudioRenderer"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
|
||||
|
||||
@@ -58,7 +58,8 @@ enum class FileSystemType : u8 {
|
||||
class IStorage final : public ServiceFramework<IStorage> {
|
||||
public:
|
||||
explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
|
||||
: ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
|
||||
: ServiceFramework{system_, "IStorage", ServiceThreadType::CreateNew},
|
||||
backend(std::move(backend_)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IStorage::Read, "Read"},
|
||||
{1, nullptr, "Write"},
|
||||
@@ -116,7 +117,8 @@ private:
|
||||
class IFile final : public ServiceFramework<IFile> {
|
||||
public:
|
||||
explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
|
||||
: ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
|
||||
: ServiceFramework{system_, "IFile", ServiceThreadType::CreateNew},
|
||||
backend(std::move(backend_)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IFile::Read, "Read"},
|
||||
{1, &IFile::Write, "Write"},
|
||||
@@ -252,7 +254,8 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
|
||||
class IDirectory final : public ServiceFramework<IDirectory> {
|
||||
public:
|
||||
explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_)
|
||||
: ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
|
||||
: ServiceFramework{system_, "IDirectory", ServiceThreadType::CreateNew},
|
||||
backend(std::move(backend_)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IDirectory::Read, "Read"},
|
||||
{1, &IDirectory::GetEntryCount, "GetEntryCount"},
|
||||
@@ -308,8 +311,8 @@ private:
|
||||
class IFileSystem final : public ServiceFramework<IFileSystem> {
|
||||
public:
|
||||
explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
|
||||
: ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
|
||||
size_)} {
|
||||
: ServiceFramework{system_, "IFileSystem", ServiceThreadType::CreateNew},
|
||||
backend{std::move(backend_)}, size{std::move(size_)} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IFileSystem::CreateFile, "CreateFile"},
|
||||
{1, &IFileSystem::DeleteFile, "DeleteFile"},
|
||||
|
||||
@@ -63,6 +63,10 @@ IAppletResource::IAppletResource(Core::System& system_,
|
||||
MakeController<Controller_Gesture>(HidController::Gesture);
|
||||
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor);
|
||||
|
||||
// Homebrew doesn't try to activate some controllers, so we activate them by default
|
||||
GetController<Controller_NPad>(HidController::NPad).ActivateController();
|
||||
GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController();
|
||||
|
||||
GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
|
||||
GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
|
||||
GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
|
||||
|
||||
53
src/core/hle/service/jit/jit.cpp
Normal file
53
src/core/hle/service/jit/jit.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2022 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/jit/jit.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::JIT {
|
||||
|
||||
class IJitEnvironment final : public ServiceFramework<IJitEnvironment> {
|
||||
public:
|
||||
explicit IJitEnvironment(Core::System& system_) : ServiceFramework{system_, "IJitEnvironment"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GenerateCode"},
|
||||
{1, nullptr, "Control"},
|
||||
{1000, nullptr, "LoadPlugin"},
|
||||
{1001, nullptr, "GetCodeAddress"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class JITU final : public ServiceFramework<JITU> {
|
||||
public:
|
||||
explicit JITU(Core::System& system_) : ServiceFramework{system_, "jit:u"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &JITU::CreateJitEnvironment, "CreateJitEnvironment"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void CreateJitEnvironment(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_JIT, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IJitEnvironment>(system);
|
||||
}
|
||||
};
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
|
||||
std::make_shared<JITU>(system)->InstallAsService(sm);
|
||||
}
|
||||
|
||||
} // namespace Service::JIT
|
||||
20
src/core/hle/service/jit/jit.h
Normal file
20
src/core/hle/service/jit/jit.h
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2022 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::SM {
|
||||
class ServiceManager;
|
||||
}
|
||||
|
||||
namespace Service::JIT {
|
||||
|
||||
/// Registers all JIT services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
|
||||
|
||||
} // namespace Service::JIT
|
||||
@@ -230,7 +230,7 @@ void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name)
|
||||
: ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} {
|
||||
: ServiceFramework{system_, name, ServiceThreadType::CreateNew}, nvdrv{std::move(nvdrv_)} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NVDRV::Open, "Open"},
|
||||
{1, &NVDRV::Ioctl1, "Ioctl"},
|
||||
|
||||
@@ -18,8 +18,7 @@ BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_)
|
||||
BufferQueueConsumer::~BufferQueueConsumer() = default;
|
||||
|
||||
Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
|
||||
std::chrono::nanoseconds expected_present,
|
||||
u64 max_frame_number) {
|
||||
std::chrono::nanoseconds expected_present) {
|
||||
std::scoped_lock lock(core->mutex);
|
||||
|
||||
// Check that the consumer doesn't currently have the maximum number of buffers acquired.
|
||||
@@ -50,12 +49,6 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
|
||||
while (core->queue.size() > 1 && !core->queue[0].is_auto_timestamp) {
|
||||
const auto& buffer_item{core->queue[1]};
|
||||
|
||||
// If dropping entry[0] would leave us with a buffer that the consumer is not yet ready
|
||||
// for, don't drop it.
|
||||
if (max_frame_number && buffer_item.frame_number > max_frame_number) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If entry[1] is timely, drop entry[0] (and repeat).
|
||||
const auto desired_present = buffer_item.timestamp;
|
||||
if (desired_present < expected_present.count() - MAX_REASONABLE_NSEC ||
|
||||
@@ -200,4 +193,39 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_
|
||||
return Status::NoError;
|
||||
}
|
||||
|
||||
Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
|
||||
if (out_slot_mask == nullptr) {
|
||||
LOG_ERROR(Service_NVFlinger, "out_slot_mask may not be nullptr");
|
||||
return Status::BadValue;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(core->mutex);
|
||||
|
||||
if (core->is_abandoned) {
|
||||
LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
|
||||
return Status::NoInit;
|
||||
}
|
||||
|
||||
u64 mask = 0;
|
||||
for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
|
||||
if (!slots[s].acquire_called) {
|
||||
mask |= (1ULL << s);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from the mask queued buffers for which acquire has been called, since the consumer
|
||||
// will not receive their buffer addresses and so must retain their cached information
|
||||
auto current(core->queue.begin());
|
||||
while (current != core->queue.end()) {
|
||||
if (current->acquire_called) {
|
||||
mask &= ~(1ULL << current->slot);
|
||||
}
|
||||
++current;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_NVFlinger, "returning mask {}", mask);
|
||||
*out_slot_mask = mask;
|
||||
return Status::NoError;
|
||||
}
|
||||
|
||||
} // namespace Service::android
|
||||
|
||||
@@ -24,10 +24,10 @@ public:
|
||||
explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
|
||||
~BufferQueueConsumer();
|
||||
|
||||
Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present,
|
||||
u64 max_frame_number = 0);
|
||||
Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
|
||||
Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
|
||||
Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app);
|
||||
Status GetReleasedBuffers(u64* out_slot_mask);
|
||||
|
||||
private:
|
||||
std::shared_ptr<BufferQueueCore> core;
|
||||
|
||||
@@ -95,7 +95,6 @@ void BufferQueueCore::FreeBufferLocked(s32 slot) {
|
||||
}
|
||||
|
||||
void BufferQueueCore::FreeAllBuffersLocked() {
|
||||
queue.clear();
|
||||
buffer_has_been_queued = false;
|
||||
|
||||
for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
|
||||
|
||||
@@ -73,8 +73,6 @@ private:
|
||||
u32 transform_hint{};
|
||||
bool is_allocating{};
|
||||
mutable std::condition_variable_any is_allocating_condition;
|
||||
bool allow_allocation{true};
|
||||
u64 buffer_age{};
|
||||
bool is_shutting_down{};
|
||||
};
|
||||
|
||||
|
||||
@@ -62,11 +62,12 @@ Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffe
|
||||
|
||||
Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
|
||||
LOG_DEBUG(Service_NVFlinger, "count = {}", buffer_count);
|
||||
std::shared_ptr<IConsumerListener> listener;
|
||||
|
||||
std::shared_ptr<IConsumerListener> listener;
|
||||
{
|
||||
std::scoped_lock lock(core->mutex);
|
||||
core->WaitWhileAllocatingLocked();
|
||||
|
||||
if (core->is_abandoned) {
|
||||
LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
|
||||
return Status::NoInit;
|
||||
@@ -120,7 +121,7 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
|
||||
}
|
||||
|
||||
Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,
|
||||
Status* returnFlags) const {
|
||||
Status* return_flags) const {
|
||||
bool try_again = true;
|
||||
|
||||
while (try_again) {
|
||||
@@ -142,10 +143,12 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,
|
||||
ASSERT(slots[s].buffer_state == BufferState::Free);
|
||||
if (slots[s].graphic_buffer != nullptr) {
|
||||
core->FreeBufferLocked(s);
|
||||
*returnFlags |= Status::ReleaseAllBuffers;
|
||||
*return_flags |= Status::ReleaseAllBuffers;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for a free buffer to give to the client
|
||||
*found = BufferQueueCore::INVALID_BUFFER_SLOT;
|
||||
s32 dequeued_count{};
|
||||
s32 acquired_count{};
|
||||
for (s32 s{}; s < max_buffer_count; ++s) {
|
||||
@@ -235,68 +238,50 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
|
||||
{
|
||||
std::scoped_lock lock(core->mutex);
|
||||
core->WaitWhileAllocatingLocked();
|
||||
|
||||
if (format == PixelFormat::NoFormat) {
|
||||
format = core->default_buffer_format;
|
||||
}
|
||||
|
||||
// Enable the usage bits the consumer requested
|
||||
usage |= core->consumer_usage_bit;
|
||||
|
||||
s32 found{};
|
||||
Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags);
|
||||
if (status != Status::NoError) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// This should not happen
|
||||
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
|
||||
LOG_ERROR(Service_NVFlinger, "no available buffer slots");
|
||||
return Status::Busy;
|
||||
}
|
||||
|
||||
*out_slot = found;
|
||||
|
||||
attached_by_consumer = slots[found].attached_by_consumer;
|
||||
|
||||
const bool use_default_size = !width && !height;
|
||||
if (use_default_size) {
|
||||
width = core->default_width;
|
||||
height = core->default_height;
|
||||
}
|
||||
|
||||
s32 found = BufferItem::INVALID_BUFFER_SLOT;
|
||||
while (found == BufferItem::INVALID_BUFFER_SLOT) {
|
||||
Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags);
|
||||
if (status != Status::NoError) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// This should not happen
|
||||
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
|
||||
LOG_DEBUG(Service_NVFlinger, "no available buffer slots");
|
||||
return Status::Busy;
|
||||
}
|
||||
|
||||
const std::shared_ptr<GraphicBuffer>& buffer(slots[found].graphic_buffer);
|
||||
|
||||
// If we are not allowed to allocate new buffers, WaitForFreeSlotThenRelock must have
|
||||
// returned a slot containing a buffer. If this buffer would require reallocation to
|
||||
// meet the requested attributes, we free it and attempt to get another one.
|
||||
if (!core->allow_allocation) {
|
||||
if (buffer->NeedsReallocation(width, height, format, usage)) {
|
||||
core->FreeBufferLocked(found);
|
||||
found = BufferItem::INVALID_BUFFER_SLOT;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out_slot = found;
|
||||
attached_by_consumer = slots[found].attached_by_consumer;
|
||||
slots[found].buffer_state = BufferState::Dequeued;
|
||||
|
||||
const std::shared_ptr<GraphicBuffer>& buffer(slots[found].graphic_buffer);
|
||||
|
||||
if ((buffer == nullptr) || buffer->NeedsReallocation(width, height, format, usage)) {
|
||||
if ((buffer == nullptr) || (buffer->Width() != width) || (buffer->Height() != height) ||
|
||||
(buffer->Format() != format) || ((buffer->Usage() & usage) != usage)) {
|
||||
slots[found].acquire_called = false;
|
||||
slots[found].graphic_buffer = nullptr;
|
||||
slots[found].request_buffer_called = false;
|
||||
slots[found].fence = Fence::NoFence();
|
||||
core->buffer_age = 0;
|
||||
|
||||
return_flags |= Status::BufferNeedsReallocation;
|
||||
} else {
|
||||
// We add 1 because that will be the frame number when this buffer
|
||||
// is queued
|
||||
core->buffer_age = core->frame_counter + 1 - slots[found].frame_number;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_NVFlinger, "setting buffer age to {}", core->buffer_age);
|
||||
|
||||
*out_fence = slots[found].fence;
|
||||
|
||||
slots[found].fence = Fence::NoFence();
|
||||
}
|
||||
|
||||
@@ -311,6 +296,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
|
||||
|
||||
{
|
||||
std::scoped_lock lock(core->mutex);
|
||||
|
||||
if (core->is_abandoned) {
|
||||
LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
|
||||
return Status::NoInit;
|
||||
@@ -327,6 +313,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
|
||||
|
||||
LOG_DEBUG(Service_NVFlinger, "returning slot={} frame={}, flags={}", *out_slot,
|
||||
slots[*out_slot].frame_number, return_flags);
|
||||
|
||||
return return_flags;
|
||||
}
|
||||
|
||||
@@ -334,6 +321,7 @@ Status BufferQueueProducer::DetachBuffer(s32 slot) {
|
||||
LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
|
||||
|
||||
std::scoped_lock lock(core->mutex);
|
||||
|
||||
if (core->is_abandoned) {
|
||||
LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
|
||||
return Status::NoInit;
|
||||
@@ -369,7 +357,6 @@ Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out
|
||||
}
|
||||
|
||||
std::scoped_lock lock(core->mutex);
|
||||
|
||||
core->WaitWhileAllocatingLocked();
|
||||
|
||||
if (core->is_abandoned) {
|
||||
@@ -423,6 +410,7 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,
|
||||
return status;
|
||||
}
|
||||
|
||||
// This should not happen
|
||||
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
|
||||
LOG_ERROR(Service_NVFlinger, "No available buffer slots");
|
||||
return Status::Busy;
|
||||
@@ -466,8 +454,8 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
||||
return Status::BadValue;
|
||||
}
|
||||
|
||||
std::shared_ptr<IConsumerListener> frameAvailableListener;
|
||||
std::shared_ptr<IConsumerListener> frameReplacedListener;
|
||||
std::shared_ptr<IConsumerListener> frame_available_listener;
|
||||
std::shared_ptr<IConsumerListener> frame_replaced_listener;
|
||||
s32 callback_ticket{};
|
||||
BufferItem item;
|
||||
|
||||
@@ -541,12 +529,13 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
||||
item.fence = fence;
|
||||
item.is_droppable = core->dequeue_buffer_cannot_block || async;
|
||||
item.swap_interval = swap_interval;
|
||||
|
||||
sticky_transform = sticky_transform_;
|
||||
|
||||
if (core->queue.empty()) {
|
||||
// When the queue is empty, we can simply queue this buffer
|
||||
core->queue.push_back(item);
|
||||
frameAvailableListener = core->consumer_listener;
|
||||
frame_available_listener = core->consumer_listener;
|
||||
} else {
|
||||
// When the queue is not empty, we need to look at the front buffer
|
||||
// state to see if we need to replace it
|
||||
@@ -563,10 +552,10 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
||||
}
|
||||
// Overwrite the droppable buffer with the incoming one
|
||||
*front = item;
|
||||
frameReplacedListener = core->consumer_listener;
|
||||
frame_replaced_listener = core->consumer_listener;
|
||||
} else {
|
||||
core->queue.push_back(item);
|
||||
frameAvailableListener = core->consumer_listener;
|
||||
frame_available_listener = core->consumer_listener;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,10 +581,10 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
||||
callback_condition.wait(callback_mutex);
|
||||
}
|
||||
|
||||
if (frameAvailableListener != nullptr) {
|
||||
frameAvailableListener->OnFrameAvailable(item);
|
||||
} else if (frameReplacedListener != nullptr) {
|
||||
frameReplacedListener->OnFrameReplaced(item);
|
||||
if (frame_available_listener != nullptr) {
|
||||
frame_available_listener->OnFrameAvailable(item);
|
||||
} else if (frame_replaced_listener != nullptr) {
|
||||
frame_replaced_listener->OnFrameReplaced(item);
|
||||
}
|
||||
|
||||
++current_callback_ticket;
|
||||
@@ -669,13 +658,6 @@ Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) {
|
||||
case NativeWindow::ConsumerUsageBits:
|
||||
value = core->consumer_usage_bit;
|
||||
break;
|
||||
case NativeWindow::BufferAge:
|
||||
if (core->buffer_age > INT32_MAX) {
|
||||
value = 0;
|
||||
} else {
|
||||
value = static_cast<u32>(core->buffer_age);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return Status::BadValue;
|
||||
@@ -737,7 +719,6 @@ Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& li
|
||||
core->buffer_has_been_queued = false;
|
||||
core->dequeue_buffer_cannot_block =
|
||||
core->consumer_controlled_by_app && producer_controlled_by_app;
|
||||
core->allow_allocation = true;
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -770,7 +751,7 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
|
||||
core->SignalDequeueCondition();
|
||||
buffer_wait_event->GetWritableEvent().Signal();
|
||||
listener = core->consumer_listener;
|
||||
} else if (core->connected_api != NativeWindowApi::NoConnectedApi) {
|
||||
} else {
|
||||
LOG_ERROR(Service_NVFlinger, "still connected to another api (cur = {} req = {})",
|
||||
core->connected_api, api);
|
||||
status = Status::BadValue;
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
private:
|
||||
BufferQueueProducer(const BufferQueueProducer&) = delete;
|
||||
|
||||
Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* returnFlags) const;
|
||||
Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags) const;
|
||||
|
||||
Kernel::KEvent* buffer_wait_event{};
|
||||
Service::KernelHelpers::ServiceContext& service_context;
|
||||
|
||||
@@ -36,38 +36,41 @@ void ConsumerBase::FreeBufferLocked(s32 slot_index) {
|
||||
}
|
||||
|
||||
void ConsumerBase::OnFrameAvailable(const BufferItem& item) {
|
||||
std::scoped_lock lock(mutex);
|
||||
LOG_DEBUG(Service_NVFlinger, "called");
|
||||
}
|
||||
|
||||
void ConsumerBase::OnFrameReplaced(const BufferItem& item) {
|
||||
std::scoped_lock lock(mutex);
|
||||
LOG_DEBUG(Service_NVFlinger, "called");
|
||||
}
|
||||
|
||||
void ConsumerBase::OnBuffersReleased() {
|
||||
std::scoped_lock lock(mutex);
|
||||
|
||||
LOG_DEBUG(Service_NVFlinger, "called");
|
||||
|
||||
if (is_abandoned) {
|
||||
// Nothing to do if we're already abandoned.
|
||||
return;
|
||||
}
|
||||
|
||||
u64 mask = 0;
|
||||
consumer->GetReleasedBuffers(&mask);
|
||||
for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) {
|
||||
if (mask & (1ULL << i)) {
|
||||
FreeBufferLocked(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConsumerBase::OnSidebandStreamChanged() {}
|
||||
|
||||
Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when,
|
||||
u64 max_frame_number) {
|
||||
if (is_abandoned) {
|
||||
LOG_ERROR(Service_NVFlinger, "consumer is abandoned!");
|
||||
return Status::NoInit;
|
||||
}
|
||||
|
||||
Status err = consumer->AcquireBuffer(item, present_when, max_frame_number);
|
||||
Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when) {
|
||||
Status err = consumer->AcquireBuffer(item, present_when);
|
||||
if (err != Status::NoError) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (item->graphic_buffer != nullptr) {
|
||||
if (slots[item->slot].graphic_buffer != nullptr) {
|
||||
FreeBufferLocked(item->slot);
|
||||
}
|
||||
slots[item->slot].graphic_buffer = item->graphic_buffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,7 @@ protected:
|
||||
virtual void OnSidebandStreamChanged() override;
|
||||
|
||||
void FreeBufferLocked(s32 slot_index);
|
||||
Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when,
|
||||
u64 max_frame_number = 0);
|
||||
Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when);
|
||||
Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer);
|
||||
bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer) const;
|
||||
Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer,
|
||||
|
||||
@@ -104,7 +104,7 @@ void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
|
||||
std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
|
||||
const auto lock_guard = Lock();
|
||||
|
||||
LOG_DEBUG(Service, "Opening \"{}\" display", name);
|
||||
LOG_DEBUG(Service_NVFlinger, "Opening \"{}\" display", name);
|
||||
|
||||
const auto itr =
|
||||
std::find_if(displays.begin(), displays.end(),
|
||||
@@ -219,7 +219,7 @@ VI::Layer* NVFlinger::FindOrCreateLayer(u64 display_id, u64 layer_id) {
|
||||
auto* layer = display->FindLayer(layer_id);
|
||||
|
||||
if (layer == nullptr) {
|
||||
LOG_DEBUG(Service, "Layer at id {} not found. Trying to create it.", layer_id);
|
||||
LOG_DEBUG(Service_NVFlinger, "Layer at id {} not found. Trying to create it.", layer_id);
|
||||
CreateLayerAtId(*display, layer_id);
|
||||
return display->FindLayer(layer_id);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "core/hle/service/glue/glue.h"
|
||||
#include "core/hle/service/grc/grc.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/jit/jit.h"
|
||||
#include "core/hle/service/lbl/lbl.h"
|
||||
#include "core/hle/service/ldn/ldn.h"
|
||||
#include "core/hle/service/ldr/ldr.h"
|
||||
@@ -91,8 +92,9 @@ namespace Service {
|
||||
}
|
||||
|
||||
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
|
||||
u32 max_sessions_, InvokerFn* handler_invoker_)
|
||||
: SessionRequestHandler(system_.Kernel(), service_name_), system{system_},
|
||||
ServiceThreadType thread_type, u32 max_sessions_,
|
||||
InvokerFn* handler_invoker_)
|
||||
: SessionRequestHandler(system_.Kernel(), service_name_, thread_type), system{system_},
|
||||
service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
|
||||
|
||||
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||
@@ -261,6 +263,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||
Glue::InstallInterfaces(system);
|
||||
GRC::InstallInterfaces(*sm, system);
|
||||
HID::InstallInterfaces(*sm, system);
|
||||
JIT::InstallInterfaces(*sm, system);
|
||||
LBL::InstallInterfaces(*sm, system);
|
||||
LDN::InstallInterfaces(*sm, system);
|
||||
LDR::InstallInterfaces(*sm, system);
|
||||
|
||||
@@ -114,7 +114,8 @@ private:
|
||||
Kernel::HLERequestContext& ctx);
|
||||
|
||||
explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_,
|
||||
u32 max_sessions_, InvokerFn* handler_invoker_);
|
||||
ServiceThreadType thread_type, u32 max_sessions_,
|
||||
InvokerFn* handler_invoker_);
|
||||
~ServiceFrameworkBase() override;
|
||||
|
||||
void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
|
||||
@@ -176,14 +177,17 @@ protected:
|
||||
/**
|
||||
* Initializes the handler with no functions installed.
|
||||
*
|
||||
* @param system_ The system context to construct this service under.
|
||||
* @param system_ The system context to construct this service under.
|
||||
* @param service_name_ Name of the service.
|
||||
* @param max_sessions_ Maximum number of sessions that can be
|
||||
* connected to this service at the same time.
|
||||
* @param thread_type Specifies the thread type for this service. If this is set to CreateNew,
|
||||
* it creates a new thread for it, otherwise this uses the default thread.
|
||||
* @param max_sessions_ Maximum number of sessions that can be connected to this service at the
|
||||
* same time.
|
||||
*/
|
||||
explicit ServiceFramework(Core::System& system_, const char* service_name_,
|
||||
ServiceThreadType thread_type = ServiceThreadType::Default,
|
||||
u32 max_sessions_ = ServerSessionCountMax)
|
||||
: ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {}
|
||||
: ServiceFrameworkBase(system_, service_name_, thread_type, max_sessions_, Invoker) {}
|
||||
|
||||
/// Registers handlers in the service.
|
||||
template <std::size_t N>
|
||||
|
||||
@@ -206,7 +206,7 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
SM::SM(ServiceManager& service_manager_, Core::System& system_)
|
||||
: ServiceFramework{system_, "sm:", 4},
|
||||
: ServiceFramework{system_, "sm:", ServiceThreadType::Default, 4},
|
||||
service_manager{service_manager_}, kernel{system_.Kernel()} {
|
||||
RegisterHandlers({
|
||||
{0, &SM::Initialize, "Initialize"},
|
||||
|
||||
@@ -837,7 +837,8 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co
|
||||
rb.PushEnum(bsd_errno);
|
||||
}
|
||||
|
||||
BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
|
||||
BSD::BSD(Core::System& system_, const char* name)
|
||||
: ServiceFramework{system_, name, ServiceThreadType::CreateNew} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &BSD::RegisterClient, "RegisterClient"},
|
||||
|
||||
@@ -77,7 +77,8 @@ static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");
|
||||
class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
|
||||
public:
|
||||
explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
|
||||
: ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) {
|
||||
: ServiceFramework{system_, "IHOSBinderDriver", ServiceThreadType::CreateNew},
|
||||
server(server_) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
|
||||
{1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
|
||||
|
||||
Reference in New Issue
Block a user