1 /* 2 * Copyright 2014 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" 11 #include "include/core/SkBlendMode.h" 12 #include "include/core/SkCanvas.h" 13 #include "include/core/SkMatrix.h" 14 #include "include/core/SkPaint.h" 15 #include "include/core/SkPath.h" 16 #include "include/core/SkPoint.h" 17 #include "include/core/SkRect.h" 18 #include "include/core/SkScalar.h" 19 #include "include/core/SkSize.h" 20 #include "include/core/SkString.h" 21 #include "include/private/GrSharedEnums.h" 22 #include "include/private/GrTypesPriv.h" 23 #include "src/core/SkTLList.h" 24 #include "src/gpu/GrFragmentProcessor.h" 25 #include "src/gpu/GrPaint.h" 26 #include "src/gpu/GrRenderTargetContext.h" 27 #include "src/gpu/GrRenderTargetContextPriv.h" 28 #include "src/gpu/effects/GrConvexPolyEffect.h" 29 #include "tools/gpu/TestOps.h" 30 31 #include <memory> 32 #include <utility> 33 34 class GrAppliedClip; 35 36 namespace skiagm { 37 38 /** 39 * This GM directly exercises a GrProcessor that draws convex polygons. 40 */ 41 class ConvexPolyEffect : public GpuGM { 42 public: ConvexPolyEffect()43 ConvexPolyEffect() { 44 this->setBGColor(0xFFFFFFFF); 45 } 46 47 protected: onShortName()48 SkString onShortName() override { 49 return SkString("convex_poly_effect"); 50 } 51 onISize()52 SkISize onISize() override { 53 return SkISize::Make(720, 800); 54 } 55 onOnceBeforeDraw()56 void onOnceBeforeDraw() override { 57 SkPath tri; 58 tri.moveTo(5.f, 5.f); 59 tri.lineTo(100.f, 20.f); 60 tri.lineTo(15.f, 100.f); 61 62 fPaths.addToTail(tri); 63 fPaths.addToTail(SkPath())->reverseAddPath(tri); 64 65 tri.close(); 66 fPaths.addToTail(tri); 67 68 SkPath ngon; 69 constexpr SkScalar kRadius = 50.f; 70 const SkPoint center = { kRadius, kRadius }; 71 for (int i = 0; i < GrConvexPolyEffect::kMaxEdges; ++i) { 72 SkScalar angle = 2 * SK_ScalarPI * i / GrConvexPolyEffect::kMaxEdges; 73 SkPoint point = { SkScalarCos(angle), SkScalarSin(angle) }; 74 point.scale(kRadius); 75 point = center + point; 76 if (0 == i) { 77 ngon.moveTo(point); 78 } else { 79 ngon.lineTo(point); 80 } 81 } 82 83 fPaths.addToTail(ngon); 84 SkMatrix scaleM; 85 scaleM.setScale(1.1f, 0.4f); 86 ngon.transform(scaleM); 87 fPaths.addToTail(ngon); 88 89 SkPath linePath; 90 linePath.moveTo(5.f, 5.f); 91 linePath.lineTo(6.f, 6.f); 92 fPaths.addToTail(linePath); 93 94 // integer edges 95 fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f)); 96 // half-integer edges 97 fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f)); 98 // vertically/horizontally thin rects that cover pixel centers 99 fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f)); 100 fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 0.75f)); 101 // vertically/horizontally thin rects that don't cover pixel centers 102 fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f)); 103 fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f)); 104 // small in x and y 105 fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f)); 106 // inverted in x and y 107 fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f)); 108 } 109 onDraw(GrRecordingContext * context,GrRenderTargetContext * renderTargetContext,SkCanvas * canvas)110 void onDraw(GrRecordingContext* context, GrRenderTargetContext* renderTargetContext, 111 SkCanvas* canvas) override { 112 SkScalar y = 0; 113 static constexpr SkScalar kDX = 12.f; 114 static constexpr SkScalar kOutset = 5.f; 115 116 for (PathList::Iter iter(fPaths, PathList::Iter::kHead_IterStart); 117 iter.get(); 118 iter.next()) { 119 const SkPath* path = iter.get(); 120 SkScalar x = 0; 121 122 for (int et = 0; et < kGrClipEdgeTypeCnt; ++et) { 123 const SkMatrix m = SkMatrix::Translate(x, y); 124 SkPath p; 125 path->transform(m, &p); 126 127 GrClipEdgeType edgeType = (GrClipEdgeType) et; 128 auto [success, fp] = GrConvexPolyEffect::Make(/*inputFP=*/nullptr, edgeType, p); 129 if (!success) { 130 continue; 131 } 132 133 GrPaint grPaint; 134 grPaint.setColor4f({ 0, 0, 0, 1.f }); 135 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); 136 grPaint.setCoverageFragmentProcessor(std::move(fp)); 137 138 auto rect = p.getBounds().makeOutset(kOutset, kOutset); 139 auto op = sk_gpu_test::test_ops::MakeRect(context, std::move(grPaint), rect); 140 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op)); 141 142 x += SkScalarCeilToScalar(path->getBounds().width() + kDX); 143 } 144 145 // Draw AA and non AA paths using normal API for reference. 146 canvas->save(); 147 canvas->translate(x, y); 148 SkPaint paint; 149 canvas->drawPath(*path, paint); 150 canvas->translate(path->getBounds().width() + 10.f, 0); 151 paint.setAntiAlias(true); 152 canvas->drawPath(*path, paint); 153 canvas->restore(); 154 155 y += SkScalarCeilToScalar(path->getBounds().height() + 20.f); 156 } 157 158 for (RectList::Iter iter(fRects, RectList::Iter::kHead_IterStart); 159 iter.get(); 160 iter.next()) { 161 162 SkScalar x = 0; 163 164 for (int et = 0; et < kGrClipEdgeTypeCnt; ++et) { 165 SkRect rect = iter.get()->makeOffset(x, y); 166 GrClipEdgeType edgeType = (GrClipEdgeType) et; 167 auto [success, fp] = GrConvexPolyEffect::Make(/*inputFP=*/nullptr, edgeType, rect); 168 if (!success) { 169 continue; 170 } 171 172 GrPaint grPaint; 173 grPaint.setColor4f({ 0, 0, 0, 1.f }); 174 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); 175 grPaint.setCoverageFragmentProcessor(std::move(fp)); 176 177 auto drawRect = rect.makeOutset(kOutset, kOutset); 178 auto op = sk_gpu_test::test_ops::MakeRect(context, std::move(grPaint), drawRect); 179 180 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op)); 181 182 x += SkScalarCeilToScalar(rect.width() + kDX); 183 } 184 185 // Draw rect without and with AA using normal API for reference 186 canvas->save(); 187 canvas->translate(x, y); 188 SkPaint paint; 189 canvas->drawRect(*iter.get(), paint); 190 x += SkScalarCeilToScalar(iter.get()->width() + kDX); 191 paint.setAntiAlias(true); 192 canvas->drawRect(*iter.get(), paint); 193 canvas->restore(); 194 195 y += SkScalarCeilToScalar(iter.get()->height() + 20.f); 196 } 197 } 198 199 private: 200 typedef SkTLList<SkPath, 1> PathList; 201 typedef SkTLList<SkRect, 1> RectList; 202 PathList fPaths; 203 RectList fRects; 204 205 using INHERITED = GM; 206 }; 207 208 DEF_GM(return new ConvexPolyEffect;) 209 } // namespace skiagm 210