diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 726312a36f3d2..0598960806adb 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -472,9 +472,11 @@ CreateEmbedderRenderTarget(const FlutterCompositor* compositor, auto c_create_callback = compositor->create_backing_store_callback; auto c_collect_callback = compositor->collect_backing_store_callback; + bool avoid_cache = false; { TRACE_EVENT0("flutter", "FlutterCompositorCreateBackingStore"); - if (!c_create_callback(&config, &backing_store, compositor->user_data)) { + if (!c_create_callback(&config, &backing_store, compositor->user_data, + &avoid_cache)) { FML_LOG(ERROR) << "Could not create the embedder backing store."; return nullptr; } @@ -526,7 +528,8 @@ CreateEmbedderRenderTarget(const FlutterCompositor* compositor, } return std::make_unique( - backing_store, std::move(render_surface), collect_callback.Release()); + backing_store, std::move(render_surface), collect_callback.Release(), + avoid_cache); } static std::pair, diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index f98f848e967b3..9f955b524cf08 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -4,7 +4,6 @@ #ifndef FLUTTER_EMBEDDER_H_ #define FLUTTER_EMBEDDER_H_ - #include #include #include @@ -905,7 +904,8 @@ typedef struct { typedef bool (*FlutterBackingStoreCreateCallback)( const FlutterBackingStoreConfig* config, FlutterBackingStore* backing_store_out, - void* user_data); + void* user_data, + bool* avoid_cache); typedef bool (*FlutterBackingStoreCollectCallback)( const FlutterBackingStore* renderer, diff --git a/shell/platform/embedder/embedder_external_view_embedder.cc b/shell/platform/embedder/embedder_external_view_embedder.cc index fc6c2905331c9..a8699a7b416be 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/shell/platform/embedder/embedder_external_view_embedder.cc @@ -263,8 +263,10 @@ void EmbedderExternalViewEmbedder::SubmitFrame( // Hold all rendered layers in the render target cache for one frame to // see if they may be reused next frame. for (auto& render_target : matched_render_targets) { - render_target_cache_.CacheRenderTarget(render_target.first, - std::move(render_target.second)); + if (!render_target.second->GetAvoidCache()) { + render_target_cache_.CacheRenderTarget(render_target.first, + std::move(render_target.second)); + } } frame->Submit(); diff --git a/shell/platform/embedder/embedder_render_target.cc b/shell/platform/embedder/embedder_render_target.cc index 8f6e447ba144e..fc9ed9fb6e47a 100644 --- a/shell/platform/embedder/embedder_render_target.cc +++ b/shell/platform/embedder/embedder_render_target.cc @@ -10,10 +10,12 @@ namespace flutter { EmbedderRenderTarget::EmbedderRenderTarget(FlutterBackingStore backing_store, sk_sp render_surface, - fml::closure on_release) + fml::closure on_release, + bool avoid_cache) : backing_store_(backing_store), render_surface_(std::move(render_surface)), - on_release_(on_release) { + on_release_(on_release), + avoid_cache_(avoid_cache) { // TODO(38468): The optimization to elide backing store updates between frames // has not been implemented yet. backing_store_.did_update = true; @@ -34,4 +36,8 @@ sk_sp EmbedderRenderTarget::GetRenderSurface() const { return render_surface_; } +bool EmbedderRenderTarget::GetAvoidCache() { + return avoid_cache_; +} + } // namespace flutter diff --git a/shell/platform/embedder/embedder_render_target.h b/shell/platform/embedder/embedder_render_target.h index 8afbed31e30f0..aad356b17eab5 100644 --- a/shell/platform/embedder/embedder_render_target.h +++ b/shell/platform/embedder/embedder_render_target.h @@ -36,7 +36,8 @@ class EmbedderRenderTarget { /// EmbedderRenderTarget(FlutterBackingStore backing_store, sk_sp render_surface, - fml::closure on_release); + fml::closure on_release, + bool avoid_cache); //---------------------------------------------------------------------------- /// @brief Destroys this instance of the render target and invokes the @@ -65,10 +66,18 @@ class EmbedderRenderTarget { /// const FlutterBackingStore* GetBackingStore() const; + //---------------------------------------------------------------------------- + /// @brief The render target may want to avoid being cached. + /// + /// @return A bool representing if the embedder render target should + /// avoid the cache. + bool GetAvoidCache(); + private: FlutterBackingStore backing_store_; sk_sp render_surface_; fml::closure on_release_; + bool avoid_cache_; FML_DISALLOW_COPY_AND_ASSIGN(EmbedderRenderTarget); }; diff --git a/shell/platform/embedder/tests/embedder_config_builder.cc b/shell/platform/embedder/tests/embedder_config_builder.cc index 93d4c6af916f2..8fcd5c95c9cc3 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.cc +++ b/shell/platform/embedder/tests/embedder_config_builder.cc @@ -257,10 +257,10 @@ void EmbedderConfigBuilder::SetCompositor() { compositor_.create_backing_store_callback = [](const FlutterBackingStoreConfig* config, // FlutterBackingStore* backing_store_out, // - void* user_data // - ) { + void* user_data, // + bool* avoid_cache) { return reinterpret_cast(user_data) - ->CreateBackingStore(config, backing_store_out); + ->CreateBackingStore(config, backing_store_out, avoid_cache); }; compositor_.collect_backing_store_callback = [](const FlutterBackingStore* backing_store, // diff --git a/shell/platform/embedder/tests/embedder_test_compositor.cc b/shell/platform/embedder/tests/embedder_test_compositor.cc index 23afb36f01e72..dc563aa3d994a 100644 --- a/shell/platform/embedder/tests/embedder_test_compositor.cc +++ b/shell/platform/embedder/tests/embedder_test_compositor.cc @@ -29,12 +29,16 @@ static void InvokeAllCallbacks(const std::vector& callbacks) { bool EmbedderTestCompositor::CreateBackingStore( const FlutterBackingStoreConfig* config, - FlutterBackingStore* backing_store_out) { + FlutterBackingStore* backing_store_out, + bool* avoid_cache) { bool success = backingstore_producer_->Create(config, backing_store_out); if (success) { backing_stores_created_++; InvokeAllCallbacks(on_create_render_target_callbacks_); } + if (avoid_cache_callback_) { + avoid_cache_callback_(avoid_cache); + } return success; } @@ -104,6 +108,11 @@ void EmbedderTestCompositor::SetPlatformViewRendererCallback( platform_view_renderer_callback_ = callback; } +void EmbedderTestCompositor::SetUpdateAvoidCacheCallback( + const UpdateAvoidCacheCallback& avoid_cache_callback) { + avoid_cache_callback_ = avoid_cache_callback; +} + size_t EmbedderTestCompositor::GetPendingBackingStoresCount() const { FML_CHECK(backing_stores_created_ >= backing_stores_collected_); return backing_stores_created_ - backing_stores_collected_; diff --git a/shell/platform/embedder/tests/embedder_test_compositor.h b/shell/platform/embedder/tests/embedder_test_compositor.h index 26d96de6cda81..f8427319b58b3 100644 --- a/shell/platform/embedder/tests/embedder_test_compositor.h +++ b/shell/platform/embedder/tests/embedder_test_compositor.h @@ -24,6 +24,8 @@ class EmbedderTestCompositor { using PresentCallback = std::function; + using UpdateAvoidCacheCallback = std::function; + EmbedderTestCompositor(SkISize surface_size, sk_sp context); virtual ~EmbedderTestCompositor(); @@ -32,7 +34,8 @@ class EmbedderTestCompositor { std::unique_ptr backingstore_producer); bool CreateBackingStore(const FlutterBackingStoreConfig* config, - FlutterBackingStore* backing_store_out); + FlutterBackingStore* backing_store_out, + bool* avoid_cache); bool CollectBackingStore(const FlutterBackingStore* backing_store); @@ -53,6 +56,15 @@ class EmbedderTestCompositor { void SetPresentCallback(const PresentCallback& present_callback, bool one_shot); + //---------------------------------------------------------------------------- + /// @brief Allows tests to install a callback to update the + /// avoid_cache_callback_ bool. + /// + /// @param[in] avoid_cache_callback The callback to update the + /// avoid_cache_callback_. + void SetUpdateAvoidCacheCallback( + const UpdateAvoidCacheCallback& avoid_cache_callback); + using NextSceneCallback = std::function image)>; void SetNextSceneCallback(const NextSceneCallback& next_scene_callback); @@ -85,6 +97,7 @@ class EmbedderTestCompositor { bool present_callback_is_one_shot_ = false; PresentCallback present_callback_; NextSceneCallback next_scene_callback_; + UpdateAvoidCacheCallback avoid_cache_callback_; sk_sp last_composition_; size_t backing_stores_created_ = 0; size_t backing_stores_collected_ = 0; diff --git a/shell/platform/embedder/tests/embedder_unittests_gl.cc b/shell/platform/embedder/tests/embedder_unittests_gl.cc index d9b0ba79bb65a..6987acf90dfae 100644 --- a/shell/platform/embedder/tests/embedder_unittests_gl.cc +++ b/shell/platform/embedder/tests/embedder_unittests_gl.cc @@ -2950,6 +2950,53 @@ TEST_F(EmbedderTest, CompositorRenderTargetsAreRecycled) { ASSERT_EQ(context.GetCompositor().GetBackingStoresCollectedCount(), 10u); } +//------------------------------------------------------------------------------ +/// The RenderTargetCache being disabled should result in the render targets +/// always being discarded. +/// +TEST_F(EmbedderTest, RenderTargetCacheDisabled) { + auto& context = GetEmbedderContext(ContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(300, 200)); + builder.SetCompositor(); + builder.SetDartEntrypoint("render_targets_are_recycled"); + builder.SetRenderTargetType( + EmbedderTestBackingStoreProducer::RenderTargetType::kOpenGLTexture); + + fml::CountDownLatch latch(2); + + context.AddNativeCallback("SignalNativeTest", + CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + latch.CountDown(); + })); + + context.GetCompositor().SetNextPresentCallback( + [&](const FlutterLayer** layers, size_t layers_count) { + ASSERT_EQ(layers_count, 20u); + latch.CountDown(); + }); + + context.GetCompositor().SetUpdateAvoidCacheCallback( + [](bool* avoid_cache) { *avoid_cache = true; }); + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = 300; + event.height = 200; + event.pixel_ratio = 1.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); + + latch.Wait(); + // Instead of being recycled, the 10 render targets should be created for each + // of the 7 frames. + ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(), 70u); +} + TEST_F(EmbedderTest, CompositorRenderTargetsAreInStableOrder) { auto& context = GetEmbedderContext(ContextType::kOpenGLContext);