From 030b562eb97d9c0c7b791062dfbf4f26ba22cc31 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 14 Jun 2014 17:08:41 -0700 Subject: [PATCH] Support render-to-offset within a framebuffer. Fixes #6324. --- GPU/GLES/Framebuffer.cpp | 26 ++++++++++++++++++++------ GPU/GLES/StateMapping.cpp | 2 ++ GPU/GPUState.cpp | 2 +- GPU/GPUState.h | 2 +- Windows/GEDebugger/VertexPreview.cpp | 2 +- 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 9ed88769f6..57716d733e 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -862,22 +862,36 @@ void FramebufferManager::DoSetRenderFrameBuffer() { // Find a matching framebuffer VirtualFramebuffer *vfb = 0; size_t i; + gstate_c.cutRTOffsetX = 0; for (i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *v = vfbs_[i]; if (MaskedEqual(v->fb_address, fb_address)) { vfb = v; // Update fb stride in case it changed vfb->fb_stride = fb_stride; - v->format = fmt; + vfb->format = fmt; // In throughmode, a higher height could be used. Let's avoid shrinking the buffer. - if (gstate.isModeThrough() && (int)v->width < fb_stride) { - v->width = std::max((int)v->width, drawing_width); - v->height = std::max((int)v->height, drawing_height); + if (gstate.isModeThrough() && (int)vfb->width < fb_stride) { + vfb->width = std::max((int)vfb->width, drawing_width); + vfb->height = std::max((int)vfb->height, drawing_height); } else { - v->width = drawing_width; - v->height = drawing_height; + vfb->width = drawing_width; + vfb->height = drawing_height; } break; + } else if (v->fb_address < fb_address && v->fb_address + v->fb_stride * 4 > fb_address) { + // Possibly a render-to-offset. + const u32 bpp = v->format == GE_FORMAT_8888 ? 4 : 2; + const int x_offset = (fb_address - v->fb_address) / bpp; + if (v->format == fmt && v->fb_stride == fb_stride && x_offset < fb_stride && v->height >= drawing_height) { + WARN_LOG_REPORT_ONCE(renderoffset, HLE, "Rendering to framebuffer offset: %08x +%dx%d", v->fb_address, x_offset, 0); + vfb = v; + gstate_c.cutRTOffsetX = x_offset; + vfb->width = std::max((int)vfb->width, x_offset + drawing_width); + // To prevent the newSize code from being confused. + drawing_width += x_offset; + break; + } } } diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index 72b631933b..970bebd9f0 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -507,6 +507,8 @@ void TransformDrawEngine::ApplyDrawState(int prim) { renderHeightFactor = renderHeight / 272.0f; } + renderX += gstate_c.cutRTOffsetX * renderWidthFactor; + // Scissor int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index cd3c8e7026..208930a60f 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -336,5 +336,5 @@ void GPUStateCache::DoState(PointerWrap &p) { p.Do(curRTWidth); p.Do(curRTHeight); - // curRTBufferWidth and curRTBufferHeight don't need to be saved. + // curRTBufferWidth, curRTBufferHeight, and cutRTOffsetX don't need to be saved. } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index e14f6a62f2..d5381fcf8e 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -474,9 +474,9 @@ struct GPUStateCache u32 curRTWidth; u32 curRTHeight; - u32 curRTRenderWidth; u32 curRTRenderHeight; + u32 cutRTOffsetX; u32 getRelativeAddress(u32 data) const; void DoState(PointerWrap &p); diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 7c7d795ad6..bfd07c9746 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -189,7 +189,7 @@ void CGEDebugger::UpdatePrimPreview(u32 op) { }; Matrix4x4 ortho; - ortho.setOrtho(0, frameWindow->TexWidth() * scale[0], frameWindow->TexHeight() * scale[1], 0, -1, 1); + ortho.setOrtho(-(int)gstate_c.cutRTOffsetX, (frameWindow->TexWidth() - (int)gstate_c.cutRTOffsetX) * scale[0], frameWindow->TexHeight() * scale[1], 0, -1, 1); glUniformMatrix4fv(previewProgram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr()); glEnableVertexAttribArray(previewProgram->a_position); glVertexAttribPointer(previewProgram->a_position, 3, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), (float *)vertices.data() + 2);