blob: 117950bdaef985dbf6725769163c4c25722fb311 [file] [log] [blame]
//
// Copyright 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMMON_MEMORYBUFFER_H_
#define COMMON_MEMORYBUFFER_H_
#include "common/Optional.h"
#include "common/angleutils.h"
#include "common/debug.h"
#include <stdint.h>
#include <cstddef>
namespace angle
{
class MemoryBuffer final : NonCopyable
{
public:
MemoryBuffer() = default;
~MemoryBuffer();
MemoryBuffer(MemoryBuffer &&other);
MemoryBuffer &operator=(MemoryBuffer &&other);
// Destroy underlying memory
void destroy();
// Updates mSize to newSize. Updates mCapacity iff newSize > mCapacity
[[nodiscard]] bool resize(size_t newSize);
// Resets mSize to 0. Reserves memory and updates mCapacity iff newSize > mCapacity
[[nodiscard]] bool clearAndReserve(size_t newSize);
// Updates mCapacity iff newSize > mCapacity
[[nodiscard]] bool reserve(size_t newSize);
// Appends content from "other" MemoryBuffer
[[nodiscard]] bool append(const MemoryBuffer &other);
// Appends content from "[buffer, buffer + bufferSize)"
[[nodiscard]] bool appendRaw(const uint8_t *buffer, const size_t bufferSize);
// Sets size bound by capacity.
void setSize(size_t size)
{
ASSERT(size <= mCapacity);
mSize = size;
}
void setSizeToCapacity() { setSize(mCapacity); }
// Invalidate current content
void clear() { (void)resize(0); }
size_t size() const { return mSize; }
size_t capacity() const { return mCapacity; }
bool empty() const { return mSize == 0; }
const uint8_t *data() const { return mData; }
uint8_t *data()
{
ASSERT(mData);
return mData;
}
uint8_t &operator[](size_t pos)
{
ASSERT(mData && pos < mSize);
return mData[pos];
}
const uint8_t &operator[](size_t pos) const
{
ASSERT(mData && pos < mSize);
return mData[pos];
}
void fill(uint8_t datum);
// Only used by unit tests
// Validate total bytes allocated during a resize
void assertTotalAllocatedBytes(size_t totalAllocatedBytes) const
{
#if defined(ANGLE_ENABLE_ASSERTS)
ASSERT(totalAllocatedBytes == mTotalAllocatedBytes);
#endif // ANGLE_ENABLE_ASSERTS
}
// Validate total bytes copied during a resize
void assertTotalCopiedBytes(size_t totalCopiedBytes) const
{
#if defined(ANGLE_ENABLE_ASSERTS)
ASSERT(totalCopiedBytes == mTotalCopiedBytes);
#endif // ANGLE_ENABLE_ASSERTS
}
private:
size_t mSize = 0;
size_t mCapacity = 0;
uint8_t *mData = nullptr;
#if defined(ANGLE_ENABLE_ASSERTS)
size_t mTotalAllocatedBytes = 0;
size_t mTotalCopiedBytes = 0;
#endif // ANGLE_ENABLE_ASSERTS
};
class ScratchBuffer final : NonCopyable
{
public:
ScratchBuffer();
// If we request a scratch buffer requesting a smaller size this many times, release and
// recreate the scratch buffer. This ensures we don't have a degenerate case where we are stuck
// hogging memory.
ScratchBuffer(uint32_t lifetime);
~ScratchBuffer();
ScratchBuffer(ScratchBuffer &&other);
ScratchBuffer &operator=(ScratchBuffer &&other);
// Returns true with a memory buffer of the requested size, or false on failure.
bool get(size_t requestedSize, MemoryBuffer **memoryBufferOut);
// Same as get, but ensures new values are initialized to a fixed constant.
bool getInitialized(size_t requestedSize, MemoryBuffer **memoryBufferOut, uint8_t initValue);
// Ticks the release counter for the scratch buffer. Also done implicitly in get().
void tick();
void clear();
MemoryBuffer *getMemoryBuffer() { return &mScratchMemory; }
private:
bool getImpl(size_t requestedSize, MemoryBuffer **memoryBufferOut, Optional<uint8_t> initValue);
uint32_t mLifetime;
uint32_t mResetCounter;
MemoryBuffer mScratchMemory;
};
} // namespace angle
#endif // COMMON_MEMORYBUFFER_H_