ccpr: Normalize homogeneous coords with frexp/ldexp

Hopefully increases cubic accuracy by manipulating exponents
instead of calling normalize().

Bug: skia:
Change-Id: I8d3596e858a2fbb6650c158753133c5a2e01e166
Reviewed-on: https://skia-review.googlesource.com/117009
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2018-03-28 20:09:58 -06:00 committed by Skia Commit-Bot
parent 64ecdce4ad
commit 7c7ff031a5
5 changed files with 42 additions and 5 deletions

View File

@ -76,6 +76,9 @@ public:
bool vertexIDSupport() const { return fVertexIDSupport; }
// frexp, ldexp, etc.
bool fpManipulationSupport() const { return fFPManipulationSupport; }
bool floatIs32Bits() const { return fFloatIs32Bits; }
bool halfIs32Bits() const { return fHalfIs32Bits; }
@ -250,6 +253,7 @@ private:
bool fExternalTextureSupport : 1;
bool fTexelFetchSupport : 1;
bool fVertexIDSupport : 1;
bool fFPManipulationSupport : 1;
bool fFloatIs32Bits : 1;
bool fHalfIs32Bits : 1;

View File

@ -46,6 +46,7 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) {
fExternalTextureSupport = false;
fTexelFetchSupport = false;
fVertexIDSupport = false;
fFPManipulationSupport = false;
fFloatIs32Bits = true;
fHalfIs32Bits = false;
@ -118,6 +119,7 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const {
writer->appendBool("External texture support", fExternalTextureSupport);
writer->appendBool("texelFetch support", fTexelFetchSupport);
writer->appendBool("sk_VertexID support", fVertexIDSupport);
writer->appendBool("Floating point manipulation support", fFPManipulationSupport);
writer->appendBool("float == fp32", fFloatIs32Bits);
writer->appendBool("half == fp32", fHalfIs32Bits);

View File

@ -8,12 +8,35 @@
#include "GrCCCubicShader.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLProgramBuilder.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
using Shader = GrCCCoverageProcessor::Shader;
void GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
const char* wind, const char** /*tighterHull*/) const {
// Define a function that normalizes the homogeneous coordinates T=t/s in order to avoid
// exponent overflow.
SkString normalizeHomogCoordFn;
GrShaderVar coord("coord", kFloat2_GrSLType);
s->emitFunction(kFloat2_GrSLType, "normalize_homogeneous_coord", 1, &coord,
s->getProgramBuilder()->shaderCaps()->fpManipulationSupport()
// Exponent manipulation version: Scale the exponents so the larger
// component has a magnitude in 1..2.
// (Neither component should be infinity because ccpr crops big paths.)
? "int exp;"
"frexp(max(abs(coord.t), abs(coord.s)), exp);"
"return coord * ldexp(1, 1 - exp);"
// Division version: Divide by the component with the larger magnitude.
// (Both should not be 0 because ccpr catches degenerate cubics.)
: "bool swap = abs(coord.t) > abs(coord.s);"
"coord = swap ? coord.ts : coord;"
"coord = float2(1, coord.t/coord.s);"
"return swap ? coord.ts : coord;",
&normalizeHomogCoordFn);
// Find the cubic's power basis coefficients.
s->codeAppendf("float2x4 C = float4x4(-1, 3, -3, 1, "
" 3, -6, 3, 0, "
@ -33,9 +56,10 @@ void GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
s->codeAppend ("q = x*D2 + (D2 >= 0 ? q : -q);");
s->codeAppend ("float2 l, m;");
s->codeAppend ("l.ts = normalize(float2(q, 2*x * D1));");
s->codeAppend ("m.ts = normalize(float2(2, q) * (discr >= 0 ? float2(D3, 1) "
": float2(D2*D2 - D3*D1, D1)));");
s->codeAppendf("l.ts = %s(float2(q, 2*x * D1));", normalizeHomogCoordFn.c_str());
s->codeAppendf("m.ts = %s(float2(2, q) * (discr >= 0 ? float2(D3, 1) "
": float2(D2*D2 - D3*D1, D1)));",
normalizeHomogCoordFn.c_str());
s->codeAppend ("float4 K;");
s->codeAppend ("float4 lm = l.sstt * m.stst;");
@ -46,7 +70,7 @@ void GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
s->codeAppend ("L = float4(-1,x,-x,1) * l.sstt * (discr >= 0 ? l.ssst * l.sttt : lm);");
s->codeAppend ("M = float4(-1,x,-x,1) * m.sstt * (discr >= 0 ? m.ssst * m.sttt : lm.xzyw);");
s->codeAppend ("short middlerow = abs(D2) > abs(D1) ? 2 : 1;");
s->codeAppend ("int middlerow = abs(D2) > abs(D1) ? 2 : 1;");
s->codeAppend ("float3x3 CI = inverse(float3x3(C[0][0], C[0][middlerow], C[0][3], "
"C[1][0], C[1][middlerow], C[1][3], "
" 0, 0, 1));");
@ -66,7 +90,7 @@ void GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
// Determine the amount of additional coverage to subtract out for the flat edge (P3 -> P0).
s->declareGlobal(fEdgeDistanceEquation);
s->codeAppendf("short edgeidx0 = %s > 0 ? 3 : 0;", wind);
s->codeAppendf("int edgeidx0 = %s > 0 ? 3 : 0;", wind);
s->codeAppendf("float2 edgept0 = %s[edgeidx0];", pts);
s->codeAppendf("float2 edgept1 = %s[3 - edgeidx0];", pts);
Shader::EmitEdgeDistanceEquation(s, "edgept0", "edgept1", fEdgeDistanceEquation.c_str());

View File

@ -805,6 +805,12 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli
shaderCaps->fVertexIDSupport = ctxInfo.glslGeneration() >= k330_GrGLSLGeneration;
}
if (kGL_GrGLStandard == standard) {
shaderCaps->fFPManipulationSupport = ctxInfo.glslGeneration() >= k400_GrGLSLGeneration;
} else {
shaderCaps->fFPManipulationSupport = ctxInfo.glslGeneration() >= k310es_GrGLSLGeneration;
}
shaderCaps->fFloatIs32Bits = is_float_fp32(ctxInfo, gli, GR_GL_HIGH_FLOAT);
shaderCaps->fHalfIs32Bits = is_float_fp32(ctxInfo, gli, GR_GL_MEDIUM_FLOAT);
}

View File

@ -261,6 +261,7 @@ void GrVkCaps::initShaderCaps(const VkPhysicalDeviceProperties& properties, uint
shaderCaps->fTexelBufferSupport = true;
shaderCaps->fTexelFetchSupport = true;
shaderCaps->fVertexIDSupport = true;
shaderCaps->fFPManipulationSupport = true;
// Assume the minimum precisions mandated by the SPIR-V spec.
shaderCaps->fFloatIs32Bits = true;