The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

c/direct: Split NVIDIA and RandR backends.

Rename functions and structs.

Define unused function overrides separatelty.

c/window: Define new backend init methods.

authored by

Lubosz Sarnecki and committed by
Jakob Bornecrantz
94bc4cba 4ddcca7a

+657 -251
+2 -1
src/xrt/compositor/CMakeLists.txt
··· 86 86 endif() 87 87 if(BUILD_WITH_XCB AND BUILD_WITH_XLIB) 88 88 list(APPEND MAIN_SOURCE_FILES 89 - main/comp_window_direct_mode.c 89 + main/comp_window_direct_randr.c 90 + main/comp_window_direct_nvidia.c 90 91 ) 91 92 endif() 92 93
+4 -3
src/xrt/compositor/main/comp_compositor.c
··· 688 688 } 689 689 #endif 690 690 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 691 - if (compositor_try_window(c, comp_window_direct_create(c))) { 691 + if (compositor_try_window(c, 692 + comp_window_direct_randr_create(c))) { 692 693 c->settings.window_type = WINDOW_DIRECT_RANDR; 693 694 return true; 694 695 } ··· 717 718 break; 718 719 case WINDOW_DIRECT_RANDR: 719 720 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 720 - compositor_try_window(c, comp_window_direct_create(c)); 721 + compositor_try_window(c, comp_window_direct_randr_create(c)); 721 722 #else 722 723 COMP_ERROR(c, "Direct mode support not compiled in!"); 723 724 #endif ··· 737 738 } 738 739 739 740 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 740 - return compositor_try_window(c, comp_window_direct_create(c)); 741 + return compositor_try_window(c, comp_window_direct_nvidia_create(c)); 741 742 #else 742 743 assert(false && 743 744 "NVIDIA direct mode depends on the xlib/xrandr direct mode.");
+10 -2
src/xrt/compositor/main/comp_window.h
··· 78 78 79 79 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 80 80 /*! 81 - * Create a direct surface to a HMD. 81 + * Create a direct surface to a HMD over RandR. 82 82 * 83 83 * @ingroup comp_main 84 84 */ 85 85 struct comp_window * 86 - comp_window_direct_create(struct comp_compositor *c); 86 + comp_window_direct_randr_create(struct comp_compositor *c); 87 + 88 + /*! 89 + * Create a direct surface to a HMD on NVIDIA. 90 + * 91 + * @ingroup comp_main 92 + */ 93 + struct comp_window * 94 + comp_window_direct_nvidia_create(struct comp_compositor *c); 87 95 #endif 88 96 89 97
+79 -244
src/xrt/compositor/main/comp_window_direct_mode.c src/xrt/compositor/main/comp_window_direct_randr.c
··· 38 38 VkDisplayKHR display; 39 39 }; 40 40 41 - struct comp_window_direct_nvidia_display 42 - { 43 - char *name; 44 - VkDisplayPropertiesKHR display_properties; 45 - VkDisplayKHR display; 46 - }; 47 - 48 41 /*! 49 42 * Direct mode "window" into a device, using Vulkan direct mode extension 50 43 * and xcb. 51 44 */ 52 - struct comp_window_direct 45 + struct comp_window_direct_randr 53 46 { 54 47 struct comp_window base; 55 48 ··· 57 50 xcb_screen_t *screen; 58 51 59 52 struct comp_window_direct_randr_display *randr_displays; 60 - struct comp_window_direct_nvidia_display *nv_displays; 61 53 62 54 uint16_t num_displays; 63 55 }; ··· 71 63 */ 72 64 73 65 static void 74 - comp_window_direct_destroy(struct comp_window *w); 66 + comp_window_direct_randr_destroy(struct comp_window *w); 75 67 76 68 XRT_MAYBE_UNUSED static void 77 - comp_window_direct_list_randr_screens(struct comp_window_direct *w); 78 - 79 - static bool 80 - comp_window_direct_init_randr(struct comp_window *w); 69 + comp_window_direct_randr_list_screens(struct comp_window_direct_randr *w); 81 70 82 71 static bool 83 - comp_window_direct_init_nvidia(struct comp_window *w); 72 + comp_window_direct_randr_init(struct comp_window *w); 84 73 85 74 static struct comp_window_direct_randr_display * 86 - comp_window_direct_current_randr_display(struct comp_window_direct *w); 87 - 88 - static struct comp_window_direct_nvidia_display * 89 - comp_window_direct_current_nvidia_display(struct comp_window_direct *w); 90 - 91 - static void 92 - comp_window_direct_flush(struct comp_window *w); 75 + comp_window_direct_randr_current_display(struct comp_window_direct_randr *w); 93 76 94 77 static VkDisplayModeKHR 95 - comp_window_direct_get_primary_display_mode(struct comp_window_direct *w, 96 - VkDisplayKHR display); 78 + comp_window_direct_randr_get_primary_display_mode( 79 + struct comp_window_direct_randr *w, VkDisplayKHR display); 97 80 98 81 static VkDisplayPlaneAlphaFlagBitsKHR 99 82 choose_alpha_mode(VkDisplayPlaneAlphaFlagsKHR flags); 100 83 101 84 static VkResult 102 - comp_window_direct_create_surface(struct comp_window_direct *w, 103 - VkInstance instance, 104 - VkSurfaceKHR *surface, 105 - uint32_t width, 106 - uint32_t height); 85 + comp_window_direct_randr_create_surface(struct comp_window_direct_randr *w, 86 + VkInstance instance, 87 + VkSurfaceKHR *surface, 88 + uint32_t width, 89 + uint32_t height); 107 90 108 91 static bool 109 - comp_window_direct_init_swapchain(struct comp_window *w, 110 - uint32_t width, 111 - uint32_t height); 92 + comp_window_direct_randr_init_swapchain(struct comp_window *w, 93 + uint32_t width, 94 + uint32_t height); 112 95 113 96 static int 114 - comp_window_direct_connect(struct comp_window_direct *w); 97 + comp_window_direct_randr_connect(struct comp_window_direct_randr *w); 115 98 116 99 static VkResult 117 - comp_window_direct_acquire_xlib_display(struct comp_window_direct *w, 118 - VkDisplayKHR display); 100 + comp_window_direct_randr_acquire_xlib_display( 101 + struct comp_window_direct_randr *w, VkDisplayKHR display); 119 102 120 103 static VkDisplayKHR 121 - comp_window_direct_get_xlib_randr_output(struct comp_window_direct *w, 122 - RROutput output); 123 - 124 - static void 125 - comp_window_direct_get_randr_outputs(struct comp_window_direct *w); 104 + comp_window_direct_randr_get_xlib_randr_output( 105 + struct comp_window_direct_randr *w, RROutput output); 126 106 127 107 static void 128 - comp_window_direct_update_window_title(struct comp_window *w, 129 - const char *title); 130 - 108 + comp_window_direct_randr_get_outputs(struct comp_window_direct_randr *w); 131 109 132 110 /* 133 111 * ··· 135 113 * 136 114 */ 137 115 116 + static void 117 + _flush(struct comp_window *w) 118 + {} 119 + 120 + static void 121 + _update_window_title(struct comp_window *w, const char *title) 122 + {} 123 + 138 124 struct comp_window * 139 - comp_window_direct_create(struct comp_compositor *c) 125 + comp_window_direct_randr_create(struct comp_compositor *c) 140 126 { 141 - struct comp_window_direct *w = 142 - U_TYPED_CALLOC(struct comp_window_direct); 127 + struct comp_window_direct_randr *w = 128 + U_TYPED_CALLOC(struct comp_window_direct_randr); 143 129 144 130 w->base.name = "direct"; 145 - w->base.destroy = comp_window_direct_destroy; 146 - w->base.flush = comp_window_direct_flush; 147 - if (c->settings.window_type == WINDOW_DIRECT_NVIDIA) { 148 - w->base.init = comp_window_direct_init_nvidia; 149 - } else { 150 - w->base.init = comp_window_direct_init_randr; 151 - } 152 - w->base.init_swapchain = comp_window_direct_init_swapchain; 153 - w->base.update_window_title = comp_window_direct_update_window_title; 131 + w->base.destroy = comp_window_direct_randr_destroy; 132 + w->base.flush = _flush; 133 + w->base.init = comp_window_direct_randr_init; 134 + w->base.init_swapchain = comp_window_direct_randr_init_swapchain; 135 + w->base.update_window_title = _update_window_title; 154 136 w->base.c = c; 155 137 156 138 return &w->base; 157 139 } 158 140 159 141 static void 160 - comp_window_direct_destroy(struct comp_window *w) 142 + comp_window_direct_randr_destroy(struct comp_window *w) 161 143 { 162 - struct comp_window_direct *w_direct = (struct comp_window_direct *)w; 144 + struct comp_window_direct_randr *w_direct = 145 + (struct comp_window_direct_randr *)w; 163 146 struct vk_bundle *vk = &w->c->vk; 164 147 165 148 for (uint32_t i = 0; i < w_direct->num_displays; i++) { ··· 174 157 d->display = VK_NULL_HANDLE; 175 158 free(d->name); 176 159 } 177 - for (uint32_t i = 0; i < w_direct->num_displays; i++) { 178 - struct comp_window_direct_nvidia_display *d = 179 - &w_direct->nv_displays[i]; 180 - d->display = VK_NULL_HANDLE; 181 - free(d->name); 182 - } 183 - 184 - if (w_direct->nv_displays != NULL) 185 - free(w_direct->nv_displays); 186 160 187 161 if (w_direct->randr_displays != NULL) 188 162 free(w_direct->randr_displays); ··· 196 170 } 197 171 198 172 static void 199 - comp_window_direct_list_randr_screens(struct comp_window_direct *w) 173 + comp_window_direct_randr_list_screens(struct comp_window_direct_randr *w) 200 174 { 201 175 for (int i = 0; i < w->num_displays; i++) { 202 176 const struct comp_window_direct_randr_display *d = ··· 210 184 } 211 185 212 186 static bool 213 - comp_window_direct_init_randr(struct comp_window *w) 187 + comp_window_direct_randr_init(struct comp_window *w) 214 188 { 215 189 // Sanity check. 216 190 if (w->c->vk.instance != VK_NULL_HANDLE) { ··· 218 192 return false; 219 193 } 220 194 221 - struct comp_window_direct *w_direct = (struct comp_window_direct *)w; 195 + struct comp_window_direct_randr *w_direct = 196 + (struct comp_window_direct_randr *)w; 222 197 223 - if (!comp_window_direct_connect(w_direct)) { 198 + if (!comp_window_direct_randr_connect(w_direct)) { 224 199 return false; 225 200 } 226 201 ··· 231 206 232 207 w_direct->screen = iter.data; 233 208 234 - comp_window_direct_get_randr_outputs(w_direct); 209 + comp_window_direct_randr_get_outputs(w_direct); 235 210 236 211 if (w_direct->num_displays == 0) { 237 212 COMP_ERROR(w->c, "No non-desktop output available."); ··· 242 217 COMP_DEBUG(w->c, 243 218 "Requested display %d, but only %d displays are " 244 219 "available.", 245 - w->c->settings.display, 246 - w_direct->num_displays); 220 + w->c->settings.display, w_direct->num_displays); 247 221 248 222 w->c->settings.display = 0; 249 223 struct comp_window_direct_randr_display *d = 250 - comp_window_direct_current_randr_display(w_direct); 224 + comp_window_direct_randr_current_display(w_direct); 251 225 COMP_DEBUG(w->c, "Selecting '%s' instead.", d->name); 252 226 } 253 227 254 228 if (w->c->settings.display < 0) { 255 229 w->c->settings.display = 0; 256 230 struct comp_window_direct_randr_display *d = 257 - comp_window_direct_current_randr_display(w_direct); 231 + comp_window_direct_randr_current_display(w_direct); 258 232 COMP_DEBUG(w->c, "Selecting '%s' first display.", d->name); 259 233 } 260 234 261 235 struct comp_window_direct_randr_display *d = 262 - comp_window_direct_current_randr_display(w_direct); 236 + comp_window_direct_randr_current_display(w_direct); 263 237 w->c->settings.width = d->primary_mode.width; 264 238 w->c->settings.height = d->primary_mode.height; 265 239 // TODO: size callback ··· 268 242 return true; 269 243 } 270 244 271 - static bool 272 - append_nvidia_entry_on_match(struct comp_window_direct *w, 273 - const char *wl_entry, 274 - struct VkDisplayPropertiesKHR *disp) 275 - { 276 - unsigned long wl_entry_length = strlen(wl_entry); 277 - unsigned long disp_entry_length = strlen(disp->displayName); 278 - if (disp_entry_length < wl_entry_length) 279 - return false; 280 - 281 - if (strncmp(wl_entry, disp->displayName, wl_entry_length) != 0) 282 - return false; 283 - 284 - // we have a match with this whitelist entry. 285 - w->base.c->settings.width = disp->physicalResolution.width; 286 - w->base.c->settings.height = disp->physicalResolution.height; 287 - struct comp_window_direct_nvidia_display d = { 288 - .name = U_TYPED_ARRAY_CALLOC(char, disp_entry_length + 1), 289 - .display_properties = *disp, 290 - .display = disp->display}; 291 - 292 - memcpy(d.name, disp->displayName, disp_entry_length); 293 - d.name[disp_entry_length] = '\0'; 294 - 295 - w->num_displays += 1; 296 - 297 - U_ARRAY_REALLOC_OR_FREE(w->nv_displays, 298 - struct comp_window_direct_nvidia_display, 299 - w->num_displays); 300 - 301 - if (w->nv_displays == NULL) 302 - COMP_ERROR(w->base.c, "Unable to reallocate randr_displays"); 303 - 304 - w->nv_displays[w->num_displays - 1] = d; 305 - 306 - return true; 307 - } 308 - 309 - static bool 310 - comp_window_direct_init_nvidia(struct comp_window *w) 311 - { 312 - // Sanity check. 313 - if (w->c->vk.instance == VK_NULL_HANDLE) { 314 - COMP_ERROR(w->c, "Vulkan not initialized before NVIDIA init!"); 315 - return false; 316 - } 317 - 318 - struct comp_window_direct *w_direct = (struct comp_window_direct *)w; 319 - 320 - if (!comp_window_direct_connect(w_direct)) { 321 - return false; 322 - } 323 - 324 - struct vk_bundle comp_vk = w->c->vk; 325 - 326 - // find our display using nvidia whitelist, enumerate its modes, and 327 - // pick the best one get a list of attached displays 328 - uint32_t display_count; 329 - if (comp_vk.vkGetPhysicalDeviceDisplayPropertiesKHR( 330 - comp_vk.physical_device, &display_count, NULL) != VK_SUCCESS) { 331 - COMP_ERROR(w->c, "Failed to get vulkan display count"); 332 - return false; 333 - } 334 - 335 - if (display_count == 0) { 336 - COMP_ERROR(w->c, "NVIDIA: No Vulkan displays found."); 337 - return false; 338 - } 339 - 340 - struct VkDisplayPropertiesKHR *display_props = 341 - U_TYPED_ARRAY_CALLOC(VkDisplayPropertiesKHR, display_count); 342 - 343 - if (display_props && comp_vk.vkGetPhysicalDeviceDisplayPropertiesKHR( 344 - comp_vk.physical_device, &display_count, 345 - display_props) != VK_SUCCESS) { 346 - COMP_ERROR(w->c, "Failed to get display properties"); 347 - free(display_props); 348 - return false; 349 - } 350 - 351 - // TODO: what if we have multiple whitelisted HMD displays connected? 352 - for (uint32_t i = 0; i < display_count; i++) { 353 - struct VkDisplayPropertiesKHR disp = *(display_props + i); 354 - // check this display against our whitelist 355 - for (uint32_t j = 0; j < ARRAY_SIZE(NV_DIRECT_WHITELIST); j++) 356 - if (append_nvidia_entry_on_match( 357 - w_direct, NV_DIRECT_WHITELIST[j], &disp)) 358 - break; 359 - } 360 - 361 - if (w_direct->num_displays == 0) { 362 - COMP_ERROR(w->c, 363 - "NVIDIA: No machting displays found. " 364 - "Is your headset whitelisted?"); 365 - 366 - COMP_ERROR(w->c, "== Whitelist =="); 367 - for (uint32_t i = 0; i < ARRAY_SIZE(NV_DIRECT_WHITELIST); i++) 368 - COMP_ERROR(w->c, "%s", NV_DIRECT_WHITELIST[i]); 369 - 370 - COMP_ERROR(w->c, "== Available =="); 371 - for (uint32_t i = 0; i < display_count; i++) 372 - COMP_ERROR(w->c, "%s", display_props[i].displayName); 373 - 374 - free(display_props); 375 - return false; 376 - } 377 - 378 - free(display_props); 379 - 380 - return true; 381 - } 382 - 383 245 static struct comp_window_direct_randr_display * 384 - comp_window_direct_current_randr_display(struct comp_window_direct *w) 246 + comp_window_direct_randr_current_display(struct comp_window_direct_randr *w) 385 247 { 386 248 int index = w->base.c->settings.display; 387 249 if (index == -1) ··· 393 255 return &w->randr_displays[index]; 394 256 } 395 257 396 - static struct comp_window_direct_nvidia_display * 397 - comp_window_direct_current_nvidia_display(struct comp_window_direct *w) 398 - { 399 - int index = w->base.c->settings.display; 400 - if (index == -1) 401 - index = 0; 402 - 403 - if (w->num_displays <= (uint32_t)index) 404 - return NULL; 405 - 406 - return &w->nv_displays[index]; 407 - } 408 - 409 - static void 410 - comp_window_direct_flush(struct comp_window *w) 411 - {} 412 - 413 258 static int 414 - choose_best_vk_mode_auto(struct comp_window_direct *w, 259 + choose_best_vk_mode_auto(struct comp_window_direct_randr *w, 415 260 VkDisplayModePropertiesKHR *mode_properties, 416 261 int mode_count) 417 262 { ··· 454 299 } 455 300 456 301 static void 457 - print_modes(struct comp_window_direct *w, 302 + print_modes(struct comp_window_direct_randr *w, 458 303 VkDisplayModePropertiesKHR *mode_properties, 459 304 int mode_count) 460 305 { ··· 472 317 } 473 318 474 319 static VkDisplayModeKHR 475 - comp_window_direct_get_primary_display_mode(struct comp_window_direct *w, 476 - VkDisplayKHR display) 320 + comp_window_direct_randr_get_primary_display_mode( 321 + struct comp_window_direct_randr *w, VkDisplayKHR display) 477 322 { 478 323 struct vk_bundle *vk = w->base.swapchain.vk; 479 324 uint32_t mode_count; ··· 562 407 } 563 408 564 409 static VkResult 565 - comp_window_direct_create_surface(struct comp_window_direct *w, 566 - VkInstance instance, 567 - VkSurfaceKHR *surface, 568 - uint32_t width, 569 - uint32_t height) 410 + comp_window_direct_randr_create_surface(struct comp_window_direct_randr *w, 411 + VkInstance instance, 412 + VkSurfaceKHR *surface, 413 + uint32_t width, 414 + uint32_t height) 570 415 { 571 416 struct comp_window_direct_randr_display *d = 572 - comp_window_direct_current_randr_display(w); 573 - struct comp_window_direct_nvidia_display *nvd = 574 - comp_window_direct_current_nvidia_display(w); 417 + comp_window_direct_randr_current_display(w); 575 418 struct vk_bundle *vk = w->base.swapchain.vk; 576 419 577 420 VkResult ret = VK_ERROR_INCOMPATIBLE_DISPLAY_KHR; ··· 583 426 (double)d->primary_mode.dot_clock / 584 427 (d->primary_mode.htotal * d->primary_mode.vtotal)); 585 428 586 - d->display = 587 - comp_window_direct_get_xlib_randr_output(w, d->output); 429 + d->display = comp_window_direct_randr_get_xlib_randr_output( 430 + w, d->output); 588 431 if (d->display == VK_NULL_HANDLE) { 589 432 return VK_ERROR_INITIALIZATION_FAILED; 590 433 } 591 - ret = comp_window_direct_acquire_xlib_display(w, d->display); 434 + ret = comp_window_direct_randr_acquire_xlib_display(w, 435 + d->display); 592 436 _display = d->display; 593 - } 594 - 595 - if (nvd) { 596 - COMP_DEBUG(w->base.c, "Will use display: %s", nvd->name); 597 - ret = comp_window_direct_acquire_xlib_display(w, nvd->display); 598 - _display = nvd->display; 599 437 } 600 438 601 439 if (ret != VK_SUCCESS) { ··· 634 472 uint32_t plane_index = 0; 635 473 636 474 VkDisplayModeKHR display_mode = 637 - comp_window_direct_get_primary_display_mode(w, _display); 475 + comp_window_direct_randr_get_primary_display_mode(w, _display); 638 476 639 477 VkDisplayPlaneCapabilitiesKHR plane_caps; 640 478 vk->vkGetDisplayPlaneCapabilitiesKHR( ··· 667 505 } 668 506 669 507 static bool 670 - comp_window_direct_init_swapchain(struct comp_window *w, 671 - uint32_t width, 672 - uint32_t height) 508 + comp_window_direct_randr_init_swapchain(struct comp_window *w, 509 + uint32_t width, 510 + uint32_t height) 673 511 { 674 - struct comp_window_direct *w_direct = (struct comp_window_direct *)w; 512 + struct comp_window_direct_randr *w_direct = 513 + (struct comp_window_direct_randr *)w; 675 514 676 - VkResult ret = comp_window_direct_create_surface( 515 + VkResult ret = comp_window_direct_randr_create_surface( 677 516 w_direct, w->swapchain.vk->instance, &w->swapchain.surface, width, 678 517 height); 679 518 if (ret != VK_SUCCESS) { ··· 689 528 } 690 529 691 530 static int 692 - comp_window_direct_connect(struct comp_window_direct *w) 531 + comp_window_direct_randr_connect(struct comp_window_direct_randr *w) 693 532 { 694 533 w->dpy = XOpenDisplay(NULL); 695 534 if (w->dpy == NULL) { ··· 700 539 } 701 540 702 541 static VkResult 703 - comp_window_direct_acquire_xlib_display(struct comp_window_direct *w, 704 - VkDisplayKHR display) 542 + comp_window_direct_randr_acquire_xlib_display( 543 + struct comp_window_direct_randr *w, VkDisplayKHR display) 705 544 { 706 545 struct vk_bundle *vk = w->base.swapchain.vk; 707 546 VkResult ret; ··· 716 555 } 717 556 718 557 static VkDisplayKHR 719 - comp_window_direct_get_xlib_randr_output(struct comp_window_direct *w, 720 - RROutput output) 558 + comp_window_direct_randr_get_xlib_randr_output( 559 + struct comp_window_direct_randr *w, RROutput output) 721 560 { 722 561 struct vk_bundle *vk = w->base.swapchain.vk; 723 562 VkResult ret; ··· 743 582 } 744 583 745 584 static void 746 - append_randr_display(struct comp_window_direct *w, 585 + append_randr_display(struct comp_window_direct_randr *w, 747 586 xcb_randr_get_output_info_reply_t *output_reply, 748 587 xcb_randr_get_screen_resources_reply_t *resources_reply, 749 588 xcb_randr_output_t xcb_output) ··· 801 640 } 802 641 803 642 static void 804 - comp_window_direct_get_randr_outputs(struct comp_window_direct *w) 643 + comp_window_direct_randr_get_outputs(struct comp_window_direct_randr *w) 805 644 { 806 645 xcb_connection_t *connection = XGetXCBConnection(w->dpy); 807 646 xcb_randr_query_version_cookie_t version_cookie = ··· 918 757 919 758 free(resources_reply); 920 759 } 921 - 922 - static void 923 - comp_window_direct_update_window_title(struct comp_window *w, const char *title) 924 - {}
+560
src/xrt/compositor/main/comp_window_direct_nvidia.c
··· 1 + // Copyright 2019, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Direct mode window code. 6 + * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 7 + * @author Jakob Bornecrantz <jakob@collabora.com> 8 + * @ingroup comp_main 9 + */ 10 + 11 + #include <inttypes.h> 12 + 13 + #include "util/u_misc.h" 14 + 15 + #include "xrt/xrt_compiler.h" 16 + #include "main/comp_window.h" 17 + 18 + 19 + /* 20 + * 21 + * Private structs 22 + * 23 + */ 24 + 25 + /*! 26 + * Probed display. 27 + */ 28 + struct comp_window_direct_nvidia_display 29 + { 30 + char *name; 31 + VkDisplayPropertiesKHR display_properties; 32 + VkDisplayKHR display; 33 + }; 34 + 35 + /*! 36 + * Direct mode "window" into a device, using Vulkan direct mode extension 37 + * and xcb. 38 + */ 39 + struct comp_window_direct_nvidia 40 + { 41 + struct comp_window base; 42 + 43 + Display *dpy; 44 + struct comp_window_direct_nvidia_display *nv_displays; 45 + uint16_t num_displays; 46 + }; 47 + 48 + 49 + 50 + /* 51 + * 52 + * Pre decalre functions 53 + * 54 + */ 55 + 56 + static void 57 + comp_window_direct_nvidia_destroy(struct comp_window *w); 58 + 59 + static bool 60 + comp_window_direct_nvidia_init(struct comp_window *w); 61 + 62 + static struct comp_window_direct_nvidia_display * 63 + comp_window_direct_nvidia_current_display(struct comp_window_direct_nvidia *w); 64 + 65 + static VkDisplayModeKHR 66 + comp_window_direct_nvidia_get_primary_display_mode( 67 + struct comp_window_direct_nvidia *w, VkDisplayKHR display); 68 + 69 + static VkDisplayPlaneAlphaFlagBitsKHR 70 + choose_alpha_mode(VkDisplayPlaneAlphaFlagsKHR flags); 71 + 72 + static VkResult 73 + comp_window_direct_nvidia_create_surface(struct comp_window_direct_nvidia *w, 74 + VkInstance instance, 75 + VkSurfaceKHR *surface, 76 + uint32_t width, 77 + uint32_t height); 78 + 79 + static bool 80 + comp_window_direct_nvidia_init_swapchain(struct comp_window *w, 81 + uint32_t width, 82 + uint32_t height); 83 + 84 + static int 85 + comp_window_direct_nvidia_connect(struct comp_window_direct_nvidia *w); 86 + 87 + static VkResult 88 + comp_window_direct_nvidia_acquire_xlib_display( 89 + struct comp_window_direct_nvidia *w, VkDisplayKHR display); 90 + 91 + /* 92 + * 93 + * Functions. 94 + * 95 + */ 96 + 97 + static void 98 + _flush(struct comp_window *w) 99 + {} 100 + 101 + static void 102 + _update_window_title(struct comp_window *w, const char *title) 103 + {} 104 + 105 + struct comp_window * 106 + comp_window_direct_nvidia_create(struct comp_compositor *c) 107 + { 108 + struct comp_window_direct_nvidia *w = 109 + U_TYPED_CALLOC(struct comp_window_direct_nvidia); 110 + 111 + w->base.name = "direct"; 112 + w->base.destroy = comp_window_direct_nvidia_destroy; 113 + w->base.flush = _flush; 114 + w->base.init = comp_window_direct_nvidia_init; 115 + w->base.init_swapchain = comp_window_direct_nvidia_init_swapchain; 116 + w->base.update_window_title = _update_window_title; 117 + w->base.c = c; 118 + 119 + return &w->base; 120 + } 121 + 122 + static void 123 + comp_window_direct_nvidia_destroy(struct comp_window *w) 124 + { 125 + struct comp_window_direct_nvidia *w_direct = 126 + (struct comp_window_direct_nvidia *)w; 127 + 128 + for (uint32_t i = 0; i < w_direct->num_displays; i++) { 129 + struct comp_window_direct_nvidia_display *d = 130 + &w_direct->nv_displays[i]; 131 + d->display = VK_NULL_HANDLE; 132 + free(d->name); 133 + } 134 + 135 + if (w_direct->nv_displays != NULL) 136 + free(w_direct->nv_displays); 137 + 138 + if (w_direct->dpy) { 139 + XCloseDisplay(w_direct->dpy); 140 + w_direct->dpy = NULL; 141 + } 142 + 143 + free(w); 144 + } 145 + 146 + static bool 147 + append_nvidia_entry_on_match(struct comp_window_direct_nvidia *w, 148 + const char *wl_entry, 149 + struct VkDisplayPropertiesKHR *disp) 150 + { 151 + unsigned long wl_entry_length = strlen(wl_entry); 152 + unsigned long disp_entry_length = strlen(disp->displayName); 153 + if (disp_entry_length < wl_entry_length) 154 + return false; 155 + 156 + if (strncmp(wl_entry, disp->displayName, wl_entry_length) != 0) 157 + return false; 158 + 159 + // we have a match with this whitelist entry. 160 + w->base.c->settings.width = disp->physicalResolution.width; 161 + w->base.c->settings.height = disp->physicalResolution.height; 162 + struct comp_window_direct_nvidia_display d = { 163 + .name = U_TYPED_ARRAY_CALLOC(char, disp_entry_length + 1), 164 + .display_properties = *disp, 165 + .display = disp->display}; 166 + 167 + memcpy(d.name, disp->displayName, disp_entry_length); 168 + d.name[disp_entry_length] = '\0'; 169 + 170 + w->num_displays += 1; 171 + 172 + U_ARRAY_REALLOC_OR_FREE(w->nv_displays, 173 + struct comp_window_direct_nvidia_display, 174 + w->num_displays); 175 + 176 + if (w->nv_displays == NULL) 177 + COMP_ERROR(w->base.c, "Unable to reallocate randr_displays"); 178 + 179 + w->nv_displays[w->num_displays - 1] = d; 180 + 181 + return true; 182 + } 183 + 184 + static bool 185 + comp_window_direct_nvidia_init(struct comp_window *w) 186 + { 187 + // Sanity check. 188 + if (w->c->vk.instance == VK_NULL_HANDLE) { 189 + COMP_ERROR(w->c, "Vulkan not initialized before NVIDIA init!"); 190 + return false; 191 + } 192 + 193 + struct comp_window_direct_nvidia *w_direct = 194 + (struct comp_window_direct_nvidia *)w; 195 + 196 + if (!comp_window_direct_nvidia_connect(w_direct)) { 197 + return false; 198 + } 199 + 200 + struct vk_bundle comp_vk = w->c->vk; 201 + 202 + // find our display using nvidia whitelist, enumerate its modes, and 203 + // pick the best one get a list of attached displays 204 + uint32_t display_count; 205 + if (comp_vk.vkGetPhysicalDeviceDisplayPropertiesKHR( 206 + comp_vk.physical_device, &display_count, NULL) != VK_SUCCESS) { 207 + COMP_ERROR(w->c, "Failed to get vulkan display count"); 208 + return false; 209 + } 210 + 211 + if (display_count == 0) { 212 + COMP_ERROR(w->c, "NVIDIA: No Vulkan displays found."); 213 + return false; 214 + } 215 + 216 + struct VkDisplayPropertiesKHR *display_props = 217 + U_TYPED_ARRAY_CALLOC(VkDisplayPropertiesKHR, display_count); 218 + 219 + if (display_props && comp_vk.vkGetPhysicalDeviceDisplayPropertiesKHR( 220 + comp_vk.physical_device, &display_count, 221 + display_props) != VK_SUCCESS) { 222 + COMP_ERROR(w->c, "Failed to get display properties"); 223 + free(display_props); 224 + return false; 225 + } 226 + 227 + // TODO: what if we have multiple whitelisted HMD displays connected? 228 + for (uint32_t i = 0; i < display_count; i++) { 229 + struct VkDisplayPropertiesKHR disp = *(display_props + i); 230 + // check this display against our whitelist 231 + for (uint32_t j = 0; j < ARRAY_SIZE(NV_DIRECT_WHITELIST); j++) 232 + if (append_nvidia_entry_on_match( 233 + w_direct, NV_DIRECT_WHITELIST[j], &disp)) 234 + break; 235 + } 236 + 237 + if (w_direct->num_displays == 0) { 238 + COMP_ERROR(w->c, 239 + "NVIDIA: No machting displays found. " 240 + "Is your headset whitelisted?"); 241 + 242 + COMP_ERROR(w->c, "== Whitelist =="); 243 + for (uint32_t i = 0; i < ARRAY_SIZE(NV_DIRECT_WHITELIST); i++) 244 + COMP_ERROR(w->c, "%s", NV_DIRECT_WHITELIST[i]); 245 + 246 + COMP_ERROR(w->c, "== Available =="); 247 + for (uint32_t i = 0; i < display_count; i++) 248 + COMP_ERROR(w->c, "%s", display_props[i].displayName); 249 + 250 + free(display_props); 251 + return false; 252 + } 253 + 254 + free(display_props); 255 + 256 + return true; 257 + } 258 + 259 + static struct comp_window_direct_nvidia_display * 260 + comp_window_direct_nvidia_current_display(struct comp_window_direct_nvidia *w) 261 + { 262 + int index = w->base.c->settings.display; 263 + if (index == -1) 264 + index = 0; 265 + 266 + if (w->num_displays <= (uint32_t)index) 267 + return NULL; 268 + 269 + return &w->nv_displays[index]; 270 + } 271 + 272 + static int 273 + choose_best_vk_mode_auto(struct comp_window_direct_nvidia *w, 274 + VkDisplayModePropertiesKHR *mode_properties, 275 + int mode_count) 276 + { 277 + if (mode_count == 1) 278 + return 0; 279 + 280 + int best_index = 0; 281 + 282 + // First priority: choose mode that maximizes rendered pixels. 283 + // Second priority: choose mode with highest refresh rate. 284 + for (int i = 1; i < mode_count; i++) { 285 + VkDisplayModeParametersKHR current = 286 + mode_properties[i].parameters; 287 + COMP_DEBUG(w->base.c, "Available Vk direct mode %d: %dx%d@%.2f", 288 + i, current.visibleRegion.width, 289 + current.visibleRegion.height, 290 + (float)current.refreshRate / 1000.); 291 + 292 + 293 + VkDisplayModeParametersKHR best = 294 + mode_properties[best_index].parameters; 295 + 296 + int best_pixels = 297 + best.visibleRegion.width * best.visibleRegion.height; 298 + int pixels = 299 + current.visibleRegion.width * current.visibleRegion.height; 300 + if (pixels > best_pixels) { 301 + best_index = i; 302 + } else if (pixels == best_pixels && 303 + current.refreshRate > best.refreshRate) { 304 + best_index = i; 305 + } 306 + } 307 + VkDisplayModeParametersKHR best = 308 + mode_properties[best_index].parameters; 309 + COMP_DEBUG(w->base.c, "Auto choosing Vk direct mode %d: %dx%d@%.2f", 310 + best_index, best.visibleRegion.width, 311 + best.visibleRegion.width, (float)best.refreshRate / 1000.); 312 + return best_index; 313 + } 314 + 315 + static void 316 + print_modes(struct comp_window_direct_nvidia *w, 317 + VkDisplayModePropertiesKHR *mode_properties, 318 + int mode_count) 319 + { 320 + COMP_PRINT_MODE(w->base.c, "Available Vk modes for direct mode"); 321 + for (int i = 0; i < mode_count; i++) { 322 + VkDisplayModePropertiesKHR props = mode_properties[i]; 323 + uint16_t width = props.parameters.visibleRegion.width; 324 + uint16_t height = props.parameters.visibleRegion.height; 325 + float refresh = (float)props.parameters.refreshRate / 1000.; 326 + 327 + COMP_PRINT_MODE(w->base.c, "| %2d | %dx%d@%.2f", i, width, 328 + height, refresh); 329 + } 330 + COMP_PRINT_MODE(w->base.c, "Listed %d modes", mode_count); 331 + } 332 + 333 + static VkDisplayModeKHR 334 + comp_window_direct_nvidia_get_primary_display_mode( 335 + struct comp_window_direct_nvidia *w, VkDisplayKHR display) 336 + { 337 + struct vk_bundle *vk = w->base.swapchain.vk; 338 + uint32_t mode_count; 339 + VkResult ret; 340 + 341 + ret = vk->vkGetDisplayModePropertiesKHR( 342 + w->base.swapchain.vk->physical_device, display, &mode_count, NULL); 343 + if (ret != VK_SUCCESS) { 344 + COMP_ERROR(w->base.c, "vkGetDisplayModePropertiesKHR: %s", 345 + vk_result_string(ret)); 346 + return VK_NULL_HANDLE; 347 + } 348 + 349 + COMP_DEBUG(w->base.c, "Found %d modes", mode_count); 350 + 351 + VkDisplayModePropertiesKHR *mode_properties = 352 + U_TYPED_ARRAY_CALLOC(VkDisplayModePropertiesKHR, mode_count); 353 + ret = vk->vkGetDisplayModePropertiesKHR( 354 + w->base.swapchain.vk->physical_device, display, &mode_count, 355 + mode_properties); 356 + if (ret != VK_SUCCESS) { 357 + COMP_ERROR(w->base.c, "vkGetDisplayModePropertiesKHR: %s", 358 + vk_result_string(ret)); 359 + free(mode_properties); 360 + return VK_NULL_HANDLE; 361 + } 362 + 363 + print_modes(w, mode_properties, mode_count); 364 + 365 + 366 + int chosen_mode = 0; 367 + 368 + int desired_mode = w->base.c->settings.desired_mode; 369 + if (desired_mode + 1 > (int)mode_count) { 370 + COMP_ERROR(w->base.c, 371 + "Requested mode index %d, but max is %d. Falling " 372 + "back to automatic mode selection", 373 + desired_mode, mode_count); 374 + chosen_mode = 375 + choose_best_vk_mode_auto(w, mode_properties, mode_count); 376 + } else if (desired_mode < 0) { 377 + chosen_mode = 378 + choose_best_vk_mode_auto(w, mode_properties, mode_count); 379 + } else { 380 + COMP_DEBUG(w->base.c, "Using manually chosen mode %d", 381 + desired_mode); 382 + chosen_mode = desired_mode; 383 + } 384 + 385 + VkDisplayModePropertiesKHR props = mode_properties[chosen_mode]; 386 + 387 + COMP_DEBUG(w->base.c, "found display mode %dx%d@%.2f", 388 + props.parameters.visibleRegion.width, 389 + props.parameters.visibleRegion.height, 390 + (float)props.parameters.refreshRate / 1000.); 391 + 392 + int64_t new_frame_interval = 393 + 1000. * 1000. * 1000. * 1000. / props.parameters.refreshRate; 394 + 395 + COMP_DEBUG( 396 + w->base.c, 397 + "Updating compositor settings nominal frame interval from %" PRIu64 398 + " (%f Hz) to %" PRIu64 " (%f Hz)", 399 + w->base.c->settings.nominal_frame_interval_ns, 400 + 1000. * 1000. * 1000. / 401 + (float)w->base.c->settings.nominal_frame_interval_ns, 402 + new_frame_interval, (float)props.parameters.refreshRate / 1000.); 403 + 404 + w->base.c->settings.nominal_frame_interval_ns = new_frame_interval; 405 + 406 + free(mode_properties); 407 + 408 + return props.displayMode; 409 + } 410 + 411 + static VkDisplayPlaneAlphaFlagBitsKHR 412 + choose_alpha_mode(VkDisplayPlaneAlphaFlagsKHR flags) 413 + { 414 + if (flags & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR) { 415 + return VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR; 416 + } 417 + if (flags & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR) { 418 + return VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR; 419 + } 420 + return VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR; 421 + } 422 + 423 + static VkResult 424 + comp_window_direct_nvidia_create_surface(struct comp_window_direct_nvidia *w, 425 + VkInstance instance, 426 + VkSurfaceKHR *surface, 427 + uint32_t width, 428 + uint32_t height) 429 + { 430 + struct comp_window_direct_nvidia_display *nvd = 431 + comp_window_direct_nvidia_current_display(w); 432 + struct vk_bundle *vk = w->base.swapchain.vk; 433 + 434 + VkResult ret = VK_ERROR_INCOMPATIBLE_DISPLAY_KHR; 435 + VkDisplayKHR _display = VK_NULL_HANDLE; 436 + 437 + if (nvd) { 438 + COMP_DEBUG(w->base.c, "Will use display: %s", nvd->name); 439 + ret = comp_window_direct_nvidia_acquire_xlib_display( 440 + w, nvd->display); 441 + _display = nvd->display; 442 + } 443 + 444 + if (ret != VK_SUCCESS) { 445 + return ret; 446 + } 447 + 448 + 449 + // Get plane properties 450 + uint32_t plane_property_count; 451 + ret = vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR( 452 + w->base.swapchain.vk->physical_device, &plane_property_count, NULL); 453 + if (ret != VK_SUCCESS) { 454 + COMP_ERROR(w->base.c, 455 + "vkGetPhysicalDeviceDisplayPlanePropertiesKHR: %s", 456 + vk_result_string(ret)); 457 + return ret; 458 + } 459 + 460 + COMP_DEBUG(w->base.c, "Found %d plane properites.", 461 + plane_property_count); 462 + 463 + VkDisplayPlanePropertiesKHR *plane_properties = U_TYPED_ARRAY_CALLOC( 464 + VkDisplayPlanePropertiesKHR, plane_property_count); 465 + 466 + ret = vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR( 467 + w->base.swapchain.vk->physical_device, &plane_property_count, 468 + plane_properties); 469 + if (ret != VK_SUCCESS) { 470 + COMP_ERROR(w->base.c, 471 + "vkGetPhysicalDeviceDisplayPlanePropertiesKHR: %s", 472 + vk_result_string(ret)); 473 + free(plane_properties); 474 + return ret; 475 + } 476 + 477 + uint32_t plane_index = 0; 478 + 479 + VkDisplayModeKHR display_mode = 480 + comp_window_direct_nvidia_get_primary_display_mode(w, _display); 481 + 482 + VkDisplayPlaneCapabilitiesKHR plane_caps; 483 + vk->vkGetDisplayPlaneCapabilitiesKHR( 484 + w->base.swapchain.vk->physical_device, display_mode, plane_index, 485 + &plane_caps); 486 + 487 + VkDisplaySurfaceCreateInfoKHR surface_info = { 488 + .sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR, 489 + .pNext = NULL, 490 + .flags = 0, 491 + .displayMode = display_mode, 492 + .planeIndex = plane_index, 493 + .planeStackIndex = plane_properties[plane_index].currentStackIndex, 494 + .transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, 495 + .globalAlpha = 1.0, 496 + .alphaMode = choose_alpha_mode(plane_caps.supportedAlpha), 497 + .imageExtent = 498 + { 499 + .width = width, 500 + .height = height, 501 + }, 502 + }; 503 + 504 + VkResult result = vk->vkCreateDisplayPlaneSurfaceKHR( 505 + instance, &surface_info, NULL, surface); 506 + 507 + free(plane_properties); 508 + 509 + return result; 510 + } 511 + 512 + static bool 513 + comp_window_direct_nvidia_init_swapchain(struct comp_window *w, 514 + uint32_t width, 515 + uint32_t height) 516 + { 517 + struct comp_window_direct_nvidia *w_direct = 518 + (struct comp_window_direct_nvidia *)w; 519 + 520 + VkResult ret = comp_window_direct_nvidia_create_surface( 521 + w_direct, w->swapchain.vk->instance, &w->swapchain.surface, width, 522 + height); 523 + if (ret != VK_SUCCESS) { 524 + COMP_ERROR(w->c, "Failed to create surface!"); 525 + return false; 526 + } 527 + 528 + vk_swapchain_create( 529 + &w->swapchain, width, height, w->c->settings.color_format, 530 + w->c->settings.color_space, w->c->settings.present_mode); 531 + 532 + return true; 533 + } 534 + 535 + static int 536 + comp_window_direct_nvidia_connect(struct comp_window_direct_nvidia *w) 537 + { 538 + w->dpy = XOpenDisplay(NULL); 539 + if (w->dpy == NULL) { 540 + COMP_ERROR(w->base.c, "Could not open X display."); 541 + return false; 542 + } 543 + return true; 544 + } 545 + 546 + static VkResult 547 + comp_window_direct_nvidia_acquire_xlib_display( 548 + struct comp_window_direct_nvidia *w, VkDisplayKHR display) 549 + { 550 + struct vk_bundle *vk = w->base.swapchain.vk; 551 + VkResult ret; 552 + 553 + ret = vk->vkAcquireXlibDisplayEXT(w->base.swapchain.vk->physical_device, 554 + w->dpy, display); 555 + if (ret != VK_SUCCESS) { 556 + COMP_ERROR(w->base.c, "vkAcquireXlibDisplayEXT: %s (%p)", 557 + vk_result_string(ret), (void *)display); 558 + } 559 + return ret; 560 + }
+2 -1
src/xrt/compositor/meson.build
··· 33 33 endif 34 34 35 35 if build_xcb_xrandr_direct 36 - compositor_srcs += ['main/comp_window_direct_mode.c'] 36 + compositor_srcs += ['main/comp_window_direct_randr.c', 37 + 'main/comp_window_direct_nvidia.c'] 37 38 compositor_deps += [xcb_randr, x11_xcb] 38 39 endif 39 40