1 /*
2 * Copyright 2021 Google LLC
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 #include "include/core/SkMath.h"
9 #include "src/gpu/GrSubRunAllocator.h"
10
11 #include <cstddef>
12 #include <memory>
13 #include <new>
14
15 // -- GrBagOfBytes ---------------------------------------------------------------------------------
GrBagOfBytes(char * bytes,size_t size,size_t firstHeapAllocation)16 GrBagOfBytes::GrBagOfBytes(char* bytes, size_t size, size_t firstHeapAllocation)
17 : fFibProgression(size, firstHeapAllocation) {
18 SkASSERT_RELEASE(size < kMaxByteSize);
19 SkASSERT_RELEASE(firstHeapAllocation < kMaxByteSize);
20
21 std::size_t space = size;
22 void* ptr = bytes;
23 if (bytes && std::align(kMaxAlignment, sizeof(Block), ptr, space)) {
24 this->setupBytesAndCapacity(bytes, size);
25 new (fEndByte) Block(nullptr, nullptr);
26 }
27 }
28
GrBagOfBytes(size_t firstHeapAllocation)29 GrBagOfBytes::GrBagOfBytes(size_t firstHeapAllocation)
30 : GrBagOfBytes(nullptr, 0, firstHeapAllocation) {}
31
~GrBagOfBytes()32 GrBagOfBytes::~GrBagOfBytes() {
33 Block* cursor = reinterpret_cast<Block*>(fEndByte);
34 while (cursor != nullptr) {
35 char* toDelete = cursor->fBlockStart;
36 cursor = cursor->fPrevious;
37 delete [] toDelete;
38 }
39 }
40
Block(char * previous,char * startOfBlock)41 GrBagOfBytes::Block::Block(char* previous, char* startOfBlock)
42 : fBlockStart{startOfBlock}
43 , fPrevious{reinterpret_cast<Block*>(previous)} {}
44
alignedBytes(int size,int alignment)45 void* GrBagOfBytes::alignedBytes(int size, int alignment) {
46 SkASSERT_RELEASE(0 < size && size < kMaxByteSize);
47 SkASSERT_RELEASE(0 < alignment && alignment <= kMaxAlignment);
48 SkASSERT_RELEASE(SkIsPow2(alignment));
49
50 return this->allocateBytes(size, alignment);
51 }
52
setupBytesAndCapacity(char * bytes,int size)53 void GrBagOfBytes::setupBytesAndCapacity(char* bytes, int size) {
54 // endByte must be aligned to the maximum alignment to allow tracking alignment using capacity;
55 // capacity and endByte are both aligned to max alignment.
56 intptr_t endByte = reinterpret_cast<intptr_t>(bytes + size - sizeof(Block)) & -kMaxAlignment;
57 fEndByte = reinterpret_cast<char*>(endByte);
58 fCapacity = fEndByte - bytes;
59 }
60
needMoreBytes(int requestedSize,int alignment)61 void GrBagOfBytes::needMoreBytes(int requestedSize, int alignment) {
62 int nextBlockSize = fFibProgression.nextBlockSize();
63 const int size = PlatformMinimumSizeWithOverhead(
64 std::max(requestedSize, nextBlockSize), alignof(max_align_t));
65 char* const bytes = new char[size];
66 // fEndByte is changed by setupBytesAndCapacity. Remember it to link back to.
67 char* const previousBlock = fEndByte;
68 this->setupBytesAndCapacity(bytes, size);
69
70 // Make a block to delete these bytes, and points to the previous block.
71 new (fEndByte) Block{previousBlock, bytes};
72
73 // Make fCapacity the alignment for the requested object.
74 fCapacity = fCapacity & -alignment;
75 SkASSERT(fCapacity >= requestedSize);
76 }
77
78 // -- GrSubRunAllocator ----------------------------------------------------------------------------
GrSubRunAllocator(char * bytes,int size,int firstHeapAllocation)79 GrSubRunAllocator::GrSubRunAllocator(char* bytes, int size, int firstHeapAllocation)
80 : fAlloc{bytes, SkTo<size_t>(size), SkTo<size_t>(firstHeapAllocation)} {}
81
GrSubRunAllocator(int firstHeapAllocation)82 GrSubRunAllocator::GrSubRunAllocator(int firstHeapAllocation)
83 : GrSubRunAllocator(nullptr, 0, firstHeapAllocation) {}
84
alignedBytes(int unsafeSize,int unsafeAlignment)85 void* GrSubRunAllocator::alignedBytes(int unsafeSize, int unsafeAlignment) {
86 return fAlloc.alignedBytes(unsafeSize, unsafeAlignment);
87 }
88