Documentation
¶
Overview ¶
Package memory provides GPU memory allocation for Vulkan backend.
Architecture ¶
The memory subsystem is organized in layers:
┌─────────────────────────────────────────────────────────┐ │ GpuAllocator │ │ (High-level API: Alloc/Free, memory type selection) │ ├─────────────────────────────────────────────────────────┤ │ MemoryTypePool │ │ (Per memory-type pools, dedicated allocation logic) │ ├─────────────────────────────────────────────────────────┤ │ BuddyAllocator │ │ (Power-of-2 block management, O(log n) operations) │ ├─────────────────────────────────────────────────────────┤ │ Vulkan Memory API │ │ (vkAllocateMemory, vkFreeMemory, vkMapMemory) │ └─────────────────────────────────────────────────────────┘
Buddy Allocator ¶
Implements classic buddy allocation algorithm:
- Memory divided into power-of-2 blocks
- Blocks split recursively until desired size reached
- Adjacent "buddy" blocks merged on free
- O(log n) allocation and deallocation
- Minimal external fragmentation
Memory Type Selection ¶
Vulkan exposes multiple memory types with different properties:
- DEVICE_LOCAL: Fast GPU access, no CPU access
- HOST_VISIBLE: CPU can map and access
- HOST_COHERENT: No flush/invalidate needed
- HOST_CACHED: CPU reads are cached
The allocator selects optimal memory type based on usage flags.
Allocation Strategies ¶
- Pooled: Small/medium allocations suballocated from large blocks
- Dedicated: Large allocations (>32MB) get their own VkDeviceMemory
- External: Memory imported from outside (not managed by allocator)
Thread Safety ¶
GpuAllocator is thread-safe. Internal synchronization via mutex. Individual MemoryBlock handles are not thread-safe.
Index ¶
- Variables
- type AllocationRequest
- type AllocatorConfig
- type AllocatorStats
- type BuddyAllocator
- type BuddyBlock
- type BuddyStats
- type DeviceMemoryProperties
- type GpuAllocator
- func (a *GpuAllocator) Alloc(req AllocationRequest) (*MemoryBlock, error)
- func (a *GpuAllocator) Destroy()
- func (a *GpuAllocator) Free(block *MemoryBlock) error
- func (a *GpuAllocator) PoolStats(memTypeIndex uint32) (PoolStats, bool)
- func (a *GpuAllocator) Selector() *MemoryTypeSelector
- func (a *GpuAllocator) Stats() AllocatorStats
- type MemoryBlock
- type MemoryHeap
- type MemoryPool
- type MemoryType
- type MemoryTypeSelector
- func (s *MemoryTypeSelector) GetHeapSize(heapIndex uint32) uint64
- func (s *MemoryTypeSelector) GetMemoryType(index uint32) (MemoryType, bool)
- func (s *MemoryTypeSelector) IsDeviceLocal(typeIndex uint32) bool
- func (s *MemoryTypeSelector) IsHostVisible(typeIndex uint32) bool
- func (s *MemoryTypeSelector) SelectMemoryType(req AllocationRequest) (uint32, bool)
- type PoolStats
- type UsageFlags
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoSuitableMemoryType indicates no memory type matches requirements. ErrNoSuitableMemoryType = errors.New("allocator: no suitable memory type") // ErrAllocationFailed indicates Vulkan memory allocation failed. ErrAllocationFailed = errors.New("allocator: allocation failed") // ErrInvalidBlock indicates an invalid memory block. ErrInvalidBlock = errors.New("allocator: invalid memory block") )
var ( // ErrOutOfMemory indicates no suitable block is available. ErrOutOfMemory = errors.New("buddy: out of memory") // ErrInvalidSize indicates the requested size is invalid. ErrInvalidSize = errors.New("buddy: invalid size (zero or too large)") // ErrDoubleFree indicates an attempt to free an unallocated block. ErrDoubleFree = errors.New("buddy: double free or invalid block") // ErrInvalidConfig indicates invalid allocator configuration. ErrInvalidConfig = errors.New("buddy: invalid configuration") )
Functions ¶
This section is empty.
Types ¶
type AllocationRequest ¶ added in v0.2.0
type AllocationRequest struct {
// Size is the required allocation size in bytes.
Size uint64
// Alignment is the required alignment (must be power of 2).
// Use 0 or 1 for no specific alignment beyond block size.
Alignment uint64
// Usage specifies how the memory will be used.
Usage UsageFlags
// MemoryTypeBits is a bitmask of allowed memory type indices.
// Typically from VkMemoryRequirements.memoryTypeBits.
MemoryTypeBits uint32
}
AllocationRequest describes a memory allocation request.
type AllocatorConfig ¶ added in v0.2.0
type AllocatorConfig struct {
// BlockSize is the size of memory blocks allocated from Vulkan.
// Default: 64MB. Must be power of 2.
BlockSize uint64
// MinAllocationSize is the minimum allocation granularity.
// Default: 256 bytes. Must be power of 2.
MinAllocationSize uint64
// DedicatedThreshold is the size above which allocations
// get their own VkDeviceMemory instead of suballocation.
// Default: 32MB.
DedicatedThreshold uint64
// MaxBlocksPerHeap limits memory blocks per heap.
// Default: 8 (512MB per heap with 64MB blocks).
MaxBlocksPerHeap int
}
AllocatorConfig configures the GPU memory allocator.
func DefaultConfig ¶ added in v0.2.0
func DefaultConfig() AllocatorConfig
DefaultConfig returns sensible default configuration.
type AllocatorStats ¶ added in v0.2.0
type AllocatorStats struct {
TotalAllocated uint64 // Total memory allocated from Vulkan
TotalUsed uint64 // Total memory in use
PooledAllocations uint64 // Number of pooled allocations
DedicatedAllocations uint64 // Number of dedicated allocations
AllocationCount uint64 // Total active allocations
}
AllocatorStats contains allocator-wide statistics.
type BuddyAllocator ¶
type BuddyAllocator struct {
// contains filtered or unexported fields
}
BuddyAllocator implements the buddy memory allocation algorithm.
The allocator manages a contiguous region of memory by dividing it into power-of-2 sized blocks. When allocating, blocks are split recursively until the smallest fitting size is found. When freeing, adjacent "buddy" blocks are merged back together.
Time complexity: O(log n) for both allocation and deallocation. Space overhead: O(n) bits for tracking block states.
func NewBuddyAllocator ¶
func NewBuddyAllocator(totalSize, minBlockSize uint64) (*BuddyAllocator, error)
NewBuddyAllocator creates a new buddy allocator.
Parameters:
- totalSize: Total memory to manage (must be power of 2)
- minBlockSize: Smallest allocatable unit (must be power of 2, <= totalSize)
Returns error if parameters are invalid.
func (*BuddyAllocator) Alloc ¶
func (b *BuddyAllocator) Alloc(size uint64) (BuddyBlock, error)
Alloc allocates a block of at least the requested size.
The returned block size will be rounded up to the next power of 2, and at least minBlockSize. Returns ErrOutOfMemory if no suitable block is available, ErrInvalidSize if size is 0 or exceeds totalSize.
func (*BuddyAllocator) Free ¶
func (b *BuddyAllocator) Free(block BuddyBlock) error
Free releases a previously allocated block.
Returns ErrDoubleFree if the block was not allocated or already freed.
func (*BuddyAllocator) Reset ¶
func (b *BuddyAllocator) Reset()
Reset releases all allocations and resets the allocator to initial state.
func (*BuddyAllocator) Stats ¶
func (b *BuddyAllocator) Stats() BuddyStats
Stats returns current allocator statistics.
type BuddyBlock ¶
type BuddyBlock struct {
Offset uint64 // Offset within the managed region
Size uint64 // Actual size (power of 2, >= requested)
// contains filtered or unexported fields
}
BuddyBlock represents an allocated memory block.
type BuddyStats ¶
type BuddyStats struct {
TotalSize uint64 // Total managed memory
AllocatedSize uint64 // Currently allocated
AllocationCount uint64 // Number of active allocations
PeakAllocated uint64 // Peak allocated size
TotalAllocated uint64 // Cumulative allocated (for throughput)
TotalFreed uint64 // Cumulative freed
SplitCount uint64 // Number of block splits
MergeCount uint64 // Number of block merges
}
BuddyStats contains allocator statistics.
type DeviceMemoryProperties ¶ added in v0.2.0
type DeviceMemoryProperties struct {
// MemoryTypes lists all available memory types.
MemoryTypes []MemoryType
// MemoryHeaps lists all available memory heaps.
MemoryHeaps []MemoryHeap
}
DeviceMemoryProperties holds all memory properties for a device.
type GpuAllocator ¶ added in v0.2.0
type GpuAllocator struct {
// contains filtered or unexported fields
}
GpuAllocator is the main GPU memory allocator.
Thread-safe. Use Alloc/Free for all allocations.
func NewGpuAllocator ¶ added in v0.2.0
func NewGpuAllocator(device vk.Device, cmds *vk.Commands, props DeviceMemoryProperties, config AllocatorConfig) (*GpuAllocator, error)
NewGpuAllocator creates a new GPU memory allocator.
Parameters:
- device: Vulkan device handle
- cmds: Vulkan commands for memory operations
- props: Device memory properties from vkGetPhysicalDeviceMemoryProperties
- config: Allocator configuration (use DefaultConfig() for defaults)
func (*GpuAllocator) Alloc ¶ added in v0.2.0
func (a *GpuAllocator) Alloc(req AllocationRequest) (*MemoryBlock, error)
Alloc allocates GPU memory.
For large allocations (>= DedicatedThreshold), creates a dedicated VkDeviceMemory. For smaller allocations, suballocates from a pool using buddy allocation.
func (*GpuAllocator) Destroy ¶ added in v0.2.0
func (a *GpuAllocator) Destroy()
Destroy releases all allocations and cleans up.
Call this before destroying the Vulkan device.
func (*GpuAllocator) Free ¶ added in v0.2.0
func (a *GpuAllocator) Free(block *MemoryBlock) error
Free releases a memory block.
func (*GpuAllocator) PoolStats ¶ added in v0.2.0
func (a *GpuAllocator) PoolStats(memTypeIndex uint32) (PoolStats, bool)
PoolStats returns statistics for a specific memory type pool.
func (*GpuAllocator) Selector ¶ added in v0.2.0
func (a *GpuAllocator) Selector() *MemoryTypeSelector
Selector returns the memory type selector.
func (*GpuAllocator) Stats ¶ added in v0.2.0
func (a *GpuAllocator) Stats() AllocatorStats
Stats returns current allocator statistics.
type MemoryBlock ¶ added in v0.2.0
type MemoryBlock struct {
// Memory is the Vulkan device memory handle.
Memory vk.DeviceMemory
// Offset is the byte offset within the device memory.
Offset uint64
// Size is the allocated size in bytes.
Size uint64
// MappedPtr holds the mapped pointer if memory is mapped.
// Set by Map(), cleared by Unmap().
MappedPtr uintptr
// contains filtered or unexported fields
}
MemoryBlock represents an allocated memory region.
func (*MemoryBlock) IsDedicated ¶ added in v0.2.0
func (b *MemoryBlock) IsDedicated() bool
IsDedicated returns true if this is a dedicated allocation.
func (*MemoryBlock) MemoryTypeIndex ¶ added in v0.2.0
func (b *MemoryBlock) MemoryTypeIndex() uint32
MemoryTypeIndex returns the Vulkan memory type index.
type MemoryHeap ¶ added in v0.2.0
type MemoryHeap struct {
// Size is the total heap size in bytes.
Size uint64
// Flags contains VkMemoryHeapFlags.
Flags vk.MemoryHeapFlags
}
MemoryHeap describes a Vulkan memory heap.
type MemoryPool ¶ added in v0.2.0
type MemoryPool struct {
// contains filtered or unexported fields
}
MemoryPool manages allocations for a single memory type.
type MemoryType ¶ added in v0.2.0
type MemoryType struct {
// PropertyFlags contains VkMemoryPropertyFlags.
PropertyFlags vk.MemoryPropertyFlags
// HeapIndex is the index of the memory heap.
HeapIndex uint32
}
MemoryType describes a Vulkan memory type.
type MemoryTypeSelector ¶ added in v0.2.0
type MemoryTypeSelector struct {
// contains filtered or unexported fields
}
MemoryTypeSelector selects optimal memory types for allocations.
func NewMemoryTypeSelector ¶ added in v0.2.0
func NewMemoryTypeSelector(props DeviceMemoryProperties) *MemoryTypeSelector
NewMemoryTypeSelector creates a selector from device memory properties.
func (*MemoryTypeSelector) GetHeapSize ¶ added in v0.2.0
func (s *MemoryTypeSelector) GetHeapSize(heapIndex uint32) uint64
GetHeapSize returns the size of the specified heap.
func (*MemoryTypeSelector) GetMemoryType ¶ added in v0.2.0
func (s *MemoryTypeSelector) GetMemoryType(index uint32) (MemoryType, bool)
GetMemoryType returns the memory type at the given index.
func (*MemoryTypeSelector) IsDeviceLocal ¶ added in v0.2.0
func (s *MemoryTypeSelector) IsDeviceLocal(typeIndex uint32) bool
IsDeviceLocal returns true if the memory type is device local.
func (*MemoryTypeSelector) IsHostVisible ¶ added in v0.2.0
func (s *MemoryTypeSelector) IsHostVisible(typeIndex uint32) bool
IsHostVisible returns true if the memory type is host visible.
func (*MemoryTypeSelector) SelectMemoryType ¶ added in v0.2.0
func (s *MemoryTypeSelector) SelectMemoryType(req AllocationRequest) (uint32, bool)
SelectMemoryType finds the best memory type for the given request.
Returns the memory type index and true if found, or 0 and false if no suitable type exists.
type PoolStats ¶ added in v0.2.0
type PoolStats struct {
BlockCount int // Number of VkDeviceMemory allocations
TotalSize uint64 // Total allocated from Vulkan
UsedSize uint64 // Currently used by suballocations
AllocationCount uint64 // Number of active suballocations
}
PoolStats contains memory pool statistics.
type UsageFlags ¶ added in v0.2.0
type UsageFlags uint32
UsageFlags specifies intended memory usage. These flags help select the optimal memory type.
const ( // UsageFastDeviceAccess indicates memory primarily accessed by GPU. // Prefers DEVICE_LOCAL memory. UsageFastDeviceAccess UsageFlags = 1 << iota // UsageHostAccess indicates memory needs CPU access. // Requires HOST_VISIBLE memory. UsageHostAccess // UsageUpload indicates memory used for CPU->GPU transfers. // Prefers HOST_VISIBLE + HOST_COHERENT, avoids HOST_CACHED. UsageUpload // UsageDownload indicates memory used for GPU->CPU readback. // Prefers HOST_VISIBLE + HOST_CACHED. UsageDownload // UsageTransient indicates memory for short-lived allocations. // May use LAZILY_ALLOCATED if available. UsageTransient )