diff --git a/Source/Core/Core/Src/HW/VideoInterface.cpp b/Source/Core/Core/Src/HW/VideoInterface.cpp index 670dbb5a30..133784b471 100644 --- a/Source/Core/Core/Src/HW/VideoInterface.cpp +++ b/Source/Core/Core/Src/HW/VideoInterface.cpp @@ -1079,44 +1079,40 @@ void Update() u8* xfbPtr = 0; int yOffset = 0; - // (mb2) hack: We request XFB updates from CPUthread (here) only when homebrews use directly XFB without FIFO and CP - if (!Core::GetStartupParameter().bUseDualCore || CommandProcessor::IsCommandProcessorNotUsed()) + if (NextXFBRender == 1) { - if (NextXFBRender == 1) - { - NextXFBRender = LinesPerField; - // TODO: proper VI regs typedef and logic for XFB to work. - // eg. Animal Crossing gc have smth in TFBL.XOF bitfield. - // "XOF - Horizontal Offset of the left-most pixel within the first word of the fetched picture." - xfbPtr = GetXFBPointerTop(); - _dbg_assert_msg_(VIDEOINTERFACE, xfbPtr, "Bad top XFB address"); - } + NextXFBRender = LinesPerField; + // TODO: proper VI regs typedef and logic for XFB to work. + // eg. Animal Crossing gc have smth in TFBL.XOF bitfield. + // "XOF - Horizontal Offset of the left-most pixel within the first word of the fetched picture." + xfbPtr = GetXFBPointerTop(); + _dbg_assert_msg_(VIDEOINTERFACE, xfbPtr, "Bad top XFB address"); + } + else + { + NextXFBRender = 1; + // Previously checked m_XFBInfoTop.POFF then used m_XFBInfoBottom.FBB, try reverting if there are problems + xfbPtr = GetXFBPointerBottom(); + _dbg_assert_msg_(VIDEOINTERFACE, xfbPtr, "Bad bottom XFB address"); + yOffset = -1; + } + + Common::PluginVideo* video = CPluginManager::GetInstance().GetVideo(); + + if (xfbPtr && video->IsValid()) + { + int fbWidth = m_HorizontalStepping.FieldSteps * 16; + int fbHeight = (m_HorizontalStepping.FbSteps / m_HorizontalStepping.FieldSteps) * m_VerticalTimingRegister.ACV; + + DEBUG_LOG(VIDEOINTERFACE, "(VI->XFBUpdate): ptr: %p | %ix%i | xoff: %i", + xfbPtr, fbWidth, fbHeight, m_XFBInfoTop.XOFF); + + if (Core::GetStartupParameter().bUseDualCore) + // scheduled on EmuThread in DC mode + video->Video_UpdateXFB(xfbPtr, fbWidth, fbHeight, yOffset, TRUE); else - { - NextXFBRender = 1; - // Previously checked m_XFBInfoTop.POFF then used m_XFBInfoBottom.FBB, try reverting if there are problems - xfbPtr = GetXFBPointerBottom(); - _dbg_assert_msg_(VIDEOINTERFACE, xfbPtr, "Bad bottom XFB address"); - yOffset = -1; - } - - Common::PluginVideo* video = CPluginManager::GetInstance().GetVideo(); - - if (xfbPtr && video->IsValid()) - { - int fbWidth = m_HorizontalStepping.FieldSteps * 16; - int fbHeight = (m_HorizontalStepping.FbSteps / m_HorizontalStepping.FieldSteps) * m_VerticalTimingRegister.ACV; - - DEBUG_LOG(VIDEOINTERFACE, "(VI->XFBUpdate): ptr: %p | %ix%i | xoff: %i", - xfbPtr, fbWidth, fbHeight, m_XFBInfoTop.XOFF); - - if (Core::GetStartupParameter().bUseDualCore) - // scheduled on EmuThread in DC mode - video->Video_UpdateXFB(xfbPtr, fbWidth, fbHeight, yOffset, TRUE); - else - // otherwise do it now from here (CPUthread) - video->Video_UpdateXFB(xfbPtr, fbWidth, fbHeight, yOffset, FALSE); - } + // otherwise do it now from here (CPUthread) + video->Video_UpdateXFB(xfbPtr, fbWidth, fbHeight, yOffset, FALSE); } } diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index e16da797e8..1325408294 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -143,7 +143,6 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) if (g_XFBUpdateRequested) { Video_UpdateXFB(NULL, 0, 0, 0, FALSE); - video_initialize.pCopiedToXFB(); } // check if we are able to run this buffer diff --git a/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp b/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp index 92ac70602e..3c5992f0b1 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp @@ -134,26 +134,7 @@ void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const b void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u8* pXFB, const u32 &dstWidth, const u32 &dstHeight) { - // EFB to XFB - if (g_Config.bUseXFB) - { - - XFB_Write(pXFB, multirc, dstWidth, dstHeight); - // FIXME: we draw XFB from here in DC mode. - // Bad hack since we can have multiple EFB to XFB copy before a draw. - // Plus we should use width and height from VI regs (see VI->Update()). - // Dixit donkopunchstania for the info. - //DebugLog("(EFB to XFB->XFB_Draw): ptr: %08x | %ix%i", (u32)pXFB, dstWidth, dstHeight); - if (g_VideoInitialize.bUseDualCore) - XFB_Draw(pXFB, dstWidth, dstHeight, 0); - } - else - { - // Hm, we need to compensate for the fact that the copy may be bigger than what is displayed. - // Seen in Spartan Warrior. Not sure how to deal with it yet. - Renderer::Swap(multirc); - } - g_VideoInitialize.pCopiedToXFB(); + Renderer::RenderToXFB(pXFB, multirc, dstWidth, dstHeight); } void ClearScreen(const Bypass &bp, const TRectangle &multirc) { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index deaae20cf0..309fa248b8 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -49,6 +49,7 @@ #include "VertexLoaderManager.h" #include "VertexLoader.h" #include "PostProcessing.h" +#include "TextureConverter.h" #include "XFB.h" #include "OnScreenDisplay.h" #include "Timer.h" @@ -122,6 +123,10 @@ static GLuint s_DepthBuffer = 0; static GLuint s_ResolvedRenderTarget = 0; static GLuint s_ResolvedDepthTarget = 0; +static TRectangle s_efbSourceRc; +static GLuint s_xfbFramebuffer = 0; // Only used when multisampling is on +static GLuint s_xfbTexture = 0; + static bool s_bHaveStencilBuffer = false; static bool s_bHaveFramebufferBlit = false; static bool s_bHaveCoverageMSAA = false; @@ -319,6 +324,12 @@ bool Renderer::Init() if (s_targetheight < EFB_HEIGHT) s_targetheight = EFB_HEIGHT; + // Create the XFB texture + glGenTextures(1, &s_xfbTexture); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, s_targetwidth, s_targetheight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + SetDefaultRectTexParams(); + glGenFramebuffersEXT(1, (GLuint *)&s_uFramebuffer); if (s_uFramebuffer == 0) { ERROR_LOG(VIDEO, "failed to create the renderbufferDoes your video card support OpenGL 2.x?"); @@ -365,6 +376,17 @@ bool Renderer::Init() } else { + // Create XFB framebuffer for transferring the multisampled EFB to the + // XFB texture + glGenFramebuffersEXT(1, &s_xfbFramebuffer); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_xfbFramebuffer); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture, 0); + + GL_REPORT_FBO_ERROR(); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer); + // MSAA rendertarget init. // First set up the boring multisampled rendertarget. glGenRenderbuffersEXT(1, &s_RenderTarget); @@ -466,12 +488,7 @@ bool Renderer::Init() if (!InitializeGL()) return false; - XFB_Init(); return glGetError() == GL_NO_ERROR && bSuccess; - - // Now save the actual settings - s_targetwidth = (int)OpenGL_GetBackbufferWidth(); - s_targetheight = (int)OpenGL_GetBackbufferHeight(); } void Renderer::Shutdown(void) @@ -479,24 +496,28 @@ void Renderer::Shutdown(void) delete s_pfont; s_pfont = 0; - XFB_Shutdown(); - if (g_cgcontext) { cgDestroyContext(g_cgcontext); g_cgcontext = 0; - } - if (s_RenderTarget) { - glDeleteTextures(1, &s_RenderTarget); - s_RenderTarget = 0; - } - if (s_DepthTarget) { - glDeleteRenderbuffersEXT(1, &s_DepthTarget); - s_DepthTarget = 0; - } - if (s_uFramebuffer) { - glDeleteFramebuffersEXT(1, &s_uFramebuffer); - s_uFramebuffer = 0; - } + } + + // Note: OpenGL delete functions automatically ignore if parameter is 0 + + glDeleteFramebuffersEXT(1, &s_uFramebuffer); + s_uFramebuffer = 0; + + glDeleteTextures(1, &s_RenderTarget); + s_RenderTarget = 0; + + glDeleteRenderbuffersEXT(1, &s_DepthTarget); + s_DepthTarget = 0; + + glDeleteFramebuffersEXT(1, &s_xfbFramebuffer); + s_xfbFramebuffer = 0; + + glDeleteTextures(1, &s_xfbTexture); + s_xfbTexture = 0; + #ifdef _WIN32 if(s_bAVIDumping) { AVIDump::Stop(); @@ -579,8 +600,11 @@ float Renderer::GetTargetScaleY() // Various supporting functions void Renderer::SetRenderTarget(GLuint targ) { - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, - targ != 0 ? targ : s_RenderTarget, 0); + if (!targ && s_MSAASamples > 1) + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_RenderTarget); + else + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, + targ != 0 ? targ : s_RenderTarget, 0); } void Renderer::SetFramebuffer(GLuint fb) @@ -603,9 +627,14 @@ void Renderer::ResetGLState() glDisable(GL_FRAGMENT_PROGRAM_ARB); } +void UpdateViewport(); + void Renderer::RestoreGLState() { // Gets us back into a more game-like state. + + UpdateViewport(); + if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE); if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST); if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE); @@ -849,11 +878,66 @@ void ComputeBackbufferRectangle(TRectangle *rc) rc->bottom = YOffset + ceil(FloatGLHeight); } +void Renderer::DecodeFromXFB(u8* xfbInRam, u32 dstWidth, u32 dstHeight, s32 yOffset) +{ + TextureConverter::DecodeToTexture(xfbInRam + yOffset*(XFB_WIDTH*2), dstWidth, dstHeight, s_xfbTexture); +} + +void Renderer::RenderToXFB(u8* xfbInRam, const TRectangle& sourceRc, u32 dstWidth, u32 dstHeight) +{ + // Make sure the previous contents made it to the screen if requested + if (g_XFBUpdateRequested) + { + Video_UpdateXFB(NULL, 0, 0, 0, FALSE); + } + + if (g_Config.bUseXFB) + { + s_efbSourceRc.left = 0; + s_efbSourceRc.top = 0; + s_efbSourceRc.right = GetTargetWidth(); + s_efbSourceRc.bottom = GetTargetHeight(); + XFB_Write(xfbInRam, sourceRc, dstWidth, dstHeight); + } + else + { + // Renderer::Swap will use the source rectangle saved here + s_efbSourceRc = sourceRc; + + if (s_MSAASamples > 1) + { + // Cannot use glCopyTexImage2D on multisampled framebuffers, so + // EXT_framebuffer_blit must be used + + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, s_xfbFramebuffer); + + glBlitFramebufferEXT( + 0, 0, s_targetwidth, s_targetheight, + 0, 0, s_targetwidth, s_targetheight, + GL_COLOR_BUFFER_BIT, GL_NEAREST + ); + + // Return to the EFB + SetFramebuffer(0); + } + else + { + // Just copy the EFB directly + SetFramebuffer(0); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture); + glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, 0, 0, s_targetwidth, s_targetheight, 0); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + } + } +} -// This function has the final picture if the XFB functions are not used. We +// This function has the final picture. We // adjust the aspect ratio here. -void Renderer::Swap(const TRectangle& rc) +void Renderer::Swap() { OpenGL_Update(); // just updates the render window position and the backbuffer size DVSTARTPROFILE(); @@ -868,8 +952,8 @@ void Renderer::Swap(const TRectangle& rc) float v_max; if (g_Config.bAutoScale) { - u_max = (rc.right - rc.left); - v_min = (float)GetTargetHeight() - (rc.bottom - rc.top); + u_max = (s_efbSourceRc.right - s_efbSourceRc.left); + v_min = (float)GetTargetHeight() - (s_efbSourceRc.bottom - s_efbSourceRc.top); v_max = (float)GetTargetHeight(); } else @@ -879,97 +963,63 @@ void Renderer::Swap(const TRectangle& rc) } // Tell the OSD Menu about the current internal resolution - OSDInternalW = rc.right; OSDInternalH = rc.bottom; + OSDInternalW = s_efbSourceRc.GetWidth(); OSDInternalH = s_efbSourceRc.bottom; // Make sure that the wireframe setting doesn't screw up the screen copy. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - // --------------------------------------------------------------------- - // Resolve the multisampled rendertarget into the normal one. - // ŻŻŻŻŻŻŻŻŻŻŻŻŻ - if (/*s_bHaveFramebufferBlit*/ s_MSAASamples > 1) + // Textured triangles are necessary because of post-processing shaders + + // Disable all other stages + for (int i = 1; i < 8; ++i) + TextureMngr::DisableStage(i); + + // Update GLViewPort + glViewport(back_rc.left, back_rc.top, + back_rc.right - back_rc.left, back_rc.bottom - back_rc.top); + + GL_REPORT_ERRORD(); + + // Copy the framebuffer to screen. + + // Render to the real buffer now. + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer + + // Texture map s_xfbTexture onto the main buffer + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_RECTANGLE_ARB); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture); + // Use linear filtering. + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + // 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()) { - // Use framebuffer blit to stretch screen. - // No messing around with annoying glBegin and viewports, plus can support multisampling. - if (s_MSAASamples > 1) - { - ResolveAndGetRenderTarget(rc); - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uResolvedFramebuffer); - } - else - { - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer); - } - // Draw to the window buffer with bilinear filtering - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); - glBlitFramebufferEXT(0, v_min, u_max, v_max, - back_rc.left, back_rc.top, back_rc.right, back_rc.bottom, - GL_COLOR_BUFFER_BIT, GL_LINEAR); + 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); + glEnd(); + + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); + glDisable(GL_FRAGMENT_PROGRAM_ARB); } - else + else { - // No framebuffer_blit extension - crappy gfx card! Fall back to plain texturing solution. - // Disable all other stages. - for (int i = 1; i < 8; ++i) - TextureMngr::DisableStage(i); - - // Update GLViewPort - glViewport(back_rc.left, back_rc.top, - back_rc.right - back_rc.left, back_rc.bottom - back_rc.top); - - GL_REPORT_ERRORD(); - - // Copy the framebuffer to screen. - // TODO: Use glBlitFramebufferEXT. - // Render to the real buffer now. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer - - // Texture map s_RenderTargets[s_curtarget] onto the main buffer - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_RECTANGLE_ARB); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget); - // Use linear filtering. - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - /* - static const float vtx_data[8] = {-1, -1, -1, 1, 1, 1, 1, -1}; - const float uv_data[8] = {0, v_min, 0, v_max, u_max, v_max, u_max, v_min}; - glBindBuffer(GL_ARRAY_BUFFER, 0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, (void *)vtx_data); - glTexCoordPointer(2, GL_FLOAT, 0, (void *)uv_data); - glDrawArrays(GL_QUADS, 0, 4); - */ - - // 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()) - { - 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); - glEnd(); - - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); - glDisable(GL_FRAGMENT_PROGRAM_ARB); - } - 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); - glEnd(); - } - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - TextureMngr::DisableStage(0); + 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); + glEnd(); } + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + TextureMngr::DisableStage(0); + // Wireframe if (g_Config.bWireFrame) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -985,7 +1035,7 @@ void Renderer::Swap(const TRectangle& rc) s_criticalScreenshot.Enter(); // Save screenshot - SaveRenderTarget(s_sScreenshotName.c_str(), rc.right, rc.bottom, (int)(v_min)); + SaveRenderTarget(s_sScreenshotName.c_str(), s_efbSourceRc.right, s_efbSourceRc.bottom, (int)(v_min)); // Reset settings s_sScreenshotName = ""; s_bScreenshot = false; @@ -1006,8 +1056,8 @@ void Renderer::Swap(const TRectangle& rc) glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer); s_criticalScreenshot.Enter(); - int w = rc.right; - int h = rc.bottom; + int w = s_efbSourceRc.right; + int h = s_efbSourceRc.bottom; int t = (int)(v_min); u8 *data = (u8 *) malloc(3 * w * h); glPixelStorei(GL_PACK_ALIGNMENT, 1); @@ -1174,7 +1224,7 @@ void Renderer::SwapBuffers() stats.ResetFrame(); // Render to the framebuffer. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer); + SetFramebuffer(0); GL_REPORT_ERRORD(); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.h b/Source/Plugins/Plugin_VideoOGL/Src/Render.h index d593f77bc7..02447f0259 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.h @@ -88,8 +88,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 DecodeFromXFB(u8* xfbInRam, u32 dstWidth, u32 dstHeight, s32 yOffset); + static void RenderToXFB(u8* xfbInRam, const TRectangle& sourceRc, u32 dstWidth, u32 dstHeight); + // Finish up the current frame, print some stats - static void Swap(const TRectangle& rc); + static void Swap(); }; void ComputeBackbufferRectangle(TRectangle *rc); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp index db55a97fb8..c4bec2beaa 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp @@ -321,6 +321,8 @@ void DecodeToTexture(u8* srcAddr, int srcWidth, int srcHeight, GLuint destTextur glBindTexture(GL_TEXTURE_RECTANGLE_ARB, destTexture); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, destTexture, 0); + GL_REPORT_FBO_ERROR(); + for (int i = 1; i < 8; ++i) TextureMngr::DisableStage(i); @@ -349,10 +351,13 @@ void DecodeToTexture(u8* srcAddr, int srcWidth, int srcHeight, GLuint destTextur // reset state glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); TextureMngr::DisableStage(0); VertexShaderManager::SetViewportChanged(); + Renderer::SetFramebuffer(0); + Renderer::RestoreGLState(); GL_REPORT_ERRORD(); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp b/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp index f7670cca99..f607f70f79 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp @@ -25,55 +25,10 @@ // ---------------------------------------------------------------------------------------------------------- #include "Globals.h" -#include "GLUtil.h" -#include "MemoryUtil.h" +#include "XFB.h" #include "Render.h" -#include "TextureMngr.h" -#include "VertexShaderManager.h" -#include "XFBConvert.h" #include "TextureConverter.h" -#define XFB_USE_SHADERS 1 - -enum { - XFB_BUF_HEIGHT = 574, //480, - // TODO: figure out what to do with PAL -}; - - -#if XFB_USE_SHADERS - -static GLuint xfb_decoded_texture; -static int XFBInitStatus = 0; -static struct -{ - u8* pXFB; - u32 width; - u32 height; - s32 yOffset; -} tUpdateXFBArgs; - -void XFB_SetUpdateArgs(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset); - -void XFB_Init() -{ - glGenTextures(1, &xfb_decoded_texture); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfb_decoded_texture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_BUF_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - XFBInitStatus = 1; -} - -void XFB_Shutdown() -{ - glDeleteTextures(1, &xfb_decoded_texture); - XFBInitStatus = 0; -} - -int XFB_isInit() -{ - return XFBInitStatus; -} - void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt) { TRectangle renderSrcRc; @@ -84,181 +39,3 @@ void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt) renderSrcRc.bottom = Renderer::GetTargetHeight() - sourceRc.bottom; TextureConverter::EncodeToRamYUYV(Renderer::ResolveAndGetRenderTarget(sourceRc), renderSrcRc, xfb_in_ram, dstWd, dstHt); } - -// Draw the XFB straight to the OpenGL backbuffer. -void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset) -{ - TextureConverter::DecodeToTexture(xfb_in_ram, width, height, xfb_decoded_texture); - - OpenGL_Update(); // just updates the render window position and the backbuffer size - Renderer::ResetGLState(); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer - - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_RECTANGLE_ARB); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfb_decoded_texture); - - TRectangle back_rc; - ComputeBackbufferRectangle(&back_rc); - - glViewport(back_rc.left, back_rc.top, back_rc.right - back_rc.left, back_rc.bottom - back_rc.top); - GL_REPORT_ERRORD(); - - float w = (float)width; - float h = (float)height; - float yOff = (float)yOffset; - - glBegin(GL_QUADS); - glTexCoord2f(w, 0 - yOff); glVertex2f(1, -1); - glTexCoord2f(w, h - yOff); glVertex2f(1, 1); - glTexCoord2f(0, h - yOff); glVertex2f(-1, 1); - glTexCoord2f(0, 0 - yOff); glVertex2f(-1,-1); - glEnd(); - - TextureMngr::DisableStage(0); - - Renderer::SwapBuffers(); - - Renderer::RestoreGLState(); - GL_REPORT_ERRORD(); -} - -void XFB_Draw() -{ - XFB_Draw(tUpdateXFBArgs.pXFB, tUpdateXFBArgs.width, tUpdateXFBArgs.height, tUpdateXFBArgs.yOffset); -} - -void XFB_SetUpdateArgs(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset) -{ - tUpdateXFBArgs.pXFB = _pXFB; - tUpdateXFBArgs.width = _dwWidth; - tUpdateXFBArgs.height = _dwHeight; - tUpdateXFBArgs.yOffset = _dwYOffset; -} - -#else - -static GLuint xfb_texture; -static u8 *xfb_buffer = 0; -static u8 *efb_buffer = 0; -static GLuint s_xfbFrameBuffer = 0; -static GLuint s_xfbRenderBuffer = 0; - -void XFB_Init() -{ - // used to render XFB - xfb_buffer = new u8[XFB_WIDTH * XFB_BUF_HEIGHT * 4]; - memset(xfb_buffer, 0, XFB_WIDTH * XFB_BUF_HEIGHT * 4); - glGenTextures(1, &xfb_texture); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfb_texture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, xfb_buffer); - - // used to render EFB - glGenFramebuffersEXT(1, &s_xfbFrameBuffer); - glGenRenderbuffersEXT(1, &s_xfbRenderBuffer); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_xfbRenderBuffer); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, nBackbufferWidth, nBackbufferHeight); - - // Ensure efb_buffer is aligned. - efb_buffer = (u8 *)AllocateMemoryPages(nBackbufferWidth * nBackbufferHeight * 4); -} - -void XFB_Shutdown() -{ - glDeleteFramebuffersEXT(1, &s_xfbFrameBuffer); - - glDeleteTextures(1, &xfb_texture); - xfb_texture = 0; - delete [] xfb_buffer; - xfb_buffer = 0; - FreeMemoryPages(efb_buffer, nBackbufferWidth * nBackbufferHeight * 4); -} - - -void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt) -{ - Renderer::SetRenderMode(Renderer::RM_Normal); - Renderer::ResetGLState(); - - // Switch to XFB frame buffer. - Renderer::SetFramebuffer(s_xfbFrameBuffer); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_xfbRenderBuffer); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_xfbRenderBuffer); - GL_REPORT_ERRORD(); - - glViewport(nXoff, nYoff, nBackbufferWidth, nBackbufferHeight); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, Renderer::GetRenderTarget()); - TextureMngr::EnableTexRECT(0); - for (int i = 1; i < 8; ++i) - TextureMngr::DisableStage(i); - GL_REPORT_ERRORD(); - - glBegin(GL_QUADS); - glTexCoord2f(0, nBackbufferHeight); glVertex2f(-1,-1); - glTexCoord2f(0, 0); glVertex2f(-1,1); - glTexCoord2f(nBackbufferWidth, 0); glVertex2f(1,1); - glTexCoord2f(nBackbufferWidth, nBackbufferHeight); glVertex2f(1,-1); - glEnd(); - GL_REPORT_ERRORD(); - - int width = sourceRc.right - sourceRc.left; - int height = sourceRc.bottom - sourceRc.top; - glReadPixels(sourceRc.left, sourceRc.top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, efb_buffer); - GL_REPORT_ERRORD(); - - Renderer::SetFramebuffer(0); - Renderer::RestoreGLState(); - VertexShaderManager::SetViewportChanged(); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - TextureMngr::DisableStage(0); - - Renderer::RestoreGLState(); - GL_REPORT_ERRORD(); - - ConvertToXFB((u32 *)xfb_in_ram, efb_buffer, dstWd, dstHt); -} - -void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset) -{ - OpenGL_Update(); // just updates the render window position and the backbuffer size - - Renderer::SetRenderMode(Renderer::RM_Normal); - - // render to the real buffer now - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer - glViewport(nXoff, nYoff, nBackbufferWidth, nBackbufferHeight); - - Renderer::ResetGLState(); - - ConvertFromXFB((u32 *)xfb_buffer, xfb_in_ram, width, height); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfb_texture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, xfb_buffer); - TextureMngr::EnableTexRECT(0); - for (int i = 1; i < 8; ++i) - TextureMngr::DisableStage(i); - - GL_REPORT_ERRORD(); - - glBegin(GL_QUADS); - glTexCoord2f(width, height + yOffset); glVertex2f( 1,-1); - glTexCoord2f(width, 0 + yOffset); glVertex2f( 1, 1); - glTexCoord2f(0, 0 + yOffset); glVertex2f(-1, 1); - glTexCoord2f(0, height + yOffset); glVertex2f(-1,-1); - glEnd(); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - TextureMngr::DisableStage(0); - - Renderer::SwapBuffers(); - - Renderer::RestoreGLState(); - GL_REPORT_ERRORD(); -} - -#endif diff --git a/Source/Plugins/Plugin_VideoOGL/Src/XFB.h b/Source/Plugins/Plugin_VideoOGL/Src/XFB.h index 90cd245bae..dabfe97f55 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/XFB.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/XFB.h @@ -18,21 +18,7 @@ #ifndef _XFB_H_ #define _XFB_H_ -#include "TextureMngr.h" - -void XFB_Init(); - // write the EFB to the XFB void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt); -// draw the XFB to the screen -void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset); -void XFB_Draw(); - -void XFB_Shutdown(); - -int XFB_isInit(); - -void XFB_SetUpdateArgs(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset); - #endif // _XFB_H_ diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index a3a2b9e63b..19b4ddedf6 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -94,6 +94,8 @@ PLUGIN_GLOBALS* globals = NULL; // Logging int GLScissorX, GLScissorY, GLScissorW, GLScissorH; +static bool s_PluginInitialized = false; + #if defined(HAVE_WX) && HAVE_WX void DllDebugger(HWND _hParent, bool Show) { @@ -359,11 +361,15 @@ void Video_Prepare(void) GL_REPORT_ERRORD(); VertexLoaderManager::Init(); TextureConverter::Init(); + + s_PluginInitialized = true; INFO_LOG(VIDEO, "Video plugin initialized."); } void Shutdown(void) { + s_PluginInitialized = false; + Fifo_Shutdown(); PostProcessing::Shutdown(); TextureConverter::Shutdown(); @@ -409,29 +415,46 @@ void Video_AddMessage(const char* pstr, u32 milliseconds) +static volatile struct +{ + u8* pXFB; + u32 width; + u32 height; + s32 yOffset; +} tUpdateXFBArgs; // Run from the CPU thread (from VideoInterface.cpp) for certain homebrew games only void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, bool scheduling) { - if (g_Config.bUseXFB && XFB_isInit()) + if (s_PluginInitialized) { - if (scheduling) // from CPU in DC without fifo&CP (some 2D homebrews) + if (scheduling) // From CPU in DC mode { - XFB_SetUpdateArgs(_pXFB, _dwWidth, _dwHeight, _dwYOffset); + tUpdateXFBArgs.pXFB = _pXFB; + tUpdateXFBArgs.width = _dwWidth; + tUpdateXFBArgs.height = _dwHeight; + tUpdateXFBArgs.yOffset = _dwYOffset; + g_XFBUpdateRequested = TRUE; } - else + else // From CPU in SC mode or graphics thread in DC mode { - if (_pXFB) // from CPU in SC mode + g_XFBUpdateRequested = FALSE; + + if (g_Config.bUseXFB) { - XFB_Draw(_pXFB, _dwWidth, _dwHeight, _dwYOffset); - g_VideoInitialize.pCopiedToXFB(); - } - else // from GP in DC without fifo&CP (some 2D homebrews) - { - XFB_Draw(); - g_XFBUpdateRequested = FALSE; + if (!_pXFB) + // From graphics thread in DC mode + Renderer::DecodeFromXFB(tUpdateXFBArgs.pXFB, tUpdateXFBArgs.width, tUpdateXFBArgs.height, tUpdateXFBArgs.yOffset); + else + // From CPU in SC mode + Renderer::DecodeFromXFB(_pXFB, _dwWidth, _dwHeight, _dwYOffset); } + + // TODO: Use real XFB source parameters based on VI settings + Renderer::Swap(); + + g_VideoInitialize.pCopiedToXFB(); } } }