mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-09 13:36:35 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a1002885f6 | |||
| a6161e7d07 | |||
| c50e5912e9 | |||
| 6b539b55d7 |
@@ -114,9 +114,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
name: Int,
|
name: Int,
|
||||||
|
|
||||||
container: ViewGroup,
|
container: ViewGroup,
|
||||||
setting: BooleanSetting,
|
setting: BooleanSetting
|
||||||
isEnabled: Boolean = true,
|
|
||||||
onValueChanged: ((Boolean) -> Unit)? = null
|
|
||||||
) {
|
) {
|
||||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||||
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
||||||
@@ -127,21 +125,15 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
|
|
||||||
titleView.text = YuzuApplication.appContext.getString(name)
|
titleView.text = YuzuApplication.appContext.getString(name)
|
||||||
switchContainer.visibility = View.VISIBLE
|
switchContainer.visibility = View.VISIBLE
|
||||||
switchContainer.isEnabled = isEnabled
|
|
||||||
switchView.isChecked = setting.getBoolean()
|
switchView.isChecked = setting.getBoolean()
|
||||||
switchView.isEnabled = isEnabled
|
|
||||||
itemView.alpha = if (isEnabled) 1.0f else 0.5f
|
|
||||||
|
|
||||||
switchView.setOnCheckedChangeListener { _, isChecked ->
|
switchView.setOnCheckedChangeListener { _, isChecked ->
|
||||||
setting.setBoolean(isChecked)
|
setting.setBoolean(isChecked)
|
||||||
saveSettings()
|
saveSettings()
|
||||||
onValueChanged?.invoke(isChecked)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switchContainer.setOnClickListener {
|
switchContainer.setOnClickListener {
|
||||||
if (switchView.isEnabled) {
|
switchView.toggle()
|
||||||
switchView.toggle()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
container.addView(itemView)
|
container.addView(itemView)
|
||||||
}
|
}
|
||||||
@@ -185,9 +177,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
setting: AbstractSetting,
|
setting: AbstractSetting,
|
||||||
minValue: Int = 0,
|
minValue: Int = 0,
|
||||||
maxValue: Int = 100,
|
maxValue: Int = 100,
|
||||||
units: String = "",
|
units: String = ""
|
||||||
isEnabled: Boolean = true,
|
|
||||||
onValueChanged: ((Int) -> Unit)? = null
|
|
||||||
) {
|
) {
|
||||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||||
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
||||||
@@ -200,13 +190,10 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
|
|
||||||
titleView.text = YuzuApplication.appContext.getString(name)
|
titleView.text = YuzuApplication.appContext.getString(name)
|
||||||
sliderContainer.visibility = View.VISIBLE
|
sliderContainer.visibility = View.VISIBLE
|
||||||
sliderContainer.isEnabled = isEnabled
|
|
||||||
|
|
||||||
slider.valueFrom = minValue.toFloat()
|
slider.valueFrom = minValue.toFloat()
|
||||||
slider.valueTo = maxValue.toFloat()
|
slider.valueTo = maxValue.toFloat()
|
||||||
slider.stepSize = 1f
|
slider.stepSize = 1f
|
||||||
slider.isEnabled = isEnabled
|
|
||||||
itemView.alpha = if (isEnabled) 1.0f else 0.5f
|
|
||||||
val currentValue = when (setting) {
|
val currentValue = when (setting) {
|
||||||
is AbstractShortSetting -> setting.getShort(needsGlobal = false).toInt()
|
is AbstractShortSetting -> setting.getShort(needsGlobal = false).toInt()
|
||||||
is AbstractIntSetting -> setting.getInt(needsGlobal = false)
|
is AbstractIntSetting -> setting.getInt(needsGlobal = false)
|
||||||
@@ -217,8 +204,8 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
val displayValue = "${slider.value.toInt()}$units"
|
val displayValue = "${slider.value.toInt()}$units"
|
||||||
valueDisplay.text = displayValue
|
valueDisplay.text = displayValue
|
||||||
|
|
||||||
slider.addOnChangeListener { _, value, changed ->
|
slider.addOnChangeListener { _, value, chanhed ->
|
||||||
if (changed) {
|
if (chanhed) {
|
||||||
val intValue = value.toInt()
|
val intValue = value.toInt()
|
||||||
when (setting) {
|
when (setting) {
|
||||||
is AbstractShortSetting -> setting.setShort(intValue.toShort())
|
is AbstractShortSetting -> setting.setShort(intValue.toShort())
|
||||||
@@ -226,7 +213,6 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
}
|
}
|
||||||
saveSettings()
|
saveSettings()
|
||||||
valueDisplay.text = "$intValue$units"
|
valueDisplay.text = "$intValue$units"
|
||||||
onValueChanged?.invoke(intValue)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ import org.yuzu.yuzu_emu.utils.GameIconUtils
|
|||||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||||
import org.yuzu.yuzu_emu.utils.InputHandler
|
import org.yuzu.yuzu_emu.utils.InputHandler
|
||||||
import org.yuzu.yuzu_emu.utils.Log
|
import org.yuzu.yuzu_emu.utils.Log
|
||||||
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
|
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
|
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils
|
import org.yuzu.yuzu_emu.utils.ViewUtils
|
||||||
@@ -1158,36 +1157,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
|
|
||||||
quickSettings.addDivider(container)
|
quickSettings.addDivider(container)
|
||||||
|
|
||||||
val frameGenAvailable = LosslessScalingHelper.isInstalled() &&
|
|
||||||
LosslessScalingHelper.isSupportedByGpu()
|
|
||||||
val frameGenEnabled = BooleanSetting.RENDERER_FRAME_GEN.getBoolean()
|
|
||||||
val usesFixedMultiplier =
|
|
||||||
IntSetting.RENDERER_FRAME_GEN_TARGET_RATE.getInt() == 0
|
|
||||||
|
|
||||||
quickSettings.addBooleanSetting(
|
|
||||||
R.string.frame_gen,
|
|
||||||
container,
|
|
||||||
BooleanSetting.RENDERER_FRAME_GEN,
|
|
||||||
isEnabled = frameGenAvailable
|
|
||||||
) {
|
|
||||||
NativeLibrary.applySettings()
|
|
||||||
addQuickSettings()
|
|
||||||
}
|
|
||||||
|
|
||||||
quickSettings.addSliderSetting(
|
|
||||||
R.string.frame_gen_multiplier,
|
|
||||||
container,
|
|
||||||
IntSetting.RENDERER_FRAME_GEN_MULTIPLIER,
|
|
||||||
minValue = 2,
|
|
||||||
maxValue = 4,
|
|
||||||
units = "x",
|
|
||||||
isEnabled = frameGenAvailable && frameGenEnabled && usesFixedMultiplier
|
|
||||||
) {
|
|
||||||
NativeLibrary.applySettings()
|
|
||||||
}
|
|
||||||
|
|
||||||
quickSettings.addDivider(container)
|
|
||||||
|
|
||||||
quickSettings.addIntSetting(
|
quickSettings.addIntSetting(
|
||||||
R.string.renderer_accuracy,
|
R.string.renderer_accuracy,
|
||||||
container,
|
container,
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
#include "jni/emu_window/emu_window.h"
|
#include "jni/emu_window/emu_window.h"
|
||||||
#include "jni/native.h"
|
#include "jni/native.h"
|
||||||
#include "video_core/renderer_base.h"
|
|
||||||
|
|
||||||
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
@@ -126,14 +125,10 @@ float EmuWindow_Android::GetFrameTimeVerifiedHint() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float EmuWindow_Android::GetPresentedFrameMultiplier() {
|
float EmuWindow_Android::GetPresentedFrameMultiplier() {
|
||||||
if (EmulationSession::GetInstance().IsRunning()) {
|
if (!Settings::values.frame_gen.GetValue()) {
|
||||||
const VideoCore::FrameGenConfig config =
|
return 1.0f;
|
||||||
EmulationSession::GetInstance().System().Renderer().Settings().GetFrameGenConfig();
|
|
||||||
return config.enabled ? static_cast<float>(config.multiplier) : 1.0f;
|
|
||||||
}
|
}
|
||||||
return Settings::values.frame_gen.GetValue()
|
return static_cast<float>(std::clamp<u32>(Settings::values.frame_gen_multiplier.GetValue(), 2, 4));
|
||||||
? static_cast<float>(Settings::FrameGenMultiplier())
|
|
||||||
: 1.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float EmuWindow_Android::GetFrameRateHint() const {
|
float EmuWindow_Android::GetFrameRateHint() const {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
|
|
||||||
AudioCore::AudioCore(Core::System& system) {
|
AudioCore::AudioCore(Core::System& system) {
|
||||||
audio_manager.emplace();
|
audio_manager.emplace(system);
|
||||||
CreateSinks();
|
CreateSinks();
|
||||||
// Must be created after the sinks
|
// Must be created after the sinks
|
||||||
adsp.emplace(system, *output_sink);
|
adsp.emplace(system, *output_sink);
|
||||||
|
|||||||
@@ -15,12 +15,12 @@
|
|||||||
|
|
||||||
namespace AudioCore::AudioIn {
|
namespace AudioCore::AudioIn {
|
||||||
|
|
||||||
Manager::Manager(Core::System& system_) : system{system_} {
|
Manager::Manager(Core::System& system) {
|
||||||
std::iota(session_ids.begin(), session_ids.end(), 0);
|
std::iota(session_ids.begin(), session_ids.end(), 0);
|
||||||
num_free_sessions = MaxInSessions;
|
num_free_sessions = MaxInSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Manager::AcquireSessionId(size_t& session_id) {
|
Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) {
|
||||||
if (num_free_sessions == 0) {
|
if (num_free_sessions == 0) {
|
||||||
LOG_ERROR(Service_Audio, "All 4 AudioIn sessions are in use, cannot create any more");
|
LOG_ERROR(Service_Audio, "All 4 AudioIn sessions are in use, cannot create any more");
|
||||||
return Service::Audio::ResultOutOfSessions;
|
return Service::Audio::ResultOutOfSessions;
|
||||||
@@ -31,7 +31,7 @@ Result Manager::AcquireSessionId(size_t& session_id) {
|
|||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::ReleaseSessionId(const size_t session_id) {
|
void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) {
|
||||||
std::scoped_lock l{mutex};
|
std::scoped_lock l{mutex};
|
||||||
LOG_DEBUG(Service_Audio, "Freeing AudioIn session {}", session_id);
|
LOG_DEBUG(Service_Audio, "Freeing AudioIn session {}", session_id);
|
||||||
session_ids[free_session_id] = session_id;
|
session_ids[free_session_id] = session_id;
|
||||||
@@ -41,21 +41,20 @@ void Manager::ReleaseSessionId(const size_t session_id) {
|
|||||||
applet_resource_user_ids[session_id] = 0;
|
applet_resource_user_ids[session_id] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Manager::LinkToManager() {
|
Result Manager::LinkToManager(Core::System& system) {
|
||||||
std::scoped_lock l{mutex};
|
std::scoped_lock l{mutex};
|
||||||
if (!linked_to_manager) {
|
if (!linked_to_manager) {
|
||||||
system.AudioCore().GetAudioManager().SetInManager(std::bind(&Manager::BufferReleaseAndRegister, this));
|
system.AudioCore().GetAudioManager().SetInManager(&Manager::BufferReleaseAndRegister);
|
||||||
linked_to_manager = true;
|
linked_to_manager = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::Start() {
|
void Manager::Start(Core::System& system) {
|
||||||
if (sessions_started) {
|
if (sessions_started) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::scoped_lock l{mutex};
|
std::scoped_lock l{mutex};
|
||||||
for (auto& session : sessions) {
|
for (auto& session : sessions) {
|
||||||
if (session) {
|
if (session) {
|
||||||
@@ -66,21 +65,19 @@ void Manager::Start() {
|
|||||||
sessions_started = true;
|
sessions_started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::BufferReleaseAndRegister() {
|
void Manager::BufferReleaseAndRegister(void *data, Core::System& system) noexcept {
|
||||||
std::scoped_lock l{mutex};
|
Manager* this_ = (Manager*)data;
|
||||||
for (auto& session : sessions) {
|
std::scoped_lock l{this_->mutex};
|
||||||
|
for (auto& session : this_->sessions) {
|
||||||
if (session != nullptr) {
|
if (session != nullptr) {
|
||||||
session->ReleaseAndRegisterBuffers();
|
session->ReleaseAndRegisterBuffers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
|
u32 Manager::GetDeviceNames(Core::System& system, std::span<Renderer::AudioDevice::AudioDeviceName> names, [[maybe_unused]] const bool filter) {
|
||||||
[[maybe_unused]] const bool filter) {
|
|
||||||
std::scoped_lock l{mutex};
|
std::scoped_lock l{mutex};
|
||||||
|
LinkToManager(system);
|
||||||
LinkToManager();
|
|
||||||
|
|
||||||
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
|
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
|
||||||
if (!input_devices.empty() && !names.empty()) {
|
if (!input_devices.empty() && !names.empty()) {
|
||||||
names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
|
names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -30,31 +33,29 @@ public:
|
|||||||
* @param session_id - Output session_id.
|
* @param session_id - Output session_id.
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
*/
|
*/
|
||||||
Result AcquireSessionId(size_t& session_id);
|
Result AcquireSessionId(Core::System& system, size_t& session_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release a session id on close.
|
* Release a session id on close.
|
||||||
*
|
*
|
||||||
* @param session_id - Session id to free.
|
* @param session_id - Session id to free.
|
||||||
*/
|
*/
|
||||||
void ReleaseSessionId(size_t session_id);
|
void ReleaseSessionId(Core::System& system, const size_t session_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link the audio in manager to the main audio manager.
|
* Link the audio in manager to the main audio manager.
|
||||||
*
|
*
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
*/
|
*/
|
||||||
Result LinkToManager();
|
Result LinkToManager(Core::System& system);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the audio in manager.
|
* Start the audio in manager.
|
||||||
*/
|
*/
|
||||||
void Start();
|
void Start(Core::System& system);
|
||||||
|
|
||||||
/**
|
/// @brief Callback function, called by the audio manager when the audio in event is signalled.
|
||||||
* Callback function, called by the audio manager when the audio in event is signalled.
|
static void BufferReleaseAndRegister(void *data, Core::System& system) noexcept;
|
||||||
*/
|
|
||||||
void BufferReleaseAndRegister();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of audio in device names.
|
* Get a list of audio in device names.
|
||||||
@@ -64,10 +65,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @return Number of names written.
|
* @return Number of names written.
|
||||||
*/
|
*/
|
||||||
u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
|
u32 GetDeviceNames(Core::System& system, std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
|
||||||
|
|
||||||
/// Core system
|
|
||||||
Core::System& system;
|
|
||||||
/// Array of session ids
|
/// Array of session ids
|
||||||
std::array<size_t, MaxInSessions> session_ids{};
|
std::array<size_t, MaxInSessions> session_ids{};
|
||||||
/// Array of resource user ids
|
/// Array of resource user ids
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
|
|
||||||
AudioManager::AudioManager() {
|
AudioManager::AudioManager(Core::System& system) {
|
||||||
thread = std::jthread([this](std::stop_token stop_token) {
|
thread = std::jthread([&](std::stop_token stop_token) {
|
||||||
Common::SetCurrentThreadName("AudioManager");
|
Common::SetCurrentThreadName("AudioManager");
|
||||||
std::unique_lock l{events.GetAudioEventLock()};
|
std::unique_lock l{events.GetAudioEventLock()};
|
||||||
events.ClearEvents();
|
events.ClearEvents();
|
||||||
@@ -25,7 +25,7 @@ AudioManager::AudioManager() {
|
|||||||
const auto event_type = Event::Type(i);
|
const auto event_type = Event::Type(i);
|
||||||
if (events.CheckAudioEventSet(event_type) || timed_out) {
|
if (events.CheckAudioEventSet(event_type) || timed_out) {
|
||||||
if (buffer_events[i]) {
|
if (buffer_events[i]) {
|
||||||
buffer_events[i]();
|
buffer_events[i](this, system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
events.SetAudioEvent(event_type, false);
|
events.SetAudioEvent(event_type, false);
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
#include "audio_core/audio_event.h"
|
#include "audio_core/audio_event.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
union Result;
|
union Result;
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
@@ -34,10 +38,9 @@ namespace AudioCore {
|
|||||||
* This is only used by audio in and audio out.
|
* This is only used by audio in and audio out.
|
||||||
*/
|
*/
|
||||||
class AudioManager {
|
class AudioManager {
|
||||||
using BufferEventFunc = std::function<void()>;
|
using BufferEventFunc = void (*)(void *data, Core::System& system) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AudioManager();
|
explicit AudioManager(Core::System& system);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shutdown the audio manager.
|
* Shutdown the audio manager.
|
||||||
|
|||||||
@@ -14,12 +14,12 @@
|
|||||||
|
|
||||||
namespace AudioCore::AudioOut {
|
namespace AudioCore::AudioOut {
|
||||||
|
|
||||||
Manager::Manager(Core::System& system_) : system{system_} {
|
Manager::Manager(Core::System& system) {
|
||||||
std::iota(session_ids.begin(), session_ids.end(), 0);
|
std::iota(session_ids.begin(), session_ids.end(), 0);
|
||||||
num_free_sessions = MaxOutSessions;
|
num_free_sessions = MaxOutSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Manager::AcquireSessionId(size_t& session_id) {
|
Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) {
|
||||||
if (num_free_sessions == 0) {
|
if (num_free_sessions == 0) {
|
||||||
LOG_ERROR(Service_Audio, "All 12 Audio Out sessions are in use, cannot create any more");
|
LOG_ERROR(Service_Audio, "All 12 Audio Out sessions are in use, cannot create any more");
|
||||||
return Service::Audio::ResultOutOfSessions;
|
return Service::Audio::ResultOutOfSessions;
|
||||||
@@ -30,7 +30,7 @@ Result Manager::AcquireSessionId(size_t& session_id) {
|
|||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::ReleaseSessionId(const size_t session_id) {
|
void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) {
|
||||||
std::scoped_lock l{mutex};
|
std::scoped_lock l{mutex};
|
||||||
LOG_DEBUG(Service_Audio, "Freeing AudioOut session {}", session_id);
|
LOG_DEBUG(Service_Audio, "Freeing AudioOut session {}", session_id);
|
||||||
session_ids[free_session_id] = session_id;
|
session_ids[free_session_id] = session_id;
|
||||||
@@ -40,17 +40,17 @@ void Manager::ReleaseSessionId(const size_t session_id) {
|
|||||||
applet_resource_user_ids[session_id] = 0;
|
applet_resource_user_ids[session_id] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Manager::LinkToManager() {
|
Result Manager::LinkToManager(Core::System& system) {
|
||||||
std::scoped_lock l{mutex};
|
std::scoped_lock l{mutex};
|
||||||
if (!linked_to_manager) {
|
if (!linked_to_manager) {
|
||||||
system.AudioCore().GetAudioManager().SetOutManager(std::bind(&Manager::BufferReleaseAndRegister, this));
|
system.AudioCore().GetAudioManager().SetOutManager(&Manager::BufferReleaseAndRegister);
|
||||||
linked_to_manager = true;
|
linked_to_manager = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::Start() {
|
void Manager::Start(Core::System& system) {
|
||||||
if (sessions_started) {
|
if (sessions_started) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -65,19 +65,14 @@ void Manager::Start() {
|
|||||||
sessions_started = true;
|
sessions_started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::BufferReleaseAndRegister() {
|
void Manager::BufferReleaseAndRegister(void *data, Core::System& system) noexcept {
|
||||||
std::scoped_lock l{mutex};
|
Manager* this_ = (Manager*)data;
|
||||||
for (auto& session : sessions) {
|
std::scoped_lock l{this_->mutex};
|
||||||
|
for (auto& session : this_->sessions) {
|
||||||
if (session != nullptr) {
|
if (session != nullptr) {
|
||||||
session->ReleaseAndRegisterBuffers();
|
session->ReleaseAndRegisterBuffers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Manager::GetAudioOutDeviceNames(
|
|
||||||
std::vector<Renderer::AudioDevice::AudioDeviceName>& names) const {
|
|
||||||
names.emplace_back("DeviceOut");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace AudioCore::AudioOut
|
} // namespace AudioCore::AudioOut
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -29,42 +32,32 @@ public:
|
|||||||
* @param session_id - Output session_id.
|
* @param session_id - Output session_id.
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
*/
|
*/
|
||||||
Result AcquireSessionId(size_t& session_id);
|
Result AcquireSessionId(Core::System& system, size_t& session_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release a session id on close.
|
* Release a session id on close.
|
||||||
*
|
*
|
||||||
* @param session_id - Session id to free.
|
* @param session_id - Session id to free.
|
||||||
*/
|
*/
|
||||||
void ReleaseSessionId(size_t session_id);
|
void ReleaseSessionId(Core::System& system, const size_t session_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link this manager to the main audio manager.
|
* Link this manager to the main audio manager.
|
||||||
*
|
*
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
*/
|
*/
|
||||||
Result LinkToManager();
|
Result LinkToManager(Core::System& system);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the audio out manager.
|
* Start the audio out manager.
|
||||||
*/
|
*/
|
||||||
void Start();
|
void Start(Core::System& system);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback function, called by the audio manager when the audio out event is signalled.
|
* Callback function, called by the audio manager when the audio out event is signalled.
|
||||||
*/
|
*/
|
||||||
void BufferReleaseAndRegister();
|
static void BufferReleaseAndRegister(void* data, Core::System& system) noexcept;
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of audio out device names.
|
|
||||||
*
|
|
||||||
* @param names - Output container to write names to.
|
|
||||||
* @return Number of names written.
|
|
||||||
*/
|
|
||||||
u32 GetAudioOutDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names) const;
|
|
||||||
|
|
||||||
/// Core system
|
|
||||||
Core::System& system;
|
|
||||||
/// Array of session ids
|
/// Array of session ids
|
||||||
std::array<size_t, MaxOutSessions> session_ids{};
|
std::array<size_t, MaxOutSessions> session_ids{};
|
||||||
/// Array of resource user ids
|
/// Array of resource user ids
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "audio_core/audio_render_manager.h"
|
#include "audio_core/audio_render_manager.h"
|
||||||
#include "audio_core/common/audio_renderer_parameter.h"
|
#include "audio_core/common/audio_renderer_parameter.h"
|
||||||
|
#include "audio_core/renderer/system_manager.h"
|
||||||
#include "audio_core/common/feature_support.h"
|
#include "audio_core/common/feature_support.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
|
||||||
namespace AudioCore::Renderer {
|
namespace AudioCore::Renderer {
|
||||||
|
|
||||||
Manager::Manager(Core::System& system_)
|
Manager::Manager(Core::System& system_)
|
||||||
: system{system_}, system_manager{std::make_unique<SystemManager>(system)} {
|
: system_manager{std::make_unique<SystemManager>(system_)}
|
||||||
|
{
|
||||||
std::iota(session_ids.begin(), session_ids.end(), 0);
|
std::iota(session_ids.begin(), session_ids.end(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,11 +64,11 @@ u32 Manager::GetSessionCount() const {
|
|||||||
return session_count;
|
return session_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Manager::AddSystem(System& system_) {
|
bool Manager::AddSystem(Renderer::System& system_) {
|
||||||
return system_manager->Add(system_);
|
return system_manager->Add(system_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Manager::RemoveSystem(System& system_) {
|
bool Manager::RemoveSystem(Renderer::System& system_) {
|
||||||
return system_manager->Remove(system_);
|
return system_manager->Remove(system_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -71,7 +74,7 @@ public:
|
|||||||
* @param system - The system to add.
|
* @param system - The system to add.
|
||||||
* @return True if the system was successfully added, otherwise false.
|
* @return True if the system was successfully added, otherwise false.
|
||||||
*/
|
*/
|
||||||
bool AddSystem(System& system);
|
bool AddSystem(Renderer::System& system);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a renderer system from the manager.
|
* Remove a renderer system from the manager.
|
||||||
@@ -79,7 +82,7 @@ public:
|
|||||||
* @param system - The system to remove.
|
* @param system - The system to remove.
|
||||||
* @return True if the system was successfully removed, otherwise false.
|
* @return True if the system was successfully removed, otherwise false.
|
||||||
*/
|
*/
|
||||||
bool RemoveSystem(System& system);
|
bool RemoveSystem(Renderer::System& system);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free a session id when the system wants to shut down.
|
* Free a session id when the system wants to shut down.
|
||||||
@@ -89,8 +92,6 @@ public:
|
|||||||
void ReleaseSessionId(s32 session_id);
|
void ReleaseSessionId(s32 session_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Core system
|
|
||||||
Core::System& system;
|
|
||||||
/// Session ids, -1 when in use
|
/// Session ids, -1 when in use
|
||||||
std::array<s32, MaxRendererSessions> session_ids{};
|
std::array<s32, MaxRendererSessions> session_ids{};
|
||||||
/// Number of active renderers
|
/// Number of active renderers
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -8,42 +11,43 @@
|
|||||||
namespace AudioCore::AudioIn {
|
namespace AudioCore::AudioIn {
|
||||||
|
|
||||||
In::In(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
|
In::In(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
|
||||||
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}, system{system_, event,
|
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}
|
||||||
session_id_} {}
|
, audio_system{system_, event, session_id_}
|
||||||
|
{}
|
||||||
|
|
||||||
void In::Free() {
|
void In::Free(Core::System& system) {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
manager.ReleaseSessionId(system.GetSessionId());
|
manager.ReleaseSessionId(system, audio_system.GetSessionId());
|
||||||
}
|
}
|
||||||
|
|
||||||
System& In::GetSystem() {
|
System& In::GetSystem() {
|
||||||
return system;
|
return audio_system;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioIn::State In::GetState() {
|
AudioIn::State In::GetState() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.GetState();
|
return audio_system.GetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result In::StartSystem() {
|
Result In::StartSystem() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.Start();
|
return audio_system.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void In::StartSession() {
|
void In::StartSession() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
system.StartSession();
|
audio_system.StartSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result In::StopSystem() {
|
Result In::StopSystem() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.Stop();
|
return audio_system.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) {
|
Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
|
|
||||||
if (system.AppendBuffer(buffer, tag)) {
|
if (audio_system.AppendBuffer(buffer, tag)) {
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
return Service::Audio::ResultBufferCountReached;
|
return Service::Audio::ResultBufferCountReached;
|
||||||
@@ -51,20 +55,20 @@ Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) {
|
|||||||
|
|
||||||
void In::ReleaseAndRegisterBuffers() {
|
void In::ReleaseAndRegisterBuffers() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
if (system.GetState() == State::Started) {
|
if (audio_system.GetState() == State::Started) {
|
||||||
system.ReleaseBuffers();
|
audio_system.ReleaseBuffers();
|
||||||
system.RegisterBuffers();
|
audio_system.RegisterBuffers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool In::FlushAudioInBuffers() {
|
bool In::FlushAudioInBuffers() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.FlushAudioInBuffers();
|
return audio_system.FlushAudioInBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 In::GetReleasedBuffers(std::span<u64> tags) {
|
u32 In::GetReleasedBuffers(std::span<u64> tags) {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.GetReleasedBuffers(tags);
|
return audio_system.GetReleasedBuffers(tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KReadableEvent& In::GetBufferEvent() {
|
Kernel::KReadableEvent& In::GetBufferEvent() {
|
||||||
@@ -74,27 +78,27 @@ Kernel::KReadableEvent& In::GetBufferEvent() {
|
|||||||
|
|
||||||
f32 In::GetVolume() const {
|
f32 In::GetVolume() const {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.GetVolume();
|
return audio_system.GetVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void In::SetVolume(f32 volume) {
|
void In::SetVolume(f32 volume) {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
system.SetVolume(volume);
|
audio_system.SetVolume(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool In::ContainsAudioBuffer(u64 tag) const {
|
bool In::ContainsAudioBuffer(u64 tag) const {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.ContainsAudioBuffer(tag);
|
return audio_system.ContainsAudioBuffer(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 In::GetBufferCount() const {
|
u32 In::GetBufferCount() const {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.GetBufferCount();
|
return audio_system.GetBufferCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 In::GetPlayedSampleCount() const {
|
u64 In::GetPlayedSampleCount() const {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.GetPlayedSampleCount();
|
return audio_system.GetPlayedSampleCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace AudioCore::AudioIn
|
} // namespace AudioCore::AudioIn
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -30,7 +33,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Free this audio in from the audio in manager.
|
* Free this audio in from the audio in manager.
|
||||||
*/
|
*/
|
||||||
void Free();
|
void Free(Core::System& system);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get this audio in's system.
|
* Get this audio in's system.
|
||||||
@@ -141,7 +144,7 @@ private:
|
|||||||
/// Buffer event, signalled when buffers are ready to be released
|
/// Buffer event, signalled when buffers are ready to be released
|
||||||
Kernel::KEvent* event;
|
Kernel::KEvent* event;
|
||||||
/// Main audio in system
|
/// Main audio in system
|
||||||
System system;
|
System audio_system;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AudioCore::AudioIn
|
} // namespace AudioCore::AudioIn
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -8,42 +11,43 @@
|
|||||||
namespace AudioCore::AudioOut {
|
namespace AudioCore::AudioOut {
|
||||||
|
|
||||||
Out::Out(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
|
Out::Out(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
|
||||||
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}, system{system_, event,
|
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}
|
||||||
session_id_} {}
|
, audio_system{system_, event, session_id_}
|
||||||
|
{}
|
||||||
|
|
||||||
void Out::Free() {
|
void Out::Free(Core::System& system) {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
manager.ReleaseSessionId(system.GetSessionId());
|
manager.ReleaseSessionId(system, audio_system.GetSessionId());
|
||||||
}
|
}
|
||||||
|
|
||||||
System& Out::GetSystem() {
|
System& Out::GetSystem() {
|
||||||
return system;
|
return audio_system;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioOut::State Out::GetState() {
|
AudioOut::State Out::GetState() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.GetState();
|
return audio_system.GetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Out::StartSystem() {
|
Result Out::StartSystem() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.Start();
|
return audio_system.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Out::StartSession() {
|
void Out::StartSession() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
system.StartSession();
|
audio_system.StartSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Out::StopSystem() {
|
Result Out::StopSystem() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.Stop();
|
return audio_system.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) {
|
Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
|
|
||||||
if (system.AppendBuffer(buffer, tag)) {
|
if (audio_system.AppendBuffer(buffer, tag)) {
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
return Service::Audio::ResultBufferCountReached;
|
return Service::Audio::ResultBufferCountReached;
|
||||||
@@ -51,20 +55,20 @@ Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) {
|
|||||||
|
|
||||||
void Out::ReleaseAndRegisterBuffers() {
|
void Out::ReleaseAndRegisterBuffers() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
if (system.GetState() == State::Started) {
|
if (audio_system.GetState() == State::Started) {
|
||||||
system.ReleaseBuffers();
|
audio_system.ReleaseBuffers();
|
||||||
system.RegisterBuffers();
|
audio_system.RegisterBuffers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Out::FlushAudioOutBuffers() {
|
bool Out::FlushAudioOutBuffers() {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.FlushAudioOutBuffers();
|
return audio_system.FlushAudioOutBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Out::GetReleasedBuffers(std::span<u64> tags) {
|
u32 Out::GetReleasedBuffers(std::span<u64> tags) {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.GetReleasedBuffers(tags);
|
return audio_system.GetReleasedBuffers(tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KReadableEvent& Out::GetBufferEvent() {
|
Kernel::KReadableEvent& Out::GetBufferEvent() {
|
||||||
@@ -74,27 +78,27 @@ Kernel::KReadableEvent& Out::GetBufferEvent() {
|
|||||||
|
|
||||||
f32 Out::GetVolume() const {
|
f32 Out::GetVolume() const {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.GetVolume();
|
return audio_system.GetVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Out::SetVolume(const f32 volume) {
|
void Out::SetVolume(const f32 volume) {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
system.SetVolume(volume);
|
audio_system.SetVolume(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Out::ContainsAudioBuffer(const u64 tag) const {
|
bool Out::ContainsAudioBuffer(const u64 tag) const {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.ContainsAudioBuffer(tag);
|
return audio_system.ContainsAudioBuffer(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Out::GetBufferCount() const {
|
u32 Out::GetBufferCount() const {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.GetBufferCount();
|
return audio_system.GetBufferCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Out::GetPlayedSampleCount() const {
|
u64 Out::GetPlayedSampleCount() const {
|
||||||
std::scoped_lock l{parent_mutex};
|
std::scoped_lock l{parent_mutex};
|
||||||
return system.GetPlayedSampleCount();
|
return audio_system.GetPlayedSampleCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace AudioCore::AudioOut
|
} // namespace AudioCore::AudioOut
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -30,7 +33,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Free this audio out from the audio out manager.
|
* Free this audio out from the audio out manager.
|
||||||
*/
|
*/
|
||||||
void Free();
|
void Free(Core::System& system);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get this audio out's system.
|
* Get this audio out's system.
|
||||||
@@ -141,7 +144,7 @@ private:
|
|||||||
/// Buffer event, signalled when buffers are ready to be released
|
/// Buffer event, signalled when buffers are ready to be released
|
||||||
Kernel::KEvent* event;
|
Kernel::KEvent* event;
|
||||||
/// Main audio out system
|
/// Main audio out system
|
||||||
System system;
|
System audio_system;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AudioCore::AudioOut
|
} // namespace AudioCore::AudioOut
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -13,56 +16,48 @@
|
|||||||
namespace AudioCore::Renderer {
|
namespace AudioCore::Renderer {
|
||||||
|
|
||||||
Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* rendered_event)
|
Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* rendered_event)
|
||||||
: core{system_}, manager{manager_}, system{system_, rendered_event} {}
|
: system{system_}, manager{manager_}
|
||||||
|
, audio_system{system_, rendered_event}
|
||||||
|
{}
|
||||||
|
|
||||||
Result Renderer::Initialize(const AudioRendererParameterInternal& params,
|
Result Renderer::Initialize(const AudioRendererParameterInternal& params, Kernel::KTransferMemory* transfer_memory, const u64 transfer_memory_size, Kernel::KProcess* process_handle, const u64 applet_resource_user_id, const s32 session_id) {
|
||||||
Kernel::KTransferMemory* transfer_memory,
|
|
||||||
const u64 transfer_memory_size, Kernel::KProcess* process_handle,
|
|
||||||
const u64 applet_resource_user_id, const s32 session_id) {
|
|
||||||
if (params.execution_mode == ExecutionMode::Auto) {
|
if (params.execution_mode == ExecutionMode::Auto) {
|
||||||
if (!manager.AddSystem(system)) {
|
if (!manager.AddSystem(audio_system)) {
|
||||||
LOG_ERROR(Service_Audio,
|
LOG_ERROR(Service_Audio, "Both Audio Render sessions are in use, cannot create any more");
|
||||||
"Both Audio Render sessions are in use, cannot create any more");
|
|
||||||
return Service::Audio::ResultOutOfSessions;
|
return Service::Audio::ResultOutOfSessions;
|
||||||
}
|
}
|
||||||
system_registered = true;
|
system_registered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
|
audio_system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, applet_resource_user_id, session_id);
|
||||||
applet_resource_user_id, session_id);
|
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::Finalize() {
|
void Renderer::Finalize() {
|
||||||
auto session_id{system.GetSessionId()};
|
auto const session_id{audio_system.GetSessionId()};
|
||||||
|
audio_system.Finalize();
|
||||||
system.Finalize();
|
|
||||||
|
|
||||||
if (system_registered) {
|
if (system_registered) {
|
||||||
manager.RemoveSystem(system);
|
manager.RemoveSystem(audio_system);
|
||||||
system_registered = false;
|
system_registered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
manager.ReleaseSessionId(session_id);
|
manager.ReleaseSessionId(session_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
System& Renderer::GetSystem() {
|
System& Renderer::GetSystem() {
|
||||||
return system;
|
return audio_system;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::Start() {
|
void Renderer::Start() {
|
||||||
system.Start();
|
audio_system.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::Stop() {
|
void Renderer::Stop() {
|
||||||
system.Stop();
|
audio_system.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Renderer::RequestUpdate(std::span<const u8> input, std::span<u8> performance,
|
Result Renderer::RequestUpdate(std::span<const u8> input, std::span<u8> performance, std::span<u8> output) {
|
||||||
std::span<u8> output) {
|
return audio_system.Update(input, performance, output);
|
||||||
return system.Update(input, performance, output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace AudioCore::Renderer
|
} // namespace AudioCore::Renderer
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -84,7 +87,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
/// System core
|
/// System core
|
||||||
Core::System& core;
|
Core::System& system;
|
||||||
/// Manager this renderer is registered with
|
/// Manager this renderer is registered with
|
||||||
Manager& manager;
|
Manager& manager;
|
||||||
/// Is the audio renderer initialized?
|
/// Is the audio renderer initialized?
|
||||||
@@ -92,7 +95,7 @@ private:
|
|||||||
/// Is the system registered with the manager?
|
/// Is the system registered with the manager?
|
||||||
bool system_registered{};
|
bool system_registered{};
|
||||||
/// Audio render system, main driver of audio rendering
|
/// Audio render system, main driver of audio rendering
|
||||||
System system;
|
System audio_system;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Renderer
|
} // namespace Renderer
|
||||||
|
|||||||
@@ -389,7 +389,7 @@ struct Values {
|
|||||||
true};
|
true};
|
||||||
|
|
||||||
SwitchableSetting<bool> frame_gen{linkage, false, "frame_gen", Category::Renderer,
|
SwitchableSetting<bool> frame_gen{linkage, false, "frame_gen", Category::Renderer,
|
||||||
Specialization::Default, true, true};
|
Specialization::Default, true, false};
|
||||||
|
|
||||||
SwitchableSetting<u32, true> frame_gen_multiplier{linkage,
|
SwitchableSetting<u32, true> frame_gen_multiplier{linkage,
|
||||||
2,
|
2,
|
||||||
@@ -399,7 +399,7 @@ struct Values {
|
|||||||
Category::Renderer,
|
Category::Renderer,
|
||||||
Specialization::Countable,
|
Specialization::Countable,
|
||||||
true,
|
true,
|
||||||
true,
|
false,
|
||||||
&frame_gen};
|
&frame_gen};
|
||||||
|
|
||||||
SwitchableSetting<u32, true> frame_gen_target_rate{linkage,
|
SwitchableSetting<u32, true> frame_gen_target_rate{linkage,
|
||||||
@@ -419,7 +419,7 @@ struct Values {
|
|||||||
Category::Renderer,
|
Category::Renderer,
|
||||||
Specialization::Default,
|
Specialization::Default,
|
||||||
true,
|
true,
|
||||||
true,
|
false,
|
||||||
&frame_gen};
|
&frame_gen};
|
||||||
|
|
||||||
SwitchableSetting<u32, true> frame_gen_flow_scale{linkage,
|
SwitchableSetting<u32, true> frame_gen_flow_scale{linkage,
|
||||||
@@ -442,11 +442,11 @@ struct Values {
|
|||||||
Category::Renderer,
|
Category::Renderer,
|
||||||
Specialization::Countable,
|
Specialization::Countable,
|
||||||
true,
|
true,
|
||||||
true,
|
false,
|
||||||
&frame_gen};
|
&frame_gen};
|
||||||
|
|
||||||
SwitchableSetting<bool> frame_gen_fp16{linkage, true, "frame_gen_fp16", Category::Renderer,
|
SwitchableSetting<bool> frame_gen_fp16{linkage, true, "frame_gen_fp16", Category::Renderer,
|
||||||
Specialization::Default, true, true, &frame_gen};
|
Specialization::Default, true, false, &frame_gen};
|
||||||
|
|
||||||
SwitchableSetting<bool> frame_gen_dump_flow{linkage, false, "frame_gen_dump_flow",
|
SwitchableSetting<bool> frame_gen_dump_flow{linkage, false, "frame_gen_dump_flow",
|
||||||
Category::Renderer};
|
Category::Renderer};
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
IAudioIn::~IAudioIn() {
|
IAudioIn::~IAudioIn() {
|
||||||
impl->Free();
|
impl->Free(system);
|
||||||
service_context.CloseEvent(event);
|
service_context.CloseEvent(event);
|
||||||
process->Close(system.Kernel());
|
process->Close(system.Kernel());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -65,7 +68,7 @@ Result IAudioInManager::OpenAudioInAuto(
|
|||||||
Result IAudioInManager::ListAudioInsAutoFiltered(
|
Result IAudioInManager::ListAudioInsAutoFiltered(
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
|
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
|
||||||
LOG_DEBUG(Service_Audio, "called");
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
*out_count = impl->GetDeviceNames(out_audio_ins, true);
|
*out_count = impl->GetDeviceNames(system, out_audio_ins, true);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,8 +93,8 @@ Result IAudioInManager::OpenAudioInProtocolSpecified(
|
|||||||
|
|
||||||
size_t new_session_id{};
|
size_t new_session_id{};
|
||||||
|
|
||||||
R_TRY(impl->LinkToManager());
|
R_TRY(impl->LinkToManager(system));
|
||||||
R_TRY(impl->AcquireSessionId(new_session_id));
|
R_TRY(impl->AcquireSessionId(system, new_session_id));
|
||||||
|
|
||||||
LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id,
|
LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id,
|
||||||
impl->num_free_sessions);
|
impl->num_free_sessions);
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
IAudioOut::~IAudioOut() {
|
IAudioOut::~IAudioOut() {
|
||||||
impl->Free();
|
impl->Free(system);
|
||||||
service_context.CloseEvent(event);
|
service_context.CloseEvent(event);
|
||||||
process->Close(system.Kernel());
|
process->Close(system.Kernel());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,8 +77,8 @@ Result IAudioOutManager::OpenAudioOutAuto(
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t new_session_id{};
|
size_t new_session_id{};
|
||||||
R_TRY(impl->LinkToManager());
|
R_TRY(impl->LinkToManager(system));
|
||||||
R_TRY(impl->AcquireSessionId(new_session_id));
|
R_TRY(impl->AcquireSessionId(system, new_session_id));
|
||||||
|
|
||||||
const auto device_name = Common::StringFromBuffer(name[0].name);
|
const auto device_name = Common::StringFromBuffer(name[0].name);
|
||||||
LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
|
LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ add_library(video_core STATIC
|
|||||||
engines/puller.h
|
engines/puller.h
|
||||||
framebuffer_config.cpp
|
framebuffer_config.cpp
|
||||||
framebuffer_config.h
|
framebuffer_config.h
|
||||||
frame_gen/frame_gen_config.h
|
|
||||||
fsr.cpp
|
fsr.cpp
|
||||||
fsr.h
|
fsr.h
|
||||||
host1x/codecs/decoder.cpp
|
host1x/codecs/decoder.cpp
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
constexpr u32 MIN_FRAME_GEN_MULTIPLIER = 2;
|
|
||||||
constexpr u32 MAX_FRAME_GEN_MULTIPLIER = 4;
|
|
||||||
|
|
||||||
struct FrameGenConfig {
|
|
||||||
bool enabled{};
|
|
||||||
u32 multiplier{MIN_FRAME_GEN_MULTIPLIER};
|
|
||||||
u32 target_rate{};
|
|
||||||
bool flow_scale_auto{true};
|
|
||||||
u32 flow_scale{75};
|
|
||||||
u32 queue_target{1};
|
|
||||||
bool fp16{true};
|
|
||||||
bool dump_flow{};
|
|
||||||
|
|
||||||
[[nodiscard]] size_t Generations() const {
|
|
||||||
return enabled ? std::clamp(multiplier, MIN_FRAME_GEN_MULTIPLIER,
|
|
||||||
MAX_FRAME_GEN_MULTIPLIER) -
|
|
||||||
1
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] size_t MaxGenerations() const {
|
|
||||||
if (!enabled) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return target_rate != 0 ? MAX_FRAME_GEN_MULTIPLIER - 1 : Generations();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const FrameGenConfig&) const = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/settings.h"
|
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "core/frontend/graphics_context.h"
|
#include "core/frontend/graphics_context.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
@@ -23,16 +22,6 @@ RendererBase::RendererBase(Core::Frontend::EmuWindow& window_,
|
|||||||
RendererBase::~RendererBase() = default;
|
RendererBase::~RendererBase() = default;
|
||||||
|
|
||||||
void RendererBase::RefreshBaseSettings() {
|
void RendererBase::RefreshBaseSettings() {
|
||||||
renderer_settings.SetFrameGenConfig({
|
|
||||||
.enabled = Settings::values.frame_gen.GetValue(),
|
|
||||||
.multiplier = Settings::FrameGenMultiplier(),
|
|
||||||
.target_rate = Settings::values.frame_gen_target_rate.GetValue(),
|
|
||||||
.flow_scale_auto = Settings::values.frame_gen_flow_scale_auto.GetValue(),
|
|
||||||
.flow_scale = Settings::values.frame_gen_flow_scale.GetValue(),
|
|
||||||
.queue_target = Settings::values.frame_gen_queue_target.GetValue(),
|
|
||||||
.fp16 = Settings::values.frame_gen_fp16.GetValue(),
|
|
||||||
.dump_flow = Settings::values.frame_gen_dump_flow.GetValue(),
|
|
||||||
});
|
|
||||||
UpdateCurrentFramebufferLayout();
|
UpdateCurrentFramebufferLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,10 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/frontend/framebuffer_layout.h"
|
#include "core/frontend/framebuffer_layout.h"
|
||||||
#include "video_core/frame_gen/frame_gen_config.h"
|
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
#include "video_core/rasterizer_interface.h"
|
#include "video_core/rasterizer_interface.h"
|
||||||
|
|
||||||
@@ -32,20 +30,6 @@ struct RendererSettings {
|
|||||||
std::function<void(bool)> screenshot_complete_callback;
|
std::function<void(bool)> screenshot_complete_callback;
|
||||||
Layout::FramebufferLayout screenshot_framebuffer_layout;
|
Layout::FramebufferLayout screenshot_framebuffer_layout;
|
||||||
Service::Nvnflinger::LayerStackId screenshot_layer_stack{Service::Nvnflinger::LayerStackId::Default};
|
Service::Nvnflinger::LayerStackId screenshot_layer_stack{Service::Nvnflinger::LayerStackId::Default};
|
||||||
|
|
||||||
void SetFrameGenConfig(FrameGenConfig config) {
|
|
||||||
std::scoped_lock lock{frame_gen_mutex};
|
|
||||||
frame_gen_config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] FrameGenConfig GetFrameGenConfig() const {
|
|
||||||
std::scoped_lock lock{frame_gen_mutex};
|
|
||||||
return frame_gen_config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable std::mutex frame_gen_mutex;
|
|
||||||
FrameGenConfig frame_gen_config;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RendererBase {
|
class RendererBase {
|
||||||
|
|||||||
@@ -23,14 +23,13 @@ constexpr size_t COLOR_CHANNELS = 4;
|
|||||||
constexpr u64 LSFG_REQUIRED_FRAMES = 2;
|
constexpr u64 LSFG_REQUIRED_FRAMES = 2;
|
||||||
constexpr u32 LSFG_RECURRENCE_FRAMES = 2;
|
constexpr u32 LSFG_RECURRENCE_FRAMES = 2;
|
||||||
|
|
||||||
[[nodiscard]] f32 ManualFlowScale(const VideoCore::FrameGenConfig& config) {
|
[[nodiscard]] f32 ManualFlowScale() {
|
||||||
return static_cast<f32>(config.flow_scale) / 100.0f;
|
return static_cast<f32>(Settings::values.frame_gen_flow_scale.GetValue()) / 100.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] f32 ConfiguredFlowScale(const VideoCore::FrameGenConfig& config,
|
[[nodiscard]] f32 ConfiguredFlowScale(VkExtent2D guest_extent, VkExtent2D presented_extent) {
|
||||||
VkExtent2D guest_extent, VkExtent2D presented_extent) {
|
if (!Settings::values.frame_gen_flow_scale_auto.GetValue()) {
|
||||||
if (!config.flow_scale_auto) {
|
return ManualFlowScale();
|
||||||
return ManualFlowScale(config);
|
|
||||||
}
|
}
|
||||||
if (guest_extent.width == 0 || presented_extent.width == 0) {
|
if (guest_extent.width == 0 || presented_extent.width == 0) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
@@ -195,61 +194,15 @@ FrameGen::FrameGen(MemoryAllocator& memory_allocator_, Scheduler& scheduler_)
|
|||||||
|
|
||||||
FrameGen::~FrameGen() = default;
|
FrameGen::~FrameGen() = default;
|
||||||
|
|
||||||
void FrameGen::UpdateConfig(const VideoCore::FrameGenConfig& new_config) {
|
|
||||||
if (!has_config) {
|
|
||||||
config = new_config;
|
|
||||||
has_config = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (config == new_config) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool has_toggled_lsfg = config.enabled != new_config.enabled;
|
|
||||||
const bool precision_changed = config.fp16 != new_config.fp16;
|
|
||||||
const bool enabling = !config.enabled && new_config.enabled;
|
|
||||||
const bool must_reset_pipeline = has_toggled_lsfg || precision_changed;
|
|
||||||
const bool must_reload_shaders = precision_changed || enabling;
|
|
||||||
const bool must_reset_pacer =
|
|
||||||
has_toggled_lsfg || config.multiplier != new_config.multiplier ||
|
|
||||||
config.target_rate != new_config.target_rate;
|
|
||||||
|
|
||||||
if (must_reset_pipeline) {
|
|
||||||
if (chain) {
|
|
||||||
scheduler.Finish();
|
|
||||||
chain.reset();
|
|
||||||
}
|
|
||||||
if (must_reload_shaders) {
|
|
||||||
shaders.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
plan = {};
|
|
||||||
peak_guest_extent = {};
|
|
||||||
built_extent = {};
|
|
||||||
built_format = VK_FORMAT_UNDEFINED;
|
|
||||||
built_flow_scale = 0.0f;
|
|
||||||
frame_count = 0;
|
|
||||||
warm_streak = 0;
|
|
||||||
generated = false;
|
|
||||||
dumped = false;
|
|
||||||
|
|
||||||
// this will pickup the dll again once toggled
|
|
||||||
if (must_reload_shaders) {
|
|
||||||
unavailable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (must_reset_pacer) {
|
|
||||||
pacer.Reset();
|
|
||||||
}
|
|
||||||
config = new_config;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGen::Process(const Device& device, Frame* frame, VkFormat format,
|
void FrameGen::Process(const Device& device, Frame* frame, VkFormat format,
|
||||||
VkExtent2D guest_extent) {
|
VkExtent2D guest_extent) {
|
||||||
generated = false;
|
generated = false;
|
||||||
|
|
||||||
if (unavailable || !config.enabled) {
|
if (unavailable || !Settings::values.frame_gen.GetValue()) {
|
||||||
|
if (chain) {
|
||||||
|
scheduler.Finish();
|
||||||
|
chain.reset();
|
||||||
|
}
|
||||||
warm_streak = 0;
|
warm_streak = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -260,7 +213,7 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!shaders) {
|
if (!shaders) {
|
||||||
shaders.emplace(device, config.fp16);
|
shaders.emplace(device);
|
||||||
if (!shaders->IsValid()) {
|
if (!shaders->IsValid()) {
|
||||||
unavailable = true;
|
unavailable = true;
|
||||||
return;
|
return;
|
||||||
@@ -271,7 +224,7 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format,
|
|||||||
peak_guest_extent.height = std::max(peak_guest_extent.height, guest_extent.height);
|
peak_guest_extent.height = std::max(peak_guest_extent.height, guest_extent.height);
|
||||||
|
|
||||||
const VkExtent2D extent{.width = frame->width, .height = frame->height};
|
const VkExtent2D extent{.width = frame->width, .height = frame->height};
|
||||||
const f32 flow_scale = ConfiguredFlowScale(config, peak_guest_extent, extent);
|
const f32 flow_scale = ConfiguredFlowScale(peak_guest_extent, extent);
|
||||||
if (!chain || built_extent.width != extent.width || built_extent.height != extent.height ||
|
if (!chain || built_extent.width != extent.width || built_extent.height != extent.height ||
|
||||||
built_format != format || built_flow_scale != flow_scale) {
|
built_format != format || built_flow_scale != flow_scale) {
|
||||||
Rebuild(device, extent, format, flow_scale);
|
Rebuild(device, extent, format, flow_scale);
|
||||||
@@ -294,7 +247,7 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const bool dump_requested = generated && config.dump_flow;
|
const bool dump_requested = generated && Settings::values.frame_gen_dump_flow.GetValue();
|
||||||
if (!dump_requested) {
|
if (!dump_requested) {
|
||||||
dumped = false;
|
dumped = false;
|
||||||
} else if (!dumped) {
|
} else if (!dumped) {
|
||||||
@@ -308,7 +261,7 @@ size_t FrameGen::WantedGenerations(size_t capacity) {
|
|||||||
plan = {};
|
plan = {};
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
plan = pacer.Plan(capacity, config);
|
plan = pacer.Plan(capacity);
|
||||||
return plan.generations;
|
return plan.generations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/frame_gen/frame_gen_config.h"
|
|
||||||
#include "video_core/renderer_vulkan/present/frame_gen_pacer.h"
|
#include "video_core/renderer_vulkan/present/frame_gen_pacer.h"
|
||||||
#include "video_core/renderer_vulkan/present/lsfg_chain.h"
|
#include "video_core/renderer_vulkan/present/lsfg_chain.h"
|
||||||
#include "video_core/renderer_vulkan/present/lsfg_shaders.h"
|
#include "video_core/renderer_vulkan/present/lsfg_shaders.h"
|
||||||
@@ -23,8 +22,6 @@ public:
|
|||||||
explicit FrameGen(MemoryAllocator& memory_allocator, Scheduler& scheduler);
|
explicit FrameGen(MemoryAllocator& memory_allocator, Scheduler& scheduler);
|
||||||
~FrameGen();
|
~FrameGen();
|
||||||
|
|
||||||
void UpdateConfig(const VideoCore::FrameGenConfig& new_config);
|
|
||||||
|
|
||||||
void Process(const Device& device, Frame* frame, VkFormat format, VkExtent2D guest_extent);
|
void Process(const Device& device, Frame* frame, VkFormat format, VkExtent2D guest_extent);
|
||||||
|
|
||||||
[[nodiscard]] size_t WantedGenerations(size_t capacity);
|
[[nodiscard]] size_t WantedGenerations(size_t capacity);
|
||||||
@@ -42,7 +39,6 @@ private:
|
|||||||
|
|
||||||
std::optional<LsfgShaders> shaders;
|
std::optional<LsfgShaders> shaders;
|
||||||
std::optional<LsfgChain> chain;
|
std::optional<LsfgChain> chain;
|
||||||
VideoCore::FrameGenConfig config;
|
|
||||||
FrameGenPacer pacer;
|
FrameGenPacer pacer;
|
||||||
FrameGenPlan plan{};
|
FrameGenPlan plan{};
|
||||||
VkExtent2D peak_guest_extent{};
|
VkExtent2D peak_guest_extent{};
|
||||||
@@ -56,7 +52,6 @@ private:
|
|||||||
bool generated{};
|
bool generated{};
|
||||||
bool unavailable{};
|
bool unavailable{};
|
||||||
bool dumped{};
|
bool dumped{};
|
||||||
bool has_config{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "common/settings.h"
|
||||||
#include "video_core/renderer_vulkan/present/frame_gen_pacer.h"
|
#include "video_core/renderer_vulkan/present/frame_gen_pacer.h"
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
@@ -45,8 +46,8 @@ constexpr auto PROBE_STEP_DELAY = std::chrono::milliseconds(250);
|
|||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
FrameGenPlan FrameGenPacer::Plan(size_t capacity, const VideoCore::FrameGenConfig& config) {
|
FrameGenPlan FrameGenPacer::Plan(size_t capacity) {
|
||||||
const size_t ceiling = std::min(capacity, config.MaxGenerations());
|
const size_t ceiling = std::min(capacity, Settings::FrameGenMaxGenerations());
|
||||||
if (ceiling == 0) {
|
if (ceiling == 0) {
|
||||||
Reset();
|
Reset();
|
||||||
return {};
|
return {};
|
||||||
@@ -68,7 +69,7 @@ FrameGenPlan FrameGenPacer::Plan(size_t capacity, const VideoCore::FrameGenConfi
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const f32 target_rate = static_cast<f32>(config.target_rate);
|
const f32 target_rate = static_cast<f32>(Settings::values.frame_gen_target_rate.GetValue());
|
||||||
|
|
||||||
if (smoothed_interval > 0.0f) {
|
if (smoothed_interval > 0.0f) {
|
||||||
f32 burst_threshold = BURST_CADENCE_RATIO / smoothed_interval;
|
f32 burst_threshold = BURST_CADENCE_RATIO / smoothed_interval;
|
||||||
@@ -108,7 +109,7 @@ FrameGenPlan FrameGenPacer::Plan(size_t capacity, const VideoCore::FrameGenConfi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (target_rate == 0.0f) {
|
if (target_rate == 0.0f) {
|
||||||
limit = std::min(config.Generations(), ceiling);
|
limit = std::min(Settings::FrameGenGenerations(), ceiling);
|
||||||
output_credit = 0.0f;
|
output_credit = 0.0f;
|
||||||
issued_generations = limit;
|
issued_generations = limit;
|
||||||
return {.generations = limit, .warm = limit > 0};
|
return {.generations = limit, .warm = limit > 0};
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/frame_gen/frame_gen_config.h"
|
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
@@ -18,7 +17,7 @@ struct FrameGenPlan {
|
|||||||
|
|
||||||
class FrameGenPacer {
|
class FrameGenPacer {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] FrameGenPlan Plan(size_t capacity, const VideoCore::FrameGenConfig& config);
|
[[nodiscard]] FrameGenPlan Plan(size_t capacity);
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "common/settings.h"
|
||||||
#include "video_core/frame_gen/lossless_dll.h"
|
#include "video_core/frame_gen/lossless_dll.h"
|
||||||
#include "video_core/renderer_vulkan/present/lsfg_shaders.h"
|
#include "video_core/renderer_vulkan/present/lsfg_shaders.h"
|
||||||
#include "video_core/renderer_vulkan/present/util.h"
|
#include "video_core/renderer_vulkan/present/util.h"
|
||||||
@@ -8,15 +9,16 @@
|
|||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
LsfgShaders::LsfgShaders(const Device& device, bool prefer_fp16) {
|
LsfgShaders::LsfgShaders(const Device& device) {
|
||||||
if (!device.IsVulkanMemoryModelSupported() || !device.HasNullDescriptor()) {
|
if (!device.IsVulkanMemoryModelSupported() || !device.HasNullDescriptor()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool allow_fp16 = device.IsFloat16Supported();
|
const bool allow_fp16 = device.IsFloat16Supported();
|
||||||
|
const bool prefer_fp16 = allow_fp16 && Settings::values.frame_gen_fp16.GetValue();
|
||||||
|
|
||||||
VideoCore::FrameGen::ShaderModules code;
|
VideoCore::FrameGen::ShaderModules code;
|
||||||
if (VideoCore::FrameGen::LoadShaderModules(code, allow_fp16, allow_fp16 && prefer_fp16) !=
|
if (VideoCore::FrameGen::LoadShaderModules(code, allow_fp16, prefer_fp16) !=
|
||||||
VideoCore::FrameGen::LosslessStatus::Ok) {
|
VideoCore::FrameGen::LosslessStatus::Ok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class Device;
|
|||||||
|
|
||||||
class LsfgShaders {
|
class LsfgShaders {
|
||||||
public:
|
public:
|
||||||
explicit LsfgShaders(const Device& device, bool prefer_fp16);
|
explicit LsfgShaders(const Device& device);
|
||||||
|
|
||||||
[[nodiscard]] bool IsValid() const {
|
[[nodiscard]] bool IsValid() const {
|
||||||
return valid;
|
return valid;
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ try
|
|||||||
, swapchain(*surface,
|
, swapchain(*surface,
|
||||||
device,
|
device,
|
||||||
scheduler,
|
scheduler,
|
||||||
Settings(),
|
|
||||||
render_window.GetFramebufferLayout().width,
|
render_window.GetFramebufferLayout().width,
|
||||||
render_window.GetFramebufferLayout().height)
|
render_window.GetFramebufferLayout().height)
|
||||||
, present_manager(instance,
|
, present_manager(instance,
|
||||||
@@ -153,7 +152,6 @@ try
|
|||||||
device,
|
device,
|
||||||
memory_allocator,
|
memory_allocator,
|
||||||
scheduler,
|
scheduler,
|
||||||
Settings(),
|
|
||||||
swapchain,
|
swapchain,
|
||||||
surface)
|
surface)
|
||||||
, blit_swapchain(device_memory,
|
, blit_swapchain(device_memory,
|
||||||
@@ -208,9 +206,6 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
|
|||||||
}
|
}
|
||||||
|
|
||||||
RenderScreenshot(framebuffers);
|
RenderScreenshot(framebuffers);
|
||||||
#ifdef HAS_LSFG
|
|
||||||
frame_gen.UpdateConfig(Settings().GetFrameGenConfig());
|
|
||||||
#endif
|
|
||||||
Frame* frame = present_manager.GetRenderFrame();
|
Frame* frame = present_manager.GetRenderFrame();
|
||||||
|
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "video_core/renderer_base.h"
|
|
||||||
#ifdef HAS_LSFG
|
#ifdef HAS_LSFG
|
||||||
#include "video_core/renderer_vulkan/present/lsfg_common.h"
|
#include "video_core/renderer_vulkan/present/lsfg_common.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -30,6 +29,9 @@ static_assert(MAX_FRAMES_IN_FLIGHT <= LSFG_MAX_TARGETS);
|
|||||||
|
|
||||||
bool CanStoreToFrame(const vk::PhysicalDevice& physical_device, VkFormat format) {
|
bool CanStoreToFrame(const vk::PhysicalDevice& physical_device, VkFormat format) {
|
||||||
#ifdef HAS_LSFG
|
#ifdef HAS_LSFG
|
||||||
|
if (!Settings::values.frame_gen.GetValue()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const VkFormatProperties props{physical_device.GetFormatProperties(format)};
|
const VkFormatProperties props{physical_device.GetFormatProperties(format)};
|
||||||
return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0;
|
return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0;
|
||||||
#else
|
#else
|
||||||
@@ -118,7 +120,6 @@ PresentManager::PresentManager(const vk::Instance& instance_,
|
|||||||
const Device& device_,
|
const Device& device_,
|
||||||
MemoryAllocator& memory_allocator_,
|
MemoryAllocator& memory_allocator_,
|
||||||
Scheduler& scheduler_,
|
Scheduler& scheduler_,
|
||||||
const VideoCore::RendererSettings& renderer_settings_,
|
|
||||||
Swapchain& swapchain_,
|
Swapchain& swapchain_,
|
||||||
vk::SurfaceKHR& surface_)
|
vk::SurfaceKHR& surface_)
|
||||||
: instance{instance_}
|
: instance{instance_}
|
||||||
@@ -126,14 +127,13 @@ PresentManager::PresentManager(const vk::Instance& instance_,
|
|||||||
, device{device_}
|
, device{device_}
|
||||||
, memory_allocator{memory_allocator_}
|
, memory_allocator{memory_allocator_}
|
||||||
, scheduler{scheduler_}
|
, scheduler{scheduler_}
|
||||||
, renderer_settings{renderer_settings_}
|
|
||||||
, swapchain{swapchain_}
|
, swapchain{swapchain_}
|
||||||
, surface{surface_}
|
, surface{surface_}
|
||||||
, blit_supported{CanBlitToSwapchain(device.GetPhysical(), swapchain.GetImageViewFormat())}
|
, blit_supported{CanBlitToSwapchain(device.GetPhysical(), swapchain.GetImageViewFormat())}
|
||||||
, storage_supported{CanStoreToFrame(device.GetPhysical(), swapchain.GetImageFormat())}
|
, storage_supported{CanStoreToFrame(device.GetPhysical(), swapchain.GetImageFormat())}
|
||||||
, use_present_thread{Settings::values.async_presentation.GetValue()}
|
, use_present_thread{Settings::values.async_presentation.GetValue()}
|
||||||
{
|
{
|
||||||
UpdateSwapchainImageCount();
|
SetImageCount();
|
||||||
|
|
||||||
auto& dld = device.GetLogical();
|
auto& dld = device.GetLogical();
|
||||||
cmdpool = dld.CreateCommandPool({
|
cmdpool = dld.CreateCommandPool({
|
||||||
@@ -143,14 +143,9 @@ PresentManager::PresentManager(const vk::Instance& instance_,
|
|||||||
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||||
.queueFamilyIndex = device.GetGraphicsFamily(),
|
.queueFamilyIndex = device.GetGraphicsFamily(),
|
||||||
});
|
});
|
||||||
#ifdef HAS_LSFG
|
auto cmdbuffers = cmdpool.Allocate(image_count);
|
||||||
constexpr size_t frame_capacity = MAX_FRAMES_IN_FLIGHT;
|
|
||||||
#else
|
|
||||||
const size_t frame_capacity = DesiredFrameCount();
|
|
||||||
#endif
|
|
||||||
auto cmdbuffers = cmdpool.Allocate(frame_capacity);
|
|
||||||
|
|
||||||
frames.resize(frame_capacity);
|
frames.resize(image_count);
|
||||||
for (u32 i = 0; i < frames.size(); i++) {
|
for (u32 i = 0; i < frames.size(); i++) {
|
||||||
Frame& frame = frames[i];
|
Frame& frame = frames[i];
|
||||||
frame.index = i;
|
frame.index = i;
|
||||||
@@ -179,10 +174,7 @@ Frame* PresentManager::GetRenderFrame() {
|
|||||||
|
|
||||||
// Wait for free presentation frames
|
// Wait for free presentation frames
|
||||||
std::unique_lock lock{free_mutex};
|
std::unique_lock lock{free_mutex};
|
||||||
free_cv.wait(lock, [this] {
|
free_cv.wait(lock, [this] { return !free_queue.empty(); });
|
||||||
const size_t outstanding = frames.size() - free_queue.size();
|
|
||||||
return !free_queue.empty() && outstanding < DesiredFrameCount();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Take the frame from the queue
|
// Take the frame from the queue
|
||||||
Frame* frame = free_queue.front();
|
Frame* frame = free_queue.front();
|
||||||
@@ -210,8 +202,7 @@ void PresentManager::Present(Frame* frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t PresentManager::MaxExtraFrames() const {
|
size_t PresentManager::MaxExtraFrames() const {
|
||||||
const size_t frame_count = DesiredFrameCount();
|
return image_count - 1;
|
||||||
return frame_count > 0 ? frame_count - 1 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format,
|
void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format,
|
||||||
@@ -360,30 +351,22 @@ void PresentManager::PresentThread(std::stop_token token) {
|
|||||||
|
|
||||||
void PresentManager::RecreateSwapchain(Frame* frame) {
|
void PresentManager::RecreateSwapchain(Frame* frame) {
|
||||||
swapchain.Create(*surface, frame->width, frame->height); // Pass raw pointer
|
swapchain.Create(*surface, frame->width, frame->height); // Pass raw pointer
|
||||||
UpdateSwapchainImageCount();
|
SetImageCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresentManager::UpdateSwapchainImageCount() {
|
void PresentManager::SetImageCount() {
|
||||||
swapchain_image_count.store(
|
|
||||||
std::min<size_t>(swapchain.GetImageCount(), MAX_FRAMES_IN_FLIGHT),
|
|
||||||
std::memory_order_release);
|
|
||||||
free_cv.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t PresentManager::DesiredFrameCount() const {
|
|
||||||
// We cannot have more than 7 images in flight at any given time.
|
// We cannot have more than 7 images in flight at any given time.
|
||||||
// FRAMES_IN_FLIGHT is 8, and the cache TICKS_TO_DESTROY is 8.
|
// FRAMES_IN_FLIGHT is 8, and the cache TICKS_TO_DESTROY is 8.
|
||||||
// Mali drivers will give us 6.
|
// Mali drivers will give us 6.
|
||||||
const size_t minimum = swapchain_image_count.load(std::memory_order_acquire);
|
|
||||||
#ifdef HAS_LSFG
|
#ifdef HAS_LSFG
|
||||||
const VideoCore::FrameGenConfig config = renderer_settings.GetFrameGenConfig();
|
const size_t generations = Settings::FrameGenMaxGenerations();
|
||||||
if (config.enabled) {
|
const size_t queued_composites = Settings::values.frame_gen_queue_target.GetValue() + 1;
|
||||||
const size_t queued_composites = std::clamp<size_t>(config.queue_target, 0, 2) + 1;
|
image_count =
|
||||||
return std::clamp<size_t>((config.MaxGenerations() + 1) * queued_composites, minimum,
|
std::clamp<size_t>((generations + 1) * queued_composites, swapchain.GetImageCount(),
|
||||||
MAX_FRAMES_IN_FLIGHT);
|
MAX_FRAMES_IN_FLIGHT);
|
||||||
}
|
#else
|
||||||
|
image_count = std::min<size_t>(swapchain.GetImageCount(), MAX_FRAMES_IN_FLIGHT);
|
||||||
#endif
|
#endif
|
||||||
return minimum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresentManager::CopyToSwapchain(Frame* frame) {
|
void PresentManager::CopyToSwapchain(Frame* frame) {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <boost/container/deque.hpp>
|
#include <boost/container/deque.hpp>
|
||||||
@@ -20,10 +19,6 @@ namespace Core::Frontend {
|
|||||||
class EmuWindow;
|
class EmuWindow;
|
||||||
} // namespace Core::Frontend
|
} // namespace Core::Frontend
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
struct RendererSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
class Device;
|
class Device;
|
||||||
@@ -50,7 +45,6 @@ public:
|
|||||||
const Device& device,
|
const Device& device,
|
||||||
MemoryAllocator& memory_allocator,
|
MemoryAllocator& memory_allocator,
|
||||||
Scheduler& scheduler,
|
Scheduler& scheduler,
|
||||||
const VideoCore::RendererSettings& renderer_settings,
|
|
||||||
Swapchain& swapchain,
|
Swapchain& swapchain,
|
||||||
vk::SurfaceKHR& surface);
|
vk::SurfaceKHR& surface);
|
||||||
~PresentManager();
|
~PresentManager();
|
||||||
@@ -80,9 +74,7 @@ private:
|
|||||||
|
|
||||||
void RecreateSwapchain(Frame* frame);
|
void RecreateSwapchain(Frame* frame);
|
||||||
|
|
||||||
void UpdateSwapchainImageCount();
|
void SetImageCount();
|
||||||
|
|
||||||
[[nodiscard]] size_t DesiredFrameCount() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const vk::Instance& instance;
|
const vk::Instance& instance;
|
||||||
@@ -90,7 +82,6 @@ private:
|
|||||||
const Device& device;
|
const Device& device;
|
||||||
MemoryAllocator& memory_allocator;
|
MemoryAllocator& memory_allocator;
|
||||||
Scheduler& scheduler;
|
Scheduler& scheduler;
|
||||||
const VideoCore::RendererSettings& renderer_settings;
|
|
||||||
Swapchain& swapchain;
|
Swapchain& swapchain;
|
||||||
vk::SurfaceKHR& surface;
|
vk::SurfaceKHR& surface;
|
||||||
vk::CommandPool cmdpool;
|
vk::CommandPool cmdpool;
|
||||||
@@ -106,7 +97,7 @@ private:
|
|||||||
bool blit_supported;
|
bool blit_supported;
|
||||||
bool storage_supported;
|
bool storage_supported;
|
||||||
bool use_present_thread;
|
bool use_present_thread;
|
||||||
std::atomic_size_t swapchain_image_count{};
|
std::size_t image_count{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/settings_enums.h"
|
#include "common/settings_enums.h"
|
||||||
#include "video_core/renderer_base.h"
|
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
#include "video_core/renderer_vulkan/vk_swapchain.h"
|
#include "video_core/renderer_vulkan/vk_swapchain.h"
|
||||||
#include "video_core/vulkan_common/vk_enum_string_helper.h"
|
#include "video_core/vulkan_common/vk_enum_string_helper.h"
|
||||||
@@ -43,13 +42,13 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
|
static VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
|
||||||
bool has_fifo_relaxed, bool frame_gen_enabled) {
|
bool has_fifo_relaxed) {
|
||||||
// Mailbox doesn't lock the application like FIFO (vsync)
|
// Mailbox doesn't lock the application like FIFO (vsync)
|
||||||
// FIFO present mode locks the framerate to the monitor's refresh rate
|
// FIFO present mode locks the framerate to the monitor's refresh rate
|
||||||
Settings::VSyncMode setting = [has_imm, has_mailbox, frame_gen_enabled]() {
|
Settings::VSyncMode setting = [has_imm, has_mailbox]() {
|
||||||
// Choose Mailbox or Immediate if unlocked and those modes are supported
|
// Choose Mailbox or Immediate if unlocked and those modes are supported
|
||||||
const auto mode = Settings::values.vsync_mode.GetValue();
|
const auto mode = Settings::values.vsync_mode.GetValue();
|
||||||
if (frame_gen_enabled) {
|
if (Settings::values.frame_gen.GetValue()) {
|
||||||
return mode == Settings::VSyncMode::FifoRelaxed ? mode : Settings::VSyncMode::Fifo;
|
return mode == Settings::VSyncMode::FifoRelaxed ? mode : Settings::VSyncMode::Fifo;
|
||||||
}
|
}
|
||||||
if (Settings::values.use_speed_limit.GetValue() &&
|
if (Settings::values.use_speed_limit.GetValue() &&
|
||||||
@@ -122,13 +121,11 @@ Swapchain::Swapchain(
|
|||||||
VkSurfaceKHR_T* surface_,
|
VkSurfaceKHR_T* surface_,
|
||||||
const Device& device_,
|
const Device& device_,
|
||||||
Scheduler& scheduler_,
|
Scheduler& scheduler_,
|
||||||
const VideoCore::RendererSettings& renderer_settings_,
|
|
||||||
u32 width_,
|
u32 width_,
|
||||||
u32 height_)
|
u32 height_)
|
||||||
: surface(surface_)
|
: surface(surface_)
|
||||||
, device{device_}
|
, device{device_}
|
||||||
, scheduler{scheduler_}
|
, scheduler{scheduler_}
|
||||||
, renderer_settings{renderer_settings_}
|
|
||||||
{
|
{
|
||||||
Create(surface, width_, height_);
|
Create(surface, width_, height_);
|
||||||
}
|
}
|
||||||
@@ -266,8 +263,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
|
|||||||
|
|
||||||
const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)};
|
const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)};
|
||||||
surface_format = ChooseSwapSurfaceFormat(formats);
|
surface_format = ChooseSwapSurfaceFormat(formats);
|
||||||
present_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed,
|
present_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed);
|
||||||
renderer_settings.GetFrameGenConfig().enabled);
|
|
||||||
|
|
||||||
u32 requested_image_count{capabilities.minImageCount + 1};
|
u32 requested_image_count{capabilities.minImageCount + 1};
|
||||||
// Ensure Triple buffering if possible.
|
// Ensure Triple buffering if possible.
|
||||||
@@ -370,9 +366,7 @@ void Swapchain::Destroy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Swapchain::NeedsPresentModeUpdate() const {
|
bool Swapchain::NeedsPresentModeUpdate() const {
|
||||||
const auto requested_mode = ChooseSwapPresentMode(
|
const auto requested_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed);
|
||||||
has_imm, has_mailbox, has_fifo_relaxed,
|
|
||||||
renderer_settings.GetFrameGenConfig().enabled);
|
|
||||||
return present_mode != requested_mode;
|
return present_mode != requested_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ namespace Layout {
|
|||||||
struct FramebufferLayout;
|
struct FramebufferLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
struct RendererSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
class Device;
|
class Device;
|
||||||
@@ -30,7 +26,6 @@ public:
|
|||||||
VkSurfaceKHR_T* surface,
|
VkSurfaceKHR_T* surface,
|
||||||
const Device& device,
|
const Device& device,
|
||||||
Scheduler& scheduler,
|
Scheduler& scheduler,
|
||||||
const VideoCore::RendererSettings& renderer_settings,
|
|
||||||
u32 width,
|
u32 width,
|
||||||
u32 height);
|
u32 height);
|
||||||
~Swapchain();
|
~Swapchain();
|
||||||
@@ -127,7 +122,6 @@ private:
|
|||||||
|
|
||||||
const Device& device;
|
const Device& device;
|
||||||
Scheduler& scheduler;
|
Scheduler& scheduler;
|
||||||
const VideoCore::RendererSettings& renderer_settings;
|
|
||||||
|
|
||||||
vk::SwapchainKHR swapchain;
|
vk::SwapchainKHR swapchain;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user