mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 01:29:41 +01:00
Merge pull request #16947 from hrydgard/depth-scale-fixes
Depth scale fixes
This commit is contained in:
14 files changed
+115
-85
No files matched your search
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user