diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index d1cd9149af..1d3630919c 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -51,13 +51,10 @@ void GenerateDepalShader300(ShaderWriter &writer, const DepalConfig &config) { writer.C(" vec2 texcoord = v_texcoord;\n"); // Implement the swizzle we need to simulate, if a game uses 8888 framebuffers and any other mode than "6" to access depth textures. - // This implements the "2" mode swizzle (it fixes up the Y direction but not X. See comments on issue #15898) + // This implements the "2" mode swizzle (it fixes up the Y direction but not X. See comments on issue #15898, Tantalus games) // NOTE: This swizzle can be made to work with any power-of-2 resolution scaleFactor by shifting // the bits around, but not sure how to handle 3x scaling. For now this is 1x-only (rough edges at higher resolutions). if (config.bufferFormat == GE_FORMAT_DEPTH16) { - DepthScaleFactors factors = GetDepthScaleFactors(gstate_c.UseFlags()); - writer.ConstFloat("z_scale", factors.ScaleU16()); - writer.ConstFloat("z_offset", factors.Offset()); if (config.depthUpperBits == 0x2) { writer.C(R"( int x = int((texcoord.x / scaleFactor) * texSize.x); @@ -117,7 +114,7 @@ void GenerateDepalShader300(ShaderWriter &writer, const DepalConfig &config) { break; case GE_FORMAT_DEPTH16: // Decode depth buffer. - writer.C(" float depth = (color.x - z_offset) * z_scale;\n"); + writer.C(" float depth = (color.x - z_offset) * z_scale * 65535.0f;\n"); if (config.bufferFormat == GE_FORMAT_DEPTH16 && config.textureFormat == GE_TFMT_5650) { // Convert depth to 565, without going through a CLUT. diff --git a/GPU/Common/DepthBufferCommon.cpp b/GPU/Common/DepthBufferCommon.cpp index 5d118a4e10..3c78362352 100644 --- a/GPU/Common/DepthBufferCommon.cpp +++ b/GPU/Common/DepthBufferCommon.cpp @@ -62,7 +62,7 @@ void GenerateDepthDownloadFs(ShaderWriter &writer) { writer.BeginFSMain(depthUniforms, varyings); writer.C(" float depth = ").SampleTexture2D("tex", "v_texcoord").C(".r; \n"); // At this point, clamped maps [0, 1] to [0, 65535]. - writer.C(" float clamped = clamp((depth + u_depthFactor.x) * u_depthFactor.y, 0.0, 1.0);\n"); + writer.C(" float clamped = clamp((depth - u_depthFactor.x) * u_depthFactor.y, 0.0, 1.0);\n"); writer.C(" vec4 enc = u_depthShift * clamped;\n"); writer.C(" enc = floor(mod(enc, 256.0)) * u_depthTo8;\n"); writer.C(" vec4 outColor = enc.yzww;\n"); // Let's ignore the bits outside 16 bit precision. @@ -221,16 +221,11 @@ bool FramebufferManagerCommon::ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x // Setting this to 0.95f eliminates flickering lights with delayed readback in Syphon Filter. // That's pretty ugly though! But we'll need to do that if we're gonna enable delayed readback in those games. const float fudgeFactor = 1.0f; + DepthScaleFactors depthScale = GetDepthScaleFactors(gstate_c.UseFlags()); + ub.u_depthFactor[0] = depthScale.Offset(); + ub.u_depthFactor[1] = depthScale.Scale(); - if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { - // Don't scale anything, since we're not using factors outside accurate mode. - ub.u_depthFactor[0] = 0.0f; - ub.u_depthFactor[1] = fudgeFactor; - } else { - const float factor = DepthSliceFactor(gstate_c.UseFlags()); - ub.u_depthFactor[0] = -0.5f * (factor - 1.0f) * (1.0f / factor); - ub.u_depthFactor[1] = factor * fudgeFactor; - } + // These are for packing a float in u8x4 colors. We should support more suitable readback formats on APIs that can do it. static constexpr float shifts[] = { 16777215.0f, 16777215.0f / 256.0f, 16777215.0f / 65536.0f, 16777215.0f / 16777216.0f }; memcpy(ub.u_depthShift, shifts, sizeof(shifts)); static constexpr float to8[] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f }; diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 61911b2a81..4f19277956 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -39,23 +39,31 @@ static const SamplerDef samplers[1] = { { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN }, }; -const UniformDef g_draw2Duniforms[2] = { +const UniformDef g_draw2Duniforms[5] = { { "vec2", "texSize", 0 }, { "float", "scaleFactor", 1}, + { "float", "z_scale", 2 }, + { "float", "z_scale_inv", 3 }, + { "float", "z_offset", 4 }, }; struct Draw2DUB { float texSizeX; float texSizeY; float scaleFactor; + float zScale; + float zScaleInv; + float zOffset; }; const UniformBufferDesc draw2DUBDesc{ sizeof(Draw2DUB), { { "texSize", -1, 0, UniformType::FLOAT2, 0 }, { "scaleFactor", -1, 1, UniformType::FLOAT1, 8 }, + { "z_scale", -1, 1, UniformType::FLOAT1, 12 }, + { "z_scale_inv", -1, 1, UniformType::FLOAT1, 16 }, + { "z_offset", -1, 1, UniformType::FLOAT1, 20 }, } }; - Draw2DPipelineInfo GenerateDraw2DCopyColorFs(ShaderWriter &writer) { writer.DeclareSamplers(samplers); writer.BeginFSMain(Slice::empty(), varyings); @@ -96,22 +104,40 @@ Draw2DPipelineInfo GenerateDraw2DCopyDepthFs(ShaderWriter &writer) { return Draw2DPipelineInfo{ "draw2d_copy_depth", + RASTER_DEPTH, // Unused in this case, I think. RASTER_DEPTH, + }; +} + +Draw2DPipelineInfo GenerateDraw2DEncodeDepthFs(ShaderWriter &writer) { + writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); + writer.HighPrecisionFloat(); + writer.DeclareSamplers(samplers); + writer.BeginFSMain(g_draw2Duniforms, varyings); + writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); + writer.C(" float depthValue = ").SampleTexture2D("tex", "v_texcoord.xy").C(".x;\n"); + writer.C(" gl_FragDepth = (depthValue * z_scale_inv) + z_offset;\n"); + writer.EndFSMain("outColor"); + + return Draw2DPipelineInfo{ + "draw2d_copy_r16_to_depth", + RASTER_COLOR, RASTER_DEPTH, }; } Draw2DPipelineInfo GenerateDraw2D565ToDepthFs(ShaderWriter &writer) { writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); + writer.HighPrecisionFloat(); writer.DeclareSamplers(samplers); - writer.BeginFSMain(Slice::empty(), varyings); + writer.BeginFSMain(g_draw2Duniforms, varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); // Unlike when just copying a depth buffer, here we're generating new depth values so we'll // have to apply the scaling. DepthScaleFactors factors = GetDepthScaleFactors(gstate_c.UseFlags()); writer.C(" vec3 rgb = ").SampleTexture2D("tex", "v_texcoord.xy").C(".xyz;\n"); - writer.F(" highp float depthValue = (floor(rgb.x * 31.99) + floor(rgb.y * 63.99) * 32.0 + floor(rgb.z * 31.99) * 2048.0); \n"); - writer.F(" gl_FragDepth = (depthValue / %f) + %f;\n", factors.ScaleU16(), factors.Offset()); + writer.F(" float depthValue = ((floor(rgb.x * 31.99) + floor(rgb.y * 63.99) * 32.0 + floor(rgb.z * 31.99) * 2048.0)) / 65535.0; \n"); + writer.C(" gl_FragDepth = (depthValue * z_scale_inv) + z_offset;\n"); writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ @@ -123,6 +149,7 @@ Draw2DPipelineInfo GenerateDraw2D565ToDepthFs(ShaderWriter &writer) { Draw2DPipelineInfo GenerateDraw2D565ToDepthDeswizzleFs(ShaderWriter &writer) { writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); + writer.HighPrecisionFloat(); writer.DeclareSamplers(samplers); writer.BeginFSMain(g_draw2Duniforms, varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); @@ -135,11 +162,11 @@ Draw2DPipelineInfo GenerateDraw2D565ToDepthDeswizzleFs(ShaderWriter &writer) { writer.C(" float in_strip = mod(coord.y, strip);\n"); writer.C(" coord.y = coord.y - in_strip + strip - in_strip;\n"); writer.C(" coord /= tsize;\n"); - writer.C(" vec3 rgb = ").SampleTexture2D("tex", "coord").C(".xyz;\n"); - writer.F(" highp float depthValue = (floor(rgb.x * 31.99) + floor(rgb.y * 63.99) * 32.0 + floor(rgb.z * 31.99) * 2048.0); \n"); - writer.F(" gl_FragDepth = (depthValue / %f) + %f;\n", factors.ScaleU16(), factors.Offset()); + writer.C(" highp vec3 rgb = ").SampleTexture2D("tex", "coord").C(".xyz;\n"); + writer.F(" highp float depthValue = floor(rgb.x * 31.99) + floor(rgb.y * 63.99) * 32.0 + floor(rgb.z * 31.99) * 2048.0; \n"); + writer.C(" gl_FragDepth = z_offset + ((depthValue / 65535.0) * z_scale_inv);\n"); writer.EndFSMain("outColor"); - + return Draw2DPipelineInfo{ "draw2d_565_to_depth_deswizzle", RASTER_COLOR, @@ -248,7 +275,7 @@ Draw2DPipeline *Draw2D::Create2DPipeline(std::functionCreateInputLayout(desc); - BlendState *blend = draw_->CreateBlendState({ false, info.writeChannel == RASTER_COLOR ? 0xF : 0 }); + BlendState *blend = draw_->CreateBlendState({ false, info.writeChannel == RASTER_COLOR ? 0xF : 0x0 }); DepthStencilStateDesc dsDesc{}; if (info.writeChannel == RASTER_DEPTH) { @@ -319,6 +346,11 @@ void Draw2D::DrawStrip2D(Draw::Texture *tex, const Draw2DVertex *verts, int vert ub.texSizeY = tex ? tex->Height() : texH; ub.scaleFactor = (float)scaleFactor; + DepthScaleFactors zScaleFactors = GetDepthScaleFactors(gstate_c.UseFlags()); + ub.zScale = zScaleFactors.Scale(); + ub.zScaleInv = 1.0f / ub.zScale; + ub.zOffset = zScaleFactors.Offset(); + draw_->BindPipeline(pipeline->pipeline); draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); @@ -343,10 +375,10 @@ Draw2DPipeline *FramebufferManagerCommon::Get2DPipeline(Draw2DShader shader) { switch (shader) { case DRAW2D_COPY_COLOR: - if (!draw2DPipelineColor_) { - draw2DPipelineColor_ = draw2D_.Create2DPipeline(&GenerateDraw2DCopyColorFs); + if (!draw2DPipelineCopyColor_) { + draw2DPipelineCopyColor_ = draw2D_.Create2DPipeline(&GenerateDraw2DCopyColorFs); } - pipeline = draw2DPipelineColor_; + pipeline = draw2DPipelineCopyColor_; break; case DRAW2D_COPY_COLOR_RECT2LIN: @@ -355,16 +387,26 @@ Draw2DPipeline *FramebufferManagerCommon::Get2DPipeline(Draw2DShader shader) { } pipeline = draw2DPipelineColorRect2Lin_; break; - case DRAW2D_COPY_DEPTH: if (!draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) { // Can't do it return nullptr; } - if (!draw2DPipelineDepth_) { - draw2DPipelineDepth_ = draw2D_.Create2DPipeline(&GenerateDraw2DCopyDepthFs); + if (!draw2DPipelineCopyDepth_) { + draw2DPipelineCopyDepth_ = draw2D_.Create2DPipeline(&GenerateDraw2DCopyDepthFs); } - pipeline = draw2DPipelineDepth_; + pipeline = draw2DPipelineCopyDepth_; + break; + + case DRAW2D_ENCODE_R16_TO_DEPTH: + if (!draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) { + // Can't do it + return nullptr; + } + if (!draw2DPipelineEncodeDepth_) { + draw2DPipelineEncodeDepth_ = draw2D_.Create2DPipeline(&GenerateDraw2DEncodeDepthFs); + } + pipeline = draw2DPipelineEncodeDepth_; break; case DRAW2D_565_TO_DEPTH: diff --git a/GPU/Common/Draw2D.h b/GPU/Common/Draw2D.h index 4d7d728404..5df67f7493 100644 --- a/GPU/Common/Draw2D.h +++ b/GPU/Common/Draw2D.h @@ -14,6 +14,7 @@ struct Draw2DVertex { enum Draw2DShader { DRAW2D_COPY_COLOR, DRAW2D_COPY_DEPTH, + DRAW2D_ENCODE_R16_TO_DEPTH, DRAW2D_565_TO_DEPTH, DRAW2D_565_TO_DEPTH_DESWIZZLE, DRAW2D_COPY_COLOR_RECT2LIN, @@ -24,6 +25,7 @@ inline RasterChannel Draw2DSourceChannel(Draw2DShader shader) { case DRAW2D_COPY_DEPTH: return RASTER_DEPTH; case DRAW2D_COPY_COLOR: + case DRAW2D_ENCODE_R16_TO_DEPTH: case DRAW2D_565_TO_DEPTH: case DRAW2D_565_TO_DEPTH_DESWIZZLE: default: @@ -38,7 +40,7 @@ struct Draw2DPipelineInfo { Slice samplers; }; -extern const UniformDef g_draw2Duniforms[2]; +extern const UniformDef g_draw2Duniforms[5]; struct Draw2DPipeline { Draw::Pipeline *pipeline; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index c6ee43f9ea..4cd163feab 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -1185,13 +1185,15 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } if (gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { - const double scale = DepthSliceFactor(gstate_c.UseFlags()) * 65535.0; + DepthScaleFactors depthScale = GetDepthScaleFactors(gstate_c.UseFlags()); + + const double scale = depthScale.ScaleU16(); WRITE(p, " highp float z = gl_FragCoord.z;\n"); if (gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { // We center the depth with an offset, but only its fraction matters. // When (DepthSliceFactor() - 1) is odd, it will be 0.5, otherwise 0. - if (((int)(DepthSliceFactor(gstate_c.UseFlags()) - 1.0f) & 1) == 1) { + if (((int)(depthScale.Scale() - 1.0f) & 1) == 1) { WRITE(p, " z = (floor((z * %f) - (1.0 / 2.0)) + (1.0 / 2.0)) * (1.0 / %f);\n", scale, scale); } else { WRITE(p, " z = floor(z * %f) * (1.0 / %f);\n", scale, scale); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 24627f8c72..05289365e8 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2964,9 +2964,10 @@ void FramebufferManagerCommon::ReleasePipelines() { DoRelease(stencilReadbackPipeline_); DoRelease(depthReadbackSampler_); DoRelease(depthReadbackPipeline_); - DoRelease(draw2DPipelineColor_); + DoRelease(draw2DPipelineCopyColor_); DoRelease(draw2DPipelineColorRect2Lin_); - DoRelease(draw2DPipelineDepth_); + DoRelease(draw2DPipelineCopyDepth_); + DoRelease(draw2DPipelineEncodeDepth_); DoRelease(draw2DPipeline565ToDepth_); DoRelease(draw2DPipeline565ToDepthDeswizzle_); } @@ -3036,7 +3037,7 @@ void FramebufferManagerCommon::DrawActiveTexture(float x, float y, float w, floa // Rearrange to strip form. std::swap(coord[2], coord[3]); - draw2D_.DrawStrip2D(nullptr, coord, 4, (flags & DRAWTEX_LINEAR) != 0, Get2DPipeline((flags & DRAWTEX_DEPTH) ? DRAW2D_COPY_DEPTH : DRAW2D_COPY_COLOR)); + draw2D_.DrawStrip2D(nullptr, coord, 4, (flags & DRAWTEX_LINEAR) != 0, Get2DPipeline((flags & DRAWTEX_DEPTH) ? DRAW2D_ENCODE_R16_TO_DEPTH : DRAW2D_COPY_COLOR)); gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index df33d549b4..ea4565e6c0 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -605,9 +605,10 @@ protected: Draw::SamplerState *depthReadbackSampler_ = nullptr; // Draw2D pipelines - Draw2DPipeline *draw2DPipelineColor_ = nullptr; + Draw2DPipeline *draw2DPipelineCopyColor_ = nullptr; Draw2DPipeline *draw2DPipelineColorRect2Lin_ = nullptr; - Draw2DPipeline *draw2DPipelineDepth_ = nullptr; + Draw2DPipeline *draw2DPipelineCopyDepth_ = nullptr; + Draw2DPipeline *draw2DPipelineEncodeDepth_ = nullptr; Draw2DPipeline *draw2DPipeline565ToDepth_ = nullptr; Draw2DPipeline *draw2DPipeline565ToDepthDeswizzle_ = nullptr; diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 8bbac0b9a2..d223283e3f 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -548,33 +548,23 @@ float DepthSliceFactor(u32 useFlags) { return DEPTH_SLICE_FACTOR_HIGH; } -// This is used for float values which might not be integers, but are in the integer scale of 0-65535. -float ToScaledDepthFromIntegerScale(u32 useFlags, float z) { - if (!(useFlags & GPU_USE_ACCURATE_DEPTH)) { - // Old style depth, shortcut. - return z * (1.0f / 65535.0f); - } - - const float depthSliceFactor = DepthSliceFactor(useFlags); - if (useFlags & GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT) { - const double doffset = 0.5 * (depthSliceFactor - 1.0) / depthSliceFactor; - // Use one bit for each value, rather than 1.0 / (65535.0 * 256.0). - return (float)((double)z * (1.0 / 16777215.0) + doffset); - } else { - const float offset = 0.5f * (depthSliceFactor - 1.0f) / depthSliceFactor; - return z / depthSliceFactor * (1.0f / 65535.0f) + offset; - } -} - // See class DepthScaleFactors for how to apply. DepthScaleFactors GetDepthScaleFactors(u32 useFlags) { if (!(useFlags & GPU_USE_ACCURATE_DEPTH)) { return DepthScaleFactors(0.0f, 65535.0f); } - const double depthSliceFactor = DepthSliceFactor(useFlags); - const double offset = 0.5f * (depthSliceFactor - 1.0f) * (1.0f / depthSliceFactor); - return DepthScaleFactors(offset, (float)(depthSliceFactor * 65535.0)); + if (useFlags & GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT) { + const double offset = 0.5 * (DEPTH_SLICE_FACTOR_16BIT - 1.0) / DEPTH_SLICE_FACTOR_16BIT; + // Use one bit for each value, rather than 1.0 / (65535.0 * 256.0). + const double scale = 16777215.0; + return DepthScaleFactors(offset, scale); + } else if (useFlags & GPU_USE_DEPTH_CLAMP) { + return DepthScaleFactors(0.0f, 65535.0f); + } else { + const double offset = 0.5f * (DEPTH_SLICE_FACTOR_HIGH - 1.0f) * (1.0f / DEPTH_SLICE_FACTOR_HIGH); + return DepthScaleFactors(offset, (float)(DEPTH_SLICE_FACTOR_HIGH * 65535.0)); + } } void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, float renderHeight, int bufferWidth, int bufferHeight, ViewportAndScissor &out) { @@ -632,6 +622,8 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo float offsetX = gstate.getOffsetX(); float offsetY = gstate.getOffsetY(); + DepthScaleFactors depthScale = GetDepthScaleFactors(gstate_c.UseFlags()); + if (out.throughMode) { // If renderX/renderY are offset to compensate for a split framebuffer, // applying the offset to the viewport isn't enough, since the viewport clips. @@ -640,8 +632,8 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo out.viewportY = renderY * renderHeightFactor + displayOffsetY; out.viewportW = curRTWidth * renderWidthFactor; out.viewportH = curRTHeight * renderHeightFactor; - out.depthRangeMin = ToScaledDepthFromIntegerScale(gstate_c.UseFlags(), 0.0f); - out.depthRangeMax = ToScaledDepthFromIntegerScale(gstate_c.UseFlags(), 65536.0f); + out.depthRangeMin = depthScale.EncodeFromU16(0.0f); + out.depthRangeMax = depthScale.EncodeFromU16(65536.0f); } else { // These we can turn into a glViewport call, offset by offsetX and offsetY. Math after. float vpXScale = gstate.getViewportXScale(); @@ -755,7 +747,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo // Here, we should "clamp." But clamping per fragment would be slow. // So, instead, we just increase the available range and hope. // If depthSliceFactor is 4, it means (75% / 2) of the depth lies in each direction. - float fullDepthRange = 65535.0f * (DepthSliceFactor(gstate_c.UseFlags()) - 1.0f) * (1.0f / 2.0f); + float fullDepthRange = 65535.0f * (depthScale.Scale() - 1.0f) * (1.0f / 2.0f); if (minz == 0) { minz -= fullDepthRange; } @@ -766,9 +758,10 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo // This means clamp isn't enabled, but we still want to allow values up to 65535.99. // If DepthSliceFactor() is 1.0, though, this would make out.depthRangeMax exceed 1. // Since that would clamp, it would make Z=1234 not match between draws when maxz changes. - if (DepthSliceFactor(gstate_c.UseFlags()) > 1.0f) + if (depthScale.Scale() > 1.0f) maxz = 65535.99f; } + // Okay. So, in our shader, -1 will map to minz, and +1 will map to maxz. float halfActualZRange = (maxz - minz) * (1.0f / 2.0f); out.depthScale = halfActualZRange < std::numeric_limits::epsilon() ? 1.0f : vpZScale / halfActualZRange; @@ -778,11 +771,11 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { out.depthScale = 1.0f; out.zOffset = 0.0f; - out.depthRangeMin = ToScaledDepthFromIntegerScale(gstate_c.UseFlags(), vpZCenter - vpZScale); - out.depthRangeMax = ToScaledDepthFromIntegerScale(gstate_c.UseFlags(), vpZCenter + vpZScale); + out.depthRangeMin = depthScale.EncodeFromU16(vpZCenter - vpZScale); + out.depthRangeMax = depthScale.EncodeFromU16(vpZCenter + vpZScale); } else { - out.depthRangeMin = ToScaledDepthFromIntegerScale(gstate_c.UseFlags(), minz); - out.depthRangeMax = ToScaledDepthFromIntegerScale(gstate_c.UseFlags(), maxz); + out.depthRangeMin = depthScale.EncodeFromU16(minz); + out.depthRangeMax = depthScale.EncodeFromU16(maxz); } // OpenGL will clamp these for us anyway, and Direct3D will error if not clamped. diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index f3a7338401..a786190f60 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -108,8 +108,9 @@ public: } float Offset() const { return (float)offset_; } + float ScaleU16() const { return (float)scale_; } - // float Scale() const { return scale_ / 65535.0f; } + float Scale() const { return (float)(scale_ / 65535.0); } private: // Doubles hardly cost anything these days, and precision matters here. @@ -119,10 +120,6 @@ private: DepthScaleFactors GetDepthScaleFactors(u32 useFlags); -// These two will be replaced with just DepthScaleFactors. -float ToScaledDepthFromIntegerScale(u32 useFlags, float z); -float DepthSliceFactor(u32 useFlags); - // These are common to all modern APIs and can be easily converted with a lookup table. enum class BlendFactor : uint8_t { ZERO, diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 02533b85aa..011d09a49b 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -251,11 +251,10 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView float vpZCenter = gstate.getViewportZCenter(); // These are just the reverse of the formulas in GPUStateUtils. - float halfActualZRange = vpZScale / gstate_c.vpDepthScale; + float halfActualZRange = gstate_c.vpDepthScale != 0.0f ? vpZScale / gstate_c.vpDepthScale : 0.0f; float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange; float viewZScale = halfActualZRange * 2.0f; - // Account for the half pixel offset. - float viewZCenter = minz + (DepthSliceFactor(gstate_c.UseFlags()) / 256.0f) * 0.5f; + float viewZCenter = minz; ub->depthRange[0] = viewZScale; ub->depthRange[1] = viewZCenter; diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index f05117160a..9aff2c301e 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -452,9 +452,10 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt bool matchingComponents = params_.allowSeparateAlphaClear || (alphaMatchesColor && depthMatchesStencil); bool stencilNotMasked = !gstate.isClearModeAlphaMask() || gstate.getStencilWriteMask() == 0x00; if (matchingComponents && stencilNotMasked) { + DepthScaleFactors depthScale = GetDepthScaleFactors(gstate_c.UseFlags()); result->color = transformed[1].color0_32; // Need to rescale from a [0, 1] float. This is the final transformed value. - result->depth = ToScaledDepthFromIntegerScale(gstate_c.UseFlags(), (int)(transformed[1].z * 65535.0f)); + result->depth = depthScale.EncodeFromU16((float)(int)(transformed[1].z * 65535.0f)); result->action = SW_CLEAR; gpuStats.numClears++; return; diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index ea341103a9..1571d517bd 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -462,11 +462,10 @@ void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) { float vpZCenter = gstate.getViewportZCenter(); // These are just the reverse of the formulas in GPUStateUtils. - float halfActualZRange = vpZScale / gstate_c.vpDepthScale; + float halfActualZRange = gstate_c.vpDepthScale != 0.0f ? vpZScale / gstate_c.vpDepthScale : 0.0f; float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange; float viewZScale = halfActualZRange * 2.0f; - // Account for the half pixel offset. - float viewZCenter = minz + (DepthSliceFactor(gstate_c.UseFlags()) / 256.0f) * 0.5f; + float viewZCenter = minz; float reverseScale = 2.0f * (1.0f / gstate_c.vpDepthScale); float reverseTranslate = gstate_c.vpZOffset * 0.5f + 0.5f; diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index c7d4d1a7f6..9df5b7f28d 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -588,7 +588,7 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin float vpZCenter = gstate.getViewportZCenter(); // These are just the reverse of the formulas in GPUStateUtils. - float halfActualZRange = vpZScale / gstate_c.vpDepthScale; + float halfActualZRange = gstate_c.vpDepthScale != 0.0f ? vpZScale / gstate_c.vpDepthScale : 0.0f; float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange; float viewZScale = halfActualZRange; float viewZCenter = minz + halfActualZRange; diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index e7fe46e52b..fcbe56f282 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -797,6 +797,8 @@ static bool TestSmallDataConvert() { return true; } +float DepthSliceFactor(u32 useFlags); + static bool TestDepthMath() { // These are in normalized space. static const volatile float testValues[] = { 0.0f, 0.1f, 0.5f, M_PI / 4.0f, 0.9f, 1.0f }; @@ -810,7 +812,7 @@ static bool TestDepthMath() { GPU_USE_DEPTH_CLAMP | GPU_USE_ACCURATE_DEPTH, GPU_USE_DEPTH_CLAMP | GPU_USE_ACCURATE_DEPTH | GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT, // Here, GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT should take precedence over USE_DEPTH_CLAMP. }; - static const float expectedScale[] = { 65535.0f, 262140.0f, 16776960.0f, 65535.0f, 16776960.0f, }; + static const float expectedScale[] = { 65535.0f, 262140.0f, 16777215.0f, 65535.0f, 16777215.0f, }; static const float expectedOffset[] = { 0.0f, 0.375f, 0.498047f, 0.0f, 0.498047f, }; EXPECT_REL_EQ_FLOAT(100000.0f, 100001.0f, 0.00001f); @@ -822,7 +824,7 @@ static bool TestDepthMath() { EXPECT_EQ_FLOAT(factors.ScaleU16(), expectedScale[j]); EXPECT_REL_EQ_FLOAT(factors.Offset(), expectedOffset[j], 0.00001f); - EXPECT_EQ_FLOAT(factors.ScaleU16(), DepthSliceFactor(useFlags) * 65535.0f); + EXPECT_REL_EQ_FLOAT(factors.Scale(), DepthSliceFactor(useFlags), 0.0001f); for (int i = 0; i < ARRAY_SIZE(testValues); i++) { float testValue = testValues[i] * 65535.0f; @@ -830,7 +832,6 @@ static bool TestDepthMath() { float encoded = factors.EncodeFromU16(testValue); float decodedU16 = factors.DecodeToU16(encoded); EXPECT_REL_EQ_FLOAT(decodedU16, testValue, 0.0001f); - EXPECT_REL_EQ_FLOAT(encoded, ToScaledDepthFromIntegerScale(useFlags, testValue), 0.000001f); } }