2020-12-05 13:08:24 +01:00
|
|
|
#pragma once
|
2016-04-02 00:18:20 +02:00
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
#include "util/StrFmt.h"
|
2025-10-05 18:28:03 +02:00
|
|
|
#include "rx/asm.hpp"
|
|
|
|
|
#include "rx/align.hpp"
|
2018-09-26 00:14:10 +02:00
|
|
|
|
2016-04-02 00:18:20 +02:00
|
|
|
/**
|
|
|
|
|
* Ring buffer memory helper :
|
2019-06-12 20:02:51 +02:00
|
|
|
* There are 2 "pointers" (offset inside a memory buffer to be provided by class derivative)
|
2016-04-02 00:18:20 +02:00
|
|
|
* PUT pointer "points" to the start of allocatable space.
|
|
|
|
|
* GET pointer "points" to the start of memory in use by the GPU.
|
|
|
|
|
* Space between GET and PUT is used by the GPU ; this structure check that this memory is not overwritten.
|
|
|
|
|
* User has to update the GET pointer when synchronisation happens.
|
|
|
|
|
*/
|
2019-11-09 14:14:21 +01:00
|
|
|
class data_heap
|
2016-04-02 00:18:20 +02:00
|
|
|
{
|
2019-11-09 14:14:21 +01:00
|
|
|
protected:
|
2016-04-02 00:18:20 +02:00
|
|
|
/**
|
2025-04-05 21:50:45 +02:00
|
|
|
* Does alloc cross get position ?
|
|
|
|
|
*/
|
|
|
|
|
template <int Alignment>
|
2020-12-18 08:39:54 +01:00
|
|
|
bool can_alloc(usz size) const
|
2016-04-02 00:18:20 +02:00
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
usz alloc_size = rx::alignUp(size, Alignment);
|
|
|
|
|
usz aligned_put_pos = rx::alignUp(m_put_pos, Alignment);
|
2016-04-02 00:18:20 +02:00
|
|
|
if (aligned_put_pos + alloc_size < m_size)
|
|
|
|
|
{
|
|
|
|
|
// range before get
|
|
|
|
|
if (aligned_put_pos + alloc_size < m_get_pos)
|
|
|
|
|
return true;
|
|
|
|
|
// range after get
|
|
|
|
|
if (aligned_put_pos > m_get_pos)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// ..]....[..get..
|
|
|
|
|
if (aligned_put_pos < m_get_pos)
|
|
|
|
|
return false;
|
|
|
|
|
// ..get..]...[...
|
|
|
|
|
// Actually all resources extending beyond heap space starts at 0
|
|
|
|
|
if (alloc_size > m_get_pos)
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-27 17:51:20 +02:00
|
|
|
// Grow the buffer to hold at least size bytes
|
2020-12-18 08:39:54 +01:00
|
|
|
virtual bool grow(usz /*size*/)
|
2019-11-09 14:14:21 +01:00
|
|
|
{
|
|
|
|
|
// Stub
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-18 08:39:54 +01:00
|
|
|
usz m_size;
|
2025-04-05 21:50:45 +02:00
|
|
|
usz m_put_pos; // Start of free space
|
|
|
|
|
usz m_min_guard_size; // If an allocation touches the guard region, reset the heap to avoid going over budget
|
2020-12-18 08:39:54 +01:00
|
|
|
usz m_current_allocated_size;
|
|
|
|
|
usz m_largest_allocated_pool;
|
2017-10-21 23:12:32 +02:00
|
|
|
|
|
|
|
|
char* m_name;
|
2025-04-05 21:50:45 +02:00
|
|
|
|
2016-04-02 00:18:20 +02:00
|
|
|
public:
|
|
|
|
|
data_heap() = default;
|
|
|
|
|
~data_heap() = default;
|
|
|
|
|
data_heap(const data_heap&) = delete;
|
|
|
|
|
data_heap(data_heap&&) = delete;
|
|
|
|
|
|
2020-12-18 08:39:54 +01:00
|
|
|
usz m_get_pos; // End of free space
|
2016-04-02 00:18:20 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
void init(usz heap_size, const char* buffer_name = "unnamed", usz min_guard_size = 0x10000)
|
2016-04-02 00:18:20 +02:00
|
|
|
{
|
2017-10-21 23:12:32 +02:00
|
|
|
m_name = const_cast<char*>(buffer_name);
|
|
|
|
|
|
2016-04-02 00:18:20 +02:00
|
|
|
m_size = heap_size;
|
|
|
|
|
m_put_pos = 0;
|
|
|
|
|
m_get_pos = heap_size - 1;
|
2017-06-10 22:32:17 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
// allocation stats
|
2017-06-10 22:32:17 +02:00
|
|
|
m_min_guard_size = min_guard_size;
|
|
|
|
|
m_current_allocated_size = 0;
|
|
|
|
|
m_largest_allocated_pool = 0;
|
2016-04-02 00:18:20 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
template <int Alignment>
|
2020-12-18 08:39:54 +01:00
|
|
|
usz alloc(usz size)
|
2016-04-02 00:18:20 +02:00
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
const usz alloc_size = rx::alignUp(size, Alignment);
|
|
|
|
|
const usz aligned_put_pos = rx::alignUp(m_put_pos, Alignment);
|
2019-11-09 14:14:21 +01:00
|
|
|
|
2021-07-27 17:51:20 +02:00
|
|
|
if (!can_alloc<Alignment>(size) && !grow(alloc_size))
|
2017-06-19 12:47:38 +02:00
|
|
|
{
|
2020-12-09 16:04:52 +01:00
|
|
|
fmt::throw_exception("[%s] Working buffer not big enough, buffer_length=%d allocated=%d requested=%d guard=%d largest_pool=%d",
|
2025-04-05 21:50:45 +02:00
|
|
|
m_name, m_size, m_current_allocated_size, size, m_min_guard_size, m_largest_allocated_pool);
|
2017-06-19 12:47:38 +02:00
|
|
|
}
|
|
|
|
|
|
2020-12-18 08:39:54 +01:00
|
|
|
const usz block_length = (aligned_put_pos - m_put_pos) + alloc_size;
|
2017-06-10 22:32:17 +02:00
|
|
|
m_current_allocated_size += block_length;
|
|
|
|
|
m_largest_allocated_pool = std::max(m_largest_allocated_pool, block_length);
|
|
|
|
|
|
2016-04-02 00:18:20 +02:00
|
|
|
if (aligned_put_pos + alloc_size < m_size)
|
|
|
|
|
{
|
|
|
|
|
m_put_pos = aligned_put_pos + alloc_size;
|
|
|
|
|
return aligned_put_pos;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_put_pos = alloc_size;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-04-05 21:50:45 +02:00
|
|
|
* return current putpos - 1
|
|
|
|
|
*/
|
2020-12-18 08:39:54 +01:00
|
|
|
usz get_current_put_pos_minus_one() const
|
2016-04-02 00:18:20 +02:00
|
|
|
{
|
2019-08-31 13:34:45 +02:00
|
|
|
return (m_put_pos > 0) ? m_put_pos - 1 : m_size - 1;
|
2016-04-02 00:18:20 +02:00
|
|
|
}
|
2020-03-07 10:29:23 +01:00
|
|
|
|
2019-11-10 08:34:53 +01:00
|
|
|
virtual bool is_critical() const
|
2017-06-10 22:32:17 +02:00
|
|
|
{
|
2020-12-18 08:39:54 +01:00
|
|
|
const usz guard_length = std::max(m_min_guard_size, m_largest_allocated_pool);
|
2018-02-03 14:42:02 +01:00
|
|
|
return (m_current_allocated_size + guard_length) >= m_size;
|
2017-06-10 22:32:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void reset_allocation_stats()
|
|
|
|
|
{
|
|
|
|
|
m_current_allocated_size = 0;
|
|
|
|
|
m_largest_allocated_pool = 0;
|
|
|
|
|
m_get_pos = get_current_put_pos_minus_one();
|
|
|
|
|
}
|
2017-09-22 17:39:48 +02:00
|
|
|
|
|
|
|
|
// Updates the current_allocated_size metrics
|
|
|
|
|
void notify()
|
|
|
|
|
{
|
2021-05-22 20:46:10 +02:00
|
|
|
if (m_get_pos == umax)
|
2017-09-22 17:39:48 +02:00
|
|
|
m_current_allocated_size = 0;
|
|
|
|
|
else if (m_get_pos < m_put_pos)
|
|
|
|
|
m_current_allocated_size = (m_put_pos - m_get_pos - 1);
|
|
|
|
|
else if (m_get_pos > m_put_pos)
|
|
|
|
|
m_current_allocated_size = (m_put_pos + (m_size - m_get_pos - 1));
|
|
|
|
|
else
|
2020-12-09 16:04:52 +01:00
|
|
|
fmt::throw_exception("m_put_pos == m_get_pos!");
|
2017-09-22 17:39:48 +02:00
|
|
|
}
|
2018-02-21 18:50:27 +01:00
|
|
|
|
2020-12-18 08:39:54 +01:00
|
|
|
usz size() const
|
2018-02-21 18:50:27 +01:00
|
|
|
{
|
|
|
|
|
return m_size;
|
|
|
|
|
}
|
2016-04-02 00:18:20 +02:00
|
|
|
};
|