Merge pull request #20207 from hrydgard/hle-work

DisableHLE: Add compat flag for sceFont, add ability to make flags permanent
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2025-04-03 20:23:22 +02:00
commit 97e6ef2dd6
12 files changed
+93 -58

No files matched your search

+3 -1
View File
@@ -1,3 +1,4 @@
#include <algorithm>
#include <cstdarg>
#include <climits>
#include <cstdio>
@@ -166,7 +167,8 @@ StringWriter &StringWriter::F(const char *format, ...) {
}
va_list args;
va_start(args, format);
p_ += vsnprintf(p_, remainder, format, args);
int wouldHaveBeenWritten = vsnprintf(p_, remainder, format, args);
p_ += std::min((int)remainder, wouldHaveBeenWritten);
va_end(args);
return *this;
}
+1
View File
@@ -149,6 +149,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "ForceEnableGPUReadback", &flags_.ForceEnableGPUReadback);
CheckSetting(iniFile, gameID, "UseFFMPEGFindStreamInfo", &flags_.UseFFMPEGFindStreamInfo);
CheckSetting(iniFile, gameID, "SoftwareRasterDepth", &flags_.SoftwareRasterDepth);
CheckSetting(iniFile, gameID, "DisableHLESceFont", &flags_.DisableHLESceFont);
}
void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) {
+1
View File
@@ -112,6 +112,7 @@ struct CompatFlags {
bool ForceEnableGPUReadback;
bool UseFFMPEGFindStreamInfo;
bool SoftwareRasterDepth;
bool DisableHLESceFont;
};
struct VRCompat {
+2 -3
View File
@@ -124,9 +124,8 @@ enum class DisableHLEFlags : int {
scePsmfPlayer = (1 << 3),
sceMpeg = (1 << 4),
sceMp3 = (1 << 5),
sceJpeg = (1 << 6),
sceParseHttp = (1 << 7),
Count = 8,
sceParseHttp = (1 << 6),
Count = 7,
// TODO: Some of the networking libraries may be interesting candidates, like HTTP.
};
ENUM_CLASS_BITOPS(DisableHLEFlags);
+30 -10
View File
@@ -122,6 +122,7 @@ static const HLEModuleMeta g_moduleMeta[] = {
{"SceFont_Library", "sceLibFttt", DisableHLEFlags::sceFont},
{"SceHttp_Library", "sceHttp"},
{"sceMpeg_library", "sceMpeg", DisableHLEFlags::sceMpeg},
{"sceMp3_Library", "sceMp3", DisableHLEFlags::sceMp3},
{"sceNetAdhocctl_Library"},
{"sceNetAdhocDownload_Library"},
{"sceNetAdhocMatching_Library"},
@@ -154,9 +155,9 @@ static const HLEModuleMeta g_moduleMeta[] = {
{"SceParseHTTPheader_Library", "sceParseHttp", DisableHLEFlags::sceParseHttp},
{"SceParseURI_Library"},
// Guessing these names
{"sceJpeg", "sceJpeg", DisableHLEFlags::sceJpeg},
{"sceJpeg_library", "sceJpeg", DisableHLEFlags::sceJpeg},
{"sceJpeg_Library", "sceJpeg", DisableHLEFlags::sceJpeg},
{"sceJpeg", "sceJpeg"},
{"sceJpeg_library", "sceJpeg"},
{"sceJpeg_Library", "sceJpeg"},
};
const HLEModuleMeta *GetHLEModuleMeta(std::string_view modname) {
@@ -186,20 +187,39 @@ const HLEModuleMeta *GetHLEModuleMetaByImport(std::string_view importModuleName)
return nullptr;
}
DisableHLEFlags AlwaysDisableHLEFlags() {
// Once a module seems stable to load properly, we'll graduate it here.
// This will hide the checkbox, too.
// return DisableHLEFlags::scePsmf | DisableHLEFlags::scePsmfPlayer;
return (DisableHLEFlags)0;
}
// Process compat flags.
static DisableHLEFlags GetDisableHLEFlags() {
DisableHLEFlags flags = (DisableHLEFlags)g_Config.iDisableHLE | AlwaysDisableHLEFlags();
if (PSP_CoreParameter().compat.flags().DisableHLESceFont) {
flags |= DisableHLEFlags::sceFont;
}
return flags;
}
// Note: name is the modname from prx, not the export module name!
bool ShouldHLEModule(std::string_view modname, bool *wasDisabled) {
if (wasDisabled) {
*wasDisabled = false;
bool ShouldHLEModule(std::string_view modname, bool *wasDisabledManually) {
if (wasDisabledManually) {
*wasDisabledManually = false;
}
const HLEModuleMeta *meta = GetHLEModuleMeta(modname);
if (!meta) {
return false;
}
bool disabled = meta->disableFlag & (DisableHLEFlags)g_Config.iDisableHLE;
bool disabled = meta->disableFlag & GetDisableHLEFlags();
if (disabled) {
if (wasDisabled) {
*wasDisabled = true;
if (wasDisabledManually) {
// We don't show notifications if a flag has "graduated".
if (!(meta->disableFlag & AlwaysDisableHLEFlags())) {
*wasDisabledManually = true;
}
}
return false;
}
@@ -210,7 +230,7 @@ bool ShouldHLEModuleByImportName(std::string_view name) {
// Check our special metadata lookup. Should probably be merged with the main one.
const HLEModuleMeta *meta = GetHLEModuleMetaByImport(name);
if (meta) {
bool disabled = meta->disableFlag & (DisableHLEFlags)g_Config.iDisableHLE;
bool disabled = meta->disableFlag & GetDisableHLEFlags();
return !disabled;
}
+2 -1
View File
@@ -107,7 +107,7 @@ struct HLEModuleMeta {
const HLEModuleMeta *GetHLEModuleMetaByFlag(DisableHLEFlags flag);
const HLEModuleMeta *GetHLEModuleMeta(std::string_view modname);
bool ShouldHLEModule(std::string_view modname, bool *wasDisabled = nullptr);
bool ShouldHLEModule(std::string_view modname, bool *wasDisabledManually = nullptr);
bool ShouldHLEModuleByImportName(std::string_view importModuleName);
const char *GetHLEFuncName(std::string_view module, u32 nib);
@@ -121,6 +121,7 @@ u32 GetNibByName(std::string_view module, std::string_view function);
void RegisterHLEModule(std::string_view name, int numFunctions, const HLEFunction *funcTable);
int GetNumRegisteredHLEModules();
const HLEModule *GetHLEModuleByIndex(int index);
DisableHLEFlags AlwaysDisableHLEFlags();
// Run the current thread's callbacks after the syscall finishes.
void hleCheckCurrentCallbacks();
+37 -34
View File
@@ -49,33 +49,26 @@ static_assert(sizeof(SceAudiocodecCodec) == 128);
//
// Known byte values.
void CalculateInputBytesAndChannels(const SceAudiocodecCodec *ctx, int codec, int *inputBytes, int *channels) {
void CalculateInputBytesAndChannelsAt3Plus(const SceAudiocodecCodec *ctx, int *inputBytes, int *channels) {
*inputBytes = 0;
*channels = 2;
switch (codec) {
case PSP_CODEC_AT3PLUS:
{
int size = ctx->unk41 * 8 + 8;
// No idea if this is accurate, this is just a guess...
if (ctx->unk40 & 8) {
*channels = 2;
} else {
*channels = 1;
}
switch (size) {
case 0x118:
case 0x178:
case 0x230:
case 0x2E8:
// These have been seen before, let's return it.
*inputBytes = size;
return;
default:
break;
}
int size = ctx->unk41 * 8 + 8;
// No idea if this is accurate, this is just a guess...
if (ctx->unk40 & 8) {
*channels = 2;
} else {
*channels = 1;
}
switch (size) {
case 0x118:
case 0x178:
case 0x230:
case 0x2E8:
// These have been seen before, let's return it.
*inputBytes = size;
return;
default:
// Unsupported codec, ignore.
break;
}
}
@@ -118,29 +111,39 @@ void __AudioCodecShutdown() {
// TODO: Actually support mono output.
static int __AudioCodecInitCommon(u32 ctxPtr, int codec, bool mono) {
PSPAudioType audioType = (PSPAudioType)codec;
const PSPAudioType audioType = (PSPAudioType)codec;
if (!IsValidCodec(audioType)) {
return hleLogError(Log::ME, SCE_KERNEL_ERROR_OUT_OF_RANGE, "Invalid codec");
}
if (removeDecoder(ctxPtr)) {
WARN_LOG_REPORT(Log::HLE, "sceAudiocodecInit(%08x, %d): replacing existing context", ctxPtr, codec);
}
// Initialize the codec memory.
auto ctx = PSPPointer<SceAudiocodecCodec>::Create(ctxPtr);
ctx->unk_init = 0x5100601; // Firmware version indicator?
ctx->err = 0;
if (codec == 0x1002) {
int inFrameBytes = 0;
int channels = 2;
// Special actions for some codecs.
switch (audioType) {
case PSP_CODEC_MP3:
ctx->mp3_9999 = 9999;
break;
case PSP_CODEC_AAC:
// AAC / mp4
// offsets 40-42 are a 24-bit LE number specifying the sample rate. It's 32000, 44100 or 48000.
// neededMem has been set to 0x18f20.
break;
case PSP_CODEC_AT3PLUS:
CalculateInputBytesAndChannelsAt3Plus(ctx, &inFrameBytes, &channels);
break;
}
// Create audio decoder for given audio codec and push it into AudioList
if (removeDecoder(ctxPtr)) {
WARN_LOG_REPORT(Log::HLE, "sceAudiocodecInit(%08x, %d): replacing existing context", ctxPtr, codec);
}
int inFrameBytes;
int channels;
CalculateInputBytesAndChannels(ctx, codec, &inFrameBytes, &channels);
if (inFrameBytes) {
INFO_LOG(Log::ME, "sceAudioDecoder: Creating codec with %04x frame size and %d channels, codec %04x", inFrameBytes, channels, codec);
AudioDecoder *decoder = CreateAudioDecoder(audioType, 44100, channels, inFrameBytes);
@@ -177,7 +180,7 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) {
auto ctx = PSPPointer<SceAudiocodecCodec>::Create(ctxPtr); // On game-owned heap, no need to allocate.
int inFrameBytes;
int channels;
CalculateInputBytesAndChannels(ctx, codec, &inFrameBytes, &channels);
CalculateInputBytesAndChannelsAt3Plus(ctx, &inFrameBytes, &channels);
// find a decoder in audioList
auto decoder = findDecoder(ctxPtr);
+1 -1
View File
@@ -26,7 +26,7 @@ enum PSPAudioType {
PSP_CODEC_AT3PLUS = 0x00001000,
PSP_CODEC_AT3 = 0x00001001,
PSP_CODEC_MP3 = 0x00001002,
PSP_CODEC_AAC = 0x00001003,
PSP_CODEC_AAC = 0x00001003, // sceMp4 decodes this in an mp4 container
PSP_CODEC_WMA = 0x00001005,
};
+1 -1
View File
@@ -1058,7 +1058,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load
}
if (wasDisabled) {
g_OSD.Show(OSDType::MESSAGE_WARNING, StringFromFormat("HLE for %s has been manually disabled", head->modname));
g_OSD.Show(OSDType::MESSAGE_WARNING, StringFromFormat("HLE for '%s' has been manually disabled", head->modname));
}
const u8 *in = ptr;
const auto isGzip = head->comp_attribute & 1;
+6 -3
View File
@@ -787,9 +787,12 @@ const HLEFunction sceReg[] = {
{ 0x2D211135, &WrapI_IUI<sceRegGetKeys>, "sceRegGetKeys", 'i', "ipi" },
{ 0xC5768D02, &WrapI_ICUU<sceRegGetKeyInfoByName>, "sceRegGetKeyInfoByName", 'i', "isxx" },
{ 0x30BE0259, &WrapI_ICUU<sceRegGetKeyValueByName>, "sceRegGetKeyValueByName", 'i', "isxx" },
// { 0x4CA16893, &WrapI_I<sceRegRemoveCategory>, "sceRegRemoveCategory", 'i', "i" },
// { 0x3615BC87, &WrapI_I<sceRegRemoveKey>, "sceRegRemoveKey", 'i', "i" },
// { 0x9B25EDF1, &WrapI_I<sceRegExit>, "sceRegExit", 'i', "i" },
{ 0x4CA16893, &WrapI_IC<sceRegRemoveCategory>, "sceRegRemoveCategory", 'i', "i" },
{ 0x3615BC87, nullptr, "sceRegRemoveKey", 'i', "i" },
{ 0x9B25EDF1, nullptr, "sceRegExit", 'i', "i" },
// TODO: Add test for these.
{ 0xBE8C1263, nullptr, "sceRegGetCategoryNumAtRoot", 'i', "ii" },
{ 0x835ECE6F, nullptr, "sceRegGetCategoryListAtRoot", 'i', "ipi" },
};
void Register_sceReg() {
+8 -3
View File
@@ -1996,11 +1996,16 @@ void DeveloperToolsScreen::CreateViews() {
list->Add(new BitCheckBox(&g_Config.iDumpFileTypes, (int)DumpFileType::Atrac3, dev->T("Atrac3/3+")));
list->Add(new ItemHeader("Disable HLE (experimental! Not expected to work yet)"));
for (int i = 0; i < (int)DisableHLEFlags::Count; i++) {
DisableHLEFlags flag = (DisableHLEFlags)(1 << i);
const HLEModuleMeta *meta = GetHLEModuleMetaByFlag(flag);
if (meta) {
list->Add(new BitCheckBox(&g_Config.iDisableHLE, (int)flag, meta->modname));
// Show a checkbox, unless the setting has graduated to always on.
if (!(flag & AlwaysDisableHLEFlags())) {
const HLEModuleMeta *meta = GetHLEModuleMetaByFlag(flag);
if (meta) {
list->Add(new BitCheckBox(&g_Config.iDisableHLE, (int)flag, meta->modname));
}
}
}
+1 -1
View File
@@ -1500,7 +1500,7 @@ static void DrawModules(const MIPSDebugInterface *debug, ImConfig &cfg, ImContro
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 170));
}
ImGui::Text("%s %d.%d (%s)\n", mod->GetName(), mod->nm.version[1], mod->nm.version[0], mod->isFake ? "FAKE/HLE" : "normal");
ImGui::Text("Attr: %08x (%s)\n", (mod->nm.attribute & 0x1000) ? "Kernel" : "User");
ImGui::Text("Attr: %08x (%s)\n", mod->nm.attribute, (mod->nm.attribute & 0x1000) ? "Kernel" : "User");
char buf[512];
mod->GetLongInfo(buf, sizeof(buf));
ImGui::TextUnformatted(buf);