blob: e487b04d4e1b58be7a58dd12bf17d4f204f944b8 [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
Brian Salomone9943802020-01-03 13:07:07 -050011#include "include/private/GrTypesPriv.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:
Kevin Lubickf76da632020-01-28 10:39:56 -050029#ifdef SK_FORCE_8_BYTE_ALIGNMENT
30 // This is an issue for WASM builds using emscripten, which had
31 // std::max_align_t = 16, but was returning pointers only aligned to 8
32 // bytes. https://github.com/emscripten-core/emscripten/issues/10072
33 // Since Skia does not use "long double" (16 bytes), we should be ok to
34 // force it back to 8 bytes until emscripten is fixed.
35 static constexpr size_t kAlignment = 8;
36#else
Brian Salomon6986c652019-12-12 10:58:47 -050037 // Guaranteed alignment of pointer returned by allocate().
38 static constexpr size_t kAlignment = alignof(std::max_align_t);
Kevin Lubickf76da632020-01-28 10:39:56 -050039#endif
Brian Salomon6986c652019-12-12 10:58:47 -050040 // Minimum size this class will allocate at once.
41 static constexpr size_t kMinAllocationSize = 1 << 10;
42
bsalomon@google.com4da34e32012-06-19 15:40:27 +000043 /**
dskibae4cd0062016-11-29 06:50:35 -080044 * Prealloc size is the amount of space to allocate at pool creation
45 * time and keep around until pool destruction. The min alloc size is
46 * the smallest allowed size of additional allocations. Both sizes are
Brian Salomon6986c652019-12-12 10:58:47 -050047 * adjusted to ensure that they are at least as large as kMinAllocationSize.
dskibae4cd0062016-11-29 06:50:35 -080048 *
Brian Salomon6986c652019-12-12 10:58:47 -050049 * Both sizes are what the pool will end up allocating from the system, and
dskibae4cd0062016-11-29 06:50:35 -080050 * portions of the allocated memory is used for internal bookkeeping.
bsalomon@google.com4da34e32012-06-19 15:40:27 +000051 */
Brian Salomon6986c652019-12-12 10:58:47 -050052 static std::unique_ptr<GrMemoryPool> Make(size_t preallocSize, size_t minAllocSize);
53 void operator delete(void* p) { ::operator delete(p); }
bsalomon@google.com4da34e32012-06-19 15:40:27 +000054
55 ~GrMemoryPool();
56
57 /**
58 * Allocates memory. The memory must be freed with release().
59 */
60 void* allocate(size_t size);
61
62 /**
63 * p must have been returned by allocate()
64 */
65 void release(void* p);
66
67 /**
68 * Returns true if there are no unreleased allocations.
69 */
70 bool isEmpty() const { return fTail == fHead && !fHead->fLiveCount; }
71
joshualittb7133be2015-04-08 09:08:31 -070072 /**
joshualitt22c6f5c2016-01-05 08:07:18 -080073 * Returns the total allocated size of the GrMemoryPool minus any preallocated amount
joshualittb7133be2015-04-08 09:08:31 -070074 */
75 size_t size() const { return fSize; }
76
dskibae4cd0062016-11-29 06:50:35 -080077 /**
78 * Returns the preallocated size of the GrMemoryPool
79 */
80 size_t preallocSize() const { return fHead->fSize; }
81
dskibae4cd0062016-11-29 06:50:35 -080082
bsalomon@google.com4da34e32012-06-19 15:40:27 +000083private:
Brian Salomon6986c652019-12-12 10:58:47 -050084 GrMemoryPool(void* preallocStart, size_t preallocSize, size_t minAllocSize);
85
bsalomon@google.com4da34e32012-06-19 15:40:27 +000086 struct BlockHeader;
87
commit-bot@chromium.org8743b8f2013-08-01 14:23:33 +000088 static BlockHeader* CreateBlock(size_t size);
Brian Salomon6986c652019-12-12 10:58:47 -050089 static BlockHeader* InitBlock(void* mem, size_t blockSize);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000090
commit-bot@chromium.org8743b8f2013-08-01 14:23:33 +000091 static void DeleteBlock(BlockHeader* block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000092
93 void validate();
94
95 struct BlockHeader {
robertphillipsb7f4b8e2016-01-07 10:12:16 -080096#ifdef SK_DEBUG
97 uint32_t fBlockSentinal; ///< known value to check for bad back pointers to blocks
98#endif
tomhudson@google.comdcba4c22012-07-24 21:36:16 +000099 BlockHeader* fNext; ///< doubly-linked list of blocks.
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000100 BlockHeader* fPrev;
tomhudson@google.comdcba4c22012-07-24 21:36:16 +0000101 int fLiveCount; ///< number of outstanding allocations in the
102 ///< block.
103 intptr_t fCurrPtr; ///< ptr to the start of blocks free space.
104 intptr_t fPrevPtr; ///< ptr to the last allocation made
105 size_t fFreeSize; ///< amount of free space left in the block.
joshualittb7133be2015-04-08 09:08:31 -0700106 size_t fSize; ///< total allocated size of the block
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000107 };
108
robertphillips19c62502016-01-06 07:04:46 -0800109 static const uint32_t kAssignedMarker = 0xCDCDCDCD;
110 static const uint32_t kFreedMarker = 0xEFEFEFEF;
111
112 struct AllocHeader {
113#ifdef SK_DEBUG
114 uint32_t fSentinal; ///< known value to check for memory stomping (e.g., (CD)*)
Brian Salomona5002c32017-03-28 16:51:02 -0400115 int32_t fID; ///< ID that can be used to track down leaks by clients.
robertphillips19c62502016-01-06 07:04:46 -0800116#endif
117 BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides
118 };
119
joshualittb7133be2015-04-08 09:08:31 -0700120 size_t fSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000121 size_t fMinAllocSize;
122 BlockHeader* fHead;
123 BlockHeader* fTail;
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000124#ifdef SK_DEBUG
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000125 int fAllocationCnt;
joshualittb7133be2015-04-08 09:08:31 -0700126 int fAllocBlockCnt;
Brian Salomona5002c32017-03-28 16:51:02 -0400127 SkTHashSet<int32_t> fAllocatedIDs;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000128#endif
dskibae4cd0062016-11-29 06:50:35 -0800129
Brian Salomon6986c652019-12-12 10:58:47 -0500130 friend class GrOpMemoryPool;
131
Brian Salomone9943802020-01-03 13:07:07 -0500132 static constexpr size_t kHeaderSize = GrAlignTo(sizeof(BlockHeader), kAlignment);
133 static constexpr size_t kPerAllocPad = GrAlignTo(sizeof(AllocHeader), kAlignment);
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000134};
135
Robert Phillips7c525e62018-06-12 10:11:12 -0400136class GrOp;
137
Michael Ludwigcb10e4d2019-12-12 13:59:20 -0500138class GrOpMemoryPool {
Robert Phillips7c525e62018-06-12 10:11:12 -0400139public:
Brian Salomon6986c652019-12-12 10:58:47 -0500140 static std::unique_ptr<GrOpMemoryPool> Make(size_t preallocSize, size_t minAllocSize);
141 void operator delete(void* p) { ::operator delete(p); }
142
143 ~GrOpMemoryPool();
Robert Phillips7c525e62018-06-12 10:11:12 -0400144
145 template <typename Op, typename... OpArgs>
146 std::unique_ptr<Op> allocate(OpArgs&&... opArgs) {
Brian Salomon6986c652019-12-12 10:58:47 -0500147 auto mem = this->pool()->allocate(sizeof(Op));
Robert Phillips7c525e62018-06-12 10:11:12 -0400148 return std::unique_ptr<Op>(new (mem) Op(std::forward<OpArgs>(opArgs)...));
149 }
150
Brian Salomon6986c652019-12-12 10:58:47 -0500151 void* allocate(size_t size) { return this->pool()->allocate(size); }
Robert Phillips7c525e62018-06-12 10:11:12 -0400152
153 void release(std::unique_ptr<GrOp> op);
154
Brian Salomon6986c652019-12-12 10:58:47 -0500155 bool isEmpty() const { return this->pool()->isEmpty(); }
Robert Phillipsc994a932018-06-19 13:09:54 -0400156
Robert Phillips7c525e62018-06-12 10:11:12 -0400157private:
Brian Salomon6986c652019-12-12 10:58:47 -0500158 GrMemoryPool* pool() const;
159
160 GrOpMemoryPool() = default;
Robert Phillips7c525e62018-06-12 10:11:12 -0400161};
162
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000163#endif