// copyright (c) 2022 the android open source project // // licensed under the apache license, version 2.0 (the "license"); // you may not use this file except in compliance with the license. // you may obtain a copy of the license at // // http://www.apache.org/licenses/license-2.0 // // unless required by applicable law or agreed to in writing, software // distributed under the license is distributed on an "as is" basis, // without warranties or conditions of any kind, either express or implied. // see the license for the specific language governing permissions and // limitations under the license. #include #include #include "VkDecoderGlobalState.cpp" #include "aemu/base/testing/TestUtils.h" namespace gfxstream { namespace vk { namespace { using ::testing::_; using ::testing::InSequence; using ::testing::MockFunction; using ::testing::Return; using ::testing::Test; using ::testing::UnorderedElementsAre; class VkDecoderGlobalStateExternalFenceTest : public Test { protected: class MockDispatch { public: MOCK_METHOD(VkResult, vkGetFenceStatus, (VkDevice device, VkFence fence), ()); MOCK_METHOD(VkResult, vkResetFences, (VkDevice device, uint32_t numFences, const VkFence* fence), ()); }; VkDecoderGlobalStateExternalFenceTest() : mDevice(reinterpret_cast(0x2222'0000)), mPool(&mMockDispatch, mDevice) {} ~VkDecoderGlobalStateExternalFenceTest() { mPool.popAll(); } MockDispatch mMockDispatch; VkDevice mDevice; ExternalFencePool mPool; }; using VkDecoderGlobalStateExternalFenceDeathTest = VkDecoderGlobalStateExternalFenceTest; TEST_F(VkDecoderGlobalStateExternalFenceTest, poolNoDeviceFences) { VkFenceCreateInfo createInfo{ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = 0, .flags = 0, }; ASSERT_EQ(VK_NULL_HANDLE, mPool.pop(&createInfo)); } TEST_F(VkDecoderGlobalStateExternalFenceTest, poolReuseSignalledFence) { { InSequence s; EXPECT_CALL(mMockDispatch, vkGetFenceStatus(_, _)).WillOnce(Return(VK_SUCCESS)); EXPECT_CALL(mMockDispatch, vkResetFences(_, _, _)).WillOnce(Return(VK_SUCCESS)); } VkFence fence = reinterpret_cast(0x1234'0000); VkFenceCreateInfo createInfo{ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = 0, .flags = 0, }; mPool.add(fence); VkFence reusedFence = mPool.pop(&createInfo); ASSERT_EQ(fence, reusedFence); } TEST_F(VkDecoderGlobalStateExternalFenceTest, poolReuseSignalledFenceAsSignaled) { { InSequence s; EXPECT_CALL(mMockDispatch, vkGetFenceStatus(_, _)).WillOnce(Return(VK_SUCCESS)); EXPECT_CALL(mMockDispatch, vkResetFences(_, _, _)).Times(0); } VkFence fence = reinterpret_cast(0x1234'0000); VkFenceCreateInfo createInfo{ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = 0, .flags = VK_FENCE_CREATE_SIGNALED_BIT, }; mPool.add(fence); VkFence reusedFence = mPool.pop(&createInfo); ASSERT_EQ(fence, reusedFence); } TEST_F(VkDecoderGlobalStateExternalFenceTest, poolUnsignalledFence) { { InSequence s; EXPECT_CALL(mMockDispatch, vkGetFenceStatus(_, _)).WillOnce(Return(VK_NOT_READY)); EXPECT_CALL(mMockDispatch, vkResetFences(_, _, _)).Times(0); } VkFence fence = reinterpret_cast(0x1234'0000); VkFenceCreateInfo createInfo{ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = 0, .flags = 0, }; mPool.add(fence); ASSERT_EQ(VK_NULL_HANDLE, mPool.pop(&createInfo)); } TEST_F(VkDecoderGlobalStateExternalFenceTest, poolPopAll) { VkFence fence1 = reinterpret_cast(0x1234'0000); VkFence fence2 = reinterpret_cast(0x2234'0000); VkFence fence3 = reinterpret_cast(0x3234'0000); mPool.add(fence1); mPool.add(fence2); mPool.add(fence3); std::vector result = mPool.popAll(); ASSERT_THAT(result, UnorderedElementsAre(fence1, fence2, fence3)); } TEST_F(VkDecoderGlobalStateExternalFenceDeathTest, undestroyedFences) { ASSERT_DEATH( { ExternalFencePool pool(&mMockDispatch, mDevice); VkFence fence = reinterpret_cast(0x1234'0000); pool.add(fence); }, MatchesStdRegex( "External fence pool for device 0000000022220000|0x22220000 destroyed but 1 " "fences still not destroyed.")); } } // namespace } // namespace vk } // namespace gfxstream