diff --git a/plugins/GSdx/GS.h b/plugins/GSdx/GS.h index 9df86a1d98..1ca341f214 100644 --- a/plugins/GSdx/GS.h +++ b/plugins/GSdx/GS.h @@ -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 +}; diff --git a/plugins/GSdx/GSRenderer.cpp b/plugins/GSdx/GSRenderer.cpp index 53c7f71014..33102ee9ff 100644 --- a/plugins/GSdx/GSRenderer.cpp +++ b/plugins/GSdx/GSRenderer.cpp @@ -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) { diff --git a/plugins/GSdx/GSRenderer.h b/plugins/GSdx/GSRenderer.h index 78309b2d40..7165dd3743 100644 --- a/plugins/GSdx/GSRenderer.h +++ b/plugins/GSdx/GSRenderer.h @@ -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); diff --git a/plugins/GSdx/GSRendererHW.cpp b/plugins/GSdx/GSRendererHW.cpp index 777832138c..ebeb95cc0c 100644 --- a/plugins/GSdx/GSRendererHW.cpp +++ b/plugins/GSdx/GSRendererHW.cpp @@ -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); diff --git a/plugins/GSdx/GSState.cpp b/plugins/GSdx/GSState.cpp index bdc80a04d0..63f10fa306 100644 --- a/plugins/GSdx/GSState.cpp +++ b/plugins/GSdx/GSState.cpp @@ -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; diff --git a/plugins/GSdx/GSState.h b/plugins/GSdx/GSState.h index ffe74645d6..e50970af69 100644 --- a/plugins/GSdx/GSState.h +++ b/plugins/GSdx/GSState.h @@ -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();