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