blob: 0918b83c3820193048e7fe4cc37362b601c73adb [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
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 Dalton5e332c82021-07-21 16:04:47 -060051 // Concatenate this path onto our uber path that matches its fill rule.
52 SkPath* uberPath = this->getUberPath(GrFillRuleForSkPath(path));
Chris Dalton83420eb2021-06-23 18:47:09 -060053 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.
Chris Dalton5e332c82021-07-21 16:04:47 -060092 for (auto fillRule : {GrFillRule::kNonzero, GrFillRule::kEvenOdd}) {
93 SkPath* uberPath = this->getUberPath(fillRule);
94 if (uberPath->isEmpty()) {
95 continue;
Chris Dalton83420eb2021-06-23 18:47:09 -060096 }
Chris Dalton5e332c82021-07-21 16:04:47 -060097 uberPath->setFillType(fillRule == GrFillRule::kNonzero ? SkPathFillType::kWinding
98 : SkPathFillType::kEvenOdd);
99 auto op = GrOp::Make<GrPathStencilCoverOp>(
100 rContext, SkMatrix::I(), *uberPath, GrPaint(), GrAAType::kMSAA,
101 GrTessellationPathRenderer::PathFlags::kStencilOnly, drawRect);
102 this->addAtlasDrawOp(std::move(op), caps);
Chris Dalton83420eb2021-06-23 18:47:09 -0600103 }
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);
Chris Dalton5e332c82021-07-21 16:04:47 -0600153 this->addAtlasDrawOp(std::move(op), *rContext->priv().caps());
Chris Dalton83420eb2021-06-23 18:47:09 -0600154}
155
Chris Dalton5e332c82021-07-21 16:04:47 -0600156void GrAtlasRenderTask::addAtlasDrawOp(GrOp::Owner op, const GrCaps& caps) {
Chris Dalton83420eb2021-06-23 18:47:09 -0600157 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());
Chris Dalton5e332c82021-07-21 16:04:47 -0600168 this->recordOp(std::move(op), true/*usesMSAA*/, processorAnalysis, nullptr, nullptr, caps);
Chris Dalton83420eb2021-06-23 18:47:09 -0600169}
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}