Created
December 17, 2025 06:27
-
-
Save yshui/05795c1054b1c5ec898a7fe6e268e3bb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <vulkan/vulkan_core.h> | |
| #include <wayland-client-core.h> | |
| #include <wayland-client-protocol.h> | |
| #include <wayland-client.h> | |
| #include <wayland-util.h> | |
| #include <vulkan/vulkan.h> | |
| #include <assert.h> | |
| #include <stdbool.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include "lease.h" | |
| struct connector { | |
| struct wp_drm_lease_connector_v1 *iface; | |
| uint32_t id; | |
| char *name; | |
| char *desc; | |
| bool done; | |
| }; | |
| struct lease_device { | |
| struct wp_drm_lease_device_v1 *iface; | |
| int drm_fd; | |
| struct connector conn; | |
| bool done; | |
| } lease_devices[10] = {}; | |
| int num_lease_devices = 0; | |
| void conn_done(void *data, struct wp_drm_lease_connector_v1 *conn) { | |
| struct connector *c = data; | |
| c->done = true; | |
| } | |
| void conn_name(void *data, struct wp_drm_lease_connector_v1 *conn, const char *name) { | |
| struct connector *c = data; | |
| c->name = strdup(name); | |
| } | |
| void conn_id(void *data, struct wp_drm_lease_connector_v1 *conn, uint32_t id) { | |
| struct connector *c = data; | |
| c->id = id; | |
| } | |
| void conn_desc(void *data, struct wp_drm_lease_connector_v1 *conn, const char *desc) { | |
| struct connector *c = data; | |
| c->desc = strdup(desc); | |
| } | |
| void conn_withdrawn(void *data, struct wp_drm_lease_connector_v1 *conn) {} | |
| static const struct wp_drm_lease_connector_v1_listener conn_listener = { | |
| .done = conn_done, | |
| .name = conn_name, | |
| .connector_id = conn_id, | |
| .description = conn_desc, | |
| .withdrawn = conn_withdrawn, | |
| }; | |
| void lease_release(void *data, struct wp_drm_lease_device_v1 *dev) {} | |
| void lease_connector(void *data, struct wp_drm_lease_device_v1 *dev, | |
| struct wp_drm_lease_connector_v1 *conn) { | |
| struct lease_device *wd = data; | |
| wd->conn.iface = conn; | |
| wp_drm_lease_connector_v1_add_listener(conn, &conn_listener, &wd->conn); | |
| } | |
| void lease_drm_fd(void *data, struct wp_drm_lease_device_v1 *dev, int drm_fd) { | |
| struct lease_device *wd = data; | |
| wd->drm_fd = drm_fd; | |
| } | |
| void lease_done(void *data, struct wp_drm_lease_device_v1 *dev) { | |
| struct lease_device *wd = data; | |
| wd->done = true; | |
| } | |
| static const struct wp_drm_lease_device_v1_listener device_listener = { | |
| .released = lease_release, | |
| .connector = lease_connector, | |
| .drm_fd = lease_drm_fd, | |
| .done = lease_done, | |
| }; | |
| static void | |
| registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, | |
| const char *interface, uint32_t version) { | |
| if (strcmp(interface, wp_drm_lease_device_v1_interface.name) == 0) { | |
| lease_devices[num_lease_devices].iface = wl_registry_bind( | |
| registry, name, &wp_drm_lease_device_v1_interface, 1); | |
| wp_drm_lease_device_v1_add_listener( | |
| lease_devices[num_lease_devices].iface, &device_listener, | |
| &lease_devices[num_lease_devices]); | |
| num_lease_devices++; | |
| } | |
| } | |
| static void registry_handle_global_remove(void *data, struct wl_registry *registry, | |
| uint32_t name) {} | |
| static const struct wl_registry_listener registry_listener = { | |
| .global = registry_handle_global, | |
| .global_remove = registry_handle_global_remove, | |
| }; | |
| struct lease { | |
| struct wp_drm_lease_v1 *iface; | |
| int fd; | |
| } lease; | |
| void lease_lease_fd(void *data, struct wp_drm_lease_v1 *lease, int fd) { | |
| struct lease *l = data; | |
| l->fd = fd; | |
| } | |
| void lease_finished(void *data, struct wp_drm_lease_v1 *lease) {} | |
| static const struct wp_drm_lease_v1_listener lease_listener = { | |
| .lease_fd = lease_lease_fd, | |
| .finished = lease_finished, | |
| }; | |
| int main() { | |
| struct wl_display *dpy = wl_display_connect(NULL); | |
| struct wl_registry *registry = wl_display_get_registry(dpy); | |
| wl_registry_add_listener(registry, ®istry_listener, NULL); | |
| wl_display_roundtrip(dpy); | |
| wl_display_roundtrip(dpy); | |
| struct lease_device *selected = NULL; | |
| for (int i = 0; i < num_lease_devices; i++) { | |
| if (lease_devices[i].conn.desc && | |
| strncmp(lease_devices[i].conn.desc, "Valve", 5) == 0) { | |
| selected = &lease_devices[i]; | |
| break; | |
| } | |
| } | |
| assert(selected); | |
| struct wp_drm_lease_request_v1 *req = | |
| wp_drm_lease_device_v1_create_lease_request(selected->iface); | |
| wp_drm_lease_request_v1_request_connector(req, selected->conn.iface); | |
| lease.iface = wp_drm_lease_request_v1_submit(req); | |
| lease.fd = -1; | |
| wp_drm_lease_v1_add_listener(lease.iface, &lease_listener, &lease); | |
| wl_display_roundtrip(dpy); | |
| assert(lease.fd != -1); | |
| // now, vulkan | |
| const struct VkApplicationInfo app = { | |
| .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, | |
| .pApplicationName = "Test", | |
| .applicationVersion = 1, | |
| .pEngineName = "Test", | |
| .engineVersion = 1, | |
| .apiVersion = VK_API_VERSION_1_2, | |
| }; | |
| const char *exts[] = { | |
| "VK_KHR_surface", | |
| "VK_KHR_xlib_surface", | |
| "VK_KHR_display", | |
| "VK_EXT_direct_mode_display", | |
| "VK_EXT_display_surface_counter", | |
| "VK_KHR_external_memory_capabilities", | |
| "VK_KHR_external_semaphore_capabilities", | |
| "VK_KHR_get_physical_device_properties2", | |
| "VK_EXT_debug_utils", | |
| "VK_EXT_acquire_drm_display", | |
| }; | |
| const struct VkInstanceCreateInfo vkci = { | |
| .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | |
| .pApplicationInfo = &app, | |
| .enabledExtensionCount = 10, | |
| .ppEnabledExtensionNames = exts, | |
| }; | |
| VkInstance instance; | |
| VkResult res = vkCreateInstance(&vkci, NULL, &instance); | |
| assert(res == VK_SUCCESS); | |
| VkPhysicalDevice devices[2]; | |
| uint32_t num_phydev = 2; | |
| res = vkEnumeratePhysicalDevices(instance, &num_phydev, devices); | |
| assert(res == VK_SUCCESS); | |
| assert(num_phydev > 0); | |
| #define GETPROC(name) \ | |
| PFN_##name p##name = (void *)vkGetInstanceProcAddr(instance, #name) | |
| GETPROC(vkGetDrmDisplayEXT); | |
| GETPROC(vkAcquireDrmDisplayEXT); | |
| GETPROC(vkCreateDisplayPlaneSurfaceKHR); | |
| GETPROC(vkGetDisplayModePropertiesKHR); | |
| GETPROC(vkGetPhysicalDeviceSurfaceFormatsKHR); | |
| VkDisplayKHR vkdpy; | |
| res = pvkGetDrmDisplayEXT(devices[0], selected->drm_fd, selected->conn.id, | |
| &vkdpy); | |
| assert(res == VK_SUCCESS); | |
| VkDisplayModePropertiesKHR display_modes[10]; | |
| uint32_t num_display_modes = 10; | |
| res = pvkGetDisplayModePropertiesKHR(devices[0], vkdpy, &num_display_modes, | |
| display_modes); | |
| assert(res == VK_SUCCESS); | |
| assert(num_display_modes > 0); | |
| res = pvkAcquireDrmDisplayEXT(devices[0], lease.fd, vkdpy); | |
| assert(res == VK_SUCCESS); | |
| VkExtent2D size = display_modes[0].parameters.visibleRegion; | |
| const struct VkDisplaySurfaceCreateInfoKHR dsci = { | |
| .sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR, | |
| .displayMode = display_modes[0].displayMode, | |
| .transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, | |
| .globalAlpha = 1.0, | |
| .alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR, | |
| .imageExtent = size, | |
| }; | |
| VkSurfaceKHR surface; | |
| res = pvkCreateDisplayPlaneSurfaceKHR(instance, &dsci, NULL, &surface); | |
| assert(res == VK_SUCCESS); | |
| uint32_t num_formats = 10; | |
| VkSurfaceFormatKHR formats[10]; | |
| res = pvkGetPhysicalDeviceSurfaceFormatsKHR(devices[0], surface, | |
| &num_formats, formats); | |
| assert(res == VK_SUCCESS); | |
| assert(num_formats > 0); // <- fails here | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment