From eadd3c57850ec8b6a9e55f75fa9b546bf99ae130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 5 Aug 2020 10:54:07 +0200 Subject: [PATCH 1/3] Remove the LARGE_VIEWPORTS separate path. The fewer paths the better, all need to work anyway. Required fixing a bug in ShaderUniforms.cpp (used by D3D11 and Vulkan, the two backends that previously exposed LARGE_VIEWPORTS). --- GPU/Common/GPUStateUtils.cpp | 26 ++++++++++++++------------ GPU/Common/ShaderUniforms.cpp | 4 ++-- GPU/D3D11/GPU_D3D11.cpp | 1 - GPU/GPUState.h | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 1 - 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index bf95736774..c2f6931d85 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -648,27 +648,29 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo float hScale = 1.0f; float yOffset = 0.0f; - if (!gstate_c.Supports(GPU_SUPPORTS_LARGE_VIEWPORTS)) { - // If we're within the bounds, we want clipping the viewport way. So leave it be. - if (left < 0.0f || right > renderWidth) { - float overageLeft = std::max(-left, 0.0f); - float overageRight = std::max(right - renderWidth, 0.0f); - // Our center drifted by the difference in overages. - float drift = overageRight - overageLeft; + // If we're within the bounds, we want clipping the viewport way. So leave it be. + { + float overageLeft = std::max(-left, 0.0f); + float overageRight = std::max(right - renderWidth, 0.0f); + // Our center drifted by the difference in overages. + float drift = overageRight - overageLeft; + if (overageLeft != 0.0f || overageRight != 0.0f) { left += overageLeft; right -= overageRight; wScale = vpWidth / (right - left); xOffset = drift / (right - left); } + } - if (top < 0.0f || bottom > renderHeight) { - float overageTop = std::max(-top, 0.0f); - float overageBottom = std::max(bottom - renderHeight, 0.0f); - // Our center drifted by the difference in overages. - float drift = overageBottom - overageTop; + { + float overageTop = std::max(-top, 0.0f); + float overageBottom = std::max(bottom - renderHeight, 0.0f); + // Our center drifted by the difference in overages. + float drift = overageBottom - overageTop; + if (overageTop != 0.0f || overageBottom != 0.0f) { top += overageTop; bottom -= overageBottom; diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index c80ae842ef..5cc61f32e3 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -15,13 +15,13 @@ using namespace Lin; static void ConvertProjMatrixToVulkan(Matrix4x4 &in) { - const Vec3 trans(0, 0, gstate_c.vpZOffset * 0.5f + 0.5f); + const Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f); const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); in.translateAndScale(trans, scale); } static void ConvertProjMatrixToD3D11(Matrix4x4 &in) { - const Vec3 trans(0, 0, gstate_c.vpZOffset * 0.5f + 0.5f); + const Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f); const Vec3 scale(gstate_c.vpWidthScale, -gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); in.translateAndScale(trans, scale); } diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 13cbb442fc..8535d1fb5e 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -143,7 +143,6 @@ void GPU_D3D11::CheckGPUFeatures() { #endif features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; - features |= GPU_SUPPORTS_LARGE_VIEWPORTS; if (draw_->GetDeviceCaps().dualSourceBlend) features |= GPU_SUPPORTS_DUALSOURCE_BLEND; if (draw_->GetDeviceCaps().depthClampSupported) diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 2f33c3fb91..4aac1e9907 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -482,7 +482,7 @@ enum { GPU_SUPPORTS_16BIT_FORMATS = FLAG_BIT(13), GPU_SUPPORTS_DEPTH_CLAMP = FLAG_BIT(14), GPU_SUPPORTS_32BIT_INT_FSHADER = FLAG_BIT(15), - GPU_SUPPORTS_LARGE_VIEWPORTS = FLAG_BIT(16), + // Free bit: 16 GPU_SUPPORTS_ACCURATE_DEPTH = FLAG_BIT(17), GPU_SUPPORTS_VAO = FLAG_BIT(18), GPU_SUPPORTS_ANY_COPY_IMAGE = FLAG_BIT(19), diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 99002e68f4..a912f4b781 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -227,7 +227,6 @@ void GPU_Vulkan::CheckGPUFeatures() { features |= GPU_SUPPORTS_BLEND_MINMAX; features |= GPU_SUPPORTS_ANY_COPY_IMAGE; features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; - features |= GPU_SUPPORTS_LARGE_VIEWPORTS; features |= GPU_SUPPORTS_INSTANCE_RENDERING; features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH; features |= GPU_SUPPORTS_TEXTURE_FLOAT; From 1b2d4dd75dfced5be687e94a20ecac2766d8bf44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 5 Aug 2020 19:03:51 +0200 Subject: [PATCH 2/3] Viewport state conversion: Move the pixel scaling to after the overage clipping. --- GPU/Common/GPUStateUtils.cpp | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index c2f6931d85..46f0b56bc5 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -568,7 +568,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo renderHeightFactor = renderHeight / 272.0f; } - renderX += gstate_c.curRTOffsetX * renderWidthFactor; + renderX = gstate_c.curRTOffsetX; // Scissor int scissorX1 = gstate.getScissorX1(); @@ -576,8 +576,6 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo int scissorX2 = gstate.getScissorX2() + 1; int scissorY2 = gstate.getScissorY2() + 1; - // This is a bit of a hack as the render buffer isn't always that size - // We always scissor on non-buffered so that clears don't spill outside the frame. out.scissorEnable = true; if (scissorX2 < scissorX1 || scissorY2 < scissorY1) { out.scissorX = 0; @@ -585,8 +583,8 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo out.scissorW = 0; out.scissorH = 0; } else { - out.scissorX = renderX + displayOffsetX + scissorX1 * renderWidthFactor; - out.scissorY = renderY + displayOffsetY + scissorY1 * renderHeightFactor; + out.scissorX = (renderX * renderWidthFactor) + displayOffsetX + scissorX1 * renderWidthFactor; + out.scissorY = (renderY * renderHeightFactor) + displayOffsetY + scissorY1 * renderHeightFactor; out.scissorW = (scissorX2 - scissorX1) * renderWidthFactor; out.scissorH = (scissorY2 - scissorY1) * renderHeightFactor; } @@ -598,8 +596,8 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo float offsetY = gstate.getOffsetY(); if (throughmode) { - out.viewportX = renderX + displayOffsetX; - out.viewportY = renderY + displayOffsetY; + out.viewportX = renderX * renderWidthFactor + displayOffsetX; + out.viewportY = renderY * renderHeightFactor + displayOffsetY; out.viewportW = curRTWidth * renderWidthFactor; out.viewportH = curRTHeight * renderHeightFactor; out.depthRangeMin = ToScaledDepthFromIntegerScale(0); @@ -629,12 +627,6 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo float vpWidth = fabsf(gstate_c.vpWidth); float vpHeight = fabsf(gstate_c.vpHeight); - // This multiplication should probably be done after viewport clipping. Would let us very slightly simplify the clipping logic? - vpX0 *= renderWidthFactor; - vpY0 *= renderHeightFactor; - vpWidth *= renderWidthFactor; - vpHeight *= renderHeightFactor; - // We used to apply the viewport here via glstate, but there are limits which vary by driver. // This may mean some games won't work, or at least won't work at higher render resolutions. // So we apply it in the shader instead. @@ -651,7 +643,8 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo // If we're within the bounds, we want clipping the viewport way. So leave it be. { float overageLeft = std::max(-left, 0.0f); - float overageRight = std::max(right - renderWidth, 0.0f); + float overageRight = std::max(right - bufferWidth, 0.0f); + // Our center drifted by the difference in overages. float drift = overageRight - overageLeft; @@ -666,7 +659,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo { float overageTop = std::max(-top, 0.0f); - float overageBottom = std::max(bottom - renderHeight, 0.0f); + float overageBottom = std::max(bottom - bufferHeight, 0.0f); // Our center drifted by the difference in overages. float drift = overageBottom - overageTop; @@ -679,10 +672,10 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo } } - out.viewportX = left + displayOffsetX; - out.viewportY = top + displayOffsetY; - out.viewportW = right - left; - out.viewportH = bottom - top; + out.viewportX = left * renderWidthFactor + displayOffsetX; + out.viewportY = top * renderHeightFactor + displayOffsetY; + out.viewportW = (right - left) * renderWidthFactor; + out.viewportH = (bottom - top) * renderHeightFactor; // The depth viewport parameters are the same, but we handle it a bit differently. // When clipping is enabled, depth is clamped to [0, 65535]. And minz/maxz discard. From fd3a9d420278ddbc0c5ec3472c3d105ac339e740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 5 Aug 2020 19:19:30 +0200 Subject: [PATCH 3/3] Expand the viewport to cover the scissor region, if it doesn't. Fixes #4845 (bloom in Dante's Inferno). --- GPU/Common/GPUStateUtils.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 46f0b56bc5..1fd166cf45 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -645,6 +645,14 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo float overageLeft = std::max(-left, 0.0f); float overageRight = std::max(right - bufferWidth, 0.0f); + // Expand viewport to cover scissor region. The viewport doesn't clip on the PSP. + if (right < scissorX2) { + overageRight -= scissorX2 - right; + } + if (left > scissorX1) { + overageLeft += scissorX1 - left; + } + // Our center drifted by the difference in overages. float drift = overageRight - overageLeft; @@ -660,6 +668,14 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo { float overageTop = std::max(-top, 0.0f); float overageBottom = std::max(bottom - bufferHeight, 0.0f); + + // Expand viewport to cover scissor region. The viewport doesn't clip on the PSP. + if (bottom < scissorY2) { + overageBottom -= scissorY2 - bottom; + } + if (top > scissorY1) { + overageTop += scissorY1 - top; + } // Our center drifted by the difference in overages. float drift = overageBottom - overageTop;