Skip to content

Commit 63b8ec6

Browse files
author
Michael Saunders
committed
Extend shader compiler define syntax to allow name=value instead of just valueless defines
1 parent 05c76db commit 63b8ec6

1 file changed

Lines changed: 41 additions & 7 deletions

File tree

src/vsg/utils/ShaderCompiler.cpp

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
1010
1111
</editor-fold> */
1212

13+
#include <vsg/core/Exception.h>
1314
#include <vsg/core/Version.h>
1415
#include <vsg/io/Logger.h>
1516
#include <vsg/io/Options.h>
@@ -30,6 +31,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
3031
#endif
3132

3233
#include <algorithm>
34+
#include <cassert>
3335
#include <iomanip>
3436

3537
#ifndef VK_API_VERSION_MAJOR
@@ -444,7 +446,8 @@ std::string ShaderCompiler::combineSourceAndDefines(const std::string& source, c
444446
return str.substr(start + 1, (end - start) - 1);
445447
};
446448

447-
auto split = [](const std::string& str, const char& separator) {
449+
// returns the string split into sanitized tokens
450+
auto split = [&sanitise](const std::string& str, const char& separator) {
448451
std::vector<std::string> elements;
449452

450453
std::string::size_type prev_pos = 0, pos = 0;
@@ -453,10 +456,12 @@ std::string ShaderCompiler::combineSourceAndDefines(const std::string& source, c
453456
{
454457
auto substring = str.substr(prev_pos, pos - prev_pos);
455458
elements.push_back(substring);
459+
sanitise(elements.back());
456460
prev_pos = ++pos;
457461
}
458462

459463
elements.push_back(str.substr(prev_pos, pos - prev_pos));
464+
sanitise(elements.back());
460465

461466
return elements;
462467
};
@@ -465,6 +470,31 @@ std::string ShaderCompiler::combineSourceAndDefines(const std::string& source, c
465470
ss << line << "\n";
466471
};
467472

473+
/*
474+
* Verify that all the shader compiler defines are of the form "name" or "name=value" and that
475+
* the set doesn't contain entries with the same name and different values. This check is only
476+
* a temporary stopgap until the shader compiler defines container is updated from a
477+
* std::set<std::string>, to a std::map<std::string,std::string> to more properly manage defines
478+
* with optional values.
479+
*/
480+
std::set<std::string> uniqueDefines;
481+
for (auto nameValueDef : defines)
482+
{
483+
auto nameValueDefElems = split(nameValueDef, '=');
484+
// simple check for formatting issues
485+
if (nameValueDefElems.size() != 1 && nameValueDefElems.size() != 2)
486+
{
487+
throw Exception{"Error: Incorrectly formatted shader compile define. Acceptable formats are either a name or name=value."};
488+
}
489+
// verify that a valueless define or a name=value define with the same name has not already been encountered
490+
if (uniqueDefines.count(nameValueDefElems.front()) != 0)
491+
{
492+
throw Exception{"Error: Found two shader compiler defines with the same name and different values."};
493+
}
494+
// keep track that we have seen this define name
495+
uniqueDefines.insert(nameValueDefElems.front());
496+
}
497+
468498
std::istringstream iss(source);
469499
std::ostringstream headerstream;
470500
std::ostringstream sourcestream;
@@ -493,16 +523,20 @@ std::string ShaderCompiler::combineSourceAndDefines(const std::string& source, c
493523

494524
addLine(headerstream, line);
495525

496-
// loop the imported defines and see if it's also requested in defines, if so insert a define line
497-
for (auto importedDef : importedDefines)
526+
// loop over the requested defines and see if it's also in the imported defines, if so insert a define line
527+
for (auto nameValueDef : defines)
498528
{
499-
auto sanitiesedImportDef = importedDef;
500-
sanitise(sanitiesedImportDef);
529+
// separate the define name from its optional value
530+
auto nameValueDefElems = split(nameValueDef, '=');
531+
assert(nameValueDefElems.size() == 1 || nameValueDefElems.size() == 2);
501532

502-
auto finditr = std::find(defines.begin(), defines.end(), sanitiesedImportDef);
533+
auto finditr = std::find(importedDefines.begin(), importedDefines.end(), nameValueDefElems.front());
503534
if (finditr != defines.end())
504535
{
505-
addLine(headerstream, "#define " + sanitiesedImportDef);
536+
// output the pre-processor define directive with its name and optional value
537+
addLine(headerstream, "#define " + nameValueDefElems.front() +
538+
(nameValueDefElems.size() == 2
539+
? " "+nameValueDefElems.back() : std::string()));
506540
}
507541
}
508542
}

0 commit comments

Comments
 (0)