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