Add per-descriptor-set IO mapping shift values.

This PR adds the ability to provide per-descriptor-set IO mapping shift
values.  If a particular binding does not land into a per-set value,
then it falls back to the prior behavior (global shifts per resource class).

Because there were already 6 copies of many different methods and internal
variables and functions, and this PR would have added 6 more, a new API is
introduced to cut down on replication and present a cleaner interface.
For the global (non-set-specific) API, the old entry points still exist
for backward compatibility, but are phrased internally in terms of the
following.

    // Resource type for IO resolver
    enum TResourceType {
        EResSampler,
        EResTexture,
        EResImage,
        EResUbo,
        EResSsbo,
        EResUav,
        EResCount
    };

Methods on TShader:

    void setShiftBinding(TResourceType res, unsigned int base);
    void setShiftBindingForSet(TResourceType res, unsigned int set, unsigned int base);

The first method replaces the 6 prior entry points of various spellings, which
exist now in depreciated form.  The second provides per-resource-set functionality.
Both accept an enum from the list above.

From the command line, the existing options can accept either a single shift value as
before, or a series of 1 or more [set offset] pairs.  Both can be provided, as in:

    ... --stb 20 --stb 2 25 3 30 ...

which will use the offset 20 for anything except descriptor set 2 (which uses 25) and
3 (which uses 30).
This commit is contained in:
LoopDawg
2017-10-17 19:27:14 -06:00
parent 7d67c6cbc2
commit 08a14422c1
9 changed files with 523 additions and 159 deletions

View File

@@ -55,6 +55,7 @@
#include <cctype>
#include <cmath>
#include <array>
#include <map>
#include <memory>
#include <thread>
@@ -157,12 +158,11 @@ int OpenGLClientVersion = 450; // doesn't influence anything yet, but
unsigned int TargetVersion = 0x00001000; // maps to, say, SPIR-V 1.0
std::vector<std::string> Processes; // what should be recorded by OpModuleProcessed, or equivalent
std::array<unsigned int, EShLangCount> baseSamplerBinding;
std::array<unsigned int, EShLangCount> baseTextureBinding;
std::array<unsigned int, EShLangCount> baseImageBinding;
std::array<unsigned int, EShLangCount> baseUboBinding;
std::array<unsigned int, EShLangCount> baseSsboBinding;
std::array<unsigned int, EShLangCount> baseUavBinding;
// Per descriptor-set binding base data
typedef std::map<unsigned int, unsigned int> TPerSetBaseBinding;
std::array<std::array<unsigned int, EShLangCount>, glslang::EResCount> baseBinding;
std::array<std::array<TPerSetBaseBinding, EShLangCount>, glslang::EResCount> baseBindingForSet;
std::array<std::vector<std::string>, EShLangCount> baseResourceSetBinding;
// Add things like "#define ..." to a preamble to use in the beginning of the shader.
@@ -266,31 +266,54 @@ void Error(const char* message)
}
//
// Process an optional binding base of the form:
// --argname [stage] base
// Process an optional binding base of one the forms:
// --argname [stage] base // base for stage (if given) or all stages (if not)
// --argname [stage] [set base]... // set/base pairs: set the base for given binding set.
// Where stage is one of the forms accepted by FindLanguage, and base is an integer
//
void ProcessBindingBase(int& argc, char**& argv, std::array<unsigned int, EShLangCount>& base)
void ProcessBindingBase(int& argc, char**& argv, glslang::TResourceType res)
{
if (argc < 2)
usage();
if (!isdigit(argv[1][0])) {
EShLanguage lang = EShLangCount;
int singleBase = 0;
TPerSetBaseBinding perSetBase;
int arg = 1;
// Parse stage, if given
if (!isdigit(argv[arg][0])) {
if (argc < 3) // this form needs one more argument
usage();
// Parse form: --argname stage base
const EShLanguage lang = FindLanguage(argv[1], false);
base[lang] = atoi(argv[2]);
argc-= 2;
argv+= 2;
} else {
// Parse form: --argname base
for (int lang=0; lang<EShLangCount; ++lang)
base[lang] = atoi(argv[1]);
lang = FindLanguage(argv[arg++], false);
}
argc--;
argv++;
if ((argc - arg) > 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) {
// Parse a per-set binding base
while ((argc - arg) > 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) {
const int setNum = atoi(argv[arg++]);
const int baseNum = atoi(argv[arg++]);
perSetBase[setNum] = baseNum;
}
} else {
// Parse single binding base
singleBase = atoi(argv[arg++]);
}
argc -= (arg-1);
argv += (arg-1);
// Set one or all languages
const int langMin = (lang < EShLangCount) ? lang+0 : 0;
const int langMax = (lang < EShLangCount) ? lang+1 : EShLangCount;
for (int lang = langMin; lang < langMax; ++lang) {
if (!perSetBase.empty())
baseBindingForSet[res][lang] = perSetBase;
else
baseBinding[res][lang] = singleBase;
}
}
@@ -339,12 +362,8 @@ void ProcessResourceSetBindingBase(int& argc, char**& argv, std::array<std::vect
//
void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItems, int argc, char* argv[])
{
baseSamplerBinding.fill(0);
baseTextureBinding.fill(0);
baseImageBinding.fill(0);
baseUboBinding.fill(0);
baseSsboBinding.fill(0);
baseUavBinding.fill(0);
for (int res = 0; res < glslang::EResCount; ++res)
baseBinding[res].fill(0);
ExecutableName = argv[0];
workItems.reserve(argc);
@@ -441,30 +460,30 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
} else if (lowerword == "shift-image-bindings" || // synonyms
lowerword == "shift-image-binding" ||
lowerword == "sib") {
ProcessBindingBase(argc, argv, baseImageBinding);
ProcessBindingBase(argc, argv, glslang::EResImage);
} else if (lowerword == "shift-sampler-bindings" || // synonyms
lowerword == "shift-sampler-binding" ||
lowerword == "ssb") {
ProcessBindingBase(argc, argv, baseSamplerBinding);
ProcessBindingBase(argc, argv, glslang::EResSampler);
} else if (lowerword == "shift-uav-bindings" || // synonyms
lowerword == "shift-uav-binding" ||
lowerword == "suavb") {
ProcessBindingBase(argc, argv, baseUavBinding);
ProcessBindingBase(argc, argv, glslang::EResUav);
} else if (lowerword == "shift-texture-bindings" || // synonyms
lowerword == "shift-texture-binding" ||
lowerword == "stb") {
ProcessBindingBase(argc, argv, baseTextureBinding);
ProcessBindingBase(argc, argv, glslang::EResTexture);
} else if (lowerword == "shift-ubo-bindings" || // synonyms
lowerword == "shift-ubo-binding" ||
lowerword == "shift-cbuffer-bindings" ||
lowerword == "shift-cbuffer-binding" ||
lowerword == "sub" ||
lowerword == "scb") {
ProcessBindingBase(argc, argv, baseUboBinding);
ProcessBindingBase(argc, argv, glslang::EResUbo);
} else if (lowerword == "shift-ssbo-bindings" || // synonyms
lowerword == "shift-ssbo-binding" ||
lowerword == "sbb") {
ProcessBindingBase(argc, argv, baseSsboBinding);
ProcessBindingBase(argc, argv, glslang::EResSsbo);
} else if (lowerword == "source-entrypoint" || // synonyms
lowerword == "sep") {
if (argc <= 1)
@@ -791,12 +810,20 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
shader->setPreamble(UserPreamble.get());
shader->addProcesses(Processes);
shader->setShiftSamplerBinding(baseSamplerBinding[compUnit.stage]);
shader->setShiftTextureBinding(baseTextureBinding[compUnit.stage]);
shader->setShiftImageBinding(baseImageBinding[compUnit.stage]);
shader->setShiftUboBinding(baseUboBinding[compUnit.stage]);
shader->setShiftSsboBinding(baseSsboBinding[compUnit.stage]);
shader->setShiftUavBinding(baseUavBinding[compUnit.stage]);
// Set IO mapper binding shift values
for (int r = 0; r < glslang::EResCount; ++r) {
const glslang::TResourceType res = glslang::TResourceType(r);
// Set base bindings
shader->setShiftBinding(res, baseBinding[res][compUnit.stage]);
// Set bindings for particular resource sets
// TODO: use a range based for loop here, when available in all environments.
for (auto i = baseBindingForSet[res][compUnit.stage].begin();
i != baseBindingForSet[res][compUnit.stage].end(); ++i)
shader->setShiftBindingForSet(res, i->first, i->second);
}
shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0);
shader->setNoStorageFormat((Options & EOptionNoStorageFormat) != 0);
shader->setResourceSetBinding(baseResourceSetBinding[compUnit.stage]);
@@ -1274,17 +1301,24 @@ void usage()
" Set descriptor set for all resources\n"
" --rsb [stage] type set binding synonym for --resource-set-binding\n"
" --shift-image-binding [stage] num base binding number for images (uav)\n"
" --shift-image-binding [stage] [set num]... per-descriptor-set shift values\n"
" --sib [stage] num synonym for --shift-image-binding\n"
" --shift-sampler-binding [stage] num base binding number for samplers\n"
" --shift-sampler-binding [stage] [set num]... per-descriptor-set shift values\n"
" --ssb [stage] num synonym for --shift-sampler-binding\n"
" --shift-ssbo-binding [stage] num base binding number for SSBOs\n"
" --shift-ssbo-binding [stage] [set num]... per-descriptor-set shift values\n"
" --sbb [stage] num synonym for --shift-ssbo-binding\n"
" --shift-texture-binding [stage] num base binding number for textures\n"
" --shift-texture-binding [stage] [set num]... per-descriptor-set shift values\n"
" --stb [stage] num synonym for --shift-texture-binding\n"
" --shift-uav-binding [stage] num base binding number for UAVs\n"
" --shift-uav-binding [stage] [set num]... per-descriptor-set shift values\n"
" --suavb [stage] num synonym for --shift-uav-binding\n"
" --shift-UBO-binding [stage] num base binding number for UBOs\n"
" --shift-UBO-binding [stage] [set num]... per-descriptor-set shift values\n"
" --shift-cbuffer-binding [stage] num synonym for --shift-UBO-binding\n"
" --shift-cbuffer-binding [stage] [set num]... per-descriptor-set shift values\n"
" --sub [stage] num synonym for --shift-UBO-binding\n"
" --source-entrypoint <name> the given shader source function is\n"
" renamed to be the <name> given in -e\n"