Home | History | Annotate | Download | only in ops
      1 /*
      2  * Copyright 2016 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 "GrRegionOp.h"
      9 
     10 #include "GrDefaultGeoProcFactory.h"
     11 #include "GrMeshDrawOp.h"
     12 #include "GrOpFlushState.h"
     13 #include "GrResourceProvider.h"
     14 #include "SkMatrixPriv.h"
     15 #include "SkRegion.h"
     16 
     17 static const int kVertsPerInstance = 4;
     18 static const int kIndicesPerInstance = 6;
     19 
     20 static sk_sp<GrGeometryProcessor> make_gp(const SkMatrix& viewMatrix) {
     21     using namespace GrDefaultGeoProcFactory;
     22     return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type,
     23                                          LocalCoords::kUsePosition_Type, viewMatrix);
     24 }
     25 
     26 static void tesselate_region(intptr_t vertices,
     27                              size_t vertexStride,
     28                              GrColor color,
     29                              const SkRegion& region) {
     30     SkRegion::Iterator iter(region);
     31 
     32     intptr_t verts = vertices;
     33     while (!iter.done()) {
     34         SkRect rect = SkRect::Make(iter.rect());
     35         SkPoint* position = (SkPoint*)verts;
     36         position->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
     37 
     38         static const int kColorOffset = sizeof(SkPoint);
     39         GrColor* vertColor = reinterpret_cast<GrColor*>(verts + kColorOffset);
     40         for (int i = 0; i < kVertsPerInstance; i++) {
     41             *vertColor = color;
     42             vertColor = (GrColor*)((intptr_t)vertColor + vertexStride);
     43         }
     44 
     45         verts += vertexStride * kVertsPerInstance;
     46         iter.next();
     47     }
     48 }
     49 
     50 class RegionOp final : public GrMeshDrawOp {
     51 public:
     52     DEFINE_OP_CLASS_ID
     53 
     54     RegionOp(GrColor color, const SkMatrix& viewMatrix, const SkRegion& region)
     55             : INHERITED(ClassID()), fViewMatrix(viewMatrix) {
     56         RegionInfo& info = fRegions.push_back();
     57         info.fColor = color;
     58         info.fRegion = region;
     59 
     60         SkRect bounds = SkRect::Make(region.getBounds());
     61         this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
     62     }
     63 
     64     const char* name() const override { return "GrRegionOp"; }
     65 
     66     SkString dumpInfo() const override {
     67         SkString str;
     68         str.appendf("# combined: %d\n", fRegions.count());
     69         for (int i = 0; i < fRegions.count(); ++i) {
     70             const RegionInfo& info = fRegions[i];
     71             str.appendf("%d: Color: 0x%08x, Region with %d rects\n", i, info.fColor,
     72                         info.fRegion.computeRegionComplexity());
     73         }
     74         str.append(DumpPipelineInfo(*this->pipeline()));
     75         str.append(INHERITED::dumpInfo());
     76         return str;
     77     }
     78 
     79 private:
     80     void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color,
     81                                             GrPipelineAnalysisCoverage* coverage) const override {
     82         color->setToConstant(fRegions[0].fColor);
     83         *coverage = GrPipelineAnalysisCoverage::kNone;
     84     }
     85 
     86     void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
     87         optimizations.getOverrideColorIfSet(&fRegions[0].fColor);
     88     }
     89 
     90     void onPrepareDraws(Target* target) const override {
     91         sk_sp<GrGeometryProcessor> gp = make_gp(fViewMatrix);
     92         if (!gp) {
     93             SkDebugf("Couldn't create GrGeometryProcessor\n");
     94             return;
     95         }
     96         SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
     97 
     98         int numRegions = fRegions.count();
     99         int numRects = 0;
    100         for (int i = 0; i < numRegions; i++) {
    101             numRects += fRegions[i].fRegion.computeRegionComplexity();
    102         }
    103 
    104         size_t vertexStride = gp->getVertexStride();
    105         sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
    106         InstancedHelper helper;
    107         void* vertices =
    108                 helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(),
    109                             kVertsPerInstance, kIndicesPerInstance, numRects);
    110         if (!vertices || !indexBuffer) {
    111             SkDebugf("Could not allocate vertices\n");
    112             return;
    113         }
    114 
    115         intptr_t verts = reinterpret_cast<intptr_t>(vertices);
    116         for (int i = 0; i < numRegions; i++) {
    117             tesselate_region(verts, vertexStride, fRegions[i].fColor, fRegions[i].fRegion);
    118             int numRectsInRegion = fRegions[i].fRegion.computeRegionComplexity();
    119             verts += numRectsInRegion * kVertsPerInstance * vertexStride;
    120         }
    121         helper.recordDraw(target, gp.get());
    122     }
    123 
    124     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
    125         RegionOp* that = t->cast<RegionOp>();
    126         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
    127                                     that->bounds(), caps)) {
    128             return false;
    129         }
    130 
    131         if (fViewMatrix != that->fViewMatrix) {
    132             return false;
    133         }
    134 
    135         fRegions.push_back_n(that->fRegions.count(), that->fRegions.begin());
    136         this->joinBounds(*that);
    137         return true;
    138     }
    139 
    140     struct RegionInfo {
    141         GrColor fColor;
    142         SkRegion fRegion;
    143     };
    144 
    145     SkMatrix fViewMatrix;
    146     SkSTArray<1, RegionInfo, true> fRegions;
    147 
    148     typedef GrMeshDrawOp INHERITED;
    149 };
    150 
    151 namespace GrRegionOp {
    152 
    153 std::unique_ptr<GrMeshDrawOp> Make(GrColor color, const SkMatrix& viewMatrix,
    154                                    const SkRegion& region) {
    155     return std::unique_ptr<GrMeshDrawOp>(new RegionOp(color, viewMatrix, region));
    156 }
    157 }
    158