From e7fbafe1da930eba9e24f60fefef5a440f715219 Mon Sep 17 00:00:00 2001 From: Chris Dalton Date: Mon, 16 Apr 2018 22:45:32 +0000 Subject: Revert "ccpr: Implement conics" This reverts commit 98b241573e6083c4c7f0ce9e30cc214c4da1a8ba. Reason for revert: TSAN not happy Original change's description: > ccpr: Implement conics > > Bug: skia: > Change-Id: I4bae8b059072af987abb7b2d9c57fe08f783d680 > Reviewed-on: https://skia-review.googlesource.com/120040 > Commit-Queue: Chris Dalton > Reviewed-by: Greg Daniel TBR=egdaniel@google.com,bsalomon@google.com,csmartdalton@google.com Change-Id: Ic29bf660f042c20b7e4492b03400412e378dbb8a No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: skia: Reviewed-on: https://skia-review.googlesource.com/121717 Reviewed-by: Chris Dalton Commit-Queue: Chris Dalton --- gn/gpu.gni | 2 - samplecode/SampleCCPRGeometry.cpp | 78 +++--------- src/gpu/ccpr/GrCCConicShader.cpp | 93 -------------- src/gpu/ccpr/GrCCConicShader.h | 44 ------- src/gpu/ccpr/GrCCCoverageProcessor.cpp | 4 - src/gpu/ccpr/GrCCCoverageProcessor.h | 19 +-- src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp | 8 +- src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp | 12 +- src/gpu/ccpr/GrCCGeometry.cpp | 161 +++--------------------- src/gpu/ccpr/GrCCGeometry.h | 19 +-- src/gpu/ccpr/GrCCPathParser.cpp | 35 +----- src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp | 9 ++ tests/SkNxTest.cpp | 16 +-- 13 files changed, 64 insertions(+), 436 deletions(-) delete mode 100644 src/gpu/ccpr/GrCCConicShader.cpp delete mode 100644 src/gpu/ccpr/GrCCConicShader.h diff --git a/gn/gpu.gni b/gn/gpu.gni index 913270dd43..774b2a70d5 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -300,8 +300,6 @@ skia_gpu_sources = [ "$_src/gpu/ccpr/GrCCAtlas.h", "$_src/gpu/ccpr/GrCCClipProcessor.cpp", "$_src/gpu/ccpr/GrCCClipProcessor.h", - "$_src/gpu/ccpr/GrCCConicShader.cpp", - "$_src/gpu/ccpr/GrCCConicShader.h", "$_src/gpu/ccpr/GrCCCoverageProcessor.cpp", "$_src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp", "$_src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp", diff --git a/samplecode/SampleCCPRGeometry.cpp b/samplecode/SampleCCPRGeometry.cpp index 52e1181e8c..a6e408749a 100644 --- a/samplecode/SampleCCPRGeometry.cpp +++ b/samplecode/SampleCCPRGeometry.cpp @@ -63,8 +63,6 @@ private: SkPoint fPoints[4] = { {100.05f, 100.05f}, {400.75f, 100.05f}, {400.75f, 300.95f}, {100.05f, 300.95f}}; - float fConicWeight = .5; - SkTArray fTriPointInstances; SkTArray fQuadPointInstances; @@ -150,22 +148,14 @@ void CCPRGeometryView::onDrawContent(SkCanvas* canvas) { SkPath outline; outline.moveTo(fPoints[0]); - switch (fPrimitiveType) { - case PrimitiveType::kTriangles: - case PrimitiveType::kWeightedTriangles: - outline.lineTo(fPoints[1]); - outline.lineTo(fPoints[3]); - outline.close(); - break; - case PrimitiveType::kQuadratics: - outline.quadTo(fPoints[1], fPoints[3]); - break; - case PrimitiveType::kCubics: - outline.cubicTo(fPoints[1], fPoints[2], fPoints[3]); - break; - case PrimitiveType::kConics: - outline.conicTo(fPoints[1], fPoints[3], fConicWeight); - break; + if (PrimitiveType::kCubics == fPrimitiveType) { + outline.cubicTo(fPoints[1], fPoints[2], fPoints[3]); + } else if (PrimitiveType::kQuadratics == fPrimitiveType) { + outline.quadTo(fPoints[1], fPoints[3]); + } else { + outline.lineTo(fPoints[1]); + outline.lineTo(fPoints[3]); + outline.close(); } SkPaint outlinePaint; @@ -218,8 +208,6 @@ void CCPRGeometryView::onDrawContent(SkCanvas* canvas) { GrCCCoverageProcessor::PrimitiveTypeName(fPrimitiveType)); if (PrimitiveType::kCubics == fPrimitiveType) { caption.appendf(" (%s)", SkCubicTypeName(fCubicType)); - } else if (PrimitiveType::kConics == fPrimitiveType) { - caption.appendf(" (w=%f)", fConicWeight); } } else { caption = "Use GPU backend to visualize geometry."; @@ -276,18 +264,13 @@ void CCPRGeometryView::updateGpuData() { continue; } } - } else if (PrimitiveType::kTriangles != fPrimitiveType) { + } else if (PrimitiveType::kQuadratics == fPrimitiveType) { SkPoint P3[3] = {fPoints[0], fPoints[1], fPoints[3]}; GrCCGeometry geometry; geometry.beginContour(P3[0]); - if (PrimitiveType::kQuadratics == fPrimitiveType) { - geometry.quadraticTo(P3); - } else { - SkASSERT(PrimitiveType::kConics == fPrimitiveType); - geometry.conicTo(P3, fConicWeight); - } + geometry.quadraticTo(P3); geometry.endContour(); - int ptsIdx = 0, conicWeightIdx = 0; + int ptsIdx = 0; for (GrCCGeometry::Verb verb : geometry.verbs()) { if (GrCCGeometry::Verb::kBeginContour == verb || GrCCGeometry::Verb::kEndOpenContour == verb || @@ -298,16 +281,8 @@ void CCPRGeometryView::updateGpuData() { ++ptsIdx; continue; } - SkASSERT(GrCCGeometry::Verb::kMonotonicQuadraticTo == verb || - GrCCGeometry::Verb::kMonotonicConicTo == verb); - if (PrimitiveType::kQuadratics == fPrimitiveType && - GrCCGeometry::Verb::kMonotonicQuadraticTo == verb) { - fTriPointInstances.push_back().set(&geometry.points()[ptsIdx], Sk2f(0, 0)); - } else if (PrimitiveType::kConics == fPrimitiveType && - GrCCGeometry::Verb::kMonotonicConicTo == verb) { - fQuadPointInstances.push_back().setW(&geometry.points()[ptsIdx], Sk2f(0, 0), - geometry.getConicWeight(conicWeightIdx++)); - } + SkASSERT(GrCCGeometry::Verb::kMonotonicQuadraticTo == verb); + fTriPointInstances.push_back().set(&geometry.points()[ptsIdx], Sk2f(0, 0)); ptsIdx += 2; } } else { @@ -326,8 +301,7 @@ void CCPRGeometryView::DrawCoverageCountOp::onExecute(GrOpFlushState* state) { SkDEBUGCODE(proc.enableDebugBloat(kDebugBloat)); SkSTArray<1, GrMesh> mesh; - if (PrimitiveType::kCubics == fView->fPrimitiveType || - PrimitiveType::kConics == fView->fPrimitiveType) { + if (PrimitiveType::kCubics == fView->fPrimitiveType) { sk_sp instBuff(rp->createBuffer( fView->fQuadPointInstances.count() * sizeof(QuadPointInstance), kVertex_GrBufferType, kDynamic_GrAccessPattern, @@ -415,7 +389,7 @@ bool CCPRGeometryView::onQuery(SkEvent* evt) { } SkUnichar unichar; if (SampleCode::CharQ(*evt, &unichar)) { - if (unichar >= '1' && unichar <= '4') { + if (unichar >= '1' && unichar <= '3') { fPrimitiveType = PrimitiveType(unichar - '1'); if (fPrimitiveType >= PrimitiveType::kWeightedTriangles) { fPrimitiveType = (PrimitiveType) ((int)fPrimitiveType + 1); @@ -423,28 +397,6 @@ bool CCPRGeometryView::onQuery(SkEvent* evt) { this->updateAndInval(); return true; } - if (PrimitiveType::kConics == fPrimitiveType) { - if (unichar == '+') { - fConicWeight *= 2; - this->updateAndInval(); - return true; - } - if (unichar == '+' || unichar == '=') { - fConicWeight *= 5/4.f; - this->updateAndInval(); - return true; - } - if (unichar == '-') { - fConicWeight *= 4/5.f; - this->updateAndInval(); - return true; - } - if (unichar == '_') { - fConicWeight *= .5f; - this->updateAndInval(); - return true; - } - } if (unichar == 'D') { SkDebugf(" SkPoint fPoints[4] = {\n"); SkDebugf(" {%ff, %ff},\n", fPoints[0].x(), fPoints[0].y()); diff --git a/src/gpu/ccpr/GrCCConicShader.cpp b/src/gpu/ccpr/GrCCConicShader.cpp deleted file mode 100644 index 01568de437..0000000000 --- a/src/gpu/ccpr/GrCCConicShader.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 "GrCCConicShader.h" - -#include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLVertexGeoBuilder.h" - -void GrCCConicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts, const char* wind, - const char** outHull4) const { - // K is distance from the line P2 -> P0. L is distance from the line P0 -> P1, scaled by 2w. - // M is distance from the line P1 -> P2, scaled by 2w. We do this in a space where P1=0. - s->declareGlobal(fKLMMatrix); - s->codeAppendf("float x0 = %s[0].x - %s[1].x, x2 = %s[2].x - %s[1].x;", pts, pts, pts, pts); - s->codeAppendf("float y0 = %s[0].y - %s[1].y, y2 = %s[2].y - %s[1].y;", pts, pts, pts, pts); - s->codeAppendf("float w = %s[3].x;", pts); - s->codeAppendf("%s = float3x3(y2 - y0, x0 - x2, x2*y0 - x0*y2, " - "2*w * float2(+y0, -x0), 0, " - "2*w * float2(-y2, +x2), 0);", fKLMMatrix.c_str()); - - s->declareGlobal(fControlPoint); - s->codeAppendf("%s = %s[1];", fControlPoint.c_str(), pts); - - // Scale KLM by the inverse Manhattan width of K. This allows K to double as the flat opposite - // edge AA. kwidth will not be 0 because we cull degenerate conics on the CPU. - s->codeAppendf("float kwidth = 2*bloat * %s * (abs(%s[0].x) + abs(%s[0].y));", - wind, fKLMMatrix.c_str(), fKLMMatrix.c_str()); - s->codeAppendf("%s *= 1/kwidth;", fKLMMatrix.c_str()); - - if (outHull4) { - // Clip the conic triangle by the tangent line at maximum height. Conics have the nice - // property that maximum height always occurs at T=.5. This is a simple application for - // De Casteljau's algorithm. - s->codeAppendf("float2 p1w = %s[1]*w;", pts); - s->codeAppend ("float r = 1 / (1 + w);"); - s->codeAppendf("float2 conic_hull[4] = float2[4](%s[0], " - "(%s[0] + p1w) * r, " - "(p1w + %s[2]) * r, " - "%s[2]);", pts, pts, pts, pts); - *outHull4 = "conic_hull"; - } -} - -void GrCCConicShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, - GrGLSLVarying::Scope scope, SkString* code, - const char* position, const char* coverage, - const char* cornerCoverage) { - fKLM_fWind.reset(kFloat4_GrSLType, scope); - varyingHandler->addVarying("klm_and_wind", &fKLM_fWind); - code->appendf("float3 klm = float3(%s - %s, 1) * %s;", - position, fControlPoint.c_str(), fKLMMatrix.c_str()); - code->appendf("%s.xyz = klm;", OutName(fKLM_fWind)); - code->appendf("%s.w = %s;", OutName(fKLM_fWind), coverage); // coverage == wind. - - fGrad_fCorner.reset(cornerCoverage ? kFloat4_GrSLType : kFloat2_GrSLType, scope); - varyingHandler->addVarying(cornerCoverage ? "grad_and_corner" : "grad", &fGrad_fCorner); - code->appendf("%s.xy = 2*bloat * (float3x2(%s) * float3(2*klm[0], -klm[2], -klm[1]));", - OutName(fGrad_fCorner), fKLMMatrix.c_str()); - - if (cornerCoverage) { - code->appendf("half hull_coverage;"); - this->calcHullCoverage(code, "klm", OutName(fGrad_fCorner), "hull_coverage"); - code->appendf("%s.zw = half2(hull_coverage, 1) * %s;", - OutName(fGrad_fCorner), cornerCoverage); - } -} - -void GrCCConicShader::onEmitFragmentCode(GrGLSLFPFragmentBuilder* f, - const char* outputCoverage) const { - this->calcHullCoverage(&AccessCodeString(f), fKLM_fWind.fsIn(), fGrad_fCorner.fsIn(), - outputCoverage); - f->codeAppendf("%s *= %s.w;", outputCoverage, fKLM_fWind.fsIn()); // Wind. - - if (kFloat4_GrSLType == fGrad_fCorner.type()) { - f->codeAppendf("%s = %s.z * %s.w + %s;", // Attenuated corner coverage. - outputCoverage, fGrad_fCorner.fsIn(), fGrad_fCorner.fsIn(), - outputCoverage); - } -} - -void GrCCConicShader::calcHullCoverage(SkString* code, const char* klm, const char* grad, - const char* outputCoverage) const { - code->appendf("float k = %s.x, l = %s.y, m = %s.z;", klm, klm, klm); - code->append ("float f = k*k - l*m;"); - code->appendf("float fwidth = abs(%s.x) + abs(%s.y);", grad, grad); - code->appendf("%s = min(0.5 - f/fwidth, 1);", outputCoverage); // Curve coverage. - code->append ("half d = min(k - 0.5, 0);"); // K doubles as the flat opposite edge's AA. - code->appendf("%s = max(%s + d, 0);", outputCoverage, outputCoverage); // Total hull coverage. -} diff --git a/src/gpu/ccpr/GrCCConicShader.h b/src/gpu/ccpr/GrCCConicShader.h deleted file mode 100644 index 16b70e7072..0000000000 --- a/src/gpu/ccpr/GrCCConicShader.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrCCConicShader_DEFINED -#define GrCCConicShader_DEFINED - -#include "ccpr/GrCCCoverageProcessor.h" - -/** - * This class renders the coverage of closed conic curves using the techniques outlined in - * "Resolution Independent Curve Rendering using Programmable Graphics Hardware" by Charles Loop and - * Jim Blinn: - * - * https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf - * - * The provided curves must be monotonic with respect to the vector of their closing edge [P2 - P0]. - * (Use GrCCGeometry::conicTo().) - */ -class GrCCConicShader : public GrCCCoverageProcessor::Shader { -public: - void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* wind, - const char** outHull4) const override; - - void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, - const char* position, const char* coverage, - const char* cornerCoverage) override; - - void onEmitFragmentCode(GrGLSLFPFragmentBuilder*, const char* outputCoverage) const override; - -private: - void calcHullCoverage(SkString* code, const char* klm, const char* grad, - const char* outputCoverage) const; - - const GrShaderVar fKLMMatrix{"klm_matrix", kFloat3x3_GrSLType}; - const GrShaderVar fControlPoint{"control_point", kFloat2_GrSLType}; - GrGLSLVarying fKLM_fWind; - GrGLSLVarying fGrad_fCorner; -}; - -#endif diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp index d38db27a19..b94b188e69 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp +++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp @@ -10,7 +10,6 @@ #include "GrGpuCommandBuffer.h" #include "GrOpFlushState.h" #include "SkMakeUnique.h" -#include "ccpr/GrCCConicShader.h" #include "ccpr/GrCCCubicShader.h" #include "ccpr/GrCCQuadraticShader.h" #include "glsl/GrGLSLVertexGeoBuilder.h" @@ -175,9 +174,6 @@ GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGLSLInstance(const GrShad case PrimitiveType::kCubics: shader = skstd::make_unique(); break; - case PrimitiveType::kConics: - shader = skstd::make_unique(); - break; } return Impl::kGeometryShader == fImpl ? this->createGSImpl(std::move(shader)) : this->createVSImpl(std::move(shader)); diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h index 454e728ae9..68180270b1 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor.h +++ b/src/gpu/ccpr/GrCCCoverageProcessor.h @@ -40,7 +40,6 @@ public: kWeightedTriangles, // Triangles (from the tessellator) whose winding magnitude > 1. kQuadratics, kCubics, - kConics }; static const char* PrimitiveTypeName(PrimitiveType); @@ -54,15 +53,14 @@ public: void set(const SkPoint&, const SkPoint&, const SkPoint&, const Sk2f& trans); }; - // Defines a single primitive shape with 4 input points, or 3 input points plus a "weight" - // parameter duplicated in both lanes of the 4th input (i.e. Cubics, Conics, and Triangles with - // a weighted winding number). X,Y point values are transposed. + // Defines a single primitive shape with 4 input points, or 3 input points plus a W parameter + // duplicated in both 4th components (i.e. Cubics or Triangles with a custom winding number). + // X,Y point values are transposed. struct QuadPointInstance { float fX[4]; float fY[4]; void set(const SkPoint[4], float dx, float dy); - void setW(const SkPoint[3], const Sk2f& trans, float w); void setW(const SkPoint&, const SkPoint&, const SkPoint&, const Sk2f& trans, float w); }; @@ -207,11 +205,6 @@ private: // Number of bezier points for curves, or 3 for triangles. int numInputPoints() const { return PrimitiveType::kCubics == fPrimitiveType ? 4 : 3; } - int hasInputWeight() const { - return PrimitiveType::kWeightedTriangles == fPrimitiveType || - PrimitiveType::kConics == fPrimitiveType; - } - enum class Impl : bool { kGeometryShader, kVertexShader @@ -266,7 +259,6 @@ inline const char* GrCCCoverageProcessor::PrimitiveTypeName(PrimitiveType type) case PrimitiveType::kWeightedTriangles: return "kWeightedTriangles"; case PrimitiveType::kQuadratics: return "kQuadratics"; case PrimitiveType::kCubics: return "kCubics"; - case PrimitiveType::kConics: return "kConics"; } SK_ABORT("Invalid PrimitiveType"); return ""; @@ -291,11 +283,6 @@ inline void GrCCCoverageProcessor::QuadPointInstance::set(const SkPoint p[4], fl (Y + dy).store(&fY); } -inline void GrCCCoverageProcessor::QuadPointInstance::setW(const SkPoint p[3], const Sk2f& trans, - float w) { - this->setW(p[0], p[1], p[2], trans, w); -} - inline void GrCCCoverageProcessor::QuadPointInstance::setW(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2, const Sk2f& trans, float w) { diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp index b1d886cf8c..f933030177 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp +++ b/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp @@ -52,10 +52,9 @@ protected: int numInputPoints = proc.numInputPoints(); SkASSERT(3 == numInputPoints || 4 == numInputPoints); - int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3; - const char* posValues = (4 == inputWidth) ? "sk_Position" : "sk_Position.xyz"; + const char* posValues = (4 == numInputPoints) ? "sk_Position" : "sk_Position.xyz"; g->codeAppendf("float%ix2 pts = transpose(float2x%i(sk_in[0].%s, sk_in[1].%s));", - inputWidth, inputWidth, posValues, posValues); + numInputPoints, numInputPoints, posValues, posValues); GrShaderVar wind("wind", kHalf_GrSLType); g->declareGlobal(wind); @@ -390,7 +389,8 @@ public: void GrCCCoverageProcessor::initGS() { SkASSERT(Impl::kGeometryShader == fImpl); - if (4 == this->numInputPoints() || this->hasInputWeight()) { + if (PrimitiveType::kCubics == fPrimitiveType || + PrimitiveType::kWeightedTriangles == fPrimitiveType) { this->addVertexAttrib("x_or_y_values", kFloat4_GrVertexAttribType); SkASSERT(sizeof(QuadPointInstance) == this->getVertexStride() * 2); SkASSERT(offsetof(QuadPointInstance, fY) == this->getVertexStride()); diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp index dd8da96f82..a1f180b031 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp +++ b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp @@ -257,10 +257,9 @@ void GrCCCoverageProcessor::VSImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) GrGLSLVertexBuilder* v = args.fVertBuilder; int numInputPoints = proc.numInputPoints(); - int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3; - const char* swizzle = (4 == inputWidth) ? "xyzw" : "xyz"; + const char* swizzle = (4 == numInputPoints) ? "xyzw" : "xyz"; v->codeAppendf("float%ix2 pts = transpose(float2x%i(%s.%s, %s.%s));", - inputWidth, inputWidth, proc.getAttrib(kAttribIdx_X).fName, swizzle, + numInputPoints, numInputPoints, proc.getAttrib(kAttribIdx_X).fName, swizzle, proc.getAttrib(kAttribIdx_Y).fName, swizzle); if (PrimitiveType::kWeightedTriangles != proc.fPrimitiveType) { @@ -477,8 +476,7 @@ void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) { } case PrimitiveType::kQuadratics: - case PrimitiveType::kCubics: - case PrimitiveType::kConics: { + case PrimitiveType::kCubics: { GR_DEFINE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey); fVSVertexBuffer = rp->findOrMakeStaticBuffer(kVertex_GrBufferType, sizeof(kCurveVertices), kCurveVertices, @@ -501,7 +499,8 @@ void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) { } } - if (4 == this->numInputPoints() || this->hasInputWeight()) { + if (PrimitiveType::kCubics == fPrimitiveType || + PrimitiveType::kWeightedTriangles == fPrimitiveType) { SkASSERT(kAttribIdx_X == this->numAttribs()); this->addInstanceAttrib("X", kFloat4_GrVertexAttribType); @@ -551,7 +550,6 @@ GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createVSImpl(std::unique_ptr= tolerance && dot1 >= tolerance; } -template static inline SkNx lerp(const SkNx& a, const SkNx& b, - const SkNx& t) { +static inline Sk2f lerp(const Sk2f& a, const Sk2f& b, const Sk2f& t) { return SkNx_fma(t, b - a, a); } @@ -329,54 +328,6 @@ static inline bool is_cubic_nearly_quadratic(const Sk2f& p0, const Sk2f& p1, con return ((c1 - c2).abs() <= 1).allTrue(); } -// Given a convex curve segment with the following order-2 tangent function: -// -// |C2x C2y| -// tan = some_scale * |dx/dt dy/dt| = |t^2 t 1| * |C1x C1y| -// |C0x C0y| -// -// This function finds the T value whose tangent angle is halfway between the tangents at T=0 and -// T=1 (tan0 and tan1). -static inline float find_midtangent(const Sk2f& tan0, const Sk2f& tan1, - float scale2, const Sk2f& C2, - float scale1, const Sk2f& C1, - float scale0, const Sk2f& C0) { - // Tangents point in the direction of increasing T, so tan0 and -tan1 both point toward the - // midtangent. 'n' will therefore bisect tan0 and -tan1, giving us the normal to the midtangent. - // - // n dot midtangent = 0 - // - Sk2f n = normalize(tan0) - normalize(tan1); - - // Find the T value at the midtangent. This is a simple quadratic equation: - // - // midtangent dot n = 0 - // - // (|t^2 t 1| * C) dot n = 0 - // - // |t^2 t 1| dot C*n = 0 - // - // First find coeffs = C*n. - Sk4f C[2]; - Sk2f::Store4(C, C2, C1, C0, 0); - Sk4f coeffs = C[0]*n[0] + C[1]*n[1]; - if (1 != scale2 || 1 != scale1 || 1 != scale0) { - coeffs *= Sk4f(scale2, scale1, scale0, 0); - } - - // Now solve the quadratic. - float a = coeffs[0], b = coeffs[1], c = coeffs[2]; - float discr = b*b - 4*a*c; - if (discr < 0) { - return 0; // This will only happen if the curve is a line. - } - - // The roots are q/a and c/q. Pick the one closer to T=.5. - float q = -.5f * (b + copysignf(std::sqrt(discr), b)); - float r = .5f*q*a; - return std::abs(q*q - r) < std::abs(a*c - r) ? q/a : c/q; -} - void GrCCGeometry::cubicTo(const SkPoint P[4], float inflectPad, float loopIntersectPad) { SkASSERT(fBuildingContour); SkASSERT(P[0] == fPoints.back()); @@ -535,7 +486,7 @@ void GrCCGeometry::cubicTo(const SkPoint P[4], float inflectPad, float loopInter this->appendMonotonicCubics(p0, ab2, abc2, abcd2); } else if (T2 > T1) { // Section 3 (middle section). - Sk2f midp2 = lerp(abc2, abcd2, Sk2f(T1/T2)); + Sk2f midp2 = lerp(abc2, abcd2, T1/T2); this->appendMonotonicCubics(midp0, midp1, midp2, abcd2); } @@ -548,18 +499,25 @@ template inline void GrCCGeometry::chopCubicAtMidTangent(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, const Sk2f& p3, const Sk2f& tan0, const Sk2f& tan1, int maxFutureSubdivisions) { - float midT = find_midtangent(tan0, tan1, 3, p3 + (p1 - p2)*3 - p0, - 6, p0 - p1*2 + p2, - 3, p1 - p0); - // Use positive logic since NaN fails comparisons. (However midT should not be NaN since we cull - // near-flat cubics in cubicTo().) - if (!(midT > 0 && midT < 1)) { - // The cubic is flat. Otherwise there would be a real midtangent inside T=0..1. - this->appendLine(p3); + // Find the T value whose tangent is perpendicular to the vector that bisects tan0 and -tan1. + Sk2f n = normalize(tan0) - normalize(tan1); + + float a = 3 * dot(p3 + (p1 - p2)*3 - p0, n); + float b = 6 * dot(p0 - p1*2 + p2, n); + float c = 3 * dot(p1 - p0, n); + + float discr = b*b - 4*a*c; + if (discr < 0) { + // If this is the case then the cubic must be nearly flat. + (this->*AppendLeftRight)(p0, p1, p2, p3, maxFutureSubdivisions); return; } - this->chopCubic(p0, p1, p2, p3, midT, maxFutureSubdivisions); + float q = -.5f * (b + copysignf(std::sqrt(discr), b)); + float m = .5f*q*a; + float T = std::abs(q*q - m) < std::abs(a*c - m) ? q/a : c/q; + + this->chopCubic(p0, p1, p2, p3, T, maxFutureSubdivisions); } template @@ -652,87 +610,6 @@ void GrCCGeometry::appendCubicApproximation(const Sk2f& p0, const Sk2f& p1, cons } } -void GrCCGeometry::conicTo(const SkPoint P[3], float w) { - SkASSERT(fBuildingContour); - SkASSERT(P[0] == fPoints.back()); - Sk2f p0 = Sk2f::Load(P); - Sk2f p1 = Sk2f::Load(P+1); - Sk2f p2 = Sk2f::Load(P+2); - - // Don't crunch on the curve if it is nearly flat (or just very small). Collinear control points - // can break the midtangent-finding math below. - if (are_collinear(p0, p1, p2)) { - this->appendLine(p2); - return; - } - - Sk2f tan0 = p1 - p0; - Sk2f tan1 = p2 - p1; - // The derivative of a conic has a cumbersome order-4 denominator. However, this isn't necessary - // if we are only interested in a vector in the same *direction* as a given tangent line. Since - // the denominator scales dx and dy uniformly, we can throw it out completely after evaluating - // the derivative with the standard quotient rule. This leaves us with a simpler quadratic - // function that we use to find the midtangent. - float midT = find_midtangent(tan0, tan1, 1, (w - 1) * (p2 - p0), - 1, (p2 - p0) - 2*w*(p1 - p0), - 1, w*(p1 - p0)); - // Use positive logic since NaN fails comparisons. (However midT should not be NaN since we cull - // near-linear conics above. And while w=0 is flat, it's not a line and has valid midtangents.) - if (!(midT > 0 && midT < 1)) { - // The conic is flat. Otherwise there would be a real midtangent inside T=0..1. - this->appendLine(p2); - return; - } - - // Evaluate the conic at midT. - Sk4f p3d0 = Sk4f(p0[0], p0[1], 1, 0); - Sk4f p3d1 = Sk4f(p1[0], p1[1], 1, 0) * w; - Sk4f p3d2 = Sk4f(p2[0], p2[1], 1, 0); - Sk4f midT4 = midT; - - Sk4f p3d01 = lerp(p3d0, p3d1, midT4); - Sk4f p3d12 = lerp(p3d1, p3d2, midT4); - Sk4f p3d012 = lerp(p3d01, p3d12, midT4); - - Sk2f midpoint = Sk2f(p3d012[0], p3d012[1]) / p3d012[2]; - - if (are_collinear(p0, midpoint, p2, 1) || // Check if the curve is within one pixel of flat. - ((midpoint - p1).abs() < 1).allTrue()) { // Check if the curve is almost a triangle. - // Draw the conic as a triangle instead. Our AA approximation won't do well if the curve - // gets wrapped too tightly, and if we get too close to p1 we will pick up artifacts from - // the implicit function's reflection. - this->appendLine(midpoint); - this->appendLine(p2); - return; - } - - if (!is_convex_curve_monotonic(p0, tan0, p2, tan1)) { - // Chop the conic at midtangent to produce two monotonic segments. - Sk2f ww = Sk2f(p3d01[2], p3d12[2]) * Sk2f(p3d012[2]).rsqrt(); - this->appendMonotonicConic(p0, Sk2f(p3d01[0], p3d01[1]) / p3d01[2], midpoint, ww[0]); - this->appendMonotonicConic(midpoint, Sk2f(p3d12[0], p3d12[1]) / p3d12[2], p2, ww[1]); - return; - } - - this->appendMonotonicConic(p0, p1, p2, w); -} - -void GrCCGeometry::appendMonotonicConic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, float w) { - SkASSERT(fPoints.back() == SkPoint::Make(p0[0], p0[1])); - - // Don't send curves to the GPU if we know they are nearly flat (or just very small). - if (are_collinear(p0, p1, p2)) { - this->appendLine(p2); - return; - } - - p1.store(&fPoints.push_back()); - p2.store(&fPoints.push_back()); - fConicWeights.push_back(w); - fVerbs.push_back(Verb::kMonotonicConicTo); - ++fCurrContourTallies.fConics; -} - GrCCGeometry::PrimitiveTallies GrCCGeometry::endContour() { SkASSERT(fBuildingContour); SkASSERT(fVerbs.count() >= fCurrContourTallies.fTriangles); diff --git a/src/gpu/ccpr/GrCCGeometry.h b/src/gpu/ccpr/GrCCGeometry.h index 7f098f958b..01cf16c68d 100644 --- a/src/gpu/ccpr/GrCCGeometry.h +++ b/src/gpu/ccpr/GrCCGeometry.h @@ -31,7 +31,6 @@ public: kLineTo, kMonotonicQuadraticTo, // Monotonic relative to the vector between its endpoints [P2 - P0]. kMonotonicCubicTo, - kMonotonicConicTo, kEndClosedContour, // endPt == startPt. kEndOpenContour // endPt != startPt. }; @@ -42,7 +41,6 @@ public: int fWeightedTriangles; // Triangles (from the tessellator) whose winding magnitude > 1. int fQuadratics; int fCubics; - int fConics; void operator+=(const PrimitiveTallies&); PrimitiveTallies operator-(const PrimitiveTallies&) const; @@ -55,7 +53,6 @@ public: const SkTArray& points() const { SkASSERT(!fBuildingContour); return fPoints; } const SkTArray& verbs() const { SkASSERT(!fBuildingContour); return fVerbs; } - float getConicWeight(int idx) const { SkASSERT(!fBuildingContour); return fConicWeights[idx]; } void reset() { SkASSERT(!fBuildingContour); @@ -92,8 +89,6 @@ public: // intersection vs. 1.489 on the tiger). void cubicTo(const SkPoint[4], float inflectPad = 0.55f, float loopIntersectPad = 2); - void conicTo(const SkPoint[3], float w); - PrimitiveTallies endContour(); // Returns the numbers of primitives needed to draw the contour. private: @@ -121,17 +116,15 @@ private: void appendCubicApproximation(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, const Sk2f& p3, int maxSubdivisions = kMaxSubdivionsPerCubicSection); - void appendMonotonicConic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, float w); - // Transient state used while building a contour. SkPoint fCurrAnchorPoint; PrimitiveTallies fCurrContourTallies; SkCubicType fCurrCubicType; SkDEBUGCODE(bool fBuildingContour = false); - SkSTArray<128, SkPoint, true> fPoints; - SkSTArray<32, float, true> fConicWeights; - SkSTArray<128, Verb, true> fVerbs; + // TODO: These points could eventually be written directly to block-allocated GPU buffers. + SkSTArray<128, SkPoint, true> fPoints; + SkSTArray<128, Verb, true> fVerbs; }; inline void GrCCGeometry::PrimitiveTallies::operator+=(const PrimitiveTallies& b) { @@ -139,7 +132,6 @@ inline void GrCCGeometry::PrimitiveTallies::operator+=(const PrimitiveTallies& b fWeightedTriangles += b.fWeightedTriangles; fQuadratics += b.fQuadratics; fCubics += b.fCubics; - fConics += b.fConics; } GrCCGeometry::PrimitiveTallies @@ -147,13 +139,12 @@ inline GrCCGeometry::PrimitiveTallies::operator-(const PrimitiveTallies& b) cons return {fTriangles - b.fTriangles, fWeightedTriangles - b.fWeightedTriangles, fQuadratics - b.fQuadratics, - fCubics - b.fCubics, - fConics - b.fConics}; + fCubics - b.fCubics}; } inline bool GrCCGeometry::PrimitiveTallies::operator==(const PrimitiveTallies& b) { return fTriangles == b.fTriangles && fWeightedTriangles == b.fWeightedTriangles && - fQuadratics == b.fQuadratics && fCubics == b.fCubics && fConics == b.fConics; + fQuadratics == b.fQuadratics && fCubics == b.fCubics; } #endif diff --git a/src/gpu/ccpr/GrCCPathParser.cpp b/src/gpu/ccpr/GrCCPathParser.cpp index 2740569fe6..f77c52e6f1 100644 --- a/src/gpu/ccpr/GrCCPathParser.cpp +++ b/src/gpu/ccpr/GrCCPathParser.cpp @@ -114,9 +114,7 @@ void GrCCPathParser::parsePath(const SkPath& path, const SkPoint* deviceSpacePts return; } - const float* conicWeights = SkPathPriv::ConicWeightData(path); int ptsIdx = 0; - int conicWeightsIdx = 0; bool insideContour = false; for (SkPath::Verb verb : SkPathPriv::Verbs(path)) { @@ -144,16 +142,11 @@ void GrCCPathParser::parsePath(const SkPath& path, const SkPoint* deviceSpacePts ptsIdx += 3; continue; case SkPath::kConic_Verb: - fGeometry.conicTo(&deviceSpacePts[ptsIdx - 1], conicWeights[conicWeightsIdx]); - ptsIdx += 2; - ++conicWeightsIdx; - continue; + SK_ABORT("Conics are not supported."); default: SK_ABORT("Unexpected path verb."); } } - SkASSERT(ptsIdx == path.countPoints()); - SkASSERT(conicWeightsIdx == SkPathPriv::ConicWeightCnt(path)); this->endContourIfNeeded(insideContour); } @@ -203,7 +196,6 @@ void GrCCPathParser::saveParsedPath(ScissorMode scissorMode, const SkIRect& clip continue; case GrCCGeometry::Verb::kMonotonicQuadraticTo: - case GrCCGeometry::Verb::kMonotonicConicTo: fan.lineTo(pts[ptsIdx + 1]); ptsIdx += 2; continue; @@ -385,9 +377,7 @@ bool GrCCPathParser::finalize(GrOnFlushResourceProvider* onFlushRP) { fBaseInstances[0].fCubics = fBaseInstances[1].fWeightedTriangles + fTotalPrimitiveCounts[1].fWeightedTriangles; fBaseInstances[1].fCubics = fBaseInstances[0].fCubics + fTotalPrimitiveCounts[0].fCubics; - fBaseInstances[0].fConics = fBaseInstances[1].fCubics + fTotalPrimitiveCounts[1].fCubics; - fBaseInstances[1].fConics = fBaseInstances[0].fConics + fTotalPrimitiveCounts[0].fConics; - int quadEndIdx = fBaseInstances[1].fConics + fTotalPrimitiveCounts[1].fConics; + int quadEndIdx = fBaseInstances[1].fCubics + fTotalPrimitiveCounts[1].fCubics; fInstanceBuffer = onFlushRP->makeBuffer(kVertex_GrBufferType, quadEndIdx * sizeof(QuadPointInstance)); @@ -410,7 +400,6 @@ bool GrCCPathParser::finalize(GrOnFlushResourceProvider* onFlushRP) { const SkTArray& pts = fGeometry.points(); int ptsIdx = -1; - int nextConicWeightIdx = 0; // Expand the ccpr verbs into GPU instance buffers. for (GrCCGeometry::Verb verb : fGeometry.verbs()) { @@ -465,17 +454,6 @@ bool GrCCPathParser::finalize(GrOnFlushResourceProvider* onFlushRP) { } continue; - case GrCCGeometry::Verb::kMonotonicConicTo: - quadPointInstanceData[currIndices->fConics++].setW( - &pts[ptsIdx], atlasOffset, fGeometry.getConicWeight(nextConicWeightIdx)); - ptsIdx += 2; - ++nextConicWeightIdx; - if (!currFanIsTessellated) { - SkASSERT(!currFan.empty()); - currFan.push_back(ptsIdx); - } - continue; - case GrCCGeometry::Verb::kEndClosedContour: // endPt == startPt. if (!currFanIsTessellated) { SkASSERT(!currFan.empty()); @@ -511,9 +489,7 @@ bool GrCCPathParser::finalize(GrOnFlushResourceProvider* onFlushRP) { SkASSERT(instanceIndices[0].fWeightedTriangles == fBaseInstances[1].fWeightedTriangles); SkASSERT(instanceIndices[1].fWeightedTriangles == fBaseInstances[0].fCubics); SkASSERT(instanceIndices[0].fCubics == fBaseInstances[1].fCubics); - SkASSERT(instanceIndices[1].fCubics == fBaseInstances[0].fConics); - SkASSERT(instanceIndices[0].fConics == fBaseInstances[1].fConics); - SkASSERT(instanceIndices[1].fConics == quadEndIdx); + SkASSERT(instanceIndices[1].fCubics == quadEndIdx); fMeshesScratchBuffer.reserve(fMaxMeshesPerDraw); fDynamicStatesScratchBuffer.reserve(fMaxMeshesPerDraw); @@ -551,11 +527,6 @@ void GrCCPathParser::drawCoverageCount(GrOpFlushState* flushState, CoverageCount this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kCubics, &PrimitiveTallies::fCubics, drawBounds); } - - if (batchTotalCounts.fConics) { - this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kConics, - &PrimitiveTallies::fConics, drawBounds); - } } void GrCCPathParser::drawPrimitives(GrOpFlushState* flushState, const GrPipeline& pipeline, diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp index b6f5770b35..90d89dec60 100644 --- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp +++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp @@ -65,6 +65,10 @@ GrPathRenderer::CanDrawPath GrCoverageCountingPathRenderer::onCanDrawPath( SkPath path; args.fShape->asPath(&path); + if (SkPathPriv::ConicWeightCnt(path)) { + return CanDrawPath::kNo; + } + SkRect devBounds; SkIRect devIBounds; args.fViewMatrix->mapRect(&devBounds, path.getBounds()); @@ -189,6 +193,11 @@ bool GrCoverageCountingPathRenderer::canMakeClipProcessor(const SkPath& deviceSp if (!fDrawCachablePaths && !deviceSpacePath.isVolatile()) { return false; } + + if (SkPathPriv::ConicWeightCnt(deviceSpacePath)) { + return false; + } + return true; } diff --git a/tests/SkNxTest.cpp b/tests/SkNxTest.cpp index 933a5fc877..bcf2a71658 100644 --- a/tests/SkNxTest.cpp +++ b/tests/SkNxTest.cpp @@ -467,8 +467,7 @@ DEF_TEST(Sk2f_Store4, r) { Sk2f p1{1, 5}; Sk2f p2{2, 6}; Sk2f p3{3, 7}; - - float dst[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; + float dst[8]; Sk2f::Store4(dst, p0, p1, p2, p3); REPORTER_ASSERT(r, dst[0] == 0); REPORTER_ASSERT(r, dst[1] == 1); @@ -478,19 +477,6 @@ DEF_TEST(Sk2f_Store4, r) { REPORTER_ASSERT(r, dst[5] == 5); REPORTER_ASSERT(r, dst[6] == 6); REPORTER_ASSERT(r, dst[7] == 7); - - // Ensure transposing to Sk4f works. - Sk4f dst4f[2] = {{-1, -1, -1, -1}, {-1, -1, -1, -1}}; - Sk2f::Store4(dst4f, p0, p1, p2, p3); - REPORTER_ASSERT(r, dst4f[0][0] == 0); - REPORTER_ASSERT(r, dst4f[0][1] == 1); - REPORTER_ASSERT(r, dst4f[0][2] == 2); - REPORTER_ASSERT(r, dst4f[0][3] == 3); - REPORTER_ASSERT(r, dst4f[1][0] == 4); - REPORTER_ASSERT(r, dst4f[1][1] == 5); - REPORTER_ASSERT(r, dst4f[1][2] == 6); - REPORTER_ASSERT(r, dst4f[1][3] == 7); - } DEF_TEST(Sk4f_minmax, r) { -- cgit v1.2.3