- Deleted clipboard-related files (clipboard.cc, clipboard.h, clipboard.mm) to streamline the codebase. - Added a performance dashboard in the EditorManager to monitor performance metrics and improve user experience. - Integrated performance monitoring capabilities across various editors, allowing for detailed timing of critical operations. - Updated the graphics system with batch processing for texture updates, significantly improving rendering performance. - Introduced a memory pool allocator for efficient memory management during graphics operations.
161 lines
4.2 KiB
C++
161 lines
4.2 KiB
C++
#include "app/gfx/memory_pool.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
namespace yaze {
|
|
namespace gfx {
|
|
|
|
using MemoryBlock = MemoryPool::MemoryBlock;
|
|
|
|
MemoryPool& MemoryPool::Get() {
|
|
static MemoryPool instance;
|
|
return instance;
|
|
}
|
|
|
|
MemoryPool::MemoryPool()
|
|
: total_allocations_(0), total_deallocations_(0),
|
|
total_used_bytes_(0), total_allocated_bytes_(0) {
|
|
// Initialize block pools with common graphics sizes
|
|
InitializeBlockPool(small_blocks_, kSmallBlockSize, 100); // 100KB for small tiles
|
|
InitializeBlockPool(medium_blocks_, kMediumBlockSize, 50); // 200KB for medium tiles
|
|
InitializeBlockPool(large_blocks_, kLargeBlockSize, 20); // 320KB for large tiles
|
|
InitializeBlockPool(huge_blocks_, kHugeBlockSize, 10); // 640KB for graphics sheets
|
|
|
|
total_allocated_bytes_ = (100 * kSmallBlockSize) + (50 * kMediumBlockSize) +
|
|
(20 * kLargeBlockSize) + (10 * kHugeBlockSize);
|
|
}
|
|
|
|
MemoryPool::~MemoryPool() {
|
|
Clear();
|
|
}
|
|
|
|
void* MemoryPool::Allocate(size_t size) {
|
|
total_allocations_++;
|
|
|
|
MemoryBlock* block = FindFreeBlock(size);
|
|
if (!block) {
|
|
// Fallback to system malloc if no pool block available
|
|
void* data = std::malloc(size);
|
|
if (data) {
|
|
total_used_bytes_ += size;
|
|
allocated_blocks_[data] = nullptr; // Mark as system allocated
|
|
}
|
|
return data;
|
|
}
|
|
|
|
block->in_use = true;
|
|
total_used_bytes_ += block->size;
|
|
allocated_blocks_[block->data] = block;
|
|
|
|
return block->data;
|
|
}
|
|
|
|
void MemoryPool::Deallocate(void* ptr) {
|
|
if (!ptr) return;
|
|
|
|
total_deallocations_++;
|
|
|
|
auto it = allocated_blocks_.find(ptr);
|
|
if (it == allocated_blocks_.end()) {
|
|
// System allocated, use free
|
|
std::free(ptr);
|
|
return;
|
|
}
|
|
|
|
MemoryBlock* block = it->second;
|
|
if (block) {
|
|
block->in_use = false;
|
|
total_used_bytes_ -= block->size;
|
|
}
|
|
|
|
allocated_blocks_.erase(it);
|
|
}
|
|
|
|
void* MemoryPool::AllocateAligned(size_t size, size_t alignment) {
|
|
// For simplicity, allocate extra space and align manually
|
|
// In a production system, you'd want more sophisticated alignment handling
|
|
size_t aligned_size = size + alignment - 1;
|
|
void* ptr = Allocate(aligned_size);
|
|
|
|
if (ptr) {
|
|
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
|
|
uintptr_t aligned_addr = (addr + alignment - 1) & ~(alignment - 1);
|
|
return reinterpret_cast<void*>(aligned_addr);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
std::pair<size_t, size_t> MemoryPool::GetMemoryStats() const {
|
|
return {total_used_bytes_, total_allocated_bytes_};
|
|
}
|
|
|
|
std::pair<size_t, size_t> MemoryPool::GetAllocationStats() const {
|
|
return {total_allocations_, total_deallocations_};
|
|
}
|
|
|
|
void MemoryPool::Clear() {
|
|
// Reset all blocks to unused state
|
|
for (auto& block : small_blocks_) {
|
|
block.in_use = false;
|
|
}
|
|
for (auto& block : medium_blocks_) {
|
|
block.in_use = false;
|
|
}
|
|
for (auto& block : large_blocks_) {
|
|
block.in_use = false;
|
|
}
|
|
for (auto& block : huge_blocks_) {
|
|
block.in_use = false;
|
|
}
|
|
|
|
allocated_blocks_.clear();
|
|
total_used_bytes_ = 0;
|
|
}
|
|
|
|
MemoryBlock* MemoryPool::FindFreeBlock(size_t size) {
|
|
// Determine which pool to use based on size
|
|
size_t pool_index = GetPoolIndex(size);
|
|
|
|
std::vector<MemoryBlock>* pools[] = {
|
|
&small_blocks_, &medium_blocks_, &large_blocks_, &huge_blocks_
|
|
};
|
|
|
|
if (pool_index >= 4) {
|
|
return nullptr; // Size too large for any pool
|
|
}
|
|
|
|
auto& pool = *pools[pool_index];
|
|
|
|
// Find first unused block
|
|
auto it = std::find_if(pool.begin(), pool.end(),
|
|
[](const MemoryBlock& block) { return !block.in_use; });
|
|
|
|
return (it != pool.end()) ? &(*it) : nullptr;
|
|
}
|
|
|
|
void MemoryPool::InitializeBlockPool(std::vector<MemoryBlock>& pool,
|
|
size_t block_size, size_t count) {
|
|
pool.reserve(count);
|
|
|
|
for (size_t i = 0; i < count; ++i) {
|
|
void* data = std::malloc(block_size);
|
|
if (data) {
|
|
pool.emplace_back(data, block_size);
|
|
}
|
|
}
|
|
}
|
|
|
|
size_t MemoryPool::GetPoolIndex(size_t size) const {
|
|
if (size <= kSmallBlockSize) return 0;
|
|
if (size <= kMediumBlockSize) return 1;
|
|
if (size <= kLargeBlockSize) return 2;
|
|
if (size <= kHugeBlockSize) return 3;
|
|
return 4; // Too large for any pool
|
|
}
|
|
|
|
} // namespace gfx
|
|
} // namespace yaze
|