Compare commits

...

7 Commits

Author SHA1 Message Date
lizzie 2672f376dd 2026-09-13 16:21:42
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-13 16:21:42 +00:00
lizzie 045274b2da 2026-09-13 16:12:52
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-13 16:12:53 +00:00
lizzie 9d9495f3b3 2026-09-13 06:27:57
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-13 06:27:57 +00:00
lizzie 13129506ba 2026-09-13 06:19:49
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-13 06:19:50 +00:00
lizzie 5f4754b3e1 2026-09-13 06:00:35
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-13 06:00:36 +00:00
lizzie c5d12e5bc6 2026-09-12 19:50:46
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-12 19:50:46 +00:00
PavelBARABANOV 5d150cac5c [dynarmic, am, android, ns] Fixes the latest qlaunch regressions on Android and adds cmd23 for launching games on FW 23 (#4407)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
[dynarmic] use TST + B.NE instead of TBNZ for marked bit
Fixes qlaunch and ac3 crashes.

[am] Bruno FIX OVERLAY 2.0
Fixes incorrect load display when the overlay applet is enabled in AC3.

[android] handle empty programId in Game.settingsName
The ReShade post-processing change started calling
SettingsFile.loadCustomConfig() on every drawer open through
withPerGameConfig(), which exposed a pre-existing crash in
Game.settingsName when programId was an empty string.

[ns] use GetApplicationControlData3 for cmd23 in IReadOnlyApplicationControlDataInterface
We can use this method for now for launching games on fw23, while we don't have all the information.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4407
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-13 02:13:06 +02:00
5 changed files with 106 additions and 90 deletions
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -37,7 +37,7 @@ class Game(
val settingsName: String
get() {
val programIdLong = programId.toLong()
val programIdLong = programId.toLongOrNull() ?: 0L
return if (programIdLong == 0L) {
FileUtil.getFilename(Uri.parse(path))
} else {
@@ -47,7 +47,7 @@ class Game(
val programIdHex: String
get() {
val programIdLong = programId.toLong()
val programIdLong = programId.toLongOrNull() ?: 0L
return if (programIdLong == 0L) {
"0"
} else {
+86 -77
View File
@@ -67,48 +67,59 @@ public:
LOG_WARNING(Audio_DSP, "using ffmpeg native opus decoder");
codec = avcodec_find_decoder(AV_CODEC_ID_OPUS);
}
if (codec) {
if ((avc = avc ? avc : avcodec_alloc_context3(codec))) {
if (is_libopus) {
const std::array<u8, 2> mapping_arr{0, 1};
mappings = mappings ? mappings : mapping_arr.data();
// handles null codec
avcodec_free_context(&avc);
if ((avc = avcodec_alloc_context3(codec))) {
if (is_libopus) {
const std::array<u8, 2> mapping_arr{0, 1};
mappings = mappings ? mappings : mapping_arr.data();
// freed by avcodec_context_free()
u8 *edata = reinterpret_cast<u8*>(av_mallocz(OPUS_HEAD_SIZE + 2 * OPUS_MAX_CHANNELS + AV_INPUT_BUFFER_PADDING_SIZE));
ASSERT(edata);
edata[9] = u8(channel_count); //channels
edata[10] = u8(0); //opus->pre_skip
edata[16] = u8(0); //gain_db
edata[18] = u8(0); //channel_map
edata[OPUS_HEAD_SIZE + 0] = u8(total_stream_count);
edata[OPUS_HEAD_SIZE + 1] = u8(stereo_stream_count);
if (channel_count >= 1) edata[OPUS_HEAD_SIZE + 2] = mappings[0];
if (channel_count >= 2) edata[OPUS_HEAD_SIZE + 3] = mappings[1];
avc->extradata = edata;
avc->extradata_size = OPUS_HEAD_SIZE + 2 * channel_count;
}
// freed by avcodec_context_free()
u8 *edata = reinterpret_cast<u8*>(av_mallocz(OPUS_HEAD_SIZE + 2 * OPUS_MAX_CHANNELS + AV_INPUT_BUFFER_PADDING_SIZE));
ASSERT(edata);
edata[9] = u8(channel_count); //channels
edata[10] = u8(0); //opus->pre_skip
edata[16] = u8(0); //gain_db
edata[18] = u8(0); //channel_map
edata[OPUS_HEAD_SIZE + 0] = u8(total_stream_count);
edata[OPUS_HEAD_SIZE + 1] = u8(stereo_stream_count);
if (channel_count >= 1) edata[OPUS_HEAD_SIZE + 2] = mappings[0];
if (channel_count >= 2) edata[OPUS_HEAD_SIZE + 3] = mappings[1];
avc->extradata = edata;
avc->extradata_size = OPUS_HEAD_SIZE + 2 * channel_count;
}
// FFmpeg hardcodes sample rate
avc->sample_rate = sample_rate;
avc->request_sample_fmt = AV_SAMPLE_FMT_S16;
av_channel_layout_default(&avc->ch_layout, channel_count);
if (avcodec_open2(avc, codec, nullptr) >= 0) {
avpkt = av_packet_alloc();
frame = av_frame_alloc();
return ResultSuccess;
} else {
avcodec_free_context(&avc);
// FFmpeg hardcodes sample rate
avc->sample_rate = sample_rate;
avc->request_sample_fmt = AV_SAMPLE_FMT_S16;
av_channel_layout_default(&avc->ch_layout, channel_count);
if (avcodec_open2(avc, codec, nullptr) >= 0) {
pkt = av_packet_alloc();
frame = av_frame_alloc();
// opus fltp -> libopus s16
if (swr_alloc_set_opts2(
&swr,
&avc->ch_layout, AV_SAMPLE_FMT_S16, 48000,
&avc->ch_layout, AV_SAMPLE_FMT_FLTP, 48000,
0, nullptr) >= 0) {
if (swr_init(swr) >= 0) {
return ResultSuccess;
}
}
}
swr_free(&swr);
av_frame_free(&frame);
av_packet_free(&pkt);
avcodec_free_context(&avc);
}
return Service::Audio::ResultLibOpusInternalError;
}
Result Shutdown() {
avcodec_free_context(&avc);
swr_free(&swr);
av_frame_free(&frame);
av_packet_free(&avpkt);
av_packet_free(&pkt);
avcodec_free_context(&avc);
return ResultSuccess;
}
@@ -122,64 +133,62 @@ public:
Result Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, u64 input_data, u64 input_data_size) {
out_sample_count = 0;
if (input_data_size == 0 || output_data_size == 0)
return ResultSuccess;
if (avc) {
int rem_output_bytes = int(output_data_size);
while (rem_output_bytes > 0) {
int r = avcodec_receive_frame(avc, frame);
if (r == AVERROR(EAGAIN)) {
av_packet_unref(avpkt);
av_new_packet(avpkt, int(input_data_size));
std::memcpy(avpkt->data, reinterpret_cast<const u8*>(input_data), input_data_size);
r = avcodec_send_packet(avc, avpkt);
ASSERT(r >= 0);
} else if (r == AVERROR_EOF) {
break;
} else if (r >= 0) {
auto const bsize = av_samples_get_buffer_size(nullptr, frame->ch_layout.nb_channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1);
if (frame->format == AV_SAMPLE_FMT_S16) {
std::memcpy(reinterpret_cast<s16*>(output_data) + (int(output_data_size) - rem_output_bytes), frame->data[0], size_t(bsize));
} else {
SwrContext *swr = nullptr;
if (swr_alloc_set_opts2(
&swr,
&avc->ch_layout,
AV_SAMPLE_FMT_S16,
48000,
&avc->ch_layout,
(enum AVSampleFormat)frame->format,
48000,
0,
nullptr
) >= 0) {
if (swr_init(swr) >= 0) {
AVFrame *s16_frame = av_frame_alloc();
s16_frame->format = AV_SAMPLE_FMT_S16;
s16_frame->sample_rate = frame->sample_rate;
av_channel_layout_copy(&s16_frame->ch_layout, &frame->ch_layout);
s16_frame->nb_samples = frame->nb_samples;
av_frame_get_buffer(s16_frame, 0);
swr_convert(swr, s16_frame->data, s16_frame->nb_samples, (const uint8_t **)frame->data, frame->nb_samples);
std::memcpy(reinterpret_cast<s16*>(output_data) + (int(output_data_size) - rem_output_bytes), s16_frame->data[0], size_t(bsize));
swr_free(&swr);
}
int r;
if ((r = av_new_packet(pkt, int(input_data_size))) >= 0) {
std::memcpy(pkt->data, reinterpret_cast<const u8*>(input_data), input_data_size);
if ((r = avcodec_send_packet(avc, pkt)) >= 0) {
int rem_output_bytes = int(output_data_size);
av_frame_unref(frame);
do {
r = avcodec_receive_frame(avc, frame);
auto const input_bsize = av_samples_get_buffer_size(frame->linesize, frame->ch_layout.nb_channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1);
ASSERT(rem_output_bytes - input_bsize >= 0);
auto const dst_data = reinterpret_cast<s16*>(output_data + (int(output_data_size) - rem_output_bytes));
if (frame->format == AV_SAMPLE_FMT_S16) {
// input_bsize == output_bsize
ASSERT(size_t(int(output_data_size) - rem_output_bytes + input_bsize) <= size_t(output_data_size));
std::memcpy(dst_data, frame->data[0], size_t(input_bsize));
} else {
int out_samples = int(av_rescale_rnd(swr_get_delay(swr, frame->sample_rate) + frame->nb_samples, frame->sample_rate, frame->sample_rate, AV_ROUND_UP));
uint8_t *output = nullptr;
av_samples_alloc(&output, frame->linesize, frame->ch_layout.nb_channels, out_samples, AV_SAMPLE_FMT_S16, 0);
out_samples = swr_convert(swr, &output, out_samples, (const uint8_t **)frame->data, frame->nb_samples);
auto const output_bsize = av_samples_get_buffer_size(frame->linesize, frame->ch_layout.nb_channels, out_samples, AV_SAMPLE_FMT_S16, 1);
std::memcpy(dst_data, output, size_t(output_bsize));
av_freep(&output);
}
out_sample_count += frame->nb_samples;
rem_output_bytes -= input_bsize;
av_frame_unref(frame);
} while (r >= 0 && rem_output_bytes > 0);
if (r == AVERROR(EAGAIN) || r == AVERROR_EOF) {
// non-errors
LOG_DEBUG(Audio_DSP, "{}", r);
} else if (r < 0) {
// errors
LOG_ERROR(Audio_DSP, "{}", r);
}
out_sample_count += frame->nb_samples;
rem_output_bytes -= bsize;
ASSERT(rem_output_bytes == 0 && "remaining bytes!");
av_packet_unref(pkt);
return ResultSuccess;
} else {
LOG_ERROR(Audio_DSP, "{}", r);
break;
}
} else {
LOG_ERROR(Audio_DSP, "{}", r);
}
ASSERT(rem_output_bytes == 0 && "remaining bytes!");
return ResultSuccess;
av_packet_unref(pkt);
}
return Service::Audio::ResultLibOpusInvalidState;
}
AVCodecContext* avc = nullptr;
AVPacket* avpkt = nullptr;
AVPacket* pkt = nullptr;
AVFrame* frame = nullptr;
SwrContext* swr = nullptr;
};
} // namespace
@@ -73,16 +73,20 @@ Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
R_TRY(m_manager_display_service->CreateManagedLayer(
out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
(void)m_display_service->GetContainer()->SetLayerStackMask(*out_layer_id,
this->GetLayerStackMask());
if (m_applet_id != AppletId::Application) {
(void)m_manager_display_service->SetLayerBlending(m_blending_enabled, *out_layer_id);
if (m_applet_id == AppletId::OverlayDisplay) {
(void)m_manager_display_service->SetLayerZIndex(-1, *out_layer_id);
(void)m_display_service->GetContainer()->SetLayerIsOverlay(*out_layer_id, true);
(void)m_manager_display_service->SetLayerZIndex(Overlay, *out_layer_id);
} else {
(void)m_manager_display_service->SetLayerZIndex(1, *out_layer_id);
(void)m_manager_display_service->SetLayerZIndex(Foreground, *out_layer_id);
}
}
(void)m_display_service->GetContainer()->SetLayerZIndex(*out_layer_id, true);
m_display_service->GetContainer()->SetLayerZIndex(*out_layer_id, true);
m_managed_display_layers.emplace(*out_layer_id);
R_SUCCEED();
@@ -122,14 +126,16 @@ Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
// Ensure the overlay layer is visible
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
m_manager_display_service->SetLayerBlending(m_blending_enabled, m_system_shared_layer_id);
s32 initial_z = 1;
(void)m_display_service->GetContainer()->SetLayerZIndex(m_system_shared_layer_id, true);
(void)m_manager_display_service->SetLayerBlending(m_blending_enabled, m_system_shared_layer_id);
s32 initial_z = Foreground;
if (m_applet_id == AppletId::OverlayDisplay) {
initial_z = -1;
initial_z = Overlay;
(void)m_manager_display_service->SetLayerZIndex(initial_z, m_system_shared_layer_id);
(void)m_display_service->GetContainer()->SetLayerIsOverlay(m_system_shared_layer_id, true);
}
m_manager_display_service->SetLayerZIndex(initial_z, m_system_shared_layer_id);
m_display_service->GetContainer()->SetLayerZIndex(m_system_shared_layer_id, true);
m_managed_display_layers.emplace(m_system_shared_layer_id);
R_SUCCEED();
}
@@ -142,6 +142,7 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa
{10, &IReadOnlyApplicationControlDataInterface::ListApplicationIcon, "ListApplicationIcon"},
{13, &IReadOnlyApplicationControlDataInterface::ListApplicationTitle, "ListApplicationTitle"},
{19, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData3>, "GetApplicationControlData"},
{23, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData3>, "GetApplicationControlData"},
};
// clang-format on
@@ -274,8 +274,8 @@ std::pair<oaknut::XReg, oaknut::XReg> InlinePageTableEmitVAddrLookup(oaknut::Cod
code.LDR(Xscratch0, Xpagetable, Xscratch0);
if (ctx.conf.page_table_marked_bit) {
// check for marked bit
code.TBNZ(Xscratch0, *ctx.conf.page_table_marked_bit, *fallback);
code.TST(Xscratch0, 1ULL << *ctx.conf.page_table_marked_bit);
code.B(NE, *fallback);
}
if (ctx.conf.page_table_pointer_mask != 0) {