From a25a48de505dadb5c0fce4afbd0da54a77f3963d Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 13:43:05 +0000 Subject: [PATCH 1/5] [compat] improve thread naming logic Signed-off-by: lizzie --- src/common/thread.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/common/thread.cpp b/src/common/thread.cpp index da1fa9b6c5..2de7465a22 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp @@ -1,6 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -18,9 +17,8 @@ #else #if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) #include -#else -#include #endif +#include #include #endif #ifndef _WIN32 @@ -93,33 +91,35 @@ void SetCurrentThreadName(const char* name) { #else // !MSVC_VER, so must be POSIX threads // MinGW with the POSIX threading model does not support pthread_setname_np -#if !defined(_WIN32) || defined(_MSC_VER) void SetCurrentThreadName(const char* name) { + // See for reference + // https://gitlab.freedesktop.org/mesa/mesa/-/blame/main/src/util/u_thread.c?ref_type=heads#L75 #ifdef __APPLE__ pthread_setname_np(name); +#elif defined(__HAIKU__) + rename_thread(find_thread(NULL), name); #elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) pthread_set_name_np(pthread_self(), name); #elif defined(__NetBSD__) pthread_setname_np(pthread_self(), "%s", (void*)name); -#elif defined(__linux__) - // Linux limits thread names to 15 characters and will outright reject any - // attempt to set a longer name with ERANGE. - std::string truncated(name, (std::min)(strlen(name), static_cast(15))); - if (int e = pthread_setname_np(pthread_self(), truncated.c_str())) { - errno = e; - LOG_ERROR(Common, "Failed to set thread name to '{}': {}", truncated, GetLastErrorMsg()); +#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun__) || defined(__glibc__) || defined(__managarm__) + int ret = pthread_setname_np(pthread_self(), name); + if (ret == ERANGE) { + // Linux limits thread names to 15 characters and will outright reject any + // attempt to set a longer name with ERANGE. + char buf[16]; + size_t const len = std::min(std::strlen(name), sizeof(buf) - 1); + std::memcpy(buf, name, len); + buf[len] = '\0'; + pthread_setname_np(pthread_self(), buf); } +#elif !defined(_WIN32) || defined(_MSC_VER) + // mingw stub + (void)name; #else pthread_setname_np(pthread_self(), name); #endif } -#endif - -#if defined(_WIN32) -void SetCurrentThreadName(const char* name) { - // Do Nothing on MingW -} -#endif #endif From 49f29e5071e02ad5bbeed7b0a3ae7997617beb87 Mon Sep 17 00:00:00 2001 From: SDK Chan Date: Mon, 22 Sep 2025 17:55:41 +0200 Subject: [PATCH 2/5] [shader_recompiler] Rewrite ISBERD (#2541) I tried to simplify ISBERD a little bit, and remove unneeded data shifting, and unneeded complexity through helper functions I previously added. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2541 Reviewed-by: MaranBr Reviewed-by: crueter Co-authored-by: SDK Chan Co-committed-by: SDK Chan --- .../frontend/maxwell/translate/impl/impl.cpp | 36 ----- .../frontend/maxwell/translate/impl/impl.h | 30 ---- .../impl/internal_stage_buffer_entry_read.cpp | 128 +++++++++++++----- 3 files changed, 94 insertions(+), 100 deletions(-) diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp index 157e5dfaaf..8b5a103006 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp @@ -271,40 +271,4 @@ void TranslatorVisitor::ResetOFlag() { SetOFlag(ir.Imm1(false)); } -IR::U32 TranslatorVisitor::apply_ISBERD_shift(IR::U32 result, Isberd::Shift shift_value) { - if (shift_value != Isberd::Shift::Default) { - return ir.ShiftLeftLogical(result, ir.Imm32(1)); - } - return result; -} - -IR::U32 TranslatorVisitor::apply_ISBERD_size_read(IR::U32 address, Isberd::SZ sz) { - switch (sz) { - case Isberd::SZ::U8: - return ir.LoadGlobalU8(ir.UConvert(64, address)); - case Isberd::SZ::U16: - return ir.LoadGlobalU16(ir.UConvert(64, address)); - case Isberd::SZ::U32: - case Isberd::SZ::F32: - return ir.LoadGlobal32(ir.UConvert(64, address)); - default: - UNREACHABLE(); - } -} - -IR::U32 TranslatorVisitor::compute_ISBERD_address(IR::Reg src_reg, u32 src_reg_num, u32 imm, u64 skew_value) { - IR::U32 address{}; - if (src_reg_num == 0xFF) { - address = ir.Imm32(imm); - } else { - auto offset = ir.Imm32(imm); - address = ir.IAdd(X(src_reg), offset); - if (skew_value != 0) { - address = ir.IAdd(address, ir.LaneId()); - } - } - - return address; -}; - } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h index 1b2547a1bd..37963dc777 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h @@ -56,30 +56,6 @@ enum class FPCompareOp : u64 { T, }; -namespace Isberd { -enum class Mode : u64 { - Default, - Patch, - Prim, - Attr, -}; - -enum class Shift : u64 { - Default, - U16, - B32, -}; - -enum class SZ : u64 { - U8, - U16, - U32, - F32, -}; - -} // namespace Isberd - - class TranslatorVisitor { public: explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_}, ir(block) {} @@ -408,12 +384,6 @@ public: void ResetSFlag(); void ResetCFlag(); void ResetOFlag(); - -private: - // Helper functions for various translator visitors - IR::U32 apply_ISBERD_shift(IR::U32 result, Isberd::Shift shift_value); - IR::U32 apply_ISBERD_size_read(IR::U32 address, Isberd::SZ sz_value); - IR::U32 compute_ISBERD_address(IR::Reg src_reg, u32 src_reg_num, u32 imm, u64 skew_value); }; } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/internal_stage_buffer_entry_read.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/internal_stage_buffer_entry_read.cpp index 2aaf85772d..e6345de65e 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/internal_stage_buffer_entry_read.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/internal_stage_buffer_entry_read.cpp @@ -9,9 +9,52 @@ #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" namespace Shader::Maxwell { +namespace { +enum class Mode : u64 { + Default, + Patch, + Prim, + Attr, +}; + +enum class SZ : u64 { + U8, + U16, + U32, + F32 +}; + +enum class Shift : u64 { + Default, + U16, + B32, +}; + +IR::U32 scaleIndex(IR::IREmitter& ir, IR::U32 index, Shift shift) { + switch (shift) { + case Shift::Default: return index; + case Shift::U16: return ir.ShiftLeftLogical(index, ir.Imm32(1)); + case Shift::B32: return ir.ShiftLeftLogical(index, ir.Imm32(2)); + default: UNREACHABLE(); + } +} + +IR::U32 skewBytes(IR::IREmitter& ir, SZ sizeRead) { + const IR::U32 lane = ir.LaneId(); + switch (sizeRead) { + case SZ::U8: return lane; + case SZ::U16: return ir.ShiftLeftLogical(lane, ir.Imm32(1)); + case SZ::U32: + case SZ::F32: return ir.ShiftLeftLogical(lane, ir.Imm32(2)); + default: UNREACHABLE(); + } +} + +} // Anonymous namespace -// Valid only for GS, TI, VS and trap void TranslatorVisitor::ISBERD(u64 insn) { + LOG_DEBUG(Shader, "called with insn={:#X}", insn); + union { u64 raw; BitField<0, 8, IR::Reg> dest_reg; @@ -20,49 +63,66 @@ void TranslatorVisitor::ISBERD(u64 insn) { BitField<24, 8, u32> imm; BitField<31, 1, u64> skew; BitField<32, 1, u64> o; - BitField<33, 2, Isberd::Mode> mode; - BitField<36, 4, Isberd::SZ> sz; - BitField<47, 2, Isberd::Shift> shift; + BitField<33, 2, Mode> mode; + BitField<36, 4, SZ> sz; + BitField<47, 2, Shift> shift; } const isberd{insn}; - auto address = compute_ISBERD_address(isberd.src_reg, isberd.src_reg_num, isberd.imm, isberd.skew); - if (isberd.o != 0) { - auto result = apply_ISBERD_size_read(address, isberd.sz.Value()); - X(isberd.dest_reg, apply_ISBERD_shift(result, isberd.shift.Value())); - - return; + IR::U32 index{}; + if (isberd.src_reg_num.Value() == 0xFF) { + index = ir.Imm32(isberd.imm.Value()); + } else { + const IR::U32 scaledIndex = scaleIndex(ir, X(isberd.src_reg.Value()), isberd.shift.Value()); + index = ir.IAdd(scaledIndex, ir.Imm32(isberd.imm.Value())); } - if (isberd.mode != Isberd::Mode::Default) { - IR::F32 result_f32{}; - switch (isberd.mode.Value()) { - case Isberd::Mode::Patch: - result_f32 = ir.GetPatch(address.Patch()); - break; - case Isberd::Mode::Prim: - result_f32 = ir.GetAttribute(address.Attribute()); - break; - case Isberd::Mode::Attr: - result_f32 = ir.GetAttributeIndexed(address); - break; - default: - UNREACHABLE(); + if (isberd.o.Value()) { + if (isberd.skew.Value()) { + index = ir.IAdd(index, skewBytes(ir, isberd.sz.Value())); } - auto result_u32 = ir.BitCast(result_f32); - X(isberd.dest_reg, apply_ISBERD_shift(result_u32, isberd.shift.Value())); - return; - } - - if (isberd.skew != 0) { - auto result = ir.IAdd(X(isberd.src_reg), ir.LaneId()); - X(isberd.dest_reg, result); + const IR::U64 index64 = ir.UConvert(64, index); + IR::U32 globalLoaded{}; + switch (isberd.sz.Value()) { + case SZ::U8: globalLoaded = ir.LoadGlobalU8 (index64); break; + case SZ::U16: globalLoaded = ir.LoadGlobalU16(index64); break; + case SZ::U32: + case SZ::F32: globalLoaded = ir.LoadGlobal32(index64); break; + default: UNREACHABLE(); + } + X(isberd.dest_reg.Value(), globalLoaded); return; } - // Fallback if nothing else applies - X(isberd.dest_reg, X(isberd.src_reg)); + if (isberd.mode.Value() != Mode::Default) { + if (isberd.skew.Value()) { + index = ir.IAdd(index, skewBytes(ir, SZ::U32)); + } + + IR::F32 float_index{}; + switch (isberd.mode.Value()) { + case Mode::Patch: float_index = ir.GetPatch(index.Patch()); + break; + case Mode::Prim: float_index = ir.GetAttribute(index.Attribute()); + break; + case Mode::Attr: float_index = ir.GetAttributeIndexed(index); + break; + default: UNREACHABLE(); + } + X(isberd.dest_reg.Value(), ir.BitCast(float_index)); + + return; + } + + if (isberd.skew.Value()) { + X(isberd.dest_reg.Value(), ir.IAdd(X(isberd.src_reg.Value()), ir.LaneId())); + + return; + } + + // Fallback copy + X(isberd.dest_reg.Value(), X(isberd.src_reg.Value())); } } // namespace Shader::Maxwell From 48f7387e3afeeef993946917804b5fa5e99cdb1e Mon Sep 17 00:00:00 2001 From: Maufeat Date: Mon, 22 Sep 2025 17:56:20 +0200 Subject: [PATCH 3/5] [texture_cache, nifm] fix crashes for linear image type and set nifm logs to debug (#2549) Example game was Mario+Rabbits Kingdom Battle. It crashes when reaches that part of copy image. Also put NIFM requests to log in DEBUG due to request spam and not being useful in debugging at all. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2549 Reviewed-by: MaranBr Reviewed-by: Shinmegumi Co-authored-by: Maufeat Co-committed-by: Maufeat --- src/core/hle/service/nifm/nifm.cpp | 8 ++++---- .../renderer_vulkan/vk_texture_cache.cpp | 14 +++++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 7d43677c6f..b486e56d68 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -381,7 +381,7 @@ public: private: void Submit(HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + LOG_DEBUG(Service_NIFM, "(STUBBED) called"); if (state == RequestState::NotSubmitted) { UpdateState(RequestState::OnHold); @@ -392,7 +392,7 @@ private: } void GetRequestState(HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + LOG_DEBUG(Service_NIFM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -424,7 +424,7 @@ private: } void GetResult(HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + LOG_DEBUG(Service_NIFM, "(STUBBED) called"); const auto result = [this] { const auto has_connection = Network::GetHostIPv4Address().has_value() && @@ -486,7 +486,7 @@ private: } void UpdateState(RequestState new_state) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + LOG_DEBUG(Service_NIFM, "(STUBBED) called"); state = new_state; event1->Signal(); } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 466be26577..fb5157a658 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1377,13 +1377,17 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src, // As per the size-compatible formats section of vulkan, copy manually via ReinterpretImage // these images that aren't size-compatible if (BytesPerBlock(src.info.format) != BytesPerBlock(dst.info.format)) { - auto oneCopy = VideoCommon::ImageCopy{ - .src_offset = VideoCommon::Offset3D(0, 0, 0), - .dst_offset = VideoCommon::Offset3D(0, 0, 0), - .extent = dst.info.size - }; + + if (src.info.type == ImageType::Linear || dst.info.type == ImageType::Linear) { + return; + } + + auto oneCopy = VideoCommon::ImageCopy{.src_offset = VideoCommon::Offset3D(0, 0, 0), + .dst_offset = VideoCommon::Offset3D(0, 0, 0), + .extent = dst.info.size}; return ReinterpretImage(dst, src, std::span{&oneCopy, 1}); } + boost::container::small_vector vk_copies(copies.size()); const VkImageAspectFlags aspect_mask = dst.AspectMask(); ASSERT(aspect_mask == src.AspectMask()); From 7050b92d61f2c2be2384f606d47b23d114353944 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 22 Sep 2025 18:21:59 +0200 Subject: [PATCH 4/5] [vk, gl] fix missing spline1 header (#2551) Thanks to @chemicalwarrior for the patch Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2551 Co-authored-by: lizzie Co-committed-by: lizzie --- src/video_core/renderer_opengl/present/filters.cpp | 1 + src/video_core/renderer_vulkan/present/filters.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/video_core/renderer_opengl/present/filters.cpp b/src/video_core/renderer_opengl/present/filters.cpp index a840de304e..5e3d1538c6 100644 --- a/src/video_core/renderer_opengl/present/filters.cpp +++ b/src/video_core/renderer_opengl/present/filters.cpp @@ -13,6 +13,7 @@ #include "video_core/host_shaders/present_bicubic_frag.h" #include "video_core/host_shaders/present_gaussian_frag.h" #include "video_core/host_shaders/present_lanczos_frag.h" +#include "video_core/host_shaders/present_spline1_frag.h" #include "video_core/renderer_opengl/present/filters.h" #include "video_core/renderer_opengl/present/util.h" diff --git a/src/video_core/renderer_vulkan/present/filters.cpp b/src/video_core/renderer_vulkan/present/filters.cpp index 6622b8daea..e0f2b26f84 100644 --- a/src/video_core/renderer_vulkan/present/filters.cpp +++ b/src/video_core/renderer_vulkan/present/filters.cpp @@ -13,6 +13,7 @@ #include "video_core/host_shaders/present_bicubic_frag_spv.h" #include "video_core/host_shaders/present_gaussian_frag_spv.h" #include "video_core/host_shaders/present_lanczos_frag_spv.h" +#include "video_core/host_shaders/present_spline1_frag_spv.h" #include "video_core/host_shaders/vulkan_present_frag_spv.h" #include "video_core/host_shaders/vulkan_present_scaleforce_fp16_frag_spv.h" #include "video_core/host_shaders/vulkan_present_scaleforce_fp32_frag_spv.h" From 177a4d8e6dc40ef52717a82712cf066b3ba10f83 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 13:43:05 +0000 Subject: [PATCH 5/5] [compat] improve thread naming logic Signed-off-by: lizzie --- src/common/thread.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/common/thread.cpp b/src/common/thread.cpp index da1fa9b6c5..2de7465a22 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp @@ -1,6 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -18,9 +17,8 @@ #else #if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) #include -#else -#include #endif +#include #include #endif #ifndef _WIN32 @@ -93,33 +91,35 @@ void SetCurrentThreadName(const char* name) { #else // !MSVC_VER, so must be POSIX threads // MinGW with the POSIX threading model does not support pthread_setname_np -#if !defined(_WIN32) || defined(_MSC_VER) void SetCurrentThreadName(const char* name) { + // See for reference + // https://gitlab.freedesktop.org/mesa/mesa/-/blame/main/src/util/u_thread.c?ref_type=heads#L75 #ifdef __APPLE__ pthread_setname_np(name); +#elif defined(__HAIKU__) + rename_thread(find_thread(NULL), name); #elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) pthread_set_name_np(pthread_self(), name); #elif defined(__NetBSD__) pthread_setname_np(pthread_self(), "%s", (void*)name); -#elif defined(__linux__) - // Linux limits thread names to 15 characters and will outright reject any - // attempt to set a longer name with ERANGE. - std::string truncated(name, (std::min)(strlen(name), static_cast(15))); - if (int e = pthread_setname_np(pthread_self(), truncated.c_str())) { - errno = e; - LOG_ERROR(Common, "Failed to set thread name to '{}': {}", truncated, GetLastErrorMsg()); +#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun__) || defined(__glibc__) || defined(__managarm__) + int ret = pthread_setname_np(pthread_self(), name); + if (ret == ERANGE) { + // Linux limits thread names to 15 characters and will outright reject any + // attempt to set a longer name with ERANGE. + char buf[16]; + size_t const len = std::min(std::strlen(name), sizeof(buf) - 1); + std::memcpy(buf, name, len); + buf[len] = '\0'; + pthread_setname_np(pthread_self(), buf); } +#elif !defined(_WIN32) || defined(_MSC_VER) + // mingw stub + (void)name; #else pthread_setname_np(pthread_self(), name); #endif } -#endif - -#if defined(_WIN32) -void SetCurrentThreadName(const char* name) { - // Do Nothing on MingW -} -#endif #endif