Home | History | Annotate | Download | only in ops
      1 /*
      2  * Copyright 2015 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 "GrColor.h"
      9 #include "GrDefaultGeoProcFactory.h"
     10 #include "GrMeshDrawOp.h"
     11 #include "GrOpFlushState.h"
     12 #include "GrRectOpFactory.h"
     13 #include "GrResourceKey.h"
     14 #include "GrResourceProvider.h"
     15 #include "GrTypes.h"
     16 #include "SkMatrix.h"
     17 #include "SkRect.h"
     18 #include "ops/GrSimpleMeshDrawOpHelper.h"
     19 
     20 GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
     21 
     22 static inline bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) {
     23     return viewMatrix.preservesRightAngles();
     24 }
     25 
     26 static inline void set_inset_fan(SkPoint* pts, size_t stride, const SkRect& r, SkScalar dx,
     27                                  SkScalar dy) {
     28     pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
     29 }
     30 
     31 static const int kNumAAFillRectsInIndexBuffer = 256;
     32 static const int kVertsPerAAFillRect = 8;
     33 static const int kIndicesPerAAFillRect = 30;
     34 
     35 const GrBuffer* get_index_buffer(GrResourceProvider* resourceProvider) {
     36     GR_DEFINE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
     37 
     38     // clang-format off
     39     static const uint16_t gFillAARectIdx[] = {
     40         0, 1, 5, 5, 4, 0,
     41         1, 2, 6, 6, 5, 1,
     42         2, 3, 7, 7, 6, 2,
     43         3, 0, 4, 4, 7, 3,
     44         4, 5, 6, 6, 7, 4,
     45     };
     46     // clang-format on
     47 
     48     GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFillAARectIdx) == kIndicesPerAAFillRect);
     49     return resourceProvider->findOrCreatePatternedIndexBuffer(
     50             gFillAARectIdx, kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer,
     51             kVertsPerAAFillRect, gAAFillRectIndexBufferKey);
     52 }
     53 
     54 static void generate_aa_fill_rect_geometry(intptr_t verts,
     55                                            size_t vertexStride,
     56                                            GrColor color,
     57                                            const SkMatrix& viewMatrix,
     58                                            const SkRect& rect,
     59                                            const SkRect& devRect,
     60                                            bool tweakAlphaForCoverage,
     61                                            const SkMatrix* localMatrix) {
     62     SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
     63     SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
     64 
     65     SkScalar inset;
     66 
     67     if (viewMatrix.rectStaysRect()) {
     68         inset = SkMinScalar(devRect.width(), SK_Scalar1);
     69         inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
     70 
     71         set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
     72         set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
     73     } else {
     74         // compute transformed (1, 0) and (0, 1) vectors
     75         SkVector vec[2] = {{viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY]},
     76                            {viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY]}};
     77 
     78         SkScalar len1 = SkPoint::Normalize(&vec[0]);
     79         vec[0].scale(SK_ScalarHalf);
     80         SkScalar len2 = SkPoint::Normalize(&vec[1]);
     81         vec[1].scale(SK_ScalarHalf);
     82 
     83         inset = SkMinScalar(len1 * rect.width(), SK_Scalar1);
     84         inset = SK_ScalarHalf * SkMinScalar(inset, len2 * rect.height());
     85 
     86         // create the rotated rect
     87         fan0Pos->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
     88         viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
     89 
     90         // Now create the inset points and then outset the original
     91         // rotated points
     92 
     93         // TL
     94         *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
     95                 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
     96         *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
     97         // BL
     98         *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
     99                 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
    100         *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
    101         // BR
    102         *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
    103                 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
    104         *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
    105         // TR
    106         *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
    107                 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
    108         *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
    109     }
    110 
    111     if (localMatrix) {
    112         SkMatrix invViewMatrix;
    113         if (!viewMatrix.invert(&invViewMatrix)) {
    114             SkDebugf("View matrix is non-invertible, local coords will be wrong.");
    115             invViewMatrix = SkMatrix::I();
    116         }
    117         SkMatrix localCoordMatrix;
    118         localCoordMatrix.setConcat(*localMatrix, invViewMatrix);
    119         SkPoint* fan0Loc = reinterpret_cast<SkPoint*>(verts + sizeof(SkPoint) + sizeof(GrColor));
    120         localCoordMatrix.mapPointsWithStride(fan0Loc, fan0Pos, vertexStride, 8);
    121     }
    122 
    123     // Make verts point to vertex color and then set all the color and coverage vertex attrs
    124     // values.
    125     verts += sizeof(SkPoint);
    126 
    127     // The coverage offset is always the last vertex attribute
    128     intptr_t coverageOffset = vertexStride - sizeof(GrColor) - sizeof(SkPoint);
    129     for (int i = 0; i < 4; ++i) {
    130         if (tweakAlphaForCoverage) {
    131             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
    132         } else {
    133             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
    134             *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = 0;
    135         }
    136     }
    137 
    138     int scale;
    139     if (inset < SK_ScalarHalf) {
    140         scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
    141         SkASSERT(scale >= 0 && scale <= 255);
    142     } else {
    143         scale = 0xff;
    144     }
    145 
    146     verts += 4 * vertexStride;
    147 
    148     float innerCoverage = GrNormalizeByteToFloat(scale);
    149     GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
    150 
    151     for (int i = 0; i < 4; ++i) {
    152         if (tweakAlphaForCoverage) {
    153             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
    154         } else {
    155             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
    156             *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = innerCoverage;
    157         }
    158     }
    159 }
    160 
    161 namespace {
    162 
    163 class AAFillRectOp final : public GrMeshDrawOp {
    164 private:
    165     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
    166 
    167 public:
    168     DEFINE_OP_CLASS_ID
    169 
    170     static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint,
    171                                           const SkMatrix& viewMatrix,
    172                                           const SkRect& rect,
    173                                           const SkRect& devRect,
    174                                           const SkMatrix* localMatrix,
    175                                           const GrUserStencilSettings* stencil) {
    176         SkASSERT(view_matrix_ok_for_aa_fill_rect(viewMatrix));
    177         return Helper::FactoryHelper<AAFillRectOp>(std::move(paint), viewMatrix, rect, devRect,
    178                                                    localMatrix, stencil);
    179     }
    180 
    181     AAFillRectOp(const Helper::MakeArgs& helperArgs,
    182                  GrColor color,
    183                  const SkMatrix& viewMatrix,
    184                  const SkRect& rect,
    185                  const SkRect& devRect,
    186                  const SkMatrix* localMatrix,
    187                  const GrUserStencilSettings* stencil)
    188             : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencil) {
    189         if (localMatrix) {
    190             void* mem = fRectData.push_back_n(sizeof(RectWithLocalMatrixInfo));
    191             new (mem) RectWithLocalMatrixInfo(color, viewMatrix, rect, devRect, *localMatrix);
    192         } else {
    193             void* mem = fRectData.push_back_n(sizeof(RectInfo));
    194             new (mem) RectInfo(color, viewMatrix, rect, devRect);
    195         }
    196         IsZeroArea zeroArea =
    197                 (!rect.width() || !rect.height()) ? IsZeroArea::kYes : IsZeroArea::kNo;
    198         this->setBounds(devRect, HasAABloat::kYes, zeroArea);
    199         fRectCnt = 1;
    200     }
    201 
    202     const char* name() const override { return "AAFillRectOp"; }
    203 
    204     SkString dumpInfo() const override {
    205         SkString str;
    206         str.append(INHERITED::dumpInfo());
    207         str.appendf("# combined: %d\n", fRectCnt);
    208         const RectInfo* info = this->first();
    209         for (int i = 0; i < fRectCnt; ++i) {
    210             const SkRect& rect = info->rect();
    211             str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
    212                         info->color(), rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
    213             info = this->next(info);
    214         }
    215         str += fHelper.dumpInfo();
    216         str += INHERITED::dumpInfo();
    217         return str;
    218     }
    219 
    220     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
    221 
    222     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
    223         GrColor color = this->first()->color();
    224         auto result = fHelper.xpRequiresDstTexture(
    225                 caps, clip, GrProcessorAnalysisCoverage::kSingleChannel, &color);
    226         this->first()->setColor(color);
    227         return result;
    228     }
    229 
    230 private:
    231     void onPrepareDraws(Target* target) const override {
    232         using namespace GrDefaultGeoProcFactory;
    233 
    234         Color color(Color::kPremulGrColorAttribute_Type);
    235         Coverage::Type coverageType = fHelper.compatibleWithAlphaAsCoverage()
    236                                               ? Coverage::kSolid_Type
    237                                               : Coverage::kAttribute_Type;
    238         LocalCoords lc = fHelper.usesLocalCoords() ? LocalCoords::kHasExplicit_Type
    239                                                    : LocalCoords::kUnused_Type;
    240         sk_sp<GrGeometryProcessor> gp =
    241                 GrDefaultGeoProcFactory::Make(color, coverageType, lc, SkMatrix::I());
    242         if (!gp) {
    243             SkDebugf("Couldn't create GrGeometryProcessor\n");
    244             return;
    245         }
    246 
    247         size_t vertexStride = gp->getVertexStride();
    248 
    249         sk_sp<const GrBuffer> indexBuffer(get_index_buffer(target->resourceProvider()));
    250         PatternHelper helper(GrPrimitiveType::kTriangles);
    251         void* vertices =
    252                 helper.init(target, vertexStride, indexBuffer.get(), kVertsPerAAFillRect,
    253                             kIndicesPerAAFillRect, fRectCnt);
    254         if (!vertices || !indexBuffer) {
    255             SkDebugf("Could not allocate vertices\n");
    256             return;
    257         }
    258 
    259         const RectInfo* info = this->first();
    260         const SkMatrix* localMatrix = nullptr;
    261         for (int i = 0; i < fRectCnt; i++) {
    262             intptr_t verts =
    263                     reinterpret_cast<intptr_t>(vertices) + i * kVertsPerAAFillRect * vertexStride;
    264             if (fHelper.usesLocalCoords()) {
    265                 if (info->hasLocalMatrix()) {
    266                     localMatrix = &static_cast<const RectWithLocalMatrixInfo*>(info)->localMatrix();
    267                 } else {
    268                     localMatrix = &SkMatrix::I();
    269                 }
    270             }
    271             generate_aa_fill_rect_geometry(verts, vertexStride, info->color(), info->viewMatrix(),
    272                                            info->rect(), info->devRect(),
    273                                            fHelper.compatibleWithAlphaAsCoverage(), localMatrix);
    274             info = this->next(info);
    275         }
    276         helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
    277     }
    278 
    279     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
    280         AAFillRectOp* that = t->cast<AAFillRectOp>();
    281         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
    282             return false;
    283         }
    284 
    285         fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
    286         fRectCnt += that->fRectCnt;
    287         this->joinBounds(*that);
    288         return true;
    289     }
    290 
    291     struct RectInfo {
    292     public:
    293         RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
    294                  const SkRect& devRect)
    295                 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {}
    296         bool hasLocalMatrix() const { return HasLocalMatrix::kYes == fHasLocalMatrix; }
    297         GrColor color() const { return fColor; }
    298         const SkMatrix& viewMatrix() const { return fViewMatrix; }
    299         const SkRect& rect() const { return fRect; }
    300         const SkRect& devRect() const { return fDevRect; }
    301 
    302         void setColor(GrColor color) { fColor = color; }
    303 
    304     protected:
    305         enum class HasLocalMatrix : uint32_t { kNo, kYes };
    306 
    307         RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
    308                  const SkRect& devRect, HasLocalMatrix hasLM)
    309                 : fHasLocalMatrix(hasLM)
    310                 , fColor(color)
    311                 , fViewMatrix(viewMatrix)
    312                 , fRect(rect)
    313                 , fDevRect(devRect) {}
    314 
    315         HasLocalMatrix fHasLocalMatrix;
    316         GrColor fColor;
    317         SkMatrix fViewMatrix;
    318         SkRect fRect;
    319         SkRect fDevRect;
    320     };
    321 
    322     struct RectWithLocalMatrixInfo : public RectInfo {
    323     public:
    324         RectWithLocalMatrixInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
    325                                 const SkRect& devRect, const SkMatrix& localMatrix)
    326                 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes)
    327                 , fLocalMatrix(localMatrix) {}
    328         const SkMatrix& localMatrix() const { return fLocalMatrix; }
    329 
    330     private:
    331         SkMatrix fLocalMatrix;
    332     };
    333 
    334     RectInfo* first() { return reinterpret_cast<RectInfo*>(fRectData.begin()); }
    335     const RectInfo* first() const { return reinterpret_cast<const RectInfo*>(fRectData.begin()); }
    336     const RectInfo* next(const RectInfo* prev) const {
    337         intptr_t next =
    338                 reinterpret_cast<intptr_t>(prev) +
    339                 (prev->hasLocalMatrix() ? sizeof(RectWithLocalMatrixInfo) : sizeof(RectInfo));
    340         return reinterpret_cast<const RectInfo*>(next);
    341     }
    342 
    343     SkSTArray<4 * sizeof(RectWithLocalMatrixInfo), uint8_t, true> fRectData;
    344     Helper fHelper;
    345     int fRectCnt;
    346 
    347     typedef GrMeshDrawOp INHERITED;
    348 };
    349 
    350 }  // anonymous namespace
    351 
    352 namespace GrRectOpFactory {
    353 
    354 std::unique_ptr<GrDrawOp> MakeAAFill(GrPaint&& paint, const SkMatrix& viewMatrix,
    355                                      const SkRect& rect, const GrUserStencilSettings* stencil) {
    356     if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
    357         return nullptr;
    358     }
    359     SkRect devRect;
    360     viewMatrix.mapRect(&devRect, rect);
    361     return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, nullptr, stencil);
    362 }
    363 
    364 std::unique_ptr<GrDrawOp> MakeAAFillWithLocalMatrix(GrPaint&& paint, const SkMatrix& viewMatrix,
    365                                                     const SkMatrix& localMatrix,
    366                                                     const SkRect& rect) {
    367     if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
    368         return nullptr;
    369     }
    370     SkRect devRect;
    371     viewMatrix.mapRect(&devRect, rect);
    372     return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, &localMatrix, nullptr);
    373 }
    374 
    375 std::unique_ptr<GrDrawOp> MakeAAFillWithLocalRect(GrPaint&& paint, const SkMatrix& viewMatrix,
    376                                                   const SkRect& rect, const SkRect& localRect) {
    377     if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
    378         return nullptr;
    379     }
    380     SkRect devRect;
    381     viewMatrix.mapRect(&devRect, rect);
    382     SkMatrix localMatrix;
    383     if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
    384         return nullptr;
    385     }
    386     return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, &localMatrix, nullptr);
    387 }
    388 
    389 }  // namespace GrRectOpFactory
    390 
    391 ///////////////////////////////////////////////////////////////////////////////////////////////////
    392 
    393 #if GR_TEST_UTILS
    394 
    395 #include "GrDrawOpTest.h"
    396 
    397 GR_DRAW_OP_TEST_DEFINE(AAFillRectOp) {
    398     SkMatrix viewMatrix;
    399     do {
    400         viewMatrix = GrTest::TestMatrixInvertible(random);
    401     } while (!view_matrix_ok_for_aa_fill_rect(viewMatrix));
    402     SkRect rect = GrTest::TestRect(random);
    403     SkRect devRect;
    404     viewMatrix.mapRect(&devRect, rect);
    405     const SkMatrix* localMatrix = nullptr;
    406     SkMatrix m;
    407     if (random->nextBool()) {
    408         m = GrTest::TestMatrix(random);
    409     }
    410     const GrUserStencilSettings* stencil =
    411             random->nextBool() ? nullptr : GrGetRandomStencil(random, context);
    412     return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, localMatrix, stencil);
    413 }
    414 
    415 #endif
    416