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
make_gp(const SkMatrix & viewMatrix)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
tesselate_region(intptr_t vertices,size_t vertexStride,GrColor color,const SkRegion & region)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
RegionOp(GrColor color,const SkMatrix & viewMatrix,const SkRegion & region)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
name() const64 const char* name() const override { return "GrRegionOp"; }
65
dumpInfo() const66 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:
getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor * color,GrPipelineAnalysisCoverage * coverage) const80 void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color,
81 GrPipelineAnalysisCoverage* coverage) const override {
82 color->setToConstant(fRegions[0].fColor);
83 *coverage = GrPipelineAnalysisCoverage::kNone;
84 }
85
applyPipelineOptimizations(const GrPipelineOptimizations & optimizations)86 void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
87 optimizations.getOverrideColorIfSet(&fRegions[0].fColor);
88 }
89
onPrepareDraws(Target * target) const90 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
onCombineIfPossible(GrOp * t,const GrCaps & caps)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
Make(GrColor color,const SkMatrix & viewMatrix,const SkRegion & region)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