Skip to content

Commit 85b7182

Browse files
Merge pull request #187 from Devsh-Graphics-Programming/mortons
Adds tests for the new Morton Code class
2 parents 1e8372b + 84eb1f7 commit 85b7182

File tree

25 files changed

+2093
-470
lines changed

25 files changed

+2093
-470
lines changed

07_StagingAndMultipleQueues/app_resources/common.hlsl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include "nbl/builtin/hlsl/cpp_compat.hlsl"
22

3-
NBL_CONSTEXPR uint32_t WorkgroupSizeX = 16;
4-
NBL_CONSTEXPR uint32_t WorkgroupSizeY = 16;
5-
NBL_CONSTEXPR uint32_t WorkgroupSize = WorkgroupSizeX*WorkgroupSizeY;
3+
NBL_CONSTEXPR_INLINE_NSPC_SCOPE_VAR uint32_t WorkgroupSizeX = 16;
4+
NBL_CONSTEXPR_INLINE_NSPC_SCOPE_VAR uint32_t WorkgroupSizeY = 16;
5+
NBL_CONSTEXPR_INLINE_NSPC_SCOPE_VAR uint32_t WorkgroupSize = WorkgroupSizeX*WorkgroupSizeY;
66

77
static const uint32_t FRAMES_IN_FLIGHT = 3u;
88

14_Mortons/CMakeLists.txt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
include(common RESULT_VARIABLE RES)
2+
if(NOT RES)
3+
message(FATAL_ERROR "common.cmake not found. Should be in {repo_root}/cmake directory")
4+
endif()
5+
6+
nbl_create_executable_project("" "" "" "" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}")
7+
8+
if(NBL_EMBED_BUILTIN_RESOURCES)
9+
set(_BR_TARGET_ ${EXECUTABLE_NAME}_builtinResourceData)
10+
set(RESOURCE_DIR "app_resources")
11+
12+
get_filename_component(_SEARCH_DIRECTORIES_ "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
13+
get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/src" ABSOLUTE)
14+
get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/include" ABSOLUTE)
15+
16+
file(GLOB_RECURSE BUILTIN_RESOURCE_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}" CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}/*")
17+
foreach(RES_FILE ${BUILTIN_RESOURCE_FILES})
18+
LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "${RES_FILE}")
19+
endforeach()
20+
21+
ADD_CUSTOM_BUILTIN_RESOURCES(${_BR_TARGET_} RESOURCES_TO_EMBED "${_SEARCH_DIRECTORIES_}" "${RESOURCE_DIR}" "nbl::this_example::builtin" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}")
22+
23+
LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} ${_BR_TARGET_})
24+
endif()

14_Mortons/CTester.h

Lines changed: 521 additions & 0 deletions
Large diffs are not rendered by default.

14_Mortons/ITester.h

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
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, { &params,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

Comments
 (0)