Check for out-of-range bindings during IO mapping.

This commit is contained in:
steve-lunarg 2016-10-05 13:40:13 -06:00
Родитель c056adcddd
Коммит 9ae34742cf
7 изменённых файлов: 72 добавлений и 13 удалений

Просмотреть файл

@ -584,6 +584,12 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
LinkFailed = true;
// Map IO
if (Options & EOptionSpv) {
if (!program.mapIO())
LinkFailed = true;
}
// Report
if (! (Options & EOptionSuppressInfolog) &&
! (Options & EOptionMemoryLeakMode)) {
@ -591,10 +597,6 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
PutsIfNonEmpty(program.getInfoDebugLog());
}
// Map IO
if (Options & EOptionSpv)
program.mapIO();
// Reflect
if (Options & EOptionDumpReflection) {
program.buildReflection();

Просмотреть файл

@ -0,0 +1,12 @@
spv.register.autoassign.rangetest.frag
Linked fragment stage:
INTERNAL ERROR: mapped binding out of range: g_tScene
INTERNAL ERROR: mapped binding out of range: g_tSamp
INTERNAL ERROR: mapped binding out of range: g_tScene
INTERNAL ERROR: mapped binding out of range: g_tSamp
INTERNAL ERROR: mapped binding out of range: g_tSamp
INTERNAL ERROR: mapped binding out of range: g_tScene
SPIR-V is not generated for failed compile or link

Просмотреть файл

@ -0,0 +1,15 @@
SamplerState g_tSamp : register(s5);
Texture2D g_tScene[2] : register(t5);
struct PS_OUTPUT
{
float4 Color : SV_Target0;
};
void main(out PS_OUTPUT psout)
{
psout.Color = g_tScene[0].Sample(g_tSamp, 0.3) +
g_tScene[1].Sample(g_tSamp, 0.3);
}

Просмотреть файл

@ -1724,7 +1724,7 @@ bool TProgram::mapIO()
for (int s = 0; s < EShLangCount; ++s) {
if (intermediate[s]) {
if (! ioMapper->addStage((EShLanguage)s, *intermediate[s]))
if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink))
return false;
}
}

Просмотреть файл

@ -34,6 +34,7 @@
//
#include "../Include/Common.h"
#include "../Include/InfoSink.h"
#include "iomapper.h"
#include "LiveTraverser.h"
#include "localintermediate.h"
@ -150,11 +151,30 @@ protected:
class TIoMappingTraverser : public TBindingTraverser {
public:
TIoMappingTraverser(TIntermediate& i, TBindingMap& bindingMap, TUsedBindings& usedBindings,
bool traverseDeadCode) :
TBindingTraverser(i, bindingMap, usedBindings, traverseDeadCode)
TInfoSink& infoSink, bool traverseDeadCode) :
TBindingTraverser(i, bindingMap, usedBindings, traverseDeadCode),
infoSink(infoSink),
assignError(false)
{ }
bool success() const { return !assignError; }
protected:
unsigned checkBindingRange(const TIntermSymbol& base, unsigned binding)
{
if (binding >= TQualifier::layoutBindingEnd) {
TString err = "mapped binding out of range: ";
err += base.getName();
infoSink.info.message(EPrefixInternalError, err.c_str());
assignError = true;
return 0;
}
return binding;
}
void addUniform(TIntermSymbol& base) override
{
// Skip things we don't intend to bind.
@ -165,7 +185,7 @@ protected:
// Apply existing binding, if we were given one or already made one up.
if (existingBinding != -1) {
base.getWritableType().getQualifier().layoutBinding = existingBinding;
base.getWritableType().getQualifier().layoutBinding = checkBindingRange(base, existingBinding);
return;
}
@ -174,7 +194,7 @@ protected:
const int freeBinding = getFreeBinding(base.getType(), getBindingBase(base.getType()));
markBinding(base, freeBinding);
base.getWritableType().getQualifier().layoutBinding = freeBinding;
base.getWritableType().getQualifier().layoutBinding = checkBindingRange(base, freeBinding);
}
}
@ -195,13 +215,17 @@ protected:
return nextBinding;
}
private:
bool assignError; // true if there was an error assigning the bindings
TInfoSink& infoSink;
};
// Map I/O variables to provided offsets, and make bindings for
// unbound but live variables.
//
// Returns false if the input is too malformed to do this.
bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate)
bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate, TInfoSink& infoSink)
{
// Trivial return if there is nothing to do.
if (intermediate.getShiftSamplerBinding() == 0 &&
@ -223,7 +247,7 @@ bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate)
TBindingTraverser it_binding_all(intermediate, bindingMap, usedBindings, true);
TBindingTraverser it_binding_live(intermediate, bindingMap, usedBindings, false);
TIoMappingTraverser it_iomap(intermediate, bindingMap, usedBindings, true);
TIoMappingTraverser it_iomap(intermediate, bindingMap, usedBindings, infoSink, true);
// Traverse all (live+dead) code to find explicit bindings, so we can avoid those.
root->traverse(&it_binding_all);
@ -240,7 +264,7 @@ bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate)
// Bind everything that needs a binding and doesn't have one.
root->traverse(&it_iomap);
return true;
return it_iomap.success();
}
} // end namespace glslang

Просмотреть файл

@ -42,6 +42,8 @@
// A reflection database and its interface, consistent with the OpenGL API reflection queries.
//
class TInfoSink;
namespace glslang {
class TIntermediate;
@ -53,7 +55,7 @@ public:
virtual ~TIoMapper() {}
// grow the reflection stage by stage
bool addStage(EShLanguage, TIntermediate&);
bool addStage(EShLanguage, TIntermediate&, TInfoSink&);
};
} // end namespace glslang

Просмотреть файл

@ -285,6 +285,10 @@ INSTANTIATE_TEST_CASE_P(
{ "spv.register.noautoassign.frag", "main_ep", 5, 10, 15, false, false },
{ "spv.register.autoassign-2.frag", "main", 5, 10, 15, true, true },
{ "spv.buffer.autoassign.frag", "main", 5, 10, 15, true, true },
{ "spv.register.autoassign.rangetest.frag", "main",
glslang::TQualifier::layoutBindingEnd-2,
glslang::TQualifier::layoutBindingEnd+5,
20, true, false },
}),
FileNameAsCustomTestSuffixIoMap
);