Extend the OGL virtual XFB to handle games that use multiple XFBs to make a frame. This should allow games that require the XFB to work without using a real XFB in RAM which is slow and limited to the original resolution. To use this enhancement you must check Use XFB in the options. The previous option was renamed Use Real XFB. I don't think this works with the aspect settings yet.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5185 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
donkopunchstania 2010-03-10 06:45:13 +00:00
parent c455673f87
commit 70627c5652
8 changed files with 224 additions and 75 deletions

View File

@ -59,6 +59,7 @@ void VideoConfig::Load(const char *ini_file)
iniFile.Get("Settings", "Crop", &bCrop, false); iniFile.Get("Settings", "Crop", &bCrop, false);
iniFile.Get("Settings", "HideCursor", &bHideCursor, false); iniFile.Get("Settings", "HideCursor", &bHideCursor, false);
iniFile.Get("Settings", "UseXFB", &bUseXFB, 0); iniFile.Get("Settings", "UseXFB", &bUseXFB, 0);
iniFile.Get("Settings", "UseRealXFB", &bUseRealXFB, 0);
iniFile.Get("Settings", "AutoScale", &bAutoScale, true); iniFile.Get("Settings", "AutoScale", &bAutoScale, true);
iniFile.Get("Settings", "SafeTextureCache", &bSafeTextureCache, false); // Settings iniFile.Get("Settings", "SafeTextureCache", &bSafeTextureCache, false); // Settings
@ -139,6 +140,8 @@ void VideoConfig::GameIniLoad(const char *ini_file)
iniFile.Get("Video", "DstAlphaPass", &bDstAlphaPass, false); iniFile.Get("Video", "DstAlphaPass", &bDstAlphaPass, false);
if (iniFile.Exists("Video", "UseXFB")) if (iniFile.Exists("Video", "UseXFB"))
iniFile.Get("Video", "UseXFB", &bUseXFB, 0); iniFile.Get("Video", "UseXFB", &bUseXFB, 0);
if (iniFile.Exists("Video", "UseRealXFB"))
iniFile.Get("Video", "UseRealXFB", &bUseRealXFB, 0);
if (iniFile.Exists("Video", "FIFOBPHack")) if (iniFile.Exists("Video", "FIFOBPHack"))
iniFile.Get("Video", "FIFOBPHack", &bFIFOBPhack, false); iniFile.Get("Video", "FIFOBPHack", &bFIFOBPhack, false);
if (iniFile.Exists("Video", "ProjectionHack")) if (iniFile.Exists("Video", "ProjectionHack"))
@ -161,6 +164,7 @@ void VideoConfig::Save(const char *ini_file)
iniFile.Set("Settings", "wideScreenHack", bWidescreenHack); iniFile.Set("Settings", "wideScreenHack", bWidescreenHack);
iniFile.Set("Settings", "HideCursor", bHideCursor); iniFile.Set("Settings", "HideCursor", bHideCursor);
iniFile.Set("Settings", "UseXFB", bUseXFB); iniFile.Set("Settings", "UseXFB", bUseXFB);
iniFile.Set("Settings", "UseRealXFB", bUseRealXFB);
iniFile.Set("Settings", "AutoScale", bAutoScale); iniFile.Set("Settings", "AutoScale", bAutoScale);
iniFile.Set("Settings", "SafeTextureCache", bSafeTextureCache); iniFile.Set("Settings", "SafeTextureCache", bSafeTextureCache);

View File

@ -81,6 +81,7 @@ struct VideoConfig
int iAspectRatio; int iAspectRatio;
bool bCrop; // Aspect ratio controls. bool bCrop; // Aspect ratio controls.
bool bUseXFB; bool bUseXFB;
bool bUseRealXFB;
bool bAutoScale; // Removes annoying borders without using XFB. Doesn't always work perfectly. bool bAutoScale; // Removes annoying borders without using XFB. Doesn't always work perfectly.
// Enhancements // Enhancements

View File

@ -188,18 +188,18 @@ void FramebufferManager::Shutdown()
void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) 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); copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
else else
copyToVirtualXFB(xfbAddr, fbWidth, fbHeight, sourceRc); 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) if (g_ActiveConfig.bUseRealXFB)
return getRealXFBSource(xfbAddr, fbWidth, fbHeight); return getRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
else else
return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight); return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
} }
GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) const GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) const
@ -286,7 +286,7 @@ FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
u32 dstLower = it->xfbAddr; u32 dstLower = it->xfbAddr;
u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight;
if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) if (dstLower >= srcLower && dstUpper <= srcUpper)
return it; return it;
} }
@ -294,6 +294,48 @@ FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
return m_virtualXFBList.end(); 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) void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
{ {
u8* pXFB = Memory_GetPtr(xfbAddr); 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); 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()) if (it != m_virtualXFBList.end())
{ {
// Overwrite an existing Virtual XFB. // Overwrite an existing Virtual XFB.
@ -320,6 +368,10 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight
it->xfbWidth = fbWidth; it->xfbWidth = fbWidth;
it->xfbHeight = fbHeight; it->xfbHeight = fbHeight;
it->xfbSource.srcAddr = xfbAddr;
it->xfbSource.srcWidth = fbWidth;
it->xfbSource.srcHeight = fbHeight;
it->xfbSource.texWidth = Renderer::GetTargetWidth(); it->xfbSource.texWidth = Renderer::GetTargetWidth();
it->xfbSource.texHeight = Renderer::GetTargetHeight(); it->xfbSource.texHeight = Renderer::GetTargetHeight();
it->xfbSource.sourceRc = ConvertEFBRectangle(sourceRc); 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. // Move this Virtual XFB to the front of the list.
m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it); m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it);
// Keep stale XFB data from being used
replaceVirtualXFB();
} }
else 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.texWidth = MAX_XFB_WIDTH;
m_realXFBSource.texHeight = MAX_XFB_HEIGHT; 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 // OpenGL texture coordinates originate at the lower left, which is why
// sourceRc.top = fbHeight and sourceRc.bottom = 0. // sourceRc.top = fbHeight and sourceRc.bottom = 0.
m_realXFBSource.sourceRc.left = 0; m_realXFBSource.sourceRc.left = 0;
@ -441,26 +502,40 @@ const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth,
// Decode YUYV data from GameCube RAM // Decode YUYV data from GameCube RAM
TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture); 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) if (m_virtualXFBList.size() == 0)
{ {
// No Virtual XFBs available. // No Virtual XFBs available.
return NULL; return NULL;
} }
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight); u32 srcLower = xfbAddr;
if (it == m_virtualXFBList.end()) 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 --it;
// one.
it = m_virtualXFBList.begin(); 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) void FramebufferManager::SetFramebuffer(GLuint fb)

View File

@ -52,7 +52,7 @@
// There may be multiple XFBs in GameCube RAM. This is the maximum number to // There may be multiple XFBs in GameCube RAM. This is the maximum number to
// virtualize. // virtualize.
const int MAX_VIRTUAL_XFB = 4; const int MAX_VIRTUAL_XFB = 8;
inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper)
{ {
@ -65,6 +65,10 @@ struct XFBSource
texture(0) texture(0)
{} {}
u32 srcAddr;
u32 srcWidth;
u32 srcHeight;
GLuint texture; GLuint texture;
int texWidth; int texWidth;
int texHeight; int texHeight;
@ -90,7 +94,7 @@ public:
void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); 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 // To get the EFB in texture form, these functions may have to transfer
// the EFB to a resolved texture first. // the EFB to a resolved texture first.
@ -132,10 +136,12 @@ private:
VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height); VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height);
void replaceVirtualXFB();
void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
void copyToVirtualXFB(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** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount);
const XFBSource* getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight); const XFBSource** getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount);
int m_targetWidth; int m_targetWidth;
int m_targetHeight; int m_targetHeight;
@ -154,6 +160,8 @@ private:
GLuint m_xfbFramebuffer; // Only used in MSAA mode GLuint m_xfbFramebuffer; // Only used in MSAA mode
XFBSource m_realXFBSource; // Only used in Real XFB mode XFBSource m_realXFBSource; // Only used in Real XFB mode
VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode
const XFBSource* m_overlappingXFBArray[MAX_VIRTUAL_XFB];
}; };
extern FramebufferManager g_framebufferManager; extern FramebufferManager g_framebufferManager;

View File

@ -46,6 +46,7 @@ BEGIN_EVENT_TABLE(GFXConfigDialogOGL,wxDialog)
EVT_CHECKBOX(ID_NATIVERESOLUTION, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_NATIVERESOLUTION, GFXConfigDialogOGL::GeneralSettingsChanged)
EVT_CHECKBOX(ID_2X_RESOLUTION, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_2X_RESOLUTION, GFXConfigDialogOGL::GeneralSettingsChanged)
EVT_CHECKBOX(ID_USEXFB, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_USEXFB, GFXConfigDialogOGL::GeneralSettingsChanged)
EVT_CHECKBOX(ID_USEREALXFB, GFXConfigDialogOGL::GeneralSettingsChanged)
EVT_CHECKBOX(ID_FORCEFILTERING, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_FORCEFILTERING, GFXConfigDialogOGL::GeneralSettingsChanged)
EVT_CHECKBOX(ID_AUTOSCALE, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_AUTOSCALE, GFXConfigDialogOGL::GeneralSettingsChanged)
EVT_CHECKBOX(ID_WIDESCREENHACK, GFXConfigDialogOGL::GeneralSettingsChanged) EVT_CHECKBOX(ID_WIDESCREENHACK, GFXConfigDialogOGL::GeneralSettingsChanged)
@ -236,6 +237,7 @@ void GFXConfigDialogOGL::InitializeGUIValues()
m_OSDHotKey->SetValue(g_Config.bOSDHotKey); m_OSDHotKey->SetValue(g_Config.bOSDHotKey);
m_VSync->SetValue(g_Config.bVSync); m_VSync->SetValue(g_Config.bVSync);
m_UseXFB->SetValue(g_Config.bUseXFB); m_UseXFB->SetValue(g_Config.bUseXFB);
m_UseRealXFB->SetValue(g_Config.bUseRealXFB);
m_AutoScale->SetValue(g_Config.bAutoScale); m_AutoScale->SetValue(g_Config.bAutoScale);
m_WidescreenHack->SetValue(g_Config.bWidescreenHack); m_WidescreenHack->SetValue(g_Config.bWidescreenHack);
@ -422,7 +424,8 @@ void GFXConfigDialogOGL::CreateGUIControls()
m_OSDHotKey->Enable(false); m_OSDHotKey->Enable(false);
#endif #endif
m_VSync = new wxCheckBox(m_PageGeneral, ID_VSYNC, wxT("VSync (req. restart)"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); 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_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); 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_OSDHotKey, wxGBPosition(1, 0), wxGBSpan(1, 2), wxALL, 5);
sBasicAdvanced->Add(m_VSync, wxGBPosition(2, 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_UseXFB, wxGBPosition(3, 0), wxGBSpan(1, 2), wxALL, 5);
sBasicAdvanced->Add(m_AutoScale, wxGBPosition(4, 0), wxGBSpan(1, 2), wxALL, 5); sBasicAdvanced->Add(m_UseRealXFB, wxGBPosition(4, 0), wxGBSpan(1, 2), wxALL, 5);
sBasicAdvanced->Add(m_WidescreenHack, wxGBPosition(5, 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); sbBasicAdvanced->Add(sBasicAdvanced);
sGeneral->Add(sbBasicAdvanced, 0, wxEXPAND|wxALL, 5); sGeneral->Add(sbBasicAdvanced, 0, wxEXPAND|wxALL, 5);
@ -662,6 +666,9 @@ void GFXConfigDialogOGL::GeneralSettingsChanged(wxCommandEvent& event)
case ID_USEXFB: case ID_USEXFB:
g_Config.bUseXFB = m_UseXFB->IsChecked(); g_Config.bUseXFB = m_UseXFB->IsChecked();
break; break;
case ID_USEREALXFB:
g_Config.bUseRealXFB = m_UseRealXFB->IsChecked();
break;
case ID_AUTOSCALE: case ID_AUTOSCALE:
g_Config.bAutoScale = m_AutoScale->IsChecked(); g_Config.bAutoScale = m_AutoScale->IsChecked();
break; break;
@ -821,8 +828,12 @@ void GFXConfigDialogOGL::UpdateGUI()
{ {
// This is only used together with the aspect ratio options // This is only used together with the aspect ratio options
m_Crop->Enable(g_Config.iAspectRatio != ASPECT_STRETCH); 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. // XFB looks much better if the copy comes from native resolution.
g_Config.bNativeResolution = true; g_Config.bNativeResolution = true;
m_NativeResolution->SetValue(true); m_NativeResolution->SetValue(true);
@ -830,7 +841,8 @@ void GFXConfigDialogOGL::UpdateGUI()
g_Config.b2xResolution = false; g_Config.b2xResolution = false;
m_2xResolution->SetValue(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 // These options are for the separate rendering window
#if !defined(HAVE_GTK2) || !HAVE_GTK2 || !defined(wxGTK) #if !defined(HAVE_GTK2) || !HAVE_GTK2 || !defined(wxGTK)
@ -841,8 +853,8 @@ void GFXConfigDialogOGL::UpdateGUI()
// Resolution settings // Resolution settings
//disable native/2x choice when real xfb is on. native simply looks best, as ector noted above. //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. //besides, it would look odd if one disabled native, and it came back on again.
m_NativeResolution->Enable(!g_Config.bUseXFB); m_NativeResolution->Enable(!g_Config.bUseRealXFB);
m_2xResolution->Enable(!g_Config.bUseXFB && (!g_Config.bRunning || Renderer::Allow2x())); m_2xResolution->Enable(!g_Config.bUseRealXFB && (!g_Config.bRunning || Renderer::Allow2x()));
m_WindowResolutionCB->Enable(!g_Config.bRunning); m_WindowResolutionCB->Enable(!g_Config.bRunning);
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK) #if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
m_WindowFSResolutionCB->Enable(!g_Config.bRunning); m_WindowFSResolutionCB->Enable(!g_Config.bRunning);

View File

@ -103,6 +103,7 @@ class GFXConfigDialogOGL : public wxDialog
wxCheckBox *m_ForceFiltering; wxCheckBox *m_ForceFiltering;
wxCheckBox *m_Crop; wxCheckBox *m_Crop;
wxCheckBox *m_UseXFB; wxCheckBox *m_UseXFB;
wxCheckBox *m_UseRealXFB;
wxCheckBox *m_AutoScale; wxCheckBox *m_AutoScale;
#ifndef _WIN32 #ifndef _WIN32
wxCheckBox *m_HideCursor; wxCheckBox *m_HideCursor;
@ -163,6 +164,7 @@ class GFXConfigDialogOGL : public wxDialog
ID_NATIVERESOLUTION, ID_2X_RESOLUTION, ID_NATIVERESOLUTION, ID_2X_RESOLUTION,
ID_ASPECT, ID_ASPECT,
ID_CROP, ID_CROP,
ID_USEREALXFB,
ID_USEXFB, ID_USEXFB,
ID_AUTOSCALE, ID_AUTOSCALE,
ID_WIDESCREENHACK, ID_WIDESCREENHACK,

View File

@ -792,22 +792,25 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect
if (!g_ActiveConfig.bUseXFB) if (!g_ActiveConfig.bUseXFB)
{ {
Renderer::Swap(xfbAddr, FIELD_PROGRESSIVE, fbWidth, fbHeight); Renderer::Swap(xfbAddr, FIELD_PROGRESSIVE, fbWidth, fbHeight);
Common::AtomicStoreRelease(s_swapRequested, FALSE);
} }
} }
// This function has the final picture. We adjust the aspect ratio here. // This function has the final picture. We adjust the aspect ratio here.
void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
{ {
Common::AtomicStoreRelease(s_swapRequested, FALSE);
if (s_skipSwap) if (s_skipSwap)
{ {
g_VideoInitialize.pCopiedToXFB(false); g_VideoInitialize.pCopiedToXFB(false);
return; return;
} }
const XFBSource* xfbSource = g_framebufferManager.GetXFBSource(xfbAddr, fbWidth, fbHeight); if (field == FIELD_LOWER)
if (!xfbSource) 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"); WARN_LOG(VIDEO, "Failed to get video for this frame");
return; return;
@ -821,27 +824,6 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
TargetRectangle back_rc; TargetRectangle back_rc;
ComputeDrawRectangle(OpenGL_GetBackbufferWidth(), OpenGL_GetBackbufferHeight(), true, &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. // Make sure that the wireframe setting doesn't screw up the screen copy.
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 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 // Texture map s_xfbTexture onto the main buffer
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_RECTANGLE_ARB); glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbSource->texture);
// Use linear filtering. // Use linear filtering.
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_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 // 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. // 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); xfbSource = xfbSourceList[i];
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); TargetRectangle sourceRc;
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); if (g_ActiveConfig.bAutoScale || g_ActiveConfig.bUseXFB)
glEnd(); {
PixelShaderCache::DisableShader();; sourceRc = xfbSource->sourceRc;
} }
else else
{ {
glBegin(GL_QUADS); sourceRc.left = 0;
glTexCoord2f(sourceRc.left, sourceRc.bottom); glVertex2f(-1, -1); sourceRc.top = xfbSource->texHeight;
glTexCoord2f(sourceRc.left, sourceRc.top); glVertex2f(-1, 1); sourceRc.right = xfbSource->texWidth;
glTexCoord2f(sourceRc.right, sourceRc.top); glVertex2f( 1, 1); sourceRc.bottom = 0;
glTexCoord2f(sourceRc.right, sourceRc.bottom); glVertex2f( 1, -1); }
glEnd();
MathUtil::Rectangle<float> 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); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
@ -909,7 +958,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
s_criticalScreenshot.Enter(); s_criticalScreenshot.Enter();
// Save screenshot // 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 // Reset settings
s_sScreenshotName = ""; s_sScreenshotName = "";
s_bScreenshot = false; 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); u8 *data = (u8 *) malloc(3 * w * h);
glPixelStorei(GL_PACK_ALIGNMENT, 1); 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 (glGetError() == GL_NO_ERROR && w > 0 && h > 0)
{ {
if (!s_bLastFrameDumped) if (!s_bLastFrameDumped)

View File

@ -484,10 +484,8 @@ void VideoFifo_CheckSwapRequest()
{ {
Renderer::Swap(s_beginFieldArgs.xfbAddr, s_beginFieldArgs.field, s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight); 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);
}
} }
} }