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