diff --git a/Source/Core/VideoCommon/Src/VideoConfig.cpp b/Source/Core/VideoCommon/Src/VideoConfig.cpp index 3d9647c259..f8abe8d762 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.cpp +++ b/Source/Core/VideoCommon/Src/VideoConfig.cpp @@ -59,6 +59,7 @@ void VideoConfig::Load(const char *ini_file) iniFile.Get("Settings", "Crop", &bCrop, false); iniFile.Get("Settings", "HideCursor", &bHideCursor, false); iniFile.Get("Settings", "UseXFB", &bUseXFB, 0); + iniFile.Get("Settings", "UseRealXFB", &bUseRealXFB, 0); iniFile.Get("Settings", "AutoScale", &bAutoScale, true); iniFile.Get("Settings", "SafeTextureCache", &bSafeTextureCache, false); // Settings @@ -139,6 +140,8 @@ void VideoConfig::GameIniLoad(const char *ini_file) iniFile.Get("Video", "DstAlphaPass", &bDstAlphaPass, false); if (iniFile.Exists("Video", "UseXFB")) iniFile.Get("Video", "UseXFB", &bUseXFB, 0); + if (iniFile.Exists("Video", "UseRealXFB")) + iniFile.Get("Video", "UseRealXFB", &bUseRealXFB, 0); if (iniFile.Exists("Video", "FIFOBPHack")) iniFile.Get("Video", "FIFOBPHack", &bFIFOBPhack, false); if (iniFile.Exists("Video", "ProjectionHack")) @@ -161,6 +164,7 @@ void VideoConfig::Save(const char *ini_file) iniFile.Set("Settings", "wideScreenHack", bWidescreenHack); iniFile.Set("Settings", "HideCursor", bHideCursor); iniFile.Set("Settings", "UseXFB", bUseXFB); + iniFile.Set("Settings", "UseRealXFB", bUseRealXFB); iniFile.Set("Settings", "AutoScale", bAutoScale); iniFile.Set("Settings", "SafeTextureCache", bSafeTextureCache); diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index d44de664dc..5d77257b3e 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -81,6 +81,7 @@ struct VideoConfig int iAspectRatio; bool bCrop; // Aspect ratio controls. bool bUseXFB; + bool bUseRealXFB; bool bAutoScale; // Removes annoying borders without using XFB. Doesn't always work perfectly. // Enhancements diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp index c9f9d3631c..a92c1584df 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp @@ -188,18 +188,18 @@ void FramebufferManager::Shutdown() void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) { - if (g_ActiveConfig.bUseXFB) + if (g_ActiveConfig.bUseRealXFB) copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc); else copyToVirtualXFB(xfbAddr, fbWidth, fbHeight, sourceRc); } -const XFBSource* FramebufferManager::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight) +const XFBSource** FramebufferManager::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) { - if (g_ActiveConfig.bUseXFB) - return getRealXFBSource(xfbAddr, fbWidth, fbHeight); + if (g_ActiveConfig.bUseRealXFB) + return getRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); else - return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight); + return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); } GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) const @@ -286,7 +286,7 @@ FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height) u32 dstLower = it->xfbAddr; u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; - if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) + if (dstLower >= srcLower && dstUpper <= srcUpper) return it; } @@ -294,6 +294,48 @@ FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height) return m_virtualXFBList.end(); } +void FramebufferManager::replaceVirtualXFB() +{ + VirtualXFBListType::iterator it = m_virtualXFBList.begin(); + + s32 srcLower = it->xfbAddr; + s32 srcUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; + s32 lineSize = 2 * it->xfbWidth; + + it++; + + while (it != m_virtualXFBList.end()) + { + s32 dstLower = it->xfbAddr; + s32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; + + if (dstLower >= srcLower && dstUpper <= srcUpper) + { + // invalidate the data + it->xfbAddr = 0; + it->xfbHeight = 0; + it->xfbWidth = 0; + } + else if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) + { + s32 upperOverlap = (srcUpper - dstLower) / lineSize; + s32 lowerOverlap = (dstUpper - srcLower) / lineSize; + + if (upperOverlap > 0 && lowerOverlap < 0) + { + it->xfbAddr += lineSize * upperOverlap; + it->xfbHeight -= upperOverlap; + } + else if (lowerOverlap > 0) + { + it->xfbHeight -= lowerOverlap; + } + } + + it++; + } +} + void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) { u8* pXFB = Memory_GetPtr(xfbAddr); @@ -312,6 +354,12 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight); + if (it == m_virtualXFBList.end() && (int)m_virtualXFBList.size() >= MAX_VIRTUAL_XFB) + { + // replace the last virtual XFB + it--; + } + if (it != m_virtualXFBList.end()) { // Overwrite an existing Virtual XFB. @@ -320,6 +368,10 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight it->xfbWidth = fbWidth; it->xfbHeight = fbHeight; + it->xfbSource.srcAddr = xfbAddr; + it->xfbSource.srcWidth = fbWidth; + it->xfbSource.srcHeight = fbHeight; + it->xfbSource.texWidth = Renderer::GetTargetWidth(); it->xfbSource.texHeight = Renderer::GetTargetHeight(); it->xfbSource.sourceRc = ConvertEFBRectangle(sourceRc); @@ -328,6 +380,9 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight // Move this Virtual XFB to the front of the list. m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it); + + // Keep stale XFB data from being used + replaceVirtualXFB(); } else { @@ -416,11 +471,17 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight } } -const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight) +const XFBSource** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) { + xfbCount = 1; + m_realXFBSource.texWidth = MAX_XFB_WIDTH; m_realXFBSource.texHeight = MAX_XFB_HEIGHT; + m_realXFBSource.srcAddr = xfbAddr; + m_realXFBSource.srcWidth = fbWidth; + m_realXFBSource.srcHeight = fbHeight; + // OpenGL texture coordinates originate at the lower left, which is why // sourceRc.top = fbHeight and sourceRc.bottom = 0. m_realXFBSource.sourceRc.left = 0; @@ -441,26 +502,40 @@ const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, // Decode YUYV data from GameCube RAM TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture); - return &m_realXFBSource; + m_overlappingXFBArray[0] = &m_realXFBSource; + + return &m_overlappingXFBArray[0]; } -const XFBSource* FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight) +const XFBSource** FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) { + xfbCount = 0; + if (m_virtualXFBList.size() == 0) { // No Virtual XFBs available. return NULL; } - VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight); - if (it == m_virtualXFBList.end()) + u32 srcLower = xfbAddr; + u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight; + + VirtualXFBListType::iterator it; + for (it = m_virtualXFBList.end(); it != m_virtualXFBList.begin();) { - // Virtual XFB is not in the list, so return the most recently rendered - // one. - it = m_virtualXFBList.begin(); + --it; + + u32 dstLower = it->xfbAddr; + u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; + + if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) + { + m_overlappingXFBArray[xfbCount] = &(it->xfbSource); + xfbCount++; + } } - return &it->xfbSource; + return &m_overlappingXFBArray[0]; } void FramebufferManager::SetFramebuffer(GLuint fb) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h index 7c98d63dbb..88770da86e 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h @@ -52,7 +52,7 @@ // There may be multiple XFBs in GameCube RAM. This is the maximum number to // virtualize. -const int MAX_VIRTUAL_XFB = 4; +const int MAX_VIRTUAL_XFB = 8; inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) { @@ -65,6 +65,10 @@ struct XFBSource texture(0) {} + u32 srcAddr; + u32 srcWidth; + u32 srcHeight; + GLuint texture; int texWidth; int texHeight; @@ -90,7 +94,7 @@ public: void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); - const XFBSource* GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight); + const XFBSource** GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); // To get the EFB in texture form, these functions may have to transfer // the EFB to a resolved texture first. @@ -132,10 +136,12 @@ private: VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height); + void replaceVirtualXFB(); + 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); + const XFBSource** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); + const XFBSource** getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); int m_targetWidth; int m_targetHeight; @@ -154,6 +160,8 @@ private: GLuint m_xfbFramebuffer; // Only used in MSAA mode XFBSource m_realXFBSource; // Only used in Real XFB mode VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode + + const XFBSource* m_overlappingXFBArray[MAX_VIRTUAL_XFB]; }; extern FramebufferManager g_framebufferManager; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp index d99b66f4fd..90aa434f4f 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp @@ -46,6 +46,7 @@ BEGIN_EVENT_TABLE(GFXConfigDialogOGL,wxDialog) EVT_CHECKBOX(ID_NATIVERESOLUTION, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_2X_RESOLUTION, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_USEXFB, GFXConfigDialogOGL::GeneralSettingsChanged) + EVT_CHECKBOX(ID_USEREALXFB, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_FORCEFILTERING, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_AUTOSCALE, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_WIDESCREENHACK, GFXConfigDialogOGL::GeneralSettingsChanged) @@ -236,6 +237,7 @@ void GFXConfigDialogOGL::InitializeGUIValues() m_OSDHotKey->SetValue(g_Config.bOSDHotKey); m_VSync->SetValue(g_Config.bVSync); m_UseXFB->SetValue(g_Config.bUseXFB); + m_UseRealXFB->SetValue(g_Config.bUseRealXFB); m_AutoScale->SetValue(g_Config.bAutoScale); m_WidescreenHack->SetValue(g_Config.bWidescreenHack); @@ -422,7 +424,8 @@ void GFXConfigDialogOGL::CreateGUIControls() m_OSDHotKey->Enable(false); #endif m_VSync = new wxCheckBox(m_PageGeneral, ID_VSYNC, wxT("VSync (req. restart)"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); - m_UseXFB = new wxCheckBox(m_PageGeneral, ID_USEXFB, wxT("Use Real XFB"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + m_UseXFB = new wxCheckBox(m_PageGeneral, ID_USEXFB, wxT("Use XFB"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + m_UseRealXFB = new wxCheckBox(m_PageGeneral, ID_USEREALXFB, wxT("Use Real XFB"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_AutoScale = new wxCheckBox(m_PageGeneral, ID_AUTOSCALE, wxT("Auto scale (try to remove borders)"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_WidescreenHack = new wxCheckBox(m_PageGeneral, ID_WIDESCREENHACK, wxT("Wide screen hack"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); @@ -470,8 +473,9 @@ void GFXConfigDialogOGL::CreateGUIControls() sBasicAdvanced->Add(m_OSDHotKey, wxGBPosition(1, 0), wxGBSpan(1, 2), wxALL, 5); sBasicAdvanced->Add(m_VSync, wxGBPosition(2, 0), wxGBSpan(1, 2), wxALL, 5); sBasicAdvanced->Add(m_UseXFB, wxGBPosition(3, 0), wxGBSpan(1, 2), wxALL, 5); - sBasicAdvanced->Add(m_AutoScale, wxGBPosition(4, 0), wxGBSpan(1, 2), wxALL, 5); - sBasicAdvanced->Add(m_WidescreenHack, wxGBPosition(5, 0), wxGBSpan(1, 2), wxALL, 5); + sBasicAdvanced->Add(m_UseRealXFB, wxGBPosition(4, 0), wxGBSpan(1, 2), wxALL, 5); + sBasicAdvanced->Add(m_AutoScale, wxGBPosition(5, 0), wxGBSpan(1, 2), wxALL, 5); + sBasicAdvanced->Add(m_WidescreenHack, wxGBPosition(6, 0), wxGBSpan(1, 2), wxALL, 5); sbBasicAdvanced->Add(sBasicAdvanced); sGeneral->Add(sbBasicAdvanced, 0, wxEXPAND|wxALL, 5); @@ -662,6 +666,9 @@ void GFXConfigDialogOGL::GeneralSettingsChanged(wxCommandEvent& event) case ID_USEXFB: g_Config.bUseXFB = m_UseXFB->IsChecked(); break; + case ID_USEREALXFB: + g_Config.bUseRealXFB = m_UseRealXFB->IsChecked(); + break; case ID_AUTOSCALE: g_Config.bAutoScale = m_AutoScale->IsChecked(); break; @@ -821,8 +828,12 @@ void GFXConfigDialogOGL::UpdateGUI() { // This is only used together with the aspect ratio options m_Crop->Enable(g_Config.iAspectRatio != ASPECT_STRETCH); - if (g_Config.bUseXFB) + if (g_Config.bUseRealXFB) { + // must use XFB to use real XFB + g_Config.bUseXFB = true; + m_UseXFB->SetValue(true); + // XFB looks much better if the copy comes from native resolution. g_Config.bNativeResolution = true; m_NativeResolution->SetValue(true); @@ -830,7 +841,8 @@ void GFXConfigDialogOGL::UpdateGUI() g_Config.b2xResolution = false; m_2xResolution->SetValue(false); } - m_AutoScale->Enable(!g_Config.bUseXFB); + m_AutoScale->Enable(!g_Config.bUseRealXFB); + m_UseXFB->Enable(!g_Config.bUseRealXFB); // These options are for the separate rendering window #if !defined(HAVE_GTK2) || !HAVE_GTK2 || !defined(wxGTK) @@ -841,8 +853,8 @@ void GFXConfigDialogOGL::UpdateGUI() // Resolution settings //disable native/2x choice when real xfb is on. native simply looks best, as ector noted above. //besides, it would look odd if one disabled native, and it came back on again. - m_NativeResolution->Enable(!g_Config.bUseXFB); - m_2xResolution->Enable(!g_Config.bUseXFB && (!g_Config.bRunning || Renderer::Allow2x())); + m_NativeResolution->Enable(!g_Config.bUseRealXFB); + m_2xResolution->Enable(!g_Config.bUseRealXFB && (!g_Config.bRunning || Renderer::Allow2x())); m_WindowResolutionCB->Enable(!g_Config.bRunning); #if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) m_WindowFSResolutionCB->Enable(!g_Config.bRunning); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h index 85617147f5..22a6bfc08c 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h @@ -103,6 +103,7 @@ class GFXConfigDialogOGL : public wxDialog wxCheckBox *m_ForceFiltering; wxCheckBox *m_Crop; wxCheckBox *m_UseXFB; + wxCheckBox *m_UseRealXFB; wxCheckBox *m_AutoScale; #ifndef _WIN32 wxCheckBox *m_HideCursor; @@ -163,6 +164,7 @@ class GFXConfigDialogOGL : public wxDialog ID_NATIVERESOLUTION, ID_2X_RESOLUTION, ID_ASPECT, ID_CROP, + ID_USEREALXFB, ID_USEXFB, ID_AUTOSCALE, ID_WIDESCREENHACK, diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 324db20a4e..0ac8153660 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -792,22 +792,25 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect if (!g_ActiveConfig.bUseXFB) { Renderer::Swap(xfbAddr, FIELD_PROGRESSIVE, fbWidth, fbHeight); + Common::AtomicStoreRelease(s_swapRequested, FALSE); } } // This function has the final picture. We adjust the aspect ratio here. void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) { - Common::AtomicStoreRelease(s_swapRequested, FALSE); - if (s_skipSwap) { g_VideoInitialize.pCopiedToXFB(false); return; } - const XFBSource* xfbSource = g_framebufferManager.GetXFBSource(xfbAddr, fbWidth, fbHeight); - if (!xfbSource) + if (field == FIELD_LOWER) + xfbAddr -= fbWidth * 2; + + u32 xfbCount = 0; + const XFBSource** xfbSourceList = g_framebufferManager.GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); + if (!xfbSourceList) { WARN_LOG(VIDEO, "Failed to get video for this frame"); return; @@ -821,27 +824,6 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) TargetRectangle back_rc; ComputeDrawRectangle(OpenGL_GetBackbufferWidth(), OpenGL_GetBackbufferHeight(), true, &back_rc); - TargetRectangle sourceRc; - - if (g_ActiveConfig.bAutoScale || g_ActiveConfig.bUseXFB) - { - sourceRc = xfbSource->sourceRc; - } - else - { - sourceRc.left = 0; - sourceRc.top = xfbSource->texHeight; - sourceRc.right = xfbSource->texWidth; - sourceRc.bottom = 0; - } - - int yOffset = (g_ActiveConfig.bUseXFB && field == FIELD_LOWER) ? -1 : 0; - sourceRc.top -= yOffset; - sourceRc.bottom -= yOffset; - - // Tell the OSD Menu about the current internal resolution - OSDInternalW = xfbSource->sourceRc.GetWidth(); OSDInternalH = xfbSource->sourceRc.GetHeight(); - // Make sure that the wireframe setting doesn't screw up the screen copy. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); @@ -864,31 +846,98 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) // Texture map s_xfbTexture onto the main buffer glActiveTexture(GL_TEXTURE0); glEnable(GL_TEXTURE_RECTANGLE_ARB); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbSource->texture); // 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()) + bool applyShader = PostProcessing::ApplyShader(); + + const XFBSource* xfbSource; + + // draw each xfb source + for (u32 i = 0; i < xfbCount; ++i) { - glBegin(GL_QUADS); - 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(); - PixelShaderCache::DisableShader();; - } - else - { - glBegin(GL_QUADS); - 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(); + xfbSource = xfbSourceList[i]; + + TargetRectangle sourceRc; + + if (g_ActiveConfig.bAutoScale || g_ActiveConfig.bUseXFB) + { + sourceRc = xfbSource->sourceRc; + } + else + { + sourceRc.left = 0; + sourceRc.top = xfbSource->texHeight; + sourceRc.right = xfbSource->texWidth; + sourceRc.bottom = 0; + } + + MathUtil::Rectangle drawRc; + + if (g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) + { + // use virtual xfb with offset + int xfbHeight = xfbSource->srcHeight; + int xfbWidth = xfbSource->srcWidth; + int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbWidth * 2); + + drawRc.top = 1.0f - (2.0f * (hOffset) / (float)fbHeight); + drawRc.bottom = 1.0f - (2.0f * (hOffset + xfbHeight) / (float)fbHeight); + drawRc.left = -(xfbWidth / (float)fbWidth); + drawRc.right = (xfbWidth / (float)fbWidth); + + if (!g_ActiveConfig.bAutoScale) + { + // scale draw area for a 1 to 1 pixel mapping with the draw target + float vScale = (float)fbHeight / (float)back_rc.GetHeight(); + float hScale = (float)fbWidth / (float)back_rc.GetWidth(); + + drawRc.top *= vScale; + drawRc.bottom *= vScale; + drawRc.left *= hScale; + drawRc.right *= hScale; + } + } + else + { + drawRc.top = 1; + drawRc.bottom = -1; + drawRc.left = -1; + drawRc.right = 1; + } + + // Tell the OSD Menu about the current internal resolution + OSDInternalW = xfbSource->sourceRc.GetWidth(); OSDInternalH = xfbSource->sourceRc.GetHeight(); + + // Texture map xfbSource->texture onto the main buffer + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbSource->texture); + + // 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 (applyShader) + { + glBegin(GL_QUADS); + glTexCoord2f(sourceRc.left, sourceRc.bottom); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0); glVertex2f(drawRc.left, drawRc.bottom); + glTexCoord2f(sourceRc.left, sourceRc.top); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1); glVertex2f(drawRc.left, drawRc.top); + glTexCoord2f(sourceRc.right, sourceRc.top); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1); glVertex2f(drawRc.right, drawRc.top); + glTexCoord2f(sourceRc.right, sourceRc.bottom); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0); glVertex2f(drawRc.right, drawRc.bottom); + glEnd(); + PixelShaderCache::DisableShader();; + } + else + { + glBegin(GL_QUADS); + glTexCoord2f(sourceRc.left, sourceRc.bottom); glVertex2f(drawRc.left, drawRc.bottom); + glTexCoord2f(sourceRc.left, sourceRc.top); glVertex2f(drawRc.left, drawRc.top); + glTexCoord2f(sourceRc.right, sourceRc.top); glVertex2f(drawRc.right, drawRc.top); + glTexCoord2f(sourceRc.right, sourceRc.bottom); glVertex2f(drawRc.right, drawRc.bottom); + glEnd(); + } + + GL_REPORT_ERRORD(); } glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); @@ -909,7 +958,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(), yOffset); + SaveRenderTarget(s_sScreenshotName.c_str(), xfbSource->sourceRc.GetWidth(), xfbSource->sourceRc.GetHeight()); // Reset settings s_sScreenshotName = ""; s_bScreenshot = false; @@ -935,7 +984,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) u8 *data = (u8 *) malloc(3 * w * h); glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, Renderer::GetTargetHeight() - h + yOffset, w, h, GL_BGR, GL_UNSIGNED_BYTE, data); + glReadPixels(0, Renderer::GetTargetHeight() - h, w, h, GL_BGR, GL_UNSIGNED_BYTE, data); if (glGetError() == GL_NO_ERROR && w > 0 && h > 0) { if (!s_bLastFrameDumped) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index bcc6e4f1e1..a763290b85 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -484,10 +484,8 @@ void VideoFifo_CheckSwapRequest() { Renderer::Swap(s_beginFieldArgs.xfbAddr, s_beginFieldArgs.field, s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight); } - else - { - Common::AtomicStoreRelease(s_swapRequested, FALSE); - } + + Common::AtomicStoreRelease(s_swapRequested, FALSE); } }