1+ #ifndef _NBL_EXAMPLES_TESTS_22_CPP_COMPAT_I_TESTER_INCLUDED_
2+ #define _NBL_EXAMPLES_TESTS_22_CPP_COMPAT_I_TESTER_INCLUDED_
3+
4+ #include < nabla.h>
5+ #include " app_resources/common.hlsl"
6+ #include " nbl/application_templates/MonoDeviceApplication.hpp"
7+
8+ using namespace nbl ;
9+
10+ class ITester
11+ {
12+ public:
13+ virtual ~ITester ()
14+ {
15+ m_outputBufferAllocation.memory ->unmap ();
16+ };
17+
18+ struct PipelineSetupData
19+ {
20+ std::string testShaderPath;
21+ core::smart_refctd_ptr<video::ILogicalDevice> device;
22+ core::smart_refctd_ptr<video::CVulkanConnection> api;
23+ core::smart_refctd_ptr<asset::IAssetManager> assetMgr;
24+ core::smart_refctd_ptr<system::ILogger> logger;
25+ video::IPhysicalDevice* physicalDevice;
26+ uint32_t computeFamilyIndex;
27+ };
28+
29+ template <typename InputStruct, typename OutputStruct>
30+ void setupPipeline (const PipelineSetupData& pipleineSetupData)
31+ {
32+ // setting up pipeline in the constructor
33+ m_device = core::smart_refctd_ptr (pipleineSetupData.device );
34+ m_physicalDevice = pipleineSetupData.physicalDevice ;
35+ m_api = core::smart_refctd_ptr (pipleineSetupData.api );
36+ m_assetMgr = core::smart_refctd_ptr (pipleineSetupData.assetMgr );
37+ m_logger = core::smart_refctd_ptr (pipleineSetupData.logger );
38+ m_queueFamily = pipleineSetupData.computeFamilyIndex ;
39+ m_semaphoreCounter = 0 ;
40+ m_semaphore = m_device->createSemaphore (0 );
41+ m_cmdpool = m_device->createCommandPool (m_queueFamily, video::IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT);
42+ if (!m_cmdpool->createCommandBuffers (video::IGPUCommandPool::BUFFER_LEVEL::PRIMARY, 1u , &m_cmdbuf))
43+ logFail (" Failed to create Command Buffers!\n " );
44+
45+ // Load shaders, set up pipeline
46+ core::smart_refctd_ptr<asset::IShader> shader;
47+ {
48+ asset::IAssetLoader::SAssetLoadParams lp = {};
49+ lp.logger = m_logger.get ();
50+ lp.workingDirectory = " " ; // virtual root
51+ auto assetBundle = m_assetMgr->getAsset (pipleineSetupData.testShaderPath , lp);
52+ const auto assets = assetBundle.getContents ();
53+ if (assets.empty ())
54+ return logFail (" Could not load shader!" );
55+
56+ // It would be super weird if loading a shader from a file produced more than 1 asset
57+ assert (assets.size () == 1 );
58+ core::smart_refctd_ptr<asset::IShader> source = asset::IAsset::castDown<asset::IShader>(assets[0 ]);
59+
60+ shader = m_device->compileShader ({source.get ()});
61+ }
62+
63+ if (!shader)
64+ logFail (" Failed to create a GPU Shader, seems the Driver doesn't like the SPIR-V we're feeding it!\n " );
65+
66+ video::IGPUDescriptorSetLayout::SBinding bindings[2 ] = {
67+ {
68+ .binding = 0 ,
69+ .type = asset::IDescriptor::E_TYPE::ET_STORAGE_BUFFER,
70+ .createFlags = video::IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE,
71+ .stageFlags = ShaderStage::ESS_COMPUTE,
72+ .count = 1
73+ },
74+ {
75+ .binding = 1 ,
76+ .type = asset::IDescriptor::E_TYPE::ET_STORAGE_BUFFER,
77+ .createFlags = video::IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE,
78+ .stageFlags = ShaderStage::ESS_COMPUTE,
79+ .count = 1
80+ }
81+ };
82+
83+ core::smart_refctd_ptr<video::IGPUDescriptorSetLayout> dsLayout = m_device->createDescriptorSetLayout (bindings);
84+ if (!dsLayout)
85+ logFail (" Failed to create a Descriptor Layout!\n " );
86+
87+ m_pplnLayout = m_device->createPipelineLayout ({}, core::smart_refctd_ptr (dsLayout));
88+ if (!m_pplnLayout)
89+ logFail (" Failed to create a Pipeline Layout!\n " );
90+
91+ {
92+ video::IGPUComputePipeline::SCreationParams params = {};
93+ params.layout = m_pplnLayout.get ();
94+ params.shader .entryPoint = " main" ;
95+ params.shader .shader = shader.get ();
96+ if (!m_device->createComputePipelines (nullptr , { ¶ms,1 }, &m_pipeline))
97+ logFail (" Failed to create pipelines (compile & link shaders)!\n " );
98+ }
99+
100+ // Allocate memory of the input buffer
101+ {
102+ constexpr size_t BufferSize = sizeof (InputStruct);
103+
104+ video::IGPUBuffer::SCreationParams params = {};
105+ params.size = BufferSize;
106+ params.usage = video::IGPUBuffer::EUF_STORAGE_BUFFER_BIT;
107+ core::smart_refctd_ptr<video::IGPUBuffer> inputBuff = m_device->createBuffer (std::move (params));
108+ if (!inputBuff)
109+ logFail (" Failed to create a GPU Buffer of size %d!\n " , params.size );
110+
111+ inputBuff->setObjectDebugName (" emulated_float64_t output buffer" );
112+
113+ video::IDeviceMemoryBacked::SDeviceMemoryRequirements reqs = inputBuff->getMemoryReqs ();
114+ reqs.memoryTypeBits &= m_physicalDevice->getHostVisibleMemoryTypeBits ();
115+
116+ m_inputBufferAllocation = m_device->allocate (reqs, inputBuff.get (), video::IDeviceMemoryAllocation::EMAF_NONE);
117+ if (!m_inputBufferAllocation.isValid ())
118+ logFail (" Failed to allocate Device Memory compatible with our GPU Buffer!\n " );
119+
120+ assert (inputBuff->getBoundMemory ().memory == m_inputBufferAllocation.memory .get ());
121+ core::smart_refctd_ptr<video::IDescriptorPool> pool = m_device->createDescriptorPoolForDSLayouts (video::IDescriptorPool::ECF_NONE, { &dsLayout.get (),1 });
122+
123+ m_ds = pool->createDescriptorSet (core::smart_refctd_ptr (dsLayout));
124+ {
125+ video::IGPUDescriptorSet::SDescriptorInfo info[1 ];
126+ info[0 ].desc = core::smart_refctd_ptr (inputBuff);
127+ info[0 ].info .buffer = { .offset = 0 ,.size = BufferSize };
128+ video::IGPUDescriptorSet::SWriteDescriptorSet writes[1 ] = {
129+ {.dstSet = m_ds.get (),.binding = 0 ,.arrayElement = 0 ,.count = 1 ,.info = info}
130+ };
131+ m_device->updateDescriptorSets (writes, {});
132+ }
133+ }
134+
135+ // Allocate memory of the output buffer
136+ {
137+ constexpr size_t BufferSize = sizeof (OutputStruct);
138+
139+ video::IGPUBuffer::SCreationParams params = {};
140+ params.size = BufferSize;
141+ params.usage = video::IGPUBuffer::EUF_STORAGE_BUFFER_BIT;
142+ core::smart_refctd_ptr<video::IGPUBuffer> outputBuff = m_device->createBuffer (std::move (params));
143+ if (!outputBuff)
144+ logFail (" Failed to create a GPU Buffer of size %d!\n " , params.size );
145+
146+ outputBuff->setObjectDebugName (" emulated_float64_t output buffer" );
147+
148+ video::IDeviceMemoryBacked::SDeviceMemoryRequirements reqs = outputBuff->getMemoryReqs ();
149+ reqs.memoryTypeBits &= m_physicalDevice->getHostVisibleMemoryTypeBits ();
150+
151+ m_outputBufferAllocation = m_device->allocate (reqs, outputBuff.get (), video::IDeviceMemoryAllocation::EMAF_NONE);
152+ if (!m_outputBufferAllocation.isValid ())
153+ logFail (" Failed to allocate Device Memory compatible with our GPU Buffer!\n " );
154+
155+ assert (outputBuff->getBoundMemory ().memory == m_outputBufferAllocation.memory .get ());
156+ core::smart_refctd_ptr<video::IDescriptorPool> pool = m_device->createDescriptorPoolForDSLayouts (video::IDescriptorPool::ECF_NONE, { &dsLayout.get (),1 });
157+
158+ {
159+ video::IGPUDescriptorSet::SDescriptorInfo info[1 ];
160+ info[0 ].desc = core::smart_refctd_ptr (outputBuff);
161+ info[0 ].info .buffer = { .offset = 0 ,.size = BufferSize };
162+ video::IGPUDescriptorSet::SWriteDescriptorSet writes[1 ] = {
163+ {.dstSet = m_ds.get (),.binding = 1 ,.arrayElement = 0 ,.count = 1 ,.info = info}
164+ };
165+ m_device->updateDescriptorSets (writes, {});
166+ }
167+ }
168+
169+ if (!m_outputBufferAllocation.memory ->map ({ 0ull ,m_outputBufferAllocation.memory ->getAllocationSize () }, video::IDeviceMemoryAllocation::EMCAF_READ))
170+ logFail (" Failed to map the Device Memory!\n " );
171+
172+ // if the mapping is not coherent the range needs to be invalidated to pull in new data for the CPU's caches
173+ const video::ILogicalDevice::MappedMemoryRange memoryRange (m_outputBufferAllocation.memory .get (), 0ull , m_outputBufferAllocation.memory ->getAllocationSize ());
174+ if (!m_outputBufferAllocation.memory ->getMemoryPropertyFlags ().hasFlags (video::IDeviceMemoryAllocation::EMPF_HOST_COHERENT_BIT))
175+ m_device->invalidateMappedMemoryRanges (1 , &memoryRange);
176+
177+ assert (memoryRange.valid () && memoryRange.length >= sizeof (OutputStruct));
178+
179+ m_queue = m_device->getQueue (m_queueFamily, 0 );
180+ }
181+
182+ enum class TestType
183+ {
184+ CPU,
185+ GPU
186+ };
187+
188+ template <typename T>
189+ void verifyTestValue (const std::string& memberName, const T& expectedVal, const T& testVal, const TestType testType)
190+ {
191+ if (expectedVal == testVal)
192+ return ;
193+
194+ std::stringstream ss;
195+ switch (testType)
196+ {
197+ case TestType::CPU:
198+ ss << " CPU TEST ERROR:\n " ;
199+ break ;
200+ case TestType::GPU:
201+ ss << " GPU TEST ERROR:\n " ;
202+ }
203+
204+ ss << " nbl::hlsl::" << memberName << " produced incorrect output!" << ' \n ' ;
205+
206+ m_logger->log (ss.str ().c_str (), system::ILogger::ELL_ERROR);
207+ }
208+
209+ protected:
210+ uint32_t m_queueFamily;
211+ core::smart_refctd_ptr<video::ILogicalDevice> m_device;
212+ core::smart_refctd_ptr<video::CVulkanConnection> m_api;
213+ video::IPhysicalDevice* m_physicalDevice;
214+ core::smart_refctd_ptr<asset::IAssetManager> m_assetMgr;
215+ core::smart_refctd_ptr<system::ILogger> m_logger;
216+ video::IDeviceMemoryAllocator::SAllocation m_inputBufferAllocation = {};
217+ video::IDeviceMemoryAllocator::SAllocation m_outputBufferAllocation = {};
218+ core::smart_refctd_ptr<video::IGPUCommandBuffer> m_cmdbuf = nullptr ;
219+ core::smart_refctd_ptr<video::IGPUCommandPool> m_cmdpool = nullptr ;
220+ core::smart_refctd_ptr<video::IGPUDescriptorSet> m_ds = nullptr ;
221+ core::smart_refctd_ptr<video::IGPUPipelineLayout> m_pplnLayout = nullptr ;
222+ core::smart_refctd_ptr<video::IGPUComputePipeline> m_pipeline;
223+ core::smart_refctd_ptr<video::ISemaphore> m_semaphore;
224+ video::IQueue* m_queue;
225+ uint64_t m_semaphoreCounter;
226+
227+ template <typename InputStruct, typename OutputStruct>
228+ OutputStruct dispatch (const InputStruct& input)
229+ {
230+ // Update input buffer
231+ if (!m_inputBufferAllocation.memory ->map ({ 0ull ,m_inputBufferAllocation.memory ->getAllocationSize () }, video::IDeviceMemoryAllocation::EMCAF_READ))
232+ logFail (" Failed to map the Device Memory!\n " );
233+
234+ const video::ILogicalDevice::MappedMemoryRange memoryRange (m_inputBufferAllocation.memory .get (), 0ull , m_inputBufferAllocation.memory ->getAllocationSize ());
235+ if (!m_inputBufferAllocation.memory ->getMemoryPropertyFlags ().hasFlags (video::IDeviceMemoryAllocation::EMPF_HOST_COHERENT_BIT))
236+ m_device->invalidateMappedMemoryRanges (1 , &memoryRange);
237+
238+ std::memcpy (static_cast <InputStruct*>(m_inputBufferAllocation.memory ->getMappedPointer ()), &input, sizeof (InputStruct));
239+
240+ m_inputBufferAllocation.memory ->unmap ();
241+
242+ // record command buffer
243+ m_cmdbuf->reset (video::IGPUCommandBuffer::RESET_FLAGS::NONE);
244+ m_cmdbuf->begin (video::IGPUCommandBuffer::USAGE::NONE);
245+ m_cmdbuf->beginDebugMarker (" test" , core::vector4df_SIMD (0 , 1 , 0 , 1 ));
246+ m_cmdbuf->bindComputePipeline (m_pipeline.get ());
247+ m_cmdbuf->bindDescriptorSets (nbl::asset::EPBP_COMPUTE, m_pplnLayout.get (), 0 , 1 , &m_ds.get ());
248+ m_cmdbuf->dispatch (1 , 1 , 1 );
249+ m_cmdbuf->endDebugMarker ();
250+ m_cmdbuf->end ();
251+
252+ video::IQueue::SSubmitInfo submitInfos[1 ] = {};
253+ const video::IQueue::SSubmitInfo::SCommandBufferInfo cmdbufs[] = { {.cmdbuf = m_cmdbuf.get ()} };
254+ submitInfos[0 ].commandBuffers = cmdbufs;
255+ const video::IQueue::SSubmitInfo::SSemaphoreInfo signals[] = { {.semaphore = m_semaphore.get (), .value = ++m_semaphoreCounter, .stageMask = asset::PIPELINE_STAGE_FLAGS::COMPUTE_SHADER_BIT} };
256+ submitInfos[0 ].signalSemaphores = signals;
257+
258+ m_api->startCapture ();
259+ m_queue->submit (submitInfos);
260+ m_api->endCapture ();
261+
262+ m_device->waitIdle ();
263+ OutputStruct output;
264+ std::memcpy (&output, static_cast <OutputStruct*>(m_outputBufferAllocation.memory ->getMappedPointer ()), sizeof (OutputStruct));
265+ m_device->waitIdle ();
266+
267+ return output;
268+ }
269+
270+ private:
271+ template <typename ... Args>
272+ inline void logFail (const char * msg, Args&&... args)
273+ {
274+ m_logger->log (msg, system::ILogger::ELL_ERROR, std::forward<Args>(args)...);
275+ exit (-1 );
276+ }
277+ };
278+
279+ #endif
0 commit comments