xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrMemoryPool.cpp (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 #include "src/gpu/ganesh/GrMemoryPool.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTPin.h"
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
15*c8dee2aaSAndroid Build Coastguard Worker #include <new>
16*c8dee2aaSAndroid Build Coastguard Worker 
17*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
18*c8dee2aaSAndroid Build Coastguard Worker     #include <atomic>
19*c8dee2aaSAndroid Build Coastguard Worker #endif
20*c8dee2aaSAndroid Build Coastguard Worker 
21*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
22*c8dee2aaSAndroid Build Coastguard Worker 
Make(size_t preallocSize,size_t minAllocSize)23*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrMemoryPool> GrMemoryPool::Make(size_t preallocSize, size_t minAllocSize) {
24*c8dee2aaSAndroid Build Coastguard Worker     static_assert(sizeof(GrMemoryPool) < GrMemoryPool::kMinAllocationSize);
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker     preallocSize = SkTPin(preallocSize, kMinAllocationSize,
27*c8dee2aaSAndroid Build Coastguard Worker                           (size_t) SkBlockAllocator::kMaxAllocationSize);
28*c8dee2aaSAndroid Build Coastguard Worker     minAllocSize = SkTPin(minAllocSize, kMinAllocationSize,
29*c8dee2aaSAndroid Build Coastguard Worker                           (size_t) SkBlockAllocator::kMaxAllocationSize);
30*c8dee2aaSAndroid Build Coastguard Worker     void* mem = operator new(preallocSize);
31*c8dee2aaSAndroid Build Coastguard Worker     return std::unique_ptr<GrMemoryPool>(new (mem) GrMemoryPool(preallocSize, minAllocSize));
32*c8dee2aaSAndroid Build Coastguard Worker }
33*c8dee2aaSAndroid Build Coastguard Worker 
GrMemoryPool(size_t preallocSize,size_t minAllocSize)34*c8dee2aaSAndroid Build Coastguard Worker GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize)
35*c8dee2aaSAndroid Build Coastguard Worker         : fAllocator(SkBlockAllocator::GrowthPolicy::kFixed, minAllocSize,
36*c8dee2aaSAndroid Build Coastguard Worker                      preallocSize - offsetof(GrMemoryPool, fAllocator) - sizeof(SkBlockAllocator)) {
37*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(
38*c8dee2aaSAndroid Build Coastguard Worker         fDebug = new Debug;
39*c8dee2aaSAndroid Build Coastguard Worker         fDebug->fAllocationCount = 0;
40*c8dee2aaSAndroid Build Coastguard Worker     )
41*c8dee2aaSAndroid Build Coastguard Worker }
42*c8dee2aaSAndroid Build Coastguard Worker 
~GrMemoryPool()43*c8dee2aaSAndroid Build Coastguard Worker GrMemoryPool::~GrMemoryPool() {
44*c8dee2aaSAndroid Build Coastguard Worker     this->reportLeaks();
45*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(0 == fDebug->fAllocationCount);
46*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->isEmpty());
47*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(delete fDebug;)
48*c8dee2aaSAndroid Build Coastguard Worker }
49*c8dee2aaSAndroid Build Coastguard Worker 
reportLeaks() const50*c8dee2aaSAndroid Build Coastguard Worker void GrMemoryPool::reportLeaks() const {
51*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
52*c8dee2aaSAndroid Build Coastguard Worker     int i = 0;
53*c8dee2aaSAndroid Build Coastguard Worker     int n = fDebug->fAllocatedIDs.count();
54*c8dee2aaSAndroid Build Coastguard Worker     for (int id : fDebug->fAllocatedIDs) {
55*c8dee2aaSAndroid Build Coastguard Worker         if (++i == 1) {
56*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("Leaked %d IDs (in no particular order): %d%s", n, id, (n == i) ? "\n" : "");
57*c8dee2aaSAndroid Build Coastguard Worker         } else if (i < 11) {
58*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf(", %d%s", id, (n == i ? "\n" : ""));
59*c8dee2aaSAndroid Build Coastguard Worker         } else if (i == 11) {
60*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf(", ...\n");
61*c8dee2aaSAndroid Build Coastguard Worker             break;
62*c8dee2aaSAndroid Build Coastguard Worker         }
63*c8dee2aaSAndroid Build Coastguard Worker     }
64*c8dee2aaSAndroid Build Coastguard Worker #endif
65*c8dee2aaSAndroid Build Coastguard Worker }
66*c8dee2aaSAndroid Build Coastguard Worker 
allocate(size_t size)67*c8dee2aaSAndroid Build Coastguard Worker void* GrMemoryPool::allocate(size_t size) {
68*c8dee2aaSAndroid Build Coastguard Worker     static_assert(alignof(Header) <= kAlignment);
69*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(this->validate();)
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker     SkBlockAllocator::ByteRange alloc = fAllocator.allocate<kAlignment, sizeof(Header)>(size);
72*c8dee2aaSAndroid Build Coastguard Worker 
73*c8dee2aaSAndroid Build Coastguard Worker     // Initialize GrMemoryPool's custom header at the start of the allocation
74*c8dee2aaSAndroid Build Coastguard Worker     Header* header = static_cast<Header*>(alloc.fBlock->ptr(alloc.fAlignedOffset - sizeof(Header)));
75*c8dee2aaSAndroid Build Coastguard Worker     header->fStart = alloc.fStart;
76*c8dee2aaSAndroid Build Coastguard Worker     header->fEnd = alloc.fEnd;
77*c8dee2aaSAndroid Build Coastguard Worker 
78*c8dee2aaSAndroid Build Coastguard Worker     // Update live count within the block
79*c8dee2aaSAndroid Build Coastguard Worker     alloc.fBlock->setMetadata(alloc.fBlock->metadata() + 1);
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_SANITIZE_ADDRESS)
82*c8dee2aaSAndroid Build Coastguard Worker     sk_asan_poison_memory_region(&header->fSentinel, sizeof(header->fSentinel));
83*c8dee2aaSAndroid Build Coastguard Worker #elif defined(SK_DEBUG)
84*c8dee2aaSAndroid Build Coastguard Worker     header->fSentinel = SkBlockAllocator::kAssignedMarker;
85*c8dee2aaSAndroid Build Coastguard Worker #endif
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
88*c8dee2aaSAndroid Build Coastguard Worker     header->fID = []{
89*c8dee2aaSAndroid Build Coastguard Worker         static std::atomic<int> nextID{1};
90*c8dee2aaSAndroid Build Coastguard Worker         return nextID.fetch_add(1, std::memory_order_relaxed);
91*c8dee2aaSAndroid Build Coastguard Worker     }();
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker     // You can set a breakpoint here when a leaked ID is allocated to see the stack frame.
94*c8dee2aaSAndroid Build Coastguard Worker     fDebug->fAllocatedIDs.add(header->fID);
95*c8dee2aaSAndroid Build Coastguard Worker     fDebug->fAllocationCount++;
96*c8dee2aaSAndroid Build Coastguard Worker #endif
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker     // User-facing pointer is after the header padding
99*c8dee2aaSAndroid Build Coastguard Worker     return alloc.fBlock->ptr(alloc.fAlignedOffset);
100*c8dee2aaSAndroid Build Coastguard Worker }
101*c8dee2aaSAndroid Build Coastguard Worker 
release(void * p)102*c8dee2aaSAndroid Build Coastguard Worker void GrMemoryPool::release(void* p) {
103*c8dee2aaSAndroid Build Coastguard Worker     Header* header = reinterpret_cast<Header*>(reinterpret_cast<intptr_t>(p) - sizeof(Header));
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_SANITIZE_ADDRESS)
106*c8dee2aaSAndroid Build Coastguard Worker     sk_asan_unpoison_memory_region(&header->fSentinel, sizeof(header->fSentinel));
107*c8dee2aaSAndroid Build Coastguard Worker #elif defined(SK_DEBUG)
108*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(SkBlockAllocator::kAssignedMarker == header->fSentinel);
109*c8dee2aaSAndroid Build Coastguard Worker     header->fSentinel = SkBlockAllocator::kFreedMarker;
110*c8dee2aaSAndroid Build Coastguard Worker #endif
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
113*c8dee2aaSAndroid Build Coastguard Worker     fDebug->fAllocatedIDs.remove(header->fID);
114*c8dee2aaSAndroid Build Coastguard Worker     fDebug->fAllocationCount--;
115*c8dee2aaSAndroid Build Coastguard Worker #endif
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker     SkBlockAllocator::Block* block = fAllocator.owningBlock<kAlignment>(header, header->fStart);
118*c8dee2aaSAndroid Build Coastguard Worker 
119*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
120*c8dee2aaSAndroid Build Coastguard Worker     // (p - block) matches the original alignedOffset value from SkBlockAllocator::allocate().
121*c8dee2aaSAndroid Build Coastguard Worker     intptr_t alignedOffset = (intptr_t)p - (intptr_t)block;
122*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(p == block->ptr(alignedOffset));
123*c8dee2aaSAndroid Build Coastguard Worker 
124*c8dee2aaSAndroid Build Coastguard Worker     // Scrub the block contents to prevent use-after-free errors.
125*c8dee2aaSAndroid Build Coastguard Worker     memset(p, 0xDD, header->fEnd - alignedOffset);
126*c8dee2aaSAndroid Build Coastguard Worker #endif
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker     int alive = block->metadata();
129*c8dee2aaSAndroid Build Coastguard Worker     if (alive == 1) {
130*c8dee2aaSAndroid Build Coastguard Worker         // This was last allocation in the block, so remove it
131*c8dee2aaSAndroid Build Coastguard Worker         fAllocator.releaseBlock(block);
132*c8dee2aaSAndroid Build Coastguard Worker     } else {
133*c8dee2aaSAndroid Build Coastguard Worker         // Update count and release storage of the allocation itself
134*c8dee2aaSAndroid Build Coastguard Worker         block->setMetadata(alive - 1);
135*c8dee2aaSAndroid Build Coastguard Worker         block->release(header->fStart, header->fEnd);
136*c8dee2aaSAndroid Build Coastguard Worker     }
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
validate() const140*c8dee2aaSAndroid Build Coastguard Worker void GrMemoryPool::validate() const {
141*c8dee2aaSAndroid Build Coastguard Worker     fAllocator.validate();
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker     int allocCount = 0;
144*c8dee2aaSAndroid Build Coastguard Worker     for (const auto* b : fAllocator.blocks()) {
145*c8dee2aaSAndroid Build Coastguard Worker         allocCount += b->metadata();
146*c8dee2aaSAndroid Build Coastguard Worker     }
147*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(allocCount == fDebug->fAllocationCount);
148*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fDebug->fAllocationCount == fDebug->fAllocatedIDs.count());
149*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(allocCount > 0 || this->isEmpty());
150*c8dee2aaSAndroid Build Coastguard Worker }
151*c8dee2aaSAndroid Build Coastguard Worker #endif
152