Purge resources on rasterizer teardown (flutter/engine#33890)

This commit is contained in:
Dan Field 2022-06-08 16:58:04 -07:00 committed by GitHub
parent e4693324bc
commit 45633ced2a
5 changed files with 158 additions and 54 deletions

View File

@ -302,6 +302,11 @@ if (enable_unittests) {
} else {
# TODO(63837): This test is hard-coded to use a TestGLSurface so it cannot run on fuchsia.
sources += [ "shell_io_manager_unittests.cc" ]
# Swiftshader only supports x86/64. Only needed on non-Fuchsia platforms.
if (shell_enable_vulkan && (target_cpu == "x86" || target_cpu == "x64")) {
deps += [ "//third_party/swiftshader_flutter:swiftshader_vulkan" ]
}
}
}
}

View File

@ -87,13 +87,17 @@ void Rasterizer::TeardownExternalViewEmbedder() {
}
void Rasterizer::Teardown() {
auto context_switch =
surface_ ? surface_->MakeRenderContextCurrent() : nullptr;
if (context_switch && context_switch->GetResult()) {
compositor_context_->OnGrContextDestroyed();
if (surface_) {
auto context_switch = surface_->MakeRenderContextCurrent();
if (context_switch->GetResult()) {
compositor_context_->OnGrContextDestroyed();
if (auto* context = surface_->GetContext()) {
context->purgeUnlockedResources(/*scratchResourcesOnly=*/false);
}
}
surface_.reset();
}
surface_.reset();
last_layer_tree_.reset();
if (raster_thread_merger_.get() != nullptr &&

View File

@ -19,6 +19,7 @@
using testing::_;
using testing::ByMove;
using testing::NiceMock;
using testing::Return;
using testing::ReturnRef;
@ -77,7 +78,7 @@ class MockExternalViewEmbedder : public ExternalViewEmbedder {
} // namespace
TEST(RasterizerTest, create) {
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
auto rasterizer = std::make_unique<Rasterizer>(delegate);
EXPECT_TRUE(rasterizer != nullptr);
}
@ -106,10 +107,10 @@ TEST(RasterizerTest, drawEmptyPipeline) {
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
EXPECT_CALL(*surface, MakeRenderContextCurrent())
.WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
rasterizer->Setup(std::move(surface));
@ -133,15 +134,15 @@ TEST(RasterizerTest,
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
std::make_shared<MockExternalViewEmbedder>();
std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
std::make_shared<NiceMock<MockExternalViewEmbedder>>();
rasterizer->SetExternalViewEmbedder(external_view_embedder);
SurfaceFrame::FramebufferInfo framebuffer_info;
@ -200,14 +201,14 @@ TEST(
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
std::make_shared<MockExternalViewEmbedder>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
std::make_shared<NiceMock<MockExternalViewEmbedder>>();
rasterizer->SetExternalViewEmbedder(external_view_embedder);
EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging)
.WillRepeatedly(Return(true));
@ -265,16 +266,16 @@ TEST(
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
std::make_shared<MockExternalViewEmbedder>();
std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
std::make_shared<NiceMock<MockExternalViewEmbedder>>();
rasterizer->SetExternalViewEmbedder(external_view_embedder);
SurfaceFrame::FramebufferInfo framebuffer_info;
@ -329,16 +330,16 @@ TEST(RasterizerTest,
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
std::make_shared<MockExternalViewEmbedder>();
std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
std::make_shared<NiceMock<MockExternalViewEmbedder>>();
rasterizer->SetExternalViewEmbedder(external_view_embedder);
SurfaceFrame::FramebufferInfo framebuffer_info;
@ -402,13 +403,13 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) {
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
std::make_shared<MockExternalViewEmbedder>();
std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
std::make_shared<NiceMock<MockExternalViewEmbedder>>();
rasterizer->SetExternalViewEmbedder(external_view_embedder);
EXPECT_CALL(
@ -445,17 +446,17 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNotUsedThisFrame) {
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
EXPECT_CALL(*surface, MakeRenderContextCurrent())
.WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
std::make_shared<MockExternalViewEmbedder>();
std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
std::make_shared<NiceMock<MockExternalViewEmbedder>>();
rasterizer->SetExternalViewEmbedder(external_view_embedder);
rasterizer->Setup(std::move(surface));
@ -500,17 +501,17 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenPipelineIsEmpty) {
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
EXPECT_CALL(*surface, MakeRenderContextCurrent())
.WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
std::make_shared<MockExternalViewEmbedder>();
std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
std::make_shared<NiceMock<MockExternalViewEmbedder>>();
rasterizer->SetExternalViewEmbedder(external_view_embedder);
rasterizer->Setup(std::move(surface));
@ -543,13 +544,13 @@ TEST(RasterizerTest,
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
auto is_gpu_disabled_sync_switch =
std::make_shared<const fml::SyncSwitch>(false);
@ -597,12 +598,12 @@ TEST(
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
auto is_gpu_disabled_sync_switch =
std::make_shared<const fml::SyncSwitch>(true);
@ -652,12 +653,12 @@ TEST(
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
auto is_gpu_disabled_sync_switch =
std::make_shared<const fml::SyncSwitch>(false);
@ -706,12 +707,12 @@ TEST(
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_)).Times(0);
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
auto is_gpu_disabled_sync_switch =
std::make_shared<const fml::SyncSwitch>(true);
@ -758,7 +759,7 @@ TEST(RasterizerTest,
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
fml::AutoResetWaitableEvent latch;
@ -769,7 +770,7 @@ TEST(RasterizerTest,
});
latch.Wait();
auto surface = std::make_unique<MockSurface>();
auto surface = std::make_unique<NiceMock<MockSurface>>();
EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled())
.WillRepeatedly(Return(true));
ON_CALL(*surface, AcquireFrame(SkISize()))
@ -831,6 +832,88 @@ TEST(RasterizerTest,
latch.Wait();
}
TEST(RasterizerTest, TeardownFreesResourceCache) {
std::string test_name =
::testing::UnitTest::GetInstance()->current_test_info()->name();
ThreadHost thread_host("io.flutter.test." + test_name + ".",
ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI);
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<NiceMock<MockSurface>>();
auto context = GrDirectContext::MakeMock(nullptr);
context->setResourceCacheLimit(0);
EXPECT_CALL(*surface, MakeRenderContextCurrent())
.WillRepeatedly([]() -> std::unique_ptr<GLContextResult> {
return std::make_unique<GLContextDefaultResult>(true);
});
EXPECT_CALL(*surface, GetContext()).WillRepeatedly(Return(context.get()));
rasterizer->Setup(std::move(surface));
EXPECT_EQ(context->getResourceCacheLimit(), 0ul);
rasterizer->SetResourceCacheMaxBytes(10000000, false);
EXPECT_EQ(context->getResourceCacheLimit(), 10000000ul);
EXPECT_EQ(context->getResourceCachePurgeableBytes(), 0ul);
int count = 0;
size_t bytes = 0;
context->getResourceCacheUsage(&count, &bytes);
EXPECT_EQ(bytes, 0ul);
auto image_info =
SkImageInfo::MakeN32Premul(500, 500, SkColorSpace::MakeSRGB());
auto sk_surface =
SkSurface::MakeRenderTarget(context.get(), SkBudgeted::kYes, image_info);
EXPECT_TRUE(sk_surface);
SkPaint paint;
sk_surface->getCanvas()->drawPaint(paint);
sk_surface->getCanvas()->flush();
context->flushAndSubmit(true);
EXPECT_EQ(context->getResourceCachePurgeableBytes(), 0ul);
sk_surface.reset();
context->getResourceCacheUsage(&count, &bytes);
EXPECT_GT(bytes, 0ul);
EXPECT_GT(context->getResourceCachePurgeableBytes(), 0ul);
rasterizer->Teardown();
EXPECT_EQ(context->getResourceCachePurgeableBytes(), 0ul);
}
TEST(RasterizerTest, TeardownNoSurface) {
std::string test_name =
::testing::UnitTest::GetInstance()->current_test_info()->name();
ThreadHost thread_host("io.flutter.test." + test_name + ".",
ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI);
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
NiceMock<MockDelegate> delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
EXPECT_TRUE(rasterizer);
rasterizer->Teardown();
}
TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) {
std::string test_name =
::testing::UnitTest::GetInstance()->current_test_info()->name();
@ -841,7 +924,8 @@ TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) {
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
fml::AutoResetWaitableEvent latch;
@ -920,7 +1004,8 @@ TEST(RasterizerTest, presentationTimeNotSetWhenVsyncTargetInPast) {
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
MockDelegate delegate;
NiceMock<MockDelegate> delegate;
ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
fml::AutoResetWaitableEvent latch;

View File

@ -8,6 +8,16 @@
#include "flutter/shell/common/context_options.h"
#include "flutter/vulkan/vulkan_utilities.h"
#if OS_FUCHSIA
#define VULKAN_SO_PATH "libvulkan.so"
#elif FML_OS_MACOSX
#define VULKAN_SO_PATH "libvk_swiftshader.dylib"
#elif FML_OS_WIN
#define VULKAN_SO_PATH "vk_swiftshader.dll"
#else
#define VULKAN_SO_PATH "libvk_swiftshader.so"
#endif
namespace flutter {
namespace testing {
@ -21,7 +31,7 @@ ShellTestPlatformViewVulkan::ShellTestPlatformViewVulkan(
: ShellTestPlatformView(delegate, std::move(task_runners)),
create_vsync_waiter_(std::move(create_vsync_waiter)),
vsync_clock_(vsync_clock),
proc_table_(fml::MakeRefCounted<vulkan::VulkanProcTable>()),
proc_table_(fml::MakeRefCounted<vulkan::VulkanProcTable>(VULKAN_SO_PATH)),
shell_test_external_view_embedder_(shell_test_external_view_embedder) {}
ShellTestPlatformViewVulkan::~ShellTestPlatformViewVulkan() = default;

View File

@ -159,7 +159,7 @@ def BuildEngineExecutableCommand(
gtest_parallel = os.path.join(
buildroot_dir, 'third_party', 'gtest-parallel', 'gtest-parallel'
)
test_command = ['python', gtest_parallel] + test_command
test_command = ['python3', gtest_parallel] + test_command
return test_command
@ -181,13 +181,15 @@ def RunEngineExecutable(
return
unstripped_exe = os.path.join(build_dir, 'exe.unstripped', executable_name)
env = os.environ.copy()
# We cannot run the unstripped binaries directly when coverage is enabled.
if IsLinux() and os.path.exists(unstripped_exe) and not coverage:
# Some tests depend on the EGL/GLES libraries placed in the build directory.
env = os.environ.copy()
env['LD_LIBRARY_PATH'] = os.path.join(build_dir, 'lib.unstripped')
elif IsMac():
env['DYLD_LIBRARY_PATH'] = build_dir
else:
env = None
env['PATH'] = build_dir + ":" + env['PATH']
print('Running %s in %s' % (executable_name, cwd))
@ -199,8 +201,6 @@ def RunEngineExecutable(
gtest=gtest,
)
if not env:
env = os.environ.copy()
env['FLUTTER_BUILD_DIRECTORY'] = build_dir
for key, value in extra_env.items():
env[key] = value
@ -1029,7 +1029,7 @@ def main():
variants_to_skip = ['host_release', 'host_profile']
if ('engine' in types or
'font-subset' in types) and args.variant not in variants_to_skip:
RunCmd(['python', 'test.py'], cwd=font_subset_dir)
RunCmd(['python3', 'test.py'], cwd=font_subset_dir)
if __name__ == '__main__':