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