Compare commits

..

2 commits

Author SHA1 Message Date
bcac8e1abe Fix headers 2025-10-09 21:37:17 +02:00
78586272a5 revert 8078990b9b
revert [vk] Fast UBO: fix tracking, resize heuristics, add debug guard (#2695)

Well, stuff showed up after testing phase, that showed us this change break SMO and some mods after being merged directly into master, we will keep stuying why happens this and add a better handling later.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: #2695
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-09 20:00:09 +02:00
38 changed files with 156 additions and 883 deletions

View file

@ -16,7 +16,7 @@
#include <ranges> #include <ranges>
namespace AudioCore { namespace AudioCore {
constexpr u32 CurrentRevision = 15; constexpr u32 CurrentRevision = 16;
enum class SupportTags { enum class SupportTags {
CommandProcessingTimeEstimatorVersion4, CommandProcessingTimeEstimatorVersion4,
@ -47,10 +47,6 @@ enum class SupportTags {
DelayChannelMappingChange, DelayChannelMappingChange,
ReverbChannelMappingChange, ReverbChannelMappingChange,
I3dl2ReverbChannelMappingChange, I3dl2ReverbChannelMappingChange,
SplitterPrevVolumeReset,
SplitterBiquadFilterParameter,
SplitterDestinationV2b,
VoiceInParameterV2,
// Not a real tag, just here to get the count. // Not a real tag, just here to get the count.
Size Size
@ -95,10 +91,6 @@ constexpr bool CheckFeatureSupported(SupportTags tag, u32 user_revision) {
{SupportTags::DelayChannelMappingChange, 11}, {SupportTags::DelayChannelMappingChange, 11},
{SupportTags::ReverbChannelMappingChange, 11}, {SupportTags::ReverbChannelMappingChange, 11},
{SupportTags::I3dl2ReverbChannelMappingChange, 11}, {SupportTags::I3dl2ReverbChannelMappingChange, 11},
{SupportTags::SplitterBiquadFilterParameter, 12},
{SupportTags::SplitterPrevVolumeReset, 13},
{SupportTags::SplitterDestinationV2b, 15},
{SupportTags::VoiceInParameterV2, 15},
}}; }};
const auto& feature = const auto& feature =

View file

@ -193,20 +193,4 @@ bool BehaviorInfo::IsI3dl2ReverbChannelMappingChanged() const {
return CheckFeatureSupported(SupportTags::I3dl2ReverbChannelMappingChange, user_revision); return CheckFeatureSupported(SupportTags::I3dl2ReverbChannelMappingChange, user_revision);
} }
bool BehaviorInfo::IsSplitterPrevVolumeResetSupported() const {
return CheckFeatureSupported(SupportTags::SplitterPrevVolumeReset, user_revision);
}
bool BehaviorInfo::IsSplitterDestinationV2bSupported() const {
return CheckFeatureSupported(SupportTags::SplitterDestinationV2b, user_revision);
}
bool BehaviorInfo::IsVoiceInParameterV2Supported() const {
return CheckFeatureSupported(SupportTags::VoiceInParameterV2, user_revision);
}
bool BehaviorInfo::IsBiquadFilterParameterForSplitterEnabled() const {
return CheckFeatureSupported(SupportTags::SplitterBiquadFilterParameter, user_revision);
}
} // namespace AudioCore::Renderer } // namespace AudioCore::Renderer

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -364,38 +361,6 @@ public:
*/ */
bool IsI3dl2ReverbChannelMappingChanged() const; bool IsI3dl2ReverbChannelMappingChanged() const;
/**
* Check if explicit previous mix volume reset is supported for splitters.
* This allows splitters to explicitly reset their previous mix volumes instead of
* doing so implicitly on first use.
*
* @return True if supported, otherwise false.
*/
bool IsSplitterPrevVolumeResetSupported() const;
/**
* Check if splitter destination v2b parameter format is supported (revision 15+).
* This uses the extended parameter format with biquad filter fields.
*
* @return True if supported, otherwise false.
*/
bool IsSplitterDestinationV2bSupported() const;
/**
* Check if voice input parameter v2 format is supported (revision 15+).
* This uses the extended parameter format with float biquad filters.
*
* @return True if supported, otherwise false.
*/
bool IsVoiceInParameterV2Supported() const;
/**
* Check if splitter destinations can carry biquad filter parameters (revision 12+).
*
* @return True if supported, otherwise false.
*/
bool IsBiquadFilterParameterForSplitterEnabled() const;
/// Host version /// Host version
u32 process_revision; u32 process_revision;
/// User version /// User version

View file

@ -64,6 +64,8 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context,
const PoolMapper pool_mapper(process_handle, memory_pools, memory_pool_count, const PoolMapper pool_mapper(process_handle, memory_pools, memory_pool_count,
behaviour.IsMemoryForceMappingEnabled()); behaviour.IsMemoryForceMappingEnabled());
const auto voice_count{voice_context.GetCount()}; const auto voice_count{voice_context.GetCount()};
std::span<const VoiceInfo::InParameter> in_params{
reinterpret_cast<const VoiceInfo::InParameter*>(input), voice_count};
std::span<VoiceInfo::OutStatus> out_params{reinterpret_cast<VoiceInfo::OutStatus*>(output), std::span<VoiceInfo::OutStatus> out_params{reinterpret_cast<VoiceInfo::OutStatus*>(output),
voice_count}; voice_count};
@ -74,104 +76,8 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context,
u32 new_voice_count{0}; u32 new_voice_count{0};
// Two input formats exist: legacy (0x170) and v2 with float biquad (0x188).
const bool use_v2 = behaviour.IsVoiceInParameterV2Supported();
const u32 in_stride = use_v2 ? 0x188u : static_cast<u32>(sizeof(VoiceInfo::InParameter));
for (u32 i = 0; i < voice_count; i++) { for (u32 i = 0; i < voice_count; i++) {
VoiceInfo::InParameter local_in{}; const auto& in_param{in_params[i]};
std::array<VoiceInfo::BiquadFilterParameter2, MaxBiquadFilters> float_biquads{};
if (!use_v2) {
const auto* in_param_ptr = reinterpret_cast<const VoiceInfo::InParameter*>(
input + i * sizeof(VoiceInfo::InParameter));
local_in = *in_param_ptr;
} else {
struct VoiceInParameterV2 {
u32 id;
u32 node_id;
bool is_new;
bool in_use;
PlayState play_state;
SampleFormat sample_format;
u32 sample_rate;
u32 priority;
u32 sort_order;
u32 channel_count;
f32 pitch;
f32 volume;
// Two BiquadFilterParameter2 (0x18 each) -> ignored/converted
struct BiquadV2 {
bool enable;
u8 r1;
u8 r2;
u8 r3;
std::array<f32, 3> b;
std::array<f32, 2> a;
} biquads[2];
u32 wave_buffer_count;
u32 wave_buffer_index;
u32 reserved1;
u64 src_data_address;
u64 src_data_size;
s32 mix_id;
u32 splitter_id;
std::array<VoiceInfo::WaveBufferInternal, MaxWaveBuffers> wavebuffers;
std::array<u32, MaxChannels> channel_resource_ids;
bool clear_voice_drop;
u8 flush_wave_buffer_count;
u16 reserved2;
VoiceInfo::Flags flags;
SrcQuality src_quality;
u32 external_ctx;
u32 external_ctx_size;
u32 reserved3[2];
};
const auto* vin = reinterpret_cast<const VoiceInParameterV2*>(input + i * in_stride);
local_in.id = vin->id;
local_in.node_id = vin->node_id;
local_in.is_new = vin->is_new;
local_in.in_use = vin->in_use;
local_in.play_state = vin->play_state;
local_in.sample_format = vin->sample_format;
local_in.sample_rate = vin->sample_rate;
local_in.priority = static_cast<s32>(vin->priority);
local_in.sort_order = static_cast<s32>(vin->sort_order);
local_in.channel_count = vin->channel_count;
local_in.pitch = vin->pitch;
local_in.volume = vin->volume;
// For REV15+, we keep float coefficients separate and only convert for compatibility
for (size_t filter_idx = 0; filter_idx < MaxBiquadFilters; filter_idx++) {
const auto& src = vin->biquads[filter_idx];
auto& dst = local_in.biquads[filter_idx];
dst.enabled = src.enable;
// Convert float coefficients to fixed-point Q2.14 for legacy path
dst.b[0] = static_cast<s16>(std::clamp(src.b[0] * 16384.0f, -32768.0f, 32767.0f));
dst.b[1] = static_cast<s16>(std::clamp(src.b[1] * 16384.0f, -32768.0f, 32767.0f));
dst.b[2] = static_cast<s16>(std::clamp(src.b[2] * 16384.0f, -32768.0f, 32767.0f));
dst.a[0] = static_cast<s16>(std::clamp(src.a[0] * 16384.0f, -32768.0f, 32767.0f));
dst.a[1] = static_cast<s16>(std::clamp(src.a[1] * 16384.0f, -32768.0f, 32767.0f));
// Also store the native float version
float_biquads[filter_idx].enabled = src.enable;
float_biquads[filter_idx].numerator = src.b;
float_biquads[filter_idx].denominator = src.a;
}
local_in.wave_buffer_count = vin->wave_buffer_count;
local_in.wave_buffer_index = static_cast<u16>(vin->wave_buffer_index);
local_in.src_data_address = static_cast<CpuAddr>(vin->src_data_address);
local_in.src_data_size = vin->src_data_size;
local_in.mix_id = static_cast<u32>(vin->mix_id);
local_in.splitter_id = vin->splitter_id;
local_in.wave_buffer_internal = vin->wavebuffers;
local_in.channel_resource_ids = vin->channel_resource_ids;
local_in.clear_voice_drop = vin->clear_voice_drop;
local_in.flush_buffer_count = vin->flush_wave_buffer_count;
local_in.flags = vin->flags;
local_in.src_quality = vin->src_quality;
}
const auto& in_param = local_in;
std::array<VoiceState*, MaxChannels> voice_states{}; std::array<VoiceState*, MaxChannels> voice_states{};
if (!in_param.in_use) { if (!in_param.in_use) {
@ -195,14 +101,6 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context,
BehaviorInfo::ErrorInfo update_error{}; BehaviorInfo::ErrorInfo update_error{};
voice_info.UpdateParameters(update_error, in_param, pool_mapper, behaviour); voice_info.UpdateParameters(update_error, in_param, pool_mapper, behaviour);
// For REV15+, store the native float biquad coefficients
if (use_v2) {
voice_info.use_float_biquads = true;
voice_info.biquads_float = float_biquads;
} else {
voice_info.use_float_biquads = false;
}
if (!update_error.error_code.IsSuccess()) { if (!update_error.error_code.IsSuccess()) {
behaviour.AppendError(update_error); behaviour.AppendError(update_error);
} }
@ -223,7 +121,7 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context,
new_voice_count += in_param.channel_count; new_voice_count += in_param.channel_count;
} }
auto consumed_input_size{voice_count * in_stride}; auto consumed_input_size{voice_count * static_cast<u32>(sizeof(VoiceInfo::InParameter))};
auto consumed_output_size{voice_count * static_cast<u32>(sizeof(VoiceInfo::OutStatus))}; auto consumed_output_size{voice_count * static_cast<u32>(sizeof(VoiceInfo::OutStatus))};
if (consumed_input_size != in_header->voices_size) { if (consumed_input_size != in_header->voices_size) {
LOG_ERROR(Service_Audio, "Consumed an incorrect voices size, header size={}, consumed={}", LOG_ERROR(Service_Audio, "Consumed an incorrect voices size, header size={}, consumed={}",
@ -359,31 +257,18 @@ Result InfoUpdater::UpdateMixes(MixContext& mix_context, const u32 mix_buffer_co
EffectContext& effect_context, SplitterContext& splitter_context) { EffectContext& effect_context, SplitterContext& splitter_context) {
s32 mix_count{0}; s32 mix_count{0};
u32 consumed_input_size{0}; u32 consumed_input_size{0};
u32 input_mix_size{0};
if (behaviour.IsMixInParameterDirtyOnlyUpdateSupported()) { if (behaviour.IsMixInParameterDirtyOnlyUpdateSupported()) {
auto in_dirty_params{reinterpret_cast<const MixInfo::InDirtyParameter*>(input)}; auto in_dirty_params{reinterpret_cast<const MixInfo::InDirtyParameter*>(input)};
mix_count = in_dirty_params->count; mix_count = in_dirty_params->count;
// Validate against expected header size to ensure structure is correct
if (mix_count < 0 || mix_count > 0x100) {
LOG_ERROR(
Service_Audio,
"Invalid mix count from dirty parameter: count={}, magic=0x{:X}, expected_size={}",
mix_count, in_dirty_params->magic, in_header->mix_size);
return Service::Audio::ResultInvalidUpdateInfo;
}
consumed_input_size += static_cast<u32>(sizeof(MixInfo::InDirtyParameter));
input += sizeof(MixInfo::InDirtyParameter); input += sizeof(MixInfo::InDirtyParameter);
consumed_input_size = static_cast<u32>(sizeof(MixInfo::InDirtyParameter) +
mix_count * sizeof(MixInfo::InParameter));
} else { } else {
mix_count = mix_context.GetCount(); mix_count = mix_context.GetCount();
consumed_input_size = static_cast<u32>(mix_count * sizeof(MixInfo::InParameter));
} }
input_mix_size = static_cast<u32>(mix_count * sizeof(MixInfo::InParameter));
consumed_input_size += input_mix_size;
if (mix_buffer_count == 0) { if (mix_buffer_count == 0) {
return Service::Audio::ResultInvalidUpdateInfo; return Service::Audio::ResultInvalidUpdateInfo;
} }

View file

@ -237,13 +237,6 @@ void CommandBuffer::GenerateBiquadFilterCommand(const s32 node_id, VoiceInfo& vo
cmd.biquad = voice_info.biquads[biquad_index]; cmd.biquad = voice_info.biquads[biquad_index];
if (voice_info.use_float_biquads) {
cmd.biquad_float = voice_info.biquads_float[biquad_index];
cmd.use_float_coefficients = true;
} else {
cmd.use_float_coefficients = false;
}
cmd.state = memory_pool->Translate(CpuAddr(voice_state.biquad_states[biquad_index].data()), cmd.state = memory_pool->Translate(CpuAddr(voice_state.biquad_states[biquad_index].data()),
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState)); MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
@ -270,9 +263,6 @@ void CommandBuffer::GenerateBiquadFilterCommand(const s32 node_id, EffectInfoBas
cmd.biquad.b = parameter.b; cmd.biquad.b = parameter.b;
cmd.biquad.a = parameter.a; cmd.biquad.a = parameter.a;
// Effects use legacy fixed-point format
cmd.use_float_coefficients = false;
cmd.state = memory_pool->Translate(CpuAddr(state), cmd.state = memory_pool->Translate(CpuAddr(state),
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState)); MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
@ -668,13 +658,6 @@ void CommandBuffer::GenerateMultitapBiquadFilterCommand(const s32 node_id, Voice
cmd.output = buffer_count + channel; cmd.output = buffer_count + channel;
cmd.biquads = voice_info.biquads; cmd.biquads = voice_info.biquads;
if (voice_info.use_float_biquads) {
cmd.biquads_float = voice_info.biquads_float;
cmd.use_float_coefficients = true;
} else {
cmd.use_float_coefficients = false;
}
cmd.states[0] = cmd.states[0] =
memory_pool->Translate(CpuAddr(voice_state.biquad_states[0].data()), memory_pool->Translate(CpuAddr(voice_state.biquad_states[0].data()),
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState)); MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));

View file

@ -51,40 +51,6 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
state.s3 = Common::BitCast<s64>(s[3]); state.s3 = Common::BitCast<s64>(s[3]);
} }
/**
* Biquad filter float implementation with native float coefficients.
*/
void ApplyBiquadFilterFloat2(std::span<s32> output, std::span<const s32> input,
std::array<f32, 3>& b, std::array<f32, 2>& a,
VoiceState::BiquadFilterState& state, const u32 sample_count) {
constexpr f64 min{std::numeric_limits<s32>::min()};
constexpr f64 max{std::numeric_limits<s32>::max()};
std::array<f64, 3> b_double{static_cast<f64>(b[0]), static_cast<f64>(b[1]),
static_cast<f64>(b[2])};
std::array<f64, 2> a_double{static_cast<f64>(a[0]), static_cast<f64>(a[1])};
std::array<f64, 4> s{Common::BitCast<f64>(state.s0), Common::BitCast<f64>(state.s1),
Common::BitCast<f64>(state.s2), Common::BitCast<f64>(state.s3)};
for (u32 i = 0; i < sample_count; i++) {
f64 in_sample{static_cast<f64>(input[i])};
auto sample{in_sample * b_double[0] + s[0] * b_double[1] + s[1] * b_double[2] +
s[2] * a_double[0] + s[3] * a_double[1]};
output[i] = static_cast<s32>(std::clamp(sample, min, max));
s[1] = s[0];
s[0] = in_sample;
s[3] = s[2];
s[2] = sample;
}
state.s0 = Common::BitCast<s64>(s[0]);
state.s1 = Common::BitCast<s64>(s[1]);
state.s2 = Common::BitCast<s64>(s[2]);
state.s3 = Common::BitCast<s64>(s[3]);
}
/** /**
* Biquad filter s32 implementation. * Biquad filter s32 implementation.
* *
@ -132,14 +98,8 @@ void BiquadFilterCommand::Process(const AudioRenderer::CommandListProcessor& pro
processor.mix_buffers.subspan(output * processor.sample_count, processor.sample_count)}; processor.mix_buffers.subspan(output * processor.sample_count, processor.sample_count)};
if (use_float_processing) { if (use_float_processing) {
// REV15+: Use native float coefficients if available
if (use_float_coefficients) {
ApplyBiquadFilterFloat2(output_buffer, input_buffer, biquad_float.numerator,
biquad_float.denominator, *state_, processor.sample_count);
} else {
ApplyBiquadFilterFloat(output_buffer, input_buffer, biquad.b, biquad.a, *state_, ApplyBiquadFilterFloat(output_buffer, input_buffer, biquad.b, biquad.a, *state_,
processor.sample_count); processor.sample_count);
}
} else { } else {
ApplyBiquadFilterInt(output_buffer, input_buffer, biquad.b, biquad.a, *state_, ApplyBiquadFilterInt(output_buffer, input_buffer, biquad.b, biquad.a, *state_,
processor.sample_count); processor.sample_count);

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -53,16 +50,12 @@ struct BiquadFilterCommand : ICommand {
s16 output; s16 output;
/// Input parameters for biquad /// Input parameters for biquad
VoiceInfo::BiquadFilterParameter biquad; VoiceInfo::BiquadFilterParameter biquad;
/// Input parameters for biquad (REV15+ native float)
VoiceInfo::BiquadFilterParameter2 biquad_float;
/// Biquad state, updated each call /// Biquad state, updated each call
CpuAddr state; CpuAddr state;
/// If true, reset the state /// If true, reset the state
bool needs_init; bool needs_init;
/// If true, use float processing rather than int /// If true, use float processing rather than int
bool use_float_processing; bool use_float_processing;
/// If true, use native float coefficients (REV15+)
bool use_float_coefficients;
}; };
/** /**
@ -79,18 +72,4 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
std::array<s16, 3>& b, std::array<s16, 2>& a, std::array<s16, 3>& b, std::array<s16, 2>& a,
VoiceState::BiquadFilterState& state, const u32 sample_count); VoiceState::BiquadFilterState& state, const u32 sample_count);
/**
* Biquad filter float implementation with native float coefficients (SDK REV15+).
*
* @param output - Output container for filtered samples.
* @param input - Input container for samples to be filtered.
* @param b - Feedforward coefficients (float).
* @param a - Feedback coefficients (float).
* @param state - State to track previous samples.
* @param sample_count - Number of samples to process.
*/
void ApplyBiquadFilterFloat2(std::span<s32> output, std::span<const s32> input,
std::array<f32, 3>& b, std::array<f32, 2>& a,
VoiceState::BiquadFilterState& state, const u32 sample_count);
} // namespace AudioCore::Renderer } // namespace AudioCore::Renderer

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -36,15 +33,9 @@ void MultiTapBiquadFilterCommand::Process(const AudioRenderer::CommandListProces
*state = {}; *state = {};
} }
// REV15+: Use native float coefficients if available
if (use_float_coefficients) {
ApplyBiquadFilterFloat2(output_buffer, input_buffer, biquads_float[i].numerator,
biquads_float[i].denominator, *state, processor.sample_count);
} else {
ApplyBiquadFilterFloat(output_buffer, input_buffer, biquads[i].b, biquads[i].a, *state, ApplyBiquadFilterFloat(output_buffer, input_buffer, biquads[i].b, biquads[i].a, *state,
processor.sample_count); processor.sample_count);
} }
}
} }
bool MultiTapBiquadFilterCommand::Verify(const AudioRenderer::CommandListProcessor& processor) { bool MultiTapBiquadFilterCommand::Verify(const AudioRenderer::CommandListProcessor& processor) {

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -52,16 +49,12 @@ struct MultiTapBiquadFilterCommand : ICommand {
s16 output; s16 output;
/// Biquad parameters /// Biquad parameters
std::array<VoiceInfo::BiquadFilterParameter, MaxBiquadFilters> biquads; std::array<VoiceInfo::BiquadFilterParameter, MaxBiquadFilters> biquads;
/// Biquad parameters (REV15+ native float)
std::array<VoiceInfo::BiquadFilterParameter2, MaxBiquadFilters> biquads_float;
/// Biquad states, updated each call /// Biquad states, updated each call
std::array<CpuAddr, MaxBiquadFilters> states; std::array<CpuAddr, MaxBiquadFilters> states;
/// If each biquad needs initialisation /// If each biquad needs initialisation
std::array<bool, MaxBiquadFilters> needs_init; std::array<bool, MaxBiquadFilters> needs_init;
/// Number of active biquads /// Number of active biquads
u8 filter_tap_count; u8 filter_tap_count;
/// If true, use native float coefficients (REV15+)
bool use_float_coefficients;
}; };
} // namespace AudioCore::Renderer } // namespace AudioCore::Renderer

View file

@ -35,16 +35,12 @@ SplitterDestinationData& SplitterContext::GetData(const u32 index) {
void SplitterContext::Setup(std::span<SplitterInfo> splitter_infos_, const u32 splitter_info_count_, void SplitterContext::Setup(std::span<SplitterInfo> splitter_infos_, const u32 splitter_info_count_,
SplitterDestinationData* splitter_destinations_, SplitterDestinationData* splitter_destinations_,
const u32 destination_count_, const bool splitter_bug_fixed_, const u32 destination_count_, const bool splitter_bug_fixed_) {
const BehaviorInfo& behavior) {
splitter_infos = splitter_infos_; splitter_infos = splitter_infos_;
info_count = splitter_info_count_; info_count = splitter_info_count_;
splitter_destinations = splitter_destinations_; splitter_destinations = splitter_destinations_;
destinations_count = destination_count_; destinations_count = destination_count_;
splitter_bug_fixed = splitter_bug_fixed_; splitter_bug_fixed = splitter_bug_fixed_;
splitter_prev_volume_reset_supported = behavior.IsSplitterPrevVolumeResetSupported();
splitter_biquad_param_supported = behavior.IsBiquadFilterParameterForSplitterEnabled();
splitter_float_coeff_supported = behavior.IsSplitterDestinationV2bSupported();
} }
bool SplitterContext::UsingSplitter() const { bool SplitterContext::UsingSplitter() const {
@ -88,7 +84,7 @@ bool SplitterContext::Initialize(const BehaviorInfo& behavior,
} }
Setup(splitter_infos, params.splitter_infos, splitter_destinations, Setup(splitter_infos, params.splitter_infos, splitter_destinations,
params.splitter_destinations, behavior.IsSplitterBugFixed(), behavior); params.splitter_destinations, behavior.IsSplitterBugFixed());
} }
return true; return true;
} }
@ -141,104 +137,19 @@ u32 SplitterContext::UpdateInfo(const u8* input, u32 offset, const u32 splitter_
u32 SplitterContext::UpdateData(const u8* input, u32 offset, const u32 count) { u32 SplitterContext::UpdateData(const u8* input, u32 offset, const u32 count) {
for (u32 i = 0; i < count; i++) { for (u32 i = 0; i < count; i++) {
// Version selection based on feature flags: auto data_header{
// - REV12: integer biquad params (Version2a) reinterpret_cast<const SplitterDestinationData::InParameter*>(input + offset)};
// - REV15: float coeff/biquad v2b
// - older: no biquad fields
if (!splitter_biquad_param_supported) {
const auto* data_header =
reinterpret_cast<const SplitterDestinationData::InParameter*>(input + offset);
if (data_header->magic != GetSplitterSendDataMagic()) { if (data_header->magic != GetSplitterSendDataMagic()) {
continue; continue;
} }
if (data_header->id < 0 || data_header->id > destinations_count) { if (data_header->id < 0 || data_header->id > destinations_count) {
continue; continue;
} }
auto modified_params = *data_header; splitter_destinations[data_header->id].Update(*data_header);
if (!splitter_prev_volume_reset_supported) {
modified_params.reset_prev_volume = false;
}
splitter_destinations[data_header->id].Update(modified_params);
offset += sizeof(SplitterDestinationData::InParameter); offset += sizeof(SplitterDestinationData::InParameter);
} else if (!splitter_float_coeff_supported) {
// Version 2a: struct contains legacy fixed-point biquad filter fields (REV12+)
const auto* data_header_v2a =
reinterpret_cast<const SplitterDestinationData::InParameterVersion2a*>(input +
offset);
if (data_header_v2a->magic != GetSplitterSendDataMagic()) {
continue;
}
if (data_header_v2a->id < 0 || data_header_v2a->id > destinations_count) {
continue;
}
// Map common fields to the base format
SplitterDestinationData::InParameter mapped{};
mapped.magic = data_header_v2a->magic;
mapped.id = data_header_v2a->id;
mapped.mix_volumes = data_header_v2a->mix_volumes;
mapped.mix_id = data_header_v2a->mix_id;
mapped.in_use = data_header_v2a->in_use;
mapped.reset_prev_volume =
splitter_prev_volume_reset_supported ? data_header_v2a->reset_prev_volume : false;
auto& destination = splitter_destinations[data_header_v2a->id];
destination.Update(mapped);
// Convert legacy fixed-point biquad params into float representation
auto biquad_filters = destination.GetBiquadFilters();
for (size_t filter_idx = 0; filter_idx < MaxBiquadFilters; filter_idx++) {
const auto& legacy = data_header_v2a->biquad_filters[filter_idx];
auto& out = biquad_filters[filter_idx];
out.enabled = legacy.enabled;
// s16 fixed-point scale: use Q14 like voices (b and a are s16, 1.0 ~= 1<<14)
constexpr float scale = 1.0f / static_cast<float>(1 << 14);
out.numerator[0] = static_cast<float>(legacy.b[0]) * scale;
out.numerator[1] = static_cast<float>(legacy.b[1]) * scale;
out.numerator[2] = static_cast<float>(legacy.b[2]) * scale;
out.denominator[0] = static_cast<float>(legacy.a[0]) * scale;
out.denominator[1] = static_cast<float>(legacy.a[1]) * scale;
}
offset += static_cast<u32>(sizeof(SplitterDestinationData::InParameterVersion2a));
} else {
// Version 2b: struct contains extra biquad filter fields with float coeffs
const auto* data_header_v2b =
reinterpret_cast<const SplitterDestinationData::InParameterVersion2b*>(input +
offset);
if (data_header_v2b->magic != GetSplitterSendDataMagic()) {
continue;
}
if (data_header_v2b->id < 0 || data_header_v2b->id > destinations_count) {
continue;
}
// Map common fields to the old format
SplitterDestinationData::InParameter mapped{};
mapped.magic = data_header_v2b->magic;
mapped.id = data_header_v2b->id;
mapped.mix_volumes = data_header_v2b->mix_volumes;
mapped.mix_id = data_header_v2b->mix_id;
mapped.in_use = data_header_v2b->in_use;
mapped.reset_prev_volume =
splitter_prev_volume_reset_supported ? data_header_v2b->reset_prev_volume : false;
// Store biquad filters from V2b (REV15+)
auto& destination = splitter_destinations[data_header_v2b->id];
destination.Update(mapped);
// Copy biquad filter parameters
auto biquad_filters = destination.GetBiquadFilters();
for (size_t filter_idx = 0; filter_idx < MaxBiquadFilters; filter_idx++) {
biquad_filters[filter_idx] = data_header_v2b->biquad_filters[filter_idx];
}
offset += static_cast<u32>(sizeof(SplitterDestinationData::InParameterVersion2b));
}
} }
return offset; return offset;

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -171,11 +168,10 @@ private:
* @param splitter_destinations - Workbuffer for splitter destinations. * @param splitter_destinations - Workbuffer for splitter destinations.
* @param destination_count - Number of destinations in the workbuffer. * @param destination_count - Number of destinations in the workbuffer.
* @param splitter_bug_fixed - Is the splitter bug fixed? * @param splitter_bug_fixed - Is the splitter bug fixed?
* @param behavior - Behavior info for feature support.
*/ */
void Setup(std::span<SplitterInfo> splitter_infos, u32 splitter_info_count, void Setup(std::span<SplitterInfo> splitter_infos, u32 splitter_info_count,
SplitterDestinationData* splitter_destinations, u32 destination_count, SplitterDestinationData* splitter_destinations, u32 destination_count,
bool splitter_bug_fixed, const BehaviorInfo& behavior); bool splitter_bug_fixed);
/// Workbuffer for splitters /// Workbuffer for splitters
std::span<SplitterInfo> splitter_infos{}; std::span<SplitterInfo> splitter_infos{};
@ -187,12 +183,6 @@ private:
s32 destinations_count{}; s32 destinations_count{};
/// Is the splitter bug fixed? /// Is the splitter bug fixed?
bool splitter_bug_fixed{}; bool splitter_bug_fixed{};
/// Is explicit previous mix volume reset supported?
bool splitter_prev_volume_reset_supported{};
/// Is biquad filter parameter for splitter (REV12) supported?
bool splitter_biquad_param_supported{};
/// Is float coefficient/biquad filter v2b parameter supported?
bool splitter_float_coeff_supported{};
}; };
} // namespace Renderer } // namespace Renderer

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -87,14 +84,4 @@ void SplitterDestinationData::SetNext(SplitterDestinationData* next_) {
next = next_; next = next_;
} }
std::span<SplitterDestinationData::BiquadFilterParameter2>
SplitterDestinationData::GetBiquadFilters() {
return biquad_filters;
}
std::span<const SplitterDestinationData::BiquadFilterParameter2>
SplitterDestinationData::GetBiquadFilters() const {
return biquad_filters;
}
} // namespace AudioCore::Renderer } // namespace AudioCore::Renderer

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -19,72 +16,16 @@ namespace AudioCore::Renderer {
*/ */
class SplitterDestinationData { class SplitterDestinationData {
public: public:
/**
* Biquad filter parameter with float coefficients (SDK REV15+).
* Defined here to avoid circular dependency with VoiceInfo.
*/
struct BiquadFilterParameter2 {
/* 0x00 */ bool enabled;
/* 0x01 */ u8 reserved1;
/* 0x02 */ u8 reserved2;
/* 0x03 */ u8 reserved3;
/* 0x04 */ std::array<f32, 3> numerator; // b0, b1, b2
/* 0x10 */ std::array<f32, 2> denominator; // a1, a2 (a0 = 1)
};
static_assert(sizeof(BiquadFilterParameter2) == 0x18,
"BiquadFilterParameter2 has the wrong size!");
/**
* Legacy biquad filter parameter with fixed-point coefficients (SDK REV12+ for splitters).
* Matches the old voice biquad format.
*/
struct BiquadFilterParameterLegacy {
/* 0x00 */ bool enabled;
/* 0x02 */ std::array<s16, 3> b; // numerator
/* 0x08 */ std::array<s16, 2> a; // denominator (a0 = 1)
};
static_assert(sizeof(BiquadFilterParameterLegacy) == 0xC,
"BiquadFilterParameterLegacy has the wrong size!");
struct InParameter { struct InParameter {
/* 0x00 */ u32 magic; // 'SNDD' /* 0x00 */ u32 magic; // 'SNDD'
/* 0x04 */ s32 id; /* 0x04 */ s32 id;
/* 0x08 */ std::array<f32, MaxMixBuffers> mix_volumes; /* 0x08 */ std::array<f32, MaxMixBuffers> mix_volumes;
/* 0x68 */ u32 mix_id; /* 0x68 */ u32 mix_id;
/* 0x6C */ bool in_use; /* 0x6C */ bool in_use;
/* 0x6D */ bool reset_prev_volume;
}; };
static_assert(sizeof(InParameter) == 0x70, static_assert(sizeof(InParameter) == 0x70,
"SplitterDestinationData::InParameter has the wrong size!"); "SplitterDestinationData::InParameter has the wrong size!");
struct InParameterVersion2a {
/* 0x00 */ u32 magic; // 'SNDD'
/* 0x04 */ s32 id;
/* 0x08 */ std::array<f32, MaxMixBuffers> mix_volumes;
/* 0x68 */ u32 mix_id;
/* 0x6C */ std::array<SplitterDestinationData::BiquadFilterParameterLegacy, MaxBiquadFilters>
biquad_filters;
/* 0x84 */ bool in_use;
/* 0x85 */ bool reset_prev_volume; // only effective if supported
/* 0x86 */ u8 reserved[10];
};
static_assert(sizeof(InParameterVersion2a) == 0x90,
"SplitterDestinationData::InParameterVersion2a has the wrong size!");
struct InParameterVersion2b {
/* 0x00 */ u32 magic; // 'SNDD'
/* 0x04 */ s32 id;
/* 0x08 */ std::array<f32, MaxMixBuffers> mix_volumes;
/* 0x68 */ u32 mix_id;
/* 0x6C */ std::array<SplitterDestinationData::BiquadFilterParameter2, MaxBiquadFilters>
biquad_filters;
/* 0x9C */ bool in_use;
/* 0x9D */ bool reset_prev_volume;
/* 0x9E */ u8 reserved[10];
};
static_assert(sizeof(InParameterVersion2b) == 0xA8,
"SplitterDestinationData::InParameterVersion2b has the wrong size!");
SplitterDestinationData(s32 id); SplitterDestinationData(s32 id);
/** /**
@ -137,7 +78,7 @@ public:
f32 GetMixVolumePrev(u32 index) const; f32 GetMixVolumePrev(u32 index) const;
/** /**
* Get the previous mix volumes for all mix buffers. * Get the previous mix volumes for all mix buffers in this destination.
* *
* @return Span of previous mix buffer volumes. * @return Span of previous mix buffer volumes.
*/ */
@ -174,20 +115,6 @@ public:
*/ */
void SetNext(SplitterDestinationData* next); void SetNext(SplitterDestinationData* next);
/**
* Get biquad filter parameters for this destination (REV15+ or mapped from REV12).
*
* @return Span of biquad filter parameters.
*/
std::span<BiquadFilterParameter2> GetBiquadFilters();
/**
* Get const biquad filter parameters for this destination (REV15+ or mapped from REV12).
*
* @return Const span of biquad filter parameters.
*/
std::span<const BiquadFilterParameter2> GetBiquadFilters() const;
private: private:
/// Id of this destination /// Id of this destination
const s32 id; const s32 id;
@ -197,8 +124,6 @@ private:
std::array<f32, MaxMixBuffers> mix_volumes{0.0f}; std::array<f32, MaxMixBuffers> mix_volumes{0.0f};
/// Previous mix volumes /// Previous mix volumes
std::array<f32, MaxMixBuffers> prev_mix_volumes{0.0f}; std::array<f32, MaxMixBuffers> prev_mix_volumes{0.0f};
/// Biquad filter parameters (REV15+ or mapped from REV12)
std::array<BiquadFilterParameter2, MaxBiquadFilters> biquad_filters{};
/// Next destination in the mix chain /// Next destination in the mix chain
SplitterDestinationData* next{}; SplitterDestinationData* next{};
/// Is this destination in use? /// Is this destination in use?

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -138,17 +135,6 @@ public:
static_assert(sizeof(BiquadFilterParameter) == 0xC, static_assert(sizeof(BiquadFilterParameter) == 0xC,
"VoiceInfo::BiquadFilterParameter has the wrong size!"); "VoiceInfo::BiquadFilterParameter has the wrong size!");
struct BiquadFilterParameter2 {
/* 0x00 */ bool enabled;
/* 0x01 */ u8 reserved1;
/* 0x02 */ u8 reserved2;
/* 0x03 */ u8 reserved3;
/* 0x04 */ std::array<f32, 3> numerator; // b0, b1, b2
/* 0x10 */ std::array<f32, 2> denominator; // a1, a2 (a0 = 1)
};
static_assert(sizeof(BiquadFilterParameter2) == 0x18,
"VoiceInfo::BiquadFilterParameter2 has the wrong size!");
struct InParameter { struct InParameter {
/* 0x000 */ u32 id; /* 0x000 */ u32 id;
/* 0x004 */ u32 node_id; /* 0x004 */ u32 node_id;
@ -182,43 +168,6 @@ public:
}; };
static_assert(sizeof(InParameter) == 0x170, "VoiceInfo::InParameter has the wrong size!"); static_assert(sizeof(InParameter) == 0x170, "VoiceInfo::InParameter has the wrong size!");
struct InParameter2 {
/* 0x000 */ u32 id;
/* 0x004 */ u32 node_id;
/* 0x008 */ bool is_new;
/* 0x009 */ bool in_use;
/* 0x00A */ PlayState play_state;
/* 0x00B */ SampleFormat sample_format;
/* 0x00C */ u32 sample_rate;
/* 0x010 */ s32 priority;
/* 0x014 */ s32 sort_order;
/* 0x018 */ u32 channel_count;
/* 0x01C */ f32 pitch;
/* 0x020 */ f32 volume;
/* 0x024 */ std::array<BiquadFilterParameter2, MaxBiquadFilters> biquads;
/* 0x054 */ u32 wave_buffer_count;
/* 0x058 */ u32 wave_buffer_index;
/* 0x05C */ u32 reserved1;
/* 0x060 */ CpuAddr src_data_address;
/* 0x068 */ u64 src_data_size;
/* 0x070 */ u32 mix_id;
/* 0x074 */ u32 splitter_id;
/* 0x078 */ std::array<WaveBufferInternal, MaxWaveBuffers> wave_buffer_internal;
/* 0x158 */ std::array<s32, MaxChannels> channel_resource_ids;
/* 0x170 */ bool clear_voice_drop;
/* 0x171 */ u8 flush_buffer_count;
/* 0x172 */ u16 reserved2;
/* 0x174 */ Flags flags;
/* 0x175 */ u8 reserved3;
/* 0x176 */ SrcQuality src_quality;
/* 0x177 */ u8 reserved4;
/* 0x178 */ u32 external_context;
/* 0x17C */ u32 external_context_size;
/* 0x180 */ u32 reserved5;
/* 0x184 */ u32 reserved6;
};
static_assert(sizeof(InParameter2) == 0x188, "VoiceInfo::InParameter2 has the wrong size!");
struct OutStatus { struct OutStatus {
/* 0x00 */ u64 played_sample_count; /* 0x00 */ u64 played_sample_count;
/* 0x08 */ u32 wave_buffers_consumed; /* 0x08 */ u32 wave_buffers_consumed;
@ -400,10 +349,6 @@ public:
f32 prev_volume{}; f32 prev_volume{};
/// Biquad filters for generating filter commands on this voice /// Biquad filters for generating filter commands on this voice
std::array<BiquadFilterParameter, MaxBiquadFilters> biquads{}; std::array<BiquadFilterParameter, MaxBiquadFilters> biquads{};
/// Float biquad filters for REV15+ (native float coefficients)
std::array<BiquadFilterParameter2, MaxBiquadFilters> biquads_float{};
/// Use float biquad coefficients (REV15+)
bool use_float_biquads{};
/// Number of active wavebuffers /// Number of active wavebuffers
u32 wave_buffer_count{}; u32 wave_buffer_count{};
/// Current playing wavebuffer index /// Current playing wavebuffer index

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -509,9 +509,6 @@ std::vector<std::string> ProfileManager::FindOrphanedProfiles()
good_uuids.emplace_back(uuid_string); good_uuids.emplace_back(uuid_string);
} }
// used for acnh, etc
good_uuids.emplace_back("00000000000000000000000000000000");
// TODO: fetch save_id programmatically // TODO: fetch save_id programmatically
const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir)
/ "user/save/0000000000000000"; / "user/save/0000000000000000";

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -71,6 +68,42 @@ std::string ResolveURL(const std::string& url) {
return url.substr(0, index) + "lp1" + url.substr(index + 1); return url.substr(0, index) + "lp1" + url.substr(index + 1);
} }
WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) {
std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader));
if (web_arg.size() == sizeof(WebArgHeader)) {
return {};
}
WebArgInputTLVMap input_tlv_map;
u64 current_offset = sizeof(WebArgHeader);
for (std::size_t i = 0; i < web_arg_header.total_tlv_entries; ++i) {
if (web_arg.size() < current_offset + sizeof(WebArgInputTLV)) {
return input_tlv_map;
}
WebArgInputTLV input_tlv;
std::memcpy(&input_tlv, web_arg.data() + current_offset, sizeof(WebArgInputTLV));
current_offset += sizeof(WebArgInputTLV);
if (web_arg.size() < current_offset + input_tlv.arg_data_size) {
return input_tlv_map;
}
std::vector<u8> data(input_tlv.arg_data_size);
std::memcpy(data.data(), web_arg.data() + current_offset, input_tlv.arg_data_size);
current_offset += input_tlv.arg_data_size;
input_tlv_map.insert_or_assign(input_tlv.input_tlv_type, std::move(data));
}
return input_tlv_map;
}
FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id, FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id,
FileSys::ContentRecordType nca_type) { FileSys::ContentRecordType nca_type) {
if (nca_type == FileSys::ContentRecordType::Data) { if (nca_type == FileSys::ContentRecordType::Data) {
@ -111,43 +144,6 @@ FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id,
} }
} }
#ifdef YUZU_USE_QT_WEB_ENGINE
WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) {
std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader));
if (web_arg.size() == sizeof(WebArgHeader)) {
return {};
}
WebArgInputTLVMap input_tlv_map;
u64 current_offset = sizeof(WebArgHeader);
for (std::size_t i = 0; i < web_arg_header.total_tlv_entries; ++i) {
if (web_arg.size() < current_offset + sizeof(WebArgInputTLV)) {
return input_tlv_map;
}
WebArgInputTLV input_tlv;
std::memcpy(&input_tlv, web_arg.data() + current_offset, sizeof(WebArgInputTLV));
current_offset += sizeof(WebArgInputTLV);
if (web_arg.size() < current_offset + input_tlv.arg_data_size) {
return input_tlv_map;
}
std::vector<u8> data(input_tlv.arg_data_size);
std::memcpy(data.data(), web_arg.data() + current_offset, input_tlv.arg_data_size);
current_offset += input_tlv.arg_data_size;
input_tlv_map.insert_or_assign(input_tlv.input_tlv_type, std::move(data));
}
return input_tlv_map;
}
void ExtractSharedFonts(Core::System& system) { void ExtractSharedFonts(Core::System& system) {
static constexpr std::array<const char*, 7> DECRYPTED_SHARED_FONTS{ static constexpr std::array<const char*, 7> DECRYPTED_SHARED_FONTS{
"FontStandard.ttf", "FontStandard.ttf",
@ -225,7 +221,6 @@ void ExtractSharedFonts(Core::System& system) {
FileSys::VfsRawCopy(decrypted_font, out_file); FileSys::VfsRawCopy(decrypted_font, out_file);
} }
} }
#endif
} // namespace } // namespace
@ -237,7 +232,6 @@ WebBrowser::WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
WebBrowser::~WebBrowser() = default; WebBrowser::~WebBrowser() = default;
void WebBrowser::Initialize() { void WebBrowser::Initialize() {
#ifdef YUZU_USE_QT_WEB_ENGINE
FrontendApplet::Initialize(); FrontendApplet::Initialize();
LOG_INFO(Service_AM, "Initializing Web Browser Applet."); LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
@ -290,7 +284,6 @@ void WebBrowser::Initialize() {
ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind); ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind);
break; break;
} }
#endif
} }
Result WebBrowser::GetStatus() const { Result WebBrowser::GetStatus() const {
@ -302,7 +295,6 @@ void WebBrowser::ExecuteInteractive() {
} }
void WebBrowser::Execute() { void WebBrowser::Execute() {
#ifdef YUZU_USE_QT_WEB_ENGINE
switch (web_arg_header.shim_kind) { switch (web_arg_header.shim_kind) {
case ShimKind::Shop: case ShimKind::Shop:
ExecuteShop(); ExecuteShop();
@ -330,10 +322,6 @@ void WebBrowser::Execute() {
WebBrowserExit(WebExitReason::EndButtonPressed); WebBrowserExit(WebExitReason::EndButtonPressed);
break; break;
} }
#else
LOG_INFO(Service_AM, "Web Browser Applet disabled, skipping.");
WebBrowserExit(WebExitReason::EndButtonPressed);
#endif
} }
void WebBrowser::ExtractOfflineRomFS() { void WebBrowser::ExtractOfflineRomFS() {

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -178,7 +175,6 @@ ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_
{0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"}, {0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"},
{1, nullptr, "TerminateAllLibraryApplets"}, {1, nullptr, "TerminateAllLibraryApplets"},
{2, nullptr, "AreAnyLibraryAppletsLeft"}, {2, nullptr, "AreAnyLibraryAppletsLeft"},
{3, D<&ILibraryAppletCreator::CreateLibraryAppletEx>, "CreateLibraryAppletEx"},
{10, D<&ILibraryAppletCreator::CreateStorage>, "CreateStorage"}, {10, D<&ILibraryAppletCreator::CreateStorage>, "CreateStorage"},
{11, D<&ILibraryAppletCreator::CreateTransferMemoryStorage>, "CreateTransferMemoryStorage"}, {11, D<&ILibraryAppletCreator::CreateTransferMemoryStorage>, "CreateTransferMemoryStorage"},
{12, D<&ILibraryAppletCreator::CreateHandleStorage>, "CreateHandleStorage"}, {12, D<&ILibraryAppletCreator::CreateHandleStorage>, "CreateHandleStorage"},
@ -214,32 +210,6 @@ Result ILibraryAppletCreator::CreateLibraryApplet(
R_SUCCEED(); R_SUCCEED();
} }
Result ILibraryAppletCreator::CreateLibraryAppletEx(
Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
LibraryAppletMode library_applet_mode, u64 thread_id) {
LOG_DEBUG(Service_AM, "called with applet_id={} applet_mode={} thread_id={}", applet_id,
library_applet_mode, thread_id);
std::shared_ptr<ILibraryAppletAccessor> library_applet;
if (ShouldCreateGuestApplet(applet_id)) {
library_applet =
CreateGuestApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
}
if (!library_applet) {
library_applet =
CreateFrontendApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
}
if (!library_applet) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
R_THROW(ResultUnknown);
}
// Applet is created, can now be launched.
m_applet->library_applet_launchable_event.Signal();
*out_library_applet_accessor = library_applet;
R_SUCCEED();
}
Result ILibraryAppletCreator::CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size) { Result ILibraryAppletCreator::CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size) {
LOG_DEBUG(Service_AM, "called, size={}", size); LOG_DEBUG(Service_AM, "called, size={}", size);

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -27,9 +24,6 @@ private:
Result CreateLibraryApplet( Result CreateLibraryApplet(
Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id, Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
LibraryAppletMode library_applet_mode); LibraryAppletMode library_applet_mode);
Result CreateLibraryAppletEx(
Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
LibraryAppletMode library_applet_mode, u64 thread_id);
Result CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size); Result CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size);
Result CreateTransferMemoryStorage( Result CreateTransferMemoryStorage(
Out<SharedPointer<IStorage>> out_storage, bool is_writable, s64 size, Out<SharedPointer<IStorage>> out_storage, bool is_writable, s64 size,

View file

@ -128,7 +128,6 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{406, nullptr, "GetApplicationControlProperty"}, {406, nullptr, "GetApplicationControlProperty"},
{407, nullptr, "ListApplicationTitle"}, {407, nullptr, "ListApplicationTitle"},
{408, nullptr, "ListApplicationIcon"}, {408, nullptr, "ListApplicationIcon"},
{419, D<&IApplicationManagerInterface::RequestDownloadApplicationControlDataInBackground>, "RequestDownloadApplicationControlDataInBackground"},
{502, nullptr, "RequestCheckGameCardRegistration"}, {502, nullptr, "RequestCheckGameCardRegistration"},
{503, nullptr, "RequestGameCardRegistrationGoldPoint"}, {503, nullptr, "RequestGameCardRegistrationGoldPoint"},
{504, nullptr, "RequestRegisterGameCard"}, {504, nullptr, "RequestRegisterGameCard"},
@ -211,7 +210,6 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{1703, nullptr, "GetApplicationViewDownloadErrorContext"}, {1703, nullptr, "GetApplicationViewDownloadErrorContext"},
{1704, D<&IApplicationManagerInterface::GetApplicationViewWithPromotionInfo>, "GetApplicationViewWithPromotionInfo"}, {1704, D<&IApplicationManagerInterface::GetApplicationViewWithPromotionInfo>, "GetApplicationViewWithPromotionInfo"},
{1705, nullptr, "IsPatchAutoDeletableApplication"}, {1705, nullptr, "IsPatchAutoDeletableApplication"},
{1706, D<&IApplicationManagerInterface::Unknown1706>, "Unknown1706"},
{1800, nullptr, "IsNotificationSetupCompleted"}, {1800, nullptr, "IsNotificationSetupCompleted"},
{1801, nullptr, "GetLastNotificationInfoCount"}, {1801, nullptr, "GetLastNotificationInfoCount"},
{1802, nullptr, "ListLastNotificationInfo"}, {1802, nullptr, "ListLastNotificationInfo"},
@ -311,7 +309,6 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{4022, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4022"}, {4022, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4022"},
{4023, D<&IApplicationManagerInterface::Unknown4023>, "Unknown4023"}, {4023, D<&IApplicationManagerInterface::Unknown4023>, "Unknown4023"},
{4088, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4088"}, {4088, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4088"},
{4053, D<&IApplicationManagerInterface::Unknown4053>, "Unknown4053"},
{9999, nullptr, "GetApplicationCertificate"}, {9999, nullptr, "GetApplicationCertificate"},
}; };
// clang-format on // clang-format on
@ -529,37 +526,6 @@ Result IApplicationManagerInterface::GetApplicationTerminateResult(Out<Result> o
R_SUCCEED(); R_SUCCEED();
} }
Result IApplicationManagerInterface::RequestDownloadApplicationControlDataInBackground(
u64 unk, u64 application_id) {
LOG_WARNING(Service_NS, "(STUBBED), app={:016X} unk={}", application_id, unk);
R_SUCCEED();
}
Result IApplicationManagerInterface::Unknown1706(
OutBuffer<BufferAttr_HipcAutoSelect> out_buffer_58,
InBuffer<BufferAttr_HipcMapAlias> in_buffer_8) {
LOG_WARNING(Service_NS, "(STUBBED) Unknown1706 called: out_size={} in_size={}",
out_buffer_58.size(), in_buffer_8.size());
if (out_buffer_58.size() < 0x58 || in_buffer_8.size() < 0x8) {
R_THROW(ResultUnknown);
}
u64 application_id = 0;
std::memcpy(&application_id, in_buffer_8.data(), sizeof(u64));
ApplicationView view{};
view.application_id = application_id;
view.unk = 0x70000;
view.flags = 0x401f17;
std::memset(out_buffer_58.data(), 0, out_buffer_58.size());
std::memcpy(out_buffer_58.data(), &view, sizeof(ApplicationView));
R_SUCCEED();
}
Result IApplicationManagerInterface::Unknown4022( Result IApplicationManagerInterface::Unknown4022(
OutCopyHandle<Kernel::KReadableEvent> out_event) { OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_NS, "(STUBBED) called"); LOG_WARNING(Service_NS, "(STUBBED) called");
@ -573,9 +539,4 @@ Result IApplicationManagerInterface::Unknown4023(Out<u64> out_result) {
R_SUCCEED(); R_SUCCEED();
} }
Result IApplicationManagerInterface::Unknown4053() {
LOG_WARNING(Service_NS, "(STUBBED) called.");
R_SUCCEED();
}
} // namespace Service::NS } // namespace Service::NS

View file

@ -55,12 +55,6 @@ public:
Result GetApplicationTerminateResult(Out<Result> out_result, u64 application_id); Result GetApplicationTerminateResult(Out<Result> out_result, u64 application_id);
Result Unknown4022(OutCopyHandle<Kernel::KReadableEvent> out_event); Result Unknown4022(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result Unknown4023(Out<u64> out_result); Result Unknown4023(Out<u64> out_result);
Result Unknown4053();
Result RequestDownloadApplicationControlDataInBackground(u64 unk,
u64 application_id);
Result Unknown1706(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer_58,
InBuffer<BufferAttr_HipcMapAlias> in_buffer_8);
private: private:
KernelHelpers::ServiceContext service_context; KernelHelpers::ServiceContext service_context;

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// 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
@ -86,9 +83,8 @@ static_assert(sizeof(PromotionInfo) == 0x20, "PromotionInfo has incorrect size."
struct ApplicationViewWithPromotionInfo { struct ApplicationViewWithPromotionInfo {
ApplicationView view; ///< \ref NsApplicationView ApplicationView view; ///< \ref NsApplicationView
PromotionInfo promotion; ///< \ref NsPromotionInfo PromotionInfo promotion; ///< \ref NsPromotionInfo
std::array<u8, 0x8> padding{}; ///< Extra padding for newer HOS versions
}; };
static_assert(sizeof(ApplicationViewWithPromotionInfo) == 0x78, static_assert(sizeof(ApplicationViewWithPromotionInfo) == 0x70,
"ApplicationViewWithPromotionInfo has incorrect size."); "ApplicationViewWithPromotionInfo has incorrect size.");
struct ApplicationOccupiedSizeEntity { struct ApplicationOccupiedSizeEntity {
@ -117,10 +113,4 @@ struct Uid {
}; };
static_assert(sizeof(Uid) == 0x10, "Uid has incorrect size."); static_assert(sizeof(Uid) == 0x10, "Uid has incorrect size.");
struct ApplicationDisplayData {
std::array<char, 0x200> application_name;
std::array<char, 0x100> developer_name;
};
static_assert(sizeof(ApplicationDisplayData) == 0x300, "ApplicationDisplayData has incorrect size.");
} // namespace Service::NS } // namespace Service::NS

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -10,7 +7,6 @@
#include "core/file_sys/vfs/vfs.h" #include "core/file_sys/vfs/vfs.h"
#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ns/language.h" #include "core/hle/service/ns/language.h"
#include "core/hle/service/ns/ns_types.h"
#include "core/hle/service/ns/ns_results.h" #include "core/hle/service/ns/ns_results.h"
#include "core/hle/service/ns/read_only_application_control_data_interface.h" #include "core/hle/service/ns/read_only_application_control_data_interface.h"
#include "core/hle/service/set/settings_server.h" #include "core/hle/service/set/settings_server.h"
@ -27,7 +23,6 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa
{2, D<&IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"}, {2, D<&IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"},
{3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
{4, nullptr, "SelectApplicationDesiredLanguage"}, {4, nullptr, "SelectApplicationDesiredLanguage"},
{5, D<&IReadOnlyApplicationControlDataInterface::GetApplicationDisplayData>, "GetApplicationDisplayData"},
}; };
// clang-format on // clang-format on
@ -124,33 +119,4 @@ Result IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLan
R_SUCCEED(); R_SUCCEED();
} }
Result IReadOnlyApplicationControlDataInterface::GetApplicationDisplayData(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u64> out_size, u64 language_code,
u64 application_id) {
LOG_INFO(Service_NS, "called with application_id={:016X}, language_code={:016X}",
application_id, language_code);
constexpr u64 payload_size = sizeof(ApplicationDisplayData);
if (out_buffer.size() < payload_size) {
LOG_ERROR(Service_NS, "output buffer is too small! (actual={}, expected_min={})",
out_buffer.size(), payload_size);
R_THROW(ResultUnknown);
}
const FileSys::PatchManager pm{application_id, system.GetFileSystemController(),
system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
ApplicationDisplayData display_data{};
std::memset(display_data.application_name.data(), 0, display_data.application_name.size());
std::memset(display_data.developer_name.data(), 0, display_data.developer_name.size());
std::memcpy(out_buffer.data(), &display_data, payload_size);
*out_size = payload_size;
R_SUCCEED();
}
} // namespace Service::NS } // namespace Service::NS

View file

@ -1,15 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2025 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
#pragma once #pragma once
#include "core/hle/service/cmif_types.h" #include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
#include "core/hle/service/ns/language.h" #include "core/hle/service/ns/language.h"
#include "core/hle/service/ns/ns_types.h" #include "core/hle/service/ns/ns_types.h"
#include "core/hle/service/service.h"
namespace Service::NS { namespace Service::NS {
@ -19,6 +16,7 @@ public:
explicit IReadOnlyApplicationControlDataInterface(Core::System& system_); explicit IReadOnlyApplicationControlDataInterface(Core::System& system_);
~IReadOnlyApplicationControlDataInterface() override; ~IReadOnlyApplicationControlDataInterface() override;
public:
Result GetApplicationControlData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Result GetApplicationControlData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u32> out_actual_size, Out<u32> out_actual_size,
ApplicationControlSource application_control_source, ApplicationControlSource application_control_source,
@ -27,10 +25,6 @@ public:
u32 supported_languages); u32 supported_languages);
Result ConvertApplicationLanguageToLanguageCode(Out<u64> out_language_code, Result ConvertApplicationLanguageToLanguageCode(Out<u64> out_language_code,
ApplicationLanguage application_language); ApplicationLanguage application_language);
Result GetApplicationDisplayData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u64> out_size, u64 language_code,
u64 application_id);
}; };
} // namespace Service::NS } // namespace Service::NS

View file

@ -1,13 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2025 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
#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ns/read_only_application_record_interface.h" #include "core/hle/service/ns/read_only_application_record_interface.h"
#include "core/hle/service/ns/ns_types.h"
#include "core/hle/service/ns/application_manager_interface.h"
namespace Service::NS { namespace Service::NS {
@ -18,8 +13,6 @@ IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::S
{1, nullptr, "NotifyApplicationFailure"}, {1, nullptr, "NotifyApplicationFailure"},
{2, D<&IReadOnlyApplicationRecordInterface::IsDataCorruptedResult>, {2, D<&IReadOnlyApplicationRecordInterface::IsDataCorruptedResult>,
"IsDataCorruptedResult"}, "IsDataCorruptedResult"},
{3, D<&IReadOnlyApplicationRecordInterface::ListApplicationRecord>,
"ListApplicationRecord"},
}; };
// clang-format on // clang-format on
@ -42,14 +35,4 @@ Result IReadOnlyApplicationRecordInterface::IsDataCorruptedResult(
R_SUCCEED(); R_SUCCEED();
} }
Result IReadOnlyApplicationRecordInterface::ListApplicationRecord(
OutArray<ApplicationRecord, BufferAttr_HipcMapAlias> out_records, Out<s32> out_count,
s32 entry_offset) {
LOG_DEBUG(Service_NS, "delegating to IApplicationManagerInterface::ListApplicationRecord, offset={} limit={}",
entry_offset, out_records.size());
R_RETURN(IApplicationManagerInterface(system).ListApplicationRecord(out_records, out_count,
entry_offset));
}
} // namespace Service::NS } // namespace Service::NS

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@ -8,7 +5,6 @@
#include "core/hle/service/cmif_types.h" #include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/ns/ns_types.h"
namespace Service::NS { namespace Service::NS {
@ -21,9 +17,6 @@ public:
private: private:
Result HasApplicationRecord(Out<bool> out_has_application_record, u64 program_id); Result HasApplicationRecord(Out<bool> out_has_application_record, u64 program_id);
Result IsDataCorruptedResult(Out<bool> out_is_data_corrupted_result, Result result); Result IsDataCorruptedResult(Out<bool> out_is_data_corrupted_result, Result result);
Result ListApplicationRecord(
OutArray<ApplicationRecord, BufferAttr_HipcMapAlias> out_records, Out<s32> out_count,
s32 entry_offset);
}; };
} // namespace Service::NS } // namespace Service::NS

View file

@ -38,7 +38,6 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
{1016, nullptr, "ConfirmShowNewsPermission"}, {1016, nullptr, "ConfirmShowNewsPermission"},
{1017, D<&IParentalControlService::EndFreeCommunication>, "EndFreeCommunication"}, {1017, D<&IParentalControlService::EndFreeCommunication>, "EndFreeCommunication"},
{1018, D<&IParentalControlService::IsFreeCommunicationAvailable>, "IsFreeCommunicationAvailable"}, {1018, D<&IParentalControlService::IsFreeCommunicationAvailable>, "IsFreeCommunicationAvailable"},
{1019, D<&IParentalControlService::ConfirmLaunchApplicationPermission>, "ConfirmLaunchApplicationPermission"},
{1031, D<&IParentalControlService::IsRestrictionEnabled>, "IsRestrictionEnabled"}, {1031, D<&IParentalControlService::IsRestrictionEnabled>, "IsRestrictionEnabled"},
{1032, D<&IParentalControlService::GetSafetyLevel>, "GetSafetyLevel"}, {1032, D<&IParentalControlService::GetSafetyLevel>, "GetSafetyLevel"},
{1033, nullptr, "SetSafetyLevel"}, {1033, nullptr, "SetSafetyLevel"},

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@ -162,17 +159,6 @@ struct NpadGcTriggerState {
}; };
static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
// This is nn::hid::NpadCondition (global controller condition structure)
struct NpadCondition {
u32 _00{};
u32 is_initialized{1};
u32 hold_type{static_cast<u32>(NpadJoyHoldType::Horizontal)};
u32 is_valid{1};
};
static_assert(sizeof(NpadCondition) == 0x10, "NpadCondition is an invalid size");
// This is nn::hid::NpadSystemProperties // This is nn::hid::NpadSystemProperties
struct NPadSystemProperties { struct NPadSystemProperties {
union { union {

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -47,7 +44,8 @@ struct Lifo {
buffer_count++; buffer_count++;
} }
buffer_tail = GetNextEntryIndex(); buffer_tail = GetNextEntryIndex();
entries[buffer_tail].sampling_number = new_state.sampling_number << 1; const auto& previous_entry = ReadPreviousEntry();
entries[buffer_tail].sampling_number = previous_entry.sampling_number + 1;
entries[buffer_tail].state = new_state; entries[buffer_tail].state = new_state;
} }
}; };

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@ -204,9 +201,7 @@ static_assert(sizeof(ConsoleSixAxisSensorSharedMemoryFormat) == 0x20,
// This is nn::hid::detail::SharedMemoryFormat // This is nn::hid::detail::SharedMemoryFormat
struct SharedMemoryFormat { struct SharedMemoryFormat {
void Initialize() { void Initialize() {}
npad_condition = NpadCondition{};
}
DebugPadSharedMemoryFormat debug_pad; DebugPadSharedMemoryFormat debug_pad;
TouchScreenSharedMemoryFormat touch_screen; TouchScreenSharedMemoryFormat touch_screen;
@ -223,9 +218,7 @@ struct SharedMemoryFormat {
ConsoleSixAxisSensorSharedMemoryFormat console; ConsoleSixAxisSensorSharedMemoryFormat console;
INSERT_PADDING_BYTES(0x19E0); INSERT_PADDING_BYTES(0x19E0);
MouseSharedMemoryFormat debug_mouse; MouseSharedMemoryFormat debug_mouse;
INSERT_PADDING_BYTES(0x200); INSERT_PADDING_BYTES(0x2000);
NpadCondition npad_condition;
INSERT_PADDING_BYTES(0x1DF0);
}; };
static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset"); static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset");
static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset"); static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset");
@ -243,8 +236,6 @@ static_assert(offsetof(SharedMemoryFormat, npad) == 0x9A00, "npad has wrong offs
static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset"); static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset");
static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset"); static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset");
static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset"); static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset");
static_assert(offsetof(SharedMemoryFormat, npad_condition) == 0x3E200,
"npad_condition has wrong offset");
static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size"); static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size");
} // namespace Service::HID } // namespace Service::HID

View file

@ -45,10 +45,6 @@ if (NOT APPLE AND ENABLE_OPENGL)
target_compile_definitions(qt_common PUBLIC HAS_OPENGL) target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
endif() endif()
if (UNIX AND NOT APPLE) if (NOT WIN32)
if (TARGET Qt6::GuiPrivate)
target_link_libraries(qt_common PRIVATE Qt6::GuiPrivate)
else()
target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
endif()
endif() endif()

View file

@ -386,9 +386,11 @@ void BufferCache<P>::BindHostComputeBuffers() {
template <class P> template <class P>
void BufferCache<P>::SetUniformBuffersState(const std::array<u32, NUM_STAGES>& mask, void BufferCache<P>::SetUniformBuffersState(const std::array<u32, NUM_STAGES>& mask,
const UniformBufferSizes* sizes) { const UniformBufferSizes* sizes) {
if (channel_state->enabled_uniform_buffer_masks != mask) {
channel_state->fast_bound_uniform_buffers.fill(0);
if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
if (channel_state->enabled_uniform_buffer_masks != mask) {
if constexpr (IS_OPENGL) {
channel_state->fast_bound_uniform_buffers.fill(0);
}
channel_state->dirty_uniform_buffers.fill(~u32{0}); channel_state->dirty_uniform_buffers.fill(~u32{0});
channel_state->uniform_buffer_binding_sizes.fill({}); channel_state->uniform_buffer_binding_sizes.fill({});
} }
@ -804,7 +806,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
channel_state->uniform_buffer_binding_sizes[stage][binding_index] != size; channel_state->uniform_buffer_binding_sizes[stage][binding_index] != size;
if (should_fast_bind) { if (should_fast_bind) {
// We only have to bind when the currently bound buffer is not the fast version // We only have to bind when the currently bound buffer is not the fast version
channel_state->fast_bound_uniform_buffers[stage] |= 1u << binding_index; channel_state->fast_bound_uniform_buffers[stage] |= 1U << binding_index;
channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size; channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
runtime.BindFastUniformBuffer(stage, binding_index, size); runtime.BindFastUniformBuffer(stage, binding_index, size);
} }
@ -813,8 +815,10 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
return; return;
} }
} }
channel_state->fast_bound_uniform_buffers[stage] |= 1u << binding_index; if constexpr (IS_OPENGL) {
channel_state->fast_bound_uniform_buffers[stage] |= 1U << binding_index;
channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size; channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
}
// Stream buffer path to avoid stalling on non-Nvidia drivers or Vulkan // Stream buffer path to avoid stalling on non-Nvidia drivers or Vulkan
const std::span<u8> span = runtime.BindMappedUniformBuffer(stage, binding_index, size); const std::span<u8> span = runtime.BindMappedUniformBuffer(stage, binding_index, size);
device_memory.ReadBlockUnsafe(device_addr, span.data(), size); device_memory.ReadBlockUnsafe(device_addr, span.data(), size);
@ -835,6 +839,9 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
} }
const u32 offset = buffer.Offset(device_addr); const u32 offset = buffer.Offset(device_addr);
if constexpr (IS_OPENGL) { if constexpr (IS_OPENGL) {
// Fast buffer will be unbound
channel_state->fast_bound_uniform_buffers[stage] &= ~(1U << binding_index);
// Mark the index as dirty if offset doesn't match // Mark the index as dirty if offset doesn't match
const bool is_copy_bind = offset != 0 && !runtime.SupportsNonZeroUniformOffset(); const bool is_copy_bind = offset != 0 && !runtime.SupportsNonZeroUniformOffset();
channel_state->dirty_uniform_buffers[stage] |= (is_copy_bind ? 1U : 0U) << index; channel_state->dirty_uniform_buffers[stage] |= (is_copy_bind ? 1U : 0U) << index;
@ -848,7 +855,6 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
} else { } else {
runtime.BindUniformBuffer(buffer, offset, size); runtime.BindUniformBuffer(buffer, offset, size);
} }
channel_state->fast_bound_uniform_buffers[stage] &= ~(1u << binding_index);
} }
template <class P> template <class P>
@ -1783,7 +1789,12 @@ std::span<u8> BufferCache<P>::ImmediateBuffer(size_t wanted_capacity) {
template <class P> template <class P>
bool BufferCache<P>::HasFastUniformBufferBound(size_t stage, u32 binding_index) const noexcept { bool BufferCache<P>::HasFastUniformBufferBound(size_t stage, u32 binding_index) const noexcept {
return ((channel_state->fast_bound_uniform_buffers[stage] >> binding_index) & 1u) != 0; if constexpr (IS_OPENGL) {
return ((channel_state->fast_bound_uniform_buffers[stage] >> binding_index) & 1) != 0;
} else {
// Only OpenGL has fast uniform buffers
return false;
}
} }
template <class P> template <class P>

View file

@ -54,8 +54,6 @@ constexpr u32 NUM_STORAGE_BUFFERS = 16;
constexpr u32 NUM_TEXTURE_BUFFERS = 32; constexpr u32 NUM_TEXTURE_BUFFERS = 32;
constexpr u32 NUM_STAGES = 5; constexpr u32 NUM_STAGES = 5;
static_assert(NUM_GRAPHICS_UNIFORM_BUFFERS <= 32, "fast bitmask must fit u32");
using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>; using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>;
using ComputeUniformBufferSizes = std::array<u32, NUM_COMPUTE_UNIFORM_BUFFERS>; using ComputeUniformBufferSizes = std::array<u32, NUM_COMPUTE_UNIFORM_BUFFERS>;
@ -139,8 +137,8 @@ public:
u32 written_compute_texture_buffers = 0; u32 written_compute_texture_buffers = 0;
u32 image_compute_texture_buffers = 0; u32 image_compute_texture_buffers = 0;
std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS> uniform_cache_hits{}; std::array<u32, 16> uniform_cache_hits{};
std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS> uniform_cache_shots{}; std::array<u32, 16> uniform_cache_shots{};
u32 uniform_buffer_skip_cache_size = DEFAULT_SKIP_CACHE_SIZE; u32 uniform_buffer_skip_cache_size = DEFAULT_SKIP_CACHE_SIZE;

View file

@ -337,11 +337,6 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& m
uint8_pass = std::make_unique<Uint8Pass>(device, scheduler, descriptor_pool, staging_pool, uint8_pass = std::make_unique<Uint8Pass>(device, scheduler, descriptor_pool, staging_pool,
compute_pass_descriptor_queue); compute_pass_descriptor_queue);
} }
const u32 ubo_align = static_cast<u32>(
device.GetUniformBufferAlignment() //check if the device has it
);
// add the ability to change the size in settings in future
uniform_ring.Init(device, memory_allocator, 8 * 1024 * 1024 /* 8 MiB */, ubo_align ? ubo_align : 256);
quad_array_index_buffer = std::make_shared<QuadArrayIndexBuffer>(device_, memory_allocator_, quad_array_index_buffer = std::make_shared<QuadArrayIndexBuffer>(device_, memory_allocator_,
scheduler_, staging_pool_); scheduler_, staging_pool_);
quad_strip_index_buffer = std::make_shared<QuadStripIndexBuffer>(device_, memory_allocator_, quad_strip_index_buffer = std::make_shared<QuadStripIndexBuffer>(device_, memory_allocator_,
@ -360,42 +355,6 @@ void BufferCacheRuntime::FreeDeferredStagingBuffer(StagingBufferRef& ref) {
staging_pool.FreeDeferred(ref); staging_pool.FreeDeferred(ref);
} }
void BufferCacheRuntime::UniformRing::Init(const Device& device,
MemoryAllocator& alloc,
u64 bytes, u32 alignment) {
for (size_t i = 0; i < NUM_FRAMES; ++i) {
VkBufferCreateInfo ci{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = bytes,
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
};
buffers[i] = alloc.CreateBuffer(ci, MemoryUsage::Upload);
mapped[i] = buffers[i].Mapped().data();
}
size = bytes;
align = alignment ? alignment : 256;
head = 0;
current_frame = 0;
}
std::span<u8> BufferCacheRuntime::UniformRing::Alloc(u32 bytes, u32& out_offset) {
const u64 aligned = Common::AlignUp(head, static_cast<u64>(align));
u64 end = aligned + bytes;
if (end > size) {
return {}; // Fallback to staging pool
}
out_offset = static_cast<u32>(aligned);
head = end;
return {mapped[current_frame] + out_offset, bytes};
}
u64 BufferCacheRuntime::GetDeviceLocalMemory() const { u64 BufferCacheRuntime::GetDeviceLocalMemory() const {
return device.GetDeviceLocalMemory(); return device.GetDeviceLocalMemory();
} }
@ -416,7 +375,6 @@ void BufferCacheRuntime::TickFrame(Common::SlotVector<Buffer>& slot_buffers) noe
for (auto it = slot_buffers.begin(); it != slot_buffers.end(); it++) { for (auto it = slot_buffers.begin(); it != slot_buffers.end(); it++) {
it->ResetUsageTracking(); it->ResetUsageTracking();
} }
uniform_ring.BeginFrame();
} }
void BufferCacheRuntime::Finish() { void BufferCacheRuntime::Finish() {

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -127,15 +124,8 @@ public:
void BindTransformFeedbackBuffers(VideoCommon::HostBindings<Buffer>& bindings); void BindTransformFeedbackBuffers(VideoCommon::HostBindings<Buffer>& bindings);
std::span<u8> BindMappedUniformBuffer([[maybe_unused]] size_t /*stage*/, std::span<u8> BindMappedUniformBuffer([[maybe_unused]] size_t stage,
[[maybe_unused]] u32 /*binding_index*/, [[maybe_unused]] u32 binding_index, u32 size) {
u32 size) {
u32 offset = 0;
if (auto span = uniform_ring.Alloc(size, offset); !span.empty()) {
BindBuffer(*uniform_ring.buffers[uniform_ring.current_frame], offset, size);
return span;
}
// Fallback for giant requests
const StagingBufferRef ref = staging_pool.Request(size, MemoryUsage::Upload); const StagingBufferRef ref = staging_pool.Request(size, MemoryUsage::Upload);
BindBuffer(ref.buffer, static_cast<u32>(ref.offset), size); BindBuffer(ref.buffer, static_cast<u32>(ref.offset), size);
return ref.mapped_span; return ref.mapped_span;
@ -163,24 +153,6 @@ private:
void ReserveNullBuffer(); void ReserveNullBuffer();
vk::Buffer CreateNullBuffer(); vk::Buffer CreateNullBuffer();
struct UniformRing {
static constexpr size_t NUM_FRAMES = 3;
std::array<vk::Buffer, NUM_FRAMES> buffers{};
std::array<u8*, NUM_FRAMES> mapped{};
u64 size = 0;
u64 head = 0;
u32 align = 256;
size_t current_frame = 0;
void Init(const Device& device, MemoryAllocator& alloc, u64 bytes, u32 alignment);
void BeginFrame() {
current_frame = (current_frame + 1) % NUM_FRAMES;
head = 0;
}
std::span<u8> Alloc(u32 bytes, u32& out_offset);
};
UniformRing uniform_ring;
const Device& device; const Device& device;
MemoryAllocator& memory_allocator; MemoryAllocator& memory_allocator;
Scheduler& scheduler; Scheduler& scheduler;

View file

@ -33,19 +33,29 @@ constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
size_t GetStreamBufferSize(const Device& device) { size_t GetStreamBufferSize(const Device& device) {
VkDeviceSize size{0}; VkDeviceSize size{0};
if (device.HasDebuggingToolAttached()) { if (device.HasDebuggingToolAttached()) {
ForEachDeviceLocalHostVisibleHeap(device, [&size](size_t index, VkMemoryHeap& heap) { bool found_heap = false;
ForEachDeviceLocalHostVisibleHeap(device, [&size, &found_heap](size_t /*index*/, VkMemoryHeap& heap) {
size = (std::max)(size, heap.size); size = (std::max)(size, heap.size);
found_heap = true;
}); });
// If no suitable heap was found fall back to the default cap to avoid creating a zero-sized stream buffer.
if (!found_heap) {
size = MAX_STREAM_BUFFER_SIZE;
} else if (size <= 256_MiB) {
// If rebar is not supported, cut the max heap size to 40%. This will allow 2 captures to be // If rebar is not supported, cut the max heap size to 40%. This will allow 2 captures to be
// loaded at the same time in RenderDoc. If rebar is supported, this shouldn't be an issue // loaded at the same time in RenderDoc. If rebar is supported, this shouldn't be an issue
// as the heap will be much larger. // as the heap will be much larger.
if (size <= 256_MiB) {
size = size * 40 / 100; size = size * 40 / 100;
} }
} else { } else {
size = MAX_STREAM_BUFFER_SIZE; size = MAX_STREAM_BUFFER_SIZE;
} }
return (std::min)(Common::AlignUp(size, MAX_ALIGNMENT), MAX_STREAM_BUFFER_SIZE);
// Clamp to the configured maximum, align up for safety, and ensure a sane minimum so
// region_size (stream_buffer_size / NUM_SYNCS) never becomes zero.
const VkDeviceSize aligned = (std::min)(Common::AlignUp(size, MAX_ALIGNMENT), MAX_STREAM_BUFFER_SIZE);
const VkDeviceSize min_size = MAX_ALIGNMENT * StagingBufferPool::NUM_SYNCS;
return static_cast<size_t>((std::max)(aligned, min_size));
} }
} // Anonymous namespace } // Anonymous namespace
@ -106,31 +116,53 @@ void StagingBufferPool::TickFrame() {
} }
StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) { StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
if (AreRegionsActive(Region(free_iterator) + 1, const size_t aligned_size = Common::AlignUp(size, MAX_ALIGNMENT);
(std::min)(Region(iterator + size) + 1, NUM_SYNCS))) { const bool wraps = iterator + size >= stream_buffer_size;
const size_t new_iterator =
wraps ? aligned_size : Common::AlignUp(iterator + size, MAX_ALIGNMENT);
const size_t begin_region = wraps ? 0 : Region(iterator);
const size_t last_byte = new_iterator == 0 ? 0 : new_iterator - 1;
const size_t end_region = (std::min)(Region(last_byte) + 1, NUM_SYNCS);
const size_t guard_begin = (std::min)(Region(free_iterator) + 1, NUM_SYNCS);
if (!wraps) {
if (guard_begin < end_region && AreRegionsActive(guard_begin, end_region)) {
// Avoid waiting for the previous usages to be free // Avoid waiting for the previous usages to be free
return GetStagingBuffer(size, MemoryUsage::Upload); return GetStagingBuffer(size, MemoryUsage::Upload);
} }
} else if (guard_begin < NUM_SYNCS && AreRegionsActive(guard_begin, NUM_SYNCS)) {
// Avoid waiting for the previous usages to be free
return GetStagingBuffer(size, MemoryUsage::Upload);
}
const u64 current_tick = scheduler.CurrentTick(); const u64 current_tick = scheduler.CurrentTick();
std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + Region(iterator), std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + Region(iterator),
current_tick); current_tick);
used_iterator = iterator; used_iterator = iterator;
free_iterator = (std::max)(free_iterator, iterator + size);
if (iterator + size >= stream_buffer_size) { if (wraps) {
std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + NUM_SYNCS, std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + NUM_SYNCS,
current_tick); current_tick);
used_iterator = 0; used_iterator = 0;
iterator = 0; iterator = 0;
free_iterator = size; free_iterator = size;
const size_t head_last_byte = aligned_size == 0 ? 0 : aligned_size - 1;
if (AreRegionsActive(0, Region(size) + 1)) { const size_t head_end_region = (std::min)(Region(head_last_byte) + 1, NUM_SYNCS);
if (AreRegionsActive(0, head_end_region)) {
// Avoid waiting for the previous usages to be free // Avoid waiting for the previous usages to be free
return GetStagingBuffer(size, MemoryUsage::Upload); return GetStagingBuffer(size, MemoryUsage::Upload);
} }
} }
const size_t offset = iterator;
iterator = Common::AlignUp(iterator + size, MAX_ALIGNMENT); std::fill(sync_ticks.begin() + begin_region, sync_ticks.begin() + end_region, current_tick);
const size_t offset = wraps ? 0 : iterator;
iterator = new_iterator;
if (!wraps) {
free_iterator = (std::max)(free_iterator, offset + size);
}
return StagingBufferRef{ return StagingBufferRef{
.buffer = *stream_buffer, .buffer = *stream_buffer,
.offset = static_cast<VkDeviceSize>(offset), .offset = static_cast<VkDeviceSize>(offset),

View file

@ -393,8 +393,16 @@ target_link_libraries(yuzu PRIVATE common core input_common frontend_common netw
target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets) target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets)
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
if (NOT WIN32)
target_include_directories(yuzu PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
endif()
if (UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
target_link_libraries(yuzu PRIVATE Qt6::DBus) target_link_libraries(yuzu PRIVATE Qt6::DBus)
if (TARGET Qt6::GuiPrivate)
target_link_libraries(yuzu PRIVATE Qt6::GuiPrivate)
endif()
endif() endif()
target_compile_definitions(yuzu PRIVATE target_compile_definitions(yuzu PRIVATE

View file

@ -83,7 +83,8 @@ void ConfigureDebug::SetConfiguration() {
#ifdef YUZU_USE_QT_WEB_ENGINE #ifdef YUZU_USE_QT_WEB_ENGINE
ui->disable_web_applet->setChecked(UISettings::values.disable_web_applet.GetValue()); ui->disable_web_applet->setChecked(UISettings::values.disable_web_applet.GetValue());
#else #else
ui->disable_web_applet->setVisible(false); ui->disable_web_applet->setEnabled(false);
ui->disable_web_applet->setText(tr("Web applet not compiled"));
#endif #endif
} }