Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit eeba9b3

Browse files
authored
Support HLSL ingestion in ImpellerC (#37461)
1 parent 5d0df76 commit eeba9b3

13 files changed

+142
-22
lines changed

impeller/compiler/compiler.cc

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,24 @@ Compiler::Compiler(const fml::Mapping& source_mapping,
265265
// here are irrelevant and get in the way of generating reflection code.
266266
spirv_options.SetGenerateDebugInfo();
267267

268-
// Expects GLSL 4.60 (Core Profile).
269-
// https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
270-
spirv_options.SetSourceLanguage(
271-
shaderc_source_language::shaderc_source_language_glsl);
272-
spirv_options.SetForcedVersionProfile(460,
273-
shaderc_profile::shaderc_profile_core);
268+
switch (options_.source_language) {
269+
case SourceLanguage::kGLSL:
270+
// Expects GLSL 4.60 (Core Profile).
271+
// https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
272+
spirv_options.SetSourceLanguage(
273+
shaderc_source_language::shaderc_source_language_glsl);
274+
spirv_options.SetForcedVersionProfile(
275+
460, shaderc_profile::shaderc_profile_core);
276+
break;
277+
case SourceLanguage::kHLSL:
278+
spirv_options.SetSourceLanguage(
279+
shaderc_source_language::shaderc_source_language_hlsl);
280+
break;
281+
case SourceLanguage::kUnknown:
282+
COMPILER_ERROR << "Source language invalid.";
283+
return;
284+
}
285+
274286
SetLimitations(spirv_options);
275287

276288
switch (source_options.target_platform) {
@@ -347,7 +359,9 @@ Compiler::Compiler(const fml::Mapping& source_mapping,
347359

348360
shaderc::Compiler spv_compiler;
349361
if (!spv_compiler.IsValid()) {
350-
COMPILER_ERROR << "Could not initialize the GLSL to SPIRV compiler.";
362+
COMPILER_ERROR << "Could not initialize the "
363+
<< SourceLanguageToString(options_.source_language)
364+
<< " to SPIRV compiler.";
351365
return;
352366
}
353367

@@ -364,7 +378,8 @@ Compiler::Compiler(const fml::Mapping& source_mapping,
364378
));
365379
if (spv_result_->GetCompilationStatus() !=
366380
shaderc_compilation_status::shaderc_compilation_status_success) {
367-
COMPILER_ERROR << "GLSL to SPIRV failed; "
381+
COMPILER_ERROR << SourceLanguageToString(options_.source_language)
382+
<< " to SPIRV failed; "
368383
<< ShaderCErrorToString(spv_result_->GetCompilationStatus())
369384
<< ". " << spv_result_->GetNumErrors() << " error(s) and "
370385
<< spv_result_->GetNumWarnings() << " warning(s).";

impeller/compiler/compiler_test.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,21 @@ std::unique_ptr<fml::FileMapping> CompilerTest::GetReflectionJson(
6666
}
6767

6868
bool CompilerTest::CanCompileAndReflect(const char* fixture_name,
69-
SourceType source_type) const {
69+
SourceType source_type,
70+
SourceLanguage source_language) const {
7071
auto fixture = flutter::testing::OpenFixtureAsMapping(fixture_name);
71-
if (!fixture->GetMapping()) {
72+
if (!fixture || !fixture->GetMapping()) {
7273
VALIDATION_LOG << "Could not find shader in fixtures: " << fixture_name;
7374
return false;
7475
}
7576

7677
SourceOptions source_options(fixture_name, source_type);
7778
source_options.target_platform = GetParam();
79+
source_options.source_language = source_language;
7880
source_options.working_directory = std::make_shared<fml::UniqueFD>(
7981
flutter::testing::OpenFixturesDirectory());
8082
source_options.entry_point_name = EntryPointFunctionNameFromSourceName(
81-
fixture_name, SourceTypeFromFileName(fixture_name));
83+
fixture_name, SourceTypeFromFileName(fixture_name), source_language);
8284

8385
Reflector::Options reflector_options;
8486
reflector_options.header_file_name = ReflectionHeaderName(fixture_name);

impeller/compiler/compiler_test.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ class CompilerTest : public ::testing::TestWithParam<TargetPlatform> {
2626

2727
bool CanCompileAndReflect(
2828
const char* fixture_name,
29-
SourceType source_type = SourceType::kUnknown) const;
29+
SourceType source_type = SourceType::kUnknown,
30+
SourceLanguage source_language = SourceLanguage::kGLSL) const;
3031

3132
private:
3233
fml::UniqueFD intermediates_directory_;

impeller/compiler/compiler_unittests.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ TEST(CompilerTest, ShaderKindMatchingIsSuccessful) {
2828
TEST_P(CompilerTest, CanCompile) {
2929
ASSERT_TRUE(CanCompileAndReflect("sample.vert"));
3030
ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader));
31+
ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader,
32+
SourceLanguage::kGLSL));
33+
}
34+
35+
TEST_P(CompilerTest, CanCompileHLSL) {
36+
ASSERT_TRUE(CanCompileAndReflect(
37+
"simple.vert.hlsl", SourceType::kVertexShader, SourceLanguage::kHLSL));
3138
}
3239

3340
TEST_P(CompilerTest, CanCompileTessellationControlShader) {

impeller/compiler/impellerc_main.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ bool Main(const fml::CommandLine& command_line) {
5959

6060
SourceOptions options;
6161
options.target_platform = switches.target_platform;
62+
options.source_language = switches.source_language;
6263
if (switches.input_type == SourceType::kUnknown) {
6364
options.type = SourceTypeFromFileName(switches.source_file_name);
6465
} else {
@@ -69,7 +70,7 @@ bool Main(const fml::CommandLine& command_line) {
6970
options.include_dirs = switches.include_directories;
7071
options.defines = switches.defines;
7172
options.entry_point_name = EntryPointFunctionNameFromSourceName(
72-
switches.source_file_name, options.type);
73+
switches.source_file_name, options.type, options.source_language);
7374
options.json_format = switches.json_format;
7475

7576
Reflector::Options reflector_options;

impeller/compiler/source_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace compiler {
1919
struct SourceOptions {
2020
SourceType type = SourceType::kUnknown;
2121
TargetPlatform target_platform = TargetPlatform::kUnknown;
22+
SourceLanguage source_language = SourceLanguage::kUnknown;
2223
std::shared_ptr<fml::UniqueFD> working_directory;
2324
std::vector<IncludeDir> include_dirs;
2425
std::string file_name = "main.glsl";

impeller/compiler/switches.cc

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
#include "impeller/compiler/switches.h"
66

7+
#include <algorithm>
8+
#include <cctype>
79
#include <filesystem>
810
#include <map>
911

1012
#include "flutter/fml/file.h"
13+
#include "impeller/compiler/types.h"
1114
#include "impeller/compiler/utilities.h"
1215

1316
namespace impeller {
@@ -44,14 +47,16 @@ void Switches::PrintHelp(std::ostream& stream) {
4447
stream << " --" << platform.first;
4548
}
4649
stream << " ]" << std::endl;
47-
stream << "--input=<glsl_file>" << std::endl;
50+
stream << "--input=<source_file>" << std::endl;
4851
stream << "[optional] --input-kind={";
4952
for (const auto& source_type : kKnownSourceTypes) {
5053
stream << source_type.first << ", ";
5154
}
5255
stream << "}" << std::endl;
5356
stream << "--sl=<sl_output_file>" << std::endl;
5457
stream << "--spirv=<spirv_output_file>" << std::endl;
58+
stream << "[optional] --source-language=glsl|hlsl (default: glsl)"
59+
<< std::endl;
5560
stream << "[optional] --iplr (causes --sl file to be emitted in iplr format)"
5661
<< std::endl;
5762
stream << "[optional] --reflection-json=<reflection_json_file>" << std::endl;
@@ -120,6 +125,16 @@ Switches::Switches(const fml::CommandLine& command_line)
120125
return;
121126
}
122127

128+
auto language =
129+
command_line.GetOptionValueWithDefault("source-language", "glsl");
130+
std::transform(language.begin(), language.end(), language.begin(),
131+
[](char x) { return std::tolower(x); });
132+
if (language == "glsl") {
133+
source_language = SourceLanguage::kGLSL;
134+
} else if (language == "hlsl") {
135+
source_language = SourceLanguage::kHLSL;
136+
}
137+
123138
for (const auto& include_dir_path : command_line.GetOptionValues("include")) {
124139
if (!include_dir_path.data()) {
125140
continue;
@@ -161,6 +176,11 @@ bool Switches::AreValid(std::ostream& explain) const {
161176
valid = false;
162177
}
163178

179+
if (source_language == SourceLanguage::kUnknown) {
180+
explain << "Invalid source language type." << std::endl;
181+
valid = false;
182+
}
183+
164184
if (!working_directory || !working_directory->is_valid()) {
165185
explain << "Could not figure out working directory." << std::endl;
166186
valid = false;

impeller/compiler/switches.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct Switches {
3232
std::string depfile_path;
3333
std::vector<std::string> defines;
3434
bool json_format;
35+
SourceLanguage source_language = SourceLanguage::kUnknown;
3536

3637
Switches();
3738

impeller/compiler/switches_unittests.cc

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#include <initializer_list>
6+
#include <vector>
7+
58
#include "flutter/fml/command_line.h"
69
#include "flutter/fml/file.h"
710
#include "flutter/testing/testing.h"
@@ -12,6 +15,19 @@ namespace impeller {
1215
namespace compiler {
1316
namespace testing {
1417

18+
Switches MakeSwitchesDesktopGL(
19+
std::initializer_list<const char*> additional_options = {}) {
20+
std::vector<const char*> options = {"--opengl-desktop", "--input=input.vert",
21+
"--sl=output.vert",
22+
"--spirv=output.spirv"};
23+
options.insert(options.end(), additional_options.begin(),
24+
additional_options.end());
25+
26+
auto cl = fml::CommandLineFromIteratorsWithArgv0("impellerc", options.begin(),
27+
options.end());
28+
return Switches(cl);
29+
}
30+
1531
TEST(SwitchesTest, DoesntMangleUnicodeIncludes) {
1632
const char* directory_name = "test_shader_include_�";
1733
fml::CreateDirectory(flutter::testing::OpenFixturesDirectory(),
@@ -21,16 +37,26 @@ TEST(SwitchesTest, DoesntMangleUnicodeIncludes) {
2137
std::string(flutter::testing::GetFixturesPath()) + "/" + directory_name;
2238
auto include_option = "--include=" + include_path;
2339

24-
const auto cl = fml::CommandLineFromInitializerList(
25-
{"impellerc", "--opengl-desktop", "--input=input.vert",
26-
"--sl=output.vert", "--spirv=output.spirv", include_option.c_str()});
27-
Switches switches(cl);
40+
Switches switches = MakeSwitchesDesktopGL({include_option.c_str()});
41+
2842
ASSERT_TRUE(switches.AreValid(std::cout));
2943
ASSERT_EQ(switches.include_directories.size(), 1u);
3044
ASSERT_NE(switches.include_directories[0].dir, nullptr);
3145
ASSERT_EQ(switches.include_directories[0].name, include_path);
3246
}
3347

48+
TEST(SwitchesTest, SourceLanguageDefaultsToGLSL) {
49+
Switches switches = MakeSwitchesDesktopGL();
50+
ASSERT_TRUE(switches.AreValid(std::cout));
51+
ASSERT_EQ(switches.source_language, SourceLanguage::kGLSL);
52+
}
53+
54+
TEST(SwitchesTest, SourceLanguageCanBeSetToHLSL) {
55+
Switches switches = MakeSwitchesDesktopGL({"--source-language=hLsL"});
56+
ASSERT_TRUE(switches.AreValid(std::cout));
57+
ASSERT_EQ(switches.source_language, SourceLanguage::kHLSL);
58+
}
59+
3460
} // namespace testing
3561
} // namespace compiler
3662
} // namespace impeller

impeller/compiler/types.cc

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,25 @@ std::string TargetPlatformToString(TargetPlatform platform) {
7474
FML_UNREACHABLE();
7575
}
7676

77-
std::string EntryPointFunctionNameFromSourceName(const std::string& file_name,
78-
SourceType type) {
77+
std::string SourceLanguageToString(SourceLanguage source_language) {
78+
switch (source_language) {
79+
case SourceLanguage::kUnknown:
80+
return "Unknown";
81+
case SourceLanguage::kGLSL:
82+
return "GLSL";
83+
case SourceLanguage::kHLSL:
84+
return "HLSL";
85+
}
86+
}
87+
88+
std::string EntryPointFunctionNameFromSourceName(
89+
const std::string& file_name,
90+
SourceType type,
91+
SourceLanguage source_language) {
92+
if (source_language == SourceLanguage::kHLSL) {
93+
return "main";
94+
}
95+
7996
std::stringstream stream;
8097
std::filesystem::path file_path(file_name);
8198
stream << Utf8FromPath(file_path.stem()) << "_";

impeller/compiler/types.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ enum class TargetPlatform {
3737
kSkSL,
3838
};
3939

40+
enum class SourceLanguage {
41+
kUnknown,
42+
kGLSL,
43+
kHLSL,
44+
};
45+
4046
bool TargetPlatformIsMetal(TargetPlatform platform);
4147

4248
bool TargetPlatformIsOpenGL(TargetPlatform platform);
@@ -47,10 +53,14 @@ std::string SourceTypeToString(SourceType type);
4753

4854
std::string TargetPlatformToString(TargetPlatform platform);
4955

56+
std::string SourceLanguageToString(SourceLanguage source_language);
57+
5058
std::string TargetPlatformSLExtension(TargetPlatform platform);
5159

52-
std::string EntryPointFunctionNameFromSourceName(const std::string& file_name,
53-
SourceType type);
60+
std::string EntryPointFunctionNameFromSourceName(
61+
const std::string& file_name,
62+
SourceType type,
63+
SourceLanguage source_language);
5464

5565
bool TargetPlatformNeedsSL(TargetPlatform platform);
5666

impeller/fixtures/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ test_fixtures("file_fixtures") {
6161
"sample.tese",
6262
"sample.vert",
6363
"sample_with_binding.vert",
64+
"simple.vert.hlsl",
6465
"sa%m#ple.vert",
6566
"struct_def_bug.vert",
6667
"table_mountain_nx.png",

impeller/fixtures/simple.vert.hlsl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
struct VertexInput {
6+
float3 position : POSITION;
7+
};
8+
9+
struct VertexOutput {
10+
float4 position : SV_POSITION;
11+
};
12+
13+
VertexOutput
14+
main(VertexInput input) {
15+
VertexOutput output;
16+
output.position = float4(input.position, 1.0);
17+
return output;
18+
}

0 commit comments

Comments
 (0)