Merge pull request #291 from unknownbrackets/ge-callbacks

Respect the desired GE callback
This commit is contained in:
Henrik Rydgård 2012-12-29 16:31:17 -08:00
commit 8f027a6282
10 changed files with 141 additions and 54 deletions

View File

@ -410,6 +410,11 @@ template<u32 func(u32, u32, u32, int)> void WrapU_UUUI() {
RETURN(retval);
}
template<u32 func(u32, u32, int, u32)> void WrapU_UUIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(u32, int, int, int)> void WrapU_UIII() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);

View File

@ -25,13 +25,19 @@
#include "../GPU/GPUState.h"
#include "../GPU/GPUInterface.h"
static PspGeCallbackData ge_callback_data[16];
static bool ge_used_callbacks[16] = {0};
void __GeInit()
{
memset(&ge_used_callbacks, 0, sizeof(ge_used_callbacks));
}
void __GeDoState(PointerWrap &p)
{
// Everything is done in sceDisplay.
p.DoArray(ge_callback_data, ARRAY_SIZE(ge_callback_data));
p.DoArray(ge_used_callbacks, ARRAY_SIZE(ge_used_callbacks));
// Everything else is done in sceDisplay.
p.DoMarker("sceGe");
}
@ -57,7 +63,29 @@ u32 sceGeEdramGetSize()
return retVal;
}
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId,
// TODO: Probably shouldn't use an interrupt?
int __GeSubIntrBase(int callbackId)
{
// Negative means don't use.
if (callbackId < 0)
return 0;
if (callbackId >= ARRAY_SIZE(ge_used_callbacks))
{
WARN_LOG(HLE, "Unexpected (too high) GE callback id %d, ignoring", callbackId);
return 0;
}
if (!ge_used_callbacks[callbackId])
{
WARN_LOG(HLE, "Unregistered GE callback id %d, ignoring", callbackId);
return 0;
}
return (callbackId + 1) << 16;
}
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId,
u32 optParamAddr)
{
DEBUG_LOG(HLE,
@ -65,14 +93,14 @@ u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId,
listAddress, stallAddress, callbackId, optParamAddr);
//if (!stallAddress)
// stallAddress = listAddress;
u32 listID = gpu->EnqueueList(listAddress, stallAddress, false);
u32 listID = gpu->EnqueueList(listAddress, stallAddress, __GeSubIntrBase(callbackId), false);
DEBUG_LOG(HLE, "List %i enqueued.", listID);
//return display list ID
return listID;
}
u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId,
u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, int callbackId,
u32 optParamAddr)
{
DEBUG_LOG(HLE,
@ -80,19 +108,26 @@ u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId,
listAddress, stallAddress, callbackId, optParamAddr);
//if (!stallAddress)
// stallAddress = listAddress;
u32 listID = gpu->EnqueueList(listAddress, stallAddress, true);
u32 listID = gpu->EnqueueList(listAddress, stallAddress, __GeSubIntrBase(callbackId), true);
DEBUG_LOG(HLE, "List %i enqueued.", listID);
//return display list ID
return listID;
}
void sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress)
int sceGeListDeQueue(u32 listID)
{
ERROR_LOG(HLE, "UNIMPL sceGeListDeQueue(%08x)", listID);
return 0;
}
int sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress)
{
DEBUG_LOG(HLE, "sceGeListUpdateStallAddr(dlid=%i,stalladdr=%08x)",
displayListID, stallAddress);
gpu->UpdateStall(displayListID, stallAddress);
return 0;
}
int sceGeListSync(u32 displayListID, u32 mode) //0 : wait for completion 1:check and return
@ -113,47 +148,82 @@ u32 sceGeDrawSync(u32 mode)
return 0;
}
void sceGeContinue()
int sceGeContinue()
{
ERROR_LOG(HLE, "UNIMPL sceGeContinue");
// no arguments
return 0;
}
void sceGeBreak(u32 mode)
int sceGeBreak(u32 mode)
{
//mode => 0 : current dlist 1: all drawing
ERROR_LOG(HLE, "UNIMPL sceGeBreak(mode=%d)", mode);
return 0;
}
u32 sceGeSetCallback(u32 structAddr)
{
DEBUG_LOG(HLE, "sceGeSetCallback(struct=%08x)", structAddr);
PspGeCallbackData ge_callback_data;
Memory::ReadStruct(structAddr, &ge_callback_data);
if (ge_callback_data.finish_func)
int cbID = -1;
for (int i = 0; i < ARRAY_SIZE(ge_used_callbacks); ++i)
if (!ge_used_callbacks[i])
{
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH,
ge_callback_data.finish_func, ge_callback_data.finish_arg);
sceKernelEnableSubIntr(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH);
cbID = i;
break;
}
if (ge_callback_data.signal_func)
if (cbID == -1)
{
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL,
ge_callback_data.signal_func, ge_callback_data.signal_arg);
sceKernelEnableSubIntr(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL);
WARN_LOG(HLE, "sceGeSetCallback(): out of callback ids");
return SCE_KERNEL_ERROR_OUT_OF_MEMORY;
}
// TODO: This should return a callback ID
return 0;
ge_used_callbacks[cbID] = true;
Memory::ReadStruct(structAddr, &ge_callback_data[cbID]);
int subIntrBase = __GeSubIntrBase(cbID);
if (ge_callback_data[cbID].finish_func)
{
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH,
ge_callback_data[cbID].finish_func, ge_callback_data[cbID].finish_arg);
sceKernelEnableSubIntr(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH);
}
if (ge_callback_data[cbID].signal_func)
{
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL,
ge_callback_data[cbID].signal_func, ge_callback_data[cbID].signal_arg);
sceKernelEnableSubIntr(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL);
}
void sceGeUnsetCallback(u32 cbID) {
return cbID;
}
int sceGeUnsetCallback(u32 cbID)
{
DEBUG_LOG(HLE, "sceGeUnsetCallback(cbid=%08x)", cbID);
sceKernelReleaseSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH);
sceKernelReleaseSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL);
if (cbID >= ARRAY_SIZE(ge_used_callbacks))
{
WARN_LOG(HLE, "sceGeUnsetCallback(cbid=%08x): invalid callback id", cbID);
return SCE_KERNEL_ERROR_INVALID_ID;
}
if (ge_used_callbacks[cbID])
{
int subIntrBase = __GeSubIntrBase(cbID);
sceKernelReleaseSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH);
sceKernelReleaseSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL);
}
else
WARN_LOG(HLE, "sceGeUnsetCallback(cbid=%08x): ignoring unregistered callback id", cbID);
ge_used_callbacks[cbID] = false;
return 0;
}
// Points to 512 32-bit words, where we can probably layout the context however we want
@ -199,9 +269,16 @@ u32 sceGeRestoreContext(u32 ctxAddr)
return 0;
}
void sceGeGetMtx()
int sceGeGetMtx(int type, u32 matrixPtr)
{
ERROR_LOG(HLE, "UNIMPL sceGeGetMtx()");
ERROR_LOG(HLE, "UNIMPL sceGeGetMtx(%d, %08x)", type, matrixPtr);
return 0;
}
u32 sceGeGetCmd(int cmd)
{
ERROR_LOG(HLE, "UNIMPL sceGeGetCmd()");
return 0;
}
u32 sceGeEdramSetAddrTranslation(int new_size)
@ -215,23 +292,23 @@ u32 sceGeEdramSetAddrTranslation(int new_size)
const HLEFunction sceGe_user[] =
{
{0xE47E40E4,&WrapU_V<sceGeEdramGetAddr>, "sceGeEdramGetAddr"},
{0xAB49E76A,&WrapU_UUUU<sceGeListEnQueue>, "sceGeListEnQueue"},
{0x1C0D95A6,&WrapU_UUUU<sceGeListEnQueueHead>, "sceGeListEnQueueHead"},
{0xE0D68148,&WrapV_UU<sceGeListUpdateStallAddr>, "sceGeListUpdateStallAddr"},
{0x03444EB4,&WrapI_UU<sceGeListSync>, "sceGeListSync"},
{0xB287BD61,&WrapU_U<sceGeDrawSync>, "sceGeDrawSync"},
{0xB448EC0D,&WrapV_U<sceGeBreak>, "sceGeBreak"},
{0x4C06E472,sceGeContinue, "sceGeContinue"},
{0xA4FC06A4,&WrapU_U<sceGeSetCallback>, "sceGeSetCallback"},
{0x05DB22CE,&WrapV_U<sceGeUnsetCallback>, "sceGeUnsetCallback"},
{0x1F6752AD,&WrapU_V<sceGeEdramGetSize>, "sceGeEdramGetSize"},
{0xB77905EA,&WrapU_I<sceGeEdramSetAddrTranslation>,"sceGeEdramSetAddrTranslation"},
{0xDC93CFEF,0,"sceGeGetCmd"},
{0x57C8945B,&sceGeGetMtx,"sceGeGetMtx"},
{0x438A385A,&WrapU_U<sceGeSaveContext>,"sceGeSaveContext"},
{0x0BF608FB,&WrapU_U<sceGeRestoreContext>,"sceGeRestoreContext"},
{0x5FB86AB0,0,"sceGeListDeQueue"},
{0xE47E40E4, WrapU_V<sceGeEdramGetAddr>, "sceGeEdramGetAddr"},
{0xAB49E76A, WrapU_UUIU<sceGeListEnQueue>, "sceGeListEnQueue"},
{0x1C0D95A6, WrapU_UUIU<sceGeListEnQueueHead>, "sceGeListEnQueueHead"},
{0xE0D68148, WrapI_UU<sceGeListUpdateStallAddr>, "sceGeListUpdateStallAddr"},
{0x03444EB4, WrapI_UU<sceGeListSync>, "sceGeListSync"},
{0xB287BD61, WrapU_U<sceGeDrawSync>, "sceGeDrawSync"},
{0xB448EC0D, WrapI_U<sceGeBreak>, "sceGeBreak"},
{0x4C06E472, WrapI_V<sceGeContinue>, "sceGeContinue"},
{0xA4FC06A4, WrapU_U<sceGeSetCallback>, "sceGeSetCallback"},
{0x05DB22CE, WrapI_U<sceGeUnsetCallback>, "sceGeUnsetCallback"},
{0x1F6752AD, WrapU_V<sceGeEdramGetSize>, "sceGeEdramGetSize"},
{0xB77905EA, WrapU_I<sceGeEdramSetAddrTranslation>, "sceGeEdramSetAddrTranslation"},
{0xDC93CFEF, WrapU_I<sceGeGetCmd>, "sceGeGetCmd"},
{0x57C8945B, WrapI_IU<sceGeGetMtx>, "sceGeGetMtx"},
{0x438A385A, WrapU_U<sceGeSaveContext>, "sceGeSaveContext"},
{0x0BF608FB, WrapU_U<sceGeRestoreContext>, "sceGeRestoreContext"},
{0x5FB86AB0, WrapI_U<sceGeListDeQueue>, "sceGeListDeQueue"},
};
void Register_sceGe_user()

View File

@ -45,4 +45,4 @@ void __GeShutdown();
u32 sceGeRestoreContext(u32 ctxAddr);
u32 sceGeSaveContext(u32 ctxAddr);
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optParamAddr);
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId, u32 optParamAddr);

View File

@ -24,6 +24,8 @@
enum
{
SCE_KERNEL_ERROR_OK = 0,
SCE_KERNEL_ERROR_OUT_OF_MEMORY = 0x80000022,
SCE_KERNEL_ERROR_INVALID_ID = 0x80000100,
SCE_KERNEL_ERROR_INVALID_VALUE = 0x800001fe,
SCE_KERNEL_ERROR_INVALID_ARGUMENT = 0x800001ff,
SCE_KERNEL_ERROR_ERROR = 0x80020001,

View File

@ -543,7 +543,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
case GE_CMD_FINISH:
// TODO: Should this run while interrupts are suspended?
if (interruptsEnabled_)
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, 0);
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_FINISH, 0);
break;
case GE_CMD_END:
@ -581,7 +581,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
}
// TODO: Should this run while interrupts are suspended?
if (interruptsEnabled_)
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, signal);
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_SIGNAL, signal);
}
break;
case GE_CMD_FINISH:

View File

@ -81,6 +81,7 @@ private:
struct CmdProcessorState {
u32 pc;
u32 stallAddr;
int subIntrBase;
};
struct VirtualFramebuffer {

View File

@ -23,13 +23,14 @@ int GPUCommon::listStatus(int listid)
return 0x80000100; // INVALID_ID
}
u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, bool head)
u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head)
{
DisplayList dl;
dl.id = dlIdGenerator++;
dl.pc = listpc & 0xFFFFFFF;
dl.stall = stall & 0xFFFFFFF;
dl.status = PSP_GE_LIST_QUEUED;
dl.subIntrBase = subIntrBase;
if(head)
dlQueue.push_front(dl);
else

View File

@ -17,7 +17,7 @@ public:
virtual bool InterpretList(DisplayList &list);
virtual bool ProcessDLQueue();
virtual void UpdateStall(int listid, u32 newstall);
virtual u32 EnqueueList(u32 listpc, u32 stall, bool head);
virtual u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head);
virtual int listStatus(int listid);
virtual void DoState(PointerWrap &p);

View File

@ -37,6 +37,7 @@ struct DisplayList
u32 pc;
u32 stall;
DisplayListStatus status;
int subIntrBase;
};
class GPUInterface
@ -49,7 +50,7 @@ public:
// Draw queue management
// TODO: Much of this should probably be shared between the different GPU implementations.
virtual u32 EnqueueList(u32 listpc, u32 stall, bool head) = 0;
virtual u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) = 0;
virtual void UpdateStall(int listid, u32 newstall) = 0;
virtual void DrawSync(int mode) = 0;
virtual void Continue() = 0;

View File

@ -138,7 +138,7 @@ void NullGPU::ExecuteOp(u32 op, u32 diff)
// TODO: Should this run while interrupts are suspended?
if (interruptsEnabled_)
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, signal);
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_SIGNAL, signal);
}
break;
@ -170,7 +170,7 @@ void NullGPU::ExecuteOp(u32 op, u32 diff)
DEBUG_LOG(G3D,"DL CMD FINISH");
// TODO: Should this run while interrupts are suspended?
if (interruptsEnabled_)
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, 0);
__TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_FINISH, 0);
break;
case GE_CMD_END: