Support HLSL ingestion in ImpellerC (flutter/engine#37461)

This commit is contained in:
Brandon DeRosier
2022-11-09 10:28:47 -08:00
committed by GitHub
parent eff03907ca
commit 32be4b0970
13 changed files with 142 additions and 22 deletions

View File

@@ -265,12 +265,24 @@ Compiler::Compiler(const fml::Mapping& source_mapping,
// here are irrelevant and get in the way of generating reflection code.
spirv_options.SetGenerateDebugInfo();
// Expects GLSL 4.60 (Core Profile).
// https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
spirv_options.SetSourceLanguage(
shaderc_source_language::shaderc_source_language_glsl);
spirv_options.SetForcedVersionProfile(460,
shaderc_profile::shaderc_profile_core);
switch (options_.source_language) {
case SourceLanguage::kGLSL:
// Expects GLSL 4.60 (Core Profile).
// https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
spirv_options.SetSourceLanguage(
shaderc_source_language::shaderc_source_language_glsl);
spirv_options.SetForcedVersionProfile(
460, shaderc_profile::shaderc_profile_core);
break;
case SourceLanguage::kHLSL:
spirv_options.SetSourceLanguage(
shaderc_source_language::shaderc_source_language_hlsl);
break;
case SourceLanguage::kUnknown:
COMPILER_ERROR << "Source language invalid.";
return;
}
SetLimitations(spirv_options);
switch (source_options.target_platform) {
@@ -347,7 +359,9 @@ Compiler::Compiler(const fml::Mapping& source_mapping,
shaderc::Compiler spv_compiler;
if (!spv_compiler.IsValid()) {
COMPILER_ERROR << "Could not initialize the GLSL to SPIRV compiler.";
COMPILER_ERROR << "Could not initialize the "
<< SourceLanguageToString(options_.source_language)
<< " to SPIRV compiler.";
return;
}
@@ -364,7 +378,8 @@ Compiler::Compiler(const fml::Mapping& source_mapping,
));
if (spv_result_->GetCompilationStatus() !=
shaderc_compilation_status::shaderc_compilation_status_success) {
COMPILER_ERROR << "GLSL to SPIRV failed; "
COMPILER_ERROR << SourceLanguageToString(options_.source_language)
<< " to SPIRV failed; "
<< ShaderCErrorToString(spv_result_->GetCompilationStatus())
<< ". " << spv_result_->GetNumErrors() << " error(s) and "
<< spv_result_->GetNumWarnings() << " warning(s).";

View File

@@ -66,19 +66,21 @@ std::unique_ptr<fml::FileMapping> CompilerTest::GetReflectionJson(
}
bool CompilerTest::CanCompileAndReflect(const char* fixture_name,
SourceType source_type) const {
SourceType source_type,
SourceLanguage source_language) const {
auto fixture = flutter::testing::OpenFixtureAsMapping(fixture_name);
if (!fixture->GetMapping()) {
if (!fixture || !fixture->GetMapping()) {
VALIDATION_LOG << "Could not find shader in fixtures: " << fixture_name;
return false;
}
SourceOptions source_options(fixture_name, source_type);
source_options.target_platform = GetParam();
source_options.source_language = source_language;
source_options.working_directory = std::make_shared<fml::UniqueFD>(
flutter::testing::OpenFixturesDirectory());
source_options.entry_point_name = EntryPointFunctionNameFromSourceName(
fixture_name, SourceTypeFromFileName(fixture_name));
fixture_name, SourceTypeFromFileName(fixture_name), source_language);
Reflector::Options reflector_options;
reflector_options.header_file_name = ReflectionHeaderName(fixture_name);

View File

@@ -26,7 +26,8 @@ class CompilerTest : public ::testing::TestWithParam<TargetPlatform> {
bool CanCompileAndReflect(
const char* fixture_name,
SourceType source_type = SourceType::kUnknown) const;
SourceType source_type = SourceType::kUnknown,
SourceLanguage source_language = SourceLanguage::kGLSL) const;
private:
fml::UniqueFD intermediates_directory_;

View File

@@ -28,6 +28,13 @@ TEST(CompilerTest, ShaderKindMatchingIsSuccessful) {
TEST_P(CompilerTest, CanCompile) {
ASSERT_TRUE(CanCompileAndReflect("sample.vert"));
ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader));
ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader,
SourceLanguage::kGLSL));
}
TEST_P(CompilerTest, CanCompileHLSL) {
ASSERT_TRUE(CanCompileAndReflect(
"simple.vert.hlsl", SourceType::kVertexShader, SourceLanguage::kHLSL));
}
TEST_P(CompilerTest, CanCompileTessellationControlShader) {

View File

@@ -59,6 +59,7 @@ bool Main(const fml::CommandLine& command_line) {
SourceOptions options;
options.target_platform = switches.target_platform;
options.source_language = switches.source_language;
if (switches.input_type == SourceType::kUnknown) {
options.type = SourceTypeFromFileName(switches.source_file_name);
} else {
@@ -69,7 +70,7 @@ bool Main(const fml::CommandLine& command_line) {
options.include_dirs = switches.include_directories;
options.defines = switches.defines;
options.entry_point_name = EntryPointFunctionNameFromSourceName(
switches.source_file_name, options.type);
switches.source_file_name, options.type, options.source_language);
options.json_format = switches.json_format;
Reflector::Options reflector_options;

View File

@@ -19,6 +19,7 @@ namespace compiler {
struct SourceOptions {
SourceType type = SourceType::kUnknown;
TargetPlatform target_platform = TargetPlatform::kUnknown;
SourceLanguage source_language = SourceLanguage::kUnknown;
std::shared_ptr<fml::UniqueFD> working_directory;
std::vector<IncludeDir> include_dirs;
std::string file_name = "main.glsl";

View File

@@ -4,10 +4,13 @@
#include "impeller/compiler/switches.h"
#include <algorithm>
#include <cctype>
#include <filesystem>
#include <map>
#include "flutter/fml/file.h"
#include "impeller/compiler/types.h"
#include "impeller/compiler/utilities.h"
namespace impeller {
@@ -44,7 +47,7 @@ void Switches::PrintHelp(std::ostream& stream) {
stream << " --" << platform.first;
}
stream << " ]" << std::endl;
stream << "--input=<glsl_file>" << std::endl;
stream << "--input=<source_file>" << std::endl;
stream << "[optional] --input-kind={";
for (const auto& source_type : kKnownSourceTypes) {
stream << source_type.first << ", ";
@@ -52,6 +55,8 @@ void Switches::PrintHelp(std::ostream& stream) {
stream << "}" << std::endl;
stream << "--sl=<sl_output_file>" << std::endl;
stream << "--spirv=<spirv_output_file>" << std::endl;
stream << "[optional] --source-language=glsl|hlsl (default: glsl)"
<< std::endl;
stream << "[optional] --iplr (causes --sl file to be emitted in iplr format)"
<< std::endl;
stream << "[optional] --reflection-json=<reflection_json_file>" << std::endl;
@@ -120,6 +125,16 @@ Switches::Switches(const fml::CommandLine& command_line)
return;
}
auto language =
command_line.GetOptionValueWithDefault("source-language", "glsl");
std::transform(language.begin(), language.end(), language.begin(),
[](char x) { return std::tolower(x); });
if (language == "glsl") {
source_language = SourceLanguage::kGLSL;
} else if (language == "hlsl") {
source_language = SourceLanguage::kHLSL;
}
for (const auto& include_dir_path : command_line.GetOptionValues("include")) {
if (!include_dir_path.data()) {
continue;
@@ -161,6 +176,11 @@ bool Switches::AreValid(std::ostream& explain) const {
valid = false;
}
if (source_language == SourceLanguage::kUnknown) {
explain << "Invalid source language type." << std::endl;
valid = false;
}
if (!working_directory || !working_directory->is_valid()) {
explain << "Could not figure out working directory." << std::endl;
valid = false;

View File

@@ -32,6 +32,7 @@ struct Switches {
std::string depfile_path;
std::vector<std::string> defines;
bool json_format;
SourceLanguage source_language = SourceLanguage::kUnknown;
Switches();

View File

@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <initializer_list>
#include <vector>
#include "flutter/fml/command_line.h"
#include "flutter/fml/file.h"
#include "flutter/testing/testing.h"
@@ -12,6 +15,19 @@ namespace impeller {
namespace compiler {
namespace testing {
Switches MakeSwitchesDesktopGL(
std::initializer_list<const char*> additional_options = {}) {
std::vector<const char*> options = {"--opengl-desktop", "--input=input.vert",
"--sl=output.vert",
"--spirv=output.spirv"};
options.insert(options.end(), additional_options.begin(),
additional_options.end());
auto cl = fml::CommandLineFromIteratorsWithArgv0("impellerc", options.begin(),
options.end());
return Switches(cl);
}
TEST(SwitchesTest, DoesntMangleUnicodeIncludes) {
const char* directory_name = "test_shader_include_Ã<EFBFBD>";
fml::CreateDirectory(flutter::testing::OpenFixturesDirectory(),
@@ -21,16 +37,26 @@ TEST(SwitchesTest, DoesntMangleUnicodeIncludes) {
std::string(flutter::testing::GetFixturesPath()) + "/" + directory_name;
auto include_option = "--include=" + include_path;
const auto cl = fml::CommandLineFromInitializerList(
{"impellerc", "--opengl-desktop", "--input=input.vert",
"--sl=output.vert", "--spirv=output.spirv", include_option.c_str()});
Switches switches(cl);
Switches switches = MakeSwitchesDesktopGL({include_option.c_str()});
ASSERT_TRUE(switches.AreValid(std::cout));
ASSERT_EQ(switches.include_directories.size(), 1u);
ASSERT_NE(switches.include_directories[0].dir, nullptr);
ASSERT_EQ(switches.include_directories[0].name, include_path);
}
TEST(SwitchesTest, SourceLanguageDefaultsToGLSL) {
Switches switches = MakeSwitchesDesktopGL();
ASSERT_TRUE(switches.AreValid(std::cout));
ASSERT_EQ(switches.source_language, SourceLanguage::kGLSL);
}
TEST(SwitchesTest, SourceLanguageCanBeSetToHLSL) {
Switches switches = MakeSwitchesDesktopGL({"--source-language=hLsL"});
ASSERT_TRUE(switches.AreValid(std::cout));
ASSERT_EQ(switches.source_language, SourceLanguage::kHLSL);
}
} // namespace testing
} // namespace compiler
} // namespace impeller

View File

@@ -74,8 +74,25 @@ std::string TargetPlatformToString(TargetPlatform platform) {
FML_UNREACHABLE();
}
std::string EntryPointFunctionNameFromSourceName(const std::string& file_name,
SourceType type) {
std::string SourceLanguageToString(SourceLanguage source_language) {
switch (source_language) {
case SourceLanguage::kUnknown:
return "Unknown";
case SourceLanguage::kGLSL:
return "GLSL";
case SourceLanguage::kHLSL:
return "HLSL";
}
}
std::string EntryPointFunctionNameFromSourceName(
const std::string& file_name,
SourceType type,
SourceLanguage source_language) {
if (source_language == SourceLanguage::kHLSL) {
return "main";
}
std::stringstream stream;
std::filesystem::path file_path(file_name);
stream << Utf8FromPath(file_path.stem()) << "_";

View File

@@ -37,6 +37,12 @@ enum class TargetPlatform {
kSkSL,
};
enum class SourceLanguage {
kUnknown,
kGLSL,
kHLSL,
};
bool TargetPlatformIsMetal(TargetPlatform platform);
bool TargetPlatformIsOpenGL(TargetPlatform platform);
@@ -47,10 +53,14 @@ std::string SourceTypeToString(SourceType type);
std::string TargetPlatformToString(TargetPlatform platform);
std::string SourceLanguageToString(SourceLanguage source_language);
std::string TargetPlatformSLExtension(TargetPlatform platform);
std::string EntryPointFunctionNameFromSourceName(const std::string& file_name,
SourceType type);
std::string EntryPointFunctionNameFromSourceName(
const std::string& file_name,
SourceType type,
SourceLanguage source_language);
bool TargetPlatformNeedsSL(TargetPlatform platform);

View File

@@ -61,6 +61,7 @@ test_fixtures("file_fixtures") {
"sample.tese",
"sample.vert",
"sample_with_binding.vert",
"simple.vert.hlsl",
"sa%m#ple.vert",
"struct_def_bug.vert",
"table_mountain_nx.png",

View File

@@ -0,0 +1,18 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
struct VertexInput {
float3 position : POSITION;
};
struct VertexOutput {
float4 position : SV_POSITION;
};
VertexOutput
main(VertexInput input) {
VertexOutput output;
output.position = float4(input.position, 1.0);
return output;
}