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
 
std::string GetVerboseErrorMessages () 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 25 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 285 of file compiler.cc.

288  : options_(source_options) {
289  if (!source_mapping || source_mapping->GetMapping() == nullptr) {
290  COMPILER_ERROR(error_stream_)
291  << "Could not read shader source or shader source was empty.";
292  return;
293  }
294 
295  if (source_options.target_platform == TargetPlatform::kUnknown) {
296  COMPILER_ERROR(error_stream_) << "Target platform not specified.";
297  return;
298  }
299 
300  SPIRVCompilerOptions spirv_options;
301 
302  // Make sure reflection is as effective as possible. The generated shaders
303  // will be processed later by backend specific compilers.
304  spirv_options.generate_debug_info = true;
305 
306  switch (options_.source_language) {
308  // Expects GLSL 4.60 (Core Profile).
309  // https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
310  spirv_options.source_langauge =
311  shaderc_source_language::shaderc_source_language_glsl;
312  spirv_options.source_profile = SPIRVCompilerSourceProfile{
313  shaderc_profile::shaderc_profile_core, //
314  460, //
315  };
316  break;
318  spirv_options.source_langauge =
319  shaderc_source_language::shaderc_source_language_hlsl;
320  break;
322  COMPILER_ERROR(error_stream_) << "Source language invalid.";
323  return;
324  }
325 
326  switch (source_options.target_platform) {
329  SPIRVCompilerTargetEnv target;
330 
331  if (source_options.use_half_textures) {
332  target.env = shaderc_target_env::shaderc_target_env_opengl;
333  target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
334  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
335  } else {
336  target.env = shaderc_target_env::shaderc_target_env_vulkan;
337  target.version = shaderc_env_version::shaderc_env_version_vulkan_1_1;
338  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_3;
339  }
340 
341  spirv_options.target = target;
342  } break;
347  SPIRVCompilerTargetEnv target;
348 
349  target.env = shaderc_target_env::shaderc_target_env_vulkan;
350  target.version = shaderc_env_version::shaderc_env_version_vulkan_1_1;
351  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_3;
352 
353  if (source_options.target_platform ==
355  spirv_options.macro_definitions.push_back("IMPELLER_GRAPHICS_BACKEND");
356  spirv_options.relaxed_vulkan_rules = true;
357  }
358  spirv_options.target = target;
359  } break;
363  SPIRVCompilerTargetEnv target;
364 
365  target.env = shaderc_target_env::shaderc_target_env_opengl;
366  target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
367  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
368 
369  spirv_options.target = target;
370  spirv_options.macro_definitions.push_back("IMPELLER_GRAPHICS_BACKEND");
371  if (source_options.target_platform == TargetPlatform::kRuntimeStageGLES ||
372  source_options.target_platform ==
374  spirv_options.macro_definitions.push_back("IMPELLER_TARGET_OPENGLES");
375  }
376  } break;
377  case TargetPlatform::kSkSL: {
378  SPIRVCompilerTargetEnv target;
379 
380  target.env = shaderc_target_env::shaderc_target_env_opengl;
381  target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
382  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
383 
384  // When any optimization level above 'zero' is enabled, the phi merges at
385  // loop continue blocks are rendered using syntax that is supported in
386  // GLSL, but not in SkSL.
387  // https://bugs.chromium.org/p/skia/issues/detail?id=13518.
388  spirv_options.optimization_level =
389  shaderc_optimization_level::shaderc_optimization_level_zero;
390  spirv_options.target = target;
391  spirv_options.macro_definitions.push_back("SKIA_GRAPHICS_BACKEND");
392  } break;
394  COMPILER_ERROR(error_stream_) << "Target platform invalid.";
395  return;
396  }
397 
398  // Implicit definition that indicates that this compilation is for the device
399  // (instead of the host).
400  spirv_options.macro_definitions.push_back("IMPELLER_DEVICE");
401  for (const auto& define : source_options.defines) {
402  spirv_options.macro_definitions.push_back(define);
403  }
404 
405  std::vector<std::string> included_file_names;
406  spirv_options.includer = std::make_shared<Includer>(
407  options_.working_directory, options_.include_dirs,
408  [&included_file_names](auto included_name) {
409  included_file_names.emplace_back(std::move(included_name));
410  });
411 
412  // SPIRV Generation.
413  SPIRVCompiler spv_compiler(source_options, source_mapping);
414 
415  spirv_assembly_ = spv_compiler.CompileToSPV(
416  error_stream_, spirv_options.BuildShadercOptions());
417 
418  if (!spirv_assembly_) {
419  return;
420  } else {
421  included_file_names_ = std::move(included_file_names);
422  }
423 
424  // SL Generation.
425  spirv_cross::Parser parser(
426  reinterpret_cast<const uint32_t*>(spirv_assembly_->GetMapping()),
427  spirv_assembly_->GetSize() / sizeof(uint32_t));
428  // The parser and compiler must be run separately because the parser contains
429  // meta information (like type member names) that are useful for reflection.
430  parser.parse();
431 
432  const auto parsed_ir =
433  std::make_shared<spirv_cross::ParsedIR>(parser.get_parsed_ir());
434 
435  auto sl_compiler = CreateCompiler(*parsed_ir, options_);
436 
437  if (!sl_compiler) {
438  COMPILER_ERROR(error_stream_)
439  << "Could not create compiler for target platform.";
440  return;
441  }
442 
443  uint32_t ubo_size = CalculateUBOSize(sl_compiler.GetCompiler());
444  if (ubo_size > kMaxUniformBufferSize) {
445  COMPILER_ERROR(error_stream_) << "Uniform buffer size exceeds max ("
446  << kMaxUniformBufferSize << "): " << ubo_size;
447  return;
448  }
449 
450  // We need to invoke the compiler even if we don't use the SL mapping later
451  // for Vulkan. The reflector needs information that is only valid after a
452  // successful compilation call.
453  auto sl_compilation_result_str = sl_compiler.GetCompiler()->compile();
454  auto sl_compilation_result =
455  CreateMappingWithString(sl_compilation_result_str);
456 
457  // If the target is Vulkan, our shading language is SPIRV which we already
458  // have. We just need to strip it of debug information. If it isn't, we need
459  // to invoke the appropriate compiler to compile the SPIRV to the target SL.
460  if (source_options.target_platform == TargetPlatform::kVulkan ||
461  source_options.target_platform == TargetPlatform::kRuntimeStageVulkan) {
462  auto stripped_spirv_options = spirv_options;
463  stripped_spirv_options.generate_debug_info = false;
464  sl_mapping_ = spv_compiler.CompileToSPV(
465  error_stream_, stripped_spirv_options.BuildShadercOptions());
466  } else {
467  sl_mapping_ = sl_compilation_result;
468  }
469 
470  if (!sl_mapping_) {
471  COMPILER_ERROR(error_stream_) << "Could not generate SL from SPIRV";
472  return;
473  }
474 
475  if (sl_compiler.GetType() == CompilerBackend::Type::kSkSL &&
476  !ValidateSkSLResult(sl_compilation_result_str).ok()) {
477  return;
478  }
479 
480  reflector_ = std::make_unique<Reflector>(std::move(reflector_options), //
481  parsed_ir, //
482  GetSLShaderSource(), //
483  sl_compiler //
484  );
485 
486  if (!reflector_->IsValid()) {
487  COMPILER_ERROR(error_stream_)
488  << "Could not complete reflection on generated shader.";
489  return;
490  }
491 
492  is_valid_ = true;
493 }
std::shared_ptr< fml::Mapping > GetSLShaderSource() const
Definition: compiler.cc:554
#define COMPILER_ERROR(stream)
Definition: logger.h:39
static const uint32_t kMaxUniformBufferSize
Definition: compiler.cc:41
static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options)
Definition: compiler.cc:233
std::shared_ptr< fml::Mapping > CreateMappingWithString(std::string string)
Creates a mapping with string data.
Definition: allocation.cc:111
std::vector< IncludeDir > include_dirs
std::shared_ptr< fml::UniqueFD > working_directory

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::kMaxUniformBufferSize, impeller::compiler::kMetalDesktop, impeller::compiler::kMetalIOS, impeller::compiler::kOpenGLDesktop, impeller::compiler::kOpenGLES, impeller::compiler::kRuntimeStageGLES, impeller::compiler::kRuntimeStageGLES3, impeller::compiler::kRuntimeStageMetal, impeller::compiler::kRuntimeStageVulkan, impeller::compiler::CompilerBackend::kSkSL, impeller::compiler::kSkSL, impeller::compiler::kUnknown, impeller::compiler::kVulkan, impeller::compiler::SPIRVCompilerOptions::macro_definitions, impeller::compiler::SPIRVCompilerOptions::optimization_level, impeller::compiler::SPIRVCompilerOptions::relaxed_vulkan_rules, 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 600 of file compiler.cc.

601  {
602  // https://github.com/ninja-build/ninja/blob/master/src/depfile_parser.cc#L28
603  const auto targets = JoinStrings(targets_names, " ");
604  const auto dependencies = GetDependencyNames(" ");
605 
606  std::stringstream stream;
607  stream << targets << ": " << dependencies << "\n";
608 
609  auto contents = std::make_shared<std::string>(stream.str());
610  return std::make_unique<fml::NonOwnedMapping>(
611  reinterpret_cast<const uint8_t*>(contents->data()), contents->size(),
612  [contents](auto, auto) {});
613 }
static std::string JoinStrings(std::vector< std::string > items, const std::string &separator)
Definition: compiler.cc:580

References impeller::compiler::JoinStrings().

◆ GetErrorMessages()

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

Definition at line 568 of file compiler.cc.

568  {
569  return error_stream_.str();
570 }

Referenced by impeller::compiler::GenerateShaderBackendFB(), and impeller::compiler::testing::TEST_P().

◆ GetIncludedFileNames()

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

Definition at line 576 of file compiler.cc.

576  {
577  return included_file_names_;
578 }

◆ GetReflector()

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

Definition at line 615 of file compiler.cc.

615  {
616  return reflector_.get();
617 }

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

◆ GetSLShaderSource()

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

Definition at line 554 of file compiler.cc.

554  {
555  return sl_mapping_;
556 }

Referenced by Compiler().

◆ GetSPIRVAssembly()

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

Definition at line 550 of file compiler.cc.

550  {
551  return spirv_assembly_;
552 }

Referenced by impeller::compiler::testing::TEST().

◆ GetVerboseErrorMessages()

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

Gets verbose error messages if available.

This is only populated when GetErrorMessages() returns a truncated error message. If GetErrorMessages() did not have to be truncated, this will return an empty string.

Definition at line 572 of file compiler.cc.

572  {
573  return verbose_error_stream_.str();
574 }

Referenced by impeller::compiler::testing::TEST_P().

◆ IsValid()

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

Definition at line 558 of file compiler.cc.

558  {
559  return is_valid_;
560 }

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


The documentation for this class was generated from the following files: