mirror of https://github.com/PCSX2/pcsx2.git
Merge pull request #1234 from PCSX2-Alpha/Time_Crisis
GSDX: Improve CRTC width detection
This commit is contained in:
commit
60e0f3b9b5
|
@ -1275,17 +1275,13 @@ enum stateType {ST_WRITE, ST_TRANSFER, ST_VSYNC};
|
|||
// default gs config settings
|
||||
#define DEFAULT_EXTRA_RENDERING_THREADS 2
|
||||
|
||||
// GS Video modes macros
|
||||
#define Vmode_VESA_DTV (m_regs->SMODE1.CMOD == 0)
|
||||
#define Vmode_NTSC (m_regs->SMODE1.CMOD == 2)
|
||||
#define Vmode_PAL (m_regs->SMODE1.CMOD == 3)
|
||||
#define Vmode_VESA_1A (m_regs->SMODE1.LC == 15 && Vmode_VESA_DTV)
|
||||
#define Vmode_VESA_1C (m_regs->SMODE1.LC == 28 && Vmode_VESA_DTV)
|
||||
#define Vmode_VESA_2B (m_regs->SMODE1.LC == 71 && Vmode_VESA_DTV)
|
||||
#define Vmode_VESA_2D (m_regs->SMODE1.LC == 44 && Vmode_VESA_DTV)
|
||||
#define Vmode_VESA_3B (m_regs->SMODE1.LC == 58 && Vmode_VESA_DTV)
|
||||
#define Vmode_VESA_3D (m_regs->SMODE1.LC == 35 && Vmode_VESA_DTV)
|
||||
#define Vmode_VESA_4A (m_regs->SMODE1.LC == 8 && Vmode_VESA_DTV)
|
||||
#define Vmode_VESA_4B (m_regs->SMODE1.LC == 10 && Vmode_VESA_DTV)
|
||||
#define Vmode_DTV_480P (m_regs->SMODE1.LC == 32 && Vmode_VESA_DTV)
|
||||
#define Vmode_DTV_720P_1080I (m_regs->SMODE1.LC == 22 && Vmode_VESA_DTV)
|
||||
enum class GSVideoMode : uint8
|
||||
{
|
||||
Unknown,
|
||||
NTSC,
|
||||
PAL,
|
||||
VESA,
|
||||
DTV_480P,
|
||||
DTV_720P,
|
||||
DTV_1080I
|
||||
};
|
||||
|
|
|
@ -99,7 +99,7 @@ bool GSRenderer::Merge(int field)
|
|||
GSVector4i fr[2];
|
||||
GSVector4i dr[2];
|
||||
|
||||
int baseline = INT_MAX;
|
||||
GSVector2i baseline = {INT_MAX, INT_MAX};
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
|
@ -110,7 +110,8 @@ bool GSRenderer::Merge(int field)
|
|||
fr[i] = GetFrameRect(i);
|
||||
dr[i] = GetDisplayRect(i);
|
||||
|
||||
baseline = min(dr[i].top, baseline);
|
||||
baseline.x = min(dr[i].left, baseline.x);
|
||||
baseline.y = min(dr[i].top, baseline.y);
|
||||
|
||||
//printf("[%d]: %d %d %d %d, %d %d %d %d\n", i, fr[i].x,fr[i].y,fr[i].z,fr[i].w , dr[i].x,dr[i].y,dr[i].z,dr[i].w);
|
||||
}
|
||||
|
@ -222,9 +223,12 @@ bool GSRenderer::Merge(int field)
|
|||
|
||||
GSVector2 off(0, 0);
|
||||
|
||||
if(dr[i].top - baseline >= 4) // 2?
|
||||
// Time Crisis 2/3 uses two side by side images when in split screen mode.
|
||||
off.x = tex[i]->GetScale().x * (dr[i].left - baseline.x);
|
||||
|
||||
if(dr[i].top - baseline.y >= 4) // 2?
|
||||
{
|
||||
off.y = tex[i]->GetScale().y * (dr[i].top - baseline);
|
||||
off.y = tex[i]->GetScale().y * (dr[i].top - baseline.y);
|
||||
|
||||
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD)
|
||||
{
|
||||
|
|
|
@ -69,7 +69,7 @@ public:
|
|||
virtual bool CanUpscale() {return false;}
|
||||
virtual int GetUpscaleMultiplier() {return 1;}
|
||||
virtual GSVector2i GetInternalResolution() {
|
||||
return GSVector2i(GetDisplayRect().width(), GetDisplayRect().height());
|
||||
return GetOutputRect();
|
||||
}
|
||||
void SetAspectRatio(int aspect) {m_aspectratio = aspect;}
|
||||
void SetVSync(bool enabled);
|
||||
|
|
|
@ -138,7 +138,7 @@ int GSRendererHW::GetUpscaleMultiplier()
|
|||
}
|
||||
|
||||
GSVector2i GSRendererHW::GetInternalResolution() {
|
||||
GSVector2i dr(GetDisplayRect().width(), GetDisplayRect().height());
|
||||
GSVector2i dr = GetOutputRect();
|
||||
|
||||
if (m_upscale_multiplier)
|
||||
return GSVector2i(dr.x * m_upscale_multiplier, dr.y * m_upscale_multiplier);
|
||||
|
|
|
@ -348,52 +348,96 @@ void GSState::ResetHandlers()
|
|||
SetMultithreaded(m_mt);
|
||||
}
|
||||
|
||||
bool GSState::isinterlaced()
|
||||
{
|
||||
return !!m_regs->SMODE2.INT;
|
||||
}
|
||||
|
||||
GSVideoMode GSState::GetVideoMode()
|
||||
{
|
||||
// TODO: Get confirmation of videomode from SYSCALL ? not necessary but would be nice.
|
||||
|
||||
GSVideoMode videomode = GSVideoMode::Unknown;
|
||||
uint8 Colorburst = m_regs->SMODE1.CMOD; // Subcarrier frequency
|
||||
uint8 PLL_Divider = m_regs->SMODE1.LC; // Phased lock loop divider
|
||||
|
||||
switch (Colorburst)
|
||||
{
|
||||
case 0:
|
||||
if (isinterlaced() && PLL_Divider == 22)
|
||||
videomode = GSVideoMode::DTV_1080I;
|
||||
|
||||
else if (!isinterlaced() && PLL_Divider == 22)
|
||||
videomode = GSVideoMode::DTV_720P;
|
||||
|
||||
else if (!isinterlaced() && PLL_Divider == 32)
|
||||
videomode = GSVideoMode::DTV_480P; // TODO: 576P will also be reported as 480P, find some way to differeniate.
|
||||
|
||||
else
|
||||
videomode = GSVideoMode::VESA;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
videomode = GSVideoMode::NTSC; break;
|
||||
|
||||
case 3:
|
||||
videomode = GSVideoMode::PAL; break;
|
||||
}
|
||||
|
||||
return videomode;
|
||||
}
|
||||
|
||||
GSVector4i GSState::GetDisplayRect(int i)
|
||||
{
|
||||
if(i < 0) i = IsEnabled(1) ? 1 : 0;
|
||||
int height = (m_regs->DISP[i].DISPLAY.DH + 1) / (m_regs->DISP[i].DISPLAY.MAGV + 1);
|
||||
int width = (m_regs->DISP[i].DISPLAY.DW + 1) / (m_regs->DISP[i].DISPLAY.MAGH + 1);
|
||||
GSVector4i r;
|
||||
|
||||
GSVideoMode videomode = GetVideoMode();
|
||||
GSVector2i magnification (m_regs->DISP[i].DISPLAY.MAGH + 1, m_regs->DISP[i].DISPLAY.MAGV + 1);
|
||||
int width = (m_regs->DISP[i].DISPLAY.DW + 1) / magnification.x;
|
||||
int height = (m_regs->DISP[i].DISPLAY.DH + 1) / magnification.y;
|
||||
|
||||
//Some games (such as Pool Paradise) use alternate line reading and provide a massive height which is really half.
|
||||
if (height > 640 && !Vmode_VESA_DTV)
|
||||
if (height > 640 && videomode < GSVideoMode::VESA)
|
||||
{
|
||||
height /= 2;
|
||||
}
|
||||
|
||||
r.left = m_regs->DISP[i].DISPLAY.DX / (m_regs->DISP[i].DISPLAY.MAGH + 1);
|
||||
r.top = m_regs->DISP[i].DISPLAY.DY / (m_regs->DISP[i].DISPLAY.MAGV + 1);
|
||||
r.right = r.left + width;
|
||||
r.bottom = r.top + height;
|
||||
// Set up the display rectangle based on the values obtained from DISPLAY registers
|
||||
GSVector4i rectangle;
|
||||
rectangle.left = m_regs->DISP[i].DISPLAY.DX / magnification.x;
|
||||
rectangle.top = m_regs->DISP[i].DISPLAY.DY / magnification.y;
|
||||
rectangle.right = rectangle.left + width;
|
||||
rectangle.bottom = rectangle.top + height;
|
||||
|
||||
// Useful for debugging games:
|
||||
//printf("DW: %d , DH: %d , left: %d , right: %d , top: %d , down: %d , MAGH: %d , MAGV: %d\n", m_regs->DISP[i].DISPLAY.DW, m_regs->DISP[i].DISPLAY.DH, r.left, r.right, r.top, r.bottom , m_regs->DISP[i].DISPLAY.MAGH,m_regs->DISP[i].DISPLAY.MAGV);
|
||||
|
||||
return r;
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
GSVector4i GSState::GetFrameRect(int i)
|
||||
{
|
||||
if (i < 0) i = IsEnabled(1) ? 1 : 0;
|
||||
|
||||
GSVector4i r = GetDisplayRect(i);
|
||||
GSVector4i rectangle = GetDisplayRect(i);
|
||||
GSVideoMode videomode = GetVideoMode();
|
||||
|
||||
int w = r.width();
|
||||
int h = r.height();
|
||||
int w = rectangle.width();
|
||||
int h = rectangle.height();
|
||||
|
||||
// Limit games to standard NTSC resolutions. games with 512X512 (PAL resolution) on NTSC video mode produces black border on the bottom.
|
||||
// 512 X 448 is the resolution generally used by NTSC, saturating the height value seems to get rid of the black borders.
|
||||
// Though it's quite a bad hack as it affects binaries which are patched to run on a non-native video mode.
|
||||
if (Vmode_NTSC && h > 448 && w < 640 && m_NTSC_Saturation)
|
||||
if (videomode == GSVideoMode::NTSC && h > 448 && w < 640 && m_NTSC_Saturation)
|
||||
h = 448;
|
||||
|
||||
if (m_regs->SMODE2.INT && m_regs->SMODE2.FFMD && h > 1)
|
||||
if (isinterlaced() && m_regs->SMODE2.FFMD && h > 1)
|
||||
h >>= 1;
|
||||
|
||||
r.left = m_regs->DISP[i].DISPFB.DBX;
|
||||
r.top = m_regs->DISP[i].DISPFB.DBY;
|
||||
r.right = r.left + w;
|
||||
r.bottom = r.top + h;
|
||||
rectangle.left = m_regs->DISP[i].DISPFB.DBX;
|
||||
rectangle.top = m_regs->DISP[i].DISPFB.DBY;
|
||||
rectangle.right = rectangle.left + w;
|
||||
rectangle.bottom = rectangle.top + h;
|
||||
|
||||
/*static GSVector4i old_r = (GSVector4i) 0;
|
||||
if ((old_r.left != r.left) || (old_r.right != r.right) || (old_r.top != r.top) || (old_r.right != r.right)){
|
||||
|
@ -401,7 +445,7 @@ GSVector4i GSState::GetFrameRect(int i)
|
|||
}
|
||||
old_r = r;*/
|
||||
|
||||
return r;
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
GSVector2i GSState::GetDeviceSize(int i)
|
||||
|
@ -414,25 +458,35 @@ GSVector2i GSState::GetDeviceSize(int i)
|
|||
|
||||
if(i < 0) i = IsEnabled(1) ? 1 : 0;
|
||||
|
||||
GSVector4i r = GetDisplayRect(i);
|
||||
GSVector4i rectangle = GetDisplayRect(i);
|
||||
GSVector2i DeviceSize(rectangle.width(), rectangle.height());
|
||||
|
||||
int w = r.width();
|
||||
int h = r.height();
|
||||
if(isinterlaced() && m_regs->SMODE2.FFMD && DeviceSize.y > 1)
|
||||
DeviceSize.y >>= 1;
|
||||
|
||||
/*if(h == 2 * 416 || h == 2 * 448 || h == 2 * 512)
|
||||
{
|
||||
h /= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
h = (m_regs->SMODE1.CMOD & 1) ? 512 : 448;
|
||||
}*/
|
||||
return DeviceSize;
|
||||
}
|
||||
|
||||
//Fixme : Just slightly better than the hack above
|
||||
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD && h > 1)
|
||||
h >>= 1;
|
||||
GSVector2i GSState::GetOutputRect()
|
||||
{
|
||||
GSVector2i Merged_Rectangle(GetDisplayRect().width(), GetDisplayRect().height());
|
||||
GSVector4i Rectangle[2] = { GetDisplayRect(0) , GetDisplayRect(1) };
|
||||
int width[2] = { Rectangle[0].width() , Rectangle[1].width() };
|
||||
int height[2] = { Rectangle[0].height() , Rectangle[1].height() };
|
||||
int x_offset[2] = { Rectangle[0].left , Rectangle[1].left };
|
||||
int y_offset[2] = { Rectangle[0].top , Rectangle[1].top };
|
||||
|
||||
if (!(IsEnabled(0) && IsEnabled(1)))
|
||||
return Merged_Rectangle;
|
||||
|
||||
if (width[0] == width[1] && width[0] == std::max(x_offset[0], x_offset[1]) - std::min(x_offset[0], x_offset[1]))
|
||||
Merged_Rectangle.x <<= 1;
|
||||
|
||||
if (height[0] == height[1] && height[0] == std::max(y_offset[0], y_offset[1]) - std::min(y_offset[0], y_offset[1]))
|
||||
Merged_Rectangle.y <<= 1;
|
||||
|
||||
return Merged_Rectangle;
|
||||
|
||||
return GSVector2i(w, h);
|
||||
}
|
||||
|
||||
bool GSState::IsEnabled(int i)
|
||||
|
@ -454,29 +508,24 @@ bool GSState::IsEnabled(int i)
|
|||
float GSState::GetTvRefreshRate()
|
||||
{
|
||||
float vertical_frequency = 0;
|
||||
GSVideoMode videomode = GetVideoMode();
|
||||
|
||||
switch (m_regs->SMODE1.CMOD)
|
||||
//TODO: Check vertical frequencies for VESA video modes, old ones were untested.
|
||||
|
||||
switch (videomode)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (Vmode_VESA_1A) vertical_frequency = 59.94f;
|
||||
if (Vmode_VESA_1C) vertical_frequency = 75;
|
||||
if (Vmode_VESA_2B) vertical_frequency = 60.317f;
|
||||
if (Vmode_VESA_2D) vertical_frequency = 75;
|
||||
if (Vmode_VESA_3B) vertical_frequency = 60.004f;
|
||||
if (Vmode_VESA_3D) vertical_frequency = 75.029f;
|
||||
if (Vmode_VESA_4A) vertical_frequency = 60.020f;
|
||||
if (Vmode_VESA_4B) vertical_frequency = 75.025f;
|
||||
if (Vmode_DTV_480P) vertical_frequency = 59.94f;
|
||||
if (Vmode_DTV_720P_1080I) vertical_frequency = 60;
|
||||
break;
|
||||
}
|
||||
case GSVideoMode::NTSC: case GSVideoMode::DTV_480P:
|
||||
vertical_frequency = (60 / 1.001f); break;
|
||||
|
||||
case 2: vertical_frequency = (60 / 1.001f); //NTSC
|
||||
break;
|
||||
case 3: vertical_frequency = 50; //PAL
|
||||
break;
|
||||
default: ASSERT(0);
|
||||
case GSVideoMode::PAL:
|
||||
vertical_frequency = 50; break;
|
||||
|
||||
case GSVideoMode::DTV_720P: case GSVideoMode::DTV_1080I:
|
||||
vertical_frequency = 60; break;
|
||||
|
||||
default:
|
||||
if (videomode == GSVideoMode::Unknown)
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
return vertical_frequency;
|
||||
|
|
|
@ -239,8 +239,11 @@ public:
|
|||
GSVector4i GetDisplayRect(int i = -1);
|
||||
GSVector4i GetFrameRect(int i = -1);
|
||||
GSVector2i GetDeviceSize(int i = -1);
|
||||
GSVector2i GetOutputRect(); //Final Output rectangle after passing through merge circuit.
|
||||
GSVideoMode GetVideoMode();
|
||||
|
||||
bool IsEnabled(int i);
|
||||
bool isinterlaced();
|
||||
|
||||
float GetTvRefreshRate();
|
||||
|
||||
|
|
Loading…
Reference in New Issue