diff options
Diffstat (limited to 'tools/render-test/shader-input-layout.cpp')
| -rw-r--r-- | tools/render-test/shader-input-layout.cpp | 1111 |
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; |
