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