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

[Impeller] Support HLSL ingestion in ImpellerC #37461

Merged
merged 1 commit into from
Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions impeller/compiler/compiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand All @@ -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).";
Expand Down
8 changes: 5 additions & 3 deletions impeller/compiler/compiler_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion impeller/compiler/compiler_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down
7 changes: 7 additions & 0 deletions impeller/compiler/compiler_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion impeller/compiler/impellerc_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions impeller/compiler/source_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
22 changes: 21 additions & 1 deletion impeller/compiler/switches.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -44,14 +47,16 @@ 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 << ", ";
}
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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions impeller/compiler/switches.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct Switches {
std::string depfile_path;
std::vector<std::string> defines;
bool json_format;
SourceLanguage source_language = SourceLanguage::kUnknown;

Switches();

Expand Down
34 changes: 30 additions & 4 deletions impeller/compiler/switches_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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_�";
fml::CreateDirectory(flutter::testing::OpenFixturesDirectory(),
Expand All @@ -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
21 changes: 19 additions & 2 deletions impeller/compiler/types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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()) << "_";
Expand Down
14 changes: 12 additions & 2 deletions impeller/compiler/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ enum class TargetPlatform {
kSkSL,
};

enum class SourceLanguage {
kUnknown,
kGLSL,
kHLSL,
};

bool TargetPlatformIsMetal(TargetPlatform platform);

bool TargetPlatformIsOpenGL(TargetPlatform platform);
Expand All @@ -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);

Expand Down
1 change: 1 addition & 0 deletions impeller/fixtures/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
18 changes: 18 additions & 0 deletions impeller/fixtures/simple.vert.hlsl
Original file line number Diff line number Diff line change
@@ -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;
}