ccpr: Draw curves in a single pass
Throws out the complicated MSAA curve corner shaders, and instead just
ramps coverage to zero at bloat vertices that fall outside the curve.
Updates SampleCCPRGeometry to better visualize this new geometry by
clearing to black and drawing with SkBlendMode::kPlus.
Bug: skia:
Change-Id: Ibe86cbc741d8b015127b10dd43e3b52e7cb35732
Reviewed-on: https://skia-review.googlesource.com/112626
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
index 686ab55..76ca8f5 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
@@ -15,35 +15,59 @@
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
+void GrCCCoverageProcessor::getGLSLProcessorKey(const GrShaderCaps&,
+ GrProcessorKeyBuilder* b) const {
+ int key = (int)fRenderPass << 2;
+ if (WindMethod::kInstanceData == fWindMethod) {
+ key |= 2;
+ }
+ if (Impl::kVertexShader == fImpl) {
+ key |= 1;
+ }
+#ifdef SK_DEBUG
+ uint32_t bloatBits;
+ memcpy(&bloatBits, &fDebugBloat, 4);
+ b->add32(bloatBits);
+#endif
+ b->add32(key);
+}
+
+GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGLSLInstance(const GrShaderCaps&) const {
+ std::unique_ptr<Shader> shader;
+ switch (fRenderPass) {
+ case RenderPass::kTriangles:
+ shader = skstd::make_unique<GrCCTriangleShader>();
+ break;
+ case RenderPass::kTriangleCorners:
+ shader = skstd::make_unique<GrCCTriangleCornerShader>();
+ break;
+ case RenderPass::kQuadratics:
+ shader = skstd::make_unique<GrCCQuadraticShader>();
+ break;
+ case RenderPass::kCubics:
+ shader = skstd::make_unique<GrCCCubicShader>();
+ break;
+ }
+ return Impl::kGeometryShader == fImpl ? this->createGSImpl(std::move(shader))
+ : this->createVSImpl(std::move(shader));
+}
+
void GrCCCoverageProcessor::Shader::emitFragmentCode(const GrCCCoverageProcessor& proc,
GrGLSLFPFragmentBuilder* f,
const char* skOutputColor,
const char* skOutputCoverage) const {
f->codeAppendf("half coverage = 0;");
- this->onEmitFragmentCode(f, "coverage");
+ this->onEmitFragmentCode(proc, f, "coverage");
f->codeAppendf("%s.a = coverage;", skOutputColor);
f->codeAppendf("%s = half4(1);", skOutputCoverage);
#ifdef SK_DEBUG
if (proc.debugVisualizationsEnabled()) {
- f->codeAppendf("%s = half4(-%s.a, %s.a, 0, 1);",
- skOutputColor, skOutputColor, skOutputColor);
+ f->codeAppendf("%s = half4(-%s.a, %s.a, 0, abs(%s.a));",
+ skOutputColor, skOutputColor, skOutputColor, skOutputColor);
}
#endif
}
-void GrCCCoverageProcessor::Shader::EmitEdgeDistanceEquation(GrGLSLVertexGeoBuilder* s,
- const char* leftPt,
- const char* rightPt,
- const char* outputDistanceEquation) {
- s->codeAppendf("float2 n = float2(%s.y - %s.y, %s.x - %s.x);",
- rightPt, leftPt, leftPt, rightPt);
- s->codeAppend ("float nwidth = (abs(n.x) + abs(n.y)) * (bloat * 2);");
- // When nwidth=0, wind must also be 0 (and coverage * wind = 0). So it doesn't matter what we
- // come up with here as long as it isn't NaN or Inf.
- s->codeAppend ("n /= (0 != nwidth) ? nwidth : 1;");
- s->codeAppendf("%s = float3(-n, dot(n, %s) - .5);", outputDistanceEquation, leftPt);
-}
-
void GrCCCoverageProcessor::Shader::CalcEdgeCoverageAtBloatVertex(GrGLSLVertexGeoBuilder* s,
const char* leftPt,
const char* rightPt,
@@ -78,66 +102,3 @@
// GPU divides by multiplying by the reciprocal?) It also guards against NaN when nwidth=0.
s->codeAppendf("%s = (abs(t) != nwidth ? t / nwidth : sign(t)) * -.5 - .5;", outputCoverage);
}
-
-int GrCCCoverageProcessor::Shader::DefineSoftSampleLocations(GrGLSLFPFragmentBuilder* f,
- const char* samplesName) {
- // Standard DX11 sample locations.
-#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS)
- f->defineConstant("float2[8]", samplesName, "float2[8]("
- "float2(+1, -3)/16, float2(-1, +3)/16, float2(+5, +1)/16, float2(-3, -5)/16, "
- "float2(-5, +5)/16, float2(-7, -1)/16, float2(+3, +7)/16, float2(+7, -7)/16."
- ")");
- return 8;
-#else
- f->defineConstant("float2[16]", samplesName, "float2[16]("
- "float2(+1, +1)/16, float2(-1, -3)/16, float2(-3, +2)/16, float2(+4, -1)/16, "
- "float2(-5, -2)/16, float2(+2, +5)/16, float2(+5, +3)/16, float2(+3, -5)/16, "
- "float2(-2, +6)/16, float2( 0, -7)/16, float2(-4, -6)/16, float2(-6, +4)/16, "
- "float2(-8, 0)/16, float2(+7, -4)/16, float2(+6, +7)/16, float2(-7, -8)/16."
- ")");
- return 16;
-#endif
-}
-
-void GrCCCoverageProcessor::getGLSLProcessorKey(const GrShaderCaps&,
- GrProcessorKeyBuilder* b) const {
- int key = (int)fRenderPass << 2;
- if (WindMethod::kInstanceData == fWindMethod) {
- key |= 2;
- }
- if (Impl::kVertexShader == fImpl) {
- key |= 1;
- }
-#ifdef SK_DEBUG
- uint32_t bloatBits;
- memcpy(&bloatBits, &fDebugBloat, 4);
- b->add32(bloatBits);
-#endif
- b->add32(key);
-}
-
-GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGLSLInstance(const GrShaderCaps&) const {
- std::unique_ptr<Shader> shader;
- switch (fRenderPass) {
- case RenderPass::kTriangles:
- shader = skstd::make_unique<GrCCTriangleShader>();
- break;
- case RenderPass::kTriangleCorners:
- shader = skstd::make_unique<GrCCTriangleCornerShader>();
- break;
- case RenderPass::kQuadratics:
- shader = skstd::make_unique<GrCCQuadraticHullShader>();
- break;
- case RenderPass::kQuadraticCorners:
- shader = skstd::make_unique<GrCCQuadraticCornerShader>();
- break;
- case RenderPass::kCubics:
- shader = skstd::make_unique<GrCCCubicHullShader>();
- break;
- case RenderPass::kCubicCorners:
- shader = skstd::make_unique<GrCCCubicCornerShader>();
- break;
- }
- return Impl::kGeometryShader == fImpl ? this->createGSImpl(std::move(shader))
- : this->createVSImpl(std::move(shader));
-}