13
13
#include < regex>
14
14
#include < iterator>
15
15
16
+ #include < lzma/C/LzmaEnc.h>
17
+ #include < lzma/C/LzmaDec.h>
18
+
16
19
using namespace nbl ;
17
20
using namespace nbl ::asset;
18
21
@@ -22,6 +25,71 @@ IShaderCompiler::IShaderCompiler(core::smart_refctd_ptr<system::ISystem>&& syste
22
25
m_defaultIncludeFinder = core::make_smart_refctd_ptr<CIncludeFinder>(core::smart_refctd_ptr (m_system));
23
26
}
24
27
28
+ static void * SzAlloc (ISzAllocPtr p, size_t size) { p = p; return _NBL_ALIGNED_MALLOC (size, _NBL_SIMD_ALIGNMENT); }
29
+ static void SzFree (ISzAllocPtr p, void * address) { p = p; _NBL_ALIGNED_FREE (address); }
30
+
31
+ inline core::smart_refctd_ptr<ICPUShader> nbl::asset::IShaderCompiler::compileToSPIRV (const std::string_view code, const SCompilerOptions& options) const
32
+ {
33
+ CCache::SEntry entry;
34
+ std::vector<CCache::SEntry::SPreprocessingDependency> dependencies;
35
+ if (options.readCache || options.writeCache )
36
+ entry = std::move (CCache::SEntry (code, options));
37
+
38
+ if (options.readCache )
39
+ {
40
+ auto found = options.readCache ->find_impl (entry, options.preprocessorOptions .includeFinder );
41
+ if (found != options.readCache ->m_container .end ())
42
+ {
43
+ if (options.writeCache )
44
+ {
45
+ CCache::SEntry writeEntry = *found;
46
+ options.writeCache ->insert (std::move (writeEntry));
47
+ }
48
+ return found->decodeShader ();
49
+ }
50
+ }
51
+
52
+ auto retVal = compileToSPIRV_impl (code, options, options.writeCache ? &dependencies : nullptr );
53
+ // compute the SPIR-V shader content hash
54
+ {
55
+ auto backingBuffer = retVal->getContent ();
56
+ const_cast <ICPUBuffer*>(backingBuffer)->setContentHash (backingBuffer->computeContentHash ());
57
+ }
58
+
59
+ std::cout << " writeCache: " << options.writeCache << " \n " ;
60
+ if (options.writeCache )
61
+ {
62
+ auto * spirvBuffer = retVal->getContent ();
63
+ size_t propsSize = LZMA_PROPS_SIZE;
64
+ size_t destLen = spirvBuffer->getSize () + spirvBuffer->getSize () / 3 + 128 ;
65
+ auto compressedSpirvBuffer = core::make_smart_refctd_ptr<ICPUBuffer>(propsSize + destLen);
66
+
67
+ CLzmaEncProps props;
68
+ LzmaEncProps_Init (&props);
69
+ props.dictSize = 1 << 16 ; // 64 KB
70
+ props.writeEndMark = 1 ; // 0 or 1
71
+
72
+ ISzAlloc alloc = { SzAlloc, SzFree };
73
+ int res = LzmaEncode (
74
+ reinterpret_cast <unsigned char *>(compressedSpirvBuffer->getPointer ()) + LZMA_PROPS_SIZE, &destLen,
75
+ reinterpret_cast <const unsigned char *>(spirvBuffer->getPointer ()), spirvBuffer->getSize (),
76
+ &props, reinterpret_cast <unsigned char *>(compressedSpirvBuffer->getPointer ()), &propsSize, props.writeEndMark ,
77
+ nullptr , &alloc, &alloc);
78
+
79
+ assert (propsSize == LZMA_PROPS_SIZE);
80
+ assert (res == SZ_OK);
81
+
82
+ entry.dependencies = std::move (dependencies);
83
+ entry.spirv = std::move (compressedSpirvBuffer);
84
+ entry.uncompressedSize = spirvBuffer->getSize ();
85
+
86
+ std::cout << " original: " << spirvBuffer->getSize () << " , compressed: " << compressedSpirvBuffer->getSize () << " \n " ;
87
+
88
+ options.writeCache ->insert (std::move (entry));
89
+ }
90
+ return retVal;
91
+ }
92
+
25
93
std::string IShaderCompiler::preprocessShader (
26
94
system::IFile* sourcefile,
27
95
IShader::E_SHADER_STAGE stage,
@@ -224,7 +292,7 @@ auto IShaderCompiler::CIncludeFinder::tryIncludeGenerators(const std::string& in
224
292
225
293
core::smart_refctd_ptr<asset::ICPUShader> IShaderCompiler::CCache::find (const SEntry& mainFile, const IShaderCompiler::CIncludeFinder* finder) const
226
294
{
227
- return find_impl (mainFile, finder)->cpuShader ;
295
+ return find_impl (mainFile, finder)->decodeShader () ;
228
296
}
229
297
230
298
IShaderCompiler::CCache::EntrySet::const_iterator IShaderCompiler::CCache::find_impl (const SEntry& mainFile, const IShaderCompiler::CIncludeFinder* finder) const
@@ -273,10 +341,10 @@ core::smart_refctd_ptr<ICPUBuffer> IShaderCompiler::CCache::serialize() const
273
341
// We keep a copy of the offsets and the sizes of each shader. This is so that later on, when we add the shaders to the buffer after json creation
274
342
// (where the params array has been moved) we don't have to read the json to get the offsets again
275
343
offsets[i] = shaderBufferSize;
276
- sizes[i] = entry.cpuShader -> getContent () ->getSize ();
344
+ sizes[i] = entry.spirv ->getSize ();
277
345
278
346
// And add the params to the shader creation parameters array
279
- shaderCreationParams.emplace_back (entry.cpuShader -> getStage (), entry. cpuShader -> getContentType () , entry.cpuShader -> getFilepathHint (), sizes[i], shaderBufferSize);
347
+ shaderCreationParams.emplace_back (entry.compilerArgs . stage , IShader::E_CONTENT_TYPE::ECT_SPIRV , entry.compilerArgs . preprocessorArgs . sourceIdentifier . data (), sizes[i], shaderBufferSize);
280
348
// Enlarge the shader buffer by the size of the current shader
281
349
shaderBufferSize += sizes[i];
282
350
i++;
@@ -300,7 +368,7 @@ core::smart_refctd_ptr<ICPUBuffer> IShaderCompiler::CCache::serialize() const
300
368
// Loop over entries again, adding each one's shader to the buffer.
301
369
i = 0u ;
302
370
for (auto & entry : m_container) {
303
- memcpy (retVal.data () + SHADER_BUFFER_SIZE_BYTES + offsets[i], entry.cpuShader -> getContent () ->getPointer (), sizes[i]);
371
+ memcpy (retVal.data () + SHADER_BUFFER_SIZE_BYTES + offsets[i], entry.spirv ->getPointer (), sizes[i]);
304
372
i++;
305
373
}
306
374
@@ -343,13 +411,30 @@ core::smart_refctd_ptr<IShaderCompiler::CCache> IShaderCompiler::CCache::deseria
343
411
// Create buffer to hold the code
344
412
auto code = core::make_smart_refctd_ptr<ICPUBuffer>(shaderCreationParams[i].codeByteSize );
345
413
// Copy the shader bytecode into the buffer
414
+
346
415
memcpy (code->getPointer (), serializedCache.data () + SHADER_BUFFER_SIZE_BYTES + shaderCreationParams[i].offset , shaderCreationParams[i].codeByteSize );
347
416
code->setContentHash (code->computeContentHash ());
348
417
// Create the ICPUShader
349
- entries[i].cpuShader = core::make_smart_refctd_ptr<ICPUShader>( std::move (code), shaderCreationParams[i]. stage , shaderCreationParams[i]. contentType , std::move (shaderCreationParams[i]. filepathHint ) );
418
+ entries[i].spirv = std::move (code);
350
419
351
420
retVal->insert (std::move (entries[i]));
352
421
}
353
422
354
423
return retVal;
355
- }
424
+ }
425
+
426
+ core::smart_refctd_ptr<ICPUShader> nbl::asset::IShaderCompiler::CCache::SEntry::decodeShader () const
427
+ {
428
+ auto uncompressedBuf = core::make_smart_refctd_ptr<ICPUBuffer>(uncompressedSize);
429
+ size_t dstSize = uncompressedBuf->getSize ();
430
+ size_t srcSize = spirv->getSize () - LZMA_PROPS_SIZE;
431
+ ELzmaStatus status;
432
+ ISzAlloc alloc = { SzAlloc, SzFree };
433
+ SRes res = LzmaDecode (
434
+ reinterpret_cast <unsigned char *>(uncompressedBuf->getPointer ()), &dstSize,
435
+ reinterpret_cast <const unsigned char *>(spirv->getPointer ()) + LZMA_PROPS_SIZE, &srcSize,
436
+ reinterpret_cast <const unsigned char *>(spirv->getPointer ()), LZMA_PROPS_SIZE,
437
+ LZMA_FINISH_ANY, &status, &alloc);
438
+ assert (res == SZ_OK);
439
+ return core::make_smart_refctd_ptr<asset::ICPUShader>(std::move (uncompressedBuf), compilerArgs.stage , IShader::E_CONTENT_TYPE::ECT_SPIRV, compilerArgs.preprocessorArgs .sourceIdentifier .data ());
440
+ }
0 commit comments