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

[Impeller] Add support for multi-rendering-backend fat shader archives. #47278

Merged
merged 2 commits into from
Oct 24, 2023
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
10 changes: 10 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -2331,6 +2331,11 @@ ORIGIN: ../../../flutter/impeller/scene/shaders/unlit.frag + ../../../flutter/LI
ORIGIN: ../../../flutter/impeller/scene/shaders/unskinned.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/scene/skin.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/scene/skin.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/shader_archive/multi_arch_shader_archive.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/shader_archive/multi_arch_shader_archive.fbs + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/shader_archive/multi_arch_shader_archive.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/shader_archive/multi_arch_shader_archive_writer.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/shader_archive/multi_arch_shader_archive_writer.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/shader_archive/shader_archive.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/shader_archive/shader_archive.fbs + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/shader_archive/shader_archive.h + ../../../flutter/LICENSE
Expand Down Expand Up @@ -5104,6 +5109,11 @@ FILE: ../../../flutter/impeller/scene/shaders/unlit.frag
FILE: ../../../flutter/impeller/scene/shaders/unskinned.vert
FILE: ../../../flutter/impeller/scene/skin.cc
FILE: ../../../flutter/impeller/scene/skin.h
FILE: ../../../flutter/impeller/shader_archive/multi_arch_shader_archive.cc
FILE: ../../../flutter/impeller/shader_archive/multi_arch_shader_archive.fbs
FILE: ../../../flutter/impeller/shader_archive/multi_arch_shader_archive.h
FILE: ../../../flutter/impeller/shader_archive/multi_arch_shader_archive_writer.cc
FILE: ../../../flutter/impeller/shader_archive/multi_arch_shader_archive_writer.h
FILE: ../../../flutter/impeller/shader_archive/shader_archive.cc
FILE: ../../../flutter/impeller/shader_archive/shader_archive.fbs
FILE: ../../../flutter/impeller/shader_archive/shader_archive.h
Expand Down
10 changes: 6 additions & 4 deletions impeller/renderer/backend/gles/shader_library_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "impeller/base/config.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/gles/shader_function_gles.h"
#include "impeller/shader_archive/multi_arch_shader_archive.h"
#include "impeller/shader_archive/shader_archive.h"

namespace impeller {
Expand Down Expand Up @@ -74,12 +75,13 @@ ShaderLibraryGLES::ShaderLibraryGLES(
return true;
};
for (auto library : shader_libraries) {
auto blob_library = ShaderArchive{std::move(library)};
if (!blob_library.IsValid()) {
VALIDATION_LOG << "Could not construct blob library for shaders.";
auto gles_archive = MultiArchShaderArchive::CreateArchiveFromMapping(
std::move(library), ArchiveRenderingBackend::kOpenGLES);
if (!gles_archive || !gles_archive->IsValid()) {
VALIDATION_LOG << "Could not construct shader library.";
return;
}
blob_library.IterateAllShaders(iterator);
gles_archive->IterateAllShaders(iterator);
}

functions_ = functions;
Expand Down
10 changes: 6 additions & 4 deletions impeller/renderer/backend/vulkan/shader_library_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "flutter/fml/trace_event.h"
#include "impeller/renderer/backend/vulkan/context_vk.h"
#include "impeller/renderer/backend/vulkan/shader_function_vk.h"
#include "impeller/shader_archive/multi_arch_shader_archive.h"
#include "impeller/shader_archive/shader_archive.h"

namespace impeller {
Expand Down Expand Up @@ -69,12 +70,13 @@ ShaderLibraryVK::ShaderLibraryVK(
return true;
};
for (const auto& library_data : shader_libraries_data) {
auto blob_library = ShaderArchive{library_data};
if (!blob_library.IsValid()) {
VALIDATION_LOG << "Could not construct shader blob library.";
auto vulkan_library = MultiArchShaderArchive::CreateArchiveFromMapping(
library_data, ArchiveRenderingBackend::kVulkan);
if (!vulkan_library || !vulkan_library->IsValid()) {
VALIDATION_LOG << "Could not construct Vulkan shader library archive.";
return;
}
blob_library.IterateAllShaders(iterator);
vulkan_library->IterateAllShaders(iterator);
}

if (!success) {
Expand Down
9 changes: 8 additions & 1 deletion impeller/shader_archive/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,20 @@ config("shader_archive_config") {
}

flatbuffers("shader_archive_flatbuffers") {
flatbuffers = [ "shader_archive.fbs" ]
flatbuffers = [
"shader_archive.fbs",
"multi_arch_shader_archive.fbs",
]
public_configs = [ ":shader_archive_config" ]
public_deps = [ "//third_party/flatbuffers" ]
}

impeller_component("shader_archive") {
sources = [
"multi_arch_shader_archive.cc",
"multi_arch_shader_archive.h",
"multi_arch_shader_archive_writer.cc",
"multi_arch_shader_archive_writer.h",
"shader_archive.cc",
"shader_archive.h",
"shader_archive_types.h",
Expand Down
104 changes: 104 additions & 0 deletions impeller/shader_archive/multi_arch_shader_archive.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// 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/multi_arch_shader_archive.h"

#include "impeller/shader_archive/multi_arch_shader_archive_flatbuffers.h"

namespace impeller {

constexpr ArchiveRenderingBackend ToArchiveRenderingBackend(
fb::RenderingBackend backend) {
switch (backend) {
case fb::RenderingBackend::kOpenGLES:
return ArchiveRenderingBackend::kOpenGLES;
case fb::RenderingBackend::kVulkan:
return ArchiveRenderingBackend::kVulkan;
case fb::RenderingBackend::kMetal:
return ArchiveRenderingBackend::kMetal;
}
FML_UNREACHABLE();
}

std::shared_ptr<ShaderArchive> MultiArchShaderArchive::CreateArchiveFromMapping(
const std::shared_ptr<const fml::Mapping>& mapping,
ArchiveRenderingBackend backend) {
{
auto multi_archive = std::make_shared<MultiArchShaderArchive>(mapping);
if (multi_archive->IsValid()) {
return multi_archive->GetShaderArchive(backend);
}
}
{
auto single_archive =
std::shared_ptr<ShaderArchive>(new ShaderArchive(mapping));
if (single_archive->IsValid()) {
return single_archive;
}
}
return nullptr;
}

MultiArchShaderArchive::MultiArchShaderArchive(
const std::shared_ptr<const fml::Mapping>& mapping) {
if (!mapping) {
return;
}

if (!fb::MultiArchShaderArchiveBufferHasIdentifier(mapping->GetMapping())) {
return;
}

const auto* multi_arch = fb::GetMultiArchShaderArchive(mapping->GetMapping());

if (!multi_arch) {
return;
}

if (auto archives = multi_arch->items()) {
for (auto i = archives->begin(), end = archives->end(); i != end; i++) {
// This implementation is unable to handle multiple archives for the same
// backend.
backend_mappings_[ToArchiveRenderingBackend(i->rendering_backend())] =
std::make_shared<fml::NonOwnedMapping>(i->mapping()->Data(),
i->mapping()->size(),
[mapping](auto, auto) {
// Just hold the mapping.
});
}
}

is_valid_ = true;
}

MultiArchShaderArchive::~MultiArchShaderArchive() = default;

bool MultiArchShaderArchive::IsValid() const {
return is_valid_;
}

std::shared_ptr<const fml::Mapping> MultiArchShaderArchive::GetArchive(
ArchiveRenderingBackend backend) const {
auto found = backend_mappings_.find(backend);
if (found == backend_mappings_.end()) {
return nullptr;
}
return found->second;
}

std::shared_ptr<ShaderArchive> MultiArchShaderArchive::GetShaderArchive(
ArchiveRenderingBackend backend) const {
auto archive = GetArchive(backend);
if (!archive) {
return nullptr;
}
auto shader_archive =
std::shared_ptr<ShaderArchive>(new ShaderArchive(std::move(archive)));
if (!shader_archive->IsValid()) {
return nullptr;
}
return shader_archive;
}

} // namespace impeller
25 changes: 25 additions & 0 deletions impeller/shader_archive/multi_arch_shader_archive.fbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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;

enum RenderingBackend:byte {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we include more information here? Right now there are some implicit version constraints in these formats more or less. We could make this explicitly kOpenGLESv100 or add additional version metadata.

You could imagine in the future that we might support targeting higher GLSL versions for desktop or webgl, and the engine will need to know the right version information to consume it. I'm not sure if we'd ever ship multiple GLSL versions of the same shader in the same file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is internal implementation detail. So I suspect we can tinker on this all we want.

In the future, we could even concatenate multiple shader libraries for the same backend instead of loading on of each.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sgtm

kOpenGLES,
kVulkan,
kMetal,
}

table ShaderArchiveBlob {
rendering_backend: RenderingBackend;
mapping: [ubyte];
}

table MultiArchShaderArchive {
// We could have just as easily used the existing `ShaderArchive` table here.
// However, those tables aren't used by Metal.
items: [ShaderArchiveBlob];
}

root_type MultiArchShaderArchive;
file_identifier "MARC";
44 changes: 44 additions & 0 deletions impeller/shader_archive/multi_arch_shader_archive.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 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 <map>
#include <memory>

#include "flutter/fml/macros.h"
#include "flutter/fml/mapping.h"
#include "impeller/shader_archive/shader_archive.h"
#include "impeller/shader_archive/shader_archive_types.h"

namespace impeller {

class MultiArchShaderArchive {
public:
static std::shared_ptr<ShaderArchive> CreateArchiveFromMapping(
const std::shared_ptr<const fml::Mapping>& mapping,
ArchiveRenderingBackend backend);

explicit MultiArchShaderArchive(
const std::shared_ptr<const fml::Mapping>& mapping);

~MultiArchShaderArchive();

std::shared_ptr<const fml::Mapping> GetArchive(
ArchiveRenderingBackend backend) const;

std::shared_ptr<ShaderArchive> GetShaderArchive(
ArchiveRenderingBackend backend) const;

bool IsValid() const;

private:
std::map<ArchiveRenderingBackend, std::shared_ptr<const fml::Mapping>>
backend_mappings_;
bool is_valid_ = false;

FML_DISALLOW_COPY_AND_ASSIGN(MultiArchShaderArchive);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we still doing this in new code? Or should the new style be used?

Copy link
Member Author

@chinmaygarde chinmaygarde Oct 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Patched #47307

};

} // namespace impeller
64 changes: 64 additions & 0 deletions impeller/shader_archive/multi_arch_shader_archive_writer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// 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/multi_arch_shader_archive_writer.h"

#include "impeller/base/validation.h"
#include "impeller/shader_archive/multi_arch_shader_archive_flatbuffers.h"

namespace impeller {

MultiArchShaderArchiveWriter::MultiArchShaderArchiveWriter() = default;

MultiArchShaderArchiveWriter::~MultiArchShaderArchiveWriter() = default;

bool MultiArchShaderArchiveWriter::RegisterShaderArchive(
ArchiveRenderingBackend backend,
std::shared_ptr<const fml::Mapping> mapping) {
if (!mapping || mapping->GetMapping() == nullptr) {
return false;
}
if (archives_.find(backend) != archives_.end()) {
VALIDATION_LOG << "Multi-archive already has a shader library registered "
"for that backend.";
return false;
}
archives_[backend] = std::move(mapping);
return true;
}

constexpr fb::RenderingBackend ToRenderingBackend(
ArchiveRenderingBackend backend) {
switch (backend) {
case ArchiveRenderingBackend::kMetal:
return fb::RenderingBackend::kMetal;
case ArchiveRenderingBackend::kVulkan:
return fb::RenderingBackend::kVulkan;
case ArchiveRenderingBackend::kOpenGLES:
return fb::RenderingBackend::kOpenGLES;
}
FML_UNREACHABLE();
}

std::shared_ptr<fml::Mapping> MultiArchShaderArchiveWriter::CreateMapping()
const {
fb::MultiArchShaderArchiveT multi_archive;
for (const auto& archive : archives_) {
auto archive_blob = std::make_unique<fb::ShaderArchiveBlobT>();
archive_blob->rendering_backend = ToRenderingBackend(archive.first);
archive_blob->mapping = {
archive.second->GetMapping(),
archive.second->GetMapping() + archive.second->GetSize()};
multi_archive.items.emplace_back(std::move(archive_blob));
}
auto builder = std::make_shared<flatbuffers::FlatBufferBuilder>();
builder->Finish(
fb::MultiArchShaderArchive::Pack(*builder.get(), &multi_archive),
fb::MultiArchShaderArchiveIdentifier());
return std::make_shared<fml::NonOwnedMapping>(builder->GetBufferPointer(),
builder->GetSize(),
[builder](auto, auto) {});
}

} // namespace impeller
34 changes: 34 additions & 0 deletions impeller/shader_archive/multi_arch_shader_archive_writer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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 <map>

#include "flutter/fml/macros.h"
#include "flutter/fml/mapping.h"
#include "impeller/shader_archive/shader_archive_types.h"

namespace impeller {

class MultiArchShaderArchiveWriter {
public:
MultiArchShaderArchiveWriter();

~MultiArchShaderArchiveWriter();

[[nodiscard]] bool RegisterShaderArchive(
ArchiveRenderingBackend backend,
std::shared_ptr<const fml::Mapping> mapping);

std::shared_ptr<fml::Mapping> CreateMapping() const;

private:
std::map<ArchiveRenderingBackend, std::shared_ptr<const fml::Mapping>>
archives_;

FML_DISALLOW_COPY_AND_ASSIGN(MultiArchShaderArchiveWriter);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto question.

};

} // namespace impeller
4 changes: 2 additions & 2 deletions impeller/shader_archive/shader_archive.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ constexpr ArchiveShaderType ToShaderType(fb::Stage stage) {
FML_UNREACHABLE();
}

ShaderArchive::ShaderArchive(std::shared_ptr<fml::Mapping> payload)
ShaderArchive::ShaderArchive(std::shared_ptr<const fml::Mapping> payload)
: payload_(std::move(payload)) {
if (!payload_ || payload_->GetMapping() == nullptr) {
VALIDATION_LOG << "Shader mapping was absent.";
return;
}

if (!fb::ShaderArchiveBufferHasIdentifier(payload_->GetMapping())) {
VALIDATION_LOG << "Invalid shader magic.";
VALIDATION_LOG << "Invalid shader archive magic.";
return;
}

Expand Down
Loading