File x11_direct.cpp
File List > display > x11_direct.cpp
Go to the documentation of this file
#ifndef __ANDROID__
# include "x11_direct.hpp"
# include "illixr/vk/vulkan_utils.hpp"
# include "X11/extensions/Xrandr.h"
# include
# include
# include
using namespace ILLIXR::display;
void x11_direct::setup_display(const std::shared_ptr<switchboard> switchboard_, VkInstance vk_instance,
VkPhysicalDevice vk_physical_device) {
this->vk_instance_ = vk_instance;
this->vk_physical_device_ = vk_physical_device;
Display* dpy = XOpenDisplay(nullptr);
if (dpy == nullptr) {
ILLIXR::abort("Failed to open X display");
return;
}
uint32_t display_count;
VK_ASSERT_SUCCESS(vkGetPhysicalDeviceDisplayPropertiesKHR(vk_physical_device, &display_count, nullptr));
std::vector<VkDisplayPropertiesKHR> display_properties(display_count);
VK_ASSERT_SUCCESS(vkGetPhysicalDeviceDisplayPropertiesKHR(vk_physical_device, &display_count, display_properties.data()));
std::cout << "Found " << display_count << " displays:" << std::endl;
int index = 0;
for (const auto& display : display_properties) {
std::cout << "\t[" << index++ << "] " << display.displayName << std::endl;
}
auto display_select_str = switchboard_->get_env_char("ILLIXR_DIRECT_MODE_DISPLAY");
int display_select = 0;
if (display_select_str == nullptr) {
std::cout << "ILLIXR_DIRECT_MODE_DISPLAY not set, defaulting to the first display ("
<< display_properties[0].displayName << ")" << std::endl;
} else {
display_select = std::stoi(display_select_str);
}
if (display_select >= (int) display_count) {
ILLIXR::abort("Invalid display selection");
return;
}
display_ = display_properties[display_select].display;
// Now we acquire the Xlib display
auto acquire_xlib_display = (PFN_vkAcquireXlibDisplayEXT) vkGetInstanceProcAddr(vk_instance, "vkAcquireXlibDisplayEXT");
if (acquire_xlib_display == nullptr) {
ILLIXR::abort("Failed to load vkAcquireXlibDisplayEXT");
return;
}
auto ret = acquire_xlib_display(vk_physical_device, dpy, display_);
if (ret != VK_SUCCESS) {
ILLIXR::abort("Failed to acquire Xlib display");
return;
}
std::cout << "Acquired Xlib display" << std::endl;
}
VkSurfaceKHR x11_direct::create_surface() {
uint32_t plane_count;
VK_ASSERT_SUCCESS(vkGetPhysicalDeviceDisplayPlanePropertiesKHR(vk_physical_device_, &plane_count, nullptr));
std::vector<VkDisplayPlanePropertiesKHR> plane_properties(plane_count);
VK_ASSERT_SUCCESS(vkGetPhysicalDeviceDisplayPlanePropertiesKHR(vk_physical_device_, &plane_count, plane_properties.data()));
uint32_t plane_index = 0;
for (const auto& plane : plane_properties) {
if (plane.currentDisplay == nullptr) {
break;
}
plane_index++;
}
if (plane_index == plane_count) {
ILLIXR::abort("Failed to find display plane");
return nullptr;
}
uint32_t mode_count;
VK_ASSERT_SUCCESS(vkGetDisplayModePropertiesKHR(vk_physical_device_, display_, &mode_count, nullptr));
std::vector<VkDisplayModePropertiesKHR> mode_properties(mode_count);
VK_ASSERT_SUCCESS(vkGetDisplayModePropertiesKHR(vk_physical_device_, display_, &mode_count, mode_properties.data()));
selected_mode_ = select_display_mode(mode_properties);
VkDisplayPlaneCapabilitiesKHR plane_capabilities;
VK_ASSERT_SUCCESS(
vkGetDisplayPlaneCapabilitiesKHR(vk_physical_device_, selected_mode_.displayMode, plane_index, &plane_capabilities));
VkDisplaySurfaceCreateInfoKHR surface_create_info = {
VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR,
nullptr,
0,
selected_mode_.displayMode,
plane_index,
plane_properties[plane_index].currentStackIndex,
VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
1.0f,
VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR,
selected_mode_.parameters.visibleRegion,
};
VkSurfaceKHR surface;
VK_ASSERT_SUCCESS(vkCreateDisplayPlaneSurfaceKHR(vk_instance_, &surface_create_info, nullptr, &surface));
return surface;
}
void x11_direct::cleanup() { }
std::set<const char*> x11_direct::get_required_instance_extensions() {
std::set<const char*> extensions;
extensions.insert(VK_KHR_SURFACE_EXTENSION_NAME);
extensions.insert(VK_KHR_DISPLAY_EXTENSION_NAME);
extensions.insert(VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME);
extensions.insert(VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME);
extensions.insert(VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME);
return extensions;
}
VkDisplayModePropertiesKHR x11_direct::select_display_mode(std::vector<VkDisplayModePropertiesKHR> modes) {
// select mode with the highest refresh rate
VkDisplayModePropertiesKHR selected_mode = modes[0];
for (const auto& mode : modes) {
if (mode.parameters.refreshRate > selected_mode.parameters.refreshRate) {
selected_mode = mode;
}
}
std::cout << "Selected display mode: " << selected_mode.parameters.visibleRegion.width << "x"
<< selected_mode.parameters.visibleRegion.height << "@" << selected_mode.parameters.refreshRate / 1000 << "Hz"
<< std::endl;
return selected_mode;
}
void x11_direct::tick() {
if (!display_timings_event_registered_) {
// yield
std::this_thread::yield();
return;
}
vkWaitForFences(vk_device_, 1, &display_event_fence_, VK_TRUE, UINT64_MAX);
auto now = clock_->now();
vkDestroyFence(vk_device_, display_event_fence_, nullptr);
register_display_timings_event(vk_device_);
// Vulkan refreshRate is in milliHz, so we convert to nanoseconds
const auto display_period = std::chrono::nanoseconds{1'000'000'000'000LL / selected_mode_.parameters.refreshRate};
now += display_period;
vsync_topic_.put(vsync_topic_.allocate(now));
}
bool x11_direct::register_display_timings_event(VkDevice vk_device) {
this->vk_device_ = vk_device;
auto register_display_event =
(PFN_vkRegisterDisplayEventEXT) vkGetInstanceProcAddr(vk_instance_, "vkRegisterDisplayEventEXT");
if (register_display_event == nullptr) {
ILLIXR::abort("Failed to load vkRegisterDisplayEventEXT");
return false;
}
VkDisplayEventInfoEXT display_event_info{
VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT,
nullptr,
VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,
};
auto ret = (register_display_event(vk_device, display_, &display_event_info, nullptr, &display_event_fence_));
if (ret != VK_SUCCESS) {
display_event_fence_ = VK_NULL_HANDLE;
} else {
display_timings_event_registered_ = true;
}
return ret == VK_SUCCESS;
}
std::set<const char*> x11_direct::get_required_device_extensions() {
auto extensions = std::set<const char*>();
extensions.insert(VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME);
return extensions;
}
display_backend::display_backend_type x11_direct::get_type() {
return X11_DIRECT;
}
#endif