diff --git a/CMakeLists.txt b/CMakeLists.txt index 37509ed442..0a1402a5d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,9 +9,7 @@ if(ANDROID) endif() if (IOS) - if (${IOS_PLATFORM} STREQUAL "OS") - set(ARM ON) - endif() + set(ARM ON) endif() if(BLACKBERRY) @@ -410,6 +408,16 @@ if(ANDROID) native/android/native-audio-so.h) target_link_libraries(native_audio OpenSLES) # No target +elseif(IOS) + set(nativeExtra ${nativeExtra} + ios/main.m + ios/AppDelegate.m + ios/AppDelegate.h + ios/ViewController.mm + ios/ViewController.h) + set(CMAKE_EXE_LINKER_FLAGS "-framework Foundation -framework CoreGraphics -framework QuartzCore -framework OpenGLES -framework UIKit") + # No target + # set(TargetBin PPSSPP) elseif(USING_QT_UI) # Currently unused find_package(Qt4 COMPONENTS QtMultimedia QtOpenGL QtGui QtCore) @@ -433,9 +441,7 @@ elseif(SDL_FOUND) elseif(PANDORA) set(nativeExtraLibs ${nativeExtraLibs} pthread EGL X11) endif() - if(NOT IOS) # No target - set(TargetBin PPSSPPSDL) - endif() + set(TargetBin PPSSPPSDL) else() message(FATAL_ERROR "Could not find SDL. Failing.") endif() @@ -950,4 +956,9 @@ endif() file(INSTALL ${NativeAssets} DESTINATION assets) +# code signing +if (IOS) + set_target_properties(${NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST PPSSPP-Info.plist XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer: My Name") +endif() + #include(CPack) diff --git a/Common/ChunkFile.h b/Common/ChunkFile.h index 095831678a..0344483514 100644 --- a/Common/ChunkFile.h +++ b/Common/ChunkFile.h @@ -625,7 +625,7 @@ public: u8 *uncomp_buffer = new u8[header.UncompressedSize]; size_t uncomp_size = header.UncompressedSize; snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size); - if (uncomp_size != header.UncompressedSize) { + if ((int)uncomp_size != header.UncompressedSize) { ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size); } ptr = uncomp_buffer; diff --git a/Common/MemArena.cpp b/Common/MemArena.cpp index dcb0c82e51..d2d03bd720 100644 --- a/Common/MemArena.cpp +++ b/Common/MemArena.cpp @@ -131,8 +131,6 @@ void MemArena::GrabLowMemSpace(size_t size) ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno)); return; } -#elif defined(UNUSABLE_MMAP) - // Do nothing as we are using malloc() #else mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode); @@ -157,8 +155,9 @@ void MemArena::ReleaseSpace() #ifdef _WIN32 CloseHandle(hMemoryMapping); hMemoryMapping = 0; -#elif defined(UNUSABLE_MMAP) - // Do nothing as we are using malloc() +#elif defined(__SYMBIAN32__) + memmap->Close(); + delete memmap; #else close(fd); #endif @@ -170,20 +169,7 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base) #ifdef _WIN32 size = roundup(size); void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); - if (!ptr) { - //ERROR_LOG(MEMMAP, "Failed to map memory: %08x %08x %08x : %s", (u32)offset, (u32)size, (u32)base, GetLastErrorMsg()); - } else { - //ERROR_LOG(MEMMAP, "Mapped memory: %08x %08x %08x : %s", (u32)offset, (u32)size, (u32)base, GetLastErrorMsg()); - } return ptr; -#elif defined(UNUSABLE_MMAP) - void *retval = malloc(size); - if (!retval) - { - NOTICE_LOG(MEMMAP, "malloc failed: %s", strerror(errno)); - return 0; - } - return retval; #else void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | ((base == 0) ? 0 : MAP_FIXED), fd, offset); @@ -202,14 +188,14 @@ void MemArena::ReleaseView(void* view, size_t size) { #ifdef _WIN32 UnmapViewOfFile(view); -#elif defined(UNUSABLE_MMAP) - free(view); +#elif defined(__SYMBIAN32__) + memmap->Decommit(((int)view - (int)memmap->Base()) & 0x3FFFFFFF, size); #else munmap(view, size); #endif } - +#ifndef __SYMBIAN32__ u8* MemArena::Find4GBBase() { #ifdef _M_X64 @@ -224,8 +210,8 @@ u8* MemArena::Find4GBBase() return reinterpret_cast(0x2300000000ULL); #endif -#else - // 32 bit +#else // 32 bit + #ifdef _WIN32 // The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it. u8* base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE); @@ -233,9 +219,6 @@ u8* MemArena::Find4GBBase() VirtualFree(base, 0, MEM_RELEASE); } return base; -#elif defined(UNUSABLE_MMAP) - // We are unable to use relative addresses due to lack of mmap() - return NULL; #else void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); @@ -248,6 +231,7 @@ u8* MemArena::Find4GBBase() #endif #endif } +#endif // yeah, this could also be done in like two bitwise ops... @@ -282,6 +266,12 @@ static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 if (view.flags & MV_MIRROR_PREVIOUS) { position = last_position; } else { +#ifdef __SYMBIAN32__ + *(view.out_ptr_low) = (u8*)((int)arena->memmap->Base() + view.virtual_address); + arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); + } + *(view.out_ptr) = (u8*)((int)arena->memmap->Base() + view.virtual_address & 0x3FFFFFFF); +#else *(view.out_ptr_low) = (u8*)arena->CreateView(position, view.size); if (!*view.out_ptr_low) goto bail; @@ -299,6 +289,8 @@ static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 if (!*view.out_ptr) goto bail; } +#endif + #endif last_position = position; position += roundup(view.size); @@ -344,7 +336,9 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena total_mem += roundup(views[i].size); } // Grab some pagefile backed memory out of the void ... +#ifndef __SYMBIAN32__ arena->GrabLowMemSpace(total_mem); +#endif // Now, create views in high memory where there's plenty of space. #ifdef _M_X64 @@ -374,6 +368,16 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena break; } } +#elif defined(__SYMBIAN32__) + arena->memmap = new RChunk(); + arena->memmap->CreateDisconnectedLocal(0 , 0, 0x10000000); + if (!Memory_TryBase(arena->memmap->Base(), views, num_views, flags, arena)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + exit(0); + return 0; + } + u8* base = arena->memmap->Base(); #else // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors. u8 *base = MemArena::Find4GBBase(); diff --git a/Common/MemArena.h b/Common/MemArena.h index 75dd738b0e..a12f8f493b 100644 --- a/Common/MemArena.h +++ b/Common/MemArena.h @@ -22,6 +22,10 @@ #include #endif +#ifdef __SYMBIAN32__ +#include +#endif + #include "Common.h" // This class lets you create a block of anonymous RAM, and then arbitrarily map views into it. @@ -36,8 +40,12 @@ public: void *CreateView(s64 offset, size_t size, void *base = 0); void ReleaseView(void *view, size_t size); +#ifdef __SYMBIAN32__ + RChunk* memmap; +#else // This only finds 1 GB in 32-bit static u8 *Find4GBBase(); +#endif private: #ifdef _WIN32 diff --git a/Common/MemoryUtil.h b/Common/MemoryUtil.h index f8c6ee6b1a..bafa7e4e88 100644 --- a/Common/MemoryUtil.h +++ b/Common/MemoryUtil.h @@ -23,11 +23,6 @@ #endif #include -#if defined(__SYMBIAN32__) - // Also Xbox 360 - #define UNUSABLE_MMAP 1 -#endif - void* AllocateExecutableMemory(size_t size, bool low = true); void* AllocateMemoryPages(size_t size); void FreeMemoryPages(void* ptr, size_t size); diff --git a/Core/Config.cpp b/Core/Config.cpp index 9b5cfe94b5..fd22d7b7df 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -49,14 +49,15 @@ void CConfig::Load(const char *iniFileName) general->Get("FirstRun", &bFirstRun, true); general->Get("AutoLoadLast", &bAutoLoadLast, false); general->Get("AutoRun", &bAutoRun, true); + general->Get("Browse", &bBrowse, false); general->Get("ConfirmOnQuit", &bConfirmOnQuit, false); general->Get("IgnoreBadMemAccess", &bIgnoreBadMemAccess, true); general->Get("CurrentDirectory", ¤tDirectory, ""); general->Get("ShowDebuggerOnLoad", &bShowDebuggerOnLoad, false); IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU"); - cpu->Get("Core", &iCpuCore, 2); - cpu->Get("FastMemory", &bFastMemory, false); + cpu->Get("Jit", &bJit, true); + cpu->Get("FastMemory", &bFastMemory, true); IniFile::Section *graphics = iniFile.GetOrCreateSection("Graphics"); graphics->Get("ShowFPSCounter", &bShowFPSCounter, false); @@ -67,6 +68,7 @@ void CConfig::Load(const char *iniFileName) graphics->Get("LinearFiltering", &bLinearFiltering, false); graphics->Get("SSAA", &SSAntiAliasing, 0); graphics->Get("VBO", &bUseVBO, false); + graphics->Get("FrameSkip", &iFrameSkip, 0); #ifdef USING_GLES2 graphics->Get("AnisotropyLevel", &iAnisotropyLevel, 0); #else @@ -112,12 +114,13 @@ void CConfig::Save() general->Set("FirstRun", bFirstRun); general->Set("AutoLoadLast", bAutoLoadLast); general->Set("AutoRun", bAutoRun); + general->Set("Browse", bBrowse); general->Set("ConfirmOnQuit", bConfirmOnQuit); general->Set("IgnoreBadMemAccess", bIgnoreBadMemAccess); general->Set("CurrentDirectory", currentDirectory); general->Set("ShowDebuggerOnLoad", bShowDebuggerOnLoad); IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU"); - cpu->Set("Core", iCpuCore); + cpu->Set("Jit", bJit); cpu->Set("FastMemory", bFastMemory); IniFile::Section *graphics = iniFile.GetOrCreateSection("Graphics"); @@ -129,6 +132,7 @@ void CConfig::Save() graphics->Set("LinearFiltering", bLinearFiltering); graphics->Set("SSAA", SSAntiAliasing); graphics->Set("VBO", bUseVBO); + graphics->Set("FrameSkip", iFrameSkip); graphics->Set("AnisotropyLevel", iAnisotropyLevel); graphics->Set("DisableG3DLog", bDisableG3DLog); graphics->Set("VertexCache", bVertexCache); diff --git a/Core/Config.h b/Core/Config.h index e14cfe06d4..d39325cc4e 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -44,11 +44,12 @@ public: bool bSpeedLimit; bool bConfirmOnQuit; bool bAutoRun; // start immediately + bool bBrowse; // Core bool bIgnoreBadMemAccess; bool bFastMemory; - int iCpuCore; + bool bJit; // GFX bool bDisplayFramebuffer; @@ -58,6 +59,7 @@ public: bool bLinearFiltering; bool bUseVBO; bool bStretchToDisplay; + int iFrameSkip; // 0 = off; 1 = auto; (future: 2 = skip every 2nd frame; 3 = skip every 3rd frame etc). int iWindowZoom; // for Windows bool SSAntiAliasing; //for Windows, too diff --git a/Core/Core.cpp b/Core/Core.cpp index f66929d071..c2de39e787 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -22,6 +22,9 @@ #include "Core.h" #include "MemMap.h" #include "MIPS/MIPS.h" +#ifdef _WIN32 +#include "Windows/OpenGLBase.h" +#endif #include "Host.h" @@ -64,7 +67,16 @@ bool Core_IsStepping() void Core_RunLoop() { - currentMIPS->RunLoopUntil(0xFFFFFFFFFFFFFFFULL); + while (!coreState) { + currentMIPS->RunLoopUntil(0xFFFFFFFFFFFFFFFULL); + if (coreState == CORE_NEXTFRAME) + { +#ifdef _WIN32 + GL_SwapBuffers(); +#endif + coreState = CORE_RUNNING; + } + } } void Core_DoSingleStep() @@ -100,6 +112,8 @@ reswitch: case CORE_STEPPING: //1: wait for step command.. #if defined(USING_QT_UI) || defined(_DEBUG) + host->UpdateDisassembly(); + host->UpdateMemView(); host->SendCoreWait(true); #endif diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 265a9fd0f4..50c55c3a01 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -68,6 +68,8 @@ Disabled ../common;..;../native;../native/ext/glew;../ext/zlib WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + StreamingSIMDExtensions2 + Fast true @@ -79,6 +81,8 @@ Disabled ../common;..;../native;../native/ext/glew;../ext/zlib WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + StreamingSIMDExtensions2 + Fast true @@ -108,6 +112,8 @@ true true ../common;..;../native;../native/ext/glew;../ext/zlib + StreamingSIMDExtensions2 + Fast true diff --git a/Core/CoreParameter.h b/Core/CoreParameter.h index 0ff37be9ed..3357fc027d 100644 --- a/Core/CoreParameter.h +++ b/Core/CoreParameter.h @@ -22,7 +22,6 @@ enum CPUCore { CPU_INTERPRETER, - CPU_FASTINTERPRETER, // unsafe, a bit faster than INTERPRETER CPU_JIT, }; diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 22762fbaa1..ce3b97089b 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -1080,7 +1080,7 @@ bool SavedataParam::CreatePNGIcon(u8* pngData, int pngSize, SaveFileInfo& info) u32 atlasPtr; if (success) atlasPtr = kernelMemory.Alloc(texSize, true, "SaveData Icon"); - if (success && atlasPtr != -1) + if (success && atlasPtr != (u32)-1) { info.textureData = atlasPtr; Memory::Memcpy(atlasPtr, textureData, texSize); diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index 77ff90de4d..9054e68d6a 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -217,7 +217,7 @@ bool ElfReader::LoadInto(u32 loadAddress) vaddr = userMemory.Alloc(totalSize, false, "ELF"); } - if (vaddr == -1) { + if (vaddr == (u32)-1) { ERROR_LOG(LOADER, "Failed to allocate memory for ELF!"); return false; } diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 6e7087c04d..48c0f87688 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -297,7 +297,7 @@ bool hleExecuteDebugBreak(const HLEFunction &func) // Never break on these, they're noise. u32 blacklistedNIDs[] = {NID_SUSPEND_INTR, NID_RESUME_INTR, NID_IDLE}; - for (int i = 0; i < ARRAY_SIZE(blacklistedNIDs); ++i) + for (size_t i = 0; i < ARRAY_SIZE(blacklistedNIDs); ++i) { if (func.ID == blacklistedNIDs[i]) return false; diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 4e6604add6..5ea398ca07 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -187,7 +187,7 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF ret = ATRAC_ERROR_ALL_DATA_DECODED; } else { // TODO: This isn't at all right, but at least it makes the music "last" some time. - int numSamples = (atrac->decodeEnd - atrac->decodePos) / (sizeof(s16) * 2); + u32 numSamples = (atrac->decodeEnd - atrac->decodePos) / (sizeof(s16) * 2); if (atrac->decodePos >= atrac->decodeEnd) { numSamples = 0; } else if (numSamples > ATRAC_MAX_SAMPLES) { @@ -554,7 +554,7 @@ int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesConsumedAddr, u32 samplesAddr, u32 sampleBytesAddr) { - ERROR_LOG(HLE, "UNIMPL sceAtracLowLevelDecode(%i, %i, %08x, %08x, %08x, %08x)", atracID, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr); + ERROR_LOG(HLE, "UNIMPL sceAtracLowLevelDecode(%i, %08x, %08x, %08x, %08x)", atracID, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr); return 0; } diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index 819b884819..348bdce8d2 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -35,7 +35,7 @@ const int PSP_CTRL_ERROR_INVALID_MODE = 0x80000107; const int PSP_CTRL_ERROR_INVALID_IDLE_PTR = 0x80000023; -const int NUM_CTRL_BUFFERS = 64; +const u32 NUM_CTRL_BUFFERS = 64; enum { @@ -68,8 +68,8 @@ static u32 ctrlOldButtons = 0; static _ctrl_data ctrlBufs[NUM_CTRL_BUFFERS]; static _ctrl_data ctrlCurrent; -static int ctrlBuf = 0; -static int ctrlBufRead = 0; +static u32 ctrlBuf = 0; +static u32 ctrlBufRead = 0; static CtrlLatch latch; static int ctrlIdleReset = -1; @@ -189,7 +189,7 @@ int __CtrlReadBuffer(u32 ctrlDataPtr, u32 nBufs, bool negative, bool peek) if (nBufs > NUM_CTRL_BUFFERS) return SCE_KERNEL_ERROR_INVALID_SIZE; - int resetRead = ctrlBufRead; + u32 resetRead = ctrlBufRead; u32 availBufs; // Peeks always work, they just go go from now X buffers. diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 86bf36750a..46b297a928 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -80,14 +80,17 @@ static bool framebufIsLatched; static int enterVblankEvent = -1; static int leaveVblankEvent = -1; +static int afterFlipEvent = -1; static int hCount; static int hCountTotal; //unused static int vCount; static int isVblank; +static int numSkippedFrames; static bool hasSetMode; // Don't include this in the state, time increases regardless of state. -static double lastFrameTime; +static double curFrameTime; +static double nextFrameTime; std::vector vblankWaitingThreads; @@ -107,10 +110,12 @@ enum { void hleEnterVblank(u64 userdata, int cyclesLate); void hleLeaveVblank(u64 userdata, int cyclesLate); +void hleAfterFlip(u64 userdata, int cyclesLate); void __DisplayInit() { gpuStats.reset(); hasSetMode = false; + numSkippedFrames = 0; framebufIsLatched = false; framebuf.topaddr = 0x04000000; framebuf.pspFramebufFormat = PSP_DISPLAY_PIXEL_FORMAT_8888; @@ -118,13 +123,15 @@ void __DisplayInit() { enterVblankEvent = CoreTiming::RegisterEvent("EnterVBlank", &hleEnterVblank); leaveVblankEvent = CoreTiming::RegisterEvent("LeaveVBlank", &hleLeaveVblank); + afterFlipEvent = CoreTiming::RegisterEvent("AfterFlip", &hleAfterFlip); CoreTiming::ScheduleEvent(msToCycles(frameMs - vblankMs), enterVblankEvent, 0); isVblank = 0; vCount = 0; hCount = 0; hCountTotal = 0; - lastFrameTime = 0; + curFrameTime = 0.0; + nextFrameTime = 0.0; InitGfxState(); } @@ -186,7 +193,7 @@ float calculateFPS() static int lastFpsFrame = 0; static double lastFpsTime = 0.0; static double fps = 0.0; - + time_update(); double now = time_now_d(); @@ -202,6 +209,127 @@ float calculateFPS() return fps; } +void DebugStats() +{ + gpu->UpdateStats(); + char stats[2048]; + + sprintf(stats, + "Frames: %i\n" + "DL processing time: %0.2f ms\n" + "Kernel processing time: %0.2f ms\n" + "Slowest syscall: %s : %0.2f ms\n" + "Most active syscall: %s : %0.2f ms\n" + "Draw calls: %i, flushes %i\n" + "Cached Draw calls: %i\n" + "Num Tracked Vertex Arrays: %i\n" + "Vertices Submitted: %i\n" + "Cached Vertices Drawn: %i\n" + "Uncached Vertices Drawn: %i\n" + "FBOs active: %i\n" + "Textures active: %i, decoded: %i\n" + "Texture invalidations: %i\n" + "Vertex shaders loaded: %i\n" + "Fragment shaders loaded: %i\n" + "Combined shaders loaded: %i\n", + gpuStats.numFrames, + gpuStats.msProcessingDisplayLists * 1000.0f, + kernelStats.msInSyscalls * 1000.0f, + kernelStats.slowestSyscallName ? kernelStats.slowestSyscallName : "(none)", + kernelStats.slowestSyscallTime * 1000.0f, + kernelStats.summedSlowestSyscallName ? kernelStats.summedSlowestSyscallName : "(none)", + kernelStats.summedSlowestSyscallTime * 1000.0f, + gpuStats.numDrawCalls, + gpuStats.numFlushes, + gpuStats.numCachedDrawCalls, + gpuStats.numTrackedVertexArrays, + gpuStats.numVertsSubmitted, + gpuStats.numCachedVertsDrawn, + gpuStats.numUncachedVertsDrawn, + gpuStats.numFBOs, + gpuStats.numTextures, + gpuStats.numTexturesDecoded, + gpuStats.numTextureInvalidations, + gpuStats.numVertexShaders, + gpuStats.numFragmentShaders, + gpuStats.numShaders + ); + + float zoom = 0.3f; /// g_Config.iWindowZoom; + float soff = 0.3f; + PPGeBegin(); + PPGeDrawText(stats, soff, soff, 0, zoom, 0xCC000000); + PPGeDrawText(stats, -soff, -soff, 0, zoom, 0xCC000000); + PPGeDrawText(stats, 0, 0, 0, zoom, 0xFFFFFFFF); + PPGeEnd(); + + gpuStats.resetFrame(); + kernelStats.ResetFrame(); +} + +// Let's collect all the throttling and frameskipping logic here. +void DoFrameTiming(bool &throttle, bool &skipFrame, bool &skipFlip) { +#ifdef _WIN32 + throttle = !GetAsyncKeyState(VK_TAB); +#else + throttle = false; +#endif + skipFlip = false; + skipFrame = false; + if (PSP_CoreParameter().headLess) + throttle = false; + + // Check if the frameskipping code should be enabled. If neither throttling or frameskipping is on, + // we have nothing to do here. + bool doFrameSkip = g_Config.iFrameSkip == 1; + if (!throttle && !doFrameSkip) + return; + + time_update(); + + curFrameTime = time_now_d(); + if (nextFrameTime == 0.0) + nextFrameTime = time_now_d() + 1.0 / 60.0; + + if (curFrameTime > nextFrameTime && doFrameSkip) { + // Argh, we are falling behind! Let's skip a frame and see if we catch up. + skipFrame = true; + skipFlip = true; + INFO_LOG(HLE,"FRAMESKIP %i", numSkippedFrames); + } + + if (curFrameTime < nextFrameTime && throttle) + { + // If time gap is huge just jump (somebody unthrottled) + if (nextFrameTime - curFrameTime > 1.0 / 30.0) { + nextFrameTime = curFrameTime + 1.0 / 60.0; + } else { + // Wait until we've catched up. + while (time_now_d() < nextFrameTime) { + Common::SleepCurrentThread(1); + time_update(); + } + } + curFrameTime = time_now_d(); + } + // Advance lastFrameTime by a constant amount each frame, + // but don't let it get too far behind as things can get very jumpy. + const double maxFallBehindFrames = 5.5; + + if (throttle || doFrameSkip) { + nextFrameTime = std::max(nextFrameTime + 1.0 / 60.0, time_now_d() - maxFallBehindFrames / 60.0); + } else { + nextFrameTime = nextFrameTime + 1.0 / 60.0; + } + + // Max 6 skipped frames in a row - 10 fps is really the bare minimum for playability. + if (numSkippedFrames >= 4) { + skipFrame = false; + skipFlip = false; + } +} + + void hleEnterVblank(u64 userdata, int cyclesLate) { int vbCount = userdata; @@ -223,7 +351,7 @@ void hleEnterVblank(u64 userdata, int cyclesLate) { // Trigger VBlank interrupt handlers. __TriggerInterrupt(PSP_INTR_IMMEDIATE | PSP_INTR_ONLY_IF_ENABLED | PSP_INTR_ALWAYS_RESCHED, PSP_VBLANK_INTR, PSP_INTR_SUB_ALL); - CoreTiming::ScheduleEvent(msToCycles(vblankMs) - cyclesLate, leaveVblankEvent, vbCount+1); + CoreTiming::ScheduleEvent(msToCycles(vblankMs) - cyclesLate, leaveVblankEvent, vbCount + 1); // TODO: Should this be done here or in hleLeaveVblank? if (framebufIsLatched) { @@ -233,65 +361,11 @@ void hleEnterVblank(u64 userdata, int cyclesLate) { gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat); } - // Draw screen overlays before blitting. Saves and restores the Ge context. gpuStats.numFrames++; // Now we can subvert the Ge engine in order to draw custom overlays like stat counters etc. if (g_Config.bShowDebugStats && gpuStats.numDrawCalls) { - gpu->UpdateStats(); - char stats[2048]; - - sprintf(stats, - "Frames: %i\n" - "DL processing time: %0.2f ms\n" - "Kernel processing time: %0.2f ms\n" - "Slowest syscall: %s : %0.2f ms\n" - "Most active syscall: %s : %0.2f ms\n" - "Draw calls: %i, flushes %i\n" - "Cached Draw calls: %i\n" - "Num Tracked Vertex Arrays: %i\n" - "Vertices Submitted: %i\n" - "Cached Vertices Drawn: %i\n" - "Uncached Vertices Drawn: %i\n" - "FBOs active: %i\n" - "Textures active: %i, decoded: %i\n" - "Texture invalidations: %i\n" - "Vertex shaders loaded: %i\n" - "Fragment shaders loaded: %i\n" - "Combined shaders loaded: %i\n", - gpuStats.numFrames, - gpuStats.msProcessingDisplayLists * 1000.0f, - kernelStats.msInSyscalls * 1000.0f, - kernelStats.slowestSyscallName ? kernelStats.slowestSyscallName : "(none)", - kernelStats.slowestSyscallTime * 1000.0f, - kernelStats.summedSlowestSyscallName ? kernelStats.summedSlowestSyscallName : "(none)", - kernelStats.summedSlowestSyscallTime * 1000.0f, - gpuStats.numDrawCalls, - gpuStats.numFlushes, - gpuStats.numCachedDrawCalls, - gpuStats.numTrackedVertexArrays, - gpuStats.numVertsSubmitted, - gpuStats.numCachedVertsDrawn, - gpuStats.numUncachedVertsDrawn, - gpuStats.numFBOs, - gpuStats.numTextures, - gpuStats.numTexturesDecoded, - gpuStats.numTextureInvalidations, - gpuStats.numVertexShaders, - gpuStats.numFragmentShaders, - gpuStats.numShaders - ); - - float zoom = 0.3f; /// g_Config.iWindowZoom; - float soff = 0.3f; - PPGeBegin(); - PPGeDrawText(stats, soff, soff, 0, zoom, 0xCC000000); - PPGeDrawText(stats, -soff, -soff, 0, zoom, 0xCC000000); - PPGeDrawText(stats, 0, 0, 0, zoom, 0xFFFFFFFF); - PPGeEnd(); - - gpuStats.resetFrame(); - kernelStats.ResetFrame(); + DebugStats(); } if (g_Config.bShowFPSCounter) { @@ -313,41 +387,42 @@ void hleEnterVblank(u64 userdata, int cyclesLate) { PPGeEnd(); } + // Draw screen overlays before blitting. Saves and restores the Ge context. // Yeah, this has to be the right moment to end the frame. Give the graphics backend opportunity // to blit the framebuffer, in order to support half-framerate games that otherwise wouldn't have // anything to draw here. - gpu->CopyDisplayToOutput(); + gstate_c.skipDrawReason &= ~SKIPDRAW_SKIPFRAME; - host->EndFrame(); + bool throttle, skipFrame, skipFlip; + + DoFrameTiming(throttle, skipFrame, skipFlip); -#ifdef _WIN32 - // Best place to throttle the frame rate on non vsynced platforms is probably here. Let's try it. - time_update(); - if (lastFrameTime == 0.0) - lastFrameTime = time_now_d(); - if (!GetAsyncKeyState(VK_TAB) && !PSP_CoreParameter().headLess) { - while (time_now_d() < lastFrameTime + 1.0 / 60.0) { - Common::SleepCurrentThread(1); - time_update(); - } - // Advance lastFrameTime by a constant amount each frame, - // but don't let it get too far behind. - lastFrameTime = std::max(lastFrameTime + 1.0 / 60.0, time_now_d() - 1.5 / 60.0); + // Setting CORE_NEXTFRAME causes a swap. + if (skipFrame) { + gstate_c.skipDrawReason |= SKIPDRAW_SKIPFRAME; + numSkippedFrames++; + } else { + numSkippedFrames = 0; } - // We are going to have to do something about audio timing for platforms that - // are vsynced to something that's not exactly 60fps.. + if (!skipFlip) { + coreState = CORE_NEXTFRAME; + CoreTiming::ScheduleEvent(0 - cyclesLate, afterFlipEvent, 0); -#endif + gpu->CopyDisplayToOutput(); + } + // Returning here with coreState == CORE_NEXTFRAME causes a buffer flip to happen (next frame). + // Right after, we regain control for a little bit in hleAfterFlip. I think that's a great + // place to do housekeeping. +} + +void hleAfterFlip(u64 userdata, int cyclesLate) +{ + // This checks input on PC. Fine to do even if not calling BeginFrame. host->BeginFrame(); - gpu->BeginFrame(); - // Tell the emu core that it's time to stop emulating - // Win32 doesn't need this. -#ifndef _WIN32 - coreState = CORE_NEXTFRAME; -#endif + gpu->BeginFrame(); // doesn't really matter if begin or end of frame. } void hleLeaveVblank(u64 userdata, int cyclesLate) { diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index 16e790d342..11ea18c711 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -237,10 +237,10 @@ u32 sceGeSetCallback(u32 structAddr) DEBUG_LOG(HLE, "sceGeSetCallback(struct=%08x)", structAddr); int cbID = -1; - for (int i = 0; i < ARRAY_SIZE(ge_used_callbacks); ++i) + for (size_t i = 0; i < ARRAY_SIZE(ge_used_callbacks); ++i) if (!ge_used_callbacks[i]) { - cbID = i; + cbID = (int) i; break; } diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 5241b1d937..a4791308e8 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -213,7 +213,7 @@ void __InterruptsInit() { interruptsEnabled = 1; inInterrupt = false; - for(int i = 0; i < ARRAY_SIZE(intrHandlers); ++i) + for (size_t i = 0; i < ARRAY_SIZE(intrHandlers); ++i) intrHandlers[i] = new IntrHandler(i); intState.clear(); } @@ -246,11 +246,11 @@ void __InterruptsDoStateLate(PointerWrap &p) void __InterruptsShutdown() { - for (int i = 0; i < ARRAY_SIZE(intrHandlers); ++i) + for (size_t i = 0; i < ARRAY_SIZE(intrHandlers); ++i) intrHandlers[i]->clear(); - for(int i = 0; i < ARRAY_SIZE(intrHandlers); ++i) + for (size_t i = 0; i < ARRAY_SIZE(intrHandlers); ++i) { - if(intrHandlers[i]) + if (intrHandlers[i]) { delete intrHandlers[i]; intrHandlers[i] = 0; diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 59a502767c..89d5e38326 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -2805,7 +2805,10 @@ std::vector GetThreadsInfo() info.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; info.status = t->nt.status; info.entrypoint = t->nt.entrypoint; - info.curPC = t->context.pc; + if(*iter == currentThread) + info.curPC = currentMIPS->pc; + else + info.curPC = t->context.pc; info.isCurrent = (*iter == currentThread); threadList.push_back(info); } diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 0a2aa4e785..16f3fec15d 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -61,55 +61,57 @@ void __SasShutdown() { } -u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u32 sampleRate) -{ +u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u32 sampleRate) { INFO_LOG(HLE,"sceSasInit(%08x, %i, %i, %i, %i)", core, grainSize, maxVoices, outputMode, sampleRate); + sas->SetGrainSize(grainSize); sas->maxVoices = maxVoices; sas->outputMode = outputMode; for (int i = 0; i < sas->maxVoices; i++) { sas->voices[i].sampleRate = sampleRate; sas->voices[i].playing = false; + sas->voices[i].loop = true; // inverted flag } return 0; } -u32 sceSasGetEndFlag(u32 core) -{ +u32 sceSasGetEndFlag(u32 core) { u32 endFlag = 0; for (int i = 0; i < sas->maxVoices; i++) { if (!sas->voices[i].playing) endFlag |= (1 << i); } + DEBUG_LOG(HLE,"sceSasGetEndFlag(%08x)", endFlag); return endFlag; } // Runs the mixer -u32 _sceSasCore(u32 core, u32 outAddr) -{ +u32 _sceSasCore(u32 core, u32 outAddr) { DEBUG_LOG(HLE,"sceSasCore(%08x, %08x)", core, outAddr); + if (!Memory::IsValidAddress(outAddr)) { return ERROR_SAS_INVALID_PARAMETER; } + Memory::Memset(outAddr, 0, sas->GetGrainSize() * 2 * 2); sas->Mix(outAddr); return 0; } // Another way of running the mixer, what was the difference again? -u32 _sceSasCoreWithMix(u32 core, u32 outAddr, int leftVolume, int rightVolume) -{ +u32 _sceSasCoreWithMix(u32 core, u32 outAddr, int leftVolume, int rightVolume) { DEBUG_LOG(HLE,"sceSasCoreWithMix(%08x, %08x, %i, %i)", core , outAddr, leftVolume, rightVolume); + if (!Memory::IsValidAddress(outAddr)) { return ERROR_SAS_INVALID_PARAMETER; } + sas->Mix(outAddr); return 0; } -u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loop) -{ +u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loop) { DEBUG_LOG(HLE,"sceSasSetVoice(%08x, %i, %08x, %i, %i)", core, voiceNum, vagAddr, size, loop); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -167,8 +169,7 @@ u32 sceSasSetVoicePCM(u32 core, int voiceNum, u32 pcmAddr, int size, int loop) return 0; } -u32 sceSasGetPauseFlag(u32 core) -{ +u32 sceSasGetPauseFlag(u32 core) { u32 pauseFlag = 0; for (int i = 0; i < sas->maxVoices; i++) { if (sas->voices[i].paused) @@ -179,24 +180,21 @@ u32 sceSasGetPauseFlag(u32 core) return pauseFlag; } -u32 sceSasSetPause(u32 core, int voicebit, int pause) -{ +u32 sceSasSetPause(u32 core, int voicebit, int pause) { DEBUG_LOG(HLE,"sceSasSetPause(%08x, %08x, %i)", core, voicebit, pause); + for (int i = 0; voicebit != 0; i++, voicebit >>= 1) { if (i < PSP_SAS_VOICES_MAX && i >= 0) { if ((voicebit & 1) != 0) sas->voices[i].paused = pause ? true : false; - } - // TODO: Correct error code? Mimana crashes otherwise. - else + } else // TODO: Correct error code? Mimana crashes otherwise. return ERROR_SAS_INVALID_VOICE; } return 0; } -u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, int effectLeftVol, int effectRightVol) -{ +u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, int effectLeftVol, int effectRightVol) { DEBUG_LOG(HLE,"sceSasSetVolume(%08x, %i, %i, %i, %i, %i)", core, voiceNum, leftVol, rightVol, effectLeftVol, effectRightVol); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -212,8 +210,7 @@ u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, int effec return 0; } -u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) -{ +u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) { DEBUG_LOG(HLE,"sceSasSetPitch(%08x, %i, %i)", core, voiceNum, pitch); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -227,8 +224,7 @@ u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) return 0; } -u32 sceSasSetKeyOn(u32 core, int voiceNum) -{ +u32 sceSasSetKeyOn(u32 core, int voiceNum) { DEBUG_LOG(HLE,"sceSasSetKeyOn(%08x, %i)", core, voiceNum); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -236,39 +232,38 @@ u32 sceSasSetKeyOn(u32 core, int voiceNum) return ERROR_SAS_INVALID_VOICE; } - SasVoice &v = sas->voices[voiceNum]; if (sas->voices[voiceNum].paused) { return ERROR_SAS_VOICE_PAUSED; } + SasVoice &v = sas->voices[voiceNum]; v.KeyOn(); return 0; } // sceSasSetKeyOff can be used to start sounds, that just sound during the Release phase! -u32 sceSasSetKeyOff(u32 core, int voiceNum) -{ +u32 sceSasSetKeyOff(u32 core, int voiceNum) { if (voiceNum == -1) { // TODO: Some games (like Every Extend Extra) deliberately pass voiceNum = -1. Does that mean all voices? for now let's ignore. DEBUG_LOG(HLE,"sceSasSetKeyOff(%08x, %i) - voiceNum = -1???", core, voiceNum); return 0; - } else if (voiceNum < 0 || voiceNum >= PSP_SAS_VOICES_MAX) { + } else if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } else { DEBUG_LOG(HLE,"sceSasSetKeyOff(%08x, %i)", core, voiceNum); - SasVoice &v = sas->voices[voiceNum]; + if (sas->voices[voiceNum].paused) { return ERROR_SAS_VOICE_PAUSED; } + SasVoice &v = sas->voices[voiceNum]; v.KeyOff(); return 0; } } -u32 sceSasSetNoise(u32 core, int voiceNum, int freq) -{ +u32 sceSasSetNoise(u32 core, int voiceNum, int freq) { DEBUG_LOG(HLE,"sceSasSetNoise(%08x, %i, %i)", core, voiceNum, freq); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -283,8 +278,7 @@ u32 sceSasSetNoise(u32 core, int voiceNum, int freq) return 0; } -u32 sceSasSetSL(u32 core, int voiceNum, int level) -{ +u32 sceSasSetSL(u32 core, int voiceNum, int level) { DEBUG_LOG(HLE,"sceSasSetSL(%08x, %i, %i)", core, voiceNum, level); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -297,8 +291,7 @@ u32 sceSasSetSL(u32 core, int voiceNum, int level) return 0; } -u32 sceSasSetADSR(u32 core, int voiceNum, int flag , int a, int d, int s, int r) -{ +u32 sceSasSetADSR(u32 core, int voiceNum, int flag , int a, int d, int s, int r) { DEBUG_LOG(HLE,"0=sceSasSetADSR(%08x, %i, %i, %08x, %08x, %08x, %08x)",core, voiceNum, flag, a, d, s, r) if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -314,8 +307,7 @@ u32 sceSasSetADSR(u32 core, int voiceNum, int flag , int a, int d, int s, int r) return 0; } -u32 sceSasSetADSRMode(u32 core, int voiceNum,int flag ,int a, int d, int s, int r) -{ +u32 sceSasSetADSRMode(u32 core, int voiceNum,int flag ,int a, int d, int s, int r) { DEBUG_LOG(HLE,"sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x)",core, voiceNum, flag, a,d,s,r) if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -332,21 +324,23 @@ u32 sceSasSetADSRMode(u32 core, int voiceNum,int flag ,int a, int d, int s, int } -u32 sceSasSetSimpleADSR(u32 core, u32 voiceNum, u32 ADSREnv1, u32 ADSREnv2) -{ +u32 sceSasSetSimpleADSR(u32 core, int voiceNum, u32 ADSREnv1, u32 ADSREnv2) { DEBUG_LOG(HLE,"sasSetSimpleADSR(%08x, %i, %08x, %08x)", core, voiceNum, ADSREnv1, ADSREnv2); + + if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { + WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + return ERROR_SAS_INVALID_VOICE; + } + SasVoice &v = sas->voices[voiceNum]; v.envelope.SetSimpleEnvelope(ADSREnv1 & 0xFFFF, ADSREnv2 & 0xFFFF); return 0; } -u32 sceSasGetEnvelopeHeight(u32 core, u32 voiceNum) -{ - // Spam reduction - if (voiceNum == 17) { - DEBUG_LOG(HLE,"sceSasGetEnvelopeHeight(%08x, %i)", core, voiceNum); - } - if (voiceNum >= PSP_SAS_VOICES_MAX) { +u32 sceSasGetEnvelopeHeight(u32 core, int voiceNum) { + DEBUG_LOG(HLE,"sceSasGetEnvelopeHeight(%08x, %i)", core, voiceNum); + + if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } @@ -355,105 +349,96 @@ u32 sceSasGetEnvelopeHeight(u32 core, u32 voiceNum) return v.envelope.GetHeight(); } -u32 sceSasRevType(u32 core, int type) -{ +u32 sceSasRevType(u32 core, int type) { DEBUG_LOG(HLE,"sceSasRevType(%08x, %i)", core, type); sas->waveformEffect.type = type; return 0; } -u32 sceSasRevParam(u32 core, int delay, int feedback) -{ +u32 sceSasRevParam(u32 core, int delay, int feedback) { DEBUG_LOG(HLE,"sceSasRevParam(%08x, %i, %i)", core, delay, feedback); sas->waveformEffect.delay = delay; sas->waveformEffect.feedback = feedback; return 0; } -u32 sceSasRevEVOL(u32 core, int lv, int rv) -{ +u32 sceSasRevEVOL(u32 core, int lv, int rv) { DEBUG_LOG(HLE,"sceSasRevEVOL(%08x, %i, %i)", core, lv, rv); sas->waveformEffect.leftVol = lv; sas->waveformEffect.rightVol = rv; return 0; } -u32 sceSasRevVON(u32 core, int dry, int wet) -{ +u32 sceSasRevVON(u32 core, int dry, int wet) { DEBUG_LOG(HLE,"sceSasRevVON(%08x, %i, %i)", core, dry, wet); sas->waveformEffect.isDryOn = (dry > 0); sas->waveformEffect.isWetOn = (wet > 0); return 0; } -u32 sceSasGetGrain(u32 core) -{ +u32 sceSasGetGrain(u32 core) { DEBUG_LOG(HLE,"sceSasGetGrain(%08x)", core); return sas->GetGrainSize(); } -u32 sceSasSetGrain(u32 core, int grain) -{ +u32 sceSasSetGrain(u32 core, int grain) { INFO_LOG(HLE,"sceSasSetGrain(%08x, %i)", core, grain); sas->SetGrainSize(grain); return 0; } -u32 sceSasGetOutputMode(u32 core) -{ +u32 sceSasGetOutputMode(u32 core) { DEBUG_LOG(HLE,"sceSasGetOutputMode(%08x)", core); return sas->outputMode; } -u32 sceSasSetOutputMode(u32 core, u32 outputMode) -{ +u32 sceSasSetOutputMode(u32 core, u32 outputMode) { DEBUG_LOG(HLE,"sceSasSetOutputMode(%08x, %i)", core, outputMode); sas->outputMode = outputMode; return 0; } -u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) -{ +u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) { DEBUG_LOG(HLE,"sceSasGetAllEnvelopeHeights(%08x, %i)", core, heightsAddr); - if (Memory::IsValidAddress(heightsAddr)) { - for (int i = 0; i < PSP_SAS_VOICES_MAX; i++) { + + if (!Memory::IsValidAddress(heightsAddr)) { + return ERROR_SAS_INVALID_PARAMETER; + } + + for (int i = 0; i < PSP_SAS_VOICES_MAX; i++) { int voiceHeight = sas->voices[i].envelope.GetHeight(); Memory::Write_U32(voiceHeight, heightsAddr + i * 4); - } } + return 0; } -u32 sceSasSetTriangularWave(u32 sasCore, int voice, int unknown) -{ +u32 sceSasSetTriangularWave(u32 sasCore, int voice, int unknown) { ERROR_LOG(HLE,"UNIMPL sceSasSetTriangularWave(%08x, %i, %i)", sasCore, voice, unknown); return 0; } -u32 sceSasSetSteepWave(u32 sasCore, int voice, int unknown) -{ +u32 sceSasSetSteepWave(u32 sasCore, int voice, int unknown) { ERROR_LOG(HLE,"UNIMPL sceSasSetSteepWave(%08x, %i, %i)", sasCore, voice, unknown); return 0; } -u32 __sceSasSetVoiceATRAC3(u32 core, int voice, int atrac3Context) -{ +u32 __sceSasSetVoiceATRAC3(u32 core, int voice, int atrac3Context) { ERROR_LOG(HLE,"UNIMPL __sceSasSetVoiceATRAC3(%08x, %i, %i)", core, voice, atrac3Context); return 0; } -u32 __sceSasConcatenateATRAC3(u32 core, int voice, u32 atrac3DataAddr, int atrac3DataLength) -{ - ERROR_LOG(HLE,"UNIMPL __sceSasConcatenateATRAC3(%08x, %i, %i)", core, voice, atrac3DataAddr, atrac3DataLength); +u32 __sceSasConcatenateATRAC3(u32 core, int voice, u32 atrac3DataAddr, int atrac3DataLength) { + ERROR_LOG(HLE,"UNIMPL __sceSasConcatenateATRAC3(%08x, %i, %08x, %i)", core, voice, atrac3DataAddr, atrac3DataLength); return 0; } -u32 __sceSasUnsetATRAC3(u32 core, int voice) -{ +u32 __sceSasUnsetATRAC3(u32 core, int voice) { ERROR_LOG(HLE, "UNIMPL __sceSasUnsetATRAC3(%08x, %i)", core, voice); return 0; } + const HLEFunction sceSasCore[] = { {0x42778a9f, WrapU_UUUUU, "__sceSasInit"}, @@ -467,8 +452,8 @@ const HLEFunction sceSasCore[] = {0x019b25eb, WrapU_UIIIIII, "__sceSasSetADSR"}, {0x9ec3676a, WrapU_UIIIIII, "__sceSasSetADSRmode"}, {0x5f9529f6, WrapU_UII, "__sceSasSetSL"}, - {0x74ae582a, WrapU_UU, "__sceSasGetEnvelopeHeight"}, - {0xcbcd4f79, WrapU_UUUU, "__sceSasSetSimpleADSR"}, + {0x74ae582a, WrapU_UI, "__sceSasGetEnvelopeHeight"}, + {0xcbcd4f79, WrapU_UIUU, "__sceSasSetSimpleADSR"}, {0xa0cf2fa4, WrapU_UI, "__sceSasSetKeyOff"}, {0x76f01aca, WrapU_UI, "__sceSasSetKeyOn"}, {0xf983b186, WrapU_UII, "__sceSasRevVON"}, diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 83966df79e..aa22d3b875 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -548,9 +548,10 @@ static int getExpCurveAt(int index, int duration) { } ADSREnvelope::ADSREnvelope() - : steps_(0), - state_(STATE_OFF), + : state_(STATE_OFF), + steps_(0), height_(0) { + memset(this, 0, sizeof(*this)); } void ADSREnvelope::WalkCurve(int rate, int type) { diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index 6529425d36..9cba6c10ef 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -157,7 +157,9 @@ private: struct SasVoice { SasVoice() - : playing(false), paused(false), on(false), + : playing(false), + paused(false), + on(false), type(VOICETYPE_OFF), vagAddr(0), vagSize(0), @@ -171,7 +173,10 @@ struct SasVoice volumeLeft(0), volumeRight(0), volumeLeftSend(0), - volumeRightSend(0) { + volumeRightSend(0), + effectLeft(0), + effectRight(0) { + memset(resampleHist, 0, sizeof(resampleHist)); } void Reset(); diff --git a/Core/Host.h b/Core/Host.h index f20277ac20..01573a1e65 100644 --- a/Core/Host.h +++ b/Core/Host.h @@ -46,7 +46,6 @@ public: virtual void InitGL() = 0; virtual void BeginFrame() {} - virtual void EndFrame() {} virtual void ShutdownGL() = 0; virtual void InitSound(PMixer *mixer) = 0; @@ -64,8 +63,9 @@ public: virtual void SendCoreWait(bool) {} virtual bool GpuStep() { return false; } - virtual void SendGPUWait() {} - virtual void SetGPUStep(bool value) {} + virtual void SendGPUStart() {} + virtual void SendGPUWait(u32 cmd, u32 addr, void* data) {} + virtual void SetGPUStep(bool value, int flag = 0, int data = 0) {} virtual void NextGPUStep() {} // Used for headless. diff --git a/Core/MIPS/ARM/ArmAsm.cpp b/Core/MIPS/ARM/ArmAsm.cpp index ff9b28336c..5153865d0f 100644 --- a/Core/MIPS/ARM/ArmAsm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -113,11 +113,7 @@ void Jit::GenerateFixedCode() // * downcount // * R2-R4 // Really starting to run low on registers already though... -#ifdef UNUSABLE_MMAP - MOVI2R(R11, (u32)Memory::m_pRAM - 0x08000000); -#else MOVI2R(R11, (u32)Memory::base); -#endif MOVI2R(R10, (u32)mips_); MOVI2R(R9, (u32)GetBlockCache()->GetCodePointers()); diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 93aee69253..4f2cc26c90 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/ChunkFile.h" #include "../../Core.h" #include "../../CoreTiming.h" #include "../MIPS.h" @@ -63,6 +64,11 @@ Jit::Jit(MIPSState *mips) : blocks(mips), gpr(mips), fpr(mips), mips_(mips) GenerateFixedCode(); } +void Jit::DoState(PointerWrap &p) +{ + p.DoMarker("Jit"); +} + void Jit::FlushAll() { gpr.FlushAll(); diff --git a/Core/MIPS/ARM/ArmJit.h b/Core/MIPS/ARM/ArmJit.h index 9e8365ef51..8d6ad7ef84 100644 --- a/Core/MIPS/ARM/ArmJit.h +++ b/Core/MIPS/ARM/ArmJit.h @@ -113,6 +113,7 @@ class Jit : public ArmGen::ARMXCodeBlock { public: Jit(MIPSState *mips); + void DoState(PointerWrap &p); // Compiled ops should ignore delay slots // the compiler will take care of them by itself @@ -168,6 +169,9 @@ public: void ClearCache(); void ClearCacheAt(u32 em_address); + // TODO: Eat VFPU prefixes here. + void EatPrefix() { } + private: void GenerateFixedCode(); void FlushAll(); diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index 7fbaa7c974..f7fc64a752 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -45,8 +45,11 @@ MIPSState::MIPSState() MIPSState::~MIPSState() { - delete MIPSComp::jit; - MIPSComp::jit = 0; + if (MIPSComp::jit) + { + delete MIPSComp::jit; + MIPSComp::jit = 0; + } } void MIPSState::Reset() @@ -107,6 +110,8 @@ void MIPSState::DoState(PointerWrap &p) // Reset the jit if we're loading. if (p.mode == p.MODE_READ) Reset(); + if (MIPSComp::jit) + MIPSComp::jit->DoState(p); p.DoArray(r, sizeof(r) / sizeof(r[0])); p.DoArray(f, sizeof(f) / sizeof(f[0])); @@ -143,11 +148,7 @@ int MIPSState::RunLoopUntil(u64 globalTicks) MIPSComp::jit->RunLoopUntil(globalTicks); break; - case CPU_FASTINTERPRETER: // For jit-less platforms. Crashier than INTERPRETER. - return MIPSInterpret_RunFastUntil(globalTicks); - case CPU_INTERPRETER: - // INFO_LOG(CPU, "Entering run loop for %i ticks, pc=%08x", (int)globalTicks, mipsr4k.pc); return MIPSInterpret_RunUntil(globalTicks); } return 1; diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 82e771927b..c9c548a739 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -98,7 +98,7 @@ namespace MIPSAnalyst "slt", "sltu", }; const char *opName = MIPSGetName(op); - for (int i = 0; i < ARRAY_SIZE(safeOps); ++i) + for (size_t i = 0; i < ARRAY_SIZE(safeOps); ++i) { if (!strcmp(safeOps[i], opName)) return true; diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index e770fc63b2..90b3fbface 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -110,6 +110,14 @@ void ApplyPrefixST(float *v, u32 data, VectorSize size) if (!constants) { + // Prefix may say "z, z, z, z" but if this is a pair, we force to x. + // TODO: But some ops seem to use const 0 instead? + if (regnum >= n) + { + ERROR_LOG(CPU, "Invalid VFPU swizzle: %08x / %d", data, size); + regnum = 0; + } + v[i] = origV[regnum]; if (abs) v[i] = fabs(v[i]); @@ -137,26 +145,22 @@ inline void ApplySwizzleT(float *v, VectorSize size) void ApplyPrefixD(float *v, VectorSize size, bool onlyWriteMask = false) { u32 data = currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX]; - if (!data) + if (!data || onlyWriteMask) return; int n = GetNumVectorElements(size); - bool writeMask[4]; for (int i = 0; i < n; i++) { - int mask = (data >> (8 + i)) & 1; - writeMask[i] = mask ? true : false; - if (!onlyWriteMask) { - int sat = (data >> (i * 2)) & 3; - if (sat == 1) - { - if (v[i] > 1.0f) v[i] = 1.0f; - if (v[i] < 0.0f) v[i] = 0.0f; - } - else if (sat == 3) - { - if (v[i] > 1.0f) v[i] = 1.0f; - if (v[i] < -1.0f) v[i] = -1.0f; - } + int sat = (data >> (i * 2)) & 3; + if (sat == 1) + { + if (v[i] > 1.0f) v[i] = 1.0f; + // This includes -0.0f -> +0.0f. + if (v[i] <= 0.0f) v[i] = 0.0f; + } + else if (sat == 3) + { + if (v[i] > 1.0f) v[i] = 1.0f; + if (v[i] < -1.0f) v[i] = -1.0f; } } } @@ -718,7 +722,7 @@ namespace MIPSInt void Int_Vx2i(u32 op) { int s[4]; - u32 d[4] = {0}; + u32 d[4] = {0}; int vd = _VD; int vs = _VS; VectorSize sz = GetVecSize(op); @@ -852,7 +856,7 @@ namespace MIPSInt _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); break; } - ApplyPrefixD((float*)d,oz,true); + ApplyPrefixD((float*)d,oz); WriteVector((float*)d,oz,vd); PC += 4; EatPrefixes(); @@ -927,7 +931,7 @@ namespace MIPSInt } d = sum; ApplyPrefixD(&d,V_Single); - V(vd) = d; + WriteVector(&d, V_Single, vd); PC += 4; EatPrefixes(); } @@ -1179,6 +1183,11 @@ namespace MIPSInt ReadVector(s, sz, vs); ApplySwizzleS(s, sz); float scale = V(vt); + if (currentMIPS->vfpuCtrl[VFPU_CTRL_TPREFIX] != 0xE4) + { + // WARN_LOG(CPU, "Broken T prefix used with VScl: %08x / %08x", currentMIPS->vfpuCtrl[VFPU_CTRL_TPREFIX], op); + ApplySwizzleT(&scale, V_Single); + } int n = GetNumVectorElements(sz); for (int i = 0; i < n; i++) { @@ -1196,6 +1205,7 @@ namespace MIPSInt int seed = VI(vd); currentMIPS->rng.Init(seed); PC += 4; + EatPrefixes(); } void Int_VrndX(u32 op) diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index ea58c8de4c..821fd72c90 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -147,22 +147,22 @@ const MIPSInstruction tableImmediate[64] = //xxxxxx ..... //48 INSTR("ll", &Jit::Comp_Generic, Dis_Generic, Int_StoreSync, 0), INSTR("lwc1", &Jit::Comp_FPULS, Dis_FPULS, Int_FPULS, IN_RT|IN_RS_ADDR), - INSTR("lv.s", &Jit::Comp_SV, Dis_SV, Int_SV, IS_VFPU), + INSTR("lv.s", &Jit::Comp_SV, Dis_SV, Int_SV, IS_VFPU|VFPU_NO_PREFIX), {-2}, // HIT THIS IN WIPEOUT {VFPU4Jump}, - INSTR("lv", &Jit::Comp_SVQ, Dis_SVLRQ, Int_SVQ, IS_VFPU), - INSTR("lv.q", &Jit::Comp_SVQ, Dis_SVQ, Int_SVQ, IS_VFPU), //copU + INSTR("lv", &Jit::Comp_SVQ, Dis_SVLRQ, Int_SVQ, IS_VFPU|VFPU_NO_PREFIX), + INSTR("lv.q", &Jit::Comp_SVQ, Dis_SVQ, Int_SVQ, IS_VFPU|VFPU_NO_PREFIX), //copU {VFPU5}, //56 INSTR("sc", &Jit::Comp_Generic, Dis_Generic, Int_StoreSync, 0), INSTR("swc1", &Jit::Comp_FPULS, Dis_FPULS, Int_FPULS, 0), //copU - INSTR("sv.s", &Jit::Comp_SV, Dis_SV, Int_SV,IS_VFPU), + INSTR("sv.s", &Jit::Comp_SV, Dis_SV, Int_SV,IS_VFPU|VFPU_NO_PREFIX), {-2}, //60 {VFPU6}, - INSTR("sv", &Jit::Comp_SVQ, Dis_SVLRQ, Int_SVQ, IS_VFPU), //copU - INSTR("sv.q", &Jit::Comp_SVQ, Dis_SVQ, Int_SVQ, IS_VFPU), - INSTR("vflush", &Jit::Comp_Generic, Dis_Vflush, Int_Vflush, IS_VFPU), + INSTR("sv", &Jit::Comp_SVQ, Dis_SVLRQ, Int_SVQ, IS_VFPU|VFPU_NO_PREFIX), //copU + INSTR("sv.q", &Jit::Comp_SVQ, Dis_SVQ, Int_SVQ, IS_VFPU|VFPU_NO_PREFIX), + INSTR("vflush", &Jit::Comp_Generic, Dis_Vflush, Int_Vflush, IS_VFPU|VFPU_NO_PREFIX), }; const MIPSInstruction tableSpecial[64] = /// 000000 ...... ...... .......... xxxxxx @@ -478,19 +478,19 @@ const MIPSInstruction tableCop1BC[32] = const MIPSInstruction tableVFPU0[8] = { - INSTR("vadd",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_VecDo3, IS_VFPU), - INSTR("vsub",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_VecDo3, IS_VFPU), + INSTR("vadd",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_VecDo3, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vsub",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_VecDo3, IS_VFPU|OUT_EAT_PREFIX), INSTR("vsbn",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vsbn, IS_VFPU), {-2}, {-2}, {-2}, {-2}, - INSTR("vdiv",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_VecDo3, IS_VFPU), + INSTR("vdiv",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_VecDo3, IS_VFPU|OUT_EAT_PREFIX), }; const MIPSInstruction tableVFPU1[8] = { - INSTR("vmul",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_VecDo3, IS_VFPU), - INSTR("vdot",&Jit::Comp_VDot, Dis_VectorDot, Int_VDot, IS_VFPU), - INSTR("vscl",&Jit::Comp_Generic, Dis_VScl, Int_VScl, IS_VFPU), + INSTR("vmul",&Jit::Comp_VecDo3, Dis_VectorSet3, Int_VecDo3, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vdot",&Jit::Comp_VDot, Dis_VectorDot, Int_VDot, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vscl",&Jit::Comp_Generic, Dis_VScl, Int_VScl, IS_VFPU|OUT_EAT_PREFIX), {-2}, INSTR("vhdp",&Jit::Comp_Generic, Dis_Generic, Int_VHdp, IS_VFPU), INSTR("vcrs",&Jit::Comp_Generic, Dis_Vcrs, Int_Vcrs, IS_VFPU), @@ -500,14 +500,14 @@ const MIPSInstruction tableVFPU1[8] = const MIPSInstruction tableVFPU3[8] = //011011 xxx { - INSTR("vcmp",&Jit::Comp_Generic, Dis_Vcmp, Int_Vcmp, IS_VFPU), + INSTR("vcmp",&Jit::Comp_Generic, Dis_Vcmp, Int_Vcmp, IS_VFPU|OUT_EAT_PREFIX), {-2}, - INSTR("vmin",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vminmax, IS_VFPU), - INSTR("vmax",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vminmax, IS_VFPU), + INSTR("vmin",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vminmax, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vmax",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vminmax, IS_VFPU|OUT_EAT_PREFIX), {-2}, - INSTR("vscmp",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vscmp, IS_VFPU), - INSTR("vsge",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vsge, IS_VFPU), - INSTR("vslt",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vslt, IS_VFPU), + INSTR("vscmp",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vscmp, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vsge",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vsge, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vslt",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vslt, IS_VFPU|OUT_EAT_PREFIX), }; @@ -516,7 +516,7 @@ const MIPSInstruction tableVFPU4Jump[32] = //110100 xxxxx {VFPU4}, {VFPU7}, {VFPU9}, - INSTR("vcst", &Jit::Comp_Generic, Dis_Vcst, Int_Vcst, IS_VFPU), + INSTR("vcst", &Jit::Comp_Generic, Dis_Vcst, Int_Vcst, IS_VFPU|OUT_EAT_PREFIX), {-2},{-2},{-2},{-2}, //8 @@ -524,13 +524,13 @@ const MIPSInstruction tableVFPU4Jump[32] = //110100 xxxxx {-2},{-2},{-2},{-2}, //16 - INSTR("vf2in", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU), - INSTR("vf2iz", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU), - INSTR("vf2iu", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU), - INSTR("vf2id", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU), + INSTR("vf2in", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vf2iz", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vf2iu", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vf2id", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU|OUT_EAT_PREFIX), //20 - INSTR("vi2f", &Jit::Comp_Generic, Dis_Vf2i, Int_Vi2f, IS_VFPU), - INSTR("vcmov", &Jit::Comp_Generic, Dis_Vcmov,Int_Vcmov,IS_VFPU), + INSTR("vi2f", &Jit::Comp_Generic, Dis_Vf2i, Int_Vi2f, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vcmov", &Jit::Comp_Generic, Dis_Vcmov,Int_Vcmov,IS_VFPU|OUT_EAT_PREFIX), {-2}, {-2}, @@ -546,10 +546,10 @@ const MIPSInstruction tableVFPU4Jump[32] = //110100 xxxxx const MIPSInstruction tableVFPU7[32] = { - INSTR("vrnds", &Jit::Comp_Generic, Dis_Generic, Int_Vrnds, IS_VFPU), - INSTR("vrndi", &Jit::Comp_Generic, Dis_Generic, Int_VrndX, IS_VFPU), - INSTR("vrndf1", &Jit::Comp_Generic, Dis_Generic, Int_VrndX, IS_VFPU), - INSTR("vrndf2", &Jit::Comp_Generic, Dis_Generic, Int_VrndX, IS_VFPU), + INSTR("vrnds", &Jit::Comp_Generic, Dis_Generic, Int_Vrnds, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vrndi", &Jit::Comp_Generic, Dis_Generic, Int_VrndX, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vrndf1", &Jit::Comp_Generic, Dis_Generic, Int_VrndX, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vrndf2", &Jit::Comp_Generic, Dis_Generic, Int_VrndX, IS_VFPU|OUT_EAT_PREFIX), {-2},{-2},{-2},{-2}, //8 @@ -559,8 +559,8 @@ const MIPSInstruction tableVFPU7[32] = //16 {-2}, {-2}, - INSTR("vf2h", &Jit::Comp_Generic, Dis_Generic, Int_Vf2h, IS_VFPU), - INSTR("vh2f", &Jit::Comp_Generic, Dis_Generic, Int_Vh2f, IS_VFPU), + INSTR("vf2h", &Jit::Comp_Generic, Dis_Generic, Int_Vf2h, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vh2f", &Jit::Comp_Generic, Dis_Generic, Int_Vh2f, IS_VFPU|OUT_EAT_PREFIX), {-2}, {-2}, @@ -572,41 +572,41 @@ const MIPSInstruction tableVFPU7[32] = INSTR("vus2i", &Jit::Comp_Generic, Dis_Vs2i, Int_Vx2i, IS_VFPU), INSTR("vs2i", &Jit::Comp_Generic, Dis_Vs2i, Int_Vx2i, IS_VFPU), - INSTR("vi2uc", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU), - INSTR("vi2c", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU), - INSTR("vi2us", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU), - INSTR("vi2s", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU), + INSTR("vi2uc", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vi2c", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vi2us", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vi2s", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU|OUT_EAT_PREFIX), }; // 110100 00000 10100 0000000000000000 // 110100 00000 10111 0000000000000000 const MIPSInstruction tableVFPU4[32] = //110100 00000 xxxxx { - INSTR("vmov", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU), - INSTR("vabs", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU), - INSTR("vneg", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU), - INSTR("vidt", &Jit::Comp_Generic, Dis_VectorSet1, Int_Vidt,IS_VFPU), - INSTR("vsat0", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), - INSTR("vsat1", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), - INSTR("vzero", &Jit::Comp_Generic, Dis_VectorSet1, Int_VVectorInit, IS_VFPU), - INSTR("vone", &Jit::Comp_Generic, Dis_VectorSet1, Int_VVectorInit, IS_VFPU), + INSTR("vmov", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU|OUT_EAT_PREFIX), + INSTR("vabs", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU|OUT_EAT_PREFIX), + INSTR("vneg", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU|OUT_EAT_PREFIX), + INSTR("vidt", &Jit::Comp_Generic, Dis_VectorSet1, Int_Vidt,IS_VFPU|OUT_EAT_PREFIX), + INSTR("vsat0", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vsat1", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vzero", &Jit::Comp_Generic, Dis_VectorSet1, Int_VVectorInit, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vone", &Jit::Comp_Generic, Dis_VectorSet1, Int_VVectorInit, IS_VFPU|OUT_EAT_PREFIX), //8 {-2},{-2},{-2},{-2},{-2},{-2},{-2},{-2}, //16 - INSTR("vrcp", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), - INSTR("vrsq", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), - INSTR("vsin", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), - INSTR("vcos", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), - INSTR("vexp2", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), - INSTR("vlog2", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), - INSTR("vsqrt", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), - INSTR("vasin", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), + INSTR("vrcp", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vrsq", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vsin", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vcos", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vexp2", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vlog2", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vsqrt", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vasin", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), //24 - INSTR("vnrcp", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU), + INSTR("vnrcp", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU|OUT_EAT_PREFIX), {-2}, - INSTR("vnsin", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU), + INSTR("vnsin", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU|OUT_EAT_PREFIX), {-2}, - INSTR("vrexp2",&Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU), + INSTR("vrexp2",&Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU|OUT_EAT_PREFIX), {-2},{-2},{-2}, //32 }; @@ -626,35 +626,35 @@ MIPSInstruction tableVFPU5[8] = //110111 xxx const MIPSInstruction tableVFPU6[32] = //111100 xxx { //0 - INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU), - INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU), - INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU), - INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU), + INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU|OUT_EAT_PREFIX), - INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), - INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), - INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), - INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), + INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), + INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), + INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), + INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), //8 - INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), - INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), - INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), - INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), + INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), + INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), + INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), + INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), - INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), - INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), - INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), - INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU), + INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), + INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), + INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), + INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU|OUT_EAT_PREFIX), //16 - INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU), - INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU), - INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU), - INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU), + INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU|OUT_EAT_PREFIX), - INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU), - INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU), - INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU), - INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU), + INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU|OUT_EAT_PREFIX), //24 {-2}, {-2}, @@ -662,22 +662,22 @@ const MIPSInstruction tableVFPU6[32] = //111100 xxx {-2}, {VFPUMatrix1}, - INSTR("vrot",&Jit::Comp_Generic, Dis_VRot, Int_Vrot, IS_VFPU), + INSTR("vrot",&Jit::Comp_Generic, Dis_VRot, Int_Vrot, IS_VFPU|OUT_EAT_PREFIX), {-2}, {-2}, }; const MIPSInstruction tableVFPUMatrixSet1[16] = //111100 11100 0xxxx (rm x is 16) { - INSTR("vmmov",&Jit::Comp_Generic, Dis_MatrixSet2, Int_Vmmov, IS_VFPU), + INSTR("vmmov",&Jit::Comp_Generic, Dis_MatrixSet2, Int_Vmmov, IS_VFPU|OUT_EAT_PREFIX), {-2}, {-2}, - INSTR("vmidt",&Jit::Comp_Generic, Dis_MatrixSet1, Int_VMatrixInit, IS_VFPU), + INSTR("vmidt",&Jit::Comp_Generic, Dis_MatrixSet1, Int_VMatrixInit, IS_VFPU|OUT_EAT_PREFIX), {-2}, {-2}, - INSTR("vmzero", &Jit::Comp_Generic, Dis_MatrixSet1, Int_VMatrixInit, IS_VFPU), - INSTR("vmone", &Jit::Comp_Generic, Dis_MatrixSet1, Int_VMatrixInit, IS_VFPU), + INSTR("vmzero", &Jit::Comp_Generic, Dis_MatrixSet1, Int_VMatrixInit, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vmone", &Jit::Comp_Generic, Dis_MatrixSet1, Int_VMatrixInit, IS_VFPU|OUT_EAT_PREFIX), {-2},{-2},{-2},{-2}, {-2},{-2},{-2},{-2}, @@ -687,12 +687,12 @@ const MIPSInstruction tableVFPU9[32] = //110100 00010 xxxxx { INSTR("vsrt1", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsrt1, IS_VFPU), INSTR("vsrt2", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsrt2, IS_VFPU), - INSTR("vbfy1", &Jit::Comp_Generic, Dis_Vbfy, Int_Vbfy, IS_VFPU), - INSTR("vbfy2", &Jit::Comp_Generic, Dis_Vbfy, Int_Vbfy, IS_VFPU), + INSTR("vbfy1", &Jit::Comp_Generic, Dis_Vbfy, Int_Vbfy, IS_VFPU|OUT_EAT_PREFIX), + INSTR("vbfy2", &Jit::Comp_Generic, Dis_Vbfy, Int_Vbfy, IS_VFPU|OUT_EAT_PREFIX), //4 INSTR("vocp", &Jit::Comp_Generic, Dis_Vbfy, Int_Vocp, IS_VFPU), // one's complement INSTR("vsocp", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsocp, IS_VFPU), - INSTR("vfad", &Jit::Comp_Generic, Dis_Vfad, Int_Vfad, IS_VFPU), + INSTR("vfad", &Jit::Comp_Generic, Dis_Vfad, Int_Vfad, IS_VFPU|OUT_EAT_PREFIX), INSTR("vavg", &Jit::Comp_Generic, Dis_Vfad, Int_Vavg, IS_VFPU), //8 INSTR("vsrt3", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsrt3, IS_VFPU), @@ -868,6 +868,7 @@ void MIPSCompileOp(u32 op) if (op==0) return; const MIPSInstruction *instr = MIPSGetInstruction(op); + const int info = MIPSGetInfo(op); if (instr) { if (instr->compile) @@ -877,6 +878,9 @@ void MIPSCompileOp(u32 op) ERROR_LOG(CPU,"MIPSCompileOp %08x failed",op); //MessageBox(0,"ARGH2",0,0);//compile an interpreter call } + + if (info & OUT_EAT_PREFIX) + MIPSComp::jit->EatPrefix(); } else { @@ -1016,124 +1020,6 @@ static inline void DelayBranchTo(MIPSState *curMips, u32 where) curMips->inDelaySlot = true; } -// Optimized interpreter loop that shortcuts the most common instructions. -// For slow platforms without JITs. -#define SIMM16 (s32)(s16)(op & 0xFFFF) -#define UIMM16 (u32)(u16)(op & 0xFFFF) -#define SUIMM16 (u32)(s32)(s16)(op & 0xFFFF) -int MIPSInterpret_RunFastUntil(u64 globalTicks) -{ - MIPSState *curMips = currentMIPS; - while (coreState == CORE_RUNNING) - { - CoreTiming::Advance(); - - while (curMips->downcount >= 0 && coreState == CORE_RUNNING) // TODO: Try to get rid of the latter check - { - again: - bool wasInDelaySlot = curMips->inDelaySlot; - u32 op = Memory::ReadUnchecked_U32(curMips->pc); - switch (op >> 29) - { - case 0x0: - { - int imm = (s16)(op&0xFFFF) << 2; - int rs = _RS; - int rt = _RT; - u32 addr = curMips->pc + imm + 4; - switch (op >> 26) - { - case 4: if (R(rt) == R(rs)) DelayBranchTo(curMips, addr); else curMips->pc += 4; break; //beq - case 5: if (R(rt) != R(rs)) DelayBranchTo(curMips, addr); else curMips->pc += 4; break; //bne - case 6: if ((s32)R(rs) <= 0) DelayBranchTo(curMips, addr); else curMips->pc += 4; break; //blez - case 7: if ((s32)R(rs) > 0) DelayBranchTo(curMips, addr); else curMips->pc += 4; break; //bgtz - default: - goto interpret; - } - } - break; - - case 0x1: - { - int rt = _RT; - int rs = _RS; - switch (op >> 26) - { - case 8: R(rt) = R(rs) + SIMM16; break; //addi - case 9: R(rt) = R(rs) + SIMM16; break; //addiu - case 10: R(rt) = (s32)R(rs) < SIMM16; break; //slti - case 11: R(rt) = R(rs) < SUIMM16; break; //sltiu - case 12: R(rt) = R(rs) & UIMM16; break; //andi - case 13: R(rt) = R(rs) | UIMM16; break; //ori - case 14: R(rt) = R(rs) ^ UIMM16; break; //xori - case 15: R(rt) = UIMM16 << 16; break; //lui - default: - goto interpret; - } - currentMIPS->pc += 4; - } - break; - - case 0x4: - { - int rt = _RT; - int rs = _RS; - int imm = (s16)(op & 0xFFFF); - u32 addr = R(rs) + imm; - switch (op >> 26) - { - case 32: R(rt) = (u32)(s32)(s8) Memory::ReadUnchecked_U8(addr); break; //lb - case 33: R(rt) = (u32)(s32)(s16)Memory::ReadUnchecked_U16(addr); break; //lh - case 35: R(rt) = Memory::ReadUnchecked_U32(addr); break; //lw - case 36: R(rt) = Memory::ReadUnchecked_U8(addr); break; //lbu - case 37: R(rt) = Memory::ReadUnchecked_U16(addr); break; //lhu - default: - goto interpret; - } - currentMIPS->pc += 4; - } - break; - - case 0x5: - { - int rt = _RT; - int rs = _RS; - int imm = (s16)(op & 0xFFFF); - u32 addr = R(rs) + imm; - switch (op >> 26) - { - case 40: Memory::WriteUnchecked_U8(R(rt), addr); break; //sb - case 41: Memory::WriteUnchecked_U16(R(rt), addr); break; //sh - case 43: Memory::WriteUnchecked_U32(R(rt), addr); break; //sw - default: - goto interpret; - } - currentMIPS->pc += 4; - } - break; - - default: - interpret: - MIPSInterpret(op); - } - - if (curMips->inDelaySlot) - { - // The reason we have to check this is the delay slot hack in Int_Syscall. - if (wasInDelaySlot) - { - curMips->pc = curMips->nextPC; - curMips->inDelaySlot = false; - } - curMips->downcount -= 1; - goto again; - } - } - } - return 1; -} - - const char *MIPSGetName(u32 op) { static const char *noname = "unk"; diff --git a/Core/MIPS/MIPSTables.h b/Core/MIPS/MIPSTables.h index 9c15072b53..68e453af99 100644 --- a/Core/MIPS/MIPSTables.h +++ b/Core/MIPS/MIPSTables.h @@ -19,31 +19,34 @@ #include "../../Globals.h" -#define IS_CONDBRANCH 0x100 -#define IS_JUMP 0x200 -#define IS_VFPU 0x80000000 -#define LIKELY 0x80 -#define UNCONDITIONAL 0x40 -#define BAD_INSTRUCTION 0x20 -#define DELAYSLOT 0x10 +#define DELAYSLOT 0x00000010 +#define BAD_INSTRUCTION 0x00000020 +#define UNCONDITIONAL 0x00000040 +#define LIKELY 0x00000080 +#define IS_CONDBRANCH 0x00000100 +#define IS_JUMP 0x00000200 -#define IN_RS_ADDR 0x800 -#define IN_RS_SHIFT 0x400 -#define IN_RS 0x1000 -#define IN_RT 0x2000 -#define IN_SA 0x4000 -#define IN_IMM16 0x8000 -#define IN_IMM26 0x10000 -#define IN_MEM 0x20000 -#define IN_OTHER 0x40000 -#define IN_FPUFLAG 0x80000 +#define IN_RS_SHIFT 0x00000400 +#define IN_RS_ADDR 0x00000800 +#define IN_RS 0x00001000 +#define IN_RT 0x00002000 +#define IN_SA 0x00004000 +#define IN_IMM16 0x00008000 +#define IN_IMM26 0x00010000 +#define IN_MEM 0x00020000 +#define IN_OTHER 0x00040000 +#define IN_FPUFLAG 0x00080000 -#define OUT_RT 0x100000 -#define OUT_RD 0x200000 -#define OUT_RA 0x400000 -#define OUT_MEM 0x800000 -#define OUT_OTHER 0x1000000 -#define OUT_FPUFLAG 0x2000000 +#define OUT_RT 0x00100000 +#define OUT_RD 0x00200000 +#define OUT_RA 0x00400000 +#define OUT_MEM 0x00800000 +#define OUT_OTHER 0x01000000 +#define OUT_FPUFLAG 0x02000000 +#define OUT_EAT_PREFIX 0x04000000 + +#define VFPU_NO_PREFIX 0x08000000 +#define IS_VFPU 0x80000000 #ifndef CDECL #define CDECL @@ -57,7 +60,6 @@ void MIPSCompileOp(u32 op); void MIPSDisAsm(u32 op, u32 pc, char *out, bool tabsToSpaces = false); u32 MIPSGetInfo(u32 op); void MIPSInterpret(u32 op); //only for those rare ones -int MIPSInterpret_RunFastUntil(u64 globalTicks); int MIPSInterpret_RunUntil(u64 globalTicks); MIPSInterpretFunc MIPSGetInterpretFunc(u32 op); diff --git a/Core/MIPS/MIPSVFPUUtils.cpp b/Core/MIPS/MIPSVFPUUtils.cpp index fd94a6cf02..acd12fd6a0 100644 --- a/Core/MIPS/MIPSVFPUUtils.cpp +++ b/Core/MIPS/MIPSVFPUUtils.cpp @@ -179,19 +179,22 @@ void WriteMatrix(const float *rd, MatrixSize size, int reg) { case M_4x4: row = (reg>>5)&2; side = 4; break; } - int transpose = (reg>>5)&1; + int transpose = (reg>>5)&1; + if (currentMIPS->VfpuWriteMask() != 0) { + ERROR_LOG(CPU, "Write mask used with vfpu matrix instruction."); + } for (int i=0; iVfpuWriteMask(i)) + if (j != side -1 || !currentMIPS->VfpuWriteMask(i)) { - int index = mtx * 4; + int index = mtx * 4; if (transpose) - index += ((row+i)&3) + ((col+j)&3)*32; - else - index += ((col+j)&3) + ((row+i)&3)*32; - V(index) = rd[j*4+i]; + index += ((row+i)&3) + ((col+j)&3)*32; + else + index += ((col+j)&3) + ((row+i)&3)*32; + V(index) = rd[j*4+i]; } } } @@ -278,7 +281,10 @@ const char *GetVectorNotation(int reg, VectorSize size) case V_Quad: c='C'; row=(reg>>5)&2; break; } if (transpose && c == 'C') c='R'; - sprintf(hej[yo],"%c%i%i%i",c,mtx,col,row); + if (transpose) + sprintf(hej[yo],"%c%i%i%i",c,mtx,row,col); + else + sprintf(hej[yo],"%c%i%i%i",c,mtx,col,row); return hej[yo]; } diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp index e1f86794c7..620fdc216a 100644 --- a/Core/MIPS/x86/CompFPU.cpp +++ b/Core/MIPS/x86/CompFPU.cpp @@ -87,7 +87,7 @@ void Jit::Comp_FPU3op(u32 op) } } -static u32 GC_ALIGNED16(ssLoadStoreTemp[1]); +static u32 GC_ALIGNED16(ssLoadStoreTemp); void Jit::Comp_FPULS(u32 op) { diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 9108471193..4d1db52c7b 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -49,7 +49,7 @@ namespace MIPSComp static const float one = 1.0f; static const float minus_one = -1.0f; -static const float zero = -1.0f; +static const float zero = 0.0f; const u32 GC_ALIGNED16( noSignMask[4] ) = {0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF}; const u32 GC_ALIGNED16( signBitLower[4] ) = {0x80000000, 0, 0, 0}; @@ -75,9 +75,6 @@ void Jit::Comp_VPFX(u32 op) } } - -// TODO: Got register value ownership issues. We need to be sure that if we modify input -// like this, it does NOT get written back! void Jit::ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz) { if (prefix == 0xE4) return; @@ -86,9 +83,7 @@ void Jit::ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz) { static const float constantArray[8] = {0.f, 1.f, 2.f, 0.5f, 3.f, 1.f/3.f, 0.25f, 1.f/6.f}; for (int i = 0; i < n; i++) - { origV[i] = vregs[i]; - } for (int i = 0; i < n; i++) { @@ -97,48 +92,104 @@ void Jit::ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz) { int negate = (prefix >> (16+i)) & 1; int constants = (prefix >> (12+i)) & 1; + // Unchanged, hurray. + if (!constants && regnum == i && !abs && !negate) + continue; + + // This puts the value into a temp reg, so we won't write the modified value back. + vregs[i] = fpr.GetTempV(); + fpr.MapRegV(vregs[i], MAP_NOINIT | MAP_DIRTY); + if (!constants) { - vregs[i] = origV[regnum]; + // Prefix may say "z, z, z, z" but if this is a pair, we force to x. + // TODO: But some ops seem to use const 0 instead? + if (regnum > n) { + ERROR_LOG(CPU, "Invalid VFPU swizzle: %08x / %d", prefix, sz); + regnum = 0; + } + MOVSS(fpr.VX(vregs[i]), fpr.V(origV[regnum])); if (abs) { ANDPS(fpr.VX(vregs[i]), M((void *)&noSignMask)); } - } else { + } else { MOVSS(fpr.VX(vregs[i]), M((void *)&constantArray[regnum + (abs<<2)])); } if (negate) XORPS(fpr.VX(vregs[i]), M((void *)&signBitLower)); + + // TODO: This probably means it will swap out soon, inefficiently... + fpr.ReleaseSpillLockV(vregs[i]); } } -void Jit::ApplyPrefixD(const u8 *vregs, u32 prefix, VectorSize sz, bool onlyWriteMask) { +void Jit::GetVectorRegsPrefixD(u8 *regs, VectorSize sz, int vectorReg) { _assert_(js.prefixDFlag & JitState::PREFIX_KNOWN); - if (!prefix) return; + + GetVectorRegs(regs, sz, vectorReg); + if (js.prefixD == 0) + return; int n = GetNumVectorElements(sz); for (int i = 0; i < n; i++) { - int mask = (prefix >> (8 + i)) & 1; - js.writeMask[i] = mask ? true : false; - if (onlyWriteMask) + // Hopefully this is rare, we'll just write it into a reg we drop. + if (js.VfpuWriteMask(i)) + regs[i] = fpr.GetTempV(); + } +} + +void Jit::ApplyPrefixD(const u8 *vregs, VectorSize sz) { + _assert_(js.prefixDFlag & JitState::PREFIX_KNOWN); + if (!js.prefixD) return; + + int n = GetNumVectorElements(sz); + for (int i = 0; i < n; i++) + { + if (js.VfpuWriteMask(i)) continue; - if (!mask) { - int sat = (prefix >> (i * 2)) & 3; - if (sat == 1) - { - MAXSS(fpr.VX(vregs[i]), M((void *)&zero)); - MINSS(fpr.VX(vregs[i]), M((void *)&one)); - } - else if (sat == 3) - { - MAXSS(fpr.VX(vregs[i]), M((void *)&minus_one)); - MINSS(fpr.VX(vregs[i]), M((void *)&one)); - } + + int sat = (js.prefixD >> (i * 2)) & 3; + if (sat == 1) + { + fpr.MapRegV(vregs[i], MAP_DIRTY); + MAXSS(fpr.VX(vregs[i]), M((void *)&zero)); + MINSS(fpr.VX(vregs[i]), M((void *)&one)); + } + else if (sat == 3) + { + fpr.MapRegV(vregs[i], MAP_DIRTY); + MAXSS(fpr.VX(vregs[i]), M((void *)&minus_one)); + MINSS(fpr.VX(vregs[i]), M((void *)&one)); } } } -static u32 GC_ALIGNED16(ssLoadStoreTemp[1]); +// Vector regs can overlap in all sorts of swizzled ways. +// This does allow a single overlap in sregs[i]. +bool IsOverlapSafeAllowS(int dreg, int di, int sn, u8 sregs[], int tn, u8 tregs[]) +{ + for (int i = 0; i < sn; ++i) + { + if (sregs[i] == dreg && i != di) + return false; + } + for (int i = 0; i < tn; ++i) + { + if (tregs[i] == dreg) + return false; + } + + // Hurray, no overlap, we can write directly. + return true; +} + +bool IsOverlapSafe(int dreg, int di, int sn, u8 sregs[], int tn, u8 tregs[]) +{ + return IsOverlapSafeAllowS(dreg, di, sn, sregs, tn, tregs) && sregs[di] != dreg; +} + +static u32 GC_ALIGNED16(ssLoadStoreTemp); void Jit::Comp_SV(u32 op) { CONDITIONAL_DISABLE; @@ -286,12 +337,10 @@ void Jit::Comp_SVQ(u32 op) } void Jit::Comp_VDot(u32 op) { - DISABLE; + CONDITIONAL_DISABLE; - // WARNING: No prefix support! - if (js.MayHavePrefix()) { + if (js.HasUnknownPrefix()) { Comp_Generic(op); - js.EatPrefix(); return; } @@ -301,45 +350,45 @@ void Jit::Comp_VDot(u32 op) { VectorSize sz = GetVecSize(op); // TODO: Force read one of them into regs? probably not. - u8 sregs[4], tregs[4], dregs[4]; - GetVectorRegs(sregs, sz, vs); - GetVectorRegs(tregs, sz, vt); - GetVectorRegs(dregs, V_Single, vd); - - // TODO: applyprefixST here somehow (shuffle, etc...) - - MOVSS(XMM0, fpr.V(sregs[0])); - MULSS(XMM0, fpr.V(tregs[0])); + u8 sregs[4], tregs[4], dregs[1]; + GetVectorRegsPrefixS(sregs, sz, vs); + GetVectorRegsPrefixT(tregs, sz, vt); + GetVectorRegsPrefixD(dregs, V_Single, vd); int n = GetNumVectorElements(sz); - for (int i = 1; i < n; i++) + X64Reg tempxreg = XMM0; + if (IsOverlapSafe(dregs[0], 0, n, sregs, n, tregs)) + { + fpr.MapRegsV(dregs, V_Single, MAP_NOINIT); + tempxreg = fpr.VX(dregs[0]); + } + + // Need to start with +0.0f so it doesn't result in -0.0f. + XORPS(tempxreg, R(tempxreg)); + for (int i = 0; i < n; i++) { // sum += s[i]*t[i]; MOVSS(XMM1, fpr.V(sregs[i])); MULSS(XMM1, fpr.V(tregs[i])); - ADDSS(XMM0, R(XMM1)); + ADDSS(tempxreg, R(XMM1)); } - fpr.ReleaseSpillLocks(); - fpr.MapRegsV(dregs, V_Single, MAP_NOINIT); + if (!fpr.V(dregs[0]).IsSimpleReg(tempxreg)) + { + fpr.MapRegsV(dregs, V_Single, MAP_NOINIT); + MOVSS(fpr.V(dregs[0]), tempxreg); + } - // TODO: applyprefixD here somehow (write mask etc..) - - MOVSS(fpr.V(vd), XMM0); + ApplyPrefixD(dregs, V_Single); fpr.ReleaseSpillLocks(); - - js.EatPrefix(); } void Jit::Comp_VecDo3(u32 op) { - DISABLE; + CONDITIONAL_DISABLE; - // WARNING: No prefix support! - if (js.MayHavePrefix()) - { + if (js.HasUnknownPrefix()) { Comp_Generic(op); - js.EatPrefix(); return; } @@ -349,9 +398,9 @@ void Jit::Comp_VecDo3(u32 op) { VectorSize sz = GetVecSize(op); u8 sregs[4], tregs[4], dregs[4]; - GetVectorRegs(sregs, sz, vs); - GetVectorRegs(tregs, sz, vt); - GetVectorRegs(dregs, sz, vd); + GetVectorRegsPrefixS(sregs, sz, vs); + GetVectorRegsPrefixT(tregs, sz, vt); + GetVectorRegsPrefixD(dregs, sz, vd); void (XEmitter::*xmmop)(X64Reg, OpArg) = NULL; switch (op >> 26) @@ -382,26 +431,53 @@ void Jit::Comp_VecDo3(u32 op) { if (xmmop == NULL) { + fpr.ReleaseSpillLocks(); Comp_Generic(op); - js.EatPrefix(); return; } int n = GetNumVectorElements(sz); - // We need at least n temporaries... - if (n > 2) - fpr.Flush(); + + X64Reg tempxregs[4]; + for (int i = 0; i < n; ++i) + { + if (!IsOverlapSafeAllowS(dregs[i], i, n, sregs, n, tregs)) + { + // On 32-bit we only have 6 xregs for mips regs, use XMM0/XMM1 if possible. + if (i < 2) + tempxregs[i] = (X64Reg) (XMM0 + i); + else + { + int reg = fpr.GetTempV(); + fpr.MapRegV(reg, MAP_NOINIT | MAP_DIRTY); + fpr.SpillLockV(reg); + tempxregs[i] = fpr.VX(reg); + } + } + else + { + fpr.MapRegV(dregs[i], (dregs[i] == sregs[i] ? 0 : MAP_NOINIT) | MAP_DIRTY); + fpr.SpillLockV(dregs[i]); + tempxregs[i] = fpr.VX(dregs[i]); + } + } for (int i = 0; i < n; ++i) - MOVSS((X64Reg) (XMM0 + i), fpr.V(sregs[i])); + { + if (!fpr.V(sregs[i]).IsSimpleReg(tempxregs[i])) + MOVSS(tempxregs[i], fpr.V(sregs[i])); + } for (int i = 0; i < n; ++i) - (this->*xmmop)((X64Reg) (XMM0 + i), fpr.V(tregs[i])); + (this->*xmmop)(tempxregs[i], fpr.V(tregs[i])); for (int i = 0; i < n; ++i) - MOVSS(fpr.V(dregs[i]), (X64Reg) (XMM0 + i)); + { + if (!fpr.V(dregs[i]).IsSimpleReg(tempxregs[i])) + MOVSS(fpr.V(dregs[i]), tempxregs[i]); + } + + ApplyPrefixD(dregs, sz); fpr.ReleaseSpillLocks(); - - js.EatPrefix(); } void Jit::Comp_Mftv(u32 op) { @@ -478,4 +554,4 @@ void Jit::Comp_Vmtvc(u32 op) { } } -} \ No newline at end of file +} diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 9fb2487713..5b56caad72 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -17,6 +17,7 @@ #include #include +#include "Common/ChunkFile.h" #include "../../Core.h" #include "../../CoreTiming.h" #include "../../Config.h" @@ -103,6 +104,15 @@ Jit::Jit(MIPSState *mips) : blocks(mips), mips_(mips) gpr.SetEmitter(this); fpr.SetEmitter(this); AllocCodeSpace(1024 * 1024 * 16); + + // TODO: If it becomes possible to switch from the interpreter, this should be set right. + js.startDefaultPrefix = true; +} + +void Jit::DoState(PointerWrap &p) +{ + p.Do(js.startDefaultPrefix); + p.DoMarker("Jit"); } void Jit::FlushAll() @@ -202,6 +212,17 @@ void Jit::Compile(u32 em_address) int block_num = blocks.AllocateBlock(em_address); JitBlock *b = blocks.GetBlock(block_num); blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, b)); + + // Drat. The VFPU hit an uneaten prefix at the end of a block. + if (js.startDefaultPrefix && js.MayHavePrefix()) + { + js.startDefaultPrefix = false; + // Our assumptions are all wrong so it's clean-slate time. + ClearCache(); + + // Let's try that one more time. We won't get back here because we toggled the value. + Compile(em_address); + } } void Jit::RunLoopUntil(u64 globalticks) @@ -282,9 +303,13 @@ void Jit::Comp_Generic(u32 op) else _dbg_assert_msg_(JIT, 0, "Trying to compile instruction that can't be interpreted"); - // Might have eaten prefixes, hard to tell... - if ((MIPSGetInfo(op) & IS_VFPU) != 0) - js.PrefixStart(); + const int info = MIPSGetInfo(op); + if ((info & IS_VFPU) != 0 && (info & VFPU_NO_PREFIX) == 0) + { + // If it does eat them, it'll happen in MIPSCompileOp(). + if ((info & OUT_EAT_PREFIX) == 0) + js.PrefixUnknown(); + } } void Jit::WriteExit(u32 destination, int exit_num) diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index 2d5f9ef3c1..cf86376393 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -66,29 +66,42 @@ struct JitState JitBlock *curBlock; // VFPU prefix magic + bool startDefaultPrefix; u32 prefixS; u32 prefixT; u32 prefixD; - bool writeMask[4]; PrefixState prefixSFlag; PrefixState prefixTFlag; PrefixState prefixDFlag; void PrefixStart() { + if (startDefaultPrefix) { + EatPrefix(); + } else { + PrefixUnknown(); + } + } + void PrefixUnknown() { prefixSFlag = PREFIX_UNKNOWN; prefixTFlag = PREFIX_UNKNOWN; prefixDFlag = PREFIX_UNKNOWN; } bool MayHavePrefix() const { - if (!(prefixSFlag & PREFIX_KNOWN) || !(prefixTFlag & PREFIX_KNOWN) || !(prefixDFlag & PREFIX_KNOWN)) { + if (HasUnknownPrefix()) { return true; } else if (prefixS != 0xE4 || prefixT != 0xE4 || prefixD != 0) { return true; - } else if (writeMask[0] || writeMask[1] || writeMask[2] || writeMask[3]) { + } else if (VfpuWriteMask() != 0) { return true; } return false; } + bool HasUnknownPrefix() const { + if (!(prefixSFlag & PREFIX_KNOWN) || !(prefixTFlag & PREFIX_KNOWN) || !(prefixDFlag & PREFIX_KNOWN)) { + return true; + } + return false; + } void EatPrefix() { if ((prefixSFlag & PREFIX_KNOWN) == 0 || prefixS != 0xE4) { prefixSFlag = PREFIX_KNOWN_DIRTY; @@ -98,12 +111,19 @@ struct JitState prefixTFlag = PREFIX_KNOWN_DIRTY; prefixT = 0xE4; } - if ((prefixDFlag & PREFIX_KNOWN) == 0 || prefixD != 0x0 || writeMask[0] || writeMask[1] || writeMask[2] || writeMask[3]) { + if ((prefixDFlag & PREFIX_KNOWN) == 0 || prefixD != 0x0 || VfpuWriteMask() != 0) { prefixDFlag = PREFIX_KNOWN_DIRTY; prefixD = 0x0; - writeMask[0] = writeMask[1] = writeMask[2] = writeMask[3] = false; } } + u8 VfpuWriteMask() const { + _assert_(prefixDFlag & JitState::PREFIX_KNOWN); + return (prefixD >> 8) & 0xF; + } + bool VfpuWriteMask(int i) const { + _assert_(prefixDFlag & JitState::PREFIX_KNOWN); + return (prefixD >> (8 + i)) & 1; + } }; enum CompileDelaySlotFlags @@ -122,6 +142,7 @@ class Jit : public Gen::XCodeBlock { public: Jit(MIPSState *mips); + void DoState(PointerWrap &p); // Compiled ops should ignore delay slots // the compiler will take care of them by itself @@ -172,7 +193,19 @@ public: void Comp_DoNothing(u32 op); void ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz); - void ApplyPrefixD(const u8 *vregs, u32 prefix, VectorSize sz, bool onlyWriteMask = false); + void ApplyPrefixD(const u8 *vregs, VectorSize sz); + void GetVectorRegsPrefixS(u8 *regs, VectorSize sz, int vectorReg) { + _assert_(js.prefixSFlag & JitState::PREFIX_KNOWN); + GetVectorRegs(regs, sz, vectorReg); + ApplyPrefixST(regs, js.prefixS, sz); + } + void GetVectorRegsPrefixT(u8 *regs, VectorSize sz, int vectorReg) { + _assert_(js.prefixTFlag & JitState::PREFIX_KNOWN); + GetVectorRegs(regs, sz, vectorReg); + ApplyPrefixST(regs, js.prefixT, sz); + } + void GetVectorRegsPrefixD(u8 *regs, VectorSize sz, int vectorReg); + void EatPrefix() { js.EatPrefix(); } JitBlockCache *GetBlockCache() { return &blocks; } AsmRoutineManager &Asm() { return asm_; } diff --git a/Core/MIPS/x86/RegCacheFPU.cpp b/Core/MIPS/x86/RegCacheFPU.cpp index dfec86c958..9256a6d8fa 100644 --- a/Core/MIPS/x86/RegCacheFPU.cpp +++ b/Core/MIPS/x86/RegCacheFPU.cpp @@ -21,6 +21,8 @@ #include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/x86/RegCacheFPU.h" +u32 FPURegCache::tempValues[NUM_TEMPS]; + FPURegCache::FPURegCache() : emit(0), mips(0) { memset(regs, 0, sizeof(regs)); memset(xregs, 0, sizeof(xregs)); @@ -37,6 +39,7 @@ void FPURegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats) { regs[i].location = GetDefaultLocation(i); regs[i].away = false; regs[i].locked = false; + regs[i].tempLocked = false; } } @@ -87,6 +90,8 @@ void FPURegCache::ReleaseSpillLock(int mipsreg) void FPURegCache::ReleaseSpillLocks() { for (int i = 0; i < NUM_MIPS_FPRS; i++) regs[i].locked = false; + for (int i = TEMP0; i < TEMP0 + NUM_TEMPS; ++i) + DiscardR(i); } void FPURegCache::BindToRegister(const int i, bool doLoad, bool makeDirty) { @@ -129,6 +134,39 @@ void FPURegCache::StoreFromRegister(int i) { } } +void FPURegCache::DiscardR(int i) { + _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "FPU can't handle imm yet."); + if (regs[i].away) { + X64Reg xr = regs[i].location.GetSimpleReg(); + _assert_msg_(DYNA_REC, xr < NUM_X_FPREGS, "DiscardR: MipsReg had bad X64Reg"); + // Note that we DO NOT write it back here. That's the whole point of Discard. + xregs[xr].dirty = false; + xregs[xr].mipsReg = -1; + regs[i].location = GetDefaultLocation(i); + regs[i].away = false; + regs[i].tempLocked = false; + } else { + // _assert_msg_(DYNA_REC,0,"already stored"); + regs[i].tempLocked = false; + } +} + +bool FPURegCache::IsTempX(X64Reg xr) { + return xregs[xr].mipsReg >= TEMP0; +} + +int FPURegCache::GetTempR() { + for (int r = TEMP0; r < TEMP0 + NUM_TEMPS; ++r) { + if (!regs[r].away && !regs[r].tempLocked) { + regs[r].tempLocked = true; + return r; + } + } + + _assert_msg_(DYNA_REC, 0, "Regcache ran out of temp regs, might need to DiscardR() some."); + return -1; +} + void FPURegCache::Flush() { for (int i = 0; i < NUM_MIPS_FPRS; i++) { if (regs[i].locked) { @@ -151,8 +189,10 @@ void FPURegCache::Flush() { OpArg FPURegCache::GetDefaultLocation(int reg) const { if (reg < 32) { return M(&mips->f[reg]); - } else { + } else if (reg < 32 + 128) { return M(&mips->v[reg - 32]); + } else { + return M(&tempValues[reg - 32 - 128]); } } @@ -208,7 +248,7 @@ X64Reg FPURegCache::GetFreeXReg() { return (X64Reg) -1; } -void FPURegCache::FlushR(X64Reg reg) { +void FPURegCache::FlushX(X64Reg reg) { if (reg >= NUM_X_FPREGS) PanicAlert("Flushing non existent reg"); if (xregs[reg].mipsReg != -1) { diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h index f1e4eab895..37d7c4c2e6 100644 --- a/Core/MIPS/x86/RegCacheFPU.h +++ b/Core/MIPS/x86/RegCacheFPU.h @@ -26,9 +26,17 @@ using namespace Gen; // GPRs are numbered 0 to 31 -// VFPU regs are numbered 32 to 160. +// VFPU regs are numbered 32 to 159. +// Then we have some temp regs for VFPU handling from 160 to 175. -#define NUM_MIPS_FPRS (32 + 128) +// Temp regs: 4 from S prefix, 4 from T prefix, 4 from D mask, and 4 for work (worst case.) +// But most of the time prefixes aren't used that heavily so we won't use all of them. + +enum { + NUM_TEMPS = 16, + TEMP0 = 32 + 128, + NUM_MIPS_FPRS = 32 + 128 + NUM_TEMPS, +}; #ifdef _M_X64 #define NUM_X_FPREGS 16 @@ -45,6 +53,8 @@ struct MIPSCachedFPReg { OpArg location; bool away; // value not in source register bool locked; + // Only for temp regs. + bool tempLocked; }; enum { @@ -68,6 +78,15 @@ public: StoreFromRegister(preg + 32); } OpArg GetDefaultLocation(int reg) const; + void DiscardR(int freg); + void DiscardV(int vreg) { + DiscardR(vreg + 32); + } + bool IsTempX(X64Reg xreg); + int GetTempR(); + int GetTempV() { + return GetTempR() - 32; + } void SetEmitter(XEmitter *emitter) {emit = emitter;} @@ -101,19 +120,28 @@ public: void MapRegV(int vreg, int flags); void MapRegsV(int vec, VectorSize vsz, int flags); void MapRegsV(const u8 *v, VectorSize vsz, int flags); + void SpillLockV(int vreg) { + SpillLock(vreg + 32); + } void SpillLockV(const u8 *v, VectorSize vsz); void SpillLockV(int vec, VectorSize vsz); + void ReleaseSpillLockV(int vreg) { + ReleaseSpillLock(vreg + 32); + } MIPSState *mips; private: X64Reg GetFreeXReg(); - void FlushR(X64Reg reg); + void FlushX(X64Reg reg); const int *GetAllocationOrder(int &count); MIPSCachedFPReg regs[NUM_MIPS_FPRS]; X64CachedFPReg xregs[NUM_X_FPREGS]; MIPSCachedFPReg *vregs; + // TEMP0, etc. are swapped in here if necessary (e.g. on x86.) + static u32 tempValues[NUM_TEMPS]; + XEmitter *emit; }; diff --git a/Core/MemMap.h b/Core/MemMap.h index bf77692018..a7731d839f 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -36,9 +36,9 @@ #if defined(_DEBUG) //#define SAFE_MEMORY #endif -// Required for UNUSABLE_MMAP. Can define this in cmake instead later + #ifdef __SYMBIAN32__ -#define SAFE_MEMORY +//#define SAFE_MEMORY #endif diff --git a/Core/MemMapFunctions.cpp b/Core/MemMapFunctions.cpp index ee2370c0da..d174cdb7e1 100644 --- a/Core/MemMapFunctions.cpp +++ b/Core/MemMapFunctions.cpp @@ -83,7 +83,7 @@ inline void ReadFromHardware(T &var, const u32 address) } else { - if (g_Config.iCpuCore == CPU_JIT) { + if (g_Config.bJit) { WARN_LOG(MEMMAP, "ReadFromHardware: Invalid address %08x", address); } else { WARN_LOG(MEMMAP, "ReadFromHardware: Invalid address %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); @@ -115,7 +115,7 @@ inline void WriteToHardware(u32 address, const T data) } else { - if (g_Config.iCpuCore == CPU_JIT) { + if (g_Config.bJit) { WARN_LOG(MEMMAP, "WriteToHardware: Invalid address %08x", address); } else { WARN_LOG(MEMMAP, "WriteToHardware: Invalid address %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index 039fc97910..cde737fedd 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -38,7 +38,7 @@ extern u32 curTextureWidth; extern u32 curTextureHeight; -static const int flushOnChangedBeforeCommandList[] = { +static const u8 flushOnChangedBeforeCommandList[] = { GE_CMD_VERTEXTYPE, GE_CMD_BLENDMODE, GE_CMD_BLENDFIXEDA, @@ -137,7 +137,7 @@ static const int flushOnChangedBeforeCommandList[] = { GE_CMD_ZBUFWIDTH, }; -static const int flushBeforeCommandList[] = { +static const u8 flushBeforeCommandList[] = { GE_CMD_BEZIER, GE_CMD_SPLINE, GE_CMD_SIGNAL, @@ -330,6 +330,9 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_PRIM: { + if (gstate_c.skipDrawReason) + return; + framebufferManager_.SetRenderFrameBuffer(); u32 count = data & 0xFFFF; @@ -1056,6 +1059,11 @@ void GLES_GPU::Resized() { framebufferManager_.Resized(); } +std::vector GLES_GPU::GetFramebufferList() +{ + return framebufferManager_.GetFramebufferList(); +} + void GLES_GPU::DoState(PointerWrap &p) { GPUCommon::DoState(p); diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index 7054f60e14..048aab400b 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -59,6 +59,12 @@ public: // Called by the window system if the window size changed. This will be reflected in PSPCoreParam.pixel*. virtual void Resized(); + virtual bool DecodeTexture(u8* dest, GPUgstate state) + { + return textureCache_.DecodeTexture(dest, state); + } + + std::vector GetFramebufferList(); private: void DoBlockTransfer(); diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 9d7dcf1367..1a994f8c01 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -326,12 +326,12 @@ void FramebufferManager::SetRenderFrameBuffer() { vfb->renderHeight = (u16)(drawing_height * renderHeightFactor); vfb->format = fmt; - vfb->colorDepth = FBO_8888; switch (fmt) { - case GE_FORMAT_4444: vfb->colorDepth = FBO_4444; - case GE_FORMAT_5551: vfb->colorDepth = FBO_5551; - case GE_FORMAT_565: vfb->colorDepth = FBO_565; - case GE_FORMAT_8888: vfb->colorDepth = FBO_8888; + case GE_FORMAT_4444: vfb->colorDepth = FBO_4444; break; + case GE_FORMAT_5551: vfb->colorDepth = FBO_5551; break; + case GE_FORMAT_565: vfb->colorDepth = FBO_565; break; + case GE_FORMAT_8888: vfb->colorDepth = FBO_8888; break; + default: vfb->colorDepth = FBO_8888; break; } //#ifdef ANDROID // vfb->colorDepth = FBO_8888; @@ -448,6 +448,26 @@ void FramebufferManager::SetDisplayFramebuffer(u32 framebuf, u32 stride, int for } } +std::vector FramebufferManager::GetFramebufferList() +{ + std::vector list; + + for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) { + VirtualFramebuffer *vfb = *iter; + + FramebufferInfo info; + info.fb_address = vfb->fb_address; + info.z_address = vfb->z_address; + info.format = vfb->format; + info.width = vfb->width; + info.height = vfb->height; + info.fbo = vfb->fbo; + list.push_back(info); + } + + return list; +} + void FramebufferManager::DecimateFBOs() { for (auto iter = vfbs_.begin(); iter != vfbs_.end();) { VirtualFramebuffer *vfb = *iter; diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index dd7dcee56a..c5a86426c9 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -26,6 +26,7 @@ #include "../Globals.h" +#include "GPU/GPUCommon.h" struct GLSLProgram; class TextureCache; @@ -80,6 +81,8 @@ public: void SetDisplayFramebuffer(u32 framebuf, u32 stride, int format); size_t NumVFBs() const { return vfbs_.size(); } + std::vector GetFramebufferList(); + int GetRenderWidth() const { return currentRenderVfb_ ? currentRenderVfb_->renderWidth : 480; } int GetRenderHeight() const { return currentRenderVfb_ ? currentRenderVfb_->renderHeight : 272; } int GetTargetWidth() const { return currentRenderVfb_ ? currentRenderVfb_->width : 480; } diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 4b964a274e..96ccc7768b 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -684,6 +684,8 @@ void TextureCache::SetTexture() { clutformat = gstate.clutformat & 3; clutaddr = GetClutAddr(clutformat == GE_CMODE_32BIT_ABGR8888 ? 4 : 2); cachekey |= (u64)clutaddr << 32; + } else { + clutaddr = 0; } int maxLevel = ((gstate.texmode >> 16) & 0x7); @@ -725,7 +727,7 @@ void TextureCache::SetTexture() { entry->hash != texhash || entry->format != format || entry->maxLevel != maxLevel || - ((format >= GE_TFMT_CLUT4 && format <= GE_TFMT_CLUT32) && + (hasClut && (entry->clutformat != clutformat || entry->clutaddr != clutaddr || entry->cluthash != Memory::Read_U32(entry->clutaddr)))) @@ -810,9 +812,9 @@ void TextureCache::SetTexture() { entry->lodBias = 0.0f; - if (format >= GE_TFMT_CLUT4 && format <= GE_TFMT_CLUT32) { + if (hasClut) { entry->clutformat = clutformat; - entry->clutaddr = GetClutAddr(clutformat == GE_CMODE_32BIT_ABGR8888 ? 4 : 2); + entry->clutaddr = clutaddr; entry->cluthash = Memory::Read_U32(entry->clutaddr); } else { entry->clutaddr = 0; @@ -1131,3 +1133,289 @@ void TextureCache::LoadTextureLevel(TexCacheEntry &entry, int level) GLuint components = dstFmt == GL_UNSIGNED_SHORT_5_6_5 ? GL_RGB : GL_RGBA; glTexImage2D(GL_TEXTURE_2D, level, components, w, h, 0, components, dstFmt, finalBuf); } + +bool TextureCache::DecodeTexture(u8* output, GPUgstate state) +{ + GPUgstate oldState = gstate; + gstate = state; + + u32 texaddr = (gstate.texaddr[0] & 0xFFFFF0) | ((gstate.texbufwidth[0]<<8) & 0x0F000000); + + if (!Memory::IsValidAddress(texaddr)) { + return false; + } + + u8 level = 0; + u32 format = gstate.texformat & 0xF; + if (format >= 11) { + ERROR_LOG(G3D, "Unknown texture format %i", format); + format = 0; + } + + u32 clutformat = gstate.clutformat & 3; + u32 clutaddr = GetClutAddr(clutformat == GE_CMODE_32BIT_ABGR8888 ? 4 : 2); + + const u8 *texptr = Memory::GetPointer(texaddr); + u32 texhash = texptr ? MiniHash((const u32*)texptr) : 0; + + u64 cachekey = texaddr ^ texhash; + if (formatUsesClut[format]) + cachekey |= (u64) clutaddr << 32; + + int bufw = gstate.texbufwidth[0] & 0x3ff; + + int w = 1 << (gstate.texsize[0] & 0xf); + int h = 1 << ((gstate.texsize[0]>>8) & 0xf); + + + GLenum dstFmt = 0; + u32 texByteAlign = 1; + + void *finalBuf = NULL; + + // TODO: Look into using BGRA for 32-bit textures when the GL_EXT_texture_format_BGRA8888 extension is available, as it's faster than RGBA on some chips. + + switch (format) + { + case GE_TFMT_CLUT4: + dstFmt = getClutDestFormat((GEPaletteFormat)(gstate.clutformat & 3)); + + switch (clutformat) { + case GE_CMODE_16BIT_BGR5650: + case GE_CMODE_16BIT_ABGR5551: + case GE_CMODE_16BIT_ABGR4444: + { + ReadClut16(clutBuf16); + const u16 *clut = clutBuf16; + u32 clutSharingOff = 0;//gstate.mipmapShareClut ? 0 : level * 16; + texByteAlign = 2; + if (!(gstate.texmode & 1)) { + const u8 *addr = Memory::GetPointer(texaddr); + for (int i = 0; i < bufw * h; i += 2) + { + u8 index = *addr++; + tmpTexBuf16[i + 0] = clut[GetClutIndex((index >> 0) & 0xf) + clutSharingOff]; + tmpTexBuf16[i + 1] = clut[GetClutIndex((index >> 4) & 0xf) + clutSharingOff]; + } + } else { + UnswizzleFromMem(texaddr, 0, level); + for (int i = 0, j = 0; i < bufw * h; i += 8, j++) + { + u32 n = tmpTexBuf32[j]; + u32 k, index; + for (k = 0; k < 8; k++) { + index = (n >> (k * 4)) & 0xf; + tmpTexBuf16[i + k] = clut[GetClutIndex(index) + clutSharingOff]; + } + } + } + finalBuf = tmpTexBuf16; + } + break; + + case GE_CMODE_32BIT_ABGR8888: + { + ReadClut32(clutBuf32); + const u32 *clut = clutBuf32; + u32 clutSharingOff = 0;//gstate.mipmapShareClut ? 0 : level * 16; + if (!(gstate.texmode & 1)) { + const u8 *addr = Memory::GetPointer(texaddr); + for (int i = 0; i < bufw * h; i += 2) + { + u8 index = *addr++; + tmpTexBuf32[i + 0] = clut[GetClutIndex((index >> 0) & 0xf) + clutSharingOff]; + tmpTexBuf32[i + 1] = clut[GetClutIndex((index >> 4) & 0xf) + clutSharingOff]; + } + } else { + u32 pixels = bufw * h; + UnswizzleFromMem(texaddr, 0, level); + for (int i = pixels - 8, j = (pixels / 8) - 1; i >= 0; i -= 8, j--) { + u32 n = tmpTexBuf32[j]; + for (int k = 0; k < 8; k++) { + u32 index = (n >> (k * 4)) & 0xf; + tmpTexBuf32[i + k] = clut[GetClutIndex(index) + clutSharingOff]; + } + } + } + finalBuf = tmpTexBuf32; + } + break; + + default: + ERROR_LOG(G3D, "Unknown CLUT4 texture mode %d", (gstate.clutformat & 3)); + return false; + } + break; + + case GE_TFMT_CLUT8: + finalBuf = readIndexedTex(level, texaddr, 1); + dstFmt = getClutDestFormat((GEPaletteFormat)(gstate.clutformat & 3)); + texByteAlign = texByteAlignMap[(gstate.clutformat & 3)]; + break; + + case GE_TFMT_CLUT16: + finalBuf = readIndexedTex(level, texaddr, 2); + dstFmt = getClutDestFormat((GEPaletteFormat)(gstate.clutformat & 3)); + texByteAlign = texByteAlignMap[(gstate.clutformat & 3)]; + break; + + case GE_TFMT_CLUT32: + finalBuf = readIndexedTex(level, texaddr, 4); + dstFmt = getClutDestFormat((GEPaletteFormat)(gstate.clutformat & 3)); + texByteAlign = texByteAlignMap[(gstate.clutformat & 3)]; + break; + + case GE_TFMT_4444: + case GE_TFMT_5551: + case GE_TFMT_5650: + if (format == GE_TFMT_4444) + dstFmt = GL_UNSIGNED_SHORT_4_4_4_4; + else if (format == GE_TFMT_5551) + dstFmt = GL_UNSIGNED_SHORT_5_5_5_1; + else if (format == GE_TFMT_5650) + dstFmt = GL_UNSIGNED_SHORT_5_6_5; + texByteAlign = 2; + + if (!(gstate.texmode & 1)) { + int len = std::max(bufw, w) * h; + for (int i = 0; i < len; i++) + tmpTexBuf16[i] = Memory::ReadUnchecked_U16(texaddr + i * 2); + finalBuf = tmpTexBuf16; + } + else + finalBuf = UnswizzleFromMem(texaddr, 2, level); + break; + + case GE_TFMT_8888: + dstFmt = GL_UNSIGNED_BYTE; + if (!(gstate.texmode & 1)) { + int len = bufw * h; + for (int i = 0; i < len; i++) + tmpTexBuf32[i] = Memory::ReadUnchecked_U32(texaddr + i * 4); + finalBuf = tmpTexBuf32; + } + else + finalBuf = UnswizzleFromMem(texaddr, 4, level); + break; + + case GE_TFMT_DXT1: + dstFmt = GL_UNSIGNED_BYTE; + { + u32 *dst = tmpTexBuf32; + DXT1Block *src = (DXT1Block*)texptr; + + for (int y = 0; y < h; y += 4) { + u32 blockIndex = (y / 4) * (bufw / 4); + for (int x = 0; x < std::min(bufw, w); x += 4) { + decodeDXT1Block(dst + bufw * y + x, src + blockIndex, bufw); + blockIndex++; + } + } + finalBuf = tmpTexBuf32; + w = (w + 3) & ~3; + } + break; + + case GE_TFMT_DXT3: + dstFmt = GL_UNSIGNED_BYTE; + { + u32 *dst = tmpTexBuf32; + DXT3Block *src = (DXT3Block*)texptr; + + // Alpha is off + for (int y = 0; y < h; y += 4) { + u32 blockIndex = (y / 4) * (bufw / 4); + for (int x = 0; x < std::min(bufw, w); x += 4) { + decodeDXT3Block(dst + bufw * y + x, src + blockIndex, bufw); + blockIndex++; + } + } + w = (w + 3) & ~3; + finalBuf = tmpTexBuf32; + } + break; + + case GE_TFMT_DXT5: + ERROR_LOG(G3D, "Unhandled compressed texture, format %i! swizzle=%i", format, gstate.texmode & 1); + dstFmt = GL_UNSIGNED_BYTE; + { + u32 *dst = tmpTexBuf32; + DXT5Block *src = (DXT5Block*)texptr; + + // Alpha is almost right + for (int y = 0; y < h; y += 4) { + u32 blockIndex = (y / 4) * (bufw / 4); + for (int x = 0; x < std::min(bufw, w); x += 4) { + decodeDXT5Block(dst + bufw * y + x, src + blockIndex, bufw); + blockIndex++; + } + } + w = (w + 3) & ~3; + finalBuf = tmpTexBuf32; + } + break; + + default: + ERROR_LOG(G3D, "Unknown Texture Format %d!!!", format); + finalBuf = tmpTexBuf32; + return false; + } + + if (!finalBuf) { + ERROR_LOG(G3D, "NO finalbuf! Will crash!"); + } + + convertColors((u8*)finalBuf, dstFmt, bufw * h); + + if(dstFmt == GL_UNSIGNED_SHORT_4_4_4_4) + { + for(int x = 0; x < h; x++) + for(int y = 0; y < bufw; y++) + { + u32 val = ((u16*)finalBuf)[x*bufw + y]; + u32 a = (val & 0xF) * 255 / 15; + u32 r = ((val & 0xF) >> 24) * 255 / 15; + u32 g = ((val & 0xF) >> 16) * 255 / 15; + u32 b = ((val & 0xF) >> 8) * 255 / 15; + ((u32*)output)[x*w + y] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + else if(dstFmt == GL_UNSIGNED_SHORT_5_5_5_1) + { + for(int x = 0; x < h; x++) + for(int y = 0; y < bufw; y++) + { + u32 val = ((u16*)finalBuf)[x*bufw + y]; + u32 a = (val & 0x1) * 255; + u32 r = ((val & 0x1F) >> 11) * 255 / 31; + u32 g = ((val & 0x1F) >> 6) * 255 / 31; + u32 b = ((val & 0x1F) >> 1) * 255 / 31; + ((u32*)output)[x*w + y] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + else if(dstFmt == GL_UNSIGNED_SHORT_5_6_5) + { + for(int x = 0; x < h; x++) + for(int y = 0; y < bufw; y++) + { + u32 val = ((u16*)finalBuf)[x*bufw + y]; + u32 a = 0xFF; + u32 r = ((val & 0x1F) >> 11) * 255 / 31; + u32 g = ((val & 0x3F) >> 6) * 255 / 63; + u32 b = ((val & 0x1F)) * 255 / 31; + ((u32*)output)[x*w + y] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + else + { + for(int x = 0; x < h; x++) + for(int y = 0; y < bufw; y++) + { + u32 val = ((u32*)finalBuf)[x*bufw + y]; + ((u32*)output)[x*w + y] = ((val & 0xFF000000)) | ((val & 0x00FF0000)>>16) | ((val & 0x0000FF00)) | ((val & 0x000000FF)<<16); + } + } + + gstate = oldState; + return true; +} diff --git a/GPU/GLES/TextureCache.h b/GPU/GLES/TextureCache.h index bb1958c365..65c64b4eb3 100644 --- a/GPU/GLES/TextureCache.h +++ b/GPU/GLES/TextureCache.h @@ -19,6 +19,7 @@ #include "../Globals.h" #include "gfx_es2/fbo.h" +#include "GPU/GPUState.h" class TextureCache { @@ -42,6 +43,7 @@ public: return cache.size(); } + bool DecodeTexture(u8 *output, GPUgstate state); private: struct TexCacheEntry { @@ -64,8 +66,8 @@ private: int numFrames; u32 framesUntilNextFullHash; u8 format; - u8 clutformat; u16 dim; + u8 clutformat; u32 clutaddr; u32 cluthash; u32 texture; //GLuint @@ -100,7 +102,7 @@ private: u32 *clutBuf32; u16 *clutBuf16; - int lastBoundTexture; + u32 lastBoundTexture; float maxAnisotropyLevel; }; diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index 85fa40b631..72b2066c57 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -53,12 +53,14 @@ enum { }; TransformDrawEngine::TransformDrawEngine() - : numDrawCalls(0), - collectedVerts(0), + : collectedVerts(0), prevPrim_(-1), lastVType_(-1), curVbo_(0), - shaderManager_(0) { + shaderManager_(0), + textureCache_(0), + framebufferManager_(0), + numDrawCalls(0) { // Allocate nicely aligned memory. Maybe graphics drivers will // appreciate it. // All this is a LOT of memory, need to see if we can cut down somehow. diff --git a/GPU/GLES/VertexDecoder.cpp b/GPU/GLES/VertexDecoder.cpp index 6e68bdec48..75614f67ea 100644 --- a/GPU/GLES/VertexDecoder.cpp +++ b/GPU/GLES/VertexDecoder.cpp @@ -197,7 +197,7 @@ void VertexDecoder::Step_Color5551() const c[0] = Convert5To8(cdata & 0x1f); c[1] = Convert5To8((cdata>>5) & 0x1f); c[2] = Convert5To8((cdata>>10) & 0x1f); - c[3] = (cdata>>15) ? 255 : 0; + c[3] = (cdata>>15) ? 255.0f : 0.0f; } void VertexDecoder::Step_Color4444() const @@ -222,15 +222,15 @@ void VertexDecoder::Step_Color565Morph() const { float w = gstate_c.morphWeights[n]; u16 cdata = *(u16*)(ptr_ + onesize_*n + coloff); - col[0] += w * (cdata & 0x1f) / 31.f; - col[1] += w * ((cdata>>5) & 0x3f) / 63.f; - col[2] += w * ((cdata>>11) & 0x1f) / 31.f; + col[0] += w * (cdata & 0x1f) / 31.0f; + col[1] += w * ((cdata>>5) & 0x3f) / 63.0f; + col[2] += w * ((cdata>>11) & 0x1f) / 31.0f; } u8 *c = decoded_ + decFmt.c0off; for (int i = 0; i < 3; i++) { c[i] = (u8)(col[i] * 255.0f); } - c[3] = 255; + c[3] = 255.0f; } void VertexDecoder::Step_Color5551Morph() const @@ -240,9 +240,9 @@ void VertexDecoder::Step_Color5551Morph() const { float w = gstate_c.morphWeights[n]; u16 cdata = *(u16*)(ptr_ + onesize_*n + coloff); - col[0] += w * (cdata & 0x1f) / 31.f; - col[1] += w * ((cdata>>5) & 0x1f) / 31.f; - col[2] += w * ((cdata>>10) & 0x1f) / 31.f; + col[0] += w * (cdata & 0x1f) / 31.0f; + col[1] += w * ((cdata>>5) & 0x1f) / 31.0f; + col[2] += w * ((cdata>>10) & 0x1f) / 31.0f; col[3] += w * ((cdata>>15) ? 1.0f : 0.0f); } u8 *c = decoded_ + decFmt.c0off; @@ -259,7 +259,7 @@ void VertexDecoder::Step_Color4444Morph() const float w = gstate_c.morphWeights[n]; u16 cdata = *(u16*)(ptr_ + onesize_*n + coloff); for (int j = 0; j < 4; j++) - col[j] += w * ((cdata >> (j * 4)) & 0xF) / 15.f; + col[j] += w * ((cdata >> (j * 4)) & 0xF) / 15.0f; } u8 *c = decoded_ + decFmt.c0off; for (int i = 0; i < 4; i++) { @@ -346,7 +346,7 @@ void VertexDecoder::Step_NormalS16Morph() const multiplier = -multiplier; } const s16 *sv = (const s16 *)(ptr_ + onesize_*n + nrmoff); - multiplier *= (1.0f/32767.f); + multiplier *= (1.0f/32767.0f); for (int j = 0; j < 3; j++) normal[j] += sv[j] * multiplier; } diff --git a/GPU/GLES/VertexDecoder.h b/GPU/GLES/VertexDecoder.h index 0be7140f13..243983c5ac 100644 --- a/GPU/GLES/VertexDecoder.h +++ b/GPU/GLES/VertexDecoder.h @@ -239,23 +239,29 @@ public: } void ReadUV(float uv[2]) { - const u8 *b = (const u8 *)(data_ + decFmt_.uvoff); - const u16 *s = (const u16 *)(data_ + decFmt_.uvoff); - const float *f = (const float *)(data_ + decFmt_.uvoff); switch (decFmt_.uvfmt) { case DEC_U8_2: - uv[0] = b[0] * (1.f / 128.f); - uv[1] = b[1] * (1.f / 128.f); + { + const u8 *b = (const u8 *)(data_ + decFmt_.uvoff); + uv[0] = b[0] * (1.f / 128.f); + uv[1] = b[1] * (1.f / 128.f); + } break; case DEC_U16_2: - uv[0] = s[0] * (1.f / 32768.f); - uv[1] = s[1] * (1.f / 32768.f); + { + const u16 *s = (const u16 *)(data_ + decFmt_.uvoff); + uv[0] = s[0] * (1.f / 32768.f); + uv[1] = s[1] * (1.f / 32768.f); + } break; case DEC_FLOAT_2: - uv[0] = f[0] * 2.0f; - uv[1] = f[1] * 2.0f; + { + const float *f = (const float *)(data_ + decFmt_.uvoff); + uv[0] = f[0] * 2.0f; + uv[1] = f[1] * 2.0f; + } break; case DEC_U16A_2: diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d41ab94ab2..8d710972ff 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -76,6 +76,12 @@ bool GPUCommon::InterpretList(DisplayList &list) ERROR_LOG(G3D, "DL PC = %08x WTF!!!!", list.pc); return true; } +#if defined(USING_QT_UI) + if(host->GpuStep()) + { + host->SendGPUStart(); + } +#endif while (!finished) { @@ -85,14 +91,16 @@ bool GPUCommon::InterpretList(DisplayList &list) list.status = PSP_GE_LIST_STALL_REACHED; return false; } + + op = Memory::ReadUnchecked_U32(list.pc); //read from memory + u32 cmd = op >> 24; + #if defined(USING_QT_UI) if(host->GpuStep()) { - host->SendGPUWait(); + host->SendGPUWait(cmd, list.pc, &gstate); } #endif - op = Memory::ReadUnchecked_U32(list.pc); //read from memory - u32 cmd = op >> 24; u32 diff = op ^ gstate.cmdmem[cmd]; PreExecuteOp(op, diff); // TODO: Add a compiler flag to remove stuff like this at very-final build time. diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 66b6ccbdd8..8feb9cb569 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -62,4 +62,13 @@ public: { return currentList; } + virtual bool DecodeTexture(u8* dest, GPUgstate state) + { + return false; + } + std::vector GetFramebufferList() + { + return std::vector(); + } + }; diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 07886c4e30..4edb5de1c5 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -18,6 +18,7 @@ #pragma once #include "../Globals.h" +#include "GPUState.h" #include class PointerWrap; @@ -32,6 +33,18 @@ enum DisplayListStatus PSP_GE_LIST_CANCEL_DONE = 5, // canceled? }; + +// Used for debug +struct FramebufferInfo +{ + u32 fb_address; + u32 z_address; + int format; + u32 width; + u32 height; + void* fbo; +}; + struct DisplayList { int id; @@ -94,4 +107,6 @@ public: virtual void DumpNextFrame() = 0; virtual const std::deque& GetDisplayLists() = 0; virtual DisplayList* GetCurrentDisplayList() = 0; + virtual bool DecodeTexture(u8* dest, GPUgstate state) = 0; + virtual std::vector GetFramebufferList() = 0; }; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index ca036b2506..8f12c7d045 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -224,7 +224,11 @@ struct GPUgstate // Real data in the context ends here }; - + +enum SkipDrawReasonFlags { + SKIPDRAW_SKIPFRAME = 1, +}; + // The rest is cached simplified/converted data for fast access. // Does not need to be saved when saving/restoring context. struct GPUStateCache @@ -236,6 +240,8 @@ struct GPUStateCache bool textureChanged; + int skipDrawReason; + float uScale,vScale; float uOff,vOff; bool flipTexture; diff --git a/Qt/EmuThread.cpp b/Qt/EmuThread.cpp index 44c3fc6366..4dd3a64570 100644 --- a/Qt/EmuThread.cpp +++ b/Qt/EmuThread.cpp @@ -152,7 +152,7 @@ void EmuThread::run() host->UpdateUI(); host->InitGL(); - glWindow->makeCurrent(); + EmuThread_LockDraw(true); #ifndef USING_GLES2 glewInit(); @@ -163,6 +163,8 @@ void EmuThread::run() QElapsedTimer timer; + EmuThread_LockDraw(false); + while(running) { //UpdateGamepad(*input_state); timer.start(); @@ -173,10 +175,7 @@ void EmuThread::run() if(gRun) { - - gameMutex->lock(); - - glWindow->makeCurrent(); + EmuThread_LockDraw(true); if(needInitGame) { g_State.bEmuThreadStarted = true; @@ -185,7 +184,7 @@ void EmuThread::run() coreParameter.fileToStart = fileToStart.toStdString(); coreParameter.enableSound = true; coreParameter.gpuCore = GPU_GLES; - coreParameter.cpuCore = (CPUCore)g_Config.iCpuCore; + coreParameter.cpuCore = g_Config.bJit ? CPU_JIT : CPU_INTERPRETER; coreParameter.enableDebugging = true; coreParameter.printfEmuLog = false; coreParameter.headLess = false; @@ -219,19 +218,6 @@ void EmuThread::run() host->BootDone(); needInitGame = false; } - UpdateInputState(input_state); - - for (int i = 0; i < controllistCount; i++) { - if (input_state->pad_buttons_down & controllist[i].emu_id) { - __CtrlButtonDown(controllist[i].psp_id); - } - if (input_state->pad_buttons_up & controllist[i].emu_id) { - __CtrlButtonUp(controllist[i].psp_id); - } - } - __CtrlSetAnalog(input_state->pad_lstick_x, input_state->pad_lstick_y); - - EndInputState(input_state); glstate.Restore(); glViewport(0, 0, pixel_xres, pixel_yres); @@ -252,14 +238,12 @@ void EmuThread::run() qint64 time = timer.elapsed(); const int frameTime = (1.0f/60.0f) * 1000; - gameMutex->unlock(); if(time < frameTime) { - glWindow->doneCurrent(); + EmuThread_LockDraw(false); msleep(frameTime-time); - glWindow->makeCurrent(); + EmuThread_LockDraw(true); } - gameMutex->lock(); timer.start(); } @@ -289,13 +273,11 @@ void EmuThread::run() } #endif glWindow->swapBuffers(); - glWindow->doneCurrent(); - gameMutex->unlock(); + EmuThread_LockDraw(false); } else { - gameMutex->lock(); - glWindow->makeCurrent(); + EmuThread_LockDraw(true); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -336,8 +318,7 @@ void EmuThread::run() ui_draw2d.Flush(UIShader_Get()); glWindow->swapBuffers(); - glWindow->doneCurrent(); - gameMutex->unlock(); + EmuThread_LockDraw(false); qint64 time = timer.elapsed(); const int frameTime = (1.0f/60.0f) * 1000; if(time < frameTime) diff --git a/Qt/QtHost.cpp b/Qt/QtHost.cpp index 78cc696698..4295edf126 100644 --- a/Qt/QtHost.cpp +++ b/Qt/QtHost.cpp @@ -12,6 +12,7 @@ #include "android/jni/EmuScreen.h" #include "android/jni/UIShader.h" #include "android/jni/ui_atlas.h" +#include "GPU/ge_constants.h" #include "EmuThread.h" std::string boot_filename = ""; @@ -27,6 +28,7 @@ recursive_mutex m_hGPUStepMutex; QtHost::QtHost(MainWindow *mainWindow_) : mainWindow(mainWindow_) , m_GPUStep(false) + , m_GPUFlag(0) { QObject::connect(this,SIGNAL(BootDoneSignal()),mainWindow,SLOT(Boot())); } @@ -48,7 +50,6 @@ void QtHost::SetWindowTitle(const char *message) void QtHost::UpdateUI() { - mainWindow->Update(); mainWindow->UpdateMenus(); } @@ -66,6 +67,10 @@ void QtHost::UpdateDisassembly() mainWindow->GetDialogDisasm()->GotoPC(); mainWindow->GetDialogDisasm()->Update(); } + if(mainWindow->GetDialogDisplaylist()) + { + mainWindow->GetDialogDisplaylist()->Update(); + } } void QtHost::SetDebugMode(bool mode) @@ -77,7 +82,9 @@ void QtHost::SetDebugMode(bool mode) void QtHost::BeginFrame() { + mainWindow->Update(); } + void QtHost::EndFrame() { } @@ -144,19 +151,59 @@ bool QtHost::GpuStep() return m_GPUStep; } -void QtHost::SendGPUWait() +void QtHost::SendGPUStart() { EmuThread_LockDraw(false); - mainWindow->GetDialogDisasm()->UpdateDisplayList(); - m_hGPUStepEvent.wait(m_hGPUStepMutex); + if(m_GPUFlag == -1) + { + m_GPUFlag = 0; + } EmuThread_LockDraw(true); } -void QtHost::SetGPUStep(bool value) +void QtHost::SendGPUWait(u32 cmd, u32 addr, void *data) +{ + EmuThread_LockDraw(false); + + if((m_GPUFlag == 1 && (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE))) + { + // Break after the draw + m_GPUFlag = 0; + } + else if(m_GPUFlag == 0) + { + mainWindow->GetDialogDisasm()->UpdateDisplayList(); + mainWindow->GetDialogDisplaylist()->Update(); + m_hGPUStepEvent.wait(m_hGPUStepMutex); + } + else if(m_GPUFlag == 2 && addr == m_GPUData) + { + mainWindow->GetDialogDisasm()->UpdateDisplayList(); + mainWindow->GetDialogDisplaylist()->Update(); + m_hGPUStepEvent.wait(m_hGPUStepMutex); + } + else if(m_GPUFlag == 3 && (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE)) + { + GPUgstate *state = (GPUgstate*)data; + u32 texAddr = (state->texaddr[0] & 0xFFFFF0) | ((state->texbufwidth[0]<<8) & 0x0F000000); + if(texAddr == m_GPUData) + { + mainWindow->GetDialogDisasm()->UpdateDisplayList(); + mainWindow->GetDialogDisplaylist()->Update(); + m_hGPUStepEvent.wait(m_hGPUStepMutex); + } + } + + EmuThread_LockDraw(true); +} + +void QtHost::SetGPUStep(bool value, int flag, int data) { m_GPUStep = value; + m_GPUFlag = flag; + m_GPUData = data; } void QtHost::NextGPUStep() diff --git a/Qt/QtHost.h b/Qt/QtHost.h index b98ec8954e..3e9305694d 100644 --- a/Qt/QtHost.h +++ b/Qt/QtHost.h @@ -51,8 +51,9 @@ public: void SendCoreWait(bool); bool GpuStep(); - void SendGPUWait(); - void SetGPUStep(bool value); + void SendGPUWait(u32 cmd, u32 addr, void* data); + void SendGPUStart(); + void SetGPUStep(bool value, int flag = 0, int data = 0); void NextGPUStep(); signals: @@ -60,6 +61,8 @@ signals: private: MainWindow* mainWindow; bool m_GPUStep; + int m_GPUFlag; + int m_GPUData; }; #endif // QTAPP_H diff --git a/Qt/ctrldisasmview.cpp b/Qt/ctrldisasmview.cpp index a2b7a00829..92d43f8e51 100644 --- a/Qt/ctrldisasmview.cpp +++ b/Qt/ctrldisasmview.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -164,9 +163,7 @@ void CtrlDisAsmView::GoToMemoryView() void CtrlDisAsmView::CopyAddress() { - char temp[16]; - sprintf(temp,"%08x",selection); - QApplication::clipboard()->setText(QString(temp)); + QApplication::clipboard()->setText(QString("%1").arg(selection,8,16,QChar('0'))); } void CtrlDisAsmView::CopyInstrDisAsm() @@ -178,11 +175,9 @@ void CtrlDisAsmView::CopyInstrDisAsm() void CtrlDisAsmView::CopyInstrHex() { - char temp[24]; EmuThread_LockDraw(true); - sprintf(temp,"%08x",debugger->readMemory(selection)); + QApplication::clipboard()->setText(QString("%1").arg(debugger->readMemory(selection),8,16,QChar('0'))); EmuThread_LockDraw(false); - QApplication::clipboard()->setText(temp); } void CtrlDisAsmView::SetNextStatement() @@ -234,8 +229,7 @@ void CtrlDisAsmView::RenameFunction() int sym = symbolMap.GetSymbolNum(selection); if (sym != -1) { - char name[256]; - strncpy(name, symbolMap.GetSymbolName(sym),256); + QString name = symbolMap.GetSymbolName(sym); bool ok; QString newname = QInputDialog::getText(this, tr("New function name"), tr("New function name:"), QLineEdit::Normal, @@ -300,8 +294,6 @@ void CtrlDisAsmView::paintEvent(QPaintEvent *) int rowY1 = rect().bottom()/2 + rowHeight*i - rowHeight/2; int rowY2 = rect().bottom()/2 + rowHeight*i + rowHeight/2 - 1; - char temp[256]; - sprintf(temp,"%08x",address); lbr.setColor(marker==address?QColor(0xFFFFEEE0):QColor(debugger->getColor(address))); QColor bg = lbr.color(); @@ -319,7 +311,6 @@ void CtrlDisAsmView::paintEvent(QPaintEvent *) if (address == debugger->getPC()) { painter.setBrush(pcBrush); - qDebug() << address; } painter.drawRect(16,rowY1,width-16-1,rowY2-rowY1); @@ -327,7 +318,7 @@ void CtrlDisAsmView::paintEvent(QPaintEvent *) QPen textPen = QPen(QColor(halfAndHalf(bg.rgba(),0))); painter.setPen(textPen); painter.setFont(alignedFont); - painter.drawText(17,rowY1-3+rowHeight,QString(temp)); + painter.drawText(17,rowY1-3+rowHeight,QString("%1").arg(address,8,16,QChar('0'))); painter.setFont(normalFont); textPen.setColor(QColor(0xFF000000)); painter.setPen(textPen); diff --git a/Qt/ctrlmemview.cpp b/Qt/ctrlmemview.cpp index ffc768c48f..0ebaa97775 100644 --- a/Qt/ctrlmemview.cpp +++ b/Qt/ctrlmemview.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "EmuThread.h" #include "Core/MemMap.h" @@ -108,7 +109,6 @@ void CtrlMemView::paintEvent(QPaintEvent *) int rowY2 = rect().bottom()/2 + rowHeight*i + rowHeight/2; char temp[256]; - sprintf(temp,"%08x",address); painter.setBrush(currentBrush); @@ -123,7 +123,7 @@ void CtrlMemView::paintEvent(QPaintEvent *) textPen.setColor(0x600000); painter.setPen(textPen); painter.setFont(alignedFont); - painter.drawText(17,rowY1-2+rowHeight, temp); + painter.drawText(17,rowY1-2+rowHeight, QString("%1").arg(address,8,16,QChar('0'))); textPen.setColor(0xFF000000); painter.setPen(textPen); if (debugger->isAlive()) @@ -222,6 +222,10 @@ void CtrlMemView::contextMenu(const QPoint &pos) connect(copyValue, SIGNAL(triggered()), this, SLOT(CopyValue())); menu.addAction(copyValue); + QAction *changeValue = new QAction(tr("C&hange value"), this); + connect(changeValue, SIGNAL(triggered()), this, SLOT(Change())); + menu.addAction(changeValue); + QAction *dump = new QAction(tr("Dump..."), this); connect(dump, SIGNAL(triggered()), this, SLOT(Dump())); menu.addAction(dump); @@ -231,9 +235,9 @@ void CtrlMemView::contextMenu(const QPoint &pos) void CtrlMemView::CopyValue() { - char temp[24]; - sprintf(temp,"%08x",Memory::ReadUnchecked_U32(selection)); - QApplication::clipboard()->setText(temp); + EmuThread_LockDraw(true); + QApplication::clipboard()->setText(QString("%1").arg(Memory::ReadUnchecked_U32(selection),8,16,QChar('0'))); + EmuThread_LockDraw(false); } void CtrlMemView::Dump() @@ -241,6 +245,27 @@ void CtrlMemView::Dump() QMessageBox::information(this,"Sorry","This feature has not been implemented.",QMessageBox::Ok); } + +void CtrlMemView::Change() +{ + EmuThread_LockDraw(true); + QString curVal = QString("%1").arg(Memory::ReadUnchecked_U32(selection),8,16,QChar('0')); + EmuThread_LockDraw(false); + + bool ok; + QString text = QInputDialog::getText(this, tr("Set new value"), + tr("Set new value:"), QLineEdit::Normal, + curVal, &ok); + if (ok && !text.isEmpty()) + { + EmuThread_LockDraw(true); + Memory::WriteUnchecked_U32(text.toInt(0,16),selection); + EmuThread_LockDraw(false); + redraw(); + } +} + + int CtrlMemView::yToAddress(int y) { int ydiff=y-rect().bottom()/2-rowHeight/2; diff --git a/Qt/ctrlmemview.h b/Qt/ctrlmemview.h index 070b1af7f9..cc7f31c506 100644 --- a/Qt/ctrlmemview.h +++ b/Qt/ctrlmemview.h @@ -72,6 +72,7 @@ signals: public slots: void CopyValue(); void Dump(); + void Change(); private: int curAddress; int align; diff --git a/Qt/ctrlregisterlist.cpp b/Qt/ctrlregisterlist.cpp index 09fa91632f..a52c5c88ab 100644 --- a/Qt/ctrlregisterlist.cpp +++ b/Qt/ctrlregisterlist.cpp @@ -236,14 +236,14 @@ void CtrlRegisterList::paintEvent(QPaintEvent *) painter.setBrush(currentBrush); if (iGetNumRegsInCategory(category)) { - char temp[256]; - sprintf(temp,"%s",cpu->GetRegName(category,i)); + QString regName = cpu->GetRegName(category,i); textPen.setColor(0x600000); painter.setPen(textPen); - painter.drawText(17,rowY1-3+rowHeight,temp); + painter.drawText(17,rowY1-3+rowHeight,regName); textPen.setColor(0xFF000000); painter.setPen(textPen); + char temp[256]; cpu->PrintRegValue(category,i,temp); if (category == 0 && changedCat0Regs[i]) { @@ -331,10 +331,7 @@ void CtrlRegisterList::CopyValue() u32 val = cpu->GetRegValue(cat,reg); EmuThread_LockDraw(false); - char temp[24]; - sprintf(temp,"%08x",val); - - QApplication::clipboard()->setText(temp); + QApplication::clipboard()->setText(QString("%1").arg(val,8,16,QChar('0'))); } void CtrlRegisterList::Change() diff --git a/Qt/ctrlvfpuview.cpp b/Qt/ctrlvfpuview.cpp index 5ce363dd95..cfdde62084 100644 --- a/Qt/ctrlvfpuview.cpp +++ b/Qt/ctrlvfpuview.cpp @@ -45,9 +45,7 @@ void CtrlVfpuView::paintEvent(QPaintEvent *) { int my = (int)(yStart + matrix * rowHeight * 5.5f); painter.drawRect(0, my, xStart-1, rowHeight-1); - char temp[256]; - sprintf(temp, "M%i00", matrix); - painter.drawText(3, my+rowHeight-3, temp); + painter.drawText(3, my+rowHeight-3, QString("M%1").arg(matrix)+"00"); painter.drawRect(xStart, my+rowHeight, columnWidth*4-1, 4*rowHeight-1); for (int column = 0; column<4; column++) @@ -56,13 +54,10 @@ void CtrlVfpuView::paintEvent(QPaintEvent *) int x = column * columnWidth + xStart; painter.drawRect(x, y, columnWidth-1, rowHeight - 1); - char temp[256]; - sprintf(temp, "R%i0%i", matrix, column); - painter.drawText(x+3, y-3+rowHeight, temp); + painter.drawText(x+3, y-3+rowHeight, QString("R%1").arg(matrix)+QString("0%1").arg(column)); painter.drawRect(0, y+rowHeight*(column+1), xStart - 1, rowHeight - 1); - sprintf(temp, "C%i%i0", matrix, column); - painter.drawText(3, y+rowHeight*(column+2)-3, temp); + painter.drawText(3, y+rowHeight*(column+2)-3, QString("C%1").arg(matrix)+QString("%1").arg(column)+"0"); y+=rowHeight; diff --git a/Qt/debugger_disasm.cpp b/Qt/debugger_disasm.cpp index bd1a007f07..2b670bb150 100644 --- a/Qt/debugger_disasm.cpp +++ b/Qt/debugger_disasm.cpp @@ -344,7 +344,7 @@ void Debugger_Disasm::FillFunctions() if(symbolMap.GetSymbolType(i) & ST_FUNCTION) { QListWidgetItem* item = new QListWidgetItem(); - item->setText(QString(symbolMap.GetSymbolName(i)) + " ("+ QVariant(symbolMap.GetSymbolSize(i)).toString() +")"); + item->setText(QString(symbolMap.GetSymbolName(i)) + " ("+ QString::number(symbolMap.GetSymbolSize(i)) +")"); item->setData(Qt::UserRole, symbolMap.GetAddress(i)); ui->FuncList->addItem(item); } @@ -372,9 +372,7 @@ void Debugger_Disasm::UpdateBreakpointsGUI() if(!CBreakPoints::IsTempBreakPoint(addr_)) { QTreeWidgetItem* item = new QTreeWidgetItem(); - char temp[24]; - sprintf(temp,"%08x",addr_); - item->setText(0,temp); + item->setText(0,QString("%1").arg(addr_,8,16,QChar('0'))); item->setData(0,Qt::UserRole,addr_); ui->breakpointsList->addTopLevelItem(item); if(curBpAddr == addr_) @@ -434,7 +432,7 @@ void Debugger_Disasm::UpdateThreadGUI() for(int i = 0; i < threads.size(); i++) { QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setText(0,QVariant(threads[i].id).toString()); + item->setText(0,QString::number(threads[i].id)); item->setData(0,Qt::UserRole,threads[i].id); item->setText(1,threads[i].name); QString status = ""; @@ -445,12 +443,9 @@ void Debugger_Disasm::UpdateThreadGUI() if(threads[i].status & THREADSTATUS_DORMANT) status += "Dormant "; if(threads[i].status & THREADSTATUS_DEAD) status += "Dead "; item->setText(2,status); - char temp[24]; - sprintf(temp,"%08x",threads[i].curPC); - item->setText(3,temp); + item->setText(3,QString("%1").arg(threads[i].curPC,8,16,QChar('0'))); item->setData(3,Qt::UserRole,threads[i].curPC); - sprintf(temp,"%08x",threads[i].entrypoint); - item->setText(4,temp); + item->setText(4,QString("%1").arg(threads[i].entrypoint,8,16,QChar('0'))); item->setData(4,Qt::UserRole,threads[i].entrypoint); if(threads[i].isCurrent) @@ -461,6 +456,8 @@ void Debugger_Disasm::UpdateThreadGUI() ui->threadList->addTopLevelItem(item); } + for(int i = 0; i < ui->threadList->columnCount(); i++) + ui->threadList->resizeColumnToContents(i); } void Debugger_Disasm::on_threadList_itemClicked(QTreeWidgetItem *item, int column) @@ -542,7 +539,6 @@ void Debugger_Disasm::UpdateDisplayListGUI() curDlId = ui->displayList->currentItem()->data(0,Qt::UserRole).toInt(); ui->displayList->clear(); - ui->displayListData->clear(); EmuThread_LockDraw(true); const std::deque& dlQueue = gpu->GetDisplayLists(); @@ -551,7 +547,7 @@ void Debugger_Disasm::UpdateDisplayListGUI() if(dl) { QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setText(0,QVariant(dl->id).toString()); + item->setText(0,QString::number(dl->id)); item->setData(0, Qt::UserRole, dl->id); switch(dl->status) { @@ -563,19 +559,15 @@ void Debugger_Disasm::UpdateDisplayListGUI() case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break; default: break; } - char temp[24]; - sprintf(temp,"%08x",dl->startpc); - item->setText(2,temp); + item->setText(2,QString("%1").arg(dl->startpc,8,16,QChar('0'))); item->setData(2, Qt::UserRole, dl->startpc); - sprintf(temp,"%08x",dl->pc); - item->setText(3,temp); + item->setText(3,QString("%1").arg(dl->pc,8,16,QChar('0'))); item->setData(3, Qt::UserRole, dl->pc); ui->displayList->addTopLevelItem(item); if(curDlId == dl->id) { ui->displayList->setCurrentItem(item); displayListRowSelected = item; - ShowDLCode(); } } @@ -584,7 +576,7 @@ void Debugger_Disasm::UpdateDisplayListGUI() if(dl && it->id == dl->id) continue; QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setText(0,QVariant(it->id).toString()); + item->setText(0,QString::number(it->id)); item->setData(0, Qt::UserRole, it->id); switch(it->status) { @@ -596,21 +588,19 @@ void Debugger_Disasm::UpdateDisplayListGUI() case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break; default: break; } - char temp[24]; - sprintf(temp,"%08x",it->startpc); - item->setText(2,temp); + item->setText(2,QString("%1").arg(it->startpc,8,16,QChar('0'))); item->setData(2, Qt::UserRole, it->startpc); - sprintf(temp,"%08x",it->pc); - item->setText(3,temp); + item->setText(3,QString("%1").arg(it->pc,8,16,QChar('0'))); item->setData(3, Qt::UserRole, it->pc); ui->displayList->addTopLevelItem(item); if(curDlId == it->id) { ui->displayList->setCurrentItem(item); displayListRowSelected = item; - ShowDLCode(); } } + for(int i = 0; i < ui->displayList->columnCount(); i++) + ui->displayList->resizeColumnToContents(i); EmuThread_LockDraw(false); } @@ -621,96 +611,12 @@ void Debugger_Disasm::on_displayList_customContextMenuRequested(const QPoint &po { displayListRowSelected = item; - QMenu menu(this); + /*QMenu menu(this); QAction *showCode = new QAction(tr("Show code"), this); connect(showCode, SIGNAL(triggered()), this, SLOT(ShowDLCode())); - menu.addAction(showCode); + menu.addAction(showCode);*/ - menu.exec( ui->displayList->mapToGlobal(pos)); + //menu.exec( ui->displayList->mapToGlobal(pos)); } } - -void Debugger_Disasm::ShowDLCode() -{ - ui->displayListData->clear(); - ui->displayListData->setColumnWidth(0,70); - - u32 startPc = displayListRowSelected->data(2,Qt::UserRole).toInt(); - u32 curPc = displayListRowSelected->data(3,Qt::UserRole).toInt(); - - std::map data; - FillDisplayListCmd(data, startPc,0); - - for(std::map::iterator it = data.begin(); it != data.end(); it++) - { - QTreeWidgetItem* item = new QTreeWidgetItem(); - char temp[24]; - sprintf(temp,"%08x",it->first); - item->setText(0,temp); - item->setText(1,it->second.c_str()); - if(curPc == it->first) - { - for(int j = 0; j < 2; j++) - item->setTextColor(j, Qt::green); - } - ui->displayListData->addTopLevelItem(item); - } -} - -void Debugger_Disasm::FillDisplayListCmd(std::map& data, u32 pc, u32 prev) -{ - u32 curPc = pc; - int debugLimit = 10000; // Anti crash if this code is bugged - while(Memory::IsValidAddress(curPc) && debugLimit > 0) - { - if(data.find(curPc) != data.end()) - return; - - u32 op = Memory::ReadUnchecked_U32(curPc); //read from memory - u32 cmd = op >> 24; - u32 diff = op ^ gstate.cmdmem[cmd]; - char temp[256]; - GeDisassembleOp(curPc, op, prev, temp); - data[curPc] = temp; - prev = op; - if(cmd == GE_CMD_JUMP) - { - u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF; - FillDisplayListCmd(data, target, prev); - return; - } - else if(cmd == GE_CMD_CALL) - { - u32 target = gstate_c.getRelativeAddress(op & 0xFFFFFF); - FillDisplayListCmd(data, target, prev); - } - else if(cmd == GE_CMD_RET) - { - return; - } - else if(cmd == GE_CMD_FINISH) - { - return; - } - else if(cmd == GE_CMD_END) - { - if(prev >> 24 == GE_CMD_FINISH) - return; - } - curPc += 4; - debugLimit--; - } -} - -void Debugger_Disasm::on_nextGPU_clicked() -{ - host->SetGPUStep(true); - host->NextGPUStep(); -} - -void Debugger_Disasm::on_runBtn_clicked() -{ - host->SetGPUStep(false); - host->NextGPUStep(); -} diff --git a/Qt/debugger_disasm.h b/Qt/debugger_disasm.h index fb47a1935f..5ca646e4be 100644 --- a/Qt/debugger_disasm.h +++ b/Qt/debugger_disasm.h @@ -41,7 +41,6 @@ public: void UpdateDisplayList(); protected: void showEvent(QShowEvent *); - void FillDisplayListCmd(std::map& data, u32 pc, u32 prev); signals: void updateDisplayList_(); @@ -52,7 +51,6 @@ public slots: void Goto(u32 addr); void RemoveBreakpoint(); void GotoThreadEntryPoint(); - void ShowDLCode(); private slots: void UpdateDisplayListGUI(); @@ -103,9 +101,6 @@ private slots: void SetThreadStatusSuspend(); void on_displayList_customContextMenuRequested(const QPoint &pos); - void on_nextGPU_clicked(); - - void on_runBtn_clicked(); private: void SetThreadStatus(ThreadStatus status); diff --git a/Qt/debugger_disasm.ui b/Qt/debugger_disasm.ui index bcf992486f..0cc8967bcf 100644 --- a/Qt/debugger_disasm.ui +++ b/Qt/debugger_disasm.ui @@ -313,7 +313,7 @@ - 2 + 0 @@ -424,70 +424,6 @@ - - - - - - false - - - false - - - false - - - 2 - - - false - - - - 1 - - - - - 2 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Run - - - - - - - Step - - - - - - - diff --git a/Qt/debugger_displaylist.cpp b/Qt/debugger_displaylist.cpp new file mode 100644 index 0000000000..5b688d7337 --- /dev/null +++ b/Qt/debugger_displaylist.cpp @@ -0,0 +1,1850 @@ +#include "debugger_displaylist.h" + +#include +#include +#include + +#include "Core/CPU.h" +#include "ui_debugger_displaylist.h" +#include "GPU/GPUInterface.h" +#include "GPU/GeDisasm.h" +#include "EmuThread.h" +#include "Core/Host.h" +#include "base/display.h" +#include "mainwindow.h" +#include "GPU/GLES/VertexDecoder.h" +#include + + +Debugger_DisplayList::Debugger_DisplayList(DebugInterface *_cpu, MainWindow* mainWindow_, QWidget *parent) : + QDialog(parent), + ui(new Ui::Debugger_DisplayList), + cpu(_cpu), + mainWindow(mainWindow_), + currentRenderFrameDisplay(0), + currentTextureDisplay(0), + fboZoomFactor(1), + maxVtxDisplay(20), + maxIdxDisplay(20) +{ + ui->setupUi(this); + + QObject::connect(this, SIGNAL(updateDisplayList_()), this, SLOT(UpdateDisplayListGUI())); + QObject::connect(this, SIGNAL(updateRenderBufferList_()), this, SLOT(UpdateRenderBufferListGUI())); + QObject::connect(this, SIGNAL(updateRenderBuffer_()), this, SLOT(UpdateRenderBufferGUI())); + +} + +Debugger_DisplayList::~Debugger_DisplayList() +{ + delete ui; +} + + +void Debugger_DisplayList::showEvent(QShowEvent *) +{ + +#ifdef Q_WS_X11 + // Hack to remove the X11 crash with threaded opengl when opening the first dialog + EmuThread_LockDraw(true); + QTimer::singleShot(100, this, SLOT(releaseLock())); +#endif + +} + +void Debugger_DisplayList::releaseLock() +{ + EmuThread_LockDraw(false); +} + + +void Debugger_DisplayList::UpdateDisplayList() +{ + emit updateDisplayList_(); +} + + +void Debugger_DisplayList::UpdateDisplayListGUI() +{ + u32 curDlId = 0; + QTreeWidgetItem* curItem = ui->displayList->currentItem(); + if(curItem) + curDlId = ui->displayList->currentItem()->data(0,Qt::UserRole).toInt(); + + displayListRowSelected = 0; + ui->displayList->clear(); + ui->displayListData->clear(); + + EmuThread_LockDraw(true); + const std::deque& dlQueue = gpu->GetDisplayLists(); + + DisplayList* dl = gpu->GetCurrentDisplayList(); + if(dl) + { + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,QString::number(dl->id)); + item->setData(0, Qt::UserRole, dl->id); + switch(dl->status) + { + case PSP_GE_LIST_DONE: item->setText(1,"Done"); break; + case PSP_GE_LIST_QUEUED: item->setText(1,"Queued"); break; + case PSP_GE_LIST_DRAWING: item->setText(1,"Drawing"); break; + case PSP_GE_LIST_STALL_REACHED: item->setText(1,"Stall Reached"); break; + case PSP_GE_LIST_END_REACHED: item->setText(1,"End Reached"); break; + case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break; + default: break; + } + item->setText(2,QString("%1").arg(dl->startpc,8,16,QChar('0'))); + item->setData(2, Qt::UserRole, dl->startpc); + item->setText(3,QString("%1").arg(dl->pc,8,16,QChar('0'))); + item->setData(3, Qt::UserRole, dl->pc); + ui->displayList->addTopLevelItem(item); + if(curDlId == dl->id) + { + ui->displayList->setCurrentItem(item); + displayListRowSelected = item; + ShowDLCode(); + } + } + + for(auto it = dlQueue.begin(); it != dlQueue.end(); ++it) + { + if(dl && it->id == dl->id) + continue; + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,QString::number(it->id)); + item->setData(0, Qt::UserRole, it->id); + switch(it->status) + { + case PSP_GE_LIST_DONE: item->setText(1,"Done"); break; + case PSP_GE_LIST_QUEUED: item->setText(1,"Queued"); break; + case PSP_GE_LIST_DRAWING: item->setText(1,"Drawing"); break; + case PSP_GE_LIST_STALL_REACHED: item->setText(1,"Stall Reached"); break; + case PSP_GE_LIST_END_REACHED: item->setText(1,"End Reached"); break; + case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break; + default: break; + } + item->setText(2,QString("%1").arg(it->startpc,8,16,QChar('0'))); + item->setData(2, Qt::UserRole, it->startpc); + item->setText(3,QString("%1").arg(it->pc,8,16,QChar('0'))); + item->setData(3, Qt::UserRole, it->pc); + ui->displayList->addTopLevelItem(item); + if(curDlId == it->id) + { + ui->displayList->setCurrentItem(item); + displayListRowSelected = item; + ShowDLCode(); + } + } + for(int i = 0; i < ui->displayList->columnCount(); i++) + ui->displayList->resizeColumnToContents(i); + EmuThread_LockDraw(false); +} + + +void Debugger_DisplayList::ShowDLCode() +{ + ui->displayListData->clear(); + ui->displayListData->setColumnCount(4); + + u32 startPc = displayListRowSelected->data(2,Qt::UserRole).toInt(); + u32 curPc = displayListRowSelected->data(3,Qt::UserRole).toInt(); + + std::map data; + GPUgstate listState; + memset(&listState,0,sizeof(GPUgstate)); + drawGPUState.clear(); + vtxBufferSize.clear(); + idxBufferSize.clear(); + + FillDisplayListCmd(data, startPc,0, listState); + + u32 curTexAddr; + u32 curVtxAddr; + u32 curIdxAddr; + + for(std::map::iterator it = data.begin(); it != data.end(); it++) + { + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,QString("%1").arg(it->first,8,16,QChar('0'))); + item->setData(0, Qt::UserRole, it->first); + item->setText(1,QString("%1").arg(it->second.cmd,2,16,QChar('0'))); + item->setText(2,QString("%1").arg(it->second.data,6,16,QChar('0'))); + item->setText(3,it->second.comment); + if(curPc == it->first) + { + curTexAddr = it->second.texAddr; + curVtxAddr = it->second.vtxAddr; + curIdxAddr = it->second.idxAddr; + setCurrentFBO(it->second.fboAddr); + for(int j = 0; j < ui->displayListData->columnCount(); j++) + item->setTextColor(j, Qt::green); + } + if(it->second.implementationNotFinished) + { + for(int j = 0; j < ui->displayListData->columnCount(); j++) + item->setBackgroundColor(j, Qt::red); + } + ui->displayListData->addTopLevelItem(item); + + if(curPc == it->first) + { + ui->displayListData->setCurrentItem(item); + } + } + for(int j = 0; j < ui->displayListData->columnCount(); j++) + ui->displayListData->resizeColumnToContents(j); + + ui->texturesList->clear(); + ui->vertexData->clear(); + ui->vertexList->clear(); + ui->indexData->clear(); + ui->indexList->clear(); + + std::set usedTexAddr; + std::set usedVtxAddr; + std::set usedIdxAddr; + for(int i = 0; i < drawGPUState.size(); i++) + { + // Textures + QTreeWidgetItem* item = new QTreeWidgetItem(); + u32 texaddr = (drawGPUState[i].texaddr[0] & 0xFFFFF0) | ((drawGPUState[i].texbufwidth[0]<<8) & 0x0F000000); + if(!(usedTexAddr.find(texaddr) != usedTexAddr.end() || !Memory::IsValidAddress(texaddr))) + { + u32 format = drawGPUState[i].texformat & 0xF; + int w = 1 << (drawGPUState[i].texsize[0] & 0xf); + int h = 1 << ((drawGPUState[i].texsize[0]>>8) & 0xf); + + item->setText(0,QString("%1").arg(texaddr,8,16,QChar('0'))); + item->setData(0, Qt::UserRole, i); + item->setText(1,QString::number(w)); + item->setText(2,QString::number(h)); + item->setText(3,QString::number(format,16)); + ui->texturesList->addTopLevelItem(item); + if(curTexAddr == texaddr) + { + ui->texturesList->setCurrentItem(item); + for(int j = 0; j < ui->texturesList->columnCount(); j++) + item->setTextColor(j,Qt::green); + } + usedTexAddr.insert(texaddr); + } + + // Vertex + QTreeWidgetItem* vertexItem = new QTreeWidgetItem(); + u32 baseExtended = ((drawGPUState[i].base & 0x0F0000) << 8) | (drawGPUState[i].vaddr & 0xFFFFFF); + u32 vaddr = ((drawGPUState[i].offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + if(!((drawGPUState[i].vaddr) == 0 || !Memory::IsValidAddress(vaddr) || usedVtxAddr.find(vaddr) != usedVtxAddr.end())) + { + vertexItem->setText(0, QString("%1").arg(vaddr,8,16,QChar('0'))); + vertexItem->setData(0,Qt::UserRole, i); + if((drawGPUState[i].vertType & GE_VTYPE_THROUGH_MASK) == GE_VTYPE_TRANSFORM) + vertexItem->setText(1, "Transform"); + else + vertexItem->setText(1, "Raw"); + vertexItem->setText(2, QString::number((drawGPUState[i].vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT)); + vertexItem->setText(3, QString::number((drawGPUState[i].vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT)); + switch(drawGPUState[i].vertType & GE_VTYPE_WEIGHT_MASK) + { + case GE_VTYPE_WEIGHT_8BIT: vertexItem->setText(4, "8bit"); break; + case GE_VTYPE_WEIGHT_16BIT: vertexItem->setText(4, "16bit"); break; + case GE_VTYPE_WEIGHT_FLOAT: vertexItem->setText(4, "float"); break; + default: vertexItem->setText(4, "No"); break; + } + switch(drawGPUState[i].vertType & GE_VTYPE_POS_MASK) + { + case GE_VTYPE_POS_8BIT: vertexItem->setText(5, "8bit"); break; + case GE_VTYPE_POS_16BIT: vertexItem->setText(5, "16bit"); break; + case GE_VTYPE_POS_FLOAT: vertexItem->setText(5, "float"); break; + default: vertexItem->setText(5, "No"); break; + } + switch(drawGPUState[i].vertType & GE_VTYPE_NRM_MASK) + { + case GE_VTYPE_NRM_8BIT: vertexItem->setText(6, "8bit"); break; + case GE_VTYPE_NRM_16BIT: vertexItem->setText(6, "16bit"); break; + case GE_VTYPE_NRM_FLOAT: vertexItem->setText(6, "float"); break; + default: vertexItem->setText(6, "No"); break; + } + switch(drawGPUState[i].vertType & GE_VTYPE_COL_MASK) + { + case GE_VTYPE_COL_4444: vertexItem->setText(7, "4444"); break; + case GE_VTYPE_COL_5551: vertexItem->setText(7, "5551"); break; + case GE_VTYPE_COL_565: vertexItem->setText(7, "565"); break; + case GE_VTYPE_COL_8888: vertexItem->setText(7, "8888"); break; + default: vertexItem->setText(7, "No"); break; + } + switch(drawGPUState[i].vertType & GE_VTYPE_TC_MASK) + { + case GE_VTYPE_TC_8BIT: vertexItem->setText(8, "8bit"); break; + case GE_VTYPE_TC_16BIT: vertexItem->setText(8, "16bit"); break; + case GE_VTYPE_TC_FLOAT: vertexItem->setText(8, "float"); break; + default: vertexItem->setText(8, "No"); break; + } + + ui->vertexList->addTopLevelItem(vertexItem); + if(curVtxAddr == vaddr) + { + ui->vertexList->setCurrentItem(vertexItem); + for(int j = 0; j < ui->vertexList->columnCount(); j++) + vertexItem->setTextColor(j,Qt::green); + } + usedVtxAddr.insert(vaddr); + } + + + // Index + QTreeWidgetItem* indexItem = new QTreeWidgetItem(); + baseExtended = ((drawGPUState[i].base & 0x0F0000) << 8) | (drawGPUState[i].iaddr & 0xFFFFFF); + u32 iaddr = ((drawGPUState[i].offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + if(!((drawGPUState[i].iaddr & 0xFFFFFF) == 0 || !Memory::IsValidAddress(iaddr) || usedIdxAddr.find(iaddr) != usedIdxAddr.end())) + { + indexItem->setText(0, QString("%1").arg(iaddr,8,16,QChar('0'))); + indexItem->setData(0,Qt::UserRole, i); + + ui->indexList->addTopLevelItem(indexItem); + if(curIdxAddr == iaddr) + { + ui->indexList->setCurrentItem(indexItem); + for(int j = 0; j < ui->indexList->columnCount(); j++) + indexItem->setTextColor(j,Qt::green); + } + usedIdxAddr.insert(iaddr); + } + } + + + for(int i = 0; i < ui->texturesList->columnCount(); i++) + ui->texturesList->resizeColumnToContents(i); + for(int i = 0; i < ui->vertexList->columnCount(); i++) + ui->vertexList->resizeColumnToContents(i); + for(int i = 0; i < ui->indexList->columnCount(); i++) + ui->indexList->resizeColumnToContents(i); + + UpdateVertexInfo(); + UpdateIndexInfo(); +} + + +QString Debugger_DisplayList::DisassembleOp(u32 pc, u32 op, u32 prev, const GPUgstate& state) { + u32 cmd = op >> 24; + u32 data = op & 0xFFFFFF; + + // Handle control and drawing commands here directly. The others we delegate. + switch (cmd) + { + case GE_CMD_BASE: + return QString("BASE: %1").arg(data & 0xFFFFFF,6,16,QChar('0')); + break; + + case GE_CMD_VADDR: /// <<8???? + { + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data & 0xFFFFFF); + baseExtended = (state.offsetAddr + baseExtended) & 0x0FFFFFFF; + return QString("VADDR: %1").arg(baseExtended,6,16,QChar('0')); + break; + } + + case GE_CMD_IADDR: + { + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data & 0xFFFFFF); + baseExtended = (state.offsetAddr + baseExtended) & 0x0FFFFFFF; + return QString("IADDR: %1").arg(baseExtended,6,16,QChar('0')); + break; + } + + case GE_CMD_PRIM: + { + u32 count = data & 0xFFFF; + u32 type = data >> 16; + static const char* types[7] = { + "POINTS", + "LINES", + "LINE_STRIP", + "TRIANGLES", + "TRIANGLE_STRIP", + "TRIANGLE_FAN", + "RECTANGLES", + }; + return QString("DrawPrim type: %1 count: %2").arg(type < 7 ? types[type] : "INVALID").arg(count); + } + break; + + // The arrow and other rotary items in Puzbob are bezier patches, strangely enough. + case GE_CMD_BEZIER: + { + int bz_ucount = data & 0xFF; + int bz_vcount = (data >> 8) & 0xFF; + return QString("DRAW BEZIER: U=%1 x V=%2").arg(bz_ucount).arg(bz_vcount); + } + break; + + case GE_CMD_SPLINE: + { + int sp_ucount = data & 0xFF; + int sp_vcount = (data >> 8) & 0xFF; + static const char* type[4] = { + "Close/Close", + "Open/Close", + "Close/Open", + "Open/Open" + }; + int sp_utype = (data >> 16) & 0x3; + int sp_vtype = (data >> 18) & 0x3; + return QString("DRAW SPLINE: U=%1 x V=%2, U Type = %3 , V Type = %4").arg(sp_ucount).arg(sp_vcount).arg(type[sp_utype]).arg(type[sp_vtype]); + } + break; + + case GE_CMD_JUMP: + { + u32 target = (((state.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF; + return QString("CMD JUMP - %1 to %2").arg(pc,8,16,QChar('0')).arg(target,8,16,QChar('0')); + } + break; + + case GE_CMD_CALL: + { + u32 retval = pc + 4; + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (op & 0xFFFFFF); + u32 target = (state.offsetAddr + baseExtended) & 0x0FFFFFFF; + return QString("CMD CALL - %1 to %2, ret=%3").arg(pc,8,16,QChar('0')).arg(target,8,16,QChar('0')).arg(retval,8,16,QChar('0')); + } + break; + + case GE_CMD_RET: + return QString("CMD RET"); + break; + + case GE_CMD_SIGNAL: + return QString("GE_CMD_SIGNAL %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_FINISH: + return QString("CMD FINISH %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_END: + switch (prev >> 24) + { + case GE_CMD_SIGNAL: + { + // TODO: see http://code.google.com/p/jpcsp/source/detail?r=2935# + int behaviour = (prev >> 16) & 0xFF; + int signal = prev & 0xFFFF; + int enddata = data & 0xFFFF; + // We should probably defer to sceGe here, no sense in implementing this stuff in every GPU + switch (behaviour) { + case 1: // Signal with Wait + return QString("Signal with Wait UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + case 2: + return QString("Signal without wait. signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + case 3: + return QString("Signal with Pause UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + case 0x10: + return QString("Signal with Jump UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + case 0x11: + return QString("Signal with Call UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + case 0x12: + return QString("Signal with Return UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + default: + return QString("UNKNOWN Signal UNIMPLEMENTED %1 ! signal/end: %1 %2").arg(behaviour).arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + } + } + break; + case GE_CMD_FINISH: + break; + default: + return QString("Ah, not finished: %1").arg(prev & 0xFFFFFF,6,16,QChar('0')); + break; + } + return "CMD END"; + break; + + case GE_CMD_BJUMP: + { + // bounding box jump. Let's just not jump, for now. + u32 target = (((state.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF; + return QString("BBOX JUMP - %1 to %2").arg(pc,8,16,QChar('0')).arg(target,8,16,QChar('0')); + break; + } + case GE_CMD_BOUNDINGBOX: + // bounding box test. Let's do nothing. + return QString("BBOX TEST - number : %1").arg(data & 0xFFFF,4,16,QChar('0')); + break; + + case GE_CMD_ORIGIN: + return QString("Origin: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_VERTEXTYPE: + { + const char* format[4] = + { + "No", + "8 Bits fixed", + "16 Bits fixed", + "Float" + }; + const char* colFormat[8] = + { + "No", + "", + "", + "", + "16-bit BGR-5650", + "16-bit ABGR-5551", + "16-bit ABGR-4444", + "32-bit ABGR-8888" + }; + QString retString = "SetVertexType:"; + + u32 transform = data & GE_VTYPE_THROUGH_MASK; + retString += QString(" Transform : %1").arg(transform==0?"Transformed":"Raw"); + + u32 numVertMorph = (data & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT; + retString += QString(", Num Vtx Morph : %1").arg(numVertMorph); + + u32 numWeight = (data & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT; + retString += QString(", Num Weights : %1").arg(numWeight); + + u32 indexFmt = (data & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT; + retString += QString(", Index Format : %1").arg(format[indexFmt]); + + u32 weightFmt = (data & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT; + retString += QString(", Weight Format : %1").arg(format[weightFmt]); + + u32 posFmt = (data & GE_VTYPE_POS_MASK) >> GE_VTYPE_POS_SHIFT; + retString += QString(", Position Format : %1").arg(format[posFmt]); + + u32 nrmFmt = (data & GE_VTYPE_NRM_MASK) >> GE_VTYPE_NRM_SHIFT; + retString += QString(", Normal Format : %1").arg(format[nrmFmt]); + + u32 colFmt = (data & GE_VTYPE_COL_MASK) >> GE_VTYPE_COL_SHIFT; + retString += QString(", Color Format : %1").arg(colFormat[colFmt]); + + u32 tcFmt = (data & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT; + retString += QString(", Texture UV Format : %1").arg(format[tcFmt]); + + return retString; + break; + } + case GE_CMD_OFFSETADDR: + return QString("OffsetAddr: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_REGION1: + { + int x1 = data & 0x3ff; + int y1 = data >> 10; + //topleft + return QString("Region TL: %1 %2").arg(x1).arg(y1); + } + break; + + case GE_CMD_REGION2: + { + int x2 = data & 0x3ff; + int y2 = data >> 10; + return QString("Region BR: %1 %2").arg(x2).arg(y2); + } + break; + + case GE_CMD_CLIPENABLE: + return QString("Clip Enable: %1").arg(data); + break; + + case GE_CMD_CULLFACEENABLE: + return QString("CullFace Enable: %1").arg(data); + break; + + case GE_CMD_TEXTUREMAPENABLE: + return QString("Texture map enable: %1").arg(data); + break; + + case GE_CMD_LIGHTINGENABLE: + return QString("Lighting enable: %1").arg(data); + break; + + case GE_CMD_FOGENABLE: + return QString("Fog Enable: %1").arg(data); + break; + + case GE_CMD_DITHERENABLE: + return QString("Dither Enable: %1").arg(data); + break; + + case GE_CMD_OFFSETX: + return QString("Offset X: %1").arg(data); + break; + + case GE_CMD_OFFSETY: + return QString("Offset Y: %1").arg(data); + break; + + case GE_CMD_TEXSCALEU: + return QString("Texture U Scale: %1").arg(getFloat24(data)); + break; + + case GE_CMD_TEXSCALEV: + return QString("Texture V Scale: %1").arg(getFloat24(data)); + break; + + case GE_CMD_TEXOFFSETU: + return QString("Texture U Offset: %1").arg(getFloat24(data)); + break; + + case GE_CMD_TEXOFFSETV: + return QString("Texture V Offset: %1").arg(getFloat24(data)); + break; + + case GE_CMD_SCISSOR1: + { + int x1 = data & 0x3ff; + int y1 = data >> 10; + return QString("Scissor TL: %1, %2").arg(x1).arg(y1); + } + break; + case GE_CMD_SCISSOR2: + { + int x2 = data & 0x3ff; + int y2 = data >> 10; + return QString("Scissor BR: %1, %2").arg(x2).arg(y2); + } + break; + + case GE_CMD_MINZ: + { + float zMin = getFloat24(data) / 65535.f; + return QString("MinZ: %1").arg(zMin); + } + break; + + case GE_CMD_MAXZ: + { + float zMax = getFloat24(data) / 65535.f; + return QString("MaxZ: %1").arg(zMax); + } + break; + + case GE_CMD_FRAMEBUFPTR: + { + u32 ptr = op & 0xFFE000; + return QString("FramebufPtr: %1").arg(data,8,16,QChar('0')); + } + break; + + case GE_CMD_FRAMEBUFWIDTH: + { + return QString("FramebufWidth: %1").arg(data); + } + break; + + case GE_CMD_FRAMEBUFPIXFORMAT: + { + const char* fmt[4] = + { + "16-bit BGR 5650", + "16-bit ABGR 5551", + "16-bit ABGR 4444", + "32-bit ABGR 8888" + }; + return QString("FramebufPixeFormat: %1").arg(fmt[data]); + break; + } + case GE_CMD_TEXADDR0: + case GE_CMD_TEXADDR1: + case GE_CMD_TEXADDR2: + case GE_CMD_TEXADDR3: + case GE_CMD_TEXADDR4: + case GE_CMD_TEXADDR5: + case GE_CMD_TEXADDR6: + case GE_CMD_TEXADDR7: + return QString("Texture address %1: %2").arg(cmd-GE_CMD_TEXADDR0).arg(data,6,16,QChar('0')); + break; + + case GE_CMD_TEXBUFWIDTH0: + case GE_CMD_TEXBUFWIDTH1: + case GE_CMD_TEXBUFWIDTH2: + case GE_CMD_TEXBUFWIDTH3: + case GE_CMD_TEXBUFWIDTH4: + case GE_CMD_TEXBUFWIDTH5: + case GE_CMD_TEXBUFWIDTH6: + case GE_CMD_TEXBUFWIDTH7: + return QString("Texture BUFWIDTHess %1: %2 width : %3").arg(cmd-GE_CMD_TEXBUFWIDTH0).arg(data,6,16,QChar('0')).arg(data & 0xFFFF); + break; + + case GE_CMD_CLUTADDR: + return QString("CLUT base addr: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_CLUTADDRUPPER: + return QString("CLUT addr upper %1").arg(data,8,16,QChar('0')); + break; + + case GE_CMD_LOADCLUT: + // This could be used to "dirty" textures with clut. + return QString("Clut load, numColor : %1").arg(data*8); + break; + + case GE_CMD_TEXMAPMODE: + { + const char* texMapMode[3] = + { + "Texture Coordinates (UV)", + "Texture Matrix", + "Environment Map" + }; + const char* texProjMode[4] = + { + "Position", + "Texture Coordinates", + "Normalized Normal", + "Normal" + }; + return QString("Tex map mode: Map mode : %1, Proj Mode : %2").arg(texMapMode[data & 0x3]).arg(texProjMode[(data >> 8) & 0x3]); + break; + } + case GE_CMD_TEXSHADELS: + return QString("Tex shade light sources: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_CLUTFORMAT: + { + const char* fmt[4] = + { + "16-bit BGR 5650", + "16-bit ABGR 5551", + "16-bit ABGR 4444", + "32-bit ABGR 8888" + }; + return QString("Clut format: %1 , Fmt : %2").arg(data,6,16,QChar('0')).arg(fmt[data & 0x3]); + } + break; + + case GE_CMD_TRANSFERSRC: + { + return QString("Block Transfer Src: %1").arg(data,6,16,QChar('0')); + // Nothing to do, the next one prints + } + break; + + case GE_CMD_TRANSFERSRCW: + { + u32 xferSrc = state.transfersrc | ((data&0xFF0000)<<8); + u32 xferSrcW = state.transfersrcw & 1023; + return QString("Block Transfer Src: %1 W: %2").arg(xferSrc,8,16,QChar('0')).arg(xferSrcW); + break; + } + + case GE_CMD_TRANSFERDST: + { + // Nothing to do, the next one prints + return QString("Block Transfer Dst: %1").arg(data,6,16,QChar('0')); + } + break; + + case GE_CMD_TRANSFERDSTW: + { + u32 xferDst= state.transferdst | ((data&0xFF0000)<<8); + u32 xferDstW = state.transferdstw & 1023; + return QString("Block Transfer Dest: %1 W: %2").arg(xferDst,8,16,QChar('0')).arg(xferDstW); + break; + } + + case GE_CMD_TRANSFERSRCPOS: + { + u32 x = (data & 1023)+1; + u32 y = ((data>>10) & 1023)+1; + return QString("Block Transfer Src Rect TL: %1, %2").arg(x).arg(y); + break; + } + + case GE_CMD_TRANSFERDSTPOS: + { + u32 x = (data & 1023)+1; + u32 y = ((data>>10) & 1023)+1; + return QString("Block Transfer Dest Rect TL: %1, %2").arg(x).arg(y); + break; + } + + case GE_CMD_TRANSFERSIZE: + { + u32 w = (data & 1023)+1; + u32 h = ((data>>10) & 1023)+1; + return QString("Block Transfer Rect Size: %1 x %2").arg(w).arg(h); + break; + } + + case GE_CMD_TRANSFERSTART: // Orphis calls this TRXKICK + { + return QString("Block Transfer Start : %1").arg(data ? "32-bit texel size" : "16-bit texel size"); + break; + } + + case GE_CMD_TEXSIZE0: + case GE_CMD_TEXSIZE1: + case GE_CMD_TEXSIZE2: + case GE_CMD_TEXSIZE3: + case GE_CMD_TEXSIZE4: + case GE_CMD_TEXSIZE5: + case GE_CMD_TEXSIZE6: + case GE_CMD_TEXSIZE7: + { + int w = 1 << (data & 0xf); + int h = 1 << ((data>>8) & 0xf); + return QString("Texture Size %1: %2, width : %3, height : %4").arg(cmd - GE_CMD_TEXSIZE0).arg(data,6,16,QChar('0')).arg(w).arg(h); + } + break; + + case GE_CMD_ZBUFPTR: + { + u32 ptr = op & 0xFFE000; + return QString("Zbuf Ptr: %1").arg(ptr,6,16,QChar('0')); + } + break; + + case GE_CMD_ZBUFWIDTH: + { + return QString("Zbuf Width: %1").arg(data,6,16,QChar('0')); + } + break; + + case GE_CMD_AMBIENTCOLOR: + return QString("Ambient Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_AMBIENTALPHA: + return QString("Ambient Alpha: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALAMBIENT: + return QString("Material Ambient Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALDIFFUSE: + return QString("Material Diffuse Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALEMISSIVE: + return QString("Material Emissive Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALSPECULAR: + return QString("Material Specular Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALALPHA: + return QString("Material Alpha Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALSPECULARCOEF: + return QString("Material specular coef: %1").arg(getFloat24(data)); + break; + + case GE_CMD_SHADEMODE: + return QString("Shade: %1 (%2)").arg(data,6,16,QChar('0')).arg(data ? "gouraud" : "flat"); + break; + + case GE_CMD_LIGHTMODE: + return QString("Lightmode: %1 (%2)").arg(data,6,16,QChar('0')).arg(data ? "separate spec" : "single color"); + break; + + case GE_CMD_LIGHTTYPE0: + case GE_CMD_LIGHTTYPE1: + case GE_CMD_LIGHTTYPE2: + case GE_CMD_LIGHTTYPE3: + { + const char* lightType[3] = + { + "Directional Light", + "Point Light", + "Spot Light" + }; + const char* lightComp[3] = + { + "Ambient & Diffuse", + "Diffuse & Specular", + "Unknown (diffuse color, affected by specular power)" + }; + return QString("Light %1 type: %2 %3").arg(cmd-GE_CMD_LIGHTTYPE0).arg(lightType[(data) >> 8 & 0x3]).arg(lightComp[data & 0x3]); + break; + } + case GE_CMD_LX0:case GE_CMD_LY0:case GE_CMD_LZ0: + case GE_CMD_LX1:case GE_CMD_LY1:case GE_CMD_LZ1: + case GE_CMD_LX2:case GE_CMD_LY2:case GE_CMD_LZ2: + case GE_CMD_LX3:case GE_CMD_LY3:case GE_CMD_LZ3: + { + int n = cmd - GE_CMD_LX0; + int l = n / 3; + int c = n % 3; + float val = getFloat24(data); + return QString("Light %1 %2 pos: %3").arg(l).arg(QChar('X')+c).arg(val); + } + break; + + case GE_CMD_LDX0:case GE_CMD_LDY0:case GE_CMD_LDZ0: + case GE_CMD_LDX1:case GE_CMD_LDY1:case GE_CMD_LDZ1: + case GE_CMD_LDX2:case GE_CMD_LDY2:case GE_CMD_LDZ2: + case GE_CMD_LDX3:case GE_CMD_LDY3:case GE_CMD_LDZ3: + { + int n = cmd - GE_CMD_LDX0; + int l = n / 3; + int c = n % 3; + float val = getFloat24(data); + return QString("Light %1 %2 dir: %3").arg(l).arg(QChar('X')+c).arg(val); + } + break; + + case GE_CMD_LKA0:case GE_CMD_LKB0:case GE_CMD_LKC0: + case GE_CMD_LKA1:case GE_CMD_LKB1:case GE_CMD_LKC1: + case GE_CMD_LKA2:case GE_CMD_LKB2:case GE_CMD_LKC2: + case GE_CMD_LKA3:case GE_CMD_LKB3:case GE_CMD_LKC3: + { + int n = cmd - GE_CMD_LKA0; + int l = n / 3; + int c = n % 3; + float val = getFloat24(data); + return QString("Light %1 %2 att: %3").arg(l).arg(QChar('X')+c).arg(val); + } + break; + + case GE_CMD_LAC0:case GE_CMD_LAC1:case GE_CMD_LAC2:case GE_CMD_LAC3: + case GE_CMD_LDC0:case GE_CMD_LDC1:case GE_CMD_LDC2:case GE_CMD_LDC3: + case GE_CMD_LSC0:case GE_CMD_LSC1:case GE_CMD_LSC2:case GE_CMD_LSC3: + { + float r = (float)(data & 0xff)/255.0f; + float g = (float)((data>>8) & 0xff)/255.0f; + float b = (float)(data>>16)/255.0f; + + int l = (cmd - GE_CMD_LAC0) / 3; + int t = (cmd - GE_CMD_LAC0) % 3; + return QString("Light %1 color %2: %3 %4 %5").arg(l).arg(t).arg(r).arg(g).arg(b); + } + break; + + case GE_CMD_VIEWPORTX1: + case GE_CMD_VIEWPORTY1: + case GE_CMD_VIEWPORTX2: + case GE_CMD_VIEWPORTY2: + return QString("Viewport param %1: %2").arg(cmd-GE_CMD_VIEWPORTX1).arg(getFloat24(data)); + break; + case GE_CMD_VIEWPORTZ1: + { + float zScale = getFloat24(data) / 65535.f; + return QString("Viewport Z scale: %1").arg(zScale); + } + break; + case GE_CMD_VIEWPORTZ2: + { + float zOff = getFloat24(data) / 65535.f; + return QString("Viewport Z pos: %1").arg(zOff); + } + break; + + case GE_CMD_LIGHTENABLE0: + case GE_CMD_LIGHTENABLE1: + case GE_CMD_LIGHTENABLE2: + case GE_CMD_LIGHTENABLE3: + return QString("Light %1 enable: %2").arg(cmd-GE_CMD_LIGHTENABLE0).arg(data); + break; + + case GE_CMD_CULL: + { + const char* cull[2] = + { + "Clockwise visible", + "Counter-clockwise visible" + }; + return QString("cull: %1").arg(cull[data & 0x1]); + break; + } + case GE_CMD_PATCHDIVISION: + { + int patch_div_s = data & 0xFF; + int patch_div_t = (data >> 8) & 0xFF; + return QString("Patch subdivision: S=%1 x T=%2").arg(patch_div_s).arg(patch_div_t); + } + break; + + case GE_CMD_PATCHPRIMITIVE: + { + const char* type[3] = + { + "Triangles", + "Lines", + "Points" + }; + return QString("Patch Primitive: %1").arg(type[data]); + break; + } + case GE_CMD_PATCHFACING: + { + const char* val[2] = + { + "Clockwise", + "Counter-Clockwise" + }; + return QString( "Patch Facing: %1").arg(val[data]); + break; + } + case GE_CMD_REVERSENORMAL: + return QString("Reverse normal: %1").arg(data); + break; + + case GE_CMD_MATERIALUPDATE: + { + QString txt = ""; + if(data & 1) txt += " Ambient"; + if(data & 2) txt += " Diffuse"; + if(data & 4) txt += " Specular"; + return QString("Material Update: %1").arg(txt); + break; + } + + ////////////////////////////////////////////////////////////////// + // CLEARING + ////////////////////////////////////////////////////////////////// + case GE_CMD_CLEARMODE: + { + // If it becomes a performance problem, check diff&1 + const char* clearMode[8] = + { + "", + "Clear Color Buffer", + "Clear Stencil/Alpha Buffer", + "", + "Clear Depth Buffer", + "", + "", + "" + }; + return QString("Clear mode: %1, enabled : %2").arg(clearMode[(data >> 8) & 0xF]).arg(data & 0x1); + break; + } + + ////////////////////////////////////////////////////////////////// + // ALPHA BLENDING + ////////////////////////////////////////////////////////////////// + case GE_CMD_ALPHABLENDENABLE: + return QString("Alpha blend enable: %1").arg(data); + break; + + case GE_CMD_BLENDMODE: + { + const char* func[9] = + { + "Source Color", + "One Minus Source Color", + "Source Alpha", + "One Minus Source Alpha", + "Destination Color", + "One Minus Destination Color", + "Destination Alpha", + "One Minus Destination Alpha", + "Fix" + }; + const char* op[6] = + { + "Add", + "Subtract", + "Reverse Subtract", + "Minimum Value", + "Maximum Value", + "Absolute Value" + }; + return QString("Blend mode: Src : %1, Dest : %2, Op : %3").arg(func[(data >> 4) & 0xF]).arg(func[(data >> 8) & 0xF]).arg(op[(data) & 0x7]); + break; + } + case GE_CMD_BLENDFIXEDA: + return QString("Blend fix A: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_BLENDFIXEDB: + return QString("Blend fix B: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_ALPHATESTENABLE: + return QString("Alpha test enable: %1").arg(data); + break; + + case GE_CMD_ALPHATEST: + { + const char* testFunc[8] = + { + "Never pass pixel", + "Always pass pixel", + "Pass pixel if match", + "Pass pixel if difference", + "Pass pixel if less", + "Pass pixel if less or equal", + "Pass pixel if greater", + "Pass pixel if greater or equal" + }; + return QString("Alpha test settings, Mask : %1, Ref : %2, Test : %3").arg((data >> 8) & 0xFF).arg((data >> 16) & 0xFF).arg(testFunc[data & 0x7]); + break; + } + case GE_CMD_ANTIALIASENABLE: + return QString("Antialias enable: %1").arg(data); + break; + + case GE_CMD_PATCHCULLENABLE: + return QString("Antialias enable: %1").arg(data); + break; + + case GE_CMD_COLORTESTENABLE: + { + const char* colorTest[4] = + { + "Never pass pixel", + "Always pass pixel", + "Pass pixel if color matches", + "Pass pixel if color differs" + }; + return QString("Color Test enable: %1").arg(colorTest[data]); + break; + } + case GE_CMD_LOGICOPENABLE: + { + const char* logicOp[16] = + { + "Clear", + "And", + "Reverse And", + "Copy", + "Inverted And", + "No Operation", + "Exclusive Or", + "Or", + "Negated Or", + "Equivalence", + "Inverted", + "Reverse Or", + "Inverted Copy", + "Inverted Or", + "Negated And", + "Set" + }; + return QString("Logic op enable: %1").arg(logicOp[data]); + break; + } + case GE_CMD_TEXFUNC: + { + const char* effect[8] = + { + "Modulate", + "Decal", + "Blend", + "Replace", + "Add", + "","","" + }; + return QString("TexFunc %1 / %2 / %3").arg((data&0x100)?"Texture alpha is read":"Texture alpha is ignored").arg((data & 0x10000)?"Fragment color is doubled":"Fragment color is untouched").arg(effect[data & 0x7]); + break; + } + case GE_CMD_TEXFILTER: + { + const char* filter[8]= + { + "Nearest", + "Linear", + "", + "", + "Nearest; Mipmap Nearest", + "Linear; Mipmap Nearest", + "Nearest; Mipmap Linear", + "Linear; Mipmap Linear" + }; + int min = data & 0x7; + int mag = (data >> 8) & 0x7; + return QString("TexFilter min: %1 mag: %2").arg(filter[min]).arg(filter[mag]); + } + break; + + case GE_CMD_TEXENVCOLOR: + return QString("TexEnvColor %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_TEXMODE: + { + u32 maxMipMap = (data >> 16) & 0xF; + return QString("TexMode MaxmipMap : %1, Swizzle : %2").arg(maxMipMap).arg(data & 0x1); + break; + } + case GE_CMD_TEXFORMAT: + { + const char* texFmt[11] = + { + "16-bit BGR 5650", + "16-bit ABGR 5551", + "16-bit ABGR 4444", + "32-bit ABGR 8888", + "4-bit indexed", + "8-bit indexed", + "16-bit indexed", + "32-bit indexed", + "DXT1", + "DXT3", + "DXT5" + }; + return QString("TexFormat %1").arg(texFmt[data]); + break; + } + case GE_CMD_TEXFLUSH: + return QString("TexFlush"); + break; + + case GE_CMD_TEXSYNC: + return QString("TexSync"); + break; + + case GE_CMD_TEXWRAP: + { + const char* wrapMode[2] = + { + "Repeat", + "Clamp" + }; + return QString("TexWrap U : %1, V : %2").arg(wrapMode[data & 0x1]).arg(wrapMode[(data >> 8) & 0x1]); + break; + } + case GE_CMD_TEXLEVEL: + return QString("TexWrap Mode: %1 Offset: %2").arg(data&3).arg(data >> 16); + break; + + case GE_CMD_FOG1: + return QString("Fog1 %1").arg(getFloat24(data)); + break; + + case GE_CMD_FOG2: + return QString( "Fog2 %1").arg(getFloat24(data)); + break; + + case GE_CMD_FOGCOLOR: + return QString("FogColor %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_TEXLODSLOPE: + return QString( "TexLodSlope %1").arg(data,6,16,QChar('0')); + break; + + ////////////////////////////////////////////////////////////////// + // Z/STENCIL TESTING + ////////////////////////////////////////////////////////////////// + + case GE_CMD_ZTESTENABLE: + return QString( "Z test enable: %1").arg(data&1); + break; + + case GE_CMD_STENCILOP: + { + const char* stencilOp[8] = + { + "Keep stencil value", + "Zero stencil value", + "Replace stencil value", + "Invert stencil value", + "Increment stencil value", + "Decrement stencil value", + "","" + }; + return QString("Stencil op: ZFail : %1, Fail : %2, Pass : %3").arg(stencilOp[(data >> 16) & 0x7]).arg(stencilOp[(data >> 8) & 0x7]).arg(stencilOp[(data) & 0x7]); + break; + } + case GE_CMD_STENCILTEST: + { + const char* testFunc[8] = + { + "Never pass stencil pixel", + "Always pass stencil pixel", + "Pass test if match", + "Pass test if difference", + "Pass test if less", + "Pass test if less or equal", + "Pass test if greater", + "Pass test if greater or equal" + }; + return QString("Stencil test, Mask : %1, Ref : %2, Test : %3").arg((data >> 8) & 0xFF).arg((data >> 16) & 0xFF).arg(testFunc[data & 0x7]); + break; + } + + case GE_CMD_STENCILTESTENABLE: + return QString("Stencil test enable: %1").arg(data); + break; + + case GE_CMD_ZTEST: + { + const char* testFunc[8] = + { + "Never pass stencil pixel", + "Always pass stencil pixel", + "Pass pixel if match", + "Pass pixel if difference", + "Pass pixel if less", + "Pass pixel if less or equal", + "Pass pixel if greater", + "Pass pixel if greater or equal" + }; + return QString("Z test mode: %1").arg(testFunc[data & 0x7]); + break; + } + case GE_CMD_MORPHWEIGHT0: + case GE_CMD_MORPHWEIGHT1: + case GE_CMD_MORPHWEIGHT2: + case GE_CMD_MORPHWEIGHT3: + case GE_CMD_MORPHWEIGHT4: + case GE_CMD_MORPHWEIGHT5: + case GE_CMD_MORPHWEIGHT6: + case GE_CMD_MORPHWEIGHT7: + { + int index = cmd - GE_CMD_MORPHWEIGHT0; + float weight = getFloat24(data); + return QString("MorphWeight %1 = %2").arg(index).arg(weight); + } + break; + + case GE_CMD_DITH0: + case GE_CMD_DITH1: + case GE_CMD_DITH2: + case GE_CMD_DITH3: + return QString("DitherMatrix %1 = %2").arg(cmd-GE_CMD_DITH0).arg(data,6,16,QChar('0')); + break; + + case GE_CMD_LOGICOP: + return QString("LogicOp: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_ZWRITEDISABLE: + return QString("ZMask: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_COLORTEST: + return QString("ColorTest: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_COLORREF: + return QString("ColorRef: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_COLORTESTMASK: + return QString( "ColorTestMask: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MASKRGB: + return QString("MaskRGB: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MASKALPHA: + return QString("MaskAlpha: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_WORLDMATRIXNUMBER: + return QString("World # %1").arg(data & 0xF); + break; + + case GE_CMD_WORLDMATRIXDATA: + return QString("World data # %1").arg(getFloat24(data)); + break; + + case GE_CMD_VIEWMATRIXNUMBER: + return QString("VIEW # %1").arg(data & 0xF); + break; + + case GE_CMD_VIEWMATRIXDATA: + return QString("VIEW data # %1").arg(getFloat24(data)); + break; + + case GE_CMD_PROJMATRIXNUMBER: + return QString("PROJECTION # %1").arg(data & 0xF); + break; + + case GE_CMD_PROJMATRIXDATA: + return QString("PROJECTION matrix data # %1").arg(getFloat24(data)); + break; + + case GE_CMD_TGENMATRIXNUMBER: + return QString("TGEN # %1").arg(data & 0xF); + break; + + case GE_CMD_TGENMATRIXDATA: + return QString("TGEN data # %1").arg(getFloat24(data)); + break; + + case GE_CMD_BONEMATRIXNUMBER: + return QString("BONE #%1").arg(data); + break; + + case GE_CMD_BONEMATRIXDATA: + return QString("BONE data #%1 %2").arg(state.boneMatrixNumber & 0x7f).arg(getFloat24(data)); + break; + + default: + return QString("Unknown: %1").arg(op,8,16,QChar('0')); + break; + } +} + + +void Debugger_DisplayList::FillDisplayListCmd(std::map& data, u32 pc, u32 prevAddr, GPUgstate& state) +{ + u32 curPc = pc; + int debugLimit = 10000; // Anti crash if this code is bugged + while(Memory::IsValidAddress(curPc) && debugLimit > 0) + { + if(data.find(curPc) != data.end()) + return; + + u32 op = Memory::ReadUnchecked_U32(curPc); //read from memory + u32 cmd = op >> 24; + u32 data_ = op & 0xFFFFFF; + u32 diff = op ^ gstate.cmdmem[cmd]; + state.cmdmem[cmd] = op; + u32 prevOp = 0; + if(Memory::IsValidAddress(prevAddr)) + Memory::ReadUnchecked_U32(prevAddr); + data[curPc].comment = DisassembleOp(curPc, op, prevOp, state); + data[curPc].addr = curPc; + data[curPc].cmd = cmd; + data[curPc].data = data_; + data[curPc].implementationNotFinished = false; + data[curPc].texAddr = (gstate.texaddr[0] & 0xFFFFF0) | ((gstate.texbufwidth[0]<<8) & 0x0F000000); + data[curPc].fboAddr = state.fbptr & 0xFFFFFF; + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (state.vaddr & 0xFFFFFF); + data[curPc].vtxAddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + baseExtended = ((state.base & 0x0F0000) << 8) | (state.iaddr & 0xFFFFFF); + data[curPc].idxAddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + // Add or remove bugged functions for highlight + if(cmd == GE_CMD_BEZIER || + cmd == GE_CMD_SPLINE || + cmd == GE_CMD_BJUMP || + cmd == GE_CMD_BOUNDINGBOX) + { + data[curPc].implementationNotFinished = true; + } + + // We are drawing, save the GPU state for texture, vertex and index list + if(cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE) + { + drawGPUState.push_back(state); + } + + if(cmd == GE_CMD_JUMP) + { + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data_ & 0xFFFFFF); + u32 target = (((state.offsetAddr & 0xFFFFFF) << 8) + baseExtended) & 0x0FFFFFFF; + FillDisplayListCmd(data, target, prevAddr, state); + return; + } + else if(cmd == GE_CMD_CALL) + { + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data_ & 0xFFFFFF); + u32 target = (((state.offsetAddr & 0xFFFFFF) << 8) + baseExtended) & 0x0FFFFFFF; + FillDisplayListCmd(data, target, prevAddr, state); + } + else if(cmd == GE_CMD_RET) + { + return; + } + else if(cmd == GE_CMD_FINISH) + { + return; + } + else if(cmd == GE_CMD_END) + { + if(prevOp >> 24 == GE_CMD_FINISH) + return; + } + prevAddr = curPc; + curPc += 4; + debugLimit--; + } +} + +void Debugger_DisplayList::Update() +{ + UpdateRenderBuffer(); + UpdateRenderBufferList(); + UpdateDisplayList(); +} + + +void Debugger_DisplayList::on_displayList_itemClicked(QTreeWidgetItem *item, int column) +{ + displayListRowSelected = item; + ShowDLCode(); +} + +void Debugger_DisplayList::on_stepBtn_clicked() +{ + host->SetGPUStep(true); + host->NextGPUStep(); +} + +void Debugger_DisplayList::on_runBtn_clicked() +{ + ui->displayList->clear(); + ui->displayListData->clear(); + host->SetGPUStep(false); + host->NextGPUStep(); +} + +void Debugger_DisplayList::on_stopBtn_clicked() +{ + host->SetGPUStep(true); +} + +void Debugger_DisplayList::UpdateRenderBuffer() +{ + emit updateRenderBuffer_(); +} + +void Debugger_DisplayList::UpdateRenderBufferGUI() +{ + EmuThread_LockDraw(true); + + gpu->Flush(); + + int FRAME_WIDTH; + int FRAME_HEIGHT; + u8 *data = 0; + int curTex; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &curTex); + if(currentTextureDisplay == 0) + { + FRAME_WIDTH = pixel_xres; + FRAME_HEIGHT = pixel_yres; + data = new u8[FRAME_WIDTH * FRAME_HEIGHT * 4]; + memset(data,0,FRAME_WIDTH * FRAME_HEIGHT * 4); + if(currentRenderFrameDisplay == 0) + { + glReadBuffer(GL_COLOR_ATTACHMENT0); + glReadPixels(0, 0, FRAME_WIDTH, FRAME_HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, data); + } + else + { + glReadBuffer(GL_DEPTH_ATTACHMENT); + glReadPixels(0, 0, FRAME_WIDTH, FRAME_HEIGHT, GL_DEPTH_COMPONENT, GL_FLOAT, data); + } + } + else + { + fbo_get_dimensions(currentTextureDisplay, &FRAME_WIDTH, &FRAME_HEIGHT); + data = new u8[FRAME_WIDTH * FRAME_HEIGHT * 4]; + memset(data,0,FRAME_WIDTH * FRAME_HEIGHT * 4); + if(currentRenderFrameDisplay == 0) + { + fbo_bind_color_as_texture(currentTextureDisplay,0); + glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); + } + } + glBindTexture(GL_TEXTURE_2D, curTex); + + QImage img = QImage(data, FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH*4, QImage::Format_ARGB32).mirrored(false,true); + QPixmap pixmap = QPixmap::fromImage(img); + ui->fboImg->setPixmap(pixmap); + ui->fboImg->setMinimumWidth(pixmap.width() * fboZoomFactor); + ui->fboImg->setMinimumHeight(pixmap.height() * fboZoomFactor); + ui->fboImg->setMaximumWidth(pixmap.width() * fboZoomFactor); + ui->fboImg->setMaximumHeight(pixmap.height() * fboZoomFactor); + + delete[] data; + + EmuThread_LockDraw(false); +} + +void Debugger_DisplayList::on_nextDrawBtn_clicked() +{ + host->SetGPUStep(true, 1); + host->NextGPUStep(); +} + +void Debugger_DisplayList::on_gotoPCBtn_clicked() +{ + if(!displayListRowSelected) + return; + u32 currentPC = displayListRowSelected->data(3, Qt::UserRole).toInt(); + + for(int i = 0; i < ui->displayListData->topLevelItemCount(); i++) + { + if(ui->displayListData->topLevelItem(i)->data(0, Qt::UserRole).toInt() == currentPC) + { + ui->displayListData->setCurrentItem(ui->displayListData->topLevelItem(i)); + } + } +} + +void Debugger_DisplayList::on_texturesList_itemDoubleClicked(QTreeWidgetItem *item, int column) +{ + mainWindow->GetDialogMemoryTex()->ShowTex(drawGPUState[item->data(0,Qt::UserRole).toInt()]); +} + +void Debugger_DisplayList::on_comboBox_currentIndexChanged(int index) +{ + currentRenderFrameDisplay = index; + UpdateRenderBufferGUI(); +} + +void Debugger_DisplayList::UpdateRenderBufferList() +{ + emit updateRenderBufferList_(); +} + +void Debugger_DisplayList::UpdateRenderBufferListGUI() +{ + ui->fboList->clear(); + + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,"Framebuffer"); + item->setData(0,Qt::UserRole, 0); + item->setText(1,QString::number(pixel_xres)); + item->setText(2,QString::number(pixel_yres)); + item->setText(3,QString::number(4)); + ui->fboList->addTopLevelItem(item); + + std::vector fboList = gpu->GetFramebufferList(); + + for(int i = 0; i < fboList.size(); i++) + { + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,QString("%1").arg(fboList[i].fb_address,8,16,QChar('0'))); + u64 addr = (u64)fboList[i].fbo; + item->setData(0,Qt::UserRole, addr); + item->setData(0,Qt::UserRole+1, fboList[i].fb_address); + item->setText(1,QString::number(fboList[i].width)); + item->setText(2,QString::number(fboList[i].height)); + item->setText(3,QString::number(fboList[i].format)); + + ui->fboList->addTopLevelItem(item); + } +} + +void Debugger_DisplayList::on_fboList_itemClicked(QTreeWidgetItem *item, int column) +{ + u64 addr = item->data(0,Qt::UserRole).toULongLong(); + FBO* fbo = (FBO*)addr; + currentTextureDisplay = fbo; + UpdateRenderBufferGUI(); +} + +void Debugger_DisplayList::on_nextDLBtn_clicked() +{ + host->SetGPUStep(true,-1); + host->NextGPUStep(); +} + +void Debugger_DisplayList::setCurrentFBO(u32 addr) +{ + for(int i = 0; i < ui->fboList->topLevelItemCount(); i++) + { + if(ui->fboList->topLevelItem(i)->data(0,Qt::UserRole+1).toInt() == addr) + { + for(int j = 0; j < ui->fboList->colorCount(); j++) + ui->fboList->topLevelItem(i)->setTextColor(j,Qt::green); + } + else + { + for(int j = 0; j < ui->fboList->colorCount(); j++) + ui->fboList->topLevelItem(i)->setTextColor(j,Qt::black); + } + } +} + +void Debugger_DisplayList::on_zoommBtn_clicked() +{ + fboZoomFactor *= 0.5; + ui->fboImg->setMinimumWidth(ui->fboImg->minimumWidth()*0.5); + ui->fboImg->setMinimumHeight(ui->fboImg->minimumHeight()*0.5); + ui->fboImg->setMaximumWidth(ui->fboImg->minimumWidth()*0.5); + ui->fboImg->setMaximumHeight(ui->fboImg->minimumHeight()*0.5); +} + +void Debugger_DisplayList::on_zoompBtn_clicked() +{ + fboZoomFactor *= 2; + ui->fboImg->setMinimumWidth(ui->fboImg->minimumWidth()*2); + ui->fboImg->setMinimumHeight(ui->fboImg->minimumHeight()*2); + ui->fboImg->setMaximumWidth(ui->fboImg->minimumWidth()*2); + ui->fboImg->setMaximumHeight(ui->fboImg->minimumHeight()*2); +} + +void Debugger_DisplayList::UpdateVertexInfo() +{ + ui->vertexData->clear(); + + QTreeWidgetItem* item = ui->vertexList->currentItem(); + if(item == 0) + return; + + GPUgstate state = drawGPUState[item->data(0,Qt::UserRole).toInt()]; + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (state.vaddr & 0xFFFFFF); + u32 vaddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + + VertexDecoder vtcDec; + vtcDec.SetVertexType(state.vertType); + u8 tmp[20*vtcDec.GetDecVtxFmt().stride]; + vtcDec.DecodeVerts(tmp,Memory::GetPointer(vaddr),0,0,0,0,19); + VertexReader vtxRead(tmp,vtcDec.GetDecVtxFmt(),state.vertType); + + for(int i = 0; i < maxVtxDisplay; i++) + { + vtxRead.Goto(i); + QTreeWidgetItem* itemTop = new QTreeWidgetItem(); + itemTop->setText(0,QString::number(i)); + itemTop->setText(1,QString("%1").arg(vaddr+i*vtcDec.GetDecVtxFmt().stride,8,16,QChar('0'))); + ui->vertexData->addTopLevelItem(itemTop); + + if (vtxRead.hasNormal()) + { + float nrm[3]; + vtxRead.ReadNrm(nrm); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(1,"Normal"); + item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(nrm[0]).arg(nrm[1]).arg(nrm[2])); + itemTop->addChild(item); + } + if (vtxRead.hasUV()) { + float uv[2]; + vtxRead.ReadUV(uv); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(1,"Uv"); + item->setText(2,QString("X: %1, Y: %2").arg(uv[0]).arg(uv[1])); + itemTop->addChild(item); + } + if (vtxRead.hasColor0()) { + float col0[4]; + vtxRead.ReadColor0(col0); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(1,"Color0"); + item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(col0[0]).arg(col0[1]).arg(col0[2])); + itemTop->addChild(item); + } + if (vtxRead.hasColor0()) { + float col1[3]; + vtxRead.ReadColor1(col1); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(1,"Color1"); + item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(col1[0]).arg(col1[1]).arg(col1[2])); + itemTop->addChild(item); + } + float pos[3]; + vtxRead.ReadPos(pos); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(1,"Position"); + item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(pos[0]).arg(pos[1]).arg(pos[2])); + itemTop->addChild(item); + } + for(int i = 0; i < ui->vertexData->columnCount(); i++) + { + ui->vertexData->resizeColumnToContents(i); + } +} + +void Debugger_DisplayList::on_vertexList_itemClicked(QTreeWidgetItem *item, int column) +{ + UpdateVertexInfo(); +} + +void Debugger_DisplayList::on_pushButton_clicked() +{ + maxVtxDisplay += 20; + UpdateVertexInfo(); +} + + +void Debugger_DisplayList::UpdateIndexInfo() +{ + ui->indexData->clear(); + + QTreeWidgetItem* item = ui->indexList->currentItem(); + if(item == 0) + return; + + GPUgstate state = drawGPUState[item->data(0,Qt::UserRole).toInt()]; + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (state.iaddr & 0xFFFFFF); + u32 iaddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + + int sizeIdx = 1; + if((state.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) + sizeIdx = 2; + + for(int i = 0; i < maxIdxDisplay; i++) + { + QTreeWidgetItem* itemTop = new QTreeWidgetItem(); + itemTop->setText(0,QString::number(i)); + itemTop->setText(1,QString("%1").arg(iaddr+i*sizeIdx,8,16,QChar('0'))); + int idx = 0; + if(sizeIdx == 1) + idx = Memory::Read_U8(iaddr+i*sizeIdx); + else + idx = Memory::Read_U16(iaddr+i*sizeIdx); + itemTop->setText(2,QString::number(idx)); + ui->indexData->addTopLevelItem(itemTop); + } + for(int i = 0; i < ui->indexData->columnCount(); i++) + { + ui->indexData->resizeColumnToContents(i); + } +} + + +void Debugger_DisplayList::on_nextIdx_clicked() +{ + maxIdxDisplay += 20; + UpdateIndexInfo(); +} + +void Debugger_DisplayList::on_indexList_itemClicked(QTreeWidgetItem *item, int column) +{ + UpdateIndexInfo(); +} + +void Debugger_DisplayList::on_displayListData_customContextMenuRequested(const QPoint &pos) +{ + QTreeWidgetItem* item = ui->displayListData->itemAt(pos); + if(!item) + return; + displayListDataSelected = item; + + QMenu menu(this); + + QAction *runToHere = new QAction(tr("Run to here"), this); + connect(runToHere, SIGNAL(triggered()), this, SLOT(RunToDLPC())); + menu.addAction(runToHere); + + menu.exec( ui->displayListData->mapToGlobal(pos)); +} + +void Debugger_DisplayList::RunToDLPC() +{ + u32 addr = displayListDataSelected->text(0).toInt(0,16); + host->SetGPUStep(true, 2, addr); + host->NextGPUStep(); +} + +void Debugger_DisplayList::on_texturesList_customContextMenuRequested(const QPoint &pos) +{ + QTreeWidgetItem* item = ui->texturesList->itemAt(pos); + if(!item) + return; + textureDataSelected = item; + + QMenu menu(this); + + QAction *runToDraw = new QAction(tr("Run to draw using this texture"), this); + connect(runToDraw, SIGNAL(triggered()), this, SLOT(RunToDrawTex())); + menu.addAction(runToDraw); + + menu.exec( ui->texturesList->mapToGlobal(pos)); +} + +void Debugger_DisplayList::RunToDrawTex() +{ + u32 addr = textureDataSelected->text(0).toInt(0,16); + host->SetGPUStep(true, 3, addr); + host->NextGPUStep(); +} diff --git a/Qt/debugger_displaylist.h b/Qt/debugger_displaylist.h new file mode 100644 index 0000000000..7ecec82302 --- /dev/null +++ b/Qt/debugger_displaylist.h @@ -0,0 +1,124 @@ +#ifndef DEBUGGER_DISPLAYLIST_H +#define DEBUGGER_DISPLAYLIST_H + +#include "Core/Debugger/DebugInterface.h" +#include +#include +#include "GPU/GPUState.h" +#include "native/gfx_es2/fbo.h" + +class MainWindow; +namespace Ui { +class Debugger_DisplayList; +} + + +class DListLine +{ +public: + u32 addr; + u32 cmd; + u32 data; + QString comment; + bool implementationNotFinished; + u32 texAddr; + u32 fboAddr; + u32 vtxAddr; + int vtxStart; + int vtxCount; + u32 idxAddr; + int idxStart; + int idxCount; +}; + +class Debugger_DisplayList : public QDialog +{ + Q_OBJECT + +public: + explicit Debugger_DisplayList(DebugInterface *_cpu, MainWindow *mainWindow_, QWidget *parent = 0); + ~Debugger_DisplayList(); + + void UpdateDisplayList(); + + void ShowDLCode(); + void FillDisplayListCmd(std::map &data, u32 pc, u32 prev, GPUgstate &state); + void Update(); + void UpdateRenderBuffer(); + void UpdateRenderBufferList(); + void UpdateVertexInfo(); + void UpdateIndexInfo(); +protected: + void showEvent(QShowEvent *); + +signals: + void updateDisplayList_(); + void updateRenderBufferList_(); + void updateRenderBuffer_(); + +private slots: + void UpdateDisplayListGUI(); + void UpdateRenderBufferListGUI(); + void UpdateRenderBufferGUI(); + void releaseLock(); + + void on_displayList_itemClicked(QTreeWidgetItem *item, int column); + + void on_stepBtn_clicked(); + + void on_runBtn_clicked(); + + void on_stopBtn_clicked(); + + void on_nextDrawBtn_clicked(); + + void on_gotoPCBtn_clicked(); + + void on_texturesList_itemDoubleClicked(QTreeWidgetItem *item, int column); + + void on_comboBox_currentIndexChanged(int index); + + void on_fboList_itemClicked(QTreeWidgetItem *item, int column); + + void on_nextDLBtn_clicked(); + void setCurrentFBO(u32 addr); + + void on_zoommBtn_clicked(); + + void on_zoompBtn_clicked(); + + void on_vertexList_itemClicked(QTreeWidgetItem *item, int column); + + void on_pushButton_clicked(); + + void on_nextIdx_clicked(); + + void on_indexList_itemClicked(QTreeWidgetItem *item, int column); + + void on_displayListData_customContextMenuRequested(const QPoint &pos); + + void on_texturesList_customContextMenuRequested(const QPoint &pos); + void RunToDLPC(); + void RunToDrawTex(); + +private: + QString DisassembleOp(u32 pc, u32 op, u32 prev, const GPUgstate &state); + + Ui::Debugger_DisplayList *ui; + DebugInterface* cpu; + MainWindow* mainWindow; + QTreeWidgetItem* displayListRowSelected; + QTreeWidgetItem* displayListDataSelected; + QTreeWidgetItem* textureDataSelected; + int currentRenderFrameDisplay; + FBO* currentTextureDisplay; + float fboZoomFactor; + int maxVtxDisplay; + int maxIdxDisplay; + + std::vector drawGPUState; + std::map vtxBufferSize; + std::map idxBufferSize; +}; + +#endif // DEBUGGER_DISPLAYLIST_H diff --git a/Qt/debugger_displaylist.ui b/Qt/debugger_displaylist.ui new file mode 100644 index 0000000000..894a479ad2 --- /dev/null +++ b/Qt/debugger_displaylist.ui @@ -0,0 +1,533 @@ + + + Debugger_DisplayList + + + + 0 + 0 + 795 + 506 + + + + Dialog + + + + + + Qt::Horizontal + + + + Qt::Vertical + + + + DisplayList + + + + + + Qt::CustomContextMenu + + + false + + + false + + + false + + + 30 + + + + Id + + + + + Status + + + + + Start Address + + + + + Current Address + + + + + + + + + + Run + + + + + + + Stop + + + + + + + Next DL + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + + Commands + + + + + + Qt::CustomContextMenu + + + false + + + false + + + false + + + 2 + + + false + + + + 1 + + + + + 2 + + + + + + + + + + Step + + + + + + + Next Draw + + + + + + + Goto PC + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Textures + + + + + + Qt::CustomContextMenu + + + + Address + + + + + Width + + + + + Height + + + + + Format + + + + + + + + + Vertex Buffer + + + + + + 30 + + + + Address + + + + + Coord Type + + + + + Number Morph + + + + + Number Weights + + + + + Has Weight + + + + + Has Position + + + + + Has Normal + + + + + Has Color + + + + + Has UV + + + + + + + + 30 + + + + Idx + + + + + Address + + + + + Values + + + + + + + + + + Next 20 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Index Buffer + + + + + + Qt::Vertical + + + + + Address + + + + + + 30 + + + + Idx + + + + + Adress + + + + + Value + + + + + + + + + + + Next 20 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Framebuffer + + + + + + Qt::Vertical + + + + + 0 + 0 + + + + + VAddress + + + + + Width + + + + + Height + + + + + Format + + + + + + + 0 + 0 + + + + true + + + + + 0 + 0 + 375 + 76 + + + + + + + QFrame::Box + + + + + + true + + + + + + + + + + + + + + Display : + + + + + + + + Color + + + + + Depth + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Zoom- + + + + + + + Zoom+ + + + + + + + + + + + + + + diff --git a/Qt/debugger_memory.cpp b/Qt/debugger_memory.cpp index 3f73ccefd9..3b5cdedf08 100644 --- a/Qt/debugger_memory.cpp +++ b/Qt/debugger_memory.cpp @@ -51,9 +51,7 @@ void Debugger_Memory::Goto(u32 addr) void Debugger_Memory::on_editAddress_textChanged(const QString &arg1) { - u32 addr; - sscanf(arg1.toStdString().c_str(),"%08x",&addr); - ui->memView->gotoAddr(addr & ~3); + ui->memView->gotoAddr(arg1.toInt(0,16) & ~3); } void Debugger_Memory::on_normalBtn_clicked() @@ -83,7 +81,7 @@ void Debugger_Memory::NotifyMapLoaded() if(symbolMap.GetSymbolType(i) & ST_DATA) { QListWidgetItem* item = new QListWidgetItem(); - item->setText(QString(symbolMap.GetSymbolName(i)) + " ("+ QVariant(symbolMap.GetSymbolSize(i)).toString() +")"); + item->setText(QString(symbolMap.GetSymbolName(i)) + " ("+ QString::number(symbolMap.GetSymbolSize(i)) +")"); item->setData(Qt::UserRole, symbolMap.GetAddress(i)); ui->symbols->addItem(item); } diff --git a/Qt/debugger_memorytex.cpp b/Qt/debugger_memorytex.cpp new file mode 100644 index 0000000000..cdbf4ae640 --- /dev/null +++ b/Qt/debugger_memorytex.cpp @@ -0,0 +1,95 @@ +#include "debugger_memorytex.h" +#include "gfx_es2/gl_state.h" +#include "gfx/gl_common.h" +#include "gfx/gl_lost_manager.h" +#include "ui_debugger_memorytex.h" +#include "Core/MemMap.h" +#include +#include +#include "Core/HLE/sceDisplay.h" +#include "GPU/GPUInterface.h" +#include "EmuThread.h" +#include "base/display.h" + +Debugger_MemoryTex::Debugger_MemoryTex(QWidget *parent) : + QDialog(parent), + ui(new Ui::Debugger_MemoryTex) +{ + ui->setupUi(this); +} + +Debugger_MemoryTex::~Debugger_MemoryTex() +{ + delete ui; +} + + +void Debugger_MemoryTex::showEvent(QShowEvent *) +{ + +#ifdef Q_WS_X11 + // Hack to remove the X11 crash with threaded opengl when opening the first dialog + EmuThread_LockDraw(true); + QTimer::singleShot(100, this, SLOT(releaseLock())); +#endif +} + +void Debugger_MemoryTex::releaseLock() +{ + EmuThread_LockDraw(false); +} + + +void Debugger_MemoryTex::ShowTex(const GPUgstate &state) +{ + ui->texaddr->setText(QString("%1").arg(state.texaddr[0] & 0xFFFFFF,8,16,QChar('0'))); + ui->texbufwidth0->setText(QString("%1").arg(state.texbufwidth[0] & 0xFFFFFF,8,16,QChar('0'))); + ui->texformat->setText(QString("%1").arg(state.texformat & 0xFFFFFF,8,16,QChar('0'))); + ui->texsize->setText(QString("%1").arg(state.texsize[0] & 0xFFFFFF,8,16,QChar('0'))); + ui->texmode->setText(QString("%1").arg(state.texmode & 0xFFFFFF,8,16,QChar('0'))); + ui->clutformat->setText(QString("%1").arg(state.clutformat & 0xFFFFFF,8,16,QChar('0'))); + ui->clutaddr->setText(QString("%1").arg(state.clutaddr & 0xFFFFFF,8,16,QChar('0'))); + ui->clutaddrupper->setText(QString("%1").arg(state.clutaddrupper & 0xFFFFFF,8,16,QChar('0'))); + ui->loadclut->setText(QString("%1").arg(state.loadclut & 0xFFFFFF,8,16,QChar('0'))); + on_readBtn_clicked(); + + show(); +} + +void Debugger_MemoryTex::on_readBtn_clicked() +{ + EmuThread_LockDraw(true); + + GPUgstate state; + state.texaddr[0] = ui->texaddr->text().toInt(0,16); + state.texbufwidth[0] = ui->texbufwidth0->text().toInt(0,16); + state.texformat = ui->texformat->text().toInt(0,16); + state.texsize[0] = ui->texsize->text().toInt(0,16); + state.texmode = ui->texmode->text().toInt(0,16); + state.clutformat = ui->clutformat->text().toInt(0,16); + state.clutaddr = ui->clutaddr->text().toInt(0,16); + state.clutaddrupper = ui->clutaddrupper->text().toInt(0,16); + state.loadclut = ui->loadclut->text().toInt(0,16); + int bufW = state.texbufwidth[0] & 0x3ff; + int w = 1 << (state.texsize[0] & 0xf); + int h = 1 << ((state.texsize[0]>>8) & 0xf); + w = std::max(bufW,w); + uchar* newData = new uchar[w*h*4]; + + if(gpu->DecodeTexture(newData, state)) + { + QImage img = QImage(newData, w, h, w*4, QImage::Format_ARGB32); // EmuThread_GrabBackBuffer(); + + QPixmap pixmap = QPixmap::fromImage(img); + ui->textureImg->setPixmap(pixmap); + ui->textureImg->setMinimumWidth(pixmap.width()); + ui->textureImg->setMinimumHeight(pixmap.height()); + ui->textureImg->setMaximumWidth(pixmap.width()); + ui->textureImg->setMaximumHeight(pixmap.height()); + } + + delete[] newData; + EmuThread_LockDraw(false); + + +} diff --git a/Qt/debugger_memorytex.h b/Qt/debugger_memorytex.h new file mode 100644 index 0000000000..c04677e8d2 --- /dev/null +++ b/Qt/debugger_memorytex.h @@ -0,0 +1,30 @@ +#ifndef DEBUGGER_MEMORYTEX_H +#define DEBUGGER_MEMORYTEX_H + +#include +#include "GPU/GPUState.h" + +namespace Ui { +class Debugger_MemoryTex; +} + +class Debugger_MemoryTex : public QDialog +{ + Q_OBJECT + +public: + explicit Debugger_MemoryTex(QWidget *parent = 0); + ~Debugger_MemoryTex(); + + void ShowTex(const GPUgstate& state); +protected: + void showEvent(QShowEvent *); +private slots: + void releaseLock(); + void on_readBtn_clicked(); + +private: + Ui::Debugger_MemoryTex *ui; +}; + +#endif // DEBUGGER_MEMORYTEX_H diff --git a/Qt/debugger_memorytex.ui b/Qt/debugger_memorytex.ui new file mode 100644 index 0000000000..b163010222 --- /dev/null +++ b/Qt/debugger_memorytex.ui @@ -0,0 +1,177 @@ + + + Debugger_MemoryTex + + + + 0 + 0 + 768 + 546 + + + + Dialog + + + + + + Qt::Horizontal + + + + + + + + + TexAddr + + + + + + + TexBufWidth0 + + + + + + + TexFormat + + + + + + + TexSize + + + + + + + ClutFormat + + + + + + + ClutAddr + + + + + + + ClutAddrUpper + + + + + + + LoadClut + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TexMode + + + + + + + + + + + + + + Read + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + true + + + + + 0 + 0 + 76 + 526 + + + + + + + QFrame::Box + + + + + + + + + + + + + + + + diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index c951d70f53..c6b45a5dcc 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -28,7 +28,9 @@ MainWindow::MainWindow(QWidget *parent) : ui(new Ui::MainWindow), nextState(CORE_POWERDOWN), dialogDisasm(0), - memoryWindow(0) + memoryWindow(0), + memoryTexWindow(0), + displaylistWindow(0) { ui->setupUi(this); qApp->installEventFilter(this); @@ -109,15 +111,11 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co gfxLog = true; break; case 'j': - g_Config.iCpuCore = CPU_JIT; - g_Config.bSaveSettings = false; - break; - case 'f': - g_Config.iCpuCore = CPU_FASTINTERPRETER; + g_Config.bJit = true; g_Config.bSaveSettings = false; break; case 'i': - g_Config.iCpuCore = CPU_INTERPRETER; + g_Config.bJit = false; g_Config.bSaveSettings = false; break; case 'l': @@ -210,6 +208,8 @@ void MainWindow::Boot() on_action_OptionsFullScreen_triggered(); memoryWindow = new Debugger_Memory(currentDebugMIPS, this, this); + memoryTexWindow = new Debugger_MemoryTex(this); + displaylistWindow = new Debugger_DisplayList(currentDebugMIPS, this, this); if (dialogDisasm) dialogDisasm->NotifyMapLoaded(); @@ -231,9 +231,8 @@ void MainWindow::UpdateMenus() { ui->action_OptionsDisplayRawFramebuffer->setChecked(g_Config.bDisplayFramebuffer); ui->action_OptionsIgnoreIllegalReadsWrites->setChecked(g_Config.bIgnoreBadMemAccess); - ui->action_CPUInterpreter->setChecked(g_Config.iCpuCore == CPU_INTERPRETER); - ui->action_CPUFastInterpreter->setChecked(g_Config.iCpuCore == CPU_FASTINTERPRETER); - ui->action_CPUDynarec->setChecked(g_Config.iCpuCore == CPU_JIT); + ui->action_CPUInterpreter->setChecked(!g_Config.bJit); + ui->action_CPUDynarec->setChecked(g_Config.bJit); ui->action_OptionsBufferedRendering->setChecked(g_Config.bBufferedRendering); ui->action_OptionsShowDebugStatistics->setChecked(g_Config.bShowDebugStats); ui->action_OptionsWireframe->setChecked(g_Config.bDrawWireframe); @@ -266,11 +265,12 @@ void MainWindow::UpdateMenus() ui->action_FileQuickSaveState->setEnabled(!enable); ui->action_CPUDynarec->setEnabled(enable); ui->action_CPUInterpreter->setEnabled(enable); - ui->action_CPUFastInterpreter->setEnabled(enable); ui->action_EmulationStop->setEnabled(!enable); ui->action_DebugDumpFrame->setEnabled(!enable); ui->action_DebugDisassembly->setEnabled(!enable); ui->action_DebugMemoryView->setEnabled(!enable); + ui->action_DebugMemoryViewTexture->setEnabled(!enable); + ui->action_DebugDisplayList->setEnabled(!enable); ui->action_OptionsScreen1x->setChecked(0 == (g_Config.iWindowZoom - 1)); ui->action_OptionsScreen2x->setChecked(1 == (g_Config.iWindowZoom - 1)); @@ -359,6 +359,10 @@ void MainWindow::on_action_EmulationStop_triggered() dialogDisasm->close(); if(memoryWindow && memoryWindow->isVisible()) memoryWindow->close(); + if(memoryTexWindow && memoryTexWindow->isVisible()) + memoryTexWindow->close(); + if(displaylistWindow && displaylistWindow->isVisible()) + displaylistWindow->close(); EmuThread_StopGame(); SetGameTitle(""); @@ -518,19 +522,13 @@ void MainWindow::on_action_FileExit_triggered() void MainWindow::on_action_CPUDynarec_triggered() { - g_Config.iCpuCore = CPU_JIT; + g_Config.bJit = true; UpdateMenus(); } void MainWindow::on_action_CPUInterpreter_triggered() { - g_Config.iCpuCore = CPU_INTERPRETER; - UpdateMenus(); -} - -void MainWindow::on_action_CPUFastInterpreter_triggered() -{ - g_Config.iCpuCore = CPU_FASTINTERPRETER; + g_Config.bJit = false; UpdateMenus(); } @@ -697,22 +695,12 @@ void MainWindow::keyPressEvent(QKeyEvent *e) return; } - for (int b = 0; b < controllistCount; b++) { - if (e->key() == controllist[b].key) - { - input_state.pad_buttons |= (controllist[b].emu_id); - } - } + pressedKeys.insert(e->key()); } void MainWindow::keyReleaseEvent(QKeyEvent *e) { - for (int b = 0; b < controllistCount; b++) { - if (e->key() == controllist[b].key) - { - input_state.pad_buttons &= ~(controllist[b].emu_id); - } - } + pressedKeys.remove(e->key()); } void MainWindow::on_MainWindow_destroyed() @@ -928,7 +916,17 @@ void MainWindow::ShowMemory(u32 addr) void MainWindow::Update() { + UpdateInputState(&input_state); + for (int i = 0; i < controllistCount; i++) + { + if (pressedKeys.contains(controllist[i].key) || + input_state.pad_buttons_down & controllist[i].emu_id) + __CtrlButtonDown(controllist[i].psp_id); + else + __CtrlButtonUp(controllist[i].psp_id); + } + __CtrlSetAnalog(input_state.pad_lstick_x, input_state.pad_lstick_y); } void MainWindow::on_action_EmulationReset_triggered() @@ -943,6 +941,10 @@ void MainWindow::on_action_EmulationReset_triggered() dialogDisasm->close(); if(memoryWindow) memoryWindow->close(); + if(memoryTexWindow) + memoryTexWindow->close(); + if(displaylistWindow) + displaylistWindow->close(); EmuThread_StopGame(); @@ -1027,3 +1029,15 @@ void MainWindow::on_action_Sound_triggered() g_Config.bEnableSound = !g_Config.bEnableSound; UpdateMenus(); } + +void MainWindow::on_action_DebugMemoryViewTexture_triggered() +{ + if(memoryTexWindow) + memoryTexWindow->show(); +} + +void MainWindow::on_action_DebugDisplayList_triggered() +{ + if(displaylistWindow) + displaylistWindow->show(); +} diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index 9b83c867ae..d2de287927 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -8,6 +8,8 @@ #include "input/input_state.h" #include "debugger_disasm.h" #include "debugger_memory.h" +#include "debugger_memorytex.h" +#include "debugger_displaylist.h" #include "controls.h" #include "gamepaddialog.h" @@ -33,6 +35,8 @@ public: Debugger_Disasm* GetDialogDisasm() { return dialogDisasm; } Debugger_Memory* GetDialogMemory() { return memoryWindow; } + Debugger_MemoryTex* GetDialogMemoryTex() { return memoryTexWindow; } + Debugger_DisplayList* GetDialogDisplaylist() { return displaylistWindow; } CoreState GetNextState() { return nextState; } void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *); @@ -81,8 +85,6 @@ private slots: void on_action_CPUInterpreter_triggered(); - void on_action_CPUFastInterpreter_triggered(); - void on_action_DebugLoadMapFile_triggered(); void on_action_DebugSaveMapFile_triggered(); @@ -171,6 +173,10 @@ private slots: void on_action_Sound_triggered(); + void on_action_DebugMemoryViewTexture_triggered(); + + void on_action_DebugDisplayList_triggered(); + private: void loadLanguage(const QString &language); void createLanguageMenu(); @@ -190,8 +196,12 @@ private: Debugger_Disasm *dialogDisasm; Debugger_Memory *memoryWindow; + Debugger_MemoryTex *memoryTexWindow; + Debugger_DisplayList *displaylistWindow; Controls* controls; GamePadDialog* gamePadDlg; + + QSet pressedKeys; }; #endif // MAINWINDOW_H diff --git a/Qt/mainwindow.ui b/Qt/mainwindow.ui index a167aad884..a6ef9df025 100644 --- a/Qt/mainwindow.ui +++ b/Qt/mainwindow.ui @@ -44,7 +44,7 @@ 0 0 800 - 21 + 23 @@ -83,8 +83,10 @@ + + @@ -180,7 +182,6 @@ &Core - @@ -289,14 +290,6 @@ &Interpreter - - - true - - - &Slightly Faster Interpreter - - true @@ -625,6 +618,11 @@ Memory View Texture... + + + DisplayList... + + true diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index cd38e3ead5..ac7e4fc153 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -68,7 +68,7 @@ DWORD TheThread(LPVOID x) coreParameter.fileToStart = fileToStart; coreParameter.enableSound = true; coreParameter.gpuCore = GPU_GLES; - coreParameter.cpuCore = (CPUCore)g_Config.iCpuCore; + coreParameter.cpuCore = g_Config.bJit ? CPU_JIT : CPU_INTERPRETER; coreParameter.enableDebugging = true; coreParameter.printfEmuLog = false; coreParameter.headLess = false; diff --git a/Windows/OpenGLBase.cpp b/Windows/OpenGLBase.cpp index f739dcab1e..92d4af4c14 100644 --- a/Windows/OpenGLBase.cpp +++ b/Windows/OpenGLBase.cpp @@ -49,14 +49,7 @@ void GL_Resized() // Resize And Initialize The GL Window glstate.viewport.restore(); } - -void GL_BeginFrame() -{ - -} - - -void GL_EndFrame() +void GL_SwapBuffers() { SwapBuffers(hDC); } diff --git a/Windows/OpenGLBase.h b/Windows/OpenGLBase.h index 50a154089f..b26ed0ebfd 100644 --- a/Windows/OpenGLBase.h +++ b/Windows/OpenGLBase.h @@ -2,9 +2,10 @@ #pragma once +#define WIN32_LEAN_AND_MEAN +#include bool GL_Init(HWND window); void GL_Shutdown(); void GL_Resized(); -void GL_BeginFrame(); -void GL_EndFrame(); +void GL_SwapBuffers(); diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index d2538d562b..6c0a8b3408 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -209,10 +209,12 @@ Android - Android + + Windows + diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index f7afab484f..cef4e558e6 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -117,11 +117,6 @@ void WindowsHost::BeginFrame() for (auto iter = this->input.begin(); iter != this->input.end(); iter++) if ((*iter)->UpdateState() == 0) break; // *iter is std::shared_ptr, **iter is InputDevice - GL_BeginFrame(); -} -void WindowsHost::EndFrame() -{ - GL_EndFrame(); } void WindowsHost::BootDone() diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h index c46c888543..923acf10b8 100644 --- a/Windows/WindowsHost.h +++ b/Windows/WindowsHost.h @@ -21,7 +21,6 @@ public: void InitGL(); void BeginFrame(); - void EndFrame(); void ShutdownGL(); void InitSound(PMixer *mixer); diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index 8db545ffd4..b97678aad5 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -73,8 +73,7 @@ namespace MainWindow void Init(HINSTANCE hInstance) { -#ifdef THEMES - WTL::CTheme::IsThemingSupported(); +#ifdef THEMES WTL::CTheme::IsThemingSupported(); #endif //Register classes WNDCLASSEX wcex; @@ -447,20 +446,21 @@ namespace MainWindow gpu->Resized(); // easy way to force a clear... break; + case ID_OPTIONS_FRAMESKIP: + g_Config.iFrameSkip = !g_Config.iFrameSkip; + UpdateMenus(); + break; + case ID_FILE_EXIT: DestroyWindow(hWnd); break; case ID_CPU_DYNAREC: - g_Config.iCpuCore = CPU_JIT; + g_Config.bJit = true; UpdateMenus(); break; case ID_CPU_INTERPRETER: - g_Config.iCpuCore = CPU_INTERPRETER; - UpdateMenus(); - break; - case ID_CPU_FASTINTERPRETER: - g_Config.iCpuCore = CPU_FASTINTERPRETER; + g_Config.bJit = false; UpdateMenus(); break; @@ -701,9 +701,8 @@ namespace MainWindow // CHECK(ID_OPTIONS_EMULATESYSCALL,g_bEmulateSyscall); CHECKITEM(ID_OPTIONS_DISPLAYRAWFRAMEBUFFER, g_Config.bDisplayFramebuffer); CHECKITEM(ID_OPTIONS_IGNOREILLEGALREADS,g_Config.bIgnoreBadMemAccess); - CHECKITEM(ID_CPU_INTERPRETER,g_Config.iCpuCore == CPU_INTERPRETER); - CHECKITEM(ID_CPU_FASTINTERPRETER,g_Config.iCpuCore == CPU_FASTINTERPRETER); - CHECKITEM(ID_CPU_DYNAREC,g_Config.iCpuCore == CPU_JIT); + CHECKITEM(ID_CPU_INTERPRETER,g_Config.bJit == false); + CHECKITEM(ID_CPU_DYNAREC,g_Config.bJit == true); CHECKITEM(ID_OPTIONS_BUFFEREDRENDERING, g_Config.bBufferedRendering); CHECKITEM(ID_OPTIONS_SHOWDEBUGSTATISTICS, g_Config.bShowDebugStats); CHECKITEM(ID_OPTIONS_WIREFRAME, g_Config.bDrawWireframe); @@ -717,6 +716,7 @@ namespace MainWindow CHECKITEM(ID_OPTIONS_DISABLEG3DLOG, g_Config.bDisableG3DLog); CHECKITEM(ID_OPTIONS_VERTEXCACHE, g_Config.bVertexCache); CHECKITEM(ID_OPTIONS_SHOWFPS, g_Config.bShowFPSCounter); + CHECKITEM(ID_OPTIONS_FRAMESKIP, g_Config.iFrameSkip != 0); UINT enable = !Core_IsStepping() ? MF_GRAYED : MF_ENABLED; EnableMenuItem(menu,ID_EMULATION_RUN, g_State.bEmuThreadStarted ? enable : MF_GRAYED); @@ -731,7 +731,6 @@ namespace MainWindow EnableMenuItem(menu,ID_FILE_QUICKLOADSTATE,!enable); EnableMenuItem(menu,ID_CPU_DYNAREC,enable); EnableMenuItem(menu,ID_CPU_INTERPRETER,enable); - EnableMenuItem(menu,ID_CPU_FASTINTERPRETER,enable); EnableMenuItem(menu,ID_DVD_INSERTISO,enable); EnableMenuItem(menu,ID_FILE_BOOTBIOS,enable); EnableMenuItem(menu,ID_EMULATION_STOP,!enable); diff --git a/Windows/main.cpp b/Windows/main.cpp index b568189d07..b40541814f 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -76,15 +76,11 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin switch (__argv[i][1]) { case 'j': - g_Config.iCpuCore = CPU_JIT; + g_Config.bJit = true; g_Config.bSaveSettings = false; break; case 'i': - g_Config.iCpuCore = CPU_INTERPRETER; - g_Config.bSaveSettings = false; - break; - case 'f': - g_Config.iCpuCore = CPU_FASTINTERPRETER; + g_Config.bJit = false; g_Config.bSaveSettings = false; break; case 'l': @@ -163,9 +159,12 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin EmuThread_Start(fileToStart); } - else + if (g_Config.bBrowse) MainWindow::BrowseAndBoot(); + if (!hideLog) + SetForegroundWindow(hwndMain); + if (fileToStart != NULL && stateToLoad != NULL) SaveState::Load(stateToLoad); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index ae0ec17aca..8d0a8e1004 100644 Binary files a/Windows/ppsspp.rc and b/Windows/ppsspp.rc differ diff --git a/Windows/resource.h b/Windows/resource.h index 91f5936a7e..f883f17e5b 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -260,6 +260,7 @@ #define ID_OPTIONS_VERTEXCACHE 40136 #define ID_OPTIONS_SHOWFPS 40137 #define ID_OPTIONS_STRETCHDISPLAY 40138 +#define ID_OPTIONS_FRAMESKIP 40139 #define IDC_STATIC -1 // Next default values for new objects @@ -267,7 +268,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 233 -#define _APS_NEXT_COMMAND_VALUE 40139 +#define _APS_NEXT_COMMAND_VALUE 40140 #define _APS_NEXT_CONTROL_VALUE 1163 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 236c3630d5..30812f98fa 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,7 +2,8 @@ + android:versionName="0.61" + android:installLocation="auto" > diff --git a/android/jni/EmuScreen.cpp b/android/jni/EmuScreen.cpp index 875dff43ed..8a0d13f84e 100644 --- a/android/jni/EmuScreen.cpp +++ b/android/jni/EmuScreen.cpp @@ -47,7 +47,7 @@ EmuScreen::EmuScreen(const std::string &filename) : invalid_(true) INFO_LOG(BOOT, "Starting up hardware."); CoreParameter coreParam; - coreParam.cpuCore = (CPUCore)g_Config.iCpuCore; + coreParam.cpuCore = g_Config.bJit ? CPU_JIT : CPU_INTERPRETER; coreParam.gpuCore = GPU_GLES; coreParam.enableSound = g_Config.bEnableSound; coreParam.fileToStart = fileToStart; @@ -156,7 +156,7 @@ void EmuScreen::render() // We just run the CPU until we get to vblank. This will quickly sync up pretty nicely. // The actual number of cycles doesn't matter so much here as we will break due to CORE_NEXTFRAME, most of the time hopefully... - int blockTicks = usToCycles(1000000 / 2); + int blockTicks = usToCycles(1000000 / 10); // Run until CORE_NEXTFRAME while (coreState == CORE_RUNNING) { diff --git a/android/jni/MenuScreens.cpp b/android/jni/MenuScreens.cpp index 56b78410bf..c170f74a2a 100644 --- a/android/jni/MenuScreens.cpp +++ b/android/jni/MenuScreens.cpp @@ -251,6 +251,9 @@ void InGameMenuScreen::render() { UICheckBox(GEN_ID, x, y += 50, "Stretch to display", ALIGN_TOPLEFT, &g_Config.bStretchToDisplay); UICheckBox(GEN_ID, x, y += 50, "Hardware Transform", ALIGN_TOPLEFT, &g_Config.bHardwareTransform); + bool fs = g_Config.iFrameSkip == 1; + UICheckBox(GEN_ID, x, y += 50, "Frameskip", ALIGN_TOPLEFT, &fs); + g_Config.iFrameSkip = fs ? 1 : 0; // TODO: Add UI for more than one slot. VLinear vlinear1(x, y + 80, 20); @@ -314,11 +317,9 @@ void SettingsScreen::render() { UICheckBox(GEN_ID, x, y += stride, "Draw using Stream VBO", ALIGN_TOPLEFT, &g_Config.bUseVBO); UICheckBox(GEN_ID, x, y += stride, "Vertex Cache", ALIGN_TOPLEFT, &g_Config.bVertexCache); - bool useJit = g_Config.iCpuCore == CPU_JIT; - UICheckBox(GEN_ID, x, y += stride, "JIT (Dynarec)", ALIGN_TOPLEFT, &useJit); - if (g_Config.iCpuCore == CPU_JIT) - UICheckBox(GEN_ID, x + 450, y, "Fastmem (may crash)", ALIGN_TOPLEFT, &g_Config.bFastMemory); - g_Config.iCpuCore = useJit ? CPU_JIT : CPU_INTERPRETER; + UICheckBox(GEN_ID, x, y += stride, "JIT (Dynarec)", ALIGN_TOPLEFT, &g_Config.bJit); + if (g_Config.bJit) + UICheckBox(GEN_ID, x + 450, y, "Fastmem (may be unstable)", ALIGN_TOPLEFT, &g_Config.bFastMemory); // ui_draw2d.DrawText(UBUNTU48, "much faster JIT coming later", x, y+=50, 0xcFFFFFFF, ALIGN_LEFT); UICheckBox(GEN_ID, x, y += stride, "On-screen Touch Controls", ALIGN_TOPLEFT, &g_Config.bShowTouchControls); if (g_Config.bShowTouchControls) { diff --git a/android/jni/NativeApp.cpp b/android/jni/NativeApp.cpp index 2979d3b57f..e00c491560 100644 --- a/android/jni/NativeApp.cpp +++ b/android/jni/NativeApp.cpp @@ -101,7 +101,6 @@ public: virtual void InitGL() {} virtual void BeginFrame() {} - virtual void EndFrame() {} virtual void ShutdownGL() {} virtual void InitSound(PMixer *mixer); @@ -201,15 +200,11 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co gfxLog = true; break; case 'j': - g_Config.iCpuCore = CPU_JIT; - g_Config.bSaveSettings = false; - break; - case 'f': - g_Config.iCpuCore = CPU_FASTINTERPRETER; + g_Config.bJit = true; g_Config.bSaveSettings = false; break; case 'i': - g_Config.iCpuCore = CPU_INTERPRETER; + g_Config.bJit = false; g_Config.bSaveSettings = false; break; case '-': diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 3cc16ae7f9..d9289c8cba 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -4,12 +4,13 @@ #include -#include "../Core/Config.h" -#include "../Core/Core.h" -#include "../Core/CoreTiming.h" -#include "../Core/System.h" -#include "../Core/MIPS/MIPS.h" -#include "../Core/Host.h" +#include "Core/Config.h" +#include "Core/Core.h" +#include "Core/CoreTiming.h" +#include "Core/System.h" +#include "Core/MIPS/MIPS.h" +#include "Core/Host.h" +#include "Windows/OpenGLBase.h" #include "Log.h" #include "LogManager.h" @@ -46,6 +47,9 @@ public: } }; +// Temporary hack around annoying linking error. +void GL_SwapBuffers() { } + void printUsage(const char *progname, const char *reason) { if (reason != NULL) @@ -66,7 +70,6 @@ void printUsage(const char *progname, const char *reason) } fprintf(stderr, " -i use the interpreter\n"); - fprintf(stderr, " -f use the fast interpreter\n"); fprintf(stderr, " -j use jit (default)\n"); fprintf(stderr, " -c, --compare compare with output in file.expected\n"); fprintf(stderr, "\nSee headless.txt for details.\n"); @@ -76,7 +79,6 @@ int main(int argc, const char* argv[]) { bool fullLog = false; bool useJit = false; - bool fastInterpreter = false; bool autoCompare = false; bool useGraphics = false; @@ -101,8 +103,6 @@ int main(int argc, const char* argv[]) useJit = false; else if (!strcmp(argv[i], "-j")) useJit = true; - else if (!strcmp(argv[i], "-f")) - fastInterpreter = true; else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compare")) autoCompare = true; else if (!strcmp(argv[i], "--graphics")) @@ -156,7 +156,7 @@ int main(int argc, const char* argv[]) coreParameter.fileToStart = bootFilename; coreParameter.mountIso = mountIso ? mountIso : ""; coreParameter.startPaused = false; - coreParameter.cpuCore = fastInterpreter ? CPU_FASTINTERPRETER : (useJit ? CPU_JIT : CPU_INTERPRETER); + coreParameter.cpuCore = useJit ? CPU_JIT : CPU_INTERPRETER; coreParameter.gpuCore = headlessHost->isGLWorking() ? GPU_GLES : GPU_NULL; coreParameter.enableSound = false; coreParameter.headLess = true; @@ -196,8 +196,10 @@ int main(int argc, const char* argv[]) mipsr4k.RunLoopUntil(nowTicks + frameTicks); // If we were rendering, this might be a nice time to do something about it. - if (coreState == CORE_NEXTFRAME) + if (coreState == CORE_NEXTFRAME) { + headlessHost->SwapBuffers(); coreState = CORE_RUNNING; + } } host->ShutdownGL(); diff --git a/headless/StubHost.h b/headless/StubHost.h index 1533c381c3..19e71c3b68 100644 --- a/headless/StubHost.h +++ b/headless/StubHost.h @@ -35,7 +35,6 @@ public: virtual void InitGL() {} virtual void BeginFrame() {} - virtual void EndFrame() {} virtual void ShutdownGL() {} virtual void InitSound(PMixer *mixer) {} @@ -53,4 +52,9 @@ public: virtual void SetComparisonScreenshot(const std::string &filename) {} virtual bool isGLWorking() { return false; } + + + // Unique for HeadlessHost + virtual void SwapBuffers() {} + }; \ No newline at end of file diff --git a/headless/WindowsHeadlessHost.cpp b/headless/WindowsHeadlessHost.cpp index 5e7448ae23..a6629982f2 100644 --- a/headless/WindowsHeadlessHost.cpp +++ b/headless/WindowsHeadlessHost.cpp @@ -218,7 +218,7 @@ void WindowsHeadlessHost::BeginFrame() } -void WindowsHeadlessHost::EndFrame() +void WindowsHeadlessHost::SwapBuffers() { - SwapBuffers(hDC); + ::SwapBuffers(hDC); } diff --git a/headless/WindowsHeadlessHost.h b/headless/WindowsHeadlessHost.h index 5abc20ca05..d624f4d3cc 100644 --- a/headless/WindowsHeadlessHost.h +++ b/headless/WindowsHeadlessHost.h @@ -30,10 +30,11 @@ class WindowsHeadlessHost : public HeadlessHost public: virtual void InitGL(); virtual void BeginFrame(); - virtual void EndFrame(); virtual void ShutdownGL(); virtual bool isGLWorking() { return glOkay; } + virtual void SwapBuffers(); + virtual void SendDebugOutput(const std::string &output); virtual void SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h); virtual void SetComparisonScreenshot(const std::string &filename); diff --git a/ios/AppDelegate.h b/ios/AppDelegate.h new file mode 100644 index 0000000000..263e85d369 --- /dev/null +++ b/ios/AppDelegate.h @@ -0,0 +1,13 @@ +// AppDelegate.h boilerplate + +#import + +@class ViewController; + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@property (strong, nonatomic) ViewController *viewController; + +@end diff --git a/ios/AppDelegate.m b/ios/AppDelegate.m new file mode 100644 index 0000000000..8601d4fee7 --- /dev/null +++ b/ios/AppDelegate.m @@ -0,0 +1,25 @@ +// AppDelegate.m boilerplate + +#import "AppDelegate.h" + +#import "ViewController.h" + +@implementation AppDelegate + +- (void)dealloc +{ + [_window release]; + [_viewController release]; + [super dealloc]; +} + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; + self.viewController = [[[ViewController alloc] init] autorelease]; + self.window.rootViewController = self.viewController; + [self.window makeKeyAndVisible]; + return YES; +} + +@end diff --git a/ios/PPSSPP-Info.plist b/ios/PPSSPP-Info.plist new file mode 100644 index 0000000000..5fe1a739c6 --- /dev/null +++ b/ios/PPSSPP-Info.plist @@ -0,0 +1,46 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.rock88dev.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ios/PPSSPP-Prefix.pch b/ios/PPSSPP-Prefix.pch new file mode 100644 index 0000000000..6cc2cfc1a8 --- /dev/null +++ b/ios/PPSSPP-Prefix.pch @@ -0,0 +1,9 @@ +#import + +#ifndef __IPHONE_4_0 +#warning "This project uses features only available in iOS SDK 4.0 and later." +#endif + +#ifdef __OBJC__ + #import +#endif diff --git a/ios/ViewController.h b/ios/ViewController.h new file mode 100644 index 0000000000..b505050d44 --- /dev/null +++ b/ios/ViewController.h @@ -0,0 +1,8 @@ +// ViewController.h boilerplate + +#import +#import + +@interface ViewController : GLKViewController + +@end diff --git a/ios/ViewController.mm b/ios/ViewController.mm new file mode 100644 index 0000000000..576d3b68ca --- /dev/null +++ b/ios/ViewController.mm @@ -0,0 +1,241 @@ +// +// ViewController.m +// +// Created by rock88 +// Modified by xSacha +// + +#import "ViewController.h" +#import + +#include "base/display.h" +#include "base/timeutil.h" +#include "file/zip_read.h" +#include "input/input_state.h" +#include "net/resolve.h" +#include "ui_atlas.h" +#include "ui/screen.h" + +#include "Config.h" +#include "gfx_es2/fbo.h" + +#define IS_IPAD() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) + +extern void UIUpdateMouse(int i, float x, float y, bool down); + +float dp_xscale = 1.0f; +float dp_yscale = 1.0f; + +static uint32_t pad_buttons_async_set = 0; +static uint32_t pad_buttons_async_clear = 0; + +extern ScreenManager *screenManager; +InputState input_state; + +extern std::string ram_temp_file; + +@interface ViewController () + +@property (strong, nonatomic) EAGLContext *context; +@property (nonatomic,retain) NSString* documentsPath; +@property (nonatomic,retain) NSString* bundlePath; +@property (nonatomic,retain) NSMutableArray* touches; + +@end + +@implementation ViewController +@synthesize documentsPath,bundlePath,touches; + +- (id)init +{ + self = [super init]; + if (self) { + self.touches = [[[NSMutableArray alloc] init] autorelease]; + + self.documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + self.bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/"]; + + memset(&input_state, 0, sizeof(input_state)); + + net::Init(); + + ram_temp_file = [[NSTemporaryDirectory() stringByAppendingPathComponent:@"ram_tmp.file"] fileSystemRepresentation]; + NativeInit(0, NULL, [self.bundlePath UTF8String], [self.documentsPath UTF8String], NULL); + + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.view.frame = [[UIScreen mainScreen] bounds]; + self.view.multipleTouchEnabled = YES; + self.context = [[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2] autorelease]; + + GLKView *view = (GLKView *)self.view; + view.context = self.context; + view.drawableDepthFormat = GLKViewDrawableDepthFormat24; + [EAGLContext setCurrentContext:self.context]; + + float scale = [UIScreen mainScreen].scale; + CGSize size = [[UIApplication sharedApplication].delegate window].frame.size; + + if (size.height > size.width) { + float h = size.height; + size.height = size.width; + size.width = h; + } + + g_dpi = (IS_IPAD() ? 200 : 150) * scale; + g_dpi_scale = 240.0f / (float)g_dpi; + pixel_xres = size.width * scale; + pixel_yres = size.height * scale; + pixel_in_dps = (float)pixel_xres / (float)dp_xres; + + dp_xres = pixel_xres * g_dpi_scale; + dp_yres = pixel_yres * g_dpi_scale; + + NativeInitGraphics(); + + dp_xscale = (float)dp_xres / (float)pixel_xres; + dp_yscale = (float)dp_yres / (float)pixel_yres; + +/* + UISwipeGestureRecognizer* gesture = [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)] autorelease]; + [self.view addGestureRecognizer:gesture]; +*/ +} + +- (void)viewDidUnload +{ + [super viewDidUnload]; + + if ([EAGLContext currentContext] == self.context) { + [EAGLContext setCurrentContext:nil]; + } + self.context = nil; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; +} + +- (void)dealloc +{ + [self viewDidUnload]; + + self.touches = nil; + self.documentsPath = nil; + self.bundlePath = nil; + + NativeShutdown(); + [super dealloc]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation +{ + return YES; +} + +//static BOOL menuDown = NO; + +- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect +{ + lock_guard guard(input_state.lock); + input_state.pad_buttons |= pad_buttons_async_set; + input_state.pad_buttons &= ~pad_buttons_async_clear; + UpdateInputState(&input_state); + + { + lock_guard guard(input_state.lock); + UIUpdateMouse(0, input_state.pointer_x[0], input_state.pointer_y[0], input_state.pointer_down[0]); + screenManager->update(input_state); + } + + { + lock_guard guard(input_state.lock); + EndInputState(&input_state); + } + + NativeRender(); + time_update(); +} + +- (void)swipeGesture:(id)sender +{ + // TODO: Use a swipe gesture to handle BACK +/* + pad_buttons_async_set |= PAD_BUTTON_MENU; + pad_buttons_async_clear &= PAD_BUTTON_MENU; + + int64_t delayInSeconds = 1.5; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + pad_buttons_async_set &= PAD_BUTTON_MENU; + pad_buttons_async_clear |= PAD_BUTTON_MENU; + }); + + if (g_Config.bBufferedRendering) + fbo_unbind(); + + screenManager->push(new InGameMenuScreen()); +*/ +} + +- (void)touchX:(float)x y:(float)y code:(int)code pointerId:(int)pointerId +{ + lock_guard guard(input_state.lock); + + float scale = [UIScreen mainScreen].scale; + + float scaledX = (int)(x * dp_xscale) * scale; + float scaledY = (int)(y * dp_yscale) * scale; + + input_state.pointer_x[pointerId] = scaledX; + input_state.pointer_y[pointerId] = scaledY; + if (code == 1) { + input_state.pointer_down[pointerId] = true; + } else if (code == 2) { + input_state.pointer_down[pointerId] = false; + } + input_state.mouse_valid = true; +} + +- (void)touchesBegan:(NSSet *)_touches withEvent:(UIEvent *)event +{ + for(UITouch* touch in _touches) { + [self.touches addObject:touch]; + CGPoint point = [touch locationInView:self.view]; + [self touchX:point.x y:point.y code:1 pointerId:[self.touches indexOfObject:touch]]; + } +} + +- (void)touchesMoved:(NSSet *)_touches withEvent:(UIEvent *)event +{ + for(UITouch* touch in _touches) { + CGPoint point = [touch locationInView:self.view]; + [self touchX:point.x y:point.y code:0 pointerId:[self.touches indexOfObject:touch]]; + } +} + +- (void)touchesEnded:(NSSet *)_touches withEvent:(UIEvent *)event +{ + for(UITouch* touch in _touches) { + CGPoint point = [touch locationInView:self.view]; + [self touchX:point.x y:point.y code:2 pointerId:[self.touches indexOfObject:touch]]; + [self.touches removeObject:touch]; + } +} + +void LaunchBrowser(char const* url) +{ + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithCString:url encoding:NSStringEncodingConversionAllowLossy]]]; +} + +void EnableFZ(){}; +void DisableFZ(){}; + +@end diff --git a/ios/ios.toolchain.cmake b/ios/ios.toolchain.cmake index 469e83acf1..9af6cb06e6 100644 --- a/ios/ios.toolchain.cmake +++ b/ios/ios.toolchain.cmake @@ -4,10 +4,9 @@ # Options: # -# IOS_PLATFORM = OS (default) or SIMULATOR -# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders +# IOS_PLATFORM = OS (default) +# This needs to be OS as the simulator cannot use the required GLES2.0 environment. # OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. -# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. # # CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder # By default this location is automatcially chosen based on the IOS_PLATFORM value above. @@ -96,16 +95,11 @@ set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") # Check the platform selection and setup for developer root if (${IOS_PLATFORM} STREQUAL "OS") set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") - - # This causes the installers to properly locate the output libraries set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") - set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") + message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. PPSSPP is unable to run on simulator") else (${IOS_PLATFORM} STREQUAL "OS") - message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") + message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or leave default") endif (${IOS_PLATFORM} STREQUAL "OS") # Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT @@ -141,9 +135,7 @@ set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS su # set the architecture for iOS # NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH armv6 armv7) -else (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH i386) + set (IOS_ARCH armv7 armv7s) endif (${IOS_PLATFORM} STREQUAL "OS") set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS") diff --git a/ios/main.m b/ios/main.m new file mode 100644 index 0000000000..2c76d754c1 --- /dev/null +++ b/ios/main.m @@ -0,0 +1,12 @@ +// main.m boilerplate + +#import + +#import "AppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/native b/native index 3caced8524..f5e7bd5a9c 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 3caced8524c06cabcf968942a7780d80337de7bf +Subproject commit f5e7bd5a9c3e4b39a4eac71b577f06ad54f2bc96