1313#include < regex>
1414#include < iterator>
1515
16+ #include < lzma/C/LzmaEnc.h>
17+ #include < lzma/C/LzmaDec.h>
18+
1619using namespace nbl ;
1720using namespace nbl ::asset;
1821
@@ -22,6 +25,71 @@ IShaderCompiler::IShaderCompiler(core::smart_refctd_ptr<system::ISystem>&& syste
2225 m_defaultIncludeFinder = core::make_smart_refctd_ptr<CIncludeFinder>(core::smart_refctd_ptr (m_system));
2326}
2427
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+
2593std::string IShaderCompiler::preprocessShader (
2694 system::IFile* sourcefile,
2795 IShader::E_SHADER_STAGE stage,
@@ -224,7 +292,7 @@ auto IShaderCompiler::CIncludeFinder::tryIncludeGenerators(const std::string& in
224292
225293core::smart_refctd_ptr<asset::ICPUShader> IShaderCompiler::CCache::find (const SEntry& mainFile, const IShaderCompiler::CIncludeFinder* finder) const
226294{
227- return find_impl (mainFile, finder)->cpuShader ;
295+ return find_impl (mainFile, finder)->decodeShader () ;
228296}
229297
230298IShaderCompiler::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
273341 // 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
274342 // (where the params array has been moved) we don't have to read the json to get the offsets again
275343 offsets[i] = shaderBufferSize;
276- sizes[i] = entry.cpuShader -> getContent () ->getSize ();
344+ sizes[i] = entry.spirv ->getSize ();
277345
278346 // 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);
280348 // Enlarge the shader buffer by the size of the current shader
281349 shaderBufferSize += sizes[i];
282350 i++;
@@ -300,7 +368,7 @@ core::smart_refctd_ptr<ICPUBuffer> IShaderCompiler::CCache::serialize() const
300368 // Loop over entries again, adding each one's shader to the buffer.
301369 i = 0u ;
302370 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]);
304372 i++;
305373 }
306374
@@ -343,13 +411,30 @@ core::smart_refctd_ptr<IShaderCompiler::CCache> IShaderCompiler::CCache::deseria
343411 // Create buffer to hold the code
344412 auto code = core::make_smart_refctd_ptr<ICPUBuffer>(shaderCreationParams[i].codeByteSize );
345413 // Copy the shader bytecode into the buffer
414+
346415 memcpy (code->getPointer (), serializedCache.data () + SHADER_BUFFER_SIZE_BYTES + shaderCreationParams[i].offset , shaderCreationParams[i].codeByteSize );
347416 code->setContentHash (code->computeContentHash ());
348417 // 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);
350419
351420 retVal->insert (std::move (entries[i]));
352421 }
353422
354423 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