| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <AnKi/Resource/ShaderProgramResourceSystem.h>
- #include <AnKi/Resource/ResourceFilesystem.h>
- #include <AnKi/Resource/ResourceManager.h>
- #include <AnKi/Util/Tracer.h>
- #include <AnKi/Gr/GrManager.h>
- #include <AnKi/ShaderCompiler/ShaderCompiler.h>
- #include <AnKi/Util/Filesystem.h>
- #include <AnKi/Util/System.h>
- #include <AnKi/Util/BitSet.h>
- #include <AnKi/Util/CVarSet.h>
- namespace anki {
- class ShaderProgramResourceSystem::ShaderH
- {
- public:
- ShaderPtr m_shader;
- U64 m_hash = 0; ///< Hash of the binary.
- };
- class ShaderProgramResourceSystem::ShaderGroup
- {
- public:
- U32 m_rayGen = kMaxU32;
- U32 m_miss = kMaxU32;
- U32 m_chit = kMaxU32;
- U32 m_ahit = kMaxU32;
- ResourceDynamicArray<U64> m_groupHashes;
- };
- class ShaderProgramResourceSystem::Lib
- {
- public:
- ResourceString m_name;
- ResourceDynamicArray<ShaderH> m_shaders;
- ResourceDynamicArray<ShaderGroup> m_rayGenGroups;
- ResourceDynamicArray<ShaderGroup> m_missGroups;
- ResourceDynamicArray<ShaderGroup> m_hitGroups;
- ShaderTypeBit m_presentStages = ShaderTypeBit::kNone;
- U32 addShader(const ShaderBinaryCodeBlock& codeBlock, CString progName, ShaderType shaderType)
- {
- ShaderH* shader = nullptr;
- for(ShaderH& s : m_shaders)
- {
- if(s.m_hash == codeBlock.m_hash)
- {
- shader = &s;
- break;
- }
- }
- if(shader == nullptr)
- {
- shader = m_shaders.emplaceBack();
- ShaderInitInfo inf(progName);
- inf.m_shaderType = shaderType;
- inf.m_binary = codeBlock.m_binary;
- inf.m_reflection = codeBlock.m_reflection;
- shader->m_shader = GrManager::getSingleton().newShader(inf);
- shader->m_hash = codeBlock.m_hash;
- m_presentStages |= ShaderTypeBit(1 << shaderType);
- }
- return U32(shader - m_shaders.getBegin());
- }
- void addGroup(CString filename, U64 mutationHash, U32 rayGen, U32 miss, U32 chit, U32 ahit)
- {
- ResourceDynamicArray<ShaderGroup>* groupArray = nullptr;
- RayTracingShaderGroupType groupType;
- if(rayGen < kMaxU32)
- {
- groupType = RayTracingShaderGroupType::kRayGen;
- groupArray = &m_rayGenGroups;
- }
- else if(miss < kMaxU32)
- {
- groupType = RayTracingShaderGroupType::kMiss;
- groupArray = &m_missGroups;
- }
- else
- {
- ANKI_ASSERT(chit < kMaxU32 || ahit < kMaxU32);
- groupType = RayTracingShaderGroupType::kHit;
- groupArray = &m_hitGroups;
- }
- ShaderGroup* pgroup = nullptr;
- for(ShaderGroup& s : *groupArray)
- {
- if(s.m_rayGen == rayGen && s.m_miss == miss && s.m_ahit == ahit && s.m_chit == chit)
- {
- pgroup = &s;
- break;
- }
- }
- if(!pgroup)
- {
- pgroup = groupArray->emplaceBack();
- pgroup->m_rayGen = rayGen;
- pgroup->m_miss = miss;
- pgroup->m_chit = chit;
- pgroup->m_ahit = ahit;
- }
- const U64 groupHash = ShaderProgramRaytracingLibrary::generateShaderGroupGroupHash(filename, mutationHash, groupType);
- #if ANKI_ASSERTIONS_ENABLED
- for(U64 hash : pgroup->m_groupHashes)
- {
- ANKI_ASSERT(hash != groupHash && "Shouldn't find group with the same hash");
- }
- #endif
- pgroup->m_groupHashes.emplaceBack(groupHash);
- }
- };
- U64 ShaderProgramRaytracingLibrary::generateShaderGroupGroupHash(CString resourceFilename, U64 mutationHash, RayTracingShaderGroupType groupType)
- {
- ANKI_ASSERT(resourceFilename.getLength() > 0);
- ANKI_ASSERT(groupType < RayTracingShaderGroupType::kCount);
- String basename;
- getFilepathFilename(resourceFilename, basename);
- U64 hash = appendHash(basename.cstr(), basename.getLength(), mutationHash);
- hash = appendHash(&groupType, sizeof(groupType), hash);
- return hash;
- }
- Error ShaderProgramResourceSystem::init()
- {
- if(!GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled)
- {
- return Error::kNone;
- }
- // Create RT pipeline libraries
- const Error err = createRayTracingPrograms(m_rtLibraries);
- if(err)
- {
- ANKI_RESOURCE_LOGE("Failed to create ray tracing programs");
- }
- return err;
- }
- Error ShaderProgramResourceSystem::createRayTracingPrograms(ResourceDynamicArray<ShaderProgramRaytracingLibrary>& outLibs)
- {
- ANKI_RESOURCE_LOGI("Creating ray tracing programs");
- U32 rtProgramCount = 0;
- ResourceDynamicArray<Lib> libs;
- const Error err = ResourceManager::getSingleton().getFilesystem().iterateAllFilenames([&](CString filename) -> Error {
- // Check file extension
- String extension;
- getFilepathExtension(filename, extension);
- const Char binExtension[] = "ankiprogbin";
- if(extension.getLength() != sizeof(binExtension) - 1 || extension != binExtension)
- {
- return Error::kNone;
- }
- // Get the binary
- ResourceFilePtr file;
- ANKI_CHECK(ResourceManager::getSingleton().getFilesystem().openFile(filename, file));
- ShaderBinary* binary;
- ANKI_CHECK(deserializeShaderBinaryFromAnyFile(*file, binary, ResourceMemoryPool::getSingleton()));
- class Dummy
- {
- public:
- ShaderBinary* m_binary;
- ~Dummy()
- {
- ResourceMemoryPool::getSingleton().free(m_binary);
- }
- } dummy{binary};
- if(!(binary->m_shaderTypes & ShaderTypeBit::kAllRayTracing))
- {
- return Error::kNone;
- }
- // Create the program name
- String progName;
- getFilepathFilename(filename, progName);
- for(const ShaderBinaryTechnique& technique : binary->m_techniques)
- {
- if(!(technique.m_shaderTypes & ShaderTypeBit::kAllRayTracing))
- {
- continue;
- }
- const U32 techniqueIdx = U32(&technique - binary->m_techniques.getBegin());
- // Find or create the lib
- Lib* lib = nullptr;
- {
- for(Lib& l : libs)
- {
- if(l.m_name == technique.m_name.getBegin())
- {
- lib = &l;
- break;
- }
- }
- if(lib == nullptr)
- {
- libs.emplaceBack();
- lib = &libs.getBack();
- lib->m_name = technique.m_name.getBegin();
- }
- }
- // Ray gen
- if(!!(technique.m_shaderTypes & ShaderTypeBit::kRayGen))
- {
- // Iterate all mutations
- ConstWeakArray<ShaderBinaryMutation> mutations;
- ShaderBinaryMutation dummyMutation;
- if(binary->m_mutations.getSize() > 1)
- {
- mutations = binary->m_mutations;
- }
- else
- {
- dummyMutation.m_hash = 0;
- dummyMutation.m_variantIndex = 0;
- mutations = ConstWeakArray<ShaderBinaryMutation>(&dummyMutation, 1);
- }
- for(const ShaderBinaryMutation& mutation : mutations)
- {
- const ShaderBinaryVariant& variant = binary->m_variants[mutation.m_variantIndex];
- const U32 codeBlockIndex = variant.m_techniqueCodeBlocks[techniqueIdx].m_codeBlockIndices[ShaderType::kRayGen];
- const U32 shaderIdx = lib->addShader(binary->m_codeBlocks[codeBlockIndex], progName, ShaderType::kRayGen);
- lib->addGroup(filename, mutation.m_hash, shaderIdx, kMaxU32, kMaxU32, kMaxU32);
- }
- }
- // Miss
- if(!!(technique.m_shaderTypes & ShaderTypeBit::kMiss))
- {
- // Iterate all mutations
- ConstWeakArray<ShaderBinaryMutation> mutations;
- ShaderBinaryMutation dummyMutation;
- if(binary->m_mutations.getSize() > 1)
- {
- mutations = binary->m_mutations;
- }
- else
- {
- dummyMutation.m_hash = 0;
- dummyMutation.m_variantIndex = 0;
- mutations = ConstWeakArray<ShaderBinaryMutation>(&dummyMutation, 1);
- }
- for(const ShaderBinaryMutation& mutation : mutations)
- {
- const ShaderBinaryVariant& variant = binary->m_variants[mutation.m_variantIndex];
- const U32 codeBlockIndex = variant.m_techniqueCodeBlocks[techniqueIdx].m_codeBlockIndices[ShaderType::kMiss];
- ANKI_ASSERT(codeBlockIndex < kMaxU32);
- const U32 shaderIdx = lib->addShader(binary->m_codeBlocks[codeBlockIndex], progName, ShaderType::kMiss);
- lib->addGroup(filename, mutation.m_hash, kMaxU32, shaderIdx, kMaxU32, kMaxU32);
- }
- }
- // Hit shaders
- if(!!(technique.m_shaderTypes & ShaderTypeBit::kAllHit))
- {
- // Before you iterate the mutations do some work if there are none
- ConstWeakArray<ShaderBinaryMutation> mutations;
- ShaderBinaryMutation dummyMutation;
- if(binary->m_mutations.getSize() > 1)
- {
- mutations = binary->m_mutations;
- }
- else
- {
- dummyMutation.m_hash = 0;
- dummyMutation.m_variantIndex = 0;
- mutations = ConstWeakArray<ShaderBinaryMutation>(&dummyMutation, 1);
- }
- // Iterate all mutations
- for(const ShaderBinaryMutation& mutation : mutations)
- {
- if(mutation.m_variantIndex == kMaxU32)
- {
- continue;
- }
- const ShaderBinaryVariant& variant = binary->m_variants[mutation.m_variantIndex];
- const U32 ahitCodeBlockIndex = variant.m_techniqueCodeBlocks[techniqueIdx].m_codeBlockIndices[ShaderType::kAnyHit];
- const U32 chitCodeBlockIndex = variant.m_techniqueCodeBlocks[techniqueIdx].m_codeBlockIndices[ShaderType::kClosestHit];
- ANKI_ASSERT(ahitCodeBlockIndex != kMaxU32 || chitCodeBlockIndex != kMaxU32);
- const U32 ahitShaderIdx = (ahitCodeBlockIndex != kMaxU32)
- ? lib->addShader(binary->m_codeBlocks[ahitCodeBlockIndex], progName, ShaderType::kAnyHit)
- : kMaxU32;
- const U32 chitShaderIdx = (chitCodeBlockIndex != kMaxU32)
- ? lib->addShader(binary->m_codeBlocks[chitCodeBlockIndex], progName, ShaderType::kClosestHit)
- : kMaxU32;
- lib->addGroup(filename, mutation.m_hash, kMaxU32, kMaxU32, chitShaderIdx, ahitShaderIdx);
- }
- }
- } // iterate techniques
- return Error::kNone;
- }); // For all RT filenames
- ANKI_CHECK(err);
- // Create the libraries. The value that goes to the m_resourceHashToShaderGroupHandleIndex hashmap is the index of the shader handle inside the
- // program. Leverage the fact that there is a predefined order between group types (ray gen first, miss and hit follows). See the ShaderProgram
- // class for info.
- if(libs.getSize() != 0)
- {
- outLibs.resize(libs.getSize());
- for(U32 libIdx = 0; libIdx < libs.getSize(); ++libIdx)
- {
- ShaderProgramRaytracingLibrary& outLib = outLibs[libIdx];
- const Lib& inLib = libs[libIdx];
- const ShaderTypeBit requiredShaders = ShaderTypeBit::kRayGen | ShaderTypeBit::kMiss;
- if((inLib.m_presentStages & requiredShaders) != requiredShaders
- || !(inLib.m_presentStages & (ShaderTypeBit::kClosestHit | ShaderTypeBit::kAnyHit)))
- {
- ANKI_RESOURCE_LOGE("The libray is missing shader types: %s", inLib.m_name.cstr());
- return Error::kUserData;
- }
- outLib.m_libraryName = inLib.m_name;
- ResourceDynamicArray<RayTracingHitGroup> initInfoHitGroups;
- ResourceDynamicArray<Shader*> missShaders;
- ResourceDynamicArray<Shader*> rayGenShaders;
- U32 groupCount = 0;
- // Ray gen
- for(const ShaderGroup& group : inLib.m_rayGenGroups)
- {
- rayGenShaders.emplaceBack(inLib.m_shaders[group.m_rayGen].m_shader.get());
- for(U64 hash : group.m_groupHashes)
- {
- outLib.m_resourceHashToShaderGroupHandleIndex.emplace(hash, groupCount);
- }
- ++groupCount;
- }
- // Miss
- for(const ShaderGroup& group : inLib.m_missGroups)
- {
- missShaders.emplaceBack(inLib.m_shaders[group.m_miss].m_shader.get());
- for(U64 hash : group.m_groupHashes)
- {
- outLib.m_resourceHashToShaderGroupHandleIndex.emplace(hash, groupCount);
- }
- ++groupCount;
- }
- // Hit
- for(const ShaderGroup& group : inLib.m_hitGroups)
- {
- RayTracingHitGroup* infoHitGroup = initInfoHitGroups.emplaceBack();
- if(group.m_ahit < kMaxU32)
- {
- infoHitGroup->m_anyHitShader = inLib.m_shaders[group.m_ahit].m_shader.get();
- }
- if(group.m_chit < kMaxU32)
- {
- infoHitGroup->m_closestHitShader = inLib.m_shaders[group.m_chit].m_shader.get();
- }
- for(U64 hash : group.m_groupHashes)
- {
- outLib.m_resourceHashToShaderGroupHandleIndex.emplace(hash, groupCount);
- }
- ++groupCount;
- }
- // Create the program
- ShaderProgramInitInfo inf(inLib.m_name);
- inf.m_rayTracingShaders.m_rayGenShaders = rayGenShaders;
- inf.m_rayTracingShaders.m_missShaders = missShaders;
- inf.m_rayTracingShaders.m_hitGroups = initInfoHitGroups;
- outLib.m_program = GrManager::getSingleton().newShaderProgram(inf);
- ++rtProgramCount;
- }
- }
- ANKI_RESOURCE_LOGI("Created %u ray tracing programs", rtProgramCount);
- return Error::kNone;
- }
- } // end namespace anki
|