blob: d008b889019d141623677c245e3915addaff5409 [file] [log] [blame]
Chad Versace94580872016-09-21 06:44:08 -07001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Chad Versace94580872016-09-21 06:44:08 -07007#include <math.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11
12#include <vulkan/vulkan.h>
13
Chad Versace94580872016-09-21 06:44:08 -070014#include "bs_drm.h"
15
16// Used for double-buffering.
17struct frame {
18 struct gbm_bo *bo;
Chad Versace94580872016-09-21 06:44:08 -070019 uint32_t drm_fb_id;
20 VkDeviceMemory vk_memory;
21 VkImage vk_image;
22 VkImageView vk_image_view;
23 VkFramebuffer vk_framebuffer;
24 VkCommandBuffer vk_cmd_buf;
25};
26
27#define check_vk_success(result, vk_func) \
28 __check_vk_success(__FILE__, __LINE__, __func__, (result), (vk_func))
29
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -080030static void __check_vk_success(const char *file, int line, const char *func, VkResult result,
31 const char *vk_func)
Chad Versace94580872016-09-21 06:44:08 -070032{
33 if (result == VK_SUCCESS)
34 return;
35
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -080036 bs_debug_print("ERROR", func, file, line, "%s failed with VkResult(%d)", vk_func, result);
Chad Versace94580872016-09-21 06:44:08 -070037 exit(EXIT_FAILURE);
38}
39
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -080040static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
41 void *data)
Chad Versace94580872016-09-21 06:44:08 -070042{
43 bool *waiting_for_flip = data;
44 *waiting_for_flip = false;
45}
46
Brian Hof14d0242019-08-21 16:43:17 -040047// Choose a physical device that supports Vulkan 1.1 or later. Exit on failure.
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -080048VkPhysicalDevice choose_physical_device(VkInstance inst)
Chad Versace94580872016-09-21 06:44:08 -070049{
50 uint32_t n_phys_devs;
51 VkResult res;
52
53 res = vkEnumeratePhysicalDevices(inst, &n_phys_devs, NULL);
54 check_vk_success(res, "vkEnumeratePhysicalDevices");
55
56 if (n_phys_devs == 0) {
57 fprintf(stderr, "No available VkPhysicalDevices\n");
58 exit(EXIT_FAILURE);
59 }
60
61 VkPhysicalDevice phys_devs[n_phys_devs];
62 res = vkEnumeratePhysicalDevices(inst, &n_phys_devs, phys_devs);
63 check_vk_success(res, "vkEnumeratePhysicalDevices");
64
65 // Print information about all available devices. This helps debugging
66 // when bringing up Vulkan on a new system.
67 printf("Available VkPhysicalDevices:\n");
68
Brian Hof14d0242019-08-21 16:43:17 -040069 uint32_t physical_device_idx = 0;
70 VkPhysicalDevice physical_device = VK_NULL_HANDLE;
Chad Versace94580872016-09-21 06:44:08 -070071 for (uint32_t i = 0; i < n_phys_devs; ++i) {
72 VkPhysicalDeviceProperties props;
73
74 vkGetPhysicalDeviceProperties(phys_devs[i], &props);
75
76 printf(" VkPhysicalDevice %u:\n", i);
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -080077 printf(" apiVersion: %u.%u.%u\n", VK_VERSION_MAJOR(props.apiVersion),
78 VK_VERSION_MINOR(props.apiVersion), VK_VERSION_PATCH(props.apiVersion));
Chad Versace94580872016-09-21 06:44:08 -070079 printf(" driverVersion: %u\n", props.driverVersion);
80 printf(" vendorID: 0x%x\n", props.vendorID);
81 printf(" deviceID: 0x%x\n", props.deviceID);
82 printf(" deviceName: %s\n", props.deviceName);
83 printf(" pipelineCacheUUID: %x%x%x%x-%x%x-%x%x-%x%x-%x%x%x%x%x%x\n",
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -080084 props.pipelineCacheUUID[0], props.pipelineCacheUUID[1],
85 props.pipelineCacheUUID[2], props.pipelineCacheUUID[3],
86 props.pipelineCacheUUID[4], props.pipelineCacheUUID[5],
87 props.pipelineCacheUUID[6], props.pipelineCacheUUID[7],
88 props.pipelineCacheUUID[8], props.pipelineCacheUUID[9],
89 props.pipelineCacheUUID[10], props.pipelineCacheUUID[11],
90 props.pipelineCacheUUID[12], props.pipelineCacheUUID[13],
91 props.pipelineCacheUUID[14], props.pipelineCacheUUID[15]);
Brian Hof14d0242019-08-21 16:43:17 -040092 if (physical_device == VK_NULL_HANDLE &&
93 VK_VERSION_MAJOR(props.apiVersion) >= 1 &&
94 VK_VERSION_MINOR(props.apiVersion) >= 1) {
95 physical_device_idx = i;
96 physical_device = phys_devs[i];
97 }
Chad Versace94580872016-09-21 06:44:08 -070098 }
99
Brian Hof14d0242019-08-21 16:43:17 -0400100 if (physical_device == VK_NULL_HANDLE) {
101 bs_debug_error("unable to find a suitable physical device");
102 exit(EXIT_FAILURE);
103 }
104 printf("Chose VkPhysicalDevice %d\n", physical_device_idx);
Chad Versace94580872016-09-21 06:44:08 -0700105 fflush(stdout);
Brian Hof14d0242019-08-21 16:43:17 -0400106 return physical_device;
Chad Versace94580872016-09-21 06:44:08 -0700107}
108
109// Return the index of a graphics-enabled queue family. Return UINT32_MAX on
110// failure.
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800111uint32_t choose_gfx_queue_family(VkPhysicalDevice phys_dev)
Chad Versace94580872016-09-21 06:44:08 -0700112{
113 uint32_t family_idx = UINT32_MAX;
114 VkQueueFamilyProperties *props = NULL;
115 uint32_t n_props = 0;
116
117 vkGetPhysicalDeviceQueueFamilyProperties(phys_dev, &n_props, NULL);
118
119 props = calloc(sizeof(props[0]), n_props);
120 if (!props) {
121 bs_debug_error("out of memory");
122 exit(EXIT_FAILURE);
123 }
124
125 vkGetPhysicalDeviceQueueFamilyProperties(phys_dev, &n_props, props);
126
127 // Choose the first graphics queue.
128 for (uint32_t i = 0; i < n_props; ++i) {
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800129 if ((props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && props[i].queueCount > 0) {
Chad Versace94580872016-09-21 06:44:08 -0700130 family_idx = i;
131 break;
132 }
133 }
134
135 free(props);
136 return family_idx;
137}
138
Brian Hof14d0242019-08-21 16:43:17 -0400139bool is_format_valid(VkPhysicalDevice phys_dev, VkFormat format)
140{
141 VkFormatProperties2 format_props = {
142 .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
143 };
144 vkGetPhysicalDeviceFormatProperties2(phys_dev, format, &format_props);
145 return format_props.formatProperties.linearTilingFeatures &
146 VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
147}
148
149VkImage create_image(VkPhysicalDevice phys_dev, VkDevice dev,
150 struct gbm_bo *bo, VkFormat format)
151{
152 VkImage image;
153 VkExternalImageFormatProperties external_image_format_props = {
154 .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
155 };
156 VkImageFormatProperties2 image_format_props = {
157 .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
158 .pNext = &external_image_format_props,
159 };
160 VkResult res = vkGetPhysicalDeviceImageFormatProperties2(phys_dev,
161 &(VkPhysicalDeviceImageFormatInfo2){
162 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
163 .pNext = &(VkPhysicalDeviceExternalImageFormatInfo){
164 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
165 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
166 },
167 .format = format,
168 .type = VK_IMAGE_TYPE_2D,
169 .tiling = VK_IMAGE_TILING_LINEAR,
170 .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
171 },
172 &image_format_props);
173 check_vk_success(res, "vkGetPhysicalDeviceFormatProperties2");
174
175 VkExternalMemoryFeatureFlags feature_flags = external_image_format_props
176 .externalMemoryProperties
177 .externalMemoryFeatures;
178 if (!(feature_flags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT)) {
179 bs_debug_error("dma-buf does not support Vulkan import");
180 exit(EXIT_FAILURE);
181 }
182
183 // TODO(crbug.com/1002071): Pass the stride of the imported buffer to vkCreateImage
184 // once the extension is supported on Intel.
185 res = vkCreateImage(dev,
186 &(VkImageCreateInfo){
187 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
188 .pNext = &(VkExternalMemoryImageCreateInfo){
189 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
190 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
191 },
192 .imageType = VK_IMAGE_TYPE_2D,
193 .format = format,
194 .extent = (VkExtent3D){
195 gbm_bo_get_width(bo),
196 gbm_bo_get_height(bo), 1
197 },
198 .mipLevels = 1,
199 .arrayLayers = 1,
200 .samples = 1,
201 .tiling = VK_IMAGE_TILING_LINEAR,
202 .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
203 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
204 },
205 /*pAllocator*/ NULL, &image);
206 check_vk_success(res, "vkCreateImage");
207
208 return image;
209}
210
211bool bind_image_bo(VkDevice dev,
212 VkImage image,
213 struct gbm_bo *bo,
214 VkDeviceMemory *mems)
215{
216 PFN_vkGetMemoryFdPropertiesKHR bs_vkGetMemoryFdPropertiesKHR =
217 (void *)vkGetDeviceProcAddr(dev, "vkGetMemoryFdPropertiesKHR");
218 if (bs_vkGetMemoryFdPropertiesKHR == NULL) {
219 bs_debug_error("vkGetDeviceProcAddr(\"vkGetMemoryFdPropertiesKHR\") failed");
220 return false;
221 }
222
223 int prime_fd = gbm_bo_get_fd(bo);
224 if (prime_fd < 0) {
225 bs_debug_error("failed to get prime fd for gbm_bo");
226 return false;
227 }
228
229 VkMemoryFdPropertiesKHR fd_props = {
230 .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
231 };
232 bs_vkGetMemoryFdPropertiesKHR(dev,
233 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
234 prime_fd, &fd_props);
235
236 /* get image memory requirements */
237 const VkImageMemoryRequirementsInfo2 mem_reqs_info = {
238 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
239 .image = image,
240 };
241 VkMemoryRequirements2 mem_reqs = {
242 .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
243 };
244 vkGetImageMemoryRequirements2(dev, &mem_reqs_info, &mem_reqs);
245
246 const uint32_t memory_type_bits = fd_props.memoryTypeBits &
247 mem_reqs.memoryRequirements.memoryTypeBits;
248 if (!memory_type_bits) {
249 bs_debug_error("no valid memory type");
250 close(prime_fd);
251 return false;
252 }
253
254 const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {
255 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
256 .image = image,
257 };
258 const VkImportMemoryFdInfoKHR memory_fd_info = {
259 .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
260 .pNext = &memory_dedicated_info,
261 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
262 .fd = prime_fd,
263 };
264 VkResult res = vkAllocateMemory(dev,
265 &(VkMemoryAllocateInfo){
266 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
267 .pNext = &memory_fd_info,
268 .allocationSize = mem_reqs.memoryRequirements.size,
269
270 // Simply choose the first available memory type. We
271 // need neither performance nor mmap, so all memory
272 // types are equally good.
273 .memoryTypeIndex = ffs(memory_type_bits) - 1,
274 },
275 /*pAllocator*/ NULL, mems);
276 check_vk_success(res, "vkAllocateMemory");
277
278 res = vkBindImageMemory(dev, image, mems[0], 0);
279 check_vk_success(res, "vkBindImageMemory");
280
281 return true;
282}
283
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800284int main(int argc, char **argv)
Chad Versace94580872016-09-21 06:44:08 -0700285{
Brian Hof14d0242019-08-21 16:43:17 -0400286 const uint32_t gbm_format = GBM_FORMAT_XBGR8888;
287 const VkFormat format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
Chad Versace94580872016-09-21 06:44:08 -0700288 VkInstance inst;
289 VkPhysicalDevice phys_dev;
290 uint32_t gfx_queue_family_idx;
291 VkDevice dev;
292 VkQueue gfx_queue;
293 VkRenderPass pass;
294 VkCommandPool cmd_pool;
295 VkResult res;
296 struct frame frames[2];
297 int err;
298
299 int dev_fd = bs_drm_open_main_display();
300 if (dev_fd < 0) {
301 bs_debug_error("failed to open display device");
302 exit(EXIT_FAILURE);
303 }
304
305 struct gbm_device *gbm = gbm_create_device(dev_fd);
306 if (!gbm) {
307 bs_debug_error("failed to create gbm_device");
308 exit(EXIT_FAILURE);
309 }
310
311 struct bs_drm_pipe pipe = { 0 };
312 if (!bs_drm_pipe_make(dev_fd, &pipe)) {
313 bs_debug_error("failed to make drm pipe");
314 exit(EXIT_FAILURE);
315 }
316
317 drmModeConnector *connector = drmModeGetConnector(dev_fd, pipe.connector_id);
318 if (!connector) {
319 bs_debug_error("drmModeGetConnector failed");
320 exit(EXIT_FAILURE);
321 }
322
323 drmModeModeInfo *mode = &connector->modes[0];
324
325 res = vkCreateInstance(
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800326 &(VkInstanceCreateInfo){
327 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
328 .pApplicationInfo =
329 &(VkApplicationInfo){
330 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
Brian Hof14d0242019-08-21 16:43:17 -0400331 .apiVersion = VK_MAKE_VERSION(1, 1, 0),
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800332 },
333 },
334 /*pAllocator*/ NULL, &inst);
Chad Versace94580872016-09-21 06:44:08 -0700335 check_vk_success(res, "vkCreateInstance");
336
337 phys_dev = choose_physical_device(inst);
338
339 gfx_queue_family_idx = choose_gfx_queue_family(phys_dev);
340 if (gfx_queue_family_idx == UINT32_MAX) {
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800341 bs_debug_error(
342 "VkPhysicalDevice exposes no VkQueueFamilyProperties "
343 "with graphics");
344 exit(EXIT_FAILURE);
Chad Versace94580872016-09-21 06:44:08 -0700345 }
346
Brian Hof14d0242019-08-21 16:43:17 -0400347 if (!is_format_valid(phys_dev, format)) {
348 bs_debug_error("VkPhysicalDevice does not support 0x%x", format);
349 exit(EXIT_FAILURE);
350 }
351
352 const uint32_t num_required_extensions = 2;
353 const char* required_extensions[] = {
354 "VK_KHR_external_memory_fd",
355 "VK_EXT_external_memory_dma_buf",
356 };
357 uint32_t extension_count;
358 vkEnumerateDeviceExtensionProperties(phys_dev, NULL, &extension_count, NULL);
359 VkExtensionProperties available_extensions[extension_count];
360 vkEnumerateDeviceExtensionProperties(phys_dev, NULL, &extension_count, available_extensions);
361 for (uint32_t i = 0; i < num_required_extensions; i++) {
362 uint32_t j;
363 for (j = 0; j < extension_count; j++) {
364 if (strcmp(required_extensions[i], available_extensions[j].extensionName) == 0) {
365 break;
366 }
367 }
368 if (j == extension_count) {
369 bs_debug_error("unsupported device extension: %s", required_extensions[i]);
370 exit(EXIT_FAILURE);
371 }
372 }
373
Chad Versace94580872016-09-21 06:44:08 -0700374 res = vkCreateDevice(phys_dev,
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800375 &(VkDeviceCreateInfo){
376 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
377 .queueCreateInfoCount = 1,
378 .pQueueCreateInfos =
379 (VkDeviceQueueCreateInfo[]){
380 {
381 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
382 .queueFamilyIndex = gfx_queue_family_idx,
383 .queueCount = 1,
384 .pQueuePriorities = (float[]){ 1.0f },
Chad Versace94580872016-09-21 06:44:08 -0700385
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800386 },
387 },
Brian Hof14d0242019-08-21 16:43:17 -0400388 .enabledExtensionCount = num_required_extensions,
389 .ppEnabledExtensionNames = required_extensions,
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800390 },
391 /*pAllocator*/ NULL, &dev);
Chad Versace94580872016-09-21 06:44:08 -0700392 check_vk_success(res, "vkCreateDevice");
393
Chad Versace94580872016-09-21 06:44:08 -0700394 vkGetDeviceQueue(dev, gfx_queue_family_idx, /*queueIndex*/ 0, &gfx_queue);
395
396 res = vkCreateCommandPool(dev,
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800397 &(VkCommandPoolCreateInfo){
398 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
399 .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT |
400 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
401 .queueFamilyIndex = gfx_queue_family_idx,
402 },
403 /*pAllocator*/ NULL, &cmd_pool);
Chad Versace94580872016-09-21 06:44:08 -0700404 check_vk_success(res, "vkCreateCommandPool");
405
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800406 res = vkCreateRenderPass(
407 dev,
408 &(VkRenderPassCreateInfo){
409 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
410 .attachmentCount = 1,
411 .pAttachments =
412 (VkAttachmentDescription[]){
413 {
Brian Hof14d0242019-08-21 16:43:17 -0400414 .format = format,
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800415 .samples = 1,
416 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
417 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
418 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
419 .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
420 },
421 },
422 .subpassCount = 1,
423 .pSubpasses =
424 (VkSubpassDescription[]){
425 {
426 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
427 .colorAttachmentCount = 1,
428 .pColorAttachments =
429 (VkAttachmentReference[]){
430 {
431 .attachment = 0,
432 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
433 },
Chad Versace94580872016-09-21 06:44:08 -0700434 },
435 },
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800436 },
437 },
438 /*pAllocator*/ NULL, &pass);
Chad Versace94580872016-09-21 06:44:08 -0700439 check_vk_success(res, "vkCreateRenderPass");
440
441 for (int i = 0; i < BS_ARRAY_LEN(frames); ++i) {
442 struct frame *fr = &frames[i];
443
Brian Hof14d0242019-08-21 16:43:17 -0400444 fr->bo = gbm_bo_create(gbm, mode->hdisplay, mode->vdisplay, gbm_format,
445 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
Chad Versace94580872016-09-21 06:44:08 -0700446 if (fr->bo == NULL) {
447 bs_debug_error("failed to create framebuffer's gbm_bo");
448 return 1;
449 }
Brian Hof14d0242019-08-21 16:43:17 -0400450 if (gbm_bo_get_modifier(fr->bo)) {
451 bs_debug_error("gmb_bo was created with modifiers");
452 return 1;
453 }
Chad Versace94580872016-09-21 06:44:08 -0700454
455 fr->drm_fb_id = bs_drm_fb_create_gbm(fr->bo);
456 if (fr->drm_fb_id == 0) {
457 bs_debug_error("failed to create drm framebuffer id");
458 return 1;
459 }
460
Brian Hof14d0242019-08-21 16:43:17 -0400461 fr->vk_image = create_image(phys_dev, dev, fr->bo, format);
462 if (fr->vk_image == VK_NULL_HANDLE) {
463 bs_debug_error("failed to create VkImage");
464 exit(EXIT_FAILURE);
Chad Versace94580872016-09-21 06:44:08 -0700465 }
466
Brian Hof14d0242019-08-21 16:43:17 -0400467 if (!bind_image_bo(dev, fr->vk_image, fr->bo, &fr->vk_memory)) {
468 bs_debug_error("failed to bind bo to image");
469 exit(EXIT_FAILURE);
470 }
Chad Versace94580872016-09-21 06:44:08 -0700471
472 res = vkCreateImageView(dev,
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800473 &(VkImageViewCreateInfo){
474 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
475 .image = fr->vk_image,
476 .viewType = VK_IMAGE_VIEW_TYPE_2D,
Brian Hof14d0242019-08-21 16:43:17 -0400477 .format = format,
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800478 .components =
479 (VkComponentMapping){
480 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
481 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
482 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
483 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
484 },
485 .subresourceRange =
486 (VkImageSubresourceRange){
487 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
488 .baseMipLevel = 0,
489 .levelCount = 1,
490 .baseArrayLayer = 0,
491 .layerCount = 1,
492 },
493 },
494 /*pAllocator*/ NULL, &fr->vk_image_view);
Chad Versace94580872016-09-21 06:44:08 -0700495 check_vk_success(res, "vkCreateImageView");
496
497 res = vkCreateFramebuffer(dev,
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800498 &(VkFramebufferCreateInfo){
499 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
500 .renderPass = pass,
501 .attachmentCount = 1,
502 .pAttachments = (VkImageView[]){ fr->vk_image_view },
503 .width = mode->hdisplay,
504 .height = mode->vdisplay,
505 .layers = 1,
506 },
507 /*pAllocator*/ NULL, &fr->vk_framebuffer);
Chad Versace94580872016-09-21 06:44:08 -0700508 check_vk_success(res, "vkCreateFramebuffer");
509
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800510 res = vkAllocateCommandBuffers(
511 dev,
512 &(VkCommandBufferAllocateInfo){
513 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
514 .commandPool = cmd_pool,
515 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
516 .commandBufferCount = 1,
517 },
518 &fr->vk_cmd_buf);
Chad Versace94580872016-09-21 06:44:08 -0700519 check_vk_success(res, "vkAllocateCommandBuffers");
520 }
521
522 // We set the screen mode using framebuffer 0. Then the first page flip
523 // waits on framebuffer 1.
524 err = drmModeSetCrtc(dev_fd, pipe.crtc_id, frames[0].drm_fb_id,
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800525 /*x*/ 0, /*y*/ 0, &pipe.connector_id, /*connector_count*/ 1, mode);
Chad Versace94580872016-09-21 06:44:08 -0700526 if (err) {
527 bs_debug_error("drmModeSetCrtc failed: %d", err);
528 exit(EXIT_FAILURE);
529 }
530
531 // We set an upper bound on the render loop so we can run this in
532 // from a testsuite.
533 for (int i = 1; i < 500; ++i) {
534 struct frame *fr = &frames[i % BS_ARRAY_LEN(frames)];
535
536 // vkBeginCommandBuffer implicity resets the command buffer due
537 // to VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT.
538 res = vkBeginCommandBuffer(fr->vk_cmd_buf,
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800539 &(VkCommandBufferBeginInfo){
540 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
541 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
542 });
Chad Versace94580872016-09-21 06:44:08 -0700543 check_vk_success(res, "vkBeginCommandBuffer");
544
Brian Hof14d0242019-08-21 16:43:17 -0400545 // Transfer ownership of the dma-buf from DRM to Vulkan.
546 vkCmdPipelineBarrier(
547 fr->vk_cmd_buf,
548 // srcStageMask is ignored when acquiring ownership, but various
549 // validation layers complain when you pass 0 here, so we just set
550 // it to the same as dstStageMask.
551 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
552 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
553 0, 0, NULL, 0, NULL,
554 1,
555 &(VkImageMemoryBarrier){
556 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
557 .pNext = NULL,
558 .srcAccessMask = 0, /** ignored for transfers */
559 .dstAccessMask = 0, /** ignored for transfers */
560 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
561 .newLayout = VK_IMAGE_LAYOUT_UNDEFINED,
562 // TODO(crbug.com/1000666): Replace this with the foreign queue
563 // family once the extension is available on CrOS.
564 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
565 .dstQueueFamilyIndex = gfx_queue_family_idx,
566 .image = fr->vk_image,
567 .subresourceRange = (VkImageSubresourceRange){
568 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
569 .baseMipLevel = 0,
570 .levelCount = 1,
571 .baseArrayLayer = 0,
572 .layerCount = 1,
573 },
574 });
575
Chad Versace94580872016-09-21 06:44:08 -0700576 // Cycle along the circumference of the RGB color wheel.
577 VkClearValue clear_color = {
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800578 .color =
579 {
580 .float32 =
581 {
582 0.5f + 0.5f * sinf(2 * M_PI * i / 240.0f),
583 0.5f + 0.5f * sinf(2 * M_PI * i / 240.0f +
584 (2.0f / 3.0f * M_PI)),
585 0.5f + 0.5f * sinf(2 * M_PI * i / 240.0f +
586 (4.0f / 3.0f * M_PI)),
Chad Versace94580872016-09-21 06:44:08 -0700587 1.0f,
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800588 },
589 },
Chad Versace94580872016-09-21 06:44:08 -0700590 };
591
Gurchetan Singh4268fca2017-11-17 18:10:48 -0800592 vkCmdBeginRenderPass(fr->vk_cmd_buf,
593 &(VkRenderPassBeginInfo){
594 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
595 .renderPass = pass,
596 .framebuffer = fr->vk_framebuffer,
597 .renderArea =
598 (VkRect2D){
599 .offset = { 0, 0 },
600 .extent = { mode->hdisplay, mode->vdisplay },
601 },
602 .clearValueCount = 1,
603 .pClearValues = (VkClearValue[]){ clear_color },
604 },
605 VK_SUBPASS_CONTENTS_INLINE);
Chad Versace94580872016-09-21 06:44:08 -0700606 vkCmdEndRenderPass(fr->vk_cmd_buf);
607
Brian Hof14d0242019-08-21 16:43:17 -0400608 // Transfer ownership of the dma-buf from Vulkan to DRM.
609 vkCmdPipelineBarrier(
610 fr->vk_cmd_buf,
611 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
612 // dstStageMask is ignored when releasing ownership, but various
613 // validation layers complain when you pass 0 here, so we just set
614 // it to the same as srcStageMask.
615 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
616 0, 0, NULL, 0, NULL,
617 1,
618 &(VkImageMemoryBarrier){
619 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
620 .pNext = NULL,
621 .srcAccessMask = 0, /** ignored for transfers */
622 .dstAccessMask = 0, /** ignored for transfers */
623 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
624 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
625 .srcQueueFamilyIndex = gfx_queue_family_idx,
626 // TODO(crbug.com/1000666): Replace this with the foreign queue
627 // family once the extension is available on CrOS.
628 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
629 .image = fr->vk_image,
630 .subresourceRange = (VkImageSubresourceRange){
631 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
632 .baseMipLevel = 0,
633 .levelCount = 1,
634 .baseArrayLayer = 0,
635 .layerCount = 1,
636 },
637 });
Chad Versace94580872016-09-21 06:44:08 -0700638 res = vkEndCommandBuffer(fr->vk_cmd_buf);
639 check_vk_success(res, "vkEndCommandBuffer");
640
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800641 res =
642 vkQueueSubmit(gfx_queue,
643 /*submitCount*/ 1,
644 (VkSubmitInfo[]){
645 {
646 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
647 .commandBufferCount = 1,
648 .pCommandBuffers = (VkCommandBuffer[]){ fr->vk_cmd_buf },
649 },
650 },
651 VK_NULL_HANDLE);
Chad Versace94580872016-09-21 06:44:08 -0700652 check_vk_success(res, "vkQueueSubmit");
653
654 res = vkQueueWaitIdle(gfx_queue);
655 check_vk_success(res, "vkQueueWaitIdle");
656
657 bool waiting_for_flip = true;
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800658 err = drmModePageFlip(dev_fd, pipe.crtc_id, fr->drm_fb_id, DRM_MODE_PAGE_FLIP_EVENT,
Chad Versace94580872016-09-21 06:44:08 -0700659 &waiting_for_flip);
660 if (err) {
661 bs_debug_error("failed page flip: error=%d", err);
662 exit(EXIT_FAILURE);
663 }
664
665 while (waiting_for_flip) {
666 drmEventContext ev_ctx = {
667 .version = DRM_EVENT_CONTEXT_VERSION,
668 .page_flip_handler = page_flip_handler,
669 };
670
671 fd_set fds;
672 FD_ZERO(&fds);
673 FD_SET(dev_fd, &fds);
674
675 int n_fds = select(dev_fd + 1, &fds, NULL, NULL, NULL);
676 if (n_fds < 0) {
677 bs_debug_error("select() failed on page flip: %s", strerror(errno));
678 exit(EXIT_FAILURE);
679 } else if (n_fds == 0) {
680 bs_debug_error("select() timeout on page flip");
681 exit(EXIT_FAILURE);
682 }
683
684 err = drmHandleEvent(dev_fd, &ev_ctx);
685 if (err) {
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -0800686 bs_debug_error(
687 "drmHandleEvent failed while "
688 "waiting for page flip: error=%d",
689 err);
Chad Versace94580872016-09-21 06:44:08 -0700690 exit(EXIT_FAILURE);
691 }
692 }
693 }
694
695 return 0;
696}