ccpr: Simplify triangle corners
Modifies triangle corner shaders to just approximate their coverage with
linear values that ramp to zero at bloat vertices outside the triangle.
For the vertex backend, since corners now have the same fragment shader
as the rest of the triangle, we fold them in with the other steps and
draw triangles in a single pass.
The geometry backend still draws triangles in two passes, as there is
not an apparent performance advantage in combining them.
Bug: skia:
Change-Id: Ib4a89d793a3c706f734d0271875c8a3e5c87c49b
Reviewed-on: https://skia-review.googlesource.com/112632
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 76ca8f5..3a9eb7b 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
@@ -7,17 +7,21 @@
#include "GrCCCoverageProcessor.h"
+#include "GrGpuCommandBuffer.h"
+#include "GrOpFlushState.h"
#include "SkMakeUnique.h"
#include "ccpr/GrCCCubicShader.h"
#include "ccpr/GrCCQuadraticShader.h"
-#include "ccpr/GrCCTriangleShader.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
void GrCCCoverageProcessor::getGLSLProcessorKey(const GrShaderCaps&,
GrProcessorKeyBuilder* b) const {
- int key = (int)fRenderPass << 2;
+ int key = ((int)fRenderPass << 3);
+ if (GSTriangleSubpass::kCorners == fGSTriangleSubpass) {
+ key |= 4;
+ }
if (WindMethod::kInstanceData == fWindMethod) {
key |= 2;
}
@@ -36,10 +40,7 @@
std::unique_ptr<Shader> shader;
switch (fRenderPass) {
case RenderPass::kTriangles:
- shader = skstd::make_unique<GrCCTriangleShader>();
- break;
- case RenderPass::kTriangleCorners:
- shader = skstd::make_unique<GrCCTriangleCornerShader>();
+ shader = skstd::make_unique<Shader>();
break;
case RenderPass::kQuadratics:
shader = skstd::make_unique<GrCCQuadraticShader>();
@@ -52,12 +53,45 @@
: this->createVSImpl(std::move(shader));
}
+void GrCCCoverageProcessor::draw(GrOpFlushState* flushState, const GrPipeline& pipeline,
+ const GrMesh meshes[],
+ const GrPipeline::DynamicState dynamicStates[], int meshCount,
+ const SkRect& drawBounds) const {
+ GrGpuRTCommandBuffer* cmdBuff = flushState->rtCommandBuffer();
+ cmdBuff->draw(pipeline, *this, meshes, dynamicStates, meshCount, drawBounds);
+
+ // Geometry shader backend draws triangles in two subpasses.
+ if (RenderPass::kTriangles == fRenderPass && Impl::kGeometryShader == fImpl) {
+ SkASSERT(GSTriangleSubpass::kHullsAndEdges == fGSTriangleSubpass);
+ GrCCCoverageProcessor cornerProc(*this, GSTriangleSubpass::kCorners);
+ cmdBuff->draw(pipeline, cornerProc, meshes, dynamicStates, meshCount, drawBounds);
+ }
+}
+
+void GrCCCoverageProcessor::Shader::emitVaryings(GrGLSLVaryingHandler* varyingHandler,
+ GrGLSLVarying::Scope scope, SkString* code,
+ const char* position, const char* coverage,
+ const char* wind) {
+ SkASSERT(GrGLSLVarying::Scope::kVertToGeo != scope);
+ code->appendf("half coverageTimesWind = %s * %s;", coverage, wind);
+ CoverageHandling coverageHandling = this->onEmitVaryings(varyingHandler, scope, code, position,
+ "coverageTimesWind");
+ if (CoverageHandling::kNotHandled == coverageHandling) {
+ fCoverageTimesWind.reset(kHalf_GrSLType, scope);
+ varyingHandler->addVarying("coverage_times_wind", &fCoverageTimesWind);
+ code->appendf("%s = coverageTimesWind;", OutName(fCoverageTimesWind));
+ }
+}
+
void GrCCCoverageProcessor::Shader::emitFragmentCode(const GrCCCoverageProcessor& proc,
GrGLSLFPFragmentBuilder* f,
const char* skOutputColor,
const char* skOutputCoverage) const {
- f->codeAppendf("half coverage = 0;");
+ f->codeAppendf("half coverage = +1;");
this->onEmitFragmentCode(proc, f, "coverage");
+ if (fCoverageTimesWind.fsIn()) {
+ f->codeAppendf("coverage *= %s;", fCoverageTimesWind.fsIn());
+ }
f->codeAppendf("%s.a = coverage;", skOutputColor);
f->codeAppendf("%s = half4(1);", skOutputCoverage);
#ifdef SK_DEBUG
@@ -102,3 +136,20 @@
// 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);
}
+
+void GrCCCoverageProcessor::Shader::CalcEdgeCoveragesAtBloatVertices(GrGLSLVertexGeoBuilder* s,
+ const char* leftPt,
+ const char* rightPt,
+ const char* bloatDir1,
+ const char* bloatDir2,
+ const char* outputCoverages) {
+ // See comments in CalcEdgeCoverageAtBloatVertex.
+ 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);");
+ s->codeAppendf("float2 t = n * float2x2(%s, %s);", bloatDir1, bloatDir2);
+ s->codeAppendf("for (int i = 0; i < 2; ++i) {");
+ s->codeAppendf( "%s[i] = (abs(t[i]) != nwidth ? t[i] / nwidth : sign(t[i])) * -.5 - .5;",
+ outputCoverages);
+ s->codeAppendf("}");
+}