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