MCPcopy Create free account
hub / github.com/PCSX2/pcsx2 / vSyncInfoCalc

Function vSyncInfoCalc

pcsx2/Counters.cpp:203–260  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

201}
202
203static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 scansPerFrame)
204{
205 constexpr double clock = static_cast<double>(PS2CLK);
206
207 const u64 Frame = clock * 10000ULL / framesPerSecond;
208 const u64 Scanline = Frame / scansPerFrame;
209
210 // There are two renders and blanks per frame. This matches the PS2 test results.
211 // The PAL and NTSC VBlank periods respectively lasts for approximately 22 and 26 scanlines.
212 // An older test suggests that these periods are actually the periods that VBlank is off, but
213 // Legendz Gekitou! Saga Battle runs very slowly if the VBlank period is inverted.
214 // Some of the more timing sensitive games and their symptoms when things aren't right:
215 // Dynasty Warriors 3 Xtreme Legends - fake save corruption when loading save
216 // Jak II - random speedups
217 // Shadow of Rome - FMV audio issues
218 const bool ntsc_hblank = gsVideoMode != GS_VideoMode::PAL && gsVideoMode != GS_VideoMode::DVD_PAL;
219 const u64 HalfFrame = Frame / 2;
220 const float extra_scanlines = static_cast<float>(IsProgressiveVideoMode()) * (ntsc_hblank ? 0.5f : 1.5f);
221 const u64 Blank = Scanline * ((ntsc_hblank ? 22.5f : 24.5f) + extra_scanlines);
222 const u64 Render = HalfFrame - Blank;
223 const u64 GSBlank = Scanline * ((ntsc_hblank ? 3.5 : 3) + extra_scanlines); // GS VBlank/CSR Swap happens roughly 3.5(NTSC) and 3(PAL) Scanlines after VBlank Start
224
225 // Important! The hRender/hBlank timer ratio below is set according to PS2 tests.
226 // in EE Cycles taken from PAL system:
227 // 18876 cycles for hsync
228 // 15796 cycles for hsync are low (render)
229 // Ratio: 83.68298368298368
230 u64 hRender = Scanline * 0.8368298368298368f;
231 u64 hBlank = Scanline - hRender;
232
233 if (!IsInterlacedVideoMode())
234 {
235 hBlank /= 2;
236 hRender /= 2;
237 }
238
239 //TODO: Carry fixed-point math all the way through the entire vsync and hsync counting processes, and continually apply rounding
240 //as needed for each scheduled v/hsync related event. Much better to handle than this messed state.
241 info->Framerate = framesPerSecond;
242 info->GSBlank = (u32)(GSBlank / 10000);
243 info->Render = (u32)(Render / 10000);
244 info->Blank = (u32)(Blank / 10000);
245 const u64 accumilated_vrender = (Render % 10000) + (Blank % 10000);
246 info->Render += (u32)(accumilated_vrender / 10000);
247
248 info->hRender = (u32)(hRender / 10000);
249 info->hBlank = (u32)(hBlank / 10000);
250 info->hScanlinesPerFrame = scansPerFrame;
251
252 const u64 accumilatedHRenderError = (hRender % 10000) + (hBlank % 10000);
253 const u64 accumilatedHFractional = accumilatedHRenderError % 10000;
254 info->hRender += (u32)(accumilatedHRenderError / 10000);
255 info->hSyncError = (u32)((accumilatedHFractional * (scansPerFrame / (IsInterlacedVideoMode() ? 2 : 1))) / 10000);
256
257 // Note: In NTSC modes there is some small rounding error in the vsync too,
258 // however it would take thousands of frames for it to amount to anything and
259 // is thus not worth the effort at this time.
260}

Callers 1

UpdateVSyncRateFunction · 0.85

Calls 2

IsProgressiveVideoModeFunction · 0.85
IsInterlacedVideoModeFunction · 0.85

Tested by

no test coverage detected