/* * 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 #include #include // -- 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(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(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(bytes + size - sizeof(Block)) & -kMaxAlignment; fEndByte = reinterpret_cast(endByte); fCapacity = fEndByte - bytes; } void GrBagOfBytes::needMoreBytes(int requestedSize, int alignment) { int nextBlockSize = fFibProgression.nextBlockSize(); const int size = PlatformMinimumSizeWithOverhead( std::max(requestedSize, nextBlockSize), alignof(max_align_t)); 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), SkTo(firstHeapAllocation)} {} GrSubRunAllocator::GrSubRunAllocator(int firstHeapAllocation) : GrSubRunAllocator(nullptr, 0, firstHeapAllocation) {} void* GrSubRunAllocator::alignedBytes(int unsafeSize, int unsafeAlignment) { return fAlloc.alignedBytes(unsafeSize, unsafeAlignment); }