// Copyright (c) 2012- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 2.0 or later versions. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "HLE.h" #include "../MIPS/MIPS.h" #include "../System.h" #include "../CoreParameter.h" #include "sceGe.h" #include "sceKernelThread.h" #include "sceKernelInterrupt.h" #include "../GPU/GPUState.h" #include "../GPU/GPUInterface.h" // TODO: This doesn't really belong here static int state; void __GeInit() { state = 0; } void __GeShutdown() { } // The GE is implemented wrong - it should be parallel to the CPU execution instead of // synchronous. u32 sceGeEdramGetAddr() { u32 retVal = 0x04000000; DEBUG_LOG(HLE, "%08x = sceGeEdramGetAddr", retVal); return retVal; } u32 sceGeEdramGetSize() { u32 retVal = 0x00200000; DEBUG_LOG(HLE, "%08x = sceGeEdramGetSize()", retVal); return retVal; } u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optParamAddr) { DEBUG_LOG(HLE, "sceGeListEnQueue(addr=%08x, stall=%08x, cbid=%08x, param=%08x)", listAddress, stallAddress, callbackId, optParamAddr); //if (!stallAddress) // stallAddress = listAddress; u32 listID = gpu->EnqueueList(listAddress, stallAddress); // HACKY if (listID) state = SCE_GE_LIST_STALLING; else state = SCE_GE_LIST_COMPLETED; DEBUG_LOG(HLE, "List %i enqueued.", listID); //return display list ID return listID; } u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optParamAddr) { DEBUG_LOG(HLE, "sceGeListEnQueueHead(addr=%08x, stall=%08x, cbid=%08x, param=%08x)", listAddress, stallAddress, callbackId, optParamAddr); //if (!stallAddress) // stallAddress = listAddress; u32 listID = gpu->EnqueueList(listAddress, stallAddress); // HACKY if (listID) state = SCE_GE_LIST_STALLING; else state = SCE_GE_LIST_COMPLETED; DEBUG_LOG(HLE, "List %i enqueued.", listID); //return display list ID return listID; } void sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress) { DEBUG_LOG(HLE, "sceGeListUpdateStallAddr(dlid=%i,stalladdr=%08x)", displayListID, stallAddress); gpu->UpdateStall(displayListID, stallAddress); } int sceGeListSync(u32 displayListID, u32 mode) //0 : wait for completion 1:check and return { DEBUG_LOG(HLE, "sceGeListSync(dlid=%08x, mode=%08x)", displayListID, mode); return 0; } u32 sceGeDrawSync(u32 mode) { //wait/check entire drawing state DEBUG_LOG(HLE, "FAKE sceGeDrawSync(mode=%d) (0=wait for completion)", mode); gpu->DrawSync(mode); return 0; } void sceGeContinue() { ERROR_LOG(HLE, "UNIMPL sceGeContinue"); // no arguments } void sceGeBreak(u32 mode) { //mode => 0 : current dlist 1: all drawing ERROR_LOG(HLE, "UNIMPL sceGeBreak(mode=%d)", mode); } 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) { 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); } if (ge_callback_data.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); } // TODO: This should return a callback ID return 0; } void 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); } // Points to 512 32-bit words, where we can probably layout the context however we want // unless some insane game pokes it and relies on it... u32 sceGeSaveContext(u32 ctxAddr) { DEBUG_LOG(HLE, "sceGeSaveContext(%08x)", ctxAddr); gpu->Flush(); if (sizeof(gstate) > 512 * 4) { ERROR_LOG(HLE, "AARGH! sizeof(gstate) has grown too large!"); return 0; } // Let's just dump gstate. if (Memory::IsValidAddress(ctxAddr)) { Memory::WriteStruct(ctxAddr, &gstate); } // This action should probably be pushed to the end of the queue of the display thread - // when we have one. return 0; } u32 sceGeRestoreContext(u32 ctxAddr) { DEBUG_LOG(HLE, "sceGeRestoreContext(%08x)", ctxAddr); gpu->Flush(); if (sizeof(gstate) > 512 * 4) { ERROR_LOG(HLE, "AARGH! sizeof(gstate) has grown too large!"); return 0; } if (Memory::IsValidAddress(ctxAddr)) { Memory::ReadStruct(ctxAddr, &gstate); } ReapplyGfxState(); return 0; } void sceGeGetMtx() { ERROR_LOG(HLE, "UNIMPL sceGeGetMtx()"); } u32 sceGeEdramSetAddrTranslation(int new_size) { INFO_LOG(HLE, "sceGeEdramSetAddrTranslation(%i)", new_size); static int EDRamWidth; int last = EDRamWidth; EDRamWidth = new_size; return last; } const HLEFunction sceGe_user[] = { {0xE47E40E4,&WrapU_V, "sceGeEdramGetAddr"}, {0xAB49E76A,&WrapU_UUUU, "sceGeListEnQueue"}, {0x1C0D95A6,&WrapU_UUUU, "sceGeListEnQueueHead"}, {0xE0D68148,&WrapV_UU, "sceGeListUpdateStallAddr"}, {0x03444EB4,&WrapI_UU, "sceGeListSync"}, {0xB287BD61,&WrapU_U, "sceGeDrawSync"}, {0xB448EC0D,&WrapV_U, "sceGeBreak"}, {0x4C06E472,sceGeContinue, "sceGeContinue"}, {0xA4FC06A4,&WrapU_U, "sceGeSetCallback"}, {0x05DB22CE,&WrapV_U, "sceGeUnsetCallback"}, {0x1F6752AD,&WrapU_V, "sceGeEdramGetSize"}, {0xB77905EA,&WrapU_I,"sceGeEdramSetAddrTranslation"}, {0xDC93CFEF,0,"sceGeGetCmd"}, {0x57C8945B,&sceGeGetMtx,"sceGeGetMtx"}, {0x438A385A,&WrapU_U,"sceGeSaveContext"}, {0x0BF608FB,&WrapU_U,"sceGeRestoreContext"}, {0x5FB86AB0,0,"sceGeListDeQueue"}, }; void Register_sceGe_user() { RegisterModule("sceGe_user", ARRAY_SIZE(sceGe_user), sceGe_user); }