|
| 1 | +// Copyright 2013 The Flutter Authors. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style license that can be |
| 3 | +// found in the LICENSE file. |
| 4 | + |
| 5 | +#include "gtest/gtest.h" |
| 6 | + |
| 7 | +#include "flutter/shell/platform/linux/fl_gl_fence.h" |
| 8 | +#include "flutter/shell/platform/linux/testing/linux_test.h" |
| 9 | +#include "flutter/shell/platform/linux/testing/mock_epoxy.h" |
| 10 | + |
| 11 | +class FlGLFenceTest : public flutter::testing::LinuxTest { |
| 12 | + protected: |
| 13 | + void SetUp() override { opengl_manager = fl_opengl_manager_new(); } |
| 14 | + |
| 15 | + ~FlGLFenceTest() override { g_clear_object(&opengl_manager); } |
| 16 | + |
| 17 | + ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy; |
| 18 | + FlOpenGLManager* opengl_manager = nullptr; |
| 19 | +}; |
| 20 | + |
| 21 | +// A fence is created in the current context, and the commands are flushed so |
| 22 | +// that it can actually be reached. |
| 23 | +TEST_F(FlGLFenceTest, New) { |
| 24 | + EXPECT_CALL(epoxy, |
| 25 | + eglCreateSyncKHR(::testing::_, EGL_SYNC_FENCE_KHR, ::testing::_)); |
| 26 | + |
| 27 | + g_autoptr(FlGLFence) fence = fl_gl_fence_new(opengl_manager); |
| 28 | + EXPECT_NE(fence, nullptr); |
| 29 | +} |
| 30 | + |
| 31 | +// Drivers without fence support are reported so the caller can fall back to |
| 32 | +// another form of synchronization. |
| 33 | +// A driver that fails to create a fence still returns an object, which is safe |
| 34 | +// to wait on and does nothing. |
| 35 | +TEST_F(FlGLFenceTest, NewFails) { |
| 36 | + EXPECT_CALL(epoxy, eglCreateSyncKHR) |
| 37 | + .WillOnce(::testing::Return(EGL_NO_SYNC_KHR)); |
| 38 | + |
| 39 | + g_autoptr(FlGLFence) fence = fl_gl_fence_new(opengl_manager); |
| 40 | + ASSERT_NE(fence, nullptr); |
| 41 | + |
| 42 | + EXPECT_CALL(epoxy, eglClientWaitSyncKHR).Times(0); |
| 43 | + EXPECT_CALL(epoxy, eglWaitSyncKHR).Times(0); |
| 44 | + fl_gl_fence_wait(fence); |
| 45 | +} |
| 46 | + |
| 47 | +// OpenGL can do the waiting, which doesn't block the calling thread. |
| 48 | +TEST_F(FlGLFenceTest, Wait) { |
| 49 | + g_autoptr(FlGLFence) fence = fl_gl_fence_new(opengl_manager); |
| 50 | + ASSERT_NE(fence, nullptr); |
| 51 | + |
| 52 | + EXPECT_CALL(epoxy, eglWaitSyncKHR(::testing::_, ::testing::_, 0)) |
| 53 | + .WillOnce(::testing::Return(EGL_TRUE)); |
| 54 | + EXPECT_CALL(epoxy, eglClientWaitSyncKHR).Times(0); |
| 55 | + |
| 56 | + fl_gl_fence_wait(fence); |
| 57 | +} |
| 58 | + |
| 59 | +// Drivers that can create fences but can't wait on them without blocking fall |
| 60 | +// back to blocking, which is slower but still correct. |
| 61 | +TEST_F(FlGLFenceTest, WaitUnsupported) { |
| 62 | + EXPECT_CALL(epoxy, epoxy_has_egl_extension( |
| 63 | + ::testing::_, ::testing::StrEq("EGL_KHR_wait_sync"))) |
| 64 | + .WillRepeatedly(::testing::Return(false)); |
| 65 | + |
| 66 | + g_autoptr(FlGLFence) fence = fl_gl_fence_new(opengl_manager); |
| 67 | + ASSERT_NE(fence, nullptr); |
| 68 | + |
| 69 | + EXPECT_CALL(epoxy, eglWaitSyncKHR).Times(0); |
| 70 | + EXPECT_CALL(epoxy, eglClientWaitSyncKHR) |
| 71 | + .WillOnce(::testing::Return(EGL_CONDITION_SATISFIED_KHR)); |
| 72 | + |
| 73 | + fl_gl_fence_wait(fence); |
| 74 | +} |
| 75 | + |
| 76 | +// The fence is destroyed with the display it was created on, so it doesn't |
| 77 | +// depend on a context being current when it is freed. |
| 78 | +TEST_F(FlGLFenceTest, Destroy) { |
| 79 | + FlGLFence* fence = fl_gl_fence_new(opengl_manager); |
| 80 | + ASSERT_NE(fence, nullptr); |
| 81 | + |
| 82 | + EXPECT_CALL(epoxy, eglDestroySyncKHR).WillOnce(::testing::Return(EGL_TRUE)); |
| 83 | + |
| 84 | + g_object_unref(fence); |
| 85 | +} |
0 commit comments