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