/src/shaderc/glslc/src/file_compiler.cc
Line | Count | Source |
1 | | // Copyright 2015 The Shaderc Authors. All rights reserved. |
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 "file_compiler.h" |
16 | | |
17 | | #include <cassert> |
18 | | #include <fstream> |
19 | | #include <iomanip> |
20 | | #include <iostream> |
21 | | #include <sstream> |
22 | | |
23 | | #if SHADERC_ENABLE_WGSL_OUTPUT == 1 |
24 | | #include "tint/tint.h" |
25 | | #endif // SHADERC_ENABLE_WGSL_OUTPUT==1 |
26 | | |
27 | | #include "file.h" |
28 | | #include "file_includer.h" |
29 | | #include "shader_stage.h" |
30 | | |
31 | | #include "libshaderc_util/io_shaderc.h" |
32 | | #include "libshaderc_util/message.h" |
33 | | |
34 | | namespace { |
35 | | using shaderc_util::string_piece; |
36 | | |
37 | | // A helper function to emit SPIR-V binary code as a list of hex numbers in |
38 | | // text form. Returns true if a non-empty compilation result is emitted |
39 | | // successfully. Return false if nothing should be emitted, either because the |
40 | | // compilation result is empty, or the compilation output is not SPIR-V binary |
41 | | // code. |
42 | | template <typename CompilationResultType> |
43 | | bool EmitSpirvBinaryAsCommaSeparatedNumbers(const CompilationResultType& result, |
44 | 0 | std::ostream* out) { |
45 | | // Return early if the compilation output is not in SPIR-V binary code form. |
46 | 0 | if (!std::is_same<CompilationResultType, |
47 | 0 | shaderc::SpvCompilationResult>::value) |
48 | 0 | return false; |
49 | | // Return early if the compilation result is empty. |
50 | 0 | if (result.cbegin() == result.cend()) return false; |
51 | 0 | std::ios::fmtflags output_stream_flag_cache(out->flags()); |
52 | 0 | *out << std::hex << std::setfill('0'); |
53 | 0 | auto RI = result.cbegin(); |
54 | 0 | *out << "0x" << std::setw(8) << *RI++; |
55 | 0 | for (size_t counter = 1; RI != result.cend(); RI++, counter++) { |
56 | 0 | *out << ","; |
57 | | // Break line for every four words. |
58 | 0 | if (counter % 4 == 0) { |
59 | 0 | *out << std::endl; |
60 | 0 | } |
61 | 0 | *out << "0x" << std::setw(8) << *RI; |
62 | 0 | } |
63 | 0 | out->flags(output_stream_flag_cache); |
64 | 0 | return true; |
65 | 0 | } Unexecuted instantiation: file_compiler.cc:bool (anonymous namespace)::EmitSpirvBinaryAsCommaSeparatedNumbers<shaderc::CompilationResult<unsigned int> >(shaderc::CompilationResult<unsigned int> const&, std::__1::basic_ostream<char, std::__1::char_traits<char> >*) Unexecuted instantiation: file_compiler.cc:bool (anonymous namespace)::EmitSpirvBinaryAsCommaSeparatedNumbers<shaderc::CompilationResult<char> >(shaderc::CompilationResult<char> const&, std::__1::basic_ostream<char, std::__1::char_traits<char> >*) |
66 | | } // anonymous namespace |
67 | | |
68 | | namespace glslc { |
69 | 2.28k | bool FileCompiler::CompileShaderFile(const InputFileSpec& input_file) { |
70 | 2.28k | std::vector<char> input_data; |
71 | 2.28k | std::string path = input_file.name; |
72 | 2.28k | if (!shaderc_util::ReadFile(path, &input_data)) { |
73 | 0 | return false; |
74 | 0 | } |
75 | | |
76 | 2.28k | std::string output_file_name = GetOutputFileName(input_file.name); |
77 | 2.28k | string_piece error_file_name = input_file.name; |
78 | | |
79 | 2.28k | if (error_file_name == "-") { |
80 | | // If the input file was stdin, we want to output errors as <stdin>. |
81 | 0 | error_file_name = "<stdin>"; |
82 | 0 | } |
83 | | |
84 | 2.28k | string_piece source_string = ""; |
85 | 2.28k | if (!input_data.empty()) { |
86 | 2.28k | source_string = {&input_data.front(), |
87 | 2.28k | &input_data.front() + input_data.size()}; |
88 | 2.28k | } |
89 | | |
90 | 2.28k | std::unique_ptr<FileIncluder> includer( |
91 | 2.28k | new FileIncluder(&include_file_finder_)); |
92 | | // Get a reference to the dependency trace before we pass the ownership to |
93 | | // shaderc::CompileOptions. |
94 | 2.28k | const auto& used_source_files = includer->file_path_trace(); |
95 | 2.28k | options_.SetIncluder(std::move(includer)); |
96 | | |
97 | 2.28k | if (input_file.stage == shaderc_spirv_assembly) { |
98 | | // Only act if the requested target is SPIR-V binary. |
99 | 0 | if (output_type_ == OutputType::SpirvBinary) { |
100 | 0 | const auto result = |
101 | 0 | compiler_.AssembleToSpv(source_string.data(), source_string.size()); |
102 | 0 | return EmitCompiledResult(result, input_file.name, output_file_name, |
103 | 0 | error_file_name, used_source_files); |
104 | 0 | } else { |
105 | 0 | return true; |
106 | 0 | } |
107 | 0 | } |
108 | | |
109 | | // Set the language. Since we only use the options object in this |
110 | | // method, then it's ok to always set it without resetting it after |
111 | | // compilation. A subsequent compilation will set it again anyway. |
112 | 2.28k | options_.SetSourceLanguage(input_file.language); |
113 | | |
114 | 2.28k | switch (output_type_) { |
115 | 760 | case OutputType::SpirvBinary: { |
116 | 760 | const auto result = compiler_.CompileGlslToSpv( |
117 | 760 | source_string.data(), source_string.size(), input_file.stage, |
118 | 760 | error_file_name.data(), input_file.entry_point_name.c_str(), |
119 | 760 | options_); |
120 | 760 | return EmitCompiledResult(result, input_file.name, output_file_name, |
121 | 760 | error_file_name, used_source_files); |
122 | 0 | } |
123 | 0 | case OutputType::SpirvAssemblyText: { |
124 | 0 | const auto result = compiler_.CompileGlslToSpvAssembly( |
125 | 0 | source_string.data(), source_string.size(), input_file.stage, |
126 | 0 | error_file_name.data(), input_file.entry_point_name.c_str(), |
127 | 0 | options_); |
128 | 0 | return EmitCompiledResult(result, input_file.name, output_file_name, |
129 | 0 | error_file_name, used_source_files); |
130 | 0 | } |
131 | 1.52k | case OutputType::PreprocessedText: { |
132 | 1.52k | const auto result = compiler_.PreprocessGlsl( |
133 | 1.52k | source_string.data(), source_string.size(), input_file.stage, |
134 | 1.52k | error_file_name.data(), options_); |
135 | 1.52k | return EmitCompiledResult(result, input_file.name, output_file_name, |
136 | 1.52k | error_file_name, used_source_files); |
137 | 0 | } |
138 | 2.28k | } |
139 | 0 | return false; |
140 | 2.28k | } |
141 | | |
142 | | template <typename CompilationResultType> |
143 | | bool FileCompiler::EmitCompiledResult( |
144 | | const CompilationResultType& result, const std::string& input_file, |
145 | | const std::string& output_file_name, string_piece error_file_name, |
146 | 2.28k | const std::unordered_set<std::string>& used_source_files) { |
147 | 2.28k | total_errors_ += result.GetNumErrors(); |
148 | 2.28k | total_warnings_ += result.GetNumWarnings(); |
149 | | |
150 | 2.28k | bool compilation_success = |
151 | 2.28k | result.GetCompilationStatus() == shaderc_compilation_status_success; |
152 | | |
153 | | // Handle the error message for failing to deduce the shader kind. |
154 | 2.28k | if (result.GetCompilationStatus() == |
155 | 2.28k | shaderc_compilation_status_invalid_stage) { |
156 | 0 | auto glsl_or_hlsl_extension = GetGlslOrHlslExtension(error_file_name); |
157 | 0 | if (glsl_or_hlsl_extension != "") { |
158 | 0 | std::cerr << "glslc: error: " |
159 | 0 | << "'" << error_file_name << "': " |
160 | 0 | << "." << glsl_or_hlsl_extension |
161 | 0 | << " file encountered but no -fshader-stage specified ahead"; |
162 | 0 | } else if (error_file_name == "<stdin>") { |
163 | 0 | std::cerr |
164 | 0 | << "glslc: error: '-': -fshader-stage required when input is from " |
165 | 0 | "standard " |
166 | 0 | "input \"-\""; |
167 | 0 | } else { |
168 | 0 | std::cerr << "glslc: error: " |
169 | 0 | << "'" << error_file_name << "': " |
170 | 0 | << "file not recognized: File format not recognized"; |
171 | 0 | } |
172 | 0 | std::cerr << "\n"; |
173 | |
|
174 | 0 | return false; |
175 | 0 | } |
176 | | |
177 | | // Get a string_piece which refers to the normal compilation output for now. |
178 | | // This string_piece might be redirected to the dependency info to be dumped |
179 | | // later, if the handler is instantiated to dump as normal compilation output, |
180 | | // and the original compilation output should be blocked. Otherwise it won't |
181 | | // be touched. The main output stream dumps this string_piece later. |
182 | 2.28k | string_piece compilation_output( |
183 | 2.28k | reinterpret_cast<const char*>(result.cbegin()), |
184 | 2.28k | reinterpret_cast<const char*>(result.cend())); |
185 | | |
186 | | // If we have dependency info dumping handler instantiated, we should dump |
187 | | // dependency info first. This may redirect the compilation output |
188 | | // string_piece to dependency info. |
189 | 2.28k | std::string potential_dependency_info_output; |
190 | 2.28k | if (dependency_info_dumping_handler_) { |
191 | 0 | if (!dependency_info_dumping_handler_->DumpDependencyInfo( |
192 | 0 | GetCandidateOutputFileName(input_file), error_file_name.data(), |
193 | 0 | &potential_dependency_info_output, used_source_files)) { |
194 | 0 | return false; |
195 | 0 | } |
196 | 0 | if (!potential_dependency_info_output.empty()) { |
197 | | // If the potential_dependency_info_output string is not empty, it means |
198 | | // we should dump dependency info as normal compilation output. Redirect |
199 | | // the compilation output string_piece to the dependency info stored in |
200 | | // potential_dependency_info_output to make it happen. |
201 | 0 | compilation_output = potential_dependency_info_output; |
202 | 0 | } |
203 | 0 | } |
204 | | |
205 | 2.28k | std::ostream* out = nullptr; |
206 | 2.28k | std::ofstream potential_file_stream; |
207 | 2.28k | if (compilation_success) { |
208 | 491 | out = shaderc_util::GetOutputStream(output_file_name, |
209 | 491 | &potential_file_stream, &std::cerr); |
210 | 491 | if (!out || out->fail()) { |
211 | | // An error message has already been emitted to the stderr stream. |
212 | 0 | return false; |
213 | 0 | } |
214 | | |
215 | | // Write compilation output to output file. If an output format for SPIR-V |
216 | | // binary code is specified, it is handled here. |
217 | 491 | switch (binary_emission_format_) { |
218 | 0 | case SpirvBinaryEmissionFormat::Unspecified: |
219 | 0 | case SpirvBinaryEmissionFormat::Binary: |
220 | | // The output format is unspecified or specified as binary output. |
221 | | // On Windows, the output stream must be set to binary mode. By |
222 | | // default the standard output stream is set to text mode, which |
223 | | // translates newlines (\n) to carriage-return newline pairs |
224 | | // (\r\n). |
225 | 0 | if (out == &std::cout) shaderc_util::FlushAndSetBinaryModeOnStdout(); |
226 | 0 | out->write(compilation_output.data(), compilation_output.size()); |
227 | 0 | if (out == &std::cout) shaderc_util::FlushAndSetTextModeOnStdout(); |
228 | 0 | break; |
229 | 0 | case SpirvBinaryEmissionFormat::Numbers: |
230 | | // The output format is specified to be a list of hex numbers, the |
231 | | // compilation output must be in SPIR-V binary code form. |
232 | 0 | assert(output_type_ == OutputType::SpirvBinary); |
233 | 0 | if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) { |
234 | | // Only emits the end-of-line character when the emitted compilation |
235 | | // result is not empty. |
236 | 0 | *out << std::endl; |
237 | 0 | } |
238 | 0 | break; |
239 | 0 | case SpirvBinaryEmissionFormat::CInitList: |
240 | | // The output format is specified to be a C-style initializer list, the |
241 | | // compilation output must be in SPIR-V binary code form. |
242 | 0 | assert(output_type_ == OutputType::SpirvBinary); |
243 | 0 | if (result.begin() != result.end()) { |
244 | | // Only emits the '{' when the compilation result is not empty. |
245 | 0 | *out << "{"; |
246 | 0 | } |
247 | 0 | if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) { |
248 | | // Only emits the end-of-line character when the emitted compilation |
249 | | // result is not empty. |
250 | 0 | *out << "}" << std::endl; |
251 | 0 | } |
252 | 0 | break; |
253 | 491 | case SpirvBinaryEmissionFormat::WGSL: { |
254 | | #if SHADERC_ENABLE_WGSL_OUTPUT == 1 |
255 | | tint::Context ctx; |
256 | | tint::reader::spirv::Parser spv_reader( |
257 | | &ctx, std::vector<uint32_t>(result.begin(), result.end())); |
258 | | if (!spv_reader.Parse()) { |
259 | | std::cout << "error: failed to convert SPIR-V binary to WGSL: " |
260 | | << spv_reader.error() << std::endl; |
261 | | return false; |
262 | | } |
263 | | tint::writer::wgsl::Generator wgsl_writer(spv_reader.module()); |
264 | | if (!wgsl_writer.Generate()) { |
265 | | std::cout << "error: failed to convert to WGSL: " |
266 | | << wgsl_writer.error() << std::endl; |
267 | | return false; |
268 | | } |
269 | | *out << wgsl_writer.result(); |
270 | | #endif // SHADERC_ENABLE_WGSL_OUTPUT==1 |
271 | 491 | break; |
272 | 0 | } |
273 | 491 | } |
274 | 491 | } |
275 | | |
276 | | // Write error message to std::cerr. |
277 | 2.28k | std::cerr << result.GetErrorMessage(); |
278 | 2.28k | if (out && out->fail()) { |
279 | | // Something wrong happened on output. |
280 | 0 | if (out == &std::cout) { |
281 | 0 | std::cerr << "glslc: error: error writing to standard output" |
282 | 0 | << std::endl; |
283 | 0 | } else { |
284 | 0 | std::cerr << "glslc: error: error writing to output file: '" |
285 | 0 | << output_file_name_ << "'" << std::endl; |
286 | 0 | } |
287 | 0 | return false; |
288 | 0 | } |
289 | | |
290 | 2.28k | return compilation_success; |
291 | 2.28k | } bool glslc::FileCompiler::EmitCompiledResult<shaderc::CompilationResult<unsigned int> >(shaderc::CompilationResult<unsigned int> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, shaderc_util::string_piece, std::__1::unordered_set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&) Line | Count | Source | 146 | 760 | const std::unordered_set<std::string>& used_source_files) { | 147 | 760 | total_errors_ += result.GetNumErrors(); | 148 | 760 | total_warnings_ += result.GetNumWarnings(); | 149 | | | 150 | 760 | bool compilation_success = | 151 | 760 | result.GetCompilationStatus() == shaderc_compilation_status_success; | 152 | | | 153 | | // Handle the error message for failing to deduce the shader kind. | 154 | 760 | if (result.GetCompilationStatus() == | 155 | 760 | shaderc_compilation_status_invalid_stage) { | 156 | 0 | auto glsl_or_hlsl_extension = GetGlslOrHlslExtension(error_file_name); | 157 | 0 | if (glsl_or_hlsl_extension != "") { | 158 | 0 | std::cerr << "glslc: error: " | 159 | 0 | << "'" << error_file_name << "': " | 160 | 0 | << "." << glsl_or_hlsl_extension | 161 | 0 | << " file encountered but no -fshader-stage specified ahead"; | 162 | 0 | } else if (error_file_name == "<stdin>") { | 163 | 0 | std::cerr | 164 | 0 | << "glslc: error: '-': -fshader-stage required when input is from " | 165 | 0 | "standard " | 166 | 0 | "input \"-\""; | 167 | 0 | } else { | 168 | 0 | std::cerr << "glslc: error: " | 169 | 0 | << "'" << error_file_name << "': " | 170 | 0 | << "file not recognized: File format not recognized"; | 171 | 0 | } | 172 | 0 | std::cerr << "\n"; | 173 | |
| 174 | 0 | return false; | 175 | 0 | } | 176 | | | 177 | | // Get a string_piece which refers to the normal compilation output for now. | 178 | | // This string_piece might be redirected to the dependency info to be dumped | 179 | | // later, if the handler is instantiated to dump as normal compilation output, | 180 | | // and the original compilation output should be blocked. Otherwise it won't | 181 | | // be touched. The main output stream dumps this string_piece later. | 182 | 760 | string_piece compilation_output( | 183 | 760 | reinterpret_cast<const char*>(result.cbegin()), | 184 | 760 | reinterpret_cast<const char*>(result.cend())); | 185 | | | 186 | | // If we have dependency info dumping handler instantiated, we should dump | 187 | | // dependency info first. This may redirect the compilation output | 188 | | // string_piece to dependency info. | 189 | 760 | std::string potential_dependency_info_output; | 190 | 760 | if (dependency_info_dumping_handler_) { | 191 | 0 | if (!dependency_info_dumping_handler_->DumpDependencyInfo( | 192 | 0 | GetCandidateOutputFileName(input_file), error_file_name.data(), | 193 | 0 | &potential_dependency_info_output, used_source_files)) { | 194 | 0 | return false; | 195 | 0 | } | 196 | 0 | if (!potential_dependency_info_output.empty()) { | 197 | | // If the potential_dependency_info_output string is not empty, it means | 198 | | // we should dump dependency info as normal compilation output. Redirect | 199 | | // the compilation output string_piece to the dependency info stored in | 200 | | // potential_dependency_info_output to make it happen. | 201 | 0 | compilation_output = potential_dependency_info_output; | 202 | 0 | } | 203 | 0 | } | 204 | | | 205 | 760 | std::ostream* out = nullptr; | 206 | 760 | std::ofstream potential_file_stream; | 207 | 760 | if (compilation_success) { | 208 | 31 | out = shaderc_util::GetOutputStream(output_file_name, | 209 | 31 | &potential_file_stream, &std::cerr); | 210 | 31 | if (!out || out->fail()) { | 211 | | // An error message has already been emitted to the stderr stream. | 212 | 0 | return false; | 213 | 0 | } | 214 | | | 215 | | // Write compilation output to output file. If an output format for SPIR-V | 216 | | // binary code is specified, it is handled here. | 217 | 31 | switch (binary_emission_format_) { | 218 | 0 | case SpirvBinaryEmissionFormat::Unspecified: | 219 | 0 | case SpirvBinaryEmissionFormat::Binary: | 220 | | // The output format is unspecified or specified as binary output. | 221 | | // On Windows, the output stream must be set to binary mode. By | 222 | | // default the standard output stream is set to text mode, which | 223 | | // translates newlines (\n) to carriage-return newline pairs | 224 | | // (\r\n). | 225 | 0 | if (out == &std::cout) shaderc_util::FlushAndSetBinaryModeOnStdout(); | 226 | 0 | out->write(compilation_output.data(), compilation_output.size()); | 227 | 0 | if (out == &std::cout) shaderc_util::FlushAndSetTextModeOnStdout(); | 228 | 0 | break; | 229 | 0 | case SpirvBinaryEmissionFormat::Numbers: | 230 | | // The output format is specified to be a list of hex numbers, the | 231 | | // compilation output must be in SPIR-V binary code form. | 232 | 0 | assert(output_type_ == OutputType::SpirvBinary); | 233 | 0 | if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) { | 234 | | // Only emits the end-of-line character when the emitted compilation | 235 | | // result is not empty. | 236 | 0 | *out << std::endl; | 237 | 0 | } | 238 | 0 | break; | 239 | 0 | case SpirvBinaryEmissionFormat::CInitList: | 240 | | // The output format is specified to be a C-style initializer list, the | 241 | | // compilation output must be in SPIR-V binary code form. | 242 | 0 | assert(output_type_ == OutputType::SpirvBinary); | 243 | 0 | if (result.begin() != result.end()) { | 244 | | // Only emits the '{' when the compilation result is not empty. | 245 | 0 | *out << "{"; | 246 | 0 | } | 247 | 0 | if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) { | 248 | | // Only emits the end-of-line character when the emitted compilation | 249 | | // result is not empty. | 250 | 0 | *out << "}" << std::endl; | 251 | 0 | } | 252 | 0 | break; | 253 | 31 | case SpirvBinaryEmissionFormat::WGSL: { | 254 | | #if SHADERC_ENABLE_WGSL_OUTPUT == 1 | 255 | | tint::Context ctx; | 256 | | tint::reader::spirv::Parser spv_reader( | 257 | | &ctx, std::vector<uint32_t>(result.begin(), result.end())); | 258 | | if (!spv_reader.Parse()) { | 259 | | std::cout << "error: failed to convert SPIR-V binary to WGSL: " | 260 | | << spv_reader.error() << std::endl; | 261 | | return false; | 262 | | } | 263 | | tint::writer::wgsl::Generator wgsl_writer(spv_reader.module()); | 264 | | if (!wgsl_writer.Generate()) { | 265 | | std::cout << "error: failed to convert to WGSL: " | 266 | | << wgsl_writer.error() << std::endl; | 267 | | return false; | 268 | | } | 269 | | *out << wgsl_writer.result(); | 270 | | #endif // SHADERC_ENABLE_WGSL_OUTPUT==1 | 271 | 31 | break; | 272 | 0 | } | 273 | 31 | } | 274 | 31 | } | 275 | | | 276 | | // Write error message to std::cerr. | 277 | 760 | std::cerr << result.GetErrorMessage(); | 278 | 760 | if (out && out->fail()) { | 279 | | // Something wrong happened on output. | 280 | 0 | if (out == &std::cout) { | 281 | 0 | std::cerr << "glslc: error: error writing to standard output" | 282 | 0 | << std::endl; | 283 | 0 | } else { | 284 | 0 | std::cerr << "glslc: error: error writing to output file: '" | 285 | 0 | << output_file_name_ << "'" << std::endl; | 286 | 0 | } | 287 | 0 | return false; | 288 | 0 | } | 289 | | | 290 | 760 | return compilation_success; | 291 | 760 | } |
bool glslc::FileCompiler::EmitCompiledResult<shaderc::CompilationResult<char> >(shaderc::CompilationResult<char> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, shaderc_util::string_piece, std::__1::unordered_set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&) Line | Count | Source | 146 | 1.52k | const std::unordered_set<std::string>& used_source_files) { | 147 | 1.52k | total_errors_ += result.GetNumErrors(); | 148 | 1.52k | total_warnings_ += result.GetNumWarnings(); | 149 | | | 150 | 1.52k | bool compilation_success = | 151 | 1.52k | result.GetCompilationStatus() == shaderc_compilation_status_success; | 152 | | | 153 | | // Handle the error message for failing to deduce the shader kind. | 154 | 1.52k | if (result.GetCompilationStatus() == | 155 | 1.52k | shaderc_compilation_status_invalid_stage) { | 156 | 0 | auto glsl_or_hlsl_extension = GetGlslOrHlslExtension(error_file_name); | 157 | 0 | if (glsl_or_hlsl_extension != "") { | 158 | 0 | std::cerr << "glslc: error: " | 159 | 0 | << "'" << error_file_name << "': " | 160 | 0 | << "." << glsl_or_hlsl_extension | 161 | 0 | << " file encountered but no -fshader-stage specified ahead"; | 162 | 0 | } else if (error_file_name == "<stdin>") { | 163 | 0 | std::cerr | 164 | 0 | << "glslc: error: '-': -fshader-stage required when input is from " | 165 | 0 | "standard " | 166 | 0 | "input \"-\""; | 167 | 0 | } else { | 168 | 0 | std::cerr << "glslc: error: " | 169 | 0 | << "'" << error_file_name << "': " | 170 | 0 | << "file not recognized: File format not recognized"; | 171 | 0 | } | 172 | 0 | std::cerr << "\n"; | 173 | |
| 174 | 0 | return false; | 175 | 0 | } | 176 | | | 177 | | // Get a string_piece which refers to the normal compilation output for now. | 178 | | // This string_piece might be redirected to the dependency info to be dumped | 179 | | // later, if the handler is instantiated to dump as normal compilation output, | 180 | | // and the original compilation output should be blocked. Otherwise it won't | 181 | | // be touched. The main output stream dumps this string_piece later. | 182 | 1.52k | string_piece compilation_output( | 183 | 1.52k | reinterpret_cast<const char*>(result.cbegin()), | 184 | 1.52k | reinterpret_cast<const char*>(result.cend())); | 185 | | | 186 | | // If we have dependency info dumping handler instantiated, we should dump | 187 | | // dependency info first. This may redirect the compilation output | 188 | | // string_piece to dependency info. | 189 | 1.52k | std::string potential_dependency_info_output; | 190 | 1.52k | if (dependency_info_dumping_handler_) { | 191 | 0 | if (!dependency_info_dumping_handler_->DumpDependencyInfo( | 192 | 0 | GetCandidateOutputFileName(input_file), error_file_name.data(), | 193 | 0 | &potential_dependency_info_output, used_source_files)) { | 194 | 0 | return false; | 195 | 0 | } | 196 | 0 | if (!potential_dependency_info_output.empty()) { | 197 | | // If the potential_dependency_info_output string is not empty, it means | 198 | | // we should dump dependency info as normal compilation output. Redirect | 199 | | // the compilation output string_piece to the dependency info stored in | 200 | | // potential_dependency_info_output to make it happen. | 201 | 0 | compilation_output = potential_dependency_info_output; | 202 | 0 | } | 203 | 0 | } | 204 | | | 205 | 1.52k | std::ostream* out = nullptr; | 206 | 1.52k | std::ofstream potential_file_stream; | 207 | 1.52k | if (compilation_success) { | 208 | 460 | out = shaderc_util::GetOutputStream(output_file_name, | 209 | 460 | &potential_file_stream, &std::cerr); | 210 | 460 | if (!out || out->fail()) { | 211 | | // An error message has already been emitted to the stderr stream. | 212 | 0 | return false; | 213 | 0 | } | 214 | | | 215 | | // Write compilation output to output file. If an output format for SPIR-V | 216 | | // binary code is specified, it is handled here. | 217 | 460 | switch (binary_emission_format_) { | 218 | 0 | case SpirvBinaryEmissionFormat::Unspecified: | 219 | 0 | case SpirvBinaryEmissionFormat::Binary: | 220 | | // The output format is unspecified or specified as binary output. | 221 | | // On Windows, the output stream must be set to binary mode. By | 222 | | // default the standard output stream is set to text mode, which | 223 | | // translates newlines (\n) to carriage-return newline pairs | 224 | | // (\r\n). | 225 | 0 | if (out == &std::cout) shaderc_util::FlushAndSetBinaryModeOnStdout(); | 226 | 0 | out->write(compilation_output.data(), compilation_output.size()); | 227 | 0 | if (out == &std::cout) shaderc_util::FlushAndSetTextModeOnStdout(); | 228 | 0 | break; | 229 | 0 | case SpirvBinaryEmissionFormat::Numbers: | 230 | | // The output format is specified to be a list of hex numbers, the | 231 | | // compilation output must be in SPIR-V binary code form. | 232 | 0 | assert(output_type_ == OutputType::SpirvBinary); | 233 | 0 | if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) { | 234 | | // Only emits the end-of-line character when the emitted compilation | 235 | | // result is not empty. | 236 | 0 | *out << std::endl; | 237 | 0 | } | 238 | 0 | break; | 239 | 0 | case SpirvBinaryEmissionFormat::CInitList: | 240 | | // The output format is specified to be a C-style initializer list, the | 241 | | // compilation output must be in SPIR-V binary code form. | 242 | 0 | assert(output_type_ == OutputType::SpirvBinary); | 243 | 0 | if (result.begin() != result.end()) { | 244 | | // Only emits the '{' when the compilation result is not empty. | 245 | 0 | *out << "{"; | 246 | 0 | } | 247 | 0 | if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) { | 248 | | // Only emits the end-of-line character when the emitted compilation | 249 | | // result is not empty. | 250 | 0 | *out << "}" << std::endl; | 251 | 0 | } | 252 | 0 | break; | 253 | 460 | case SpirvBinaryEmissionFormat::WGSL: { | 254 | | #if SHADERC_ENABLE_WGSL_OUTPUT == 1 | 255 | | tint::Context ctx; | 256 | | tint::reader::spirv::Parser spv_reader( | 257 | | &ctx, std::vector<uint32_t>(result.begin(), result.end())); | 258 | | if (!spv_reader.Parse()) { | 259 | | std::cout << "error: failed to convert SPIR-V binary to WGSL: " | 260 | | << spv_reader.error() << std::endl; | 261 | | return false; | 262 | | } | 263 | | tint::writer::wgsl::Generator wgsl_writer(spv_reader.module()); | 264 | | if (!wgsl_writer.Generate()) { | 265 | | std::cout << "error: failed to convert to WGSL: " | 266 | | << wgsl_writer.error() << std::endl; | 267 | | return false; | 268 | | } | 269 | | *out << wgsl_writer.result(); | 270 | | #endif // SHADERC_ENABLE_WGSL_OUTPUT==1 | 271 | 460 | break; | 272 | 0 | } | 273 | 460 | } | 274 | 460 | } | 275 | | | 276 | | // Write error message to std::cerr. | 277 | 1.52k | std::cerr << result.GetErrorMessage(); | 278 | 1.52k | if (out && out->fail()) { | 279 | | // Something wrong happened on output. | 280 | 0 | if (out == &std::cout) { | 281 | 0 | std::cerr << "glslc: error: error writing to standard output" | 282 | 0 | << std::endl; | 283 | 0 | } else { | 284 | 0 | std::cerr << "glslc: error: error writing to output file: '" | 285 | 0 | << output_file_name_ << "'" << std::endl; | 286 | 0 | } | 287 | 0 | return false; | 288 | 0 | } | 289 | | | 290 | 1.52k | return compilation_success; | 291 | 1.52k | } |
|
292 | | |
293 | 760 | void FileCompiler::AddIncludeDirectory(const std::string& path) { |
294 | 760 | include_file_finder_.search_path().push_back(path); |
295 | 760 | } |
296 | | |
297 | 0 | void FileCompiler::SetIndividualCompilationFlag() { |
298 | 0 | if (output_type_ != OutputType::SpirvAssemblyText) { |
299 | 0 | needs_linking_ = false; |
300 | 0 | file_extension_ = ".spv"; |
301 | 0 | } |
302 | 0 | } |
303 | | |
304 | 760 | void FileCompiler::SetDisassemblyFlag() { |
305 | 760 | if (!PreprocessingOnly()) { |
306 | 0 | output_type_ = OutputType::SpirvAssemblyText; |
307 | 0 | needs_linking_ = false; |
308 | 0 | file_extension_ = ".spvasm"; |
309 | 0 | } |
310 | 760 | } |
311 | | |
312 | 760 | void FileCompiler::SetPreprocessingOnlyFlag() { |
313 | 760 | output_type_ = OutputType::PreprocessedText; |
314 | 760 | needs_linking_ = false; |
315 | 760 | if (output_file_name_.empty()) { |
316 | 0 | output_file_name_ = "-"; |
317 | 0 | } |
318 | 760 | } |
319 | | |
320 | 760 | bool FileCompiler::ValidateOptions(size_t num_files) { |
321 | 760 | if (num_files == 0) { |
322 | 0 | std::cerr << "glslc: error: no input files" << std::endl; |
323 | 0 | return false; |
324 | 0 | } |
325 | | |
326 | 760 | if (num_files > 1 && needs_linking_) { |
327 | 0 | std::cerr << "glslc: error: linking multiple files is not supported yet. " |
328 | 0 | "Use -c to compile files individually." |
329 | 0 | << std::endl; |
330 | 0 | return false; |
331 | 0 | } |
332 | | |
333 | | // If we are outputting many object files, we cannot specify -o. Also |
334 | | // if we are preprocessing multiple files they must be to stdout. |
335 | 760 | if (num_files > 1 && ((!PreprocessingOnly() && !needs_linking_ && |
336 | 0 | !output_file_name_.empty()) || |
337 | 0 | (PreprocessingOnly() && output_file_name_ != "-"))) { |
338 | 0 | std::cerr << "glslc: error: cannot specify -o when generating multiple" |
339 | 0 | " output files" |
340 | 0 | << std::endl; |
341 | 0 | return false; |
342 | 0 | } |
343 | | |
344 | | // If we have dependency info dumping handler instantiated, we should check |
345 | | // its validity. |
346 | 760 | if (dependency_info_dumping_handler_) { |
347 | 0 | std::string dependency_info_dumping_hander_error_msg; |
348 | 0 | if (!dependency_info_dumping_handler_->IsValid( |
349 | 0 | &dependency_info_dumping_hander_error_msg, num_files)) { |
350 | 0 | std::cerr << "glslc: error: " << dependency_info_dumping_hander_error_msg |
351 | 0 | << std::endl; |
352 | 0 | return false; |
353 | 0 | } |
354 | 0 | } |
355 | | |
356 | | // If the output format is specified to be a binary, a list of hex numbers or |
357 | | // a C-style initializer list, the output must be in SPIR-V binary code form. |
358 | 760 | if (binary_emission_format_ != SpirvBinaryEmissionFormat::Unspecified) { |
359 | 760 | if (output_type_ != OutputType::SpirvBinary) { |
360 | 760 | std::cerr << "glslc: error: cannot emit output as a "; |
361 | 760 | switch (binary_emission_format_) { |
362 | 0 | case SpirvBinaryEmissionFormat::Binary: |
363 | 0 | std::cerr << "binary"; |
364 | 0 | break; |
365 | 0 | case SpirvBinaryEmissionFormat::Numbers: |
366 | 0 | std::cerr << "list of hex numbers"; |
367 | 0 | break; |
368 | 0 | case SpirvBinaryEmissionFormat::CInitList: |
369 | 0 | std::cerr << "C-style initializer list"; |
370 | 0 | break; |
371 | 760 | case SpirvBinaryEmissionFormat::WGSL: |
372 | 760 | std::cerr << "WGSL source program"; |
373 | 760 | break; |
374 | 0 | case SpirvBinaryEmissionFormat::Unspecified: |
375 | | // The compiler should never be here at runtime. This case is added to |
376 | | // complete the switch cases. |
377 | 0 | break; |
378 | 760 | } |
379 | 760 | std::cerr << " when only preprocessing the source" << std::endl; |
380 | 760 | return false; |
381 | 760 | } |
382 | 0 | if (dependency_info_dumping_handler_ && |
383 | 0 | dependency_info_dumping_handler_->DumpingAsCompilationOutput()) { |
384 | 0 | std::cerr << "glslc: error: cannot dump dependency info when specifying " |
385 | 0 | "any binary output format" |
386 | 0 | << std::endl; |
387 | 0 | return false; |
388 | 0 | } |
389 | 0 | } |
390 | | |
391 | 0 | if (binary_emission_format_ == SpirvBinaryEmissionFormat::WGSL) { |
392 | 0 | #if SHADERC_ENABLE_WGSL_OUTPUT != 1 |
393 | 0 | std::cerr << "glslc: error: can't output WGSL: glslc was built without " |
394 | 0 | "WGSL output support" |
395 | 0 | << std::endl; |
396 | 0 | return false; |
397 | 0 | #endif |
398 | 0 | } |
399 | | |
400 | 0 | return true; |
401 | 0 | } |
402 | | |
403 | 0 | void FileCompiler::OutputMessages() { |
404 | 0 | shaderc_util::OutputMessages(&std::cerr, total_warnings_, total_errors_); |
405 | 0 | } |
406 | | |
407 | 2.28k | std::string FileCompiler::GetOutputFileName(std::string input_filename) { |
408 | 2.28k | if (output_file_name_.empty()) { |
409 | 0 | return needs_linking_ ? std::string("a.spv") |
410 | 0 | : GetCandidateOutputFileName(input_filename); |
411 | 2.28k | } else { |
412 | 2.28k | return output_file_name_.str(); |
413 | 2.28k | } |
414 | 2.28k | } |
415 | | |
416 | | std::string FileCompiler::GetCandidateOutputFileName( |
417 | 0 | std::string input_filename) { |
418 | 0 | if (!output_file_name_.empty() && !PreprocessingOnly()) { |
419 | 0 | return output_file_name_.str(); |
420 | 0 | } |
421 | | |
422 | 0 | std::string extension = file_extension_; |
423 | 0 | if (PreprocessingOnly() || needs_linking_) { |
424 | 0 | extension = ".spv"; |
425 | 0 | } |
426 | |
|
427 | 0 | std::string candidate_output_file_name = |
428 | 0 | IsStageFile(input_filename) |
429 | 0 | ? shaderc_util::GetBaseFileName(input_filename) + extension |
430 | 0 | : shaderc_util::GetBaseFileName( |
431 | 0 | input_filename.substr(0, input_filename.find_last_of('.')) + |
432 | 0 | extension); |
433 | 0 | return candidate_output_file_name; |
434 | 0 | } |
435 | | } // namesapce glslc |