| /* | |
| * Copyright 2021 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "include/core/SkMath.h" | |
| #include "src/gpu/GrSubRunAllocator.h" | |
| #include <cstddef> | |
| #include <memory> | |
| #include <new> | |
| // -- GrBagOfBytes --------------------------------------------------------------------------------- | |
| GrBagOfBytes::GrBagOfBytes(char* bytes, size_t size, size_t firstHeapAllocation) | |
| : fFibProgression(size, firstHeapAllocation) { | |
| SkASSERT_RELEASE(size < kMaxByteSize); | |
| SkASSERT_RELEASE(firstHeapAllocation < kMaxByteSize); | |
| std::size_t space = size; | |
| void* ptr = bytes; | |
| if (bytes && std::align(kMaxAlignment, sizeof(Block), ptr, space)) { | |
| this->setupBytesAndCapacity(bytes, size); | |
| new (fEndByte) Block(nullptr, nullptr); | |
| } | |
| } | |
| GrBagOfBytes::GrBagOfBytes(size_t firstHeapAllocation) | |
| : GrBagOfBytes(nullptr, 0, firstHeapAllocation) {} | |
| GrBagOfBytes::~GrBagOfBytes() { | |
| Block* cursor = reinterpret_cast<Block*>(fEndByte); | |
| while (cursor != nullptr) { | |
| char* toDelete = cursor->fBlockStart; | |
| cursor = cursor->fPrevious; | |
| delete [] toDelete; | |
| } | |
| } | |
| GrBagOfBytes::Block::Block(char* previous, char* startOfBlock) | |
| : fBlockStart{startOfBlock} | |
| , fPrevious{reinterpret_cast<Block*>(previous)} {} | |
| void* GrBagOfBytes::alignedBytes(int size, int alignment) { | |
| SkASSERT_RELEASE(0 < size && size < kMaxByteSize); | |
| SkASSERT_RELEASE(0 < alignment && alignment <= kMaxAlignment); | |
| SkASSERT_RELEASE(SkIsPow2(alignment)); | |
| return this->allocateBytes(size, alignment); | |
| } | |
| void GrBagOfBytes::setupBytesAndCapacity(char* bytes, int size) { | |
| // endByte must be aligned to the maximum alignment to allow tracking alignment using capacity; | |
| // capacity and endByte are both aligned to max alignment. | |
| intptr_t endByte = reinterpret_cast<intptr_t>(bytes + size - sizeof(Block)) & -kMaxAlignment; | |
| fEndByte = reinterpret_cast<char*>(endByte); | |
| fCapacity = fEndByte - bytes; | |
| } | |
| void GrBagOfBytes::needMoreBytes(int requestedSize, int alignment) { | |
| int nextBlockSize = fFibProgression.nextBlockSize(); | |
| const int size = PlatformMinimumSizeWithOverhead( | |
| std::max(requestedSize, nextBlockSize), kAllocationAlignment); | |
| char* const bytes = new char[size]; | |
| // fEndByte is changed by setupBytesAndCapacity. Remember it to link back to. | |
| char* const previousBlock = fEndByte; | |
| this->setupBytesAndCapacity(bytes, size); | |
| // Make a block to delete these bytes, and points to the previous block. | |
| new (fEndByte) Block{previousBlock, bytes}; | |
| // Make fCapacity the alignment for the requested object. | |
| fCapacity = fCapacity & -alignment; | |
| SkASSERT(fCapacity >= requestedSize); | |
| } | |
| // -- GrSubRunAllocator ---------------------------------------------------------------------------- | |
| GrSubRunAllocator::GrSubRunAllocator(char* bytes, int size, int firstHeapAllocation) | |
| : fAlloc{bytes, SkTo<size_t>(size), SkTo<size_t>(firstHeapAllocation)} {} | |
| GrSubRunAllocator::GrSubRunAllocator(int firstHeapAllocation) | |
| : GrSubRunAllocator(nullptr, 0, firstHeapAllocation) {} | |
| void* GrSubRunAllocator::alignedBytes(int unsafeSize, int unsafeAlignment) { | |
| return fAlloc.alignedBytes(unsafeSize, unsafeAlignment); | |
| } |