From 7309c477d1898d8b27ab14a6a8f418d4a4d52fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 23 May 2026 20:30:52 +0200 Subject: [PATCH 1/6] Logging change --- Core/FileSystems/BlockDevices.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/FileSystems/BlockDevices.cpp b/Core/FileSystems/BlockDevices.cpp index de9970a845..ed3083f6ad 100644 --- a/Core/FileSystems/BlockDevices.cpp +++ b/Core/FileSystems/BlockDevices.cpp @@ -357,7 +357,7 @@ UDFFileBlockDevice::UDFFileBlockDevice(FileLoader *fileLoader) return; } - INFO_LOG(Log::Loader, "Detected PSP DVD-R wrapper: USER_L0=%u blocks at %u, USER_L1=%u blocks at %u", + DEBUG_LOG(Log::Loader, "Detected PSP DVD-R wrapper: USER_L0=%u blocks at %u, USER_L1=%u blocks at %u", layer0_.numBlocks, layer0_.startBlock, layer1_.numBlocks, layer1_.startBlock); } @@ -436,7 +436,7 @@ ISOContainerFileBlockDevice::ISOContainerFileBlockDevice(FileLoader *fileLoader) return; } - INFO_LOG(Log::Loader, "Detected PSP ISO wrapper: USER_L0=%u blocks at %u, USER_L1=%u blocks at %u", + DEBUG_LOG(Log::Loader, "Detected PSP ISO wrapper: USER_L0=%u blocks at %u, USER_L1=%u blocks at %u", layer0_.numBlocks, layer0_.startBlock, layer1_.numBlocks, layer1_.startBlock); } From 886d9c255b3e2ff67539297c6a3ac69e0013ef3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 25 May 2026 21:27:32 +0200 Subject: [PATCH 2/6] D3D11: Improve compilation error reporting --- GPU/D3D11/D3D11Util.cpp | 41 ++++++++++++++++++++++++------- GPU/D3D11/D3D11Util.h | 2 +- unittest/TestShaderGenerators.cpp | 14 ++++++++--- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp index d2cc4c5556..aa68dc7709 100644 --- a/GPU/D3D11/D3D11Util.cpp +++ b/GPU/D3D11/D3D11Util.cpp @@ -22,7 +22,7 @@ using namespace Microsoft::WRL; -std::vector CompileShaderToBytecodeD3D11(const char *code, size_t codeSize, const char *target, UINT flags) { +std::vector CompileShaderToBytecodeD3D11(const char *code, size_t codeSize, const char *target, UINT flags, std::string *errorMessage) { ComPtr compiledCode; ComPtr errorMsgs; HRESULT result = ptr_D3DCompile(code, codeSize, nullptr, nullptr, nullptr, "main", target, flags, 0, &compiledCode, &errorMsgs); @@ -45,6 +45,9 @@ std::vector CompileShaderToBytecodeD3D11(const char *code, size_t codeS } } else { ERROR_LOG(Log::G3D, "%s: %s\n\n%s", "errors", errors.c_str(), numberedCode.c_str()); + if (errorMessage) { + *errorMessage = errors; + } OutputDebugStringA(errors.c_str()); OutputDebugStringA(numberedCode.c_str()); } @@ -63,9 +66,14 @@ HRESULT CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t c if (ppVertexShader) *ppVertexShader = nullptr; const char *profile = featureLevel <= D3D_FEATURE_LEVEL_9_3 ? "vs_4_0_level_9_1" : "vs_4_0"; - std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, profile, flags); - if (byteCode.empty()) + std::string errorMessage; + std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, profile, flags, &errorMessage); + if (byteCode.empty()) { + if (!errorMessage.empty()) { + ERROR_LOG(Log::G3D, "%s", errorMessage.c_str()); + } return S_FALSE; + } auto hr = device->CreateVertexShader(byteCode.data(), byteCode.size(), nullptr, ppVertexShader); if (byteCodeOut) @@ -77,9 +85,14 @@ HRESULT CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t co if (ppPixelShader) *ppPixelShader = nullptr; const char *profile = featureLevel <= D3D_FEATURE_LEVEL_9_3 ? "ps_4_0_level_9_1" : "ps_4_0"; - std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, profile, flags); - if (byteCode.empty()) + std::string errorMessage; + std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, profile, flags, &errorMessage); + if (byteCode.empty()) { + if (!errorMessage.empty()) { + ERROR_LOG(Log::G3D, "%s", errorMessage.c_str()); + } return S_FALSE; + } return device->CreatePixelShader(byteCode.data(), byteCode.size(), nullptr, ppPixelShader); } @@ -89,9 +102,14 @@ HRESULT CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t *ppComputeShader = nullptr; if (featureLevel <= D3D_FEATURE_LEVEL_9_3) return S_FALSE; - std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, "cs_4_0", flags); - if (byteCode.empty()) + std::string errorMessage; + std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, "cs_4_0", flags, &errorMessage); + if (byteCode.empty()) { + if (!errorMessage.empty()) { + ERROR_LOG(Log::G3D, "%s", errorMessage.c_str()); + } return S_FALSE; + } return device->CreateComputeShader(byteCode.data(), byteCode.size(), nullptr, ppComputeShader); } @@ -101,9 +119,14 @@ HRESULT CreateGeometryShaderD3D11(ID3D11Device *device, const char *code, size_t *ppGeometryShader = nullptr; if (featureLevel <= D3D_FEATURE_LEVEL_9_3) return S_FALSE; - std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, "gs_5_0", flags); - if (byteCode.empty()) + std::string errorMessage; + std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, "gs_5_0", flags, &errorMessage); + if (byteCode.empty()) { + if (!errorMessage.empty()) { + ERROR_LOG(Log::G3D, "%s", errorMessage.c_str()); + } return S_FALSE; + } return device->CreateGeometryShader(byteCode.data(), byteCode.size(), nullptr, ppGeometryShader); } diff --git a/GPU/D3D11/D3D11Util.h b/GPU/D3D11/D3D11Util.h index d5d52b9fef..04f0cc20d2 100644 --- a/GPU/D3D11/D3D11Util.h +++ b/GPU/D3D11/D3D11Util.h @@ -73,7 +73,7 @@ private: bool nextMapDiscard_ = false; }; -std::vector CompileShaderToBytecodeD3D11(const char *code, size_t codeSize, const char *target, UINT flags); +std::vector CompileShaderToBytecodeD3D11(const char *code, size_t codeSize, const char *target, UINT flags, std::string *errorMessage = nullptr); HRESULT CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector *byteCodeOut, D3D_FEATURE_LEVEL featureLevel, UINT flags, ID3D11VertexShader **); HRESULT CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags, ID3D11PixelShader **); diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index c4978484be..ccfc9afaa4 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -139,9 +139,14 @@ bool TestCompileShader(const char *buffer, ShaderLanguage lang, ShaderStage stag case ShaderStage::Vertex: programType = "vs_4_0"; break; case ShaderStage::Fragment: programType = "ps_4_0"; break; case ShaderStage::Geometry: programType = "gs_4_0"; break; - default: return false; + default: + *errorMessage = "Unknown shader stage"; + return false; + } + auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), programType, 0, errorMessage); + if (output.empty() && errorMessage->empty()) { + *errorMessage = "Error compiling HLSL shader: bytecode empty"; } - auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), programType, 0); return !output.empty(); } #endif @@ -153,6 +158,7 @@ bool TestCompileShader(const char *buffer, ShaderLanguage lang, ShaderStage stag case ShaderLanguage::GLSL_3xx: return GLSLtoSPV(StageToVulkan(stage), buffer, GLSLVariant::GLES300, spirv, errorMessage); default: + *errorMessage = "Unknown shader language"; return false; } } @@ -422,7 +428,7 @@ bool TestVertexShaders() { if (generateSuccess[j]) { std::string errorMessage; if (!TestCompileShader(buffer[j], languages[j], ShaderStage::Vertex, &errorMessage)) { - printf("Error compiling vertex shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer[j]).c_str(), errorMessage.c_str()); + printf("Error compiling vertex shader %d:\n\n%s\n\nERROR: %s\n\n(end of error)\n\n", (int)j, LineNumberString(buffer[j]).c_str(), errorMessage.c_str()); for (int i = 0; i < numLanguages; i++) { delete[] buffer[i]; } @@ -496,7 +502,7 @@ bool TestFragmentShaders() { if (generateSuccess[j]) { std::string errorMessage; if (!TestCompileShader(buffer[j], languages[j], ShaderStage::Fragment, &errorMessage)) { - printf("Error compiling fragment shader:\n\n%s\n\n%s\n", LineNumberString(buffer[j]).c_str(), errorMessage.c_str()); + printf("Error compiling fragment shader %d:\n\n%s\n\nERROR: %s\n\n(end of error)\n\n", (int)j, LineNumberString(buffer[j]).c_str(), errorMessage.c_str()); for (int i = 0; i < numLanguages; i++) { delete[] buffer[i]; } From 328e1b681c57ef26aad1e4331b67b15fd52acb43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 27 May 2026 10:52:15 +0200 Subject: [PATCH 3/6] More CrossSIMD ops --- Common/Math/CrossSIMD.h | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/Common/Math/CrossSIMD.h b/Common/Math/CrossSIMD.h index 58ca672373..9f883354de 100644 --- a/Common/Math/CrossSIMD.h +++ b/Common/Math/CrossSIMD.h @@ -189,6 +189,10 @@ inline bool AllCompareBitsSet(Vec4S32 value) { return _mm_movemask_ps(_mm_castsi128_ps(value.v)) == 0xF; } +inline bool AnyCompareBitsSet(Vec4S32 value) { + return _mm_movemask_ps(_mm_castsi128_ps(value.v)) != 0; +} + struct Vec4F32 { __m128 v; @@ -241,6 +245,12 @@ struct Vec4F32 { return Vec4F32{ _mm_or_ps(_mm_and_ps(value, _mm_load_ps((const float *)mask)), _mm_load_ps(onelane3)) }; } + static Vec4F32 LoadF24x3_DontCare(const uint32_t *src) { + alignas(16) static const uint32_t mask[4] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0}; + + return Vec4F32{_mm_castsi128_ps(_mm_slli_epi32(_mm_loadu_si128((const __m128i *)src), 8))}; + } + void Store(float *dst) { _mm_storeu_ps(dst, v); } void Store2(float *dst) { _mm_storel_epi64((__m128i *)dst, _mm_castps_si128(v)); } void StoreAligned(float *dst) { _mm_store_ps(dst, v); } @@ -299,6 +309,12 @@ struct Vec4F32 { return Vec4F32{ _mm_or_ps(_mm_and_ps(v, _mm_load_ps((const float *)mask)), _mm_load_ps((const float *)onelane3)) }; } + Vec4F32 WithLane3From(Vec4F32 other) const { + alignas(16) static const uint32_t mask[4] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0}; + __m128 maskVec = _mm_load_ps((const float *)mask); + return Vec4F32{_mm_or_ps(_mm_and_ps(maskVec, v), _mm_andnot_ps(maskVec, other.v))}; + } + inline Vec4F32 AsVec3ByMatrix44(const Mat4F32 &m) { return Vec4F32{ _mm_add_ps( _mm_add_ps( @@ -353,6 +369,9 @@ inline bool AnyZeroSignBit(Vec4F32 value) { inline bool AllCompareBitsSet(Vec4F32 value) { return _mm_movemask_ps(value.v) == 0xF; } +inline bool AnyCompareBitsSet(Vec4F32 value) { + return _mm_movemask_ps(value.v) != 0; +} // Make sure the W component of scale is 1.0f. inline void ScaleInplace(Mat4F32 &m, Vec4F32 scale) { @@ -600,6 +619,9 @@ struct Vec4F32 { static Vec4F32 LoadF24x3_One(const uint32_t *src) { return Vec4F32{ vsetq_lane_f32(1.0f, vreinterpretq_f32_u32(vshlq_n_u32(vld1q_u32(src), 8)), 3) }; } + static Vec4F32 LoadF24x3_DontCare(const uint32_t *src) { + return Vec4F32{vreinterpretq_f32_u32(vshlq_n_u32(vld1q_u32(src), 8))}; + } static Vec4F32 FromVec4S32(Vec4S32 other) { return Vec4F32{ vcvtq_f32_s32(other.v) }; @@ -683,6 +705,10 @@ struct Vec4F32 { return Vec4F32{ vsetq_lane_f32(1.0f, v, 3) }; } + Vec4F32 WithLane3From(Vec4F32 other) const { + return Vec4F32{vsetq_lane_f32(vgetq_lane_f32(other.v, 3), v, 3)}; + } + Vec4F32 ShuffleXXYY() const { float32x2_t low = vget_low_f32(v); // {X, Y} pair // Combine them into {X, X, Y, Y} @@ -796,6 +822,17 @@ inline bool AllCompareBitsSet(Vec4S32 value) { #endif } +inline bool AnyCompareBitsSet(Vec4S32 value) { +#if PPSSPP_ARCH(ARM64_NEON) + return vmaxvq_u32(vreinterpretq_u32_s32(value.v)) != 0; +#else + // Very suboptimal, let's optimize later. + int32x2_t prod = vand_s32(vget_low_s32(value.v), vget_high_s32(value.v)); + int mask = vget_lane_s32(prod, 0) & vget_lane_s32(prod, 1); + return mask != 0; +#endif +} + inline bool AnyZeroSignBit(Vec4F32 value) { int32x4_t ival = vreinterpretq_s32_f32(value.v); #if PPSSPP_ARCH(ARM64_NEON) @@ -1045,6 +1082,9 @@ struct Vec4F32 { value = __lsx_vinsgr2vr_w(value, kOneF32Bits, 3); return Vec4F32{ (__m128)value }; } + static Vec4F32 LoadF24x3_DontCare(const uint32_t *src) { + return Vec4F32{(__m128)__lsx_vslli_w(__lsx_vld(src, 0), 8)}; + } static Vec4F32 FromVec4S32(Vec4S32 other) { return Vec4F32{ (__m128)__lsx_vffint_s_w(other.v) }; @@ -1115,6 +1155,13 @@ struct Vec4F32 { return Vec4F32{ (__m128)__lsx_vinsgr2vr_w((__m128i)v, kOneF32Bits, 3) }; } + Vec4F32 WithLane3From(Vec4F32 other) const { + // Use vinsgr2vr_w to insert just the lane 3 + // Extract lane 3 from other as an integer, then insert it into v + int lane3 = __lsx_vpickve2gr_w((__m128i)other.v, 3); + return Vec4F32{ (__m128)__lsx_vinsgr2vr_w((__m128i)v, lane3, 3) }; + } + Vec4S32 CompareEq(Vec4F32 other) const { return Vec4S32{ (__m128i)__lsx_vfcmp_ceq_s(v, other.v) }; } Vec4S32 CompareLt(Vec4F32 other) const { return Vec4S32{ (__m128i)__lsx_vfcmp_clt_s(v, other.v) }; } Vec4S32 CompareGt(Vec4F32 other) const { return Vec4S32{ (__m128i)__lsx_vfcmp_clt_s(other.v, v) }; } @@ -1223,6 +1270,11 @@ inline bool AllCompareBitsSet(Vec4S32 value) { return mask == 0xF; } +inline bool AnyCompareBitsSet(Vec4S32 value) { + int mask = __lsx_vpickve2gr_w(__lsx_vmskltz_w((__m128i)value.v), 0); + return mask != 0; +} + struct Vec4U16 { __m128i v; // we only use the lower 64 bits. @@ -1478,6 +1530,10 @@ struct Vec4F32 { return temp; } + static Vec4F32 LoadF24x3_DontCare(const uint32_t *src) { + return LoadR24x3_One(src); + } + static Vec4F32 FromVec4S32(Vec4S32 src) { Vec4F32 temp; for (int i = 0; i < 4; i++) { From 9845a78a4632b35dc2b0d17083539d22da533ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 27 May 2026 17:52:17 +0200 Subject: [PATCH 4/6] Vulkan: Correct handling of VK_ERROR_OUT_OF_DATE_KHR --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index e134b34d49..70f41e8f28 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -327,6 +327,8 @@ void VulkanQueueRunner::RunSteps(std::vector &steps, int curFrame, Fr frameData.AcquireNextImage(vulkan_); if (frameData.hasAcquired && frameData.curSwapchainImage != (uint32_t)-1) { SetBackbuffer(framebuffers_[frameData.curSwapchainImage], frameDataShared.swapchainImages_[frameData.curSwapchainImage].image); + } else { + perform = false; } } @@ -1888,4 +1890,4 @@ const char *VKRRenderCommandToString(VKRRenderCommand cmd) { } else { return "N/A"; } -} \ No newline at end of file +} From e6a4cdb213840aef32acae61ef1ed4fbaf2c19b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 27 May 2026 23:15:20 +0200 Subject: [PATCH 5/6] Fix minor UI issue --- UI/InstallZipScreen.h | 4 +++- UI/SimpleDialogScreen.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/UI/InstallZipScreen.h b/UI/InstallZipScreen.h index 3ff4beb65e..eb6ed062e3 100644 --- a/UI/InstallZipScreen.h +++ b/UI/InstallZipScreen.h @@ -42,7 +42,9 @@ protected: void CreateSettingsViews(UI::ViewGroup *parent) override; void CreateContentViews(UI::ViewGroup *parent) override; std::string_view GetTitle() const override; - + ViewLayoutMode LayoutMode() const override { + return ViewLayoutMode::ApplyInsets; + } private: void OnInstall(UI::EventParams ¶ms); void OnPlay(UI::EventParams ¶ms); diff --git a/UI/SimpleDialogScreen.cpp b/UI/SimpleDialogScreen.cpp index 2088f8648e..e0c0cc201c 100644 --- a/UI/SimpleDialogScreen.cpp +++ b/UI/SimpleDialogScreen.cpp @@ -45,7 +45,7 @@ void UISimpleBaseDialogScreen::CreateViews() { ViewLayoutMode UITwoPaneBaseDialogScreen::LayoutMode() const { const bool portrait = GetDeviceOrientation() == DeviceOrientation::Portrait; if (portrait) { - if ((flags_ & TwoPaneFlags::SettingsCanScroll) || (flags_ & TwoPaneFlags::ContentsCanScroll)) { + if (((flags_ & TwoPaneFlags::SettingsCanScroll) && !(flags_ & TwoPaneFlags::SettingsToTheRight)) || (flags_ & TwoPaneFlags::ContentsCanScroll)) { return ViewLayoutMode::IgnoreBottomInset; } else { return ViewLayoutMode::ApplyInsets; From 22b20cf2eab5575e695bc13945d8a4771e7a5f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 28 May 2026 09:12:17 +0200 Subject: [PATCH 6/6] Bypass the InstallZipScreen for zipped framedumps - there's only one action that makes sense. --- UI/InstallZipScreen.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/UI/InstallZipScreen.cpp b/UI/InstallZipScreen.cpp index 5d0c079985..6e2139ee5a 100644 --- a/UI/InstallZipScreen.cpp +++ b/UI/InstallZipScreen.cpp @@ -393,6 +393,11 @@ void InstallZipScreen::update() { } MainScreen::showHomebrewTab = returnToHomebrew_; } + + if (zipFileInfo_.contents == ZipFileContents::FRAME_DUMP) { + // For frame dumps, just launch them immediately. + screenManager()->switchScreen(new EmuScreen(zipPath_)); + } } if (existingSaveView_) {