GrFillRectOp.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. /*
  2. * Copyright 2018 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. #include "src/gpu/ops/GrFillRectOp.h"
  8. #include "include/core/SkMatrix.h"
  9. #include "include/core/SkRect.h"
  10. #include "src/gpu/GrCaps.h"
  11. #include "src/gpu/GrGeometryProcessor.h"
  12. #include "src/gpu/GrPaint.h"
  13. #include "src/gpu/SkGr.h"
  14. #include "src/gpu/geometry/GrQuad.h"
  15. #include "src/gpu/geometry/GrQuadBuffer.h"
  16. #include "src/gpu/geometry/GrQuadUtils.h"
  17. #include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
  18. #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
  19. #include "src/gpu/glsl/GrGLSLVarying.h"
  20. #include "src/gpu/ops/GrMeshDrawOp.h"
  21. #include "src/gpu/ops/GrQuadPerEdgeAA.h"
  22. #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
  23. namespace {
  24. using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
  25. using ColorType = GrQuadPerEdgeAA::ColorType;
  26. #ifdef SK_DEBUG
  27. static SkString dump_quad_info(int index, const GrQuad& deviceQuad,
  28. const GrQuad& localQuad, const SkPMColor4f& color,
  29. GrQuadAAFlags aaFlags) {
  30. SkString str;
  31. str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
  32. " device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
  33. "(%.2f, %.2f, %.2f)],\n"
  34. " local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
  35. "(%.2f, %.2f, %.2f)]\n",
  36. index, color.fR, color.fG, color.fB, color.fA,
  37. (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
  38. (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
  39. (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
  40. (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
  41. deviceQuad.x(0), deviceQuad.y(0), deviceQuad.w(0),
  42. deviceQuad.x(1), deviceQuad.y(1), deviceQuad.w(1),
  43. deviceQuad.x(2), deviceQuad.y(2), deviceQuad.w(2),
  44. deviceQuad.x(3), deviceQuad.y(3), deviceQuad.w(3),
  45. localQuad.x(0), localQuad.y(0), localQuad.w(0),
  46. localQuad.x(1), localQuad.y(1), localQuad.w(1),
  47. localQuad.x(2), localQuad.y(2), localQuad.w(2),
  48. localQuad.x(3), localQuad.y(3), localQuad.w(3));
  49. return str;
  50. }
  51. #endif
  52. class FillRectOp final : public GrMeshDrawOp {
  53. private:
  54. using Helper = GrSimpleMeshDrawOpHelperWithStencil;
  55. public:
  56. static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
  57. GrPaint&& paint,
  58. GrAAType aaType,
  59. GrQuadAAFlags edgeAA,
  60. const GrUserStencilSettings* stencilSettings,
  61. const GrQuad& deviceQuad,
  62. const GrQuad& localQuad) {
  63. // Clean up deviations between aaType and edgeAA
  64. GrQuadUtils::ResolveAAType(aaType, edgeAA, deviceQuad, &aaType, &edgeAA);
  65. return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, edgeAA,
  66. stencilSettings, deviceQuad, localQuad);
  67. }
  68. // aaType is passed to Helper in the initializer list, so incongruities between aaType and
  69. // edgeFlags must be resolved prior to calling this constructor.
  70. FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
  71. GrQuadAAFlags edgeFlags, const GrUserStencilSettings* stencil,
  72. const GrQuad& deviceQuad, const GrQuad& localQuad)
  73. : INHERITED(ClassID())
  74. , fHelper(args, aaType, stencil)
  75. , fQuads(1, !fHelper.isTrivial()) {
  76. // Conservatively keep track of the local coordinates; it may be that the paint doesn't
  77. // need them after analysis is finished. If the paint is known to be solid up front they
  78. // can be skipped entirely.
  79. fQuads.append(deviceQuad, { paintColor, edgeFlags },
  80. fHelper.isTrivial() ? nullptr : &localQuad);
  81. this->setBounds(deviceQuad.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
  82. IsZeroArea::kNo);
  83. }
  84. const char* name() const override { return "FillRectOp"; }
  85. void visitProxies(const VisitProxyFunc& func) const override {
  86. return fHelper.visitProxies(func);
  87. }
  88. #ifdef SK_DEBUG
  89. SkString dumpInfo() const override {
  90. SkString str;
  91. str.appendf("# draws: %u\n", fQuads.count());
  92. str.appendf("Device quad type: %u, local quad type: %u\n",
  93. (uint32_t) fQuads.deviceQuadType(), (uint32_t) fQuads.localQuadType());
  94. str += fHelper.dumpInfo();
  95. int i = 0;
  96. auto iter = fQuads.iterator();
  97. while(iter.next()) {
  98. const ColorAndAA& info = iter.metadata();
  99. str += dump_quad_info(i, iter.deviceQuad(), iter.localQuad(),
  100. info.fColor, info.fAAFlags);
  101. i++;
  102. }
  103. str += INHERITED::dumpInfo();
  104. return str;
  105. }
  106. #endif
  107. GrProcessorSet::Analysis finalize(
  108. const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
  109. GrClampType clampType) override {
  110. // Initialize aggregate color analysis with the first quad's color (which always exists)
  111. auto iter = fQuads.metadata();
  112. SkAssertResult(iter.next());
  113. GrProcessorAnalysisColor quadColors(iter->fColor);
  114. // Then combine the colors of any additional quads (e.g. from MakeSet)
  115. while(iter.next()) {
  116. quadColors = GrProcessorAnalysisColor::Combine(quadColors, iter->fColor);
  117. if (quadColors.isUnknown()) {
  118. // No point in accumulating additional starting colors, combining cannot make it
  119. // less unknown.
  120. break;
  121. }
  122. }
  123. // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
  124. // then the coverage is always 1.0, so specify kNone for more optimal blending.
  125. GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
  126. GrProcessorAnalysisCoverage::kSingleChannel :
  127. GrProcessorAnalysisCoverage::kNone;
  128. auto result = fHelper.finalizeProcessors(
  129. caps, clip, hasMixedSampledCoverage, clampType, coverage, &quadColors);
  130. // If there is a constant color after analysis, that means all of the quads should be set
  131. // to the same color (even if they started out with different colors).
  132. iter = fQuads.metadata();
  133. SkPMColor4f colorOverride;
  134. if (quadColors.isConstant(&colorOverride)) {
  135. fColorType = GrQuadPerEdgeAA::MinColorType(colorOverride, clampType, caps);
  136. while(iter.next()) {
  137. iter->fColor = colorOverride;
  138. }
  139. } else {
  140. // Otherwise compute the color type needed as the max over all quads.
  141. fColorType = ColorType::kNone;
  142. while(iter.next()) {
  143. fColorType = SkTMax(fColorType,
  144. GrQuadPerEdgeAA::MinColorType(iter->fColor, clampType, caps));
  145. }
  146. }
  147. // Most SkShaders' FPs multiply their calculated color by the paint color or alpha. We want
  148. // to use ColorType::kNone to optimize out that multiply. However, if there are no color
  149. // FPs then were really writing a special shader for white rectangles and not saving any
  150. // multiples. So in that case use bytes to avoid the extra shader (and possibly work around
  151. // an ANGLE issue: crbug.com/942565).
  152. if (fColorType == ColorType::kNone && !result.hasColorFragmentProcessor()) {
  153. fColorType = ColorType::kByte;
  154. }
  155. return result;
  156. }
  157. FixedFunctionFlags fixedFunctionFlags() const override {
  158. // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
  159. // the helper's fixed function flags are appropriate.
  160. return fHelper.fixedFunctionFlags();
  161. }
  162. DEFINE_OP_CLASS_ID
  163. private:
  164. // For GrFillRectOp::MakeSet's use of addQuad
  165. friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(
  166. GrRecordingContext*,
  167. GrPaint&&,
  168. GrAAType, const SkMatrix& viewMatrix,
  169. const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
  170. const GrUserStencilSettings*);
  171. void onPrepareDraws(Target* target) override {
  172. TRACE_EVENT0("skia.gpu", TRACE_FUNC);
  173. using Domain = GrQuadPerEdgeAA::Domain;
  174. static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
  175. VertexSpec vertexSpec(fQuads.deviceQuadType(), fColorType, fQuads.localQuadType(),
  176. fHelper.usesLocalCoords(), Domain::kNo, fHelper.aaType(),
  177. fHelper.compatibleWithCoverageAsAlpha());
  178. // Make sure that if the op thought it was a solid color, the vertex spec does not use
  179. // local coords.
  180. SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
  181. sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
  182. size_t vertexSize = gp->vertexStride();
  183. sk_sp<const GrBuffer> vbuffer;
  184. int vertexOffsetInBuffer = 0;
  185. // Fill the allocated vertex data
  186. void* vdata = target->makeVertexSpace(
  187. vertexSize, fQuads.count() * vertexSpec.verticesPerQuad(),
  188. &vbuffer, &vertexOffsetInBuffer);
  189. if (!vdata) {
  190. SkDebugf("Could not allocate vertices\n");
  191. return;
  192. }
  193. // vertices pointer advances through vdata based on Tessellate's return value
  194. void* vertices = vdata;
  195. auto iter = fQuads.iterator();
  196. while(iter.next()) {
  197. // All entries should have local coords, or no entries should have local coords,
  198. // matching !helper.isTrivial() (which is more conservative than helper.usesLocalCoords)
  199. SkASSERT(iter.isLocalValid() != fHelper.isTrivial());
  200. auto info = iter.metadata();
  201. vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, iter.deviceQuad(),
  202. info.fColor, iter.localQuad(), kEmptyDomain, info.fAAFlags);
  203. }
  204. // Configure the mesh for the vertex data
  205. GrMesh* mesh = target->allocMeshes(1);
  206. if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, mesh, vertexSpec, fQuads.count())) {
  207. SkDebugf("Could not allocate indices\n");
  208. return;
  209. }
  210. mesh->setVertexData(std::move(vbuffer), vertexOffsetInBuffer);
  211. target->recordDraw(std::move(gp), mesh);
  212. }
  213. void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
  214. fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
  215. }
  216. CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
  217. TRACE_EVENT0("skia.gpu", TRACE_FUNC);
  218. const auto* that = t->cast<FillRectOp>();
  219. if ((fHelper.aaType() == GrAAType::kCoverage ||
  220. that->fHelper.aaType() == GrAAType::kCoverage) &&
  221. fQuads.count() + that->fQuads.count() > GrQuadPerEdgeAA::kNumAAQuadsInIndexBuffer) {
  222. // This limit on batch size seems to help on Adreno devices
  223. return CombineResult::kCannotCombine;
  224. }
  225. // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
  226. // ops together, so pass true as the last argument.
  227. if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
  228. return CombineResult::kCannotCombine;
  229. }
  230. // If the paints were compatible, the trivial/solid-color state should be the same
  231. SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
  232. // If the processor sets are compatible, the two ops are always compatible; it just needs to
  233. // adjust the state of the op to be the more general quad and aa types of the two ops and
  234. // then concatenate the per-quad data.
  235. fColorType = SkTMax(fColorType, that->fColorType);
  236. // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
  237. // types to be none and coverage, in which case this op's aa type must be lifted to coverage
  238. // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
  239. if (fHelper.aaType() == GrAAType::kNone && that->fHelper.aaType() == GrAAType::kCoverage) {
  240. fHelper.setAAType(GrAAType::kCoverage);
  241. }
  242. fQuads.concat(that->fQuads);
  243. return CombineResult::kMerged;
  244. }
  245. // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
  246. // But since it's avoiding the op list management, it must update the op's bounds. This is only
  247. // used with quad sets, which uses the same view matrix for each quad so this assumes that the
  248. // device quad type of the new quad is the same as the op's.
  249. void addQuad(const GrQuad& deviceQuad, const GrQuad& localQuad,
  250. const SkPMColor4f& color, GrQuadAAFlags edgeAA, GrAAType aaType) {
  251. // The new quad's aa type should be the same as the first quad's or none, except when the
  252. // first quad's aa type was already downgraded to none, in which case the stored type must
  253. // be lifted to back to the requested type.
  254. if (aaType != fHelper.aaType()) {
  255. if (aaType != GrAAType::kNone) {
  256. // Original quad was downgraded to non-aa, lift back up to this quad's required type
  257. SkASSERT(fHelper.aaType() == GrAAType::kNone);
  258. fHelper.setAAType(aaType);
  259. }
  260. // else the new quad could have been downgraded but the other quads can't be, so don't
  261. // reset the op's accumulated aa type.
  262. }
  263. // Update the bounds and add the quad to this op's storage
  264. SkRect newBounds = this->bounds();
  265. newBounds.joinPossiblyEmptyRect(deviceQuad.bounds());
  266. this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
  267. IsZeroArea::kNo);
  268. fQuads.append(deviceQuad, { color, edgeAA }, fHelper.isTrivial() ? nullptr : &localQuad);
  269. }
  270. struct ColorAndAA {
  271. SkPMColor4f fColor;
  272. GrQuadAAFlags fAAFlags;
  273. };
  274. Helper fHelper;
  275. GrQuadBuffer<ColorAndAA> fQuads;
  276. ColorType fColorType;
  277. typedef GrMeshDrawOp INHERITED;
  278. };
  279. } // anonymous namespace
  280. namespace GrFillRectOp {
  281. std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
  282. GrPaint&& paint,
  283. GrAAType aaType,
  284. GrQuadAAFlags aaFlags,
  285. const GrQuad& deviceQuad,
  286. const GrQuad& localQuad,
  287. const GrUserStencilSettings* stencil) {
  288. return FillRectOp::Make(context, std::move(paint), aaType, aaFlags, stencil,
  289. deviceQuad, localQuad);
  290. }
  291. std::unique_ptr<GrDrawOp> MakeNonAARect(GrRecordingContext* context,
  292. GrPaint&& paint,
  293. const SkMatrix& view,
  294. const SkRect& rect,
  295. const GrUserStencilSettings* stencil) {
  296. return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, GrQuadAAFlags::kNone,
  297. stencil, GrQuad::MakeFromRect(rect, view), GrQuad(rect));
  298. }
  299. std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
  300. GrPaint&& paint,
  301. GrAAType aaType,
  302. const SkMatrix& viewMatrix,
  303. const GrRenderTargetContext::QuadSetEntry quads[],
  304. int cnt,
  305. const GrUserStencilSettings* stencilSettings) {
  306. // First make a draw op for the first quad in the set
  307. SkASSERT(cnt > 0);
  308. paint.setColor4f(quads[0].fColor);
  309. std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
  310. quads[0].fAAFlags, stencilSettings,
  311. GrQuad::MakeFromRect(quads[0].fRect, viewMatrix),
  312. GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix));
  313. auto* fillRects = op->cast<FillRectOp>();
  314. // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
  315. for (int i = 1; i < cnt; ++i) {
  316. GrQuad deviceQuad = GrQuad::MakeFromRect(quads[i].fRect, viewMatrix);
  317. GrAAType resolvedAA;
  318. GrQuadAAFlags resolvedEdgeFlags;
  319. GrQuadUtils::ResolveAAType(aaType, quads[i].fAAFlags, deviceQuad,
  320. &resolvedAA, &resolvedEdgeFlags);
  321. fillRects->addQuad(deviceQuad,
  322. GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
  323. quads[i].fColor, resolvedEdgeFlags,resolvedAA);
  324. }
  325. return op;
  326. }
  327. } // namespace GrFillRectOp
  328. #if GR_TEST_UTILS
  329. #include "src/gpu/GrDrawOpTest.h"
  330. #include "src/gpu/SkGr.h"
  331. GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
  332. SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
  333. SkRect rect = GrTest::TestRect(random);
  334. GrAAType aaType = GrAAType::kNone;
  335. if (random->nextBool()) {
  336. aaType = (numSamples > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
  337. }
  338. const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
  339. : GrGetRandomStencil(random, context);
  340. GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
  341. aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
  342. aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
  343. aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
  344. aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
  345. if (random->nextBool()) {
  346. if (random->nextBool()) {
  347. if (random->nextBool()) {
  348. // Local matrix with a set op
  349. uint32_t extraQuadCt = random->nextRangeU(1, 4);
  350. SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
  351. quads.push_back(
  352. {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
  353. GrTest::TestMatrixInvertible(random), aaFlags});
  354. for (uint32_t i = 0; i < extraQuadCt; ++i) {
  355. GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
  356. aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
  357. aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
  358. aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
  359. aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
  360. quads.push_back(
  361. {GrTest::TestRect(random),
  362. SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
  363. GrTest::TestMatrixInvertible(random), aaFlags});
  364. }
  365. return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
  366. quads.begin(), quads.count(), stencil);
  367. } else {
  368. // Single local matrix
  369. SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
  370. return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
  371. GrQuad::MakeFromRect(rect, viewMatrix),
  372. GrQuad::MakeFromRect(rect, localMatrix), stencil);
  373. }
  374. } else {
  375. // Pass local rect directly
  376. SkRect localRect = GrTest::TestRect(random);
  377. return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
  378. GrQuad::MakeFromRect(rect, viewMatrix),
  379. GrQuad(localRect), stencil);
  380. }
  381. } else {
  382. // The simplest constructor
  383. return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
  384. GrQuad::MakeFromRect(rect, viewMatrix),
  385. GrQuad(rect), stencil);
  386. }
  387. }
  388. #endif