22// This file is part of the "Nabla Engine".
33// For conditions of distribution and use, see copyright notice in nabla.h
44
5- #ifndef _NBL_EXT_DRAW_AABB_H_
6- #define _NBL_EXT_DRAW_AABB_H_
5+ #ifndef _NBL_EXT_DEBUG_DRAW_DRAW_AABB_H_
6+ #define _NBL_EXT_DEBUG_DRAW_DRAW_AABB_H_
77
88#include " nbl/video/declarations.h"
99#include " nbl/builtin/hlsl/cpp_compat.hlsl"
1010#include " nbl/builtin/hlsl/shapes/aabb.hlsl"
11+ #include " nbl/builtin/hlsl/math/linalg/fast_affine.hlsl"
1112#include " nbl/ext/DebugDraw/builtin/hlsl/common.hlsl"
1213
1314namespace nbl ::ext::debug_draw
1415{
15- class DrawAABB final : public core::IReferenceCounted
16- {
16+ class DrawAABB final : public core::IReferenceCounted
17+ {
1718 public:
1819 static constexpr inline uint32_t IndicesCount = 24u ;
19- static constexpr inline uint32_t VerticesCount = 8u ;
2020
2121 enum DrawMode : uint16_t
2222 {
@@ -39,7 +39,8 @@ class DrawAABB final : public core::IReferenceCounted
3939 // ! optional, default MDI buffer allocated if not provided
4040 core::smart_refctd_ptr<streaming_buffer_t > streamingBuffer = nullptr ;
4141 };
42-
42+
43+ // only used to make the 24 element index buffer and instanced pipeline on create
4344 struct SCreationParameters : SCachedCreationParameters
4445 {
4546 video::IQueue* transfer = nullptr ;
@@ -48,6 +49,29 @@ class DrawAABB final : public core::IReferenceCounted
4849 core::smart_refctd_ptr<video::IGPUPipelineLayout> singlePipelineLayout;
4950 core::smart_refctd_ptr<video::IGPUPipelineLayout> batchPipelineLayout;
5051 core::smart_refctd_ptr<video::IGPURenderpass> renderpass = nullptr ;
52+
53+ inline bool validate () const
54+ {
55+ const auto validation = std::to_array
56+ ({
57+ std::make_pair (bool (assetManager), " Invalid `creationParams.assetManager` is nullptr!" ),
58+ std::make_pair (bool (assetManager->getSystem ()), " Invalid `creationParams.assetManager->getSystem()` is nullptr!" ),
59+ std::make_pair (bool (utilities), " Invalid `creationParams.utilities` is nullptr!" ),
60+ std::make_pair (bool (transfer), " Invalid `creationParams.transfer` is nullptr!" ),
61+ std::make_pair (bool (renderpass), " Invalid `creationParams.renderpass` is nullptr!" ),
62+ (assetManager && utilities && transfer && renderpass) ? std::make_pair (bool (utilities->getLogicalDevice ()->getPhysicalDevice ()->getQueueFamilyProperties ()[transfer->getFamilyIndex ()].queueFlags .hasFlags (video::IQueue::FAMILY_FLAGS::TRANSFER_BIT)), " Invalid `creationParams.transfer` is not capable of transfer operations!" ) : std::make_pair (false , " Pass valid required DrawAABB::S_CREATION_PARAMETERS!" )
63+ });
64+
65+ system::logger_opt_ptr logger = utilities->getLogger ();
66+ for (const auto & [ok, error] : validation)
67+ if (!ok)
68+ {
69+ logger.log (error, system::ILogger::ELL_ERROR);
70+ return false ;
71+ }
72+
73+ return true ;
74+ }
5175 };
5276
5377 // creates an instance that can draw one AABB via push constant or multiple using streaming buffer
@@ -67,7 +91,73 @@ class DrawAABB final : public core::IReferenceCounted
6791 // records draw command for single AABB, user has to set pipeline outside
6892 bool renderSingle (video::IGPUCommandBuffer* commandBuffer, const hlsl::shapes::AABB<3 , float >& aabb, const hlsl::float32_t4& color, const hlsl::float32_t4x4& cameraMat);
6993
70- bool render (video::IGPUCommandBuffer* commandBuffer, video::ISemaphore::SWaitInfo waitInfo, std::span<const InstanceData> aabbInstances, const hlsl::float32_t4x4& cameraMat);
94+ // records draw command for rendering batch of AABB instances as InstanceData
95+ // user has to set span of filled-in InstanceData; camera matrix used in push constant
96+ inline bool render (video::IGPUCommandBuffer* commandBuffer, video::ISemaphore::SWaitInfo waitInfo, std::span<const InstanceData> aabbInstances, const hlsl::float32_t4x4& cameraMat)
97+ {
98+ if (!(m_cachedCreationParams.drawMode & ADM_DRAW_BATCH))
99+ {
100+ m_cachedCreationParams.utilities ->getLogger ()->log (" DrawAABB has not been enabled for draw batches!" , system::ILogger::ELL_ERROR);
101+ return false ;
102+ }
103+
104+ using offset_t = SCachedCreationParameters::streaming_buffer_t ::size_type;
105+ constexpr auto MdiSizes = std::to_array<offset_t >({ sizeof (hlsl::float32_t3), sizeof (InstanceData) });
106+ // shared nPoT alignment needs to be divisible by all smaller ones to satisfy an allocation from all
107+ constexpr offset_t MaxAlignment = std::reduce (MdiSizes.begin (), MdiSizes.end (), 1 , [](const offset_t a, const offset_t b)->offset_t {return std::lcm (a, b); });
108+ // allocator initialization needs us to round up to PoT
109+ const auto MaxPOTAlignment = hlsl::roundUpToPoT (MaxAlignment);
110+
111+ auto * streaming = m_cachedCreationParams.streamingBuffer .get ();
112+
113+ auto * const streamingPtr = reinterpret_cast <uint8_t *>(streaming->getBufferPointer ());
114+ assert (streamingPtr);
115+
116+ commandBuffer->bindGraphicsPipeline (m_batchPipeline.get ());
117+ commandBuffer->setLineWidth (1 .f );
118+ asset::SBufferBinding<video::IGPUBuffer> indexBinding = { .offset = 0 , .buffer = m_indicesBuffer };
119+ commandBuffer->bindIndexBuffer (indexBinding, asset::EIT_32BIT);
120+
121+ std::vector<InstanceData> instances (aabbInstances.size ());
122+ for (uint32_t i = 0 ; i < aabbInstances.size (); i++)
123+ {
124+ auto & inst = instances[i];
125+ inst = aabbInstances[i];
126+ inst.transform = hlsl::mul (cameraMat, inst.transform );
127+ }
128+
129+ auto instancesIt = instances.begin ();
130+ const uint32_t instancesPerIter = streaming->getBuffer ()->getSize () / sizeof (InstanceData);
131+ using suballocator_t = core::LinearAddressAllocatorST<offset_t >;
132+ while (instancesIt != instances.end ())
133+ {
134+ const uint32_t instanceCount = hlsl::min<uint32_t >(instancesPerIter, instances.size ());
135+ offset_t inputOffset = 0u ;
136+ offset_t ImaginarySizeUpperBound = 0x1 << 30 ;
137+ suballocator_t imaginaryChunk (nullptr , inputOffset, 0 , hlsl::roundUpToPoT (MaxAlignment), ImaginarySizeUpperBound);
138+ uint32_t instancesByteOffset = imaginaryChunk.alloc_addr (sizeof (InstanceData) * instanceCount, sizeof (InstanceData));
139+ const uint32_t totalSize = imaginaryChunk.get_allocated_size ();
140+
141+ inputOffset = SCachedCreationParameters::streaming_buffer_t ::invalid_value;
142+ std::chrono::steady_clock::time_point waitTill = std::chrono::steady_clock::now () + std::chrono::milliseconds (1u );
143+ streaming->multi_allocate (waitTill, 1 , &inputOffset, &totalSize, &MaxAlignment);
144+
145+ memcpy (streamingPtr + instancesByteOffset, std::addressof (*instancesIt), sizeof (InstanceData) * instanceCount);
146+ instancesIt += instanceCount;
147+
148+ assert (!streaming->needsManualFlushOrInvalidate ());
149+
150+ SPushConstants pc;
151+ pc.pInstanceBuffer = m_cachedCreationParams.streamingBuffer ->getBuffer ()->getDeviceAddress () + instancesByteOffset;
152+
153+ commandBuffer->pushConstants (m_batchPipeline->getLayout (), asset::IShader::E_SHADER_STAGE::ESS_VERTEX, 0 , sizeof (SPushConstants), &pc);
154+ commandBuffer->drawIndexed (IndicesCount, instanceCount, 0 , 0 , 0 );
155+
156+ streaming->multi_deallocate (1 , &inputOffset, &totalSize, waitInfo);
157+ }
158+
159+ return true ;
160+ }
71161
72162 static hlsl::float32_t4x4 getTransformFromAABB (const hlsl::shapes::AABB<3 , float >& aabb);
73163
@@ -77,7 +167,7 @@ class DrawAABB final : public core::IReferenceCounted
77167 ~DrawAABB () override ;
78168
79169 private:
80- static bool validateCreationParameters (SCreationParameters& params);
170+ // static bool validateCreationParameters(SCreationParameters& params);
81171 static core::smart_refctd_ptr<video::IGPUGraphicsPipeline> createPipeline (SCreationParameters& params, const video::IGPUPipelineLayout* pipelineLayout, const std::string& vsPath, const std::string& fsPath);
82172 static bool createStreamingBuffer (SCreationParameters& params);
83173 static core::smart_refctd_ptr<video::IGPUBuffer> createIndicesBuffer (SCreationParameters& params);
0 commit comments