From 73234941e17cba2b10f33f8b5ea26f70d700347e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 1 Jun 2014 13:50:37 -0700 Subject: [PATCH 01/11] Consider stride more when determining fb size. --- GPU/GLES/Framebuffer.cpp | 72 ++++++++++++++++++++++++++++------------ GPU/GLES/Framebuffer.h | 1 + 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 889dd637ce..0d65675831 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -637,38 +637,66 @@ VirtualFramebuffer *FramebufferManager::GetVFBAt(u32 addr) { } // Heuristics to figure out the size of FBO to create. -static void EstimateDrawingSize(int &drawing_width, int &drawing_height) { - int default_width = 480; - int default_height = 272; - int viewport_width = (int) gstate.getViewportX1(); - int viewport_height = (int) gstate.getViewportY1(); - int region_width = gstate.getRegionX2() + 1; - int region_height = gstate.getRegionY2() + 1; - int scissor_width = gstate.getScissorX2() + 1; - int scissor_height = gstate.getScissorY2() + 1; - int fb_stride = gstate.FrameBufStride(); +void FramebufferManager::EstimateDrawingSize(int &drawing_width, int &drawing_height) { + const int default_width = 480; + const int default_height = 272; + const int viewport_width = (int) gstate.getViewportX1(); + const int viewport_height = (int) gstate.getViewportY1(); + const int region_width = gstate.getRegionX2() + 1; + const int region_height = gstate.getRegionY2() + 1; + const int scissor_width = gstate.getScissorX2() + 1; + const int scissor_height = gstate.getScissorY2() + 1; + const int fb_stride = gstate.FrameBufStride(); DEBUG_LOG(SCEGE,"viewport : %ix%i, region : %ix%i , scissor: %ix%i, stride: %i, %i", viewport_width,viewport_height, region_width, region_height, scissor_width, scissor_height, fb_stride, gstate.isModeThrough()); - // Viewport may return 0x0 for example FF Type-0 / God of War and we set it to 480x272 - if (viewport_width <= 1 && viewport_height <=1) { - viewport_width = default_width; - viewport_height = default_height; - } + // TODO: God of War sets region = 1024x1024 on a buffer that is used only as 64x64, and occupies 1024x64 of VRAM. + // In this case, viewport=64x64, region=1024x1024, scissor varies (480x272 sometimes), stride=1024 - if (fb_stride > 0 && fb_stride <= 512) { - if (fb_stride == viewport_width) { - drawing_width = viewport_width; - drawing_height = viewport_height; - } else { + // Games don't always set any of these. Take the greatest parameter that looks valid based on stride. + if (viewport_width <= fb_stride) { + drawing_width = viewport_width; + drawing_height = viewport_height; + // Sometimes region is set larger than the VRAM for the framebuffer. + if (region_width <= fb_stride && region_width > drawing_width) { + drawing_width = region_width; + drawing_height = region_height; + } + // Scissor is often set to a subsection of the framebuffer, so we pay the least attention to it. + if (scissor_width <= fb_stride && scissor_width > drawing_width) { drawing_width = scissor_width; drawing_height = scissor_height; } } else { - drawing_width = default_width; - drawing_height = default_height; + // If viewport wasn't valid, let's just take the greatest anything regardless of stride. + drawing_width = std::min(std::max(region_width, scissor_width), fb_stride); + drawing_height = std::max(region_height, scissor_height); } + // Assume no buffer is > 512 tall, it couldn't be textured or displayed fully if so. + drawing_height = std::min(drawing_height, 512); + + if (viewport_width != region_width) { + // The majority of the time, these are equal. If not, let's check what we know. + const u32 fb_address = gstate.getFrameBufAddress(); + u32 nearest_address = 0xFFFFFFFF; + for (size_t i = 0; i < vfbs_.size(); ++i) { + const u32 other_address = vfbs_[i]->fb_address | 0x44000000; + if (other_address > fb_address && other_address < nearest_address) { + nearest_address = other_address; + } + } + + // Unless the game is using overlapping buffers, the next buffer should be far enough away. + // This catches some cases where we can know this. + // Hmm. The problem is that we could only catch it for the first of two buffers... + const u32 bpp = gstate.FrameBufFormat() == GE_FORMAT_8888 ? 4 : 2; + int avail_height = (nearest_address - fb_address) / (fb_stride * bpp); + if (avail_height < drawing_height && avail_height == region_height) { + drawing_width = std::min(region_width, fb_stride); + drawing_height = avail_height; + } + } } void FramebufferManager::DestroyFramebuf(VirtualFramebuffer *v) { diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index 7dd127b1ff..86d6674bbb 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -233,6 +233,7 @@ private: void SetNumExtraFBOs(int num); + void EstimateDrawingSize(int &drawing_width, int &drawing_height); static void DisableState(); static void ClearBuffer(); static bool MaskedEqual(u32 addr1, u32 addr2); From 32439bc0062e6627eb7c591d8de2792f5c8a3eae Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 1 Jun 2014 13:51:58 -0700 Subject: [PATCH 02/11] Recreate framebuffers when they get bigger. To avoid cases where they remain too small, and to make sure size always matches up sanely. --- GPU/GLES/Framebuffer.cpp | 41 ++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 0d65675831..df1c3aaccf 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -781,31 +781,39 @@ void FramebufferManager::DoSetRenderFrameBuffer() { vfb = v; // Update fb stride in case it changed vfb->fb_stride = fb_stride; - if (v->width < drawing_width && v->height < drawing_height) { + v->format = fmt; + if (v->width < drawing_width) { v->width = drawing_width; - v->height = drawing_height; } - if (v->format != fmt) { - v->width = drawing_width; + if (v->height < drawing_height) { v->height = drawing_height; - v->format = fmt; } break; } } + VirtualFramebuffer *destroyVfb = 0; if (vfb) { if ((drawing_width != vfb->bufferWidth || drawing_height != vfb->bufferHeight)) { - // If it's newly wrong, or changing every frame, just keep track. - if (vfb->newWidth != drawing_width || vfb->newHeight != drawing_height) { + // Even if it's not newly wrong, if this is larger we need to resize up. + if (vfb->width > vfb->bufferWidth || vfb->height > vfb->bufferHeight) { + destroyVfb = vfb; + vfb = NULL; + } else if (vfb->newWidth != drawing_width || vfb->newHeight != drawing_height) { + // If it's newly wrong, or changing every frame, just keep track. vfb->newWidth = drawing_width; vfb->newHeight = drawing_height; vfb->lastFrameNewSize = gpuStats.numFlips; } else if (vfb->lastFrameNewSize + FBO_OLD_AGE < gpuStats.numFlips) { // Okay, it's changed for a while (and stayed that way.) Let's start over. - DestroyFramebuf(vfb); - vfbs_.erase(vfbs_.begin() + i); - vfb = NULL; + // But only if we really need to, to avoid blinking. + bool needsRecreate = vfb->bufferWidth > fb_stride; + needsRecreate = needsRecreate || vfb->newWidth > vfb->bufferWidth || vfb->newWidth * 2 < vfb->bufferWidth; + needsRecreate = needsRecreate || vfb->newHeight > vfb->newHeight || vfb->newHeight * 2 < vfb->newHeight; + if (needsRecreate) { + destroyVfb = vfb; + vfb = NULL; + } } } else { // It's not different, let's keep track of that too. @@ -880,6 +888,17 @@ void FramebufferManager::DoSetRenderFrameBuffer() { gstate_c.skipDrawReason |= SKIPDRAW_NON_DISPLAYED_FB; } + if (destroyVfb) { + // Do this before notifying of creation at the same address. + DestroyFramebuf(destroyVfb); + destroyVfb = 0; + vfbs_.erase(vfbs_.begin() + i); + + INFO_LOG(SCEGE, "Resizing FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format); + } else { + INFO_LOG(SCEGE, "Creating FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format); + } + textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED); vfb->last_frame_render = gpuStats.numFlips; @@ -895,8 +914,6 @@ void FramebufferManager::DoSetRenderFrameBuffer() { framebufRangeEnd_ = fb_address_mem + byteSize; } - INFO_LOG(SCEGE, "Creating FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format); - // Let's check for depth buffer overlap. Might be interesting. bool sharingReported = false; for (size_t i = 0, end = vfbs_.size(); i < end; ++i) { From d03397f056a6b7a3cc7996ea3b71702a29f99451 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 1 Jun 2014 13:53:34 -0700 Subject: [PATCH 03/11] Blit framebuf contents when resizing. This avoids a blink when sizing up. --- GPU/GLES/Framebuffer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index df1c3aaccf..9e485a525f 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -879,6 +879,12 @@ void FramebufferManager::DoSetRenderFrameBuffer() { vfb->fbo = fbo_create(vfb->renderWidth, vfb->renderHeight, 1, true, vfb->colorDepth); if (vfb->fbo) { fbo_bind_as_render_target(vfb->fbo); + + if (destroyVfb) { + // Copy over the contents of the framebuffer we're replacing. + BlitFramebuffer_(vfb, 0, 0, destroyVfb, 0, 0, vfb->width, vfb->height, 0); + fbo_bind_as_render_target(vfb->fbo); + } } else { ERROR_LOG(SCEGE, "Error creating FBO! %i x %i", vfb->renderWidth, vfb->renderHeight); } From a351a42041b233c21d53ff9bcbd2529b0354f702 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 1 Jun 2014 14:00:58 -0700 Subject: [PATCH 04/11] Cleanup some old comments/code. --- GPU/GLES/Framebuffer.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 9e485a525f..0deb8afba9 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -752,15 +752,11 @@ void FramebufferManager::DoSetRenderFrameBuffer() { gstate_c.framebufChanged = false; // Get parameters - u32 fb_address = gstate.getFrameBufRawAddress(); - int fb_stride = gstate.FrameBufStride(); + const u32 fb_address = gstate.getFrameBufRawAddress(); + const int fb_stride = gstate.FrameBufStride(); - u32 z_address = gstate.getDepthBufRawAddress(); - int z_stride = gstate.DepthBufStride(); - - // Yeah this is not completely right. but it'll do for now. - //int drawing_width = ((gstate.region2) & 0x3FF) + 1; - //int drawing_height = ((gstate.region2 >> 10) & 0x3FF) + 1; + const u32 z_address = gstate.getDepthBufRawAddress(); + const int z_stride = gstate.DepthBufStride(); GEBufferFormat fmt = gstate.FrameBufFormat(); @@ -769,9 +765,6 @@ void FramebufferManager::DoSetRenderFrameBuffer() { int drawing_width, drawing_height; EstimateDrawingSize(drawing_width, drawing_height); - int buffer_width = drawing_width; - int buffer_height = drawing_height; - // Find a matching framebuffer VirtualFramebuffer *vfb = 0; size_t i; @@ -845,8 +838,8 @@ void FramebufferManager::DoSetRenderFrameBuffer() { vfb->lastFrameNewSize = gpuStats.numFlips; vfb->renderWidth = (u16)(drawing_width * renderWidthFactor); vfb->renderHeight = (u16)(drawing_height * renderHeightFactor); - vfb->bufferWidth = buffer_width; - vfb->bufferHeight = buffer_height; + vfb->bufferWidth = drawing_width; + vfb->bufferHeight = drawing_height; vfb->format = fmt; vfb->usageFlags = FB_USAGE_RENDERTARGET; vfb->dirtyAfterDisplay = true; From d64d2afcb38efb4d9c6bc2daef7562a6b11dbdc8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 1 Jun 2014 18:45:03 -0700 Subject: [PATCH 05/11] Don't allow a zero framebuf stride in estimation. --- GPU/GLES/Framebuffer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 0deb8afba9..1a5dea517e 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -638,15 +638,13 @@ VirtualFramebuffer *FramebufferManager::GetVFBAt(u32 addr) { // Heuristics to figure out the size of FBO to create. void FramebufferManager::EstimateDrawingSize(int &drawing_width, int &drawing_height) { - const int default_width = 480; - const int default_height = 272; const int viewport_width = (int) gstate.getViewportX1(); const int viewport_height = (int) gstate.getViewportY1(); const int region_width = gstate.getRegionX2() + 1; const int region_height = gstate.getRegionY2() + 1; const int scissor_width = gstate.getScissorX2() + 1; const int scissor_height = gstate.getScissorY2() + 1; - const int fb_stride = gstate.FrameBufStride(); + const int fb_stride = std::max(gstate.FrameBufStride(), 4); DEBUG_LOG(SCEGE,"viewport : %ix%i, region : %ix%i , scissor: %ix%i, stride: %i, %i", viewport_width,viewport_height, region_width, region_height, scissor_width, scissor_height, fb_stride, gstate.isModeThrough()); From cfb21707b69a0dfe306550998d943d2144ba405d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 1 Jun 2014 18:45:25 -0700 Subject: [PATCH 06/11] Take the tallest estimate, scissor may be short. Even if it's wider but short, it should not reduce the height of the buffer. --- GPU/GLES/Framebuffer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 1a5dea517e..0c5deac56f 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -652,18 +652,18 @@ void FramebufferManager::EstimateDrawingSize(int &drawing_width, int &drawing_he // In this case, viewport=64x64, region=1024x1024, scissor varies (480x272 sometimes), stride=1024 // Games don't always set any of these. Take the greatest parameter that looks valid based on stride. - if (viewport_width <= fb_stride) { + if (viewport_width > 4 && viewport_width <= fb_stride) { drawing_width = viewport_width; drawing_height = viewport_height; // Sometimes region is set larger than the VRAM for the framebuffer. if (region_width <= fb_stride && region_width > drawing_width) { drawing_width = region_width; - drawing_height = region_height; + drawing_height = std::max(drawing_height, region_height); } // Scissor is often set to a subsection of the framebuffer, so we pay the least attention to it. if (scissor_width <= fb_stride && scissor_width > drawing_width) { drawing_width = scissor_width; - drawing_height = scissor_height; + drawing_height = std::max(drawing_height, scissor_height); } } else { // If viewport wasn't valid, let's just take the greatest anything regardless of stride. From c2ccfd5629a215ea0aab9d47a40a548d88990321 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 1 Jun 2014 21:20:04 -0700 Subject: [PATCH 07/11] Stop stretching things to the FBO size. Instead, draw in the top corner. This way, even if framebuffers get smaller things stay consistent. --- GPU/GLES/Framebuffer.cpp | 25 ++++++++++--------------- GPU/GLES/Framebuffer.h | 2 ++ GPU/GLES/StateMapping.cpp | 11 +++++++---- GPU/GLES/TextureCache.cpp | 4 ++-- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 0c5deac56f..67e714171d 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -480,7 +480,7 @@ void FramebufferManager::MakePixelTexture(const u8 *srcPixels, GEBufferFormat sr void FramebufferManager::DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) { MakePixelTexture(srcPixels, srcPixelFormat, srcStride, width, height); DisableState(); - DrawActiveTexture(0, dstX, dstY, width, height, vfb->width, vfb->height, false, 0.0f, 0.0f, 1.0f, 1.0f); + DrawActiveTexture(0, dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, false, 0.0f, 0.0f, 1.0f, 1.0f); } void FramebufferManager::DrawFramebuffer(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, bool applyPostShader) { @@ -773,12 +773,8 @@ void FramebufferManager::DoSetRenderFrameBuffer() { // Update fb stride in case it changed vfb->fb_stride = fb_stride; v->format = fmt; - if (v->width < drawing_width) { - v->width = drawing_width; - } - if (v->height < drawing_height) { - v->height = drawing_height; - } + v->width = drawing_width; + v->height = drawing_height; break; } } @@ -1101,7 +1097,6 @@ void FramebufferManager::BindFramebufferColor(VirtualFramebuffer *framebuffer, b fbo_bind_as_render_target(currentRenderVfb_->fbo); fbo_bind_color_as_texture(renderCopy, 0); - glstate.viewport.restore(); } else { fbo_bind_color_as_texture(framebuffer->fbo, 0); } @@ -1174,7 +1169,7 @@ void FramebufferManager::CopyDisplayToOutput() { if (!usePostShader_) { glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); // These are in the output display coordinates - DrawActiveTexture(colorTexture, x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, true, 0.0f, 0.0f, 480.0f / (float)vfb->width, 272.0f / (float)vfb->height); + DrawActiveTexture(colorTexture, x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, true, 0.0f, 0.0f, 480.0f / (float)vfb->bufferWidth, 272.0f / (float)vfb->bufferHeight); } else if (usePostShader_ && extraFBOs_.size() == 1 && !postShaderAtOutputResolution_) { // An additional pass, post-processing shader to the extra FBO. fbo_bind_as_render_target(extraFBOs_[0]); @@ -1194,12 +1189,12 @@ void FramebufferManager::CopyDisplayToOutput() { colorTexture = fbo_get_color_texture(extraFBOs_[0]); glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); // These are in the output display coordinates - DrawActiveTexture(colorTexture, x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, true, 0.0f, 0.0f, 480.0f / (float)vfb->width, 272.0f / (float)vfb->height); + DrawActiveTexture(colorTexture, x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, true, 0.0f, 0.0f, 480.0f / (float)vfb->bufferWidth, 272.0f / (float)vfb->bufferHeight); } else { // Use post-shader, but run shader at output resolution. glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); // These are in the output display coordinates - DrawActiveTexture(colorTexture, x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, true, 0.0f, 0.0f, 480.0f / (float)vfb->width, 272.0f / (float)vfb->height, postShaderProgram_); + DrawActiveTexture(colorTexture, x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, true, 0.0f, 0.0f, 480.0f / (float)vfb->bufferWidth, 272.0f / (float)vfb->bufferHeight, postShaderProgram_); } glBindTexture(GL_TEXTURE_2D, 0); @@ -1422,14 +1417,14 @@ void FramebufferManager::BlitFramebuffer_(VirtualFramebuffer *dst, int dstX, int // Make sure our 2D drawing program is ready. Compiles only if not already compiled. CompileDraw2DProgram(); - glViewport(0, 0, dst->width, dst->height); + glViewport(0, 0, dst->renderWidth, dst->renderHeight); DisableState(); // The first four coordinates are relative to the 6th and 7th arguments of DrawActiveTexture. // Should maybe revamp that interface. - float srcW = src->width; - float srcH = src->height; - DrawActiveTexture(0, dstX, dstY, w, h, dst->width, dst->height, false, srcX / srcW, srcY / srcH, (srcX + w) / srcW, (srcY + h) / srcH, draw2dprogram_); + float srcW = src->bufferWidth; + float srcH = src->bufferHeight; + DrawActiveTexture(0, dstX, dstY, w, h, dst->bufferWidth, dst->bufferHeight, !flip, srcX / srcW, srcY / srcH, (srcX + w) / srcW, (srcY + h) / srcH, draw2dprogram_); glBindTexture(GL_TEXTURE_2D, 0); textureCache_->ForgetLastTexture(); } diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index 86d6674bbb..d36fa6dcee 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -186,6 +186,8 @@ public: int GetRenderHeight() const { return currentRenderVfb_ ? currentRenderVfb_->renderHeight : 272; } int GetTargetWidth() const { return currentRenderVfb_ ? currentRenderVfb_->width : 480; } int GetTargetHeight() const { return currentRenderVfb_ ? currentRenderVfb_->height : 272; } + int GetTargetBufferWidth() const { return currentRenderVfb_ ? currentRenderVfb_->bufferWidth : 480; } + int GetTargetBufferHeight() const { return currentRenderVfb_ ? currentRenderVfb_->bufferHeight : 272; } u32 PrevDisplayFramebufAddr() { return prevDisplayFramebuf_ ? (0x04000000 | prevDisplayFramebuf_->fb_address) : 0; diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index 47cd3a49c9..c257feef90 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -461,6 +461,8 @@ void TransformDrawEngine::ApplyDrawState(int prim) { } } + bool throughmode = gstate.isModeThrough(); + float renderWidthFactor, renderHeightFactor; float renderWidth, renderHeight; float renderX, renderY; @@ -470,8 +472,8 @@ void TransformDrawEngine::ApplyDrawState(int prim) { renderY = 0.0f; renderWidth = framebufferManager_->GetRenderWidth(); renderHeight = framebufferManager_->GetRenderHeight(); - renderWidthFactor = (float)renderWidth / framebufferManager_->GetTargetWidth(); - renderHeightFactor = (float)renderHeight / framebufferManager_->GetTargetHeight(); + renderWidthFactor = (float)renderWidth / framebufferManager_->GetTargetBufferWidth(); + renderHeightFactor = (float)renderHeight / framebufferManager_->GetTargetBufferHeight(); } else { // TODO: Aspect-ratio aware and centered float pixelW = PSP_CoreParameter().pixelWidth; @@ -481,8 +483,6 @@ void TransformDrawEngine::ApplyDrawState(int prim) { renderHeightFactor = renderHeight / 272.0f; } - bool throughmode = gstate.isModeThrough(); - // Scissor int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); @@ -518,6 +518,9 @@ void TransformDrawEngine::ApplyDrawState(int prim) { float offsetY = gstate.getOffsetY(); if (throughmode) { + // If the buffer is too large, offset the viewport to the top. + renderY += renderHeight - framebufferManager_->GetTargetHeight() * renderHeightFactor; + // No viewport transform here. Let's experiment with using region. glstate.viewport.set( renderX + (0 + regionX1) * renderWidthFactor, diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index aae75a7964..a1a610585f 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -959,8 +959,8 @@ void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry) { entry->framebuffer->last_frame_used = gpuStats.numFlips; // We need to force it, since we may have set it on a texture before attaching. - gstate_c.curTextureWidth = entry->framebuffer->width; - gstate_c.curTextureHeight = entry->framebuffer->height; + gstate_c.curTextureWidth = entry->framebuffer->bufferWidth; + gstate_c.curTextureHeight = entry->framebuffer->bufferHeight; gstate_c.flipTexture = true; gstate_c.textureFullAlpha = entry->framebuffer->format == GE_FORMAT_565; gstate_c.textureSimpleAlpha = gstate_c.textureFullAlpha; From 3021640897f25cc67e963cf8aeaaede36e576a07 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 1 Jun 2014 21:24:33 -0700 Subject: [PATCH 08/11] Correct widths in stencil upload too. --- GPU/GLES/StencilBuffer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GLES/StencilBuffer.cpp b/GPU/GLES/StencilBuffer.cpp index 53937add18..196d4f0c38 100644 --- a/GPU/GLES/StencilBuffer.cpp +++ b/GPU/GLES/StencilBuffer.cpp @@ -88,7 +88,7 @@ bool FramebufferManager::NotifyStencilUpload(u32 addr, int size) { shaderManager_->DirtyLastShader(); - MakePixelTexture(Memory::GetPointer(addr), dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstBuffer->height); + MakePixelTexture(Memory::GetPointer(addr), dstBuffer->format, dstBuffer->fb_stride, dstBuffer->renderWidth, dstBuffer->renderHeight); DisableState(); glstate.colorMask.set(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); glstate.stencilTest.enable(); @@ -136,7 +136,7 @@ bool FramebufferManager::NotifyStencilUpload(u32 addr, int size) { glStencilMask(i); glUniform1f(u_stencilValue, i * (1.0f / 255.0f)); } - DrawActiveTexture(0, 0, 0, dstBuffer->width, dstBuffer->height, dstBuffer->width, dstBuffer->height, false, 0.0f, 0.0f, 1.0f, 1.0f, stencilUploadProgram_); + DrawActiveTexture(0, 0, 0, dstBuffer->width, dstBuffer->height, dstBuffer->bufferWidth, dstBuffer->bufferHeight, false, 0.0f, 0.0f, 1.0f, 1.0f, stencilUploadProgram_); } glStencilMask(0xFF); From 78c83e122d7438972cff1f8d9adb6442ae16e423 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 1 Jun 2014 23:47:37 -0700 Subject: [PATCH 09/11] Force 481x273 to 480x272, it's seen in a few games. --- GPU/GLES/Framebuffer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 67e714171d..1252fa828d 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -655,6 +655,11 @@ void FramebufferManager::EstimateDrawingSize(int &drawing_width, int &drawing_he if (viewport_width > 4 && viewport_width <= fb_stride) { drawing_width = viewport_width; drawing_height = viewport_height; + // Some games specify a viewport with 0.5, but don't have VRAM for 273. 480x272 is the buffer size. + if (viewport_width == 481 && region_width == 480 && viewport_height == 273 && region_height == 272) { + drawing_width = 480; + drawing_height = 272; + } // Sometimes region is set larger than the VRAM for the framebuffer. if (region_width <= fb_stride && region_width > drawing_width) { drawing_width = region_width; From 304d372f4899002f87a4323528a4d43c14373f5d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 2 Jun 2014 21:46:22 -0700 Subject: [PATCH 10/11] When clamping height to 512, try region/scissor. --- GPU/GLES/Framebuffer.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 1252fa828d..baa70902f4 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -677,7 +677,13 @@ void FramebufferManager::EstimateDrawingSize(int &drawing_width, int &drawing_he } // Assume no buffer is > 512 tall, it couldn't be textured or displayed fully if so. - drawing_height = std::min(drawing_height, 512); + if (drawing_height > 512) { + if (region_height < 512) { + drawing_height = region_height; + } else if (scissor_height < 512) { + drawing_height = scissor_height; + } + } if (viewport_width != region_width) { // The majority of the time, these are equal. If not, let's check what we know. From b069462bead59b26729f23b71cabdf31ab71913a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 2 Jun 2014 22:51:37 -0700 Subject: [PATCH 11/11] Relax display buffer / GetVfbAt() requirements. Castlevania actually uses a display buffer of 420, it seems. Since we no longer allow multiple FBOs at the same address, this should be safe. --- GPU/GLES/Framebuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index baa70902f4..637b161ab0 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -621,7 +621,7 @@ VirtualFramebuffer *FramebufferManager::GetVFBAt(u32 addr) { VirtualFramebuffer *match = NULL; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *v = vfbs_[i]; - if (MaskedEqual(v->fb_address, addr) && v->format == displayFormat_ && v->width >= 480) { + if (MaskedEqual(v->fb_address, addr)) { // Could check w too but whatever if (match == NULL || match->last_frame_render < v->last_frame_render) { match = v;