OpenGL: Fixed the screen size adjustment by moving it to Render::Swap(), where the final version of the picture is placed

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2344 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
John Peterson 2009-02-21 20:59:30 +00:00
parent ca47268669
commit b4b94fe594
8 changed files with 239 additions and 136 deletions

View File

@ -36,6 +36,12 @@
// This may remove sound artifacts in Wario Land Shake It and perhaps other games
//#define SETUP_AVOID_SOUND_ARTIFACTS
// This may fix a problem with Stop and Start that I described in the comments to revision 2,139
//#define SETUP_FREE_PLUGIN_ON_BOOT
// Use Stop when rendering to a child window
//#define SETUP_AVOID_CHILD_WINDOW_RENDERING_HANG
// Build with playback rerecording options
//#define RERECORDING

View File

@ -242,7 +242,11 @@ void Stop() // - Hammertime!
Core::StopTrace();
LogManager::Shutdown();
Host_SetWaitCursor(false);
#ifdef SETUP_AVOID_CHILD_WINDOW_RENDERING_HANG
/* I have to use this to avoid the hangings, it seems harmless and it works so I'm
okay with it */
if (GetParent((HWND)g_pWindowHandle) == NULL)
#endif
delete g_EmuThread; // Wait for emuthread to close.
g_EmuThread = 0;
}
@ -327,6 +331,10 @@ THREAD_RETURN EmuThread(void *pArg)
VideoInitialize.pKeyPress = Callback_KeyPress;
VideoInitialize.bWii = _CoreParameter.bWii;
VideoInitialize.bUseDualCore = _CoreParameter.bUseDualCore;
// Needed for Stop and Start
#ifdef SETUP_FREE_PLUGIN_ON_BOOT
Plugins.FreeVideo();
#endif
Plugins.GetVideo()->Initialize(&VideoInitialize); // Call the dll
// Under linux, this is an X11 Display, not an HWND!
@ -347,6 +355,10 @@ THREAD_RETURN EmuThread(void *pArg)
dspInit.pGetAudioStreaming = AudioInterface::Callback_GetStreaming;
dspInit.pEmulatorState = (int *)PowerPC::GetStatePtr();
dspInit.bWii = _CoreParameter.bWii;
// Needed for Stop and Start
#ifdef SETUP_FREE_PLUGIN_ON_BOOT
Plugins.FreeDSP();
#endif
Plugins.GetDSP()->Initialize((void *)&dspInit);
// Load and Init PadPlugin

View File

@ -37,6 +37,8 @@
2. Sond plugin: If FreeLibrary() is not called between Stop and Start I got the "Tried to
"get pointer for unknown address ffffffff" message for all games I tried.
Currently this holds if the 'SETUP_FREE_PLUGIN_ON_BOOT' option is used
For some reason the time when the FreeLibrary() is placed produce different results. If it's placed
after ShutDown() I don't get a black screen when I start SSBM (PAL) again, if I have stopped the game
before the first 3D appears (on the start screen), if I show the start screen and then Stop and Start
@ -205,15 +207,21 @@ void CPluginManager::ShutdownPlugins()
if (m_video)
{
m_video->Shutdown();
delete m_video;
m_video = NULL;
// With this option, this is done on boot instead
#ifndef SETUP_FREE_PLUGIN_ON_BOOT
delete m_video;
m_video = NULL;
#endif
}
if (m_dsp)
{
m_dsp->Shutdown();
delete m_dsp;
m_dsp = NULL;
// With this option, this is done on boot instead
#ifndef SETUP_FREE_PLUGIN_ON_BOOT
delete m_dsp;
m_dsp = NULL;
#endif
}
}
//////////////////////////////////////////////
@ -537,4 +545,4 @@ void CPluginManager::OpenDebug(void* _Parent, const char *_rFilename, PLUGIN_TYP
PanicAlert("Type %d debug not supported in plugin %s", Type, _rFilename);
}
}
///////////////////////////////////////////
///////////////////////////////////////////

View File

@ -339,6 +339,7 @@ Global
{E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA}.Release JITIL|x64.ActiveCfg = Release|x64
{E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA}.Release JITIL|x64.Build.0 = Release|x64
{E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA}.Release|Win32.ActiveCfg = Release|Win32
{E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA}.Release|Win32.Build.0 = Release|Win32
{E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA}.Release|x64.ActiveCfg = Release|x64
{E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA}.Release|x64.Build.0 = Release|x64
{D6E56527-BBB9-4EAD-A6EC-49D4BF6AFCD8}.Debug|Win32.ActiveCfg = Debug|Win32

View File

@ -449,13 +449,13 @@ void BPWritten(int addr, int changes, int newval)
}
else
{
Renderer::Swap();
Renderer::Swap(multirc);
}
g_VideoInitialize.pCopiedToXFB();
}
// --------------------------------------------------------
// Clearing
// Clear the picture after it's done and submitted, to prepare for the next picture
// --------------------------
if (PE_copy.clear)
{
@ -464,20 +464,17 @@ void BPWritten(int addr, int changes, int newval)
// Clear Z-Buffer target
u32 nRestoreZBufferTarget = Renderer::GetZBufferTarget();
// Why do we have this here and in Render.cpp?
// -----------------------------------------------------------------
// Update the view port for clearing the picture
// -----------------------
glViewport(0, 0, Renderer::GetTargetWidth(), Renderer::GetTargetHeight());
// Always set the scissor in case it was set by the game and has not been reset
// But we will do that at the end of this section, in SetScissorRect(), why would we do it twice in the same function?
// Because this is needed by the intermediate functions diirectly below here, in glDrawBuffer()
// and so on.
/* We will also do this at the end of this section, in SetScissorRect(), but that is for creating the new picture
this is for clearing the picture */
glScissor(multirc.left, (Renderer::GetTargetHeight() - multirc.bottom),
(multirc.right - multirc.left), (multirc.bottom - multirc.top));
// Logging
GLScissorX = multirc.left; GLScissorY = (Renderer::GetTargetHeight() - multirc.bottom);
GLScissorW = (multirc.right - multirc.left); GLScissorH = (multirc.bottom - multirc.top);
//Console::Print("%i %i %i %i\n", GLScissorX, GLScissorY, GLScissorW, GLScissorH);
(multirc.right - multirc.left), (multirc.bottom - multirc.top));
// ---------------------------
VertexShaderManager::SetViewportChanged();

View File

@ -44,7 +44,7 @@ void Config::Load()
strncpy(iBackend, temp.c_str(), 16);
iniFile.Get("Hardware", "Fullscreen", &bFullscreen, 0); // Hardware
iniFile.Get("Hardware", "RenderToMainframe", &renderToMainframe, 0);
iniFile.Get("Hardware", "RenderToMainframe", &renderToMainframe, false);
iniFile.Get("Settings", "StretchToFit", &bStretchToFit, true);
iniFile.Get("Settings", "KeepAR", &bKeepAR, false);
iniFile.Get("Settings", "HideCursor", &bHideCursor, false);

View File

@ -592,31 +592,11 @@ bool Renderer::SetScissorRect()
// Check that the coordinates are good
if (rc_right >= rc_left && rc_bottom >= rc_top)
{
// -----------------------------------------------------------------------
// XFB supplement, fix the black borders problem
// ------------------
// See comment in UpdateViewport() about why I don't the XFB supplement to these options
//if(g_Config.bStretchToFit && !g_Config.bUseXFB)
if(false)
{
int WidthDifference = 640 - (int)(rc_right - rc_left);
int HeightDifference = 480 - (int)(rc_bottom - rc_top);
GLScissorX = (int)rc_left; GLScissorY = -(Renderer::GetTargetHeight() - (int)(rc_bottom));
GLScissorW = Renderer::GetTargetWidth() + WidthDifference; GLScissorH = Renderer::GetTargetHeight() + HeightDifference;
}
// ------------------------
else
{
GLScissorX = (int)rc_left; GLScissorY = Renderer::GetTargetHeight() - (int)(rc_bottom);
GLScissorW = (int)(rc_right - rc_left); GLScissorH = (int)(rc_bottom - rc_top);
}
glScissor(
GLScissorX, // x = 0
GLScissorY, // y = 0
GLScissorW, // width = 640 for example
GLScissorH // height = 480 for example
(int)rc_left, // x = 0 for example
Renderer::GetTargetHeight() - (int)(rc_bottom), // y = 0 for example
(int)(rc_right-rc_left), // width = 640 for example
(int)(rc_bottom-rc_top) // height = 480 for example
);
return true;
}
@ -775,7 +755,12 @@ Renderer::RenderMode Renderer::GetRenderMode()
return s_RenderMode;
}
void Renderer::Swap()
//////////////////////////////////////////////////////////////////////////////////////
// This function has the final picture if the XFB functions are not used. We adjust the aspect ratio
// here.
// ----------------------
void Renderer::Swap(const TRectangle& rc)
{
OpenGL_Update(); // just updates the render window position and the backbuffer size
@ -794,8 +779,183 @@ void Renderer::Swap()
#else
// render to the real buffer now
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer
glViewport(OpenGL_GetXoff(), OpenGL_GetYoff(), (int)OpenGL_GetWidth(), (int)OpenGL_GetHeight());
// -----------------------------------------------------------------------
// GLViewPort variables
// ------------------
/* Work with float values for the XFB supplement and aspect ratio functions. These are default
values that are used if the XFB supplement and the keep aspect ratio function are unused */
float FloatGLWidth = (float)OpenGL_GetWidth();
float FloatGLHeight = (float)OpenGL_GetHeight();
float FloatXOffset = 0, FloatYOffset = 0;
// -------------------------------------
// -----------------------------------------------------------------------
// XFB supplement, fix the black borders problem
// ------------------
/* I'm limiting it to the stretch to fit option because I don't know how the other mode works. The reason
I don't allow this option together with UseXFB is that they are supplements and the XFB function
should be able to produce the same result */
if(g_Config.bStretchToFit && !g_Config.bUseXFB)
{
// The rendering window size
float WinWidth = (float)OpenGL_GetWidth();
float WinHeight = (float)OpenGL_GetHeight();
// The fraction of the screen that the image occupies
// Rc.right and rc.bottom is the original picture pixel size
/* There is a +1 in Rc (earlier called multirc, the input to this function), but these
adjustments seems to work better without it. */
float WidthRatio = (float)(rc.right - 1) / 640.0;
float HeightRatio = (float)(rc.bottom - 1) / 480.0;
// The pixel size of the image on the screen, adjusted for the actual window size
float OldWidth = WidthRatio * (float)WinWidth;
float OldHeight = HeightRatio * (float)WinHeight;
// The adjusted width and height
FloatGLWidth = ceil((float)WinWidth / WidthRatio);
FloatGLHeight = ceil((float)WinHeight / HeightRatio);
// The width and height deficit in actual pixels
float WidthDeficit = (float)WinWidth - OldWidth;
float HeightDeficit = (float)WinHeight - OldHeight;
// The picture will be drawn from the bottom so we need this YOffset
// The X-axis needs no adjustment because the picture begins from the left
FloatYOffset = -HeightDeficit / HeightRatio;
// -----------------------------------------------------------------------
// Logging
// ------------------
/*
Console::ClearScreen();
Console::Print("Bpmem L:%i T:%i X:%i Y:%i\n", bpmem.copyTexSrcXY.x, bpmem.copyTexSrcXY.y, bpmem.copyTexSrcWH.x, bpmem.copyTexSrcWH.y);
Console::Print("Config Left:%i Top:%i Width:%i Height:%i\n", g_Config.iScreenLeft, g_Config.iScreenTop, g_Config.iScreenWidth, g_Config.iScreenHeight);
Console::Print("Input Left:%i Top:%i Right:%i Bottom:%i\n", rc.left, rc.top, rc.right, rc.bottom);
Console::Print("Old picture: Width[%1.2f]:%4.0f Height[%1.2f]:%4.0f\n", WidthRatio, OldWidth, HeightRatio, OldHeight);
Console::Print("New picture: Width[%1.2f]:%4.0f Height[%1.2f]:%4.0f YOffset:%4.0f YDeficit:%4.0f\n", WidthRatio, WinWidth, HeightRatio, WinHeight, FloatYOffset, HeightDeficit);
Console::Print("----------------------------------------------------------------\n");
*/
// ------------------------------
}
// ------------------------------
// -----------------------------------------------------------------------
/* Keep aspect ratio at 4:3. This may be interesting if you for example have a 5:4 screen but don't like
the stretching, and would rather have a letterbox. */
// Output: GLWidth, GLHeight, XOffset, YOffset
// ------------------
// The rendering window size
float WinWidth = (float)OpenGL_GetWidth();
float WinHeight = (float)OpenGL_GetHeight();
// The rendering window aspect ratio as a fraction of the 4:3 ratio
float Ratio = WinWidth / WinHeight / (4.0 / 3.0);
float wAdj, hAdj;
float ActualRatioW, ActualRatioH;
float Overflow;
// Actual pixel size of the picture after adjustment
float PictureWidth = WinWidth, PictureHeight = WinHeight;
// This function currently only works together with the Stretch To Fit option
if (g_Config.bKeepAR && g_Config.bStretchToFit)
{
// Check if height or width is the limiting factor. If ratio > 1 the picture is to wide and have to limit the width.
if (Ratio > 1)
{
// ------------------------------------------------
// Calculate the new width and height for glViewport, this is not the actual size of either the picture or the screen
// ----------------
wAdj = Ratio;
hAdj = 1.0;
FloatGLWidth = FloatGLWidth / wAdj;
FloatGLHeight = FloatGLHeight / hAdj;
// --------------------
// ------------------------------------------------
// Calculate the new X offset
// ----------------
// The picture width
PictureWidth = WinWidth / Ratio;
// Move the left of the picture to the middle of the screen
FloatXOffset = FloatXOffset + WinWidth / 2.0;
// Then remove half the picture height to move it to the horizontal center
FloatXOffset = FloatXOffset - PictureWidth / 2.0;
// --------------------
}
// The window is to high, we have to limit the height
else
{
// ------------------------------------------------
// Calculate the new width and height for glViewport, this is not the actual size of either the picture or the screen
// ----------------
// Invert the ratio to make it > 1
Ratio = 1.0 / Ratio;
wAdj = 1.0;
hAdj = Ratio;
FloatGLWidth = FloatGLWidth / wAdj;
FloatGLHeight = FloatGLHeight / hAdj;
// --------------------
// ------------------------------------------------
// Calculate the new Y offset
// ----------------
// The picture height
PictureHeight = WinHeight / Ratio;
// Keep the picture on the bottom of the screen, this is needed because YOffset may not be 0 here
FloatYOffset = FloatYOffset / hAdj;
// Move the bottom of the picture to the middle of the screen
FloatYOffset = FloatYOffset + WinHeight / 2.0;
// Then remove half the picture height to move it to the vertical center
FloatYOffset = FloatYOffset - PictureHeight / 2.0;
// --------------------
}
// -----------------------------------------------------------------------
// Logging
// ------------------
/*
Console::Print("Screen Width:%4.0f Height:%4.0f Ratio:%1.2f\n", WinWidth, WinHeight, Ratio);
Console::Print("GL Width:%4.1f Height:%4.1f\n", FloatGLWidth, FloatGLHeight);
Console::Print("Picture Width:%4.1f Height:%4.1f YOffset:%4.0f\n", PictureWidth, PictureHeight, FloatYOffset);
Console::Print("----------------------------------------------------------------\n");
*/
// ------------------------------
}
// -------------------------------------
// -----------------------------------------------------------------------
/* Adjustments to
FloatGLWidth
FloatGLHeight
XOffset
YOffset
are done. Calculate the new new windows width and height. */
// --------------------
int GLx = OpenGL_GetXoff(); // These two are zero
int GLy = OpenGL_GetYoff();
int GLWidth = ceil(FloatGLWidth);
int GLHeight = ceil(FloatGLHeight);
// Because there is no round() function we use round(float) = floor(float + 0.5) instead
int YOffset = floor(FloatYOffset + 0.5);
int XOffset = floor(FloatXOffset+ 0.5);
// -------------------------------------
// Update GLViewPort
glViewport(
GLx + XOffset,
GLy + YOffset,
GLWidth,
GLHeight
);
// Reset GL state
ResetGLState();
// texture map s_RenderTargets[s_curtarget] onto the main buffer
@ -836,6 +996,8 @@ void Renderer::Swap()
//Renderer::SetZBufferRender();
//SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, GetTargetWidth(), GetTargetHeight());
}
////////////////////////////////////////////////
void Renderer::SwapBuffers()
{
@ -1011,7 +1173,8 @@ bool Renderer::SaveRenderTarget(const char* filename, int jpeg)
}
//////////////////////////////////////////////////////////////////////////////////////
// Called from VertexShaderManager
// Function: This function does not have the final picture. Use Renderer::Swap() to adjust the final picture.
// Call schedule: Called from VertexShaderManager
// ----------------------
void UpdateViewport()
{
@ -1043,92 +1206,6 @@ void UpdateViewport()
// rawViewport[0] = 320, rawViewport[1] = -240
int scissorXOff = bpmem.scissorOffset.x * 2 - 342;
int scissorYOff = bpmem.scissorOffset.y * 2 - 342;
// Used in the XFB supplement and the keep aspect ratio function
int XOffset = 0, YOffset = 0;
// -------------------------------------
// -----------------------------------------------------------------------
/* XFB supplement, fix the black borders problem. This has to be used together with the adjustment
of glScissor in Renderer::SetScissorRect() */
// ------------------
/* I'm limiting it to the stretch to fit option because I don't know how the other mode works. The reason
I don't allow this option together with UseXFB is that they are supplements and the XFB function
should be able to produce the same result */
//if(g_Config.bStretchToFit && !g_Config.bUseXFB)
if (false)
{
XOffset = (640 - GLScissorW);
YOffset = (480 - GLScissorH);
FloatGLWidth = FloatGLWidth - XOffset;
FloatGLHeight = FloatGLHeight - YOffset;
}
// ------------------------
// -----------------------------------------------------------------------
// Keep aspect ratio at 4:3
// Output: GLWidth, GLHeight, XOffset, YOffset
// ------------------
// Internal functions
float FourThree = 4.0f / 3.0f;
float wAdj, hAdj;
float actualRatiow, actualRatioh;
int overfl;
int actualWid, actualHei;
// The rendering window width and height
int WinW = OpenGL_GetWidth();
int WinH = OpenGL_GetHeight();
// The rendering window aspect ratio
float Ratio = (float)WinW / (float)WinH / FourThree;
// The XOffset and YOffset values are currently only used in the Stretch To Fit option
if (g_Config.bKeepAR && g_Config.bStretchToFit)
{
// Check if height or width is the limiting factor. If ratio > 1 the picture is to wide and have to limit the width.
if (Ratio > 1)
{
wAdj = Ratio;
hAdj = 1;
GLWidth = (int)ceil(FloatGLWidth / wAdj);
GLHeight = (int)ceil(FloatGLHeight / hAdj);
actualWid = (int)ceil((float)WinW / Ratio);
// The picture compared to the screen
actualRatiow = (float)actualWid / (float)GLWidth;
overfl = (int)ceil((WinW - actualWid) / actualRatiow);
XOffset = XOffset + overfl / 2;
}
// The window is to high, we have to limit the height
else
{
// Invert the ratio
Ratio = 1 / Ratio;
wAdj = 1;
hAdj = Ratio;
GLWidth = (int)ceil(FloatGLWidth / wAdj);
GLHeight = (int)ceil(FloatGLHeight / hAdj);
actualHei = (int)ceil((float)WinH / Ratio);
// The picture compared to the screen
actualRatioh = (float)actualHei / (float)GLHeight;
overfl = (int)ceil((WinH - actualHei) / actualRatioh);
YOffset = YOffset + overfl / 2;
}
}
// Don't adjust the position of screen size
else
{
// Round up to the nearest integer
GLWidth = (int)ceil(FloatGLWidth);
GLHeight = (int)ceil(FloatGLHeight);
}
// -------------------------------------
@ -1137,8 +1214,11 @@ void UpdateViewport()
// ------------------
if (g_Config.bStretchToFit)
{
GLx = (int)(xfregs.rawViewport[3] - xfregs.rawViewport[0] - 342 - scissorXOff) + XOffset;
GLy = Renderer::GetTargetHeight() - ((int)(xfregs.rawViewport[4] - xfregs.rawViewport[1] - 342 - scissorYOff)) + YOffset;
GLx = (int)(xfregs.rawViewport[3] - xfregs.rawViewport[0] - 342 - scissorXOff);
GLy = Renderer::GetTargetHeight() - ((int)(xfregs.rawViewport[4] - xfregs.rawViewport[1] - 342 - scissorYOff));
// Round up to the nearest integer
GLWidth = (int)ceil(FloatGLWidth);
GLHeight = (int)ceil(FloatGLHeight);
}
// -----------------------------------------------------------------------
// Stretch picture with increased internal resolution
@ -1180,7 +1260,6 @@ void UpdateViewport()
GetWindowRect(Top, &RcTop);
GetWindowRect(Parent, &RcParent);
GetWindowRect(Child, &RcChild);
//Console::ClearScreen();
Console::Print("----------------------------------------------------------------\n");

View File

@ -128,7 +128,7 @@ public:
static bool SaveRenderTarget(const char* filename, int jpeg);
// Finish up the current frame, print some stats
static void Swap();
static void Swap(const TRectangle& rc);
};
#endif