From 5cedc0e6e70cce89032e7e875b99ca3b8b687760 Mon Sep 17 00:00:00 2001 From: Sergey Lipskiy Date: Sun, 29 Sep 2013 22:02:50 +0700 Subject: [PATCH] Implement VI emulation: treat main frame buffer as TV screen and render FBO buffers on it according to VI registers values. --- FrameBuffer.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- VI.cpp | 15 ++++++++++++--- VI.h | 5 ++++- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/FrameBuffer.cpp b/FrameBuffer.cpp index bed89d5f..51b7b841 100644 --- a/FrameBuffer.cpp +++ b/FrameBuffer.cpp @@ -324,18 +324,53 @@ void FrameBuffer_SaveBuffer( u32 address, u16 format, u16 size, u16 width, u16 h #if 1 void FrameBuffer_RenderBuffer( u32 address ) { + if (_SHIFTR( *REG.VI_H_START, 0, 10 ) == 0) // H width is zero. Don't draw + return; FrameBuffer *current = FrameBuffer_FindBuffer(address); if (current == NULL) return; + GLint srcY0, srcY1, dstY0, dstY1; + GLint partHeight = 0; + dstY0 = 1; + const u32 vStart = _SHIFTR( *REG.VI_V_START, 17, 9 ); + const u32 vEnd = _SHIFTR( *REG.VI_V_START, 1, 9 ); + const float viScaleY = OGL.height / (float)VI.vHeight; + + if (VI.vStart != vStart) + dstY0 += vStart - VI.vStart; + dstY1 = dstY0 + vEnd - vStart; + srcY0 = ((address - current->startAddress) << 1 >> current->size) / (*REG.VI_WIDTH); + srcY1 = srcY0 + VI.real_height; + if (srcY1 > VI.height) { + partHeight = srcY1 - VI.height; + srcY1 = VI.height; + dstY1 -= partHeight; + } + ogl_glBindFramebuffer(GL_READ_FRAMEBUFFER, current->fbo); ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glDrawBuffer( GL_FRONT ); ogl_glBlitFramebuffer( -// 0, 0, current->texture->realWidth, current->texture->realHeight, - 0, 0, OGL.width, OGL.height, - 0, OGL.heightOffset, OGL.width, OGL.height+OGL.heightOffset, + 0, (GLint)(srcY0*OGL.scaleY), OGL.width, (GLint)(srcY1*OGL.scaleY), + 0, OGL.heightOffset + (GLint)(dstY0*viScaleY), OGL.width, OGL.heightOffset + (GLint)(dstY1*viScaleY), GL_COLOR_BUFFER_BIT, GL_LINEAR ); + if (partHeight > 0) { + const u32 size = *REG.VI_STATUS & 3; + current = FrameBuffer_FindBuffer(address + (((*REG.VI_WIDTH)*VI.height)<>1)); + if (current != NULL) { + srcY0 = 0; + srcY1 = partHeight; + dstY0 = dstY1; + dstY1 = dstY0 + partHeight; + ogl_glBindFramebuffer(GL_READ_FRAMEBUFFER, current->fbo); + ogl_glBlitFramebuffer( + 0, (GLint)(srcY0*OGL.scaleY), OGL.width, (GLint)(srcY1*OGL.scaleY), + 0, OGL.heightOffset + (GLint)(dstY0*viScaleY), OGL.width, OGL.heightOffset + (GLint)(dstY1*viScaleY), + GL_COLOR_BUFFER_BIT, GL_LINEAR + ); + } + } glDrawBuffer( GL_BACK ); ogl_glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer.top->fbo); diff --git a/VI.cpp b/VI.cpp index 9ece0002..ef24d4a3 100644 --- a/VI.cpp +++ b/VI.cpp @@ -27,9 +27,16 @@ void VI_UpdateSize() u32 vStart = _SHIFTR( *REG.VI_V_START, 17, 9 ); VI.width = (hEnd - hStart) * xScale; - VI.height = (vEnd - vStart) * yScale * 1.0126582f; + VI.real_height = (vEnd - vStart) * yScale; + VI.height = VI.real_height*1.0126582f; - if (VI.width == 0.0f) VI.width = 320.0f; + if (VI.vStart == 0) { + VI.vStart = vStart; + VI.vEnd = vEnd; + VI.vHeight = VI.height; + } + + if (VI.width == 0.0f) VI.width = *REG.VI_WIDTH; if (VI.height == 0.0f) VI.height = 240.0f; } @@ -42,10 +49,12 @@ void VI_UpdateScreen() OGL_SaveScreenshot(); OGL.captureScreen = false; } + if (((*REG.VI_STATUS)&3) == 0) + VI.vStart = VI.vEnd = 0; if (OGL.frameBufferTextures) { const bool bCFB = (gSP.changed&CHANGED_CPU_FB_WRITE) == CHANGED_CPU_FB_WRITE; - const bool bNeedUpdate = bCFB ? true : (*REG.VI_ORIGIN != VI.lastOrigin) && gDP.colorImage.changed; + const bool bNeedUpdate = bCFB ? true : (*REG.VI_ORIGIN != VI.lastOrigin);// && gDP.colorImage.changed; if (bNeedUpdate) { FrameBuffer * pBuffer = FrameBuffer_FindBuffer(*REG.VI_ORIGIN); diff --git a/VI.h b/VI.h index 6f6c0b23..7927ef55 100644 --- a/VI.h +++ b/VI.h @@ -4,8 +4,11 @@ struct VIInfo { - u32 width, height; + u32 width, height, real_height; + u32 vStart, vEnd, vHeight; u32 lastOrigin; + + VIInfo() : width(0), height(0), real_height(0), vStart(0), vEnd(0), vHeight(0), lastOrigin(0) {} }; extern VIInfo VI;