blob: 2d08e0a4631c98e58be8e9f4b2f8f48a588b3090 [file] [log] [blame]
/*
* 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), 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_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);
}