• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <gtest/gtest.h>
2 
3 #include "DisplayVk.h"
4 
5 #include "Standalone.h"
6 #include "base/Lock.h"
7 #include "tests/VkTestUtils.h"
8 #include "vulkan/VulkanDispatch.h"
9 
10 class DisplayVkTest : public ::testing::Test {
11    protected:
SetUpTestCase()12     static void SetUpTestCase() { k_vk = emugl::vkDispatch(false); }
13 
SetUp()14     void SetUp() override {
15         // skip the test when testing without a window
16         if (!emugl::shouldUseWindow()) {
17             GTEST_SKIP();
18         }
19         ASSERT_NE(k_vk, nullptr);
20 
21         createInstance();
22         createWindowAndSurface();
23         m_window = emugl::createOrGetTestWindow(0, 0, k_width, k_height);
24         pickPhysicalDevice();
25         createLogicalDevice();
26         k_vk->vkGetDeviceQueue(m_vkDevice, m_compositorQueueFamilyIndex, 0, &m_compositorVkQueue);
27         m_compositorVkQueueLock = std::make_shared<android::base::Lock>();
28         k_vk->vkGetDeviceQueue(m_vkDevice, m_swapChainQueueFamilyIndex, 0, &m_swapChainVkQueue);
29         m_swapChainVkQueueLock = std::make_shared<android::base::Lock>();
30         VkCommandPoolCreateInfo commandPoolCi = {
31             .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
32             .queueFamilyIndex = m_compositorQueueFamilyIndex};
33         ASSERT_EQ(k_vk->vkCreateCommandPool(m_vkDevice, &commandPoolCi, nullptr, &m_vkCommandPool),
34                   VK_SUCCESS);
35         m_displayVk = std::make_unique<DisplayVk>(
36             *k_vk, m_vkPhysicalDevice, m_swapChainQueueFamilyIndex, m_compositorQueueFamilyIndex,
37             m_vkDevice, m_compositorVkQueue, m_compositorVkQueueLock, m_swapChainVkQueue,
38             m_swapChainVkQueueLock);
39         m_displayVk->bindToSurface(m_vkSurface, k_width, k_height);
40     }
41 
TearDown()42     void TearDown() override {
43         if (emugl::shouldUseWindow()) {
44             ASSERT_EQ(k_vk->vkQueueWaitIdle(m_compositorVkQueue), VK_SUCCESS);
45             ASSERT_EQ(k_vk->vkQueueWaitIdle(m_swapChainVkQueue), VK_SUCCESS);
46 
47             m_displayVk.reset();
48             k_vk->vkDestroyCommandPool(m_vkDevice, m_vkCommandPool, nullptr);
49             k_vk->vkDestroyDevice(m_vkDevice, nullptr);
50             k_vk->vkDestroySurfaceKHR(m_vkInstance, m_vkSurface, nullptr);
51             k_vk->vkDestroyInstance(m_vkInstance, nullptr);
52         }
53     }
54 
55     using RenderTexture = emugl::RenderTextureVk;
56 
57     static const goldfish_vk::VulkanDispatch *k_vk;
58     static const uint32_t k_width = 0x100;
59     static const uint32_t k_height = 0x100;
60 
61     OSWindow *m_window;
62     VkInstance m_vkInstance = VK_NULL_HANDLE;
63     VkSurfaceKHR m_vkSurface = VK_NULL_HANDLE;
64     VkPhysicalDevice m_vkPhysicalDevice = VK_NULL_HANDLE;
65     uint32_t m_swapChainQueueFamilyIndex = 0;
66     uint32_t m_compositorQueueFamilyIndex = 0;
67     VkDevice m_vkDevice = VK_NULL_HANDLE;
68     VkQueue m_compositorVkQueue = VK_NULL_HANDLE;
69     std::shared_ptr<android::base::Lock> m_compositorVkQueueLock;
70     VkQueue m_swapChainVkQueue = VK_NULL_HANDLE;
71     std::shared_ptr<android::base::Lock> m_swapChainVkQueueLock;
72     VkCommandPool m_vkCommandPool = VK_NULL_HANDLE;
73     std::unique_ptr<DisplayVk> m_displayVk = nullptr;
74 
75    private:
createInstance()76     void createInstance() {
77         VkApplicationInfo appInfo = {.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
78                                      .pNext = nullptr,
79                                      .pApplicationName = "emulator SwapChainStateVk unittest",
80                                      .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
81                                      .pEngineName = "No Engine",
82                                      .engineVersion = VK_MAKE_VERSION(1, 0, 0),
83                                      .apiVersion = VK_API_VERSION_1_1};
84         auto extensions = SwapChainStateVk::getRequiredInstanceExtensions();
85         VkInstanceCreateInfo instanceCi = {
86             .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
87             .pApplicationInfo = &appInfo,
88             .enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
89             .ppEnabledExtensionNames = extensions.data()};
90         ASSERT_EQ(k_vk->vkCreateInstance(&instanceCi, nullptr, &m_vkInstance), VK_SUCCESS);
91         ASSERT_TRUE(m_vkInstance != VK_NULL_HANDLE);
92     }
93 
createWindowAndSurface()94     void createWindowAndSurface() {
95         m_window = emugl::createOrGetTestWindow(0, 0, k_width, k_height);
96         ASSERT_NE(m_window, nullptr);
97         // TODO(kaiyili, b/179477624): add support for other platforms
98 #ifdef _WIN32
99         VkWin32SurfaceCreateInfoKHR surfaceCi = {
100             .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
101             .hinstance = GetModuleHandle(nullptr),
102             .hwnd = m_window->getNativeWindow()};
103         ASSERT_EQ(k_vk->vkCreateWin32SurfaceKHR(m_vkInstance, &surfaceCi, nullptr, &m_vkSurface),
104                   VK_SUCCESS);
105 #endif
106     }
107 
pickPhysicalDevice()108     void pickPhysicalDevice() {
109         uint32_t physicalDeviceCount = 0;
110         ASSERT_EQ(k_vk->vkEnumeratePhysicalDevices(m_vkInstance, &physicalDeviceCount, nullptr),
111                   VK_SUCCESS);
112         ASSERT_GT(physicalDeviceCount, 0);
113         std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
114         ASSERT_EQ(k_vk->vkEnumeratePhysicalDevices(m_vkInstance, &physicalDeviceCount,
115                                                    physicalDevices.data()),
116                   VK_SUCCESS);
117         for (const auto &device : physicalDevices) {
118             uint32_t queueFamilyCount = 0;
119             k_vk->vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
120             ASSERT_GT(queueFamilyCount, 0);
121             std::vector<VkQueueFamilyProperties> queueProps(queueFamilyCount);
122             k_vk->vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount,
123                                                            queueProps.data());
124             std::optional<uint32_t> maybeSwapChainQueueFamilyIndex = std::nullopt;
125             std::optional<uint32_t> maybeCompositorQueueFamilyIndex = std::nullopt;
126             for (uint32_t queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount;
127                  queueFamilyIndex++) {
128                 if (!maybeSwapChainQueueFamilyIndex.has_value() &&
129                     SwapChainStateVk::validateQueueFamilyProperties(*k_vk, device, m_vkSurface,
130                                                                     queueFamilyIndex) &&
131                     SwapChainStateVk::createSwapChainCi(*k_vk, m_vkSurface, device, k_width,
132                                                         k_height, {queueFamilyIndex})) {
133                     maybeSwapChainQueueFamilyIndex = queueFamilyIndex;
134                 }
135                 if (!maybeCompositorQueueFamilyIndex.has_value() &&
136                     CompositorVk::validateQueueFamilyProperties(queueProps[queueFamilyIndex])) {
137                     maybeCompositorQueueFamilyIndex = queueFamilyIndex;
138                 }
139             }
140             if (!maybeSwapChainQueueFamilyIndex.has_value() ||
141                 !maybeCompositorQueueFamilyIndex.has_value()) {
142                 continue;
143             }
144             m_swapChainQueueFamilyIndex = maybeSwapChainQueueFamilyIndex.value();
145             m_compositorQueueFamilyIndex = maybeCompositorQueueFamilyIndex.value();
146             m_vkPhysicalDevice = device;
147             return;
148         }
149         FAIL() << "Can't find a suitable VkPhysicalDevice.";
150     }
151 
createLogicalDevice()152     void createLogicalDevice() {
153         const float queuePriority = 1.0f;
154         std::vector<VkDeviceQueueCreateInfo> queueCis(0);
155         for (auto queueFamilyIndex : std::unordered_set<uint32_t>(
156                  {m_swapChainQueueFamilyIndex, m_compositorQueueFamilyIndex})) {
157             VkDeviceQueueCreateInfo queueCi = {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
158                                                .queueFamilyIndex = queueFamilyIndex,
159                                                .queueCount = 1,
160                                                .pQueuePriorities = &queuePriority};
161             queueCis.push_back(queueCi);
162         }
163         VkPhysicalDeviceFeatures2 features = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
164                                               .pNext = nullptr};
165         auto extensions = SwapChainStateVk::getRequiredDeviceExtensions();
166         VkDeviceCreateInfo deviceCi = {
167             .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
168             .pNext = &features,
169             .queueCreateInfoCount = static_cast<uint32_t>(queueCis.size()),
170             .pQueueCreateInfos = queueCis.data(),
171             .enabledLayerCount = 0,
172             .enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
173             .ppEnabledExtensionNames = extensions.data(),
174             .pEnabledFeatures = nullptr};
175         ASSERT_EQ(k_vk->vkCreateDevice(m_vkPhysicalDevice, &deviceCi, nullptr, &m_vkDevice),
176                   VK_SUCCESS);
177         ASSERT_TRUE(m_vkDevice != VK_NULL_HANDLE);
178     }
179 };
180 
181 const goldfish_vk::VulkanDispatch *DisplayVkTest::k_vk = nullptr;
182 
TEST_F(DisplayVkTest,Init)183 TEST_F(DisplayVkTest, Init) {}
184 
TEST_F(DisplayVkTest,PostWithoutSurfaceShouldntCrash)185 TEST_F(DisplayVkTest, PostWithoutSurfaceShouldntCrash) {
186     uint32_t textureWidth = 20;
187     uint32_t textureHeight = 40;
188     DisplayVk displayVk(*k_vk, m_vkPhysicalDevice, m_swapChainQueueFamilyIndex,
189                         m_compositorQueueFamilyIndex, m_vkDevice, m_compositorVkQueue,
190                         m_compositorVkQueueLock, m_swapChainVkQueue, m_swapChainVkQueueLock);
191     auto texture = RenderTexture::create(*k_vk, m_vkDevice, m_vkPhysicalDevice, m_compositorVkQueue,
192                                          m_vkCommandPool, textureWidth, textureHeight);
193     std::vector<uint32_t> pixels(textureWidth * textureHeight, 0);
194     ASSERT_TRUE(texture->write(pixels));
195     auto cbvk = displayVk.createDisplayBuffer(texture->m_vkImage, texture->m_vkImageCreateInfo);
196     ASSERT_TRUE(std::get<0>(displayVk.post(cbvk)));
197 }
198 
TEST_F(DisplayVkTest,SimplePost)199 TEST_F(DisplayVkTest, SimplePost) {
200     uint32_t textureWidth = 20;
201     uint32_t textureHeight = 40;
202     auto texture = RenderTexture::create(*k_vk, m_vkDevice, m_vkPhysicalDevice, m_compositorVkQueue,
203                                          m_vkCommandPool, textureWidth, textureHeight);
204     std::vector<uint32_t> pixels(textureWidth * textureHeight);
205     for (int i = 0; i < textureHeight; i++) {
206         for (int j = 0; j < textureWidth; j++) {
207             uint8_t *pixel = reinterpret_cast<uint8_t *>(&pixels[i * textureWidth + j]);
208             pixel[0] = static_cast<uint8_t>((i * 0xff / textureHeight) & 0xff);
209             pixel[1] = static_cast<uint8_t>((j * 0xff / textureWidth) & 0xff);
210             pixel[2] = 0;
211             pixel[3] = 0xff;
212         }
213     }
214     ASSERT_TRUE(texture->write(pixels));
215     auto cbvk = m_displayVk->createDisplayBuffer(texture->m_vkImage, texture->m_vkImageCreateInfo);
216     std::vector<std::shared_future<void>> waitForGpuFutures;
217     for (uint32_t i = 0; i < 10; i++) {
218         auto [success, waitForGpuFuture] = m_displayVk->post(cbvk);
219         ASSERT_TRUE(success);
220         waitForGpuFutures.emplace_back(std::move(waitForGpuFuture));
221     }
222     for (auto &waitForGpuFuture : waitForGpuFutures) {
223         waitForGpuFuture.wait();
224     }
225 }
226 
TEST_F(DisplayVkTest,PostTwoColorBuffers)227 TEST_F(DisplayVkTest, PostTwoColorBuffers) {
228     uint32_t textureWidth = 20;
229     uint32_t textureHeight = 40;
230     auto redTexture =
231         RenderTexture::create(*k_vk, m_vkDevice, m_vkPhysicalDevice, m_compositorVkQueue,
232                               m_vkCommandPool, textureWidth, textureHeight);
233     auto greenTexture =
234         RenderTexture::create(*k_vk, m_vkDevice, m_vkPhysicalDevice, m_compositorVkQueue,
235                               m_vkCommandPool, textureWidth, textureHeight);
236     uint32_t red = 0xff0000ff;
237     uint32_t green = 0xff00ff00;
238     std::vector<uint32_t> redPixels(textureWidth * textureHeight, red);
239     std::vector<uint32_t> greenPixels(textureWidth * textureHeight, green);
240     ASSERT_TRUE(redTexture->write(redPixels));
241     ASSERT_TRUE(greenTexture->write(greenPixels));
242     auto redCbvk =
243         m_displayVk->createDisplayBuffer(redTexture->m_vkImage, redTexture->m_vkImageCreateInfo);
244     auto greenCbvk = m_displayVk->createDisplayBuffer(greenTexture->m_vkImage,
245                                                       greenTexture->m_vkImageCreateInfo);
246     std::vector<std::shared_future<void>> waitForGpuFutures;
247     for (uint32_t i = 0; i < 10; i++) {
248         auto [success, waitForGpuFuture] = m_displayVk->post(redCbvk);
249         ASSERT_TRUE(success);
250         waitForGpuFutures.emplace_back(std::move(waitForGpuFuture));
251         std::tie(success, waitForGpuFuture) = m_displayVk->post(greenCbvk);
252         ASSERT_TRUE(success);
253         waitForGpuFutures.emplace_back(std::move(waitForGpuFuture));
254     }
255     for (auto &waitForGpuFuture : waitForGpuFutures) {
256         waitForGpuFuture.wait();
257     }
258 }
259