aboutsummaryrefslogtreecommitdiffhomepage
path: root/gm/beziereffects.cpp
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2017-06-08 13:12:02 -0600
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-06-09 17:13:54 +0000
commitfebbffad1c24136f041d7fc2d5ffcd50e47a047f (patch)
tree860970fa626aa0901fadce958e755c107f7c97ca /gm/beziereffects.cpp
parent01b2b83aba10bc3767d660cd619c1da58b5eb0b5 (diff)
Improve cubic KLM accuracy
Moves cubic root finding logic out of GrPathUtils and PathOpsCubicIntersectionTest, and unifies it in SkGeometry. "Normalizes" the homogeneous parameter values of the roots, rather than the cubic inflection function. Does this normalization by twiddling the exponents instead of division (which causes a loss of precision). Abandons the built-in derivatives in GrCubicEffect. These don't have high enough precision on many mobile gpus. Instead we pass the KLM matrix to the vertex shader via uniform, where we can use it to set up new linear functionals from which the fragment shader can calculate the gradient of the implicit function. Bug: skia:4410 Change-Id: Ibd64e999520adc8cdef7803a492d3699995aef5a Reviewed-on: https://skia-review.googlesource.com/19017 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Chris Dalton <csmartdalton@google.com>
Diffstat (limited to 'gm/beziereffects.cpp')
-rw-r--r--gm/beziereffects.cpp111
1 files changed, 73 insertions, 38 deletions
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index d3f1965d4f..7e492b0ca2 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -24,53 +24,36 @@
namespace skiagm {
-class BezierCubicOrConicTestOp : public GrTestMeshDrawOp {
+class BezierCubicTestOp : public GrTestMeshDrawOp {
public:
DEFINE_OP_CLASS_ID
- const char* name() const override { return "BezierCubicOrConicTestOp"; }
+ const char* name() const override { return "BezierCubicTestOp"; }
static std::unique_ptr<GrLegacyMeshDrawOp> Make(sk_sp<GrGeometryProcessor> gp,
- const SkRect& rect, GrColor color,
- const SkMatrix& klm, SkScalar sign) {
- return std::unique_ptr<GrLegacyMeshDrawOp>(
- new BezierCubicOrConicTestOp(gp, rect, color, klm, sign));
+ const SkRect& rect, GrColor color) {
+ return std::unique_ptr<GrLegacyMeshDrawOp>(new BezierCubicTestOp(gp, rect, color));
}
private:
- BezierCubicOrConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
- const SkMatrix& klm, SkScalar sign)
+ BezierCubicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color)
: INHERITED(ClassID(), rect, color)
- , fKLM(klm)
, fRect(rect)
, fGeometryProcessor(std::move(gp)) {
- if (1 != sign) {
- fKLM.postScale(sign, sign);
- }
}
- struct Vertex {
- SkPoint fPosition;
- float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
- };
void onPrepareDraws(Target* target) const override {
QuadHelper helper;
size_t vertexStride = fGeometryProcessor->getVertexStride();
- SkASSERT(vertexStride == sizeof(Vertex));
- Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
- if (!verts) {
+ SkASSERT(vertexStride == sizeof(SkPoint));
+ SkPoint* pts = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1));
+ if (!pts) {
return;
}
- verts[0].fPosition.setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
- sizeof(Vertex));
- for (int v = 0; v < 4; ++v) {
- SkScalar pt3[3] = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
- fKLM.mapHomogeneousPoints(verts[v].fKLM, pt3, 1);
- }
+ pts[0].setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom, vertexStride);
helper.recordDraw(target, fGeometryProcessor.get(), this->pipeline());
}
- SkMatrix fKLM;
SkRect fRect;
sk_sp<GrGeometryProcessor> fGeometryProcessor;
@@ -135,13 +118,9 @@ protected:
{rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
{rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
};
- for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
- sk_sp<GrGeometryProcessor> gp;
- GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
- gp = GrCubicEffect::Make(color, SkMatrix::I(), et, *context->caps());
- if (!gp) {
- continue;
- }
+ for(GrPrimitiveEdgeType edgeType : {kFillBW_GrProcessorEdgeType,
+ kFillAA_GrProcessorEdgeType,
+ kHairlineAA_GrProcessorEdgeType}) {
SkScalar x = col * w;
SkScalar y = row * h;
SkPoint controlPts[] = {
@@ -193,13 +172,16 @@ protected:
GrPaint grPaint;
grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
- SkScalar sign = 1.0f;
- if (c == loopIndex && cnt != 3) {
- sign = -1.0f;
+ bool flipKL = (c == loopIndex && cnt != 3);
+ sk_sp<GrGeometryProcessor> gp = GrCubicEffect::Make(color, SkMatrix::I(), klm,
+ flipKL, edgeType,
+ *context->caps());
+ if (!gp) {
+ break;
}
std::unique_ptr<GrLegacyMeshDrawOp> op =
- BezierCubicOrConicTestOp::Make(gp, bounds, color, klm, sign);
+ BezierCubicTestOp::Make(std::move(gp), bounds, color);
renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
std::move(grPaint), GrAAType::kNone, std::move(op));
@@ -219,6 +201,59 @@ private:
//////////////////////////////////////////////////////////////////////////////
+class BezierConicTestOp : public GrTestMeshDrawOp {
+public:
+ DEFINE_OP_CLASS_ID
+
+ const char* name() const override { return "BezierConicTestOp"; }
+
+ static std::unique_ptr<GrLegacyMeshDrawOp> Make(sk_sp<GrGeometryProcessor> gp,
+ const SkRect& rect, GrColor color,
+ const SkMatrix& klm) {
+ return std::unique_ptr<GrLegacyMeshDrawOp>(new BezierConicTestOp(gp, rect, color, klm));
+ }
+
+private:
+ BezierConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
+ const SkMatrix& klm)
+ : INHERITED(ClassID(), rect, color)
+ , fKLM(klm)
+ , fRect(rect)
+ , fGeometryProcessor(std::move(gp)) {
+ }
+ struct Vertex {
+ SkPoint fPosition;
+ float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
+ };
+
+ void onPrepareDraws(Target* target) const override {
+ QuadHelper helper;
+ size_t vertexStride = fGeometryProcessor->getVertexStride();
+ SkASSERT(vertexStride == sizeof(Vertex));
+ Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
+ if (!verts) {
+ return;
+ }
+ verts[0].fPosition.setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
+ sizeof(Vertex));
+ for (int v = 0; v < 4; ++v) {
+ SkScalar pt3[3] = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
+ fKLM.mapHomogeneousPoints(verts[v].fKLM, pt3, 1);
+ }
+ helper.recordDraw(target, fGeometryProcessor.get(), this->pipeline());
+ }
+
+ SkMatrix fKLM;
+ SkRect fRect;
+ sk_sp<GrGeometryProcessor> fGeometryProcessor;
+
+ static constexpr int kVertsPerCubic = 4;
+ static constexpr int kIndicesPerCubic = 6;
+
+ typedef GrTestMeshDrawOp INHERITED;
+};
+
+
/**
* This GM directly exercises effects that draw Bezier curves in the GPU backend.
*/
@@ -332,7 +367,7 @@ protected:
grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
std::unique_ptr<GrLegacyMeshDrawOp> op =
- BezierCubicOrConicTestOp::Make(gp, bounds, color, klm, 1.f);
+ BezierConicTestOp::Make(gp, bounds, color, klm);
renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
std::move(grPaint), GrAAType::kNone, std::move(op));