Chris Dalton | 6a3dbee | 2017-10-16 10:44:41 -0600 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2017 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
Chris Dalton | 383a2ef | 2018-01-08 17:21:41 -0500 | [diff] [blame] | 8 | #include "GrCCQuadraticShader.h" |
Chris Dalton | 6a3dbee | 2017-10-16 10:44:41 -0600 | [diff] [blame] | 9 | |
Chris Dalton | 90e8fb1 | 2017-12-22 02:24:53 -0700 | [diff] [blame] | 10 | #include "glsl/GrGLSLVertexGeoBuilder.h" |
Chris Dalton | 6a3dbee | 2017-10-16 10:44:41 -0600 | [diff] [blame] | 11 | #include "glsl/GrGLSLFragmentShaderBuilder.h" |
Chris Dalton | 1fbdb61 | 2017-12-12 12:48:47 -0700 | [diff] [blame] | 12 | #include "glsl/GrGLSLVertexGeoBuilder.h" |
Chris Dalton | 6a3dbee | 2017-10-16 10:44:41 -0600 | [diff] [blame] | 13 | |
Chris Dalton | 383a2ef | 2018-01-08 17:21:41 -0500 | [diff] [blame] | 14 | using Shader = GrCCCoverageProcessor::Shader; |
Chris Dalton | de5a814 | 2017-12-18 10:05:15 -0700 | [diff] [blame] | 15 | |
Chris Dalton | fe462ef | 2018-03-08 15:54:01 +0000 | [diff] [blame] | 16 | void GrCCQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts, |
Chris Dalton | 21ba551 | 2018-03-21 17:20:21 -0600 | [diff] [blame] | 17 | const char* wind, const char** tighterHull) const { |
Chris Dalton | 52076d1 | 2018-03-21 12:14:10 -0600 | [diff] [blame] | 18 | s->declareGlobal(fQCoordMatrix); |
| 19 | s->codeAppendf("%s = float2x2(1, 1, .5, 0) * inverse(float2x2(%s[2] - %s[0], %s[1] - %s[0]));", |
| 20 | fQCoordMatrix.c_str(), pts, pts, pts, pts); |
| 21 | |
| 22 | s->declareGlobal(fQCoord0); |
| 23 | s->codeAppendf("%s = %s[0];", fQCoord0.c_str(), pts); |
Chris Dalton | 6a3dbee | 2017-10-16 10:44:41 -0600 | [diff] [blame] | 24 | |
Chris Dalton | baf3e78 | 2018-03-08 15:55:58 +0000 | [diff] [blame] | 25 | s->declareGlobal(fEdgeDistanceEquation); |
| 26 | s->codeAppendf("float2 edgept0 = %s[%s > 0 ? 2 : 0];", pts, wind); |
| 27 | s->codeAppendf("float2 edgept1 = %s[%s > 0 ? 0 : 2];", pts, wind); |
| 28 | Shader::EmitEdgeDistanceEquation(s, "edgept0", "edgept1", fEdgeDistanceEquation.c_str()); |
| 29 | |
Chris Dalton | 21ba551 | 2018-03-21 17:20:21 -0600 | [diff] [blame] | 30 | if (tighterHull) { |
| 31 | // Find the T value whose tangent is halfway between the tangents at the endpionts. |
| 32 | s->codeAppendf("float2 tan0 = %s[1] - %s[0];", pts, pts); |
| 33 | s->codeAppendf("float2 tan1 = %s[2] - %s[1];", pts, pts); |
| 34 | s->codeAppend ("float2 midnorm = normalize(tan0) - normalize(tan1);"); |
| 35 | s->codeAppend ("float2 T = midnorm * float2x2(tan0 - tan1, tan0);"); |
| 36 | s->codeAppend ("float t = clamp(T.t / T.s, 0, 1);"); // T.s!=0; we cull flat curves on CPU. |
| 37 | |
| 38 | // Clip the bezier triangle by the tangent at our new t value. This is a simple application |
| 39 | // for De Casteljau's algorithm. |
| 40 | s->codeAppendf("float4x2 quadratic_hull = float4x2(%s[0], " |
| 41 | "%s[0] + tan0 * t, " |
| 42 | "%s[1] + tan1 * t, " |
| 43 | "%s[2]);", pts, pts, pts, pts); |
| 44 | *tighterHull = "quadratic_hull"; |
| 45 | } |
Chris Dalton | baf3e78 | 2018-03-08 15:55:58 +0000 | [diff] [blame] | 46 | } |
| 47 | |
| 48 | void GrCCQuadraticShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, |
| 49 | GrGLSLVarying::Scope scope, SkString* code, |
Chris Dalton | 04a1de5 | 2018-03-14 02:04:09 -0600 | [diff] [blame] | 50 | const char* position, const char* coverage, |
Chris Dalton | 4c23934 | 2018-04-05 18:43:40 -0600 | [diff] [blame^] | 51 | const char* cornerCoverage) { |
| 52 | fCoord_fGrad.reset(kFloat4_GrSLType, scope); |
| 53 | varyingHandler->addVarying("coord_and_grad", &fCoord_fGrad); |
Chris Dalton | 21ba551 | 2018-03-21 17:20:21 -0600 | [diff] [blame] | 54 | code->appendf("%s.xy = %s * (%s - %s);", // Quadratic coords. |
Chris Dalton | 4c23934 | 2018-04-05 18:43:40 -0600 | [diff] [blame^] | 55 | OutName(fCoord_fGrad), fQCoordMatrix.c_str(), position, fQCoord0.c_str()); |
Chris Dalton | 21ba551 | 2018-03-21 17:20:21 -0600 | [diff] [blame] | 56 | code->appendf("%s.zw = 2*bloat * float2(2 * %s.x, -1) * %s;", // Gradient. |
Chris Dalton | 4c23934 | 2018-04-05 18:43:40 -0600 | [diff] [blame^] | 57 | OutName(fCoord_fGrad), OutName(fCoord_fGrad), fQCoordMatrix.c_str()); |
Chris Dalton | baf3e78 | 2018-03-08 15:55:58 +0000 | [diff] [blame] | 58 | |
Chris Dalton | 21ba551 | 2018-03-21 17:20:21 -0600 | [diff] [blame] | 59 | // Coverages need full precision since distance to the opposite edge can be large. |
Chris Dalton | 4c23934 | 2018-04-05 18:43:40 -0600 | [diff] [blame^] | 60 | fEdge_fWind_fCorner.reset(cornerCoverage ? kFloat4_GrSLType : kFloat2_GrSLType, scope); |
| 61 | varyingHandler->addVarying("edge_and_wind_and_corner", &fEdge_fWind_fCorner); |
| 62 | code->appendf("float edge = dot(%s, float3(%s, 1));", // Distance to flat opposite edge. |
| 63 | fEdgeDistanceEquation.c_str(), position); |
| 64 | code->appendf("%s.x = edge;", OutName(fEdge_fWind_fCorner)); |
| 65 | code->appendf("%s.y = %s;", OutName(fEdge_fWind_fCorner), coverage); // coverage == wind. |
| 66 | |
| 67 | if (cornerCoverage) { |
| 68 | code->appendf("half hull_coverage;"); |
| 69 | this->calcHullCoverage(code, OutName(fCoord_fGrad), "edge", "hull_coverage"); |
| 70 | code->appendf("%s.zw = half2(hull_coverage, 1) * %s;", |
| 71 | OutName(fEdge_fWind_fCorner), cornerCoverage); |
Chris Dalton | 21ba551 | 2018-03-21 17:20:21 -0600 | [diff] [blame] | 72 | } |
Chris Dalton | baf3e78 | 2018-03-08 15:55:58 +0000 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | void GrCCQuadraticShader::onEmitFragmentCode(GrGLSLFPFragmentBuilder* f, |
| 76 | const char* outputCoverage) const { |
Chris Dalton | 4c23934 | 2018-04-05 18:43:40 -0600 | [diff] [blame^] | 77 | this->calcHullCoverage(&AccessCodeString(f), fCoord_fGrad.fsIn(), |
| 78 | SkStringPrintf("%s.x", fEdge_fWind_fCorner.fsIn()).c_str(), |
| 79 | outputCoverage); |
| 80 | f->codeAppendf("%s *= %s.y;", outputCoverage, fEdge_fWind_fCorner.fsIn()); // Wind. |
Chris Dalton | baf3e78 | 2018-03-08 15:55:58 +0000 | [diff] [blame] | 81 | |
Chris Dalton | 4c23934 | 2018-04-05 18:43:40 -0600 | [diff] [blame^] | 82 | if (kFloat4_GrSLType == fEdge_fWind_fCorner.type()) { |
| 83 | f->codeAppendf("%s = %s.z * %s.w + %s;",// Attenuated corner coverage. |
| 84 | outputCoverage, fEdge_fWind_fCorner.fsIn(), fEdge_fWind_fCorner.fsIn(), |
| 85 | outputCoverage); |
Chris Dalton | 21ba551 | 2018-03-21 17:20:21 -0600 | [diff] [blame] | 86 | } |
Chris Dalton | 6a3dbee | 2017-10-16 10:44:41 -0600 | [diff] [blame] | 87 | } |
Chris Dalton | 4c23934 | 2018-04-05 18:43:40 -0600 | [diff] [blame^] | 88 | |
| 89 | void GrCCQuadraticShader::calcHullCoverage(SkString* code, const char* coordAndGrad, |
| 90 | const char* edge, const char* outputCoverage) const { |
| 91 | code->appendf("float x = %s.x, y = %s.y;", coordAndGrad, coordAndGrad); |
| 92 | code->appendf("float2 grad = %s.zw;", coordAndGrad); |
| 93 | code->append ("float f = x*x - y;"); |
| 94 | code->append ("float fwidth = abs(grad.x) + abs(grad.y);"); |
| 95 | code->appendf("%s = min(0.5 - f/fwidth, 1);", outputCoverage); // Curve coverage. |
| 96 | code->appendf("half d = min(%s, 0);", edge); // Flat edge opposite the curve. |
| 97 | code->appendf("%s = max(%s + d, 0);", outputCoverage, outputCoverage); // Total hull coverage. |
| 98 | } |