Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
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
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,8 @@ FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc
FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.h
FILE: ../../../flutter/impeller/entity/contents/rrect_shadow_contents.cc
FILE: ../../../flutter/impeller/entity/contents/rrect_shadow_contents.h
FILE: ../../../flutter/impeller/entity/contents/runtime_effect_contents.cc
FILE: ../../../flutter/impeller/entity/contents/runtime_effect_contents.h
FILE: ../../../flutter/impeller/entity/contents/solid_color_contents.cc
FILE: ../../../flutter/impeller/entity/contents/solid_color_contents.h
FILE: ../../../flutter/impeller/entity/contents/solid_stroke_contents.cc
Expand Down Expand Up @@ -1280,6 +1282,7 @@ FILE: ../../../flutter/impeller/entity/shaders/morphology_filter.frag
FILE: ../../../flutter/impeller/entity/shaders/morphology_filter.vert
FILE: ../../../flutter/impeller/entity/shaders/position.vert
FILE: ../../../flutter/impeller/entity/shaders/position_color.vert
FILE: ../../../flutter/impeller/entity/shaders/position_no_color.vert
FILE: ../../../flutter/impeller/entity/shaders/position_uv.vert
FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.frag
Expand Down Expand Up @@ -1555,6 +1558,7 @@ FILE: ../../../flutter/impeller/runtime_stage/runtime_stage.h
FILE: ../../../flutter/impeller/runtime_stage/runtime_stage_playground.cc
FILE: ../../../flutter/impeller/runtime_stage/runtime_stage_playground.h
FILE: ../../../flutter/impeller/runtime_stage/runtime_stage_unittests.cc
FILE: ../../../flutter/impeller/runtime_stage/runtime_types.cc
FILE: ../../../flutter/impeller/runtime_stage/runtime_types.h
FILE: ../../../flutter/impeller/tessellator/c/tessellator.cc
FILE: ../../../flutter/impeller/tessellator/c/tessellator.h
Expand Down
26 changes: 25 additions & 1 deletion impeller/display_list/display_list_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
#include "impeller/display_list/display_list_dispatcher.h"

#include <algorithm>
#include <cstring>
#include <memory>
#include <optional>
#include <unordered_map>

#include "display_list/display_list_blend_mode.h"
#include "display_list/display_list_color_filter.h"
#include "display_list/display_list_color_source.h"
#include "display_list/display_list_path_effect.h"
#include "display_list/display_list_tile_mode.h"
#include "flutter/fml/logging.h"
Expand All @@ -21,6 +24,7 @@
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/contents/linear_gradient_contents.h"
#include "impeller/entity/contents/radial_gradient_contents.h"
#include "impeller/entity/contents/runtime_effect_contents.h"
#include "impeller/entity/contents/solid_stroke_contents.h"
#include "impeller/entity/contents/sweep_gradient_contents.h"
#include "impeller/entity/contents/tiled_texture_contents.h"
Expand Down Expand Up @@ -425,8 +429,28 @@ void DisplayListDispatcher::setColorSource(
};
return;
}
case flutter::DlColorSourceType::kRuntimeEffect: {
const flutter::DlRuntimeEffectColorSource* runtime_effect_color_source =
source->asRuntimeEffect();
auto runtime_stage =
runtime_effect_color_source->runtime_effect()->runtime_stage();
auto uniform_data_sk = runtime_effect_color_source->uniform_data();

paint_.color_source = [runtime_stage, uniform_data_sk]() {
// TODO(113714): Get rid of the allocation + copy for uniform data.
std::vector<uint8_t> uniform_data;
uniform_data.resize(uniform_data_sk->size());
memcpy(uniform_data.data(), uniform_data_sk->bytes(),
uniform_data.size());

auto contents = std::make_shared<RuntimeEffectContents>();
contents->SetRuntimeStage(runtime_stage);
contents->SetUniformData(std::move(uniform_data));
return contents;
};
return;
}
case flutter::DlColorSourceType::kConicalGradient:
case flutter::DlColorSourceType::kRuntimeEffect:
case flutter::DlColorSourceType::kUnknown:
UNIMPLEMENTED;
break;
Expand Down
9 changes: 6 additions & 3 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ impeller_shaders("entity_shaders") {
"shaders/linear_gradient_fill.frag",
"shaders/morphology_filter.frag",
"shaders/morphology_filter.vert",
"shaders/position_color.vert",
"shaders/position_no_color.vert",
"shaders/position_uv.vert",
"shaders/position.vert",
"shaders/radial_gradient_fill.frag",
"shaders/rrect_blur.vert",
"shaders/rrect_blur.frag",
Expand All @@ -57,9 +61,6 @@ impeller_shaders("entity_shaders") {
"shaders/tiled_texture_fill.frag",
"shaders/tiled_texture_fill.vert",
"shaders/vertices.frag",
"shaders/position_color.vert",
"shaders/position.vert",
"shaders/position_uv.vert",
]
}

Expand Down Expand Up @@ -113,6 +114,8 @@ impeller_component("entity") {
"contents/radial_gradient_contents.h",
"contents/rrect_shadow_contents.cc",
"contents/rrect_shadow_contents.h",
"contents/runtime_effect_contents.cc",
"contents/runtime_effect_contents.h",
"contents/solid_color_contents.cc",
"contents/solid_color_contents.h",
"contents/solid_stroke_contents.cc",
Expand Down
166 changes: 166 additions & 0 deletions impeller/entity/contents/runtime_effect_contents.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// 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/entity/contents/runtime_effect_contents.h"

#include <future>
#include <memory>

#include "flutter/fml/logging.h"
#include "flutter/fml/make_copyable.h"
#include "impeller/base/validation.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/position_no_color.vert.h"
#include "impeller/renderer/formats.h"
#include "impeller/renderer/pipeline_library.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/shader_function.h"
#include "impeller/renderer/shader_types.h"

namespace impeller {

void RuntimeEffectContents::SetRuntimeStage(
std::shared_ptr<RuntimeStage> runtime_stage) {
runtime_stage_ = std::move(runtime_stage);
}

void RuntimeEffectContents::SetUniformData(std::vector<uint8_t> uniform_data) {
uniform_data_ = std::move(uniform_data);
}

bool RuntimeEffectContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
auto context = renderer.GetContext();
auto library = context->GetShaderLibrary();

//--------------------------------------------------------------------------
/// Get or register shader.
///

// TODO(113719): Register the shader function earlier.

std::shared_ptr<const ShaderFunction> function = library->GetFunction(
runtime_stage_->GetEntrypoint(), ShaderStage::kFragment);

if (!function) {
std::promise<bool> promise;
auto future = promise.get_future();

library->RegisterFunction(
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 be doing this immediately after reading the shader in from the asset?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, but I'd like to defer figuring out the threading and g3 dependency situation to a later patch. I assume we're already building all of Impeller though, so maybe g3 isn't as much a concern.
Added an issue: flutter/flutter#113719

runtime_stage_->GetEntrypoint(),
ToShaderStage(runtime_stage_->GetShaderStage()),
runtime_stage_->GetCodeMapping(),
fml::MakeCopyable([promise = std::move(promise)](bool result) mutable {
promise.set_value(result);
}));

if (!future.get()) {
VALIDATION_LOG << "Failed to build runtime effect (entry point: "
<< runtime_stage_->GetEntrypoint() << ")";
return false;
}

function = library->GetFunction(runtime_stage_->GetEntrypoint(),
ShaderStage::kFragment);
if (!function) {
VALIDATION_LOG
<< "Failed to fetch runtime effect function immediately after "
"registering it (entry point: "
<< runtime_stage_->GetEntrypoint() << ")";
return false;
}
}

//--------------------------------------------------------------------------
/// Resolve geometry.
///

auto geometry_result = GetGeometry()->GetPositionBuffer(
context->GetResourceAllocator(), pass.GetTransientsBuffer(),
renderer.GetTessellator(), pass.GetRenderTargetSize());

//--------------------------------------------------------------------------
/// Get or create runtime stage pipeline.
///

using VS = PositionNoColorVertexShader;
PipelineDescriptor desc;
desc.SetLabel("Runtime Stage");
desc.AddStageEntrypoint(
library->GetFunction(VS::kEntrypointName, ShaderStage::kVertex));
desc.AddStageEntrypoint(library->GetFunction(runtime_stage_->GetEntrypoint(),
ShaderStage::kFragment));
auto vertex_descriptor = std::make_shared<VertexDescriptor>();
if (!vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs)) {
VALIDATION_LOG << "Failed to set stage inputs for runtime effect pipeline.";
}
desc.SetVertexDescriptor(std::move(vertex_descriptor));
desc.SetColorAttachmentDescriptor(0u, {.format = PixelFormat::kDefaultColor});
desc.SetStencilAttachmentDescriptors({});
desc.SetStencilPixelFormat(PixelFormat::kDefaultStencil);

auto options = OptionsFromPassAndEntity(pass, entity);
if (geometry_result.prevent_overdraw) {
options.stencil_compare = CompareFunction::kEqual;
options.stencil_operation = StencilOperation::kIncrementClamp;
}
options.ApplyToPipelineDescriptor(desc);

auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).get();
if (!pipeline) {
VALIDATION_LOG << "Failed to get or create runtime effect pipeline.";
return false;
}

Command cmd;
cmd.label = "RuntimeEffectContents";
cmd.pipeline = pipeline;
cmd.stencil_reference = entity.GetStencilDepth();
cmd.BindVertices(geometry_result.vertex_buffer);
cmd.primitive_type = geometry_result.type;

//--------------------------------------------------------------------------
/// Vertex stage uniforms.
///

VS::VertInfo frame_info;
frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation();
VS::BindVertInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info));

//--------------------------------------------------------------------------
/// Fragment stage uniforms.
///

size_t buffer_index = 0;
for (auto uniform : runtime_stage_->GetUniforms()) {
// TODO(113715): Populate this metadata once GLES is able to handle
// non-struct uniform names.
ShaderMetadata metadata;

size_t alignment =
std::max(uniform.bit_width / 8, DefaultUniformAlignment());
auto buffer_view = pass.GetTransientsBuffer().Emplace(
&uniform_data_[uniform.location * sizeof(float)], uniform.GetSize(),
alignment);

ShaderUniformSlot slot;
slot.name = uniform.name.c_str();
slot.ext_res_0 = buffer_index;
cmd.BindResource(ShaderStage::kFragment, slot, metadata, buffer_view);

buffer_index++;
}

pass.AddCommand(std::move(cmd));

if (geometry_result.prevent_overdraw) {
return ClipRestoreContents().Render(renderer, entity, pass);
}
return true;
}

} // namespace impeller
29 changes: 29 additions & 0 deletions impeller/entity/contents/runtime_effect_contents.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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 <functional>
#include <memory>

#include "impeller/entity/contents/color_source_contents.h"
#include "impeller/runtime_stage/runtime_stage.h"

namespace impeller {

class RuntimeEffectContents final : public ColorSourceContents {
public:
void SetRuntimeStage(std::shared_ptr<RuntimeStage> runtime_stage);

void SetUniformData(std::vector<uint8_t> uniform_data);

// |Contents|
bool Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;

private:
std::shared_ptr<RuntimeStage> runtime_stage_;
std::vector<uint8_t> uniform_data_;
};

} // namespace impeller
37 changes: 37 additions & 0 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
// found in the LICENSE file.

#include <algorithm>
#include <cstring>
#include <memory>
#include <optional>
#include <unordered_map>
#include <vector>

#include "flutter/testing/testing.h"
#include "fml/logging.h"
#include "fml/time/time_point.h"
#include "gtest/gtest.h"
#include "impeller/entity/contents/atlas_contents.h"
#include "impeller/entity/contents/clip_contents.h"
Expand All @@ -19,6 +21,7 @@
#include "impeller/entity/contents/filters/filter_contents.h"
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/contents/rrect_shadow_contents.h"
#include "impeller/entity/contents/runtime_effect_contents.h"
#include "impeller/entity/contents/solid_color_contents.h"
#include "impeller/entity/contents/solid_stroke_contents.h"
#include "impeller/entity/contents/text_contents.h"
Expand All @@ -37,6 +40,7 @@
#include "impeller/playground/widgets.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/vertex_buffer_builder.h"
#include "impeller/runtime_stage/runtime_stage.h"
#include "impeller/tessellator/tessellator.h"
#include "impeller/typographer/backends/skia/text_frame_skia.h"
#include "impeller/typographer/backends/skia/text_render_context_skia.h"
Expand Down Expand Up @@ -2026,5 +2030,38 @@ TEST_P(EntityTest, SdfText) {
ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_P(EntityTest, RuntimeEffect) {
if (GetParam() != PlaygroundBackend::kMetal) {
GTEST_SKIP_("This test only has a Metal fixture at the moment.");
}

auto callback = [&](ContentContext& context, RenderPass& pass) -> bool {
auto contents = std::make_shared<RuntimeEffectContents>();
contents->SetGeometry(Geometry::MakeCover());

auto runtime_stage =
LoadFixtureRuntimeStage("runtime_stage_example.frag.iplr");
contents->SetRuntimeStage(runtime_stage);

struct FragUniforms {
Scalar iTime;
Vector2 iResolution;
} frag_uniforms = {
.iTime = static_cast<Scalar>(
fml::TimePoint::Now().ToEpochDelta().ToSecondsF()),
.iResolution = Vector2(GetWindowSize().width, GetWindowSize().height),
};
std::vector<uint8_t> uniform_data;
uniform_data.resize(sizeof(FragUniforms));
memcpy(uniform_data.data(), &frag_uniforms, sizeof(FragUniforms));
contents->SetUniformData(uniform_data);

Entity entity;
entity.SetContents(contents);
return contents->Render(context, entity, pass);
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}

} // namespace testing
} // namespace impeller
17 changes: 17 additions & 0 deletions impeller/entity/shaders/position_no_color.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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/transform.glsl>

uniform VertInfo {
mat4 mvp;
} vert_info;

in vec2 position;
out vec2 v_position;

void main() {
gl_Position = vert_info.mvp * vec4(position, 0.0, 1.0);
v_position = IPVec2TransformPosition(vert_info.mvp, position);
}
Loading