Files
ppsspp/Core/Compatibility.h
T
Henrik RydgårdandClaude Opus 5.5 20530d35c0 Add a ReadbackShadow compat flag, for games that read many pieces of a buffer
Since the sequential copies heuristic went (50696c5b1f), every partial readback
waits for the GPU. Motorstorm reads parts of the screen about 18 times a frame,
and ran about 75% slower than 1.20.4: 5403 blocking readbacks in 10 emulated
seconds, against 156.

With the flag, the first partial color readback of a buffer reads all of it into
a copy outside PSP memory, and the pieces until the next render to the buffer
are copied from there. Unlike the old heuristic, only what the game asked for is
written to PSP memory. Motorstorm is back to 153 blocking readbacks and 1.20.4's
speed, with identical output. Grand Knights History, which the heuristic was
added for, gets the flag too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:56:32 +02:00

175 lines
5.5 KiB
C++

// Copyright (c) 2015- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <string>
#include <vector>
#include <cstdint>
#include <set>
// Compatibility flags are controlled by assets/compat.ini.
// Alternatively, if PSP/System/compat.ini exists, it is merged on top, to enable editing
// the file on Android for tests.
//
// This file is not meant to be user-editable, although is kept as a separate ini
// file instead of compiled into the code for debugging purposes.
//
// The uses cases are strict:
// * Enable fixes for things we can't reasonably emulate without completely ruining
// performance for other games, such as the screen copies in Dangan Ronpa
// * Disabling accuracy features like 16-bit depth rounding, when we can't seem to
// implement them at all in a 100% compatible way
// * Emergency game-specific compatibility fixes before releases, such as the GTA
// music problem where every attempted fix has reduced compatibility with other games
// * Enable "unsafe" performance optimizations that some games can tolerate and
// others cannot. We do not currently have any of those.
//
// This functionality should NOT be used for any of the following:
// * Cheats
// * Fun hacks, like enlarged heads or whatever
// * Fixing general compatibility issues. First try to find a general solution. Try hard.
//
// We already have the Action Replay-based cheat system for such use cases.
// TODO: Turn into bitfield for smaller mem footprint.
struct CompatFlags {
bool VertexDepthRounding;
bool PixelDepthRounding;
bool ClearToRAM;
bool Force04154000Download;
bool DrawSyncEatCycles;
bool DrawSyncInstant;
bool FakeMipmapChange;
bool RequireBufferedRendering;
bool RequireBlockTransfer;
bool RequireDefaultCPUClock;
bool MGS2AcidHack;
bool SonicRivalsHack;
bool TiledDepalHack;
bool BlockTransferAllowCreateFB;
bool IntraVRAMBlockTransferAllowCreateFB;
bool YugiohSaveFix;
bool ForceUMDDelay;
bool ForceMax60FPS;
bool GoWFramerateHack60;
bool FramerateHack30;
bool HideISOFiles;
bool MoreAccurateVMMUL;
bool ForceSoftwareRenderer;
bool DarkStalkersPresentHack;
bool ReportSmallMemstick;
bool MemstickFixedFree;
bool DateLimited;
bool DisableFirstFrameReadback;
bool MpegAvcWarmUp;
bool BlueToAlpha;
bool CenteredLines;
bool ZZT3SelectHack;
bool AllowLargeFBTextureOffsets;
bool AtracLoopHack;
bool DeswizzleDepth;
bool SplitFramebufferMargin;
bool ForceLowerResolutionForEffectsOn;
bool ForceLowerResolutionForEffectsOff;
bool AllowDownloadCLUT;
bool NearestFilteringOnFramebufferCreate;
bool EnglishOrJapaneseOnly;
bool OldAdrenoPixelDepthRoundingGL;
bool ForceCircleButtonConfirm;
bool DisallowFramebufferAtOffset;
bool RockmanDash2SoundFix;
bool ReadbackDepth;
bool BlockTransferDepth;
bool DaxterRotatedAnalogStick;
bool ForceMaxDepthResolution;
bool LoadCLUTFromCurrentFrameOnly;
bool ForceUMDReadSpeed;
bool KernelGetSystemTimeLowEatMoreCycles;
bool TacticsOgreEliminateDebugReadback;
bool FramebufferAllowLargeVerticalOffset;
bool DisableMemcpySlicing;
bool ForceEnableGPUReadback;
bool UseFFMPEGFindStreamInfo;
bool SoftwareRasterDepth;
bool DisableHLESceFont;
bool ForceHLEPsmf;
bool SaveStatesNotRecommended;
bool MsgDialogAutoStatus;
bool NullPageValid;
bool DetectDestBlendSquared;
bool BoostExactFramebufferMatch;
bool PersistentFramebuffers;
bool FileCreatedTimeHack;
bool FastEmulatedGPU;
bool CorrectCullAfterClip;
float SpriteBorderFix;
bool TextureCLUTInShader;
bool DisableRangeCulling;
bool BlockTransferReadbackSmall;
bool DepthCLUTIntoHalves;
bool AccurateSplines;
bool ReadbackShadow;
};
struct VRCompat {
bool ForceMono;
bool ForceFlatScreen;
bool IdentityViewHack;
int MirroringVariant;
bool ProjectionHack;
bool Skyplane;
float UnitsPerMeter;
};
class IniFile;
class Compatibility {
public:
Compatibility() {
Clear();
}
// Flags enforced read-only through const. Only way to change them is to load assets/compat.ini.
const CompatFlags &flags() const { return flags_; }
const VRCompat &vrCompat() const { return vrCompat_; }
void Load(const std::string &gameID);
// No flags at all.
void Clear();
const std::string &GetActiveFlagsString() const {
return activeList_;
}
const std::vector<std::string> &filesLoaded() const { return filesLoaded_; }
private:
void CheckSettings(IniFile &iniFile, const std::string &gameID);
void CheckVRSettings(IniFile &iniFile, const std::string &gameID);
void CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag);
void CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, float *value);
void CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, int *value);
CompatFlags flags_{};
VRCompat vrCompat_{};
std::set<std::string> ignored_;
std::string activeList_;
std::vector<std::string> filesLoaded_;
};