1 // Copyright (C) 2018 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 <gtest/gtest.h>
16
17 #include "FrameBuffer.h"
18 #include "VkCommonOperations.h"
19 #include "VulkanDispatch.h"
20
21 #include "aemu/base/ArraySize.h"
22 #include "aemu/base/GLObjectCounter.h"
23 #include "aemu/base/files/PathUtils.h"
24 #include "aemu/base/system/System.h"
25 #include "aemu/base/testing/TestSystem.h"
26 #include "host-common/GraphicsAgentFactory.h"
27 #include "host-common/opengl/misc.h"
28 #include "host-common/testing/MockGraphicsAgentFactory.h"
29 #include "tests/VkTestUtils.h"
30
31 #include "Standalone.h"
32
33 #include <sstream>
34 #include <string>
35 #include <vulkan/vulkan.h>
36
37 #ifdef _WIN32
38 #include <windows.h>
39 #include "aemu/base/system/Win32UnicodeString.h"
40 using android::base::Win32UnicodeString;
41 #else
42 #include <dlfcn.h>
43 #endif
44
45 using android::base::arraySize;
46 using android::base::pj;
47 using android::base::TestSystem;
48
49 namespace gfxstream {
50 namespace vk {
51 namespace {
52
53 static constexpr const HandleType kArbitraryColorBufferHandle = 5;
54
55 #ifdef _WIN32
56 #define SKIP_TEST_IF_WIN32() GTEST_SKIP()
57 #else
58 #define SKIP_TEST_IF_WIN32()
59 #endif
60
deviceTypeToString(VkPhysicalDeviceType type)61 static std::string deviceTypeToString(VkPhysicalDeviceType type) {
62 #define DO_ENUM_RETURN_STRING(e) \
63 case e: \
64 return #e; \
65
66 switch (type) {
67 DO_ENUM_RETURN_STRING(VK_PHYSICAL_DEVICE_TYPE_OTHER)
68 DO_ENUM_RETURN_STRING(VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
69 DO_ENUM_RETURN_STRING(VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
70 DO_ENUM_RETURN_STRING(VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU)
71 DO_ENUM_RETURN_STRING(VK_PHYSICAL_DEVICE_TYPE_CPU)
72 default:
73 return "Unknown";
74 }
75 }
76
queueFlagsToString(VkQueueFlags queueFlags)77 static std::string queueFlagsToString(VkQueueFlags queueFlags) {
78 std::stringstream ss;
79
80 if (queueFlags & VK_QUEUE_GRAPHICS_BIT) {
81 ss << "VK_QUEUE_GRAPHICS_BIT | ";
82 }
83 if (queueFlags & VK_QUEUE_COMPUTE_BIT) {
84 ss << "VK_QUEUE_COMPUTE_BIT | ";
85 }
86 if (queueFlags & VK_QUEUE_TRANSFER_BIT) {
87 ss << "VK_QUEUE_TRANSFER_BIT | ";
88 }
89 if (queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) {
90 ss << "VK_QUEUE_SPARSE_BINDING_BIT | ";
91 }
92 if (queueFlags & VK_QUEUE_PROTECTED_BIT) {
93 ss << "VK_QUEUE_PROTECTED_BIT";
94 }
95
96 return ss.str();
97 }
98
getPhysicalDevicePropertiesString(const VulkanDispatch * vk,VkPhysicalDevice physicalDevice,const VkPhysicalDeviceProperties & props)99 static std::string getPhysicalDevicePropertiesString(const VulkanDispatch* vk,
100 VkPhysicalDevice physicalDevice,
101 const VkPhysicalDeviceProperties& props) {
102 std::stringstream ss;
103
104 uint16_t apiMaj = (uint16_t)(props.apiVersion >> 22);
105 uint16_t apiMin = (uint16_t)(0x000003ff & (props.apiVersion >> 12));
106 uint16_t apiPatch = (uint16_t)(0x000007ff & (props.apiVersion));
107
108 ss << "API version: " << apiMaj << "." << apiMin << "." << apiPatch << "\n";
109 ss << "Driver version: " << std::hex << props.driverVersion << "\n";
110 ss << "Vendor ID: " << std::hex << props.vendorID << "\n";
111 ss << "Device ID: " << std::hex << props.deviceID << "\n";
112 ss << "Device type: " << deviceTypeToString(props.deviceType) << "\n";
113 ss << "Device name: " << props.deviceName << "\n";
114
115 uint32_t deviceExtensionCount;
116 std::vector<VkExtensionProperties> deviceExtensionProperties;
117 vk->vkEnumerateDeviceExtensionProperties(
118 physicalDevice,
119 nullptr,
120 &deviceExtensionCount,
121 nullptr);
122
123 deviceExtensionProperties.resize(deviceExtensionCount);
124 vk->vkEnumerateDeviceExtensionProperties(
125 physicalDevice,
126 nullptr,
127 &deviceExtensionCount,
128 deviceExtensionProperties.data());
129
130 for (uint32_t i = 0; i < deviceExtensionCount; ++i) {
131 ss << "Device extension: " <<
132 deviceExtensionProperties[i].extensionName << "\n";
133 }
134
135 return ss.str();
136 }
137
testInstanceCreation(const VulkanDispatch * vk,VkInstance * instance_out)138 static void testInstanceCreation(const VulkanDispatch* vk,
139 VkInstance* instance_out) {
140
141 EXPECT_TRUE(vk->vkEnumerateInstanceExtensionProperties);
142 EXPECT_TRUE(vk->vkCreateInstance);
143
144 uint32_t count;
145 vk->vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
146
147 fprintf(stderr, "%s: exts: %u\n", __func__, count);
148
149 std::vector<VkExtensionProperties> props(count);
150 vk->vkEnumerateInstanceExtensionProperties(nullptr, &count, props.data());
151
152 for (uint32_t i = 0; i < count; i++) {
153 fprintf(stderr, "%s: ext: %s\n", __func__, props[i].extensionName);
154 }
155
156 VkInstanceCreateInfo instanceCreateInfo = {
157 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0,
158 nullptr,
159 0, nullptr,
160 0, nullptr,
161 };
162
163 VkInstance instance;
164
165 EXPECT_EQ(VK_SUCCESS,
166 vk->vkCreateInstance(
167 &instanceCreateInfo, nullptr, &instance));
168
169 *instance_out = instance;
170 }
171
testDeviceCreation(const VulkanDispatch * vk,VkInstance instance,VkPhysicalDevice * physDevice_out,VkDevice * device_out)172 static void testDeviceCreation(const VulkanDispatch* vk,
173 VkInstance instance,
174 VkPhysicalDevice* physDevice_out,
175 VkDevice* device_out) {
176
177 fprintf(stderr, "%s: call\n", __func__);
178
179 EXPECT_TRUE(vk->vkEnumeratePhysicalDevices);
180 EXPECT_TRUE(vk->vkGetPhysicalDeviceProperties);
181 EXPECT_TRUE(vk->vkGetPhysicalDeviceQueueFamilyProperties);
182
183 uint32_t physicalDeviceCount;
184 std::vector<VkPhysicalDevice> physicalDevices;
185
186 EXPECT_EQ(VK_SUCCESS,
187 vk->vkEnumeratePhysicalDevices(
188 instance, &physicalDeviceCount, nullptr));
189
190 physicalDevices.resize(physicalDeviceCount);
191
192 EXPECT_EQ(VK_SUCCESS,
193 vk->vkEnumeratePhysicalDevices(
194 instance, &physicalDeviceCount, physicalDevices.data()));
195
196 std::vector<VkPhysicalDeviceProperties> physicalDeviceProps(physicalDeviceCount);
197
198 // at the end of the day, we need to pick a physical device.
199 // Pick one that has graphics + compute if possible, otherwise settle for a device
200 // that has at least one queue family capable of graphics.
201 // TODO: Pick the device that has present capability for that queue if
202 // we are not running in no-window mode.
203
204 bool bestPhysicalDeviceFound = false;
205 uint32_t bestPhysicalDeviceIndex = 0;
206
207 std::vector<uint32_t> physDevsWithBothGraphicsAndCompute;
208 std::vector<uint32_t> physDevsWithGraphicsOnly;
209
210 for (uint32_t i = 0; i < physicalDeviceCount; i++) {
211 uint32_t deviceExtensionCount;
212 std::vector<VkExtensionProperties> deviceExtensionProperties;
213 vk->vkEnumerateDeviceExtensionProperties(
214 physicalDevices[i],
215 nullptr,
216 &deviceExtensionCount,
217 nullptr);
218
219 deviceExtensionProperties.resize(deviceExtensionCount);
220 vk->vkEnumerateDeviceExtensionProperties(
221 physicalDevices[i],
222 nullptr,
223 &deviceExtensionCount,
224 deviceExtensionProperties.data());
225
226 bool hasSwapchainExtension = false;
227
228 fprintf(stderr, "%s: check swapchain ext\n", __func__);
229 for (uint32_t j = 0; j < deviceExtensionCount; j++) {
230 std::string ext = deviceExtensionProperties[j].extensionName;
231 if (ext == "VK_KHR_swapchain") {
232 hasSwapchainExtension = true;
233 }
234 }
235
236 if (!hasSwapchainExtension) continue;
237
238 vk->vkGetPhysicalDeviceProperties(
239 physicalDevices[i],
240 physicalDeviceProps.data() + i);
241
242 auto str = getPhysicalDevicePropertiesString(vk, physicalDevices[i], physicalDeviceProps[i]);
243 fprintf(stderr, "device %u: %s\n", i, str.c_str());
244
245 uint32_t queueFamilyCount;
246 vk->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevices[i], &queueFamilyCount, nullptr);
247
248 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
249 vk->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevices[i], &queueFamilyCount, queueFamilies.data());
250
251 bool hasGraphicsQueue = false;
252 bool hasComputeQueue = false;
253
254 for (uint32_t j = 0; j < queueFamilyCount; j++) {
255 if (queueFamilies[j].queueCount > 0) {
256
257 auto flags = queueFamilies[j].queueFlags;
258 auto flagsAsString =
259 queueFlagsToString(flags);
260
261 fprintf(stderr, "%s: found %u @ family %u with caps: %s\n",
262 __func__,
263 queueFamilies[j].queueCount, j,
264 flagsAsString.c_str());
265
266 if ((flags & VK_QUEUE_GRAPHICS_BIT) &&
267 (flags & VK_QUEUE_COMPUTE_BIT)) {
268 hasGraphicsQueue = true;
269 hasComputeQueue = true;
270 bestPhysicalDeviceFound = true;
271 break;
272 }
273
274 if (flags & VK_QUEUE_GRAPHICS_BIT) {
275 hasGraphicsQueue = true;
276 bestPhysicalDeviceFound = true;
277 }
278
279 if (flags & VK_QUEUE_COMPUTE_BIT) {
280 hasComputeQueue = true;
281 bestPhysicalDeviceFound = true;
282 }
283 }
284 }
285
286 if (hasGraphicsQueue && hasComputeQueue) {
287 physDevsWithBothGraphicsAndCompute.push_back(i);
288 break;
289 }
290
291 if (hasGraphicsQueue) {
292 physDevsWithGraphicsOnly.push_back(i);
293 }
294 }
295
296 EXPECT_TRUE(bestPhysicalDeviceFound);
297
298 if (physDevsWithBothGraphicsAndCompute.size() > 0) {
299 bestPhysicalDeviceIndex = physDevsWithBothGraphicsAndCompute[0];
300 } else if (physDevsWithGraphicsOnly.size() > 0) {
301 bestPhysicalDeviceIndex = physDevsWithGraphicsOnly[0];
302 } else {
303 EXPECT_TRUE(false);
304 return;
305 }
306
307 // Now we got our device; select it
308 VkPhysicalDevice bestPhysicalDevice = physicalDevices[bestPhysicalDeviceIndex];
309
310 uint32_t queueFamilyCount;
311 vk->vkGetPhysicalDeviceQueueFamilyProperties(
312 bestPhysicalDevice, &queueFamilyCount, nullptr);
313
314 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
315 vk->vkGetPhysicalDeviceQueueFamilyProperties(
316 bestPhysicalDevice, &queueFamilyCount, queueFamilies.data());
317
318 std::vector<uint32_t> wantedQueueFamilies;
319 std::vector<uint32_t> wantedQueueFamilyCounts;
320
321 for (uint32_t i = 0; i < queueFamilyCount; i++) {
322 if (queueFamilies[i].queueCount > 0) {
323 auto flags = queueFamilies[i].queueFlags;
324 if ((flags & VK_QUEUE_GRAPHICS_BIT) &&
325 (flags & VK_QUEUE_COMPUTE_BIT)) {
326 wantedQueueFamilies.push_back(i);
327 wantedQueueFamilyCounts.push_back(queueFamilies[i].queueCount);
328 break;
329 }
330
331 if ((flags & VK_QUEUE_GRAPHICS_BIT) ||
332 (flags & VK_QUEUE_COMPUTE_BIT)) {
333 wantedQueueFamilies.push_back(i);
334 wantedQueueFamilyCounts.push_back(queueFamilies[i].queueCount);
335 }
336 }
337 }
338
339 std::vector<VkDeviceQueueCreateInfo> queueCis;
340
341 for (uint32_t i = 0; i < wantedQueueFamilies.size(); ++i) {
342 auto familyIndex = wantedQueueFamilies[i];
343 auto queueCount = wantedQueueFamilyCounts[i];
344
345 std::vector<float> priorities;
346
347 for (uint32_t j = 0; j < queueCount; ++j) {
348 priorities.push_back(1.0f);
349 }
350
351 VkDeviceQueueCreateInfo dqci = {
352 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0,
353 familyIndex,
354 queueCount,
355 priorities.data(),
356 };
357
358 queueCis.push_back(dqci);
359 }
360
361 const char* exts[] = {
362 "VK_KHR_swapchain",
363 };
364
365 VkDeviceCreateInfo ci = {
366 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0,
367 (uint32_t)queueCis.size(),
368 queueCis.data(),
369 0, nullptr,
370 arraySize(exts), exts,
371 nullptr,
372 };
373
374 VkDevice device;
375 EXPECT_EQ(VK_SUCCESS,
376 vk->vkCreateDevice(bestPhysicalDevice, &ci, nullptr, &device));
377
378 *physDevice_out = bestPhysicalDevice;
379 *device_out = device;
380 }
381
teardownVulkanTest(const VulkanDispatch * vk,VkDevice dev,VkInstance instance)382 static void teardownVulkanTest(const VulkanDispatch* vk,
383 VkDevice dev,
384 VkInstance instance) {
385 vk->vkDestroyDevice(dev, nullptr);
386 vk->vkDestroyInstance(instance, nullptr);
387 }
388
389 class VulkanTest : public ::testing::Test {
390 protected:
SetUpTestSuite()391 static void SetUpTestSuite() {
392 android::emulation::injectGraphicsAgents(
393 android::emulation::MockGraphicsAgentFactory());
394 }
395
TearDownTestSuite()396 static void TearDownTestSuite() { }
397
SetUp()398 void SetUp() override {
399 auto dispatch = vkDispatch(false);
400 ASSERT_NE(dispatch, nullptr);
401 mVk = *dispatch;
402
403 testInstanceCreation(&mVk, &mInstance);
404 testDeviceCreation(&mVk, mInstance, &mPhysicalDevice, &mDevice);
405 }
406
TearDown()407 void TearDown() override {
408 teardownVulkanTest(&mVk, mDevice, mInstance);
409 }
410
411 VulkanDispatch mVk;
412 VkInstance mInstance;
413 VkPhysicalDevice mPhysicalDevice;
414 VkDevice mDevice;
415 };
416
417 // Basic Vulkan instance/device setup.
TEST_F(VulkanTest,Basic)418 TEST_F(VulkanTest, Basic) { }
419
420 // Checks that staging memory query is successful.
TEST_F(VulkanTest,StagingMemoryQuery)421 TEST_F(VulkanTest, StagingMemoryQuery) {
422 VkPhysicalDeviceMemoryProperties memProps;
423 uint32_t typeIndex;
424
425 mVk.vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memProps);
426
427 EXPECT_TRUE(getStagingMemoryTypeIndex(&mVk, mDevice, &memProps, &typeIndex));
428 }
429
430 #ifndef _WIN32 // TODO: Get this working w/ Swiftshader vk on Windows
431 class VulkanFrameBufferTest : public VulkanTest {
432 protected:
SetUp()433 void SetUp() override {
434 // SwiftShader Vulkan doesn't work on Windows, so we skip all
435 // the rendering tests on Windows for now.
436 SKIP_TEST_IF_WIN32();
437
438 gfxstream::host::FeatureSet features;
439 features.GlesDynamicVersion.enabled = true;
440 features.PlayStoreImage.enabled = true;
441 features.Vulkan.enabled = true;
442 features.VulkanIgnoredHandles.enabled = true;
443
444 VulkanTest::SetUp();
445
446 emugl::setGLObjectCounter(android::base::GLObjectCounter::get());
447 emugl::set_emugl_window_operations(*getGraphicsAgents()->emu);
448 emugl::set_emugl_multi_display_operations(*getGraphicsAgents()->multi_display);
449 ASSERT_NE(nullptr, gl::LazyLoadedEGLDispatch::get());
450 ASSERT_NE(nullptr, gl::LazyLoadedGLESv2Dispatch::get());
451
452 bool useHostGpu = false;
453 EXPECT_TRUE(FrameBuffer::initialize(mWidth, mHeight, features, false,
454 !useHostGpu /* egl2egl */));
455 mFb = FrameBuffer::getFB();
456 ASSERT_NE(nullptr, mFb);
457 mRenderThreadInfo = std::make_unique<RenderThreadInfo>();
458 }
459
TearDown()460 void TearDown() override {
461 VulkanTest::TearDown();
462 if (mFb) { FrameBuffer::finalize(); }
463 if (mRenderThreadInfo) mRenderThreadInfo.reset();
464 }
465
466 FrameBuffer* mFb = nullptr;
467 std::unique_ptr<RenderThreadInfo> mRenderThreadInfo;
468
469 constexpr static uint32_t mWidth = 640u;
470 constexpr static uint32_t mHeight = 480u;
471 };
472
TEST_F(VulkanFrameBufferTest,VkColorBufferWithoutMemoryProperties)473 TEST_F(VulkanFrameBufferTest, VkColorBufferWithoutMemoryProperties) {
474 // Create a color buffer without any memory properties restriction.
475 EXPECT_TRUE(createVkColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE,
476 kArbitraryColorBufferHandle, true, /* vulkanOnly */
477 0 /* memoryProperty */
478 ));
479 EXPECT_TRUE(teardownVkColorBuffer(kArbitraryColorBufferHandle));
480 }
481
TEST_F(VulkanFrameBufferTest,VkColorBufferWithMemoryPropertyFlags)482 TEST_F(VulkanFrameBufferTest, VkColorBufferWithMemoryPropertyFlags) {
483 auto* vkEmulation = getGlobalVkEmulation();
484 VkMemoryPropertyFlags kTargetMemoryPropertyFlags =
485 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
486
487 // Create a Vulkan image with the same dimension and usage as
488 // the color buffer, to get a possible memory type index.
489 VkImageCreateInfo testImageCi = {
490 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
491 nullptr,
492 0,
493 VK_IMAGE_TYPE_2D,
494 VK_FORMAT_R8G8B8A8_UNORM,
495 {
496 mWidth,
497 mHeight,
498 1,
499 },
500 1,
501 1,
502 VK_SAMPLE_COUNT_1_BIT,
503 VK_IMAGE_TILING_OPTIMAL,
504 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
505 VK_SHARING_MODE_EXCLUSIVE,
506 0,
507 nullptr /* shared queue families */,
508 VK_IMAGE_LAYOUT_UNDEFINED,
509 };
510 VkImage image;
511 mVk.vkCreateImage(mDevice, &testImageCi, nullptr, &image);
512
513 VkMemoryRequirements memReq;
514 mVk.vkGetImageMemoryRequirements(mDevice, image, &memReq);
515
516 mVk.vkDestroyImage(mDevice, image, nullptr);
517
518 if (!memReq.memoryTypeBits) {
519 GTEST_SKIP();
520 }
521
522 int32_t memoryTypeIndex = 31;
523 do {
524 if (((1 << memoryTypeIndex) & memReq.memoryTypeBits) &&
525 (vkEmulation->deviceInfo.memProps.memoryTypes[memoryTypeIndex]
526 .propertyFlags &
527 kTargetMemoryPropertyFlags)) {
528 break;
529 }
530 } while (--memoryTypeIndex >= 0);
531
532 if (memoryTypeIndex < 0) {
533 fprintf(stderr,
534 "No memory type supported for HOST_VISBILE memory "
535 "properties. Test skipped.\n");
536 GTEST_SKIP();
537 }
538
539 // Create a color buffer with the target memory property flags.
540 EXPECT_TRUE(createVkColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE,
541 kArbitraryColorBufferHandle, true, /* vulkanOnly */
542 static_cast<uint32_t>(kTargetMemoryPropertyFlags)));
543
544 uint32_t allocatedTypeIndex = 0u;
545 EXPECT_TRUE(getColorBufferAllocationInfo(kArbitraryColorBufferHandle, nullptr,
546 &allocatedTypeIndex, nullptr, nullptr));
547
548 EXPECT_TRUE(vkEmulation->deviceInfo.memProps.memoryTypes[allocatedTypeIndex]
549 .propertyFlags &
550 kTargetMemoryPropertyFlags);
551
552 EXPECT_TRUE(teardownVkColorBuffer(kArbitraryColorBufferHandle));
553 }
554
555 #endif // !_WIN32
556
557 } // namespace
558 } // namespace vk
559 } // namespace gfxstream
560