Skip to content

Commit ba23336

Browse files
committed
it had to be my previous streaming buffer *which uses general purpose under the hood* as it was but with linear suballocator & more clever block upstream loop; update the code, make it work
1 parent b083751 commit ba23336

File tree

3 files changed

+39
-49
lines changed

3 files changed

+39
-49
lines changed

examples_tests

include/nbl/ext/ImGui/ImGui.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ class UI final : public core::IReferenceCounted
1111
public:
1212
struct MDI
1313
{
14-
using COMPOSE_T = nbl::video::IGPUBuffer; //! composes memory available for the allocator which allocates submemory ranges
15-
using ALLOCATOR_TRAITS_T = nbl::core::address_allocator_traits<nbl::core::GeneralpurposeAddressAllocator<uint32_t>>; //! traits for MDI buffer allocator - requests memory range from the compose memory
14+
using COMPOSE_T = nbl::video::StreamingTransientDataBufferST<nbl::core::allocator<uint8_t>>; //! composes memory available for the general purpose allocator to suballocate memory ranges
1615
using SUBALLOCATOR_TRAITS_T = nbl::core::address_allocator_traits<nbl::core::LinearAddressAllocatorST<uint32_t>>; //! traits for MDI buffer suballocator - fills the data given the mdi allocator memory request
1716

1817
enum E_BUFFER_CONTENT : uint8_t
@@ -25,7 +24,6 @@ class UI final : public core::IReferenceCounted
2524
EBC_COUNT,
2625
};
2726

28-
typename ALLOCATOR_TRAITS_T::allocator_type allocator; //! mdi buffer allocator
2927
nbl::core::smart_refctd_ptr<typename COMPOSE_T> buffer; //! streaming mdi buffer
3028

3129
static constexpr auto MDI_BUFFER_REQUIRED_ALLOCATE_FLAGS = nbl::core::bitflag<nbl::video::IDeviceMemoryAllocation::E_MEMORY_ALLOCATE_FLAGS>(nbl::video::IDeviceMemoryAllocation::EMAF_DEVICE_ADDRESS_BIT); //! required flags
@@ -93,7 +91,7 @@ class UI final : public core::IReferenceCounted
9391
bool update(const S_UPDATE_PARAMETERS& params);
9492

9593
//! updates mapped mdi buffer & records *gpu* draw command, you are required to bind UI's graphics pipeline & descriptor sets before calling this function - use getPipeline() to get the pipeline & getCreationParameters() to get info about your set resources
96-
bool render(nbl::video::IGPUCommandBuffer* commandBuffer, const std::span<const VkRect2D> scissors = {});
94+
bool render(nbl::video::IGPUCommandBuffer* const commandBuffer, nbl::video::ISemaphore::SWaitInfo waitInfo, const std::span<const VkRect2D> scissors = {});
9795

9896
//! registers lambda listener in which ImGUI calls should be recorded
9997
size_t registerListener(std::function<void()> const& listener);
@@ -114,9 +112,6 @@ class UI final : public core::IReferenceCounted
114112
//! mdi streaming buffer
115113
inline typename MDI::COMPOSE_T* getStreamingBuffer() { return m_mdi.buffer.get(); }
116114

117-
//! mdi buffer allocator
118-
inline typename MDI::ALLOCATOR_TRAITS_T::allocator_type* getStreamingAllocator() { return &m_mdi.allocator; }
119-
120115
//! ImGUI context, you are supposed to cast it, eg. reinterpret_cast<ImGuiContext*>(this->getContext());
121116
void* getContext();
122117
private:

src/nbl/ext/ImGui/ImGui.cpp

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ using namespace nbl::ui;
2020

2121
namespace nbl::ext::imgui
2222
{
23+
using MDI_SIZE_TYPE = typename UI::MDI::COMPOSE_T::size_type;
24+
static constexpr auto INVALID_ADDRESS = UI::MDI::COMPOSE_T::invalid_value;
2325
static constexpr auto MDI_COMPONENT_COUNT = UI::MDI::EBC_COUNT;
24-
static constexpr auto MDI_ALIGNMENTS = std::to_array<typename UI::MDI::ALLOCATOR_TRAITS_T::size_type>({ alignof(VkDrawIndexedIndirectCommand), alignof(PerObjectData), alignof(ImDrawIdx), alignof(ImDrawVert) });
26+
static constexpr auto MDI_ALIGNMENTS = std::to_array<MDI_SIZE_TYPE>({ alignof(VkDrawIndexedIndirectCommand), alignof(PerObjectData), alignof(ImDrawIdx), alignof(ImDrawVert) });
2527
static constexpr auto MDI_MAX_ALIGNMENT = *std::max_element(MDI_ALIGNMENTS.begin(), MDI_ALIGNMENTS.end());
2628

2729
void UI::createPipeline()
@@ -865,15 +867,12 @@ namespace nbl::ext::imgui
865867
if (!memory->map({ 0ull, memoryReqs.size }, getRequiredAccessFlags(memory->getMemoryPropertyFlags())))
866868
m_creationParams.utilities->getLogger()->log("Could not map device memory!", system::ILogger::ELL_ERROR);
867869

868-
m_mdi.buffer = std::move(buffer);
870+
m_mdi.buffer = core::make_smart_refctd_ptr<MDI::COMPOSE_T>(asset::SBufferRange<video::IGPUBuffer>{0ull, mdiCreationParams.size, std::move(buffer)}, maxStreamingBufferAllocationAlignment, minStreamingBufferAllocationSize);
869871
}
870872

871-
auto buffer = m_mdi.buffer;
873+
auto buffer = m_mdi.buffer->getBuffer();
872874
auto binding = buffer->getBoundMemory();
873875

874-
constexpr auto ALIGN_OFFSET = 0u, MIN_BLOCK_SIZE = 1024u;
875-
m_mdi.allocator = MDI::ALLOCATOR_TRAITS_T::allocator_type(binding.memory->getMappedPointer(), binding.offset, ALIGN_OFFSET, MDI_MAX_ALIGNMENT, binding.memory->getAllocationSize(), MIN_BLOCK_SIZE);
876-
877876
const auto validation = std::to_array
878877
({
879878
std::make_pair(buffer->getCreationParams().usage.hasFlags(MDI::MDI_BUFFER_REQUIRED_USAGE_FLAGS), "MDI buffer must be created with IBuffer::EUF_INDIRECT_BUFFER_BIT | IBuffer::EUF_INDEX_BUFFER_BIT | IBuffer::EUF_VERTEX_BUFFER_BIT | IBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT enabled!"),
@@ -891,10 +890,7 @@ namespace nbl::ext::imgui
891890
}
892891
}
893892

894-
template<typename T>
895-
concept ImDrawBufferType = std::same_as<T, ImDrawVert> || std::same_as<T, ImDrawIdx>;
896-
897-
bool UI::render(nbl::video::IGPUCommandBuffer* commandBuffer, const std::span<const VkRect2D> scissors)
893+
bool UI::render(nbl::video::IGPUCommandBuffer* const commandBuffer, nbl::video::ISemaphore::SWaitInfo waitInfo, const std::span<const VkRect2D> scissors)
898894
{
899895
if (!commandBuffer)
900896
{
@@ -991,8 +987,8 @@ namespace nbl::ext::imgui
991987

992988
struct MDI_PARAMS
993989
{
994-
std::array<typename MDI::ALLOCATOR_TRAITS_T::size_type, MDI_COMPONENT_COUNT> bytesToFill = {}; //! used with MDI::E_BUFFER_CONTENT for elements
995-
typename MDI::ALLOCATOR_TRAITS_T::size_type totalByteSizeRequest = {}, //! sum of bytesToFill
990+
std::array<MDI_SIZE_TYPE, MDI_COMPONENT_COUNT> bytesToFill = {}; //! used with MDI::E_BUFFER_CONTENT for elements
991+
MDI_SIZE_TYPE totalByteSizeRequest = {}, //! sum of bytesToFill
996992
drawCount = {}; //! amount of indirect draw objects
997993
};
998994

@@ -1018,52 +1014,51 @@ namespace nbl::ext::imgui
10181014

10191015
std::array<bool, MDI_COMPONENT_COUNT> mdiBytesFilled;
10201016
std::fill(mdiBytesFilled.data(), mdiBytesFilled.data() + MDI_COMPONENT_COUNT, false);
1021-
std::array<typename MDI::ALLOCATOR_TRAITS_T::size_type, MDI_COMPONENT_COUNT> mdiOffsets;
1022-
std::fill(mdiOffsets.data(), mdiOffsets.data() + MDI_COMPONENT_COUNT, MDI::ALLOCATOR_TRAITS_T::allocator_type::invalid_address);
1017+
std::array<MDI_SIZE_TYPE, MDI_COMPONENT_COUNT> mdiOffsets;
1018+
std::fill(mdiOffsets.data(), mdiOffsets.data() + MDI_COMPONENT_COUNT, INVALID_ADDRESS);
10231019

1024-
auto mdiBuffer = m_mdi.buffer;
1020+
auto streamingBuffer = m_mdi.buffer;
10251021
{
1026-
auto binding = mdiBuffer->getBoundMemory();
1022+
auto binding = streamingBuffer->getBuffer()->getBoundMemory();
10271023
assert(binding.memory->isCurrentlyMapped());
10281024

1029-
auto* const mdiData = reinterpret_cast<uint8_t*>(binding.memory->getMappedPointer()) + binding.offset;
1025+
auto* const mdiData = reinterpret_cast<uint8_t*>(streamingBuffer->getBufferPointer());
10301026

10311027
struct
10321028
{
1033-
typename MDI::ALLOCATOR_TRAITS_T::size_type offset = MDI::ALLOCATOR_TRAITS_T::allocator_type::invalid_address,
1029+
MDI_SIZE_TYPE offset = INVALID_ADDRESS,
10341030
multiAllocationSize = {};
10351031
} requestState;
10361032

10371033
const auto start = std::chrono::steady_clock::now();
1038-
float blockRequestFactor = 1.f;
1039-
requestState.multiAllocationSize = m_mdi.allocator.max_size(); // first we will try with single allocation request given max free block size from the allocator
10401034

10411035
//! we must upload entire MDI buffer data to our streaming buffer, but we cannot guarantee allocation can be done in single request
1042-
for (typename MDI::ALLOCATOR_TRAITS_T::size_type uploadedSize = 0ull; uploadedSize < mdiParams.totalByteSizeRequest;)
1036+
for (MDI_SIZE_TYPE uploadedSize = 0ull; uploadedSize < mdiParams.totalByteSizeRequest;)
10431037
{
10441038
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
10451039

10461040
if (elapsed.count() >= 1u)
1041+
{
1042+
streamingBuffer->cull_frees();
10471043
return false;
1044+
}
10481045

1049-
const auto leftSizeToUpload = mdiParams.totalByteSizeRequest - uploadedSize,
1050-
maxTotalFreeBlockSizeToAlloc = m_mdi.allocator.max_size();
1051-
1052-
MDI::ALLOCATOR_TRAITS_T::multi_alloc_addr(m_mdi.allocator, 1u, &requestState.offset, &requestState.multiAllocationSize, &MDI_MAX_ALIGNMENT);
1046+
requestState.offset = INVALID_ADDRESS;
1047+
requestState.multiAllocationSize = streamingBuffer->max_size(); // request available block memory size which we can try to allocate
10531048

1054-
if (requestState.offset == MDI::ALLOCATOR_TRAITS_T::allocator_type::invalid_address)
1055-
{
1056-
requestState.multiAllocationSize = (blockRequestFactor *= 0.5f); // failed? our following allocation reqest will be half of the previous
1057-
continue;
1058-
}
1049+
static constexpr auto STREAMING_ALLOCATION_COUNT = 1u;
1050+
const size_t unallocatedSize = m_mdi.buffer->multi_allocate(std::chrono::steady_clock::now() + std::chrono::microseconds(100u), STREAMING_ALLOCATION_COUNT, &requestState.offset, &requestState.multiAllocationSize, &MDI_MAX_ALIGNMENT); //! (*) note we request single tight chunk of memory with max alignment instead of MDI::E_BUFFER_CONTENT separate chunks
1051+
1052+
if (requestState.offset == INVALID_ADDRESS)
1053+
continue; // failed? lets try again, TODO: should I here have my "blockMemoryFactor =* 0.5" and apply to requestState.multiAllocationSize?
10591054
else
10601055
{
10611056
static constexpr auto ALIGN_OFFSET_NEEDED = 0u;
1062-
MDI::SUBALLOCATOR_TRAITS_T::allocator_type fillSubAllocator(mdiData, requestState.offset, ALIGN_OFFSET_NEEDED, MDI_MAX_ALIGNMENT, requestState.multiAllocationSize);
1057+
MDI::SUBALLOCATOR_TRAITS_T::allocator_type fillSubAllocator(mdiData, requestState.offset, ALIGN_OFFSET_NEEDED, MDI_MAX_ALIGNMENT, requestState.multiAllocationSize); //! (*) we create linear suballocator to fill the chunk memory (some of at least) with MDI::E_BUFFER_CONTENT data
10631058

1064-
std::array<typename MDI::ALLOCATOR_TRAITS_T::size_type, MDI_COMPONENT_COUNT> offsets;
1065-
std::fill(offsets.data(), offsets.data() + MDI_COMPONENT_COUNT, MDI::ALLOCATOR_TRAITS_T::allocator_type::invalid_address);
1066-
MDI::SUBALLOCATOR_TRAITS_T::multi_alloc_addr(fillSubAllocator, offsets.size(), offsets.data(), mdiParams.bytesToFill.data(), MDI_ALIGNMENTS.data());
1059+
std::array<MDI_SIZE_TYPE, MDI_COMPONENT_COUNT> offsets;
1060+
std::fill(offsets.data(), offsets.data() + MDI_COMPONENT_COUNT, INVALID_ADDRESS);
1061+
MDI::SUBALLOCATOR_TRAITS_T::multi_alloc_addr(fillSubAllocator, offsets.size(), offsets.data(), mdiParams.bytesToFill.data(), MDI_ALIGNMENTS.data()); //! (*) we suballocate memory regions from the allocated chunk with required alignment per MDI::E_BUFFER_CONTENT block
10671062

10681063
//! linear allocator is used to fill the mdi data within suballocation memory range,
10691064
//! there are a few restrictions regarding how MDI::E_BUFFER_CONTENT(s) can be packed,
@@ -1073,9 +1068,9 @@ namespace nbl::ext::imgui
10731068

10741069
auto fillDrawBuffers = [&]<MDI::E_BUFFER_CONTENT type>()
10751070
{
1076-
const typename MDI::ALLOCATOR_TRAITS_T::size_type globalBlockOffset = offsets[type];
1071+
const MDI_SIZE_TYPE globalBlockOffset = offsets[type];
10771072

1078-
if (globalBlockOffset == MDI::ALLOCATOR_TRAITS_T::allocator_type::invalid_address or mdiBytesFilled[type])
1073+
if (globalBlockOffset == INVALID_ADDRESS or mdiBytesFilled[type])
10791074
return 0u;
10801075

10811076
auto* data = mdiData + globalBlockOffset;
@@ -1105,9 +1100,9 @@ namespace nbl::ext::imgui
11051100

11061101
auto fillIndirectStructures = [&]<MDI::E_BUFFER_CONTENT type>()
11071102
{
1108-
const typename MDI::ALLOCATOR_TRAITS_T::size_type globalBlockOffset = offsets[type];
1103+
const MDI_SIZE_TYPE globalBlockOffset = offsets[type];
11091104

1110-
if (globalBlockOffset == MDI::ALLOCATOR_TRAITS_T::allocator_type::invalid_address or mdiBytesFilled[type])
1105+
if (globalBlockOffset == INVALID_ADDRESS or mdiBytesFilled[type])
11111106
return 0u;
11121107

11131108
auto* const data = mdiData + globalBlockOffset;
@@ -1172,20 +1167,20 @@ namespace nbl::ext::imgui
11721167
uploadedSize += fillIndirectStructures.template operator() < MDI::EBC_DRAW_INDIRECT_STRUCTURES > ();
11731168
uploadedSize += fillIndirectStructures.template operator() < MDI::EBC_ELEMENT_STRUCTURES > ();
11741169
}
1175-
1176-
MDI::ALLOCATOR_TRAITS_T::multi_free_addr(m_mdi.allocator, 1u, &requestState.offset, &requestState.multiAllocationSize);
1170+
streamingBuffer->multi_deallocate(STREAMING_ALLOCATION_COUNT, &requestState.offset, &requestState.multiAllocationSize, waitInfo); //! (*) block allocated, we just latch offsets deallocation to keep it alive as long as required
11771171
}
11781172
}
11791173

11801174
assert([&mdiOffsets]() -> bool
11811175
{
11821176
for (const auto& offset : mdiOffsets)
1183-
if (offset == MDI::ALLOCATOR_TRAITS_T::allocator_type::invalid_address)
1177+
if (offset == INVALID_ADDRESS)
11841178
return false; // we should never hit this at this point
11851179

11861180
return true;
11871181
}()); // debug check only
11881182

1183+
auto mdiBuffer = smart_refctd_ptr<IGPUBuffer>(m_mdi.buffer->getBuffer());
11891184
const auto offset = mdiBuffer->getBoundMemory().offset;
11901185
{
11911186
const asset::SBufferBinding<const video::IGPUBuffer> binding =

0 commit comments

Comments
 (0)