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