Merge pull request #3075 from unknownbrackets/gpu-thread

Prep work for GE and CPU on separate threads
This commit is contained in:
Henrik Rydgård 2013-08-07 01:00:26 -07:00
commit b8978e49d2
11 changed files with 38 additions and 47 deletions

View File

@ -204,7 +204,7 @@ void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata
{
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
Event *ne = GetNewTsEvent();
ne->time = globalTimer + cyclesIntoFuture;
ne->time = GetTicks() + cyclesIntoFuture;
ne->type = event_type;
ne->next = 0;
ne->userdata = userdata;
@ -337,7 +337,10 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata)
}
}
if (!tsFirst)
{
tsLast = NULL;
return result;
}
Event *prev = tsFirst;
Event *ptr = prev->next;
@ -348,6 +351,8 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata)
result = ptr->time - globalTimer;
prev->next = ptr->next;
if (ptr == tsLast)
tsLast = prev;
FreeTsEvent(ptr);
ptr = prev->next;
}
@ -439,6 +444,7 @@ void RemoveThreadsafeEvent(int event_type)
}
if (!tsFirst)
{
tsLast = NULL;
return;
}
Event *prev = tsFirst;
@ -448,6 +454,8 @@ void RemoveThreadsafeEvent(int event_type)
if (ptr->type == event_type)
{
prev->next = ptr->next;
if (ptr == tsLast)
tsLast = prev;
FreeTsEvent(ptr);
ptr = prev->next;
}
@ -460,7 +468,7 @@ void RemoveThreadsafeEvent(int event_type)
}
void RemoveAllEvents(int event_type)
{
{
RemoveThreadsafeEvent(event_type);
RemoveEvent(event_type);
}
@ -491,7 +499,7 @@ void MoveEvents()
Common::AtomicStoreRelease(hasTsEvents, 0);
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
// Move events from async queue into main queue
// Move events from async queue into main queue
while (tsFirst)
{
Event *next = tsFirst->next;
@ -511,12 +519,14 @@ void MoveEvents()
}
}
void AdvanceQuick()
void Advance()
{
int cyclesExecuted = slicelength - currentMIPS->downcount;
globalTimer += cyclesExecuted;
currentMIPS->downcount = slicelength;
if (Common::AtomicLoadAcquire(hasTsEvents))
MoveEvents();
ProcessFifoWaitEvents();
if (!first)
@ -535,14 +545,6 @@ void AdvanceQuick()
advanceCallback(cyclesExecuted);
}
void Advance()
{
if (Common::AtomicLoadAcquire(hasTsEvents))
MoveEvents();
AdvanceQuick();
}
void LogPendingEvents()
{
Event *ptr = first;

View File

@ -99,7 +99,6 @@ namespace CoreTiming
void RemoveAllEvents(int event_type);
bool IsScheduled(int event_type);
void Advance();
void AdvanceQuick();
void MoveEvents();
void ProcessFifoWaitEvents();

View File

@ -199,11 +199,11 @@ bool __GeTriggerSync(WaitType waitType, int id, u64 atTicks)
s64 future = atTicks - CoreTiming::GetTicks();
if (waitType == WAITTYPE_GEDRAWSYNC)
{
s64 left = CoreTiming::UnscheduleEvent(geSyncEvent, userdata);
s64 left = CoreTiming::UnscheduleThreadsafeEvent(geSyncEvent, userdata);
if (left > future)
future = left;
}
CoreTiming::ScheduleEvent(future, geSyncEvent, userdata);
CoreTiming::ScheduleEvent_Threadsafe(future, geSyncEvent, userdata);
return true;
}
@ -211,7 +211,7 @@ bool __GeTriggerSync(WaitType waitType, int id, u64 atTicks)
bool __GeTriggerInterrupt(int listid, u32 pc, u64 atTicks)
{
u64 userdata = (u64)listid << 32 | (u64) pc;
CoreTiming::ScheduleEvent(atTicks - CoreTiming::GetTicks(), geInterruptEvent, userdata);
CoreTiming::ScheduleEvent_Threadsafe(atTicks - CoreTiming::GetTicks(), geInterruptEvent, userdata);
return true;
}
@ -279,7 +279,7 @@ int sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress)
{
DEBUG_LOG(HLE, "sceGeListUpdateStallAddr(dlid=%i, stalladdr=%08x)", displayListID, stallAddress);
hleEatCycles(190);
CoreTiming::AdvanceQuick();
CoreTiming::Advance();
return gpu->UpdateStall(displayListID, stallAddress);
}

View File

@ -1169,7 +1169,7 @@ void __KernelIdle()
CoreTiming::Idle();
// Advance must happen between Idle and Reschedule, so that threads that were waiting for something
// that was triggered at the end of the Idle period must get a chance to be scheduled.
CoreTiming::AdvanceQuick();
CoreTiming::Advance();
// We must've exited a callback?
if (__KernelInCallback())
@ -1724,7 +1724,7 @@ void __KernelReSchedule(const char *reason)
}
// Execute any pending events while we're doing scheduling.
CoreTiming::AdvanceQuick();
CoreTiming::Advance();
if (__IsInInterrupt() || __KernelInCallback() || !__KernelIsDispatchEnabled())
{
reason = "In Interrupt Or Callback";

View File

@ -60,23 +60,15 @@ namespace SaveState
void *cbUserData;
};
static int timer;
static bool needsProcess = false;
static std::vector<Operation> pending;
static std::recursive_mutex mutex;
void Process(u64 userdata, int cyclesLate);
void SaveStart::DoState(PointerWrap &p)
{
// Gotta do CoreTiming first since we'll restore into it.
CoreTiming::DoState(p);
// This save state even saves its own state.
p.Do(timer);
CoreTiming::RestoreRegisterEvent(timer, "SaveState", Process);
p.DoMarker("SaveState");
Memory::DoState(p);
MemoryStick_DoState(p);
currentMIPS->DoState(p);
@ -96,10 +88,8 @@ namespace SaveState
if (Core_IsInactive() && __KernelIsRunning())
{
// Warning: this may run on a different thread.
Process(0, 0);
Process();
}
else if (__KernelIsRunning())
CoreTiming::ScheduleEvent_Threadsafe(0, timer);
else
needsProcess = true;
}
@ -210,8 +200,12 @@ namespace SaveState
return copy;
}
void Process(u64 userdata, int cyclesLate)
void Process()
{
if (!needsProcess)
return;
needsProcess = false;
if (!__KernelIsRunning())
{
ERROR_LOG(COMMON, "Savestate failure: Unable to load without kernel, this should never happen.");
@ -272,15 +266,9 @@ namespace SaveState
void Init()
{
timer = CoreTiming::RegisterEvent("SaveState", Process);
// Make sure there's a directory for save slots
pspFileSystem.MkDir("ms0:/PSP/PPSSPP_STATE");
std::lock_guard<std::recursive_mutex> guard(mutex);
if (needsProcess)
{
CoreTiming::ScheduleEvent(0, timer);
needsProcess = false;
}
}
}

View File

@ -31,7 +31,9 @@ namespace SaveState
void SaveSlot(int slot, Callback callback, void *cbUserData = 0);
void LoadSlot(int slot, Callback callback, void *cbUserData = 0);
// Checks whether there's an existing save in the specified slot.
bool HasSaveInSlot(int slot);
// Returns -1 if there's no newest slot.
int GetNewestSlot();
// Load the specified file into the current state (async.)
@ -45,4 +47,7 @@ namespace SaveState
// For testing / automated tests. Runs a save state verification pass (async.)
// Warning: callback will be called on a different thread.
void Verify(Callback callback = 0, void *cbUserData = 0);
// Check if there's any save stating needing to be done. Normally called once per frame.
void Process();
};

View File

@ -38,6 +38,7 @@
#include "Core/Loaders.h"
#include "Core/PSPLoaders.h"
#include "Core/ELF/ParamSFO.h"
#include "Core/SaveState.h"
#include "Common/LogManager.h"
MetaFileSystem pspFileSystem;
@ -151,6 +152,7 @@ void PSP_Shutdown()
}
void PSP_RunLoopUntil(u64 globalticks) {
SaveState::Process();
mipsr4k.RunLoopUntil(globalticks);
}

View File

@ -326,12 +326,6 @@ void GLES_GPU::CopyDisplayToOutput() {
// Render queue
u32 GLES_GPU::DrawSync(int mode)
{
transformDraw_.Flush();
return GPUCommon::DrawSync(mode);
}
void GLES_GPU::FastRunLoop(DisplayList &list) {
for (; downcount > 0; --downcount) {
u32 op = Memory::ReadUnchecked_U32(list.pc);

View File

@ -38,7 +38,6 @@ public:
virtual void InitClear();
virtual void PreExecuteOp(u32 op, u32 diff);
virtual void ExecuteOp(u32 op, u32 diff);
virtual u32 DrawSync(int mode);
virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format);
virtual void CopyDisplayToOutput();

View File

@ -186,6 +186,7 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head)
dl.signal = PSP_GE_SIGNAL_NONE;
dl.interrupted = false;
dl.waitTicks = (u64)-1;
dl.interruptsEnabled = interruptsEnabled_;
if (head) {
if (currentList) {
@ -720,7 +721,7 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
break;
}
// TODO: Technically, jump/call/ret should generate an interrupt, but before the pc change maybe?
if (interruptsEnabled_ && trigger) {
if (currentList->interruptsEnabled && trigger) {
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted))
UpdateState(GPUSTATE_INTERRUPT);
}
@ -729,7 +730,7 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
case GE_CMD_FINISH:
switch (currentList->signal) {
case PSP_GE_SIGNAL_HANDLER_PAUSE:
if (interruptsEnabled_) {
if (currentList->interruptsEnabled) {
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted))
UpdateState(GPUSTATE_INTERRUPT);
}
@ -744,7 +745,7 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
currentList->subIntrToken = prev & 0xFFFF;
currentList->state = PSP_GE_DL_STATE_COMPLETED;
UpdateState(GPUSTATE_DONE);
if (!interruptsEnabled_ || !__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
if (!currentList->interruptsEnabled || !__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
currentList->waitTicks = startingTicks + cyclesExecuted;
busyTicks = std::max(busyTicks, currentList->waitTicks);
__GeTriggerSync(WAITTYPE_GELISTSYNC, currentList->id, currentList->waitTicks);

View File

@ -130,6 +130,7 @@ struct DisplayList
int stackptr;
bool interrupted;
u64 waitTicks;
bool interruptsEnabled;
};
enum GPUInvalidationType {