diff --git a/README.md b/README.md index 8eaac9955..129fc1a34 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 3580. +This is the source code for early-access 3581. ## Legal Notice diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp index fcf49b299..3ba1cfc55 100755 --- a/src/audio_core/renderer/adsp/audio_renderer.cpp +++ b/src/audio_core/renderer/adsp/audio_renderer.cpp @@ -188,8 +188,6 @@ void AudioRenderer::ThreadFunc() { max_time = std::min(command_buffer.time_limit, max_time); command_list_processor.SetProcessTimeMax(max_time); - streams[index]->WaitFreeSpace(); - // Process the command list { MICROPROFILE_SCOPE(Audio_Renderer); diff --git a/src/audio_core/renderer/system_manager.cpp b/src/audio_core/renderer/system_manager.cpp index 5f96579b8..cc59a2883 100755 --- a/src/audio_core/renderer/system_manager.cpp +++ b/src/audio_core/renderer/system_manager.cpp @@ -15,9 +15,14 @@ MICROPROFILE_DEFINE(Audio_RenderSystemManager, "Audio", "Render System Manager", MP_RGB(60, 19, 97)); namespace AudioCore::AudioRenderer { +constexpr std::chrono::nanoseconds RENDER_TIME{5'000'000UL}; SystemManager::SystemManager(Core::System& core_) - : core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()} {} + : core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()}, + thread_event{Core::Timing::CreateEvent( + "AudioRendererSystemManager", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) { + return ThreadFunc2(time); + })} {} SystemManager::~SystemManager() { Stop(); @@ -27,7 +32,9 @@ bool SystemManager::InitializeUnsafe() { if (!active) { if (adsp.Start()) { active = true; - thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(); }); + thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(stop_token); }); + core.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), RENDER_TIME, + thread_event); } } @@ -38,9 +45,13 @@ void SystemManager::Stop() { if (!active) { return; } + core.CoreTiming().UnscheduleEvent(thread_event, {}); active = false; - update.store(true); - update.notify_all(); + { + std::scoped_lock l{cv_mutex}; + do_update = false; + } + thread.request_stop(); thread.join(); adsp.Stop(); } @@ -85,12 +96,12 @@ bool SystemManager::Remove(System& system_) { return true; } -void SystemManager::ThreadFunc() { +void SystemManager::ThreadFunc(std::stop_token stop_token) { static constexpr char name[]{"AudioRenderSystemManager"}; MicroProfileOnThreadCreate(name); Common::SetCurrentThreadName(name); Common::SetCurrentThreadPriority(Common::ThreadPriority::High); - while (active) { + while (active && !stop_token.stop_requested()) { { std::scoped_lock l{mutex1}; @@ -103,7 +114,20 @@ void SystemManager::ThreadFunc() { adsp.Signal(); adsp.Wait(); + + std::unique_lock l{cv_mutex}; + Common::CondvarWait(update_cv, l, stop_token, [this]() { return do_update; }); + do_update = false; } } +std::optional SystemManager::ThreadFunc2(s64 time) { + { + std::scoped_lock l{cv_mutex}; + do_update = true; + } + update_cv.notify_all(); + return std::nullopt; +} + } // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/system_manager.h b/src/audio_core/renderer/system_manager.h index cfaa4053b..41bbbdac1 100755 --- a/src/audio_core/renderer/system_manager.h +++ b/src/audio_core/renderer/system_manager.h @@ -66,13 +66,12 @@ private: /** * Main thread responsible for command generation. */ - void ThreadFunc(); + void ThreadFunc(std::stop_token stop_token); - enum class StreamState { - Filling, - Steady, - Draining, - }; + /** + * Signalling core timing thread to run ThreadFunc. + */ + std::optional ThreadFunc2(s64 time); /// Core system Core::System& core; @@ -90,8 +89,12 @@ private: ADSP::ADSP& adsp; /// AudioRenderer mailbox for communication ADSP::AudioRenderer_Mailbox* mailbox{}; + /// Core timing event to signal main thread + std::shared_ptr thread_event; /// Atomic for main thread to wait on - std::atomic update{}; + std::mutex cv_mutex{}; + bool do_update{}; + std::condition_variable_any update_cv{}; }; } // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index d57be6189..49ca91efd 100755 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp @@ -268,10 +268,4 @@ u64 SinkStream::GetExpectedPlayedSampleCount() { return std::min(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 3; } -void SinkStream::WaitFreeSpace() { - std::unique_lock lk{release_mutex}; - release_cv.wait( - lk, [this]() { return queued_buffers < max_queue_size || system.IsShuttingDown(); }); -} - } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h index 1e7658818..e2f8fb97f 100755 --- a/src/audio_core/sink/sink_stream.h +++ b/src/audio_core/sink/sink_stream.h @@ -207,11 +207,6 @@ public: */ u64 GetExpectedPlayedSampleCount(); - /** - * Waits for free space in the sample ring buffer - */ - void WaitFreeSpace(); - protected: /// Core system Core::System& system; diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index 7ea746efd..8a70d98f5 100755 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp @@ -339,9 +339,7 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { if (ctx.profile.support_vertex_instance_id) { return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_id)); } else { - const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)}; - const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)}; - return ctx.OpBitcast(ctx.F32[1], ctx.OpISub(ctx.U32[1], index, base)); + return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_index)); } case IR::Attribute::BaseInstance: return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_instance)); @@ -386,9 +384,7 @@ Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id) { if (ctx.profile.support_vertex_instance_id) { return ctx.OpLoad(ctx.U32[1], ctx.vertex_id); } else { - const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)}; - const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)}; - return ctx.OpISub(ctx.U32[1], index, base); + return ctx.OpLoad(ctx.U32[1], ctx.vertex_index); } case IR::Attribute::BaseInstance: return ctx.OpLoad(ctx.U32[1], ctx.base_instance); diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp index 073cebc80..e61c222c6 100755 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp @@ -102,12 +102,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) { } IR::F32 value{v.ir.CompositeExtract(sample, element)}; if (element < 2) { - IR::U32 casted_value; - if (element == 0) { - casted_value = v.ir.ConvertFToU(32, value); - } else { - casted_value = v.ir.ConvertFToS(16, value); - } + IR::U32 casted_value = v.ir.ConvertFToU(32, value); v.X(dest_reg, v.ir.ShiftLeftLogical(casted_value, v.ir.Imm32(8))); } else { v.F(dest_reg, value); diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index e7fbed02b..2e7425f27 100755 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -48,7 +48,9 @@ ConfigureHotkeys::ConfigureHotkeys(Core::HID::HIDCore& hid_core, QWidget* parent connect(poll_timer.get(), &QTimer::timeout, [this] { const auto buttons = controller->GetNpadButtons(); - if (buttons.raw != Core::HID::NpadButton::None) { + const auto home_pressed = controller->GetHomeButtons().home != 0; + const auto capture_pressed = controller->GetCaptureButtons().capture != 0; + if (home_pressed || capture_pressed) { SetPollingResult(buttons.raw, false); return; } @@ -154,8 +156,10 @@ void ConfigureHotkeys::ConfigureController(QModelIndex index) { model->setData(index, previous_key); return; } - - const QString button_string = tr("Home+%1").arg(GetButtonName(button)); + const auto home_pressed = this->controller->GetHomeButtons().home != 0; + const auto capture_pressed = this->controller->GetCaptureButtons().capture != 0; + const QString button_string = + GetButtonCombinationName(button, home_pressed, capture_pressed); const auto [key_sequence_used, used_action] = IsUsedControllerKey(button_string); @@ -174,72 +178,83 @@ void ConfigureHotkeys::ConfigureController(QModelIndex index) { poll_timer->start(200); // Check for new inputs every 200ms // We need to disable configuration to be able to read npad buttons controller->DisableConfiguration(); - controller->DisableSystemButtons(); } void ConfigureHotkeys::SetPollingResult(Core::HID::NpadButton button, const bool cancel) { timeout_timer->stop(); poll_timer->stop(); + (*input_setter)(button, cancel); // Re-Enable configuration controller->EnableConfiguration(); - controller->EnableSystemButtons(); - - (*input_setter)(button, cancel); input_setter = std::nullopt; } -QString ConfigureHotkeys::GetButtonName(Core::HID::NpadButton button) const { +QString ConfigureHotkeys::GetButtonCombinationName(Core::HID::NpadButton button, + const bool home = false, + const bool capture = false) const { Core::HID::NpadButtonState state{button}; + QString button_combination; + if (home) { + button_combination.append(QStringLiteral("Home+")); + } + if (capture) { + button_combination.append(QStringLiteral("Screenshot+")); + } if (state.a) { - return QStringLiteral("A"); + button_combination.append(QStringLiteral("A+")); } if (state.b) { - return QStringLiteral("B"); + button_combination.append(QStringLiteral("B+")); } if (state.x) { - return QStringLiteral("X"); + button_combination.append(QStringLiteral("X+")); } if (state.y) { - return QStringLiteral("Y"); + button_combination.append(QStringLiteral("Y+")); } if (state.l || state.right_sl || state.left_sl) { - return QStringLiteral("L"); + button_combination.append(QStringLiteral("L+")); } if (state.r || state.right_sr || state.left_sr) { - return QStringLiteral("R"); + button_combination.append(QStringLiteral("R+")); } if (state.zl) { - return QStringLiteral("ZL"); + button_combination.append(QStringLiteral("ZL+")); } if (state.zr) { - return QStringLiteral("ZR"); + button_combination.append(QStringLiteral("ZR+")); } if (state.left) { - return QStringLiteral("Dpad_Left"); + button_combination.append(QStringLiteral("Dpad_Left+")); } if (state.right) { - return QStringLiteral("Dpad_Right"); + button_combination.append(QStringLiteral("Dpad_Right+")); } if (state.up) { - return QStringLiteral("Dpad_Up"); + button_combination.append(QStringLiteral("Dpad_Up+")); } if (state.down) { - return QStringLiteral("Dpad_Down"); + button_combination.append(QStringLiteral("Dpad_Down+")); } if (state.stick_l) { - return QStringLiteral("Left_Stick"); + button_combination.append(QStringLiteral("Left_Stick+")); } if (state.stick_r) { - return QStringLiteral("Right_Stick"); + button_combination.append(QStringLiteral("Right_Stick+")); } if (state.minus) { - return QStringLiteral("Minus"); + button_combination.append(QStringLiteral("Minus+")); } if (state.plus) { - return QStringLiteral("Plus"); + button_combination.append(QStringLiteral("Plus+")); + } + if (button_combination.isEmpty()) { + return tr("Invalid"); + } else { + button_combination.chop(1); + return button_combination; } - return tr("Invalid"); } std::pair ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) const { diff --git a/src/yuzu/configuration/configure_hotkeys.h b/src/yuzu/configuration/configure_hotkeys.h index 39ebb44f5..5651bdb21 100755 --- a/src/yuzu/configuration/configure_hotkeys.h +++ b/src/yuzu/configuration/configure_hotkeys.h @@ -59,7 +59,7 @@ private: QStandardItemModel* model; void SetPollingResult(Core::HID::NpadButton button, bool cancel); - QString GetButtonName(Core::HID::NpadButton button) const; + QString GetButtonCombinationName(Core::HID::NpadButton button, bool home, bool capture) const; Core::HID::EmulatedController* controller; std::unique_ptr timeout_timer; std::unique_ptr poll_timer; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 8d0ef2b15..2657b92e3 100755 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1164,7 +1164,8 @@ void GMainWindow::InitializeRecentFileMenuActions() { UpdateRecentFiles(); } -void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name) { +void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name, + const bool tas_allowed) { static const QString main_window = QStringLiteral("Main Window"); action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name)); action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name)); @@ -1176,7 +1177,14 @@ void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name const auto* controller_hotkey = hotkey_registry.GetControllerHotkey(main_window, action_name, controller); connect( - controller_hotkey, &ControllerShortcut::Activated, this, [action] { action->trigger(); }, + controller_hotkey, &ControllerShortcut::Activated, this, + [action, tas_allowed, this] { + auto [tas_status, current_tas_frame, total_tas_frames] = + input_subsystem->GetTas()->GetStatus(); + if (tas_allowed || tas_status == InputCommon::TasInput::TasState::Stopped) { + action->trigger(); + } + }, Qt::QueuedConnection); } @@ -1193,9 +1201,9 @@ void GMainWindow::InitializeHotkeys() { LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar")); LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen")); LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot")); - LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop")); - LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record")); - LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset")); + LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"), true); + LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"), true); + LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"), true); static const QString main_window = QStringLiteral("Main Window"); const auto connect_shortcut = [&](const QString& action_name, const Fn& function) { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 6093029d0..38d5e7469 100755 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -214,7 +214,8 @@ public slots: private: /// Updates an action's shortcut and text to reflect an updated hotkey from the hotkey registry. - void LinkActionShortcut(QAction* action, const QString& action_name); + void LinkActionShortcut(QAction* action, const QString& action_name, + const bool tas_allowed = false); void RegisterMetaTypes();