Skip to content

Commit 51567ce

Browse files
Merge branch 'master' of github.com:Devsh-Graphics-Programming/Nabla-Examples-and-Tests
2 parents bb0a76f + 38b5b08 commit 51567ce

31 files changed

+1358
-499
lines changed

01_HelloCoreSystemAsset/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,12 @@ if(NBL_EMBED_BUILTIN_RESOURCES)
2525
endif()
2626

2727
LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} ${_BR_TARGET_})
28+
endif()
29+
30+
# temporary
31+
option(NBL_BLAKE_EX_01_TEST "Test native blake3 with 01 example" OFF)
32+
33+
if(NBL_BLAKE_EX_01_TEST)
34+
target_link_libraries(${EXECUTABLE_NAME} PUBLIC blake3)
35+
target_compile_definitions(${EXECUTABLE_NAME} PUBLIC NBL_ENABLE_BLAKE_TEST)
2836
endif()

01_HelloCoreSystemAsset/main.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@
1010
#include "nbl/system/CColoredStdoutLoggerWin32.h"
1111
#include "nbl/system/IApplicationFramework.h"
1212

13+
#include "blake3.h"
1314
#include <iostream>
1415
#include <cstdio>
16+
#include <errno.h>
17+
#include <stdio.h>
18+
#include <stdlib.h>
19+
#include <string.h>
1520

1621
// if this config cmake flag is available then we embedded resources using cmake into C++ source
1722
#ifdef NBL_EMBED_BUILTIN_RESOURCES
@@ -252,6 +257,38 @@ int main(int argc, char** argv)
252257
wp.workingDirectory = CWD;
253258
assetManager->writeAsset("pngWriteSuccessful.png", wp);
254259
}
260+
261+
#ifdef NBL_ENABLE_BLAKE_TEST
262+
// blake3 hash. TODO: use with Nabla
263+
{
264+
// Initialize the hasher.
265+
blake3_hasher hasher;
266+
blake3_hasher_init(&hasher);
267+
268+
std::array<unsigned char, 65536> buf;
269+
while (true)
270+
{
271+
std::cin.getline(reinterpret_cast<char*>(buf.data()), buf.size());
272+
std::streamsize n = std::cin.gcount();
273+
274+
if (n < 2 || std::cin.eof())
275+
break;
276+
else
277+
blake3_hasher_update(&hasher, buf.data(), n);
278+
}
279+
280+
// Finalize the hash. BLAKE3_OUT_LEN is the default output length, 32 bytes.
281+
uint8_t output[BLAKE3_OUT_LEN];
282+
blake3_hasher_finalize(&hasher, output, BLAKE3_OUT_LEN);
283+
284+
// Print the hash as hexadecimal.
285+
for (size_t i = 0; i < BLAKE3_OUT_LEN; i++) {
286+
printf("%02x", output[i]);
287+
}
288+
printf("\n");
289+
}
290+
#endif // NBL_ENABLE_BLAKE_TEST
291+
255292
//JPEG loader test
256293
if (auto cpuImage = checkedLoad.operator()<nbl::asset::ICPUImage>("dwarf.jpg"))
257294
{
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
// Copyright (C) 2018-2024 - DevSH Graphics Programming Sp. z O.O.
2+
// This file is part of the "Nabla Engine".
3+
// For conditions of distribution and use, see copyright notice in nabla.h
4+
#ifndef _NBL_TESTERS_H_INCLUDED_
5+
#define _NBL_TESTERS_H_INCLUDED_
6+
7+
#include "nbl/application_templates/MonoDeviceApplication.hpp"
8+
#include "nbl/application_templates/MonoAssetManagerAndBuiltinResourceApplication.hpp"
9+
10+
using namespace nbl;
11+
12+
class IntrospectionTesterBase
13+
{
14+
15+
public:
16+
IntrospectionTesterBase(const std::string& functionToTestName)
17+
: m_functionToTestName(functionToTestName) {};
18+
19+
void virtual performTests(video::IPhysicalDevice* physicalDevice, video::ILogicalDevice* device, system::ILogger* logger, asset::IAssetManager* assetMgr) = 0;
20+
21+
virtual ~IntrospectionTesterBase() {};
22+
23+
protected:
24+
const std::string m_functionToTestName = "";
25+
26+
protected:
27+
static std::pair<smart_refctd_ptr<ICPUShader>, smart_refctd_ptr<const CSPIRVIntrospector::CStageIntrospectionData>> compileHLSLShaderAndTestIntrospection(
28+
video::IPhysicalDevice* physicalDevice, video::ILogicalDevice* device, system::ILogger* logger, asset::IAssetManager* assetMgr, const std::string& shaderPath, CSPIRVIntrospector& introspector)
29+
{
30+
IAssetLoader::SAssetLoadParams lp = {};
31+
lp.logger = logger;
32+
lp.workingDirectory = ""; // virtual root
33+
// this time we load a shader directly from a file
34+
auto assetBundle = assetMgr->getAsset(shaderPath, lp);
35+
const auto assets = assetBundle.getContents();
36+
if (assets.empty())
37+
{
38+
logFail(logger, "Could not load shader!");
39+
assert(0);
40+
}
41+
42+
// It would be super weird if loading a shader from a file produced more than 1 asset
43+
assert(assets.size() == 1);
44+
smart_refctd_ptr<ICPUShader> source = IAsset::castDown<ICPUShader>(assets[0]);
45+
46+
smart_refctd_ptr<const CSPIRVIntrospector::CStageIntrospectionData> introspection;
47+
{
48+
// The Asset Manager has a Default Compiler Set which contains all built-in compilers (so it can try them all)
49+
auto* compilerSet = assetMgr->getCompilerSet();
50+
51+
// This time we use a more "generic" option struct which works with all compilers
52+
nbl::asset::IShaderCompiler::SCompilerOptions options = {};
53+
// The Shader Asset Loaders deduce the stage from the file extension,
54+
// if the extension is generic (.glsl or .hlsl) the stage is unknown.
55+
// But it can still be overriden from within the source with a `#pragma shader_stage`
56+
options.stage = source->getStage() == IShader::ESS_COMPUTE ? source->getStage() : IShader::ESS_VERTEX; // TODO: do smth with it
57+
options.targetSpirvVersion = device->getPhysicalDevice()->getLimits().spirvVersion;
58+
// we need to perform an unoptimized compilation with source debug info or we'll lose names of variable sin the introspection
59+
options.spirvOptimizer = nullptr;
60+
options.debugInfoFlags |= IShaderCompiler::E_DEBUG_INFO_FLAGS::EDIF_SOURCE_BIT;
61+
// The nice thing is that when you load a shader from file, it has a correctly set `filePathHint`
62+
// so it plays nicely with the preprocessor, and finds `#include`s without intervention.
63+
options.preprocessorOptions.sourceIdentifier = source->getFilepathHint();
64+
options.preprocessorOptions.logger = logger;
65+
options.preprocessorOptions.includeFinder = compilerSet->getShaderCompiler(source->getContentType())->getDefaultIncludeFinder();
66+
67+
auto spirvUnspecialized = compilerSet->compileToSPIRV(source.get(), options);
68+
const CSPIRVIntrospector::CStageIntrospectionData::SParams inspctParams = { .entryPoint = "main", .shader = spirvUnspecialized };
69+
70+
introspection = introspector.introspect(inspctParams);
71+
if (!introspection)
72+
{
73+
logFail(logger, "SPIR-V Introspection failed, probably the required SPIR-V compilation failed first!");
74+
return std::pair(nullptr, nullptr);
75+
}
76+
77+
{
78+
auto* srcContent = spirvUnspecialized->getContent();
79+
80+
system::ISystem::future_t<core::smart_refctd_ptr<system::IFile>> future;
81+
physicalDevice->getSystem()->createFile(future, system::path("../app_resources/compiled.spv"), system::IFileBase::ECF_WRITE);
82+
if (auto file = future.acquire(); file && bool(*file))
83+
{
84+
system::IFile::success_t succ;
85+
(*file)->write(succ, srcContent->getPointer(), 0, srcContent->getSize());
86+
succ.getBytesProcessed(true);
87+
}
88+
}
89+
90+
// now we need to swap out the HLSL for SPIR-V
91+
source = std::move(spirvUnspecialized);
92+
}
93+
94+
return std::pair(source, introspection);
95+
}
96+
97+
void confirmExpectedOutput(system::ILogger* logger, bool value, bool expectedValue)
98+
{
99+
if (value != expectedValue)
100+
{
101+
logger->log("\"CSPIRVIntrospector::CPipelineIntrospectionData::merge\" function FAIL, incorrect output.",
102+
ILogger::E_LOG_LEVEL::ELL_ERROR);
103+
}
104+
else
105+
{
106+
logger->log("\"CSPIRVIntrospector::CPipelineIntrospectionData::merge\" function SUCCESS, correct output.",
107+
ILogger::E_LOG_LEVEL::ELL_PERFORMANCE);
108+
}
109+
}
110+
111+
template<typename... Args>
112+
static inline bool logFail(system::ILogger* logger, const char* msg, Args&&... args)
113+
{
114+
logger->log(msg, system::ILogger::ELL_ERROR, std::forward<Args>(args)...);
115+
return false;
116+
}
117+
};
118+
119+
class MergeTester final : public IntrospectionTesterBase
120+
{
121+
public:
122+
MergeTester(const std::string& functionToTestName)
123+
: IntrospectionTesterBase(functionToTestName) {};
124+
125+
void virtual performTests(video::IPhysicalDevice* physicalDevice, video::ILogicalDevice* device, system::ILogger* logger, asset::IAssetManager* assetMgr)
126+
{
127+
constexpr std::array mergeTestShadersPaths = {
128+
"app_resources/pplnLayoutMergeTest/shader_0.comp.hlsl",
129+
"app_resources/pplnLayoutMergeTest/shader_1.comp.hlsl",
130+
"app_resources/pplnLayoutMergeTest/shader_2.comp.hlsl",
131+
"app_resources/pplnLayoutMergeTest/shader_3.comp.hlsl",
132+
"app_resources/pplnLayoutMergeTest/shader_4.comp.hlsl",
133+
"app_resources/pplnLayoutMergeTest/shader_5.comp.hlsl"
134+
};
135+
constexpr uint32_t MERGE_TEST_SHADERS_CNT = mergeTestShadersPaths.size();
136+
137+
CSPIRVIntrospector introspector[MERGE_TEST_SHADERS_CNT];
138+
smart_refctd_ptr<const CSPIRVIntrospector::CStageIntrospectionData> introspections[MERGE_TEST_SHADERS_CNT];
139+
140+
for (uint32_t i = 0u; i < MERGE_TEST_SHADERS_CNT; ++i)
141+
{
142+
auto sourceIntrospectionPair = compileHLSLShaderAndTestIntrospection(physicalDevice, device, logger, assetMgr, mergeTestShadersPaths[i], introspector[i]);
143+
introspections[i] = sourceIntrospectionPair.second;
144+
}
145+
146+
core::smart_refctd_ptr<CSPIRVIntrospector::CPipelineIntrospectionData> pplnIntroData;
147+
pplnIntroData = core::make_smart_refctd_ptr<CSPIRVIntrospector::CPipelineIntrospectionData>();
148+
149+
// should merge successfully since shader is not messed up and it is the first merge
150+
confirmExpectedOutput(logger, pplnIntroData->merge(introspections[0].get()), true);
151+
// should merge successfully since pipeline layout of "shader_1.comp.hlsl" is compatible with "shader_0.comp.hlsl"
152+
confirmExpectedOutput(logger, pplnIntroData->merge(introspections[1].get()), true);
153+
// should merge since pipeline layout of "shader_2.comp.hlsl" is not compatible with "shader_0.comp.hlsl"
154+
confirmExpectedOutput(logger, pplnIntroData->merge(introspections[2].get()), true);
155+
156+
pplnIntroData = core::make_smart_refctd_ptr<CSPIRVIntrospector::CPipelineIntrospectionData>();
157+
158+
// should not merge since run-time sized destriptor of "shader_3.comp.hlsl" is not last
159+
confirmExpectedOutput(logger, pplnIntroData->merge(introspections[3].get()), false);
160+
161+
pplnIntroData = core::make_smart_refctd_ptr<CSPIRVIntrospector::CPipelineIntrospectionData>();
162+
163+
// should merge successfully since shader is not messed up and it is the first merge
164+
confirmExpectedOutput(logger, pplnIntroData->merge(introspections[4].get()), true);
165+
// TODO: should merge successfully since shader 5 is compatible with shader 4, it is allowed for last binding in one shader to be run-time sized and statically sized in the other
166+
confirmExpectedOutput(logger, pplnIntroData->merge(introspections[5].get()), true);
167+
}
168+
};
169+
170+
class PredefinedLayoutTester final : public IntrospectionTesterBase
171+
{
172+
public:
173+
PredefinedLayoutTester(const std::string& functionToTestName)
174+
: IntrospectionTesterBase(functionToTestName) {};
175+
176+
void virtual performTests(video::IPhysicalDevice* physicalDevice, video::ILogicalDevice* device, system::ILogger* logger, asset::IAssetManager* assetMgr)
177+
{
178+
constexpr std::array mergeTestShadersPaths = {
179+
"app_resources/pplnLayoutCreationWithPredefinedLayoutTest/shader_0.comp.hlsl",
180+
"app_resources/pplnLayoutCreationWithPredefinedLayoutTest/shader_1.comp.hlsl",
181+
"app_resources/pplnLayoutCreationWithPredefinedLayoutTest/shader_2.comp.hlsl",
182+
"app_resources/pplnLayoutCreationWithPredefinedLayoutTest/shader_3.comp.hlsl",
183+
"app_resources/pplnLayoutCreationWithPredefinedLayoutTest/shader_4.comp.hlsl",
184+
"app_resources/pplnLayoutCreationWithPredefinedLayoutTest/shader_5.comp.hlsl"
185+
};
186+
constexpr uint32_t MERGE_TEST_SHADERS_CNT = mergeTestShadersPaths.size();
187+
188+
CSPIRVIntrospector introspector[MERGE_TEST_SHADERS_CNT];
189+
smart_refctd_ptr<ICPUShader> sources[MERGE_TEST_SHADERS_CNT];
190+
191+
for (uint32_t i = 0u; i < MERGE_TEST_SHADERS_CNT; ++i)
192+
{
193+
auto sourceIntrospectionPair = compileHLSLShaderAndTestIntrospection(physicalDevice, device, logger, assetMgr, mergeTestShadersPaths[i], introspector[i]);
194+
// TODO: disctinct functions for shader compilation and introspection
195+
sources[i] = sourceIntrospectionPair.first;
196+
}
197+
198+
constexpr uint32_t BINDINGS_DS_0_CNT = 1u;
199+
const ICPUDescriptorSetLayout::SBinding bindingsDS0[BINDINGS_DS_0_CNT] = {
200+
{
201+
.binding = 0,
202+
.type = nbl::asset::IDescriptor::E_TYPE::ET_STORAGE_BUFFER,
203+
.createFlags = ICPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE,
204+
.stageFlags = ICPUShader::ESS_COMPUTE,
205+
.count = 1,
206+
.samplers = nullptr
207+
}
208+
};
209+
210+
constexpr uint32_t BINDINGS_DS_1_CNT = 2u;
211+
const ICPUDescriptorSetLayout::SBinding bindingsDS1[BINDINGS_DS_1_CNT] = {
212+
{
213+
.binding = 0,
214+
.type = nbl::asset::IDescriptor::E_TYPE::ET_STORAGE_BUFFER,
215+
.createFlags = ICPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE,
216+
.stageFlags = ICPUShader::ESS_COMPUTE,
217+
.count = 1,
218+
.samplers = nullptr
219+
},
220+
{
221+
.binding = 1,
222+
.type = nbl::asset::IDescriptor::E_TYPE::ET_STORAGE_BUFFER,
223+
.createFlags = ICPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE,
224+
.stageFlags = ICPUShader::ESS_COMPUTE,
225+
.count = 2,
226+
.samplers = nullptr
227+
}
228+
};
229+
230+
core::smart_refctd_ptr<ICPUDescriptorSetLayout> dsLayout0 = core::make_smart_refctd_ptr<ICPUDescriptorSetLayout>(bindingsDS0, bindingsDS0 + BINDINGS_DS_0_CNT);
231+
core::smart_refctd_ptr<ICPUDescriptorSetLayout> dsLayout1 = core::make_smart_refctd_ptr<ICPUDescriptorSetLayout>(bindingsDS1, bindingsDS1 + BINDINGS_DS_1_CNT);
232+
233+
if (!dsLayout0 || !dsLayout1)
234+
{
235+
logFail(logger, "Failed to create a Descriptor Layout!\n");
236+
return;
237+
}
238+
239+
SPushConstantRange pc;
240+
pc.offset = 0u;
241+
pc.size = 5 * sizeof(uint32_t);
242+
pc.stageFlags = IShader::E_SHADER_STAGE::ESS_COMPUTE;
243+
244+
smart_refctd_ptr<ICPUPipelineLayout> predefinedPplnLayout = core::make_smart_refctd_ptr<ICPUPipelineLayout>(std::span<const asset::SPushConstantRange>({ pc }), std::move(dsLayout0), std::move(dsLayout1), nullptr, nullptr);
245+
if (!predefinedPplnLayout)
246+
{
247+
logFail(logger, "Failed to create a Pipeline Layout!\n");
248+
return;
249+
}
250+
251+
bool pplnCreationSuccess[MERGE_TEST_SHADERS_CNT];
252+
for (uint32_t i = 0u; i < MERGE_TEST_SHADERS_CNT; ++i)
253+
{
254+
ICPUShader::SSpecInfo specInfo;
255+
specInfo.entryPoint = "main";
256+
specInfo.shader = sources[i].get();
257+
pplnCreationSuccess[i] = static_cast<bool>(introspector[i].createApproximateComputePipelineFromIntrospection(specInfo, core::smart_refctd_ptr<ICPUPipelineLayout>(predefinedPplnLayout)));
258+
}
259+
260+
// DESCRIPTOR VALIDATION TESTS
261+
// layout from introspection is a subset of pre-defined layout, hence ppln creation should SUCCEED
262+
confirmExpectedOutput(logger, pplnCreationSuccess[0], true);
263+
// layout from introspection is NOT a subset (too many bindings in descriptor set 0) of pre-defined layout, hence ppln creation should FAIL
264+
confirmExpectedOutput(logger, pplnCreationSuccess[1], false);
265+
// layout from introspection is NOT a subset (pre-defined layout doesn't have descriptor set 2) of pre-defined layout, hence ppln creation should FAIL
266+
confirmExpectedOutput(logger, pplnCreationSuccess[2], false);
267+
// layout from introspection is NOT a subset (same bindings, different type of one of the bindings) of pre-defined layout, hence ppln creation should FAIL
268+
confirmExpectedOutput(logger, pplnCreationSuccess[3], false);
269+
270+
// PUSH CONSTANTS VALIDATION TESTS
271+
// layout from introspection is a subset of pre-defined layout (Push constant size declared in shader are compatible), hence ppln creation should SUCCEED
272+
confirmExpectedOutput(logger, pplnCreationSuccess[4], true);
273+
// layout from introspection is NOT a subset of pre-defined layout (Push constant size declared in shader are NOT compatible), hence ppln creation should FAIL
274+
confirmExpectedOutput(logger, pplnCreationSuccess[5], false);
275+
}
276+
};
277+
278+
class SandboxTester final : public IntrospectionTesterBase
279+
{
280+
public:
281+
SandboxTester(const std::string& functionToTestName)
282+
: IntrospectionTesterBase(functionToTestName) {};
283+
284+
void virtual performTests(video::IPhysicalDevice* physicalDevice, video::ILogicalDevice* device, system::ILogger* logger, asset::IAssetManager* assetMgr)
285+
{
286+
CSPIRVIntrospector introspector;
287+
auto sourceIntrospectionPair = compileHLSLShaderAndTestIntrospection(physicalDevice, device, logger, assetMgr, "app_resources/test.hlsl", introspector);
288+
auto pplnIntroData = core::make_smart_refctd_ptr<CSPIRVIntrospector::CPipelineIntrospectionData>();
289+
confirmExpectedOutput(logger, pplnIntroData->merge(sourceIntrospectionPair.second.get()), true);
290+
291+
sourceIntrospectionPair.second->debugPrint(logger);
292+
293+
// TODO
294+
/*CSPIRVIntrospector introspector_test1;
295+
auto vtx_test1 = compileHLSLShaderAndTestIntrospection(physicalDevice, device, logger, assetMgr, "app_resources/vtx_test1.hlsl", introspector_test1);
296+
auto test1_frag = compileHLSLShaderAndTestIntrospection(physicalDevice, device, logger, assetMgr, "app_resources/frag_test1.hlsl", introspector_test1);
297+
298+
CSPIRVIntrospector introspector_test2;
299+
auto test2_comp = compileHLSLShaderAndTestIntrospection(physicalDevice, device, logger, assetMgr, "app_resources/comp_test2_nestedStructs.hlsl", introspector_test2);
300+
301+
CSPIRVIntrospector introspector_test3;
302+
auto test3_comp = compileHLSLShaderAndTestIntrospection(physicalDevice, device, logger, assetMgr, "app_resources/comp_test3_ArraysAndMatrices.hlsl", introspector_test3);
303+
304+
CSPIRVIntrospector introspector_test4;
305+
auto test4_comp = compileHLSLShaderAndTestIntrospection(physicalDevice, device, logger, assetMgr, "app_resources/frag_test4_SamplersTexBuffAndImgStorage.hlsl", introspector_test4);*/
306+
}
307+
};
308+
309+
#endif
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
struct PSInput
2+
{
3+
[[vk::location(2)]] nointerpolation uint4 data1 : COLOR1;
4+
[[vk::location(5)]] float2 data2 : COLOR2;
5+
};
6+
7+
[[vk::binding(6,3)]] RWByteAddressBuffer outputBuff;

0 commit comments

Comments
 (0)