comp: add VkDisplayKHR window backend

Must be activated/selected with an env var for now: XRT_COMPOSITOR_FORCE_VK_DISPLAY=2
This commit is contained in:
Christoph Haag 2021-01-15 15:24:00 +01:00 committed by Jakob Bornecrantz
parent 1ea5403435
commit 9481013081
11 changed files with 314 additions and 10 deletions

View file

@ -250,7 +250,9 @@ endif()
if(WIN32)
set(VK_USE_PLATFORM_WIN32_KHR TRUE)
endif()
if (XRT_HAVE_VULKAN AND NOT ANDROID)
set(VK_USE_PLATFORM_DISPLAY_KHR TRUE)
endif()
if(NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -Wextra -Wno-unused-parameter")

View file

@ -131,6 +131,9 @@ endif
build_xcb_xrandr_direct = build_xcb and build_xlib and xcb_randr.found() and x11_xcb.found()
# requires only vulkan
build_vk_khr_display = true
build_wayland = false
if get_option('wayland').enabled() or get_option('wayland').auto()
build_wayland = wayland.found() and wayland_protos.found() and wayland_scanner.found()

View file

@ -119,7 +119,11 @@ if(XRT_FEATURE_COMPOSITOR_MAIN)
main/comp_window_mswin.c
)
endif()
if (VK_USE_PLATFORM_DISPLAY_KHR)
list(APPEND MAIN_SOURCE_FILES
main/comp_window_vk_display.c
)
endif()
# generate wayland protocols
if(XRT_HAVE_WAYLAND)

View file

@ -694,6 +694,13 @@ static const char *instance_extensions_direct_mode[] = {
};
#endif
#ifdef VK_USE_PLATFORM_DISPLAY_KHR
static const char *instance_extensions_vk_display[] = {
COMP_INSTANCE_EXTENSIONS_COMMON,
VK_KHR_DISPLAY_EXTENSION_NAME,
};
#endif
#ifdef VK_USE_PLATFORM_ANDROID_KHR
static const char *instance_extensions_android[] = {COMP_INSTANCE_EXTENSIONS_COMMON,
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME};
@ -785,6 +792,12 @@ select_instances_extensions(struct comp_compositor *c, const char ***out_exts, u
*out_exts = instance_extensions_windows;
*out_num = ARRAY_SIZE(instance_extensions_windows);
break;
#endif
#ifdef VK_USE_PLATFORM_DISPLAY_KHR
case WINDOW_VK_DISPLAY:
*out_exts = instance_extensions_vk_display;
*out_num = ARRAY_SIZE(instance_extensions_vk_display);
break;
#endif
default: return VK_ERROR_INITIALIZATION_FAILED;
}
@ -1106,8 +1119,8 @@ compositor_try_window(struct comp_compositor *c, struct comp_target *ct)
static bool
compositor_init_window_pre_vulkan(struct comp_compositor *c)
{
// Nothing to do for nvidia.
if (c->settings.window_type == WINDOW_DIRECT_NVIDIA) {
// Nothing to do for nvidia and vk_display.
if (c->settings.window_type == WINDOW_DIRECT_NVIDIA || c->settings.window_type == WINDOW_VK_DISPLAY) {
return true;
}
@ -1197,16 +1210,25 @@ compositor_init_window_pre_vulkan(struct comp_compositor *c)
static bool
compositor_init_window_post_vulkan(struct comp_compositor *c)
{
if (c->settings.window_type != WINDOW_DIRECT_NVIDIA) {
return true;
}
if (c->settings.window_type == WINDOW_DIRECT_NVIDIA) {
#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
return compositor_try_window(c, comp_window_direct_nvidia_create(c));
#else
assert(false && "NVIDIA direct mode depends on the xlib/xrandr direct mode.");
return false;
#endif
}
if (c->settings.window_type == WINDOW_VK_DISPLAY) {
#ifdef VK_USE_PLATFORM_DISPLAY_KHR
return compositor_try_window(c, comp_window_vk_display_create(c));
#else
assert(false && "VkDisplayKHR direct mode depends on VK_USE_PLATFORM_DISPLAY_KHR.");
return false;
#endif
}
return true;
}
static bool

View file

@ -16,6 +16,7 @@ DEBUG_GET_ONCE_BOOL_OPTION(print_modes, "XRT_COMPOSITOR_PRINT_MODES", false)
DEBUG_GET_ONCE_BOOL_OPTION(force_randr, "XRT_COMPOSITOR_FORCE_RANDR", false)
DEBUG_GET_ONCE_BOOL_OPTION(force_nvidia, "XRT_COMPOSITOR_FORCE_NVIDIA", false)
DEBUG_GET_ONCE_OPTION(nvidia_display, "XRT_COMPOSITOR_FORCE_NVIDIA_DISPLAY", NULL)
DEBUG_GET_ONCE_NUM_OPTION(vk_display, "XRT_COMPOSITOR_FORCE_VK_DISPLAY", -1)
DEBUG_GET_ONCE_BOOL_OPTION(force_xcb, "XRT_COMPOSITOR_FORCE_XCB", false)
DEBUG_GET_ONCE_BOOL_OPTION(force_wayland, "XRT_COMPOSITOR_FORCE_WAYLAND", false)
DEBUG_GET_ONCE_BOOL_OPTION(wireframe, "XRT_COMPOSITOR_WIREFRAME", false)
@ -60,6 +61,10 @@ comp_settings_init(struct comp_settings *s, struct xrt_device *xdev)
}
s->nvidia_display = debug_get_option_nvidia_display();
s->vk_display = debug_get_num_option_vk_display();
if (s->vk_display >= 0) {
s->window_type = WINDOW_VK_DISPLAY;
}
if (debug_get_bool_option_force_randr()) {
s->window_type = WINDOW_DIRECT_RANDR;

View file

@ -48,6 +48,7 @@ enum window_type
WINDOW_DIRECT_NVIDIA,
WINDOW_ANDROID,
WINDOW_MSWIN,
WINDOW_VK_DISPLAY,
};
@ -70,6 +71,9 @@ struct comp_settings
//! display string forced by user or NULL
const char *nvidia_display;
//! vk display number to use when forcing vk_display
int vk_display;
struct
{
uint32_t width;

View file

@ -68,6 +68,14 @@ struct comp_target *
comp_window_direct_nvidia_create(struct comp_compositor *c);
#endif
/*!
* Create a direct surface to an HMD on VkDisplay.
*
* @ingroup comp_main
* @public @memberof comp_window_direct_vk_display
*/
struct comp_target *
comp_window_vk_display_create(struct comp_compositor *c);
#ifdef XRT_OS_ANDROID

View file

@ -0,0 +1,248 @@
// Copyright 2019-2021, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Direct mode on PLATFORM_DISPLAY_KHR code.
* @author Christoph Haag <christoph.haag@collabora.com>
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup comp_main
*/
#include "util/u_misc.h"
#include "main/comp_window_direct.h"
/*
*
* Private structs
*
*/
/*!
* Probed display.
*/
struct vk_display
{
VkDisplayPropertiesKHR display_properties;
VkDisplayKHR display;
};
/*!
* Direct mode "window" into a device, using PLATFORM_DISPLAY_KHR.
*
* @implements comp_target_swapchain
*/
struct comp_window_vk_display
{
struct comp_target_swapchain base;
struct vk_display *displays;
uint16_t num_displays;
};
/*
*
* Forward declare functions
*
*/
static void
comp_window_vk_display_destroy(struct comp_target *ct);
static bool
comp_window_vk_display_init(struct comp_target *ct);
static struct vk_display *
comp_window_vk_display_current_display(struct comp_window_vk_display *w);
static bool
comp_window_vk_display_init_swapchain(struct comp_target *ct, uint32_t width, uint32_t height);
/*
*
* Functions.
*
*/
static void
_flush(struct comp_target *ct)
{
(void)ct;
}
static void
_update_window_title(struct comp_target *ct, const char *title)
{
(void)ct;
(void)title;
}
struct comp_target *
comp_window_vk_display_create(struct comp_compositor *c)
{
struct comp_window_vk_display *w = U_TYPED_CALLOC(struct comp_window_vk_display);
comp_target_swapchain_init_set_fnptrs(&w->base);
w->base.base.name = "VkDisplayKHR";
w->base.base.destroy = comp_window_vk_display_destroy;
w->base.base.flush = _flush;
w->base.base.init_pre_vulkan = comp_window_vk_display_init;
w->base.base.init_post_vulkan = comp_window_vk_display_init_swapchain;
w->base.base.set_title = _update_window_title;
w->base.base.c = c;
return &w->base.base;
}
static void
comp_window_vk_display_destroy(struct comp_target *ct)
{
struct comp_window_vk_display *w_direct = (struct comp_window_vk_display *)ct;
comp_target_swapchain_cleanup(&w_direct->base);
for (uint32_t i = 0; i < w_direct->num_displays; i++) {
struct vk_display *d = &w_direct->displays[i];
d->display = VK_NULL_HANDLE;
}
if (w_direct->displays != NULL)
free(w_direct->displays);
free(ct);
}
static bool
append_vk_display_entry(struct comp_window_vk_display *w, struct VkDisplayPropertiesKHR *disp)
{
w->base.base.c->settings.preferred.width = disp->physicalResolution.width;
w->base.base.c->settings.preferred.height = disp->physicalResolution.height;
struct vk_display d = {.display_properties = *disp, .display = disp->display};
w->num_displays += 1;
U_ARRAY_REALLOC_OR_FREE(w->displays, struct vk_display, w->num_displays);
if (w->displays == NULL)
COMP_ERROR(w->base.base.c, "Unable to reallocate vk_display displays");
w->displays[w->num_displays - 1] = d;
return true;
}
static void
print_found_displays(struct comp_compositor *c, struct VkDisplayPropertiesKHR *display_props, uint32_t display_count)
{
COMP_ERROR(c, "== Found Displays ==");
for (uint32_t i = 0; i < display_count; i++) {
struct VkDisplayPropertiesKHR *p = &display_props[i];
COMP_ERROR(c, "[%d] %s with resolution %dx%d, dims %dx%d", i, p->displayName,
p->physicalResolution.width, p->physicalResolution.height, p->physicalDimensions.width,
p->physicalDimensions.height);
}
}
static bool
comp_window_vk_display_init(struct comp_target *ct)
{
struct comp_window_vk_display *w_direct = (struct comp_window_vk_display *)ct;
// Sanity check.
if (ct->c->vk.instance == VK_NULL_HANDLE) {
COMP_ERROR(ct->c, "Vulkan not initialized before vk display init!");
return false;
}
struct vk_bundle comp_vk = ct->c->vk;
uint32_t display_count;
if (comp_vk.vkGetPhysicalDeviceDisplayPropertiesKHR(comp_vk.physical_device, &display_count, NULL) !=
VK_SUCCESS) {
COMP_ERROR(ct->c, "Failed to get vulkan display count");
return false;
}
if (display_count == 0) {
COMP_ERROR(ct->c, "No Vulkan displays found.");
return false;
}
struct VkDisplayPropertiesKHR *display_props = U_TYPED_ARRAY_CALLOC(VkDisplayPropertiesKHR, display_count);
if (display_props && comp_vk.vkGetPhysicalDeviceDisplayPropertiesKHR(comp_vk.physical_device, &display_count,
display_props) != VK_SUCCESS) {
COMP_ERROR(ct->c, "Failed to get display properties");
free(display_props);
return false;
}
if (ct->c->settings.vk_display > (int)display_count) {
COMP_ERROR(ct->c, "Requested display %d, but only %d found.", ct->c->settings.vk_display,
display_count);
print_found_displays(ct->c, display_props, display_count);
free(display_props);
return false;
}
append_vk_display_entry(w_direct, &display_props[ct->c->settings.vk_display]);
struct vk_display *d = comp_window_vk_display_current_display(w_direct);
if (!d) {
COMP_ERROR(ct->c, "display not found!");
print_found_displays(ct->c, display_props, display_count);
free(display_props);
return false;
}
free(display_props);
return true;
}
static struct vk_display *
comp_window_vk_display_current_display(struct comp_window_vk_display *w)
{
int index = w->base.base.c->settings.display;
if (index == -1)
index = 0;
if (w->num_displays <= (uint32_t)index)
return NULL;
return &w->displays[index];
}
static bool
init_swapchain(struct comp_target_swapchain *cts, VkDisplayKHR display, uint32_t width, uint32_t height)
{
VkResult ret;
ret = comp_window_direct_create_surface(cts, display, width, height);
if (ret != VK_SUCCESS) {
COMP_ERROR(cts->base.c, "Failed to create surface! '%s'", vk_result_string(ret));
return false;
}
return true;
}
static bool
comp_window_vk_display_init_swapchain(struct comp_target *ct, uint32_t width, uint32_t height)
{
struct comp_window_vk_display *w_direct = (struct comp_window_vk_display *)ct;
struct vk_display *d = comp_window_vk_display_current_display(w_direct);
if (!d) {
COMP_ERROR(ct->c, "display not found.");
return false;
}
COMP_DEBUG(ct->c, "Will use display: %s", d->display_properties.displayName);
return init_swapchain(&w_direct->base, d->display, width, height);
}

View file

@ -36,6 +36,10 @@ compositor_srcs = [
compile_args = []
if build_vk_khr_display
compositor_srcs += ['main/comp_window_vk_display.c']
endif
if build_xcb
compositor_srcs += ['main/comp_window_xcb.c']
compositor_deps += [xcb]

View file

@ -151,6 +151,9 @@ endif
if build_xcb_xrandr_direct
vulkan_conf.set('VK_USE_PLATFORM_XLIB_XRANDR_EXT', true)
endif
if build_vk_khr_display
vulkan_conf.set('VK_USE_PLATFORM_DISPLAY_KHR', true)
endif
xrt_config_vulkan_h = configure_file(
output: 'xrt_config_vulkan.h',

View file

@ -14,3 +14,4 @@
#cmakedefine VK_USE_PLATFORM_XCB_KHR
#cmakedefine VK_USE_PLATFORM_XLIB_XRANDR_EXT
#cmakedefine VK_USE_PLATFORM_WIN32_KHR
#cmakedefine VK_USE_PLATFORM_DISPLAY_KHR