Flutter Impeller
impeller::compiler::Compiler Class Reference

#include <compiler.h>

Public Member Functions

 Compiler (const std::shared_ptr< const fml::Mapping > &source_mapping, const SourceOptions &options, Reflector::Options reflector_options)
 
 ~Compiler ()
 
bool IsValid () const
 
std::shared_ptr< fml::Mapping > GetSPIRVAssembly () const
 
std::shared_ptr< fml::Mapping > GetSLShaderSource () const
 
std::string GetErrorMessages () const
 
const std::vector< std::string > & GetIncludedFileNames () const
 
std::unique_ptr< fml::Mapping > CreateDepfileContents (std::initializer_list< std::string > targets) const
 
const ReflectorGetReflector () const
 

Detailed Description

Definition at line 24 of file compiler.h.

Constructor & Destructor Documentation

◆ Compiler()

impeller::compiler::Compiler::Compiler ( const std::shared_ptr< const fml::Mapping > &  source_mapping,
const SourceOptions options,
Reflector::Options  reflector_options 
)

Definition at line 234 of file compiler.cc.

237  : options_(source_options) {
238  if (!source_mapping || source_mapping->GetMapping() == nullptr) {
239  COMPILER_ERROR(error_stream_)
240  << "Could not read shader source or shader source was empty.";
241  return;
242  }
243 
244  if (source_options.target_platform == TargetPlatform::kUnknown) {
245  COMPILER_ERROR(error_stream_) << "Target platform not specified.";
246  return;
247  }
248 
249  SPIRVCompilerOptions spirv_options;
250 
251  // Make sure reflection is as effective as possible. The generated shaders
252  // will be processed later by backend specific compilers.
253  spirv_options.generate_debug_info = true;
254 
255  switch (options_.source_language) {
257  // Expects GLSL 4.60 (Core Profile).
258  // https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
259  spirv_options.source_langauge =
260  shaderc_source_language::shaderc_source_language_glsl;
261  spirv_options.source_profile = SPIRVCompilerSourceProfile{
262  shaderc_profile::shaderc_profile_core, //
263  460, //
264  };
265  break;
267  spirv_options.source_langauge =
268  shaderc_source_language::shaderc_source_language_hlsl;
269  break;
271  COMPILER_ERROR(error_stream_) << "Source language invalid.";
272  return;
273  }
274 
275  switch (source_options.target_platform) {
278  SPIRVCompilerTargetEnv target;
279 
280  if (source_options.use_half_textures) {
281  target.env = shaderc_target_env::shaderc_target_env_opengl;
282  target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
283  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
284  } else {
285  target.env = shaderc_target_env::shaderc_target_env_vulkan;
286  target.version = shaderc_env_version::shaderc_env_version_vulkan_1_1;
287  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_3;
288  }
289 
290  spirv_options.target = target;
291  } break;
295  SPIRVCompilerTargetEnv target;
296 
297  target.env = shaderc_target_env::shaderc_target_env_vulkan;
298  target.version = shaderc_env_version::shaderc_env_version_vulkan_1_1;
299  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_3;
300 
301  spirv_options.target = target;
302  } break;
306  SPIRVCompilerTargetEnv target;
307 
308  target.env = shaderc_target_env::shaderc_target_env_opengl;
309  target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
310  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
311 
312  spirv_options.target = target;
313  spirv_options.macro_definitions.push_back("IMPELLER_GRAPHICS_BACKEND");
314  } break;
315  case TargetPlatform::kSkSL: {
316  SPIRVCompilerTargetEnv target;
317 
318  target.env = shaderc_target_env::shaderc_target_env_opengl;
319  target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
320  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
321 
322  // When any optimization level above 'zero' is enabled, the phi merges at
323  // loop continue blocks are rendered using syntax that is supported in
324  // GLSL, but not in SkSL.
325  // https://bugs.chromium.org/p/skia/issues/detail?id=13518.
326  spirv_options.optimization_level =
327  shaderc_optimization_level::shaderc_optimization_level_zero;
328  spirv_options.target = target;
329  spirv_options.macro_definitions.push_back("SKIA_GRAPHICS_BACKEND");
330  } break;
332  COMPILER_ERROR(error_stream_) << "Target platform invalid.";
333  return;
334  }
335 
336  // Implicit definition that indicates that this compilation is for the device
337  // (instead of the host).
338  spirv_options.macro_definitions.push_back("IMPELLER_DEVICE");
339  for (const auto& define : source_options.defines) {
340  spirv_options.macro_definitions.push_back(define);
341  }
342 
343  std::vector<std::string> included_file_names;
344  spirv_options.includer = std::make_shared<Includer>(
345  options_.working_directory, options_.include_dirs,
346  [&included_file_names](auto included_name) {
347  included_file_names.emplace_back(std::move(included_name));
348  });
349 
350  // SPIRV Generation.
351  SPIRVCompiler spv_compiler(source_options, source_mapping);
352 
353  spirv_assembly_ = spv_compiler.CompileToSPV(
354  error_stream_, spirv_options.BuildShadercOptions());
355 
356  if (!spirv_assembly_) {
357  return;
358  } else {
359  included_file_names_ = std::move(included_file_names);
360  }
361 
362  // SL Generation.
363  spirv_cross::Parser parser(
364  reinterpret_cast<const uint32_t*>(spirv_assembly_->GetMapping()),
365  spirv_assembly_->GetSize() / sizeof(uint32_t));
366  // The parser and compiler must be run separately because the parser contains
367  // meta information (like type member names) that are useful for reflection.
368  parser.parse();
369 
370  const auto parsed_ir =
371  std::make_shared<spirv_cross::ParsedIR>(parser.get_parsed_ir());
372 
373  auto sl_compiler = CreateCompiler(*parsed_ir, options_);
374 
375  if (!sl_compiler) {
376  COMPILER_ERROR(error_stream_)
377  << "Could not create compiler for target platform.";
378  return;
379  }
380 
381  // We need to invoke the compiler even if we don't use the SL mapping later
382  // for Vulkan. The reflector needs information that is only valid after a
383  // successful compilation call.
384  auto sl_compilation_result =
385  CreateMappingWithString(sl_compiler.GetCompiler()->compile());
386 
387  // If the target is Vulkan, our shading language is SPIRV which we already
388  // have. We just need to strip it of debug information. If it isn't, we need
389  // to invoke the appropriate compiler to compile the SPIRV to the target SL.
390  if (source_options.target_platform == TargetPlatform::kVulkan) {
391  auto stripped_spirv_options = spirv_options;
392  stripped_spirv_options.generate_debug_info = false;
393  sl_mapping_ = spv_compiler.CompileToSPV(
394  error_stream_, stripped_spirv_options.BuildShadercOptions());
395  } else {
396  sl_mapping_ = sl_compilation_result;
397  }
398 
399  if (!sl_mapping_) {
400  COMPILER_ERROR(error_stream_) << "Could not generate SL from SPIRV";
401  return;
402  }
403 
404  reflector_ = std::make_unique<Reflector>(std::move(reflector_options), //
405  parsed_ir, //
406  GetSLShaderSource(), //
407  sl_compiler //
408  );
409 
410  if (!reflector_->IsValid()) {
411  COMPILER_ERROR(error_stream_)
412  << "Could not complete reflection on generated shader.";
413  return;
414  }
415 
416  is_valid_ = true;
417 }

References impeller::compiler::SPIRVCompilerOptions::BuildShadercOptions(), COMPILER_ERROR, impeller::compiler::SPIRVCompiler::CompileToSPV(), impeller::compiler::CreateCompiler(), impeller::CreateMappingWithString(), impeller::compiler::SourceOptions::defines, impeller::compiler::SPIRVCompilerTargetEnv::env, impeller::compiler::SPIRVCompilerOptions::generate_debug_info, GetSLShaderSource(), impeller::compiler::SourceOptions::include_dirs, impeller::compiler::SPIRVCompilerOptions::includer, impeller::compiler::kGLSL, impeller::compiler::kHLSL, impeller::compiler::kMetalDesktop, impeller::compiler::kMetalIOS, impeller::compiler::kOpenGLDesktop, impeller::compiler::kOpenGLES, impeller::compiler::kRuntimeStageGLES, impeller::compiler::kRuntimeStageMetal, impeller::compiler::kRuntimeStageVulkan, impeller::compiler::kSkSL, impeller::compiler::kUnknown, impeller::compiler::kVulkan, impeller::compiler::SPIRVCompilerOptions::macro_definitions, impeller::compiler::SPIRVCompilerOptions::optimization_level, impeller::compiler::SPIRVCompilerOptions::source_langauge, impeller::compiler::SourceOptions::source_language, impeller::compiler::SPIRVCompilerOptions::source_profile, impeller::compiler::SPIRVCompilerTargetEnv::spirv_version, impeller::compiler::SPIRVCompilerOptions::target, impeller::compiler::SourceOptions::target_platform, impeller::compiler::SourceOptions::use_half_textures, impeller::compiler::SPIRVCompilerTargetEnv::version, and impeller::compiler::SourceOptions::working_directory.

◆ ~Compiler()

impeller::compiler::Compiler::~Compiler ( )
default

Member Function Documentation

◆ CreateDepfileContents()

std::unique_ptr< fml::Mapping > impeller::compiler::Compiler::CreateDepfileContents ( std::initializer_list< std::string >  targets) const

Definition at line 467 of file compiler.cc.

468  {
469  // https://github.com/ninja-build/ninja/blob/master/src/depfile_parser.cc#L28
470  const auto targets = JoinStrings(targets_names, " ");
471  const auto dependencies = GetDependencyNames(" ");
472 
473  std::stringstream stream;
474  stream << targets << ": " << dependencies << "\n";
475 
476  auto contents = std::make_shared<std::string>(stream.str());
477  return std::make_unique<fml::NonOwnedMapping>(
478  reinterpret_cast<const uint8_t*>(contents->data()), contents->size(),
479  [contents](auto, auto) {});
480 }

References impeller::compiler::JoinStrings().

Referenced by impeller::compiler::Main().

◆ GetErrorMessages()

std::string impeller::compiler::Compiler::GetErrorMessages ( ) const

Definition at line 439 of file compiler.cc.

439  {
440  return error_stream_.str();
441 }

Referenced by impeller::compiler::testing::CompilerTest::CanCompileAndReflect(), and impeller::compiler::Main().

◆ GetIncludedFileNames()

const std::vector< std::string > & impeller::compiler::Compiler::GetIncludedFileNames ( ) const

Definition at line 443 of file compiler.cc.

443  {
444  return included_file_names_;
445 }

◆ GetReflector()

const Reflector * impeller::compiler::Compiler::GetReflector ( ) const

Definition at line 482 of file compiler.cc.

482  {
483  return reflector_.get();
484 }

Referenced by impeller::compiler::testing::CompilerTest::CanCompileAndReflect(), and impeller::compiler::Main().

◆ GetSLShaderSource()

std::shared_ptr< fml::Mapping > impeller::compiler::Compiler::GetSLShaderSource ( ) const

Definition at line 425 of file compiler.cc.

425  {
426  return sl_mapping_;
427 }

Referenced by impeller::compiler::testing::CompilerTest::CanCompileAndReflect(), Compiler(), and impeller::compiler::Main().

◆ GetSPIRVAssembly()

std::shared_ptr< fml::Mapping > impeller::compiler::Compiler::GetSPIRVAssembly ( ) const

Definition at line 421 of file compiler.cc.

421  {
422  return spirv_assembly_;
423 }

Referenced by impeller::compiler::testing::CompilerTest::CanCompileAndReflect(), and impeller::compiler::Main().

◆ IsValid()

bool impeller::compiler::Compiler::IsValid ( ) const

Definition at line 429 of file compiler.cc.

429  {
430  return is_valid_;
431 }

Referenced by impeller::compiler::testing::CompilerTest::CanCompileAndReflect(), and impeller::compiler::Main().


The documentation for this class was generated from the following files:
impeller::compiler::SourceOptions::include_dirs
std::vector< IncludeDir > include_dirs
Definition: source_options.h:24
impeller::compiler::TargetPlatform::kMetalDesktop
@ kMetalDesktop
impeller::compiler::TargetPlatform::kMetalIOS
@ kMetalIOS
impeller::compiler::SourceLanguage::kGLSL
@ kGLSL
impeller::compiler::SourceOptions::source_language
SourceLanguage source_language
Definition: source_options.h:22
impeller::compiler::SourceLanguage::kHLSL
@ kHLSL
impeller::compiler::TargetPlatform::kVulkan
@ kVulkan
impeller::compiler::TargetPlatform::kRuntimeStageVulkan
@ kRuntimeStageVulkan
impeller::compiler::JoinStrings
static std::string JoinStrings(std::vector< std::string > items, const std::string &separator)
Definition: compiler.cc:447
impeller::compiler::SourceLanguage::kUnknown
@ kUnknown
impeller::compiler::SourceOptions::working_directory
std::shared_ptr< fml::UniqueFD > working_directory
Definition: source_options.h:23
impeller::CreateMappingWithString
std::shared_ptr< fml::Mapping > CreateMappingWithString(std::string string)
Definition: allocation.cc:112
impeller::compiler::TargetPlatform::kOpenGLDesktop
@ kOpenGLDesktop
impeller::compiler::TargetPlatform::kUnknown
@ kUnknown
impeller::compiler::TargetPlatform::kOpenGLES
@ kOpenGLES
impeller::compiler::Compiler::GetSLShaderSource
std::shared_ptr< fml::Mapping > GetSLShaderSource() const
Definition: compiler.cc:425
impeller::compiler::CreateCompiler
static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options)
Definition: compiler.cc:200
impeller::compiler::TargetPlatform::kRuntimeStageMetal
@ kRuntimeStageMetal
COMPILER_ERROR
#define COMPILER_ERROR(stream)
Definition: logger.h:37
impeller::compiler::TargetPlatform::kSkSL
@ kSkSL
impeller::compiler::TargetPlatform::kRuntimeStageGLES
@ kRuntimeStageGLES