[Impeller Scene] Add offline mesh importer (flutter/engine#37981)

This commit is contained in:
Brandon DeRosier
2022-12-01 12:57:28 -08:00
committed by GitHub
parent 2fdcc89f45
commit c3c2ac340d
13 changed files with 514 additions and 2 deletions

View File

@@ -1648,6 +1648,13 @@ FILE: ../../../flutter/impeller/scene/camera.cc
FILE: ../../../flutter/impeller/scene/camera.h
FILE: ../../../flutter/impeller/scene/geometry.cc
FILE: ../../../flutter/impeller/scene/geometry.h
FILE: ../../../flutter/impeller/scene/importer/importer.h
FILE: ../../../flutter/impeller/scene/importer/importer_gltf.cc
FILE: ../../../flutter/impeller/scene/importer/importer_main.cc
FILE: ../../../flutter/impeller/scene/importer/mesh.fbs
FILE: ../../../flutter/impeller/scene/importer/switches.cc
FILE: ../../../flutter/impeller/scene/importer/switches.h
FILE: ../../../flutter/impeller/scene/importer/types.h
FILE: ../../../flutter/impeller/scene/material.cc
FILE: ../../../flutter/impeller/scene/material.h
FILE: ../../../flutter/impeller/scene/scene.cc

View File

@@ -5,6 +5,24 @@
import("//flutter/impeller/tools/impeller.gni")
import("//flutter/shell/version/version.gni")
impeller_component("utilities") {
# Current versions of libcxx have deprecated some of the UTF-16 string
# conversion APIs.
defines = [ "_LIBCPP_DISABLE_DEPRECATION_WARNINGS" ]
sources = [
"utilities.cc",
"utilities.h",
]
public_deps = [
"../base",
"../geometry",
"../runtime_stage",
"//flutter/fml",
]
}
impeller_component("compiler_lib") {
include_dirs = [ "//third_party/vulkan-deps/spirv-cross/src/" ]
@@ -34,11 +52,10 @@ impeller_component("compiler_lib") {
"switches.h",
"types.cc",
"types.h",
"utilities.cc",
"utilities.h",
]
public_deps = [
":utilities",
"../base",
"../geometry",
"../runtime_stage",

View File

@@ -33,6 +33,11 @@ impeller_shaders("shader_fixtures") {
}
}
scene_importer("geometry_fixtures") {
geometry = [ "flutter_logo.glb" ]
type = "gltf"
}
impellerc("runtime_stages") {
shaders = [
"ink_sparkle.frag",
@@ -88,6 +93,7 @@ group("fixtures") {
public_deps = [
":file_fixtures",
":geometry_fixtures",
":shader_fixtures",
]
}

Binary file not shown.

View File

@@ -0,0 +1,93 @@
# 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.
import("//flutter/impeller/tools/impeller.gni")
import("//flutter/shell/version/version.gni")
import("//third_party/flatbuffers/flatbuffers.gni")
config("runtime_stage_config") {
configs = [ "//flutter/impeller:impeller_public_config" ]
include_dirs = [ "$root_gen_dir/flutter" ]
}
flatbuffers("importer_flatbuffers") {
flatbuffers = [ "mesh.fbs" ]
public_configs = [ ":runtime_stage_config" ]
public_deps = [ "//third_party/flatbuffers" ]
}
impeller_component("importer_lib") {
# Current versions of libcxx have deprecated some of the UTF-16 string
# conversion APIs.
defines = [ "_LIBCPP_DISABLE_DEPRECATION_WARNINGS" ]
sources = [
"importer.h",
"importer_gltf.cc",
"switches.cc",
"switches.h",
"types.h",
]
public_deps = [
":importer_flatbuffers",
"../../base",
"../../compiler:utilities",
"../../geometry",
"//flutter/fml",
# All third_party deps must be reflected below in the scene_importer_license
# target.
# TODO(bdero): Fix tinygltf compilation warnings.
#"//third_party/tinygltf",
]
}
generated_file("scene_importer_license") {
source_path = rebase_path(".", "//flutter")
git_url = "https://github.com/flutter/engine/tree/$engine_version"
outputs = [ "$target_gen_dir/LICENSE.scene_importer.md" ]
contents = [
"# scene_importer",
"",
"This tool is used by the Flutter SDK to import 3D geometry.",
"",
"Source code for this tool: [flutter/engine/$source_path]($git_url/$source_path).",
"",
"## Licenses",
"",
"### scene_importer",
"",
read_file("//flutter/sky/packages/sky_engine/LICENSE", "string"),
"",
# These licenses are ignored by the main license checker, since they are not
# shipped to end-application binaries and only shipped as part of developer
# tooling in scene_importer. Add them here.
"## Additional open source licenses",
"",
"### tinygltf",
"",
read_file("//third_party/tinygltf/LICENSE", "string"),
]
}
group("importer") {
deps = [
":scene_importer",
":scene_importer_license",
]
}
impeller_component("scene_importer") {
target_type = "executable"
sources = [ "importer_main.cc" ]
deps = [ ":importer_lib" ]
metadata = {
entitlement_file_path = [ "scene_importer" ]
}
}

View File

@@ -0,0 +1,19 @@
// 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.
#include <array>
#include <memory>
#include "flutter/fml/mapping.h"
#include "impeller/scene/importer/mesh_flatbuffers.h"
namespace impeller {
namespace scene {
namespace importer {
bool ParseGLTF(const fml::Mapping& source_mapping, fb::MeshT& out_mesh);
}
} // namespace scene
} // namespace impeller

View File

@@ -0,0 +1,24 @@
// 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.
#include <array>
#include <memory>
#include "impeller/scene/importer/importer.h"
#include "flutter/fml/mapping.h"
namespace impeller {
namespace scene {
namespace importer {
bool ParseGLTF(const fml::Mapping& source_mapping, fb::MeshT& out_mesh) {
// TODO(bdero): Parse source_mapping and populare out_mesh with just the first
// mesh in the GLTF.
return true;
}
} // namespace importer
} // namespace scene
} // namespace impeller

View File

@@ -0,0 +1,108 @@
// 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.
#include <filesystem>
#include <memory>
#include "flutter/fml/backtrace.h"
#include "flutter/fml/command_line.h"
#include "flutter/fml/file.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/mapping.h"
#include "impeller/base/strings.h"
#include "impeller/compiler/utilities.h"
#include "impeller/scene/importer/importer.h"
#include "impeller/scene/importer/switches.h"
#include "impeller/scene/importer/types.h"
#include "third_party/flatbuffers/include/flatbuffers/flatbuffer_builder.h"
namespace impeller {
namespace scene {
namespace importer {
// Sets the file access mode of the file at path 'p' to 0644.
static bool SetPermissiveAccess(const std::filesystem::path& p) {
auto permissions =
std::filesystem::perms::owner_read | std::filesystem::perms::owner_write |
std::filesystem::perms::group_read | std::filesystem::perms::others_read;
std::error_code error;
std::filesystem::permissions(p, permissions, error);
if (error) {
std::cerr << "Failed to set access on file '" << p
<< "': " << error.message() << std::endl;
return false;
}
return true;
}
bool Main(const fml::CommandLine& command_line) {
fml::InstallCrashHandler();
if (command_line.HasOption("help")) {
Switches::PrintHelp(std::cout);
return true;
}
Switches switches(command_line);
if (!switches.AreValid(std::cerr)) {
std::cerr << "Invalid flags specified." << std::endl;
Switches::PrintHelp(std::cerr);
return false;
}
auto source_file_mapping =
fml::FileMapping::CreateReadOnly(switches.source_file_name);
if (!source_file_mapping) {
std::cerr << "Could not open input file." << std::endl;
return false;
}
fb::MeshT mesh;
bool success = false;
switch (switches.input_type) {
case SourceType::kGLTF:
success = ParseGLTF(*source_file_mapping, mesh);
break;
case SourceType::kUnknown:
std::cerr << "Unknown input type." << std::endl;
return false;
}
if (!success) {
std::cerr << "Failed to parse input file." << std::endl;
return false;
}
flatbuffers::FlatBufferBuilder builder;
builder.Finish(fb::Mesh::Pack(builder, &mesh));
auto output_file_name = std::filesystem::absolute(
std::filesystem::current_path() / switches.output_file_name);
fml::NonOwnedMapping mapping(builder.GetCurrentBufferPointer(),
builder.GetSize());
if (!fml::WriteAtomically(*switches.working_directory,
compiler::Utf8FromPath(output_file_name).c_str(),
mapping)) {
std::cerr << "Could not write file to " << switches.output_file_name
<< std::endl;
return false;
}
// Tools that consume the geometry data expect the access mode to be 0644.
if (!SetPermissiveAccess(output_file_name)) {
return false;
}
return true;
}
} // namespace importer
} // namespace scene
} // namespace impeller
int main(int argc, char const* argv[]) {
return impeller::scene::importer::Main(
fml::CommandLineFromPlatformOrArgcArgv(argc, argv))
? EXIT_SUCCESS
: EXIT_FAILURE;
}

View File

@@ -0,0 +1,37 @@
// 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.
namespace impeller.fb;
struct Vec2 {
x: float;
y: float;
}
struct Vec3 {
x: float;
y: float;
z: float;
}
struct Color {
r: float;
g: float;
b: float;
}
struct Vertex {
position: Vec3;
normal: Vec3;
tangent: Vec3;
texture_coords: Vec2;
}
table Mesh {
vertices: [Vertex];
indices: [uint16];
}
root_type Mesh;
file_identifier "IPME";

View File

@@ -0,0 +1,96 @@
// 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.
#include "impeller/scene/importer/switches.h"
#include <algorithm>
#include <cctype>
#include <filesystem>
#include <map>
#include "flutter/fml/file.h"
#include "impeller/compiler/utilities.h"
#include "impeller/scene/importer/types.h"
namespace impeller {
namespace scene {
namespace importer {
static const std::map<std::string, SourceType> kKnownSourceTypes = {
{"gltf", SourceType::kGLTF},
};
void Switches::PrintHelp(std::ostream& stream) {
stream << std::endl;
stream << "Scene Importer is an offline 3D geometry file parser."
<< std::endl;
stream << "---------------------------------------------------------------"
<< std::endl;
stream << "Valid Argument are:" << std::endl;
stream << "--input=<source_file>" << std::endl;
stream << "[optional] --input-kind={";
for (const auto& source_type : kKnownSourceTypes) {
stream << source_type.first << ", ";
}
stream << "} (default: gltf)" << std::endl;
stream << "--output=<output_file>" << std::endl;
}
Switches::Switches() = default;
Switches::~Switches() = default;
static SourceType SourceTypeFromCommandLine(
const fml::CommandLine& command_line) {
auto source_type_option =
command_line.GetOptionValueWithDefault("input-type", "gltf");
auto source_type_search = kKnownSourceTypes.find(source_type_option);
if (source_type_search == kKnownSourceTypes.end()) {
return SourceType::kUnknown;
}
return source_type_search->second;
}
Switches::Switches(const fml::CommandLine& command_line)
: working_directory(std::make_shared<fml::UniqueFD>(fml::OpenDirectory(
compiler::Utf8FromPath(std::filesystem::current_path()).c_str(),
false, // create if necessary,
fml::FilePermission::kRead))),
source_file_name(command_line.GetOptionValueWithDefault("input", "")),
input_type(SourceTypeFromCommandLine(command_line)),
output_file_name(command_line.GetOptionValueWithDefault("output", "")) {
if (!working_directory || !working_directory->is_valid()) {
return;
}
}
bool Switches::AreValid(std::ostream& explain) const {
bool valid = true;
if (input_type == SourceType::kUnknown) {
explain << "Unknown input type." << std::endl;
valid = false;
}
if (!working_directory || !working_directory->is_valid()) {
explain << "Could not figure out working directory." << std::endl;
valid = false;
}
if (source_file_name.empty()) {
explain << "Input file name was empty." << std::endl;
valid = false;
}
if (output_file_name.empty()) {
explain << "Target output file name was empty." << std::endl;
valid = false;
}
return valid;
}
} // namespace importer
} // namespace scene
} // namespace impeller

View File

@@ -0,0 +1,38 @@
// 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.
#pragma once
#include <iostream>
#include <memory>
#include "flutter/fml/command_line.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/unique_fd.h"
#include "impeller/scene/importer/types.h"
namespace impeller {
namespace scene {
namespace importer {
struct Switches {
std::shared_ptr<fml::UniqueFD> working_directory;
std::string source_file_name;
SourceType input_type;
std::string output_file_name;
Switches();
~Switches();
explicit Switches(const fml::CommandLine& command_line);
bool AreValid(std::ostream& explain) const;
static void PrintHelp(std::ostream& stream);
};
} // namespace importer
} // namespace scene
} // namespace impeller

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.
#pragma once
namespace impeller {
namespace scene {
namespace importer {
enum class SourceType {
kUnknown,
kGLTF,
};
} // namespace importer
} // namespace scene
} // namespace impeller

View File

@@ -24,6 +24,11 @@ declare_args() {
# If it is non-empty, it should be the absolute path to impellerc.
impeller_use_prebuilt_impellerc = ""
# Whether to use a prebuilt scene_importer.
# If this is the empty string, scene_importer will be built.
# If it is non-empty, it should be the absolute path to scene_importer.
impeller_use_prebuilt_scene_importer = ""
# If enabled, all OpenGL calls will be traced. Because additional trace
# overhead may be substantial, this is not enabled by default.
impeller_trace_all_gl_calls = false
@@ -613,3 +618,47 @@ template("impeller_shaders") {
}
}
}
# Dispatches to the build or prebuilt scene_importer depending on the value of
# the impeller_use_prebuilt_scene_importer argument. Forwards all variables to
# compiled_action_foreach or action_foreach as appropriate.
template("_scene_importer") {
if (impeller_use_prebuilt_scene_importer == "") {
compiled_action_foreach(target_name) {
forward_variables_from(invoker, "*")
tool = "//flutter/impeller/scene/importer:scene_importer"
}
} else {
action_foreach(target_name) {
forward_variables_from(invoker, "*", [ "args" ])
script = "//build/gn_run_binary.py"
scene_importer_path =
rebase_path(impeller_use_prebuilt_scene_importer, root_build_dir)
args = [ scene_importer_path ] + invoker.args
}
}
}
template("scene_importer") {
assert(defined(invoker.geometry), "Geometry input files must be specified.")
assert(defined(invoker.type),
"The type of geometry to be parsed (gltf, etc..).")
_scene_importer(target_name) {
sources = invoker.geometry
generated_dir = "$target_gen_dir"
input_type = invoker.type
args = [
"--input={{source}}",
"--input-type=$input_type",
]
output = "$generated_dir/{{source_file_part}}.ipmesh"
output_path = rebase_path(output, root_build_dir)
args += [ "--output=$output_path" ]
outputs = [ output ]
}
}