From 26e9acee4b4721879206606e02db7ad4c31b4eb2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 15 May 2016 15:54:04 -0700 Subject: [PATCH 1/6] Display: Skip transitions between off/on in FPS. We're just trying to detect frequent flips, so off/on doesn't play into it. --- Core/HLE/sceDisplay.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index cd861be764..a4ee1f1bbc 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -761,7 +761,8 @@ static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int hleEatCycles(290); s64 delayCycles = 0; - if (topaddr != framebuf.topaddr && g_Config.iForceMaxEmulatedFPS > 0) { + // Don't count transitions between display off and display on. + if (topaddr != 0 && topaddr != framebuf.topaddr && framebuf.topaddr != 0 && g_Config.iForceMaxEmulatedFPS > 0) { // Sometimes we get a small number, there's probably no need to delay the thread for this. // sceDisplaySetFramebuf() isn't supposed to delay threads at all. This is a hack. const int FLIP_DELAY_CYCLES_MIN = 10; From 958d7f0944280318f9b0dc189d918154fc7a6495 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 15 May 2016 15:55:04 -0700 Subject: [PATCH 2/6] Display: Record bufw/fmt even when display is off. These are returned by sceDisplayGetFrameBuf(). --- Core/HLE/sceDisplay.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index a4ee1f1bbc..b3e7d39e43 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -752,11 +752,9 @@ static u32 sceDisplaySetMode(int displayMode, int displayWidth, int displayHeigh // Some games (GTA) never call this during gameplay, so bad place to put a framerate counter. static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) { FrameBufferState fbstate = {0}; - if (topaddr != 0) { - fbstate.topaddr = topaddr; - fbstate.pspFramebufFormat = (GEBufferFormat)pixelformat; - fbstate.pspFramebufLinesize = linesize; - } + fbstate.topaddr = topaddr; + fbstate.pspFramebufFormat = (GEBufferFormat)pixelformat; + fbstate.pspFramebufLinesize = linesize; hleEatCycles(290); From 44cee09adc41cce84c1ee38ef3db742781182b38 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 15 May 2016 16:29:58 -0700 Subject: [PATCH 3/6] Dsiplay: Initialize the framebuf params better. --- Core/HLE/sceDisplay.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index b3e7d39e43..da5055131c 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -55,8 +55,8 @@ struct FrameBufferState { u32 topaddr; - GEBufferFormat pspFramebufFormat; - int pspFramebufLinesize; + GEBufferFormat fmt; + int stride; }; struct WaitVBlankInfo { @@ -185,9 +185,9 @@ void __DisplayInit() { numVBlanksSinceFlip = 0; framebufIsLatched = false; framebuf.topaddr = 0x04000000; - framebuf.pspFramebufFormat = GE_FORMAT_8888; - framebuf.pspFramebufLinesize = 480; // ?? - memset(&latchedFramebuf, 0, sizeof(latchedFramebuf)); + framebuf.fmt = GE_FORMAT_8888; + framebuf.stride = 512; + memcpy(&latchedFramebuf, &framebuf, sizeof(latchedFramebuf)); lastFlipCycles = 0; lastFlipsTooFrequent = 0; wasPaused = false; @@ -302,7 +302,7 @@ void __DisplayDoState(PointerWrap &p) { if (hasSetMode) { gpu->InitClear(); } - gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat); + gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.stride, framebuf.fmt); } } @@ -617,7 +617,7 @@ void hleEnterVblank(u64 userdata, int cyclesLate) { DEBUG_LOG(SCEDISPLAY, "Setting latched framebuffer %08x (prev: %08x)", latchedFramebuf.topaddr, framebuf.topaddr); framebuf = latchedFramebuf; framebufIsLatched = false; - gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat); + gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.stride, framebuf.fmt); } // We flip only if the framebuffer was dirty. This eliminates flicker when using // non-buffered rendering. The interaction with frame skipping seems to need @@ -753,8 +753,8 @@ static u32 sceDisplaySetMode(int displayMode, int displayWidth, int displayHeigh static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) { FrameBufferState fbstate = {0}; fbstate.topaddr = topaddr; - fbstate.pspFramebufFormat = (GEBufferFormat)pixelformat; - fbstate.pspFramebufLinesize = linesize; + fbstate.fmt = (GEBufferFormat)pixelformat; + fbstate.stride = linesize; hleEatCycles(290); @@ -787,7 +787,7 @@ static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE) { // Write immediately to the current framebuffer parameters framebuf = fbstate; - gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat); + gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.stride, framebuf.fmt); } else { // Delay the write until vblank latchedFramebuf = fbstate; @@ -809,26 +809,26 @@ static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int } bool __DisplayGetFramebuf(u8 **topaddr, u32 *linesize, u32 *pixelFormat, int latchedMode) { - const FrameBufferState &fbState = latchedMode == 1 ? latchedFramebuf : framebuf; + const FrameBufferState &fbState = latchedMode == PSP_DISPLAY_SETBUF_NEXTFRAME ? latchedFramebuf : framebuf; if (topaddr != nullptr) *topaddr = Memory::GetPointer(fbState.topaddr); if (linesize != nullptr) - *linesize = fbState.pspFramebufLinesize; + *linesize = fbState.stride; if (pixelFormat != nullptr) - *pixelFormat = fbState.pspFramebufFormat; + *pixelFormat = fbState.fmt; return true; } static u32 sceDisplayGetFramebuf(u32 topaddrPtr, u32 linesizePtr, u32 pixelFormatPtr, int latchedMode) { - const FrameBufferState &fbState = latchedMode == 1 && framebufIsLatched ? latchedFramebuf : framebuf; + const FrameBufferState &fbState = latchedMode == PSP_DISPLAY_SETBUF_NEXTFRAME ? latchedFramebuf : framebuf; if (Memory::IsValidAddress(topaddrPtr)) Memory::Write_U32(fbState.topaddr, topaddrPtr); if (Memory::IsValidAddress(linesizePtr)) - Memory::Write_U32(fbState.pspFramebufLinesize, linesizePtr); + Memory::Write_U32(fbState.stride, linesizePtr); if (Memory::IsValidAddress(pixelFormatPtr)) - Memory::Write_U32(fbState.pspFramebufFormat, pixelFormatPtr); + Memory::Write_U32(fbState.fmt, pixelFormatPtr); return hleLogSuccessI(SCEDISPLAY, 0); } From 249a85b7e0cc2fe027aef71dbe49f00c533ab849 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 15 May 2016 16:38:00 -0700 Subject: [PATCH 4/6] Display: Validate framebuf parameters. --- Core/HLE/sceDisplay.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index da5055131c..dfa158658f 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -756,6 +756,22 @@ static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int fbstate.fmt = (GEBufferFormat)pixelformat; fbstate.stride = linesize; + if (sync != PSP_DISPLAY_SETBUF_IMMEDIATE && sync != PSP_DISPLAY_SETBUF_NEXTFRAME) { + return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "invalid sync mode"); + } + if (topaddr != 0 && !Memory::IsRAMAddress(topaddr) && !Memory::IsVRAMAddress(topaddr)) { + return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid address"); + } + if ((topaddr & 0xF) != 0) { + return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_POINTER, "misaligned address"); + } + if ((linesize & 0x3F) != 0 || (linesize == 0 && topaddr != 0)) { + return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid stride"); + } + if (pixelformat < 0 || pixelformat > GE_FORMAT_8888) { + return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_FORMAT, "invalid format"); + } + hleEatCycles(290); s64 delayCycles = 0; From 5e8e2d5e568d01a01bd87da911dd0381b0a216a4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 15 May 2016 16:38:26 -0700 Subject: [PATCH 5/6] Display: Allow only immediate address changes. It seems you must latch a change to stride/fmt first, which basically makes sense. Otherwise it would revert, I suppose. --- Core/HLE/sceDisplay.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index dfa158658f..cf95e7c674 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -772,6 +772,12 @@ static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_FORMAT, "invalid format"); } + if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE) { + if (fbstate.fmt != latchedFramebuf.fmt || fbstate.stride != latchedFramebuf.stride) { + return hleReportError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "must change latched framebuf first"); + } + } + hleEatCycles(290); s64 delayCycles = 0; @@ -808,6 +814,10 @@ static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int // Delay the write until vblank latchedFramebuf = fbstate; framebufIsLatched = true; + + // If we update the format or stride, this affects the current framebuf immediately. + framebuf.fmt = latchedFramebuf.fmt; + framebuf.stride = latchedFramebuf.stride; } if (delayCycles > 0) { From 597824eec603fea09728906a6d8d2f5c90e12322 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 15 May 2016 22:16:31 -0700 Subject: [PATCH 6/6] Display: Add validation/report to set mode. This seems to be involved in using the video out cable, but fails for anything but these fixed parameters in normal situations. --- Core/HLE/sceDisplay.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index cf95e7c674..35a6f675b4 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -723,22 +723,20 @@ void hleLagSync(u64 userdata, int cyclesLate) { } static u32 sceDisplayIsVblank() { - DEBUG_LOG(SCEDISPLAY,"%i=sceDisplayIsVblank()",isVblank); - return isVblank; + return hleLogSuccessI(SCEDISPLAY, isVblank); } static u32 sceDisplaySetMode(int displayMode, int displayWidth, int displayHeight) { - if (displayWidth <= 0 || displayHeight <= 0 || (displayWidth & 0x7) != 0) { - WARN_LOG(SCEDISPLAY, "sceDisplaySetMode INVALID SIZE (%i, %i, %i)", displayMode, displayWidth, displayHeight); - return SCE_KERNEL_ERROR_INVALID_SIZE; + if (displayMode != PSP_DISPLAY_MODE_LCD || displayWidth != 480 || displayHeight != 272) { + WARN_LOG_REPORT(SCEDISPLAY, "Video out requested, not supported: mode=%d size=%d,%d", displayMode, displayWidth, displayHeight); + } + if (displayWidth != 480 || displayHeight != 272) { + return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid size"); } - if (displayMode != PSP_DISPLAY_MODE_LCD) { - WARN_LOG(SCEDISPLAY, "sceDisplaySetMode INVALID MODE(%i, %i, %i)", displayMode, displayWidth, displayHeight); - return SCE_KERNEL_ERROR_INVALID_MODE; + return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "invalid mode"); } - DEBUG_LOG(SCEDISPLAY,"sceDisplaySetMode(%i, %i, %i)", displayMode, displayWidth, displayHeight); if (!hasSetMode) { gpu->InitClear(); hasSetMode = true; @@ -746,7 +744,7 @@ static u32 sceDisplaySetMode(int displayMode, int displayWidth, int displayHeigh mode = displayMode; width = displayWidth; height = displayHeight; - return 0; + return hleLogSuccessI(SCEDISPLAY, 0); } // Some games (GTA) never call this during gameplay, so bad place to put a framerate counter.