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