1 // Copyright 2022 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <gmock/gmock.h>
16 #include <gtest/gtest.h>
17 
18 #include "vk_util.h"
19 
20 #include <vulkan/vulkan_core.h>
21 
22 #include <tuple>
23 
24 namespace gfxstream {
25 namespace vk {
26 namespace vk_util {
27 namespace vk_fn_info {
28 
29 // Register a fake Vulkan function for testing.
30 using PFN_vkGfxstreamTestFunc = PFN_vkCreateDevice;
31 REGISTER_VK_FN_INFO(GfxstreamTestFunc, ("vkGfxstreamTestFunc", "vkGfxstreamTestFuncGOOGLE",
32                                         "vkGfxstreamTestFuncGFXSTREAM"))
33 constexpr auto vkGfxstreamTestFuncNames = vk_fn_info::GetVkFnInfo<GfxstreamTestFunc>::names;
34 
35 namespace {
36 using ::testing::_;
37 using ::testing::MockFunction;
38 using ::testing::Return;
39 using ::testing::StrEq;
40 using ::testing::StrNe;
41 
TEST(getVkInstanceProcAddrWithFallbackTest,ShouldReturnNullOnFailure)42 TEST(getVkInstanceProcAddrWithFallbackTest, ShouldReturnNullOnFailure) {
43     VkInstance instance = reinterpret_cast<VkInstance>(0x1234'0000);
44     MockFunction<std::remove_pointer_t<PFN_vkGetInstanceProcAddr>> vkGetInstanceProcAddrAlwaysNULL;
45 
46     EXPECT_CALL(vkGetInstanceProcAddrAlwaysNULL, Call(instance, _)).WillRepeatedly(Return(nullptr));
47 
48     EXPECT_EQ(getVkInstanceProcAddrWithFallback<GfxstreamTestFunc>({}, instance), nullptr);
49     EXPECT_EQ(getVkInstanceProcAddrWithFallback<GfxstreamTestFunc>({nullptr, nullptr}, instance),
50               nullptr);
51     EXPECT_EQ(getVkInstanceProcAddrWithFallback<GfxstreamTestFunc>(
52                   {vkGetInstanceProcAddrAlwaysNULL.AsStdFunction(),
53                    vkGetInstanceProcAddrAlwaysNULL.AsStdFunction()},
54                   instance),
55               nullptr);
56 }
57 
TEST(getVkInstanceProcAddrWithFallbackTest,ShouldSkipNullVkGetInstanceProcAddr)58 TEST(getVkInstanceProcAddrWithFallbackTest, ShouldSkipNullVkGetInstanceProcAddr) {
59     VkInstance instance = reinterpret_cast<VkInstance>(0x1234'0000);
60     PFN_vkGfxstreamTestFunc validFp = reinterpret_cast<PFN_vkGfxstreamTestFunc>(0x4321'0000);
61     MockFunction<std::remove_pointer_t<PFN_vkGetInstanceProcAddr>> vkGetInstanceProcAddrMock;
62 
63     EXPECT_CALL(vkGetInstanceProcAddrMock, Call(instance, _))
64         .WillRepeatedly(Return(reinterpret_cast<PFN_vkVoidFunction>(validFp)));
65 
66     EXPECT_EQ(getVkInstanceProcAddrWithFallback<GfxstreamTestFunc>(
67                   {nullptr, vkGetInstanceProcAddrMock.AsStdFunction()}, instance),
68               validFp);
69     EXPECT_EQ(getVkInstanceProcAddrWithFallback<GfxstreamTestFunc>(
70                   {vkGetInstanceProcAddrMock.AsStdFunction(), nullptr}, instance),
71               validFp);
72 }
73 
TEST(getVkInstanceProcAddrWithFallbackTest,ShouldSkipNullFpReturned)74 TEST(getVkInstanceProcAddrWithFallbackTest, ShouldSkipNullFpReturned) {
75     VkInstance instance = reinterpret_cast<VkInstance>(0x1234'0000);
76     PFN_vkGfxstreamTestFunc validFp = reinterpret_cast<PFN_vkGfxstreamTestFunc>(0x4321'0000);
77     MockFunction<std::remove_pointer_t<PFN_vkGetInstanceProcAddr>> vkGetInstanceProcAddrMock;
78     MockFunction<std::remove_pointer_t<PFN_vkGetInstanceProcAddr>> vkGetInstanceProcAddrAlwaysNULL;
79 
80     // We know that vkGfxstreamTest has different names.
81     EXPECT_CALL(vkGetInstanceProcAddrMock,
82                 Call(instance, StrNe(std::get<1>(vkGfxstreamTestFuncNames))))
83         .WillRepeatedly(Return(nullptr));
84     EXPECT_CALL(vkGetInstanceProcAddrMock,
85                 Call(instance, StrEq(std::get<1>(vkGfxstreamTestFuncNames))))
86         .WillRepeatedly(Return(reinterpret_cast<PFN_vkVoidFunction>(validFp)));
87     EXPECT_CALL(vkGetInstanceProcAddrAlwaysNULL, Call(instance, _)).WillRepeatedly(Return(nullptr));
88 
89     EXPECT_EQ(getVkInstanceProcAddrWithFallback<GfxstreamTestFunc>(
90                   {vkGetInstanceProcAddrMock.AsStdFunction(),
91                    vkGetInstanceProcAddrAlwaysNULL.AsStdFunction()},
92                   instance),
93               validFp);
94     EXPECT_EQ(getVkInstanceProcAddrWithFallback<GfxstreamTestFunc>(
95                   {vkGetInstanceProcAddrAlwaysNULL.AsStdFunction(),
96                    vkGetInstanceProcAddrMock.AsStdFunction()},
97                   instance),
98               validFp);
99 }
100 
TEST(getVkInstanceProcAddrWithFallbackTest,firstVkInstanceProcAddrShouldTakeThePriority)101 TEST(getVkInstanceProcAddrWithFallbackTest, firstVkInstanceProcAddrShouldTakeThePriority) {
102     VkInstance instance = reinterpret_cast<VkInstance>(0x1234'0000);
103     PFN_vkGfxstreamTestFunc validFp1 = reinterpret_cast<PFN_vkGfxstreamTestFunc>(0x4321'0000);
104     PFN_vkGfxstreamTestFunc validFp2 = reinterpret_cast<PFN_vkGfxstreamTestFunc>(0x3421'0070);
105     MockFunction<std::remove_pointer_t<PFN_vkGetInstanceProcAddr>> vkGetInstanceProcAddrMock1;
106     MockFunction<std::remove_pointer_t<PFN_vkGetInstanceProcAddr>> vkGetInstanceProcAddrMock2;
107 
108     EXPECT_CALL(vkGetInstanceProcAddrMock1, Call(instance, _))
109         .WillRepeatedly(Return(reinterpret_cast<PFN_vkVoidFunction>(validFp1)));
110     EXPECT_CALL(vkGetInstanceProcAddrMock2, Call(instance, _))
111         .WillRepeatedly(Return(reinterpret_cast<PFN_vkVoidFunction>(validFp2)));
112 
113     EXPECT_EQ(getVkInstanceProcAddrWithFallback<GfxstreamTestFunc>(
114                   {vkGetInstanceProcAddrMock1.AsStdFunction(),
115                    vkGetInstanceProcAddrMock2.AsStdFunction()},
116                   instance),
117               validFp1);
118 }
119 
TEST(getVkInstanceProcAddrWithFallbackTest,firstNameShouldTakeThePriority)120 TEST(getVkInstanceProcAddrWithFallbackTest, firstNameShouldTakeThePriority) {
121     VkInstance instance = reinterpret_cast<VkInstance>(0x1234'0000);
122     PFN_vkGfxstreamTestFunc validFps[] = {reinterpret_cast<PFN_vkGfxstreamTestFunc>(0x4321'0000),
123                                           reinterpret_cast<PFN_vkGfxstreamTestFunc>(0x3421'0070),
124                                           reinterpret_cast<PFN_vkGfxstreamTestFunc>(0x2222'4321)};
125     MockFunction<std::remove_pointer_t<PFN_vkGetInstanceProcAddr>> vkGetInstanceProcAddrMock;
126 
127     EXPECT_CALL(vkGetInstanceProcAddrMock,
128                 Call(instance, StrEq(std::get<0>(vkGfxstreamTestFuncNames))))
129         .WillRepeatedly(Return(reinterpret_cast<PFN_vkVoidFunction>(validFps[0])));
130     ON_CALL(vkGetInstanceProcAddrMock, Call(instance, StrEq(std::get<1>(vkGfxstreamTestFuncNames))))
131         .WillByDefault(Return(reinterpret_cast<PFN_vkVoidFunction>(validFps[1])));
132     ON_CALL(vkGetInstanceProcAddrMock, Call(instance, StrEq(std::get<2>(vkGfxstreamTestFuncNames))))
133         .WillByDefault(Return(reinterpret_cast<PFN_vkVoidFunction>(validFps[2])));
134 
135     EXPECT_EQ(getVkInstanceProcAddrWithFallback<GfxstreamTestFunc>(
136                   {vkGetInstanceProcAddrMock.AsStdFunction()}, instance),
137               validFps[0]);
138 }
139 
TEST(VkCheckCallbacksDeathTest,deviceLostCallbackShouldBeCalled)140 TEST(VkCheckCallbacksDeathTest, deviceLostCallbackShouldBeCalled) {
141     setVkCheckCallbacks(std::make_unique<VkCheckCallbacks>(VkCheckCallbacks{
142         .onVkErrorDeviceLost = [] { exit(43); },
143     }));
144 
145     EXPECT_EXIT(VK_CHECK(VK_ERROR_DEVICE_LOST), testing::ExitedWithCode(43), "");
146 }
147 
TEST(VkCheckCallbacksDeathTest,deviceLostCallbackShouldNotBeCalled)148 TEST(VkCheckCallbacksDeathTest, deviceLostCallbackShouldNotBeCalled) {
149     // Default death function uses exit code 42
150     emugl::setDieFunction([] { exit(42); });
151 
152     // Device lost death function uses exit code 43
153     setVkCheckCallbacks(std::make_unique<VkCheckCallbacks>(VkCheckCallbacks{
154         .onVkErrorDeviceLost = [] { exit(43); },
155     }));
156 
157     EXPECT_EXIT(VK_CHECK(VK_ERROR_OUT_OF_DEVICE_MEMORY), testing::ExitedWithCode(42), "");
158 }
159 
TEST(VkCheckCallbacksDeathTest,nullCallbacksShouldntCrash)160 TEST(VkCheckCallbacksDeathTest, nullCallbacksShouldntCrash) {
161     emugl::setDieFunction([] { exit(42); });
162     setVkCheckCallbacks(nullptr);
163     EXPECT_EXIT(VK_CHECK(VK_ERROR_DEVICE_LOST), testing::ExitedWithCode(42), "");
164 }
165 
TEST(VkCheckCallbacksDeathTest,nullVkDeviceLostErrorCallbackShouldntCrash)166 TEST(VkCheckCallbacksDeathTest, nullVkDeviceLostErrorCallbackShouldntCrash) {
167     emugl::setDieFunction([] { exit(42); });
168     setVkCheckCallbacks(
169         std::make_unique<VkCheckCallbacks>(VkCheckCallbacks{.onVkErrorDeviceLost = nullptr}));
170     EXPECT_EXIT(VK_CHECK(VK_ERROR_DEVICE_LOST), testing::ExitedWithCode(42), "");
171 }
172 
173 template <typename T, class U = CrtpBase>
174 class ExampleCrtpClass1 : public U {
175    public:
doCtrp1()176     void doCtrp1() {
177         T& self = static_cast<T&>(*this);
178         EXPECT_EQ(self.value, 42);
179         self.doCtrp1WasCalled = true;
180     }
181 };
182 
183 template <typename T, class U = CrtpBase>
184 class ExampleCrtpClass2 : public U {
185    public:
doCtrp2()186     void doCtrp2() {
187         T& self = static_cast<T&>(*this);
188         EXPECT_EQ(self.value, 42);
189         self.doCtrp2WasCalled = true;
190     }
191 };
192 
193 template <typename T, class U = CrtpBase>
194 class ExampleCrtpClass3 : public U {
195    public:
doCtrp3()196     void doCtrp3() {
197         T& self = static_cast<T&>(*this);
198         EXPECT_EQ(self.value, 42);
199         self.doCtrp3WasCalled = true;
200     }
201 };
202 
203 struct MultiCrtpTestStruct
204     : MultiCrtp<MultiCrtpTestStruct, ExampleCrtpClass1, ExampleCrtpClass2, ExampleCrtpClass3> {
doCtrpMethodsgfxstream::vk::vk_util::vk_fn_info::__anon520c25a30111::MultiCrtpTestStruct205     void doCtrpMethods() {
206         doCtrp1();
207         doCtrp2();
208         doCtrp3();
209     }
210 
211     int value = 42;
212     bool doCtrp1WasCalled = false;
213     bool doCtrp2WasCalled = false;
214     bool doCtrp3WasCalled = false;
215 };
216 
TEST(MultiCrtp,MultiCrtp)217 TEST(MultiCrtp, MultiCrtp) {
218     MultiCrtpTestStruct object;
219     object.doCtrpMethods();
220     EXPECT_TRUE(object.doCtrp1WasCalled);
221     EXPECT_TRUE(object.doCtrp2WasCalled);
222     EXPECT_TRUE(object.doCtrp3WasCalled);
223 }
224 
TEST(vk_util,vk_insert_struct)225 TEST(vk_util, vk_insert_struct) {
226     VkDeviceCreateInfo deviceCi = {
227         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
228         .pNext = nullptr,
229     };
230     VkPhysicalDeviceFeatures2 physicalDeviceFeature = {
231         .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
232         .pNext = nullptr,
233     };
234     vk_insert_struct(deviceCi, physicalDeviceFeature);
235     ASSERT_EQ(deviceCi.pNext, &physicalDeviceFeature);
236     ASSERT_EQ(physicalDeviceFeature.pNext, nullptr);
237 
238     VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcrFeature = {
239         .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
240         .pNext = nullptr,
241     };
242     VkPhysicalDeviceDescriptorIndexingFeatures indexingFeatures = {
243         .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES,
244         .pNext = nullptr,
245     };
246     vk_insert_struct(ycbcrFeature, indexingFeatures);
247     ASSERT_EQ(ycbcrFeature.pNext, &indexingFeatures);
248     ASSERT_EQ(indexingFeatures.pNext, nullptr);
249 
250     vk_insert_struct(deviceCi, ycbcrFeature);
251     const VkBaseInStructure* base = reinterpret_cast<VkBaseInStructure*>(&deviceCi);
252     ASSERT_EQ(base, reinterpret_cast<VkBaseInStructure*>(&deviceCi));
253     base = base->pNext;
254     ASSERT_EQ(base, reinterpret_cast<VkBaseInStructure*>(&ycbcrFeature));
255     base = base->pNext;
256     ASSERT_EQ(base, reinterpret_cast<VkBaseInStructure*>(&indexingFeatures));
257     base = base->pNext;
258     ASSERT_EQ(base, reinterpret_cast<VkBaseInStructure*>(&physicalDeviceFeature));
259     base = base->pNext;
260     ASSERT_EQ(base, nullptr);
261 }
262 
263 }  // namespace
264 }  // namespace vk_fn_info
265 }  // namespace vk_util
266 }  // namespace vk
267 }  // namespace gfxstream
268