diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index cccbe6a7537c7..112953b981b11 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -82,6 +82,7 @@ FILE: ../../../flutter/flow/skia_gpu_object.cc FILE: ../../../flutter/flow/skia_gpu_object.h FILE: ../../../flutter/flow/texture.cc FILE: ../../../flutter/flow/texture.h +FILE: ../../../flutter/flow/texture_unittests.cc FILE: ../../../flutter/flow/view_holder.cc FILE: ../../../flutter/flow/view_holder.h FILE: ../../../flutter/fml/base32.cc diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 90975c05e6096..3ecc8381c5d33 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -114,6 +114,7 @@ executable("flow_unittests") { "matrix_decomposition_unittests.cc", "mutators_stack_unittests.cc", "raster_cache_unittests.cc", + "texture_unittests.cc", ] deps = [ diff --git a/flow/texture.cc b/flow/texture.cc index 7bc40f0c1d43b..6f25c6df89593 100644 --- a/flow/texture.cc +++ b/flow/texture.cc @@ -15,6 +15,7 @@ void TextureRegistry::RegisterTexture(std::shared_ptr texture) { } void TextureRegistry::UnregisterTexture(int64_t id) { + mapping_[id]->OnTextureUnregistered(); mapping_.erase(id); } diff --git a/flow/texture.h b/flow/texture.h index 749e3835b236a..6e06445884b66 100644 --- a/flow/texture.h +++ b/flow/texture.h @@ -36,6 +36,9 @@ class Texture { // Called on GPU thread. virtual void MarkNewFrameAvailable() = 0; + // Called on GPU thread. + virtual void OnTextureUnregistered() = 0; + int64_t Id() { return id_; } private: diff --git a/flow/texture_unittests.cc b/flow/texture_unittests.cc new file mode 100644 index 0000000000000..d292e3965af87 --- /dev/null +++ b/flow/texture_unittests.cc @@ -0,0 +1,46 @@ +// 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 "flutter/flow/texture.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +class MockTexture : public Texture { + public: + MockTexture(int64_t textureId) : Texture(textureId) {} + + ~MockTexture() override = default; + + // Called from GPU thread. + void Paint(SkCanvas& canvas, + const SkRect& bounds, + bool freeze, + GrContext* context) override {} + + void OnGrContextCreated() override {} + + void OnGrContextDestroyed() override {} + + void MarkNewFrameAvailable() override {} + + void OnTextureUnregistered() override { unregistered_ = true; } + + bool unregistered() { return unregistered_; } + + private: + bool unregistered_ = false; +}; + +TEST(TextureRegistry, UnregisterTextureCallbackTriggered) { + TextureRegistry textureRegistry; + std::shared_ptr mockTexture = std::make_shared(0); + textureRegistry.RegisterTexture(mockTexture); + textureRegistry.UnregisterTexture(0); + ASSERT_TRUE(mockTexture->unregistered()); +} + +} // namespace testing +} // namespace flutter diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 6968cf72994a4..1871f4ea0818a 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -799,5 +799,79 @@ TEST_F(ShellTest, CanCreateImagefromDecompressedBytes) { latch.Wait(); } +class MockTexture : public Texture { + public: + MockTexture(int64_t textureId, + std::shared_ptr latch) + : Texture(textureId), latch_(latch) {} + + ~MockTexture() override = default; + + // Called from GPU thread. + void Paint(SkCanvas& canvas, + const SkRect& bounds, + bool freeze, + GrContext* context) override {} + + void OnGrContextCreated() override {} + + void OnGrContextDestroyed() override {} + + void MarkNewFrameAvailable() override { + frames_available_++; + latch_->Signal(); + } + + void OnTextureUnregistered() override { + unregistered_ = true; + latch_->Signal(); + } + + bool unregistered() { return unregistered_; } + int frames_available() { return frames_available_; } + + private: + bool unregistered_ = false; + int frames_available_ = 0; + std::shared_ptr latch_; +}; + +TEST_F(ShellTest, TextureFrameMarkedAvailableAndUnregister) { + Settings settings = CreateSettingsForFixture(); + auto configuration = RunConfiguration::InferFromSettings(settings); + auto task_runner = CreateNewThread(); + TaskRunners task_runners("test", task_runner, task_runner, task_runner, + task_runner); + std::unique_ptr shell = + CreateShell(std::move(settings), std::move(task_runners)); + + ASSERT_TRUE(ValidateShell(shell.get())); + PlatformViewNotifyCreated(shell.get()); + + RunEngine(shell.get(), std::move(configuration)); + + std::shared_ptr latch = + std::make_shared(); + + std::shared_ptr mockTexture = + std::make_shared(0, latch); + + fml::TaskRunner::RunNowOrPostTask( + shell->GetTaskRunners().GetGPUTaskRunner(), [&]() { + shell->GetPlatformView()->RegisterTexture(mockTexture); + shell->GetPlatformView()->MarkTextureFrameAvailable(0); + }); + latch->Wait(); + + EXPECT_EQ(mockTexture->frames_available(), 1); + + fml::TaskRunner::RunNowOrPostTask( + shell->GetTaskRunners().GetGPUTaskRunner(), + [&]() { shell->GetPlatformView()->UnregisterTexture(0); }); + latch->Wait(); + + EXPECT_EQ(mockTexture->unregistered(), true); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/android/android_external_texture_gl.cc b/shell/platform/android/android_external_texture_gl.cc index 935f60b455797..8c4f960b0f232 100644 --- a/shell/platform/android/android_external_texture_gl.cc +++ b/shell/platform/android/android_external_texture_gl.cc @@ -135,4 +135,6 @@ void AndroidExternalTextureGL::Detach() { } } +void AndroidExternalTextureGL::OnTextureUnregistered() {} + } // namespace flutter diff --git a/shell/platform/android/android_external_texture_gl.h b/shell/platform/android/android_external_texture_gl.h index 9ce87b3255bd1..4e2b187eb3f61 100644 --- a/shell/platform/android/android_external_texture_gl.h +++ b/shell/platform/android/android_external_texture_gl.h @@ -30,6 +30,8 @@ class AndroidExternalTextureGL : public flutter::Texture { void MarkNewFrameAvailable() override; + void OnTextureUnregistered() override; + private: void Attach(jint textureName); diff --git a/shell/platform/darwin/ios/framework/Headers/FlutterTexture.h b/shell/platform/darwin/ios/framework/Headers/FlutterTexture.h index e7cd01337deb9..bfb66b092a684 100644 --- a/shell/platform/darwin/ios/framework/Headers/FlutterTexture.h +++ b/shell/platform/darwin/ios/framework/Headers/FlutterTexture.h @@ -15,6 +15,14 @@ NS_ASSUME_NONNULL_BEGIN FLUTTER_EXPORT @protocol FlutterTexture - (CVPixelBufferRef _Nullable)copyPixelBuffer; + +/** + * Called when the texture is unregistered. + * + * Called on the GPU thread. + */ +@optional +- (void)onTextureUnregistered:(NSObject*)texture; @end FLUTTER_EXPORT diff --git a/shell/platform/darwin/ios/ios_external_texture_gl.h b/shell/platform/darwin/ios/ios_external_texture_gl.h index 88be5cc7c466a..33e2eee6f7deb 100644 --- a/shell/platform/darwin/ios/ios_external_texture_gl.h +++ b/shell/platform/darwin/ios/ios_external_texture_gl.h @@ -26,6 +26,8 @@ class IOSExternalTextureGL : public flutter::Texture { void MarkNewFrameAvailable() override; + void OnTextureUnregistered() override; + private: void CreateTextureFromPixelBuffer(); diff --git a/shell/platform/darwin/ios/ios_external_texture_gl.mm b/shell/platform/darwin/ios/ios_external_texture_gl.mm index a5e729195ce34..a2efe17c4e146 100644 --- a/shell/platform/darwin/ios/ios_external_texture_gl.mm +++ b/shell/platform/darwin/ios/ios_external_texture_gl.mm @@ -104,4 +104,10 @@ new_frame_ready_ = true; } +void IOSExternalTextureGL::OnTextureUnregistered() { + if ([external_texture_ respondsToSelector:@selector(onTextureUnregistered:)]) { + [external_texture_ onTextureUnregistered:external_texture_]; + } +} + } // namespace flutter diff --git a/shell/platform/embedder/embedder_external_texture_gl.cc b/shell/platform/embedder/embedder_external_texture_gl.cc index b9857ae4ee363..e170654bbd9cf 100644 --- a/shell/platform/embedder/embedder_external_texture_gl.cc +++ b/shell/platform/embedder/embedder_external_texture_gl.cc @@ -44,4 +44,7 @@ void EmbedderExternalTextureGL::OnGrContextDestroyed() {} // |flutter::Texture| void EmbedderExternalTextureGL::MarkNewFrameAvailable() {} +// |flutter::Texture| +void EmbedderExternalTextureGL::OnTextureUnregistered() {} + } // namespace flutter diff --git a/shell/platform/embedder/embedder_external_texture_gl.h b/shell/platform/embedder/embedder_external_texture_gl.h index e1cd383c72f5a..e696ebf9eb08e 100644 --- a/shell/platform/embedder/embedder_external_texture_gl.h +++ b/shell/platform/embedder/embedder_external_texture_gl.h @@ -41,6 +41,9 @@ class EmbedderExternalTextureGL : public flutter::Texture { // |flutter::Texture| void MarkNewFrameAvailable() override; + // |flutter::Texture| + void OnTextureUnregistered() override; + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalTextureGL); };