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