blob: 26e11b3192cd316eb764cc4aded2579582a194ce [file] [log] [blame]
bsalomon@google.com4da34e32012-06-19 15:40:27 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/GrMemoryPool.h"
Michael Ludwigcd019792020-03-17 10:14:48 -04009
Mike Klein8aa0edf2020-10-16 11:04:18 -050010#include "include/private/SkTPin.h"
John Stiles5c7e1a12020-11-04 09:59:36 -050011#include "src/core/SkASAN.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/gpu/ops/GrOp.h"
Michael Ludwigcd019792020-03-17 10:14:48 -040013
Mike Klein0ec1c572018-12-04 11:52:51 -050014#ifdef SK_DEBUG
15 #include <atomic>
16#endif
Herb Derbyd7b34a52017-03-20 11:19:23 -040017
Michael Ludwigcd019792020-03-17 10:14:48 -040018///////////////////////////////////////////////////////////////////////////////////////////////////
bsalomon@google.com4da34e32012-06-19 15:40:27 +000019
Brian Salomon6986c652019-12-12 10:58:47 -050020std::unique_ptr<GrMemoryPool> GrMemoryPool::Make(size_t preallocSize, size_t minAllocSize) {
Michael Ludwigcd019792020-03-17 10:14:48 -040021 static_assert(sizeof(GrMemoryPool) < GrMemoryPool::kMinAllocationSize);
22
23 preallocSize = SkTPin(preallocSize, kMinAllocationSize,
24 (size_t) GrBlockAllocator::kMaxAllocationSize);
25 minAllocSize = SkTPin(minAllocSize, kMinAllocationSize,
26 (size_t) GrBlockAllocator::kMaxAllocationSize);
27 void* mem = operator new(preallocSize);
28 return std::unique_ptr<GrMemoryPool>(new (mem) GrMemoryPool(preallocSize, minAllocSize));
Robert Phillips7c525e62018-06-12 10:11:12 -040029}
30
Michael Ludwigcd019792020-03-17 10:14:48 -040031GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize)
32 : fAllocator(GrBlockAllocator::GrowthPolicy::kFixed, minAllocSize,
33 preallocSize - offsetof(GrMemoryPool, fAllocator) - sizeof(GrBlockAllocator)) {
34 SkDEBUGCODE(fAllocationCount = 0;)
35}
bsalomon@google.com4da34e32012-06-19 15:40:27 +000036
37GrMemoryPool::~GrMemoryPool() {
John Stiles244ebf72020-10-28 11:08:06 -040038 this->reportLeaks();
39 SkASSERT(0 == fAllocationCount);
40 SkASSERT(this->isEmpty());
41}
42
43void GrMemoryPool::reportLeaks() const {
Brian Salomona5002c32017-03-28 16:51:02 -040044#ifdef SK_DEBUG
45 int i = 0;
46 int n = fAllocatedIDs.count();
John Stiles5d00e152020-12-22 09:01:57 -050047 for (int id : fAllocatedIDs) {
Brian Salomona5002c32017-03-28 16:51:02 -040048 if (++i == 1) {
Robert Phillips19f466d2020-02-26 10:27:07 -050049 SkDebugf("Leaked %d IDs (in no particular order): %d%s", n, id, (n == i) ? "\n" : "");
Brian Salomona5002c32017-03-28 16:51:02 -040050 } else if (i < 11) {
51 SkDebugf(", %d%s", id, (n == i ? "\n" : ""));
52 } else if (i == 11) {
53 SkDebugf(", ...\n");
John Stiles5d00e152020-12-22 09:01:57 -050054 break;
Brian Salomona5002c32017-03-28 16:51:02 -040055 }
John Stiles5d00e152020-12-22 09:01:57 -050056 }
Brian Salomona5002c32017-03-28 16:51:02 -040057#endif
Michael Ludwigcd019792020-03-17 10:14:48 -040058}
bsalomon@google.com4da34e32012-06-19 15:40:27 +000059
60void* GrMemoryPool::allocate(size_t size) {
Michael Ludwigcd019792020-03-17 10:14:48 -040061 static_assert(alignof(Header) <= kAlignment);
62 SkDEBUGCODE(this->validate();)
bsalomon@google.com4da34e32012-06-19 15:40:27 +000063
Michael Ludwigcd019792020-03-17 10:14:48 -040064 GrBlockAllocator::ByteRange alloc = fAllocator.allocate<kAlignment, sizeof(Header)>(size);
65
66 // Initialize GrMemoryPool's custom header at the start of the allocation
67 Header* header = static_cast<Header*>(alloc.fBlock->ptr(alloc.fAlignedOffset - sizeof(Header)));
68 header->fStart = alloc.fStart;
69 header->fEnd = alloc.fEnd;
70
71 // Update live count within the block
72 alloc.fBlock->setMetadata(alloc.fBlock->metadata() + 1);
73
John Stiles5c7e1a12020-11-04 09:59:36 -050074#if defined(SK_SANITIZE_ADDRESS)
75 sk_asan_poison_memory_region(&header->fSentinel, sizeof(header->fSentinel));
76#elif defined(SK_DEBUG)
Michael Ludwigcd019792020-03-17 10:14:48 -040077 header->fSentinel = GrBlockAllocator::kAssignedMarker;
John Stiles5c7e1a12020-11-04 09:59:36 -050078#endif
79
80#if defined(SK_DEBUG)
Michael Ludwigcd019792020-03-17 10:14:48 -040081 header->fID = []{
82 static std::atomic<int> nextID{1};
Adlai Holler4888cda2020-11-06 16:37:37 -050083 return nextID.fetch_add(1, std::memory_order_relaxed);
Michael Ludwigcd019792020-03-17 10:14:48 -040084 }();
85
Brian Salomona5002c32017-03-28 16:51:02 -040086 // You can set a breakpoint here when a leaked ID is allocated to see the stack frame.
Michael Ludwigcd019792020-03-17 10:14:48 -040087 fAllocatedIDs.add(header->fID);
88 fAllocationCount++;
89#endif
90
91 // User-facing pointer is after the header padding
92 return alloc.fBlock->ptr(alloc.fAlignedOffset);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000093}
94
95void GrMemoryPool::release(void* p) {
Michael Ludwigcd019792020-03-17 10:14:48 -040096 // NOTE: if we needed it, (p - block) would equal the original alignedOffset value returned by
97 // GrBlockAllocator::allocate()
98 Header* header = reinterpret_cast<Header*>(reinterpret_cast<intptr_t>(p) - sizeof(Header));
John Stiles5c7e1a12020-11-04 09:59:36 -050099
100#if defined(SK_SANITIZE_ADDRESS)
101 sk_asan_unpoison_memory_region(&header->fSentinel, sizeof(header->fSentinel));
102#elif defined(SK_DEBUG)
Michael Ludwigcd019792020-03-17 10:14:48 -0400103 SkASSERT(GrBlockAllocator::kAssignedMarker == header->fSentinel);
Michael Ludwigcd019792020-03-17 10:14:48 -0400104 header->fSentinel = GrBlockAllocator::kFreedMarker;
John Stiles5c7e1a12020-11-04 09:59:36 -0500105#endif
106
107#if defined(SK_DEBUG)
Michael Ludwigcd019792020-03-17 10:14:48 -0400108 fAllocatedIDs.remove(header->fID);
109 fAllocationCount--;
humper@google.com0e515772013-01-07 19:54:40 +0000110#endif
Michael Ludwigcd019792020-03-17 10:14:48 -0400111
John Stiles5c7e1a12020-11-04 09:59:36 -0500112 GrBlockAllocator::Block* block = fAllocator.owningBlock<kAlignment>(header, header->fStart);
Michael Ludwigcd019792020-03-17 10:14:48 -0400113 int alive = block->metadata();
114 if (alive == 1) {
115 // This was last allocation in the block, so remove it
116 fAllocator.releaseBlock(block);
117 } else {
118 // Update count and release storage of the allocation itself
119 block->setMetadata(alive - 1);
120 block->release(header->fStart, header->fEnd);
121 }
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000122}
Brian Salomon6986c652019-12-12 10:58:47 -0500123
Michael Ludwigcd019792020-03-17 10:14:48 -0400124#ifdef SK_DEBUG
125void GrMemoryPool::validate() const {
126 fAllocator.validate();
Brian Salomon6986c652019-12-12 10:58:47 -0500127
Michael Ludwigcd019792020-03-17 10:14:48 -0400128 int allocCount = 0;
129 for (const auto* b : fAllocator.blocks()) {
130 allocCount += b->metadata();
131 }
132 SkASSERT(allocCount == fAllocationCount);
133 SkASSERT(fAllocationCount == fAllocatedIDs.count());
134 SkASSERT(allocCount > 0 || this->isEmpty());
135}
136#endif