diff --git a/Source/Core/VideoBackends/D3D/Src/Render.cpp b/Source/Core/VideoBackends/D3D/Src/Render.cpp index 7f9218de11..3cdd703fba 100644 --- a/Source/Core/VideoBackends/D3D/Src/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Src/Render.cpp @@ -477,30 +477,9 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) } } -// Viewport correction: -// Say you want a viewport at (ix, iy) with size (iw, ih), -// but your viewport must be clamped at (ax, ay) with size (aw, ah). -// Just multiply the projection matrix with the following to get the same -// effect: -// [ (iw/aw) 0 0 ((iw - 2*(ax-ix)) / aw - 1) ] -// [ 0 (ih/ah) 0 ((-ih + 2*(ay-iy)) / ah + 1) ] -// [ 0 0 1 0 ] -// [ 0 0 0 1 ] -static void ViewportCorrectionMatrix(Matrix44& result, - float ix, float iy, float iw, float ih, // Intended viewport (x, y, width, height) - float ax, float ay, float aw, float ah) // Actual viewport (x, y, width, height) -{ - Matrix44::LoadIdentity(result); - if (aw == 0.f || ah == 0.f) - return; - result.data[4*0+0] = iw / aw; - result.data[4*0+3] = (iw - 2.f * (ax - ix)) / aw - 1.f; - result.data[4*1+1] = ih / ah; - result.data[4*1+3] = (-ih + 2.f * (ay - iy)) / ah + 1.f; -} // Called from VertexShaderManager -void Renderer::UpdateViewport(Matrix44& vpCorrection) +void Renderer::UpdateViewport() { // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) // [0] = width/2 @@ -513,34 +492,26 @@ void Renderer::UpdateViewport(Matrix44& vpCorrection) int scissorXOff = bpmem.scissorOffset.x * 2; int scissorYOff = bpmem.scissorOffset.y * 2; - float intendedX = Renderer::EFBToScaledXf(xfregs.viewport.xOrig - xfregs.viewport.wd - scissorXOff); - float intendedY = Renderer::EFBToScaledYf(xfregs.viewport.yOrig + xfregs.viewport.ht - scissorYOff); - float intendedWd = Renderer::EFBToScaledXf(2.0f * xfregs.viewport.wd); - float intendedHt = Renderer::EFBToScaledYf(-2.0f * xfregs.viewport.ht); - if (intendedWd < 0.f) + float X = Renderer::EFBToScaledXf(xfregs.viewport.xOrig - xfregs.viewport.wd - scissorXOff); + float Y = Renderer::EFBToScaledYf(xfregs.viewport.yOrig + xfregs.viewport.ht - scissorYOff); + float Wd = Renderer::EFBToScaledXf(2.0f * xfregs.viewport.wd); + float Ht = Renderer::EFBToScaledYf(-2.0f * xfregs.viewport.ht); + if (Wd < 0.0f) { - intendedX += intendedWd; - intendedWd = -intendedWd; + X += Wd; + Wd = -Wd; } - if (intendedHt < 0.f) + if (Ht < 0.0f) { - intendedY += intendedHt; - intendedHt = -intendedHt; + Y += Ht; + Ht = -Ht; } // In D3D, the viewport rectangle must fit within the render target. - float X = (intendedX >= 0.f) ? intendedX : 0.f; - float Y = (intendedY >= 0.f) ? intendedY : 0.f; - float Wd = (X + intendedWd <= GetTargetWidth()) ? intendedWd : (GetTargetWidth() - X); - float Ht = (Y + intendedHt <= GetTargetHeight()) ? intendedHt : (GetTargetHeight() - Y); - - // If GX viewport is off the render target, we must clamp our viewport - // within the bounds. Use the correction matrix to compensate. - ViewportCorrectionMatrix(vpCorrection, - intendedX, intendedY, - intendedWd, intendedHt, - X, Y, - Wd, Ht); + X = (X >= 0.f) ? X : 0.f; + Y = (Y >= 0.f) ? Y : 0.f; + Wd = (X + Wd <= GetTargetWidth()) ? Wd : (GetTargetWidth() - X); + Ht = (Y + Ht <= GetTargetHeight()) ? Ht : (GetTargetHeight() - Y); // Some games set invalid values for z-min and z-max so fix them to the max and min allowed and let the shaders do this work D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y, @@ -1055,10 +1026,10 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbHeight,const EFBRectangle& r } // begin next frame - Renderer::RestoreAPIState(); + RestoreAPIState(); D3D::BeginFrame(); D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); - VertexShaderManager::SetViewportChanged(); + UpdateViewport(); Core::Callback_VideoCopiedToXFB(XFBWrited || (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB)); XFBWrited = false; @@ -1078,7 +1049,7 @@ void Renderer::RestoreAPIState() D3D::stateman->PopBlendState(); D3D::stateman->PopDepthState(); D3D::stateman->PopRasterizerState(); - VertexShaderManager::SetViewportChanged(); + UpdateViewport(); BPFunctions::SetScissor(); } diff --git a/Source/Core/VideoBackends/D3D/Src/Render.h b/Source/Core/VideoBackends/D3D/Src/Render.h index 39b5b90d81..12e5b595d3 100644 --- a/Source/Core/VideoBackends/D3D/Src/Render.h +++ b/Source/Core/VideoBackends/D3D/Src/Render.h @@ -46,7 +46,7 @@ public: void ReinterpretPixelData(unsigned int convtype); - void UpdateViewport(Matrix44& vpCorrection); + void UpdateViewport(); bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc); diff --git a/Source/Core/VideoBackends/D3D/Src/main.cpp b/Source/Core/VideoBackends/D3D/Src/main.cpp index 989fb2ef91..0514106da5 100644 --- a/Source/Core/VideoBackends/D3D/Src/main.cpp +++ b/Source/Core/VideoBackends/D3D/Src/main.cpp @@ -90,6 +90,7 @@ void InitBackendInfo() g_Config.backend_info.bSupportsFormatReinterpretation = true; g_Config.backend_info.bSupportsPixelLighting = true; g_Config.backend_info.bSupportsPrimitiveRestart = true; + g_Config.backend_info.bSupportsOversizedViewports = false; IDXGIFactory* factory; IDXGIAdapter* ad; diff --git a/Source/Core/VideoBackends/OGL/Src/GLUtil.cpp b/Source/Core/VideoBackends/OGL/Src/GLUtil.cpp index 256b30ace8..eb05e8cddc 100644 --- a/Source/Core/VideoBackends/OGL/Src/GLUtil.cpp +++ b/Source/Core/VideoBackends/OGL/Src/GLUtil.cpp @@ -10,7 +10,6 @@ #include "ConfigManager.h" #include "Render.h" -#include "VertexShaderManager.h" #include "GLUtil.h" diff --git a/Source/Core/VideoBackends/OGL/Src/Render.cpp b/Source/Core/VideoBackends/OGL/Src/Render.cpp index 9234a8a6e2..5c560dc3cd 100644 --- a/Source/Core/VideoBackends/OGL/Src/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Src/Render.cpp @@ -33,7 +33,6 @@ #include "RasterFont.h" #include "VertexShaderGen.h" #include "DLCache.h" -#include "PixelShaderManager.h" #include "ProgramShaderCache.h" #include "VertexShaderManager.h" #include "VertexLoaderManager.h" @@ -1093,7 +1092,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) } // Called from VertexShaderManager -void Renderer::UpdateViewport(Matrix44& vpCorrection) +void Renderer::UpdateViewport() { // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) // [0] = width/2 @@ -1124,9 +1123,6 @@ void Renderer::UpdateViewport(Matrix44& vpCorrection) Height *= -1; } - // OpenGL does not require any viewport correct - Matrix44::LoadIdentity(vpCorrection); - // Update the view port if(g_ogl_config.bSupportViewportFloat) { @@ -1664,7 +1660,7 @@ void Renderer::RestoreAPIState() SetDepthMode(); SetBlendMode(true); SetLogicOpMode(); - VertexShaderManager::SetViewportChanged(); + UpdateViewport(); #ifndef USE_GLES3 glPolygonMode(GL_FRONT_AND_BACK, g_ActiveConfig.bWireFrame ? GL_LINE : GL_FILL); diff --git a/Source/Core/VideoBackends/OGL/Src/Render.h b/Source/Core/VideoBackends/OGL/Src/Render.h index efafb8708d..e30380d627 100644 --- a/Source/Core/VideoBackends/OGL/Src/Render.h +++ b/Source/Core/VideoBackends/OGL/Src/Render.h @@ -78,7 +78,7 @@ public: void ReinterpretPixelData(unsigned int convtype); - void UpdateViewport(Matrix44& vpCorrection); + void UpdateViewport(); bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc); diff --git a/Source/Core/VideoBackends/OGL/Src/TextureCache.cpp b/Source/Core/VideoBackends/OGL/Src/TextureCache.cpp index c3349f5f2c..7810ff00eb 100644 --- a/Source/Core/VideoBackends/OGL/Src/TextureCache.cpp +++ b/Source/Core/VideoBackends/OGL/Src/TextureCache.cpp @@ -30,14 +30,12 @@ #include "ImageWrite.h" #include "MemoryUtil.h" #include "ProgramShaderCache.h" -#include "PixelShaderManager.h" #include "Render.h" #include "Statistics.h" #include "StringUtil.h" #include "TextureCache.h" #include "TextureConverter.h" #include "TextureDecoder.h" -#include "VertexShaderManager.h" #include "VideoConfig.h" namespace OGL @@ -391,7 +389,6 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo } FramebufferManager::SetFramebuffer(0); - VertexShaderManager::SetViewportChanged(); GL_REPORT_ERRORD(); diff --git a/Source/Core/VideoBackends/OGL/Src/TextureConverter.cpp b/Source/Core/VideoBackends/OGL/Src/TextureConverter.cpp index d4ce2eb5bb..05742ddc95 100644 --- a/Source/Core/VideoBackends/OGL/Src/TextureConverter.cpp +++ b/Source/Core/VideoBackends/OGL/Src/TextureConverter.cpp @@ -9,7 +9,6 @@ #include "TextureConversionShader.h" #include "TextureCache.h" #include "ProgramShaderCache.h" -#include "VertexShaderManager.h" #include "FramebufferManager.h" #include "Globals.h" #include "VideoConfig.h" @@ -350,7 +349,6 @@ void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* des EncodeToRamUsingShader(srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false); FramebufferManager::SetFramebuffer(0); - VertexShaderManager::SetViewportChanged(); TextureCache::DisableStage(0); g_renderer->RestoreAPIState(); GL_REPORT_ERRORD(); @@ -426,8 +424,6 @@ void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTextur GL_REPORT_ERRORD(); - VertexShaderManager::SetViewportChanged(); - FramebufferManager::SetFramebuffer(0); g_renderer->RestoreAPIState(); diff --git a/Source/Core/VideoBackends/OGL/Src/main.cpp b/Source/Core/VideoBackends/OGL/Src/main.cpp index b109fcdd8b..07c1fcfc0b 100644 --- a/Source/Core/VideoBackends/OGL/Src/main.cpp +++ b/Source/Core/VideoBackends/OGL/Src/main.cpp @@ -146,6 +146,7 @@ void InitBackendInfo() g_Config.backend_info.bSupportsFormatReinterpretation = true; g_Config.backend_info.bSupportsPixelLighting = true; //g_Config.backend_info.bSupportsEarlyZ = true; // is gpu dependent and must be set in renderer + g_Config.backend_info.bSupportsOversizedViewports = true; // aamodes const char* caamodes[] = {_trans("None"), "2x", "4x", "8x", "8x CSAA", "8xQ CSAA", "16x CSAA", "16xQ CSAA", "4x SSAA"}; diff --git a/Source/Core/VideoCommon/Src/BPFunctions.cpp b/Source/Core/VideoCommon/Src/BPFunctions.cpp index 9f4f4f3060..43623a94a8 100644 --- a/Source/Core/VideoCommon/Src/BPFunctions.cpp +++ b/Source/Core/VideoCommon/Src/BPFunctions.cpp @@ -49,8 +49,6 @@ void SetScissor() TargetRectangle trc = g_renderer->ConvertEFBRectangle(rc); g_renderer->SetScissorRect(trc); - - UpdateViewportWithCorrection(); } void SetLineWidth() diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index ab5789a078..e3ada3c0bf 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -185,6 +185,7 @@ void BPWritten(const BPCmd& bp) case BPMEM_SCISSORBR: // Scissor Rectable Bottom, Right case BPMEM_SCISSOROFFSET: // Scissor Offset SetScissor(); + VertexShaderManager::SetViewportChanged(); break; case BPMEM_LINEPTWIDTH: // Line Width SetLineWidth(); diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp index 3ab9bd6f47..e509ccb980 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.cpp +++ b/Source/Core/VideoCommon/Src/RenderBase.cpp @@ -30,7 +30,6 @@ #include "XFMemory.h" #include "FifoPlayer/FifoRecorder.h" #include "AVIDump.h" -#include "VertexShaderManager.h" #include #include @@ -231,7 +230,6 @@ bool Renderer::CalculateTargetSize(unsigned int framebuffer_width, unsigned int { s_target_width = newEFBWidth; s_target_height = newEFBHeight; - VertexShaderManager::SetViewportChanged(); return true; } return false; @@ -520,8 +518,8 @@ void Renderer::RecordVideoMemory() FifoRecorder::GetInstance().SetVideoMemory(bpMem, cpMem, xfMem, xfRegs, sizeof(XFRegisters) / 4); } -void UpdateViewport(Matrix44& vpCorrection) +void UpdateViewport() { if (xfregs.viewport.wd != 0 && xfregs.viewport.ht != 0) - g_renderer->UpdateViewport(vpCorrection); + g_renderer->UpdateViewport(); } diff --git a/Source/Core/VideoCommon/Src/RenderBase.h b/Source/Core/VideoCommon/Src/RenderBase.h index 06dbd7124e..22d31cde23 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.h +++ b/Source/Core/VideoCommon/Src/RenderBase.h @@ -108,7 +108,7 @@ public: // Finish up the current frame, print some stats virtual void Swap(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& rc,float Gamma = 1.0f) = 0; - virtual void UpdateViewport(Matrix44& vpCorrection) = 0; + virtual void UpdateViewport() = 0; virtual bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc) = 0; @@ -163,6 +163,6 @@ private: extern Renderer *g_renderer; -void UpdateViewport(Matrix44& vpCorrection); +void UpdateViewport(); #endif // _COMMON_RENDERBASE_H_ diff --git a/Source/Core/VideoCommon/Src/TextureConversionShader.cpp b/Source/Core/VideoCommon/Src/TextureConversionShader.cpp index 9b6c8762ff..9e8467fe44 100644 --- a/Source/Core/VideoCommon/Src/TextureConversionShader.cpp +++ b/Source/Core/VideoCommon/Src/TextureConversionShader.cpp @@ -12,7 +12,6 @@ #include "TextureConversionShader.h" #include "TextureDecoder.h" -#include "PixelShaderManager.h" #include "PixelShaderGen.h" #include "BPMemory.h" #include "RenderBase.h" diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.h b/Source/Core/VideoCommon/Src/VertexShaderGen.h index 1143867a25..378f2cd77d 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.h +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.h @@ -39,7 +39,7 @@ #define I_TRANSFORMMATRICES "ctrmtx" #define I_NORMALMATRICES "cnmtx" #define I_POSTTRANSFORMMATRICES "cpostmtx" -#define I_DEPTHPARAMS "cDepth" // farZ, zRange, scaled viewport width, scaled viewport height +#define I_DEPTHPARAMS "cDepth" // farZ, zRange //TODO: get rid of them, they aren't used at all #define C_POSNORMALMATRIX 0 diff --git a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp index e603e6e6c4..6fa22c4b9c 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp @@ -39,13 +39,6 @@ static float s_fViewRotation[2]; VertexShaderConstants VertexShaderManager::constants; bool VertexShaderManager::dirty; -void UpdateViewport(Matrix44& vpCorrection); - -void UpdateViewportWithCorrection() -{ - UpdateViewport(s_viewportCorrection); -} - struct ProjectionHack { float sign; @@ -130,6 +123,58 @@ void UpdateProjectionHack(int iPhackvalue[], std::string sPhackvalue[]) g_ProjHack3 = bProjHack3; } + +// Viewport correction: +// In D3D, the viewport rectangle must fit within the render target. +// Say you want a viewport at (ix, iy) with size (iw, ih), +// but your viewport must be clamped at (ax, ay) with size (aw, ah). +// Just multiply the projection matrix with the following to get the same +// effect: +// [ (iw/aw) 0 0 ((iw - 2*(ax-ix)) / aw - 1) ] +// [ 0 (ih/ah) 0 ((-ih + 2*(ay-iy)) / ah + 1) ] +// [ 0 0 1 0 ] +// [ 0 0 0 1 ] +static void ViewportCorrectionMatrix(Matrix44& result) +{ + int scissorXOff = bpmem.scissorOffset.x * 2; + int scissorYOff = bpmem.scissorOffset.y * 2; + + // TODO: ceil, floor or just cast to int? + // TODO: Directly use the floats instead of rounding them? + float intendedX = xfregs.viewport.xOrig - xfregs.viewport.wd - scissorXOff; + float intendedY = xfregs.viewport.yOrig + xfregs.viewport.ht - scissorYOff; + float intendedWd = 2.0f * xfregs.viewport.wd; + float intendedHt = -2.0f * xfregs.viewport.ht; + + if (intendedWd < 0.f) + { + intendedX += intendedWd; + intendedWd = -intendedWd; + } + if (intendedHt < 0.f) + { + intendedY += intendedHt; + intendedHt = -intendedHt; + } + + // fit to EFB size + float X = (intendedX >= 0.f) ? intendedX : 0.f; + float Y = (intendedY >= 0.f) ? intendedY : 0.f; + float Wd = (X + intendedWd <= EFB_WIDTH) ? intendedWd : (EFB_WIDTH - X); + float Ht = (Y + intendedHt <= EFB_HEIGHT) ? intendedHt : (EFB_HEIGHT - Y); + + Matrix44::LoadIdentity(result); + if (Wd == 0 || Ht == 0) + return; + + result.data[4*0+0] = intendedWd / Wd; + result.data[4*0+3] = (intendedWd - 2.f * (X - intendedX)) / Wd - 1.f; + result.data[4*1+1] = intendedHt / Ht; + result.data[4*1+3] = (-intendedHt + 2.f * (Y - intendedY)) / Ht + 1.f; +} + +void UpdateViewport(); + void VertexShaderManager::Init() { Dirty(); @@ -326,12 +371,16 @@ void VertexShaderManager::SetConstants() bViewportChanged = false; constants.depthparams[0] = xfregs.viewport.farZ / 16777216.0f; constants.depthparams[1] = xfregs.viewport.zRange / 16777216.0f; - constants.depthparams[2] = -1.f / g_renderer->EFBToScaledX(ceilf(2.0f * xfregs.viewport.wd)); - constants.depthparams[3] = 1.f / g_renderer->EFBToScaledY(ceilf(-2.0f * xfregs.viewport.ht)); dirty = true; // This is so implementation-dependent that we can't have it here. - UpdateViewport(s_viewportCorrection); - bProjectionChanged = true; + UpdateViewport(); + + // Update projection if the viewport isn't 1:1 useable + if(!g_ActiveConfig.backend_info.bSupportsOversizedViewports) + { + ViewportCorrectionMatrix(s_viewportCorrection); + bProjectionChanged = true; + } } if (bProjectionChanged) diff --git a/Source/Core/VideoCommon/Src/VertexShaderManager.h b/Source/Core/VideoCommon/Src/VertexShaderManager.h index 60e23902f1..8b5875a8ac 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderManager.h +++ b/Source/Core/VideoCommon/Src/VertexShaderManager.h @@ -12,8 +12,6 @@ class PointerWrap; void UpdateProjectionHack(int iParams[], std::string sParams[]); -void UpdateViewportWithCorrection(); - // The non-API dependent parts. class VertexShaderManager { diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index 890b9b9eda..e717cc463b 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -153,6 +153,7 @@ struct VideoConfig bool bSupportsPixelLighting; bool bSupportsPrimitiveRestart; bool bSupportsSeparateAlphaFunction; + bool bSupportsOversizedViewports; bool bSupportsGLSLUBO; // needed by PixelShaderGen, so must stay in VideoCommon bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon } backend_info;