summaryrefslogtreecommitdiffstats
path: root/tools/render-test/shader-input-layout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/render-test/shader-input-layout.cpp')
-rw-r--r--tools/render-test/shader-input-layout.cpp1111
1 files changed, 578 insertions, 533 deletions
diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp
index 071c694b5..5783c6eb8 100644
--- a/tools/render-test/shader-input-layout.cpp
+++ b/tools/render-test/shader-input-layout.cpp
@@ -42,596 +42,641 @@ namespace renderer_test
return SLANG_SCALAR_TYPE_NONE;
}
- Index ShaderInputLayout::findEntryIndexByName(const String& name) const
+ void ShaderInputLayout::AggVal::addField(ShaderInputLayout::Field const& field)
{
- const Index count = Index(entries.getCount());
- for (Index i = 0; i < count; ++i)
- {
- const auto& entry = entries[i];
- if (entry.name == name)
- {
- return Index(i);
- }
- }
- return -1;
+ fields.add(field);
}
- static bool _isCPULikeBindingTarget(SlangCompileTarget target)
+ void ShaderInputLayout::ArrayVal::addField(ShaderInputLayout::Field const& field)
{
- // CUDA and C++ are 'CPULike' in terms of their binding mechanism
- switch (target)
+ vals.add(field.val);
+ }
+
+ class ShaderInputLayoutFormatException : public Exception
+ {
+ public:
+ ShaderInputLayoutFormatException(String message)
+ : Exception(message)
+ {}
+ };
+
+ struct ShaderInputLayoutParser
+ {
+ ShaderInputLayout* layout;
+ RandomGenerator* rand;
+
+ ShaderInputLayoutParser(ShaderInputLayout* layout, RandomGenerator* rand)
+ : layout(layout)
+ , rand(rand)
+ {}
+
+ RefPtr<ShaderInputLayout::ParentVal> parentVal;
+ List<RefPtr<ShaderInputLayout::ParentVal>> parentValStack;
+
+ SlangResult parseOption(TokenReader& parser, String const& word, ShaderInputLayout::TextureVal* val)
{
- case SLANG_C_SOURCE:
- case SLANG_CPP_SOURCE:
- case SLANG_EXECUTABLE:
- case SLANG_SHARED_LIBRARY:
- case SLANG_HOST_CALLABLE:
- case SLANG_CUDA_SOURCE:
- case SLANG_PTX:
+ if (word == "depth")
+ {
+ val->textureDesc.isDepthTexture = true;
+ }
+ else if (word == "arrayLength")
+ {
+ parser.Read("=");
+ val->textureDesc.arrayLength = parser.ReadInt();
+ }
+ else if (word == "size")
{
- return true;
+ parser.Read("=");
+ auto size = parser.ReadInt();
+ val->textureDesc.size = size;
}
- default: return false;
+ else if (word == "content")
+ {
+ parser.Read("=");
+ auto contentWord = parser.ReadWord();
+ if (contentWord == "zero")
+ val->textureDesc.content = InputTextureContent::Zero;
+ else if (contentWord == "one")
+ val->textureDesc.content = InputTextureContent::One;
+ else if (contentWord == "chessboard")
+ val->textureDesc.content = InputTextureContent::ChessBoard;
+ else
+ val->textureDesc.content = InputTextureContent::Gradient;
+ }
+ else if(word == "mipMaps")
+ {
+ parser.Read("=");
+ val->textureDesc.mipMapCount = int(parser.ReadInt());
+ }
+ else if(word == "format")
+ {
+ val->textureDesc.format = parseFormatOption(parser);
+ }
+ else
+ {
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
}
- }
- void ShaderInputLayout::updateForTarget(SlangCompileTarget target)
- {
- if (!_isCPULikeBindingTarget(target))
+ SlangResult parseOption(TokenReader& parser, String const& word, ShaderInputLayout::SamplerVal* val)
{
- int count = int(entries.getCount());
- for (int i = 0; i < count; ++i)
+ if (word == "depthCompare")
{
- auto& entry = entries[i];
- if (entry.onlyCPULikeBinding)
- {
- entries.removeAt(i);
- i--;
- count--;
- }
+ val->samplerDesc.isCompareSampler = true;
}
+ else
+ {
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
}
- }
- void ShaderInputLayout::parse(RandomGenerator* rand, const char * source)
- {
- entries.clear();
- globalSpecializationArgs.clear();
- entryPointSpecializationArgs.clear();
- auto lines = Split(source, '\n');
- for (auto & line : lines)
+ SlangResult parseOption(TokenReader& parser, String const& word, ShaderInputLayout::DataValBase* val)
{
- if (line.startsWith("//TEST_INPUT:"))
+ if (word == "data")
{
- auto lineContent = line.subString(13, line.getLength() - 13);
- TokenReader parser(lineContent);
- try
+ parser.Read("=");
+
+ parser.Read("[");
+ uint32_t offset = 0;
+ while (!parser.IsEnd() && !parser.LookAhead("]"))
{
- if (parser.LookAhead("entryPointSpecializationArg")
- || parser.LookAhead("type")
- || parser.LookAhead("entryPointExistentialType"))
+ bool negate = false;
+ if(parser.NextToken().Type == TokenType::OpSub)
{
parser.ReadToken();
- StringBuilder typeExp;
- while (!parser.IsEnd())
- typeExp << parser.ReadToken().Content;
- entryPointSpecializationArgs.add(typeExp);
+ negate = true;
}
- else if (parser.LookAhead("globalSpecializationArg")
- || parser.LookAhead("global_type")
- || parser.LookAhead("globalExistentialType"))
+
+ if (parser.NextToken().Type == TokenType::IntLiteral)
{
- parser.ReadToken();
- StringBuilder typeExp;
- while (!parser.IsEnd())
- typeExp << parser.ReadToken().Content;
- globalSpecializationArgs.add(typeExp);
+ uint32_t value = parser.ReadUInt();
+ if(negate) value = uint32_t(-int32_t(value));
+ val->bufferData.add(value);
}
else
{
- ShaderInputLayoutEntry entry;
+ auto floatNum = parser.ReadFloat();
+ if(negate) floatNum = -floatNum;
+ val->bufferData.add(*(unsigned int*)&floatNum);
+ }
+ offset += 4;
+ }
+ parser.Read("]");
+ }
+ else
+ {
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
+ }
- if (parser.LookAhead("array"))
- {
- entry.type = ShaderInputType::Array;
- }
- else if (parser.LookAhead("cbuffer"))
- {
- entry.type = ShaderInputType::Buffer;
- entry.bufferDesc.type = InputBufferType::ConstantBuffer;
- }
- else if (parser.LookAhead("object"))
- {
- entry.type = ShaderInputType::Object;
- }
- else if (parser.LookAhead("root_constants"))
- {
- entry.type = ShaderInputType::Buffer;
- entry.bufferDesc.type = InputBufferType::RootConstantBuffer;
- }
- else if (parser.LookAhead("Uniform"))
- {
- entry.type = ShaderInputType::Uniform;
- }
- else if (parser.LookAhead("ubuffer"))
- {
- entry.type = ShaderInputType::Buffer;
- entry.bufferDesc.type = InputBufferType::StorageBuffer;
- }
- else if (parser.LookAhead("Texture1D"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 1;
- }
- else if (parser.LookAhead("Texture2D"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 2;
- }
- else if (parser.LookAhead("Texture3D"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 3;
- }
- else if (parser.LookAhead("TextureCube"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 2;
- entry.textureDesc.isCube = true;
- }
- else if (parser.LookAhead("RWTexture1D"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 1;
- entry.textureDesc.isRWTexture = true;
- }
- else if (parser.LookAhead("RWTexture2D"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 2;
- entry.textureDesc.isRWTexture = true;
- }
- else if (parser.LookAhead("RWTexture3D"))
+ SlangResult parseOption(TokenReader& parser, String const& word, ShaderInputLayout::BufferVal* val)
+ {
+ if (word == "stride")
+ {
+ parser.Read("=");
+ val->bufferDesc.stride = parser.ReadInt();
+ }
+ else if (word == "random")
+ {
+ parser.Read("(");
+ // Read the type
+ String type = parser.ReadWord();
+ SlangScalarType scalarType = _getScalarType(type.getUnownedSlice());
+ if (scalarType == SLANG_SCALAR_TYPE_NONE)
+ {
+ StringBuilder scalarTypeNames;
+ for (const auto& info : g_scalarTypeInfos)
+ {
+ if (scalarTypeNames.getLength() != 0)
{
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 3;
- entry.textureDesc.isRWTexture = true;
+ scalarTypeNames << ", ";
}
- else if (parser.LookAhead("RWTextureCube"))
+ scalarTypeNames << info.name;
+ }
+
+ throw ShaderInputLayoutFormatException(StringBuilder() << "Expecting " << scalarTypeNames << " " << parser.NextToken().Position.Line);
+ }
+
+ parser.Read(",");
+ const int size = int(parser.ReadUInt());
+
+ switch (scalarType)
+ {
+ case SLANG_SCALAR_TYPE_INT32:
+ {
+ bool hasRange = false;
+
+ int32_t minValue = -0x7fffffff - 1;
+ int32_t maxValue = 0x7fffffff;
+
+ if (parser.LookAhead(","))
{
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 2;
- entry.textureDesc.isCube = true;
- entry.textureDesc.isRWTexture = true;
+ hasRange = true;
+ parser.ReadToken();
+ minValue = parser.ReadInt();
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ maxValue = parser.ReadInt();
+ }
}
- else if (parser.LookAhead("Sampler"))
+ SLANG_ASSERT(minValue <= maxValue);
+ maxValue = (maxValue >= minValue) ? maxValue : minValue;
+
+ // Generate the data
+ val->bufferData.setCount(size);
+
+ int32_t* dst = (int32_t*)val->bufferData.getBuffer();
+ for (int i = 0; i < size; ++i)
{
- entry.type = ShaderInputType::Sampler;
+ dst[i] = hasRange ? rand->nextInt32InRange(minValue, maxValue) : rand->nextInt32();
}
- else if (parser.LookAhead("Sampler1D"))
+ break;
+ }
+ case SLANG_SCALAR_TYPE_UINT32:
+ {
+ bool hasRange = false;
+ uint32_t minValue = 0;
+ uint32_t maxValue = 0xffffffff;
+
+ if (parser.LookAhead(","))
{
- entry.type = ShaderInputType::CombinedTextureSampler;
- entry.textureDesc.dimension = 1;
+ parser.ReadToken();
+ minValue = parser.ReadUInt();
+
+ hasRange = true;
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ maxValue = parser.ReadUInt();
+ }
}
- else if (parser.LookAhead("Sampler2D"))
+
+ SLANG_ASSERT(minValue <= maxValue);
+ maxValue = (maxValue >= minValue) ? maxValue : minValue;
+
+ // Generate the data
+ val->bufferData.setCount(size);
+
+ uint32_t* dst = (uint32_t*)val->bufferData.getBuffer();
+ for (int i = 0; i < size; ++i)
{
- entry.type = ShaderInputType::CombinedTextureSampler;
- entry.textureDesc.dimension = 2;
+ dst[i] = hasRange ? rand->nextUInt32InRange(minValue, maxValue) : rand->nextUInt32();
}
- else if (parser.LookAhead("Sampler3D"))
+
+ break;
+ }
+ case SLANG_SCALAR_TYPE_FLOAT32:
+ {
+ float minValue = -1.0f;
+ float maxValue = 1.0f;
+
+ if (parser.LookAhead(","))
{
- entry.type = ShaderInputType::CombinedTextureSampler;
- entry.textureDesc.dimension = 3;
+ parser.ReadToken();
+ minValue = parser.ReadFloat();
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ maxValue = parser.ReadFloat();
+ }
}
- else if (parser.LookAhead("SamplerCube"))
+
+ SLANG_ASSERT(minValue <= maxValue);
+ maxValue = (maxValue >= minValue) ? maxValue : minValue;
+
+ // Generate the data
+ val->bufferData.setCount(size);
+
+ float* dst = (float*)val->bufferData.getBuffer();
+ for (int i = 0; i < size; ++i)
{
- entry.type = ShaderInputType::CombinedTextureSampler;
- entry.textureDesc.dimension = 2;
- entry.textureDesc.isCube = true;
+ dst[i] = (rand->nextUnitFloat32() * (maxValue - minValue)) + minValue;
}
- else if (parser.LookAhead("render_targets"))
+ break;
+ }
+ }
+
+ // Read the range
+
+ parser.Read(")");
+ }
+ else if(word == "format")
+ {
+ val->bufferDesc.format = parseFormatOption(parser);
+ }
+ else
+ {
+ return parseOption(parser, word, static_cast<ShaderInputLayout::DataValBase*>(val));
+ }
+ return SLANG_OK;
+ }
+
+ SlangResult parseOption(TokenReader& parser, String const& word, ShaderInputLayout::ObjectVal* val)
+ {
+ if( word == "type" )
+ {
+ parser.Read("=");
+ val->typeName = parser.ReadWord();
+ }
+ else
+ {
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
+ }
+
+ Format parseFormatOption(TokenReader& parser)
+ {
+ Format format = Format::Unknown;
+
+ parser.Read("=");
+ auto formatWord = parser.ReadWord();
+ if(formatWord == "R_UInt32")
+ {
+ format = Format::R_UInt32;
+ }
+ else if (formatWord == "R_Float32")
+ {
+ format = Format::R_Float32;
+ }
+ else if (formatWord == "RGBA_Unorm_UInt8")
+ {
+ format = Format::RGBA_Unorm_UInt8;
+ }
+ else
+ {
+ // TODO: an error message here
+ }
+ return format;
+ }
+
+ template<typename T>
+ void maybeParseOptions(TokenReader& parser, T* val)
+ {
+ // parse options
+ if (parser.LookAhead("("))
+ {
+ parser.Read("(");
+ while (!parser.IsEnd() && !parser.LookAhead(")"))
+ {
+ auto word = parser.ReadWord();
+ if( SLANG_FAILED(parseOption(parser, word, val)) )
+ {
+ throw ShaderInputLayoutFormatException(String("Unsupported option '") + word + String("' at line ") + String(parser.NextToken().Position.Line));
+ }
+
+ if (parser.LookAhead(","))
+ parser.Read(",");
+ else
+ break;
+ }
+ parser.Read(")");
+ }
+ }
+
+ RefPtr<ShaderInputLayout::Val> parseVal(TokenReader& parser)
+ {
+ auto word = parser.NextToken().Content;
+ if (parser.AdvanceIf("begin_array"))
+ {
+ RefPtr<ShaderInputLayout::ArrayVal> val = new ShaderInputLayout::ArrayVal;
+ pushParentVal(val);
+ return val;
+ }
+ else if (parser.AdvanceIf("begin_object"))
+ {
+ RefPtr<ShaderInputLayout::ObjectVal> val = new ShaderInputLayout::ObjectVal;
+ maybeParseOptions(parser, val.Ptr());
+
+ RefPtr<ShaderInputLayout::AggVal> contentVal = new ShaderInputLayout::AggVal;
+ val->contentVal = contentVal;
+ pushParentVal(contentVal);
+
+ return val;
+ }
+ else if (parser.AdvanceIf("uniform"))
+ {
+ RefPtr<ShaderInputLayout::DataVal> val = new ShaderInputLayout::DataVal;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("cbuffer"))
+ {
+ // A `cbuffer` is basically just an object where the content of
+ // the object is being provided by `uniform` data instead.
+
+ RefPtr<ShaderInputLayout::ObjectVal> objVal = new ShaderInputLayout::ObjectVal;
+
+ RefPtr<ShaderInputLayout::DataVal> dataVal = new ShaderInputLayout::DataVal;
+ maybeParseOptions(parser, dataVal.Ptr());
+
+ objVal->contentVal = dataVal;
+
+ return objVal;
+ }
+ else if (parser.AdvanceIf("ubuffer"))
+ {
+ RefPtr<ShaderInputLayout::BufferVal> val = new ShaderInputLayout::BufferVal;
+ val->bufferDesc.type = InputBufferType::StorageBuffer;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("Texture1D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 1;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("Texture2D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 2;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("Texture3D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 3;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("TextureCube"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 2;
+ val->textureDesc.isCube = true;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("RWTexture1D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 1;
+ val->textureDesc.isRWTexture = true;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("RWTexture2D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 2;
+ val->textureDesc.isRWTexture = true;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("RWTexture3D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 3;
+ val->textureDesc.isRWTexture = true;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("RWTextureCube"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 2;
+ val->textureDesc.isCube = true;
+ val->textureDesc.isRWTexture = true;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("Sampler"))
+ {
+ RefPtr<ShaderInputLayout::SamplerVal> val = new ShaderInputLayout::SamplerVal;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ // TODO: We can include combined texture/sampler cases
+ // here, but we don't really have tests for them and
+ // it might be better to save it for a point where
+ // we support hierarchical binding values more directly.
+ else
+ {
+ throw ShaderInputLayoutFormatException(String("Unknown shader input type '") + word + String("' at line") + String(parser.NextToken().Position.Line));
+ }
+ parser.ReadToken();
+ }
+
+ void parseFieldBindings(TokenReader& parser, ShaderInputLayout::Field& ioField)
+ {
+ // parse bindings
+ if (parser.LookAhead(":"))
+ {
+ parser.Read(":");
+ while (!parser.IsEnd())
+ {
+ if (parser.AdvanceIf("out"))
+ {
+ ioField.val->isOutput = true;
+ }
+ else if (parser.AdvanceIf("name"))
+ {
+ // Optionally consume '='
+ if (parser.NextToken().Type == TokenType::OpAssign)
{
- numRenderTargets = parser.ReadInt();
- continue;
+ parser.ReadToken();
}
- else
+
+ StringBuilder builder;
+
+ Token nameToken = parser.ReadToken();
+ if (nameToken.Type != TokenType::Identifier)
{
- throw TextFormatException(String("Invalid input syntax at line ") + String(parser.NextToken().Position.Line));
+ throw ShaderInputLayoutFormatException(StringBuilder() << "Invalid input syntax at line " << parser.NextToken().Position.Line);
}
- parser.ReadToken();
- // parse options
- if (parser.LookAhead("("))
+ builder << nameToken.Content;
+
+ while (!parser.IsEnd())
{
- parser.Read("(");
- while (!parser.IsEnd() && !parser.LookAhead(")"))
+ Token token = parser.NextToken(0);
+
+ if (token.Type == TokenType::LBracket)
{
- auto word = parser.ReadWord();
- if (word == "depth")
- {
- entry.textureDesc.isDepthTexture = true;
- }
- else if (word == "depthCompare")
- {
- entry.samplerDesc.isCompareSampler = true;
- }
- else if (word == "arrayLength")
- {
- parser.Read("=");
- entry.textureDesc.arrayLength = parser.ReadInt();
- }
- else if (word == "stride")
- {
- parser.Read("=");
- entry.bufferDesc.stride = parser.ReadInt();
- }
- else if (word == "size")
- {
- parser.Read("=");
- auto size = parser.ReadInt();
- if (entry.type == ShaderInputType::Array)
- {
- entry.arrayDesc.size = size;
- }
- else
- {
- entry.textureDesc.size = size;
- }
- }
- else if (word == "random")
- {
- parser.Read("(");
- // Read the type
- String type = parser.ReadWord();
- SlangScalarType scalarType = _getScalarType(type.getUnownedSlice());
- if (scalarType == SLANG_SCALAR_TYPE_NONE)
- {
- StringBuilder scalarTypeNames;
- for (const auto& info : g_scalarTypeInfos)
- {
- if (scalarTypeNames.getLength() != 0)
- {
- scalarTypeNames << ", ";
- }
- scalarTypeNames << info.name;
- }
-
- throw TextFormatException(StringBuilder() << "Expecting " << scalarTypeNames << " " << parser.NextToken().Position.Line);
- }
-
- parser.Read(",");
- const int size = int(parser.ReadUInt());
-
- switch (scalarType)
- {
- case SLANG_SCALAR_TYPE_INT32:
- {
- bool hasRange = false;
-
- int32_t minValue = -0x7fffffff - 1;
- int32_t maxValue = 0x7fffffff;
-
- if (parser.LookAhead(","))
- {
- hasRange = true;
- parser.ReadToken();
- minValue = parser.ReadInt();
-
- if (parser.LookAhead(","))
- {
- parser.ReadToken();
- maxValue = parser.ReadInt();
- }
- }
- SLANG_ASSERT(minValue <= maxValue);
- maxValue = (maxValue >= minValue) ? maxValue : minValue;
-
- // Generate the data
- entry.bufferData.setCount(size);
-
- int32_t* dst = (int32_t*)entry.bufferData.getBuffer();
- for (int i = 0; i < size; ++i)
- {
- dst[i] = hasRange ? rand->nextInt32InRange(minValue, maxValue) : rand->nextInt32();
- }
- break;
- }
- case SLANG_SCALAR_TYPE_UINT32:
- {
- bool hasRange = false;
- uint32_t minValue = 0;
- uint32_t maxValue = 0xffffffff;
-
- if (parser.LookAhead(","))
- {
- parser.ReadToken();
- minValue = parser.ReadUInt();
-
- hasRange = true;
-
- if (parser.LookAhead(","))
- {
- parser.ReadToken();
- maxValue = parser.ReadUInt();
- }
- }
-
- SLANG_ASSERT(minValue <= maxValue);
- maxValue = (maxValue >= minValue) ? maxValue : minValue;
-
- // Generate the data
- entry.bufferData.setCount(size);
-
- uint32_t* dst = (uint32_t*)entry.bufferData.getBuffer();
- for (int i = 0; i < size; ++i)
- {
- dst[i] = hasRange ? rand->nextUInt32InRange(minValue, maxValue) : rand->nextUInt32();
- }
-
- break;
- }
- case SLANG_SCALAR_TYPE_FLOAT32:
- {
- float minValue = -1.0f;
- float maxValue = 1.0f;
-
- if (parser.LookAhead(","))
- {
- parser.ReadToken();
- minValue = parser.ReadFloat();
-
- if (parser.LookAhead(","))
- {
- parser.ReadToken();
- maxValue = parser.ReadFloat();
- }
- }
-
- SLANG_ASSERT(minValue <= maxValue);
- maxValue = (maxValue >= minValue) ? maxValue : minValue;
-
- // Generate the data
- entry.bufferData.setCount(size);
-
- float* dst = (float*)entry.bufferData.getBuffer();
- for (int i = 0; i < size; ++i)
- {
- dst[i] = (rand->nextUnitFloat32() * (maxValue - minValue)) + minValue;
- }
- break;
- }
- }
-
- // Read the range
-
- parser.Read(")");
- }
- else if (word == "data")
- {
- parser.Read("=");
-
- parser.Read("[");
- uint32_t offset = 0;
- while (!parser.IsEnd() && !parser.LookAhead("]"))
- {
- RTTIDataEntry rttiEntry;
- if (parser.LookAhead("rtti"))
- {
- parser.ReadToken();
- parser.Read("(");
- rttiEntry.type = RTTIDataEntryType::RTTIObject;
- rttiEntry.typeName = parser.ReadWord();
- rttiEntry.offset = offset;
- parser.Read(")");
- offset += 8;
- entry.rttiEntries.add(rttiEntry);
- entry.bufferData.add(0);
- entry.bufferData.add(0);
- continue;
- }
- else if (parser.LookAhead("witness"))
- {
- parser.ReadToken();
- parser.Read("(");
- rttiEntry.type = RTTIDataEntryType::WitnessTable;
- rttiEntry.typeName = parser.ReadWord();
- parser.Read(",");
- rttiEntry.interfaceName = parser.ReadWord();
- rttiEntry.offset = offset;
- parser.Read(")");
- offset += 8;
- entry.rttiEntries.add(rttiEntry);
- entry.bufferData.add(0);
- entry.bufferData.add(0);
- continue;
- }
- else if (parser.LookAhead("handle"))
- {
- BindlessHandleDataEntry handleEntry;
- parser.ReadToken();
- parser.Read("(");
- handleEntry.name = parser.ReadWord();
- handleEntry.offset = offset;
- parser.Read(")");
- offset += 8;
- entry.bindlessHandleEntry.add(handleEntry);
- entry.bufferData.add(0);
- entry.bufferData.add(0);
- continue;
- }
-
- bool negate = false;
- if(parser.NextToken().Type == TokenType::OpSub)
- {
- parser.ReadToken();
- negate = true;
- }
-
- if (parser.NextToken().Type == TokenType::IntLiteral)
- {
- uint32_t val = parser.ReadUInt();
- if(negate) val = uint32_t(-int32_t(val));
- entry.bufferData.add(val);
- }
- else
- {
- auto floatNum = parser.ReadFloat();
- if(negate) floatNum = -floatNum;
- entry.bufferData.add(*(unsigned int*)&floatNum);
- }
- offset += 4;
- }
- parser.Read("]");
- }
- else if (word == "content")
- {
- parser.Read("=");
- auto contentWord = parser.ReadWord();
- if (contentWord == "zero")
- entry.textureDesc.content = InputTextureContent::Zero;
- else if (contentWord == "one")
- entry.textureDesc.content = InputTextureContent::One;
- else if (contentWord == "chessboard")
- entry.textureDesc.content = InputTextureContent::ChessBoard;
- else
- entry.textureDesc.content = InputTextureContent::Gradient;
- }
- else if(word == "format")
- {
- Format format = Format::Unknown;
-
- parser.Read("=");
- auto formatWord = parser.ReadWord();
- if(formatWord == "R_UInt32")
- {
- format = Format::R_UInt32;
- }
- else if (formatWord == "R_Float32")
- {
- format = Format::R_Float32;
- }
- else if (formatWord == "RGBA_Unorm_UInt8")
- {
- format = Format::RGBA_Unorm_UInt8;
- }
-
- entry.textureDesc.format = format;
- entry.bufferDesc.format = format;
- }
- else if(word == "mipMaps")
- {
- parser.Read("=");
- entry.textureDesc.mipMapCount = int(parser.ReadInt());
- }
- else if( word == "type" )
- {
- parser.Read("=");
- entry.objectDesc.typeName = parser.ReadWord();
- }
-
- if (parser.LookAhead(","))
- parser.Read(",");
- else
- break;
+ parser.ReadToken();
+ int index = parser.ReadInt();
+ SLANG_ASSERT(index >= 0);
+ parser.ReadMatchingToken(TokenType::RBracket);
+
+ builder << "[" << index << "]";
}
- parser.Read(")");
- }
- // parse bindings
- if (parser.LookAhead(":"))
- {
- parser.Read(":");
- while (!parser.IsEnd())
+ else if (token.Type == TokenType::Dot)
+ {
+ parser.ReadToken();
+ Token identifierToken = parser.ReadMatchingToken(TokenType::Identifier);
+
+ builder << "." << identifierToken.Content;
+ }
+ else if (token.Type == TokenType::Comma)
+ {
+ // Break out
+ break;
+ }
+ else
{
- if (parser.LookAhead("onlyCPULikeBinding"))
- {
- entry.onlyCPULikeBinding = true;
- parser.ReadToken();
- }
- else if (parser.LookAhead("out"))
- {
- parser.ReadToken();
- entry.isOutput = true;
- }
- else if (parser.LookAhead("name"))
- {
- parser.ReadToken();
-
- // Optionally consume '='
- if (parser.NextToken().Type == TokenType::OpAssign)
- {
- parser.ReadToken();
- }
-
- StringBuilder builder;
-
- Token nameToken = parser.ReadToken();
- if (nameToken.Type != TokenType::Identifier)
- {
- throw TextFormatException(StringBuilder() << "Invalid input syntax at line " << parser.NextToken().Position.Line);
- }
- builder << nameToken.Content;
-
- while (!parser.IsEnd())
- {
- Token token = parser.NextToken(0);
-
- if (token.Type == TokenType::LBracket)
- {
- parser.ReadToken();
- int index = parser.ReadInt();
- SLANG_ASSERT(index >= 0);
- parser.ReadMatchingToken(TokenType::RBracket);
-
- builder << "[" << index << "]";
- }
- else if (token.Type == TokenType::Dot)
- {
- parser.ReadToken();
- Token identifierToken = parser.ReadMatchingToken(TokenType::Identifier);
-
- builder << "." << identifierToken.Content;
- }
- else if (token.Type == TokenType::Comma)
- {
- // Break out
- break;
- }
- else
- {
- throw TextFormatException(StringBuilder() << "Invalid input syntax at line " << parser.NextToken().Position.Line);
- }
- }
-
- entry.name = builder;
- }
- else if (parser.LookAhead("bindless"))
- {
- parser.ReadToken();
- entry.isBindlessObject = true;
- }
- else
- {
- fprintf(stderr, "Invalid TEST_INPUT syntax '%s'\n", parser.NextToken().Content.getBuffer());
- break;
- }
-
- if (parser.LookAhead(","))
- parser.Read(",");
+ throw ShaderInputLayoutFormatException(StringBuilder() << "Invalid input syntax at line " << parser.NextToken().Position.Line);
}
}
- entries.add(entry);
+
+ ioField.name = builder;
}
+ else
+ {
+ fprintf(stderr, "Invalid TEST_INPUT syntax '%s'\n", parser.NextToken().Content.getBuffer());
+ break;
+ }
+
+ if (parser.LookAhead(","))
+ parser.Read(",");
}
- catch (const TextFormatException&)
+ }
+ }
+
+ void pushParentVal(ShaderInputLayout::ParentVal* val)
+ {
+ parentValStack.add(parentVal);
+ parentVal = val;
+ }
+
+ void parseValEntry(TokenReader& parser)
+ {
+ auto parentForNewVal = parentVal;
+
+ ShaderInputLayout::Field field;
+ field.val = parseVal(parser);
+ parseFieldBindings(parser, field);
+
+ parentForNewVal->addField(field);
+ }
+
+ void parseLine(TokenReader& parser)
+ {
+ if (parser.LookAhead("entryPointSpecializationArg")
+ || parser.LookAhead("type")
+ || parser.LookAhead("entryPointExistentialType"))
+ {
+ parser.ReadToken();
+ StringBuilder typeExp;
+ while (!parser.IsEnd())
+ typeExp << parser.ReadToken().Content;
+ layout->entryPointSpecializationArgs.add(typeExp);
+ }
+ else if (parser.LookAhead("globalSpecializationArg")
+ || parser.LookAhead("global_type")
+ || parser.LookAhead("globalExistentialType"))
+ {
+ parser.ReadToken();
+ StringBuilder typeExp;
+ while (!parser.IsEnd())
+ typeExp << parser.ReadToken().Content;
+ layout->globalSpecializationArgs.add(typeExp);
+ }
+ else if (parser.AdvanceIf("render_targets"))
+ {
+ layout->numRenderTargets = parser.ReadInt();
+ }
+ else if( parser.AdvanceIf("end") )
+ {
+ parentVal = parentValStack.getLast();
+ parentValStack.removeLast();
+ }
+ else
+ {
+ parseValEntry(parser);
+ }
+ }
+
+ RefPtr<ShaderInputLayout::AggVal> parse(const char * source)
+ {
+ RefPtr<ShaderInputLayout::AggVal> rootVal = new ShaderInputLayout::AggVal;
+ parentVal = rootVal;
+
+ auto lines = Split(source, '\n');
+ for (auto & line : lines)
+ {
+ if (line.startsWith("//TEST_INPUT:"))
{
- StringBuilder msg;
- msg << "Invalid input syntax at line " << parser.NextToken().Position.Line;
- throw TextFormatException(msg);
+ auto lineContent = line.subString(13, line.getLength() - 13);
+ TokenReader parser(lineContent);
+ try
+ {
+ parseLine(parser);
+ }
+ catch (const TextFormatException&)
+ {
+ StringBuilder msg;
+ msg << "Invalid input syntax at line " << parser.NextToken().Position.Line;
+ throw ShaderInputLayoutFormatException(msg);
+ }
}
}
+
+ // TODO: check that stack has been maintained correctly...
+
+ return rootVal;
}
+ };
+
+ void ShaderInputLayout::parse(RandomGenerator* rand, const char * source)
+ {
+ rootVal = nullptr;
+ globalSpecializationArgs.clear();
+ entryPointSpecializationArgs.clear();
+
+ ShaderInputLayoutParser parser(this, rand);
+ rootVal = parser.parse(source);
}
- /* static */SlangResult ShaderInputLayout::writeBinding(const ShaderInputLayoutEntry& entry, slang::TypeLayoutReflection* typeLayout, const void* data, size_t sizeInBytes, WriterHelper writer)
+ /* static */SlangResult ShaderInputLayout::writeBinding(slang::TypeLayoutReflection* typeLayout, const void* data, size_t sizeInBytes, WriterHelper writer)
{
typedef slang::TypeReflection::ScalarType ScalarType;