Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
beziereffects.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8// This test only works with the GPU backend.
9
10#include "gm/gm.h"
17#include "include/core/SkRect.h"
20#include "include/core/SkSize.h"
26#include "src/base/SkRandom.h"
28#include "src/core/SkGeometry.h"
51
52#include <memory>
53#include <utility>
54
55class GrAppliedClip;
56
57namespace skiagm {
58
59class BezierTestOp : public GrMeshDrawOp {
60public:
62
64 const GrCaps& caps, const GrAppliedClip* clip, GrClampType clampType) override {
65 return fProcessorSet.finalize(
67 &GrUserStencilSettings::kUnused, caps, clampType, &fColor);
68 }
69
70 void visitProxies(const GrVisitProxyFunc& func) const override {
71 if (fProgramInfo) {
72 fProgramInfo->visitFPProxies(func);
73 } else {
74 fProcessorSet.visitProxies(func);
75 }
76 }
77
78protected:
81 , fRect(rect)
82 , fColor(color)
83 , fProcessorSet(SkBlendMode::kSrc) {
85 }
86
87 virtual GrGeometryProcessor* makeGP(const GrCaps& caps, SkArenaAlloc* arena) = 0;
88
89 GrProgramInfo* programInfo() override { return fProgramInfo; }
90
91 void onCreateProgramInfo(const GrCaps* caps,
92 SkArenaAlloc* arena,
93 const GrSurfaceProxyView& writeView,
94 bool usesMSAASurface,
95 GrAppliedClip&& appliedClip,
96 const GrDstProxyView& dstProxyView,
97 GrXferBarrierFlags renderPassXferBarriers,
98 GrLoadOp colorLoadOp) override {
99 auto gp = this->makeGP(*caps, arena);
100 if (!gp) {
101 return;
102 }
103
105
106 fProgramInfo = GrSimpleMeshDrawOpHelper::CreateProgramInfo(caps, arena, writeView,
107 usesMSAASurface,
108 std::move(appliedClip),
109 dstProxyView, gp,
110 std::move(fProcessorSet),
112 renderPassXferBarriers,
113 colorLoadOp,
114 flags);
115 }
116
117 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) final {
118 if (!fProgramInfo) {
119 this->createProgramInfo(flushState);
120 }
121
122 if (!fProgramInfo) {
123 return;
124 }
125
126 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
127 flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
128 flushState->drawMesh(*fMesh);
129 }
130
131 const SkRect& rect() const { return fRect; }
132 const SkPMColor4f& color() const { return fColor; }
133
134protected:
135 GrSimpleMesh* fMesh = nullptr; // filled in by the derived classes
136
137private:
138 SkRect fRect;
139 SkPMColor4f fColor;
140 GrProcessorSet fProcessorSet;
141 GrProgramInfo* fProgramInfo = nullptr;
142
143 using INHERITED = GrMeshDrawOp;
144};
145
146/**
147 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
148 */
150public:
152
153 const char* name() const final { return "BezierConicTestOp"; }
154
156 const SkRect& rect,
157 const SkPMColor4f& color,
158 const SkMatrix& klm) {
159 return GrOp::Make<BezierConicTestOp>(context, rect, color, klm);
160 }
161
162private:
163 friend class ::GrOp; // for ctor
164
165 BezierConicTestOp(const SkRect& rect, const SkPMColor4f& color, const SkMatrix& klm)
166 : INHERITED(rect, color, ClassID())
167 , fKLM(klm) {}
168
169 struct Vertex {
170 SkPoint fPosition;
171 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
172 };
173
174 GrGeometryProcessor* makeGP(const GrCaps& caps, SkArenaAlloc* arena) final {
175 auto tmp = GrConicEffect::Make(arena, this->color(), SkMatrix::I(), caps, SkMatrix::I(),
176 false);
177 if (!tmp) {
178 return nullptr;
179 }
180 SkASSERT(tmp->vertexStride() == sizeof(Vertex));
181 return tmp;
182 }
183
185 QuadHelper helper(target, sizeof(Vertex), 1);
186 Vertex* verts = reinterpret_cast<Vertex*>(helper.vertices());
187 if (!verts) {
188 return;
189 }
190 SkRect rect = this->rect();
191 SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect, sizeof(Vertex));
192 for (int v = 0; v < 4; ++v) {
193 SkPoint3 pt3 = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
194 fKLM.mapHomogeneousPoints((SkPoint3* ) verts[v].fKLM, &pt3, 1);
195 }
196
197 fMesh = helper.mesh();
198 }
199
200 SkMatrix fKLM;
201
202 inline static constexpr int kVertsPerCubic = 4;
203 inline static constexpr int kIndicesPerCubic = 6;
204
205 using INHERITED = BezierTestOp;
206};
207
208
209/**
210 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
211 */
212class BezierConicEffects : public GpuGM {
213public:
215 this->setBGColor(0xFFFFFFFF);
216 }
217
218protected:
219 static const int kNumConics = 10;
220 static const int kCellWidth = 128;
221 static const int kCellHeight = 128;
222
223 SkString getName() const override { return SkString("bezier_conic_effects"); }
224
226
227 DrawResult onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) override {
229 if (!sdc) {
230 *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
231 return DrawResult::kSkip;
232 }
233
234 const SkScalar w = kCellWidth, h = kCellHeight;
235 const SkPMColor4f kOpaqueBlack = SkPMColor4f::FromBytes_RGBA(0xff000000);
236
237 const SkPoint baseControlPts[kNumConics][3] = {
238 { { 0.31f * w, 0.01f * h}, { 0.48f * w, 0.74f * h }, { 0.19f * w, 0.33f * h } },
239 { { 0.00f * w, 0.07f * h}, { 0.30f * w, 0.70f * h }, { 0.47f * w, 0.37f * h } },
240 { { 0.15f * w, 0.23f * h}, { 0.49f * w, 0.87f * h }, { 0.85f * w, 0.66f * h } },
241 { { 0.09f * w, 0.15f * h}, { 0.42f * w, 0.33f * h }, { 0.17f * w, 0.38f * h } },
242 { { 0.98f * w, 0.54f * h}, { 0.83f * w, 0.91f * h }, { 0.62f * w, 0.40f * h } },
243 { { 0.96f * w, 0.65f * h}, { 0.03f * w, 0.79f * h }, { 0.24f * w, 0.56f * h } },
244 { { 0.57f * w, 0.12f * h}, { 0.33f * w, 0.67f * h }, { 0.59f * w, 0.33f * h } },
245 { { 0.12f * w, 0.72f * h}, { 0.69f * w, 0.85f * h }, { 0.46f * w, 0.32f * h } },
246 { { 0.27f * w, 0.49f * h}, { 0.41f * w, 0.02f * h }, { 0.11f * w, 0.42f * h } },
247 { { 0.40f * w, 0.13f * h}, { 0.83f * w, 0.30f * h }, { 0.31f * w, 0.68f * h } },
248 };
249 const SkScalar weights[kNumConics] = { 0.62f, 0.01f, 0.95f, 1.48f, 0.37f,
250 0.66f, 0.15f, 0.14f, 0.61f, 1.4f };
251
252 SkPaint ctrlPtPaint;
253 ctrlPtPaint.setColor(SK_ColorRED);
254
255 SkPaint choppedPtPaint;
256 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
257
258 SkPaint polyPaint;
259 polyPaint.setColor(0xffA0A0A0);
260 polyPaint.setStrokeWidth(0);
262
263 SkPaint boundsPaint;
264 boundsPaint.setColor(0xff808080);
265 boundsPaint.setStrokeWidth(0);
266 boundsPaint.setStyle(SkPaint::kStroke_Style);
267
268
269 for (int row = 0; row < kNumConics; ++row) {
270 SkScalar x = 0;
271 SkScalar y = row * h;
272 SkPoint controlPts[] = {
273 {x + baseControlPts[row][0].fX, y + baseControlPts[row][0].fY},
274 {x + baseControlPts[row][1].fX, y + baseControlPts[row][1].fY},
275 {x + baseControlPts[row][2].fX, y + baseControlPts[row][2].fY}
276 };
277
278 for (int i = 0; i < 3; ++i) {
279 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
280 }
281
282 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
283
284 SkConic dst[4];
285 SkMatrix klm;
286 int cnt = ChopConic(controlPts, dst, weights[row]);
287 GrPathUtils::getConicKLM(controlPts, weights[row], &klm);
288
289 for (int c = 0; c < cnt; ++c) {
290 SkPoint* pts = dst[c].fPts;
291 for (int i = 0; i < 3; ++i) {
292 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
293 }
294
295 SkRect bounds;
296 bounds.setBounds(pts, 3);
297
298 canvas->drawRect(bounds, boundsPaint);
299
300 GrOp::Owner op = BezierConicTestOp::Make(rContext, bounds,
301 kOpaqueBlack, klm);
302 sdc->addDrawOp(std::move(op));
303 }
304 }
305
306 return DrawResult::kOk;
307 }
308
309private:
310 // Uses the max curvature function for quads to estimate
311 // where to chop the conic. If the max curvature is not
312 // found along the curve segment it will return 1 and
313 // dst[0] is the original conic. If it returns 2 the dst[0]
314 // and dst[1] are the two new conics.
315 static int SplitConic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
317 if (t == 0 || t == 1) {
318 if (dst) {
319 dst[0].set(src, weight);
320 }
321 return 1;
322 } else {
323 if (dst) {
325 conic.set(src, weight);
326 if (!conic.chopAt(t, dst)) {
327 dst[0].set(src, weight);
328 return 1;
329 }
330 }
331 return 2;
332 }
333 }
334
335 // Calls SplitConic on the entire conic and then once more on each subsection.
336 // Most cases will result in either 1 conic (chop point is not within t range)
337 // or 3 points (split once and then one subsection is split again).
338 static int ChopConic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
339 SkConic dstTemp[2];
340 int conicCnt = SplitConic(src, dstTemp, weight);
341 if (2 == conicCnt) {
342 int conicCnt2 = SplitConic(dstTemp[0].fPts, dst, dstTemp[0].fW);
343 conicCnt = conicCnt2 + SplitConic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
344 } else {
345 dst[0] = dstTemp[0];
346 }
347 return conicCnt;
348 }
349
350 using INHERITED = GM;
351};
352
353//////////////////////////////////////////////////////////////////////////////
354
356public:
358 const char* name() const override { return "BezierQuadTestOp"; }
359
361 const SkRect& rect,
362 const SkPMColor4f& color,
363 const GrPathUtils::QuadUVMatrix& devToUV) {
364 return GrOp::Make<BezierQuadTestOp>(context, rect, color, devToUV);
365 }
366
367private:
368 friend class ::GrOp; // for ctor
369
371 const GrPathUtils::QuadUVMatrix& devToUV)
372 : INHERITED(rect, color, ClassID())
373 , fDevToUV(devToUV) {}
374
375 struct Vertex {
376 SkPoint fPosition;
377 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
378 };
379
380 GrGeometryProcessor* makeGP(const GrCaps& caps, SkArenaAlloc* arena) final {
381 auto tmp = GrQuadEffect::Make(arena, this->color(), SkMatrix::I(), caps, SkMatrix::I(),
382 false);
383 if (!tmp) {
384 return nullptr;
385 }
386 SkASSERT(tmp->vertexStride() == sizeof(Vertex));
387 return tmp;
388 }
389
391 QuadHelper helper(target, sizeof(Vertex), 1);
392 Vertex* verts = reinterpret_cast<Vertex*>(helper.vertices());
393 if (!verts) {
394 return;
395 }
396 SkRect rect = this->rect();
397 SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect, sizeof(Vertex));
398 fDevToUV.apply(verts, 4, sizeof(Vertex), sizeof(SkPoint));
399
400 fMesh = helper.mesh();
401 }
402
404
405 inline static constexpr int kVertsPerCubic = 4;
406 inline static constexpr int kIndicesPerCubic = 6;
407
408 using INHERITED = BezierTestOp;
409};
410
411/**
412 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
413 */
414class BezierQuadEffects : public GpuGM {
415public:
417 this->setBGColor(0xFFFFFFFF);
418 }
419
420protected:
421 static const int kNumQuads = 5;
422 static const int kCellWidth = 128;
423 static const int kCellHeight = 128;
424
425 SkString getName() const override { return SkString("bezier_quad_effects"); }
426
428
429 DrawResult onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) override {
431 if (!sdc) {
432 *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
433 return DrawResult::kSkip;
434 }
435
436 const SkScalar w = kCellWidth, h = kCellHeight;
437 const SkPMColor4f kOpaqueBlack = SkPMColor4f::FromBytes_RGBA(0xff000000);
438
439 const SkPoint baseControlPts[kNumQuads][3] = {
440 { { 0.31f * w, 0.01f * h}, { 0.48f * w, 0.74f * h }, { 0.19f * w, 0.33f * h } },
441 { { 0.00f * w, 0.07f * h}, { 0.30f * w, 0.70f * h }, { 0.47f * w, 0.37f * h } },
442 { { 0.15f * w, 0.23f * h}, { 0.49f * w, 0.87f * h }, { 0.85f * w, 0.66f * h } },
443 { { 0.09f * w, 0.15f * h}, { 0.42f * w, 0.33f * h }, { 0.17f * w, 0.38f * h } },
444 { { 0.98f * w, 0.54f * h}, { 0.83f * w, 0.91f * h }, { 0.62f * w, 0.40f * h } },
445 };
446
447 SkPaint ctrlPtPaint;
448 ctrlPtPaint.setColor(SK_ColorRED);
449
450 SkPaint choppedPtPaint;
451 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
452
453 SkPaint polyPaint;
454 polyPaint.setColor(0xffA0A0A0);
455 polyPaint.setStrokeWidth(0);
457
458 SkPaint boundsPaint;
459 boundsPaint.setColor(0xff808080);
460 boundsPaint.setStrokeWidth(0);
461 boundsPaint.setStyle(SkPaint::kStroke_Style);
462
463 for (int row = 0; row < kNumQuads; ++row) {
464 SkScalar x = 0;
465 SkScalar y = row * h;
466 SkPoint controlPts[] = {
467 {x + baseControlPts[row][0].fX, y + baseControlPts[row][0].fY},
468 {x + baseControlPts[row][1].fX, y + baseControlPts[row][1].fY},
469 {x + baseControlPts[row][2].fX, y + baseControlPts[row][2].fY}
470 };
471
472 for (int i = 0; i < 3; ++i) {
473 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
474 }
475
476 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
477
478 SkPoint chopped[5];
479 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
480
481 for (int c = 0; c < cnt; ++c) {
482 SkPoint* pts = chopped + 2 * c;
483
484 for (int i = 0; i < 3; ++i) {
485 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
486 }
487
488 SkRect bounds;
489 bounds.setBounds(pts, 3);
490
491 canvas->drawRect(bounds, boundsPaint);
492
493 GrPathUtils::QuadUVMatrix DevToUV(pts);
494
495 GrOp::Owner op = BezierQuadTestOp::Make(rContext, bounds,
496 kOpaqueBlack, DevToUV);
497 sdc->addDrawOp(std::move(op));
498 }
499 }
500
501 return DrawResult::kOk;
502 }
503
504private:
505 using INHERITED = GM;
506};
507
508DEF_GM(return new BezierConicEffects;)
509DEF_GM(return new BezierQuadEffects;)
510} // namespace skiagm
SkPoint fPts[2]
GrTriangulator::Vertex Vertex
#define DEFINE_OP_CLASS_ID
Definition GrOp.h:64
GrClampType
std::function< void(GrSurfaceProxy *, skgpu::Mipmapped)> GrVisitProxyFunc
GrLoadOp
GrXferBarrierFlags
#define SkASSERT(cond)
Definition SkAssert.h:116
SkBlendMode
Definition SkBlendMode.h:38
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
SkScalar SkFindQuadMaxCurvature(const SkPoint src[3])
int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5])
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
static GrGeometryProcessor * Make(SkArenaAlloc *arena, const SkPMColor4f &color, const SkMatrix &viewMatrix, const GrCaps &caps, const SkMatrix &localMatrix, bool usesLocalCoords, uint8_t coverage=0xff)
FixedFunctionFlags
Definition GrDrawOp.h:104
void * vertices() const
GrSimpleMesh * mesh()
void createProgramInfo(const GrCaps *caps, SkArenaAlloc *arena, const GrSurfaceProxyView &writeView, bool usesMSAASurface, GrAppliedClip &&appliedClip, const GrDstProxyView &dstProxyView, GrXferBarrierFlags renderPassXferBarriers, GrLoadOp colorLoadOp)
std::unique_ptr< GrOp > Owner
Definition GrOp.h:72
uint32_t classID() const
Definition GrOp.h:158
void setBounds(const SkRect &newBounds, HasAABloat aabloat, IsHairline zeroArea)
Definition GrOp.h:279
void apply(void *vertices, int vertexCount, size_t stride, size_t uvOffset) const
Definition GrPathUtils.h:87
void visitProxies(const GrVisitProxyFunc &) const
Analysis finalize(const GrProcessorAnalysisColor &, const GrProcessorAnalysisCoverage, const GrAppliedClip *, const GrUserStencilSettings *, const GrCaps &, GrClampType, SkPMColor4f *inputColorOverride)
const GrPipeline & pipeline() const
const GrGeometryProcessor & geomProc() const
void visitFPProxies(const GrVisitProxyFunc &func) const
static GrGeometryProcessor * Make(SkArenaAlloc *arena, const SkPMColor4f &color, const SkMatrix &viewMatrix, const GrCaps &caps, const SkMatrix &localMatrix, bool usesLocalCoords, uint8_t coverage=0xff)
static GrProgramInfo * CreateProgramInfo(const GrCaps *, SkArenaAlloc *, const GrPipeline *, const GrSurfaceProxyView &writeView, bool usesMSAASurface, GrGeometryProcessor *, GrPrimitiveType, GrXferBarrierFlags renderPassXferBarriers, GrLoadOp colorLoadOp, const GrUserStencilSettings *=&GrUserStencilSettings::kUnused)
void drawRect(const SkRect &rect, const SkPaint &paint)
void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint &paint)
@ kPolygon_PointMode
draw the array of points as a open polygon
Definition SkCanvas.h:1243
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const
static const SkMatrix & I()
void setStyle(Style style)
Definition SkPaint.cpp:105
void setColor(SkColor color)
Definition SkPaint.cpp:119
SkColor getColor() const
Definition SkPaint.h:225
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
void setStrokeWidth(SkScalar width)
Definition SkPaint.cpp:159
static void SetRectTriStrip(SkPoint v[], SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride)
SkString getName() const override
DrawResult onDraw(GrRecordingContext *rContext, SkCanvas *canvas, SkString *errorMsg) override
SkISize getISize() override
DEFINE_OP_CLASS_ID const char * name() const final
static GrOp::Owner Make(GrRecordingContext *context, const SkRect &rect, const SkPMColor4f &color, const SkMatrix &klm)
void onPrepareDraws(GrMeshDrawTarget *target) final
GrGeometryProcessor * makeGP(const GrCaps &caps, SkArenaAlloc *arena) final
DrawResult onDraw(GrRecordingContext *rContext, SkCanvas *canvas, SkString *errorMsg) override
SkString getName() const override
SkISize getISize() override
DEFINE_OP_CLASS_ID const char * name() const override
void onPrepareDraws(GrMeshDrawTarget *target) final
GrGeometryProcessor * makeGP(const GrCaps &caps, SkArenaAlloc *arena) final
static GrOp::Owner Make(GrRecordingContext *context, const SkRect &rect, const SkPMColor4f &color, const GrPathUtils::QuadUVMatrix &devToUV)
const SkRect & rect() const
void visitProxies(const GrVisitProxyFunc &func) const override
void onExecute(GrOpFlushState *flushState, const SkRect &chainBounds) final
void onCreateProgramInfo(const GrCaps *caps, SkArenaAlloc *arena, const GrSurfaceProxyView &writeView, bool usesMSAASurface, GrAppliedClip &&appliedClip, const GrDstProxyView &dstProxyView, GrXferBarrierFlags renderPassXferBarriers, GrLoadOp colorLoadOp) override
BezierTestOp(const SkRect &rect, const SkPMColor4f &color, int32_t classID)
GrProcessorSet::Analysis finalize(const GrCaps &caps, const GrAppliedClip *clip, GrClampType clampType) override
GrProgramInfo * programInfo() override
FixedFunctionFlags fixedFunctionFlags() const override
virtual GrGeometryProcessor * makeGP(const GrCaps &caps, SkArenaAlloc *arena)=0
const SkPMColor4f & color() const
float SkScalar
Definition extension.cpp:12
FlutterSemanticsFlag flags
uint32_t * target
#define DEF_GM(CODE)
Definition gm.h:40
double y
double x
void getConicKLM(const SkPoint p[3], const SkScalar weight, SkMatrix *klm)
dst
Definition cp.py:12
SurfaceDrawContext * TopDeviceSurfaceDrawContext(const SkCanvas *canvas)
Definition GrCanvas.cpp:20
AI float conic(float tolerance, const SkPoint pts[], float w, const VectorXform &vectorXform=VectorXform())
DrawResult
Definition gm.h:104
SkScalar w
SkScalar h
static const GrUserStencilSettings & kUnused
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
SkScalar x() const
Definition SkPoint3.h:24
float fX
x-axis value
float fY
y-axis value
static SkRGBA4f FromBytes_RGBA(uint32_t color)