Home | History | Annotate | Download | only in ops
      1 /*
      2  * Copyright 2017 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 #include "GrAppliedClip.h"
      9 #include "GrColor.h"
     10 #include "GrDefaultGeoProcFactory.h"
     11 #include "GrDrawOpTest.h"
     12 #include "GrMeshDrawOp.h"
     13 #include "GrOpFlushState.h"
     14 #include "GrPrimitiveProcessor.h"
     15 #include "GrQuad.h"
     16 #include "GrRectOpFactory.h"
     17 #include "GrResourceProvider.h"
     18 #include "GrSimpleMeshDrawOpHelper.h"
     19 #include "SkMatrixPriv.h"
     20 
     21 static const int kVertsPerRect = 4;
     22 static const int kIndicesPerRect = 6;
     23 
     24 /** We always use per-vertex colors so that rects can be combined across color changes. Sometimes
     25     we  have explicit local coords and sometimes not. We *could* always provide explicit local
     26     coords and just duplicate the positions when the caller hasn't provided a local coord rect,
     27     but we haven't seen a use case which frequently switches between local rect and no local
     28     rect draws.
     29 
     30     The vertex attrib order is always pos, color, [local coords].
     31  */
     32 static sk_sp<GrGeometryProcessor> make_gp() {
     33     using namespace GrDefaultGeoProcFactory;
     34     return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type,
     35                                          LocalCoords::kHasExplicit_Type, SkMatrix::I());
     36 }
     37 
     38 static sk_sp<GrGeometryProcessor> make_perspective_gp(const SkMatrix& viewMatrix,
     39                                                       bool hasExplicitLocalCoords,
     40                                                       const SkMatrix* localMatrix) {
     41     SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
     42 
     43     using namespace GrDefaultGeoProcFactory;
     44 
     45     // If we have perspective on the viewMatrix then we won't map on the CPU, nor will we map
     46     // the local rect on the cpu (in case the localMatrix also has perspective).
     47     // Otherwise, if we have a local rect, then we apply the localMatrix directly to the localRect
     48     // to generate vertex local coords
     49     if (viewMatrix.hasPerspective()) {
     50         LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type
     51                                                        : LocalCoords::kUsePosition_Type,
     52                                 localMatrix);
     53         return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
     54                                              Coverage::kSolid_Type, localCoords, viewMatrix);
     55     } else if (hasExplicitLocalCoords) {
     56         LocalCoords localCoords(LocalCoords::kHasExplicit_Type, localMatrix);
     57         return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
     58                                              Coverage::kSolid_Type, localCoords, SkMatrix::I());
     59     } else {
     60         LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix);
     61         return GrDefaultGeoProcFactory::MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type,
     62                                                            Coverage::kSolid_Type, localCoords,
     63                                                            viewMatrix);
     64     }
     65 }
     66 
     67 static void tesselate(intptr_t vertices,
     68                       size_t vertexStride,
     69                       GrColor color,
     70                       const SkMatrix* viewMatrix,
     71                       const SkRect& rect,
     72                       const GrQuad* localQuad) {
     73     SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
     74 
     75     positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
     76 
     77     if (viewMatrix) {
     78         SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerRect);
     79     }
     80 
     81     // Setup local coords
     82     // TODO we should only do this if local coords are being read
     83     if (localQuad) {
     84         static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
     85         for (int i = 0; i < kVertsPerRect; i++) {
     86             SkPoint* coords =
     87                     reinterpret_cast<SkPoint*>(vertices + kLocalOffset + i * vertexStride);
     88             *coords = localQuad->point(i);
     89         }
     90     }
     91 
     92     static const int kColorOffset = sizeof(SkPoint);
     93     GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
     94     for (int j = 0; j < 4; ++j) {
     95         *vertColor = color;
     96         vertColor = (GrColor*)((intptr_t)vertColor + vertexStride);
     97     }
     98 }
     99 
    100 namespace {
    101 
    102 class NonAAFillRectOp final : public GrMeshDrawOp {
    103 private:
    104     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
    105 
    106 public:
    107     static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
    108                                           const SkRect& rect, const SkRect* localRect,
    109                                           const SkMatrix* localMatrix, GrAAType aaType,
    110                                           const GrUserStencilSettings* stencilSettings) {
    111         SkASSERT(GrAAType::kCoverage != aaType);
    112         return Helper::FactoryHelper<NonAAFillRectOp>(std::move(paint), viewMatrix, rect, localRect,
    113                                                       localMatrix, aaType, stencilSettings);
    114     }
    115 
    116     NonAAFillRectOp() = delete;
    117 
    118     NonAAFillRectOp(const Helper::MakeArgs& args, GrColor color, const SkMatrix& viewMatrix,
    119                     const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix,
    120                     GrAAType aaType, const GrUserStencilSettings* stencilSettings)
    121             : INHERITED(ClassID()), fHelper(args, aaType, stencilSettings) {
    122 
    123         SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective()));
    124         RectInfo& info = fRects.push_back();
    125         info.fColor = color;
    126         info.fViewMatrix = viewMatrix;
    127         info.fRect = rect;
    128         if (localRect && localMatrix) {
    129             info.fLocalQuad.setFromMappedRect(*localRect, *localMatrix);
    130         } else if (localRect) {
    131             info.fLocalQuad.set(*localRect);
    132         } else if (localMatrix) {
    133             info.fLocalQuad.setFromMappedRect(rect, *localMatrix);
    134         } else {
    135             info.fLocalQuad.set(rect);
    136         }
    137         this->setTransformedBounds(fRects[0].fRect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
    138     }
    139 
    140     const char* name() const override { return "NonAAFillRectOp"; }
    141 
    142     SkString dumpInfo() const override {
    143         SkString str;
    144         str.append(GrMeshDrawOp::dumpInfo());
    145         str.appendf("# combined: %d\n", fRects.count());
    146         for (int i = 0; i < fRects.count(); ++i) {
    147             const RectInfo& info = fRects[i];
    148             str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
    149                         info.fColor, info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight,
    150                         info.fRect.fBottom);
    151         }
    152         str += fHelper.dumpInfo();
    153         str += INHERITED::dumpInfo();
    154         return str;
    155     }
    156 
    157     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
    158         GrColor* color = &fRects.front().fColor;
    159         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
    160     }
    161 
    162     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
    163 
    164     DEFINE_OP_CLASS_ID
    165 
    166 private:
    167     void onPrepareDraws(Target* target) const override {
    168         sk_sp<GrGeometryProcessor> gp = make_gp();
    169         if (!gp) {
    170             SkDebugf("Couldn't create GrGeometryProcessor\n");
    171             return;
    172         }
    173         SkASSERT(gp->getVertexStride() ==
    174                  sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
    175 
    176         size_t vertexStride = gp->getVertexStride();
    177         int rectCount = fRects.count();
    178 
    179         sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
    180         PatternHelper helper(GrPrimitiveType::kTriangles);
    181         void* vertices = helper.init(target, vertexStride, indexBuffer.get(), kVertsPerRect,
    182                                      kIndicesPerRect, rectCount);
    183         if (!vertices || !indexBuffer) {
    184             SkDebugf("Could not allocate vertices\n");
    185             return;
    186         }
    187 
    188         for (int i = 0; i < rectCount; i++) {
    189             intptr_t verts =
    190                     reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
    191             tesselate(verts, vertexStride, fRects[i].fColor, &fRects[i].fViewMatrix,
    192                       fRects[i].fRect, &fRects[i].fLocalQuad);
    193         }
    194         helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
    195     }
    196 
    197     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
    198         NonAAFillRectOp* that = t->cast<NonAAFillRectOp>();
    199         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
    200             return false;
    201         }
    202         fRects.push_back_n(that->fRects.count(), that->fRects.begin());
    203         this->joinBounds(*that);
    204         return true;
    205     }
    206 
    207     struct RectInfo {
    208         GrColor fColor;
    209         SkMatrix fViewMatrix;
    210         SkRect fRect;
    211         GrQuad fLocalQuad;
    212     };
    213 
    214     Helper fHelper;
    215     SkSTArray<1, RectInfo, true> fRects;
    216     typedef GrMeshDrawOp INHERITED;
    217 };
    218 
    219 // We handle perspective in the local matrix or viewmatrix with special ops.
    220 class NonAAFillRectPerspectiveOp final : public GrMeshDrawOp {
    221 private:
    222     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
    223 
    224 public:
    225     static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
    226                                           const SkRect& rect, const SkRect* localRect,
    227                                           const SkMatrix* localMatrix, GrAAType aaType,
    228                                           const GrUserStencilSettings* stencilSettings) {
    229         SkASSERT(GrAAType::kCoverage != aaType);
    230         return Helper::FactoryHelper<NonAAFillRectPerspectiveOp>(std::move(paint), viewMatrix, rect,
    231                                                                  localRect, localMatrix, aaType,
    232                                                                  stencilSettings);
    233     }
    234 
    235     NonAAFillRectPerspectiveOp() = delete;
    236 
    237     NonAAFillRectPerspectiveOp(const Helper::MakeArgs& args, GrColor color,
    238                                const SkMatrix& viewMatrix, const SkRect& rect,
    239                                const SkRect* localRect, const SkMatrix* localMatrix,
    240                                GrAAType aaType, const GrUserStencilSettings* stencilSettings)
    241             : INHERITED(ClassID())
    242             , fHelper(args, aaType, stencilSettings)
    243             , fViewMatrix(viewMatrix) {
    244         SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
    245         RectInfo& info = fRects.push_back();
    246         info.fColor = color;
    247         info.fRect = rect;
    248         fHasLocalRect = SkToBool(localRect);
    249         fHasLocalMatrix = SkToBool(localMatrix);
    250         if (fHasLocalMatrix) {
    251             fLocalMatrix = *localMatrix;
    252         }
    253         if (fHasLocalRect) {
    254             info.fLocalRect = *localRect;
    255         }
    256         this->setTransformedBounds(rect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
    257     }
    258 
    259     const char* name() const override { return "NonAAFillRectPerspectiveOp"; }
    260 
    261     SkString dumpInfo() const override {
    262         SkString str;
    263         str.appendf("# combined: %d\n", fRects.count());
    264         for (int i = 0; i < fRects.count(); ++i) {
    265             const RectInfo& geo = fRects[0];
    266             str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
    267                         geo.fColor, geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight,
    268                         geo.fRect.fBottom);
    269         }
    270         str += fHelper.dumpInfo();
    271         str += INHERITED::dumpInfo();
    272         return str;
    273     }
    274 
    275     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
    276         GrColor* color = &fRects.front().fColor;
    277         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
    278     }
    279 
    280     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
    281 
    282     DEFINE_OP_CLASS_ID
    283 
    284 private:
    285     void onPrepareDraws(Target* target) const override {
    286         sk_sp<GrGeometryProcessor> gp = make_perspective_gp(
    287                 fViewMatrix, fHasLocalRect, fHasLocalMatrix ? &fLocalMatrix : nullptr);
    288         if (!gp) {
    289             SkDebugf("Couldn't create GrGeometryProcessor\n");
    290             return;
    291         }
    292         SkASSERT(fHasLocalRect
    293                          ? gp->getVertexStride() ==
    294                                    sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
    295                          : gp->getVertexStride() ==
    296                                    sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
    297 
    298         size_t vertexStride = gp->getVertexStride();
    299         int rectCount = fRects.count();
    300 
    301         sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
    302         PatternHelper helper(GrPrimitiveType::kTriangles);
    303         void* vertices = helper.init(target, vertexStride, indexBuffer.get(), kVertsPerRect,
    304                                      kIndicesPerRect, rectCount);
    305         if (!vertices || !indexBuffer) {
    306             SkDebugf("Could not allocate vertices\n");
    307             return;
    308         }
    309 
    310         for (int i = 0; i < rectCount; i++) {
    311             const RectInfo& info = fRects[i];
    312             intptr_t verts =
    313                     reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
    314             if (fHasLocalRect) {
    315                 GrQuad quad(info.fLocalRect);
    316                 tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, &quad);
    317             } else {
    318                 tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, nullptr);
    319             }
    320         }
    321         helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
    322     }
    323 
    324     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
    325         NonAAFillRectPerspectiveOp* that = t->cast<NonAAFillRectPerspectiveOp>();
    326         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
    327             return false;
    328         }
    329 
    330         // We could combine across perspective vm changes if we really wanted to.
    331         if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
    332             return false;
    333         }
    334         if (fHasLocalRect != that->fHasLocalRect) {
    335             return false;
    336         }
    337         if (fHasLocalMatrix && !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) {
    338             return false;
    339         }
    340 
    341         fRects.push_back_n(that->fRects.count(), that->fRects.begin());
    342         this->joinBounds(*that);
    343         return true;
    344     }
    345 
    346     struct RectInfo {
    347         SkRect fRect;
    348         GrColor fColor;
    349         SkRect fLocalRect;
    350     };
    351 
    352     SkSTArray<1, RectInfo, true> fRects;
    353     Helper fHelper;
    354     bool fHasLocalMatrix;
    355     bool fHasLocalRect;
    356     SkMatrix fLocalMatrix;
    357     SkMatrix fViewMatrix;
    358 
    359     typedef GrMeshDrawOp INHERITED;
    360 };
    361 
    362 }  // anonymous namespace
    363 
    364 namespace GrRectOpFactory {
    365 
    366 std::unique_ptr<GrDrawOp> MakeNonAAFill(GrPaint&& paint, const SkMatrix& viewMatrix,
    367                                         const SkRect& rect, GrAAType aaType,
    368                                         const GrUserStencilSettings* stencilSettings) {
    369     if (viewMatrix.hasPerspective()) {
    370         return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, nullptr,
    371                                                 nullptr, aaType, stencilSettings);
    372     } else {
    373         return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, nullptr, nullptr, aaType,
    374                                      stencilSettings);
    375     }
    376 }
    377 
    378 std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalMatrix(
    379         GrPaint&& paint, const SkMatrix& viewMatrix, const SkMatrix& localMatrix,
    380         const SkRect& rect, GrAAType aaType, const GrUserStencilSettings* stencilSettings) {
    381     if (viewMatrix.hasPerspective() || localMatrix.hasPerspective()) {
    382         return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, nullptr,
    383                                                 &localMatrix, aaType, stencilSettings);
    384     } else {
    385         return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, nullptr, &localMatrix,
    386                                      aaType, stencilSettings);
    387     }
    388 }
    389 
    390 std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalRect(GrPaint&& paint, const SkMatrix& viewMatrix,
    391                                                      const SkRect& rect, const SkRect& localRect,
    392                                                      GrAAType aaType) {
    393     if (viewMatrix.hasPerspective()) {
    394         return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, &localRect,
    395                                                 nullptr, aaType, nullptr);
    396     } else {
    397         return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, &localRect, nullptr,
    398                                      aaType, nullptr);
    399     }
    400 }
    401 
    402 }  // namespace GrRectOpFactory
    403 
    404 ///////////////////////////////////////////////////////////////////////////////////////////////////
    405 
    406 #if GR_TEST_UTILS
    407 
    408 GR_DRAW_OP_TEST_DEFINE(NonAAFillRectOp) {
    409     SkRect rect = GrTest::TestRect(random);
    410     SkRect localRect = GrTest::TestRect(random);
    411     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
    412     SkMatrix localMatrix = GrTest::TestMatrix(random);
    413     const GrUserStencilSettings* stencil = GrGetRandomStencil(random, context);
    414     GrAAType aaType = GrAAType::kNone;
    415     if (fsaaType == GrFSAAType::kUnifiedMSAA) {
    416         aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
    417     }
    418     const SkRect* lr = random->nextBool() ? &localRect : nullptr;
    419     const SkMatrix* lm = random->nextBool() ? &localMatrix : nullptr;
    420     if (viewMatrix.hasPerspective() || (lm && lm->hasPerspective())) {
    421         return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, lr, lm, aaType,
    422                                                 stencil);
    423     } else {
    424         return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, lr, lm, aaType, stencil);
    425     }
    426 }
    427 
    428 #endif
    429