Support HLSL ingestion in ImpellerC (flutter/engine#37461)
This commit is contained in:
@@ -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).";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -32,6 +32,7 @@ struct Switches {
|
||||
std::string depfile_path;
|
||||
std::vector<std::string> defines;
|
||||
bool json_format;
|
||||
SourceLanguage source_language = SourceLanguage::kUnknown;
|
||||
|
||||
Switches();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()) << "_";
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
18
engine/src/flutter/impeller/fixtures/simple.vert.hlsl
Normal file
18
engine/src/flutter/impeller/fixtures/simple.vert.hlsl
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user