diff --git a/Source/Core/Common/Src/MathUtil.h b/Source/Core/Common/Src/MathUtil.h index 04d5034ff7..c3957e7ab9 100644 --- a/Source/Core/Common/Src/MathUtil.h +++ b/Source/Core/Common/Src/MathUtil.h @@ -103,6 +103,38 @@ int ClassifyDouble(double dvalue); // More efficient float version. int ClassifyFloat(float fvalue); +template +struct Rectangle +{ + T left; + T top; + T right; + T bottom; + + T GetWidth() const { return abs(right - left); } + T GetHeight() const { return abs(bottom - top); } + + // If the rectangle is in a coordinate system with a lower-left origin, use + // this Clamp. + void ClampLL(T x1, T y1, T x2, T y2) + { + if (left < x1) left = x1; + if (right > x2) right = x2; + if (top > y1) top = y1; + if (bottom < y2) bottom = y2; + } + + // If the rectangle is in an coordinate system with an upper-left origin, + // use this Clamp. + void ClampUL(T x1, T y1, T x2, T y2) + { + if (left < x1) left = x1; + if (right > x2) right = x2; + if (top < y1) top = y1; + if (bottom > y2) bottom = y2; + } +}; + } // namespace MathUtil inline float pow2f(float x) {return x * x;} @@ -158,5 +190,4 @@ public: float data[16]; }; - #endif // _MATH_UTIL_H_ diff --git a/Source/Core/VideoCommon/Src/BPFunctions.h b/Source/Core/VideoCommon/Src/BPFunctions.h index aa476e0d83..b56398bc3b 100644 --- a/Source/Core/VideoCommon/Src/BPFunctions.h +++ b/Source/Core/VideoCommon/Src/BPFunctions.h @@ -45,11 +45,9 @@ void SetBlendMode(const Bypass &bp); void SetDitherMode(const Bypass &bp); void SetLogicOpMode(const Bypass &bp); void SetColorMask(const Bypass &bp); -float GetRendererTargetScaleX(); -float GetRendererTargetScaleY(); -void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf); -void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight); -void ClearScreen(const Bypass &bp, const TRectangle &multirc); +void CopyEFB(const Bypass &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf); +void RenderToXFB(const Bypass &bp, const EFBRectangle &rc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight); +void ClearScreen(const Bypass &bp, const EFBRectangle &rc); void RestoreRenderState(const Bypass &bp); u8 *GetPointer(const u32 &address); bool GetConfig(const int &type); diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index 3780edb0b3..c9c2cfc2ab 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -176,24 +176,13 @@ void BPWritten(const Bypass& bp) DVSTARTSUBPROFILE("LoadBPReg:swap"); // The bottom right is within the rectangle // The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in this function - TRectangle rc = { - (int)(bpmem.copyTexSrcXY.x), - (int)(bpmem.copyTexSrcXY.y), - (int)((bpmem.copyTexSrcXY.x + bpmem.copyTexSrcWH.x + 1)), - (int)((bpmem.copyTexSrcXY.y + bpmem.copyTexSrcWH.y + 1)) - }; - float MValueX = GetRendererTargetScaleX(); - float MValueY = GetRendererTargetScaleY(); + EFBRectangle rc; + rc.left = (int)bpmem.copyTexSrcXY.x; + rc.top = (int)bpmem.copyTexSrcXY.y; + rc.right = (int)(bpmem.copyTexSrcXY.x + bpmem.copyTexSrcWH.x + 1); + rc.bottom = (int)(bpmem.copyTexSrcXY.y + bpmem.copyTexSrcWH.y + 1); - // Need another rc here to get it to scale. - // Here the bottom right is the out of the rectangle. - TRectangle multirc = { - (int)(bpmem.copyTexSrcXY.x * MValueX), - (int)(bpmem.copyTexSrcXY.y * MValueY), - (int)((bpmem.copyTexSrcXY.x * MValueX + (bpmem.copyTexSrcWH.x + 1) * MValueX)), - (int)((bpmem.copyTexSrcXY.y * MValueY + (bpmem.copyTexSrcWH.y + 1) * MValueY)) - }; UPE_Copy PE_copy; PE_copy.Hex = bpmem.triggerEFBCopy; @@ -219,7 +208,7 @@ void BPWritten(const Bypass& bp) #endif const float yScale = bpmem.dispcopyyscale / 256.0f; const float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale); - RenderToXFB(bp, multirc, yScale, xfbLines, + RenderToXFB(bp, rc, yScale, xfbLines, bpmem.copyTexDest << 5, bpmem.copyMipMapStrideChannels << 4, (u32)ceil(xfbLines)); @@ -227,7 +216,7 @@ void BPWritten(const Bypass& bp) // Clear the picture after it's done and submitted, to prepare for the next picture if (PE_copy.clear) - ClearScreen(bp, multirc); + ClearScreen(bp, rc); RestoreRenderState(bp); diff --git a/Source/Core/VideoCommon/Src/Statistics.h b/Source/Core/VideoCommon/Src/Statistics.h index 09d29b6e51..eb9e284121 100644 --- a/Source/Core/VideoCommon/Src/Statistics.h +++ b/Source/Core/VideoCommon/Src/Statistics.h @@ -48,7 +48,7 @@ struct Statistics float g2proj_0, g2proj_1, g2proj_2, g2proj_3, g2proj_4, g2proj_5; float g2proj_6, g2proj_7, g2proj_8, g2proj_9, g2proj_10, g2proj_11, g2proj_12, g2proj_13, g2proj_14, g2proj_15; - std::vector efb_regions; + std::vector efb_regions; struct ThisFrame { diff --git a/Source/Core/VideoCommon/Src/VideoCommon.h b/Source/Core/VideoCommon/Src/VideoCommon.h index 78006e8693..5b72acd453 100644 --- a/Source/Core/VideoCommon/Src/VideoCommon.h +++ b/Source/Core/VideoCommon/Src/VideoCommon.h @@ -19,6 +19,7 @@ #define _VIDEOCOMMON_H #include "Common.h" +#include "MathUtil.h" #include "pluginspecs_video.h" #if defined(_MSC_VER) && !defined(__x86_64__) && !defined(_M_X64) @@ -40,9 +41,14 @@ enum enum { - XFB_WIDTH = 640, - XFB_HEIGHT = 480, // 574 can be used with tricks (multi pass render and dual xfb copies, etc). - // TODO: figure out what to do with PAL + // XFB width is decided by EFB copy operation. The VI can do horizontal + // scaling (TODO: emulate). + MAX_XFB_WIDTH = EFB_WIDTH, + + // Although EFB height is 528, 574-line XFB's can be created either with + // vertical scaling by the EFB copy operation or copying to multiple XFB's + // that are next to each other in memory (TODO: handle that situation). + MAX_XFB_HEIGHT = 574 }; // If this is enabled, bounding boxes will be computed for everything drawn. @@ -54,11 +60,6 @@ enum extern SVideoInitialize g_VideoInitialize; -// (mb2) for XFB update hack. TODO: find a static better place -extern volatile u32 g_XFBUpdateRequested; - -extern volatile bool g_EFBAccessRequested; - ////////////////////////////////////////////////////////////////////////// inline u8 *Memory_GetPtr(u32 _uAddress) { @@ -103,48 +104,11 @@ inline float Memory_Read_Float(u32 _uAddress) return temp.f; } -struct TRectangle -{ - int left; - int top; - int right; - int bottom; - - int GetWidth() const { return right - left; } - int GetHeight() const { return bottom - top; } - - void FlipYPosition(int y_height, TRectangle *dest) const - { - int offset = y_height - (bottom - top); - dest->left = left; - dest->top = top + offset; - dest->right = right; - dest->bottom = bottom + offset; - } - - void FlipY(int y_height, TRectangle *dest) const { - dest->left = left; - dest->right = right; - dest->bottom = y_height - bottom; - dest->top = y_height - top; - } - - void Scale(float factor_x, float factor_y, TRectangle *dest) const - { - dest->left = (int)(factor_x * left); - dest->right = (int)(factor_x * right); - dest->top = (int)(factor_y * top); - dest->bottom = (int)(factor_y * bottom); - } - - void Clamp(int x1, int y1, int x2, int y2) - { - if (left < x1) left = x1; - if (right > x2) right = x2; - if (top < y1) top = y1; - if (bottom > y2) bottom = y2; - } -}; +// This structure should only be used to represent a rectangle in EFB +// coordinates, where the origin is at the upper left and the frame dimensions +// are 640 x 528. +struct EFBRectangle : public MathUtil::Rectangle +{}; // Logging // ŻŻŻŻŻŻŻŻŻŻ diff --git a/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp b/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp index 876efd0d5f..5a321f43d1 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp @@ -214,28 +214,25 @@ void SetColorMask(const Bypass &bp) Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write); } -float GetRendererTargetScaleX() -{ - return Renderer::GetXScale(); -} -float GetRendererTargetScaleY() -{ - return Renderer::GetYScale(); -} -void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf) + +void CopyEFB(const Bypass &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf) { + // TODO: Scale EFBRectangle correctly + RECT rec = { rc.left, rc.top, rc.right, rc.bottom }; TextureCache::CopyEFBToRenderTarget(bpmem.copyTexDest<<5, &rec); } -void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight) +void RenderToXFB(const Bypass &bp, const EFBRectangle &rc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight) { Renderer::SwapBuffers(); PRIM_LOG("Renderer::SwapBuffers()"); g_VideoInitialize.pCopiedToXFB(); } -void ClearScreen(const Bypass &bp, const TRectangle &multirc) +void ClearScreen(const Bypass &bp, const EFBRectangle &rc) { + // TODO: Scale EFBRectangle correctly + // it seems that the GC is able to alpha blend on color-fill // we cant do that so if alpha is != 255 we skip it diff --git a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp index ebb111de1f..2067231455 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp @@ -374,7 +374,6 @@ u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y) if (g_VideoInitialize.bUseDualCore) { - g_EFBAccessRequested = true; s_AccessEFBDone.Init(); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp b/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp index 97b13beda5..b1454b354e 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp @@ -110,19 +110,13 @@ void SetLogicOpMode(const Bypass &bp) else glDisable(GL_COLOR_LOGIC_OP); } + void SetColorMask(const Bypass &bp) { Renderer::SetColorMask(); } -float GetRendererTargetScaleX() -{ - return Renderer::GetTargetScaleX(); -} -float GetRendererTargetScaleY() -{ - return Renderer::GetTargetScaleY(); -} -void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf) + +void CopyEFB(const Bypass &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf) { // bpmem.zcontrol.pixel_format to PIXELFMT_Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format) if (!g_Config.bEFBCopyDisable) @@ -132,49 +126,24 @@ void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const b TextureMngr::CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc); } -void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight) +void RenderToXFB(const Bypass &bp, const EFBRectangle &rc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight) { - Renderer::RenderToXFB(xfbAddr, dstWidth, dstHeight, multirc); + Renderer::RenderToXFB(xfbAddr, dstWidth, dstHeight, rc); } -void ClearScreen(const Bypass &bp, const TRectangle &multirc) + +void ClearScreen(const Bypass &bp, const EFBRectangle &rc) { - // Update the view port for clearing the picture - glViewport(0, 0, Renderer::GetTargetWidth(), Renderer::GetTargetHeight()); + bool colorEnable = bpmem.blendmode.colorupdate; + bool alphaEnable = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24 && bpmem.blendmode.alphaupdate); + bool zEnable = bpmem.zmode.updateenable; - // Always set the scissor in case it was set by the game and has not been reset - glScissor(multirc.left, (Renderer::GetTargetHeight() - multirc.bottom), - (multirc.right - multirc.left), (multirc.bottom - multirc.top)); - // --------------------------- + if (colorEnable || alphaEnable || zEnable) + { + u32 color = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; + u32 z = bpmem.clearZValue; - VertexShaderManager::SetViewportChanged(); - - // Since clear operations use the source rectangle, we have to do - // regular renders (glClear clears the entire buffer) - if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate || bpmem.zmode.updateenable) - { - GLbitfield bits = 0; - if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate) - { - u32 clearColor = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; - - // Alpha may or may not be present depending on the EFB pixel format. - GLclampf clearAlpha = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24) ? - ((clearColor>>24) & 0xff)*(1/255.0f) : 1.0f; - - glClearColor(((clearColor>>16) & 0xff)*(1/255.0f), - ((clearColor>>8 ) & 0xff)*(1/255.0f), - ((clearColor>>0 ) & 0xff)*(1/255.0f), - clearAlpha); - bits |= GL_COLOR_BUFFER_BIT; - } - if (bpmem.zmode.updateenable) - { - glClearDepth((float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF)); - bits |= GL_DEPTH_BUFFER_BIT; - } - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - glClear(bits); - } + Renderer::ClearScreen(rc, colorEnable, alphaEnable, zEnable, color, z); + } } void RestoreRenderState(const Bypass &bp) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp index 3619a90272..fb0b26c081 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp @@ -183,7 +183,7 @@ void FramebufferManager::Shutdown() m_virtualXFBList.clear(); } -void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc) +void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) { if (g_Config.bUseXFB) copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc); @@ -199,7 +199,7 @@ const XFBSource* FramebufferManager::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight); } -GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const +GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) const { if (m_msaaSamples <= 1) { @@ -210,17 +210,15 @@ GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is // required. - // Flip source rectangle upside-down for OpenGL. - TRectangle glRect; - sourceRc.FlipYPosition(m_targetHeight, &glRect); - glRect.Clamp(0, 0, m_targetWidth, m_targetHeight); + TargetRectangle targetRc = ConvertEFBRectangle(sourceRc); + targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight); // Resolve. glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer); glBlitFramebufferEXT( - glRect.left, glRect.top, glRect.right, glRect.bottom, - glRect.left, glRect.top, glRect.right, glRect.bottom, + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST ); @@ -231,7 +229,7 @@ GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const } } -GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const +GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc) const { if (m_msaaSamples <= 1) { @@ -242,17 +240,15 @@ GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is // required. - // Flip source rectangle upside-down for OpenGL. - TRectangle glRect; - sourceRc.FlipYPosition(m_targetHeight, &glRect); - glRect.Clamp(0, 0, m_targetWidth, m_targetHeight); + TargetRectangle targetRc = ConvertEFBRectangle(sourceRc); + targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight); // Resolve. glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer); glBlitFramebufferEXT( - glRect.left, glRect.top, glRect.right, glRect.bottom, - glRect.left, glRect.top, glRect.right, glRect.bottom, + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, GL_DEPTH_BUFFER_BIT, GL_NEAREST ); @@ -263,6 +259,16 @@ GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const } } +TargetRectangle FramebufferManager::ConvertEFBRectangle(const EFBRectangle& rc) const +{ + TargetRectangle result; + result.left = rc.left * m_targetWidth / EFB_WIDTH; + result.top = m_targetHeight - (rc.top * m_targetHeight / EFB_HEIGHT); + result.right = rc.right * m_targetWidth / EFB_WIDTH; + result.bottom = m_targetHeight - (rc.bottom * m_targetHeight / EFB_HEIGHT); + return result; +} + FramebufferManager::VirtualXFBListType::iterator FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height) { @@ -283,7 +289,7 @@ FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height) return m_virtualXFBList.end(); } -void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc) +void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) { u8* pXFB = Memory_GetPtr(xfbAddr); if (!pXFB) @@ -295,7 +301,7 @@ void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, c XFB_Write(pXFB, sourceRc, fbWidth, fbHeight); } -void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc) +void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) { GLuint xfbTexture; @@ -311,7 +317,7 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight it->xfbSource.texWidth = m_targetWidth; it->xfbSource.texHeight = m_targetHeight; - it->xfbSource.sourceRc = sourceRc; + it->xfbSource.sourceRc = ConvertEFBRectangle(sourceRc); xfbTexture = it->xfbSource.texture; @@ -348,7 +354,7 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight newVirt.xfbSource.texture = xfbTexture; newVirt.xfbSource.texWidth = m_targetWidth; newVirt.xfbSource.texHeight = m_targetHeight; - newVirt.xfbSource.sourceRc = sourceRc; + newVirt.xfbSource.sourceRc = ConvertEFBRectangle(sourceRc); // Add the new Virtual XFB to the list @@ -407,20 +413,22 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight) { - m_realXFBSource.texWidth = XFB_WIDTH; - m_realXFBSource.texHeight = XFB_HEIGHT; + m_realXFBSource.texWidth = MAX_XFB_WIDTH; + m_realXFBSource.texHeight = MAX_XFB_HEIGHT; + // OpenGL texture coordinates originate at the lower left, which is why + // sourceRc.top = fbHeight and sourceRc.bottom = 0. m_realXFBSource.sourceRc.left = 0; - m_realXFBSource.sourceRc.top = 0; + m_realXFBSource.sourceRc.top = fbHeight; m_realXFBSource.sourceRc.right = fbWidth; - m_realXFBSource.sourceRc.bottom = fbHeight; + m_realXFBSource.sourceRc.bottom = 0; if (!m_realXFBSource.texture) { glGenTextures(1, &m_realXFBSource.texture); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h index 99850d82d8..2ee3314b81 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h @@ -74,7 +74,7 @@ struct XFBSource int texWidth; int texHeight; - TRectangle sourceRc; + TargetRectangle sourceRc; }; class FramebufferManager @@ -95,19 +95,19 @@ public: void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples); void Shutdown(); - // sourceRc is in GL target coordinates, not GameCube EFB coordinates! - // TODO: Clean that up. - void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc); + void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); const XFBSource* GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight); // To get the EFB in texture form, these functions may have to transfer // the EFB to a resolved texture first. - GLuint GetEFBColorTexture(const TRectangle& sourceRc) const; - GLuint GetEFBDepthTexture(const TRectangle& sourceRc) const; + GLuint GetEFBColorTexture(const EFBRectangle& sourceRc) const; + GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc) const; GLuint GetEFBFramebuffer() const { return m_efbFramebuffer; } + TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) const; + private: struct VirtualXFB @@ -124,8 +124,8 @@ private: VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height); - void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc); - void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc); + void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); const XFBSource* getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight); const XFBSource* getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h b/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h index d75638d9ec..7e1c7bfd9b 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h @@ -22,6 +22,7 @@ #include "nGLUtil.h" #else #include "Config.h" +#include "MathUtil.h" #include "pluginspecs_video.h" #ifdef _WIN32 @@ -112,6 +113,13 @@ extern GLWindow GLWin; // Public OpenGL util +// This structure should only be used to represent a rectangle in OpenGL target +// coordinates, where the origin is at the lower left and the frame dimensions +// depend on the resolution settings. Use Renderer::ConvertEFBRectangle to +// convert an EFBRectangle to a TargetRectangle. +struct TargetRectangle : public MathUtil::Rectangle +{}; + // Initialization / upkeep bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _width, int _height); void OpenGL_Shutdown(); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index e254f13784..2c26016e12 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -442,6 +442,11 @@ float Renderer::GetTargetScaleY() return (float)GetTargetHeight() / (float)EFB_HEIGHT; } +TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) +{ + return s_framebufferManager.ConvertEFBRectangle(rc); +} + void Renderer::SetFramebuffer(GLuint fb) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : s_framebufferManager.GetEFBFramebuffer()); @@ -451,15 +456,15 @@ void Renderer::ResetGLState() { // Gets us to a reasonably sane state where it's possible to do things like // image copies with textured quads, etc. + glDisable(GL_VERTEX_PROGRAM_ARB); + glDisable(GL_FRAGMENT_PROGRAM_ARB); + glDisable(GL_SCISSOR_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_BLEND); glDepthMask(GL_FALSE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - glDisable(GL_VERTEX_PROGRAM_ARB); - glDisable(GL_FRAGMENT_PROGRAM_ARB); } void UpdateViewport(); @@ -533,13 +538,76 @@ void Renderer::SetBlendMode(bool forceUpdate) s_blendMode = newval; } +u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) +{ + // Get the rectangular target region covered by the EFB pixel. + EFBRectangle efbPixelRc; + efbPixelRc.left = x; + efbPixelRc.top = y; + efbPixelRc.right = x + 1; + efbPixelRc.bottom = y + 1; + + TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc); + + switch (type) + { + + case PEEK_Z: + { + if (s_MSAASamples > 1) + { + // XXX: What is this? Binding a texture to a framebuffer slot? + // It's not documented in the OpenGL spec, but it seems to work! + // (ATI Radeon HD 3870, CATALYST 9.6 drivers, Windows Vista 64-bit...) + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ResolveAndGetDepthTarget(efbPixelRc)); + } + + // Sample from the center of the target region. + int srcX = (targetPixelRc.left + targetPixelRc.right) / 2; + int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2; + + u32 z; + glReadPixels(srcX, srcY, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &z); + GL_REPORT_ERRORD(); + + if (s_MSAASamples > 1) + { + // Return to the EFB (this may not be necessary). + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_framebufferManager.GetEFBFramebuffer()); + } + + // Scale the 32-bit value returned by glReadPixels to a 24-bit + // value (GC uses a 24-bit Z-buffer). + return z >> 8; + } + + case POKE_Z: + // TODO: Implement + break; + + case PEEK_COLOR: + // TODO: Implement + break; + + case POKE_COLOR: + // TODO: Implement. One way is to draw a tiny pixel-sized rectangle at + // the exact location. Note: EFB pokes are susceptible to Z-buffering + // and perhaps blending. + //WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering"); + break; + + } + + return 0; +} + // Apply AA if enabled -GLuint Renderer::ResolveAndGetRenderTarget(const TRectangle &source_rect) +GLuint Renderer::ResolveAndGetRenderTarget(const EFBRectangle &source_rect) { return s_framebufferManager.GetEFBColorTexture(source_rect); } -GLuint Renderer::ResolveAndGetDepthTarget(const TRectangle &source_rect) +GLuint Renderer::ResolveAndGetDepthTarget(const EFBRectangle &source_rect) { return s_framebufferManager.GetEFBDepthTexture(source_rect); } @@ -600,7 +668,7 @@ bool Renderer::SetScissorRect() } // Aspect ratio functions -void ComputeBackbufferRectangle(TRectangle *rc) +static void ComputeBackbufferRectangle(TargetRectangle *rc) { float FloatGLWidth = (float)OpenGL_GetBackbufferWidth(); float FloatGLHeight = (float)OpenGL_GetBackbufferHeight(); @@ -657,12 +725,45 @@ void ComputeBackbufferRectangle(TRectangle *rc) int XOffset = floor(FloatXOffset + 0.5); int YOffset = floor(FloatYOffset + 0.5); rc->left = XOffset; - rc->top = YOffset; + rc->top = YOffset + ceil(FloatGLHeight); rc->right = XOffset + ceil(FloatGLWidth); - rc->bottom = YOffset + ceil(FloatGLHeight); + rc->bottom = YOffset; } -void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc) +void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) +{ + // Update the view port for clearing the picture + glViewport(0, 0, Renderer::GetTargetWidth(), Renderer::GetTargetHeight()); + + TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc); + + // Always set the scissor in case it was set by the game and has not been reset + glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight()); + + VertexShaderManager::SetViewportChanged(); + + GLbitfield bits = 0; + if (colorEnable) + { + bits |= GL_COLOR_BUFFER_BIT; + glClearColor( + ((color >> 16) & 0xFF) / 255.0f, + ((color >> 8) & 0xFF) / 255.0f, + (color & 0xFF) / 255.0f, + (alphaEnable ? ((color >> 24) & 0xFF) / 255.0f : 1.0f) + ); + } + if (zEnable) + { + bits |= GL_DEPTH_BUFFER_BIT; + glClearDepth((z & 0xFFFFFF) / float(0xFFFFFF)); + } + + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glClear(bits); +} + +void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) { // If we're about to write to a requested XFB, make sure the previous // contents make it to the screen first. @@ -686,29 +787,26 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) ResetGLState(); - TRectangle back_rc; + TargetRectangle back_rc; ComputeBackbufferRectangle(&back_rc); - float u_max; - float v_min; - float v_max; + TargetRectangle sourceRc; - if (g_Config.bAutoScale) + if (g_Config.bAutoScale || g_Config.bUseXFB) { - u_max = (xfbSource->sourceRc.right - xfbSource->sourceRc.left); - v_min = (float)xfbSource->texHeight - (xfbSource->sourceRc.bottom - xfbSource->sourceRc.top); - v_max = (float)xfbSource->texHeight; + sourceRc = xfbSource->sourceRc; } else { - u_max = (float)xfbSource->texWidth; - v_min = 0.f; - v_max = (float)xfbSource->texHeight; + sourceRc.left = 0; + sourceRc.top = xfbSource->texHeight; + sourceRc.right = xfbSource->texWidth; + sourceRc.bottom = 0; } int yOffset = (g_Config.bUseXFB && field == FIELD_LOWER) ? -1 : 0; - v_min -= yOffset; - v_max -= yOffset; + sourceRc.top -= yOffset; + sourceRc.bottom -= yOffset; // Tell the OSD Menu about the current internal resolution OSDInternalW = xfbSource->sourceRc.GetWidth(); OSDInternalH = xfbSource->sourceRc.GetHeight(); @@ -723,8 +821,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) TextureMngr::DisableStage(i); // Update GLViewPort - glViewport(back_rc.left, back_rc.top, - back_rc.right - back_rc.left, back_rc.bottom - back_rc.top); + glViewport(back_rc.left, back_rc.bottom, back_rc.GetWidth(), back_rc.GetHeight()); GL_REPORT_ERRORD(); @@ -743,25 +840,25 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) // We must call ApplyShader here even if no post proc is selected - it takes // care of disabling it in that case. It returns false in case of no post processing. - if (PostProcessing::ApplyShader()) + if (PostProcessing::ApplyShader()) { glBegin(GL_QUADS); - glTexCoord2f(0, v_min); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0); glVertex2f(-1, -1); - glTexCoord2f(0, v_max); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1); glVertex2f(-1, 1); - glTexCoord2f(u_max, v_max); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1); glVertex2f( 1, 1); - glTexCoord2f(u_max, v_min); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0); glVertex2f( 1, -1); + glTexCoord2f(sourceRc.left, sourceRc.bottom); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0); glVertex2f(-1, -1); + glTexCoord2f(sourceRc.left, sourceRc.top); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1); glVertex2f(-1, 1); + glTexCoord2f(sourceRc.right, sourceRc.top); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1); glVertex2f( 1, 1); + glTexCoord2f(sourceRc.right, sourceRc.bottom); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0); glVertex2f( 1, -1); glEnd(); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); glDisable(GL_FRAGMENT_PROGRAM_ARB); } - else + else { glBegin(GL_QUADS); - glTexCoord2f(0, v_min); glVertex2f(-1, -1); - glTexCoord2f(0, v_max); glVertex2f(-1, 1); - glTexCoord2f(u_max, v_max); glVertex2f( 1, 1); - glTexCoord2f(u_max, v_min); glVertex2f( 1, -1); + glTexCoord2f(sourceRc.left, sourceRc.bottom); glVertex2f(-1, -1); + glTexCoord2f(sourceRc.left, sourceRc.top); glVertex2f(-1, 1); + glTexCoord2f(sourceRc.right, sourceRc.top); glVertex2f( 1, 1); + glTexCoord2f(sourceRc.right, sourceRc.bottom); glVertex2f( 1, -1); glEnd(); } @@ -783,7 +880,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) s_criticalScreenshot.Enter(); // Save screenshot - SaveRenderTarget(s_sScreenshotName.c_str(), xfbSource->sourceRc.GetWidth(), xfbSource->sourceRc.GetHeight(), (int)(v_min)); + SaveRenderTarget(s_sScreenshotName.c_str(), xfbSource->sourceRc.GetWidth(), xfbSource->sourceRc.GetHeight(), yOffset); // Reset settings s_sScreenshotName = ""; s_bScreenshot = false; @@ -806,7 +903,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) s_criticalScreenshot.Enter(); int w = xfbSource->sourceRc.GetWidth(); int h = xfbSource->sourceRc.GetHeight(); - int t = (int)(v_min); + int t = yOffset; u8 *data = (u8 *) malloc(3 * w * h); glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, t, w, h, GL_BGR, GL_UNSIGNED_BYTE, data); @@ -1005,8 +1102,10 @@ void Renderer::DrawDebugText() glBegin(GL_LINES); // Draw EFB copy regions rectangles - for (std::vector::const_iterator it = stats.efb_regions.begin(); it != stats.efb_regions.end(); ++it) + for (std::vector::const_iterator it = stats.efb_regions.begin(); it != stats.efb_regions.end(); ++it) { + // TODO: Scale EFBRectangles correctly + GLfloat halfWidth = Renderer::GetTargetWidth() / 2.0f; GLfloat halfHeight = Renderer::GetTargetHeight() / 2.0f; GLfloat x = (GLfloat) -1.0f + ((GLfloat)it->left / halfWidth); @@ -1257,13 +1356,9 @@ void Renderer::FlipImageData(u8 *data, int w, int h) } } } -////////////////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////////// -// Function: This function does not have the final picture. Use Renderer::Swap() to adjust the final picture. +// This function does not have the final picture. Use Renderer::Swap() to adjust the final picture. // Call schedule: Called from VertexShaderManager -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ void UpdateViewport() { // --------- diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.h b/Source/Plugins/Plugin_VideoOGL/Src/Render.h index c55f5cc285..f4a07e430f 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.h @@ -68,17 +68,21 @@ public: static float GetTargetScaleX(); static float GetTargetScaleY(); + static TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc); + static void SetFramebuffer(GLuint fb); + static u32 AccessEFB(EFBAccessType type, int x, int y); + // If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID. // Thus, this call may be expensive. Don't repeat it unnecessarily. // If not in MSAA mode, will just return the render target texture ID. // After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to. - static GLuint ResolveAndGetRenderTarget(const TRectangle &rect); + static GLuint ResolveAndGetRenderTarget(const EFBRectangle &rect); // Same as above but for the depth Target. // After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to. - static GLuint ResolveAndGetDepthTarget(const TRectangle &rect); + static GLuint ResolveAndGetDepthTarget(const EFBRectangle &rect); // Random utilities static void RenderText(const char* pstr, int left, int top, u32 color); @@ -87,12 +91,11 @@ public: static void FlipImageData(u8 *data, int w, int h); static bool SaveRenderTarget(const char *filename, int w, int h, int YOffset = 0); - static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc); + static void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z); + static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); // Finish up the current frame, print some stats static void Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight); }; -void ComputeBackbufferRectangle(TRectangle *rc); - #endif // _GCOGL_RENDER_H_ diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp index 3db8a816f6..b128716437 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp @@ -166,7 +166,7 @@ void Shutdown() s_texConvFrameBuffer = 0; } -void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TRectangle& sourceRc, +void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight, bool linearFilter) { Renderer::ResetGLState(); @@ -228,7 +228,7 @@ void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TRe GL_REPORT_ERRORD(); } -void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const TRectangle& source) +void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle& source) { u32 format = copyfmt; @@ -250,10 +250,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf u8 *dest_ptr = Memory_GetPtr(address); - TRectangle scaledTargetSource; - source.Scale(Renderer::GetTargetScaleX(), Renderer::GetTargetScaleY(), &scaledTargetSource); - - u32 source_texture = bFromZBuffer ? Renderer::ResolveAndGetDepthTarget(scaledTargetSource) : Renderer::ResolveAndGetRenderTarget(scaledTargetSource); + GLuint source_texture = bFromZBuffer ? Renderer::ResolveAndGetDepthTarget(source) : Renderer::ResolveAndGetRenderTarget(source); int width = source.right - source.left; int height = source.bottom - source.top; @@ -291,7 +288,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf TextureConversionShader::SetShaderParameters((float)expandedWidth, expandedHeight * MValueY, source.left * MValueX, top, sampleStride * MValueX, sampleStride * MValueY); - TRectangle scaledSource; + TargetRectangle scaledSource; scaledSource.top = 0; scaledSource.bottom = expandedHeight; scaledSource.left = 0; @@ -300,7 +297,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, bScaleByHalf); } -void EncodeToRamYUYV(GLuint srcTexture, const TRectangle& sourceRc, +void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight) { EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, false); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.h b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.h index f9f3785117..8ae7801d35 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.h @@ -30,9 +30,9 @@ void Init(); void Shutdown(); void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, - u32 copyfmt, bool bScaleByHalf, const TRectangle& source); + u32 copyfmt, bool bScaleByHalf, const EFBRectangle& source); -void EncodeToRamYUYV(GLuint srcTexture, const TRectangle& sourceRc, +void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight); void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp index 3af2827787..5f7ba43474 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp @@ -488,7 +488,7 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width } -void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const TRectangle &source_rect) +void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect) { DVSTARTPROFILE(); GL_REPORT_ERRORD(); @@ -682,24 +682,9 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool } } -// if (bCopyToTarget) { -// _assert_(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT); -// glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); -// GL_REPORT_ERRORD(); -// glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, source->left, source->top, source->right-source->left, source->bottom-source->top); -// entry.isUpsideDown = true; // note that the copy is upside down!! -// GL_REPORT_ERRORD(); -// return; -// } - - TRectangle scaled_rect; - source_rect.Scale(Renderer::GetTargetScaleX(), Renderer::GetTargetScaleY(), &scaled_rect); - TRectangle flipped_rect; - scaled_rect.FlipY(Renderer::GetTargetHeight(), &flipped_rect); - // Make sure to resolve anything we need to read from. // TODO - it seems that it sometimes doesn't resolve the entire area we are interested in. See shadows in Burnout 2. - GLuint read_texture = bFromZBuffer ? Renderer::ResolveAndGetDepthTarget(scaled_rect) : Renderer::ResolveAndGetRenderTarget(scaled_rect); + GLuint read_texture = bFromZBuffer ? Renderer::ResolveAndGetDepthTarget(source_rect) : Renderer::ResolveAndGetRenderTarget(source_rect); GL_REPORT_ERRORD(); @@ -727,11 +712,13 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation GL_REPORT_ERRORD(); + TargetRectangle targetSource = Renderer::ConvertEFBRectangle(source_rect); + glBegin(GL_QUADS); - glTexCoord2f((GLfloat)flipped_rect.left, (GLfloat)flipped_rect.bottom); glVertex2f(-1, 1); - glTexCoord2f((GLfloat)flipped_rect.left, (GLfloat)flipped_rect.top ); glVertex2f(-1, -1); - glTexCoord2f((GLfloat)flipped_rect.right, (GLfloat)flipped_rect.top ); glVertex2f( 1, -1); - glTexCoord2f((GLfloat)flipped_rect.right, (GLfloat)flipped_rect.bottom); glVertex2f( 1, 1); + glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.bottom); glVertex2f(-1, 1); + glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.top ); glVertex2f(-1, -1); + glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.top ); glVertex2f( 1, -1); + glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.bottom); glVertex2f( 1, 1); glEnd(); GL_REPORT_ERRORD(); @@ -751,10 +738,6 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool { static int count = 0; SaveTexture(StringFromFormat("%s/efb_frame_%i.tga", FULL_DUMP_TEXTURES_DIR, count++).c_str(), GL_TEXTURE_RECTANGLE_ARB, entry.texture, entry.w, entry.h); - //TODO: Fix this - //SaveTexture(StringFromFormat("%s/efb_tex_%i.tga", FULL_DUMP_TEXTURES_DIR, --count).c_str(), GL_TEXTURE_RECTANGLE_ARB, - // bFromZBuffer ? Renderer::ResolveAndGetFakeZTarget(source_rect) : Renderer::ResolveAndGetRenderTarget(source_rect), - // Renderer::GetTargetWidth() * 2, Renderer::GetTargetHeight() * 2); } } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h index 0fb6c5e80d..eaf4b83f8e 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h @@ -71,7 +71,7 @@ public: static void InvalidateRange(u32 start_address, u32 size); static TCacheEntry* Load(int texstage, u32 address, int width, int height, int format, int tlutaddr, int tlutfmt); - static void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const TRectangle &source); + static void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source); static void DisableStage(int stage); // sets active texture diff --git a/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp b/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp index f607f70f79..0b86c1d63f 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp @@ -29,13 +29,8 @@ #include "Render.h" #include "TextureConverter.h" -void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt) +void XFB_Write(u8 *xfb_in_ram, const EFBRectangle& sourceRc, u32 dstWd, u32 dstHt) { - TRectangle renderSrcRc; - renderSrcRc.left = sourceRc.left; - renderSrcRc.right = sourceRc.right; - // OpenGL upside down as usual... - renderSrcRc.top = Renderer::GetTargetHeight() - sourceRc.top; - renderSrcRc.bottom = Renderer::GetTargetHeight() - sourceRc.bottom; - TextureConverter::EncodeToRamYUYV(Renderer::ResolveAndGetRenderTarget(sourceRc), renderSrcRc, xfb_in_ram, dstWd, dstHt); + TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc); + TextureConverter::EncodeToRamYUYV(Renderer::ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram, dstWd, dstHt); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/XFB.h b/Source/Plugins/Plugin_VideoOGL/Src/XFB.h index dabfe97f55..658a575d53 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/XFB.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/XFB.h @@ -18,7 +18,9 @@ #ifndef _XFB_H_ #define _XFB_H_ +#include "GLUtil.h" + // write the EFB to the XFB -void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt); +void XFB_Write(u8 *xfb_in_ram, const EFBRectangle& sourceRc, u32 dstWd, u32 dstHt); #endif // _XFB_H_ diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index a284bf3b21..2cd4c8f5ff 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -523,55 +523,7 @@ void VideoFifo_CheckEFBAccess() { s_efbAccessRequested = FALSE; - switch (s_accessEFBArgs.type) - { - case PEEK_Z: - { - u32 z = 0; - float xScale = Renderer::GetTargetScaleX(); - float yScale = Renderer::GetTargetScaleY(); - - if (g_Config.iMultisampleMode != MULTISAMPLE_OFF) - { - // Find the proper dimensions - TRectangle source, scaledTargetSource; - ComputeBackbufferRectangle(&source); - source.Scale(xScale, yScale, &scaledTargetSource); - // This will resolve and bind to the depth buffer - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Renderer::ResolveAndGetDepthTarget(scaledTargetSource)); - } - - // Read the z value! Also adjust the pixel to read to the upscaled EFB resolution - // Plus we need to flip the y value as the OGL image is upside down - glReadPixels(s_accessEFBArgs.x*xScale, Renderer::GetTargetHeight() - s_accessEFBArgs.y*yScale, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &z); - GL_REPORT_ERRORD(); - - // Clamp the 32bits value returned by glReadPixels to a 24bits value (GC uses a 24bits Z-Buffer) - s_AccessEFBResult = z / 0x100; - - // We should probably re-bind the old fbo here. - if (g_Config.iMultisampleMode != MULTISAMPLE_OFF) { - Renderer::SetFramebuffer(0); - } - } - break; - - case POKE_Z: - // TODO: Implement - break; - - case PEEK_COLOR: - // TODO: Implement - s_AccessEFBResult = 0; - break; - - case POKE_COLOR: - // TODO: Implement. One way is to draw a tiny pixel-sized rectangle at - // the exact location. Note: EFB pokes are susceptible to Z-buffering - // and perhaps blending. - //WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering"); - break; - } + s_AccessEFBResult = Renderer::AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y); s_efbResponseEvent.Set(); }