blob: 83c0459f34ebe05a40939ebdb614b7349447ca07 [file] [log] [blame]
// 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/shader_archive/shader_archive_writer.h"
#include <array>
#include <filesystem>
#include <optional>
#include "impeller/shader_archive/shader_archive_flatbuffers.h"
namespace impeller {
ShaderArchiveWriter::ShaderArchiveWriter() = default;
ShaderArchiveWriter::~ShaderArchiveWriter() = default;
std::optional<ArchiveShaderType> InferShaderTypefromFileExtension(
const std::filesystem::path& path) {
if (path == ".vert") {
return ArchiveShaderType::kVertex;
} else if (path == ".frag") {
return ArchiveShaderType::kFragment;
} else if (path == ".comp") {
return ArchiveShaderType::kCompute;
}
return std::nullopt;
}
bool ShaderArchiveWriter::AddShaderAtPath(const std::string& std_path) {
std::filesystem::path path(std_path);
if (path.stem().empty()) {
FML_LOG(ERROR) << "File path stem was empty for " << path;
return false;
}
if (path.extension() != ".gles" && path.extension() != ".vkspv") {
FML_LOG(ERROR) << "File path doesn't have a known shader extension "
<< path;
return false;
}
// Get rid of .gles
path = path.replace_extension();
auto shader_type = InferShaderTypefromFileExtension(path.extension());
if (!shader_type.has_value()) {
FML_LOG(ERROR) << "Could not infer shader type from file extension: "
<< path.extension().string();
return false;
}
// Get rid of the shader type extension (.vert, .frag, etc..).
path = path.replace_extension();
const auto shader_name = path.stem().string();
if (shader_name.empty()) {
FML_LOG(ERROR) << "Shader name was empty.";
return false;
}
auto file_mapping = fml::FileMapping::CreateReadOnly(std_path);
if (!file_mapping) {
FML_LOG(ERROR) << "File doesn't exist at path: " << path;
return false;
}
return AddShader(shader_type.value(), shader_name, std::move(file_mapping));
}
bool ShaderArchiveWriter::AddShader(ArchiveShaderType type,
std::string name,
std::shared_ptr<fml::Mapping> mapping) {
if (name.empty() || !mapping || mapping->GetMapping() == nullptr) {
return false;
}
shader_descriptions_.emplace_back(
ShaderDescription{type, std::move(name), std::move(mapping)});
return true;
}
constexpr fb::Stage ToStage(ArchiveShaderType type) {
switch (type) {
case ArchiveShaderType::kVertex:
return fb::Stage::kVertex;
case ArchiveShaderType::kFragment:
return fb::Stage::kFragment;
case ArchiveShaderType::kCompute:
return fb::Stage::kCompute;
}
FML_UNREACHABLE();
}
std::shared_ptr<fml::Mapping> ShaderArchiveWriter::CreateMapping() const {
fb::ShaderArchiveT shader_archive;
for (const auto& shader_description : shader_descriptions_) {
auto mapping = shader_description.mapping;
if (!mapping) {
return nullptr;
}
auto desc = std::make_unique<fb::ShaderBlobT>();
desc->name = shader_description.name;
desc->stage = ToStage(shader_description.type);
desc->mapping = {mapping->GetMapping(),
mapping->GetMapping() + mapping->GetSize()};
shader_archive.items.emplace_back(std::move(desc));
}
auto builder = std::make_shared<flatbuffers::FlatBufferBuilder>();
builder->Finish(fb::ShaderArchive::Pack(*builder.get(), &shader_archive),
fb::ShaderArchiveIdentifier());
return std::make_shared<fml::NonOwnedMapping>(builder->GetBufferPointer(),
builder->GetSize(),
[builder](auto, auto) {});
}
} // namespace impeller