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