blob: e05908e711afe70b8c87ea514f21e22d24bcbba7 [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
Robert Phillipsfdafc0c2021-08-25 16:39:14 -04008#include "src/gpu/ops/AtlasRenderTask.h"
Chris Dalton83420eb2021-06-23 18:47:09 -06009
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"
Robert Phillipsfbf02142021-09-01 16:31:34 -040015#include "src/gpu/ops/FillRectOp.h"
Robert Phillipse453fa02021-08-19 14:57:05 -040016#include "src/gpu/ops/PathStencilCoverOp.h"
Chris Dalton83420eb2021-06-23 18:47:09 -060017
Robert Phillipsfdafc0c2021-08-25 16:39:14 -040018namespace skgpu::v1 {
19
20AtlasRenderTask::AtlasRenderTask(GrRecordingContext* rContext,
21 sk_sp<GrArenas> arenas,
22 std::unique_ptr<GrDynamicAtlas> dynamicAtlas)
Robert Phillips3e87a8e2021-08-25 13:22:24 -040023 : OpsTask(rContext->priv().drawingManager(),
24 dynamicAtlas->writeView(*rContext->priv().caps()),
25 rContext->priv().auditTrail(),
26 std::move(arenas))
Chris Dalton83420eb2021-06-23 18:47:09 -060027 , fDynamicAtlas(std::move(dynamicAtlas)) {
28}
29
Robert Phillipsfdafc0c2021-08-25 16:39:14 -040030bool AtlasRenderTask::addPath(const SkMatrix& viewMatrix, const SkPath& path,
31 SkIPoint pathDevTopLeft, int widthInAtlas, int heightInAtlas,
32 bool transposedInAtlas, SkIPoint16* locationInAtlas) {
Chris Dalton83420eb2021-06-23 18:47:09 -060033 SkASSERT(!this->isClosed());
34 SkASSERT(this->isEmpty());
35 SkASSERT(!fDynamicAtlas->isInstantiated()); // Paths can't be added after instantiate().
36
37 if (!fDynamicAtlas->addRect(widthInAtlas, heightInAtlas, locationInAtlas)) {
38 return false;
39 }
40
41 SkMatrix pathToAtlasMatrix = viewMatrix;
42 if (transposedInAtlas) {
43 std::swap(pathToAtlasMatrix[0], pathToAtlasMatrix[3]);
44 std::swap(pathToAtlasMatrix[1], pathToAtlasMatrix[4]);
45 float tx=pathToAtlasMatrix.getTranslateX(), ty=pathToAtlasMatrix.getTranslateY();
46 pathToAtlasMatrix.setTranslateX(ty - pathDevTopLeft.y() + locationInAtlas->x());
47 pathToAtlasMatrix.setTranslateY(tx - pathDevTopLeft.x() + locationInAtlas->y());
48 } else {
49 pathToAtlasMatrix.postTranslate(locationInAtlas->x() - pathDevTopLeft.x(),
50 locationInAtlas->y() - pathDevTopLeft.y());
51 }
52
Chris Dalton8a1bbaa2021-07-28 14:43:07 -060053 if (GrFillRuleForSkPath(path) == GrFillRule::kNonzero) {
54 fWindingPathList.add(&fPathDrawAllocator, pathToAtlasMatrix, path);
55 } else {
56 fEvenOddPathList.add(&fPathDrawAllocator, pathToAtlasMatrix, path);
57 }
Chris Dalton83420eb2021-06-23 18:47:09 -060058 return true;
59}
60
Robert Phillipsfdafc0c2021-08-25 16:39:14 -040061GrRenderTask::ExpectedOutcome AtlasRenderTask::onMakeClosed(GrRecordingContext* rContext,
62 SkIRect* targetUpdateBounds) {
Chris Dalton83420eb2021-06-23 18:47:09 -060063 // We don't add our ops until now, at which point we know the atlas is done being built.
64 SkASSERT(this->isEmpty());
65 SkASSERT(!fDynamicAtlas->isInstantiated()); // Instantiation happens after makeClosed().
66
67 const GrCaps& caps = *rContext->priv().caps();
68
Robert Phillips3e87a8e2021-08-25 13:22:24 -040069 // Set our dimensions now. OpsTask will need them when we add our ops.
Chris Dalton83420eb2021-06-23 18:47:09 -060070 this->target(0)->priv().setLazyDimensions(fDynamicAtlas->drawBounds());
71 this->target(0)->asRenderTargetProxy()->setNeedsStencil();
72 SkRect drawRect = target(0)->getBoundsRect();
73
74 // Clear the atlas.
75 if (caps.performColorClearsAsDraws() || caps.performStencilClearsAsDraws()) {
76 this->setColorLoadOp(GrLoadOp::kDiscard);
Robert Phillips3e87a8e2021-08-25 13:22:24 -040077 this->setInitialStencilContent(StencilContent::kDontCare);
Chris Dalton83420eb2021-06-23 18:47:09 -060078
79 constexpr static GrUserStencilSettings kClearStencil(
80 GrUserStencilSettings::StaticInit<
81 0x0000,
82 GrUserStencilTest::kAlways,
83 0xffff,
84 GrUserStencilOp::kReplace,
85 GrUserStencilOp::kReplace,
86 0xffff>());
87
88 this->stencilAtlasRect(rContext, drawRect, SK_PMColor4fTRANSPARENT, &kClearStencil);
89 } else {
90 this->setColorLoadOp(GrLoadOp::kClear);
Robert Phillips3e87a8e2021-08-25 13:22:24 -040091 this->setInitialStencilContent(StencilContent::kUserBitsCleared);
Chris Dalton83420eb2021-06-23 18:47:09 -060092 }
93
94 // Add ops to stencil the atlas paths.
Chris Dalton8a1bbaa2021-07-28 14:43:07 -060095 for (const auto* pathList : {&fWindingPathList, &fEvenOddPathList}) {
96 if (pathList->pathCount() > 0) {
Robert Phillips62bd6332021-08-26 09:56:55 -040097 auto op = GrOp::Make<PathStencilCoverOp>(
Chris Dalton8a1bbaa2021-07-28 14:43:07 -060098 rContext,
99 pathList->pathDrawList(),
100 pathList->totalCombinedPathVerbCnt(),
101 pathList->pathCount(),
102 GrPaint(),
103 GrAAType::kMSAA,
Robert Phillips832f3fb2021-08-18 13:05:15 -0400104 GrTessellationPathFlags::kStencilOnly,
Chris Dalton8a1bbaa2021-07-28 14:43:07 -0600105 drawRect);
106 this->addAtlasDrawOp(std::move(op), caps);
Chris Dalton83420eb2021-06-23 18:47:09 -0600107 }
108 }
109
110 // Finally, draw a fullscreen rect to cover our stencilled paths.
111 const GrUserStencilSettings* stencil;
112 if (caps.discardStencilValuesAfterRenderPass()) {
113 constexpr static GrUserStencilSettings kTestStencil(
114 GrUserStencilSettings::StaticInit<
115 0x0000,
116 GrUserStencilTest::kNotEqual,
117 0xffff,
118 GrUserStencilOp::kKeep,
119 GrUserStencilOp::kKeep,
120 0xffff>());
121
122 // This is the final op in the task. Since Ganesh is planning to discard the stencil values
123 // anyway, there is no need to reset the stencil values back to 0.
124 stencil = &kTestStencil;
125 } else {
126 constexpr static GrUserStencilSettings kTestAndResetStencil(
127 GrUserStencilSettings::StaticInit<
128 0x0000,
129 GrUserStencilTest::kNotEqual,
130 0xffff,
131 GrUserStencilOp::kZero,
132 GrUserStencilOp::kKeep,
133 0xffff>());
134
135 // Outset the cover rect to make extra sure we clear every stencil value touched by the
136 // atlas.
137 drawRect.outset(1, 1);
138 stencil = &kTestAndResetStencil;
139 }
140 this->stencilAtlasRect(rContext, drawRect, SK_PMColor4fWHITE, stencil);
141
Robert Phillips3e87a8e2021-08-25 13:22:24 -0400142 this->OpsTask::onMakeClosed(rContext, targetUpdateBounds);
Chris Dalton83420eb2021-06-23 18:47:09 -0600143
144 // Don't mark msaa dirty. Since this op defers being closed, the drawing manager's dirty
145 // tracking doesn't work anyway. We will just resolve msaa manually during onExecute.
146 return ExpectedOutcome::kTargetUnchanged;
147}
148
Robert Phillipsfdafc0c2021-08-25 16:39:14 -0400149void AtlasRenderTask::stencilAtlasRect(GrRecordingContext* rContext, const SkRect& rect,
150 const SkPMColor4f& color,
151 const GrUserStencilSettings* stencil) {
Chris Dalton83420eb2021-06-23 18:47:09 -0600152 GrPaint paint;
153 paint.setColor4f(color);
154 paint.setXPFactory(SkBlendMode_AsXPFactory(SkBlendMode::kSrc));
155 GrQuad quad(rect);
156 DrawQuad drawQuad{quad, quad, GrQuadAAFlags::kAll};
Robert Phillipsfbf02142021-09-01 16:31:34 -0400157 auto op = FillRectOp::Make(rContext, std::move(paint), GrAAType::kMSAA, &drawQuad, stencil);
Chris Dalton5e332c82021-07-21 16:04:47 -0600158 this->addAtlasDrawOp(std::move(op), *rContext->priv().caps());
Chris Dalton83420eb2021-06-23 18:47:09 -0600159}
160
Robert Phillipsfdafc0c2021-08-25 16:39:14 -0400161void AtlasRenderTask::addAtlasDrawOp(GrOp::Owner op, const GrCaps& caps) {
Chris Dalton83420eb2021-06-23 18:47:09 -0600162 SkASSERT(!this->isClosed());
163
164 auto drawOp = static_cast<GrDrawOp*>(op.get());
165 SkDEBUGCODE(drawOp->fAddDrawOpCalled = true;)
166
167 auto processorAnalysis = drawOp->finalize(caps, nullptr,
168 GrColorTypeClampType(fDynamicAtlas->colorType()));
169 SkASSERT(!processorAnalysis.requiresDstTexture());
170 SkASSERT(!processorAnalysis.usesNonCoherentHWBlending());
171
172 drawOp->setClippedBounds(drawOp->bounds());
Chris Dalton5e332c82021-07-21 16:04:47 -0600173 this->recordOp(std::move(op), true/*usesMSAA*/, processorAnalysis, nullptr, nullptr, caps);
Chris Dalton83420eb2021-06-23 18:47:09 -0600174}
175
Robert Phillipsfdafc0c2021-08-25 16:39:14 -0400176bool AtlasRenderTask::onExecute(GrOpFlushState* flushState) {
Robert Phillips3e87a8e2021-08-25 13:22:24 -0400177 if (!this->OpsTask::onExecute(flushState)) {
Chris Dalton83420eb2021-06-23 18:47:09 -0600178 return false;
179 }
180 if (this->target(0)->requiresManualMSAAResolve()) {
181 // Since atlases don't get closed until they are done being built, the drawingManager
182 // doesn't detect that they need an MSAA resolve. Do it here manually.
183 auto nativeRect = GrNativeRect::MakeIRectRelativeTo(
184 GrDynamicAtlas::kTextureOrigin,
185 this->target(0)->backingStoreDimensions().height(),
186 SkIRect::MakeSize(fDynamicAtlas->drawBounds()));
187 flushState->gpu()->resolveRenderTarget(this->target(0)->peekRenderTarget(), nativeRect);
188 }
189 return true;
190}
Robert Phillipsfdafc0c2021-08-25 16:39:14 -0400191
192} // namespace skgpu::v1