public static void onGeStartList(PspGeList list) { if (Available && DurationStatistics.collectStatistics) { NativeUtils.notifyEvent(NativeUtils.EVENT_GE_START_LIST); } }
public static void onGeFinishList(PspGeList list) { if (Available && DurationStatistics.collectStatistics) { NativeUtils.notifyEvent(NativeUtils.EVENT_GE_FINISH_LIST); } }
private static void addListToHead(PspGeList list) { lock (drawListQueue) { // The ConcurrentLinkedQueue type doesn't allow adding // objects directly at the head of the queue. // This function creates a new array using the given list as it's head // and constructs a new ConcurrentLinkedQueue based on it. // The actual drawListQueue is then replaced by this new one. int arraySize = drawListQueue.size(); if (arraySize > 0) { PspGeList[] array = drawListQueue.toArray(new PspGeList[arraySize]); ConcurrentLinkedQueue <PspGeList> newQueue = new ConcurrentLinkedQueue <PspGeList>(); PspGeList[] newArray = new PspGeList[arraySize + 1]; newArray[0] = list; for (int i = 0; i < arraySize; i++) { newArray[i + 1] = array[i]; newQueue.add(newArray[i]); } drawListQueue = newQueue; } else { // If the queue is empty. drawListQueue.add(list); } } }
public static void onGeUserStop() { lock (drawListQueue) { drawListQueue.clear(); if (currentList != null) { currentList.sync(); } currentList = null; CoreThread.Instance.sync(); } }
public virtual int sceGeListDeQueue(int id) { lock (this) { PspGeList list = allGeLists[id]; list.reset(); if (!listFreeQueue.contains(list)) { listFreeQueue.add(list); } } return(0); }
private void executeCommandFINISH(PspGeList list) { //if (log.DebugEnabled) { Console.WriteLine(string.Format("FINISH {0}", list)); } list.clearRestart(); list.finishList(); list.pushFinishCallback(list.id, NativeUtils.getCoreCmdArray(GeCommands.FINISH) & 0x00FFFFFF); list.endList(); list.status = sceGe_user.PSP_GE_LIST_DONE; ExternalGE.finishList(list); }
public static void startCapture(string filename, PspGeList list) { //public static void startCapture(int displayBufferAddress, int displayBufferWidth, int displayBufferPsm, // int drawBufferAddress, int drawBufferWidth, int drawBufferPsm, // int depthBufferAddress, int depthBufferWidth) { if (captureInProgress) { VideoEngine.log_Renamed.error("Ignoring startCapture, capture is already in progress"); return; } // Set the VideoEngine log level to TRACE when capturing, // the information in the log file is also interesting logLevel = VideoEngine.log_Renamed.Level; VideoEngine.Instance.LogLevel = Level.TRACE; capturedImages = new HashSet <int>(); try { VideoEngine.log_Renamed.info("Starting capture... (list=" + list.id + ")"); @out = new BufferedOutputStream(new System.IO.FileStream(filename, System.IO.FileMode.Create, System.IO.FileAccess.Write)); CaptureHeader header; /* * // write render target details * header = new CaptureHeader(CaptureHeader.PACKET_TYPE_DISPLAY_DETAILS); * header.write(out); * CaptureDisplayDetails displayDetails = new CaptureDisplayDetails(); * displayDetails.write(out); */ // write command buffer header = new CaptureHeader(CaptureHeader.PACKET_TYPE_LIST); header.write(@out); CaptureList commandList = new CaptureList(list); commandList.write(@out); captureInProgress = true; listExecuted = false; } catch (Exception e) { VideoEngine.log_Renamed.error("Failed to start capture: " + e.Message); Console.WriteLine(e.ToString()); Console.Write(e.StackTrace); Emulator.PauseEmu(); } }
public static void startList(PspGeList list) { if (list == null) { return; } lock (drawListQueue) { if (currentList == null) { if (State.captureGeNextFrame) { State.captureGeNextFrame = false; CaptureManager.captureInProgress = true; NativeUtils.DumpFrames = true; NativeUtils.DumpTextures = true; logLevel = log.Level; log.Level = Level.TRACE; } // Save the context at the beginning of the list processing to the given address (used by sceGu). if (list.hasSaveContextAddr()) { saveContext(list.SaveContextAddr); } list.status = sceGe_user.PSP_GE_LIST_DRAWING; NativeUtils.setLogLevel(); NativeUtils.CoreSadr = list.StallAddr; NativeUtils.setCoreCtrlActive(); lock (screenScaleLock) { // Update the screen scale only at the start of a new list NativeUtils.ScreenScale = ScreenScale; } currentList = list; currentList.sync(); CoreThread.Instance.sync(); } else { drawListQueue.add(list); } } }
private void blockCurrentThreadOnList(PspGeList list, IAction action) { ThreadManForUser threadMan = Modules.ThreadManForUserModule; bool blockCurrentThread = false; bool executeAction = false; lock (this) { int currentThreadId = threadMan.CurrentThreadID; if (list.Done) { // There has been some race condition: the list has just completed // do not block the thread //if (log.DebugEnabled) { Console.WriteLine("blockCurrentThreadOnList not blocking thread " + currentThreadId.ToString("x") + ", list completed " + list); } executeAction = true; } else { //if (log.DebugEnabled) { Console.WriteLine("blockCurrentThreadOnList blocking thread " + currentThreadId.ToString("x") + " on list " + list); } list.blockedThreadIds.Add(currentThreadId); blockCurrentThread = true; } } // Execute the action outside of the synchronized block if (executeAction && action != null) { action.execute(); } // Block the thread outside of the synchronized block if (blockCurrentThread) { // Block the thread, but do not execute callbacks. threadMan.hleBlockCurrentThread(SceKernelThreadInfo.JPCSP_WAIT_GE_LIST, list.id, false, action, new ListSyncWaitStateChecker(list)); ExternalGE.onGeStartWaitList(); } }
public virtual int hleGeListSync(int id) { if (id < 0 || id >= NUMBER_GE_LISTS) { return(-1); } PspGeList list = null; int result; lock (this) { list = allGeLists[id]; result = list.status; } return(result); }
public virtual int sceGeListSync(int id, int mode) { if (mode == 0 && IntrManager.Instance.InsideInterrupt) { Console.WriteLine("sceGeListSync (mode==0) cannot be called inside an interrupt handler!"); return(SceKernelErrors.ERROR_KERNEL_CANNOT_BE_CALLED_FROM_INTERRUPT); } PspGeList list = null; bool blockCurrentThread = false; int result; lock (this) { list = allGeLists[id]; //if (log.DebugEnabled) { Console.WriteLine(string.Format("sceGeListSync on list: {0}", list)); } if (list.Reset) { throw new SceKernelErrorException(SceKernelErrors.ERROR_INVALID_ID); } if (mode == 0 && !list.Done) { result = 0; blockCurrentThread = true; } else { result = list.SyncStatus; } } // Block the current thread outside of the synchronized block if (blockCurrentThread) { blockCurrentThreadOnList(list, null); } return(result); }
private void setStallAddressWithCachedMemory(PspGeList list, int stallAddr) { int startAddress = list.list_addr; int Length; if (stallAddr != 0) { Length = stallAddr - startAddress; } else { // The list has no stall address, scan for the FINISH command IMemoryReader memoryReader = MemoryReader.getMemoryReader(startAddress, 4); Length = 0; while (true) { int instruction = memoryReader.readNext(); int command = VideoEngine.command(instruction); if (command == GeCommands.FINISH) { // Add 4 to include the END command that follows the FINISH command Length = memoryReader.CurrentAddress - startAddress + 4; break; } } } if (Length >= 0) { int[] baseMemoryInts = Utilities.readInt32(startAddress, Length); list.setStallAddr(stallAddr, MemoryReader.getMemoryReader(startAddress, baseMemoryInts, 0, Length), startAddress, startAddress + Length); //if (log.DebugEnabled) { Console.WriteLine(string.Format("setStallAddressWithCachedMemory [0x{0:X8}-0x{1:X8}] {2}", startAddress, startAddress + Length, list)); } } else { list.StallAddr = stallAddr; } }
public virtual void hleGeOnAfterCallback(int listId, int behavior, bool hasCallback) { // (gid15) I could not make any difference between // PSP_GE_BEHAVIOR_CONTINUE and PSP_GE_BEHAVIOR_SUSPEND // Both wait for the completion of the callback before continuing // the list processing... if (behavior == PSP_GE_SIGNAL_HANDLER_CONTINUE || behavior == PSP_GE_SIGNAL_HANDLER_SUSPEND || !hasCallback) { if (listId >= 0 && listId < NUMBER_GE_LISTS) { PspGeList list = allGeLists[listId]; //if (log.DebugEnabled) { Console.WriteLine("hleGeOnAfterCallback restarting list " + list); } list.restartList(); } } }
/// <summary> /// Called from VideoEngine </summary> public virtual void hleGeListSyncDone(PspGeList list) { //if (log.DebugEnabled) { string msg = "hleGeListSyncDone list " + list; if (list.Done) { msg += ", done"; } else { msg += ", NOT done"; } if (list.blockedThreadIds.Count > 0 && list.status != PSP_GE_LIST_END_REACHED) { msg += ", waking thread"; foreach (int threadId in list.blockedThreadIds) { msg += " " + threadId.ToString("x"); } } Console.WriteLine(msg); } lock (this) { if (list.blockedThreadIds.Count > 0 && list.status != PSP_GE_LIST_END_REACHED) { // things might go wrong if the thread already exists in the queue deferredThreadWakeupQueue.addAll(list.blockedThreadIds); } if (list.Done) { listFreeQueue.add(list); } } }
public virtual int sceGeListUpdateStallAddr(int id, TPointer stallAddr) { lock (this) { PspGeList list = allGeLists[id]; if (list.StallAddr != stallAddr.Address) { if (list.hasBaseMemoryReader()) { setStallAddressWithCachedMemory(list, stallAddr.Address); } else { list.StallAddr = stallAddr.Address; } Modules.sceDisplayModule.GeDirty = true; } } return(0); }
public static void onStallAddrUpdated(PspGeList list) { if (Available && DurationStatistics.collectStatistics) { NativeUtils.stopEvent(NativeUtils.EVENT_GE_UPDATE_STALL_ADDR); } if (Active) { if (list == null) { return; } if (list == currentList) { NativeUtils.CoreSadr = list.StallAddr; CoreThread.Instance.sync(); } } }
public static void onRestartList(PspGeList list) { if (Active) { if (list == null || list.Finished) { return; } lock (drawListQueue) { if (list == currentList) { list.status = sceGe_user.PSP_GE_LIST_DRAWING; NativeUtils.setCoreCtrlActive(); CoreThread.Instance.sync(); list.sync(); } } } }
public static void startListHead(PspGeList list) { if (list == null) { return; } if (currentList == null) { startList(list); // } else if (!currentList.isDrawing()) { // if (!drawListQueue.contains(currentList)) { // addListToHead(currentList); // } // currentList = null; // startList(list); } else { addListToHead(list); } }
public static void finishList(PspGeList list) { Modules.sceGe_userModule.hleGeListSyncDone(list); lock (drawListQueue) { if (list == currentList) { if (CaptureManager.captureInProgress) { log.Level = logLevel; NativeUtils.DumpFrames = false; NativeUtils.DumpTextures = false; NativeUtils.setLogLevel(); CaptureManager.captureInProgress = false; Emulator.PauseEmu(); } // Restore the context to the state at the beginning of the list processing (used by sceGu). if (list.hasSaveContextAddr()) { restoreContext(list.SaveContextAddr); } currentList = null; } else { drawListQueue.remove(list); } } if (currentList == null) { startList(drawListQueue.poll()); } }
public override void start() { Console.WriteLine(string.Format("Starting {0}", Name)); waitingForSync = false; syncDone = false; signalCallbacks = new Dictionary <int, SceKernelCallbackInfo>(); finishCallbacks = new Dictionary <int, SceKernelCallbackInfo>(); listFreeQueue = new ConcurrentLinkedQueue <PspGeList>(); allGeLists = new PspGeList[NUMBER_GE_LISTS]; for (int i = 0; i < NUMBER_GE_LISTS; i++) { allGeLists[i] = new PspGeList(i); listFreeQueue.add(allGeLists[i]); } deferredThreadWakeupQueue = new ConcurrentLinkedQueue <int>(); eDRAMMemoryWidth = 1024; base.start(); }
public override void run() { setLog4jMDC(); bool doCoreInterpret = false; while (!exit_Renamed) { PspGeList list = ExternalGE.CurrentList; if (list == null) { if (!Emulator.pause && log.DebugEnabled) { Console.WriteLine(string.Format("CoreThread no current list available... waiting")); } waitForSync(100); } else if (doCoreInterpret || list.waitForSync(100)) { InsideRendering = true; doCoreInterpret = false; NativeUtils.CoreMadr = list.Pc; NativeUtils.updateMemoryUnsafeAddr(); //if (log.DebugEnabled) { Console.WriteLine(string.Format("CoreThread processing {0}", list)); } while (NativeUtils.coreInterpret()) { NativeUtils.updateMemoryUnsafeAddr(); //if (log.DebugEnabled) { list.Pc = NativeUtils.CoreMadr; Console.WriteLine(string.Format("CoreThread looping {0}", list)); } if (ExternalGE.numberRendererThread > 0 && NativeUtils.RendererIndexCount > 0) { break; } } list.Pc = NativeUtils.CoreMadr; int intrStat = NativeUtils.CoreIntrStat; if ((intrStat & INTR_STAT_END) != 0) { if ((intrStat & INTR_STAT_SIGNAL) != 0) { executeCommandSIGNAL(list); } if ((intrStat & INTR_STAT_FINISH) != 0) { executeCommandFINISH(list); } intrStat &= ~(INTR_STAT_END | INTR_STAT_SIGNAL | INTR_STAT_FINISH); NativeUtils.CoreIntrStat = intrStat; } if (ExternalGE.numberRendererThread > 0 && NativeUtils.RendererIndexCount > 0) { ExternalGE.render(); doCoreInterpret = true; } InsideRendering = false; } } Console.WriteLine(string.Format("CoreThread exited")); }
private void executeCommandSIGNAL(PspGeList list) { int args = NativeUtils.getCoreCmdArray(GeCommands.SIGNAL) & 0x00FFFFFF; int behavior = (args >> 16) & 0xFF; int signal = args & 0xFFFF; //if (log.DebugEnabled) { Console.WriteLine(string.Format("SIGNAL (behavior={0:D}, signal=0x{1:X})",behavior,signal)); } switch (behavior) { case sceGe_user.PSP_GE_SIGNAL_SYNC: { // Skip FINISH / END Memory mem = Memory.Instance; if (command(mem.read32(list.Pc)) == FINISH) { list.readNextInstruction(); if (command(mem.read32(list.Pc)) == END) { list.readNextInstruction(); } } //if (log.DebugEnabled) { Console.WriteLine(string.Format("PSP_GE_SIGNAL_SYNC ignored PC: 0x{0:X8}", list.Pc)); } break; } case sceGe_user.PSP_GE_SIGNAL_CALL: { // Call list using absolute address from SIGNAL + END. int hi16 = signal & 0x0FFF; int lo16 = NativeUtils.getCoreCmdArray(GeCommands.END) & 0xFFFF; int addr = (hi16 << 16) | lo16; int oldPc = list.Pc; list.callAbsolute(addr); int newPc = list.Pc; //if (log.DebugEnabled) { Console.WriteLine(string.Format("PSP_GE_SIGNAL_CALL old PC: 0x{0:X8}, new PC: 0x{1:X8}", oldPc, newPc)); } break; } case sceGe_user.PSP_GE_SIGNAL_RETURN: { // Return from PSP_GE_SIGNAL_CALL. int oldPc = list.Pc; list.ret(); int newPc = list.Pc; //if (log.DebugEnabled) { Console.WriteLine(string.Format("PSP_GE_SIGNAL_RETURN old PC: 0x{0:X8}, new PC: 0x{1:X8}", oldPc, newPc)); } break; } case sceGe_user.PSP_GE_SIGNAL_TBP0_REL: case sceGe_user.PSP_GE_SIGNAL_TBP1_REL: case sceGe_user.PSP_GE_SIGNAL_TBP2_REL: case sceGe_user.PSP_GE_SIGNAL_TBP3_REL: case sceGe_user.PSP_GE_SIGNAL_TBP4_REL: case sceGe_user.PSP_GE_SIGNAL_TBP5_REL: case sceGe_user.PSP_GE_SIGNAL_TBP6_REL: case sceGe_user.PSP_GE_SIGNAL_TBP7_REL: { // Overwrite TBPn and TBPw with SIGNAL + END (uses relative address only). int hi16 = signal & 0xFFFF; int end = NativeUtils.getCoreCmdArray(GeCommands.END); int lo16 = end & 0xFFFF; int width = (end >> 16) & 0xFF; int addr = list.getAddressRel((hi16 << 16) | lo16); int tbpValue = (behavior - sceGe_user.PSP_GE_SIGNAL_TBP0_REL + GeCommands.TBP0) << 24 | (addr & 0x00FFFFFF); int tbwValue = (behavior - sceGe_user.PSP_GE_SIGNAL_TBP0_REL + GeCommands.TBW0) << 24 | ((addr >> 8) & 0x00FF0000) | (width & 0xFFFF); NativeUtils.interpretCoreCmd(command(tbpValue), tbpValue, NativeUtils.CoreMadr); NativeUtils.interpretCoreCmd(command(tbwValue), tbwValue, NativeUtils.CoreMadr); break; } case sceGe_user.PSP_GE_SIGNAL_TBP0_REL_OFFSET: case sceGe_user.PSP_GE_SIGNAL_TBP1_REL_OFFSET: case sceGe_user.PSP_GE_SIGNAL_TBP2_REL_OFFSET: case sceGe_user.PSP_GE_SIGNAL_TBP3_REL_OFFSET: case sceGe_user.PSP_GE_SIGNAL_TBP4_REL_OFFSET: case sceGe_user.PSP_GE_SIGNAL_TBP5_REL_OFFSET: case sceGe_user.PSP_GE_SIGNAL_TBP6_REL_OFFSET: case sceGe_user.PSP_GE_SIGNAL_TBP7_REL_OFFSET: { // Overwrite TBPn and TBPw with SIGNAL + END (uses relative address with offset). int hi16 = signal & 0xFFFF; // Read & skip END int end = NativeUtils.getCoreCmdArray(GeCommands.END); int lo16 = end & 0xFFFF; int width = (end >> 16) & 0xFF; int addr = list.getAddressRelOffset((hi16 << 16) | lo16); int tbpValue = (behavior - sceGe_user.PSP_GE_SIGNAL_TBP0_REL + GeCommands.TBP0) << 24 | (addr & 0x00FFFFFF); int tbwValue = (behavior - sceGe_user.PSP_GE_SIGNAL_TBP0_REL + GeCommands.TBW0) << 24 | ((addr >> 8) & 0x00FF0000) | (width & 0xFFFF); NativeUtils.interpretCoreCmd(command(tbpValue), tbpValue, NativeUtils.CoreMadr); NativeUtils.interpretCoreCmd(command(tbwValue), tbwValue, NativeUtils.CoreMadr); break; } case sceGe_user.PSP_GE_SIGNAL_HANDLER_SUSPEND: case sceGe_user.PSP_GE_SIGNAL_HANDLER_CONTINUE: case sceGe_user.PSP_GE_SIGNAL_HANDLER_PAUSE: { list.clearRestart(); list.pushSignalCallback(list.id, behavior, signal); list.endList(); list.status = sceGe_user.PSP_GE_LIST_END_REACHED; break; } default: { if (log.InfoEnabled) { Console.WriteLine(string.Format("SIGNAL (behavior={0:D}, signal=0x{1:X}) unknown behavior at 0x{2:X8}", behavior, signal, list.Pc - 4)); } } break; } if (list.Drawing) { list.sync(); NativeUtils.setCoreCtrlActive(); } }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: public int hleGeListEnQueue(pspsharp.HLE.TPointer listAddr, @CanBeNull pspsharp.HLE.TPointer stallAddr, int cbid, @CanBeNull pspsharp.HLE.TPointer argAddr, int saveContextAddr, bool enqueueHead) public virtual int hleGeListEnQueue(TPointer listAddr, TPointer stallAddr, int cbid, TPointer argAddr, int saveContextAddr, bool enqueueHead) { pspGeListOptParam optParams = null; int stackAddr = 0; if (argAddr.NotNull) { optParams = new pspGeListOptParam(); optParams.read(argAddr); stackAddr = optParams.stackAddr; saveContextAddr = optParams.contextAddr; //if (log.DebugEnabled) { Console.WriteLine(string.Format("hleGeListEnQueue optParams={0}", optParams)); } } bool useCachedMemory = false; if (Modules.SysMemUserForUserModule.hleKernelGetCompiledSdkVersion() >= 0x02000000) { bool isBusy; if (ExternalGE.Active) { isBusy = ExternalGE.hasDrawList(listAddr.Address, stackAddr); } else { isBusy = VideoEngine.Instance.hasDrawList(listAddr.Address, stackAddr); } if (isBusy) { Console.WriteLine(string.Format("hleGeListEnQueue can't enqueue duplicate list address {0}, stack 0x{1:X8}", listAddr, stackAddr)); return(SceKernelErrors.ERROR_BUSY); } } else { // Old games (i.e. having PSP SDK version < 2.00) are sometimes // reusing the same address for multiple lists, without waiting // for the previous list to complete. They assume that the lists // are being executed quite quickly, which is not the case when // using the OpenGL rendering engine. There is some delay before // the OpenGL frame refresh is being processed. useCachedMemory = true; } // No need to cache any memory when using the external software renderer if (ExternalGE.Active) { useCachedMemory = false; } int result; lock (this) { PspGeList list = listFreeQueue.poll(); if (list == null) { Console.WriteLine("hleGeListEnQueue no more free list available!"); //if (log.DebugEnabled) { for (int i = 0; i < NUMBER_GE_LISTS; i++) { Console.WriteLine(string.Format("List#{0:D}: {1}", i, allGeLists[i])); } } return(SceKernelErrors.ERROR_OUT_OF_MEMORY); } list.init(listAddr.Address, stallAddr.Address, cbid, optParams); list.SaveContextAddr = saveContextAddr; if (useCachedMemory) { setStallAddressWithCachedMemory(list, stallAddr.Address); } if (enqueueHead) { // Send the list to the VideoEngine at the head of the queue. list.startListHead(); } else { // Send the list to the VideoEngine before triggering the display (setting GE dirty) list.startList(); } Modules.sceDisplayModule.GeDirty = true; result = list.id; } //if (log.DebugEnabled) { Console.WriteLine(string.Format("hleGeListEnQueue returning 0x{0:X}", result)); } return(result); }
public ListSyncWaitStateChecker(PspGeList list) { this.list = list; }