1 2 /* 3 * Copyright 2014 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 // This test only works with the GPU backend. 10 11 #include "gm.h" 12 13 #if SK_SUPPORT_GPU 14 15 #include "GrBatchTarget.h" 16 #include "GrContext.h" 17 #include "GrDefaultGeoProcFactory.h" 18 #include "GrPathUtils.h" 19 #include "GrTest.h" 20 #include "GrTestBatch.h" 21 #include "SkColorPriv.h" 22 #include "SkDevice.h" 23 #include "SkGeometry.h" 24 #include "SkTLList.h" 25 26 #include "effects/GrConvexPolyEffect.h" 27 28 namespace skiagm { 29 30 class ConvexPolyTestBatch : public GrTestBatch { 31 public: 32 struct Geometry : public GrTestBatch::Geometry { 33 SkRect fBounds; 34 }; 35 36 const char* name() const override { return "ConvexPolyTestBatch"; } 37 38 static GrBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo) { 39 return SkNEW_ARGS(ConvexPolyTestBatch, (gp, geo)); 40 } 41 42 private: 43 ConvexPolyTestBatch(const GrGeometryProcessor* gp, const Geometry& geo) 44 : INHERITED(gp, geo.fBounds) 45 , fGeometry(geo) { 46 } 47 48 Geometry* geoData(int index) override { 49 SkASSERT(0 == index); 50 return &fGeometry; 51 } 52 53 const Geometry* geoData(int index) const override { 54 SkASSERT(0 == index); 55 return &fGeometry; 56 } 57 58 void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override { 59 size_t vertexStride = this->geometryProcessor()->getVertexStride(); 60 SkASSERT(vertexStride == sizeof(SkPoint)); 61 QuadHelper helper; 62 SkPoint* verts = reinterpret_cast<SkPoint*>(helper.init(batchTarget, vertexStride, 1)); 63 if (!verts) { 64 return; 65 } 66 67 // Make sure any artifacts around the exterior of path are visible by using overly 68 // conservative bounding geometry. 69 fGeometry.fBounds.outset(5.f, 5.f); 70 fGeometry.fBounds.toQuad(verts); 71 72 helper.issueDraw(batchTarget); 73 } 74 75 Geometry fGeometry; 76 77 typedef GrTestBatch INHERITED; 78 }; 79 80 /** 81 * This GM directly exercises a GrProcessor that draws convex polygons. 82 */ 83 class ConvexPolyEffect : public GM { 84 public: 85 ConvexPolyEffect() { 86 this->setBGColor(0xFFFFFFFF); 87 } 88 89 protected: 90 SkString onShortName() override { 91 return SkString("convex_poly_effect"); 92 } 93 94 SkISize onISize() override { 95 return SkISize::Make(720, 800); 96 } 97 98 void onOnceBeforeDraw() override { 99 SkPath tri; 100 tri.moveTo(5.f, 5.f); 101 tri.lineTo(100.f, 20.f); 102 tri.lineTo(15.f, 100.f); 103 104 fPaths.addToTail(tri); 105 fPaths.addToTail(SkPath())->reverseAddPath(tri); 106 107 tri.close(); 108 fPaths.addToTail(tri); 109 110 SkPath ngon; 111 static const SkScalar kRadius = 50.f; 112 const SkPoint center = { kRadius, kRadius }; 113 for (int i = 0; i < GrConvexPolyEffect::kMaxEdges; ++i) { 114 SkScalar angle = 2 * SK_ScalarPI * i / GrConvexPolyEffect::kMaxEdges; 115 SkPoint point; 116 point.fY = SkScalarSinCos(angle, &point.fX); 117 point.scale(kRadius); 118 point = center + point; 119 if (0 == i) { 120 ngon.moveTo(point); 121 } else { 122 ngon.lineTo(point); 123 } 124 } 125 126 fPaths.addToTail(ngon); 127 SkMatrix scaleM; 128 scaleM.setScale(1.1f, 0.4f); 129 ngon.transform(scaleM); 130 fPaths.addToTail(ngon); 131 132 // integer edges 133 fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f)); 134 // half-integer edges 135 fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f)); 136 // vertically/horizontally thin rects that cover pixel centers 137 fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f)); 138 fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 0.75f)); 139 // vertically/horizontally thin rects that don't cover pixel centers 140 fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f)); 141 fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f)); 142 // small in x and y 143 fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f)); 144 // inverted in x and y 145 fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f)); 146 } 147 148 void onDraw(SkCanvas* canvas) override { 149 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget(); 150 if (NULL == rt) { 151 this->drawGpuOnlyMessage(canvas); 152 return; 153 } 154 GrContext* context = rt->getContext(); 155 if (NULL == context) { 156 return; 157 } 158 159 static const GrColor color = 0xff000000; 160 SkAutoTUnref<const GrGeometryProcessor> gp( 161 GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType, color)); 162 163 SkScalar y = 0; 164 for (SkTLList<SkPath>::Iter iter(fPaths, SkTLList<SkPath>::Iter::kHead_IterStart); 165 iter.get(); 166 iter.next()) { 167 const SkPath* path = iter.get(); 168 SkScalar x = 0; 169 170 for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) { 171 GrTestTarget tt; 172 context->getTestTarget(&tt); 173 if (NULL == tt.target()) { 174 SkDEBUGFAIL("Couldn't get Gr test target."); 175 return; 176 } 177 const SkMatrix m = SkMatrix::MakeTrans(x, y); 178 SkPath p; 179 path->transform(m, &p); 180 181 GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et; 182 SkAutoTUnref<GrFragmentProcessor> fp(GrConvexPolyEffect::Create(edgeType, p)); 183 if (!fp) { 184 continue; 185 } 186 187 GrPipelineBuilder pipelineBuilder; 188 pipelineBuilder.addCoverageProcessor(fp); 189 pipelineBuilder.setRenderTarget(rt); 190 191 ConvexPolyTestBatch::Geometry geometry; 192 geometry.fColor = color; 193 geometry.fBounds = p.getBounds(); 194 195 SkAutoTUnref<GrBatch> batch(ConvexPolyTestBatch::Create(gp, geometry)); 196 197 tt.target()->drawBatch(&pipelineBuilder, batch); 198 199 x += SkScalarCeilToScalar(path->getBounds().width() + 10.f); 200 } 201 202 // Draw AA and non AA paths using normal API for reference. 203 canvas->save(); 204 canvas->translate(x, y); 205 SkPaint paint; 206 canvas->drawPath(*path, paint); 207 canvas->translate(path->getBounds().width() + 10.f, 0); 208 paint.setAntiAlias(true); 209 canvas->drawPath(*path, paint); 210 canvas->restore(); 211 212 y += SkScalarCeilToScalar(path->getBounds().height() + 20.f); 213 } 214 215 for (SkTLList<SkRect>::Iter iter(fRects, SkTLList<SkRect>::Iter::kHead_IterStart); 216 iter.get(); 217 iter.next()) { 218 219 SkScalar x = 0; 220 221 for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) { 222 GrTestTarget tt; 223 context->getTestTarget(&tt); 224 if (NULL == tt.target()) { 225 SkDEBUGFAIL("Couldn't get Gr test target."); 226 return; 227 } 228 SkRect rect = *iter.get(); 229 rect.offset(x, y); 230 GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et; 231 SkAutoTUnref<GrFragmentProcessor> fp(GrConvexPolyEffect::Create(edgeType, rect)); 232 if (!fp) { 233 continue; 234 } 235 236 GrPipelineBuilder pipelineBuilder; 237 pipelineBuilder.addCoverageProcessor(fp); 238 pipelineBuilder.setRenderTarget(rt); 239 240 ConvexPolyTestBatch::Geometry geometry; 241 geometry.fColor = color; 242 geometry.fBounds = rect; 243 244 SkAutoTUnref<GrBatch> batch(ConvexPolyTestBatch::Create(gp, geometry)); 245 246 tt.target()->drawBatch(&pipelineBuilder, batch); 247 248 x += SkScalarCeilToScalar(rect.width() + 10.f); 249 } 250 251 // Draw rect without and with AA using normal API for reference 252 canvas->save(); 253 canvas->translate(x, y); 254 SkPaint paint; 255 canvas->drawRect(*iter.get(), paint); 256 x += SkScalarCeilToScalar(iter.get()->width() + 10.f); 257 paint.setAntiAlias(true); 258 canvas->drawRect(*iter.get(), paint); 259 canvas->restore(); 260 261 y += SkScalarCeilToScalar(iter.get()->height() + 20.f); 262 } 263 } 264 265 private: 266 SkTLList<SkPath> fPaths; 267 SkTLList<SkRect> fRects; 268 269 typedef GM INHERITED; 270 }; 271 272 DEF_GM( return SkNEW(ConvexPolyEffect); ) 273 } 274 275 #endif 276