From c3027513ac2247f73861c1a34404a89442735329 Mon Sep 17 00:00:00 2001 From: Christopher James Halse Rogers Date: Thu, 13 Jul 2023 18:06:52 +1000 Subject: [PATCH] TestBasicScreenShooter: Test threading requirements. Because the `Renderer` hides thread-local state (in the form of an EGL context) it's important that the `BasicScreenShooter` do the dance required to ensure the `Renderer` tries to be current on at most one thread at a time. --- .../compositor/test_basic_screen_shooter.cpp | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/unit-tests/compositor/test_basic_screen_shooter.cpp b/tests/unit-tests/compositor/test_basic_screen_shooter.cpp index ec9a7125538..2db361dce1d 100644 --- a/tests/unit-tests/compositor/test_basic_screen_shooter.cpp +++ b/tests/unit-tests/compositor/test_basic_screen_shooter.cpp @@ -14,6 +14,7 @@ * along with this program. If not, see . */ +#include "mir/executor.h" #include "mir/graphics/platform.h" #include "mir/renderer/gl/gl_surface.h" #include "mir/test/doubles/stub_gl_rendering_provider.h" @@ -233,3 +234,56 @@ TEST_F(BasicScreenShooter, throw_in_render_causes_graceful_failure) EXPECT_CALL(callback, Call(nullopt_time)); executor.execute(); } + +TEST_F(BasicScreenShooter, ensures_renderer_is_current_on_only_one_thread) +{ + thread_local bool is_current_here = false; + std::atomic is_current = false; + + auto shooter = std::make_unique( + scene, + clock, + mir::thread_pool_executor, + gl_providers, + renderer_factory); + + ON_CALL(*next_renderer, render(_)) + .WillByDefault( + [&](auto) -> std::unique_ptr + { + /* It's OK if we're being made current again on the same thread + * without having been released previously. + * We just need to ensure that, if we are current *anywhere* then + * it's *this* thread that we're current on. + */ + EXPECT_THAT(is_current_here, Eq(is_current.load())); + is_current = true; + is_current_here = true; + return {}; + }); + ON_CALL(*next_renderer, suspend()) + .WillByDefault( + [&]() + { + EXPECT_THAT(is_current_here, Eq(is_current.load())); + is_current = false; + is_current_here = false; + }); + + // This doesn't actually have to be atomic + std::atomic call_count = 0; + auto const spawn_a_capture = + [&]() + { + shooter->capture(buffer, viewport_rect, [&](auto) { call_count++; }); + }; + + auto const expected_call_count = 20; + for (auto i = 0; i < expected_call_count; ++i) + { + mir::thread_pool_executor.spawn(spawn_a_capture); + } + + mir::ThreadPoolExecutor::quiesce(); + EXPECT_THAT(call_count, Eq(expected_call_count)); +}