Skip to content

Commit f8f7455

Browse files
authored
[Impeller] libImpeller: Allow user supplied fragment programs to shade pixels. (#170616)
Fixes flutter/flutter#170008
1 parent 90e5f43 commit f8f7455

17 files changed

Lines changed: 627 additions & 3 deletions

engine/src/flutter/ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52349,6 +52349,8 @@ ORIGIN: ../../../flutter/impeller/toolkit/interop/example_mtl.m + ../../../flutt
5234952349
ORIGIN: ../../../flutter/impeller/toolkit/interop/example_vk.c + ../../../flutter/LICENSE
5235052350
ORIGIN: ../../../flutter/impeller/toolkit/interop/formats.cc + ../../../flutter/LICENSE
5235152351
ORIGIN: ../../../flutter/impeller/toolkit/interop/formats.h + ../../../flutter/LICENSE
52352+
ORIGIN: ../../../flutter/impeller/toolkit/interop/fragment_program.cc + ../../../flutter/LICENSE
52353+
ORIGIN: ../../../flutter/impeller/toolkit/interop/fragment_program.h + ../../../flutter/LICENSE
5235252354
ORIGIN: ../../../flutter/impeller/toolkit/interop/glyph_info.cc + ../../../flutter/LICENSE
5235352355
ORIGIN: ../../../flutter/impeller/toolkit/interop/glyph_info.h + ../../../flutter/LICENSE
5235452356
ORIGIN: ../../../flutter/impeller/toolkit/interop/image_filter.cc + ../../../flutter/LICENSE
@@ -55405,6 +55407,8 @@ FILE: ../../../flutter/impeller/toolkit/interop/example_mtl.m
5540555407
FILE: ../../../flutter/impeller/toolkit/interop/example_vk.c
5540655408
FILE: ../../../flutter/impeller/toolkit/interop/formats.cc
5540755409
FILE: ../../../flutter/impeller/toolkit/interop/formats.h
55410+
FILE: ../../../flutter/impeller/toolkit/interop/fragment_program.cc
55411+
FILE: ../../../flutter/impeller/toolkit/interop/fragment_program.h
5540855412
FILE: ../../../flutter/impeller/toolkit/interop/glyph_info.cc
5540955413
FILE: ../../../flutter/impeller/toolkit/interop/glyph_info.h
5541055414
FILE: ../../../flutter/impeller/toolkit/interop/image_filter.cc

engine/src/flutter/impeller/fixtures/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ impellerc("runtime_stages") {
8888
"ink_sparkle.frag",
8989
"runtime_stage_example.frag",
9090
"runtime_stage_filter_example.frag",
91+
"interop_runtime_stage_cs.frag",
9192
"runtime_stage_simple.frag",
9293
"runtime_stage_position.frag",
9394
"gradient.frag",
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
#include <flutter/runtime_effect.glsl>
6+
7+
uniform vec2 uSize;
8+
uniform sampler2D uTexture;
9+
10+
out vec4 fragColor;
11+
12+
void main() {
13+
fragColor = texture(uTexture, FlutterFragCoord().xy / uSize);
14+
}

engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,10 @@ static bool LinkProgram(
167167

168168
if (link_status != GL_TRUE) {
169169
VALIDATION_LOG << "Could not link shader program: "
170-
<< gl.GetProgramInfoLogString(*program);
170+
<< gl.GetProgramInfoLogString(*program)
171+
<< "\nVertex Shader:\n"
172+
<< GetShaderSource(gl, vert_shader) << "\nFragment Shader:\n"
173+
<< GetShaderSource(gl, frag_shader);
171174
return false;
172175
}
173176
return true;

engine/src/flutter/impeller/toolkit/interop/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ impeller_component("interop_base") {
4141
"dl_builder.h",
4242
"formats.cc",
4343
"formats.h",
44+
"fragment_program.cc",
45+
"fragment_program.h",
4446
"glyph_info.cc",
4547
"glyph_info.h",
4648
"image_filter.cc",

engine/src/flutter/impeller/toolkit/interop/color_source.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,36 @@ ScopedObject<ColorSource> ColorSource::MakeImage(
111111
return Create<ColorSource>(std::move(dl_filter));
112112
}
113113

114+
ScopedObject<ColorSource> ColorSource::MakeFragmentProgram(
115+
const Context& context,
116+
const FragmentProgram& program,
117+
std::vector<std::shared_ptr<flutter::DlColorSource>> samplers,
118+
std::shared_ptr<std::vector<uint8_t>> uniform_data) {
119+
auto runtime_stage =
120+
program.FindRuntimeStage(context.GetContext()->GetRuntimeStageBackend());
121+
if (!runtime_stage) {
122+
VALIDATION_LOG << "Could not find runtime stage for backend.";
123+
return nullptr;
124+
}
125+
auto runtime_effect =
126+
flutter::DlRuntimeEffect::MakeImpeller(std::move(runtime_stage));
127+
if (!runtime_effect) {
128+
VALIDATION_LOG << "Could not make runtime effect.";
129+
return nullptr;
130+
}
131+
132+
auto dl_filter =
133+
flutter::DlColorSource::MakeRuntimeEffect(std::move(runtime_effect), //
134+
std::move(samplers), //
135+
std::move(uniform_data) //
136+
);
137+
if (!dl_filter) {
138+
VALIDATION_LOG << "Could not create runtime effect color source.";
139+
return nullptr;
140+
}
141+
return Create<ColorSource>(std::move(dl_filter));
142+
}
143+
114144
ColorSource::ColorSource(std::shared_ptr<flutter::DlColorSource> source)
115145
: color_source_(std::move(source)) {}
116146

engine/src/flutter/impeller/toolkit/interop/color_source.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "impeller/geometry/matrix.h"
1313
#include "impeller/geometry/point.h"
1414
#include "impeller/toolkit/interop/formats.h"
15+
#include "impeller/toolkit/interop/fragment_program.h"
1516
#include "impeller/toolkit/interop/impeller.h"
1617
#include "impeller/toolkit/interop/object.h"
1718
#include "impeller/toolkit/interop/texture.h"
@@ -64,6 +65,12 @@ class ColorSource final
6465
flutter::DlImageSampling sampling,
6566
const Matrix& transformation);
6667

68+
static ScopedObject<ColorSource> MakeFragmentProgram(
69+
const Context& context,
70+
const FragmentProgram& program,
71+
std::vector<std::shared_ptr<flutter::DlColorSource>> samplers,
72+
std::shared_ptr<std::vector<uint8_t>> uniform_data);
73+
6774
explicit ColorSource(std::shared_ptr<flutter::DlColorSource> source);
6875

6976
~ColorSource() override;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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+
#include "impeller/toolkit/interop/fragment_program.h"
6+
7+
#include "impeller/base/validation.h"
8+
9+
namespace impeller::interop {
10+
11+
FragmentProgram::FragmentProgram(const std::shared_ptr<fml::Mapping>& data) {
12+
if (data == nullptr || data->GetSize() == 0) {
13+
VALIDATION_LOG << "No data provided to create fragment program.";
14+
return;
15+
}
16+
17+
auto stages = RuntimeStage::DecodeRuntimeStages(data);
18+
19+
for (const auto& stage : stages) {
20+
if (auto data = stage.second) {
21+
stages_[stage.first] = std::move(data);
22+
}
23+
}
24+
25+
if (stages_.empty()) {
26+
VALIDATION_LOG << "No valid runtime stages present in fragment program.";
27+
return;
28+
}
29+
30+
is_valid_ = true;
31+
}
32+
33+
FragmentProgram::~FragmentProgram() = default;
34+
35+
bool FragmentProgram::IsValid() const {
36+
return is_valid_;
37+
}
38+
39+
static std::string AvailableStagesAsString(
40+
const std::set<RuntimeStageBackend>& stages) {
41+
std::stringstream stream;
42+
size_t count = 0;
43+
for (const auto& stage : stages) {
44+
stream << RuntimeStageBackendToString(stage);
45+
count++;
46+
if (count != stages.size()) {
47+
stream << ", ";
48+
}
49+
}
50+
return stream.str();
51+
}
52+
53+
std::shared_ptr<RuntimeStage> FragmentProgram::FindRuntimeStage(
54+
RuntimeStageBackend backend) const {
55+
if (backend == RuntimeStageBackend::kOpenGLES3) {
56+
return FindRuntimeStage(RuntimeStageBackend::kOpenGLES);
57+
}
58+
auto found = stages_.find(backend);
59+
if (found == stages_.end()) {
60+
VALIDATION_LOG << "Could not find runtime shader for backend: "
61+
<< RuntimeStageBackendToString(backend)
62+
<< ". Shaders were packaged for "
63+
<< AvailableStagesAsString(GetAvailableStages())
64+
<< ". Check your shader compiler options.";
65+
return nullptr;
66+
}
67+
return found->second;
68+
}
69+
70+
const char* RuntimeStageBackendToString(RuntimeStageBackend backend) {
71+
switch (backend) {
72+
case RuntimeStageBackend::kSkSL:
73+
return "SKSL";
74+
case RuntimeStageBackend::kMetal:
75+
return "Metal";
76+
case RuntimeStageBackend::kOpenGLES:
77+
return "OpenGL ES2";
78+
case RuntimeStageBackend::kOpenGLES3:
79+
return "OpenGL ES3";
80+
case RuntimeStageBackend::kVulkan:
81+
return "Vulkan";
82+
}
83+
return "Unknown";
84+
}
85+
86+
std::set<RuntimeStageBackend> FragmentProgram::GetAvailableStages() const {
87+
std::set<RuntimeStageBackend> stages;
88+
for (const auto& stage : stages_) {
89+
stages.insert(stage.first);
90+
}
91+
return stages;
92+
}
93+
94+
} // namespace impeller::interop
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
#ifndef FLUTTER_IMPELLER_TOOLKIT_INTEROP_FRAGMENT_PROGRAM_H_
6+
#define FLUTTER_IMPELLER_TOOLKIT_INTEROP_FRAGMENT_PROGRAM_H_
7+
8+
#include "flutter/fml/mapping.h"
9+
#include "impeller/runtime_stage/runtime_stage.h"
10+
#include "impeller/toolkit/interop/impeller.h"
11+
#include "impeller/toolkit/interop/object.h"
12+
13+
namespace impeller::interop {
14+
15+
class FragmentProgram final
16+
: public Object<FragmentProgram,
17+
IMPELLER_INTERNAL_HANDLE_NAME(ImpellerFragmentProgram)> {
18+
public:
19+
explicit FragmentProgram(const std::shared_ptr<fml::Mapping>& mapping);
20+
21+
~FragmentProgram();
22+
23+
FragmentProgram(const FragmentProgram&) = delete;
24+
25+
FragmentProgram& operator=(const FragmentProgram&) = delete;
26+
27+
bool IsValid() const;
28+
29+
std::shared_ptr<RuntimeStage> FindRuntimeStage(
30+
RuntimeStageBackend backend) const;
31+
32+
private:
33+
RuntimeStage::Map stages_;
34+
bool is_valid_ = false;
35+
36+
std::set<RuntimeStageBackend> GetAvailableStages() const;
37+
};
38+
39+
const char* RuntimeStageBackendToString(RuntimeStageBackend backend);
40+
41+
} // namespace impeller::interop
42+
43+
#endif // FLUTTER_IMPELLER_TOOLKIT_INTEROP_FRAGMENT_PROGRAM_H_

engine/src/flutter/impeller/toolkit/interop/image_filter.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include "impeller/toolkit/interop/image_filter.h"
66

77
#include "flutter/display_list/effects/dl_image_filters.h"
8+
#include "flutter/display_list/effects/dl_runtime_effect.h"
9+
#include "impeller/base/validation.h"
810

911
namespace impeller::interop {
1012

@@ -51,6 +53,35 @@ ScopedObject<ImageFilter> ImageFilter::MakeMatrix(
5153
return Create<ImageFilter>(std::move(filter));
5254
}
5355

56+
ScopedObject<ImageFilter> ImageFilter::MakeFragmentProgram(
57+
const Context& context,
58+
const FragmentProgram& program,
59+
std::vector<std::shared_ptr<flutter::DlColorSource>> samplers,
60+
std::shared_ptr<std::vector<uint8_t>> uniform_data) {
61+
auto runtime_stage =
62+
program.FindRuntimeStage(context.GetContext()->GetRuntimeStageBackend());
63+
if (!runtime_stage) {
64+
VALIDATION_LOG << "Could not find runtime stage for backend.";
65+
return nullptr;
66+
}
67+
auto runtime_effect =
68+
flutter::DlRuntimeEffect::MakeImpeller(std::move(runtime_stage));
69+
if (!runtime_effect) {
70+
VALIDATION_LOG << "Could not make runtime effect.";
71+
return nullptr;
72+
}
73+
auto filter =
74+
flutter::DlRuntimeEffectImageFilter::Make(std::move(runtime_effect), //
75+
std::move(samplers), //
76+
std::move(uniform_data) //
77+
);
78+
if (!filter) {
79+
VALIDATION_LOG << "Could not create runtime effect image filter.";
80+
return nullptr;
81+
}
82+
return Create<ImageFilter>(std::move(filter));
83+
}
84+
5485
ScopedObject<ImageFilter> ImageFilter::MakeCompose(const ImageFilter& outer,
5586
const ImageFilter& inner) {
5687
auto filter = flutter::DlComposeImageFilter::Make(outer.GetImageFilter(),

0 commit comments

Comments
 (0)