diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 2795e24c4f..4de18203a4 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -410,6 +410,11 @@ template void WrapU_UUUI() { RETURN(retval); } +template void WrapU_UUIU() { + u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); + RETURN(retval); +} + template void WrapU_UIII() { u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); RETURN(retval); diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index ca277b5856..80fe768c17 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -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,7 +108,7 @@ 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 @@ -138,32 +166,54 @@ u32 sceGeSetCallback(u32 structAddr) { DEBUG_LOG(HLE, "sceGeSetCallback(struct=%08x)", structAddr); - PspGeCallbackData ge_callback_data; - Memory::ReadStruct(structAddr, &ge_callback_data); + int cbID = -1; + for (int i = 0; i < ARRAY_SIZE(ge_used_callbacks); ++i) + if (!ge_used_callbacks[i]) + { + cbID = i; + break; + } - if (ge_callback_data.finish_func) + if (cbID == -1) + return SCE_KERNEL_ERROR_OUT_OF_MEMORY; + + 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, PSP_GE_SUBINTR_FINISH, - ge_callback_data.finish_func, ge_callback_data.finish_arg); - sceKernelEnableSubIntr(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH); + 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.signal_func) + if (ge_callback_data[cbID].signal_func) { - 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); + 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); } - // TODO: This should return a callback ID - return 0; + 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)) + 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); + } + + ge_used_callbacks[cbID] = false; return 0; } @@ -235,8 +285,8 @@ u32 sceGeEdramSetAddrTranslation(int new_size) const HLEFunction sceGe_user[] = { {0xE47E40E4, WrapU_V, "sceGeEdramGetAddr"}, - {0xAB49E76A, WrapU_UUUU, "sceGeListEnQueue"}, - {0x1C0D95A6, WrapU_UUUU, "sceGeListEnQueueHead"}, + {0xAB49E76A, WrapU_UUIU, "sceGeListEnQueue"}, + {0x1C0D95A6, WrapU_UUIU, "sceGeListEnQueueHead"}, {0xE0D68148, WrapI_UU, "sceGeListUpdateStallAddr"}, {0x03444EB4, WrapI_UU, "sceGeListSync"}, {0xB287BD61, WrapU_U, "sceGeDrawSync"}, diff --git a/Core/HLE/sceGe.h b/Core/HLE/sceGe.h index d6a19a0767..b37508a672 100644 --- a/Core/HLE/sceGe.h +++ b/Core/HLE/sceGe.h @@ -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); diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h index 90835442d1..08c373dfe6 100644 --- a/Core/HLE/sceKernel.h +++ b/Core/HLE/sceKernel.h @@ -23,7 +23,9 @@ enum { - SCE_KERNEL_ERROR_OK = 0, + 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, diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index d5fd95edac..0c0ab11386 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -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: diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index fbb7f46c21..fdceb8a551 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -81,6 +81,7 @@ private: struct CmdProcessorState { u32 pc; u32 stallAddr; + int subIntrBase; }; struct VirtualFramebuffer { diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 725f5295a5..d439de6cb1 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -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 diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 3bed056585..fbd55fd005 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -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); diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 19c2212d77..94d0fc9d77 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -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; diff --git a/GPU/Null/NullGpu.cpp b/GPU/Null/NullGpu.cpp index 8518704b7e..706caa616e 100644 --- a/GPU/Null/NullGpu.cpp +++ b/GPU/Null/NullGpu.cpp @@ -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: