1 #include <gtest/gtest.h>
2
3 #include "DisplayVk.h"
4
5 #include "Standalone.h"
6 #include "tests/VkTestUtils.h"
7 #include "vulkan/VulkanDispatch.h"
8
9 class DisplayVkTest : public ::testing::Test {
10 protected:
SetUpTestCase()11 static void SetUpTestCase() { k_vk = emugl::vkDispatch(false); }
12
SetUp()13 void SetUp() override {
14 // skip the test when testing without a window
15 if (!emugl::shouldUseWindow()) {
16 GTEST_SKIP();
17 }
18 ASSERT_NE(k_vk, nullptr);
19
20 createInstance();
21 createWindowAndSurface();
22 m_window = emugl::createOrGetTestWindow(0, 0, k_width, k_height);
23 pickPhysicalDevice();
24 createLogicalDevice();
25 k_vk->vkGetDeviceQueue(m_vkDevice, m_compositorQueueFamilyIndex, 0,
26 &m_compositorVkQueue);
27 k_vk->vkGetDeviceQueue(m_vkDevice, m_swapChainQueueFamilyIndex, 0,
28 &m_swapChainVkQueue);
29 VkCommandPoolCreateInfo commandPoolCi = {
30 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
31 .queueFamilyIndex = m_compositorQueueFamilyIndex};
32 ASSERT_EQ(k_vk->vkCreateCommandPool(m_vkDevice, &commandPoolCi, nullptr,
33 &m_vkCommandPool),
34 VK_SUCCESS);
35 m_displayVk = std::make_unique<DisplayVk>(
36 *k_vk, m_vkPhysicalDevice, m_swapChainQueueFamilyIndex,
37 m_compositorQueueFamilyIndex, m_vkDevice, m_compositorVkQueue,
38 m_swapChainVkQueue);
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 VkQueue m_swapChainVkQueue = VK_NULL_HANDLE;
70 VkCommandPool m_vkCommandPool = VK_NULL_HANDLE;
71 std::unique_ptr<DisplayVk> m_displayVk = nullptr;
72
73 private:
createInstance()74 void createInstance() {
75 VkApplicationInfo appInfo = {
76 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
77 .pNext = nullptr,
78 .pApplicationName = "emulator SwapChainStateVk unittest",
79 .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
80 .pEngineName = "No Engine",
81 .engineVersion = VK_MAKE_VERSION(1, 0, 0),
82 .apiVersion = VK_API_VERSION_1_1};
83 auto extensions = SwapChainStateVk::getRequiredInstanceExtensions();
84 VkInstanceCreateInfo instanceCi = {
85 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
86 .pApplicationInfo = &appInfo,
87 .enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
88 .ppEnabledExtensionNames = extensions.data()};
89 ASSERT_EQ(k_vk->vkCreateInstance(&instanceCi, nullptr, &m_vkInstance),
90 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,
104 nullptr, &m_vkSurface),
105 VK_SUCCESS);
106 #endif
107 }
108
pickPhysicalDevice()109 void pickPhysicalDevice() {
110 uint32_t physicalDeviceCount = 0;
111 ASSERT_EQ(k_vk->vkEnumeratePhysicalDevices(
112 m_vkInstance, &physicalDeviceCount, nullptr),
113 VK_SUCCESS);
114 ASSERT_GT(physicalDeviceCount, 0);
115 std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
116 ASSERT_EQ(
117 k_vk->vkEnumeratePhysicalDevices(m_vkInstance, &physicalDeviceCount,
118 physicalDevices.data()),
119 VK_SUCCESS);
120 for (const auto &device : physicalDevices) {
121 VkPhysicalDeviceDescriptorIndexingFeaturesEXT descIndexingFeatures = {
122 .sType =
123 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT};
124 VkPhysicalDeviceFeatures2 features = {
125 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
126 .pNext = &descIndexingFeatures};
127 k_vk->vkGetPhysicalDeviceFeatures2(device, &features);
128 if (!CompositorVk::validatePhysicalDeviceFeatures(features)) {
129 continue;
130 }
131 uint32_t queueFamilyCount = 0;
132 k_vk->vkGetPhysicalDeviceQueueFamilyProperties(
133 device, &queueFamilyCount, nullptr);
134 ASSERT_GT(queueFamilyCount, 0);
135 std::vector<VkQueueFamilyProperties> queueProps(queueFamilyCount);
136 k_vk->vkGetPhysicalDeviceQueueFamilyProperties(
137 device, &queueFamilyCount, queueProps.data());
138 std::optional<uint32_t> maybeSwapChainQueueFamilyIndex =
139 std::nullopt;
140 std::optional<uint32_t> maybeCompositorQueueFamilyIndex =
141 std::nullopt;
142 for (uint32_t queueFamilyIndex = 0;
143 queueFamilyIndex < queueFamilyCount; queueFamilyIndex++) {
144 if (!maybeSwapChainQueueFamilyIndex.has_value() &&
145 SwapChainStateVk::validateQueueFamilyProperties(
146 *k_vk, device, m_vkSurface, queueFamilyIndex) &&
147 SwapChainStateVk::createSwapChainCi(
148 *k_vk, m_vkSurface, device, k_width, k_height,
149 {queueFamilyIndex}) != nullptr) {
150 maybeSwapChainQueueFamilyIndex = queueFamilyIndex;
151 }
152 if (!maybeCompositorQueueFamilyIndex.has_value() &&
153 CompositorVk::validateQueueFamilyProperties(
154 queueProps[queueFamilyIndex])) {
155 maybeCompositorQueueFamilyIndex = queueFamilyIndex;
156 }
157 }
158 if (!maybeSwapChainQueueFamilyIndex.has_value() ||
159 !maybeCompositorQueueFamilyIndex.has_value()) {
160 continue;
161 }
162 m_swapChainQueueFamilyIndex =
163 maybeSwapChainQueueFamilyIndex.value();
164 m_compositorQueueFamilyIndex =
165 maybeCompositorQueueFamilyIndex.value();
166 m_vkPhysicalDevice = device;
167 return;
168 }
169 FAIL() << "Can't find a suitable VkPhysicalDevice.";
170 }
171
createLogicalDevice()172 void createLogicalDevice() {
173 const float queuePriority = 1.0f;
174 std::vector<VkDeviceQueueCreateInfo> queueCis(0);
175 for (auto queueFamilyIndex : std::unordered_set(
176 {m_swapChainQueueFamilyIndex, m_compositorQueueFamilyIndex})) {
177 VkDeviceQueueCreateInfo queueCi = {
178 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
179 .queueFamilyIndex = queueFamilyIndex,
180 .queueCount = 1,
181 .pQueuePriorities = &queuePriority};
182 queueCis.push_back(queueCi);
183 }
184 VkPhysicalDeviceDescriptorIndexingFeaturesEXT descIndexingFeatures = {
185 .sType =
186 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT};
187 VkPhysicalDeviceFeatures2 features = {
188 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
189 .pNext = &descIndexingFeatures};
190 ASSERT_TRUE(CompositorVk::enablePhysicalDeviceFeatures(features));
191 auto extensions = SwapChainStateVk::getRequiredDeviceExtensions();
192 const auto compositorExtensions =
193 CompositorVk::getRequiredDeviceExtensions();
194 extensions.insert(extensions.end(), compositorExtensions.begin(),
195 compositorExtensions.end());
196 VkDeviceCreateInfo deviceCi = {
197 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
198 .pNext = &features,
199 .queueCreateInfoCount = static_cast<uint32_t>(queueCis.size()),
200 .pQueueCreateInfos = queueCis.data(),
201 .enabledLayerCount = 0,
202 .enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
203 .ppEnabledExtensionNames = extensions.data(),
204 .pEnabledFeatures = nullptr};
205 ASSERT_EQ(k_vk->vkCreateDevice(m_vkPhysicalDevice, &deviceCi, nullptr,
206 &m_vkDevice),
207 VK_SUCCESS);
208 ASSERT_TRUE(m_vkDevice != VK_NULL_HANDLE);
209 }
210 };
211
212 const goldfish_vk::VulkanDispatch *DisplayVkTest::k_vk = nullptr;
213
TEST_F(DisplayVkTest,Init)214 TEST_F(DisplayVkTest, Init) {}
215
TEST_F(DisplayVkTest,PostWithoutSurfaceShouldntCrash)216 TEST_F(DisplayVkTest, PostWithoutSurfaceShouldntCrash) {
217 uint32_t textureWidth = 20;
218 uint32_t textureHeight = 40;
219 DisplayVk displayVk(*k_vk, m_vkPhysicalDevice, m_swapChainQueueFamilyIndex,
220 m_compositorQueueFamilyIndex, m_vkDevice,
221 m_compositorVkQueue, m_swapChainVkQueue);
222 auto texture = RenderTexture::create(*k_vk, m_vkDevice, m_vkPhysicalDevice,
223 m_compositorVkQueue, m_vkCommandPool,
224 textureWidth, textureHeight);
225 std::vector<uint32_t> pixels(textureWidth * textureHeight, 0);
226 ASSERT_TRUE(texture->write(pixels));
227 auto cbvk = displayVk.createDisplayBuffer(texture->m_vkImage,
228 RenderTexture::k_vkFormat,
229 textureWidth, textureHeight);
230 displayVk.post(cbvk);
231 }
232
TEST_F(DisplayVkTest,SimplePost)233 TEST_F(DisplayVkTest, SimplePost) {
234 uint32_t textureWidth = 20;
235 uint32_t textureHeight = 40;
236 auto texture = RenderTexture::create(*k_vk, m_vkDevice, m_vkPhysicalDevice,
237 m_compositorVkQueue, m_vkCommandPool,
238 textureWidth, textureHeight);
239 std::vector<uint32_t> pixels(textureWidth * textureHeight);
240 for (int i = 0; i < textureHeight; i++) {
241 for (int j = 0; j < textureWidth; j++) {
242 uint8_t *pixel =
243 reinterpret_cast<uint8_t *>(&pixels[i * textureWidth + j]);
244 pixel[0] = static_cast<uint8_t>((i * 0xff / textureHeight) & 0xff);
245 pixel[1] = static_cast<uint8_t>((j * 0xff / textureWidth) & 0xff);
246 pixel[2] = 0;
247 pixel[3] = 0xff;
248 }
249 }
250 ASSERT_TRUE(texture->write(pixels));
251 auto cbvk = m_displayVk->createDisplayBuffer(
252 texture->m_vkImage, texture->k_vkFormat, texture->m_width,
253 texture->m_height);
254 for (uint32_t i = 0; i < 10; i++) {
255 m_displayVk->post(cbvk);
256 }
257 }
258
TEST_F(DisplayVkTest,PostTwoColorBuffers)259 TEST_F(DisplayVkTest, PostTwoColorBuffers) {
260 uint32_t textureWidth = 20;
261 uint32_t textureHeight = 40;
262 auto redTexture = RenderTexture::create(
263 *k_vk, m_vkDevice, m_vkPhysicalDevice, m_compositorVkQueue,
264 m_vkCommandPool, textureWidth, textureHeight);
265 auto greenTexture = RenderTexture::create(
266 *k_vk, m_vkDevice, m_vkPhysicalDevice, m_compositorVkQueue,
267 m_vkCommandPool, textureWidth, textureHeight);
268 uint32_t red = 0xff0000ff;
269 uint32_t green = 0xff00ff00;
270 std::vector<uint32_t> redPixels(textureWidth * textureHeight, red);
271 std::vector<uint32_t> greenPixels(textureWidth * textureHeight, green);
272 ASSERT_TRUE(redTexture->write(redPixels));
273 ASSERT_TRUE(greenTexture->write(greenPixels));
274 auto redCbvk = m_displayVk->createDisplayBuffer(
275 redTexture->m_vkImage, redTexture->k_vkFormat, redTexture->m_width,
276 redTexture->m_height);
277 auto greenCbvk = m_displayVk->createDisplayBuffer(
278 greenTexture->m_vkImage, greenTexture->k_vkFormat,
279 greenTexture->m_width, greenTexture->m_height);
280 for (uint32_t i = 0; i < 10; i++) {
281 m_displayVk->post(redCbvk);
282 m_displayVk->post(greenCbvk);
283 }
284 }