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