Merge pull request #16947 from hrydgard/depth-scale-fixes

Depth scale fixes
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2023-02-11 23:09:15 +01:00
commit c02fbd4bb7
14 files changed
+115 -85

No files matched your search

+2 -5
View File
@@ -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.
+5 -10
View File
@@ -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 };
+59 -17
View File
@@ -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<UniformDef>::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<UniformDef>::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::function<Draw2DPipelineInfo (Shade
};
InputLayout *inputLayout = draw_->CreateInputLayout(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:
+3 -1
View File
@@ -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<SamplerDef> samplers;
};
extern const UniformDef g_draw2Duniforms[2];
extern const UniformDef g_draw2Duniforms[5];
struct Draw2DPipeline {
Draw::Pipeline *pipeline;
+4 -2
View File
@@ -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);
+4 -3
View File
@@ -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);
}
+3 -2
View File
@@ -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;
+22 -29
View File
@@ -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<float>::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.
+2 -5
View File
@@ -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,
+2 -3
View File
@@ -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;
+2 -1
View File
@@ -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;
+2 -3
View File
@@ -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;
+1 -1
View File
@@ -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;
+4 -3
View File
@@ -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);
}
}