#ifndef GPU_COMMAND_BUFFER_CLIENT_MAPPED_MEMORY_H_
#define GPU_COMMAND_BUFFER_CLIENT_MAPPED_MEMORY_H_
#include <stddef.h>
#include <stdint.h>
#include <bit>
#include <memory>
#include "base/compiler_specific.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_span.h"
#include "base/trace_event/memory_dump_provider.h"
#include "gpu/command_buffer/client/fenced_allocator.h"
#include "gpu/command_buffer/client/gpu_command_buffer_client_export.h"
#include "gpu/command_buffer/common/buffer.h"
#include "gpu/command_buffer/common/constants.h"
namespace gpu {
class CommandBufferHelper;
class GPU_COMMAND_BUFFER_CLIENT_EXPORT MemoryChunk {
public:
MemoryChunk(int32_t shm_id,
scoped_refptr<gpu::Buffer> shm,
CommandBufferHelper* helper);
MemoryChunk(const MemoryChunk&) = delete;
MemoryChunk& operator=(const MemoryChunk&) = delete;
~MemoryChunk();
uint32_t GetLargestFreeSizeWithoutWaiting() {
return allocator_.GetLargestFreeSize();
}
uint32_t GetLargestFreeSizeWithWaiting() {
return allocator_.GetLargestFreeOrPendingSize();
}
uint32_t GetSize() const { return shm_->size(); }
int32_t shm_id() const { return shm_id_; }
gpu::Buffer* shared_memory() const { return shm_.get(); }
void* Alloc(uint32_t size) { return allocator_.Alloc(size); }
uint32_t GetOffset(void* pointer) { return allocator_.GetOffset(pointer); }
void Free(void* pointer) {
allocator_.Free(pointer);
}
void FreePendingToken(void* pointer, uint32_t token) {
allocator_.FreePendingToken(pointer, token);
}
void FreeUnused() {
allocator_.FreeUnused();
}
uint32_t GetFreeSize() { return allocator_.GetFreeSize(); }
bool IsInChunk(void* pointer) const {
return pointer >= shm_->memory() && pointer <= &shm_->as_byte_span().back();
}
bool InUseOrFreePending() { return allocator_.InUseOrFreePending(); }
uint32_t bytes_in_use() const { return allocator_.bytes_in_use(); }
FencedAllocator::State GetPointerStatusForTest(void* pointer,
int32_t* token_if_pending) {
return allocator_.GetPointerStatusForTest(pointer, token_if_pending);
}
private:
int32_t shm_id_;
scoped_refptr<gpu::Buffer> shm_;
FencedAllocatorWrapper allocator_;
};
class GPU_COMMAND_BUFFER_CLIENT_EXPORT MappedMemoryManager {
public:
enum MemoryLimit {
kNoLimit = 0,
};
MappedMemoryManager(CommandBufferHelper* helper,
size_t unused_memory_reclaim_limit);
MappedMemoryManager(const MappedMemoryManager&) = delete;
MappedMemoryManager& operator=(const MappedMemoryManager&) = delete;
~MappedMemoryManager();
uint32_t chunk_size_multiple() const { return chunk_size_multiple_; }
void set_chunk_size_multiple(uint32_t multiple) {
DCHECK(std::has_single_bit(multiple));
DCHECK_GE(multiple, FencedAllocator::kAllocAlignment);
chunk_size_multiple_ = multiple;
}
size_t max_allocated_bytes() const {
return max_allocated_bytes_;
}
void set_max_allocated_bytes(size_t max_allocated_bytes) {
max_allocated_bytes_ = max_allocated_bytes;
}
void* Alloc(uint32_t size,
int32_t* shm_id,
uint32_t* shm_offset,
TransferBufferAllocationOption option =
TransferBufferAllocationOption::kLoseContextOnOOM);
void Free(void* pointer);
void FreePendingToken(void* pointer, int32_t token);
void FreeUnused();
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd);
size_t num_chunks() const {
return chunks_.size();
}
size_t bytes_in_use() const {
size_t bytes_in_use = 0;
for (size_t ii = 0; ii < chunks_.size(); ++ii) {
bytes_in_use += chunks_[ii]->bytes_in_use();
}
return bytes_in_use;
}
size_t allocated_memory() const {
return allocated_memory_;
}
FencedAllocator::State GetPointerStatusForTest(void* pointer,
int32_t* token_if_pending);
private:
typedef std::vector<std::unique_ptr<MemoryChunk>> MemoryChunkVector;
uint32_t chunk_size_multiple_;
raw_ptr<CommandBufferHelper> helper_;
MemoryChunkVector chunks_;
size_t allocated_memory_;
size_t max_free_bytes_;
size_t max_allocated_bytes_;
int tracing_id_;
};
class GPU_COMMAND_BUFFER_CLIENT_EXPORT ScopedMappedMemoryPtr {
public:
ScopedMappedMemoryPtr(uint32_t size,
CommandBufferHelper* helper,
MappedMemoryManager* mapped_memory_manager)
: buffer_(nullptr),
size_(0),
shm_id_(0),
shm_offset_(0),
flush_after_release_(false),
helper_(helper),
mapped_memory_manager_(mapped_memory_manager) {
Reset(size);
}
ScopedMappedMemoryPtr(const ScopedMappedMemoryPtr&) = delete;
ScopedMappedMemoryPtr& operator=(const ScopedMappedMemoryPtr&) = delete;
~ScopedMappedMemoryPtr() {
Release();
}
bool valid() const { return buffer_ != nullptr; }
void SetFlushAfterRelease(bool flush_after_release) {
flush_after_release_ = flush_after_release;
}
uint32_t size() const {
return size_;
}
int32_t shm_id() const {
return shm_id_;
}
uint32_t offset() const {
return shm_offset_;
}
void* address() const {
return buffer_;
}
base::span<uint8_t> as_byte_span() {
return UNSAFE_TODO(base::span(static_cast<uint8_t*>(buffer_), size_));
}
base::span<const uint8_t> as_byte_span() const {
return UNSAFE_TODO(base::span(static_cast<const uint8_t*>(buffer_), size_));
}
void Release();
void Reset(uint32_t new_size);
private:
raw_ptr<void> buffer_;
uint32_t size_;
int32_t shm_id_;
uint32_t shm_offset_;
bool flush_after_release_;
raw_ptr<CommandBufferHelper> helper_;
raw_ptr<MappedMemoryManager> mapped_memory_manager_;
};
}
#endif