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