xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrMemoryPool.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2012 Google Inc.
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 GrMemoryPool_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define GrMemoryPool_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkBlockAllocator.h"
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
15*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
16*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
17*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits>
18*c8dee2aaSAndroid Build Coastguard Worker 
19*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTHash.h"
21*c8dee2aaSAndroid Build Coastguard Worker #endif
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker /**
24*c8dee2aaSAndroid Build Coastguard Worker  * Allocates memory in blocks and parcels out space in the blocks for allocation requests. It is
25*c8dee2aaSAndroid Build Coastguard Worker  * optimized for allocate / release speed over memory efficiency. The interface is designed to be
26*c8dee2aaSAndroid Build Coastguard Worker  * used to implement operator new and delete overrides. All allocations are expected to be released
27*c8dee2aaSAndroid Build Coastguard Worker  * before the pool's destructor is called. Allocations will be aligned to sizeof(std::max_align_t).
28*c8dee2aaSAndroid Build Coastguard Worker  *
29*c8dee2aaSAndroid Build Coastguard Worker  * All allocated objects must be released back to the memory pool before it can be destroyed.
30*c8dee2aaSAndroid Build Coastguard Worker  */
31*c8dee2aaSAndroid Build Coastguard Worker class GrMemoryPool {
32*c8dee2aaSAndroid Build Coastguard Worker public:
33*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_FORCE_8_BYTE_ALIGNMENT
34*c8dee2aaSAndroid Build Coastguard Worker     // https://github.com/emscripten-core/emscripten/issues/10072
35*c8dee2aaSAndroid Build Coastguard Worker     // Since Skia does not use "long double" (16 bytes), we should be ok to force it back to 8 bytes
36*c8dee2aaSAndroid Build Coastguard Worker     // until emscripten is fixed.
37*c8dee2aaSAndroid Build Coastguard Worker     static constexpr size_t kAlignment = 8;
38*c8dee2aaSAndroid Build Coastguard Worker #else
39*c8dee2aaSAndroid Build Coastguard Worker     // Guaranteed alignment of pointer returned by allocate().
40*c8dee2aaSAndroid Build Coastguard Worker     static constexpr size_t kAlignment = alignof(std::max_align_t);
41*c8dee2aaSAndroid Build Coastguard Worker #endif
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker     // Smallest block size allocated on the heap (not the smallest reservation via allocate()).
44*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr size_t kMinAllocationSize = 1 << 10;
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker     /**
47*c8dee2aaSAndroid Build Coastguard Worker      * Prealloc size is the amount of space to allocate at pool creation
48*c8dee2aaSAndroid Build Coastguard Worker      * time and keep around until pool destruction. The min alloc size is
49*c8dee2aaSAndroid Build Coastguard Worker      * the smallest allowed size of additional allocations. Both sizes are
50*c8dee2aaSAndroid Build Coastguard Worker      * adjusted to ensure that they are at least as large as kMinAllocationSize
51*c8dee2aaSAndroid Build Coastguard Worker      * and less than SkBlockAllocator::kMaxAllocationSize.
52*c8dee2aaSAndroid Build Coastguard Worker      *
53*c8dee2aaSAndroid Build Coastguard Worker      * Both sizes are what the pool will end up allocating from the system, and
54*c8dee2aaSAndroid Build Coastguard Worker      * portions of the allocated memory is used for internal bookkeeping.
55*c8dee2aaSAndroid Build Coastguard Worker      */
56*c8dee2aaSAndroid Build Coastguard Worker     static std::unique_ptr<GrMemoryPool> Make(size_t preallocSize, size_t minAllocSize);
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker     ~GrMemoryPool();
delete(void * p)59*c8dee2aaSAndroid Build Coastguard Worker     void operator delete(void* p) { ::operator delete(p); }
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker     /**
62*c8dee2aaSAndroid Build Coastguard Worker      * Allocates memory. The memory must be freed with release() before the GrMemoryPool is deleted.
63*c8dee2aaSAndroid Build Coastguard Worker      */
64*c8dee2aaSAndroid Build Coastguard Worker     void* allocate(size_t size);
65*c8dee2aaSAndroid Build Coastguard Worker     /**
66*c8dee2aaSAndroid Build Coastguard Worker      * p must have been returned by allocate().
67*c8dee2aaSAndroid Build Coastguard Worker      */
68*c8dee2aaSAndroid Build Coastguard Worker     void release(void* p);
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker     /**
71*c8dee2aaSAndroid Build Coastguard Worker      * Returns true if there are no unreleased allocations.
72*c8dee2aaSAndroid Build Coastguard Worker      */
isEmpty()73*c8dee2aaSAndroid Build Coastguard Worker     bool isEmpty() const {
74*c8dee2aaSAndroid Build Coastguard Worker         // If size is the same as preallocSize, there aren't any heap blocks, so currentBlock()
75*c8dee2aaSAndroid Build Coastguard Worker         // is the inline head block.
76*c8dee2aaSAndroid Build Coastguard Worker         return fAllocator.currentBlock() == fAllocator.headBlock() &&
77*c8dee2aaSAndroid Build Coastguard Worker                fAllocator.currentBlock()->metadata() == 0;
78*c8dee2aaSAndroid Build Coastguard Worker     }
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker     /**
81*c8dee2aaSAndroid Build Coastguard Worker      * In debug mode, this reports the IDs of unfreed nodes via `SkDebugf`. This reporting is also
82*c8dee2aaSAndroid Build Coastguard Worker      * performed automatically whenever a GrMemoryPool is destroyed.
83*c8dee2aaSAndroid Build Coastguard Worker      * In release mode, this method is a no-op.
84*c8dee2aaSAndroid Build Coastguard Worker      */
85*c8dee2aaSAndroid Build Coastguard Worker     void reportLeaks() const;
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker     /**
88*c8dee2aaSAndroid Build Coastguard Worker      * Returns the total allocated size of the GrMemoryPool minus any preallocated amount
89*c8dee2aaSAndroid Build Coastguard Worker      */
size()90*c8dee2aaSAndroid Build Coastguard Worker     size_t size() const { return fAllocator.totalSize() - fAllocator.preallocSize(); }
91*c8dee2aaSAndroid Build Coastguard Worker 
92*c8dee2aaSAndroid Build Coastguard Worker     /**
93*c8dee2aaSAndroid Build Coastguard Worker      * Returns the preallocated size of the GrMemoryPool
94*c8dee2aaSAndroid Build Coastguard Worker      */
preallocSize()95*c8dee2aaSAndroid Build Coastguard Worker     size_t preallocSize() const {
96*c8dee2aaSAndroid Build Coastguard Worker         // Account for the debug-only fields in this count, the offset is 0 for release builds
97*c8dee2aaSAndroid Build Coastguard Worker         static_assert(std::is_standard_layout<GrMemoryPool>::value, "");
98*c8dee2aaSAndroid Build Coastguard Worker         return offsetof(GrMemoryPool, fAllocator) + fAllocator.preallocSize();
99*c8dee2aaSAndroid Build Coastguard Worker     }
100*c8dee2aaSAndroid Build Coastguard Worker 
101*c8dee2aaSAndroid Build Coastguard Worker     /**
102*c8dee2aaSAndroid Build Coastguard Worker      * Frees any scratch blocks that are no longer being used.
103*c8dee2aaSAndroid Build Coastguard Worker      */
resetScratchSpace()104*c8dee2aaSAndroid Build Coastguard Worker     void resetScratchSpace() {
105*c8dee2aaSAndroid Build Coastguard Worker         fAllocator.resetScratchSpace();
106*c8dee2aaSAndroid Build Coastguard Worker     }
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
109*c8dee2aaSAndroid Build Coastguard Worker     void validate() const;
110*c8dee2aaSAndroid Build Coastguard Worker #endif
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker private:
113*c8dee2aaSAndroid Build Coastguard Worker     // Per-allocation overhead so that GrMemoryPool can always identify the block owning each and
114*c8dee2aaSAndroid Build Coastguard Worker     // release all occupied bytes, including any resulting from alignment padding.
115*c8dee2aaSAndroid Build Coastguard Worker     struct Header {
116*c8dee2aaSAndroid Build Coastguard Worker         int fStart;
117*c8dee2aaSAndroid Build Coastguard Worker         int fEnd;
118*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
119*c8dee2aaSAndroid Build Coastguard Worker         int fID;       // ID that can be used to track down leaks by clients.
120*c8dee2aaSAndroid Build Coastguard Worker #endif
121*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG) || defined(SK_SANITIZE_ADDRESS)
122*c8dee2aaSAndroid Build Coastguard Worker         uint32_t fSentinel; // set to a known value to check for memory stomping; poisoned in ASAN mode
123*c8dee2aaSAndroid Build Coastguard Worker #endif
124*c8dee2aaSAndroid Build Coastguard Worker     };
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker     GrMemoryPool(size_t preallocSize, size_t minAllocSize);
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
129*c8dee2aaSAndroid Build Coastguard Worker     // Because this exists preallocSize wants to use offsetof, so keep GrMemoryPool standard layout
130*c8dee2aaSAndroid Build Coastguard Worker     // without depending on THashSet being standard layout. Note that std::unique_ptr may not be
131*c8dee2aaSAndroid Build Coastguard Worker     // standard layout.
132*c8dee2aaSAndroid Build Coastguard Worker     struct Debug{
133*c8dee2aaSAndroid Build Coastguard Worker         skia_private::THashSet<int> fAllocatedIDs;
134*c8dee2aaSAndroid Build Coastguard Worker         int                         fAllocationCount;
135*c8dee2aaSAndroid Build Coastguard Worker     };
136*c8dee2aaSAndroid Build Coastguard Worker     Debug* fDebug{nullptr};
137*c8dee2aaSAndroid Build Coastguard Worker #endif
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker     SkBlockAllocator fAllocator; // Must be the last field, in order to use extra allocated space
140*c8dee2aaSAndroid Build Coastguard Worker };
141*c8dee2aaSAndroid Build Coastguard Worker #endif
142