| Flutter Impeller |

spirv_compiler.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/compiler/spirv_compiler.h"
6
7 #include <array>
8
9 #include "impeller/compiler/logger.h"
10 #include "impeller/compiler/types.h"
11
12 namespace impeller {
13 namespace compiler {
14
15 SPIRVCompiler::SPIRVCompiler(const SourceOptions& options,
16 std::shared_ptr<const fml::Mapping> sources)
17 : options_(options), sources_(std::move(sources)) {}
18
19 SPIRVCompiler::~SPIRVCompiler() = default;
20
21 std::shared_ptr<fml::Mapping> SPIRVCompiler::CompileToSPV(
22 std::stringstream& stream,
23 const shaderc::CompileOptions& spirv_options) const {
24 if (!sources_ || sources_->GetMapping() == nullptr) {
25 COMPILER_ERROR(stream) << "Invalid sources for SPIRV Compiler.";
26 return nullptr;
27 }
28
29 shaderc::Compiler spv_compiler;
30 if (!spv_compiler.IsValid()) {
31 COMPILER_ERROR(stream) << "Could not initialize the "
32 << SourceLanguageToString(options_.source_language)
33 << " to SPIRV compiler.";
34 return nullptr;
35 }
36
37 const auto shader_kind = ToShaderCShaderKind(options_.type);
38
39 if (shader_kind == shaderc_shader_kind::shaderc_glsl_infer_from_source) {
40 COMPILER_ERROR(stream) << "Could not figure out shader stage.";
41 return nullptr;
42 }
43
44 auto result = std::make_shared<shaderc::SpvCompilationResult>(
45 spv_compiler.CompileGlslToSpv(
46 reinterpret_cast<const char*>(sources_->GetMapping()), // source_text
47 sources_->GetSize(), // source_text_size
48 shader_kind, // shader_kind
49 options_.file_name.c_str(), // input_file_name
50 options_.entry_point_name.c_str(), // entry_point_name
51 spirv_options // options
52 ));
53 if (result->GetCompilationStatus() !=
54 shaderc_compilation_status::shaderc_compilation_status_success) {
55 COMPILER_ERROR(stream) << SourceLanguageToString(options_.source_language)
56 << " to SPIRV failed; "
57 << ShaderCErrorToString(
58 result->GetCompilationStatus())
59 << ". " << result->GetNumErrors() << " error(s) and "
60 << result->GetNumWarnings() << " warning(s).";
61 // It should normally be enough to check that there are errors or warnings,
62 // but some cases result in no errors or warnings and still have an error
63 // message. If there's a message we should print it.
64 if (result->GetNumErrors() > 0 || result->GetNumWarnings() > 0 ||
65 !result->GetErrorMessage().empty()) {
66 COMPILER_ERROR_NO_PREFIX(stream) << result->GetErrorMessage();
67 }
68 return nullptr;
69 }
70
71 if (!result) {
72 COMPILER_ERROR(stream) << "Could not fetch SPIRV from compile job.";
73 return nullptr;
74 }
75
76 const auto data_length = (result->cend() - result->cbegin()) *
77 sizeof(decltype(result)::element_type::element_type);
78
79 return std::make_unique<fml::NonOwnedMapping>(
80 reinterpret_cast<const uint8_t*>(result->cbegin()), //
81 data_length, //
82 [result](auto, auto) {} //
83 );
84 }
85
86 std::string SPIRVCompiler::GetSourcePrefix() const {
87 std::stringstream stream;
88 stream << options_.file_name << ": ";
89 return stream.str();
90 }
91
92 static void SetDefaultLimitations(shaderc::CompileOptions& compiler_opts) {
93 using Limit = std::pair<shaderc_limit, int>;
94 static constexpr std::array<Limit, 83> limits = {
95 Limit{shaderc_limit::shaderc_limit_max_lights, 8},
96 Limit{shaderc_limit::shaderc_limit_max_clip_planes, 6},
97 Limit{shaderc_limit::shaderc_limit_max_texture_units, 2},
98 Limit{shaderc_limit::shaderc_limit_max_texture_coords, 8},
99 Limit{shaderc_limit::shaderc_limit_max_vertex_attribs, 16},
100 Limit{shaderc_limit::shaderc_limit_max_vertex_uniform_components, 4096},
101 Limit{shaderc_limit::shaderc_limit_max_varying_floats, 60},
102 Limit{shaderc_limit::shaderc_limit_max_vertex_texture_image_units, 16},
103 Limit{shaderc_limit::shaderc_limit_max_combined_texture_image_units, 80},
104 Limit{shaderc_limit::shaderc_limit_max_texture_image_units, 16},
105 Limit{shaderc_limit::shaderc_limit_max_fragment_uniform_components, 1024},
106 Limit{shaderc_limit::shaderc_limit_max_draw_buffers, 8},
107 Limit{shaderc_limit::shaderc_limit_max_vertex_uniform_vectors, 256},
108 Limit{shaderc_limit::shaderc_limit_max_varying_vectors, 15},
109 Limit{shaderc_limit::shaderc_limit_max_fragment_uniform_vectors, 256},
110 Limit{shaderc_limit::shaderc_limit_max_vertex_output_vectors, 16},
111 Limit{shaderc_limit::shaderc_limit_max_fragment_input_vectors, 15},
112 Limit{shaderc_limit::shaderc_limit_min_program_texel_offset, -8},
113 Limit{shaderc_limit::shaderc_limit_max_program_texel_offset, 7},
114 Limit{shaderc_limit::shaderc_limit_max_clip_distances, 8},
115 Limit{shaderc_limit::shaderc_limit_max_compute_work_group_count_x, 65535},
116 Limit{shaderc_limit::shaderc_limit_max_compute_work_group_count_y, 65535},
117 Limit{shaderc_limit::shaderc_limit_max_compute_work_group_count_z, 65535},
118 Limit{shaderc_limit::shaderc_limit_max_compute_work_group_size_x, 1024},
119 Limit{shaderc_limit::shaderc_limit_max_compute_work_group_size_y, 1024},
120 Limit{shaderc_limit::shaderc_limit_max_compute_work_group_size_z, 64},
121 Limit{shaderc_limit::shaderc_limit_max_compute_uniform_components, 512},
122 Limit{shaderc_limit::shaderc_limit_max_compute_texture_image_units, 16},
123 Limit{shaderc_limit::shaderc_limit_max_compute_image_uniforms, 8},
124 Limit{shaderc_limit::shaderc_limit_max_compute_atomic_counters, 8},
125 Limit{shaderc_limit::shaderc_limit_max_compute_atomic_counter_buffers, 1},
126 Limit{shaderc_limit::shaderc_limit_max_varying_components, 60},
127 Limit{shaderc_limit::shaderc_limit_max_vertex_output_components, 64},
128 Limit{shaderc_limit::shaderc_limit_max_geometry_input_components, 64},
129 Limit{shaderc_limit::shaderc_limit_max_geometry_output_components, 128},
130 Limit{shaderc_limit::shaderc_limit_max_fragment_input_components, 128},
131 Limit{shaderc_limit::shaderc_limit_max_image_units, 8},
132 Limit{shaderc_limit::
133 shaderc_limit_max_combined_image_units_and_fragment_outputs,
134 8},
135 Limit{shaderc_limit::shaderc_limit_max_combined_shader_output_resources,
136 8},
137 Limit{shaderc_limit::shaderc_limit_max_image_samples, 0},
138 Limit{shaderc_limit::shaderc_limit_max_vertex_image_uniforms, 0},
139 Limit{shaderc_limit::shaderc_limit_max_tess_control_image_uniforms, 0},
140 Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_image_uniforms, 0},
141 Limit{shaderc_limit::shaderc_limit_max_geometry_image_uniforms, 0},
142 Limit{shaderc_limit::shaderc_limit_max_fragment_image_uniforms, 8},
143 Limit{shaderc_limit::shaderc_limit_max_combined_image_uniforms, 8},
144 Limit{shaderc_limit::shaderc_limit_max_geometry_texture_image_units, 16},
145 Limit{shaderc_limit::shaderc_limit_max_geometry_output_vertices, 256},
146 Limit{shaderc_limit::shaderc_limit_max_geometry_total_output_components,
147 1024},
148 Limit{shaderc_limit::shaderc_limit_max_geometry_uniform_components, 512},
149 Limit{shaderc_limit::shaderc_limit_max_geometry_varying_components, 60},
150 Limit{shaderc_limit::shaderc_limit_max_tess_control_input_components,
151 128},
152 Limit{shaderc_limit::shaderc_limit_max_tess_control_output_components,
153 128},
154 Limit{shaderc_limit::shaderc_limit_max_tess_control_texture_image_units,
155 16},
156 Limit{shaderc_limit::shaderc_limit_max_tess_control_uniform_components,
157 1024},
158 Limit{
159 shaderc_limit::shaderc_limit_max_tess_control_total_output_components,
160 4096},
161 Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_input_components,
162 128},
163 Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_output_components,
164 128},
165 Limit{
166 shaderc_limit::shaderc_limit_max_tess_evaluation_texture_image_units,
167 16},
168 Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_uniform_components,
169 1024},
170 Limit{shaderc_limit::shaderc_limit_max_tess_patch_components, 120},
171 Limit{shaderc_limit::shaderc_limit_max_patch_vertices, 32},
172 Limit{shaderc_limit::shaderc_limit_max_tess_gen_level, 64},
173 Limit{shaderc_limit::shaderc_limit_max_viewports, 16},
174 Limit{shaderc_limit::shaderc_limit_max_vertex_atomic_counters, 0},
175 Limit{shaderc_limit::shaderc_limit_max_tess_control_atomic_counters, 0},
176 Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_atomic_counters,
177 0},
178 Limit{shaderc_limit::shaderc_limit_max_geometry_atomic_counters, 0},
179 Limit{shaderc_limit::shaderc_limit_max_fragment_atomic_counters, 8},
180 Limit{shaderc_limit::shaderc_limit_max_combined_atomic_counters, 8},
181 Limit{shaderc_limit::shaderc_limit_max_atomic_counter_bindings, 1},
182 Limit{shaderc_limit::shaderc_limit_max_vertex_atomic_counter_buffers, 0},
183 Limit{
184 shaderc_limit::shaderc_limit_max_tess_control_atomic_counter_buffers,
185 0},
186 Limit{shaderc_limit::
187 shaderc_limit_max_tess_evaluation_atomic_counter_buffers,
188 0},
189 Limit{shaderc_limit::shaderc_limit_max_geometry_atomic_counter_buffers,
190 0},
191 Limit{shaderc_limit::shaderc_limit_max_fragment_atomic_counter_buffers,
192 0},
193 Limit{shaderc_limit::shaderc_limit_max_combined_atomic_counter_buffers,
194 1},
195 Limit{shaderc_limit::shaderc_limit_max_atomic_counter_buffer_size, 32},
196 Limit{shaderc_limit::shaderc_limit_max_transform_feedback_buffers, 4},
197 Limit{shaderc_limit::
198 shaderc_limit_max_transform_feedback_interleaved_components,
199 64},
200 Limit{shaderc_limit::shaderc_limit_max_cull_distances, 8},
201 Limit{shaderc_limit::shaderc_limit_max_combined_clip_and_cull_distances,
202 8},
203 Limit{shaderc_limit::shaderc_limit_max_samples, 4},
204 };
205 for (auto& [limit, value] : limits) {
206 compiler_opts.SetLimit(limit, value);
207 }
208 }
209
210 static void SetBindingBaseOffset(shaderc::CompileOptions& options) {
211 constexpr uint32_t kBindingBaseOffset = 64;
212 static const shaderc_uniform_kind kUniformKinds[] = {
213 shaderc_uniform_kind::shaderc_uniform_kind_sampler,
214 shaderc_uniform_kind::shaderc_uniform_kind_texture,
215 shaderc_uniform_kind::shaderc_uniform_kind_image,
216 shaderc_uniform_kind::shaderc_uniform_kind_buffer, // UBOs
217 shaderc_uniform_kind::shaderc_uniform_kind_storage_buffer, // SSBOs
218 };
219
220 for (size_t i = 0u; i < sizeof(kUniformKinds) / sizeof(shaderc_uniform_kind);
221 i++) {
222 options.SetBindingBaseForStage(
223 shaderc_shader_kind::shaderc_fragment_shader, //
224 kUniformKinds[i], //
225 kBindingBaseOffset //
226 );
227 }
228 }
229
230 //------------------------------------------------------------------------------
231 /// @brief Wraps a shared includer so unique includers may be created to
232 /// satisfy the shaderc API. This is a simple proxy object and does
233 /// nothing.
234 ///
235 class UniqueIncluder final : public shaderc::CompileOptions::IncluderInterface {
236 public:
237 static std::unique_ptr<UniqueIncluder> Make(
238 std::shared_ptr<Includer> includer) {
239 return std::unique_ptr<UniqueIncluder>(
240 new UniqueIncluder(std::move(includer)));
241 }
242
243 // |shaderc::CompileOptions::IncluderInterface|
244 ~UniqueIncluder() = default;
245
246 // |shaderc::CompileOptions::IncluderInterface|
247 shaderc_include_result* GetInclude(const char* requested_source,
248 shaderc_include_type type,
249 const char* requesting_source,
250 size_t include_depth) override {
251 return includer_->GetInclude(requested_source, //
252 type, //
253 requesting_source, //
254 include_depth //
255 );
256 }
257
258 // |shaderc::CompileOptions::IncluderInterface|
259 void ReleaseInclude(shaderc_include_result* data) override {
260 return includer_->ReleaseInclude(data);
261 }
262
263 private:
264 std::shared_ptr<Includer> includer_;
265
266 explicit UniqueIncluder(std::shared_ptr<Includer> includer)
267 : includer_(std::move(includer)) {
268 FML_CHECK(includer_);
269 }
270
271 UniqueIncluder(const UniqueIncluder&) = delete;
272
273 UniqueIncluder& operator=(const UniqueIncluder&) = delete;
274 };
275
276 shaderc::CompileOptions SPIRVCompilerOptions::BuildShadercOptions() const {
277 shaderc::CompileOptions options;
278
279 SetDefaultLimitations(options);
280 SetBindingBaseOffset(options);
281
282 options.SetAutoBindUniforms(true);
283 options.SetAutoMapLocations(true);
284
285 options.SetOptimizationLevel(optimization_level);
286
287 if (generate_debug_info) {
288 options.SetGenerateDebugInfo();
289 }
290
291 if (source_langauge.has_value()) {
292 options.SetSourceLanguage(source_langauge.value());
293 }
294
295 if (source_profile.has_value()) {
296 options.SetForcedVersionProfile(source_profile->version,
297 source_profile->profile);
298 }
299
300 if (target.has_value()) {
301 options.SetTargetEnvironment(target->env, target->version);
302 options.SetTargetSpirv(target->spirv_version);
303 }
304
305 for (const auto& macro : macro_definitions) {
306 options.AddMacroDefinition(macro);
307 }
308
309 if (includer) {
310 options.SetIncluder(UniqueIncluder::Make(includer));
311 }
312
313 return options;
314 }
315
316 } // namespace compiler
317 } // namespace impeller
impeller::compiler::SPIRVCompiler::~SPIRVCompiler
~SPIRVCompiler()
impeller::compiler::SourceOptions::type
SourceType type
Definition: source_options.h:21
impeller::compiler::SPIRVCompiler::CompileToSPV
std::shared_ptr< fml::Mapping > CompileToSPV(std::stringstream &error_stream, const shaderc::CompileOptions &spirv_options) const
Definition: spirv_compiler.cc:21
impeller::compiler::SPIRVCompilerOptions::generate_debug_info
bool generate_debug_info
Definition: spirv_compiler.h:33
logger.h
COMPILER_ERROR_NO_PREFIX
#define COMPILER_ERROR_NO_PREFIX(stream)
Definition: logger.h:42
impeller::compiler::SPIRVCompiler::SPIRVCompiler
SPIRVCompiler(const SourceOptions &options, std::shared_ptr< const fml::Mapping > sources)
Definition: spirv_compiler.cc:15
impeller::compiler::UniqueIncluder::ReleaseInclude
void ReleaseInclude(shaderc_include_result *data) override
Definition: spirv_compiler.cc:259
impeller::compiler::SourceOptions
Definition: source_options.h:20
impeller::compiler::SourceLanguageToString
std::string SourceLanguageToString(SourceLanguage source_language)
Definition: types.cc:100
impeller::compiler::SPIRVCompilerOptions::includer
std::shared_ptr< Includer > includer
Definition: spirv_compiler.h:50
impeller::compiler::SetBindingBaseOffset
static void SetBindingBaseOffset(shaderc::CompileOptions &options)
Definition: spirv_compiler.cc:210
impeller::compiler::SPIRVCompilerOptions::source_profile
std::optional< SPIRVCompilerSourceProfile > source_profile
Definition: spirv_compiler.h:38
impeller::compiler::SourceOptions::source_language
SourceLanguage source_language
Definition: source_options.h:23
impeller::compiler::SPIRVCompilerOptions::target
std::optional< SPIRVCompilerTargetEnv > target
Definition: spirv_compiler.h:46
impeller::compiler::SourceOptions::entry_point_name
std::string entry_point_name
Definition: source_options.h:27
impeller::compiler::UniqueIncluder::Make
static std::unique_ptr< UniqueIncluder > Make(std::shared_ptr< Includer > includer)
Definition: spirv_compiler.cc:237
impeller::compiler::UniqueIncluder::~UniqueIncluder
~UniqueIncluder()=default
impeller::compiler::SourceOptions::file_name
std::string file_name
Definition: source_options.h:26
spirv_compiler.h
impeller::compiler::SetDefaultLimitations
static void SetDefaultLimitations(shaderc::CompileOptions &compiler_opts)
Definition: spirv_compiler.cc:92
impeller::compiler::SPIRVCompilerOptions::source_langauge
std::optional< shaderc_source_language > source_langauge
Definition: spirv_compiler.h:37
impeller::compiler::SPIRVCompilerOptions::macro_definitions
std::vector< std::string > macro_definitions
Definition: spirv_compiler.h:48
impeller::compiler::SPIRVCompilerOptions::BuildShadercOptions
shaderc::CompileOptions BuildShadercOptions() const
Definition: spirv_compiler.cc:276
std
Definition: comparable.h:95
impeller::compiler::UniqueIncluder
Wraps a shared includer so unique includers may be created to satisfy the shaderc API....
Definition: spirv_compiler.cc:235
impeller::compiler::UniqueIncluder::GetInclude
shaderc_include_result * GetInclude(const char *requested_source, shaderc_include_type type, const char *requesting_source, size_t include_depth) override
Definition: spirv_compiler.cc:247
impeller::compiler::ToShaderCShaderKind
shaderc_shader_kind ToShaderCShaderKind(SourceType type)
Definition: types.cc:184
impeller
Definition: aiks_context.cc:10
COMPILER_ERROR
#define COMPILER_ERROR(stream)
Definition: logger.h:39
impeller::compiler::ShaderCErrorToString
std::string ShaderCErrorToString(shaderc_compilation_status status)
Definition: types.cc:159
impeller::compiler::SPIRVCompilerOptions::optimization_level
shaderc_optimization_level optimization_level
Definition: spirv_compiler.h:40
types.h