beziereffects.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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. // This test only works with the GPU backend.
  8. #include "gm/gm.h"
  9. #include "include/core/SkBlendMode.h"
  10. #include "include/core/SkCanvas.h"
  11. #include "include/core/SkMatrix.h"
  12. #include "include/core/SkPaint.h"
  13. #include "include/core/SkPoint.h"
  14. #include "include/core/SkPoint3.h"
  15. #include "include/core/SkRect.h"
  16. #include "include/core/SkRefCnt.h"
  17. #include "include/core/SkScalar.h"
  18. #include "include/core/SkSize.h"
  19. #include "include/core/SkString.h"
  20. #include "include/core/SkTypes.h"
  21. #include "include/gpu/GrContext.h"
  22. #include "include/private/GrRecordingContext.h"
  23. #include "include/private/GrSharedEnums.h"
  24. #include "include/private/GrTypesPriv.h"
  25. #include "include/private/SkColorData.h"
  26. #include "include/utils/SkRandom.h"
  27. #include "src/core/SkGeometry.h"
  28. #include "src/core/SkPointPriv.h"
  29. #include "src/gpu/GrCaps.h"
  30. #include "src/gpu/GrContextPriv.h"
  31. #include "src/gpu/GrGeometryProcessor.h"
  32. #include "src/gpu/GrMemoryPool.h"
  33. #include "src/gpu/GrOpFlushState.h"
  34. #include "src/gpu/GrPaint.h"
  35. #include "src/gpu/GrProcessorAnalysis.h"
  36. #include "src/gpu/GrProcessorSet.h"
  37. #include "src/gpu/GrRecordingContextPriv.h"
  38. #include "src/gpu/GrRenderTargetContext.h"
  39. #include "src/gpu/GrRenderTargetContextPriv.h"
  40. #include "src/gpu/GrUserStencilSettings.h"
  41. #include "src/gpu/effects/GrBezierEffect.h"
  42. #include "src/gpu/effects/GrPorterDuffXferProcessor.h"
  43. #include "src/gpu/geometry/GrPathUtils.h"
  44. #include "src/gpu/ops/GrDrawOp.h"
  45. #include "src/gpu/ops/GrMeshDrawOp.h"
  46. #include "src/gpu/ops/GrOp.h"
  47. #include <memory>
  48. #include <utility>
  49. class GrAppliedClip;
  50. namespace skiagm {
  51. class BezierTestOp : public GrMeshDrawOp {
  52. public:
  53. FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
  54. GrProcessorSet::Analysis finalize(
  55. const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
  56. GrClampType clampType) override {
  57. return fProcessorSet.finalize(
  58. fColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
  59. &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, caps, clampType, &fColor);
  60. }
  61. void visitProxies(const VisitProxyFunc& func) const override {
  62. fProcessorSet.visitProxies(func);
  63. }
  64. protected:
  65. BezierTestOp(sk_sp<const GrGeometryProcessor> gp, const SkRect& rect, const SkPMColor4f& color,
  66. int32_t classID)
  67. : INHERITED(classID)
  68. , fRect(rect)
  69. , fColor(color)
  70. , fGeometryProcessor(std::move(gp))
  71. , fProcessorSet(SkBlendMode::kSrc) {
  72. this->setBounds(rect, HasAABloat::kYes, IsZeroArea::kNo);
  73. }
  74. void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
  75. flushState->executeDrawsAndUploadsForMeshDrawOp(
  76. this, chainBounds, std::move(fProcessorSet));
  77. }
  78. sk_sp<const GrGeometryProcessor> gp() const { return fGeometryProcessor; }
  79. const SkRect& rect() const { return fRect; }
  80. const SkPMColor4f& color() const { return fColor; }
  81. private:
  82. SkRect fRect;
  83. SkPMColor4f fColor;
  84. sk_sp<const GrGeometryProcessor> fGeometryProcessor;
  85. GrProcessorSet fProcessorSet;
  86. typedef GrMeshDrawOp INHERITED;
  87. };
  88. /**
  89. * This GM directly exercises effects that draw Bezier curves in the GPU backend.
  90. */
  91. class BezierConicTestOp : public BezierTestOp {
  92. public:
  93. DEFINE_OP_CLASS_ID
  94. const char* name() const override { return "BezierConicTestOp"; }
  95. static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
  96. sk_sp<const GrGeometryProcessor> gp,
  97. const SkRect& rect,
  98. const SkPMColor4f& color,
  99. const SkMatrix& klm) {
  100. GrOpMemoryPool* pool = context->priv().opMemoryPool();
  101. return pool->allocate<BezierConicTestOp>(std::move(gp), rect, color, klm);
  102. }
  103. private:
  104. friend class ::GrOpMemoryPool; // for ctor
  105. BezierConicTestOp(sk_sp<const GrGeometryProcessor> gp, const SkRect& rect,
  106. const SkPMColor4f& color, const SkMatrix& klm)
  107. : INHERITED(std::move(gp), rect, color, ClassID()), fKLM(klm) {}
  108. struct Vertex {
  109. SkPoint fPosition;
  110. float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
  111. };
  112. void onPrepareDraws(Target* target) override {
  113. SkASSERT(this->gp()->vertexStride() == sizeof(Vertex));
  114. QuadHelper helper(target, sizeof(Vertex), 1);
  115. Vertex* verts = reinterpret_cast<Vertex*>(helper.vertices());
  116. if (!verts) {
  117. return;
  118. }
  119. SkRect rect = this->rect();
  120. SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect.fLeft, rect.fTop, rect.fRight,
  121. rect.fBottom, sizeof(Vertex));
  122. for (int v = 0; v < 4; ++v) {
  123. SkPoint3 pt3 = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
  124. fKLM.mapHomogeneousPoints((SkPoint3* ) verts[v].fKLM, &pt3, 1);
  125. }
  126. helper.recordDraw(target, this->gp());
  127. }
  128. SkMatrix fKLM;
  129. static constexpr int kVertsPerCubic = 4;
  130. static constexpr int kIndicesPerCubic = 6;
  131. typedef BezierTestOp INHERITED;
  132. };
  133. /**
  134. * This GM directly exercises effects that draw Bezier curves in the GPU backend.
  135. */
  136. class BezierConicEffects : public GpuGM {
  137. public:
  138. BezierConicEffects() {
  139. this->setBGColor(0xFFFFFFFF);
  140. }
  141. protected:
  142. SkString onShortName() override {
  143. return SkString("bezier_conic_effects");
  144. }
  145. SkISize onISize() override {
  146. return SkISize::Make(800, 800);
  147. }
  148. void onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
  149. SkCanvas* canvas) override {
  150. struct Vertex {
  151. SkPoint fPosition;
  152. float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
  153. };
  154. constexpr int kNumConics = 10;
  155. SkRandom rand;
  156. // Mult by 3 for each edge effect type
  157. int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
  158. int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
  159. SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
  160. SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
  161. int row = 0;
  162. int col = 0;
  163. SkPMColor4f color = SkPMColor4f::FromBytes_RGBA(0xff000000);
  164. for (int i = 0; i < kNumConics; ++i) {
  165. SkPoint baseControlPts[] = {
  166. {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
  167. {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
  168. {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
  169. };
  170. SkScalar weight = rand.nextRangeF(0.f, 2.f);
  171. for(int edgeType = 0; edgeType < kGrClipEdgeTypeCnt; ++edgeType) {
  172. sk_sp<GrGeometryProcessor> gp;
  173. GrClipEdgeType et = (GrClipEdgeType)edgeType;
  174. gp = GrConicEffect::Make(color, SkMatrix::I(), et, *context->priv().caps(),
  175. SkMatrix::I(), false);
  176. if (!gp) {
  177. continue;
  178. }
  179. SkScalar x = col * w;
  180. SkScalar y = row * h;
  181. SkPoint controlPts[] = {
  182. {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
  183. {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
  184. {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
  185. };
  186. SkConic dst[4];
  187. SkMatrix klm;
  188. int cnt = chop_conic(controlPts, dst, weight);
  189. GrPathUtils::getConicKLM(controlPts, weight, &klm);
  190. SkPaint ctrlPtPaint;
  191. ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
  192. for (int i = 0; i < 3; ++i) {
  193. canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
  194. }
  195. SkPaint polyPaint;
  196. polyPaint.setColor(0xffA0A0A0);
  197. polyPaint.setStrokeWidth(0);
  198. polyPaint.setStyle(SkPaint::kStroke_Style);
  199. canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
  200. SkPaint choppedPtPaint;
  201. choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
  202. for (int c = 0; c < cnt; ++c) {
  203. SkPoint* pts = dst[c].fPts;
  204. for (int i = 0; i < 3; ++i) {
  205. canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
  206. }
  207. SkRect bounds;
  208. //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
  209. //bounds.set(bPts, 2);
  210. bounds.set(pts, 3);
  211. SkPaint boundsPaint;
  212. boundsPaint.setColor(0xff808080);
  213. boundsPaint.setStrokeWidth(0);
  214. boundsPaint.setStyle(SkPaint::kStroke_Style);
  215. canvas->drawRect(bounds, boundsPaint);
  216. std::unique_ptr<GrDrawOp> op = BezierConicTestOp::Make(context, gp, bounds,
  217. color, klm);
  218. renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
  219. }
  220. ++col;
  221. if (numCols == col) {
  222. col = 0;
  223. ++row;
  224. }
  225. }
  226. }
  227. }
  228. private:
  229. // Uses the max curvature function for quads to estimate
  230. // where to chop the conic. If the max curvature is not
  231. // found along the curve segment it will return 1 and
  232. // dst[0] is the original conic. If it returns 2 the dst[0]
  233. // and dst[1] are the two new conics.
  234. int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
  235. SkScalar t = SkFindQuadMaxCurvature(src);
  236. if (t == 0 || t == 1) {
  237. if (dst) {
  238. dst[0].set(src, weight);
  239. }
  240. return 1;
  241. } else {
  242. if (dst) {
  243. SkConic conic;
  244. conic.set(src, weight);
  245. if (!conic.chopAt(t, dst)) {
  246. dst[0].set(src, weight);
  247. return 1;
  248. }
  249. }
  250. return 2;
  251. }
  252. }
  253. // Calls split_conic on the entire conic and then once more on each subsection.
  254. // Most cases will result in either 1 conic (chop point is not within t range)
  255. // or 3 points (split once and then one subsection is split again).
  256. int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
  257. SkConic dstTemp[2];
  258. int conicCnt = split_conic(src, dstTemp, weight);
  259. if (2 == conicCnt) {
  260. int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
  261. conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
  262. } else {
  263. dst[0] = dstTemp[0];
  264. }
  265. return conicCnt;
  266. }
  267. typedef GM INHERITED;
  268. };
  269. //////////////////////////////////////////////////////////////////////////////
  270. class BezierQuadTestOp : public BezierTestOp {
  271. public:
  272. DEFINE_OP_CLASS_ID
  273. const char* name() const override { return "BezierQuadTestOp"; }
  274. static std::unique_ptr<GrDrawOp> Make(GrContext* context,
  275. sk_sp<const GrGeometryProcessor> gp,
  276. const SkRect& rect,
  277. const SkPMColor4f& color,
  278. const GrPathUtils::QuadUVMatrix& devToUV) {
  279. GrOpMemoryPool* pool = context->priv().opMemoryPool();
  280. return pool->allocate<BezierQuadTestOp>(std::move(gp), rect, color, devToUV);
  281. }
  282. private:
  283. friend class ::GrOpMemoryPool; // for ctor
  284. BezierQuadTestOp(sk_sp<const GrGeometryProcessor> gp, const SkRect& rect,
  285. const SkPMColor4f& color, const GrPathUtils::QuadUVMatrix& devToUV)
  286. : INHERITED(std::move(gp), rect, color, ClassID()), fDevToUV(devToUV) {}
  287. struct Vertex {
  288. SkPoint fPosition;
  289. float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
  290. };
  291. void onPrepareDraws(Target* target) override {
  292. SkASSERT(this->gp()->vertexStride() == sizeof(Vertex));
  293. QuadHelper helper(target, sizeof(Vertex), 1);
  294. Vertex* verts = reinterpret_cast<Vertex*>(helper.vertices());
  295. if (!verts) {
  296. return;
  297. }
  298. SkRect rect = this->rect();
  299. SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect, sizeof(Vertex));
  300. fDevToUV.apply(verts, 4, sizeof(Vertex), sizeof(SkPoint));
  301. helper.recordDraw(target, this->gp());
  302. }
  303. GrPathUtils::QuadUVMatrix fDevToUV;
  304. static constexpr int kVertsPerCubic = 4;
  305. static constexpr int kIndicesPerCubic = 6;
  306. typedef BezierTestOp INHERITED;
  307. };
  308. /**
  309. * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
  310. */
  311. class BezierQuadEffects : public GpuGM {
  312. public:
  313. BezierQuadEffects() {
  314. this->setBGColor(0xFFFFFFFF);
  315. }
  316. protected:
  317. SkString onShortName() override {
  318. return SkString("bezier_quad_effects");
  319. }
  320. SkISize onISize() override {
  321. return SkISize::Make(800, 800);
  322. }
  323. void onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
  324. SkCanvas* canvas) override {
  325. struct Vertex {
  326. SkPoint fPosition;
  327. float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
  328. };
  329. constexpr int kNumQuads = 5;
  330. SkRandom rand;
  331. int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
  332. int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
  333. SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
  334. SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
  335. int row = 0;
  336. int col = 0;
  337. SkPMColor4f color = SkPMColor4f::FromBytes_RGBA(0xff000000);
  338. for (int i = 0; i < kNumQuads; ++i) {
  339. SkPoint baseControlPts[] = {
  340. {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
  341. {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
  342. {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
  343. };
  344. for(int edgeType = 0; edgeType < kGrClipEdgeTypeCnt; ++edgeType) {
  345. sk_sp<GrGeometryProcessor> gp;
  346. GrClipEdgeType et = (GrClipEdgeType)edgeType;
  347. gp = GrQuadEffect::Make(color, SkMatrix::I(), et, *context->priv().caps(),
  348. SkMatrix::I(), false);
  349. if (!gp) {
  350. continue;
  351. }
  352. SkScalar x = col * w;
  353. SkScalar y = row * h;
  354. SkPoint controlPts[] = {
  355. {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
  356. {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
  357. {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
  358. };
  359. SkPoint chopped[5];
  360. int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
  361. SkPaint ctrlPtPaint;
  362. ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
  363. for (int i = 0; i < 3; ++i) {
  364. canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
  365. }
  366. SkPaint polyPaint;
  367. polyPaint.setColor(0xffA0A0A0);
  368. polyPaint.setStrokeWidth(0);
  369. polyPaint.setStyle(SkPaint::kStroke_Style);
  370. canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
  371. SkPaint choppedPtPaint;
  372. choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
  373. for (int c = 0; c < cnt; ++c) {
  374. SkPoint* pts = chopped + 2 * c;
  375. for (int i = 0; i < 3; ++i) {
  376. canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
  377. }
  378. SkRect bounds;
  379. bounds.set(pts, 3);
  380. SkPaint boundsPaint;
  381. boundsPaint.setColor(0xff808080);
  382. boundsPaint.setStrokeWidth(0);
  383. boundsPaint.setStyle(SkPaint::kStroke_Style);
  384. canvas->drawRect(bounds, boundsPaint);
  385. GrPaint grPaint;
  386. grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
  387. GrPathUtils::QuadUVMatrix DevToUV(pts);
  388. std::unique_ptr<GrDrawOp> op = BezierQuadTestOp::Make(context, gp,
  389. bounds, color, DevToUV);
  390. renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
  391. }
  392. ++col;
  393. if (numCols == col) {
  394. col = 0;
  395. ++row;
  396. }
  397. }
  398. }
  399. }
  400. private:
  401. typedef GM INHERITED;
  402. };
  403. DEF_GM(return new BezierConicEffects;)
  404. DEF_GM(return new BezierQuadEffects;)
  405. }