// Copyright 2018 The Amber Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "src/vkscript/section_parser.h" #include #include #include #include #include "src/make_unique.h" #include "src/shader_data.h" namespace amber { namespace vkscript { // static bool SectionParser::HasShader(const NodeType type) { return type == NodeType::kShader; } SectionParser::SectionParser() = default; SectionParser::~SectionParser() = default; Result SectionParser::Parse(const std::string& data) { Result result = SplitSections(data); if (!result.IsSuccess()) return result; return {}; } Result SectionParser::NameToNodeType(const std::string& data, NodeType* section_type, ShaderType* shader_type, ShaderFormat* fmt) const { assert(section_type); assert(shader_type); assert(fmt); *fmt = kShaderFormatText; std::string name; size_t pos = data.rfind(" spirv hex"); if (pos != std::string::npos) { *fmt = kShaderFormatSpirvHex; name = data.substr(0, pos); } else { pos = data.rfind(" spirv"); if (pos != std::string::npos) { *fmt = kShaderFormatSpirvAsm; name = data.substr(0, pos); } else { name = data; } } pos = data.rfind(" passthrough"); if (pos != std::string::npos) { *fmt = kShaderFormatDefault; name = data.substr(0, pos); } if (name == "comment") { *section_type = NodeType::kComment; } else if (name == "indices") { *section_type = NodeType::kIndices; } else if (name == "require") { *section_type = NodeType::kRequire; } else if (name == "test") { *section_type = NodeType::kTest; } else if (name == "vertex data") { *section_type = NodeType::kVertexData; } else if (name == "compute shader") { *section_type = NodeType::kShader; *shader_type = kShaderTypeCompute; if (*fmt == kShaderFormatText) *fmt = kShaderFormatGlsl; } else if (name == "fragment shader") { *section_type = NodeType::kShader; *shader_type = kShaderTypeFragment; if (*fmt == kShaderFormatText) *fmt = kShaderFormatGlsl; } else if (name == "geometry shader") { *section_type = NodeType::kShader; *shader_type = kShaderTypeGeometry; if (*fmt == kShaderFormatText) *fmt = kShaderFormatGlsl; } else if (name == "tessellation control shader") { *section_type = NodeType::kShader; *shader_type = kShaderTypeTessellationControl; if (*fmt == kShaderFormatText) *fmt = kShaderFormatGlsl; } else if (name == "tessellation evaluation shader") { *section_type = NodeType::kShader; *shader_type = kShaderTypeTessellationEvaluation; if (*fmt == kShaderFormatText) *fmt = kShaderFormatGlsl; } else if (name == "vertex shader") { *section_type = NodeType::kShader; *shader_type = kShaderTypeVertex; if (*fmt == kShaderFormatText) *fmt = kShaderFormatGlsl; } else { return Result("Invalid name: " + data); } if (!SectionParser::HasShader(*section_type) && (*fmt == kShaderFormatGlsl || *fmt == kShaderFormatSpirvAsm || *fmt == kShaderFormatSpirvHex)) { return Result("Invalid source format: " + data); } return {}; } void SectionParser::AddSection(NodeType section_type, ShaderType shader_type, ShaderFormat fmt, size_t line_count, const std::string& contents) { if (section_type == NodeType::kComment) return; if (fmt == kShaderFormatDefault) { sections_.push_back({section_type, shader_type, kShaderFormatSpirvAsm, line_count, kPassThroughShader}); return; } size_t size = contents.size(); while (size > 0) { if (contents[size - 1] == '\n' || contents[size - 1] == '\r') { --size; continue; } break; } sections_.push_back( {section_type, shader_type, fmt, line_count, contents.substr(0, size)}); } Result SectionParser::SplitSections(const std::string& data) { std::stringstream ss(data); size_t line_count = 0; size_t section_start = 0; bool in_section = false; NodeType current_type = NodeType::kComment; ShaderType current_shader = kShaderTypeVertex; ShaderFormat current_fmt = kShaderFormatText; std::string section_contents; for (std::string line; std::getline(ss, line);) { ++line_count; if (!in_section) { if (line.empty() || line[0] == '#' || line == "\r") continue; if (line[0] != '[') return Result(std::to_string(line_count) + ": Invalid character"); section_start = line_count; in_section = true; } if (line.empty()) { section_contents += "\n"; continue; } if (line[0] == '[') { AddSection(current_type, current_shader, current_fmt, section_start, section_contents); section_start = line_count; section_contents = ""; size_t name_end = line.rfind("]"); if (name_end == std::string::npos) return Result(std::to_string(line_count) + ": Missing section close"); std::string name = line.substr(1, name_end - 1); Result r = NameToNodeType(name, ¤t_type, ¤t_shader, ¤t_fmt); if (!r.IsSuccess()) return Result(std::to_string(line_count) + ": " + r.Error()); } else { section_contents += line + "\n"; } } AddSection(current_type, current_shader, current_fmt, section_start, section_contents); return {}; } } // namespace vkscript } // namespace amber