VideoCommon: move ViewportCorrection into VideoCommon

D3D doesn't allow bigger viewports than rendertargets. But flipper does, so the viewport will be clipped and the transformation matrix will be changed.
This was done in the D3D backend itself. This is now moved into VideoCommon. This don't reduce code, but in this way, VideoCommon doesn't depend on the backends.
This commit is contained in:
degasus 2013-10-14 15:16:42 +02:00
parent 0002236e3e
commit 3151d8709c
10 changed files with 92 additions and 63 deletions

View File

@ -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 // Called from VertexShaderManager
void Renderer::UpdateViewport(Matrix44& vpCorrection) void Renderer::UpdateViewport()
{ {
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
// [0] = width/2 // [0] = width/2
@ -513,34 +492,26 @@ void Renderer::UpdateViewport(Matrix44& vpCorrection)
int scissorXOff = bpmem.scissorOffset.x * 2; int scissorXOff = bpmem.scissorOffset.x * 2;
int scissorYOff = bpmem.scissorOffset.y * 2; int scissorYOff = bpmem.scissorOffset.y * 2;
float intendedX = Renderer::EFBToScaledXf(xfregs.viewport.xOrig - xfregs.viewport.wd - scissorXOff); float X = Renderer::EFBToScaledXf(xfregs.viewport.xOrig - xfregs.viewport.wd - scissorXOff);
float intendedY = Renderer::EFBToScaledYf(xfregs.viewport.yOrig + xfregs.viewport.ht - scissorYOff); float Y = Renderer::EFBToScaledYf(xfregs.viewport.yOrig + xfregs.viewport.ht - scissorYOff);
float intendedWd = Renderer::EFBToScaledXf(2.0f * xfregs.viewport.wd); float Wd = Renderer::EFBToScaledXf(2.0f * xfregs.viewport.wd);
float intendedHt = Renderer::EFBToScaledYf(-2.0f * xfregs.viewport.ht); float Ht = Renderer::EFBToScaledYf(-2.0f * xfregs.viewport.ht);
if (intendedWd < 0.f) if (Wd < 0.0f)
{ {
intendedX += intendedWd; X += Wd;
intendedWd = -intendedWd; Wd = -Wd;
} }
if (intendedHt < 0.f) if (Ht < 0.0f)
{ {
intendedY += intendedHt; Y += Ht;
intendedHt = -intendedHt; Ht = -Ht;
} }
// In D3D, the viewport rectangle must fit within the render target. // In D3D, the viewport rectangle must fit within the render target.
float X = (intendedX >= 0.f) ? intendedX : 0.f; X = (X >= 0.f) ? X : 0.f;
float Y = (intendedY >= 0.f) ? intendedY : 0.f; Y = (Y >= 0.f) ? Y : 0.f;
float Wd = (X + intendedWd <= GetTargetWidth()) ? intendedWd : (GetTargetWidth() - X); Wd = (X + Wd <= GetTargetWidth()) ? Wd : (GetTargetWidth() - X);
float Ht = (Y + intendedHt <= GetTargetHeight()) ? intendedHt : (GetTargetHeight() - Y); Ht = (Y + Ht <= GetTargetHeight()) ? Ht : (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);
// 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 // 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, D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y,

View File

@ -46,7 +46,7 @@ public:
void ReinterpretPixelData(unsigned int convtype); void ReinterpretPixelData(unsigned int convtype);
void UpdateViewport(Matrix44& vpCorrection); void UpdateViewport();
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc); bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);

View File

@ -90,6 +90,7 @@ void InitBackendInfo()
g_Config.backend_info.bSupportsFormatReinterpretation = true; g_Config.backend_info.bSupportsFormatReinterpretation = true;
g_Config.backend_info.bSupportsPixelLighting = true; g_Config.backend_info.bSupportsPixelLighting = true;
g_Config.backend_info.bSupportsPrimitiveRestart = true; g_Config.backend_info.bSupportsPrimitiveRestart = true;
g_Config.backend_info.bSupportsOversizedViewports = false;
IDXGIFactory* factory; IDXGIFactory* factory;
IDXGIAdapter* ad; IDXGIAdapter* ad;

View File

@ -1093,7 +1093,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
} }
// Called from VertexShaderManager // Called from VertexShaderManager
void Renderer::UpdateViewport(Matrix44& vpCorrection) void Renderer::UpdateViewport()
{ {
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
// [0] = width/2 // [0] = width/2
@ -1124,9 +1124,6 @@ void Renderer::UpdateViewport(Matrix44& vpCorrection)
Height *= -1; Height *= -1;
} }
// OpenGL does not require any viewport correct
Matrix44::LoadIdentity(vpCorrection);
// Update the view port // Update the view port
if(g_ogl_config.bSupportViewportFloat) if(g_ogl_config.bSupportViewportFloat)
{ {

View File

@ -78,7 +78,7 @@ public:
void ReinterpretPixelData(unsigned int convtype); void ReinterpretPixelData(unsigned int convtype);
void UpdateViewport(Matrix44& vpCorrection); void UpdateViewport();
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc); bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);

View File

@ -146,6 +146,7 @@ void InitBackendInfo()
g_Config.backend_info.bSupportsFormatReinterpretation = true; g_Config.backend_info.bSupportsFormatReinterpretation = true;
g_Config.backend_info.bSupportsPixelLighting = 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.bSupportsEarlyZ = true; // is gpu dependent and must be set in renderer
g_Config.backend_info.bSupportsOversizedViewports = true;
// aamodes // aamodes
const char* caamodes[] = {_trans("None"), "2x", "4x", "8x", "8x CSAA", "8xQ CSAA", "16x CSAA", "16xQ CSAA", "4x SSAA"}; const char* caamodes[] = {_trans("None"), "2x", "4x", "8x", "8x CSAA", "8xQ CSAA", "16x CSAA", "16xQ CSAA", "4x SSAA"};

View File

@ -520,8 +520,8 @@ void Renderer::RecordVideoMemory()
FifoRecorder::GetInstance().SetVideoMemory(bpMem, cpMem, xfMem, xfRegs, sizeof(XFRegisters) / 4); 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) if (xfregs.viewport.wd != 0 && xfregs.viewport.ht != 0)
g_renderer->UpdateViewport(vpCorrection); g_renderer->UpdateViewport();
} }

View File

@ -108,7 +108,7 @@ public:
// Finish up the current frame, print some stats // 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 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; virtual bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc) = 0;
@ -163,6 +163,6 @@ private:
extern Renderer *g_renderer; extern Renderer *g_renderer;
void UpdateViewport(Matrix44& vpCorrection); void UpdateViewport();
#endif // _COMMON_RENDERBASE_H_ #endif // _COMMON_RENDERBASE_H_

View File

@ -39,13 +39,6 @@ static float s_fViewRotation[2];
VertexShaderConstants VertexShaderManager::constants; VertexShaderConstants VertexShaderManager::constants;
bool VertexShaderManager::dirty; bool VertexShaderManager::dirty;
void UpdateViewport(Matrix44& vpCorrection);
void UpdateViewportWithCorrection()
{
UpdateViewport(s_viewportCorrection);
}
struct ProjectionHack struct ProjectionHack
{ {
float sign; float sign;
@ -130,6 +123,65 @@ void UpdateProjectionHack(int iPhackvalue[], std::string sPhackvalue[])
g_ProjHack3 = bProjHack3; 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 UpdateViewportWithCorrection()
{
// TODO: get rid of this function
ViewportCorrectionMatrix(s_viewportCorrection);
UpdateViewport();
}
void VertexShaderManager::Init() void VertexShaderManager::Init()
{ {
Dirty(); Dirty();
@ -330,9 +382,15 @@ void VertexShaderManager::SetConstants()
constants.depthparams[3] = 1.f / g_renderer->EFBToScaledY(ceilf(-2.0f * xfregs.viewport.ht)); constants.depthparams[3] = 1.f / g_renderer->EFBToScaledY(ceilf(-2.0f * xfregs.viewport.ht));
dirty = true; dirty = true;
// This is so implementation-dependent that we can't have it here. // This is so implementation-dependent that we can't have it here.
UpdateViewport(s_viewportCorrection); UpdateViewport();
// Update projection if the viewport isn't 1:1 useable
if(!g_ActiveConfig.backend_info.bSupportsOversizedViewports)
{
ViewportCorrectionMatrix(s_viewportCorrection);
bProjectionChanged = true; bProjectionChanged = true;
} }
}
if (bProjectionChanged) if (bProjectionChanged)
{ {

View File

@ -153,6 +153,7 @@ struct VideoConfig
bool bSupportsPixelLighting; bool bSupportsPixelLighting;
bool bSupportsPrimitiveRestart; bool bSupportsPrimitiveRestart;
bool bSupportsSeparateAlphaFunction; bool bSupportsSeparateAlphaFunction;
bool bSupportsOversizedViewports;
bool bSupportsGLSLUBO; // needed by PixelShaderGen, so must stay in VideoCommon bool bSupportsGLSLUBO; // needed by PixelShaderGen, so must stay in VideoCommon
bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon
} backend_info; } backend_info;