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