Switch to a fixed size displaylist queue.

This commit is contained in:
Unknown W. Brackets 2013-04-04 23:19:28 -07:00
parent c986228d12
commit 339b444703
4 changed files with 132 additions and 69 deletions

View file

@ -115,7 +115,7 @@ void __GeShutdown()
void __GeTriggerInterrupt(int listid, u32 pc, int subIntrBase, u16 subIntrToken)
{
// ClaDun X2 does not expect sceGeListEnqueue to reschedule (which it does not on the PSP.)
// Once PPSSPP's GPU is multithreaded, we can remove this check.
// Once PPSSPP's GPU uses cycles, we can remove this check.
if (subIntrBase < 0)
return;

View file

@ -12,16 +12,40 @@
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/sceGe.h"
static int dlIdGenerator = 1;
GPUCommon::GPUCommon() :
currentList(NULL),
isbreak(false),
dumpNextFrame_(false),
dumpThisFrame_(false),
interruptsEnabled_(true)
{
for (int i = 0; i < DisplayListMaxCount; ++i)
dls[i].state = PSP_GE_DL_STATE_NONE;
}
void init() {
dlIdGenerator = 1;
void GPUCommon::PopDLQueue() {
if(!dlQueue.empty()) {
dlQueue.pop_front();
if(!dlQueue.empty()) {
bool running = currentList->state == PSP_GE_DL_STATE_RUNNING;
currentList = &dls[dlQueue.front()];
if (running)
currentList->state = PSP_GE_DL_STATE_RUNNING;
} else {
currentList = NULL;
}
}
}
u32 GPUCommon::DrawSync(int mode) {
if (mode < 0 || mode > 1)
return SCE_KERNEL_ERROR_INVALID_MODE;
while (currentList != NULL && currentList->state == PSP_GE_DL_STATE_COMPLETED)
PopDLQueue();
CheckDrawSync();
if (mode == 0) {
// TODO: Wait.
return 0;
@ -36,30 +60,33 @@ u32 GPUCommon::DrawSync(int mode) {
return PSP_GE_LIST_DRAWING;
}
void GPUCommon::CheckDrawSync()
{
if (dlQueue.empty()) {
for (int i = 0; i < DisplayListMaxCount; ++i)
dls[i].state = PSP_GE_DL_STATE_NONE;
}
}
int GPUCommon::ListSync(int listid, int mode)
{
if (listid < 0 || listid >= DisplayListMaxCount)
return SCE_KERNEL_ERROR_INVALID_ID;
if (mode < 0 || mode > 1)
return SCE_KERNEL_ERROR_INVALID_MODE;
if (mode == 1) {
DisplayList *dl = NULL;
for (DisplayListQueue::iterator it(dlQueue.begin()); it != dlQueue.end(); ++it) {
if (it->id == listid) {
dl = &*it;
}
}
DisplayList& dl = dls[listid];
if (!dl)
return SCE_KERNEL_ERROR_INVALID_ID;
switch (dl->state) {
switch (dl.state) {
case PSP_GE_DL_STATE_QUEUED:
if (dl->interrupted)
if (dl.interrupted)
return PSP_GE_LIST_PAUSED;
return PSP_GE_LIST_QUEUED;
case PSP_GE_DL_STATE_RUNNING:
if (dl->pc == dl->stall)
if (dl.pc == dl.stall)
return PSP_GE_LIST_STALLING;
return PSP_GE_LIST_DRAWING;
@ -87,8 +114,49 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head)
if (((listpc | stall) & 3) != 0)
return 0x80000103;
DisplayList dl;
dl.id = dlIdGenerator++;
int id = -1;
bool oldCompatibility = true;
if (sceKernelGetCompiledSdkVersion() > 0x01FFFFFF) {
//numStacks = 0;
//stack = NULL;
oldCompatibility = false;
}
for (int i = 0; i < DisplayListMaxCount; ++i)
{
if (dls[i].state != PSP_GE_DL_STATE_NONE && dls[i].state != PSP_GE_DL_STATE_COMPLETED) {
if (dls[i].pc == listpc && !oldCompatibility) {
ERROR_LOG(G3D, "sceGeListEnqueue: can't enqueue, list address %08X already used", listpc);
return 0x80000021;
}
//if(dls[i].stack == stack) {
// ERROR_LOG(G3D, "sceGeListEnqueue: can't enqueue, list stack %08X already used", context);
// return 0x80000021;
//}
}
if (dls[i].state == PSP_GE_DL_STATE_NONE)
{
// Prefer a list that isn't used
id = i;
break;
}
if (id < 0 && dls[i].state == PSP_GE_DL_STATE_COMPLETED)
{
id = i;
}
}
if (id < 0)
{
ERROR_LOG(G3D, "No DL ID available to enqueue");
for(auto it = dlQueue.begin(); it != dlQueue.end(); ++it) {
DisplayList &dl = dls[*it];
DEBUG_LOG(G3D, "DisplayList %d status %d pc %08x stall %08x", *it, dl.state, dl.pc, dl.stall);
}
return SCE_KERNEL_ERROR_OUT_OF_MEMORY;
}
DisplayList &dl = dls[id];
dl.id = id;
dl.startpc = listpc & 0xFFFFFFF;
dl.pc = listpc & 0xFFFFFFF;
dl.stall = stall & 0xFFFFFFF;
@ -97,6 +165,7 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head)
dl.stackptr = 0;
dl.signal = PSP_GE_SIGNAL_NONE;
dl.interrupted = false;
if (head) {
if (currentList) {
if (currentList->state != PSP_GE_DL_STATE_PAUSED)
@ -105,21 +174,22 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head)
}
dl.state = PSP_GE_DL_STATE_PAUSED;
dlQueue.push_front(dl);
currentList = &dlQueue.front();
currentList = &dl;
dlQueue.push_front(id);
} else if (currentList) {
dl.state = PSP_GE_DL_STATE_QUEUED;
dlQueue.push_back(dl);
dlQueue.push_back(id);
} else {
dl.state = PSP_GE_DL_STATE_RUNNING;
dlQueue.push_back(dl);
currentList = &dlQueue.front();
currentList = &dl;
dlQueue.push_front(id);
// TODO save context when starting the list if param is set
ProcessDLQueue();
}
return dl.id;
return id;
}
u32 GPUCommon::DequeueList(int listid)
@ -130,14 +200,10 @@ u32 GPUCommon::DequeueList(int listid)
u32 GPUCommon::UpdateStall(int listid, u32 newstall)
{
for (auto iter = dlQueue.begin(); iter != dlQueue.end(); ++iter)
{
DisplayList &cur = *iter;
if (cur.id == listid)
{
cur.stall = newstall & 0xFFFFFFF;
}
}
if (listid < 0 || listid >= DisplayListMaxCount || dls[listid].state == PSP_GE_DL_STATE_NONE)
return 0x80000100;
dls[listid].stall = newstall & 0xFFFFFFF;
ProcessDLQueue();
@ -190,10 +256,17 @@ u32 GPUCommon::Break(int mode)
if (!currentList)
return 0x80000020;
if(mode == 1)
if (mode == 1)
{
currentList = NULL;
// Clear the queue
dlQueue.clear();
for (int i = 0; i < DisplayListMaxCount; ++i)
{
dls[i].state = PSP_GE_DL_STATE_NONE;
dls[i].signal = PSP_GE_SIGNAL_NONE;
}
currentList = NULL;
return 0;
}
@ -321,7 +394,7 @@ bool GPUCommon::ProcessDLQueue()
DisplayListQueue::iterator iter = dlQueue.begin();
while (iter != dlQueue.end())
{
DisplayList &l = *iter;
DisplayList &l = dls[*iter];
DEBUG_LOG(G3D,"Okay, starting DL execution at %08x - stall = %08x", l.pc, l.stall);
if (!InterpretList(l))
{
@ -477,19 +550,18 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
}
void GPUCommon::DoState(PointerWrap &p) {
p.Do(dlIdGenerator);
p.Do<DisplayList>(dlQueue);
int currentID = currentList == NULL ? 0 : currentList->id;
p.Do<int>(dlQueue);
p.DoArray(dls, ARRAY_SIZE(dls));
int currentID = 0;
if (currentList != NULL) {
ptrdiff_t off = currentList - &dls[0];
currentID = off / sizeof(DisplayList);
}
p.Do(currentID);
if (currentID == 0) {
currentList = 0;
currentList = NULL;
} else {
for (auto it = dlQueue.begin(), end = dlQueue.end(); it != end; ++it) {
if (it->id == currentID) {
currentList = &*it;
break;
}
}
currentList = &dls[currentID];
}
p.Do(interruptRunning);
p.Do(prev);

View file

@ -5,14 +5,8 @@
class GPUCommon : public GPUInterface
{
public:
GPUCommon() :
dlIdGenerator(1),
currentList(NULL),
isbreak(false),
dumpNextFrame_(false),
dumpThisFrame_(false),
interruptsEnabled_(true)
{}
GPUCommon();
virtual ~GPUCommon() {}
virtual void InterruptStart();
virtual void InterruptEnd();
@ -36,10 +30,12 @@ public:
protected:
void UpdateCycles(u32 pc, u32 newPC = 0);
void PopDLQueue();
void CheckDrawSync();
typedef std::deque<DisplayList> DisplayListQueue;
typedef std::list<int> DisplayListQueue;
int dlIdGenerator;
DisplayList dls[DisplayListMaxCount];
DisplayList *currentList;
DisplayListQueue dlQueue;
@ -59,17 +55,10 @@ protected:
public:
virtual DisplayList* getList(int listid)
{
if (currentList && currentList->id == listid)
return currentList;
for(auto it = dlQueue.begin(); it != dlQueue.end(); ++it)
{
if(it->id == listid)
return &*it;
}
return NULL;
return &dls[listid];
}
const std::deque<DisplayList>& GetDisplayLists()
const std::list<int>& GetDisplayLists()
{
return dlQueue;
}

View file

@ -19,7 +19,7 @@
#include "../Globals.h"
#include "GPUState.h"
#include <deque>
#include <list>
class PointerWrap;
@ -128,16 +128,19 @@ class GPUInterface
public:
virtual ~GPUInterface() {}
static const int DisplayListMaxCount = 64;
// Initialization
virtual void InitClear() = 0;
// Draw queue management
virtual DisplayList* getList(int listid) = 0;
// TODO: Much of this should probably be shared between the different GPU implementations.
virtual u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) = 0;
virtual u32 UpdateStall(int listid, u32 newstall) = 0;
virtual u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) = 0;
virtual u32 DequeueList(int listid) = 0;
virtual u32 UpdateStall(int listid, u32 newstall) = 0;
virtual u32 DrawSync(int mode) = 0;
virtual int ListSync(int listid, int mode) = 0;
virtual u32 Continue() = 0;
virtual u32 Break(int mode) = 0;
@ -147,7 +150,6 @@ public:
virtual void PreExecuteOp(u32 op, u32 diff) = 0;
virtual void ExecuteOp(u32 op, u32 diff) = 0;
virtual bool InterpretList(DisplayList& list) = 0;
virtual int ListSync(int listid, int mode) = 0;
// Framebuffer management
virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, int format) = 0;
@ -175,7 +177,7 @@ public:
// Debugging
virtual void DumpNextFrame() = 0;
virtual const std::deque<DisplayList>& GetDisplayLists() = 0;
virtual const std::list<int>& GetDisplayLists() = 0;
virtual DisplayList* GetCurrentDisplayList() = 0;
virtual bool DecodeTexture(u8* dest, GPUgstate state) = 0;
virtual std::vector<FramebufferInfo> GetFramebufferList() = 0;