Home | History | Annotate | Download | only in gm
      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.h"
     11 
     12 #if SK_SUPPORT_GPU
     13 
     14 #include "GrContext.h"
     15 #include "GrDefaultGeoProcFactory.h"
     16 #include "GrOpFlushState.h"
     17 #include "GrPathUtils.h"
     18 #include "GrRenderTargetContextPriv.h"
     19 #include "GrTest.h"
     20 #include "SkColorPriv.h"
     21 #include "SkGeometry.h"
     22 #include "SkTLList.h"
     23 #include "effects/GrConvexPolyEffect.h"
     24 #include "ops/GrMeshDrawOp.h"
     25 
     26 /** outset rendered rect to visualize anti-aliased poly edges */
     27 static SkRect outset(const SkRect& unsorted) {
     28     SkRect r = unsorted;
     29     r.outset(5.f, 5.f);
     30     return r;
     31 }
     32 
     33 /** sorts a rect */
     34 static SkRect sorted_rect(const SkRect& unsorted) {
     35     SkRect r = unsorted;
     36     r.sort();
     37     return r;
     38 }
     39 
     40 namespace skiagm {
     41 class PolyBoundsOp : public GrMeshDrawOp {
     42 public:
     43     DEFINE_OP_CLASS_ID
     44 
     45     const char* name() const override { return "PolyBoundsOp"; }
     46 
     47     static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& rect) {
     48         return std::unique_ptr<GrDrawOp>(new PolyBoundsOp(std::move(paint), rect));
     49     }
     50 
     51     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
     52 
     53     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
     54         auto analysis = fProcessors.finalize(
     55                 fColor, GrProcessorAnalysisCoverage::kNone, clip, false, caps, &fColor);
     56         return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
     57     }
     58 
     59 private:
     60     PolyBoundsOp(GrPaint&& paint, const SkRect& rect)
     61             : INHERITED(ClassID())
     62             , fColor(paint.getColor())
     63             , fProcessors(std::move(paint))
     64             , fRect(outset(rect)) {
     65         this->setBounds(sorted_rect(fRect), HasAABloat::kNo, IsZeroArea::kNo);
     66     }
     67 
     68     void onPrepareDraws(Target* target) const override {
     69         using namespace GrDefaultGeoProcFactory;
     70 
     71         Color color(fColor);
     72         sk_sp<GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Make(
     73                 color, Coverage::kSolid_Type, LocalCoords::kUnused_Type, SkMatrix::I()));
     74 
     75         size_t vertexStride = gp->getVertexStride();
     76         SkASSERT(vertexStride == sizeof(SkPoint));
     77         QuadHelper helper;
     78         SkPoint* verts = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1));
     79         if (!verts) {
     80             return;
     81         }
     82 
     83         fRect.toQuad(verts);
     84 
     85         helper.recordDraw(target, gp.get(), target->makePipeline(0, &fProcessors));
     86     }
     87 
     88     bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
     89 
     90     GrColor fColor;
     91     GrProcessorSet fProcessors;
     92     SkRect fRect;
     93 
     94     typedef GrMeshDrawOp INHERITED;
     95 };
     96 
     97 /**
     98  * This GM directly exercises a GrProcessor that draws convex polygons.
     99  */
    100 class ConvexPolyEffect : public GM {
    101 public:
    102     ConvexPolyEffect() {
    103         this->setBGColor(0xFFFFFFFF);
    104     }
    105 
    106 protected:
    107     SkString onShortName() override {
    108         return SkString("convex_poly_effect");
    109     }
    110 
    111     SkISize onISize() override {
    112         return SkISize::Make(720, 800);
    113     }
    114 
    115     void onOnceBeforeDraw() override {
    116         SkPath tri;
    117         tri.moveTo(5.f, 5.f);
    118         tri.lineTo(100.f, 20.f);
    119         tri.lineTo(15.f, 100.f);
    120 
    121         fPaths.addToTail(tri);
    122         fPaths.addToTail(SkPath())->reverseAddPath(tri);
    123 
    124         tri.close();
    125         fPaths.addToTail(tri);
    126 
    127         SkPath ngon;
    128         constexpr SkScalar kRadius = 50.f;
    129         const SkPoint center = { kRadius, kRadius };
    130         for (int i = 0; i < GrConvexPolyEffect::kMaxEdges; ++i) {
    131             SkScalar angle = 2 * SK_ScalarPI * i / GrConvexPolyEffect::kMaxEdges;
    132             SkPoint point;
    133             point.fY = SkScalarSinCos(angle, &point.fX);
    134             point.scale(kRadius);
    135             point = center + point;
    136             if (0 == i) {
    137                 ngon.moveTo(point);
    138             } else {
    139                 ngon.lineTo(point);
    140             }
    141         }
    142 
    143         fPaths.addToTail(ngon);
    144         SkMatrix scaleM;
    145         scaleM.setScale(1.1f, 0.4f);
    146         ngon.transform(scaleM);
    147         fPaths.addToTail(ngon);
    148 
    149         SkPath linePath;
    150         linePath.moveTo(5.f, 5.f);
    151         linePath.lineTo(6.f, 6.f);
    152         fPaths.addToTail(linePath);
    153 
    154         // integer edges
    155         fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f));
    156         // half-integer edges
    157         fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f));
    158         // vertically/horizontally thin rects that cover pixel centers
    159         fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f));
    160         fRects.addToTail(SkRect::MakeLTRB(5.5f,  0.5f, 29.5f, 0.75f));
    161         // vertically/horizontally thin rects that don't cover pixel centers
    162         fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f));
    163         fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f));
    164         // small in x and y
    165         fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f));
    166         // inverted in x and y
    167         fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f));
    168     }
    169 
    170     void onDraw(SkCanvas* canvas) override {
    171         GrRenderTargetContext* renderTargetContext =
    172             canvas->internal_private_accessTopLayerRenderTargetContext();
    173         if (!renderTargetContext) {
    174             skiagm::GM::DrawGpuOnlyMessage(canvas);
    175             return;
    176         }
    177 
    178         SkScalar y = 0;
    179         constexpr SkScalar kDX = 12.f;
    180         for (PathList::Iter iter(fPaths, PathList::Iter::kHead_IterStart);
    181              iter.get();
    182              iter.next()) {
    183             const SkPath* path = iter.get();
    184             SkScalar x = 0;
    185 
    186             for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) {
    187                 const SkMatrix m = SkMatrix::MakeTrans(x, y);
    188                 SkPath p;
    189                 path->transform(m, &p);
    190 
    191                 GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et;
    192                 sk_sp<GrFragmentProcessor> fp(GrConvexPolyEffect::Make(edgeType, p));
    193                 if (!fp) {
    194                     continue;
    195                 }
    196 
    197                 GrPaint grPaint;
    198                 grPaint.setColor4f(GrColor4f(0, 0, 0, 1.f));
    199                 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
    200                 grPaint.addCoverageFragmentProcessor(std::move(fp));
    201 
    202                 std::unique_ptr<GrDrawOp> op =
    203                         PolyBoundsOp::Make(std::move(grPaint), p.getBounds());
    204                 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
    205 
    206                 x += SkScalarCeilToScalar(path->getBounds().width() + kDX);
    207             }
    208 
    209             // Draw AA and non AA paths using normal API for reference.
    210             canvas->save();
    211             canvas->translate(x, y);
    212             SkPaint paint;
    213             canvas->drawPath(*path, paint);
    214             canvas->translate(path->getBounds().width() + 10.f, 0);
    215             paint.setAntiAlias(true);
    216             canvas->drawPath(*path, paint);
    217             canvas->restore();
    218 
    219             y += SkScalarCeilToScalar(path->getBounds().height() + 20.f);
    220         }
    221 
    222         for (RectList::Iter iter(fRects, RectList::Iter::kHead_IterStart);
    223              iter.get();
    224              iter.next()) {
    225 
    226             SkScalar x = 0;
    227 
    228             for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) {
    229                 SkRect rect = *iter.get();
    230                 rect.offset(x, y);
    231                 GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et;
    232                 sk_sp<GrFragmentProcessor> fp(GrConvexPolyEffect::Make(edgeType, rect));
    233                 if (!fp) {
    234                     continue;
    235                 }
    236 
    237                 GrPaint grPaint;
    238                 grPaint.setColor4f(GrColor4f(0, 0, 0, 1.f));
    239                 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
    240                 grPaint.addCoverageFragmentProcessor(std::move(fp));
    241 
    242                 std::unique_ptr<GrDrawOp> op = PolyBoundsOp::Make(std::move(grPaint), rect);
    243                 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
    244 
    245                 x += SkScalarCeilToScalar(rect.width() + kDX);
    246             }
    247 
    248             // Draw rect without and with AA using normal API for reference
    249             canvas->save();
    250             canvas->translate(x, y);
    251             SkPaint paint;
    252             canvas->drawRect(*iter.get(), paint);
    253             x += SkScalarCeilToScalar(iter.get()->width() + kDX);
    254             paint.setAntiAlias(true);
    255             canvas->drawRect(*iter.get(), paint);
    256             canvas->restore();
    257 
    258             y += SkScalarCeilToScalar(iter.get()->height() + 20.f);
    259         }
    260     }
    261 
    262 private:
    263     typedef SkTLList<SkPath, 1> PathList;
    264     typedef SkTLList<SkRect, 1> RectList;
    265     PathList fPaths;
    266     RectList fRects;
    267 
    268     typedef GM INHERITED;
    269 };
    270 
    271 DEF_GM(return new ConvexPolyEffect;)
    272 }
    273 
    274 #endif
    275