diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index a0076a5291..ddedde12d5 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -517,54 +517,65 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { return REPLACE_BLEND_STANDARD; } +// Viewport and scissor really could be treated entirely separately, but the non-buffered case is nicer by doing them "together". void ConvertViewportAndScissor(const DisplayLayoutConfig &config, bool useBufferedRendering, float renderWidth, float renderHeight, int bufferWidth, int bufferHeight, ViewportAndScissor &out) { - float renderWidthFactor, renderHeightFactor; - float renderX = 0.0f, renderY = 0.0f; - float displayOffsetX, displayOffsetY; + // Scissor. The scissor needs to be offset by the framebuffer offset. + const int scissorX1 = gstate.getScissorX1(); + const int scissorY1 = gstate.getScissorY1(); + const int scissorW = gstate.getScissorX2() + 1 - scissorX1; + const int scissorH = gstate.getScissorY2() + 1 - scissorY1; + if (useBufferedRendering) { - displayOffsetX = 0.0f; - displayOffsetY = 0.0f; - renderWidthFactor = (float)renderWidth / (float)bufferWidth; - renderHeightFactor = (float)renderHeight / (float)bufferHeight; + const float renderWidthFactor = (float)renderWidth / (float)bufferWidth; + const float renderHeightFactor = (float)renderHeight / (float)bufferHeight; + + if (scissorW < 0 || scissorH < 0) { + // Bad scissor, kill all drawing with a valid scissor setup. + out.scissorX = 0; + out.scissorY = 0; + out.scissorW = 0; + out.scissorH = 0; + } else { + out.scissorX = (scissorX1 + gstate_c.curRTOffsetX) * renderWidthFactor; + out.scissorY = (scissorY1 + gstate_c.curRTOffsetY) * renderHeightFactor; + out.scissorW = scissorW * renderWidthFactor; + out.scissorH = scissorH * renderHeightFactor; + } + out.viewportX = 0.0f; + out.viewportY = 0.0f; + out.viewportW = gstate_c.curRTWidth * renderWidthFactor; + out.viewportH = gstate_c.curRTHeight * renderHeightFactor; } else { + // Hacky path for non-buffered rendering. float pixelW = PSP_CoreParameter().pixelWidth; float pixelH = PSP_CoreParameter().pixelHeight; FRect frame = GetScreenFrame(config.bIgnoreScreenInsets, pixelW, pixelH); FRect rc; CalculateDisplayOutputRect(config, &rc, 480, 272, frame, ROTATION_LOCKED_HORIZONTAL); - displayOffsetX = rc.x; - displayOffsetY = rc.y; + const float displayOffsetX = rc.x; + const float displayOffsetY = rc.y; renderWidth = rc.w; renderHeight = rc.h; - renderWidthFactor = renderWidth / 480.0f; - renderHeightFactor = renderHeight / 272.0f; + const float renderWidthFactor = renderWidth / 480.0f; + const float renderHeightFactor = renderHeight / 272.0f; + if (scissorW < 0 || scissorH < 0) { + // Bad scissor, kill all drawing with a valid scissor setup. + out.scissorX = 0; + out.scissorY = 0; + out.scissorW = 0; + out.scissorH = 0; + } else { + out.scissorX = displayOffsetX + (scissorX1 + gstate_c.curRTOffsetX) * renderWidthFactor; + out.scissorY = displayOffsetY + (scissorY1 + gstate_c.curRTOffsetY) * renderHeightFactor; + out.scissorW = scissorW * renderWidthFactor; + out.scissorH = scissorH * renderHeightFactor; + } + + out.viewportX = displayOffsetX; + out.viewportY = displayOffsetY; + out.viewportW = gstate_c.curRTWidth * renderWidthFactor; + out.viewportH = gstate_c.curRTHeight * renderHeightFactor; } - - // Scissor - int scissorX1 = gstate.getScissorX1(); - int scissorY1 = gstate.getScissorY1(); - int scissorX2 = gstate.getScissorX2() + 1; - int scissorY2 = gstate.getScissorY2() + 1; - - if (scissorX2 < scissorX1 || scissorY2 < scissorY1) { - out.scissorX = 0; - out.scissorY = 0; - out.scissorW = 0; - out.scissorH = 0; - } else { - out.scissorX = displayOffsetX + scissorX1 * renderWidthFactor; - out.scissorY = displayOffsetY + scissorY1 * renderHeightFactor; - out.scissorW = (scissorX2 - scissorX1) * renderWidthFactor; - out.scissorH = (scissorY2 - scissorY1) * renderHeightFactor; - } - - int curRTWidth = gstate_c.curRTWidth; - int curRTHeight = gstate_c.curRTHeight; - - out.viewportX = displayOffsetX; - out.viewportY = displayOffsetY; - out.viewportW = curRTWidth * renderWidthFactor; - out.viewportH = curRTHeight * renderHeightFactor; } static const BlendFactor genericALookup[11] = { diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 27d4bf8b1f..7f07262c4d 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -79,8 +79,8 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool useBuffe if (dirtyUniforms & DIRTY_FRAMEBUFFER_DIM) { ub->xywh[0] = (float)gstate_c.curRTOffsetX; ub->xywh[1] = (float)gstate_c.curRTOffsetY; - ub->xywh[2] = (float)gstate_c.curRTWidth; - ub->xywh[3] = (float)gstate_c.curRTHeight; + ub->xywh[2] = (float)(2.0 / gstate_c.curRTWidth); // intentionally do double precision here. + ub->xywh[3] = (float)(2.0 / gstate_c.curRTHeight); ub->rotation = useBufferedRendering ? 0 : (float)g_display.rotation; } diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index c2c3635871..731ebc5ce5 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -1041,8 +1041,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " %sgl_ClipDistance%s = u_minZmaxZ.y < 65535.0 ? (u_minZmaxZ.y - clipZFar) * outPos.w : 1.0;\n", compat.vsOutPrefix, maxZClipPlaneSuffix); } - // Convert to NDC space, using the framebuffer offset and size stored in u_xywh. - WRITE(p, " outPos.xy = ((outPos.xy - u_xywh.xy) / u_xywh.zw) * 2.0 - 1.0;\n"); + // Convert to NDC space, using the framebuffer offset and (inverse size * 2) stored in u_xywh. + WRITE(p, " outPos.xy = ((outPos.xy + u_xywh.xy) * u_xywh.zw) - vec2(1.0, 1.0);\n"); if (gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) { // Actually 15-bit. Truncate here fixes Afterburner (similarly to the min/max clipping above). diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index ce6cd5ec6d..ac3b72b8df 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -410,8 +410,8 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, const ShaderLanguageDesc float xywh[4]; xywh[0] = (float)gstate_c.curRTOffsetX; xywh[1] = (float)gstate_c.curRTOffsetY; - xywh[2] = (float)gstate_c.curRTWidth; - xywh[3] = (float)gstate_c.curRTHeight; + xywh[2] = (float)(2.0 / gstate_c.curRTWidth); // intentionally double precision here + xywh[3] = (float)(2.0 / gstate_c.curRTHeight); SetFloatUniform4(render_, &u_xywh, xywh); float nan = std::numeric_limits::quiet_NaN(); render_->SetUniformF1(&u_NaN, nan);