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