ccpr: Add an attenuation parameter to triangle corners

Adds an attenuation parameter to corners that corrects the over-coverage
from linear interpolation.

Adds a GM for shared corners that ensures we're doing this right.

Bug: skia:
Change-Id: Iff8bd40554f9fda2e7e03faa3c9fbefe65f27568
Reviewed-on: https://skia-review.googlesource.com/114272
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2018-03-14 02:04:09 -06:00 committed by Skia Commit-Bot
parent c2d0dd658b
commit 04a1de5545
11 changed files with 349 additions and 81 deletions

158
gm/sharedcorners.cpp Normal file
View File

@ -0,0 +1,158 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "sk_tool_utils.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkPoint.h"
#include <array>
#include <vector>
namespace skiagm {
static constexpr int kPadSize = 20;
static constexpr int kBoxSize = 100;
static constexpr SkPoint kJitters[] = {{0, 0}, {.5f, .5f}, {2/3.f, 1/3.f}};
// Tests various corners of different angles falling on the same pixel, particularly to ensure
// analytic AA is working properly.
class SharedCornersGM : public GM {
public:
SharedCornersGM() {
this->setBGColor(sk_tool_utils::color_to_565(0xFF1A65D7));
}
protected:
SkString onShortName() override {
return SkString("sharedcorners");
}
SkISize onISize() override {
constexpr int numRows = 3 * 2;
constexpr int numCols = (1 + SK_ARRAY_COUNT(kJitters)) * 2;
return SkISize::Make(numCols * (kBoxSize + kPadSize) + kPadSize,
numRows * (kBoxSize + kPadSize) + kPadSize);
}
void onOnceBeforeDraw() override {
fFillPaint.setColor(SK_ColorWHITE);
fFillPaint.setAntiAlias(true);
fWireFramePaint = fFillPaint;
fWireFramePaint.setStyle(SkPaint::kStroke_Style);
}
void onDraw(SkCanvas* canvas) override {
canvas->translate(kPadSize, kPadSize);
canvas->save();
// Adjacent rects.
this->drawTriangleBoxes(canvas,
{{0, 0}, {40, 0}, {80, 0}, {120, 0},
{0, 20}, {40, 20}, {80, 20}, {120, 20},
{40, 40}, {80, 40},
{40, 60}, {80, 60}},
{{{0, 1, 4}}, {{1, 5, 4}},
{{5, 1, 6}}, {{1, 2, 6}},
{{2, 3, 6}}, {{3, 7, 6}},
{{8, 5, 9}}, {{5, 6, 9}},
{{10, 8, 11}}, {{8, 9, 11}}});
// Obtuse angles.
this->drawTriangleBoxes(canvas,
{{ 0, 0}, {10, 0}, {20, 0},
{ 0, 2}, {20, 2},
{10, 4},
{ 0, 6}, {20, 6},
{ 0, 8}, {10, 8}, {20, 8}},
{{{3, 1, 4}}, {{4, 5, 3}}, {{6, 5, 7}}, {{7, 9, 6}},
{{0, 1, 3}}, {{1, 2, 4}},
{{3, 5, 6}}, {{5, 4, 7}},
{{6, 9, 8}}, {{9, 7, 10}}});
canvas->restore();
canvas->translate((kBoxSize + kPadSize) * 4, 0);
// Right angles.
this->drawTriangleBoxes(canvas,
{{0, 0}, {-1, 0}, {0, -1}, {1, 0}, {0, 1}},
{{{0, 1, 2}}, {{0, 2, 3}}, {{0, 3, 4}}, {{0, 4, 1}}});
// Acute angles.
SkRandom rand;
std::vector<SkPoint> pts;
std::vector<std::array<int, 3>> indices;
SkScalar theta = 0;
pts.push_back({0, 0});
while (theta < 2*SK_ScalarPI) {
pts.push_back({SkScalarCos(theta), SkScalarSin(theta)});
if (pts.size() > 2) {
indices.push_back({{0, (int)pts.size() - 2, (int)pts.size() - 1}});
}
theta += rand.nextRangeF(0, SK_ScalarPI/3);
}
indices.push_back({{0, (int)pts.size() - 1, 1}});
this->drawTriangleBoxes(canvas, pts, indices);
}
void drawTriangleBoxes(SkCanvas* canvas, const std::vector<SkPoint>& points,
const std::vector<std::array<int, 3>>& triangles) {
SkPath path;
path.setFillType(SkPath::kEvenOdd_FillType);
path.setIsVolatile(true);
for (const std::array<int, 3>& triangle : triangles) {
path.moveTo(points[triangle[0]]);
path.lineTo(points[triangle[1]]);
path.lineTo(points[triangle[2]]);
path.close();
}
SkScalar scale = kBoxSize / SkTMax(path.getBounds().height(), path.getBounds().width());
path.transform(SkMatrix::MakeScale(scale, scale));
this->drawRow(canvas, path);
canvas->translate(0, kBoxSize + kPadSize);
SkMatrix rot;
rot.setRotate(45, path.getBounds().centerX(), path.getBounds().centerY());
path.transform(rot);
this->drawRow(canvas, path);
canvas->translate(0, kBoxSize + kPadSize);
rot.setRotate(-45 - 69.38111f, path.getBounds().centerX(), path.getBounds().centerY());
path.transform(rot);
this->drawRow(canvas, path);
canvas->translate(0, kBoxSize + kPadSize);
}
void drawRow(SkCanvas* canvas, const SkPath& path) {
SkAutoCanvasRestore acr(canvas, true);
const SkRect& bounds = path.getBounds();
canvas->translate((kBoxSize - bounds.width()) / 2 - bounds.left(),
(kBoxSize - bounds.height()) / 2 - bounds.top());
canvas->drawPath(path, fWireFramePaint);
canvas->translate(kBoxSize + kPadSize, 0);
for (SkPoint jitter : kJitters) {
{
SkAutoCanvasRestore acr(canvas, true);
canvas->translate(jitter.x(), jitter.y());
canvas->drawPath(path, fFillPaint);
}
canvas->translate(kBoxSize + kPadSize, 0);
}
}
SkPaint fWireFramePaint;
SkPaint fFillPaint;
};
DEF_GM(return new SharedCornersGM;)
}

View File

@ -272,6 +272,7 @@ gm_sources = [
"$_gm/shallowgradient.cpp",
"$_gm/shapes.cpp",
"$_gm/shapes_as_paths.cpp",
"$_gm/sharedcorners.cpp",
"$_gm/showmiplevels.cpp",
"$_gm/simpleaaclip.cpp",
"$_gm/simple_magnification.cpp",

View File

@ -96,6 +96,43 @@ void GrCCCoverageProcessor::Shader::CalcEdgeCoveragesAtBloatVertices(GrGLSLVerte
s->codeAppendf("}");
}
void GrCCCoverageProcessor::Shader::CalcCornerCoverageAttenuation(GrGLSLVertexGeoBuilder* s,
const char* leftDir,
const char* rightDir,
const char* outputAttenuation) {
// obtuseness = cos(corner_angle) if corner_angle > 90 degrees
// 0 if corner_angle <= 90 degrees
s->codeAppendf("half obtuseness = max(dot(%s, %s), 0);", leftDir, rightDir);
// axis_alignedness = 1 when the leftDir/rightDir bisector is aligned with the x- or y-axis
// 0 when the bisector falls on a 45 degree angle
// (i.e. 1 - tan(angle_to_nearest_axis))
s->codeAppendf("half2 abs_bisect = abs(%s - %s);", leftDir, rightDir);
s->codeAppend ("half axis_alignedness = 1 - min(abs_bisect.y, abs_bisect.x) / "
"max(abs_bisect.x, abs_bisect.y);");
// ninety_degreesness = sin^2(corner_angle)
// sin^2 just because... it's always positive and the results looked better than plain sine... ?
s->codeAppendf("half ninety_degreesness = determinant(half2x2(%s, %s));", leftDir, rightDir);
s->codeAppend ("ninety_degreesness = ninety_degreesness * ninety_degreesness;");
// The below formula is not smart. It was just arrived at by considering the following
// observations:
//
// 1. 90-degree, axis-aligned corners have full attenuation along the bisector.
// (i.e. coverage = 1 - distance_to_corner^2)
// (i.e. outputAttenuation = 0)
//
// 2. 180-degree corners always have zero attenuation.
// (i.e. coverage = 1 - distance_to_corner)
// (i.e. outputAttenuation = 1)
//
// 3. 90-degree corners whose bisector falls on a 45 degree angle also do not attenuate.
// (i.e. outputAttenuation = 1)
s->codeAppendf("%s = max(obtuseness, axis_alignedness * ninety_degreesness);",
outputAttenuation);
}
int GrCCCoverageProcessor::Shader::DefineSoftSampleLocations(GrGLSLFPFragmentBuilder* f,
const char* samplesName) {
// Standard DX11 sample locations.

View File

@ -150,10 +150,11 @@ public:
GeometryVars*) const {}
void emitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope,
SkString* code, const char* position, const char* inputCoverage,
const char* wind) {
SkString* code, const char* position, const char* coverage,
const char* attenuatedCoverage, const char* wind) {
SkASSERT(GrGLSLVarying::Scope::kVertToGeo != scope);
this->onEmitVaryings(varyingHandler, scope, code, position, inputCoverage, wind);
this->onEmitVaryings(varyingHandler, scope, code, position, coverage,
attenuatedCoverage, wind);
}
void emitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*,
@ -183,16 +184,24 @@ public:
const char* bloatDir2,
const char* outputCoverages);
// Corner boxes require an additional "attenuation" varying that is multiplied by the
// regular (linearly-interpolated) coverage. This function calculates the attenuation value
// to use in the single, outermost vertex. The remaining three vertices of the corner box
// all use an attenuation value of 1.
static void CalcCornerCoverageAttenuation(GrGLSLVertexGeoBuilder*, const char* leftDir,
const char* rightDir,
const char* outputAttenuation);
virtual ~Shader() {}
protected:
// Here the subclass adds its internal varyings to the handler and produces code to
// initialize those varyings from a given position, input coverage value, and wind.
//
// NOTE: the coverage input is only relevant for triangles. Otherwise it is null.
// NOTE: the coverage inputs are only relevant for triangles. Otherwise they are null.
virtual void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
const char* position, const char* inputCoverage,
const char* wind) = 0;
const char* position, const char* coverage,
const char* attenuatedCoverage, const char* wind) = 0;
// Emits the fragment code that calculates a pixel's signed coverage value.
virtual void onEmitFragmentCode(GrGLSLFPFragmentBuilder*,

View File

@ -80,10 +80,15 @@ protected:
RenderPass::kTriangleCorners == proc.fRenderPass) {
coverage = emitArgs.emplace_back("coverage", kHalf_GrSLType).c_str();
}
const char* attenuatedCoverage = nullptr;
if (RenderPass::kTriangleCorners == proc.fRenderPass) {
attenuatedCoverage = emitArgs.emplace_back("attenuated_coverage",
kHalf2_GrSLType).c_str();
}
g->emitFunction(kVoid_GrSLType, "emitVertex", emitArgs.count(), emitArgs.begin(), [&]() {
SkString fnBody;
fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kGeoToFrag, &fnBody,
position, coverage, wind.c_str());
position, coverage, attenuatedCoverage, wind.c_str());
g->emitVertex(&fnBody, position, rtAdjust);
return fnBody;
}().c_str(), &emitVertexFn);
@ -218,7 +223,7 @@ public:
/**
* Generates conservative rasters around triangle corners (aka pixel-size boxes) and calculates
* coverage ramps that fix up the coverage values written by GSTriangleImpl.
* coverage and attenuation ramps to fix up the coverage values written by GSTriangleImpl.
*/
class GSTriangleCornerImpl : public GrCCCoverageProcessor::GSImpl {
public:
@ -236,36 +241,55 @@ public:
g->codeAppendf("float2 right = pts[(sk_InvocationID + (%s > 0 ? 1 : 2)) %% 3];",
wind.c_str());
g->codeAppend ("float2 leftdir = corner - left;");
g->codeAppend ("leftdir = (float2(0) != leftdir) ? normalize(leftdir) : float2(1, 0);");
g->codeAppend ("float2 rightdir = right - corner;");
g->codeAppend ("rightdir = (float2(0) != rightdir) ? normalize(rightdir) : float2(1, 0);");
// Find "outbloat" and "crossbloat" at our corner. The outbloat points diagonally out of the
// triangle, in the direction that should ramp to zero coverage. The crossbloat runs
// perpindicular to outbloat, and ramps from left-edge coverage to right-edge coverage.
g->codeAppend ("float2 leftdir = normalize(corner - left);");
g->codeAppend ("float2 rightdir = normalize(right - corner);");
// triangle, in the direction that should ramp to zero coverage with attenuation. The
// crossbloat runs perpindicular to outbloat.
g->codeAppend ("float2 outbloat = float2(leftdir.x > rightdir.x ? +1 : -1, "
"leftdir.y > rightdir.y ? +1 : -1);");
g->codeAppend ("float2 crossbloat = float2(-outbloat.y, +outbloat.x);");
g->codeAppend ("half2 left_coverages; {");
Shader::CalcEdgeCoveragesAtBloatVertices(g, "left", "corner", "outbloat", "crossbloat",
Shader::CalcEdgeCoveragesAtBloatVertices(g, "left", "corner", "-outbloat", "-crossbloat",
"left_coverages");
g->codeAppend ("}");
g->codeAppend ("half2 right_coverages; {");
Shader::CalcEdgeCoveragesAtBloatVertices(g, "corner", "right", "outbloat", "-crossbloat",
Shader::CalcEdgeCoveragesAtBloatVertices(g, "corner", "right", "-outbloat", "crossbloat",
"right_coverages");
g->codeAppend ("}");
// Emit a corner box that erases whatever coverage was written previously, and replaces it
// using linearly-interpolated values that ramp to zero in bloat vertices that fall outside
// the triangle.
g->codeAppend ("half attenuation; {");
Shader::CalcCornerCoverageAttenuation(g, "leftdir", "rightdir", "attenuation");
g->codeAppend ("}");
// Emit a corner box. The first coverage argument erases the values that were written
// previously by the hull and edge geometry. The second pair are multiplied together by the
// fragment shader. They ramp to 0 with attenuation in the direction of outbloat, and
// linearly from left-edge coverage to right-edge coverage in the direction of crossbloat.
//
// NOTE: Since this is not a linear mapping, it is important that the box's diagonal shared
// edge points out of the triangle as much as possible.
g->codeAppendf("%s(corner - crossbloat * bloat, -right_coverages[1]);", emitVertexFn);
// edge points in the direction of outbloat.
g->codeAppendf("%s(corner - crossbloat * bloat, "
"right_coverages[1] - left_coverages[1],"
"half2(1 + left_coverages[1], 1));", emitVertexFn);
g->codeAppendf("%s(corner + outbloat * bloat, "
"-1 - left_coverages[0] - right_coverages[0]);", emitVertexFn);
g->codeAppendf("%s(corner - outbloat * bloat, 0);", emitVertexFn);
g->codeAppendf("%s(corner + crossbloat * bloat, -left_coverages[1]);", emitVertexFn);
"1 + left_coverages[0] + right_coverages[0],"
"half2(0, attenuation));", emitVertexFn);
g->codeAppendf("%s(corner - outbloat * bloat, "
"-1 - left_coverages[0] - right_coverages[0],"
"half2(1 + left_coverages[0] + right_coverages[0], 1));", emitVertexFn);
g->codeAppendf("%s(corner + crossbloat * bloat, "
"left_coverages[1] - right_coverages[1],"
"half2(1 + right_coverages[1], 1));", emitVertexFn);
g->configure(InputType::kLines, OutputType::kTriangleStrip, 4, 3);
}

View File

@ -28,6 +28,11 @@ protected:
this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
}
struct Coverages {
const char* fCoverage = nullptr; // half
const char* fAttenuatedCoverage = nullptr; // half2
};
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
const GrCCCoverageProcessor& proc = args.fGP.cast<GrCCCoverageProcessor>();
@ -63,13 +68,15 @@ protected:
#endif
v->defineConstant("bloat", bloat);
const char* coverage = this->emitVertexPosition(proc, v, gpArgs);
Coverages coverages;
this->emitVertexPosition(proc, v, gpArgs, &coverages);
SkASSERT(kFloat2_GrSLType == gpArgs->fPositionVar.getType());
GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
SkString varyingCode;
fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &varyingCode,
gpArgs->fPositionVar.c_str(), coverage, "wind");
gpArgs->fPositionVar.c_str(), coverages.fCoverage,
coverages.fAttenuatedCoverage, "wind");
v->codeAppend(varyingCode.c_str());
varyingHandler->emitAttributes(proc);
@ -79,8 +86,8 @@ protected:
fShader->emitFragmentCode(proc, args.fFragBuilder, args.fOutputColor, args.fOutputCoverage);
}
virtual const char* emitVertexPosition(const GrCCCoverageProcessor&, GrGLSLVertexBuilder*,
GrGPArgs*) const = 0;
virtual void emitVertexPosition(const GrCCCoverageProcessor&, GrGLSLVertexBuilder*, GrGPArgs*,
Coverages* outCoverages) const = 0;
virtual ~VSImpl() {}
@ -187,9 +194,9 @@ static constexpr uint16_t kTriangleIndicesAsStrips[] = {
10, 9, 11, 14, 12, 13, kRestartStrip, // First edge.
16, 15, 17, 20, 18, 19, kRestartStrip, // Second edge.
22, 21, 23, 26, 24, 25, kRestartStrip, // Third edge.
27, 28, 30, 29, kRestartStrip, // First corner.
31, 32, 34, 33, kRestartStrip, // Second corner.
35, 36, 38, 37 // Third corner.
28, 27, 29, 30, kRestartStrip, // First corner.
32, 31, 33, 34, kRestartStrip, // Second corner.
36, 35, 37, 38 // Third corner.
};
static constexpr uint16_t kTriangleIndicesAsTris[] = {
@ -223,16 +230,16 @@ static constexpr uint16_t kTriangleIndicesAsTris[] = {
26, 25, 24,
// First corner.
27, 28, 30,
28, 29, 30,
28, 27, 29,
27, 30, 29,
// Second corner.
31, 32, 34,
32, 33, 34,
32, 31, 33,
31, 34, 33,
// Third corner.
35, 36, 38,
36, 37, 38,
36, 35, 37,
35, 38, 37,
};
GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey);
@ -300,8 +307,8 @@ public:
VSHullAndEdgeImpl(std::unique_ptr<Shader> shader, int numSides)
: VSImpl(std::move(shader)), fNumSides(numSides) {}
const char* emitVertexPosition(const GrCCCoverageProcessor& proc, GrGLSLVertexBuilder* v,
GrGPArgs* gpArgs) const override {
void emitVertexPosition(const GrCCCoverageProcessor& proc, GrGLSLVertexBuilder* v,
GrGPArgs* gpArgs, Coverages* outCoverages) const override {
Shader::GeometryVars vars;
fShader->emitSetupCode(v, "pts", nullptr, "wind", &vars);
@ -344,22 +351,26 @@ public:
v->codeAppend ("float2 bloatdir = leftbloat;");
if (3 == fNumSides) { // Only triangles emit corner boxes.
v->codeAppend ("float2 leftdir = corner - left;");
v->codeAppend ("leftdir = (float2(0) != leftdir) ? normalize(leftdir) : float2(1, 0);");
v->codeAppend ("float2 rightdir = right - corner;");
v->codeAppend ("rightdir = (float2(0) != rightdir)"
"? normalize(rightdir) : float2(1, 0);");
v->codeAppendf("if (0 != (%s & %i)) {", // Are we a corner?
proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_IsCornerBit);
// For corner boxes, we hack 'left_right_notequal' to [true, true].
// This causes the upcoming code to always rotate, which is the right
// thing for corners.
v->codeAppendf( "left_right_notequal = bool2(true, true);");
// In corner boxes, all 4 coverage values will not map linearly.
// Therefore it is important to align the box so its diagonal shared
// edge points out of the triangle, in the direction that ramps to 0.
v->codeAppend ( "bloatdir = float2(leftdir.x > rightdir.x ? +1 : -1, "
"leftdir.y > rightdir.y ? +1 : -1);");
// In corner boxes, all 4 coverage values will not map linearly, so
// it is important to rotate the box so its diagonal shared edge
// points out of the triangle, in the direction that ramps to zero.
v->codeAppend ( "float2 bisect = normalize(corner - right) +"
"normalize(corner - left);");
v->codeAppend ( "if (sign(bisect) == sign(leftbloat)) {");
v->codeAppend ( "bloatdir = float2(+bloatdir.y, -bloatdir.x);");
v->codeAppend ( "}");
// For corner boxes, we hack left_right_notequal to always true. This
// in turn causes the upcoming code to always rotate, generating all
// 4 vertices of the corner box.
v->codeAppendf( "left_right_notequal = bool2(true);");
v->codeAppend ("}");
}
@ -392,12 +403,14 @@ public:
v->codeAppend ("float2 vertex = corner + bloatdir * bloat;");
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
// For triangles, we also emit coverage in order to handle edges and corners.
const char* coverage = nullptr;
// For triangles, we also emit coverage and attenuation.
if (3 == fNumSides) {
// The hull has a coverage of +1 all around.
v->codeAppend ("half coverage = +1;");
// Corner boxes require attenuation.
v->codeAppend ("half2 attenuated_coverage = half2(0);");
v->codeAppendf("if (0 != (%s & %i)) {", // Are we an edge OR corner?
proc.getAttrib(kAttribIdx_VertexData).fName,
kVertexData_IsEdgeBit | kVertexData_IsCornerBit);
@ -406,20 +419,31 @@ public:
v->codeAppendf("if (0 != (%s & %i)) {", // Are we a corner?
proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_IsCornerBit);
// Corner boxes erase whatever coverage was written previously, and
// replace it with linearly-interpolated values that ramp to zero in
// the diagonal that points out of the triangle, and ramp from
// left-edge coverage to right-edge coverage in the other diagonal.
v->codeAppend ( "half left_coverage = coverage;");
v->codeAppend ( "half right_coverage;");
Shader::CalcEdgeCoverageAtBloatVertex(v, "corner", "right", "bloatdir",
"right_coverage");
v->codeAppend ( "coverage = (1 == bloatidx) ? -1 : 0;");
v->codeAppend ( "if (((bloatidx + 3) & 3) < 2) {");
v->codeAppend ( "coverage -= left_coverage;");
v->codeAppend ( "half attenuation;");
Shader::CalcCornerCoverageAttenuation(v, "leftdir", "rightdir", "attenuation");
// For corners, "coverage" erases the values that were written
// previously by the hull and edge geometry.
v->codeAppend ( "coverage = -1 - left_coverage - right_coverage;");
// The x and y components of "attenuated_coverage" are multiplied
// together by the fragment shader. They ramp to 0 with attenuation
// in the diagonal that points out of the triangle, and linearly from
// left-edge coverage to right in the opposite diagonal. bloatidx=0
// is the outermost vertex; the one that has attenuation.
v->codeAppend ( "attenuated_coverage = (0 == bloatidx)"
"? half2(0, attenuation) : half2(1);");
v->codeAppend ( "if (1 == bloatidx || 2 == bloatidx) {");
v->codeAppend ( "attenuated_coverage.x += right_coverage;");
v->codeAppend ( "}");
v->codeAppend ( "if (bloatidx < 2) {");
v->codeAppend ( "coverage -= right_coverage;");
v->codeAppend ( "if (bloatidx >= 2) {");
v->codeAppend ( "attenuated_coverage.x += left_coverage;");
v->codeAppend ( "}");
v->codeAppend ("}");
@ -429,10 +453,9 @@ public:
v->codeAppend ( "coverage = -1 - coverage;");
v->codeAppend ("}");
coverage = "coverage";
outCoverages->fCoverage = "coverage";
outCoverages->fAttenuatedCoverage = "attenuated_coverage";
}
return coverage;
}
private:
@ -463,8 +486,8 @@ class VSCornerImpl : public GrCCCoverageProcessor::VSImpl {
public:
VSCornerImpl(std::unique_ptr<Shader> shader) : VSImpl(std::move(shader)) {}
const char* emitVertexPosition(const GrCCCoverageProcessor&, GrGLSLVertexBuilder* v,
GrGPArgs* gpArgs) const override {
void emitVertexPosition(const GrCCCoverageProcessor&, GrGLSLVertexBuilder* v, GrGPArgs* gpArgs,
Coverages* /*outCoverages*/) const override {
Shader::GeometryVars vars;
v->codeAppend ("int corner_id = sk_VertexID / 4;");
fShader->emitSetupCode(v, "pts", "corner_id", "wind", &vars);
@ -474,7 +497,6 @@ public:
v->codeAppend ("vertex.y += (0 == (sk_VertexID & 1)) ? -bloat : +bloat;");
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
return nullptr; // Corner vertices don't have an initial coverage value.
}
};

View File

@ -79,9 +79,10 @@ void GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
void GrCCCubicShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
GrGLSLVarying::Scope scope, SkString* code,
const char* position, const char* inputCoverage,
const char* /*wind*/) {
SkASSERT(!inputCoverage);
const char* position, const char* coverage,
const char* attenuatedCoverage, const char* /*wind*/) {
SkASSERT(!coverage);
SkASSERT(!attenuatedCoverage);
fKLMD.reset(kFloat4_GrSLType, scope);
varyingHandler->addVarying("klmd", &fKLMD);

View File

@ -29,7 +29,8 @@ protected:
GeometryVars*) const {}
void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
const char* position, const char* inputCoverage, const char* wind) final;
const char* position, const char* coverage, const char* attenuatedCoverage,
const char* wind) final;
virtual void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) = 0;
void onEmitFragmentCode(GrGLSLFPFragmentBuilder*, const char* outputCoverage) const final;

View File

@ -35,9 +35,10 @@ void GrCCQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* p
void GrCCQuadraticShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
GrGLSLVarying::Scope scope, SkString* code,
const char* position, const char* inputCoverage,
const char* wind) {
SkASSERT(!inputCoverage);
const char* position, const char* coverage,
const char* attenuatedCoverage, const char* wind) {
SkASSERT(!coverage);
SkASSERT(!attenuatedCoverage);
fXYDW.reset(kFloat4_GrSLType, scope);
varyingHandler->addVarying("xydw", &fXYDW);

View File

@ -28,7 +28,8 @@ protected:
GeometryVars*) const = 0;
void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
const char* position, const char* inputCoverage, const char* wind) final;
const char* position, const char* coverage, const char* attenuatedCoverage,
const char* wind) final;
virtual void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code) {}
void onEmitFragmentCode(GrGLSLFPFragmentBuilder*, const char* outputCoverage) const final;

View File

@ -18,16 +18,29 @@
*/
class GrCCTriangleShader : public GrCCCoverageProcessor::Shader {
void onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope,
SkString* code, const char* /*position*/, const char* inputCoverage,
const char* wind) override {
SkASSERT(inputCoverage);
fCoverageTimesWind.reset(kHalf_GrSLType, scope);
varyingHandler->addVarying("coverage_times_wind", &fCoverageTimesWind);
code->appendf("%s = %s * %s;", OutName(fCoverageTimesWind), inputCoverage, wind);
SkString* code, const char* position, const char* coverage,
const char* attenuatedCoverage, const char* wind) override {
if (!attenuatedCoverage) {
fCoverageTimesWind.reset(kHalf_GrSLType, scope);
varyingHandler->addVarying("coverage_times_wind", &fCoverageTimesWind);
code->appendf("%s = %s * %s;", OutName(fCoverageTimesWind), coverage, wind);
} else {
fCoverageTimesWind.reset(kHalf3_GrSLType, scope);
varyingHandler->addVarying("coverage_times_wind", &fCoverageTimesWind);
code->appendf("%s = half3(%s, %s);",
OutName(fCoverageTimesWind), attenuatedCoverage, coverage);
code->appendf("%s.yz *= %s;", OutName(fCoverageTimesWind), wind);
}
}
void onEmitFragmentCode(GrGLSLFPFragmentBuilder* f, const char* outputCoverage) const override {
f->codeAppendf("%s = %s;", outputCoverage, fCoverageTimesWind.fsIn());
if (kHalf_GrSLType == fCoverageTimesWind.type()) {
f->codeAppendf("%s = %s;", outputCoverage, fCoverageTimesWind.fsIn());
} else {
f->codeAppendf("%s = %s.x * %s.y + %s.z;",
outputCoverage, fCoverageTimesWind.fsIn(), fCoverageTimesWind.fsIn(),
fCoverageTimesWind.fsIn());
}
}
GrGLSLVarying fCoverageTimesWind;