c/direct: Move common direct mode code to comp_window_direct.

Create code file for common direct mode code.

Make common functions take generic parameters.

Use common code in randr and nvidia back ends.

Remove redunant includes.
This commit is contained in:
Lubosz Sarnecki 2020-04-08 16:40:58 +02:00 committed by Jakob Bornecrantz
parent 94bc4cba28
commit 29b771818e
6 changed files with 358 additions and 608 deletions

View file

@ -86,6 +86,7 @@ if(BUILD_COMPOSITOR_MAIN)
endif()
if(BUILD_WITH_XCB AND BUILD_WITH_XLIB)
list(APPEND MAIN_SOURCE_FILES
main/comp_window_direct.c
main/comp_window_direct_randr.c
main/comp_window_direct_nvidia.c
)

View file

@ -0,0 +1,262 @@
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Common direct mode window code.
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup comp_main
*/
#include <inttypes.h>
#include "comp_window_direct.h"
#include "util/u_misc.h"
static int
choose_best_vk_mode_auto(struct comp_window *w,
VkDisplayModePropertiesKHR *mode_properties,
int mode_count)
{
if (mode_count == 1)
return 0;
int best_index = 0;
// First priority: choose mode that maximizes rendered pixels.
// Second priority: choose mode with highest refresh rate.
for (int i = 1; i < mode_count; i++) {
VkDisplayModeParametersKHR current =
mode_properties[i].parameters;
COMP_DEBUG(w->c, "Available Vk direct mode %d: %dx%d@%.2f", i,
current.visibleRegion.width,
current.visibleRegion.height,
(float)current.refreshRate / 1000.);
VkDisplayModeParametersKHR best =
mode_properties[best_index].parameters;
int best_pixels =
best.visibleRegion.width * best.visibleRegion.height;
int pixels =
current.visibleRegion.width * current.visibleRegion.height;
if (pixels > best_pixels) {
best_index = i;
} else if (pixels == best_pixels &&
current.refreshRate > best.refreshRate) {
best_index = i;
}
}
VkDisplayModeParametersKHR best =
mode_properties[best_index].parameters;
COMP_DEBUG(w->c, "Auto choosing Vk direct mode %d: %dx%d@%.2f",
best_index, best.visibleRegion.width,
best.visibleRegion.width, (float)best.refreshRate / 1000.);
return best_index;
}
static void
print_modes(struct comp_window *w,
VkDisplayModePropertiesKHR *mode_properties,
int mode_count)
{
COMP_PRINT_MODE(w->c, "Available Vk modes for direct mode");
for (int i = 0; i < mode_count; i++) {
VkDisplayModePropertiesKHR props = mode_properties[i];
uint16_t width = props.parameters.visibleRegion.width;
uint16_t height = props.parameters.visibleRegion.height;
float refresh = (float)props.parameters.refreshRate / 1000.;
COMP_PRINT_MODE(w->c, "| %2d | %dx%d@%.2f", i, width, height,
refresh);
}
COMP_PRINT_MODE(w->c, "Listed %d modes", mode_count);
}
VkDisplayModeKHR
comp_window_direct_get_primary_display_mode(struct comp_window *w,
VkDisplayKHR display)
{
struct vk_bundle *vk = w->swapchain.vk;
uint32_t mode_count;
VkResult ret;
ret = vk->vkGetDisplayModePropertiesKHR(vk->physical_device, display,
&mode_count, NULL);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->c, "vkGetDisplayModePropertiesKHR: %s",
vk_result_string(ret));
return VK_NULL_HANDLE;
}
COMP_DEBUG(w->c, "Found %d modes", mode_count);
VkDisplayModePropertiesKHR *mode_properties =
U_TYPED_ARRAY_CALLOC(VkDisplayModePropertiesKHR, mode_count);
ret = vk->vkGetDisplayModePropertiesKHR(vk->physical_device, display,
&mode_count, mode_properties);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->c, "vkGetDisplayModePropertiesKHR: %s",
vk_result_string(ret));
free(mode_properties);
return VK_NULL_HANDLE;
}
print_modes(w, mode_properties, mode_count);
int chosen_mode = 0;
int desired_mode = w->c->settings.desired_mode;
if (desired_mode + 1 > (int)mode_count) {
COMP_ERROR(w->c,
"Requested mode index %d, but max is %d. Falling "
"back to automatic mode selection",
desired_mode, mode_count);
chosen_mode =
choose_best_vk_mode_auto(w, mode_properties, mode_count);
} else if (desired_mode < 0) {
chosen_mode =
choose_best_vk_mode_auto(w, mode_properties, mode_count);
} else {
COMP_DEBUG(w->c, "Using manually chosen mode %d", desired_mode);
chosen_mode = desired_mode;
}
VkDisplayModePropertiesKHR props = mode_properties[chosen_mode];
COMP_DEBUG(w->c, "found display mode %dx%d@%.2f",
props.parameters.visibleRegion.width,
props.parameters.visibleRegion.height,
(float)props.parameters.refreshRate / 1000.);
int64_t new_frame_interval =
1000. * 1000. * 1000. * 1000. / props.parameters.refreshRate;
COMP_DEBUG(
w->c,
"Updating compositor settings nominal frame interval from %" PRIu64
" (%f Hz) to %" PRIu64 " (%f Hz)",
w->c->settings.nominal_frame_interval_ns,
1000. * 1000. * 1000. /
(float)w->c->settings.nominal_frame_interval_ns,
new_frame_interval, (float)props.parameters.refreshRate / 1000.);
w->c->settings.nominal_frame_interval_ns = new_frame_interval;
free(mode_properties);
return props.displayMode;
}
static VkDisplayPlaneAlphaFlagBitsKHR
choose_alpha_mode(VkDisplayPlaneAlphaFlagsKHR flags)
{
if (flags & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR) {
return VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR;
}
if (flags & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR) {
return VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR;
}
return VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR;
}
VkResult
comp_window_direct_create_surface(struct comp_window *w,
VkDisplayKHR display,
uint32_t width,
uint32_t height)
{
struct vk_bundle *vk = w->swapchain.vk;
// Get plane properties
uint32_t plane_property_count;
VkResult ret = vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
w->swapchain.vk->physical_device, &plane_property_count, NULL);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->c,
"vkGetPhysicalDeviceDisplayPlanePropertiesKHR: %s",
vk_result_string(ret));
return ret;
}
COMP_DEBUG(w->c, "Found %d plane properites.", plane_property_count);
VkDisplayPlanePropertiesKHR *plane_properties = U_TYPED_ARRAY_CALLOC(
VkDisplayPlanePropertiesKHR, plane_property_count);
ret = vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
w->swapchain.vk->physical_device, &plane_property_count,
plane_properties);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->c,
"vkGetPhysicalDeviceDisplayPlanePropertiesKHR: %s",
vk_result_string(ret));
free(plane_properties);
return ret;
}
uint32_t plane_index = 0;
VkDisplayModeKHR display_mode =
comp_window_direct_get_primary_display_mode(w, display);
VkDisplayPlaneCapabilitiesKHR plane_caps;
vk->vkGetDisplayPlaneCapabilitiesKHR(w->swapchain.vk->physical_device,
display_mode, plane_index,
&plane_caps);
VkDisplaySurfaceCreateInfoKHR surface_info = {
.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR,
.pNext = NULL,
.flags = 0,
.displayMode = display_mode,
.planeIndex = plane_index,
.planeStackIndex = plane_properties[plane_index].currentStackIndex,
.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
.globalAlpha = 1.0,
.alphaMode = choose_alpha_mode(plane_caps.supportedAlpha),
.imageExtent =
{
.width = width,
.height = height,
},
};
VkResult result = vk->vkCreateDisplayPlaneSurfaceKHR(
vk->instance, &surface_info, NULL, &w->swapchain.surface);
free(plane_properties);
return result;
}
int
comp_window_direct_connect(struct comp_window *w, Display **dpy)
{
*dpy = XOpenDisplay(NULL);
if (*dpy == NULL) {
COMP_ERROR(w->c, "Could not open X display.");
return false;
}
return true;
}
VkResult
comp_window_direct_acquire_xlib_display(struct comp_window *w,
Display *dpy,
VkDisplayKHR display)
{
struct vk_bundle *vk = w->swapchain.vk;
VkResult ret;
ret = vk->vkAcquireXlibDisplayEXT(w->swapchain.vk->physical_device, dpy,
display);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->c, "vkAcquireXlibDisplayEXT: %s (%p)",
vk_result_string(ret), (void *)display);
}
return ret;
}

View file

@ -0,0 +1,39 @@
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Common direct mode window code header.
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup comp_main
*/
#pragma once
#include "main/comp_window.h"
#ifdef __cplusplus
extern "C" {
#endif
VkDisplayModeKHR
comp_window_direct_get_primary_display_mode(struct comp_window *w,
VkDisplayKHR display);
VkResult
comp_window_direct_create_surface(struct comp_window *w,
VkDisplayKHR display,
uint32_t width,
uint32_t height);
int
comp_window_direct_connect(struct comp_window *w, Display **dpy);
VkResult
comp_window_direct_acquire_xlib_display(struct comp_window *w,
Display *dpy,
VkDisplayKHR display);
#ifdef __cplusplus
}
#endif

View file

@ -8,13 +8,9 @@
* @ingroup comp_main
*/
#include <inttypes.h>
#include "util/u_misc.h"
#include "xrt/xrt_compiler.h"
#include "main/comp_window.h"
#include "main/comp_window_direct.h"
/*
*
@ -62,32 +58,11 @@ comp_window_direct_nvidia_init(struct comp_window *w);
static struct comp_window_direct_nvidia_display *
comp_window_direct_nvidia_current_display(struct comp_window_direct_nvidia *w);
static VkDisplayModeKHR
comp_window_direct_nvidia_get_primary_display_mode(
struct comp_window_direct_nvidia *w, VkDisplayKHR display);
static VkDisplayPlaneAlphaFlagBitsKHR
choose_alpha_mode(VkDisplayPlaneAlphaFlagsKHR flags);
static VkResult
comp_window_direct_nvidia_create_surface(struct comp_window_direct_nvidia *w,
VkInstance instance,
VkSurfaceKHR *surface,
uint32_t width,
uint32_t height);
static bool
comp_window_direct_nvidia_init_swapchain(struct comp_window *w,
uint32_t width,
uint32_t height);
static int
comp_window_direct_nvidia_connect(struct comp_window_direct_nvidia *w);
static VkResult
comp_window_direct_nvidia_acquire_xlib_display(
struct comp_window_direct_nvidia *w, VkDisplayKHR display);
/*
*
* Functions.
@ -193,7 +168,7 @@ comp_window_direct_nvidia_init(struct comp_window *w)
struct comp_window_direct_nvidia *w_direct =
(struct comp_window_direct_nvidia *)w;
if (!comp_window_direct_nvidia_connect(w_direct)) {
if (!comp_window_direct_connect(w, &w_direct->dpy)) {
return false;
}
@ -269,246 +244,6 @@ comp_window_direct_nvidia_current_display(struct comp_window_direct_nvidia *w)
return &w->nv_displays[index];
}
static int
choose_best_vk_mode_auto(struct comp_window_direct_nvidia *w,
VkDisplayModePropertiesKHR *mode_properties,
int mode_count)
{
if (mode_count == 1)
return 0;
int best_index = 0;
// First priority: choose mode that maximizes rendered pixels.
// Second priority: choose mode with highest refresh rate.
for (int i = 1; i < mode_count; i++) {
VkDisplayModeParametersKHR current =
mode_properties[i].parameters;
COMP_DEBUG(w->base.c, "Available Vk direct mode %d: %dx%d@%.2f",
i, current.visibleRegion.width,
current.visibleRegion.height,
(float)current.refreshRate / 1000.);
VkDisplayModeParametersKHR best =
mode_properties[best_index].parameters;
int best_pixels =
best.visibleRegion.width * best.visibleRegion.height;
int pixels =
current.visibleRegion.width * current.visibleRegion.height;
if (pixels > best_pixels) {
best_index = i;
} else if (pixels == best_pixels &&
current.refreshRate > best.refreshRate) {
best_index = i;
}
}
VkDisplayModeParametersKHR best =
mode_properties[best_index].parameters;
COMP_DEBUG(w->base.c, "Auto choosing Vk direct mode %d: %dx%d@%.2f",
best_index, best.visibleRegion.width,
best.visibleRegion.width, (float)best.refreshRate / 1000.);
return best_index;
}
static void
print_modes(struct comp_window_direct_nvidia *w,
VkDisplayModePropertiesKHR *mode_properties,
int mode_count)
{
COMP_PRINT_MODE(w->base.c, "Available Vk modes for direct mode");
for (int i = 0; i < mode_count; i++) {
VkDisplayModePropertiesKHR props = mode_properties[i];
uint16_t width = props.parameters.visibleRegion.width;
uint16_t height = props.parameters.visibleRegion.height;
float refresh = (float)props.parameters.refreshRate / 1000.;
COMP_PRINT_MODE(w->base.c, "| %2d | %dx%d@%.2f", i, width,
height, refresh);
}
COMP_PRINT_MODE(w->base.c, "Listed %d modes", mode_count);
}
static VkDisplayModeKHR
comp_window_direct_nvidia_get_primary_display_mode(
struct comp_window_direct_nvidia *w, VkDisplayKHR display)
{
struct vk_bundle *vk = w->base.swapchain.vk;
uint32_t mode_count;
VkResult ret;
ret = vk->vkGetDisplayModePropertiesKHR(
w->base.swapchain.vk->physical_device, display, &mode_count, NULL);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->base.c, "vkGetDisplayModePropertiesKHR: %s",
vk_result_string(ret));
return VK_NULL_HANDLE;
}
COMP_DEBUG(w->base.c, "Found %d modes", mode_count);
VkDisplayModePropertiesKHR *mode_properties =
U_TYPED_ARRAY_CALLOC(VkDisplayModePropertiesKHR, mode_count);
ret = vk->vkGetDisplayModePropertiesKHR(
w->base.swapchain.vk->physical_device, display, &mode_count,
mode_properties);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->base.c, "vkGetDisplayModePropertiesKHR: %s",
vk_result_string(ret));
free(mode_properties);
return VK_NULL_HANDLE;
}
print_modes(w, mode_properties, mode_count);
int chosen_mode = 0;
int desired_mode = w->base.c->settings.desired_mode;
if (desired_mode + 1 > (int)mode_count) {
COMP_ERROR(w->base.c,
"Requested mode index %d, but max is %d. Falling "
"back to automatic mode selection",
desired_mode, mode_count);
chosen_mode =
choose_best_vk_mode_auto(w, mode_properties, mode_count);
} else if (desired_mode < 0) {
chosen_mode =
choose_best_vk_mode_auto(w, mode_properties, mode_count);
} else {
COMP_DEBUG(w->base.c, "Using manually chosen mode %d",
desired_mode);
chosen_mode = desired_mode;
}
VkDisplayModePropertiesKHR props = mode_properties[chosen_mode];
COMP_DEBUG(w->base.c, "found display mode %dx%d@%.2f",
props.parameters.visibleRegion.width,
props.parameters.visibleRegion.height,
(float)props.parameters.refreshRate / 1000.);
int64_t new_frame_interval =
1000. * 1000. * 1000. * 1000. / props.parameters.refreshRate;
COMP_DEBUG(
w->base.c,
"Updating compositor settings nominal frame interval from %" PRIu64
" (%f Hz) to %" PRIu64 " (%f Hz)",
w->base.c->settings.nominal_frame_interval_ns,
1000. * 1000. * 1000. /
(float)w->base.c->settings.nominal_frame_interval_ns,
new_frame_interval, (float)props.parameters.refreshRate / 1000.);
w->base.c->settings.nominal_frame_interval_ns = new_frame_interval;
free(mode_properties);
return props.displayMode;
}
static VkDisplayPlaneAlphaFlagBitsKHR
choose_alpha_mode(VkDisplayPlaneAlphaFlagsKHR flags)
{
if (flags & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR) {
return VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR;
}
if (flags & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR) {
return VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR;
}
return VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR;
}
static VkResult
comp_window_direct_nvidia_create_surface(struct comp_window_direct_nvidia *w,
VkInstance instance,
VkSurfaceKHR *surface,
uint32_t width,
uint32_t height)
{
struct comp_window_direct_nvidia_display *nvd =
comp_window_direct_nvidia_current_display(w);
struct vk_bundle *vk = w->base.swapchain.vk;
VkResult ret = VK_ERROR_INCOMPATIBLE_DISPLAY_KHR;
VkDisplayKHR _display = VK_NULL_HANDLE;
if (nvd) {
COMP_DEBUG(w->base.c, "Will use display: %s", nvd->name);
ret = comp_window_direct_nvidia_acquire_xlib_display(
w, nvd->display);
_display = nvd->display;
}
if (ret != VK_SUCCESS) {
return ret;
}
// Get plane properties
uint32_t plane_property_count;
ret = vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
w->base.swapchain.vk->physical_device, &plane_property_count, NULL);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->base.c,
"vkGetPhysicalDeviceDisplayPlanePropertiesKHR: %s",
vk_result_string(ret));
return ret;
}
COMP_DEBUG(w->base.c, "Found %d plane properites.",
plane_property_count);
VkDisplayPlanePropertiesKHR *plane_properties = U_TYPED_ARRAY_CALLOC(
VkDisplayPlanePropertiesKHR, plane_property_count);
ret = vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
w->base.swapchain.vk->physical_device, &plane_property_count,
plane_properties);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->base.c,
"vkGetPhysicalDeviceDisplayPlanePropertiesKHR: %s",
vk_result_string(ret));
free(plane_properties);
return ret;
}
uint32_t plane_index = 0;
VkDisplayModeKHR display_mode =
comp_window_direct_nvidia_get_primary_display_mode(w, _display);
VkDisplayPlaneCapabilitiesKHR plane_caps;
vk->vkGetDisplayPlaneCapabilitiesKHR(
w->base.swapchain.vk->physical_device, display_mode, plane_index,
&plane_caps);
VkDisplaySurfaceCreateInfoKHR surface_info = {
.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR,
.pNext = NULL,
.flags = 0,
.displayMode = display_mode,
.planeIndex = plane_index,
.planeStackIndex = plane_properties[plane_index].currentStackIndex,
.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
.globalAlpha = 1.0,
.alphaMode = choose_alpha_mode(plane_caps.supportedAlpha),
.imageExtent =
{
.width = width,
.height = height,
},
};
VkResult result = vk->vkCreateDisplayPlaneSurfaceKHR(
instance, &surface_info, NULL, surface);
free(plane_properties);
return result;
}
static bool
comp_window_direct_nvidia_init_swapchain(struct comp_window *w,
uint32_t width,
@ -517,9 +252,25 @@ comp_window_direct_nvidia_init_swapchain(struct comp_window *w,
struct comp_window_direct_nvidia *w_direct =
(struct comp_window_direct_nvidia *)w;
VkResult ret = comp_window_direct_nvidia_create_surface(
w_direct, w->swapchain.vk->instance, &w->swapchain.surface, width,
height);
struct comp_window_direct_nvidia_display *nvd =
comp_window_direct_nvidia_current_display(w_direct);
VkResult ret = VK_ERROR_INCOMPATIBLE_DISPLAY_KHR;
VkDisplayKHR _display = VK_NULL_HANDLE;
if (nvd) {
COMP_DEBUG(w->c, "Will use display: %s", nvd->name);
ret = comp_window_direct_acquire_xlib_display(w, w_direct->dpy,
nvd->display);
_display = nvd->display;
}
if (ret != VK_SUCCESS) {
return ret;
}
ret = comp_window_direct_create_surface(w, _display, width, height);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->c, "Failed to create surface!");
return false;
@ -531,30 +282,3 @@ comp_window_direct_nvidia_init_swapchain(struct comp_window *w,
return true;
}
static int
comp_window_direct_nvidia_connect(struct comp_window_direct_nvidia *w)
{
w->dpy = XOpenDisplay(NULL);
if (w->dpy == NULL) {
COMP_ERROR(w->base.c, "Could not open X display.");
return false;
}
return true;
}
static VkResult
comp_window_direct_nvidia_acquire_xlib_display(
struct comp_window_direct_nvidia *w, VkDisplayKHR display)
{
struct vk_bundle *vk = w->base.swapchain.vk;
VkResult ret;
ret = vk->vkAcquireXlibDisplayEXT(w->base.swapchain.vk->physical_device,
w->dpy, display);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->base.c, "vkAcquireXlibDisplayEXT: %s (%p)",
vk_result_string(ret), (void *)display);
}
return ret;
}

View file

@ -13,13 +13,9 @@
#include <X11/Xlib-xcb.h>
#include <X11/extensions/Xrandr.h>
#include <inttypes.h>
#include "util/u_misc.h"
#include "xrt/xrt_compiler.h"
#include "main/comp_window.h"
#include "main/comp_window_direct.h"
/*
*
@ -74,35 +70,14 @@ comp_window_direct_randr_init(struct comp_window *w);
static struct comp_window_direct_randr_display *
comp_window_direct_randr_current_display(struct comp_window_direct_randr *w);
static VkDisplayModeKHR
comp_window_direct_randr_get_primary_display_mode(
struct comp_window_direct_randr *w, VkDisplayKHR display);
static VkDisplayPlaneAlphaFlagBitsKHR
choose_alpha_mode(VkDisplayPlaneAlphaFlagsKHR flags);
static VkResult
comp_window_direct_randr_create_surface(struct comp_window_direct_randr *w,
VkInstance instance,
VkSurfaceKHR *surface,
uint32_t width,
uint32_t height);
static bool
comp_window_direct_randr_init_swapchain(struct comp_window *w,
uint32_t width,
uint32_t height);
static int
comp_window_direct_randr_connect(struct comp_window_direct_randr *w);
static VkResult
comp_window_direct_randr_acquire_xlib_display(
struct comp_window_direct_randr *w, VkDisplayKHR display);
static VkDisplayKHR
comp_window_direct_randr_get_xlib_randr_output(
struct comp_window_direct_randr *w, RROutput output);
comp_window_direct_randr_get_output(struct comp_window_direct_randr *w,
RROutput output);
static void
comp_window_direct_randr_get_outputs(struct comp_window_direct_randr *w);
@ -195,7 +170,7 @@ comp_window_direct_randr_init(struct comp_window *w)
struct comp_window_direct_randr *w_direct =
(struct comp_window_direct_randr *)w;
if (!comp_window_direct_randr_connect(w_direct)) {
if (!comp_window_direct_connect(w, &w_direct->dpy)) {
return false;
}
@ -255,255 +230,6 @@ comp_window_direct_randr_current_display(struct comp_window_direct_randr *w)
return &w->randr_displays[index];
}
static int
choose_best_vk_mode_auto(struct comp_window_direct_randr *w,
VkDisplayModePropertiesKHR *mode_properties,
int mode_count)
{
if (mode_count == 1)
return 0;
int best_index = 0;
// First priority: choose mode that maximizes rendered pixels.
// Second priority: choose mode with highest refresh rate.
for (int i = 1; i < mode_count; i++) {
VkDisplayModeParametersKHR current =
mode_properties[i].parameters;
COMP_DEBUG(w->base.c, "Available Vk direct mode %d: %dx%d@%.2f",
i, current.visibleRegion.width,
current.visibleRegion.height,
(float)current.refreshRate / 1000.);
VkDisplayModeParametersKHR best =
mode_properties[best_index].parameters;
int best_pixels =
best.visibleRegion.width * best.visibleRegion.height;
int pixels =
current.visibleRegion.width * current.visibleRegion.height;
if (pixels > best_pixels) {
best_index = i;
} else if (pixels == best_pixels &&
current.refreshRate > best.refreshRate) {
best_index = i;
}
}
VkDisplayModeParametersKHR best =
mode_properties[best_index].parameters;
COMP_DEBUG(w->base.c, "Auto choosing Vk direct mode %d: %dx%d@%.2f",
best_index, best.visibleRegion.width,
best.visibleRegion.width, (float)best.refreshRate / 1000.);
return best_index;
}
static void
print_modes(struct comp_window_direct_randr *w,
VkDisplayModePropertiesKHR *mode_properties,
int mode_count)
{
COMP_PRINT_MODE(w->base.c, "Available Vk modes for direct mode");
for (int i = 0; i < mode_count; i++) {
VkDisplayModePropertiesKHR props = mode_properties[i];
uint16_t width = props.parameters.visibleRegion.width;
uint16_t height = props.parameters.visibleRegion.height;
float refresh = (float)props.parameters.refreshRate / 1000.;
COMP_PRINT_MODE(w->base.c, "| %2d | %dx%d@%.2f", i, width,
height, refresh);
}
COMP_PRINT_MODE(w->base.c, "Listed %d modes", mode_count);
}
static VkDisplayModeKHR
comp_window_direct_randr_get_primary_display_mode(
struct comp_window_direct_randr *w, VkDisplayKHR display)
{
struct vk_bundle *vk = w->base.swapchain.vk;
uint32_t mode_count;
VkResult ret;
ret = vk->vkGetDisplayModePropertiesKHR(
w->base.swapchain.vk->physical_device, display, &mode_count, NULL);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->base.c, "vkGetDisplayModePropertiesKHR: %s",
vk_result_string(ret));
return VK_NULL_HANDLE;
}
COMP_DEBUG(w->base.c, "Found %d modes", mode_count);
VkDisplayModePropertiesKHR *mode_properties =
U_TYPED_ARRAY_CALLOC(VkDisplayModePropertiesKHR, mode_count);
ret = vk->vkGetDisplayModePropertiesKHR(
w->base.swapchain.vk->physical_device, display, &mode_count,
mode_properties);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->base.c, "vkGetDisplayModePropertiesKHR: %s",
vk_result_string(ret));
free(mode_properties);
return VK_NULL_HANDLE;
}
print_modes(w, mode_properties, mode_count);
int chosen_mode = 0;
int desired_mode = w->base.c->settings.desired_mode;
if (desired_mode + 1 > (int)mode_count) {
COMP_ERROR(w->base.c,
"Requested mode index %d, but max is %d. Falling "
"back to automatic mode selection",
desired_mode, mode_count);
chosen_mode =
choose_best_vk_mode_auto(w, mode_properties, mode_count);
} else if (desired_mode < 0) {
chosen_mode =
choose_best_vk_mode_auto(w, mode_properties, mode_count);
} else {
COMP_DEBUG(w->base.c, "Using manually chosen mode %d",
desired_mode);
chosen_mode = desired_mode;
}
VkDisplayModePropertiesKHR props = mode_properties[chosen_mode];
COMP_DEBUG(w->base.c, "found display mode %dx%d@%.2f",
props.parameters.visibleRegion.width,
props.parameters.visibleRegion.height,
(float)props.parameters.refreshRate / 1000.);
int64_t new_frame_interval =
1000. * 1000. * 1000. * 1000. / props.parameters.refreshRate;
COMP_DEBUG(
w->base.c,
"Updating compositor settings nominal frame interval from %" PRIu64
" (%f Hz) to %" PRIu64 " (%f Hz)",
w->base.c->settings.nominal_frame_interval_ns,
1000. * 1000. * 1000. /
(float)w->base.c->settings.nominal_frame_interval_ns,
new_frame_interval, (float)props.parameters.refreshRate / 1000.);
w->base.c->settings.nominal_frame_interval_ns = new_frame_interval;
free(mode_properties);
return props.displayMode;
}
static VkDisplayPlaneAlphaFlagBitsKHR
choose_alpha_mode(VkDisplayPlaneAlphaFlagsKHR flags)
{
if (flags & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR) {
return VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR;
}
if (flags & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR) {
return VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR;
}
return VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR;
}
static VkResult
comp_window_direct_randr_create_surface(struct comp_window_direct_randr *w,
VkInstance instance,
VkSurfaceKHR *surface,
uint32_t width,
uint32_t height)
{
struct comp_window_direct_randr_display *d =
comp_window_direct_randr_current_display(w);
struct vk_bundle *vk = w->base.swapchain.vk;
VkResult ret = VK_ERROR_INCOMPATIBLE_DISPLAY_KHR;
VkDisplayKHR _display = VK_NULL_HANDLE;
if (d) {
COMP_DEBUG(
w->base.c, "Will use display: %s %dx%d@%.2f", d->name,
d->primary_mode.width, d->primary_mode.height,
(double)d->primary_mode.dot_clock /
(d->primary_mode.htotal * d->primary_mode.vtotal));
d->display = comp_window_direct_randr_get_xlib_randr_output(
w, d->output);
if (d->display == VK_NULL_HANDLE) {
return VK_ERROR_INITIALIZATION_FAILED;
}
ret = comp_window_direct_randr_acquire_xlib_display(w,
d->display);
_display = d->display;
}
if (ret != VK_SUCCESS) {
return ret;
}
// Get plane properties
uint32_t plane_property_count;
ret = vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
w->base.swapchain.vk->physical_device, &plane_property_count, NULL);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->base.c,
"vkGetPhysicalDeviceDisplayPlanePropertiesKHR: %s",
vk_result_string(ret));
return ret;
}
COMP_DEBUG(w->base.c, "Found %d plane properites.",
plane_property_count);
VkDisplayPlanePropertiesKHR *plane_properties = U_TYPED_ARRAY_CALLOC(
VkDisplayPlanePropertiesKHR, plane_property_count);
ret = vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
w->base.swapchain.vk->physical_device, &plane_property_count,
plane_properties);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->base.c,
"vkGetPhysicalDeviceDisplayPlanePropertiesKHR: %s",
vk_result_string(ret));
free(plane_properties);
return ret;
}
uint32_t plane_index = 0;
VkDisplayModeKHR display_mode =
comp_window_direct_randr_get_primary_display_mode(w, _display);
VkDisplayPlaneCapabilitiesKHR plane_caps;
vk->vkGetDisplayPlaneCapabilitiesKHR(
w->base.swapchain.vk->physical_device, display_mode, plane_index,
&plane_caps);
VkDisplaySurfaceCreateInfoKHR surface_info = {
.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR,
.pNext = NULL,
.flags = 0,
.displayMode = display_mode,
.planeIndex = plane_index,
.planeStackIndex = plane_properties[plane_index].currentStackIndex,
.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
.globalAlpha = 1.0,
.alphaMode = choose_alpha_mode(plane_caps.supportedAlpha),
.imageExtent =
{
.width = width,
.height = height,
},
};
VkResult result = vk->vkCreateDisplayPlaneSurfaceKHR(
instance, &surface_info, NULL, surface);
free(plane_properties);
return result;
}
static bool
comp_window_direct_randr_init_swapchain(struct comp_window *w,
uint32_t width,
@ -512,9 +238,33 @@ comp_window_direct_randr_init_swapchain(struct comp_window *w,
struct comp_window_direct_randr *w_direct =
(struct comp_window_direct_randr *)w;
VkResult ret = comp_window_direct_randr_create_surface(
w_direct, w->swapchain.vk->instance, &w->swapchain.surface, width,
height);
struct comp_window_direct_randr_display *d =
comp_window_direct_randr_current_display(w_direct);
VkResult ret = VK_ERROR_INCOMPATIBLE_DISPLAY_KHR;
VkDisplayKHR _display = VK_NULL_HANDLE;
if (d) {
COMP_DEBUG(
w->c, "Will use display: %s %dx%d@%.2f", d->name,
d->primary_mode.width, d->primary_mode.height,
(double)d->primary_mode.dot_clock /
(d->primary_mode.htotal * d->primary_mode.vtotal));
d->display =
comp_window_direct_randr_get_output(w_direct, d->output);
if (d->display == VK_NULL_HANDLE) {
return VK_ERROR_INITIALIZATION_FAILED;
}
ret = comp_window_direct_acquire_xlib_display(w, w_direct->dpy,
d->display);
_display = d->display;
}
if (ret != VK_SUCCESS) {
return ret;
}
ret = comp_window_direct_create_surface(w, _display, width, height);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->c, "Failed to create surface!");
return false;
@ -527,36 +277,9 @@ comp_window_direct_randr_init_swapchain(struct comp_window *w,
return true;
}
static int
comp_window_direct_randr_connect(struct comp_window_direct_randr *w)
{
w->dpy = XOpenDisplay(NULL);
if (w->dpy == NULL) {
COMP_ERROR(w->base.c, "Could not open X display.");
return false;
}
return true;
}
static VkResult
comp_window_direct_randr_acquire_xlib_display(
struct comp_window_direct_randr *w, VkDisplayKHR display)
{
struct vk_bundle *vk = w->base.swapchain.vk;
VkResult ret;
ret = vk->vkAcquireXlibDisplayEXT(w->base.swapchain.vk->physical_device,
w->dpy, display);
if (ret != VK_SUCCESS) {
COMP_ERROR(w->base.c, "vkAcquireXlibDisplayEXT: %s (%p)",
vk_result_string(ret), (void *)display);
}
return ret;
}
static VkDisplayKHR
comp_window_direct_randr_get_xlib_randr_output(
struct comp_window_direct_randr *w, RROutput output)
comp_window_direct_randr_get_output(struct comp_window_direct_randr *w,
RROutput output)
{
struct vk_bundle *vk = w->base.swapchain.vk;
VkResult ret;

View file

@ -33,7 +33,8 @@ if build_xcb
endif
if build_xcb_xrandr_direct
compositor_srcs += ['main/comp_window_direct_randr.c',
compositor_srcs += ['main/comp_window_direct.c',
'main/comp_window_direct_randr.c',
'main/comp_window_direct_nvidia.c']
compositor_deps += [xcb_randr, x11_xcb]
endif