Merge pull request #22322 from hrydgard/pace-video-decode

Add PaceVideocodecDecode compat.ini option
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-09-21 09:41:18 -06:00
commit 6964cb0489
6 files changed
+42 -1

No files matched your search

+1
View File
@@ -169,6 +169,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "SpriteBorderFix", &flags_.SpriteBorderFix);
CheckSetting(iniFile, gameID, "TextureCLUTInShader", &flags_.TextureCLUTInShader);
CheckSetting(iniFile, gameID, "DisableRangeCulling", &flags_.DisableRangeCulling);
CheckSetting(iniFile, gameID, "PaceVideocodecDecode", &flags_.PaceVideocodecDecode);
}
void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) {
+1
View File
@@ -124,6 +124,7 @@ struct CompatFlags {
float SpriteBorderFix;
bool TextureCLUTInShader;
bool DisableRangeCulling;
bool PaceVideocodecDecode;
};
struct VRCompat {
+20 -1
View File
@@ -33,6 +33,9 @@
#include "Common/Serialize/Serializer.h"
#include "Common/Serialize/SerializeFuncs.h"
#include "Core/Config.h"
#include "Core/CoreTiming.h"
#include "Core/System.h"
#include "Core/HLE/ErrorCodes.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"
@@ -95,6 +98,9 @@ struct VideocodecCtx {
u32 frameBuffersSize = 0;
int frameBufferWidth = 0;
int frameBufferHeight = 0;
// When the next decode may finish, for PaceVideocodecDecode. Not serialized: a restored state
// just paces from scratch.
s64 pacedUntilUs = 0;
};
static std::map<u32, VideocodecCtx> g_videocodecCtxs;
@@ -583,12 +589,25 @@ static int sceVideocodecDecode(u32 ctxAddr, int type) {
out32(36, published ? 0 : 1);
}
// This is a compat hack for games that do not seem to pace playback in any way, such as Ys I & II.
if (gotFrame && PSP_CoreParameter().compat.flags().PaceVideocodecDecode && vctx.decoder) {
const int period = vctx.decoder->FramePeriodUs();
if (period > 0) {
const s64 now = CoreTiming::GetGlobalTimeUs();
const int wait = (int)std::max((s64)0, vctx.pacedUntilUs - now);
vctx.pacedUntilUs = now + wait + period;
if (wait > 0) {
return hleDelayResult(hleLogDebug(Log::ME, 0, "type %d, %d bytes -> frame %dx%d",
type, auBytes, width, height), "videocodec decode", wait);
}
}
}
return hleLogDebug(Log::ME, 0, "type %d, %d bytes -> %s %dx%d",
type, auBytes, gotFrame ? "frame" : "no frame yet", width, height);
}
// Stopping or deleting the decoder is an ME round-trip and takes real time on hardware. Returning
// immediately matters beyond speed: a game can be relying on a thread of its own getting to run
// immediately is not correct, because a game can be relying on a thread of its own getting to run
// once more before it tears things down. Jak and Daxter deletes its video_sound_thread straight
// after sceVideocodecDelete without waiting for it to exit, and with no time passing here the audio
// thread never gets to deliver the wake that would let it exit - so the delete fails with
+11
View File
@@ -193,6 +193,17 @@ bool AvcDecoder::Decode(const u8 *data, int size) {
#endif
}
int AvcDecoder::FramePeriodUs() const {
#ifdef USE_FFMPEG
if (!codecCtx_ || codecCtx_->framerate.num <= 0 || codecCtx_->framerate.den <= 0) {
return 0;
}
return (int)((s64)1000000 * codecCtx_->framerate.den / codecCtx_->framerate.num);
#else
return 0;
#endif
}
const u8 *AvcDecoder::Plane(int index) const {
#ifdef USE_FFMPEG
if (!haveFrame_ || !frame_ || index < 0 || index >= 3) {
+2
View File
@@ -56,6 +56,8 @@ public:
// necessarily the width.
const u8 *Plane(int index) const;
int Stride(int index) const;
// The frame period the bitstream declares, in microseconds, or 0 if it says nothing useful.
int FramePeriodUs() const;
// True if we were built without ffmpeg, in which case nothing decodes.
static bool IsAvailable();
+7
View File
@@ -2209,3 +2209,10 @@ UCJS10100 = true
UCKS45127 = true
UCJS18055 = true
NPJG00027 = true
[PaceVideocodecDecode]
# Ys I & II Chronicles - the game never paces the video itself, so an instant decode runs
# the picture ahead of the audio and the movie ends early.
ULUS10547 = true
ULJM05475 = true
NPUH10091 = true