summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2017-05-30 01:23:41 -0700
committerKeith Packard <keithp@keithp.com>2017-06-01 14:17:34 -0700
commit4b08fecc5c68478f857c5505309a964736c67df7 (patch)
treec5cdc5c8628611fc8ebac260d53c8d9024fef7ca
parent062ee2e834efa4a9a01beba49e15905dbb2f8475 (diff)
Use the VK_KEITHP_kms_display and VK_KHR_display extensions and DRM leases
This creates a lease for an idle-but-connected monitor, passes that in to the Vulkan driver using the VK_KEITHP_kms_display extension and then uses the VK_KHR_display extension to display output directly to that, bypassing the window system. Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--Makefile4
-rw-r--r--cube.c201
2 files changed, 191 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index 91544e4..697bb3b 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ INCS=\
gettime.h\
linmath.h
-LIBS=-L/local/xorg/lib -lvulkan -lxcb -lm
+LIBS=-L/local/xorg/lib -lvulkan -lxcb-randr -lxcb -lm -ldrm
TARGET=cube
@@ -15,7 +15,7 @@ GLSV=glslangValidator
SPV=cube-vert.spv cube-frag.spv
-CFLAGS=-O0 -g -DVK_USE_PLATFORM_XCB_KHR -DVK_USE_PLATFORM_KMS_KEITHP -I/local/xorg/include -I/local/xorg/include/libdrm
+CFLAGS=-O0 -g -DVK_USE_PLATFORM_DISPLAY_KHR -I/local/xorg/include -I/local/xorg/include/libdrm
all: $(TARGET) $(SPV)
diff --git a/cube.c b/cube.c
index 2f94711..4be94d5 100644
--- a/cube.c
+++ b/cube.c
@@ -36,9 +36,14 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
-#if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
+#include <unistd.h>
+#if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_DISPLAY_KHR)
#include <X11/Xutil.h>
#endif
+#if defined (VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_DISPLAY_KHR)
+#include <xcb/xcb.h>
+#include <xcb/randr.h>
+#endif
#ifdef _WIN32
#pragma comment(linker, "/subsystem:windows")
@@ -55,6 +60,8 @@
#include <vulkan/vulkan.h>
#endif
+#include <vulkan/vulkan_keithp.h>
+
#include <vulkan/vk_sdk_platform.h>
#include "linmath.h"
@@ -325,7 +332,7 @@ struct demo {
Display *display;
Window xlib_window;
Atom xlib_wm_delete_window;
-#elif defined(VK_USE_PLATFORM_XCB_KHR)
+#elif defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_DISPLAY_KHR)
Display *display;
xcb_connection_t *connection;
xcb_screen_t *screen;
@@ -345,6 +352,7 @@ struct demo {
void *window;
#endif
VkSurfaceKHR surface;
+ VkKmsDisplayInfoKEITHP display_info;
bool prepared;
bool use_staging_buffer;
bool separate_present_queue;
@@ -2406,8 +2414,7 @@ static void demo_cleanup(struct demo *demo) {
#if defined(VK_USE_PLATFORM_XLIB_KHR)
XDestroyWindow(demo->display, demo->xlib_window);
XCloseDisplay(demo->display);
-#elif defined(VK_USE_PLATFORM_XCB_KHR)
- xcb_destroy_window(demo->connection, demo->xcb_window);
+#elif defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_DISPLAY_KHR)
xcb_disconnect(demo->connection);
free(demo->atom_wm_delete_window);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
@@ -3005,6 +3012,149 @@ static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
return 1;
}
+static VkBool32 fill_in_display_info(struct demo *demo)
+{
+ VkKmsDisplayInfoKEITHP *display_info = &demo->display_info;
+
+ if (getenv("CUBE_NATIVE")) {
+ display_info->fd = open("/dev/dri/card0", 2);
+ display_info->sType = VK_STRUCTURE_TYPE_KMS_DISPLAY_INFO_KEITHP;
+ display_info->pNext = NULL;
+ return display_info->fd >= 0;
+ }
+
+ xcb_connection_t *connection;
+ int screen = 0;
+ int fd;
+ drmModeResPtr mode_res;
+ drmModeConnectorPtr mode_connector;
+ drmModeModeInfoPtr mode, mode_copy;
+ const xcb_setup_t *setup;
+ xcb_screen_iterator_t iter;
+ int scr;
+
+ demo->connection = xcb_connect(NULL, &scr);
+ if (xcb_connection_has_error(demo->connection) > 0) {
+ printf("Cannot find a compatible Vulkan installable client driver "
+ "(ICD).\nExiting ...\n");
+ fflush(stdout);
+ exit(1);
+ }
+
+ setup = xcb_get_setup(demo->connection);
+ iter = xcb_setup_roots_iterator(setup);
+ while (scr-- > 0)
+ xcb_screen_next(&iter);
+
+ demo->screen = iter.data;
+
+ connection = demo->connection;
+
+ xcb_randr_query_version_cookie_t rqv_c = xcb_randr_query_version(connection,
+ XCB_RANDR_MAJOR_VERSION,
+ XCB_RANDR_MINOR_VERSION);
+ xcb_randr_query_version_reply_t *rqv_r = xcb_randr_query_version_reply(connection, rqv_c, NULL);
+
+ if (!rqv_r || rqv_r->minor_version < 6) {
+ printf("No new-enough RandR version\n");
+ return 0;
+ }
+
+ xcb_screen_iterator_t s_i;
+
+ int i_s = 0;
+
+ for (s_i = xcb_setup_roots_iterator(xcb_get_setup(connection));
+ s_i.rem;
+ xcb_screen_next(&s_i), i_s++) {
+ printf ("index %d screen %d\n", s_i.index, screen);
+ if (i_s == screen)
+ break;
+ }
+
+ xcb_window_t root = s_i.data->root;
+
+ printf("root %x\n", root);
+
+ xcb_randr_get_screen_resources_cookie_t gsr_c = xcb_randr_get_screen_resources(connection, root);
+
+ xcb_randr_get_screen_resources_reply_t *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
+
+ if (!gsr_r) {
+ printf("get_screen_resources failed\n");
+ return 0;
+ }
+
+ xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
+ int o, c;
+
+ xcb_randr_output_t output = 0;
+
+ /* Find a connected but idle output */
+ for (o = 0; output == 0 && o < gsr_r->num_outputs; o++) {
+ xcb_randr_get_output_info_cookie_t goi_c = xcb_randr_get_output_info(connection, ro[o], gsr_r->config_timestamp);
+
+ xcb_randr_get_output_info_reply_t *goi_r = xcb_randr_get_output_info_reply(connection, goi_c, NULL);
+
+ /* Find the first connected but unused output */
+ if (goi_r->connection == XCB_RANDR_CONNECTION_CONNECTED &&
+ goi_r->crtc == 0) {
+ output = ro[o];
+ }
+
+ free(goi_r);
+ }
+
+ xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
+
+ xcb_randr_crtc_t crtc = 0;
+
+ /* Find an idle crtc */
+ for (c = 0; crtc == 0 && c < gsr_r->num_crtcs; c++) {
+ xcb_randr_get_crtc_info_cookie_t gci_c = xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
+
+ xcb_randr_get_crtc_info_reply_t *gci_r = xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
+
+ /* Find the first connected but unused crtc */
+ if (gci_r->mode == 0)
+ crtc = rc[c];
+
+ free(gci_r);
+ }
+
+ free(gsr_r);
+
+ printf("output %x crtc %x\n", output, crtc);
+
+ xcb_randr_lease_t lease = xcb_generate_id(connection);
+
+ xcb_randr_create_lease_cookie_t rcl_c = xcb_randr_create_lease(connection,
+ root,
+ lease,
+ 1,
+ 1,
+ &crtc,
+ &output);
+ xcb_randr_create_lease_reply_t *rcl_r = xcb_randr_create_lease_reply(connection, rcl_c, NULL);
+
+ if (!rcl_r) {
+ printf("create_lease failed\n");
+ return 0;
+ }
+
+ int *rcl_f = xcb_randr_create_lease_reply_fds(connection, rcl_r);
+
+ fd = rcl_f[0];
+
+ printf("fd %d\n", fd);
+
+ display_info->sType = VK_STRUCTURE_TYPE_KMS_DISPLAY_INFO_KEITHP;
+ display_info->pNext = NULL;
+ display_info->fd = fd;
+
+ return 1;
+}
+
static void demo_init_vk(struct demo *demo) {
VkResult err;
uint32_t instance_extension_count = 0;
@@ -3078,6 +3228,7 @@ static void demo_init_vk(struct demo *demo) {
VkBool32 surfaceExtFound = 0;
VkBool32 platformSurfaceExtFound = 0;
VkBool32 kmsExtFound = 0;
+ VkBool32 displayExtFound = 0;
memset(demo->extension_names, 0, sizeof(demo->extension_names));
err = vkEnumerateInstanceExtensionProperties(
@@ -3154,6 +3305,7 @@ static void demo_init_vk(struct demo *demo) {
if (!strcmp(VK_KEITHP_KMS_DISPLAY_EXTENSION_NAME,
instance_extensions[i].extensionName)) {
printf("found kms display extension\n");
+ kmsExtFound = 1;
demo->extension_names[demo->enabled_extension_count++] = VK_KEITHP_KMS_DISPLAY_EXTENSION_NAME;
}
if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
@@ -3272,7 +3424,7 @@ static void demo_init_vk(struct demo *demo) {
VkValidationFlagsEXT val_flags;
if (demo->validate) {
dbgCreateInfoTemp.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
- dbgCreateInfoTemp.pNext = NULL;
+ dbgCreateInfoTemp.pNext = inst_info.pNext;
dbgCreateInfoTemp.pfnCallback = demo->use_break ? BreakCallback : dbgFunc;
dbgCreateInfoTemp.pUserData = demo;
dbgCreateInfoTemp.flags =
@@ -3290,6 +3442,13 @@ static void demo_init_vk(struct demo *demo) {
uint32_t gpu_count;
+ if (kmsExtFound) {
+ if (fill_in_display_info(demo)) {
+ demo->display_info.pNext = inst_info.pNext;
+ inst_info.pNext = &demo->display_info;
+ }
+ }
+
err = vkCreateInstance(&inst_info, NULL, &demo->inst);
if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
@@ -3307,12 +3466,6 @@ static void demo_init_vk(struct demo *demo) {
"vkCreateInstance Failure");
}
- VkKmsDisplayInfoKEITHP display_info = {
- .fd = open("/dev/dri/renderD128", 2),
- };
-
- vkSetKmsDisplayInfoKEITHP(demo->inst, &display_info);
-
/* Make initial call to query gpu_count, then second call for gpu info*/
err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
assert(!err && gpu_count > 0);
@@ -3331,7 +3484,31 @@ static void demo_init_vk(struct demo *demo) {
"additional information.\n",
"vkEnumeratePhysicalDevices Failure");
}
- close(display_info.fd);
+
+ if (kmsExtFound)
+ close(demo->display_info.fd);
+
+ if (displayExtFound) {
+ uint32_t display_property_count = 0;
+ VkDisplayPropertiesKHR *display_properties;
+ err = vkGetPhysicalDeviceDisplayPropertiesKHR(demo->gpu, &display_property_count, NULL);
+ if (err != VK_SUCCESS)
+ ERR_EXIT("Cannot enumerate physical device display properties\n",
+ "vkGetPhysicalDeviceDisplayPropertiesKHR Failure");
+
+ display_properties = calloc(display_property_count, sizeof (VkDisplayPropertiesKHR));
+ err = vkGetPhysicalDeviceDisplayPropertiesKHR(demo->gpu, &display_property_count, display_properties);
+ if (err != VK_SUCCESS)
+ ERR_EXIT("Cannot enumerate physical device display properties\n",
+ "vkGetPhysicalDeviceDisplayPropertiesKHR Failure");
+
+ for (uint32_t i = 0; i < display_property_count; i++) {
+ printf("name %s %dx%d pixels\n",
+ display_properties[i].displayName,
+ display_properties[i].physicalResolution.width,
+ display_properties[i].physicalResolution.height);
+ }
+ }
/* Look for device extensions */
uint32_t device_extension_count = 0;