Added EFB Scale option to the OpenGL plug-in.

Renamed EFB Scale to Internal Resolution.
Removed Auto Scale option (it is now always on).
Added on-the-fly changing of the Internal Resolution in the OpenGL and Direct3D9 plug-ins.
Further consolidated the code in the video plug-ins.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6240 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
skidau
2010-09-30 15:24:34 +00:00
parent ce1057f17d
commit 719521eeeb
25 changed files with 423 additions and 450 deletions

View File

@ -94,6 +94,7 @@ static int s_MSAACoverageSamples = 0;
bool s_bHaveFramebufferBlit = false; // export to FramebufferManager.cpp
static bool s_bHaveCoverageMSAA = false;
static u32 s_blendMode;
static u32 s_LastEFBScale;
static volatile bool s_bScreenshot = false;
#if defined(HAVE_WX) && HAVE_WX
@ -105,6 +106,9 @@ static std::string s_sScreenshotName;
int frameCount;
// The custom resolution
static int s_Fulltarget_width;
static int s_Fulltarget_height;
// TODO: Add functionality to reinit all the render targets when the window is resized.
static int s_backbuffer_width;
static int s_backbuffer_height;
@ -348,29 +352,40 @@ bool Renderer::Init()
TargetRectangle dst_rect;
ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect);
xScale = 1.0f;
yScale = 1.0f;
if(!g_ActiveConfig.bNativeResolution)
if(g_ActiveConfig.bUseRealXFB)
{
if (g_ActiveConfig.b2xResolution)
{
xScale = 2.0f;
yScale = 2.0f;
}
else
{
xScale = (float)(dst_rect.right - dst_rect.left) / (float)s_XFB_width;
yScale = (float)(dst_rect.bottom - dst_rect.top) / (float)s_XFB_height;
}
xScale = 1.0f;
yScale = 1.0f;
}
else
{
xScale = (float)(dst_rect.right - dst_rect.left) / (float)s_XFB_width;
yScale = (float)(dst_rect.bottom - dst_rect.top) / (float)s_XFB_height;
}
EFBxScale = ceilf(xScale);
EFByScale = ceilf(yScale);
s_LastEFBScale = g_ActiveConfig.iEFBScale;
switch(s_LastEFBScale)
{
case 0:
EFBxScale = xScale;
EFByScale = yScale;
break;
case 1:
EFBxScale = ceilf(xScale);
EFByScale = ceilf(yScale);
break;
default:
EFBxScale = g_ActiveConfig.iEFBScale - 1;
EFByScale = EFBxScale;
break;
};
s_target_width = EFB_WIDTH * EFBxScale;
s_target_height = EFB_HEIGHT * EFByScale;
s_Fulltarget_width = s_target_width;
s_Fulltarget_height = s_target_height;
// Because of the fixed framebuffer size we need to disable the resolution
// options while running
g_Config.bRunning = true;
@ -488,7 +503,7 @@ bool Renderer::Init()
return GL_REPORT_ERROR() == GL_NO_ERROR && bSuccess;
}
void Renderer::Shutdown(void)
void Renderer::Shutdown()
{
g_Config.bRunning = false;
UpdateActiveConfig();
@ -530,15 +545,14 @@ int Renderer::GetTargetHeight()
return s_target_height;
}
// Return the custom resolution
int Renderer::GetCustomWidth()
int Renderer::GetFullTargetWidth()
{
return s_backbuffer_width;
return s_Fulltarget_width;
}
int Renderer::GetCustomHeight()
int Renderer::GetFullTargetHeight()
{
return s_backbuffer_height;
return s_Fulltarget_height;
}
float Renderer::GetTargetScaleX()
@ -561,17 +575,6 @@ float Renderer::GetXFBScaleY()
return yScale;
}
// Return the framebuffer size
int Renderer::GetFrameBufferWidth()
{
return s_target_width;
}
int Renderer::GetFrameBufferHeight()
{
return s_target_height;
}
// Create On-Screen-Messages
void Renderer::DrawDebugText()
{
@ -657,16 +660,26 @@ void Renderer::DrawDebugText()
std::string T1 = "", T2 = "";
std::vector<std::string> T0;
int W, H;
W = OpenGL_GetBackbufferWidth();
H = OpenGL_GetBackbufferHeight();
std::string OSDM1;
switch(g_ActiveConfig.iEFBScale)
{
case 0:
OSDM1 = "Auto (fractional)";
break;
case 1:
OSDM1 = "Auto (integral)";
break;
case 2:
OSDM1 = "Native";
break;
case 3:
OSDM1 = "2x";
break;
case 4:
OSDM1 = "3x";
break;
}
std::string OSDM1 =
g_ActiveConfig.bNativeResolution || g_ActiveConfig.b2xResolution ?
(g_ActiveConfig.bNativeResolution ?
StringFromFormat("%i x %i (native)", OSDInternalW, OSDInternalH)
: StringFromFormat("%i x %i (2x)", OSDInternalW, OSDInternalH))
: StringFromFormat("%i x %i (custom)", W, H);
std::string OSDM21;
switch(g_ActiveConfig.iAspectRatio)
{
@ -740,7 +753,14 @@ void Renderer::RenderText(const char *text, int left, int top, u32 color)
TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
{
return g_framebufferManager.ConvertEFBRectangle(rc);
TargetRectangle result;
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
result.left = (int)(rc.left * EFBxScale) + Xstride;
result.top = (int)((EFB_HEIGHT - rc.top) * EFByScale) + Ystride;
result.right = (int)(rc.right * EFBxScale) - (Xstride * 2);
result.bottom = (int)((EFB_HEIGHT - rc.bottom) * EFByScale) - (Ystride * 2);
return result;
}
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
@ -778,39 +798,51 @@ bool Renderer::SetScissorRect()
{
int xoff = bpmem.scissorOffset.x * 2 - 342;
int yoff = bpmem.scissorOffset.y * 2 - 342;
float rc_left = (float)bpmem.scissorTL.x - xoff - 342; // left = 0
if (rc_left < 0) rc_left = 0;
float rc_top = (float)bpmem.scissorTL.y - yoff - 342; // right = 0
if (rc_top < 0) rc_top = 0;
float rc_right = (float)bpmem.scissorBR.x - xoff - 341; // right = 640
if (rc_right > EFB_WIDTH) rc_right = EFB_WIDTH;
float rc_bottom = (float)bpmem.scissorBR.y - yoff - 341; // bottom = 480
// TODO: Sanity checks require further testing
if (rc_left < 0) rc_left = 0;
//if (rc_right < 0) rc_right = 0;
//if (rc_left > EFB_WIDTH) rc_left = EFB_WIDTH;
if (rc_right > EFB_WIDTH) rc_right = EFB_WIDTH;
if (rc_top < 0) rc_top = 0;
//if (rc_bottom < 0) rc_bottom = 0;
//if (rc_top > EFB_HEIGHT) rc_top = EFB_HEIGHT;
if (rc_bottom > EFB_HEIGHT) rc_bottom = EFB_HEIGHT;
if(rc_left > rc_right)
if (rc_left > rc_right)
{
int temp = rc_right;
rc_right = rc_left;
rc_left = temp;
}
if(rc_top > rc_bottom)
if (rc_top > rc_bottom)
{
int temp = rc_bottom;
rc_bottom = rc_top;
rc_top = temp;
}
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
rc_left = (int)(rc_left * EFBxScale);// + Xstride;
rc_top = (int)((rc_bottom - rc_top) * EFByScale);// + Ystride;
rc_right = (int)((rc_right - rc_left) * EFBxScale);
rc_bottom = (int)((EFB_HEIGHT - rc_bottom) * EFByScale); // -Ystride?
// Check that the coordinates are good
if (rc_right != rc_left && rc_bottom != rc_top)
{
glScissor(
(int)(rc_left * EFBxScale), // x = 0 for example
(int)((EFB_HEIGHT - rc_bottom) * EFByScale), // y = 0 for example
(int)((rc_right - rc_left)* EFBxScale), // width = 640 for example
(int)((rc_bottom - rc_top) * EFByScale) // height = 480 for example
(int)(rc_left), // x = 0 for example
(int)(rc_bottom), // y = 0 for example
(int)(rc_right), // width = 640 for example
(int)(rc_top) // height = 480 for example
);
return true;
}
@ -835,7 +867,7 @@ void Renderer::SetColorMask()
u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
{
if(!g_ActiveConfig.bEFBAccessEnable)
if (!g_ActiveConfig.bEFBAccessEnable)
return 0;
// Get the rectangular target region covered by the EFB pixel
@ -845,7 +877,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
efbPixelRc.right = x + 1;
efbPixelRc.bottom = y + 1;
TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc);
TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc);
// TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel
switch (type)
@ -929,42 +961,44 @@ void UpdateViewport()
// [3] = xorig + width/2 + 342
// [4] = yorig + height/2 + 342
// [5] = 16777215 * farz
float scissorXOff = float(bpmem.scissorOffset.x) * 2.0f; // 342
float scissorYOff = float(bpmem.scissorOffset.y) * 2.0f; // 342
int scissorXOff = bpmem.scissorOffset.x * 2;
int scissorYOff = bpmem.scissorOffset.y * 2;
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
// Stretch picture with increased internal resolution
int GLx = (int)ceil((xfregs.rawViewport[3] - xfregs.rawViewport[0] - scissorXOff) *
EFBxScale);
int GLy = (int)ceil(
(float(EFB_HEIGHT) - xfregs.rawViewport[4] + xfregs.rawViewport[1] + scissorYOff) *
EFByScale);
int GLWidth = (int)ceil(2.0f * xfregs.rawViewport[0] * EFBxScale);
int GLHeight = (int)ceil(-2.0f * xfregs.rawViewport[1] * EFByScale);
int X = (int)ceil((xfregs.rawViewport[3] - xfregs.rawViewport[0] - float(scissorXOff)) * EFBxScale);
int Y = (int)ceil((float(EFB_HEIGHT) - xfregs.rawViewport[4] + xfregs.rawViewport[1] + float(scissorYOff)) * EFByScale);
int Width = (int)ceil(2.0f * xfregs.rawViewport[0] * EFBxScale);
int Height = (int)ceil(-2.0f * xfregs.rawViewport[1] * EFByScale);
double GLNear = (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f;
double GLFar = xfregs.rawViewport[5] / 16777216.0f;
if(GLWidth < 0)
if (Width < 0)
{
GLx += GLWidth;
GLWidth*=-1;
X += Width;
Width*=-1;
}
if(GLHeight < 0)
if (Height < 0)
{
GLy += GLHeight;
GLHeight *= -1;
Y += Height;
Height *= -1;
}
// Update the view port
glViewport(GLx, GLy, GLWidth, GLHeight);
glViewport(X, Y, Width, Height);
glDepthRange(GLNear, GLFar);
}
void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
{
// Update the view port for clearing the picture
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc);
TargetRectangle targetRc = ConvertEFBRectangle(rc);
glViewport(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
// Always set the scissor in case it was set by the game and has not been reset
glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
VertexShaderManager::SetViewportChanged();
@ -1048,10 +1082,9 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
}
DVSTARTPROFILE();
ResetAPIState();
TargetRectangle back_rc;
ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, true, &back_rc);
TargetRectangle dst_rect;
ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, true, &dst_rect);
// Make sure that the wireframe setting doesn't screw up the screen copy.
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@ -1063,7 +1096,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
TextureCache::DisableStage(i);
// Update GLViewPort
glViewport(back_rc.left, back_rc.bottom, back_rc.GetWidth(), back_rc.GetHeight());
glViewport(dst_rect.left, dst_rect.bottom, dst_rect.GetWidth(), dst_rect.GetHeight());
GL_REPORT_ERRORD();
@ -1094,21 +1127,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
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;
}
sourceRc = xfbSource->sourceRc;
MathUtil::Rectangle<float> drawRc;
if (g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
if (!g_ActiveConfig.bUseRealXFB)
{
// use virtual xfb with offset
int xfbHeight = xfbSource->srcHeight;
@ -1120,17 +1143,14 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
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;
}
// The following code disables auto stretch. Kept for reference.
// scale draw area for a 1 to 1 pixel mapping with the draw target
//float vScale = (float)fbHeight / (float)dst_rect.GetHeight();
//float hScale = (float)fbWidth / (float)dst_rect.GetWidth();
//drawRc.top *= vScale;
//drawRc.bottom *= vScale;
//drawRc.left *= hScale;
//drawRc.right *= hScale;
}
else
{
@ -1192,7 +1212,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
}
else
{
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc);
TargetRectangle targetRc = ConvertEFBRectangle(rc);
GLuint read_texture = g_framebufferManager.ResolveAndGetRenderTarget(rc);
// Render to the real buffer now.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer
@ -1234,12 +1254,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
glVertex2f( 1, -1);
glEnd();
}
}
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
TextureCache::DisableStage(0);
if(g_ActiveConfig.bAnaglyphStereo)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Wireframe
if (g_ActiveConfig.bWireFrame)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@ -1249,7 +1268,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{
s_criticalScreenshot.Enter();
// Save screenshot
SaveRenderTarget(s_sScreenshotName.c_str(), back_rc);
SaveRenderTarget(s_sScreenshotName.c_str(), dst_rect);
// Reset settings
s_sScreenshotName = "";
s_bScreenshot = false;
@ -1261,11 +1280,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
if (g_ActiveConfig.bDumpFrames)
{
s_criticalScreenshot.Enter();
int w = back_rc.GetWidth();
int h = back_rc.GetHeight();
int w = dst_rect.GetWidth();
int h = dst_rect.GetHeight();
u8 *data = (u8 *) malloc(3 * w * h);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(back_rc.left, back_rc.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data);
glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data);
if (GL_REPORT_ERROR() == GL_NO_ERROR && w > 0 && h > 0)
{
if (!s_bLastFrameDumped)
@ -1306,11 +1325,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{
s_criticalScreenshot.Enter();
char movie_file_name[255];
int w = back_rc.GetWidth();
int h = back_rc.GetHeight();
int w = dst_rect.GetWidth();
int h = dst_rect.GetHeight();
u8 *data = (u8 *) malloc(3 * w * h);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(back_rc.left, back_rc.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data);
glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data);
if (GL_REPORT_ERROR() == GL_NO_ERROR)
{
if (!s_bLastFrameDumped)
@ -1348,6 +1367,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
s_bLastFrameDumped = false;
}
#endif
// Finish up the current frame, print some stats
OpenGL_Update(); // just updates the render window position and the backbuffer size
bool xfbchanged = false;
@ -1364,38 +1384,47 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
}
bool WindowResized = false;
int W = (int)OpenGL_GetBackbufferWidth(), H = (int)OpenGL_GetBackbufferHeight();
if (W != s_backbuffer_width || H != s_backbuffer_height)
int W = (int)OpenGL_GetBackbufferWidth();
int H = (int)OpenGL_GetBackbufferHeight();
if (W != s_backbuffer_width || H != s_backbuffer_height || s_LastEFBScale != g_ActiveConfig.iEFBScale)
{
WindowResized = true;
s_backbuffer_width = W;
s_backbuffer_height = H;
s_LastEFBScale = g_ActiveConfig.iEFBScale;
}
if( xfbchanged || WindowResized)
if (xfbchanged || WindowResized)
{
TargetRectangle dst_rect;
ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect);
xScale = 1.0f;
yScale = 1.0f;
if(!g_ActiveConfig.bNativeResolution)
if(g_ActiveConfig.bUseRealXFB)
{
if (g_ActiveConfig.b2xResolution)
{
xScale = 2.0f;
yScale = 2.0f;
}
else
{
xScale = (float)(dst_rect.right - dst_rect.left) / (float)s_XFB_width;
yScale = (float)(dst_rect.bottom - dst_rect.top) / (float)s_XFB_height;
}
xScale = 1.0f;
yScale = 1.0f;
}
else
{
xScale = (float)(dst_rect.right - dst_rect.left) / (float)s_XFB_width;
yScale = (float)(dst_rect.bottom - dst_rect.top) / (float)s_XFB_height;
}
EFBxScale = ceilf(xScale);
EFByScale = ceilf(yScale);
switch(s_LastEFBScale)
{
case 0:
EFBxScale = xScale;
EFByScale = yScale;
break;
case 1:
EFBxScale = ceilf(xScale);
EFByScale = ceilf(yScale);
break;
default:
EFBxScale = g_ActiveConfig.iEFBScale - 1;
EFByScale = EFBxScale;
break;
};
int m_newFrameBufferWidth = EFB_WIDTH * EFBxScale;
int m_newFrameBufferHeight = EFB_HEIGHT * EFByScale;
@ -1405,6 +1434,9 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
s_target_width = m_newFrameBufferWidth;
s_target_height = m_newFrameBufferHeight;
s_Fulltarget_width = s_target_width;
s_Fulltarget_height = s_target_height;
g_framebufferManager.Shutdown();
g_framebufferManager.Init(s_target_width, s_target_height,
s_MSAASamples, s_MSAACoverageSamples);
@ -1617,23 +1649,6 @@ void Renderer::SetScreenshot(const char *filename)
s_criticalScreenshot.Leave();
}
// For the OSD menu's live resolution change
bool Renderer::Allow2x()
{
if (GetFrameBufferWidth() >= 1280 && GetFrameBufferHeight() >= 960)
return true;
else
return false;
}
bool Renderer::AllowCustom()
{
if (GetCustomWidth() <= GetFrameBufferWidth() && GetCustomHeight() <= GetFrameBufferHeight())
return true;
else
return false;
}
void Renderer::FlipImageData(u8 *data, int w, int h)
{
// Flip image upside down. Damn OpenGL.