1 // Copyright 2018 The Amber Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/vkscript/section_parser.h"
16
17 #include <cassert>
18 #include <iostream>
19 #include <sstream>
20 #include <string>
21
22 #include "src/make_unique.h"
23 #include "src/shader_data.h"
24
25 namespace amber {
26 namespace vkscript {
27
28 // static
HasShader(const NodeType type)29 bool SectionParser::HasShader(const NodeType type) {
30 return type == NodeType::kShader;
31 }
32
33 SectionParser::SectionParser() = default;
34
35 SectionParser::~SectionParser() = default;
36
Parse(const std::string & data)37 Result SectionParser::Parse(const std::string& data) {
38 Result result = SplitSections(data);
39 if (!result.IsSuccess())
40 return result;
41 return {};
42 }
43
NameToNodeType(const std::string & data,NodeType * section_type,ShaderType * shader_type,ShaderFormat * fmt) const44 Result SectionParser::NameToNodeType(const std::string& data,
45 NodeType* section_type,
46 ShaderType* shader_type,
47 ShaderFormat* fmt) const {
48 assert(section_type);
49 assert(shader_type);
50 assert(fmt);
51
52 *fmt = kShaderFormatText;
53
54 std::string name;
55 size_t pos = data.rfind(" spirv hex");
56 if (pos != std::string::npos) {
57 *fmt = kShaderFormatSpirvHex;
58 name = data.substr(0, pos);
59 } else {
60 pos = data.rfind(" spirv");
61 if (pos != std::string::npos) {
62 *fmt = kShaderFormatSpirvAsm;
63 name = data.substr(0, pos);
64 } else {
65 name = data;
66 }
67 }
68
69 pos = data.rfind(" passthrough");
70 if (pos != std::string::npos) {
71 *fmt = kShaderFormatDefault;
72 name = data.substr(0, pos);
73 }
74
75 if (name == "comment") {
76 *section_type = NodeType::kComment;
77 } else if (name == "indices") {
78 *section_type = NodeType::kIndices;
79 } else if (name == "require") {
80 *section_type = NodeType::kRequire;
81 } else if (name == "test") {
82 *section_type = NodeType::kTest;
83 } else if (name == "vertex data") {
84 *section_type = NodeType::kVertexData;
85 } else if (name == "compute shader") {
86 *section_type = NodeType::kShader;
87 *shader_type = kShaderTypeCompute;
88 if (*fmt == kShaderFormatText)
89 *fmt = kShaderFormatGlsl;
90 } else if (name == "fragment shader") {
91 *section_type = NodeType::kShader;
92 *shader_type = kShaderTypeFragment;
93 if (*fmt == kShaderFormatText)
94 *fmt = kShaderFormatGlsl;
95 } else if (name == "geometry shader") {
96 *section_type = NodeType::kShader;
97 *shader_type = kShaderTypeGeometry;
98 if (*fmt == kShaderFormatText)
99 *fmt = kShaderFormatGlsl;
100 } else if (name == "tessellation control shader") {
101 *section_type = NodeType::kShader;
102 *shader_type = kShaderTypeTessellationControl;
103 if (*fmt == kShaderFormatText)
104 *fmt = kShaderFormatGlsl;
105 } else if (name == "tessellation evaluation shader") {
106 *section_type = NodeType::kShader;
107 *shader_type = kShaderTypeTessellationEvaluation;
108 if (*fmt == kShaderFormatText)
109 *fmt = kShaderFormatGlsl;
110 } else if (name == "vertex shader") {
111 *section_type = NodeType::kShader;
112 *shader_type = kShaderTypeVertex;
113 if (*fmt == kShaderFormatText)
114 *fmt = kShaderFormatGlsl;
115 } else {
116 return Result("Invalid name: " + data);
117 }
118
119 if (!SectionParser::HasShader(*section_type) &&
120 (*fmt == kShaderFormatGlsl || *fmt == kShaderFormatSpirvAsm ||
121 *fmt == kShaderFormatSpirvHex)) {
122 return Result("Invalid source format: " + data);
123 }
124
125 return {};
126 }
127
AddSection(NodeType section_type,ShaderType shader_type,ShaderFormat fmt,size_t line_count,const std::string & contents)128 void SectionParser::AddSection(NodeType section_type,
129 ShaderType shader_type,
130 ShaderFormat fmt,
131 size_t line_count,
132 const std::string& contents) {
133 if (section_type == NodeType::kComment)
134 return;
135
136 if (fmt == kShaderFormatDefault) {
137 sections_.push_back({section_type, shader_type, kShaderFormatSpirvAsm,
138 line_count, kPassThroughShader});
139 return;
140 }
141
142 size_t size = contents.size();
143 while (size > 0) {
144 if (contents[size - 1] == '\n' || contents[size - 1] == '\r') {
145 --size;
146 continue;
147 }
148 break;
149 }
150
151 sections_.push_back(
152 {section_type, shader_type, fmt, line_count, contents.substr(0, size)});
153 }
154
SplitSections(const std::string & data)155 Result SectionParser::SplitSections(const std::string& data) {
156 std::stringstream ss(data);
157 size_t line_count = 0;
158 size_t section_start = 0;
159 bool in_section = false;
160
161 NodeType current_type = NodeType::kComment;
162 ShaderType current_shader = kShaderTypeVertex;
163 ShaderFormat current_fmt = kShaderFormatText;
164 std::string section_contents;
165
166 for (std::string line; std::getline(ss, line);) {
167 ++line_count;
168
169 if (!in_section) {
170 if (line.empty() || line[0] == '#' || line == "\r")
171 continue;
172
173 if (line[0] != '[')
174 return Result(std::to_string(line_count) + ": Invalid character");
175
176 section_start = line_count;
177 in_section = true;
178 }
179
180 if (line.empty()) {
181 section_contents += "\n";
182 continue;
183 }
184
185 if (line[0] == '[') {
186 AddSection(current_type, current_shader, current_fmt, section_start,
187 section_contents);
188 section_start = line_count;
189 section_contents = "";
190
191 size_t name_end = line.rfind("]");
192 if (name_end == std::string::npos)
193 return Result(std::to_string(line_count) + ": Missing section close");
194
195 std::string name = line.substr(1, name_end - 1);
196
197 Result r =
198 NameToNodeType(name, ¤t_type, ¤t_shader, ¤t_fmt);
199 if (!r.IsSuccess())
200 return Result(std::to_string(line_count) + ": " + r.Error());
201 } else {
202 section_contents += line + "\n";
203 }
204 }
205 AddSection(current_type, current_shader, current_fmt, section_start,
206 section_contents);
207
208 return {};
209 }
210
211 } // namespace vkscript
212 } // namespace amber
213