xref: /aosp_15_r20/external/skia/src/gpu/graphite/geom/BoundsManager.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef skgpu_graphite_geom_BoundsManager_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define skgpu_graphite_geom_BoundsManager_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkBlockAllocator.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTBlockList.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkVx.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawOrder.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Rect.h"
20*c8dee2aaSAndroid Build Coastguard Worker 
21*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
22*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
23*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker /**
28*c8dee2aaSAndroid Build Coastguard Worker  * BoundsManager is an acceleration structure for device-space related pixel bounds queries.
29*c8dee2aaSAndroid Build Coastguard Worker  * The BoundsManager tracks a single ordinal value per bounds: the CompressedPaintersOrder of a draw
30*c8dee2aaSAndroid Build Coastguard Worker  * The CompressedPaintersOrder enforces a specific submission order of draws to the GPU but can
31*c8dee2aaSAndroid Build Coastguard Worker  * re-arrange draws out of their original painter's order if the GREATER depth test and the draw's Z
32*c8dee2aaSAndroid Build Coastguard Worker  * value resolve out-of-order rendering.
33*c8dee2aaSAndroid Build Coastguard Worker  *
34*c8dee2aaSAndroid Build Coastguard Worker  * It supports querying the most recent draw intersecting a bounding rect (represented as a
35*c8dee2aaSAndroid Build Coastguard Worker  * CompressedPaintersOrder value), and recording a (bounds, CompressedPaintersOrder) pair.
36*c8dee2aaSAndroid Build Coastguard Worker  */
37*c8dee2aaSAndroid Build Coastguard Worker class BoundsManager {
38*c8dee2aaSAndroid Build Coastguard Worker public:
~BoundsManager()39*c8dee2aaSAndroid Build Coastguard Worker     virtual ~BoundsManager() {}
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker     virtual CompressedPaintersOrder getMostRecentDraw(const Rect& bounds) const = 0;
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker     virtual void recordDraw(const Rect& bounds, CompressedPaintersOrder order) = 0;
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker     virtual void reset() = 0;
46*c8dee2aaSAndroid Build Coastguard Worker };
47*c8dee2aaSAndroid Build Coastguard Worker 
48*c8dee2aaSAndroid Build Coastguard Worker // TODO: Select one most-effective BoundsManager implementation, make it the only option, and remove
49*c8dee2aaSAndroid Build Coastguard Worker // virtual-ness. For now, this seems useful for correctness testing by comparing against trivial
50*c8dee2aaSAndroid Build Coastguard Worker // implementations and for identifying how much "smarts" are actually worthwhile.
51*c8dee2aaSAndroid Build Coastguard Worker 
52*c8dee2aaSAndroid Build Coastguard Worker // A BoundsManager that produces exact painter's order and assumes nothing is occluded.
53*c8dee2aaSAndroid Build Coastguard Worker class NaiveBoundsManager final : public BoundsManager {
54*c8dee2aaSAndroid Build Coastguard Worker public:
~NaiveBoundsManager()55*c8dee2aaSAndroid Build Coastguard Worker     ~NaiveBoundsManager() override {}
56*c8dee2aaSAndroid Build Coastguard Worker 
getMostRecentDraw(const Rect & bounds)57*c8dee2aaSAndroid Build Coastguard Worker     CompressedPaintersOrder getMostRecentDraw(const Rect& bounds) const override {
58*c8dee2aaSAndroid Build Coastguard Worker         return fLatestDraw;
59*c8dee2aaSAndroid Build Coastguard Worker     }
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker 
recordDraw(const Rect & bounds,CompressedPaintersOrder order)62*c8dee2aaSAndroid Build Coastguard Worker     void recordDraw(const Rect& bounds, CompressedPaintersOrder order) override {
63*c8dee2aaSAndroid Build Coastguard Worker         if (fLatestDraw < order) {
64*c8dee2aaSAndroid Build Coastguard Worker             fLatestDraw = order;
65*c8dee2aaSAndroid Build Coastguard Worker         }
66*c8dee2aaSAndroid Build Coastguard Worker     }
67*c8dee2aaSAndroid Build Coastguard Worker 
reset()68*c8dee2aaSAndroid Build Coastguard Worker     void reset() override {
69*c8dee2aaSAndroid Build Coastguard Worker         fLatestDraw = CompressedPaintersOrder::First();
70*c8dee2aaSAndroid Build Coastguard Worker     }
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker private:
73*c8dee2aaSAndroid Build Coastguard Worker     CompressedPaintersOrder fLatestDraw = CompressedPaintersOrder::First();
74*c8dee2aaSAndroid Build Coastguard Worker };
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker // A BoundsManager that tracks every draw and can exactly determine all queries
77*c8dee2aaSAndroid Build Coastguard Worker // using a brute force search.
78*c8dee2aaSAndroid Build Coastguard Worker class BruteForceBoundsManager : public BoundsManager {
79*c8dee2aaSAndroid Build Coastguard Worker public:
~BruteForceBoundsManager()80*c8dee2aaSAndroid Build Coastguard Worker     ~BruteForceBoundsManager() override {}
81*c8dee2aaSAndroid Build Coastguard Worker 
getMostRecentDraw(const Rect & bounds)82*c8dee2aaSAndroid Build Coastguard Worker     CompressedPaintersOrder getMostRecentDraw(const Rect& bounds) const override {
83*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fRects.count() == fOrders.count());
84*c8dee2aaSAndroid Build Coastguard Worker 
85*c8dee2aaSAndroid Build Coastguard Worker         Rect::ComplementRect boundsComplement(bounds);
86*c8dee2aaSAndroid Build Coastguard Worker         CompressedPaintersOrder max = CompressedPaintersOrder::First();
87*c8dee2aaSAndroid Build Coastguard Worker         auto orderIter = fOrders.items().begin();
88*c8dee2aaSAndroid Build Coastguard Worker         for (const Rect& r : fRects.items()) {
89*c8dee2aaSAndroid Build Coastguard Worker             if (r.intersects(boundsComplement) && max < *orderIter) {
90*c8dee2aaSAndroid Build Coastguard Worker                 max = *orderIter;
91*c8dee2aaSAndroid Build Coastguard Worker             }
92*c8dee2aaSAndroid Build Coastguard Worker             ++orderIter;
93*c8dee2aaSAndroid Build Coastguard Worker         }
94*c8dee2aaSAndroid Build Coastguard Worker         return max;
95*c8dee2aaSAndroid Build Coastguard Worker     }
96*c8dee2aaSAndroid Build Coastguard Worker 
recordDraw(const Rect & bounds,CompressedPaintersOrder order)97*c8dee2aaSAndroid Build Coastguard Worker     void recordDraw(const Rect& bounds, CompressedPaintersOrder order) override {
98*c8dee2aaSAndroid Build Coastguard Worker         fRects.push_back(bounds);
99*c8dee2aaSAndroid Build Coastguard Worker         fOrders.push_back(order);
100*c8dee2aaSAndroid Build Coastguard Worker     }
101*c8dee2aaSAndroid Build Coastguard Worker 
reset()102*c8dee2aaSAndroid Build Coastguard Worker     void reset() override {
103*c8dee2aaSAndroid Build Coastguard Worker         fRects.reset();
104*c8dee2aaSAndroid Build Coastguard Worker         fOrders.reset();
105*c8dee2aaSAndroid Build Coastguard Worker     }
106*c8dee2aaSAndroid Build Coastguard Worker 
count()107*c8dee2aaSAndroid Build Coastguard Worker     int count() const { return fRects.count(); }
108*c8dee2aaSAndroid Build Coastguard Worker 
replayDraws(BoundsManager * manager)109*c8dee2aaSAndroid Build Coastguard Worker     void replayDraws(BoundsManager* manager) const {
110*c8dee2aaSAndroid Build Coastguard Worker         auto orderIter = fOrders.items().begin();
111*c8dee2aaSAndroid Build Coastguard Worker         for (const Rect& r : fRects.items()) {
112*c8dee2aaSAndroid Build Coastguard Worker             manager->recordDraw(r, *orderIter);
113*c8dee2aaSAndroid Build Coastguard Worker             ++orderIter;
114*c8dee2aaSAndroid Build Coastguard Worker         }
115*c8dee2aaSAndroid Build Coastguard Worker     }
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker private:
118*c8dee2aaSAndroid Build Coastguard Worker     // fRects and fOrders are parallel, but kept separate to avoid wasting padding since Rect is
119*c8dee2aaSAndroid Build Coastguard Worker     // an over-aligned type.
120*c8dee2aaSAndroid Build Coastguard Worker     SkTBlockList<Rect, 16> fRects{SkBlockAllocator::GrowthPolicy::kFibonacci};
121*c8dee2aaSAndroid Build Coastguard Worker     SkTBlockList<CompressedPaintersOrder, 16> fOrders{SkBlockAllocator::GrowthPolicy::kFibonacci};
122*c8dee2aaSAndroid Build Coastguard Worker };
123*c8dee2aaSAndroid Build Coastguard Worker 
124*c8dee2aaSAndroid Build Coastguard Worker // A BoundsManager that tracks highest CompressedPaintersOrder over a uniform spatial grid.
125*c8dee2aaSAndroid Build Coastguard Worker class GridBoundsManager : public BoundsManager {
126*c8dee2aaSAndroid Build Coastguard Worker public:
127*c8dee2aaSAndroid Build Coastguard Worker     // 'gridSize' is the number of cells in the X and Y directions, splitting the pixels from [0,0]
128*c8dee2aaSAndroid Build Coastguard Worker     // to 'deviceSize' into uniformly-sized cells.
Make(const SkISize & deviceSize,const SkISize & gridSize)129*c8dee2aaSAndroid Build Coastguard Worker     static std::unique_ptr<GridBoundsManager> Make(const SkISize& deviceSize,
130*c8dee2aaSAndroid Build Coastguard Worker                                                    const SkISize& gridSize) {
131*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(deviceSize.width() > 0 && deviceSize.height() > 0);
132*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(gridSize.width() >= 1 && gridSize.height() >= 1);
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker         return std::unique_ptr<GridBoundsManager>(new GridBoundsManager(deviceSize, gridSize));
135*c8dee2aaSAndroid Build Coastguard Worker     }
136*c8dee2aaSAndroid Build Coastguard Worker 
Make(const SkISize & deviceSize,int gridSize)137*c8dee2aaSAndroid Build Coastguard Worker     static std::unique_ptr<GridBoundsManager> Make(const SkISize& deviceSize, int gridSize) {
138*c8dee2aaSAndroid Build Coastguard Worker         return Make(deviceSize, {gridSize, gridSize});
139*c8dee2aaSAndroid Build Coastguard Worker     }
140*c8dee2aaSAndroid Build Coastguard Worker 
141*c8dee2aaSAndroid Build Coastguard Worker     static std::unique_ptr<GridBoundsManager> MakeRes(SkISize deviceSize,
142*c8dee2aaSAndroid Build Coastguard Worker                                                       int gridCellSize,
143*c8dee2aaSAndroid Build Coastguard Worker                                                       int maxGridSize=0) {
144*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(deviceSize.width() > 0 && deviceSize.height() > 0);
145*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(gridCellSize >= 1);
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker         int gridWidth = SkScalarCeilToInt(deviceSize.width() / (float) gridCellSize);
148*c8dee2aaSAndroid Build Coastguard Worker         if (maxGridSize > 0 && gridWidth > maxGridSize) {
149*c8dee2aaSAndroid Build Coastguard Worker             // We'd have too many sizes so clamp the grid resolution, leave the device size alone
150*c8dee2aaSAndroid Build Coastguard Worker             // since the grid cell size can't be preserved anyways.
151*c8dee2aaSAndroid Build Coastguard Worker             gridWidth = maxGridSize;
152*c8dee2aaSAndroid Build Coastguard Worker         } else {
153*c8dee2aaSAndroid Build Coastguard Worker              // Pad out the device size to keep cell size the same
154*c8dee2aaSAndroid Build Coastguard Worker             deviceSize.fWidth = gridWidth * gridCellSize;
155*c8dee2aaSAndroid Build Coastguard Worker         }
156*c8dee2aaSAndroid Build Coastguard Worker 
157*c8dee2aaSAndroid Build Coastguard Worker         int gridHeight = SkScalarCeilToInt(deviceSize.height() / (float) gridCellSize);
158*c8dee2aaSAndroid Build Coastguard Worker         if (maxGridSize > 0 && gridHeight > maxGridSize) {
159*c8dee2aaSAndroid Build Coastguard Worker             gridHeight = maxGridSize;
160*c8dee2aaSAndroid Build Coastguard Worker         } else {
161*c8dee2aaSAndroid Build Coastguard Worker             deviceSize.fHeight = gridHeight * gridCellSize;
162*c8dee2aaSAndroid Build Coastguard Worker         }
163*c8dee2aaSAndroid Build Coastguard Worker         return Make(deviceSize, {gridWidth, gridHeight});
164*c8dee2aaSAndroid Build Coastguard Worker     }
165*c8dee2aaSAndroid Build Coastguard Worker 
~GridBoundsManager()166*c8dee2aaSAndroid Build Coastguard Worker     ~GridBoundsManager() override {}
167*c8dee2aaSAndroid Build Coastguard Worker 
168*c8dee2aaSAndroid Build Coastguard Worker 
getMostRecentDraw(const Rect & bounds)169*c8dee2aaSAndroid Build Coastguard Worker     CompressedPaintersOrder getMostRecentDraw(const Rect& bounds) const override {
170*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!bounds.isEmptyNegativeOrNaN());
171*c8dee2aaSAndroid Build Coastguard Worker 
172*c8dee2aaSAndroid Build Coastguard Worker         auto ltrb = this->getGridCoords(bounds);
173*c8dee2aaSAndroid Build Coastguard Worker         const CompressedPaintersOrder* p = fNodes.data() + ltrb[1] * fGridWidth + ltrb[0];
174*c8dee2aaSAndroid Build Coastguard Worker         int h = ltrb[3] - ltrb[1];
175*c8dee2aaSAndroid Build Coastguard Worker         int w = ltrb[2] - ltrb[0];
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker         CompressedPaintersOrder max = CompressedPaintersOrder::First();
178*c8dee2aaSAndroid Build Coastguard Worker         for (int y = 0; y <= h; ++y ) {
179*c8dee2aaSAndroid Build Coastguard Worker             for (int x = 0; x <= w; ++x) {
180*c8dee2aaSAndroid Build Coastguard Worker                 CompressedPaintersOrder v = *(p + x);
181*c8dee2aaSAndroid Build Coastguard Worker                 if (v > max) {
182*c8dee2aaSAndroid Build Coastguard Worker                     max = v;
183*c8dee2aaSAndroid Build Coastguard Worker                 }
184*c8dee2aaSAndroid Build Coastguard Worker             }
185*c8dee2aaSAndroid Build Coastguard Worker             p = p + fGridWidth;
186*c8dee2aaSAndroid Build Coastguard Worker         }
187*c8dee2aaSAndroid Build Coastguard Worker 
188*c8dee2aaSAndroid Build Coastguard Worker         return max;
189*c8dee2aaSAndroid Build Coastguard Worker     }
190*c8dee2aaSAndroid Build Coastguard Worker 
recordDraw(const Rect & bounds,CompressedPaintersOrder order)191*c8dee2aaSAndroid Build Coastguard Worker     void recordDraw(const Rect& bounds, CompressedPaintersOrder order) override {
192*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!bounds.isEmptyNegativeOrNaN());
193*c8dee2aaSAndroid Build Coastguard Worker 
194*c8dee2aaSAndroid Build Coastguard Worker         auto ltrb = this->getGridCoords(bounds);
195*c8dee2aaSAndroid Build Coastguard Worker         CompressedPaintersOrder* p = fNodes.data() + ltrb[1] * fGridWidth + ltrb[0];
196*c8dee2aaSAndroid Build Coastguard Worker         int h = ltrb[3] - ltrb[1];
197*c8dee2aaSAndroid Build Coastguard Worker         int w = ltrb[2] - ltrb[0];
198*c8dee2aaSAndroid Build Coastguard Worker 
199*c8dee2aaSAndroid Build Coastguard Worker         for (int y = 0; y <= h; ++y) {
200*c8dee2aaSAndroid Build Coastguard Worker             for (int x = 0; x <= w; ++x) {
201*c8dee2aaSAndroid Build Coastguard Worker                 CompressedPaintersOrder v = *(p + x);
202*c8dee2aaSAndroid Build Coastguard Worker                 if (order > v) {
203*c8dee2aaSAndroid Build Coastguard Worker                     *(p + x) = order;
204*c8dee2aaSAndroid Build Coastguard Worker                 }
205*c8dee2aaSAndroid Build Coastguard Worker             }
206*c8dee2aaSAndroid Build Coastguard Worker             p = p + fGridWidth;
207*c8dee2aaSAndroid Build Coastguard Worker         }
208*c8dee2aaSAndroid Build Coastguard Worker     }
209*c8dee2aaSAndroid Build Coastguard Worker 
reset()210*c8dee2aaSAndroid Build Coastguard Worker     void reset() override {
211*c8dee2aaSAndroid Build Coastguard Worker         memset(fNodes.data(), 0, sizeof(CompressedPaintersOrder) * fGridWidth * fGridHeight);
212*c8dee2aaSAndroid Build Coastguard Worker     }
213*c8dee2aaSAndroid Build Coastguard Worker 
214*c8dee2aaSAndroid Build Coastguard Worker private:
GridBoundsManager(const SkISize & deviceSize,const SkISize & gridSize)215*c8dee2aaSAndroid Build Coastguard Worker     GridBoundsManager(const SkISize& deviceSize, const SkISize& gridSize)
216*c8dee2aaSAndroid Build Coastguard Worker             : fScaleX(gridSize.width() / (float) deviceSize.width())
217*c8dee2aaSAndroid Build Coastguard Worker             , fScaleY(gridSize.height() / (float) deviceSize.height())
218*c8dee2aaSAndroid Build Coastguard Worker             , fGridWidth(gridSize.width())
219*c8dee2aaSAndroid Build Coastguard Worker             , fGridHeight(gridSize.height())
220*c8dee2aaSAndroid Build Coastguard Worker             , fNodes((size_t) fGridWidth * fGridHeight) {
221*c8dee2aaSAndroid Build Coastguard Worker         // Reset is needed to zero-out the uninitialized fNodes values.
222*c8dee2aaSAndroid Build Coastguard Worker         this->reset();
223*c8dee2aaSAndroid Build Coastguard Worker     }
224*c8dee2aaSAndroid Build Coastguard Worker 
getGridCoords(const Rect & bounds)225*c8dee2aaSAndroid Build Coastguard Worker     skvx::int4 getGridCoords(const Rect& bounds) const {
226*c8dee2aaSAndroid Build Coastguard Worker         // Normalize bounds by 1/wh of device bounds, then scale up to number of cells per side.
227*c8dee2aaSAndroid Build Coastguard Worker         // fScaleXY includes both 1/wh and the grid dimension scaling, then clamp to [0, gridDim-1].
228*c8dee2aaSAndroid Build Coastguard Worker         return pin(skvx::cast<int32_t>(bounds.ltrb() * skvx::float2(fScaleX, fScaleY).xyxy()),
229*c8dee2aaSAndroid Build Coastguard Worker                    skvx::int4(0),
230*c8dee2aaSAndroid Build Coastguard Worker                    skvx::int2(fGridWidth, fGridHeight).xyxy() - 1);
231*c8dee2aaSAndroid Build Coastguard Worker     }
232*c8dee2aaSAndroid Build Coastguard Worker 
233*c8dee2aaSAndroid Build Coastguard Worker     const float fScaleX;
234*c8dee2aaSAndroid Build Coastguard Worker     const float fScaleY;
235*c8dee2aaSAndroid Build Coastguard Worker 
236*c8dee2aaSAndroid Build Coastguard Worker     const int   fGridWidth;
237*c8dee2aaSAndroid Build Coastguard Worker     const int   fGridHeight;
238*c8dee2aaSAndroid Build Coastguard Worker 
239*c8dee2aaSAndroid Build Coastguard Worker     skia_private::AutoTMalloc<CompressedPaintersOrder> fNodes;
240*c8dee2aaSAndroid Build Coastguard Worker };
241*c8dee2aaSAndroid Build Coastguard Worker 
242*c8dee2aaSAndroid Build Coastguard Worker // A BoundsManager that first relies on BruteForceBoundsManager for N draw calls, and then switches
243*c8dee2aaSAndroid Build Coastguard Worker // to the GridBoundsManager if it exceeds its limit. For low N, the brute force approach is
244*c8dee2aaSAndroid Build Coastguard Worker // surprisingly efficient, has the highest accuracy, and very low memory overhead. Once the draw
245*c8dee2aaSAndroid Build Coastguard Worker // call count is large enough, the grid's lower performance complexity outweigh its memory cost and
246*c8dee2aaSAndroid Build Coastguard Worker // reduced accuracy.
247*c8dee2aaSAndroid Build Coastguard Worker class HybridBoundsManager : public BoundsManager {
248*c8dee2aaSAndroid Build Coastguard Worker public:
249*c8dee2aaSAndroid Build Coastguard Worker     HybridBoundsManager(const SkISize& deviceSize,
250*c8dee2aaSAndroid Build Coastguard Worker                         int gridCellSize,
251*c8dee2aaSAndroid Build Coastguard Worker                         int maxBruteForceN,
252*c8dee2aaSAndroid Build Coastguard Worker                         int maxGridSize=0)
fDeviceSize(deviceSize)253*c8dee2aaSAndroid Build Coastguard Worker             : fDeviceSize(deviceSize)
254*c8dee2aaSAndroid Build Coastguard Worker             , fGridCellSize(gridCellSize)
255*c8dee2aaSAndroid Build Coastguard Worker             , fMaxBruteForceN(maxBruteForceN)
256*c8dee2aaSAndroid Build Coastguard Worker             , fMaxGridSize(maxGridSize)
257*c8dee2aaSAndroid Build Coastguard Worker             , fCurrentManager(&fBruteForceManager) {
258*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(deviceSize.width() >= 1 && deviceSize.height() >= 1 &&
259*c8dee2aaSAndroid Build Coastguard Worker                  gridCellSize >= 1 && maxBruteForceN >= 1);
260*c8dee2aaSAndroid Build Coastguard Worker     }
261*c8dee2aaSAndroid Build Coastguard Worker 
getMostRecentDraw(const Rect & bounds)262*c8dee2aaSAndroid Build Coastguard Worker     CompressedPaintersOrder getMostRecentDraw(const Rect& bounds) const override {
263*c8dee2aaSAndroid Build Coastguard Worker         return fCurrentManager->getMostRecentDraw(bounds);
264*c8dee2aaSAndroid Build Coastguard Worker     }
265*c8dee2aaSAndroid Build Coastguard Worker 
recordDraw(const Rect & bounds,CompressedPaintersOrder order)266*c8dee2aaSAndroid Build Coastguard Worker     void recordDraw(const Rect& bounds, CompressedPaintersOrder order) override {
267*c8dee2aaSAndroid Build Coastguard Worker         this->updateCurrentManagerIfNeeded();
268*c8dee2aaSAndroid Build Coastguard Worker         fCurrentManager->recordDraw(bounds, order);
269*c8dee2aaSAndroid Build Coastguard Worker     }
270*c8dee2aaSAndroid Build Coastguard Worker 
reset()271*c8dee2aaSAndroid Build Coastguard Worker     void reset() override {
272*c8dee2aaSAndroid Build Coastguard Worker         const bool usedGrid = fCurrentManager == fGridManager.get();
273*c8dee2aaSAndroid Build Coastguard Worker         if (usedGrid) {
274*c8dee2aaSAndroid Build Coastguard Worker             // Reset the grid manager so it's ready to use next frame, but don't delete it.
275*c8dee2aaSAndroid Build Coastguard Worker             fGridManager->reset();
276*c8dee2aaSAndroid Build Coastguard Worker             // Assume brute force manager was reset when we swapped to the grid originally
277*c8dee2aaSAndroid Build Coastguard Worker             fCurrentManager = &fBruteForceManager;
278*c8dee2aaSAndroid Build Coastguard Worker         } else {
279*c8dee2aaSAndroid Build Coastguard Worker             if (fGridManager) {
280*c8dee2aaSAndroid Build Coastguard Worker                 // Clean up the grid manager that was created over a frame ago without being used.
281*c8dee2aaSAndroid Build Coastguard Worker                 // This could lead to re-allocating the grid every-other frame, but it's a simple
282*c8dee2aaSAndroid Build Coastguard Worker                 // way to ensure we don't hold onto the grid in perpetuity if it's not needed.
283*c8dee2aaSAndroid Build Coastguard Worker                 fGridManager = nullptr;
284*c8dee2aaSAndroid Build Coastguard Worker             }
285*c8dee2aaSAndroid Build Coastguard Worker             fBruteForceManager.reset();
286*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fCurrentManager == &fBruteForceManager);
287*c8dee2aaSAndroid Build Coastguard Worker         }
288*c8dee2aaSAndroid Build Coastguard Worker     }
289*c8dee2aaSAndroid Build Coastguard Worker 
290*c8dee2aaSAndroid Build Coastguard Worker private:
291*c8dee2aaSAndroid Build Coastguard Worker     const SkISize fDeviceSize;
292*c8dee2aaSAndroid Build Coastguard Worker     const int     fGridCellSize;
293*c8dee2aaSAndroid Build Coastguard Worker     const int     fMaxBruteForceN;
294*c8dee2aaSAndroid Build Coastguard Worker     const int     fMaxGridSize;
295*c8dee2aaSAndroid Build Coastguard Worker 
296*c8dee2aaSAndroid Build Coastguard Worker     BoundsManager* fCurrentManager;
297*c8dee2aaSAndroid Build Coastguard Worker 
298*c8dee2aaSAndroid Build Coastguard Worker     BruteForceBoundsManager                  fBruteForceManager;
299*c8dee2aaSAndroid Build Coastguard Worker 
300*c8dee2aaSAndroid Build Coastguard Worker     // The grid manager starts out null and is created the first time we exceed fMaxBruteForceN.
301*c8dee2aaSAndroid Build Coastguard Worker     // However, even if we reset back to the brute force manager, we keep the grid around under the
302*c8dee2aaSAndroid Build Coastguard Worker     // assumption that the owning Device will have similar frame-to-frame draw counts and will need
303*c8dee2aaSAndroid Build Coastguard Worker     // to upgrade to the grid manager again.
304*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<GridBoundsManager>       fGridManager;
305*c8dee2aaSAndroid Build Coastguard Worker 
updateCurrentManagerIfNeeded()306*c8dee2aaSAndroid Build Coastguard Worker     void updateCurrentManagerIfNeeded() {
307*c8dee2aaSAndroid Build Coastguard Worker         if (fCurrentManager == fGridManager.get() ||
308*c8dee2aaSAndroid Build Coastguard Worker             fBruteForceManager.count() < fMaxBruteForceN) {
309*c8dee2aaSAndroid Build Coastguard Worker             // Already using the grid or the about-to-be-recorded draw will not cause us to exceed
310*c8dee2aaSAndroid Build Coastguard Worker             // the brute force limit, so no need to change the current manager implementation.
311*c8dee2aaSAndroid Build Coastguard Worker             return;
312*c8dee2aaSAndroid Build Coastguard Worker         }
313*c8dee2aaSAndroid Build Coastguard Worker         // Else we need to switch from the brute force manager to the grid manager
314*c8dee2aaSAndroid Build Coastguard Worker         if (!fGridManager) {
315*c8dee2aaSAndroid Build Coastguard Worker             fGridManager = GridBoundsManager::MakeRes(fDeviceSize, fGridCellSize, fMaxGridSize);
316*c8dee2aaSAndroid Build Coastguard Worker         }
317*c8dee2aaSAndroid Build Coastguard Worker         fCurrentManager = fGridManager.get();
318*c8dee2aaSAndroid Build Coastguard Worker 
319*c8dee2aaSAndroid Build Coastguard Worker         // Fill out the grid manager with the recorded draws in the brute force manager
320*c8dee2aaSAndroid Build Coastguard Worker         fBruteForceManager.replayDraws(fCurrentManager);
321*c8dee2aaSAndroid Build Coastguard Worker         fBruteForceManager.reset();
322*c8dee2aaSAndroid Build Coastguard Worker     }
323*c8dee2aaSAndroid Build Coastguard Worker };
324*c8dee2aaSAndroid Build Coastguard Worker 
325*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
326*c8dee2aaSAndroid Build Coastguard Worker 
327*c8dee2aaSAndroid Build Coastguard Worker #endif // skgpu_graphite_geom_BoundsManager_DEFINED
328