Line data Source code
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 "GrNonAAFillRectOp.h"
9 :
10 : #include "GrColor.h"
11 : #include "GrDefaultGeoProcFactory.h"
12 : #include "GrMeshDrawOp.h"
13 : #include "GrOpFlushState.h"
14 : #include "GrPrimitiveProcessor.h"
15 : #include "GrQuad.h"
16 : #include "GrResourceProvider.h"
17 :
18 : static const int kVertsPerInstance = 4;
19 : static const int kIndicesPerInstance = 6;
20 :
21 : /** We always use per-vertex colors so that rects can be combined across color changes. Sometimes
22 : we have explicit local coords and sometimes not. We *could* always provide explicit local
23 : coords and just duplicate the positions when the caller hasn't provided a local coord rect,
24 : but we haven't seen a use case which frequently switches between local rect and no local
25 : rect draws.
26 :
27 : The vertex attrib order is always pos, color, [local coords].
28 : */
29 0 : static sk_sp<GrGeometryProcessor> make_persp_gp(const SkMatrix& viewMatrix,
30 : bool hasExplicitLocalCoords,
31 : const SkMatrix* localMatrix) {
32 0 : SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
33 :
34 : using namespace GrDefaultGeoProcFactory;
35 :
36 : // If we have perspective on the viewMatrix then we won't map on the CPU, nor will we map
37 : // the local rect on the cpu (in case the localMatrix also has perspective).
38 : // Otherwise, if we have a local rect, then we apply the localMatrix directly to the localRect
39 : // to generate vertex local coords
40 0 : if (viewMatrix.hasPerspective()) {
41 : LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type
42 : : LocalCoords::kUsePosition_Type,
43 0 : localMatrix);
44 : return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
45 0 : Coverage::kSolid_Type, localCoords, viewMatrix);
46 0 : } else if (hasExplicitLocalCoords) {
47 0 : LocalCoords localCoords(LocalCoords::kHasExplicit_Type, localMatrix);
48 : return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
49 0 : Coverage::kSolid_Type, localCoords, SkMatrix::I());
50 : } else {
51 0 : LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix);
52 : return GrDefaultGeoProcFactory::MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type,
53 : Coverage::kSolid_Type, localCoords,
54 0 : viewMatrix);
55 : }
56 : }
57 :
58 0 : static void tesselate(intptr_t vertices,
59 : size_t vertexStride,
60 : GrColor color,
61 : const SkMatrix* viewMatrix,
62 : const SkRect& rect,
63 : const GrQuad* localQuad) {
64 0 : SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
65 :
66 0 : positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
67 :
68 0 : if (viewMatrix) {
69 0 : viewMatrix->mapPointsWithStride(positions, vertexStride, kVertsPerInstance);
70 : }
71 :
72 : // Setup local coords
73 : // TODO we should only do this if local coords are being read
74 0 : if (localQuad) {
75 : static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
76 0 : for (int i = 0; i < kVertsPerInstance; i++) {
77 : SkPoint* coords =
78 0 : reinterpret_cast<SkPoint*>(vertices + kLocalOffset + i * vertexStride);
79 0 : *coords = localQuad->point(i);
80 : }
81 : }
82 :
83 : static const int kColorOffset = sizeof(SkPoint);
84 0 : GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
85 0 : for (int j = 0; j < 4; ++j) {
86 0 : *vertColor = color;
87 0 : vertColor = (GrColor*)((intptr_t)vertColor + vertexStride);
88 : }
89 0 : }
90 :
91 : // We handle perspective in the local matrix or viewmatrix with special ops.
92 0 : class NonAAFillRectPerspectiveOp final : public GrLegacyMeshDrawOp {
93 : public:
94 0 : DEFINE_OP_CLASS_ID
95 :
96 0 : NonAAFillRectPerspectiveOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
97 : const SkRect* localRect, const SkMatrix* localMatrix)
98 0 : : INHERITED(ClassID()), fViewMatrix(viewMatrix) {
99 0 : SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
100 0 : RectInfo& info = fRects.push_back();
101 0 : info.fColor = color;
102 0 : info.fRect = rect;
103 0 : fHasLocalRect = SkToBool(localRect);
104 0 : fHasLocalMatrix = SkToBool(localMatrix);
105 0 : if (fHasLocalMatrix) {
106 0 : fLocalMatrix = *localMatrix;
107 : }
108 0 : if (fHasLocalRect) {
109 0 : info.fLocalRect = *localRect;
110 : }
111 0 : this->setTransformedBounds(rect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
112 0 : }
113 :
114 0 : const char* name() const override { return "NonAAFillRectPerspectiveOp"; }
115 :
116 0 : SkString dumpInfo() const override {
117 0 : SkString str;
118 0 : str.appendf("# combined: %d\n", fRects.count());
119 0 : for (int i = 0; i < fRects.count(); ++i) {
120 0 : const RectInfo& geo = fRects[0];
121 0 : str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
122 0 : geo.fColor, geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight,
123 0 : geo.fRect.fBottom);
124 : }
125 0 : str.append(DumpPipelineInfo(*this->pipeline()));
126 0 : str.append(INHERITED::dumpInfo());
127 0 : return str;
128 : }
129 :
130 : private:
131 : NonAAFillRectPerspectiveOp() : INHERITED(ClassID()) {}
132 :
133 0 : void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
134 : GrProcessorAnalysisCoverage* coverage) const override {
135 0 : color->setToConstant(fRects[0].fColor);
136 0 : *coverage = GrProcessorAnalysisCoverage::kNone;
137 0 : }
138 :
139 0 : void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override {
140 0 : optimizations.getOverrideColorIfSet(&fRects[0].fColor);
141 0 : }
142 :
143 0 : void onPrepareDraws(Target* target) const override {
144 : sk_sp<GrGeometryProcessor> gp = make_persp_gp(fViewMatrix,
145 0 : fHasLocalRect,
146 0 : fHasLocalMatrix ? &fLocalMatrix : nullptr);
147 0 : if (!gp) {
148 0 : SkDebugf("Couldn't create GrGeometryProcessor\n");
149 0 : return;
150 : }
151 0 : SkASSERT(fHasLocalRect
152 : ? gp->getVertexStride() ==
153 : sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
154 : : gp->getVertexStride() ==
155 : sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
156 :
157 0 : size_t vertexStride = gp->getVertexStride();
158 0 : int instanceCount = fRects.count();
159 :
160 0 : sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
161 0 : InstancedHelper helper;
162 : void* vertices =
163 0 : helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(),
164 0 : kVertsPerInstance, kIndicesPerInstance, instanceCount);
165 0 : if (!vertices || !indexBuffer) {
166 0 : SkDebugf("Could not allocate vertices\n");
167 0 : return;
168 : }
169 :
170 0 : for (int i = 0; i < instanceCount; i++) {
171 0 : const RectInfo& info = fRects[i];
172 : intptr_t verts =
173 0 : reinterpret_cast<intptr_t>(vertices) + i * kVertsPerInstance * vertexStride;
174 0 : if (fHasLocalRect) {
175 0 : GrQuad quad(info.fLocalRect);
176 0 : tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, &quad);
177 : } else {
178 0 : tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, nullptr);
179 : }
180 : }
181 0 : helper.recordDraw(target, gp.get(), this->pipeline());
182 : }
183 :
184 0 : bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
185 0 : NonAAFillRectPerspectiveOp* that = t->cast<NonAAFillRectPerspectiveOp>();
186 0 : if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
187 : that->bounds(), caps)) {
188 0 : return false;
189 : }
190 :
191 : // We could combine across perspective vm changes if we really wanted to.
192 0 : if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
193 0 : return false;
194 : }
195 0 : if (fHasLocalRect != that->fHasLocalRect) {
196 0 : return false;
197 : }
198 0 : if (fHasLocalMatrix && !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) {
199 0 : return false;
200 : }
201 :
202 0 : fRects.push_back_n(that->fRects.count(), that->fRects.begin());
203 0 : this->joinBounds(*that);
204 0 : return true;
205 : }
206 :
207 : struct RectInfo {
208 : SkRect fRect;
209 : GrColor fColor;
210 : SkRect fLocalRect;
211 : };
212 :
213 : SkSTArray<1, RectInfo, true> fRects;
214 : bool fHasLocalMatrix;
215 : bool fHasLocalRect;
216 : SkMatrix fLocalMatrix;
217 : SkMatrix fViewMatrix;
218 :
219 : typedef GrLegacyMeshDrawOp INHERITED;
220 : };
221 :
222 : namespace GrNonAAFillRectOp {
223 :
224 0 : std::unique_ptr<GrLegacyMeshDrawOp> MakeWithPerspective(GrColor color,
225 : const SkMatrix& viewMatrix,
226 : const SkRect& rect,
227 : const SkRect* localRect,
228 : const SkMatrix* localMatrix) {
229 : return std::unique_ptr<GrLegacyMeshDrawOp>(
230 0 : new NonAAFillRectPerspectiveOp(color, viewMatrix, rect, localRect, localMatrix));
231 : }
232 : };
233 :
234 : ///////////////////////////////////////////////////////////////////////////////////////////////////
235 :
236 : #if GR_TEST_UTILS
237 :
238 : #include "GrDrawOpTest.h"
239 :
240 0 : DRAW_OP_TEST_DEFINE(NonAAFillRectPerspectiveOp) {
241 0 : GrColor color = GrRandomColor(random);
242 0 : SkRect rect = GrTest::TestRect(random);
243 0 : SkRect localRect = GrTest::TestRect(random);
244 0 : SkMatrix viewMatrix = GrTest::TestMatrix(random);
245 0 : bool hasLocalMatrix = random->nextBool();
246 : SkMatrix localMatrix;
247 0 : if (!viewMatrix.hasPerspective()) {
248 0 : localMatrix = GrTest::TestMatrixPerspective(random);
249 0 : hasLocalMatrix = true;
250 : }
251 :
252 0 : bool hasLocalRect = random->nextBool();
253 : return GrNonAAFillRectOp::MakeWithPerspective(color, viewMatrix, rect,
254 : hasLocalRect ? &localRect : nullptr,
255 0 : hasLocalMatrix ? &localMatrix : nullptr);
256 : }
257 :
258 : #endif
|