early-access version 2947
This commit is contained in:
parent
0281449da2
commit
be5f850e61
@ -1,7 +1,7 @@
|
|||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 2945.
|
This is the source code for early-access 2947.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
@ -47,16 +47,6 @@ AudioRenderer::ADSP::ADSP& AudioCore::GetADSP() {
|
|||||||
return *adsp;
|
return *adsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioCore::PauseSinks(const bool pausing) const {
|
|
||||||
if (pausing) {
|
|
||||||
output_sink->PauseStreams();
|
|
||||||
input_sink->PauseStreams();
|
|
||||||
} else {
|
|
||||||
output_sink->UnpauseStreams();
|
|
||||||
input_sink->UnpauseStreams();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioCore::SetNVDECActive(bool active) {
|
void AudioCore::SetNVDECActive(bool active) {
|
||||||
nvdec_active = active;
|
nvdec_active = active;
|
||||||
}
|
}
|
||||||
|
@ -57,14 +57,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
AudioRenderer::ADSP::ADSP& GetADSP();
|
AudioRenderer::ADSP::ADSP& GetADSP();
|
||||||
|
|
||||||
/**
|
|
||||||
* Pause the sink. Called from the core.
|
|
||||||
*
|
|
||||||
* @param pausing - Is this pause due to an actual pause, or shutdown?
|
|
||||||
* Unfortunately, shutdown also pauses streams, which can cause issues.
|
|
||||||
*/
|
|
||||||
void PauseSinks(bool pausing) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle NVDEC state, used to avoid stall in playback.
|
* Toggle NVDEC state, used to avoid stall in playback.
|
||||||
*
|
*
|
||||||
|
@ -22,9 +22,7 @@ SystemManager::SystemManager(Core::System& core_)
|
|||||||
thread_event{Core::Timing::CreateEvent(
|
thread_event{Core::Timing::CreateEvent(
|
||||||
"AudioRendererSystemManager", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) {
|
"AudioRendererSystemManager", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) {
|
||||||
return ThreadFunc2(time);
|
return ThreadFunc2(time);
|
||||||
})} {
|
})} {}
|
||||||
core.CoreTiming().RegisterPauseCallback([this](bool paused) { PauseCallback(paused); });
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemManager::~SystemManager() {
|
SystemManager::~SystemManager() {
|
||||||
Stop();
|
Stop();
|
||||||
@ -125,11 +123,4 @@ std::optional<std::chrono::nanoseconds> SystemManager::ThreadFunc2(s64 time) {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemManager::PauseCallback(bool paused) {
|
|
||||||
if (paused && core.IsPoweredOn() && core.IsShuttingDown()) {
|
|
||||||
update.store(true);
|
|
||||||
update.notify_all();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace AudioCore::AudioRenderer
|
} // namespace AudioCore::AudioRenderer
|
||||||
|
@ -73,13 +73,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
std::optional<std::chrono::nanoseconds> ThreadFunc2(s64 time);
|
std::optional<std::chrono::nanoseconds> ThreadFunc2(s64 time);
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback from core timing when pausing, used to detect shutdowns and stop ThreadFunc.
|
|
||||||
*
|
|
||||||
* @param paused - Are we pausing or resuming?
|
|
||||||
*/
|
|
||||||
void PauseCallback(bool paused);
|
|
||||||
|
|
||||||
enum class StreamState {
|
enum class StreamState {
|
||||||
Filling,
|
Filling,
|
||||||
Steady,
|
Steady,
|
||||||
@ -106,8 +99,6 @@ private:
|
|||||||
std::shared_ptr<Core::Timing::EventType> thread_event;
|
std::shared_ptr<Core::Timing::EventType> thread_event;
|
||||||
/// Atomic for main thread to wait on
|
/// Atomic for main thread to wait on
|
||||||
std::atomic<bool> update{};
|
std::atomic<bool> update{};
|
||||||
/// Current state of the streams
|
|
||||||
StreamState state{StreamState::Filling};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AudioCore::AudioRenderer
|
} // namespace AudioCore::AudioRenderer
|
||||||
|
@ -129,21 +129,14 @@ public:
|
|||||||
* Default false.
|
* Default false.
|
||||||
*/
|
*/
|
||||||
void Start(bool resume = false) override {
|
void Start(bool resume = false) override {
|
||||||
if (!ctx) {
|
if (!ctx || !paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resume && was_playing) {
|
|
||||||
if (cubeb_stream_start(stream_backend) != CUBEB_OK) {
|
if (cubeb_stream_start(stream_backend) != CUBEB_OK) {
|
||||||
LOG_CRITICAL(Audio_Sink, "Error starting cubeb stream");
|
LOG_CRITICAL(Audio_Sink, "Error starting cubeb stream");
|
||||||
}
|
}
|
||||||
paused = false;
|
paused = false;
|
||||||
} else if (!resume) {
|
|
||||||
if (cubeb_stream_start(stream_backend) != CUBEB_OK) {
|
|
||||||
LOG_CRITICAL(Audio_Sink, "Error starting cubeb stream");
|
|
||||||
}
|
|
||||||
paused = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,7 +144,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void Stop() override {
|
void Stop() override {
|
||||||
Unstall();
|
Unstall();
|
||||||
if (!ctx) {
|
|
||||||
|
if (!ctx || paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,18 +280,6 @@ void CubebSink::CloseStreams() {
|
|||||||
sink_streams.clear();
|
sink_streams.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CubebSink::PauseStreams() {
|
|
||||||
for (auto& stream : sink_streams) {
|
|
||||||
stream->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubebSink::UnpauseStreams() {
|
|
||||||
for (auto& stream : sink_streams) {
|
|
||||||
stream->Start(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f32 CubebSink::GetDeviceVolume() const {
|
f32 CubebSink::GetDeviceVolume() const {
|
||||||
if (sink_streams.empty()) {
|
if (sink_streams.empty()) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
|
@ -53,16 +53,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void CloseStreams() override;
|
void CloseStreams() override;
|
||||||
|
|
||||||
/**
|
|
||||||
* Pause all streams.
|
|
||||||
*/
|
|
||||||
void PauseStreams() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpause all streams.
|
|
||||||
*/
|
|
||||||
void UnpauseStreams() override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the device volume. Set from calls to the IAudioDevice service.
|
* Get the device volume. Set from calls to the IAudioDevice service.
|
||||||
*
|
*
|
||||||
|
@ -44,8 +44,6 @@ public:
|
|||||||
|
|
||||||
void CloseStream(SinkStream*) override {}
|
void CloseStream(SinkStream*) override {}
|
||||||
void CloseStreams() override {}
|
void CloseStreams() override {}
|
||||||
void PauseStreams() override {}
|
|
||||||
void UnpauseStreams() override {}
|
|
||||||
f32 GetDeviceVolume() const override {
|
f32 GetDeviceVolume() const override {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
@ -108,17 +108,12 @@ public:
|
|||||||
* Default false.
|
* Default false.
|
||||||
*/
|
*/
|
||||||
void Start(bool resume = false) override {
|
void Start(bool resume = false) override {
|
||||||
if (device == 0) {
|
if (device == 0 || !paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resume && was_playing) {
|
|
||||||
SDL_PauseAudioDevice(device, 0);
|
SDL_PauseAudioDevice(device, 0);
|
||||||
paused = false;
|
paused = false;
|
||||||
} else if (!resume) {
|
|
||||||
SDL_PauseAudioDevice(device, 0);
|
|
||||||
paused = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,7 +121,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
void Stop() override {
|
void Stop() override {
|
||||||
Unstall();
|
Unstall();
|
||||||
if (device == 0) {
|
if (device == 0 || paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SDL_PauseAudioDevice(device, 1);
|
SDL_PauseAudioDevice(device, 1);
|
||||||
@ -207,18 +202,6 @@ void SDLSink::CloseStreams() {
|
|||||||
sink_streams.clear();
|
sink_streams.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLSink::PauseStreams() {
|
|
||||||
for (auto& stream : sink_streams) {
|
|
||||||
stream->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLSink::UnpauseStreams() {
|
|
||||||
for (auto& stream : sink_streams) {
|
|
||||||
stream->Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f32 SDLSink::GetDeviceVolume() const {
|
f32 SDLSink::GetDeviceVolume() const {
|
||||||
if (sink_streams.empty()) {
|
if (sink_streams.empty()) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
|
@ -51,16 +51,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void CloseStreams() override;
|
void CloseStreams() override;
|
||||||
|
|
||||||
/**
|
|
||||||
* Pause all streams.
|
|
||||||
*/
|
|
||||||
void PauseStreams() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpause all streams.
|
|
||||||
*/
|
|
||||||
void UnpauseStreams() override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the device volume. Set from calls to the IAudioDevice service.
|
* Get the device volume. Set from calls to the IAudioDevice service.
|
||||||
*
|
*
|
||||||
|
@ -39,16 +39,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void CloseStreams() = 0;
|
virtual void CloseStreams() = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Pause all streams.
|
|
||||||
*/
|
|
||||||
virtual void PauseStreams() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpause all streams.
|
|
||||||
*/
|
|
||||||
virtual void UnpauseStreams() = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new sink stream, kept within this sink, with a pointer returned for use.
|
* Create a new sink stream, kept within this sink, with a pointer returned for use.
|
||||||
* Do not free the returned pointer. When done with the stream, call CloseStream on the sink.
|
* Do not free the returned pointer. When done with the stream, call CloseStream on the sink.
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -145,6 +143,12 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n
|
|||||||
const std::size_t frame_size_bytes = frame_size * sizeof(s16);
|
const std::size_t frame_size_bytes = frame_size * sizeof(s16);
|
||||||
size_t frames_written{0};
|
size_t frames_written{0};
|
||||||
|
|
||||||
|
// If we're paused or going to shut down, we don't want to consume buffers as coretiming is
|
||||||
|
// paused and we'll desync, so just return.
|
||||||
|
if (system.IsPaused() || system.IsShuttingDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (queued_buffers > max_queue_size) {
|
if (queued_buffers > max_queue_size) {
|
||||||
Stall();
|
Stall();
|
||||||
}
|
}
|
||||||
@ -195,6 +199,16 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
|
|||||||
const std::size_t frame_size_bytes = frame_size * sizeof(s16);
|
const std::size_t frame_size_bytes = frame_size * sizeof(s16);
|
||||||
size_t frames_written{0};
|
size_t frames_written{0};
|
||||||
|
|
||||||
|
// If we're paused or going to shut down, we don't want to consume buffers as coretiming is
|
||||||
|
// paused and we'll desync, so just play silence.
|
||||||
|
if (system.IsPaused() || system.IsShuttingDown()) {
|
||||||
|
constexpr std::array<s16, 6> silence{};
|
||||||
|
for (size_t i = frames_written; i < num_frames; i++) {
|
||||||
|
std::memcpy(&output_buffer[i * frame_size], &silence[0], frame_size_bytes);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Due to many frames being queued up with nvdec (5 frames or so?), a lot of buffers also get
|
// Due to many frames being queued up with nvdec (5 frames or so?), a lot of buffers also get
|
||||||
// queued up (30+) but not all at once, which causes constant stalling here, so just let the
|
// queued up (30+) but not all at once, which causes constant stalling here, so just let the
|
||||||
// video play out without attempting to stall.
|
// video play out without attempting to stall.
|
||||||
|
@ -141,8 +141,6 @@ struct System::Impl {
|
|||||||
core_timing.SyncPause(false);
|
core_timing.SyncPause(false);
|
||||||
is_paused = false;
|
is_paused = false;
|
||||||
|
|
||||||
audio_core->PauseSinks(false);
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,8 +148,6 @@ struct System::Impl {
|
|||||||
std::unique_lock<std::mutex> lk(suspend_guard);
|
std::unique_lock<std::mutex> lk(suspend_guard);
|
||||||
status = SystemResultStatus::Success;
|
status = SystemResultStatus::Success;
|
||||||
|
|
||||||
audio_core->PauseSinks(true);
|
|
||||||
|
|
||||||
core_timing.SyncPause(true);
|
core_timing.SyncPause(true);
|
||||||
kernel.Suspend(true);
|
kernel.Suspend(true);
|
||||||
is_paused = true;
|
is_paused = true;
|
||||||
|
@ -73,7 +73,6 @@ void CoreTiming::Shutdown() {
|
|||||||
if (timer_thread) {
|
if (timer_thread) {
|
||||||
timer_thread->join();
|
timer_thread->join();
|
||||||
}
|
}
|
||||||
pause_callbacks.clear();
|
|
||||||
ClearPendingEvents();
|
ClearPendingEvents();
|
||||||
timer_thread.reset();
|
timer_thread.reset();
|
||||||
has_started = false;
|
has_started = false;
|
||||||
@ -86,10 +85,6 @@ void CoreTiming::Pause(bool is_paused) {
|
|||||||
if (!is_paused) {
|
if (!is_paused) {
|
||||||
pause_end_time = GetGlobalTimeNs().count();
|
pause_end_time = GetGlobalTimeNs().count();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& cb : pause_callbacks) {
|
|
||||||
cb(is_paused);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::SyncPause(bool is_paused) {
|
void CoreTiming::SyncPause(bool is_paused) {
|
||||||
@ -110,10 +105,6 @@ void CoreTiming::SyncPause(bool is_paused) {
|
|||||||
if (!is_paused) {
|
if (!is_paused) {
|
||||||
pause_end_time = GetGlobalTimeNs().count();
|
pause_end_time = GetGlobalTimeNs().count();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& cb : pause_callbacks) {
|
|
||||||
cb(is_paused);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CoreTiming::IsRunning() const {
|
bool CoreTiming::IsRunning() const {
|
||||||
@ -223,11 +214,6 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) {
|
|
||||||
std::scoped_lock lock{basic_lock};
|
|
||||||
pause_callbacks.emplace_back(std::move(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<s64> CoreTiming::Advance() {
|
std::optional<s64> CoreTiming::Advance() {
|
||||||
std::scoped_lock lock{advance_lock, basic_lock};
|
std::scoped_lock lock{advance_lock, basic_lock};
|
||||||
global_timer = GetGlobalTimeNs().count();
|
global_timer = GetGlobalTimeNs().count();
|
||||||
|
@ -22,7 +22,6 @@ namespace Core::Timing {
|
|||||||
/// A callback that may be scheduled for a particular core timing event.
|
/// A callback that may be scheduled for a particular core timing event.
|
||||||
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
|
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
|
||||||
std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
|
std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
|
||||||
using PauseCallback = std::function<void(bool paused)>;
|
|
||||||
|
|
||||||
/// Contains the characteristics of a particular event.
|
/// Contains the characteristics of a particular event.
|
||||||
struct EventType {
|
struct EventType {
|
||||||
@ -134,9 +133,6 @@ public:
|
|||||||
/// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
|
/// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
|
||||||
std::optional<s64> Advance();
|
std::optional<s64> Advance();
|
||||||
|
|
||||||
/// Register a callback function to be called when coretiming pauses.
|
|
||||||
void RegisterPauseCallback(PauseCallback&& callback);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Event;
|
struct Event;
|
||||||
|
|
||||||
@ -176,8 +172,6 @@ private:
|
|||||||
/// Cycle timing
|
/// Cycle timing
|
||||||
u64 ticks{};
|
u64 ticks{};
|
||||||
s64 downcount{};
|
s64 downcount{};
|
||||||
|
|
||||||
std::vector<PauseCallback> pause_callbacks{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates a core timing event with the given name and callback.
|
/// Creates a core timing event with the given name and callback.
|
||||||
|
Loading…
Reference in New Issue
Block a user