1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2021 Google LLC 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 #ifndef sktext_gpu_SubRunAllocator_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define sktext_gpu_SubRunAllocator_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSpan.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTLogic.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h" 18*c8dee2aaSAndroid Build Coastguard Worker 19*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm> 20*c8dee2aaSAndroid Build Coastguard Worker #include <array> 21*c8dee2aaSAndroid Build Coastguard Worker #include <climits> 22*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 23*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 24*c8dee2aaSAndroid Build Coastguard Worker #include <cstring> 25*c8dee2aaSAndroid Build Coastguard Worker #include <limits> 26*c8dee2aaSAndroid Build Coastguard Worker #include <memory> 27*c8dee2aaSAndroid Build Coastguard Worker #include <new> 28*c8dee2aaSAndroid Build Coastguard Worker #include <tuple> 29*c8dee2aaSAndroid Build Coastguard Worker #include <utility> 30*c8dee2aaSAndroid Build Coastguard Worker 31*c8dee2aaSAndroid Build Coastguard Worker namespace sktext::gpu { 32*c8dee2aaSAndroid Build Coastguard Worker 33*c8dee2aaSAndroid Build Coastguard Worker // BagOfBytes parcels out bytes with a given size and alignment. 34*c8dee2aaSAndroid Build Coastguard Worker class BagOfBytes { 35*c8dee2aaSAndroid Build Coastguard Worker public: 36*c8dee2aaSAndroid Build Coastguard Worker BagOfBytes(char* block, size_t blockSize, size_t firstHeapAllocation); 37*c8dee2aaSAndroid Build Coastguard Worker explicit BagOfBytes(size_t firstHeapAllocation = 0); 38*c8dee2aaSAndroid Build Coastguard Worker BagOfBytes(const BagOfBytes&) = delete; 39*c8dee2aaSAndroid Build Coastguard Worker BagOfBytes& operator=(const BagOfBytes&) = delete; BagOfBytes(BagOfBytes && that)40*c8dee2aaSAndroid Build Coastguard Worker BagOfBytes(BagOfBytes&& that) 41*c8dee2aaSAndroid Build Coastguard Worker : fEndByte{std::exchange(that.fEndByte, nullptr)} 42*c8dee2aaSAndroid Build Coastguard Worker , fCapacity{that.fCapacity} 43*c8dee2aaSAndroid Build Coastguard Worker , fFibProgression{that.fFibProgression} {} 44*c8dee2aaSAndroid Build Coastguard Worker BagOfBytes& operator=(BagOfBytes&& that) { 45*c8dee2aaSAndroid Build Coastguard Worker this->~BagOfBytes(); new(this)46*c8dee2aaSAndroid Build Coastguard Worker new (this) BagOfBytes{std::move(that)}; 47*c8dee2aaSAndroid Build Coastguard Worker return *this; 48*c8dee2aaSAndroid Build Coastguard Worker } 49*c8dee2aaSAndroid Build Coastguard Worker 50*c8dee2aaSAndroid Build Coastguard Worker ~BagOfBytes(); 51*c8dee2aaSAndroid Build Coastguard Worker 52*c8dee2aaSAndroid Build Coastguard Worker // Given a requestedSize round up to the smallest size that accounts for all the per block 53*c8dee2aaSAndroid Build Coastguard Worker // overhead and alignment. It crashes if requestedSize is negative or too big. PlatformMinimumSizeWithOverhead(int requestedSize,int assumedAlignment)54*c8dee2aaSAndroid Build Coastguard Worker static constexpr int PlatformMinimumSizeWithOverhead(int requestedSize, int assumedAlignment) { 55*c8dee2aaSAndroid Build Coastguard Worker return MinimumSizeWithOverhead( 56*c8dee2aaSAndroid Build Coastguard Worker requestedSize, assumedAlignment, sizeof(Block), kMaxAlignment); 57*c8dee2aaSAndroid Build Coastguard Worker } 58*c8dee2aaSAndroid Build Coastguard Worker MinimumSizeWithOverhead(int requestedSize,int assumedAlignment,int blockSize,int maxAlignment)59*c8dee2aaSAndroid Build Coastguard Worker static constexpr int MinimumSizeWithOverhead( 60*c8dee2aaSAndroid Build Coastguard Worker int requestedSize, int assumedAlignment, int blockSize, int maxAlignment) { 61*c8dee2aaSAndroid Build Coastguard Worker SkASSERT_RELEASE(0 <= requestedSize && requestedSize < kMaxByteSize); 62*c8dee2aaSAndroid Build Coastguard Worker SkASSERT_RELEASE(SkIsPow2(assumedAlignment) && SkIsPow2(maxAlignment)); 63*c8dee2aaSAndroid Build Coastguard Worker 64*c8dee2aaSAndroid Build Coastguard Worker const int minAlignment = std::min(maxAlignment, assumedAlignment); 65*c8dee2aaSAndroid Build Coastguard Worker // There are two cases, one easy and one subtle. The easy case is when minAlignment == 66*c8dee2aaSAndroid Build Coastguard Worker // maxAlignment. When that happens, the term maxAlignment - minAlignment is zero, and the 67*c8dee2aaSAndroid Build Coastguard Worker // block will be placed at the proper alignment because alignUp is properly 68*c8dee2aaSAndroid Build Coastguard Worker // aligned. 69*c8dee2aaSAndroid Build Coastguard Worker // The subtle case is where minAlignment < maxAlignment. Because 70*c8dee2aaSAndroid Build Coastguard Worker // minAlignment < maxAlignment, alignUp(requestedSize, minAlignment) + blockSize does not 71*c8dee2aaSAndroid Build Coastguard Worker // guarantee that block can be placed at a maxAlignment address. Block can be placed at 72*c8dee2aaSAndroid Build Coastguard Worker // maxAlignment/minAlignment different address to achieve alignment, so we need 73*c8dee2aaSAndroid Build Coastguard Worker // to add memory to allow the block to be placed on a maxAlignment address. 74*c8dee2aaSAndroid Build Coastguard Worker // For example, if assumedAlignment = 4 and maxAlignment = 16 then block can be placed at 75*c8dee2aaSAndroid Build Coastguard Worker // the following address offsets at the end of minimumSize bytes. 76*c8dee2aaSAndroid Build Coastguard Worker // 0 * minAlignment = 0 77*c8dee2aaSAndroid Build Coastguard Worker // 1 * minAlignment = 4 78*c8dee2aaSAndroid Build Coastguard Worker // 2 * minAlignment = 8 79*c8dee2aaSAndroid Build Coastguard Worker // 3 * minAlignment = 12 80*c8dee2aaSAndroid Build Coastguard Worker // Following this logic, the equation for the additional bytes is 81*c8dee2aaSAndroid Build Coastguard Worker // (maxAlignment/minAlignment - 1) * minAlignment 82*c8dee2aaSAndroid Build Coastguard Worker // = maxAlignment - minAlignment. 83*c8dee2aaSAndroid Build Coastguard Worker int minimumSize = SkToInt(AlignUp(requestedSize, minAlignment)) 84*c8dee2aaSAndroid Build Coastguard Worker + blockSize 85*c8dee2aaSAndroid Build Coastguard Worker + maxAlignment - minAlignment; 86*c8dee2aaSAndroid Build Coastguard Worker 87*c8dee2aaSAndroid Build Coastguard Worker // If minimumSize is > 32k then round to a 4K boundary unless it is too close to the 88*c8dee2aaSAndroid Build Coastguard Worker // maximum int. The > 32K heuristic is from the JEMalloc behavior. 89*c8dee2aaSAndroid Build Coastguard Worker constexpr int k32K = (1 << 15); 90*c8dee2aaSAndroid Build Coastguard Worker if (minimumSize >= k32K && minimumSize < std::numeric_limits<int>::max() - k4K) { 91*c8dee2aaSAndroid Build Coastguard Worker minimumSize = SkToInt(AlignUp(minimumSize, k4K)); 92*c8dee2aaSAndroid Build Coastguard Worker } 93*c8dee2aaSAndroid Build Coastguard Worker 94*c8dee2aaSAndroid Build Coastguard Worker return minimumSize; 95*c8dee2aaSAndroid Build Coastguard Worker } 96*c8dee2aaSAndroid Build Coastguard Worker 97*c8dee2aaSAndroid Build Coastguard Worker template <int size> 98*c8dee2aaSAndroid Build Coastguard Worker using Storage = std::array<char, PlatformMinimumSizeWithOverhead(size, 1)>; 99*c8dee2aaSAndroid Build Coastguard Worker 100*c8dee2aaSAndroid Build Coastguard Worker // Returns true if n * sizeof(T) will fit in an allocation block. 101*c8dee2aaSAndroid Build Coastguard Worker template <typename T> WillCountFit(int n)102*c8dee2aaSAndroid Build Coastguard Worker static bool WillCountFit(int n) { 103*c8dee2aaSAndroid Build Coastguard Worker constexpr int kMaxN = kMaxByteSize / sizeof(T); 104*c8dee2aaSAndroid Build Coastguard Worker return 0 <= n && n < kMaxN; 105*c8dee2aaSAndroid Build Coastguard Worker } 106*c8dee2aaSAndroid Build Coastguard Worker 107*c8dee2aaSAndroid Build Coastguard Worker // Returns a pointer to memory suitable for holding n Ts. 108*c8dee2aaSAndroid Build Coastguard Worker template <typename T> char* allocateBytesFor(int n = 1) { 109*c8dee2aaSAndroid Build Coastguard Worker static_assert(alignof(T) <= kMaxAlignment, "Alignment is too big for arena"); 110*c8dee2aaSAndroid Build Coastguard Worker static_assert(sizeof(T) < kMaxByteSize, "Size is too big for arena"); 111*c8dee2aaSAndroid Build Coastguard Worker SkASSERT_RELEASE(WillCountFit<T>(n)); 112*c8dee2aaSAndroid Build Coastguard Worker 113*c8dee2aaSAndroid Build Coastguard Worker int size = n ? n * sizeof(T) : 1; 114*c8dee2aaSAndroid Build Coastguard Worker return this->allocateBytes(size, alignof(T)); 115*c8dee2aaSAndroid Build Coastguard Worker } 116*c8dee2aaSAndroid Build Coastguard Worker 117*c8dee2aaSAndroid Build Coastguard Worker void* alignedBytes(int unsafeSize, int unsafeAlignment); 118*c8dee2aaSAndroid Build Coastguard Worker 119*c8dee2aaSAndroid Build Coastguard Worker private: 120*c8dee2aaSAndroid Build Coastguard Worker // The maximum alignment supported by GrBagOfBytes. 16 seems to be a good number for alignment. 121*c8dee2aaSAndroid Build Coastguard Worker // If a use case for larger alignments is found, we can turn this into a template parameter. 122*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kMaxAlignment = std::max(16, (int)alignof(std::max_align_t)); 123*c8dee2aaSAndroid Build Coastguard Worker // The largest size that can be allocated. In larger sizes, the block is rounded up to 4K 124*c8dee2aaSAndroid Build Coastguard Worker // chunks. Leave a 4K of slop. 125*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int k4K = (1 << 12); 126*c8dee2aaSAndroid Build Coastguard Worker // This should never overflow with the calculations done on the code. 127*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kMaxByteSize = std::numeric_limits<int>::max() - k4K; 128*c8dee2aaSAndroid Build Coastguard Worker // The assumed alignment of new char[] given the platform. 129*c8dee2aaSAndroid Build Coastguard Worker // There is a bug in Emscripten's allocator that make alignment different than max_align_t. 130*c8dee2aaSAndroid Build Coastguard Worker // kAllocationAlignment accounts for this difference. For more information see: 131*c8dee2aaSAndroid Build Coastguard Worker // https://github.com/emscripten-core/emscripten/issues/10072 132*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_FORCE_8_BYTE_ALIGNMENT) 133*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kAllocationAlignment = alignof(std::max_align_t); 134*c8dee2aaSAndroid Build Coastguard Worker #else 135*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kAllocationAlignment = 8; 136*c8dee2aaSAndroid Build Coastguard Worker #endif 137*c8dee2aaSAndroid Build Coastguard Worker AlignUp(int size,int alignment)138*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t AlignUp(int size, int alignment) { 139*c8dee2aaSAndroid Build Coastguard Worker return (size + (alignment - 1)) & -alignment; 140*c8dee2aaSAndroid Build Coastguard Worker } 141*c8dee2aaSAndroid Build Coastguard Worker 142*c8dee2aaSAndroid Build Coastguard Worker // The Block starts at the location pointed to by fEndByte. 143*c8dee2aaSAndroid Build Coastguard Worker // Beware. Order is important here. The destructor for fPrevious must be called first because 144*c8dee2aaSAndroid Build Coastguard Worker // the Block is embedded in fBlockStart. Destructors are run in reverse order. 145*c8dee2aaSAndroid Build Coastguard Worker struct Block { 146*c8dee2aaSAndroid Build Coastguard Worker Block(char* previous, char* startOfBlock); 147*c8dee2aaSAndroid Build Coastguard Worker // The start of the originally allocated bytes. This is the thing that must be deleted. 148*c8dee2aaSAndroid Build Coastguard Worker char* const fBlockStart; 149*c8dee2aaSAndroid Build Coastguard Worker Block* const fPrevious; 150*c8dee2aaSAndroid Build Coastguard Worker }; 151*c8dee2aaSAndroid Build Coastguard Worker 152*c8dee2aaSAndroid Build Coastguard Worker // Note: fCapacity is the number of bytes remaining, and is subtracted from fEndByte to 153*c8dee2aaSAndroid Build Coastguard Worker // generate the location of the object. allocateBytes(int size,int alignment)154*c8dee2aaSAndroid Build Coastguard Worker char* allocateBytes(int size, int alignment) { 155*c8dee2aaSAndroid Build Coastguard Worker fCapacity = fCapacity & -alignment; 156*c8dee2aaSAndroid Build Coastguard Worker if (fCapacity < size) { 157*c8dee2aaSAndroid Build Coastguard Worker this->needMoreBytes(size, alignment); 158*c8dee2aaSAndroid Build Coastguard Worker } 159*c8dee2aaSAndroid Build Coastguard Worker char* const ptr = fEndByte - fCapacity; 160*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(((intptr_t)ptr & (alignment - 1)) == 0); 161*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fCapacity >= size); 162*c8dee2aaSAndroid Build Coastguard Worker fCapacity -= size; 163*c8dee2aaSAndroid Build Coastguard Worker return ptr; 164*c8dee2aaSAndroid Build Coastguard Worker } 165*c8dee2aaSAndroid Build Coastguard Worker 166*c8dee2aaSAndroid Build Coastguard Worker // Adjust fEndByte and fCapacity give a new block starting at bytes with size. 167*c8dee2aaSAndroid Build Coastguard Worker void setupBytesAndCapacity(char* bytes, int size); 168*c8dee2aaSAndroid Build Coastguard Worker 169*c8dee2aaSAndroid Build Coastguard Worker // Adjust fEndByte and fCapacity to satisfy the size and alignment request. 170*c8dee2aaSAndroid Build Coastguard Worker void needMoreBytes(int size, int alignment); 171*c8dee2aaSAndroid Build Coastguard Worker 172*c8dee2aaSAndroid Build Coastguard Worker // This points to the highest kMaxAlignment address in the allocated block. The address of 173*c8dee2aaSAndroid Build Coastguard Worker // the current end of allocated data is given by fEndByte - fCapacity. While the negative side 174*c8dee2aaSAndroid Build Coastguard Worker // of this pointer are the bytes to be allocated. The positive side points to the Block for 175*c8dee2aaSAndroid Build Coastguard Worker // this memory. In other words, the pointer to the Block structure for these bytes is 176*c8dee2aaSAndroid Build Coastguard Worker // reinterpret_cast<Block*>(fEndByte). 177*c8dee2aaSAndroid Build Coastguard Worker char* fEndByte{nullptr}; 178*c8dee2aaSAndroid Build Coastguard Worker 179*c8dee2aaSAndroid Build Coastguard Worker // The number of bytes remaining in this block. 180*c8dee2aaSAndroid Build Coastguard Worker int fCapacity{0}; 181*c8dee2aaSAndroid Build Coastguard Worker 182*c8dee2aaSAndroid Build Coastguard Worker SkFibBlockSizes<kMaxByteSize> fFibProgression; 183*c8dee2aaSAndroid Build Coastguard Worker }; 184*c8dee2aaSAndroid Build Coastguard Worker 185*c8dee2aaSAndroid Build Coastguard Worker template <typename T> 186*c8dee2aaSAndroid Build Coastguard Worker class SubRunInitializer { 187*c8dee2aaSAndroid Build Coastguard Worker public: SubRunInitializer(void * memory)188*c8dee2aaSAndroid Build Coastguard Worker SubRunInitializer(void* memory) : fMemory{memory} { SkASSERT(memory != nullptr); } ~SubRunInitializer()189*c8dee2aaSAndroid Build Coastguard Worker ~SubRunInitializer() { 190*c8dee2aaSAndroid Build Coastguard Worker ::operator delete(fMemory); 191*c8dee2aaSAndroid Build Coastguard Worker } 192*c8dee2aaSAndroid Build Coastguard Worker template <typename... Args> initialize(Args &&...args)193*c8dee2aaSAndroid Build Coastguard Worker T* initialize(Args&&... args) { 194*c8dee2aaSAndroid Build Coastguard Worker // Warn on more than one initialization. 195*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fMemory != nullptr); 196*c8dee2aaSAndroid Build Coastguard Worker return new (std::exchange(fMemory, nullptr)) T(std::forward<Args>(args)...); 197*c8dee2aaSAndroid Build Coastguard Worker } 198*c8dee2aaSAndroid Build Coastguard Worker 199*c8dee2aaSAndroid Build Coastguard Worker private: 200*c8dee2aaSAndroid Build Coastguard Worker void* fMemory; 201*c8dee2aaSAndroid Build Coastguard Worker }; 202*c8dee2aaSAndroid Build Coastguard Worker 203*c8dee2aaSAndroid Build Coastguard Worker // GrSubRunAllocator provides fast allocation where the user takes care of calling the destructors 204*c8dee2aaSAndroid Build Coastguard Worker // of the returned pointers, and GrSubRunAllocator takes care of deleting the storage. The 205*c8dee2aaSAndroid Build Coastguard Worker // unique_ptrs returned, are to assist in assuring the object's destructor is called. 206*c8dee2aaSAndroid Build Coastguard Worker // A note on zero length arrays: according to the standard a pointer must be returned, and it 207*c8dee2aaSAndroid Build Coastguard Worker // can't be a nullptr. In such a case, SkArena allocates one byte, but does not initialize it. 208*c8dee2aaSAndroid Build Coastguard Worker class SubRunAllocator { 209*c8dee2aaSAndroid Build Coastguard Worker public: 210*c8dee2aaSAndroid Build Coastguard Worker struct Destroyer { 211*c8dee2aaSAndroid Build Coastguard Worker template <typename T> operatorDestroyer212*c8dee2aaSAndroid Build Coastguard Worker void operator()(T* ptr) { ptr->~T(); } 213*c8dee2aaSAndroid Build Coastguard Worker }; 214*c8dee2aaSAndroid Build Coastguard Worker 215*c8dee2aaSAndroid Build Coastguard Worker struct ArrayDestroyer { 216*c8dee2aaSAndroid Build Coastguard Worker int n; 217*c8dee2aaSAndroid Build Coastguard Worker template <typename T> operatorArrayDestroyer218*c8dee2aaSAndroid Build Coastguard Worker void operator()(T* ptr) { 219*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < n; i++) { ptr[i].~T(); } 220*c8dee2aaSAndroid Build Coastguard Worker } 221*c8dee2aaSAndroid Build Coastguard Worker }; 222*c8dee2aaSAndroid Build Coastguard Worker 223*c8dee2aaSAndroid Build Coastguard Worker template<class T> 224*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr bool HasNoDestructor = std::is_trivially_destructible<T>::value; 225*c8dee2aaSAndroid Build Coastguard Worker 226*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator(char* block, int blockSize, int firstHeapAllocation); 227*c8dee2aaSAndroid Build Coastguard Worker explicit SubRunAllocator(int firstHeapAllocation = 0); 228*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator(const SubRunAllocator&) = delete; 229*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator& operator=(const SubRunAllocator&) = delete; 230*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator(SubRunAllocator&&) = default; 231*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator& operator=(SubRunAllocator&&) = default; 232*c8dee2aaSAndroid Build Coastguard Worker 233*c8dee2aaSAndroid Build Coastguard Worker template <typename T> 234*c8dee2aaSAndroid Build Coastguard Worker static std::tuple<SubRunInitializer<T>, int, SubRunAllocator> AllocateClassMemoryAndArena(int allocSizeHint)235*c8dee2aaSAndroid Build Coastguard Worker AllocateClassMemoryAndArena(int allocSizeHint) { 236*c8dee2aaSAndroid Build Coastguard Worker SkASSERT_RELEASE(allocSizeHint >= 0); 237*c8dee2aaSAndroid Build Coastguard Worker // Round the size after the object the optimal amount. 238*c8dee2aaSAndroid Build Coastguard Worker int extraSize = BagOfBytes::PlatformMinimumSizeWithOverhead(allocSizeHint, alignof(T)); 239*c8dee2aaSAndroid Build Coastguard Worker 240*c8dee2aaSAndroid Build Coastguard Worker // Don't overflow or die. 241*c8dee2aaSAndroid Build Coastguard Worker SkASSERT_RELEASE(INT_MAX - SkTo<int>(sizeof(T)) > extraSize); 242*c8dee2aaSAndroid Build Coastguard Worker int totalMemorySize = sizeof(T) + extraSize; 243*c8dee2aaSAndroid Build Coastguard Worker 244*c8dee2aaSAndroid Build Coastguard Worker void* memory = ::operator new (totalMemorySize); 245*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator alloc{SkTAddOffset<char>(memory, sizeof(T)), extraSize, extraSize/2}; 246*c8dee2aaSAndroid Build Coastguard Worker return {memory, totalMemorySize, std::move(alloc)}; 247*c8dee2aaSAndroid Build Coastguard Worker } 248*c8dee2aaSAndroid Build Coastguard Worker makePOD(Args &&...args)249*c8dee2aaSAndroid Build Coastguard Worker template <typename T, typename... Args> T* makePOD(Args&&... args) { 250*c8dee2aaSAndroid Build Coastguard Worker static_assert(HasNoDestructor<T>, "This is not POD. Use makeUnique."); 251*c8dee2aaSAndroid Build Coastguard Worker char* bytes = fAlloc.template allocateBytesFor<T>(); 252*c8dee2aaSAndroid Build Coastguard Worker return new (bytes) T(std::forward<Args>(args)...); 253*c8dee2aaSAndroid Build Coastguard Worker } 254*c8dee2aaSAndroid Build Coastguard Worker 255*c8dee2aaSAndroid Build Coastguard Worker template <typename T, typename... Args> makeUnique(Args &&...args)256*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<T, Destroyer> makeUnique(Args&&... args) { 257*c8dee2aaSAndroid Build Coastguard Worker static_assert(!HasNoDestructor<T>, "This is POD. Use makePOD."); 258*c8dee2aaSAndroid Build Coastguard Worker char* bytes = fAlloc.template allocateBytesFor<T>(); 259*c8dee2aaSAndroid Build Coastguard Worker return std::unique_ptr<T, Destroyer>{new (bytes) T(std::forward<Args>(args)...)}; 260*c8dee2aaSAndroid Build Coastguard Worker } 261*c8dee2aaSAndroid Build Coastguard Worker makePODArray(int n)262*c8dee2aaSAndroid Build Coastguard Worker template<typename T> T* makePODArray(int n) { 263*c8dee2aaSAndroid Build Coastguard Worker static_assert(HasNoDestructor<T>, "This is not POD. Use makeUniqueArray."); 264*c8dee2aaSAndroid Build Coastguard Worker return reinterpret_cast<T*>(fAlloc.template allocateBytesFor<T>(n)); 265*c8dee2aaSAndroid Build Coastguard Worker } 266*c8dee2aaSAndroid Build Coastguard Worker 267*c8dee2aaSAndroid Build Coastguard Worker template<typename T> makePODSpan(SkSpan<const T> s)268*c8dee2aaSAndroid Build Coastguard Worker SkSpan<T> makePODSpan(SkSpan<const T> s) { 269*c8dee2aaSAndroid Build Coastguard Worker static_assert(HasNoDestructor<T>, "This is not POD. Use makeUniqueArray."); 270*c8dee2aaSAndroid Build Coastguard Worker if (s.empty()) { 271*c8dee2aaSAndroid Build Coastguard Worker return SkSpan<T>{}; 272*c8dee2aaSAndroid Build Coastguard Worker } 273*c8dee2aaSAndroid Build Coastguard Worker 274*c8dee2aaSAndroid Build Coastguard Worker T* result = this->makePODArray<T>(SkTo<int>(s.size())); 275*c8dee2aaSAndroid Build Coastguard Worker memcpy(result, s.data(), s.size_bytes()); 276*c8dee2aaSAndroid Build Coastguard Worker return {result, s.size()}; 277*c8dee2aaSAndroid Build Coastguard Worker } 278*c8dee2aaSAndroid Build Coastguard Worker 279*c8dee2aaSAndroid Build Coastguard Worker template<typename T, typename Src, typename Map> makePODArray(const Src & src,Map map)280*c8dee2aaSAndroid Build Coastguard Worker SkSpan<T> makePODArray(const Src& src, Map map) { 281*c8dee2aaSAndroid Build Coastguard Worker static_assert(HasNoDestructor<T>, "This is not POD. Use makeUniqueArray."); 282*c8dee2aaSAndroid Build Coastguard Worker int size = SkTo<int>(src.size()); 283*c8dee2aaSAndroid Build Coastguard Worker T* result = this->template makePODArray<T>(size); 284*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < size; i++) { 285*c8dee2aaSAndroid Build Coastguard Worker new (&result[i]) T(map(src[i])); 286*c8dee2aaSAndroid Build Coastguard Worker } 287*c8dee2aaSAndroid Build Coastguard Worker return {result, src.size()}; 288*c8dee2aaSAndroid Build Coastguard Worker } 289*c8dee2aaSAndroid Build Coastguard Worker 290*c8dee2aaSAndroid Build Coastguard Worker template<typename T> makeUniqueArray(int n)291*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<T[], ArrayDestroyer> makeUniqueArray(int n) { 292*c8dee2aaSAndroid Build Coastguard Worker static_assert(!HasNoDestructor<T>, "This is POD. Use makePODArray."); 293*c8dee2aaSAndroid Build Coastguard Worker T* array = reinterpret_cast<T*>(fAlloc.template allocateBytesFor<T>(n)); 294*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < n; i++) { 295*c8dee2aaSAndroid Build Coastguard Worker new (&array[i]) T{}; 296*c8dee2aaSAndroid Build Coastguard Worker } 297*c8dee2aaSAndroid Build Coastguard Worker return std::unique_ptr<T[], ArrayDestroyer>{array, ArrayDestroyer{n}}; 298*c8dee2aaSAndroid Build Coastguard Worker } 299*c8dee2aaSAndroid Build Coastguard Worker 300*c8dee2aaSAndroid Build Coastguard Worker template<typename T, typename I> makeUniqueArray(int n,I initializer)301*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<T[], ArrayDestroyer> makeUniqueArray(int n, I initializer) { 302*c8dee2aaSAndroid Build Coastguard Worker static_assert(!HasNoDestructor<T>, "This is POD. Use makePODArray."); 303*c8dee2aaSAndroid Build Coastguard Worker T* array = reinterpret_cast<T*>(fAlloc.template allocateBytesFor<T>(n)); 304*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < n; i++) { 305*c8dee2aaSAndroid Build Coastguard Worker new (&array[i]) T(initializer(i)); 306*c8dee2aaSAndroid Build Coastguard Worker } 307*c8dee2aaSAndroid Build Coastguard Worker return std::unique_ptr<T[], ArrayDestroyer>{array, ArrayDestroyer{n}}; 308*c8dee2aaSAndroid Build Coastguard Worker } 309*c8dee2aaSAndroid Build Coastguard Worker 310*c8dee2aaSAndroid Build Coastguard Worker template<typename T, typename U, typename Map> makeUniqueArray(SkSpan<const U> src,Map map)311*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<T[], ArrayDestroyer> makeUniqueArray(SkSpan<const U> src, Map map) { 312*c8dee2aaSAndroid Build Coastguard Worker static_assert(!HasNoDestructor<T>, "This is POD. Use makePODArray."); 313*c8dee2aaSAndroid Build Coastguard Worker int count = SkCount(src); 314*c8dee2aaSAndroid Build Coastguard Worker T* array = reinterpret_cast<T*>(fAlloc.template allocateBytesFor<T>(src.size())); 315*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < count; ++i) { 316*c8dee2aaSAndroid Build Coastguard Worker new (&array[i]) T(map(src[i])); 317*c8dee2aaSAndroid Build Coastguard Worker } 318*c8dee2aaSAndroid Build Coastguard Worker return std::unique_ptr<T[], ArrayDestroyer>{array, ArrayDestroyer{count}}; 319*c8dee2aaSAndroid Build Coastguard Worker } 320*c8dee2aaSAndroid Build Coastguard Worker 321*c8dee2aaSAndroid Build Coastguard Worker void* alignedBytes(int size, int alignment); 322*c8dee2aaSAndroid Build Coastguard Worker 323*c8dee2aaSAndroid Build Coastguard Worker private: 324*c8dee2aaSAndroid Build Coastguard Worker BagOfBytes fAlloc; 325*c8dee2aaSAndroid Build Coastguard Worker }; 326*c8dee2aaSAndroid Build Coastguard Worker 327*c8dee2aaSAndroid Build Coastguard Worker // Helper for defining allocators with inline/reserved storage. 328*c8dee2aaSAndroid Build Coastguard Worker // For argument declarations, stick to the base type (SubRunAllocator). 329*c8dee2aaSAndroid Build Coastguard Worker // Note: Inheriting from the storage first means the storage will outlive the 330*c8dee2aaSAndroid Build Coastguard Worker // SubRunAllocator, letting ~SubRunAllocator read it as it calls destructors. 331*c8dee2aaSAndroid Build Coastguard Worker // (This is mostly only relevant for strict tools like MSAN.) 332*c8dee2aaSAndroid Build Coastguard Worker template <size_t InlineStorageSize, size_t InlineStorageAlignment> 333*c8dee2aaSAndroid Build Coastguard Worker class STSubRunAllocator : private std::array<char, 334*c8dee2aaSAndroid Build Coastguard Worker BagOfBytes::PlatformMinimumSizeWithOverhead( 335*c8dee2aaSAndroid Build Coastguard Worker InlineStorageSize, InlineStorageAlignment)>, 336*c8dee2aaSAndroid Build Coastguard Worker public SubRunAllocator { 337*c8dee2aaSAndroid Build Coastguard Worker public: 338*c8dee2aaSAndroid Build Coastguard Worker explicit STSubRunAllocator(size_t firstHeapAllocation = InlineStorageSize) 339*c8dee2aaSAndroid Build Coastguard Worker : SubRunAllocator{this->data(), SkToInt(this->size()), SkToInt(firstHeapAllocation)} {} 340*c8dee2aaSAndroid Build Coastguard Worker }; 341*c8dee2aaSAndroid Build Coastguard Worker } // namespace sktext::gpu 342*c8dee2aaSAndroid Build Coastguard Worker 343*c8dee2aaSAndroid Build Coastguard Worker #endif // sktext_gpu_SubRunAllocator_DEFINED 344