Revert "ccpr: Implement conics"
This reverts commit 98b241573e
.
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 <csmartdalton@google.com>
> Reviewed-by: Greg Daniel <egdaniel@google.com>
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 <csmartdalton@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
parent
98b241573e
commit
e7fbafe1da
@ -300,8 +300,6 @@ skia_gpu_sources = [
|
|||||||
"$_src/gpu/ccpr/GrCCAtlas.h",
|
"$_src/gpu/ccpr/GrCCAtlas.h",
|
||||||
"$_src/gpu/ccpr/GrCCClipProcessor.cpp",
|
"$_src/gpu/ccpr/GrCCClipProcessor.cpp",
|
||||||
"$_src/gpu/ccpr/GrCCClipProcessor.h",
|
"$_src/gpu/ccpr/GrCCClipProcessor.h",
|
||||||
"$_src/gpu/ccpr/GrCCConicShader.cpp",
|
|
||||||
"$_src/gpu/ccpr/GrCCConicShader.h",
|
|
||||||
"$_src/gpu/ccpr/GrCCCoverageProcessor.cpp",
|
"$_src/gpu/ccpr/GrCCCoverageProcessor.cpp",
|
||||||
"$_src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp",
|
"$_src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp",
|
||||||
"$_src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp",
|
"$_src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp",
|
||||||
|
@ -63,8 +63,6 @@ private:
|
|||||||
SkPoint fPoints[4] = {
|
SkPoint fPoints[4] = {
|
||||||
{100.05f, 100.05f}, {400.75f, 100.05f}, {400.75f, 300.95f}, {100.05f, 300.95f}};
|
{100.05f, 100.05f}, {400.75f, 100.05f}, {400.75f, 300.95f}, {100.05f, 300.95f}};
|
||||||
|
|
||||||
float fConicWeight = .5;
|
|
||||||
|
|
||||||
SkTArray<TriPointInstance> fTriPointInstances;
|
SkTArray<TriPointInstance> fTriPointInstances;
|
||||||
SkTArray<QuadPointInstance> fQuadPointInstances;
|
SkTArray<QuadPointInstance> fQuadPointInstances;
|
||||||
|
|
||||||
@ -150,22 +148,14 @@ void CCPRGeometryView::onDrawContent(SkCanvas* canvas) {
|
|||||||
|
|
||||||
SkPath outline;
|
SkPath outline;
|
||||||
outline.moveTo(fPoints[0]);
|
outline.moveTo(fPoints[0]);
|
||||||
switch (fPrimitiveType) {
|
if (PrimitiveType::kCubics == fPrimitiveType) {
|
||||||
case PrimitiveType::kTriangles:
|
outline.cubicTo(fPoints[1], fPoints[2], fPoints[3]);
|
||||||
case PrimitiveType::kWeightedTriangles:
|
} else if (PrimitiveType::kQuadratics == fPrimitiveType) {
|
||||||
outline.lineTo(fPoints[1]);
|
outline.quadTo(fPoints[1], fPoints[3]);
|
||||||
outline.lineTo(fPoints[3]);
|
} else {
|
||||||
outline.close();
|
outline.lineTo(fPoints[1]);
|
||||||
break;
|
outline.lineTo(fPoints[3]);
|
||||||
case PrimitiveType::kQuadratics:
|
outline.close();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPaint outlinePaint;
|
SkPaint outlinePaint;
|
||||||
@ -218,8 +208,6 @@ void CCPRGeometryView::onDrawContent(SkCanvas* canvas) {
|
|||||||
GrCCCoverageProcessor::PrimitiveTypeName(fPrimitiveType));
|
GrCCCoverageProcessor::PrimitiveTypeName(fPrimitiveType));
|
||||||
if (PrimitiveType::kCubics == fPrimitiveType) {
|
if (PrimitiveType::kCubics == fPrimitiveType) {
|
||||||
caption.appendf(" (%s)", SkCubicTypeName(fCubicType));
|
caption.appendf(" (%s)", SkCubicTypeName(fCubicType));
|
||||||
} else if (PrimitiveType::kConics == fPrimitiveType) {
|
|
||||||
caption.appendf(" (w=%f)", fConicWeight);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
caption = "Use GPU backend to visualize geometry.";
|
caption = "Use GPU backend to visualize geometry.";
|
||||||
@ -276,18 +264,13 @@ void CCPRGeometryView::updateGpuData() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (PrimitiveType::kTriangles != fPrimitiveType) {
|
} else if (PrimitiveType::kQuadratics == fPrimitiveType) {
|
||||||
SkPoint P3[3] = {fPoints[0], fPoints[1], fPoints[3]};
|
SkPoint P3[3] = {fPoints[0], fPoints[1], fPoints[3]};
|
||||||
GrCCGeometry geometry;
|
GrCCGeometry geometry;
|
||||||
geometry.beginContour(P3[0]);
|
geometry.beginContour(P3[0]);
|
||||||
if (PrimitiveType::kQuadratics == fPrimitiveType) {
|
geometry.quadraticTo(P3);
|
||||||
geometry.quadraticTo(P3);
|
|
||||||
} else {
|
|
||||||
SkASSERT(PrimitiveType::kConics == fPrimitiveType);
|
|
||||||
geometry.conicTo(P3, fConicWeight);
|
|
||||||
}
|
|
||||||
geometry.endContour();
|
geometry.endContour();
|
||||||
int ptsIdx = 0, conicWeightIdx = 0;
|
int ptsIdx = 0;
|
||||||
for (GrCCGeometry::Verb verb : geometry.verbs()) {
|
for (GrCCGeometry::Verb verb : geometry.verbs()) {
|
||||||
if (GrCCGeometry::Verb::kBeginContour == verb ||
|
if (GrCCGeometry::Verb::kBeginContour == verb ||
|
||||||
GrCCGeometry::Verb::kEndOpenContour == verb ||
|
GrCCGeometry::Verb::kEndOpenContour == verb ||
|
||||||
@ -298,16 +281,8 @@ void CCPRGeometryView::updateGpuData() {
|
|||||||
++ptsIdx;
|
++ptsIdx;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SkASSERT(GrCCGeometry::Verb::kMonotonicQuadraticTo == verb ||
|
SkASSERT(GrCCGeometry::Verb::kMonotonicQuadraticTo == verb);
|
||||||
GrCCGeometry::Verb::kMonotonicConicTo == verb);
|
fTriPointInstances.push_back().set(&geometry.points()[ptsIdx], Sk2f(0, 0));
|
||||||
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++));
|
|
||||||
}
|
|
||||||
ptsIdx += 2;
|
ptsIdx += 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -326,8 +301,7 @@ void CCPRGeometryView::DrawCoverageCountOp::onExecute(GrOpFlushState* state) {
|
|||||||
SkDEBUGCODE(proc.enableDebugBloat(kDebugBloat));
|
SkDEBUGCODE(proc.enableDebugBloat(kDebugBloat));
|
||||||
|
|
||||||
SkSTArray<1, GrMesh> mesh;
|
SkSTArray<1, GrMesh> mesh;
|
||||||
if (PrimitiveType::kCubics == fView->fPrimitiveType ||
|
if (PrimitiveType::kCubics == fView->fPrimitiveType) {
|
||||||
PrimitiveType::kConics == fView->fPrimitiveType) {
|
|
||||||
sk_sp<GrBuffer> instBuff(rp->createBuffer(
|
sk_sp<GrBuffer> instBuff(rp->createBuffer(
|
||||||
fView->fQuadPointInstances.count() * sizeof(QuadPointInstance),
|
fView->fQuadPointInstances.count() * sizeof(QuadPointInstance),
|
||||||
kVertex_GrBufferType, kDynamic_GrAccessPattern,
|
kVertex_GrBufferType, kDynamic_GrAccessPattern,
|
||||||
@ -415,7 +389,7 @@ bool CCPRGeometryView::onQuery(SkEvent* evt) {
|
|||||||
}
|
}
|
||||||
SkUnichar unichar;
|
SkUnichar unichar;
|
||||||
if (SampleCode::CharQ(*evt, &unichar)) {
|
if (SampleCode::CharQ(*evt, &unichar)) {
|
||||||
if (unichar >= '1' && unichar <= '4') {
|
if (unichar >= '1' && unichar <= '3') {
|
||||||
fPrimitiveType = PrimitiveType(unichar - '1');
|
fPrimitiveType = PrimitiveType(unichar - '1');
|
||||||
if (fPrimitiveType >= PrimitiveType::kWeightedTriangles) {
|
if (fPrimitiveType >= PrimitiveType::kWeightedTriangles) {
|
||||||
fPrimitiveType = (PrimitiveType) ((int)fPrimitiveType + 1);
|
fPrimitiveType = (PrimitiveType) ((int)fPrimitiveType + 1);
|
||||||
@ -423,28 +397,6 @@ bool CCPRGeometryView::onQuery(SkEvent* evt) {
|
|||||||
this->updateAndInval();
|
this->updateAndInval();
|
||||||
return true;
|
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') {
|
if (unichar == 'D') {
|
||||||
SkDebugf(" SkPoint fPoints[4] = {\n");
|
SkDebugf(" SkPoint fPoints[4] = {\n");
|
||||||
SkDebugf(" {%ff, %ff},\n", fPoints[0].x(), fPoints[0].y());
|
SkDebugf(" {%ff, %ff},\n", fPoints[0].x(), fPoints[0].y());
|
||||||
|
@ -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.
|
|
||||||
}
|
|
@ -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
|
|
@ -10,7 +10,6 @@
|
|||||||
#include "GrGpuCommandBuffer.h"
|
#include "GrGpuCommandBuffer.h"
|
||||||
#include "GrOpFlushState.h"
|
#include "GrOpFlushState.h"
|
||||||
#include "SkMakeUnique.h"
|
#include "SkMakeUnique.h"
|
||||||
#include "ccpr/GrCCConicShader.h"
|
|
||||||
#include "ccpr/GrCCCubicShader.h"
|
#include "ccpr/GrCCCubicShader.h"
|
||||||
#include "ccpr/GrCCQuadraticShader.h"
|
#include "ccpr/GrCCQuadraticShader.h"
|
||||||
#include "glsl/GrGLSLVertexGeoBuilder.h"
|
#include "glsl/GrGLSLVertexGeoBuilder.h"
|
||||||
@ -175,9 +174,6 @@ GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGLSLInstance(const GrShad
|
|||||||
case PrimitiveType::kCubics:
|
case PrimitiveType::kCubics:
|
||||||
shader = skstd::make_unique<GrCCCubicShader>();
|
shader = skstd::make_unique<GrCCCubicShader>();
|
||||||
break;
|
break;
|
||||||
case PrimitiveType::kConics:
|
|
||||||
shader = skstd::make_unique<GrCCConicShader>();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return Impl::kGeometryShader == fImpl ? this->createGSImpl(std::move(shader))
|
return Impl::kGeometryShader == fImpl ? this->createGSImpl(std::move(shader))
|
||||||
: this->createVSImpl(std::move(shader));
|
: this->createVSImpl(std::move(shader));
|
||||||
|
@ -40,7 +40,6 @@ public:
|
|||||||
kWeightedTriangles, // Triangles (from the tessellator) whose winding magnitude > 1.
|
kWeightedTriangles, // Triangles (from the tessellator) whose winding magnitude > 1.
|
||||||
kQuadratics,
|
kQuadratics,
|
||||||
kCubics,
|
kCubics,
|
||||||
kConics
|
|
||||||
};
|
};
|
||||||
static const char* PrimitiveTypeName(PrimitiveType);
|
static const char* PrimitiveTypeName(PrimitiveType);
|
||||||
|
|
||||||
@ -54,15 +53,14 @@ public:
|
|||||||
void set(const SkPoint&, const SkPoint&, const SkPoint&, const Sk2f& trans);
|
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"
|
// Defines a single primitive shape with 4 input points, or 3 input points plus a W parameter
|
||||||
// parameter duplicated in both lanes of the 4th input (i.e. Cubics, Conics, and Triangles with
|
// duplicated in both 4th components (i.e. Cubics or Triangles with a custom winding number).
|
||||||
// a weighted winding number). X,Y point values are transposed.
|
// X,Y point values are transposed.
|
||||||
struct QuadPointInstance {
|
struct QuadPointInstance {
|
||||||
float fX[4];
|
float fX[4];
|
||||||
float fY[4];
|
float fY[4];
|
||||||
|
|
||||||
void set(const SkPoint[4], float dx, float dy);
|
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);
|
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.
|
// Number of bezier points for curves, or 3 for triangles.
|
||||||
int numInputPoints() const { return PrimitiveType::kCubics == fPrimitiveType ? 4 : 3; }
|
int numInputPoints() const { return PrimitiveType::kCubics == fPrimitiveType ? 4 : 3; }
|
||||||
|
|
||||||
int hasInputWeight() const {
|
|
||||||
return PrimitiveType::kWeightedTriangles == fPrimitiveType ||
|
|
||||||
PrimitiveType::kConics == fPrimitiveType;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class Impl : bool {
|
enum class Impl : bool {
|
||||||
kGeometryShader,
|
kGeometryShader,
|
||||||
kVertexShader
|
kVertexShader
|
||||||
@ -266,7 +259,6 @@ inline const char* GrCCCoverageProcessor::PrimitiveTypeName(PrimitiveType type)
|
|||||||
case PrimitiveType::kWeightedTriangles: return "kWeightedTriangles";
|
case PrimitiveType::kWeightedTriangles: return "kWeightedTriangles";
|
||||||
case PrimitiveType::kQuadratics: return "kQuadratics";
|
case PrimitiveType::kQuadratics: return "kQuadratics";
|
||||||
case PrimitiveType::kCubics: return "kCubics";
|
case PrimitiveType::kCubics: return "kCubics";
|
||||||
case PrimitiveType::kConics: return "kConics";
|
|
||||||
}
|
}
|
||||||
SK_ABORT("Invalid PrimitiveType");
|
SK_ABORT("Invalid PrimitiveType");
|
||||||
return "";
|
return "";
|
||||||
@ -291,11 +283,6 @@ inline void GrCCCoverageProcessor::QuadPointInstance::set(const SkPoint p[4], fl
|
|||||||
(Y + dy).store(&fY);
|
(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,
|
inline void GrCCCoverageProcessor::QuadPointInstance::setW(const SkPoint& p0, const SkPoint& p1,
|
||||||
const SkPoint& p2, const Sk2f& trans,
|
const SkPoint& p2, const Sk2f& trans,
|
||||||
float w) {
|
float w) {
|
||||||
|
@ -52,10 +52,9 @@ protected:
|
|||||||
int numInputPoints = proc.numInputPoints();
|
int numInputPoints = proc.numInputPoints();
|
||||||
SkASSERT(3 == numInputPoints || 4 == numInputPoints);
|
SkASSERT(3 == numInputPoints || 4 == numInputPoints);
|
||||||
|
|
||||||
int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3;
|
const char* posValues = (4 == numInputPoints) ? "sk_Position" : "sk_Position.xyz";
|
||||||
const char* posValues = (4 == inputWidth) ? "sk_Position" : "sk_Position.xyz";
|
|
||||||
g->codeAppendf("float%ix2 pts = transpose(float2x%i(sk_in[0].%s, sk_in[1].%s));",
|
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);
|
GrShaderVar wind("wind", kHalf_GrSLType);
|
||||||
g->declareGlobal(wind);
|
g->declareGlobal(wind);
|
||||||
@ -390,7 +389,8 @@ public:
|
|||||||
|
|
||||||
void GrCCCoverageProcessor::initGS() {
|
void GrCCCoverageProcessor::initGS() {
|
||||||
SkASSERT(Impl::kGeometryShader == fImpl);
|
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);
|
this->addVertexAttrib("x_or_y_values", kFloat4_GrVertexAttribType);
|
||||||
SkASSERT(sizeof(QuadPointInstance) == this->getVertexStride() * 2);
|
SkASSERT(sizeof(QuadPointInstance) == this->getVertexStride() * 2);
|
||||||
SkASSERT(offsetof(QuadPointInstance, fY) == this->getVertexStride());
|
SkASSERT(offsetof(QuadPointInstance, fY) == this->getVertexStride());
|
||||||
|
@ -257,10 +257,9 @@ void GrCCCoverageProcessor::VSImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs)
|
|||||||
GrGLSLVertexBuilder* v = args.fVertBuilder;
|
GrGLSLVertexBuilder* v = args.fVertBuilder;
|
||||||
int numInputPoints = proc.numInputPoints();
|
int numInputPoints = proc.numInputPoints();
|
||||||
|
|
||||||
int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3;
|
const char* swizzle = (4 == numInputPoints) ? "xyzw" : "xyz";
|
||||||
const char* swizzle = (4 == inputWidth) ? "xyzw" : "xyz";
|
|
||||||
v->codeAppendf("float%ix2 pts = transpose(float2x%i(%s.%s, %s.%s));",
|
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);
|
proc.getAttrib(kAttribIdx_Y).fName, swizzle);
|
||||||
|
|
||||||
if (PrimitiveType::kWeightedTriangles != proc.fPrimitiveType) {
|
if (PrimitiveType::kWeightedTriangles != proc.fPrimitiveType) {
|
||||||
@ -477,8 +476,7 @@ void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case PrimitiveType::kQuadratics:
|
case PrimitiveType::kQuadratics:
|
||||||
case PrimitiveType::kCubics:
|
case PrimitiveType::kCubics: {
|
||||||
case PrimitiveType::kConics: {
|
|
||||||
GR_DEFINE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey);
|
GR_DEFINE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey);
|
||||||
fVSVertexBuffer = rp->findOrMakeStaticBuffer(kVertex_GrBufferType,
|
fVSVertexBuffer = rp->findOrMakeStaticBuffer(kVertex_GrBufferType,
|
||||||
sizeof(kCurveVertices), kCurveVertices,
|
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());
|
SkASSERT(kAttribIdx_X == this->numAttribs());
|
||||||
this->addInstanceAttrib("X", kFloat4_GrVertexAttribType);
|
this->addInstanceAttrib("X", kFloat4_GrVertexAttribType);
|
||||||
|
|
||||||
@ -551,7 +550,6 @@ GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createVSImpl(std::unique_ptr<Sh
|
|||||||
return new VSImpl(std::move(shadr), 3);
|
return new VSImpl(std::move(shadr), 3);
|
||||||
case PrimitiveType::kQuadratics:
|
case PrimitiveType::kQuadratics:
|
||||||
case PrimitiveType::kCubics:
|
case PrimitiveType::kCubics:
|
||||||
case PrimitiveType::kConics:
|
|
||||||
return new VSImpl(std::move(shadr), 4);
|
return new VSImpl(std::move(shadr), 4);
|
||||||
}
|
}
|
||||||
SK_ABORT("Invalid RenderPass");
|
SK_ABORT("Invalid RenderPass");
|
||||||
|
@ -27,7 +27,7 @@ void GrCCGeometry::beginContour(const SkPoint& pt) {
|
|||||||
SkASSERT(!fBuildingContour);
|
SkASSERT(!fBuildingContour);
|
||||||
// Store the current verb count in the fTriangles field for now. When we close the contour we
|
// Store the current verb count in the fTriangles field for now. When we close the contour we
|
||||||
// will use this value to calculate the actual number of triangles in its fan.
|
// will use this value to calculate the actual number of triangles in its fan.
|
||||||
fCurrContourTallies = {fVerbs.count(), 0, 0, 0, 0};
|
fCurrContourTallies = {fVerbs.count(), 0, 0, 0};
|
||||||
|
|
||||||
fPoints.push_back(pt);
|
fPoints.push_back(pt);
|
||||||
fVerbs.push_back(Verb::kBeginContour);
|
fVerbs.push_back(Verb::kBeginContour);
|
||||||
@ -125,8 +125,7 @@ static inline bool is_convex_curve_monotonic(const Sk2f& startPt, const Sk2f& ta
|
|||||||
return dot0 >= tolerance && dot1 >= tolerance;
|
return dot0 >= tolerance && dot1 >= tolerance;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int N> static inline SkNx<N,float> lerp(const SkNx<N,float>& a, const SkNx<N,float>& b,
|
static inline Sk2f lerp(const Sk2f& a, const Sk2f& b, const Sk2f& t) {
|
||||||
const SkNx<N,float>& t) {
|
|
||||||
return SkNx_fma(t, b - a, a);
|
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();
|
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) {
|
void GrCCGeometry::cubicTo(const SkPoint P[4], float inflectPad, float loopIntersectPad) {
|
||||||
SkASSERT(fBuildingContour);
|
SkASSERT(fBuildingContour);
|
||||||
SkASSERT(P[0] == fPoints.back());
|
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);
|
this->appendMonotonicCubics(p0, ab2, abc2, abcd2);
|
||||||
} else if (T2 > T1) {
|
} else if (T2 > T1) {
|
||||||
// Section 3 (middle section).
|
// 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);
|
this->appendMonotonicCubics(midp0, midp1, midp2, abcd2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,18 +499,25 @@ template<GrCCGeometry::AppendCubicFn AppendLeftRight>
|
|||||||
inline void GrCCGeometry::chopCubicAtMidTangent(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2,
|
inline void GrCCGeometry::chopCubicAtMidTangent(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2,
|
||||||
const Sk2f& p3, const Sk2f& tan0,
|
const Sk2f& p3, const Sk2f& tan0,
|
||||||
const Sk2f& tan1, int maxFutureSubdivisions) {
|
const Sk2f& tan1, int maxFutureSubdivisions) {
|
||||||
float midT = find_midtangent(tan0, tan1, 3, p3 + (p1 - p2)*3 - p0,
|
// Find the T value whose tangent is perpendicular to the vector that bisects tan0 and -tan1.
|
||||||
6, p0 - p1*2 + p2,
|
Sk2f n = normalize(tan0) - normalize(tan1);
|
||||||
3, p1 - p0);
|
|
||||||
// Use positive logic since NaN fails comparisons. (However midT should not be NaN since we cull
|
float a = 3 * dot(p3 + (p1 - p2)*3 - p0, n);
|
||||||
// near-flat cubics in cubicTo().)
|
float b = 6 * dot(p0 - p1*2 + p2, n);
|
||||||
if (!(midT > 0 && midT < 1)) {
|
float c = 3 * dot(p1 - p0, n);
|
||||||
// The cubic is flat. Otherwise there would be a real midtangent inside T=0..1.
|
|
||||||
this->appendLine(p3);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->chopCubic<AppendLeftRight, AppendLeftRight>(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<AppendLeftRight, AppendLeftRight>(p0, p1, p2, p3, T, maxFutureSubdivisions);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<GrCCGeometry::AppendCubicFn AppendLeft, GrCCGeometry::AppendCubicFn AppendRight>
|
template<GrCCGeometry::AppendCubicFn AppendLeft, GrCCGeometry::AppendCubicFn AppendRight>
|
||||||
@ -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() {
|
GrCCGeometry::PrimitiveTallies GrCCGeometry::endContour() {
|
||||||
SkASSERT(fBuildingContour);
|
SkASSERT(fBuildingContour);
|
||||||
SkASSERT(fVerbs.count() >= fCurrContourTallies.fTriangles);
|
SkASSERT(fVerbs.count() >= fCurrContourTallies.fTriangles);
|
||||||
|
@ -31,7 +31,6 @@ public:
|
|||||||
kLineTo,
|
kLineTo,
|
||||||
kMonotonicQuadraticTo, // Monotonic relative to the vector between its endpoints [P2 - P0].
|
kMonotonicQuadraticTo, // Monotonic relative to the vector between its endpoints [P2 - P0].
|
||||||
kMonotonicCubicTo,
|
kMonotonicCubicTo,
|
||||||
kMonotonicConicTo,
|
|
||||||
kEndClosedContour, // endPt == startPt.
|
kEndClosedContour, // endPt == startPt.
|
||||||
kEndOpenContour // endPt != startPt.
|
kEndOpenContour // endPt != startPt.
|
||||||
};
|
};
|
||||||
@ -42,7 +41,6 @@ public:
|
|||||||
int fWeightedTriangles; // Triangles (from the tessellator) whose winding magnitude > 1.
|
int fWeightedTriangles; // Triangles (from the tessellator) whose winding magnitude > 1.
|
||||||
int fQuadratics;
|
int fQuadratics;
|
||||||
int fCubics;
|
int fCubics;
|
||||||
int fConics;
|
|
||||||
|
|
||||||
void operator+=(const PrimitiveTallies&);
|
void operator+=(const PrimitiveTallies&);
|
||||||
PrimitiveTallies operator-(const PrimitiveTallies&) const;
|
PrimitiveTallies operator-(const PrimitiveTallies&) const;
|
||||||
@ -55,7 +53,6 @@ public:
|
|||||||
|
|
||||||
const SkTArray<SkPoint, true>& points() const { SkASSERT(!fBuildingContour); return fPoints; }
|
const SkTArray<SkPoint, true>& points() const { SkASSERT(!fBuildingContour); return fPoints; }
|
||||||
const SkTArray<Verb, true>& verbs() const { SkASSERT(!fBuildingContour); return fVerbs; }
|
const SkTArray<Verb, true>& verbs() const { SkASSERT(!fBuildingContour); return fVerbs; }
|
||||||
float getConicWeight(int idx) const { SkASSERT(!fBuildingContour); return fConicWeights[idx]; }
|
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
SkASSERT(!fBuildingContour);
|
SkASSERT(!fBuildingContour);
|
||||||
@ -92,8 +89,6 @@ public:
|
|||||||
// intersection vs. 1.489 on the tiger).
|
// intersection vs. 1.489 on the tiger).
|
||||||
void cubicTo(const SkPoint[4], float inflectPad = 0.55f, float loopIntersectPad = 2);
|
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.
|
PrimitiveTallies endContour(); // Returns the numbers of primitives needed to draw the contour.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -121,17 +116,15 @@ private:
|
|||||||
void appendCubicApproximation(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, const Sk2f& p3,
|
void appendCubicApproximation(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, const Sk2f& p3,
|
||||||
int maxSubdivisions = kMaxSubdivionsPerCubicSection);
|
int maxSubdivisions = kMaxSubdivionsPerCubicSection);
|
||||||
|
|
||||||
void appendMonotonicConic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, float w);
|
|
||||||
|
|
||||||
// Transient state used while building a contour.
|
// Transient state used while building a contour.
|
||||||
SkPoint fCurrAnchorPoint;
|
SkPoint fCurrAnchorPoint;
|
||||||
PrimitiveTallies fCurrContourTallies;
|
PrimitiveTallies fCurrContourTallies;
|
||||||
SkCubicType fCurrCubicType;
|
SkCubicType fCurrCubicType;
|
||||||
SkDEBUGCODE(bool fBuildingContour = false);
|
SkDEBUGCODE(bool fBuildingContour = false);
|
||||||
|
|
||||||
SkSTArray<128, SkPoint, true> fPoints;
|
// TODO: These points could eventually be written directly to block-allocated GPU buffers.
|
||||||
SkSTArray<32, float, true> fConicWeights;
|
SkSTArray<128, SkPoint, true> fPoints;
|
||||||
SkSTArray<128, Verb, true> fVerbs;
|
SkSTArray<128, Verb, true> fVerbs;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void GrCCGeometry::PrimitiveTallies::operator+=(const PrimitiveTallies& b) {
|
inline void GrCCGeometry::PrimitiveTallies::operator+=(const PrimitiveTallies& b) {
|
||||||
@ -139,7 +132,6 @@ inline void GrCCGeometry::PrimitiveTallies::operator+=(const PrimitiveTallies& b
|
|||||||
fWeightedTriangles += b.fWeightedTriangles;
|
fWeightedTriangles += b.fWeightedTriangles;
|
||||||
fQuadratics += b.fQuadratics;
|
fQuadratics += b.fQuadratics;
|
||||||
fCubics += b.fCubics;
|
fCubics += b.fCubics;
|
||||||
fConics += b.fConics;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GrCCGeometry::PrimitiveTallies
|
GrCCGeometry::PrimitiveTallies
|
||||||
@ -147,13 +139,12 @@ inline GrCCGeometry::PrimitiveTallies::operator-(const PrimitiveTallies& b) cons
|
|||||||
return {fTriangles - b.fTriangles,
|
return {fTriangles - b.fTriangles,
|
||||||
fWeightedTriangles - b.fWeightedTriangles,
|
fWeightedTriangles - b.fWeightedTriangles,
|
||||||
fQuadratics - b.fQuadratics,
|
fQuadratics - b.fQuadratics,
|
||||||
fCubics - b.fCubics,
|
fCubics - b.fCubics};
|
||||||
fConics - b.fConics};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool GrCCGeometry::PrimitiveTallies::operator==(const PrimitiveTallies& b) {
|
inline bool GrCCGeometry::PrimitiveTallies::operator==(const PrimitiveTallies& b) {
|
||||||
return fTriangles == b.fTriangles && fWeightedTriangles == b.fWeightedTriangles &&
|
return fTriangles == b.fTriangles && fWeightedTriangles == b.fWeightedTriangles &&
|
||||||
fQuadratics == b.fQuadratics && fCubics == b.fCubics && fConics == b.fConics;
|
fQuadratics == b.fQuadratics && fCubics == b.fCubics;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -114,9 +114,7 @@ void GrCCPathParser::parsePath(const SkPath& path, const SkPoint* deviceSpacePts
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float* conicWeights = SkPathPriv::ConicWeightData(path);
|
|
||||||
int ptsIdx = 0;
|
int ptsIdx = 0;
|
||||||
int conicWeightsIdx = 0;
|
|
||||||
bool insideContour = false;
|
bool insideContour = false;
|
||||||
|
|
||||||
for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {
|
for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {
|
||||||
@ -144,16 +142,11 @@ void GrCCPathParser::parsePath(const SkPath& path, const SkPoint* deviceSpacePts
|
|||||||
ptsIdx += 3;
|
ptsIdx += 3;
|
||||||
continue;
|
continue;
|
||||||
case SkPath::kConic_Verb:
|
case SkPath::kConic_Verb:
|
||||||
fGeometry.conicTo(&deviceSpacePts[ptsIdx - 1], conicWeights[conicWeightsIdx]);
|
SK_ABORT("Conics are not supported.");
|
||||||
ptsIdx += 2;
|
|
||||||
++conicWeightsIdx;
|
|
||||||
continue;
|
|
||||||
default:
|
default:
|
||||||
SK_ABORT("Unexpected path verb.");
|
SK_ABORT("Unexpected path verb.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SkASSERT(ptsIdx == path.countPoints());
|
|
||||||
SkASSERT(conicWeightsIdx == SkPathPriv::ConicWeightCnt(path));
|
|
||||||
|
|
||||||
this->endContourIfNeeded(insideContour);
|
this->endContourIfNeeded(insideContour);
|
||||||
}
|
}
|
||||||
@ -203,7 +196,6 @@ void GrCCPathParser::saveParsedPath(ScissorMode scissorMode, const SkIRect& clip
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GrCCGeometry::Verb::kMonotonicQuadraticTo:
|
case GrCCGeometry::Verb::kMonotonicQuadraticTo:
|
||||||
case GrCCGeometry::Verb::kMonotonicConicTo:
|
|
||||||
fan.lineTo(pts[ptsIdx + 1]);
|
fan.lineTo(pts[ptsIdx + 1]);
|
||||||
ptsIdx += 2;
|
ptsIdx += 2;
|
||||||
continue;
|
continue;
|
||||||
@ -385,9 +377,7 @@ bool GrCCPathParser::finalize(GrOnFlushResourceProvider* onFlushRP) {
|
|||||||
fBaseInstances[0].fCubics = fBaseInstances[1].fWeightedTriangles +
|
fBaseInstances[0].fCubics = fBaseInstances[1].fWeightedTriangles +
|
||||||
fTotalPrimitiveCounts[1].fWeightedTriangles;
|
fTotalPrimitiveCounts[1].fWeightedTriangles;
|
||||||
fBaseInstances[1].fCubics = fBaseInstances[0].fCubics + fTotalPrimitiveCounts[0].fCubics;
|
fBaseInstances[1].fCubics = fBaseInstances[0].fCubics + fTotalPrimitiveCounts[0].fCubics;
|
||||||
fBaseInstances[0].fConics = fBaseInstances[1].fCubics + fTotalPrimitiveCounts[1].fCubics;
|
int quadEndIdx = fBaseInstances[1].fCubics + fTotalPrimitiveCounts[1].fCubics;
|
||||||
fBaseInstances[1].fConics = fBaseInstances[0].fConics + fTotalPrimitiveCounts[0].fConics;
|
|
||||||
int quadEndIdx = fBaseInstances[1].fConics + fTotalPrimitiveCounts[1].fConics;
|
|
||||||
|
|
||||||
fInstanceBuffer = onFlushRP->makeBuffer(kVertex_GrBufferType,
|
fInstanceBuffer = onFlushRP->makeBuffer(kVertex_GrBufferType,
|
||||||
quadEndIdx * sizeof(QuadPointInstance));
|
quadEndIdx * sizeof(QuadPointInstance));
|
||||||
@ -410,7 +400,6 @@ bool GrCCPathParser::finalize(GrOnFlushResourceProvider* onFlushRP) {
|
|||||||
|
|
||||||
const SkTArray<SkPoint, true>& pts = fGeometry.points();
|
const SkTArray<SkPoint, true>& pts = fGeometry.points();
|
||||||
int ptsIdx = -1;
|
int ptsIdx = -1;
|
||||||
int nextConicWeightIdx = 0;
|
|
||||||
|
|
||||||
// Expand the ccpr verbs into GPU instance buffers.
|
// Expand the ccpr verbs into GPU instance buffers.
|
||||||
for (GrCCGeometry::Verb verb : fGeometry.verbs()) {
|
for (GrCCGeometry::Verb verb : fGeometry.verbs()) {
|
||||||
@ -465,17 +454,6 @@ bool GrCCPathParser::finalize(GrOnFlushResourceProvider* onFlushRP) {
|
|||||||
}
|
}
|
||||||
continue;
|
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.
|
case GrCCGeometry::Verb::kEndClosedContour: // endPt == startPt.
|
||||||
if (!currFanIsTessellated) {
|
if (!currFanIsTessellated) {
|
||||||
SkASSERT(!currFan.empty());
|
SkASSERT(!currFan.empty());
|
||||||
@ -511,9 +489,7 @@ bool GrCCPathParser::finalize(GrOnFlushResourceProvider* onFlushRP) {
|
|||||||
SkASSERT(instanceIndices[0].fWeightedTriangles == fBaseInstances[1].fWeightedTriangles);
|
SkASSERT(instanceIndices[0].fWeightedTriangles == fBaseInstances[1].fWeightedTriangles);
|
||||||
SkASSERT(instanceIndices[1].fWeightedTriangles == fBaseInstances[0].fCubics);
|
SkASSERT(instanceIndices[1].fWeightedTriangles == fBaseInstances[0].fCubics);
|
||||||
SkASSERT(instanceIndices[0].fCubics == fBaseInstances[1].fCubics);
|
SkASSERT(instanceIndices[0].fCubics == fBaseInstances[1].fCubics);
|
||||||
SkASSERT(instanceIndices[1].fCubics == fBaseInstances[0].fConics);
|
SkASSERT(instanceIndices[1].fCubics == quadEndIdx);
|
||||||
SkASSERT(instanceIndices[0].fConics == fBaseInstances[1].fConics);
|
|
||||||
SkASSERT(instanceIndices[1].fConics == quadEndIdx);
|
|
||||||
|
|
||||||
fMeshesScratchBuffer.reserve(fMaxMeshesPerDraw);
|
fMeshesScratchBuffer.reserve(fMaxMeshesPerDraw);
|
||||||
fDynamicStatesScratchBuffer.reserve(fMaxMeshesPerDraw);
|
fDynamicStatesScratchBuffer.reserve(fMaxMeshesPerDraw);
|
||||||
@ -551,11 +527,6 @@ void GrCCPathParser::drawCoverageCount(GrOpFlushState* flushState, CoverageCount
|
|||||||
this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kCubics,
|
this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kCubics,
|
||||||
&PrimitiveTallies::fCubics, drawBounds);
|
&PrimitiveTallies::fCubics, drawBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batchTotalCounts.fConics) {
|
|
||||||
this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kConics,
|
|
||||||
&PrimitiveTallies::fConics, drawBounds);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrCCPathParser::drawPrimitives(GrOpFlushState* flushState, const GrPipeline& pipeline,
|
void GrCCPathParser::drawPrimitives(GrOpFlushState* flushState, const GrPipeline& pipeline,
|
||||||
|
@ -65,6 +65,10 @@ GrPathRenderer::CanDrawPath GrCoverageCountingPathRenderer::onCanDrawPath(
|
|||||||
|
|
||||||
SkPath path;
|
SkPath path;
|
||||||
args.fShape->asPath(&path);
|
args.fShape->asPath(&path);
|
||||||
|
if (SkPathPriv::ConicWeightCnt(path)) {
|
||||||
|
return CanDrawPath::kNo;
|
||||||
|
}
|
||||||
|
|
||||||
SkRect devBounds;
|
SkRect devBounds;
|
||||||
SkIRect devIBounds;
|
SkIRect devIBounds;
|
||||||
args.fViewMatrix->mapRect(&devBounds, path.getBounds());
|
args.fViewMatrix->mapRect(&devBounds, path.getBounds());
|
||||||
@ -189,6 +193,11 @@ bool GrCoverageCountingPathRenderer::canMakeClipProcessor(const SkPath& deviceSp
|
|||||||
if (!fDrawCachablePaths && !deviceSpacePath.isVolatile()) {
|
if (!fDrawCachablePaths && !deviceSpacePath.isVolatile()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SkPathPriv::ConicWeightCnt(deviceSpacePath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,8 +467,7 @@ DEF_TEST(Sk2f_Store4, r) {
|
|||||||
Sk2f p1{1, 5};
|
Sk2f p1{1, 5};
|
||||||
Sk2f p2{2, 6};
|
Sk2f p2{2, 6};
|
||||||
Sk2f p3{3, 7};
|
Sk2f p3{3, 7};
|
||||||
|
float dst[8];
|
||||||
float dst[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
|
|
||||||
Sk2f::Store4(dst, p0, p1, p2, p3);
|
Sk2f::Store4(dst, p0, p1, p2, p3);
|
||||||
REPORTER_ASSERT(r, dst[0] == 0);
|
REPORTER_ASSERT(r, dst[0] == 0);
|
||||||
REPORTER_ASSERT(r, dst[1] == 1);
|
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[5] == 5);
|
||||||
REPORTER_ASSERT(r, dst[6] == 6);
|
REPORTER_ASSERT(r, dst[6] == 6);
|
||||||
REPORTER_ASSERT(r, dst[7] == 7);
|
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) {
|
DEF_TEST(Sk4f_minmax, r) {
|
||||||
|
Loading…
Reference in New Issue
Block a user