diff --git a/impeller/compiler/reflector.cc b/impeller/compiler/reflector.cc index 1fd6ba2e0d204..e60613e0c5b26 100644 --- a/impeller/compiler/reflector.cc +++ b/impeller/compiler/reflector.cc @@ -348,6 +348,8 @@ std::shared_ptr Reflector::GenerateRuntimeStageData() uniform_description.name = compiler_->get_name(var.self); uniform_description.location = compiler_->get_decoration( var.self, spv::Decoration::DecorationLocation); + uniform_description.binding = + compiler_->get_decoration(var.self, spv::Decoration::DecorationBinding); uniform_description.type = spir_type.basetype; uniform_description.rows = spir_type.vecsize; uniform_description.columns = spir_type.columns; @@ -410,6 +412,7 @@ std::shared_ptr Reflector::GenerateRuntimeStageData() .name = ubo.name, .location = 64, // Magic constant that must match the descriptor set // location for fragment programs. + .binding = 64, .type = spirv_cross::SPIRType::Struct, .struct_layout = std::move(struct_layout), .struct_float_count = float_count, diff --git a/impeller/compiler/types.h b/impeller/compiler/types.h index c41423014071f..ccea85ecbad43 100644 --- a/impeller/compiler/types.h +++ b/impeller/compiler/types.h @@ -48,6 +48,7 @@ enum class SourceLanguage { struct UniformDescription { std::string name; size_t location = 0u; + size_t binding = 0u; spirv_cross::SPIRType::BaseType type = spirv_cross::SPIRType::BaseType::Float; size_t rows = 0u; size_t columns = 0u; diff --git a/impeller/core/runtime_types.h b/impeller/core/runtime_types.h index 48a8744e0e654..b38d61b0eb87a 100644 --- a/impeller/core/runtime_types.h +++ b/impeller/core/runtime_types.h @@ -39,6 +39,8 @@ struct RuntimeUniformDimensions { struct RuntimeUniformDescription { std::string name; size_t location = 0u; + /// Location, but for Vulkan. + size_t binding = 0u; RuntimeUniformType type = RuntimeUniformType::kFloat; RuntimeUniformDimensions dimensions = {}; size_t bit_width = 0u; diff --git a/impeller/entity/contents/runtime_effect_contents.cc b/impeller/entity/contents/runtime_effect_contents.cc index 423cbdcb95637..9077bf6ce4ffd 100644 --- a/impeller/entity/contents/runtime_effect_contents.cc +++ b/impeller/entity/contents/runtime_effect_contents.cc @@ -4,6 +4,7 @@ #include "impeller/entity/contents/runtime_effect_contents.h" +#include #include #include @@ -19,6 +20,7 @@ #include "impeller/renderer/pipeline_library.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/shader_function.h" +#include "impeller/renderer/vertex_descriptor.h" namespace impeller { @@ -65,18 +67,22 @@ static std::shared_ptr MakeShaderMetadata( return metadata; } -bool RuntimeEffectContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { +bool RuntimeEffectContents::BootstrapShader( + const ContentContext& renderer) const { + if (!RegisterShader(renderer)) { + return false; + } + ContentContextOptions options; + options.color_attachment_pixel_format = + renderer.GetContext()->GetCapabilities()->GetDefaultColorFormat(); + return !!CreatePipeline(renderer, options); +} + +bool RuntimeEffectContents::RegisterShader( + const ContentContext& renderer) const { const std::shared_ptr& context = renderer.GetContext(); const std::shared_ptr& library = context->GetShaderLibrary(); - //-------------------------------------------------------------------------- - /// Get or register shader. - /// - - // TODO(113719): Register the shader function earlier. - std::shared_ptr function = library->GetFunction( runtime_stage_->GetEntrypoint(), ShaderStage::kFragment); @@ -123,29 +129,75 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, runtime_stage_->SetClean(); } + return true; +} - //-------------------------------------------------------------------------- - /// Set up the command. Defer setting up the pipeline until the descriptor set - /// layouts are known from the uniforms. - /// - +std::shared_ptr> +RuntimeEffectContents::CreatePipeline(const ContentContext& renderer, + ContentContextOptions options) const { + const std::shared_ptr& context = renderer.GetContext(); + const std::shared_ptr& library = context->GetShaderLibrary(); const std::shared_ptr& caps = context->GetCapabilities(); const auto color_attachment_format = caps->GetDefaultColorFormat(); const auto stencil_attachment_format = caps->GetDefaultDepthStencilFormat(); using VS = RuntimeEffectVertexShader; - //-------------------------------------------------------------------------- - /// Fragment stage uniforms. - /// + PipelineDescriptor desc; + desc.SetLabel("Runtime Stage"); + desc.AddStageEntrypoint( + library->GetFunction(VS::kEntrypointName, ShaderStage::kVertex)); + desc.AddStageEntrypoint(library->GetFunction(runtime_stage_->GetEntrypoint(), + ShaderStage::kFragment)); + + std::shared_ptr vertex_descriptor = + std::make_shared(); + vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs, + VS::kInterleavedBufferLayout); + vertex_descriptor->RegisterDescriptorSetLayouts(VS::kDescriptorSetLayouts); + vertex_descriptor->RegisterDescriptorSetLayouts( + runtime_stage_->GetDescriptorSetLayouts().data(), + runtime_stage_->GetDescriptorSetLayouts().size()); + desc.SetVertexDescriptor(std::move(vertex_descriptor)); + desc.SetColorAttachmentDescriptor( + 0u, {.format = color_attachment_format, .blending_enabled = true}); + + desc.SetStencilAttachmentDescriptors(StencilAttachmentDescriptor{}); + desc.SetStencilPixelFormat(stencil_attachment_format); + + desc.SetDepthStencilAttachmentDescriptor(DepthAttachmentDescriptor{}); + desc.SetDepthPixelFormat(stencil_attachment_format); + + options.ApplyToPipelineDescriptor(desc); + auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get(); + if (!pipeline) { + VALIDATION_LOG << "Failed to get or create runtime effect pipeline."; + return nullptr; + } - std::vector descriptor_set_layouts; + return pipeline; +} - BindFragmentCallback bind_callback = [this, &renderer, &context, - &descriptor_set_layouts]( - RenderPass& pass) { - descriptor_set_layouts.clear(); +bool RuntimeEffectContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + const std::shared_ptr& context = renderer.GetContext(); + const std::shared_ptr& library = context->GetShaderLibrary(); + //-------------------------------------------------------------------------- + /// Get or register shader. Flutter will do this when the runtime effect + /// is first loaded, but this check is added to supporting testing of the + /// Aiks API and non-flutter usage of Impeller. + /// + if (!RegisterShader(renderer)) { + return false; + } + + //-------------------------------------------------------------------------- + /// Fragment stage uniforms. + /// + BindFragmentCallback bind_callback = [this, &renderer, + &context](RenderPass& pass) { size_t minimum_sampler_index = 100000000; size_t buffer_index = 0; size_t buffer_offset = 0; @@ -173,9 +225,10 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, Context::BackendType::kVulkan) << "Uniform " << uniform.name << " had unexpected type kFloat for Vulkan backend."; + size_t alignment = std::max(uniform.bit_width / 8, DefaultUniformAlignment()); - auto buffer_view = renderer.GetTransientsBuffer().Emplace( + BufferView buffer_view = renderer.GetTransientsBuffer().Emplace( uniform_data_->data() + buffer_offset, uniform.GetSize(), alignment); @@ -184,7 +237,7 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, uniform_slot.ext_res_0 = uniform.location; pass.BindResource(ShaderStage::kFragment, DescriptorType::kUniformBuffer, uniform_slot, - metadata, buffer_view); + metadata, std::move(buffer_view)); buffer_index++; buffer_offset += uniform.GetSize(); break; @@ -192,15 +245,12 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, case kStruct: { FML_DCHECK(renderer.GetContext()->GetBackendType() == Context::BackendType::kVulkan); - descriptor_set_layouts.emplace_back(DescriptorSetLayout{ - static_cast(uniform.location), - DescriptorType::kUniformBuffer, - ShaderStage::kFragment, - }); ShaderUniformSlot uniform_slot; uniform_slot.name = uniform.name.c_str(); uniform_slot.binding = uniform.location; + // TODO(jonahwilliams): rewrite this to emplace directly into + // HostBuffer. std::vector uniform_buffer; uniform_buffer.reserve(uniform.struct_layout.size()); size_t uniform_byte_index = 0u; @@ -214,16 +264,15 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, FML_UNREACHABLE(); } } - size_t alignment = std::max(sizeof(float) * uniform_buffer.size(), DefaultUniformAlignment()); - auto buffer_view = renderer.GetTransientsBuffer().Emplace( + BufferView buffer_view = renderer.GetTransientsBuffer().Emplace( reinterpret_cast(uniform_buffer.data()), sizeof(float) * uniform_buffer.size(), alignment); pass.BindResource(ShaderStage::kFragment, DescriptorType::kUniformBuffer, uniform_slot, - ShaderMetadata{}, buffer_view); + ShaderMetadata{}, std::move(buffer_view)); } } } @@ -243,20 +292,7 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, SampledImageSlot image_slot; image_slot.name = uniform.name.c_str(); - - uint32_t sampler_binding_location = 0u; - if (!descriptor_set_layouts.empty()) { - sampler_binding_location = - descriptor_set_layouts.back().binding + 1; - } - - descriptor_set_layouts.emplace_back(DescriptorSetLayout{ - sampler_binding_location, - DescriptorType::kSampledImage, - ShaderStage::kFragment, - }); - - image_slot.binding = sampler_binding_location; + image_slot.binding = uniform.binding; image_slot.texture_index = uniform.location - minimum_sampler_index; pass.BindResource(ShaderStage::kFragment, DescriptorType::kSampledImage, image_slot, @@ -273,47 +309,15 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, }; /// Now that the descriptor set layouts are known, get the pipeline. + using VS = RuntimeEffectVertexShader; - PipelineBuilderCallback pipeline_callback = [&](ContentContextOptions - options) { - // Pipeline creation callback for the cache handler to call. - auto create_callback = - [&]() -> std::shared_ptr> { - 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(); - vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs, - VS::kInterleavedBufferLayout); - vertex_descriptor->RegisterDescriptorSetLayouts( - VS::kDescriptorSetLayouts); - vertex_descriptor->RegisterDescriptorSetLayouts( - descriptor_set_layouts.data(), descriptor_set_layouts.size()); - desc.SetVertexDescriptor(std::move(vertex_descriptor)); - desc.SetColorAttachmentDescriptor( - 0u, {.format = color_attachment_format, .blending_enabled = true}); - - desc.SetStencilAttachmentDescriptors(StencilAttachmentDescriptor{}); - desc.SetStencilPixelFormat(stencil_attachment_format); - - desc.SetDepthStencilAttachmentDescriptor(DepthAttachmentDescriptor{}); - desc.SetDepthPixelFormat(stencil_attachment_format); - - options.ApplyToPipelineDescriptor(desc); - auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get(); - if (!pipeline) { - VALIDATION_LOG << "Failed to get or create runtime effect pipeline."; - return nullptr; - } - - return pipeline; - }; - return renderer.GetCachedRuntimeEffectPipeline( - runtime_stage_->GetEntrypoint(), options, create_callback); - }; + PipelineBuilderCallback pipeline_callback = + [&](ContentContextOptions options) { + // Pipeline creation callback for the cache handler to call. + return renderer.GetCachedRuntimeEffectPipeline( + runtime_stage_->GetEntrypoint(), options, + [&]() { return CreatePipeline(renderer, options); }); + }; return ColorSourceContents::DrawGeometry(renderer, entity, pass, pipeline_callback, diff --git a/impeller/entity/contents/runtime_effect_contents.h b/impeller/entity/contents/runtime_effect_contents.h index c92b6eff24cb4..7d71ba3f3c9b1 100644 --- a/impeller/entity/contents/runtime_effect_contents.h +++ b/impeller/entity/contents/runtime_effect_contents.h @@ -35,7 +35,16 @@ class RuntimeEffectContents final : public ColorSourceContents { const Entity& entity, RenderPass& pass) const override; + /// Load the runtime effect and ensure a default PSO is initialized. + bool BootstrapShader(const ContentContext& renderer) const; + private: + bool RegisterShader(const ContentContext& renderer) const; + + std::shared_ptr> CreatePipeline( + const ContentContext& renderer, + ContentContextOptions options) const; + std::shared_ptr runtime_stage_; std::shared_ptr> uniform_data_; std::vector texture_inputs_; diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index f4b77f77479c7..0282807fccfbb 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -2242,6 +2242,20 @@ TEST_P(EntityTest, RuntimeEffectCanSuccessfullyRender) { .has_value()); } +TEST_P(EntityTest, RuntimeEffectCanPrecache) { + auto runtime_stages = + OpenAssetAsRuntimeStage("runtime_stage_example.frag.iplr"); + auto runtime_stage = + runtime_stages[PlaygroundBackendToRuntimeStageBackend(GetBackend())]; + ASSERT_TRUE(runtime_stage); + ASSERT_TRUE(runtime_stage->IsDirty()); + + auto contents = std::make_shared(); + contents->SetRuntimeStage(runtime_stage); + + EXPECT_TRUE(contents->BootstrapShader(*GetContentContext())); +} + TEST_P(EntityTest, RuntimeEffectSetsRightSizeWhenUniformIsStruct) { if (GetBackend() != PlaygroundBackend::kVulkan) { GTEST_SKIP() << "Test only applies to Vulkan"; diff --git a/impeller/runtime_stage/runtime_stage.cc b/impeller/runtime_stage/runtime_stage.cc index 4b5c6924fa386..9e6b3eb42cc22 100644 --- a/impeller/runtime_stage/runtime_stage.cc +++ b/impeller/runtime_stage/runtime_stage.cc @@ -10,6 +10,7 @@ #include "fml/mapping.h" #include "impeller/base/validation.h" #include "impeller/core/runtime_types.h" +#include "impeller/core/shader_types.h" #include "impeller/runtime_stage/runtime_stage_flatbuffers.h" #include "runtime_stage_types_flatbuffers.h" @@ -93,6 +94,7 @@ RuntimeStage::RuntimeStage(const fb::RuntimeStage* runtime_stage, RuntimeUniformDescription desc; desc.name = i->name()->str(); desc.location = i->location(); + desc.binding = i->binding(); desc.type = ToType(i->type()); desc.dimensions = RuntimeUniformDimensions{ static_cast(i->rows()), static_cast(i->columns())}; @@ -103,8 +105,9 @@ RuntimeStage::RuntimeStage(const fb::RuntimeStage* runtime_stage, desc.struct_layout.push_back(static_cast(byte_type)); } } + desc.binding = i->binding(); desc.struct_float_count = i->struct_float_count(); - uniforms_.emplace_back(std::move(desc)); + uniforms_.push_back(std::move(desc)); } } @@ -114,6 +117,22 @@ RuntimeStage::RuntimeStage(const fb::RuntimeStage* runtime_stage, [payload = payload_](auto, auto) {} // ); + for (const auto& uniform : GetUniforms()) { + if (uniform.type == kStruct) { + descriptor_set_layouts_.push_back(DescriptorSetLayout{ + static_cast(uniform.location), + DescriptorType::kUniformBuffer, + ShaderStage::kFragment, + }); + } else if (uniform.type == kSampledImage) { + descriptor_set_layouts_.push_back(DescriptorSetLayout{ + static_cast(uniform.binding), + DescriptorType::kSampledImage, + ShaderStage::kFragment, + }); + } + } + is_valid_ = true; } @@ -160,4 +179,9 @@ void RuntimeStage::SetClean() { is_dirty_ = false; } +const std::vector& RuntimeStage::GetDescriptorSetLayouts() + const { + return descriptor_set_layouts_; +} + } // namespace impeller diff --git a/impeller/runtime_stage/runtime_stage.h b/impeller/runtime_stage/runtime_stage.h index a86344a89d4c5..86af3111f84ab 100644 --- a/impeller/runtime_stage/runtime_stage.h +++ b/impeller/runtime_stage/runtime_stage.h @@ -12,6 +12,7 @@ #include "flutter/fml/mapping.h" #include "flutter/impeller/core/runtime_types.h" +#include "impeller/core/shader_types.h" #include "runtime_stage_types_flatbuffers.h" namespace impeller { @@ -35,6 +36,8 @@ class RuntimeStage { const std::vector& GetUniforms() const; + const std::vector& GetDescriptorSetLayouts() const; + const std::string& GetEntrypoint() const; const RuntimeUniformDescription* GetUniform(const std::string& name) const; @@ -51,6 +54,7 @@ class RuntimeStage { std::string entrypoint_; std::shared_ptr code_mapping_; std::vector uniforms_; + std::vector descriptor_set_layouts_; bool is_valid_ = false; bool is_dirty_ = true; diff --git a/impeller/runtime_stage/runtime_stage_types.fbs b/impeller/runtime_stage/runtime_stage_types.fbs index b6f88f1fa73b7..39c8af71cfdbc 100644 --- a/impeller/runtime_stage/runtime_stage_types.fbs +++ b/impeller/runtime_stage/runtime_stage_types.fbs @@ -30,6 +30,7 @@ enum StructByteType:uint8 { table UniformDescription { name: string; location: uint64; + binding: uint64; type: UniformDataType; bit_width: uint64; rows: uint64; diff --git a/lib/ui/painting/fragment_program.cc b/lib/ui/painting/fragment_program.cc index 5e1f91cac6ebd..6e63cbd6161ae 100644 --- a/lib/ui/painting/fragment_program.cc +++ b/lib/ui/painting/fragment_program.cc @@ -11,17 +11,12 @@ #include "flutter/assets/asset_manager.h" #include "flutter/fml/trace_event.h" #include "flutter/impeller/runtime_stage/runtime_stage.h" -#include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/platform_configuration.h" #include "impeller/core/runtime_types.h" #include "third_party/skia/include/core/SkString.h" #include "third_party/tonic/converter/dart_converter.h" -#include "third_party/tonic/dart_args.h" -#include "third_party/tonic/dart_binding_macros.h" -#include "third_party/tonic/dart_library_natives.h" -#include "third_party/tonic/typed_data/typed_list.h" namespace flutter { @@ -44,10 +39,10 @@ static std::string RuntimeStageBackendToString( std::string FragmentProgram::initFromAsset(const std::string& asset_name) { FML_TRACE_EVENT("flutter", "FragmentProgram::initFromAsset", "asset", asset_name); - std::shared_ptr asset_manager = UIDartState::Current() - ->platform_configuration() - ->client() - ->GetAssetManager(); + UIDartState* ui_dart_state = UIDartState::Current(); + std::shared_ptr asset_manager = + ui_dart_state->platform_configuration()->client()->GetAssetManager(); + std::unique_ptr data = asset_manager->GetAsMapping(asset_name); if (data == nullptr) { return std::string("Asset '") + asset_name + std::string("' not found"); @@ -61,8 +56,10 @@ std::string FragmentProgram::initFromAsset(const std::string& asset_name) { std::string("' does not contain any shader data."); } - auto backend = UIDartState::Current()->GetRuntimeStageBackend(); - auto runtime_stage = runtime_stages[backend]; + impeller::RuntimeStageBackend backend = + ui_dart_state->GetRuntimeStageBackend(); + std::shared_ptr runtime_stage = + runtime_stages[backend]; if (!runtime_stage) { std::ostringstream stream; stream << "Asset '" << asset_name @@ -90,6 +87,16 @@ std::string FragmentProgram::initFromAsset(const std::string& asset_name) { } if (UIDartState::Current()->IsImpellerEnabled()) { + // Spawn (but do not block on) a task that will load the runtime stage and + // populate an initial shader variant. + auto snapshot_controller = UIDartState::Current()->GetSnapshotDelegate(); + ui_dart_state->GetTaskRunners().GetRasterTaskRunner()->PostTask( + [runtime_stage, snapshot_controller]() { + if (!snapshot_controller) { + return; + } + snapshot_controller->CacheRuntimeStage(runtime_stage); + }); runtime_effect_ = DlRuntimeEffect::MakeImpeller(std::move(runtime_stage)); } else { const auto& code_mapping = runtime_stage->GetCodeMapping(); @@ -110,6 +117,7 @@ std::string FragmentProgram::initFromAsset(const std::string& asset_name) { if (Dart_IsError(ths)) { Dart_PropagateError(ths); } + Dart_Handle result = Dart_SetField(ths, tonic::ToDart("_samplerCount"), Dart_NewInteger(sampled_image_count)); if (Dart_IsError(result)) { diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 2c3677d8551a8..a45ee777b9dfa 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -71,6 +71,12 @@ class SnapshotDelegate { SkISize picture_size) = 0; virtual sk_sp ConvertToRasterImage(sk_sp image) = 0; + + /// Load and compile and initial PSO for the provided [runtime_stage]. + /// + /// Impeller only. + virtual void CacheRuntimeStage( + const std::shared_ptr& runtime_stage) = 0; }; } // namespace flutter diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 1c2cfd2e6a4bf..9eaf200df1ac2 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -432,6 +432,12 @@ sk_sp Rasterizer::ConvertToRasterImage(sk_sp image) { return snapshot_controller_->ConvertToRasterImage(image); } +// |SnapshotDelegate| +void Rasterizer::CacheRuntimeStage( + const std::shared_ptr& runtime_stage) { + snapshot_controller_->CacheRuntimeStage(runtime_stage); +} + fml::Milliseconds Rasterizer::GetFrameBudget() const { return delegate_.GetFrameBudget(); }; diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 949402257f4a1..67887f0813a7b 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -649,6 +649,10 @@ class Rasterizer final : public SnapshotDelegate, // |SnapshotDelegate| sk_sp ConvertToRasterImage(sk_sp image) override; + // |SnapshotDelegate| + void CacheRuntimeStage( + const std::shared_ptr& runtime_stage) override; + // |Stopwatch::Delegate| /// Time limit for a smooth frame. /// diff --git a/shell/common/snapshot_controller.h b/shell/common/snapshot_controller.h index c402c3ec709fa..6f12704eac7bc 100644 --- a/shell/common/snapshot_controller.h +++ b/shell/common/snapshot_controller.h @@ -44,6 +44,9 @@ class SnapshotController { virtual sk_sp ConvertToRasterImage(sk_sp image) = 0; + virtual void CacheRuntimeStage( + const std::shared_ptr& runtime_stage) = 0; + protected: explicit SnapshotController(const Delegate& delegate); const Delegate& GetDelegate() { return delegate_; } diff --git a/shell/common/snapshot_controller_impeller.cc b/shell/common/snapshot_controller_impeller.cc index ea68bd91188a4..83f53d9d06629 100644 --- a/shell/common/snapshot_controller_impeller.cc +++ b/shell/common/snapshot_controller_impeller.cc @@ -70,6 +70,17 @@ sk_sp SnapshotControllerImpeller::DoMakeRasterSnapshot( return nullptr; } +void SnapshotControllerImpeller::CacheRuntimeStage( + const std::shared_ptr& runtime_stage) { + impeller::RuntimeEffectContents runtime_effect; + runtime_effect.SetRuntimeStage(runtime_stage); + auto context = GetDelegate().GetAiksContext(); + if (!context) { + return; + } + runtime_effect.BootstrapShader(context->GetContentContext()); +} + sk_sp SnapshotControllerImpeller::ConvertToRasterImage( sk_sp image) { FML_UNREACHABLE(); diff --git a/shell/common/snapshot_controller_impeller.h b/shell/common/snapshot_controller_impeller.h index d9f1d632e3553..4e14036e1f9c6 100644 --- a/shell/common/snapshot_controller_impeller.h +++ b/shell/common/snapshot_controller_impeller.h @@ -6,6 +6,7 @@ #define FLUTTER_SHELL_COMMON_SNAPSHOT_CONTROLLER_IMPELLER_H_ #include "flutter/shell/common/snapshot_controller.h" +#include "impeller/runtime_stage/runtime_stage.h" namespace flutter { @@ -20,6 +21,9 @@ class SnapshotControllerImpeller : public SnapshotController { sk_sp ConvertToRasterImage(sk_sp image) override; + void CacheRuntimeStage( + const std::shared_ptr& runtime_stage) override; + private: sk_sp DoMakeRasterSnapshot(const sk_sp& display_list, SkISize size); diff --git a/shell/common/snapshot_controller_skia.cc b/shell/common/snapshot_controller_skia.cc index fe7897f38d178..ef494d1019521 100644 --- a/shell/common/snapshot_controller_skia.cc +++ b/shell/common/snapshot_controller_skia.cc @@ -160,4 +160,7 @@ sk_sp SnapshotControllerSkia::ConvertToRasterImage( return result->skia_image(); } +void SnapshotControllerSkia::CacheRuntimeStage( + const std::shared_ptr& runtime_stage) {} + } // namespace flutter diff --git a/shell/common/snapshot_controller_skia.h b/shell/common/snapshot_controller_skia.h index 8be1d8e1ec274..b254c6c4cec31 100644 --- a/shell/common/snapshot_controller_skia.h +++ b/shell/common/snapshot_controller_skia.h @@ -20,6 +20,9 @@ class SnapshotControllerSkia : public SnapshotController { virtual sk_sp ConvertToRasterImage(sk_sp image) override; + void CacheRuntimeStage( + const std::shared_ptr& runtime_stage) override; + private: sk_sp DoMakeRasterSnapshot( SkISize size,