Use a timer to keep gpu/cpu in sync periodically.

Fixes Diva Extend demo, at least, losing FPS.
This commit is contained in:
Unknown W. Brackets 2013-08-11 13:41:42 -07:00
parent 7c4d273879
commit cf7c718706
4 changed files with 48 additions and 1 deletions

View file

@ -40,6 +40,11 @@ struct GeInterruptData
static std::list<GeInterruptData> ge_pending_cb;
static int geSyncEvent;
static int geInterruptEvent;
static int geCycleEvent;
// Let's try updating 10 times per vblank.
const int geIntervalUs = 1000000 / (60 * 10);
const int geBehindThresholdUs = 1000000 / (60 * 10);
class GeIntrHandler : public IntrHandler
{
@ -162,6 +167,20 @@ void __GeExecuteInterrupt(u64 userdata, int cyclesLate)
__TriggerInterrupt(PSP_INTR_IMMEDIATE, PSP_GE_INTR, PSP_INTR_SUB_NONE);
}
void __GeCheckCycles(u64 userdata, int cyclesLate)
{
u64 geTicks = gpu->GetTickEstimate();
if (geTicks != 0)
{
if (CoreTiming::GetTicks() > geTicks + usToCycles(geBehindThresholdUs)) {
u64 diff = CoreTiming::GetTicks() - geTicks;
gpu->SyncThread();
CoreTiming::Advance();
}
}
CoreTiming::ScheduleEvent(usToCycles(geIntervalUs), geCycleEvent, 0);
}
void __GeInit()
{
memset(&ge_used_callbacks, 0, sizeof(ge_used_callbacks));
@ -170,6 +189,12 @@ void __GeInit()
geSyncEvent = CoreTiming::RegisterEvent("GeSyncEvent", &__GeExecuteSync);
geInterruptEvent = CoreTiming::RegisterEvent("GeInterruptEvent", &__GeExecuteInterrupt);
geCycleEvent = CoreTiming::RegisterEvent("GeCycleEvent", &__GeCheckCycles);
// When we're using separate CPU/GPU threads, we need to keep them in sync.
if (IsOnSeparateCPUThread()) {
CoreTiming::ScheduleEvent(usToCycles(geIntervalUs), geCycleEvent, 0);
}
}
void __GeDoState(PointerWrap &p)
@ -182,6 +207,8 @@ void __GeDoState(PointerWrap &p)
CoreTiming::RestoreRegisterEvent(geSyncEvent, "GeSyncEvent", &__GeExecuteSync);
p.Do(geInterruptEvent);
CoreTiming::RestoreRegisterEvent(geInterruptEvent, "GeInterruptEvent", &__GeExecuteInterrupt);
p.Do(geCycleEvent);
CoreTiming::RestoreRegisterEvent(geCycleEvent, "GeCycleEvent", &__GeCheckCycles);
// Everything else is done in sceDisplay.
p.DoMarker("sceGe");

View file

@ -20,7 +20,8 @@ GPUCommon::GPUCommon() :
busyTicks(0),
dumpNextFrame_(false),
dumpThisFrame_(false),
interruptsEnabled_(true)
interruptsEnabled_(true),
curTickEst_(0)
{
memset(dls, 0, sizeof(dls));
for (int i = 0; i < DisplayListMaxCount; ++i) {
@ -579,6 +580,7 @@ bool GPUCommon::ProcessDLQueue() {
void GPUCommon::ProcessDLQueueInternal() {
startingTicks = CoreTiming::GetTicks();
cyclesExecuted = 0;
UpdateTickEstimate(std::max(busyTicks, startingTicks + cyclesExecuted));
if (startingTicks < busyTicks) {
DEBUG_LOG(HLE, "Can't execute a list yet, still busy for %lld ticks", busyTicks - startingTicks);
@ -594,6 +596,7 @@ void GPUCommon::ProcessDLQueueInternal() {
easy_guard guard(listLock);
// At the end, we can remove it from the queue and continue.
dlQueue.erase(std::remove(dlQueue.begin(), dlQueue.end(), listIndex), dlQueue.end());
UpdateTickEstimate(std::max(busyTicks, startingTicks + cyclesExecuted));
}
}
@ -603,6 +606,8 @@ void GPUCommon::ProcessDLQueueInternal() {
drawCompleteTicks = startingTicks + cyclesExecuted;
busyTicks = std::max(busyTicks, drawCompleteTicks);
__GeTriggerSync(WAITTYPE_GEDRAWSYNC, 1, drawCompleteTicks);
// Since the event is in CoreTiming, we're in sync. Just set 0 now.
UpdateTickEstimate(0);
}
void GPUCommon::PreExecuteOp(u32 op, u32 diff) {

View file

@ -36,6 +36,11 @@ public:
virtual u32 Break(int mode);
virtual void ReapplyGfxState();
virtual u64 GetTickEstimate() {
lock_guard guard(curTickEstLock_);
return curTickEst_;
}
protected:
// To avoid virtual calls to PreExecuteOp().
virtual void FastRunLoop(DisplayList &list) = 0;
@ -86,6 +91,15 @@ protected:
bool dumpThisFrame_;
bool interruptsEnabled_;
// For CPU/GPU sync.
volatile u64 curTickEst_;
recursive_mutex curTickEstLock_;
virtual void UpdateTickEstimate(u64 value) {
lock_guard guard(curTickEstLock_);
curTickEst_ = value;
}
public:
virtual DisplayList* getList(int listid)
{

View file

@ -224,6 +224,7 @@ public:
virtual void DeviceLost() = 0;
virtual void ReapplyGfxState() = 0;
virtual void SyncThread() = 0;
virtual u64 GetTickEstimate() = 0;
virtual void DoState(PointerWrap &p) = 0;
// Called by the window system if the window size changed. This will be reflected in PSPCoreParam.pixel*.