Merge remote-tracking branch 'upstream/canary_experimental' into edge

This commit is contained in:
Herman S.
2025-10-29 10:42:02 +09:00
10 changed files with 124 additions and 12 deletions
+79
View File
@@ -490,6 +490,73 @@ void EmulatorWindow::EmulatorWindowListener::OnMouseDoubleClick(
emulator_window_.OnMouseDoubleClick(e);
}
void EmulatorWindow::XMPConfigDialog::OnDraw(ImGuiIO& io) {
// Center window horizontally, position in lower portion of screen
float window_width = 400.0f;
float window_height = 150.0f;
float x = (io.DisplaySize.x - window_width) * 0.5f;
float y = io.DisplaySize.y * 0.85f - window_height * 0.5f;
ImGui::SetNextWindowPos(ImVec2(x, y), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
ImGuiCond_FirstUseEver);
bool dialog_open = true;
if (!ImGui::Begin("Audio Player Menu", &dialog_open,
ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_HorizontalScrollbar)) {
Close();
ImGui::End();
return;
}
auto audio_player = emulator_window_.emulator_->audio_media_player();
using xmp_state = kernel::xam::apps::XmpApp::State;
if (audio_player) {
ImGui::Text("Audio player status:");
ImGui::SameLine();
switch (audio_player->GetState()) {
case xmp_state::kIdle:
ImGui::Text("Idle");
break;
case xmp_state::kPaused:
ImGui::Text("Paused");
break;
case xmp_state::kPlaying:
ImGui::Text("Playing");
break;
default:
break;
}
if (audio_player->IsPlaying()) {
if (ImGui::Button("Pause")) {
audio_player->Pause();
}
} else if (audio_player->IsPaused()) {
if (ImGui::Button("Resume")) {
audio_player->Continue();
}
}
volume_ =
emulator_window_.emulator_->audio_media_player()->GetVolume()->load();
if (ImGui::SliderFloat("Audio player volume", &volume_, 0.0f, 1.0f)) {
audio_player->SetVolume(volume_);
}
}
if (!dialog_open) {
ImGui::End();
emulator_window_.ToggleXMPConfigDialog();
return;
}
ImGui::End();
}
bool EmulatorWindow::Initialize() {
window_->AddListener(&window_listener_);
window_->AddInputListener(&window_listener_, kZOrderEmulatorWindowInput);
@@ -1050,6 +1117,9 @@ void EmulatorWindow::OnMouseDown(const ui::MouseEvent& e) {
context_menu->AddAction("Profiles Menu",
[this]() { ToggleProfilesConfigDialog(); });
context_menu->AddAction("XMP Audio Player",
[this]() { ToggleXMPConfigDialog(); });
// Show menu at mouse position
QPoint global_pos = QCursor::pos();
context_menu->ShowAt(global_pos);
@@ -1544,6 +1614,15 @@ void EmulatorWindow::OpenConfigDialog(const std::string& category) {
config_dialog_qt_->activateWindow();
}
void EmulatorWindow::ToggleXMPConfigDialog() {
if (!xmp_config_dialog_) {
xmp_config_dialog_ = std::unique_ptr<XMPConfigDialog>(
new XMPConfigDialog(imgui_drawer_.get(), *this));
} else {
xmp_config_dialog_.reset();
}
}
void EmulatorWindow::ToggleControllerVibration() {
auto input_sys = emulator()->input_system();
if (input_sys) {
+23
View File
@@ -113,6 +113,7 @@ class EmulatorWindow {
const xe::ui::RawImage& image);
void ToggleProfilesConfigDialog();
void ToggleXMPConfigDialog();
void SetHotkeysState(bool enabled) { disable_hotkeys_ = !enabled; }
void FileOpen();
const std::vector<RecentTitleEntry>& GetRecentlyLaunchedTitles() const {
@@ -180,6 +181,26 @@ class EmulatorWindow {
};
public:
class XMPConfigDialog final : public ui::ImGuiDialog {
public:
XMPConfigDialog(ui::ImGuiDrawer* imgui_drawer,
EmulatorWindow& emulator_window)
: ui::ImGuiDialog(imgui_drawer), emulator_window_(emulator_window) {
if (emulator_window_.emulator_->audio_media_player()) {
volume_ = emulator_window_.emulator_->audio_media_player()
->GetVolume()
->load();
}
}
protected:
void OnDraw(ImGuiIO& io) override;
private:
EmulatorWindow& emulator_window_;
float volume_ = 0.0f;
};
explicit EmulatorWindow(Emulator* emulator,
ui::WindowedAppContext& app_context, uint32_t width,
uint32_t height, bool is_game_process = false);
@@ -283,6 +304,8 @@ class EmulatorWindow {
// messages back to guest.
std::unique_ptr<ProfileConfigDialog> profile_config_dialog_;
std::unique_ptr<XMPConfigDialog> xmp_config_dialog_;
std::vector<RecentTitleEntry> recently_launched_titles_;
// Menu items that need to be enabled/disabled based on child process state
+1 -1
View File
@@ -448,7 +448,7 @@ void AudioMediaPlayer::RemovePlaylist(uint32_t handle) {
}
X_STATUS AudioMediaPlayer::SetVolume(float volume) {
volume_ = std::min(volume, 1.0f);
volume_.store(std::min(volume, 1.0f));
std::unique_lock<xe_mutex> guard(driver_mutex_);
if (!driver_) {
+2 -2
View File
@@ -51,7 +51,7 @@ class AudioMediaPlayer {
bool IsLastSongInPlaylist() const;
X_STATUS SetVolume(float volume);
float GetVolume() const { return volume_; }
const std::atomic<float>* GetVolume() const { return &volume_; }
void SetPlaybackMode(XmpApp::PlaybackMode playback_mode) {
playback_mode_ = playback_mode;
@@ -106,7 +106,7 @@ class AudioMediaPlayer {
XmpApp::PlaybackMode playback_mode_ = XmpApp::PlaybackMode::kInOrder;
XmpApp::RepeatMode repeat_mode_ = XmpApp::RepeatMode::kPlaylist;
XmpApp::PlaybackFlags playback_flags_ = XmpApp::PlaybackFlags::kDefault;
float volume_ = 1.0f;
std::atomic<float> volume_ = 0.0f;
uint32_t dash_init_state = 0;
std::unordered_map<uint32_t, std::unique_ptr<XmpApp::Playlist>> playlists_;
+4
View File
@@ -175,6 +175,10 @@ struct ValueOp : Op<ValueOp<T, KEY_TYPE, REG_TYPE, CONST_TYPE>, KEY_TYPE> {
virtual bool ConstantFitsIn32Reg() const { return true; }
const REG_TYPE& reg() const {
assert_true(!is_constant);
if (is_constant) {
XELOGE("{} - Invalid handling of constant! Report this to developers!",
__FUNCTION__);
}
return reg_;
}
operator const REG_TYPE&() const { return reg(); }
+6 -1
View File
@@ -1885,7 +1885,12 @@ struct VECTOR_ROTATE_LEFT_V128
} break;
case INT32_TYPE: {
if (e.IsFeatureEnabled(kX64EmitAVX512Ortho)) {
e.vprolvd(i.dest, i.src1, i.src2);
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.vprolvd(i.dest, i.src1, e.xmm0);
} else {
e.vprolvd(i.dest, i.src1, i.src2);
}
} else if (e.IsFeatureEnabled(kX64EmitAVX2)) {
Xmm temp = i.dest;
if (i.dest == i.src1 || i.dest == i.src2) {
+2 -2
View File
@@ -262,7 +262,7 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
xe::store_and_swap<float>(
memory_->TranslateVirtual(args->volume_ptr),
kernel_state_->emulator()->audio_media_player()->GetVolume());
kernel_state_->emulator()->audio_media_player()->GetVolume()->load());
return X_E_SUCCESS;
}
case 0x0007000C: {
@@ -401,7 +401,7 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
XMP_CREATE_USER_PLAYLIST_ENUMERATOR* args =
reinterpret_cast<XMP_CREATE_USER_PLAYLIST_ENUMERATOR*>(buffer);
XELOGD("XMPSetPlaybackController({:08X}, {:08X}, {:08X})",
XELOGD("XMPCreateUserPlaylistEnumerator({:08X}, {:08X}, {:08X})",
uint32_t(args->xmp_client), uint32_t(args->flags),
uint32_t(args->unk_ptr));
return X_E_SUCCESS;
+1 -1
View File
@@ -86,7 +86,7 @@ static_assert_size(XMP_GET_VOLUME, 0x8);
struct XMP_SET_VOLUME {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> value;
xe::be<float> value;
};
static_assert_size(XMP_SET_VOLUME, 0x8);
+4 -3
View File
@@ -672,7 +672,8 @@ dword_result_t NetDll_socket_entry(dword_t caller, dword_t af, dword_t type,
socket->Release();
XThread::SetLastError(socket->GetLastWSAError());
XELOGI("NetDll_socket: failed with error");
XELOGE("NetDll_socket: failed with error {:08X}",
socket->GetLastWSAError());
return -1;
}
@@ -765,7 +766,8 @@ dword_result_t NetDll_ioctlsocket_entry(dword_t caller, dword_t socket_handle,
X_STATUS status = socket->IOControl(cmd, arg_ptr);
if (XFAILED(status)) {
XThread::SetLastError(socket->GetLastWSAError());
XELOGI("NetDll_ioctlsocket: failed");
XELOGE("NetDll_ioctlsocket: failed with error {:08X}",
socket->GetLastWSAError());
return -1;
}
@@ -1072,7 +1074,6 @@ dword_result_t NetDll_sendto_entry(dword_t caller, dword_t socket_handle,
N_XSOCKADDR_IN native_to(to_ptr);
int ret = socket->SendTo(buf_ptr, buf_len, flags, &native_to, to_len);
XELOGD("NetDll_sendto: returned {}", ret);
return ret;
}
DECLARE_XAM_EXPORT1(NetDll_sendto, kNetworking, kImplemented);
+2 -2
View File
@@ -157,7 +157,7 @@ X_STATUS XSocket::SetOption(uint32_t level, uint32_t optname, void* optval_ptr,
}
int ret = setsockopt(native_handle_, native_level, native_optname,
(char*)optval_ptr, optlen);
static_cast<char*>(optval_ptr), optlen);
if (ret < 0) {
XELOGE("XSocket::SetOption: setsockopt failed, errno={}", errno);
return X_STATUS_UNSUCCESSFUL;
@@ -218,7 +218,7 @@ X_STATUS XSocket::Bind(N_XSOCKADDR_IN* name, int name_len) {
// privileges. Remap to port + 10000 to avoid privilege issues.
// Note: sin_port is xe::be<uint16_t> which automatically handles endianness,
// so we use it directly without ntohs/htons.
uint16_t original_port = uint16_t(name->sin_port);
const uint16_t original_port = uint16_t(name->sin_port);
if (original_port < 1024) {
uint16_t new_port = original_port + 10000;
name->sin_port = new_port;