blob: 364f58e32e57b2899fdcbd40633c8295b4a0116c [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
8#ifndef GrMemoryPool_DEFINED
9#define GrMemoryPool_DEFINED
10
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/gpu/GrTypes.h"
Robert Phillips7c525e62018-06-12 10:11:12 -040012
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkRefCnt.h"
Robert Phillips7c525e62018-06-12 10:11:12 -040014
Brian Salomona5002c32017-03-28 16:51:02 -040015#ifdef SK_DEBUG
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/private/SkTHash.h"
Brian Salomona5002c32017-03-28 16:51:02 -040017#endif
bsalomon@google.com4da34e32012-06-19 15:40:27 +000018
19/**
20 * Allocates memory in blocks and parcels out space in the blocks for allocation
21 * requests. It is optimized for allocate / release speed over memory
dskibae4cd0062016-11-29 06:50:35 -080022 * efficiency. The interface is designed to be used to implement operator new
bsalomon@google.com4da34e32012-06-19 15:40:27 +000023 * and delete overrides. All allocations are expected to be released before the
Brian Salomon6986c652019-12-12 10:58:47 -050024 * pool's destructor is called. Allocations will be aligned to
25 * sizeof(std::max_align_t).
bsalomon@google.com4da34e32012-06-19 15:40:27 +000026 */
27class GrMemoryPool {
28public:
Brian Salomon6986c652019-12-12 10:58:47 -050029 // Guaranteed alignment of pointer returned by allocate().
30 static constexpr size_t kAlignment = alignof(std::max_align_t);
31 // Minimum size this class will allocate at once.
32 static constexpr size_t kMinAllocationSize = 1 << 10;
33
bsalomon@google.com4da34e32012-06-19 15:40:27 +000034 /**
dskibae4cd0062016-11-29 06:50:35 -080035 * Prealloc size is the amount of space to allocate at pool creation
36 * time and keep around until pool destruction. The min alloc size is
37 * the smallest allowed size of additional allocations. Both sizes are
Brian Salomon6986c652019-12-12 10:58:47 -050038 * adjusted to ensure that they are at least as large as kMinAllocationSize.
dskibae4cd0062016-11-29 06:50:35 -080039 *
Brian Salomon6986c652019-12-12 10:58:47 -050040 * Both sizes are what the pool will end up allocating from the system, and
dskibae4cd0062016-11-29 06:50:35 -080041 * portions of the allocated memory is used for internal bookkeeping.
bsalomon@google.com4da34e32012-06-19 15:40:27 +000042 */
Brian Salomon6986c652019-12-12 10:58:47 -050043 static std::unique_ptr<GrMemoryPool> Make(size_t preallocSize, size_t minAllocSize);
44 void operator delete(void* p) { ::operator delete(p); }
bsalomon@google.com4da34e32012-06-19 15:40:27 +000045
46 ~GrMemoryPool();
47
48 /**
49 * Allocates memory. The memory must be freed with release().
50 */
51 void* allocate(size_t size);
52
53 /**
54 * p must have been returned by allocate()
55 */
56 void release(void* p);
57
58 /**
59 * Returns true if there are no unreleased allocations.
60 */
61 bool isEmpty() const { return fTail == fHead && !fHead->fLiveCount; }
62
joshualittb7133be2015-04-08 09:08:31 -070063 /**
joshualitt22c6f5c2016-01-05 08:07:18 -080064 * Returns the total allocated size of the GrMemoryPool minus any preallocated amount
joshualittb7133be2015-04-08 09:08:31 -070065 */
66 size_t size() const { return fSize; }
67
dskibae4cd0062016-11-29 06:50:35 -080068 /**
69 * Returns the preallocated size of the GrMemoryPool
70 */
71 size_t preallocSize() const { return fHead->fSize; }
72
dskibae4cd0062016-11-29 06:50:35 -080073
bsalomon@google.com4da34e32012-06-19 15:40:27 +000074private:
Brian Salomon6986c652019-12-12 10:58:47 -050075 GrMemoryPool(void* preallocStart, size_t preallocSize, size_t minAllocSize);
76
bsalomon@google.com4da34e32012-06-19 15:40:27 +000077 struct BlockHeader;
78
commit-bot@chromium.org8743b8f2013-08-01 14:23:33 +000079 static BlockHeader* CreateBlock(size_t size);
Brian Salomon6986c652019-12-12 10:58:47 -050080 static BlockHeader* InitBlock(void* mem, size_t blockSize);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000081
commit-bot@chromium.org8743b8f2013-08-01 14:23:33 +000082 static void DeleteBlock(BlockHeader* block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000083
84 void validate();
85
86 struct BlockHeader {
robertphillipsb7f4b8e2016-01-07 10:12:16 -080087#ifdef SK_DEBUG
88 uint32_t fBlockSentinal; ///< known value to check for bad back pointers to blocks
89#endif
tomhudson@google.comdcba4c22012-07-24 21:36:16 +000090 BlockHeader* fNext; ///< doubly-linked list of blocks.
bsalomon@google.com4da34e32012-06-19 15:40:27 +000091 BlockHeader* fPrev;
tomhudson@google.comdcba4c22012-07-24 21:36:16 +000092 int fLiveCount; ///< number of outstanding allocations in the
93 ///< block.
94 intptr_t fCurrPtr; ///< ptr to the start of blocks free space.
95 intptr_t fPrevPtr; ///< ptr to the last allocation made
96 size_t fFreeSize; ///< amount of free space left in the block.
joshualittb7133be2015-04-08 09:08:31 -070097 size_t fSize; ///< total allocated size of the block
bsalomon@google.com4da34e32012-06-19 15:40:27 +000098 };
99
robertphillips19c62502016-01-06 07:04:46 -0800100 static const uint32_t kAssignedMarker = 0xCDCDCDCD;
101 static const uint32_t kFreedMarker = 0xEFEFEFEF;
102
103 struct AllocHeader {
104#ifdef SK_DEBUG
105 uint32_t fSentinal; ///< known value to check for memory stomping (e.g., (CD)*)
Brian Salomona5002c32017-03-28 16:51:02 -0400106 int32_t fID; ///< ID that can be used to track down leaks by clients.
robertphillips19c62502016-01-06 07:04:46 -0800107#endif
108 BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides
109 };
110
joshualittb7133be2015-04-08 09:08:31 -0700111 size_t fSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000112 size_t fMinAllocSize;
113 BlockHeader* fHead;
114 BlockHeader* fTail;
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000115#ifdef SK_DEBUG
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000116 int fAllocationCnt;
joshualittb7133be2015-04-08 09:08:31 -0700117 int fAllocBlockCnt;
Brian Salomona5002c32017-03-28 16:51:02 -0400118 SkTHashSet<int32_t> fAllocatedIDs;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000119#endif
dskibae4cd0062016-11-29 06:50:35 -0800120
Brian Salomon6986c652019-12-12 10:58:47 -0500121 friend class GrOpMemoryPool;
122
123 static constexpr size_t kHeaderSize = GrSizeAlignUp(sizeof(BlockHeader), kAlignment);
124 static constexpr size_t kPerAllocPad = GrSizeAlignUp(sizeof(AllocHeader), kAlignment);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000125};
126
Robert Phillips7c525e62018-06-12 10:11:12 -0400127class GrOp;
128
Michael Ludwigcb10e4d2019-12-12 13:59:20 -0500129class GrOpMemoryPool {
Robert Phillips7c525e62018-06-12 10:11:12 -0400130public:
Brian Salomon6986c652019-12-12 10:58:47 -0500131 static std::unique_ptr<GrOpMemoryPool> Make(size_t preallocSize, size_t minAllocSize);
132 void operator delete(void* p) { ::operator delete(p); }
133
134 ~GrOpMemoryPool();
Robert Phillips7c525e62018-06-12 10:11:12 -0400135
136 template <typename Op, typename... OpArgs>
137 std::unique_ptr<Op> allocate(OpArgs&&... opArgs) {
Brian Salomon6986c652019-12-12 10:58:47 -0500138 auto mem = this->pool()->allocate(sizeof(Op));
Robert Phillips7c525e62018-06-12 10:11:12 -0400139 return std::unique_ptr<Op>(new (mem) Op(std::forward<OpArgs>(opArgs)...));
140 }
141
Brian Salomon6986c652019-12-12 10:58:47 -0500142 void* allocate(size_t size) { return this->pool()->allocate(size); }
Robert Phillips7c525e62018-06-12 10:11:12 -0400143
144 void release(std::unique_ptr<GrOp> op);
145
Brian Salomon6986c652019-12-12 10:58:47 -0500146 bool isEmpty() const { return this->pool()->isEmpty(); }
Robert Phillipsc994a932018-06-19 13:09:54 -0400147
Robert Phillips7c525e62018-06-12 10:11:12 -0400148private:
Brian Salomon6986c652019-12-12 10:58:47 -0500149 GrMemoryPool* pool() const;
150
151 GrOpMemoryPool() = default;
Robert Phillips7c525e62018-06-12 10:11:12 -0400152};
153
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000154#endif