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 "GrPathUtils.h" 17 #include "GrTest.h" 18 #include "SkColorPriv.h" 19 #include "SkDevice.h" 20 #include "SkGeometry.h" 21 #include "SkTLList.h" 22 23 #include "effects/GrConvexPolyEffect.h" 24 25 namespace skiagm { 26 /** 27 * This GM directly exercises a GrProcessor that draws convex polygons. 28 */ 29 class ConvexPolyEffect : public GM { 30 public: ConvexPolyEffect()31 ConvexPolyEffect() { 32 this->setBGColor(0xFFFFFFFF); 33 } 34 35 protected: onShortName()36 virtual SkString onShortName() SK_OVERRIDE { 37 return SkString("convex_poly_effect"); 38 } 39 onISize()40 virtual SkISize onISize() SK_OVERRIDE { 41 return SkISize::Make(720, 800); 42 } 43 onGetFlags() const44 virtual uint32_t onGetFlags() const SK_OVERRIDE { 45 // This is a GPU-specific GM. 46 return kGPUOnly_Flag; 47 } 48 onOnceBeforeDraw()49 virtual void onOnceBeforeDraw() SK_OVERRIDE { 50 SkPath tri; 51 tri.moveTo(5.f, 5.f); 52 tri.lineTo(100.f, 20.f); 53 tri.lineTo(15.f, 100.f); 54 55 fPaths.addToTail(tri); 56 fPaths.addToTail(SkPath())->reverseAddPath(tri); 57 58 tri.close(); 59 fPaths.addToTail(tri); 60 61 SkPath ngon; 62 static const SkScalar kRadius = 50.f; 63 const SkPoint center = { kRadius, kRadius }; 64 for (int i = 0; i < GrConvexPolyEffect::kMaxEdges; ++i) { 65 SkScalar angle = 2 * SK_ScalarPI * i / GrConvexPolyEffect::kMaxEdges; 66 SkPoint point; 67 point.fY = SkScalarSinCos(angle, &point.fX); 68 point.scale(kRadius); 69 point = center + point; 70 if (0 == i) { 71 ngon.moveTo(point); 72 } else { 73 ngon.lineTo(point); 74 } 75 } 76 77 fPaths.addToTail(ngon); 78 SkMatrix scaleM; 79 scaleM.setScale(1.1f, 0.4f); 80 ngon.transform(scaleM); 81 fPaths.addToTail(ngon); 82 83 // integer edges 84 fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f)); 85 // half-integer edges 86 fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f)); 87 // vertically/horizontally thin rects that cover pixel centers 88 fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f)); 89 fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 0.75f)); 90 // vertically/horizontally thin rects that don't cover pixel centers 91 fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f)); 92 fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f)); 93 // small in x and y 94 fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f)); 95 // inverted in x and y 96 fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f)); 97 } 98 onDraw(SkCanvas * canvas)99 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { 100 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget(); 101 if (NULL == rt) { 102 return; 103 } 104 GrContext* context = rt->getContext(); 105 if (NULL == context) { 106 return; 107 } 108 109 SkScalar y = 0; 110 for (SkTLList<SkPath>::Iter iter(fPaths, SkTLList<SkPath>::Iter::kHead_IterStart); 111 iter.get(); 112 iter.next()) { 113 const SkPath* path = iter.get(); 114 SkScalar x = 0; 115 116 for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) { 117 GrTestTarget tt; 118 context->getTestTarget(&tt); 119 if (NULL == tt.target()) { 120 SkDEBUGFAIL("Couldn't get Gr test target."); 121 return; 122 } 123 GrDrawState* drawState = tt.target()->drawState(); 124 125 SkMatrix m; 126 SkPath p; 127 m.setTranslate(x, y); 128 path->transform(m, &p); 129 130 GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et; 131 SkAutoTUnref<GrFragmentProcessor> fp(GrConvexPolyEffect::Create(edgeType, p)); 132 if (!fp) { 133 continue; 134 } 135 drawState->addCoverageProcessor(fp); 136 drawState->setIdentityViewMatrix(); 137 drawState->setRenderTarget(rt); 138 drawState->setColor(0xff000000); 139 140 SkPoint verts[4]; 141 SkRect bounds = p.getBounds(); 142 // Make sure any artifacts around the exterior of path are visible by using overly 143 // conservative bounding geometry. 144 bounds.outset(5.f, 5.f); 145 bounds.toQuad(verts); 146 147 tt.target()->setVertexSourceToArray(verts, 4); 148 tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer()); 149 tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6); 150 151 x += SkScalarCeilToScalar(path->getBounds().width() + 10.f); 152 } 153 154 // Draw AA and non AA paths using normal API for reference. 155 canvas->save(); 156 canvas->translate(x, y); 157 SkPaint paint; 158 canvas->drawPath(*path, paint); 159 canvas->translate(path->getBounds().width() + 10.f, 0); 160 paint.setAntiAlias(true); 161 canvas->drawPath(*path, paint); 162 canvas->restore(); 163 164 y += SkScalarCeilToScalar(path->getBounds().height() + 20.f); 165 } 166 167 for (SkTLList<SkRect>::Iter iter(fRects, SkTLList<SkRect>::Iter::kHead_IterStart); 168 iter.get(); 169 iter.next()) { 170 171 SkScalar x = 0; 172 173 for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) { 174 GrTestTarget tt; 175 context->getTestTarget(&tt); 176 if (NULL == tt.target()) { 177 SkDEBUGFAIL("Couldn't get Gr test target."); 178 return; 179 } 180 SkRect rect = *iter.get(); 181 rect.offset(x, y); 182 GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et; 183 SkAutoTUnref<GrFragmentProcessor> fp(GrConvexPolyEffect::Create(edgeType, rect)); 184 if (!fp) { 185 continue; 186 } 187 188 GrDrawState* drawState = tt.target()->drawState(); 189 drawState->addCoverageProcessor(fp); 190 drawState->setIdentityViewMatrix(); 191 drawState->setRenderTarget(rt); 192 drawState->setColor(0xff000000); 193 194 SkPoint verts[4]; 195 SkRect bounds = rect; 196 bounds.outset(5.f, 5.f); 197 bounds.toQuad(verts); 198 199 tt.target()->setVertexSourceToArray(verts, 4); 200 tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer()); 201 tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6); 202 203 x += SkScalarCeilToScalar(rect.width() + 10.f); 204 } 205 206 // Draw rect without and with AA using normal API for reference 207 canvas->save(); 208 canvas->translate(x, y); 209 SkPaint paint; 210 canvas->drawRect(*iter.get(), paint); 211 x += SkScalarCeilToScalar(iter.get()->width() + 10.f); 212 paint.setAntiAlias(true); 213 canvas->drawRect(*iter.get(), paint); 214 canvas->restore(); 215 216 y += SkScalarCeilToScalar(iter.get()->height() + 20.f); 217 } 218 } 219 220 private: 221 SkTLList<SkPath> fPaths; 222 SkTLList<SkRect> fRects; 223 224 typedef GM INHERITED; 225 }; 226 227 DEF_GM( return SkNEW(ConvexPolyEffect); ) 228 } 229 230 #endif 231