blob: 00319159b5f6a854ab1d1ccb6190db123c81ecc3 [file] [log] [blame]
Chris Dalton83420eb2021-06-23 18:47:09 -06001/*
2 * Copyright 2021 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 "src/gpu/tessellate/GrAtlasRenderTask.h"
9
10#include "src/core/SkBlendModePriv.h"
11#include "src/core/SkIPoint16.h"
12#include "src/gpu/GrGpu.h"
13#include "src/gpu/GrOpFlushState.h"
Robert Phillipse40495d2021-07-20 09:40:13 -040014#include "src/gpu/GrOpsTypes.h"
Chris Dalton83420eb2021-06-23 18:47:09 -060015#include "src/gpu/ops/GrFillRectOp.h"
Robert Phillipse453fa02021-08-19 14:57:05 -040016#include "src/gpu/ops/PathStencilCoverOp.h"
Chris Dalton83420eb2021-06-23 18:47:09 -060017
Robert Phillipsa92913e2021-07-12 16:31:52 -040018GrAtlasRenderTask::GrAtlasRenderTask(GrRecordingContext* rContext,
Chris Dalton83420eb2021-06-23 18:47:09 -060019 sk_sp<GrArenas> arenas,
20 std::unique_ptr<GrDynamicAtlas> dynamicAtlas)
21 : GrOpsTask(rContext->priv().drawingManager(),
Robert Phillipsa92913e2021-07-12 16:31:52 -040022 dynamicAtlas->writeView(*rContext->priv().caps()),
23 rContext->priv().auditTrail(),
Chris Dalton83420eb2021-06-23 18:47:09 -060024 std::move(arenas))
25 , fDynamicAtlas(std::move(dynamicAtlas)) {
26}
27
Chris Dalton5e332c82021-07-21 16:04:47 -060028bool GrAtlasRenderTask::addPath(const SkMatrix& viewMatrix, const SkPath& path,
Chris Dalton83420eb2021-06-23 18:47:09 -060029 SkIPoint pathDevTopLeft, int widthInAtlas, int heightInAtlas,
30 bool transposedInAtlas, SkIPoint16* locationInAtlas) {
31 SkASSERT(!this->isClosed());
32 SkASSERT(this->isEmpty());
33 SkASSERT(!fDynamicAtlas->isInstantiated()); // Paths can't be added after instantiate().
34
35 if (!fDynamicAtlas->addRect(widthInAtlas, heightInAtlas, locationInAtlas)) {
36 return false;
37 }
38
39 SkMatrix pathToAtlasMatrix = viewMatrix;
40 if (transposedInAtlas) {
41 std::swap(pathToAtlasMatrix[0], pathToAtlasMatrix[3]);
42 std::swap(pathToAtlasMatrix[1], pathToAtlasMatrix[4]);
43 float tx=pathToAtlasMatrix.getTranslateX(), ty=pathToAtlasMatrix.getTranslateY();
44 pathToAtlasMatrix.setTranslateX(ty - pathDevTopLeft.y() + locationInAtlas->x());
45 pathToAtlasMatrix.setTranslateY(tx - pathDevTopLeft.x() + locationInAtlas->y());
46 } else {
47 pathToAtlasMatrix.postTranslate(locationInAtlas->x() - pathDevTopLeft.x(),
48 locationInAtlas->y() - pathDevTopLeft.y());
49 }
50
Chris Dalton8a1bbaa2021-07-28 14:43:07 -060051 if (GrFillRuleForSkPath(path) == GrFillRule::kNonzero) {
52 fWindingPathList.add(&fPathDrawAllocator, pathToAtlasMatrix, path);
53 } else {
54 fEvenOddPathList.add(&fPathDrawAllocator, pathToAtlasMatrix, path);
55 }
Chris Dalton83420eb2021-06-23 18:47:09 -060056 return true;
57}
58
59GrRenderTask::ExpectedOutcome GrAtlasRenderTask::onMakeClosed(GrRecordingContext* rContext,
60 SkIRect* targetUpdateBounds) {
61 // We don't add our ops until now, at which point we know the atlas is done being built.
62 SkASSERT(this->isEmpty());
63 SkASSERT(!fDynamicAtlas->isInstantiated()); // Instantiation happens after makeClosed().
64
65 const GrCaps& caps = *rContext->priv().caps();
66
67 // Set our dimensions now. GrOpsTask will need them when we add our ops.
68 this->target(0)->priv().setLazyDimensions(fDynamicAtlas->drawBounds());
69 this->target(0)->asRenderTargetProxy()->setNeedsStencil();
70 SkRect drawRect = target(0)->getBoundsRect();
71
72 // Clear the atlas.
73 if (caps.performColorClearsAsDraws() || caps.performStencilClearsAsDraws()) {
74 this->setColorLoadOp(GrLoadOp::kDiscard);
75 this->setInitialStencilContent(GrOpsTask::StencilContent::kDontCare);
76
77 constexpr static GrUserStencilSettings kClearStencil(
78 GrUserStencilSettings::StaticInit<
79 0x0000,
80 GrUserStencilTest::kAlways,
81 0xffff,
82 GrUserStencilOp::kReplace,
83 GrUserStencilOp::kReplace,
84 0xffff>());
85
86 this->stencilAtlasRect(rContext, drawRect, SK_PMColor4fTRANSPARENT, &kClearStencil);
87 } else {
88 this->setColorLoadOp(GrLoadOp::kClear);
89 this->setInitialStencilContent(GrOpsTask::StencilContent::kUserBitsCleared);
90 }
91
92 // Add ops to stencil the atlas paths.
Chris Dalton8a1bbaa2021-07-28 14:43:07 -060093 for (const auto* pathList : {&fWindingPathList, &fEvenOddPathList}) {
94 if (pathList->pathCount() > 0) {
95 auto op = GrOp::Make<GrPathStencilCoverOp>(
96 rContext,
97 pathList->pathDrawList(),
98 pathList->totalCombinedPathVerbCnt(),
99 pathList->pathCount(),
100 GrPaint(),
101 GrAAType::kMSAA,
Robert Phillips832f3fb2021-08-18 13:05:15 -0400102 GrTessellationPathFlags::kStencilOnly,
Chris Dalton8a1bbaa2021-07-28 14:43:07 -0600103 drawRect);
104 this->addAtlasDrawOp(std::move(op), caps);
Chris Dalton83420eb2021-06-23 18:47:09 -0600105 }
106 }
107
108 // Finally, draw a fullscreen rect to cover our stencilled paths.
109 const GrUserStencilSettings* stencil;
110 if (caps.discardStencilValuesAfterRenderPass()) {
111 constexpr static GrUserStencilSettings kTestStencil(
112 GrUserStencilSettings::StaticInit<
113 0x0000,
114 GrUserStencilTest::kNotEqual,
115 0xffff,
116 GrUserStencilOp::kKeep,
117 GrUserStencilOp::kKeep,
118 0xffff>());
119
120 // This is the final op in the task. Since Ganesh is planning to discard the stencil values
121 // anyway, there is no need to reset the stencil values back to 0.
122 stencil = &kTestStencil;
123 } else {
124 constexpr static GrUserStencilSettings kTestAndResetStencil(
125 GrUserStencilSettings::StaticInit<
126 0x0000,
127 GrUserStencilTest::kNotEqual,
128 0xffff,
129 GrUserStencilOp::kZero,
130 GrUserStencilOp::kKeep,
131 0xffff>());
132
133 // Outset the cover rect to make extra sure we clear every stencil value touched by the
134 // atlas.
135 drawRect.outset(1, 1);
136 stencil = &kTestAndResetStencil;
137 }
138 this->stencilAtlasRect(rContext, drawRect, SK_PMColor4fWHITE, stencil);
139
140 this->GrOpsTask::onMakeClosed(rContext, targetUpdateBounds);
141
142 // Don't mark msaa dirty. Since this op defers being closed, the drawing manager's dirty
143 // tracking doesn't work anyway. We will just resolve msaa manually during onExecute.
144 return ExpectedOutcome::kTargetUnchanged;
145}
146
147void GrAtlasRenderTask::stencilAtlasRect(GrRecordingContext* rContext, const SkRect& rect,
148 const SkPMColor4f& color,
149 const GrUserStencilSettings* stencil) {
150 GrPaint paint;
151 paint.setColor4f(color);
152 paint.setXPFactory(SkBlendMode_AsXPFactory(SkBlendMode::kSrc));
153 GrQuad quad(rect);
154 DrawQuad drawQuad{quad, quad, GrQuadAAFlags::kAll};
155 auto op = GrFillRectOp::Make(rContext, std::move(paint), GrAAType::kMSAA, &drawQuad, stencil);
Chris Dalton5e332c82021-07-21 16:04:47 -0600156 this->addAtlasDrawOp(std::move(op), *rContext->priv().caps());
Chris Dalton83420eb2021-06-23 18:47:09 -0600157}
158
Chris Dalton5e332c82021-07-21 16:04:47 -0600159void GrAtlasRenderTask::addAtlasDrawOp(GrOp::Owner op, const GrCaps& caps) {
Chris Dalton83420eb2021-06-23 18:47:09 -0600160 SkASSERT(!this->isClosed());
161
162 auto drawOp = static_cast<GrDrawOp*>(op.get());
163 SkDEBUGCODE(drawOp->fAddDrawOpCalled = true;)
164
165 auto processorAnalysis = drawOp->finalize(caps, nullptr,
166 GrColorTypeClampType(fDynamicAtlas->colorType()));
167 SkASSERT(!processorAnalysis.requiresDstTexture());
168 SkASSERT(!processorAnalysis.usesNonCoherentHWBlending());
169
170 drawOp->setClippedBounds(drawOp->bounds());
Chris Dalton5e332c82021-07-21 16:04:47 -0600171 this->recordOp(std::move(op), true/*usesMSAA*/, processorAnalysis, nullptr, nullptr, caps);
Chris Dalton83420eb2021-06-23 18:47:09 -0600172}
173
174bool GrAtlasRenderTask::onExecute(GrOpFlushState* flushState) {
175 if (!this->GrOpsTask::onExecute(flushState)) {
176 return false;
177 }
178 if (this->target(0)->requiresManualMSAAResolve()) {
179 // Since atlases don't get closed until they are done being built, the drawingManager
180 // doesn't detect that they need an MSAA resolve. Do it here manually.
181 auto nativeRect = GrNativeRect::MakeIRectRelativeTo(
182 GrDynamicAtlas::kTextureOrigin,
183 this->target(0)->backingStoreDimensions().height(),
184 SkIRect::MakeSize(fDynamicAtlas->drawBounds()));
185 flushState->gpu()->resolveRenderTarget(this->target(0)->peekRenderTarget(), nativeRect);
186 }
187 return true;
188}