1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#ifndef GrMemoryPool_DEFINED
9cb93a386Sopenharmony_ci#define GrMemoryPool_DEFINED
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "src/core/SkBlockAllocator.h"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_ci#ifdef SK_DEBUG
14cb93a386Sopenharmony_ci#include "include/private/SkTHash.h"
15cb93a386Sopenharmony_ci#endif
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ci/**
18cb93a386Sopenharmony_ci * Allocates memory in blocks and parcels out space in the blocks for allocation requests. It is
19cb93a386Sopenharmony_ci * optimized for allocate / release speed over memory efficiency. The interface is designed to be
20cb93a386Sopenharmony_ci * used to implement operator new and delete overrides. All allocations are expected to be released
21cb93a386Sopenharmony_ci * before the pool's destructor is called. Allocations will be aligned to sizeof(std::max_align_t).
22cb93a386Sopenharmony_ci *
23cb93a386Sopenharmony_ci * All allocated objects must be released back to the memory pool before it can be destroyed.
24cb93a386Sopenharmony_ci */
25cb93a386Sopenharmony_ciclass GrMemoryPool {
26cb93a386Sopenharmony_cipublic:
27cb93a386Sopenharmony_ci#ifdef SK_FORCE_8_BYTE_ALIGNMENT
28cb93a386Sopenharmony_ci    // https://github.com/emscripten-core/emscripten/issues/10072
29cb93a386Sopenharmony_ci    // Since Skia does not use "long double" (16 bytes), we should be ok to force it back to 8 bytes
30cb93a386Sopenharmony_ci    // until emscripten is fixed.
31cb93a386Sopenharmony_ci    inline static constexpr size_t kAlignment = 8;
32cb93a386Sopenharmony_ci#else
33cb93a386Sopenharmony_ci    // Guaranteed alignment of pointer returned by allocate().
34cb93a386Sopenharmony_ci    inline static constexpr size_t kAlignment = alignof(std::max_align_t);
35cb93a386Sopenharmony_ci#endif
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_ci    // Smallest block size allocated on the heap (not the smallest reservation via allocate()).
38cb93a386Sopenharmony_ci    inline static constexpr size_t kMinAllocationSize = 1 << 10;
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci    /**
41cb93a386Sopenharmony_ci     * Prealloc size is the amount of space to allocate at pool creation
42cb93a386Sopenharmony_ci     * time and keep around until pool destruction. The min alloc size is
43cb93a386Sopenharmony_ci     * the smallest allowed size of additional allocations. Both sizes are
44cb93a386Sopenharmony_ci     * adjusted to ensure that they are at least as large as kMinAllocationSize
45cb93a386Sopenharmony_ci     * and less than SkBlockAllocator::kMaxAllocationSize.
46cb93a386Sopenharmony_ci     *
47cb93a386Sopenharmony_ci     * Both sizes are what the pool will end up allocating from the system, and
48cb93a386Sopenharmony_ci     * portions of the allocated memory is used for internal bookkeeping.
49cb93a386Sopenharmony_ci     */
50cb93a386Sopenharmony_ci    static std::unique_ptr<GrMemoryPool> Make(size_t preallocSize, size_t minAllocSize);
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci    ~GrMemoryPool();
53cb93a386Sopenharmony_ci    void operator delete(void* p) { ::operator delete(p); }
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci    /**
56cb93a386Sopenharmony_ci     * Allocates memory. The memory must be freed with release() before the GrMemoryPool is deleted.
57cb93a386Sopenharmony_ci     */
58cb93a386Sopenharmony_ci    void* allocate(size_t size);
59cb93a386Sopenharmony_ci    /**
60cb93a386Sopenharmony_ci     * p must have been returned by allocate().
61cb93a386Sopenharmony_ci     */
62cb93a386Sopenharmony_ci    void release(void* p);
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ci    /**
65cb93a386Sopenharmony_ci     * Returns true if there are no unreleased allocations.
66cb93a386Sopenharmony_ci     */
67cb93a386Sopenharmony_ci    bool isEmpty() const {
68cb93a386Sopenharmony_ci        // If size is the same as preallocSize, there aren't any heap blocks, so currentBlock()
69cb93a386Sopenharmony_ci        // is the inline head block.
70cb93a386Sopenharmony_ci        return fAllocator.currentBlock() == fAllocator.headBlock() &&
71cb93a386Sopenharmony_ci               fAllocator.currentBlock()->metadata() == 0;
72cb93a386Sopenharmony_ci    }
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci    /**
75cb93a386Sopenharmony_ci     * In debug mode, this reports the IDs of unfreed nodes via `SkDebugf`. This reporting is also
76cb93a386Sopenharmony_ci     * performed automatically whenever a GrMemoryPool is destroyed.
77cb93a386Sopenharmony_ci     * In release mode, this method is a no-op.
78cb93a386Sopenharmony_ci     */
79cb93a386Sopenharmony_ci    void reportLeaks() const;
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ci    /**
82cb93a386Sopenharmony_ci     * Returns the total allocated size of the GrMemoryPool minus any preallocated amount
83cb93a386Sopenharmony_ci     */
84cb93a386Sopenharmony_ci    size_t size() const { return fAllocator.totalSize() - fAllocator.preallocSize(); }
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci    /**
87cb93a386Sopenharmony_ci     * Returns the preallocated size of the GrMemoryPool
88cb93a386Sopenharmony_ci     */
89cb93a386Sopenharmony_ci    size_t preallocSize() const {
90cb93a386Sopenharmony_ci        // Account for the debug-only fields in this count, the offset is 0 for release builds
91cb93a386Sopenharmony_ci        return offsetof(GrMemoryPool, fAllocator) + fAllocator.preallocSize();
92cb93a386Sopenharmony_ci    }
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci    /**
95cb93a386Sopenharmony_ci     * Frees any scratch blocks that are no longer being used.
96cb93a386Sopenharmony_ci     */
97cb93a386Sopenharmony_ci    void resetScratchSpace() {
98cb93a386Sopenharmony_ci        fAllocator.resetScratchSpace();
99cb93a386Sopenharmony_ci    }
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci#ifdef SK_DEBUG
102cb93a386Sopenharmony_ci    void validate() const;
103cb93a386Sopenharmony_ci#endif
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ciprivate:
106cb93a386Sopenharmony_ci    // Per-allocation overhead so that GrMemoryPool can always identify the block owning each and
107cb93a386Sopenharmony_ci    // release all occupied bytes, including any resulting from alignment padding.
108cb93a386Sopenharmony_ci    struct Header {
109cb93a386Sopenharmony_ci        int fStart;
110cb93a386Sopenharmony_ci        int fEnd;
111cb93a386Sopenharmony_ci#if defined(SK_DEBUG)
112cb93a386Sopenharmony_ci        int fID;       // ID that can be used to track down leaks by clients.
113cb93a386Sopenharmony_ci#endif
114cb93a386Sopenharmony_ci#if defined(SK_DEBUG) || defined(SK_SANITIZE_ADDRESS)
115cb93a386Sopenharmony_ci        int fSentinel; // set to a known value to check for memory stomping; poisoned in ASAN mode
116cb93a386Sopenharmony_ci#endif
117cb93a386Sopenharmony_ci    };
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci    GrMemoryPool(size_t preallocSize, size_t minAllocSize);
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci#ifdef SK_DEBUG
122cb93a386Sopenharmony_ci    SkTHashSet<int>  fAllocatedIDs;
123cb93a386Sopenharmony_ci    int              fAllocationCount;
124cb93a386Sopenharmony_ci#endif
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci    SkBlockAllocator fAllocator; // Must be the last field, in order to use extra allocated space
127cb93a386Sopenharmony_ci};
128cb93a386Sopenharmony_ci#endif
129