• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }