• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "aemu/base/ArraySize.h"
23 #include "aemu/base/GLObjectCounter.h"
24 #include "aemu/base/files/PathUtils.h"
25 #include "aemu/base/system/System.h"
26 #include "aemu/base/testing/TestSystem.h"
27 #include "host-common/GraphicsAgentFactory.h"
28 #include "host-common/opengl/misc.h"
29 #include "host-common/testing/MockGraphicsAgentFactory.h"
30 #include "tests/VkTestUtils.h"
31 
32 #include "Standalone.h"
33 
34 #include <sstream>
35 #include <string>
36 #include <vulkan/vulkan.h>
37 
38 #ifdef _WIN32
39 #include <windows.h>
40 #include "aemu/base/system/Win32UnicodeString.h"
41 using android::base::Win32UnicodeString;
42 #else
43 #include <dlfcn.h>
44 #endif
45 
46 using android::base::arraySize;
47 using android::base::pj;
48 using android::base::TestSystem;
49 
50 namespace gfxstream {
51 namespace vk {
52 namespace {
53 
54 static constexpr const HandleType kArbitraryColorBufferHandle = 5;
55 
56 #ifdef _WIN32
57 #define SKIP_TEST_IF_WIN32() GTEST_SKIP()
58 #else
59 #define SKIP_TEST_IF_WIN32()
60 #endif
61 
deviceTypeToString(VkPhysicalDeviceType type)62 static std::string deviceTypeToString(VkPhysicalDeviceType type) {
63 #define DO_ENUM_RETURN_STRING(e) \
64     case e: \
65         return #e; \
66 
67     switch (type) {
68     DO_ENUM_RETURN_STRING(VK_PHYSICAL_DEVICE_TYPE_OTHER)
69     DO_ENUM_RETURN_STRING(VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
70     DO_ENUM_RETURN_STRING(VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
71     DO_ENUM_RETURN_STRING(VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU)
72     DO_ENUM_RETURN_STRING(VK_PHYSICAL_DEVICE_TYPE_CPU)
73         default:
74             return "Unknown";
75     }
76 }
77 
queueFlagsToString(VkQueueFlags queueFlags)78 static std::string queueFlagsToString(VkQueueFlags queueFlags) {
79     std::stringstream ss;
80 
81     if (queueFlags & VK_QUEUE_GRAPHICS_BIT) {
82         ss << "VK_QUEUE_GRAPHICS_BIT | ";
83     }
84     if (queueFlags & VK_QUEUE_COMPUTE_BIT) {
85         ss << "VK_QUEUE_COMPUTE_BIT | ";
86     }
87     if (queueFlags & VK_QUEUE_TRANSFER_BIT) {
88         ss << "VK_QUEUE_TRANSFER_BIT | ";
89     }
90     if (queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) {
91         ss << "VK_QUEUE_SPARSE_BINDING_BIT | ";
92     }
93     if (queueFlags & VK_QUEUE_PROTECTED_BIT) {
94         ss << "VK_QUEUE_PROTECTED_BIT";
95     }
96 
97     return ss.str();
98 }
99 
getPhysicalDevicePropertiesString(const VulkanDispatch * vk,VkPhysicalDevice physicalDevice,const VkPhysicalDeviceProperties & props)100 static std::string getPhysicalDevicePropertiesString(const VulkanDispatch* vk,
101                                                      VkPhysicalDevice physicalDevice,
102                                                      const VkPhysicalDeviceProperties& props) {
103     std::stringstream ss;
104 
105     uint16_t apiMaj = (uint16_t)(props.apiVersion >> 22);
106     uint16_t apiMin = (uint16_t)(0x000003ff & (props.apiVersion >> 12));
107     uint16_t apiPatch = (uint16_t)(0x000007ff & (props.apiVersion));
108 
109     ss << "API version: " << apiMaj << "." << apiMin << "." << apiPatch << "\n";
110     ss << "Driver version: " << std::hex << props.driverVersion << "\n";
111     ss << "Vendor ID: " << std::hex << props.vendorID << "\n";
112     ss << "Device ID: " << std::hex << props.deviceID << "\n";
113     ss << "Device type: " << deviceTypeToString(props.deviceType) << "\n";
114     ss << "Device name: " << props.deviceName << "\n";
115 
116     uint32_t deviceExtensionCount;
117     std::vector<VkExtensionProperties> deviceExtensionProperties;
118     vk->vkEnumerateDeviceExtensionProperties(
119         physicalDevice,
120         nullptr,
121         &deviceExtensionCount,
122         nullptr);
123 
124     deviceExtensionProperties.resize(deviceExtensionCount);
125     vk->vkEnumerateDeviceExtensionProperties(
126         physicalDevice,
127         nullptr,
128         &deviceExtensionCount,
129         deviceExtensionProperties.data());
130 
131     for (uint32_t i = 0; i < deviceExtensionCount; ++i) {
132         ss << "Device extension: " <<
133             deviceExtensionProperties[i].extensionName << "\n";
134     }
135 
136     return ss.str();
137 }
138 
testInstanceCreation(const VulkanDispatch * vk,VkInstance * instance_out)139 static void testInstanceCreation(const VulkanDispatch* vk,
140                                  VkInstance* instance_out) {
141 
142     EXPECT_TRUE(vk->vkEnumerateInstanceExtensionProperties);
143     EXPECT_TRUE(vk->vkCreateInstance);
144 
145     uint32_t count;
146     vk->vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
147 
148     fprintf(stderr, "%s: exts: %u\n", __func__, count);
149 
150     std::vector<VkExtensionProperties> props(count);
151     vk->vkEnumerateInstanceExtensionProperties(nullptr, &count, props.data());
152 
153     for (uint32_t i = 0; i < count; i++) {
154         fprintf(stderr, "%s: ext: %s\n", __func__, props[i].extensionName);
155     }
156 
157     VkInstanceCreateInfo instanceCreateInfo = {
158         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0,
159         nullptr,
160         0, nullptr,
161         0, nullptr,
162     };
163 
164     VkInstance instance;
165 
166     EXPECT_EQ(VK_SUCCESS,
167         vk->vkCreateInstance(
168             &instanceCreateInfo, nullptr, &instance));
169 
170     *instance_out = instance;
171 }
172 
testDeviceCreation(const VulkanDispatch * vk,VkInstance instance,VkPhysicalDevice * physDevice_out,VkDevice * device_out)173 static void testDeviceCreation(const VulkanDispatch* vk,
174                                VkInstance instance,
175                                VkPhysicalDevice* physDevice_out,
176                                VkDevice* device_out) {
177 
178     fprintf(stderr, "%s: call\n", __func__);
179 
180     EXPECT_TRUE(vk->vkEnumeratePhysicalDevices);
181     EXPECT_TRUE(vk->vkGetPhysicalDeviceProperties);
182     EXPECT_TRUE(vk->vkGetPhysicalDeviceQueueFamilyProperties);
183 
184     uint32_t physicalDeviceCount;
185     std::vector<VkPhysicalDevice> physicalDevices;
186 
187     EXPECT_EQ(VK_SUCCESS,
188         vk->vkEnumeratePhysicalDevices(
189             instance, &physicalDeviceCount, nullptr));
190 
191     physicalDevices.resize(physicalDeviceCount);
192 
193     EXPECT_EQ(VK_SUCCESS,
194         vk->vkEnumeratePhysicalDevices(
195             instance, &physicalDeviceCount, physicalDevices.data()));
196 
197     std::vector<VkPhysicalDeviceProperties> physicalDeviceProps(physicalDeviceCount);
198 
199     // at the end of the day, we need to pick a physical device.
200     // Pick one that has graphics + compute if possible, otherwise settle for a device
201     // that has at least one queue family capable of graphics.
202     // TODO: Pick the device that has present capability for that queue if
203     // we are not running in no-window mode.
204 
205     bool bestPhysicalDeviceFound = false;
206     uint32_t bestPhysicalDeviceIndex = 0;
207 
208     std::vector<uint32_t> physDevsWithBothGraphicsAndCompute;
209     std::vector<uint32_t> physDevsWithGraphicsOnly;
210 
211     for (uint32_t i = 0; i < physicalDeviceCount; i++) {
212         uint32_t deviceExtensionCount;
213         std::vector<VkExtensionProperties> deviceExtensionProperties;
214         vk->vkEnumerateDeviceExtensionProperties(
215             physicalDevices[i],
216             nullptr,
217             &deviceExtensionCount,
218             nullptr);
219 
220         deviceExtensionProperties.resize(deviceExtensionCount);
221         vk->vkEnumerateDeviceExtensionProperties(
222             physicalDevices[i],
223             nullptr,
224             &deviceExtensionCount,
225             deviceExtensionProperties.data());
226 
227         bool hasSwapchainExtension = false;
228 
229         fprintf(stderr, "%s: check swapchain ext\n", __func__);
230         for (uint32_t j = 0; j < deviceExtensionCount; j++) {
231             std::string ext = deviceExtensionProperties[j].extensionName;
232             if (ext == "VK_KHR_swapchain") {
233                 hasSwapchainExtension = true;
234             }
235         }
236 
237         if (!hasSwapchainExtension) continue;
238 
239         vk->vkGetPhysicalDeviceProperties(
240             physicalDevices[i],
241             physicalDeviceProps.data() + i);
242 
243         auto str = getPhysicalDevicePropertiesString(vk, physicalDevices[i], physicalDeviceProps[i]);
244         fprintf(stderr, "device %u: %s\n", i, str.c_str());
245 
246         uint32_t queueFamilyCount;
247         vk->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevices[i], &queueFamilyCount, nullptr);
248 
249         std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
250         vk->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevices[i], &queueFamilyCount, queueFamilies.data());
251 
252         bool hasGraphicsQueue = false;
253         bool hasComputeQueue = false;
254 
255         for (uint32_t j = 0; j < queueFamilyCount; j++) {
256             if (queueFamilies[j].queueCount > 0) {
257 
258                 auto flags = queueFamilies[j].queueFlags;
259                 auto flagsAsString =
260                     queueFlagsToString(flags);
261 
262                 fprintf(stderr, "%s: found %u @ family %u with caps: %s\n",
263                         __func__,
264                         queueFamilies[j].queueCount, j,
265                         flagsAsString.c_str());
266 
267                 if ((flags & VK_QUEUE_GRAPHICS_BIT) &&
268                     (flags & VK_QUEUE_COMPUTE_BIT)) {
269                     hasGraphicsQueue = true;
270                     hasComputeQueue = true;
271                     bestPhysicalDeviceFound = true;
272                     break;
273                 }
274 
275                 if (flags & VK_QUEUE_GRAPHICS_BIT) {
276                     hasGraphicsQueue = true;
277                     bestPhysicalDeviceFound = true;
278                 }
279 
280                 if (flags & VK_QUEUE_COMPUTE_BIT) {
281                     hasComputeQueue = true;
282                     bestPhysicalDeviceFound = true;
283                 }
284             }
285         }
286 
287         if (hasGraphicsQueue && hasComputeQueue) {
288             physDevsWithBothGraphicsAndCompute.push_back(i);
289             break;
290         }
291 
292         if (hasGraphicsQueue) {
293             physDevsWithGraphicsOnly.push_back(i);
294         }
295     }
296 
297     EXPECT_TRUE(bestPhysicalDeviceFound);
298 
299     if (physDevsWithBothGraphicsAndCompute.size() > 0) {
300         bestPhysicalDeviceIndex = physDevsWithBothGraphicsAndCompute[0];
301     } else if (physDevsWithGraphicsOnly.size() > 0) {
302         bestPhysicalDeviceIndex = physDevsWithGraphicsOnly[0];
303     } else {
304         EXPECT_TRUE(false);
305         return;
306     }
307 
308     // Now we got our device; select it
309     VkPhysicalDevice bestPhysicalDevice = physicalDevices[bestPhysicalDeviceIndex];
310 
311     uint32_t queueFamilyCount;
312     vk->vkGetPhysicalDeviceQueueFamilyProperties(
313         bestPhysicalDevice, &queueFamilyCount, nullptr);
314 
315     std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
316     vk->vkGetPhysicalDeviceQueueFamilyProperties(
317         bestPhysicalDevice, &queueFamilyCount, queueFamilies.data());
318 
319     std::vector<uint32_t> wantedQueueFamilies;
320     std::vector<uint32_t> wantedQueueFamilyCounts;
321 
322     for (uint32_t i = 0; i < queueFamilyCount; i++) {
323         if (queueFamilies[i].queueCount > 0) {
324             auto flags = queueFamilies[i].queueFlags;
325             if ((flags & VK_QUEUE_GRAPHICS_BIT) &&
326                     (flags & VK_QUEUE_COMPUTE_BIT)) {
327                 wantedQueueFamilies.push_back(i);
328                 wantedQueueFamilyCounts.push_back(queueFamilies[i].queueCount);
329                 break;
330             }
331 
332             if ((flags & VK_QUEUE_GRAPHICS_BIT) ||
333                     (flags & VK_QUEUE_COMPUTE_BIT)) {
334                 wantedQueueFamilies.push_back(i);
335                 wantedQueueFamilyCounts.push_back(queueFamilies[i].queueCount);
336             }
337         }
338     }
339 
340     std::vector<VkDeviceQueueCreateInfo> queueCis;
341 
342     for (uint32_t i = 0; i < wantedQueueFamilies.size(); ++i) {
343         auto familyIndex = wantedQueueFamilies[i];
344         auto queueCount = wantedQueueFamilyCounts[i];
345 
346         std::vector<float> priorities;
347 
348         for (uint32_t j = 0; j < queueCount; ++j) {
349             priorities.push_back(1.0f);
350         }
351 
352         VkDeviceQueueCreateInfo dqci = {
353             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0,
354             familyIndex,
355             queueCount,
356             priorities.data(),
357         };
358 
359         queueCis.push_back(dqci);
360     }
361 
362     const char* exts[] = {
363         "VK_KHR_swapchain",
364     };
365 
366     VkDeviceCreateInfo ci = {
367         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0,
368         (uint32_t)queueCis.size(),
369         queueCis.data(),
370         0, nullptr,
371         arraySize(exts), exts,
372         nullptr,
373     };
374 
375     VkDevice device;
376     EXPECT_EQ(VK_SUCCESS,
377         vk->vkCreateDevice(bestPhysicalDevice, &ci, nullptr, &device));
378 
379     *physDevice_out = bestPhysicalDevice;
380     *device_out = device;
381 }
382 
teardownVulkanTest(const VulkanDispatch * vk,VkDevice dev,VkInstance instance)383 static void teardownVulkanTest(const VulkanDispatch* vk,
384                                VkDevice dev,
385                                VkInstance instance) {
386     vk->vkDestroyDevice(dev, nullptr);
387     vk->vkDestroyInstance(instance, nullptr);
388 }
389 
390 class VulkanTest : public ::testing::Test {
391 protected:
SetUpTestSuite()392     static void SetUpTestSuite() {
393         android::emulation::injectGraphicsAgents(
394                 android::emulation::MockGraphicsAgentFactory());
395     }
396 
TearDownTestSuite()397     static void TearDownTestSuite() { }
398 
SetUp()399     void SetUp() override {
400         auto dispatch = vkDispatch(false);
401         ASSERT_NE(dispatch, nullptr);
402         mVk = *dispatch;
403 
404         testInstanceCreation(&mVk, &mInstance);
405         testDeviceCreation(&mVk, mInstance, &mPhysicalDevice, &mDevice);
406     }
407 
TearDown()408     void TearDown() override {
409         teardownVulkanTest(&mVk, mDevice, mInstance);
410     }
411 
412     VulkanDispatch mVk;
413     VkInstance mInstance;
414     VkPhysicalDevice mPhysicalDevice;
415     VkDevice mDevice;
416 };
417 
418 // Basic Vulkan instance/device setup.
TEST_F(VulkanTest,Basic)419 TEST_F(VulkanTest, Basic) { }
420 
421 // Checks that staging memory query is successful.
TEST_F(VulkanTest,StagingMemoryQuery)422 TEST_F(VulkanTest, StagingMemoryQuery) {
423     VkPhysicalDeviceMemoryProperties memProps;
424     uint32_t typeIndex;
425 
426     mVk.vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memProps);
427 
428     EXPECT_TRUE(getStagingMemoryTypeIndex(&mVk, mDevice, &memProps, &typeIndex));
429 }
430 
431 #ifndef _WIN32 // TODO: Get this working w/ Swiftshader vk on Windows
432 class VulkanFrameBufferTest : public VulkanTest {
433 protected:
SetUp()434     void SetUp() override {
435         // SwiftShader Vulkan doesn't work on Windows, so we skip all
436         // the rendering tests on Windows for now.
437         SKIP_TEST_IF_WIN32();
438 
439         feature_set_enabled_override(kFeature_GLESDynamicVersion, true);
440         feature_set_enabled_override(kFeature_PlayStoreImage, false);
441         feature_set_enabled_override(kFeature_Vulkan, true);
442         feature_set_enabled_override(kFeature_VulkanIgnoredHandles, 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, 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) { delete mFb; mFb = nullptr; }
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(setupVkColorBuffer(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(setupVkColorBuffer(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