blob: 5d9f404087c546cbd118ea1b907e1dcd6314ec76 [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"
16#include "src/gpu/tessellate/GrPathStencilCoverOp.h"
17
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
28bool GrAtlasRenderTask::addPath(const SkMatrix& viewMatrix, const SkPath& path, bool antialias,
29 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
51 // Concatenate this path onto our uber path that matches its fill and AA types.
52 SkPath* uberPath = this->getUberPath(path.getFillType(), antialias);
53 uberPath->moveTo(locationInAtlas->x(), locationInAtlas->y()); // Implicit moveTo(0,0).
54 uberPath->addPath(path, pathToAtlasMatrix);
55 return true;
56}
57
58GrRenderTask::ExpectedOutcome GrAtlasRenderTask::onMakeClosed(GrRecordingContext* rContext,
59 SkIRect* targetUpdateBounds) {
60 // We don't add our ops until now, at which point we know the atlas is done being built.
61 SkASSERT(this->isEmpty());
62 SkASSERT(!fDynamicAtlas->isInstantiated()); // Instantiation happens after makeClosed().
63
64 const GrCaps& caps = *rContext->priv().caps();
65
66 // Set our dimensions now. GrOpsTask will need them when we add our ops.
67 this->target(0)->priv().setLazyDimensions(fDynamicAtlas->drawBounds());
68 this->target(0)->asRenderTargetProxy()->setNeedsStencil();
69 SkRect drawRect = target(0)->getBoundsRect();
70
71 // Clear the atlas.
72 if (caps.performColorClearsAsDraws() || caps.performStencilClearsAsDraws()) {
73 this->setColorLoadOp(GrLoadOp::kDiscard);
74 this->setInitialStencilContent(GrOpsTask::StencilContent::kDontCare);
75
76 constexpr static GrUserStencilSettings kClearStencil(
77 GrUserStencilSettings::StaticInit<
78 0x0000,
79 GrUserStencilTest::kAlways,
80 0xffff,
81 GrUserStencilOp::kReplace,
82 GrUserStencilOp::kReplace,
83 0xffff>());
84
85 this->stencilAtlasRect(rContext, drawRect, SK_PMColor4fTRANSPARENT, &kClearStencil);
86 } else {
87 this->setColorLoadOp(GrLoadOp::kClear);
88 this->setInitialStencilContent(GrOpsTask::StencilContent::kUserBitsCleared);
89 }
90
91 // Add ops to stencil the atlas paths.
92 for (auto antialias : {false, true}) {
93 for (auto fillType : {SkPathFillType::kWinding, SkPathFillType::kEvenOdd}) {
94 SkPath* uberPath = this->getUberPath(fillType, antialias);
95 if (uberPath->isEmpty()) {
96 continue;
97 }
98 uberPath->setFillType(fillType);
99 GrAAType aaType = (antialias) ? GrAAType::kMSAA : GrAAType::kNone;
100 auto op = GrOp::Make<GrPathStencilCoverOp>(
101 rContext, SkMatrix::I(), *uberPath, GrPaint(), aaType,
102 GrTessellationPathRenderer::PathFlags::kStencilOnly, drawRect);
103 this->addAtlasDrawOp(std::move(op), antialias, caps);
104 }
105 }
106
107 // Finally, draw a fullscreen rect to cover our stencilled paths.
108 const GrUserStencilSettings* stencil;
109 if (caps.discardStencilValuesAfterRenderPass()) {
110 constexpr static GrUserStencilSettings kTestStencil(
111 GrUserStencilSettings::StaticInit<
112 0x0000,
113 GrUserStencilTest::kNotEqual,
114 0xffff,
115 GrUserStencilOp::kKeep,
116 GrUserStencilOp::kKeep,
117 0xffff>());
118
119 // This is the final op in the task. Since Ganesh is planning to discard the stencil values
120 // anyway, there is no need to reset the stencil values back to 0.
121 stencil = &kTestStencil;
122 } else {
123 constexpr static GrUserStencilSettings kTestAndResetStencil(
124 GrUserStencilSettings::StaticInit<
125 0x0000,
126 GrUserStencilTest::kNotEqual,
127 0xffff,
128 GrUserStencilOp::kZero,
129 GrUserStencilOp::kKeep,
130 0xffff>());
131
132 // Outset the cover rect to make extra sure we clear every stencil value touched by the
133 // atlas.
134 drawRect.outset(1, 1);
135 stencil = &kTestAndResetStencil;
136 }
137 this->stencilAtlasRect(rContext, drawRect, SK_PMColor4fWHITE, stencil);
138
139 this->GrOpsTask::onMakeClosed(rContext, targetUpdateBounds);
140
141 // Don't mark msaa dirty. Since this op defers being closed, the drawing manager's dirty
142 // tracking doesn't work anyway. We will just resolve msaa manually during onExecute.
143 return ExpectedOutcome::kTargetUnchanged;
144}
145
146void GrAtlasRenderTask::stencilAtlasRect(GrRecordingContext* rContext, const SkRect& rect,
147 const SkPMColor4f& color,
148 const GrUserStencilSettings* stencil) {
149 GrPaint paint;
150 paint.setColor4f(color);
151 paint.setXPFactory(SkBlendMode_AsXPFactory(SkBlendMode::kSrc));
152 GrQuad quad(rect);
153 DrawQuad drawQuad{quad, quad, GrQuadAAFlags::kAll};
154 auto op = GrFillRectOp::Make(rContext, std::move(paint), GrAAType::kMSAA, &drawQuad, stencil);
155 this->addAtlasDrawOp(std::move(op), true/*usesMSAA*/, *rContext->priv().caps());
156}
157
158void GrAtlasRenderTask::addAtlasDrawOp(GrOp::Owner op, bool usesMSAA, const GrCaps& caps) {
159 SkASSERT(!this->isClosed());
160
161 auto drawOp = static_cast<GrDrawOp*>(op.get());
162 SkDEBUGCODE(drawOp->fAddDrawOpCalled = true;)
163
164 auto processorAnalysis = drawOp->finalize(caps, nullptr,
165 GrColorTypeClampType(fDynamicAtlas->colorType()));
166 SkASSERT(!processorAnalysis.requiresDstTexture());
167 SkASSERT(!processorAnalysis.usesNonCoherentHWBlending());
168
169 drawOp->setClippedBounds(drawOp->bounds());
170 this->recordOp(std::move(op), usesMSAA, processorAnalysis, nullptr, nullptr, caps);
171}
172
173bool GrAtlasRenderTask::onExecute(GrOpFlushState* flushState) {
174 if (!this->GrOpsTask::onExecute(flushState)) {
175 return false;
176 }
177 if (this->target(0)->requiresManualMSAAResolve()) {
178 // Since atlases don't get closed until they are done being built, the drawingManager
179 // doesn't detect that they need an MSAA resolve. Do it here manually.
180 auto nativeRect = GrNativeRect::MakeIRectRelativeTo(
181 GrDynamicAtlas::kTextureOrigin,
182 this->target(0)->backingStoreDimensions().height(),
183 SkIRect::MakeSize(fDynamicAtlas->drawBounds()));
184 flushState->gpu()->resolveRenderTarget(this->target(0)->peekRenderTarget(), nativeRect);
185 }
186 return true;
187}