11#include < map>
22#include < set>
33#include < string>
4+ #include < unordered_map>
45#include < vector>
56
67#include " processor.h"
78
9+ #include < cage-core/containerSerialization.h>
810#include < cage-core/hashString.h>
9- #include < cage-core/timer .h>
11+ #include < cage-engine/spirv .h>
1012
1113namespace
1214{
13- std::map<String, std::string> codes;
14- std::map<String, String> defines;
15- std::set<String, StringComparatorFast> onces;
15+ struct Variant
16+ {
17+ Holder<Spirv> spirv;
18+ uint32 id = 0 ;
19+ };
20+
21+ std::unordered_map<uint32, std::string> codes;
22+ std::map<String, String, StringComparatorFast> defines;
23+ std::set<String> onces;
1624 std::set<detail::StringBase<20 >> keywords;
25+ std::vector<Variant> variants;
1726
1827 const ConfigBool configShaderPrint (" cage-asset-processor/shader/preview" , false );
1928
@@ -226,28 +235,22 @@ namespace
226235 return evalExp (l);
227236 }
228237
229- void output (const String &s)
230- {
231- if (defines[" shader" ].empty ())
232- {
233- if (!s.empty ())
234- {
235- CAGE_LOG_DEBUG (SeverityEnum::Warning, " assetProcessor" , Stringizer () + " output to unspecified shader: " + s);
236- }
237- return ;
238- }
239- codes[defines[" shader" ]] += std::string (s.c_str (), s.length ()) + " \n " ;
240- }
241-
242238 uint32 shaderType (const String &name)
243239 {
240+ if (name == " " )
241+ return 0 ;
244242 if (name == " vertex" )
245243 return 1 ;
246244 if (name == " fragment" )
247245 return 2 ;
248246 if (name == " compute" )
249247 return 3 ;
250- return 0 ;
248+ CAGE_THROW_ERROR (Exception, " unknwon shader stage name" );
249+ }
250+
251+ void output (const String &s)
252+ {
253+ codes[shaderType (defines[" shader" ])] += std::string (s.c_str (), s.length ()) + " \n " ;
251254 }
252255
253256 bool stackIsOk (const std::vector<sint32> &stack)
@@ -445,6 +448,48 @@ namespace
445448 CAGE_THROW_ERROR (Exception, " unexpected end of file; expecting $end" );
446449 }
447450 }
451+
452+ std::vector<bool > selectedKeys;
453+ void generateVariants (uint32 keyIndex)
454+ {
455+ if (keyIndex == keywords.size ())
456+ {
457+ std::string preamble = " " ;
458+ uint32 id = 0 ;
459+ for (uint32 i = 0 ; i < keywords.size (); i++)
460+ {
461+ if (selectedKeys[i])
462+ {
463+ auto it = keywords.begin ();
464+ std::advance (it, i);
465+ const detail::StringBase<20 > k = *it;
466+ preamble += std::string (" #define " ) + k.c_str () + " 1\n " ;
467+ id += hashRawString (k.c_str ());
468+ }
469+ }
470+ try
471+ {
472+ Holder<Spirv> sp = newSpirv ();
473+ GlslConfig glsl;
474+ static const std::string prepend = std::string () + " #version 450 core\n " + " // " + processor->inputName .c_str () + " \n " ;
475+ glsl.vertex = prepend + preamble + " #define varying out\n " + codes[0 ] + codes[1 ];
476+ glsl.fragment = prepend + preamble + " #define varying in\n " + codes[0 ] + codes[2 ];
477+ sp->importGlsl (glsl);
478+ variants.push_back ({ std::move (sp), id });
479+ }
480+ catch (...)
481+ {
482+ CAGE_LOG (SeverityEnum::Warning, " assetProcessor" , " failed to build shader variant" );
483+ }
484+ }
485+ else
486+ {
487+ selectedKeys[keyIndex] = true ;
488+ generateVariants (keyIndex + 1 );
489+ selectedKeys[keyIndex] = false ;
490+ generateVariants (keyIndex + 1 );
491+ }
492+ }
448493}
449494
450495void processShader ()
@@ -456,39 +501,41 @@ void processShader()
456501
457502 parse (processor->inputFileName );
458503
504+ for (const auto &it : keywords)
505+ CAGE_LOG (SeverityEnum::Info, " assetProcessor" , Stringizer () + " keyword: " + it);
506+
507+ selectedKeys.resize (keywords.size (), false );
508+ generateVariants (0 );
509+ if (variants.empty ())
459510 {
460- std::string prepend = R"foo( #version 450 core
461- )foo" ;
462- prepend += std::string () + " // " + processor->inputName .c_str () + " \n " ;
463- for (auto &it : codes)
464- it.second = prepend + it.second ;
511+ CAGE_THROW_ERROR (Exception, " generated no shader variants" );
465512 }
513+ else
514+ CAGE_LOG (SeverityEnum::Info, " assetProcessor" , Stringizer () + " generated variants: " + variants.size ());
466515
467516 {
468517 MultiShaderHeader header;
469- header.variantsCount = codes.size ();
470518 if (defines.count (" customDataCount" ))
471519 {
472520 const uint32 cdc = toUint32 (defines[" customDataCount" ]);
473521 CAGE_LOG (SeverityEnum::Info, " assetProcessor" , Stringizer () + " custom data count: " + cdc);
474522 header.customDataCount = cdc;
475523 }
524+ header.variantsCount = variants.size ();
525+
476526 MemoryBuffer buff;
477527 Serializer ser (buff);
478528 ser << header;
479- /*
480- for (const auto &it : keywords)
481529 {
482- CAGE_LOG(SeverityEnum::Info, "assetProcessor", Stringizer() + "keyword: " + it );
483- ser << it ;
530+ std::vector<detail::StringBase< 20 >> ks (keywords. begin (), keywords. end () );
531+ ser << ks ;
484532 }
485- */
486- for (const auto &it : codes)
533+ for (const Variant &v : variants)
487534 {
488- ser << (uint32) shaderType (it. first );
489- ser << numeric_cast<uint32>(it. second . length ()) ;
490- ser. write (it. second );
491- CAGE_LOG (SeverityEnum::Info, " assetProcessor " , Stringizer () + " stage: " + it. first + " , length: " + it. second . size () );
535+ const auto b = v. spirv -> exportBuffer ( );
536+ ser << v. id ;
537+ ser << numeric_cast<uint32>(b. size () );
538+ ser. write (b );
492539 }
493540
494541 CAGE_LOG (SeverityEnum::Info, " assetProcessor" , Stringizer () + " buffer size (before compression): " + buff.size ());
@@ -508,7 +555,7 @@ void processShader()
508555 {
509556 for (const auto &it : codes)
510557 {
511- String name = pathJoin (configGetString (" cage-asset-processor/shader/path" , " asset-preview" ), pathReplaceInvalidCharacters (processor->inputName ) + " _" + it.first + " .glsl" );
558+ const String name = pathJoin (configGetString (" cage-asset-processor/shader/path" , " asset-preview" ), Stringizer () + pathReplaceInvalidCharacters (processor->inputName ) + " _" + it.first + " .glsl" );
512559 FileMode fm (false , true );
513560 fm.textual = true ;
514561 Holder<File> f = newFile (name, fm);
0 commit comments