mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
Compare commits
27 commits
12281b8736
...
7dc492bde9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7dc492bde9 | ||
|
|
879243e370 | ||
|
|
989cffe70d | ||
|
|
3e08e3be4a | ||
|
|
91f4890ec2 | ||
|
|
74ce6c22a5 | ||
|
|
0b58bddf13 | ||
|
|
3d36ab9211 | ||
|
|
d786e07899 | ||
|
|
6d63871f05 | ||
|
|
19c5d22beb | ||
|
|
06275103f2 | ||
|
|
03e7966650 | ||
|
|
5529aae3e6 | ||
|
|
6e1c8748ff | ||
|
|
d8fb7adcf0 | ||
|
|
c2d9ae2142 | ||
|
|
6978509f64 | ||
|
|
2252854297 | ||
|
|
dde07b6840 | ||
|
|
406aa5f7f5 | ||
|
|
2ec4012559 | ||
|
|
d039ad8da3 | ||
|
|
3f0d338643 | ||
|
|
60d72724cd | ||
|
|
ade7fee5d2 | ||
|
|
85ab6b7eb2 |
32 changed files with 577 additions and 105 deletions
|
|
@ -41,9 +41,10 @@ tasks:
|
||||||
cd wlroots/build-gcc/tinywl
|
cd wlroots/build-gcc/tinywl
|
||||||
sudo modprobe vkms
|
sudo modprobe vkms
|
||||||
udevadm settle
|
udevadm settle
|
||||||
|
card="/dev/dri/$(ls /sys/devices/faux/vkms/drm/ | grep ^card)"
|
||||||
export WLR_BACKENDS=drm
|
export WLR_BACKENDS=drm
|
||||||
export WLR_RENDERER=pixman
|
export WLR_RENDERER=pixman
|
||||||
export WLR_DRM_DEVICES=/dev/dri/by-path/platform-vkms-card
|
export WLR_DRM_DEVICES="$card"
|
||||||
export UBSAN_OPTIONS=halt_on_error=1
|
export UBSAN_OPTIONS=halt_on_error=1
|
||||||
sudo chmod ugo+rw /dev/dri/by-path/platform-vkms-card
|
sudo chmod ugo+rw "$card"
|
||||||
sudo -E seatd-launch -- ./tinywl -s 'kill $PPID' || [ $? = 143 ]
|
sudo -E seatd-launch -- ./tinywl -s 'kill $PPID' || [ $? = 143 ]
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,10 @@ static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) {
|
||||||
return 2;
|
return 2;
|
||||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||||
abort(); // unsupported
|
abort(); // unsupported
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
abort(); // unsupported
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||||
|
abort(); // unsupported
|
||||||
}
|
}
|
||||||
abort(); // unreachable
|
abort(); // unreachable
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
#include "backend/drm/drm.h"
|
#include "backend/drm/drm.h"
|
||||||
#include "backend/drm/fb.h"
|
#include "backend/drm/fb.h"
|
||||||
|
#include "backend/drm/util.h"
|
||||||
#include "render/drm_format_set.h"
|
#include "render/drm_format_set.h"
|
||||||
|
|
||||||
struct wlr_drm_backend *get_drm_backend_from_backend(
|
struct wlr_drm_backend *get_drm_backend_from_backend(
|
||||||
|
|
@ -225,6 +226,9 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
|
||||||
wlr_log(WLR_INFO, "Initializing DRM backend for %s (%s)", name, version->name);
|
wlr_log(WLR_INFO, "Initializing DRM backend for %s (%s)", name, version->name);
|
||||||
drmFreeVersion(version);
|
drmFreeVersion(version);
|
||||||
|
|
||||||
|
drmDevice *dev_info = NULL;
|
||||||
|
drmGetDevice2(dev->fd, 0, &dev_info);
|
||||||
|
|
||||||
struct wlr_drm_backend *drm = calloc(1, sizeof(*drm));
|
struct wlr_drm_backend *drm = calloc(1, sizeof(*drm));
|
||||||
if (!drm) {
|
if (!drm) {
|
||||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||||
|
|
@ -243,6 +247,9 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
|
||||||
drm->fd = dev->fd;
|
drm->fd = dev->fd;
|
||||||
drm->name = name;
|
drm->name = name;
|
||||||
|
|
||||||
|
drm->bus = get_drm_bus_str(dev_info);
|
||||||
|
drmFreeDevice(&dev_info);
|
||||||
|
|
||||||
if (parent != NULL) {
|
if (parent != NULL) {
|
||||||
drm->parent = get_drm_backend_from_backend(parent);
|
drm->parent = get_drm_backend_from_backend(parent);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1603,6 +1603,92 @@ static drmModeModeInfo *connector_get_current_mode(struct wlr_drm_connector *wlr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct wlr_drm_connector *find_drm_connector_by_id(struct wlr_drm_backend *drm, uint32_t id) {
|
||||||
|
struct wlr_drm_connector *conn = NULL;
|
||||||
|
wl_list_for_each(conn, &drm->connectors, link) {
|
||||||
|
if (conn->id == id) {
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool connector_write_root_port(struct wlr_drm_connector *wlr_conn, FILE *f) {
|
||||||
|
struct wlr_drm_backend *drm = wlr_conn->backend;
|
||||||
|
|
||||||
|
size_t seq_num = 0;
|
||||||
|
struct wlr_drm_connector *c;
|
||||||
|
wl_list_for_each(c, &drm->connectors, link) {
|
||||||
|
seq_num++;
|
||||||
|
if (c == wlr_conn) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fprintf(f, "%s/connector-%zu", drm->bus, seq_num) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool connector_write_port(struct wlr_drm_connector *wlr_conn, FILE *f);
|
||||||
|
|
||||||
|
static bool connector_write_nested_port(struct wlr_drm_connector *wlr_conn, FILE *f) {
|
||||||
|
struct wlr_drm_backend *drm = wlr_conn->backend;
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
size_t size = 0;
|
||||||
|
void *path_prop_data = get_drm_prop_blob(drm->fd, wlr_conn->id, wlr_conn->props.path, &size);
|
||||||
|
if (path_prop_data == NULL) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t parent_conn_id = 0;
|
||||||
|
const char *child_path = NULL;
|
||||||
|
if (!parse_dp_mst_path(path_prop_data, &parent_conn_id, &child_path)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
struct wlr_drm_connector *parent = find_drm_connector_by_id(drm, parent_conn_id);
|
||||||
|
if (parent == NULL) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!connector_write_port(parent, f)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = fprintf(f, "/mst-%s", child_path) > 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(path_prop_data);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool connector_write_port(struct wlr_drm_connector *wlr_conn, FILE *f) {
|
||||||
|
if (wlr_conn->props.path != 0) {
|
||||||
|
return connector_write_nested_port(wlr_conn, f);
|
||||||
|
} else {
|
||||||
|
return connector_write_root_port(wlr_conn, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *connector_get_port(struct wlr_drm_connector *wlr_conn) {
|
||||||
|
if (wlr_conn->backend->bus == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *str = NULL;
|
||||||
|
size_t str_size = 0;
|
||||||
|
FILE *f = open_memstream(&str, &str_size);
|
||||||
|
if (f == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = connector_write_port(wlr_conn, f);
|
||||||
|
if (fclose(f) != 0 || !ok) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
||||||
const drmModeConnector *drm_conn) {
|
const drmModeConnector *drm_conn) {
|
||||||
struct wlr_drm_backend *drm = wlr_conn->backend;
|
struct wlr_drm_backend *drm = wlr_conn->backend;
|
||||||
|
|
@ -1717,7 +1803,11 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
||||||
size_t edid_len = 0;
|
size_t edid_len = 0;
|
||||||
uint8_t *edid = get_drm_prop_blob(drm->fd,
|
uint8_t *edid = get_drm_prop_blob(drm->fd,
|
||||||
wlr_conn->id, wlr_conn->props.edid, &edid_len);
|
wlr_conn->id, wlr_conn->props.edid, &edid_len);
|
||||||
parse_edid(wlr_conn, edid_len, edid);
|
if (edid_len > 0) {
|
||||||
|
parse_edid(wlr_conn, edid_len, edid);
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_DEBUG, "Connector has no EDID");
|
||||||
|
}
|
||||||
free(edid);
|
free(edid);
|
||||||
|
|
||||||
char *subconnector = NULL;
|
char *subconnector = NULL;
|
||||||
|
|
@ -1741,6 +1831,9 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
||||||
wlr_output_set_description(output, description);
|
wlr_output_set_description(output, description);
|
||||||
|
|
||||||
free(subconnector);
|
free(subconnector);
|
||||||
|
|
||||||
|
output->port = connector_get_port(wlr_conn);
|
||||||
|
|
||||||
wlr_conn->status = DRM_MODE_CONNECTED;
|
wlr_conn->status = DRM_MODE_CONNECTED;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -281,3 +281,44 @@ void generate_cvt_mode(drmModeModeInfo *mode, int hdisplay, int vdisplay,
|
||||||
};
|
};
|
||||||
snprintf(mode->name, sizeof(mode->name), "%dx%d", hdisplay, vdisplay);
|
snprintf(mode->name, sizeof(mode->name), "%dx%d", hdisplay, vdisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *get_drm_bus_str(const drmDevice *dev) {
|
||||||
|
char buf[128];
|
||||||
|
switch (dev->bustype) {
|
||||||
|
case DRM_BUS_PCI:;
|
||||||
|
const drmPciBusInfo *pci = dev->businfo.pci;
|
||||||
|
snprintf(buf, sizeof(buf), "pci-%04" PRIx16 ":%02" PRIx8 ":%02" PRIx8 ".%" PRIu8,
|
||||||
|
pci->domain, pci->bus, pci->dev, pci->func);
|
||||||
|
return strdup(buf);
|
||||||
|
case DRM_BUS_PLATFORM:;
|
||||||
|
const drmPlatformBusInfo *platform = dev->businfo.platform;
|
||||||
|
size_t str_size = strlen("platform-") + strlen(platform->fullname) + 1;
|
||||||
|
char *str = malloc(str_size);
|
||||||
|
if (str == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
snprintf(str, str_size, "platform-%s", platform->fullname);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_dp_mst_path(const char *path, uint32_t *parent_conn_id, const char **child_path) {
|
||||||
|
const char prefix[] = "mst:";
|
||||||
|
if (strncmp(path, prefix, strlen(prefix)) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
path = &path[strlen(prefix)];
|
||||||
|
|
||||||
|
char *id_end;
|
||||||
|
errno = 0;
|
||||||
|
unsigned long id = strtoul(path, &id_end, 10);
|
||||||
|
if (errno != 0 || id_end[0] != '-' || id > UINT32_MAX) {
|
||||||
|
wlr_log(WLR_ERROR, "Malformed PATH DP-MST property: invalid parent connector ID");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*parent_conn_id = (uint32_t)id;
|
||||||
|
*child_path = &id_end[1];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -367,7 +367,10 @@ void wlr_session_close_file(struct wlr_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(wl_list_empty(&dev->events.change.listener_list));
|
assert(wl_list_empty(&dev->events.change.listener_list));
|
||||||
assert(wl_list_empty(&dev->events.remove.listener_list));
|
// TODO: assert that the "remove" listener list is empty as well. Listeners
|
||||||
|
// will typically call wlr_session_close_file() in response, and
|
||||||
|
// wl_signal_emit_mutable() installs two phantom listeners, so we'd count
|
||||||
|
// these two.
|
||||||
|
|
||||||
close(dev->fd);
|
close(dev->fd);
|
||||||
wl_list_remove(&dev->link);
|
wl_list_remove(&dev->link);
|
||||||
|
|
@ -516,8 +519,6 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_boot_vga = false;
|
|
||||||
|
|
||||||
const char *path = udev_list_entry_get_name(entry);
|
const char *path = udev_list_entry_get_name(entry);
|
||||||
struct udev_device *dev = udev_device_new_from_syspath(session->udev, path);
|
struct udev_device *dev = udev_device_new_from_syspath(session->udev, path);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
|
|
@ -533,14 +534,20 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is owned by 'dev', so we don't need to free it
|
bool is_primary = false;
|
||||||
struct udev_device *pci =
|
const char *boot_display = udev_device_get_sysattr_value(dev, "boot_display");
|
||||||
udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
|
if (boot_display && strcmp(boot_display, "1") == 0) {
|
||||||
|
is_primary = true;
|
||||||
|
} else {
|
||||||
|
// This is owned by 'dev', so we don't need to free it
|
||||||
|
struct udev_device *pci =
|
||||||
|
udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
|
||||||
|
|
||||||
if (pci) {
|
if (pci) {
|
||||||
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
||||||
if (id && strcmp(id, "1") == 0) {
|
if (id && strcmp(id, "1") == 0) {
|
||||||
is_boot_vga = true;
|
is_primary = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -554,7 +561,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
||||||
udev_device_unref(dev);
|
udev_device_unref(dev);
|
||||||
|
|
||||||
ret[i] = wlr_dev;
|
ret[i] = wlr_dev;
|
||||||
if (is_boot_vga) {
|
if (is_primary) {
|
||||||
struct wlr_device *tmp = ret[0];
|
struct wlr_device *tmp = ret[0];
|
||||||
ret[0] = ret[i];
|
ret[0] = ret[i];
|
||||||
ret[i] = tmp;
|
ret[i] = tmp;
|
||||||
|
|
|
||||||
|
|
@ -55,14 +55,6 @@ struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *wlr_backe
|
||||||
static int dispatch_events(int fd, uint32_t mask, void *data) {
|
static int dispatch_events(int fd, uint32_t mask, void *data) {
|
||||||
struct wlr_wl_backend *wl = data;
|
struct wlr_wl_backend *wl = data;
|
||||||
|
|
||||||
if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
|
|
||||||
if (mask & WL_EVENT_ERROR) {
|
|
||||||
wlr_log(WLR_ERROR, "Failed to read from remote Wayland display");
|
|
||||||
}
|
|
||||||
wlr_backend_destroy(&wl->backend);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
if (mask & WL_EVENT_READABLE) {
|
if (mask & WL_EVENT_READABLE) {
|
||||||
count = wl_display_dispatch(wl->remote_display);
|
count = wl_display_dispatch(wl->remote_display);
|
||||||
|
|
@ -75,6 +67,18 @@ static int dispatch_events(int fd, uint32_t mask, void *data) {
|
||||||
wl_display_flush(wl->remote_display);
|
wl_display_flush(wl->remote_display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure we've consumed all data before disconnecting due to hangup,
|
||||||
|
// so that we process any wl_display.error events
|
||||||
|
if (!(mask & WL_EVENT_READABLE) && (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR))) {
|
||||||
|
if (mask & WL_EVENT_ERROR) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to read from remote Wayland display");
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_DEBUG, "Disconnected from remote Wayland display");
|
||||||
|
}
|
||||||
|
wlr_backend_destroy(&wl->backend);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
wlr_log(WLR_ERROR, "Failed to dispatch remote Wayland display");
|
wlr_log(WLR_ERROR, "Failed to dispatch remote Wayland display");
|
||||||
wlr_backend_destroy(&wl->backend);
|
wlr_backend_destroy(&wl->backend);
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ struct wlr_drm_backend {
|
||||||
bool addfb2_modifiers;
|
bool addfb2_modifiers;
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
char *name;
|
char *name, *bus;
|
||||||
struct wlr_device *dev;
|
struct wlr_device *dev;
|
||||||
struct liftoff_device *liftoff;
|
struct liftoff_device *liftoff;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,4 +38,7 @@ void match_connectors_with_crtcs(size_t num_conns,
|
||||||
size_t num_crtcs, const uint32_t prev_crtcs[static restrict num_crtcs],
|
size_t num_crtcs, const uint32_t prev_crtcs[static restrict num_crtcs],
|
||||||
uint32_t new_crtcs[static restrict num_crtcs]);
|
uint32_t new_crtcs[static restrict num_crtcs]);
|
||||||
|
|
||||||
|
char *get_drm_bus_str(const drmDevice *dev);
|
||||||
|
bool parse_dp_mst_path(const char *path, uint32_t *parent_conn_id, const char **child_path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ enum wlr_color_transform_type {
|
||||||
COLOR_TRANSFORM_INVERSE_EOTF,
|
COLOR_TRANSFORM_INVERSE_EOTF,
|
||||||
COLOR_TRANSFORM_LCMS2,
|
COLOR_TRANSFORM_LCMS2,
|
||||||
COLOR_TRANSFORM_LUT_3X1D,
|
COLOR_TRANSFORM_LUT_3X1D,
|
||||||
|
COLOR_TRANSFORM_PIPELINE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_color_transform {
|
struct wlr_color_transform {
|
||||||
|
|
@ -39,6 +40,13 @@ struct wlr_color_transform_lut_3x1d {
|
||||||
size_t dim;
|
size_t dim;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_color_transform_pipeline {
|
||||||
|
struct wlr_color_transform base;
|
||||||
|
|
||||||
|
struct wlr_color_transform **transforms;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
void wlr_color_transform_init(struct wlr_color_transform *tr,
|
void wlr_color_transform_init(struct wlr_color_transform *tr,
|
||||||
enum wlr_color_transform_type type);
|
enum wlr_color_transform_type type);
|
||||||
|
|
||||||
|
|
@ -72,12 +80,6 @@ struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_b
|
||||||
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
||||||
struct wlr_color_transform *tr);
|
struct wlr_color_transform *tr);
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluate a 3x1D LUT color transform for a given RGB triplet.
|
|
||||||
*/
|
|
||||||
void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
|
||||||
float out[static 3], const float in[static 3]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain primaries values from a well-known primaries name.
|
* Obtain primaries values from a well-known primaries name.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,8 @@ enum wlr_vk_texture_transform {
|
||||||
WLR_VK_TEXTURE_TRANSFORM_IDENTITY = 0,
|
WLR_VK_TEXTURE_TRANSFORM_IDENTITY = 0,
|
||||||
WLR_VK_TEXTURE_TRANSFORM_SRGB = 1,
|
WLR_VK_TEXTURE_TRANSFORM_SRGB = 1,
|
||||||
WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2,
|
WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2,
|
||||||
|
WLR_VK_TEXTURE_TRANSFORM_GAMMA22 = 3,
|
||||||
|
WLR_VK_TEXTURE_TRANSFORM_BT1886 = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum wlr_vk_shader_source {
|
enum wlr_vk_shader_source {
|
||||||
|
|
@ -167,6 +169,8 @@ enum wlr_vk_output_transform {
|
||||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 1,
|
WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 1,
|
||||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ = 2,
|
WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ = 2,
|
||||||
WLR_VK_OUTPUT_TRANSFORM_LUT3D = 3,
|
WLR_VK_OUTPUT_TRANSFORM_LUT3D = 3,
|
||||||
|
WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22 = 4,
|
||||||
|
WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886 = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_vk_pipeline_key {
|
struct wlr_vk_pipeline_key {
|
||||||
|
|
@ -199,6 +203,8 @@ struct wlr_vk_render_format_setup {
|
||||||
VkPipeline output_pipe_srgb;
|
VkPipeline output_pipe_srgb;
|
||||||
VkPipeline output_pipe_pq;
|
VkPipeline output_pipe_pq;
|
||||||
VkPipeline output_pipe_lut3d;
|
VkPipeline output_pipe_lut3d;
|
||||||
|
VkPipeline output_pipe_gamma22;
|
||||||
|
VkPipeline output_pipe_bt1886;
|
||||||
|
|
||||||
struct wlr_vk_renderer *renderer;
|
struct wlr_vk_renderer *renderer;
|
||||||
struct wl_list pipelines; // struct wlr_vk_pipeline.link
|
struct wl_list pipelines; // struct wlr_vk_pipeline.link
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ enum wlr_color_transfer_function {
|
||||||
WLR_COLOR_TRANSFER_FUNCTION_SRGB = 1 << 0,
|
WLR_COLOR_TRANSFER_FUNCTION_SRGB = 1 << 0,
|
||||||
WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1,
|
WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1,
|
||||||
WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2,
|
WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2,
|
||||||
|
WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 = 1 << 3,
|
||||||
|
WLR_COLOR_TRANSFER_FUNCTION_BT1886 = 1 << 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +141,13 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
|
||||||
struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
|
struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
|
||||||
const uint16_t *r, const uint16_t *g, const uint16_t *b);
|
const uint16_t *r, const uint16_t *g, const uint16_t *b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a color transformation to apply a sequence of color transforms
|
||||||
|
* one after another.
|
||||||
|
*/
|
||||||
|
struct wlr_color_transform *wlr_color_transform_init_pipeline(
|
||||||
|
struct wlr_color_transform **transforms, size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase the reference count of the color transform by 1.
|
* Increase the reference count of the color transform by 1.
|
||||||
*/
|
*/
|
||||||
|
|
@ -150,4 +159,10 @@ struct wlr_color_transform *wlr_color_transform_ref(struct wlr_color_transform *
|
||||||
*/
|
*/
|
||||||
void wlr_color_transform_unref(struct wlr_color_transform *tr);
|
void wlr_color_transform_unref(struct wlr_color_transform *tr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate a color transform for a given RGB triplet.
|
||||||
|
*/
|
||||||
|
void wlr_color_transform_eval(struct wlr_color_transform *tr,
|
||||||
|
float out[static 3], const float in[static 3]);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,9 @@ struct wlr_render_timer;
|
||||||
struct wlr_buffer_pass_options {
|
struct wlr_buffer_pass_options {
|
||||||
/* Timer to measure the duration of the render pass */
|
/* Timer to measure the duration of the render pass */
|
||||||
struct wlr_render_timer *timer;
|
struct wlr_render_timer *timer;
|
||||||
/* Color transform to apply to the output of the render pass,
|
/* Color transform to apply to the output of the render pass.
|
||||||
* leave NULL to indicate sRGB/no custom transform */
|
* Leave NULL to indicate the default transform (Gamma 2.2 encoding for
|
||||||
|
* sRGB monitors) */
|
||||||
struct wlr_color_transform *color_transform;
|
struct wlr_color_transform *color_transform;
|
||||||
/** Primaries describing the color volume of the destination buffer */
|
/** Primaries describing the color volume of the destination buffer */
|
||||||
const struct wlr_color_primaries *primaries;
|
const struct wlr_color_primaries *primaries;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ struct wlr_gamma_control_manager_v1 {
|
||||||
struct wl_global *global;
|
struct wl_global *global;
|
||||||
struct wl_list controls; // wlr_gamma_control_v1.link
|
struct wl_list controls; // wlr_gamma_control_v1.link
|
||||||
|
|
||||||
|
// Fallback to use when an struct wlr_output doesn't support gamma LUTs.
|
||||||
|
// Can be used to apply gamma LUTs via a struct wlr_renderer. Leave zero to
|
||||||
|
// indicate that the fallback is unsupported.
|
||||||
|
size_t fallback_gamma_size;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct wl_signal destroy;
|
struct wl_signal destroy;
|
||||||
struct wl_signal set_gamma; // struct wlr_gamma_control_manager_v1_set_gamma_event
|
struct wl_signal set_gamma; // struct wlr_gamma_control_manager_v1_set_gamma_event
|
||||||
|
|
@ -49,6 +54,8 @@ struct wlr_gamma_control_v1 *wlr_gamma_control_manager_v1_get_control(
|
||||||
struct wlr_gamma_control_manager_v1 *manager, struct wlr_output *output);
|
struct wlr_gamma_control_manager_v1 *manager, struct wlr_output *output);
|
||||||
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
|
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
|
||||||
struct wlr_output_state *output_state);
|
struct wlr_output_state *output_state);
|
||||||
|
struct wlr_color_transform *wlr_gamma_control_v1_get_color_transform(
|
||||||
|
struct wlr_gamma_control_v1 *gamma_control);
|
||||||
void wlr_gamma_control_v1_send_failed_and_destroy(struct wlr_gamma_control_v1 *gamma_control);
|
void wlr_gamma_control_v1_send_failed_and_destroy(struct wlr_gamma_control_v1 *gamma_control);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,7 @@ struct wlr_output {
|
||||||
char *name;
|
char *name;
|
||||||
char *description; // may be NULL
|
char *description; // may be NULL
|
||||||
char *make, *model, *serial; // may be NULL
|
char *make, *model, *serial; // may be NULL
|
||||||
|
char *port; // may be NULL
|
||||||
int32_t phys_width, phys_height; // mm
|
int32_t phys_width, phys_height; // mm
|
||||||
|
|
||||||
// Note: some backends may have zero modes
|
// Note: some backends may have zero modes
|
||||||
|
|
@ -267,6 +268,7 @@ struct wlr_output {
|
||||||
struct {
|
struct {
|
||||||
struct wl_listener display_destroy;
|
struct wl_listener display_destroy;
|
||||||
struct wlr_output_image_description image_description_value;
|
struct wlr_output_image_description image_description_value;
|
||||||
|
struct wlr_color_transform *color_transform;
|
||||||
} WLR_PRIVATE;
|
} WLR_PRIVATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,11 @@ struct wlr_scene_output {
|
||||||
|
|
||||||
bool gamma_lut_changed;
|
bool gamma_lut_changed;
|
||||||
struct wlr_gamma_control_v1 *gamma_lut;
|
struct wlr_gamma_control_v1 *gamma_lut;
|
||||||
|
struct wlr_color_transform *gamma_lut_color_transform;
|
||||||
|
|
||||||
|
struct wlr_color_transform *prev_gamma_lut_color_transform;
|
||||||
|
struct wlr_color_transform *prev_supplied_color_transform;
|
||||||
|
struct wlr_color_transform *prev_combined_color_transform;
|
||||||
|
|
||||||
struct wl_listener output_commit;
|
struct wl_listener output_commit;
|
||||||
struct wl_listener output_damage;
|
struct wl_listener output_damage;
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,7 @@ struct wlr_xwm {
|
||||||
struct wl_listener drop_focus_destroy;
|
struct wl_listener drop_focus_destroy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// xwm_create takes ownership of wm_fd and will close it under all circumstances.
|
||||||
struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland, int wm_fd);
|
struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland, int wm_fd);
|
||||||
|
|
||||||
void xwm_destroy(struct wlr_xwm *xwm);
|
void xwm_destroy(struct wlr_xwm *xwm);
|
||||||
|
|
|
||||||
130
render/color.c
130
render/color.c
|
|
@ -62,6 +62,33 @@ struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
|
||||||
return &tx->base;
|
return &tx->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_color_transform *wlr_color_transform_init_pipeline(
|
||||||
|
struct wlr_color_transform **transforms, size_t len) {
|
||||||
|
assert(len > 0);
|
||||||
|
|
||||||
|
struct wlr_color_transform **copy = calloc(len, sizeof(copy[0]));
|
||||||
|
if (copy == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_color_transform_pipeline *tx = calloc(1, sizeof(*tx));
|
||||||
|
if (!tx) {
|
||||||
|
free(copy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_PIPELINE);
|
||||||
|
|
||||||
|
// TODO: flatten nested pipeline transforms
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
copy[i] = wlr_color_transform_ref(transforms[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tx->transforms = copy;
|
||||||
|
tx->len = len;
|
||||||
|
|
||||||
|
return &tx->base;
|
||||||
|
}
|
||||||
|
|
||||||
static void color_transform_destroy(struct wlr_color_transform *tr) {
|
static void color_transform_destroy(struct wlr_color_transform *tr) {
|
||||||
switch (tr->type) {
|
switch (tr->type) {
|
||||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||||
|
|
@ -73,6 +100,14 @@ static void color_transform_destroy(struct wlr_color_transform *tr) {
|
||||||
struct wlr_color_transform_lut_3x1d *lut_3x1d = color_transform_lut_3x1d_from_base(tr);
|
struct wlr_color_transform_lut_3x1d *lut_3x1d = color_transform_lut_3x1d_from_base(tr);
|
||||||
free(lut_3x1d->lut_3x1d);
|
free(lut_3x1d->lut_3x1d);
|
||||||
break;
|
break;
|
||||||
|
case COLOR_TRANSFORM_PIPELINE:;
|
||||||
|
struct wlr_color_transform_pipeline *pipeline =
|
||||||
|
wl_container_of(tr, pipeline, base);
|
||||||
|
for (size_t i = 0; i < pipeline->len; i++) {
|
||||||
|
wlr_color_transform_unref(pipeline->transforms[i]);
|
||||||
|
}
|
||||||
|
free(pipeline->transforms);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
wlr_addon_set_finish(&tr->addons);
|
wlr_addon_set_finish(&tr->addons);
|
||||||
free(tr);
|
free(tr);
|
||||||
|
|
@ -108,8 +143,67 @@ struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
||||||
return lut_3x1d;
|
return lut_3x1d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float srgb_eval_inverse_eotf(float x) {
|
||||||
|
// See https://www.w3.org/Graphics/Color/srgb
|
||||||
|
if (x <= 0.0031308) {
|
||||||
|
return 12.92 * x;
|
||||||
|
} else {
|
||||||
|
return 1.055 * powf(x, 1.0 / 2.4) - 0.055;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static float st2084_pq_eval_inverse_eotf(float x) {
|
||||||
|
// H.273 TransferCharacteristics code point 16
|
||||||
|
float c1 = 0.8359375;
|
||||||
|
float c2 = 18.8515625;
|
||||||
|
float c3 = 18.6875;
|
||||||
|
float m = 78.84375;
|
||||||
|
float n = 0.1593017578125;
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if (x > 1) {
|
||||||
|
x = 1;
|
||||||
|
}
|
||||||
|
float pow_n = powf(x, n);
|
||||||
|
return powf((c1 + c2 * pow_n) / (1 + c3 * pow_n), m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float bt1886_eval_inverse_eotf(float x) {
|
||||||
|
float lb = powf(0.0001, 1.0 / 2.4);
|
||||||
|
float lw = powf(1.0, 1.0 / 2.4);
|
||||||
|
float a = powf(lw - lb, 2.4);
|
||||||
|
float b = lb / (lw - lb);
|
||||||
|
return powf(x / a, 1.0 / 2.4) - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float transfer_function_eval_inverse_eotf(
|
||||||
|
enum wlr_color_transfer_function tf, float x) {
|
||||||
|
switch (tf) {
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||||
|
return srgb_eval_inverse_eotf(x);
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||||
|
return st2084_pq_eval_inverse_eotf(x);
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||||
|
return x;
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
return powf(x, 1.0 / 2.2);
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||||
|
return bt1886_eval_inverse_eotf(x);
|
||||||
|
}
|
||||||
|
abort(); // unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
static void color_transform_inverse_eotf_eval(
|
||||||
|
struct wlr_color_transform_inverse_eotf *tr,
|
||||||
|
float out[static 3], const float in[static 3]) {
|
||||||
|
for (size_t i = 0; i < 3; i++) {
|
||||||
|
out[i] = transfer_function_eval_inverse_eotf(tr->tf, in[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static float lut_1d_get(const uint16_t *lut, size_t len, size_t i) {
|
static float lut_1d_get(const uint16_t *lut, size_t len, size_t i) {
|
||||||
if (i > len) {
|
if (i >= len) {
|
||||||
i = len - 1;
|
i = len - 1;
|
||||||
}
|
}
|
||||||
return (float) lut[i] / UINT16_MAX;
|
return (float) lut[i] / UINT16_MAX;
|
||||||
|
|
@ -125,13 +219,38 @@ static float lut_1d_eval(const uint16_t *lut, size_t len, float x) {
|
||||||
return a * (1 - frac_part) + b * frac_part;
|
return a * (1 - frac_part) + b * frac_part;
|
||||||
}
|
}
|
||||||
|
|
||||||
void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
static void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
||||||
float out[static 3], const float in[static 3]) {
|
float out[static 3], const float in[static 3]) {
|
||||||
for (size_t i = 0; i < 3; i++) {
|
for (size_t i = 0; i < 3; i++) {
|
||||||
out[i] = lut_1d_eval(&tr->lut_3x1d[tr->dim * i], tr->dim, in[i]);
|
out[i] = lut_1d_eval(&tr->lut_3x1d[tr->dim * i], tr->dim, in[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wlr_color_transform_eval(struct wlr_color_transform *tr,
|
||||||
|
float out[static 3], const float in[static 3]) {
|
||||||
|
switch (tr->type) {
|
||||||
|
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||||
|
color_transform_inverse_eotf_eval(wlr_color_transform_inverse_eotf_from_base(tr), out, in);
|
||||||
|
break;
|
||||||
|
case COLOR_TRANSFORM_LCMS2:
|
||||||
|
color_transform_lcms2_eval(color_transform_lcms2_from_base(tr), out, in);
|
||||||
|
break;
|
||||||
|
case COLOR_TRANSFORM_LUT_3X1D:
|
||||||
|
color_transform_lut_3x1d_eval(color_transform_lut_3x1d_from_base(tr), out, in);
|
||||||
|
break;
|
||||||
|
case COLOR_TRANSFORM_PIPELINE:;
|
||||||
|
struct wlr_color_transform_pipeline *pipeline =
|
||||||
|
wl_container_of(tr, pipeline, base);
|
||||||
|
float color[3];
|
||||||
|
memcpy(color, in, sizeof(color));
|
||||||
|
for (size_t i = 0; i < pipeline->len; i++) {
|
||||||
|
wlr_color_transform_eval(pipeline->transforms[i], color, color);
|
||||||
|
}
|
||||||
|
memcpy(out, color, sizeof(color));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void wlr_color_primaries_from_named(struct wlr_color_primaries *out,
|
void wlr_color_primaries_from_named(struct wlr_color_primaries *out,
|
||||||
enum wlr_color_named_primaries named) {
|
enum wlr_color_named_primaries named) {
|
||||||
switch (named) {
|
switch (named) {
|
||||||
|
|
@ -202,6 +321,13 @@ void wlr_color_transfer_function_get_default_luminance(enum wlr_color_transfer_f
|
||||||
.reference = 203,
|
.reference = 203,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||||
|
*lum = (struct wlr_color_luminances){
|
||||||
|
.min = 0.01,
|
||||||
|
.max = 100,
|
||||||
|
.reference = 100,
|
||||||
|
};
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
*lum = (struct wlr_color_luminances){
|
*lum = (struct wlr_color_luminances){
|
||||||
.min = 0.2,
|
.min = 0.2,
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,7 @@ static void convert_pixman_box_to_vk_rect(const pixman_box32_t *box, VkRect2D *r
|
||||||
}
|
}
|
||||||
|
|
||||||
static float color_to_linear(float non_linear) {
|
static float color_to_linear(float non_linear) {
|
||||||
// See https://www.w3.org/Graphics/Color/srgb
|
return pow(non_linear, 2.2);
|
||||||
return (non_linear > 0.04045) ?
|
|
||||||
pow((non_linear + 0.055) / 1.055, 2.4) :
|
|
||||||
non_linear / 12.92;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static float color_to_linear_premult(float non_linear, float alpha) {
|
static float color_to_linear_premult(float non_linear, float alpha) {
|
||||||
|
|
@ -229,7 +226,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
||||||
if (pass->color_transform && pass->color_transform->type != COLOR_TRANSFORM_INVERSE_EOTF) {
|
if (pass->color_transform && pass->color_transform->type != COLOR_TRANSFORM_INVERSE_EOTF) {
|
||||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_lut3d;
|
pipeline = render_buffer->two_pass.render_setup->output_pipe_lut3d;
|
||||||
} else {
|
} else {
|
||||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||||
if (pass->color_transform && pass->color_transform->type == COLOR_TRANSFORM_INVERSE_EOTF) {
|
if (pass->color_transform && pass->color_transform->type == COLOR_TRANSFORM_INVERSE_EOTF) {
|
||||||
struct wlr_color_transform_inverse_eotf *inverse_eotf =
|
struct wlr_color_transform_inverse_eotf *inverse_eotf =
|
||||||
wlr_color_transform_inverse_eotf_from_base(pass->color_transform);
|
wlr_color_transform_inverse_eotf_from_base(pass->color_transform);
|
||||||
|
|
@ -246,6 +243,12 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
||||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_pq;
|
pipeline = render_buffer->two_pass.render_setup->output_pipe_pq;
|
||||||
break;
|
break;
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
pipeline = render_buffer->two_pass.render_setup->output_pipe_gamma22;
|
||||||
|
break;
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||||
|
pipeline = render_buffer->two_pass.render_setup->output_pipe_bt1886;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_color_luminances srgb_lum, dst_lum;
|
struct wlr_color_luminances srgb_lum, dst_lum;
|
||||||
|
|
@ -776,7 +779,7 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
||||||
|
|
||||||
enum wlr_color_transfer_function tf = options->transfer_function;
|
enum wlr_color_transfer_function tf = options->transfer_function;
|
||||||
if (tf == 0) {
|
if (tf == 0) {
|
||||||
tf = WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool srgb_image_view = false;
|
bool srgb_image_view = false;
|
||||||
|
|
@ -796,6 +799,12 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
||||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ;
|
tex_transform = WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ;
|
||||||
break;
|
break;
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
tex_transform = WLR_VK_TEXTURE_TRANSFORM_GAMMA22;
|
||||||
|
break;
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||||
|
tex_transform = WLR_VK_TEXTURE_TRANSFORM_BT1886;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline(
|
struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline(
|
||||||
|
|
@ -840,7 +849,8 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
||||||
}
|
}
|
||||||
|
|
||||||
float luminance_multiplier = 1;
|
float luminance_multiplier = 1;
|
||||||
if (tf != WLR_COLOR_TRANSFER_FUNCTION_SRGB) {
|
if (tf != WLR_COLOR_TRANSFER_FUNCTION_SRGB
|
||||||
|
&& tf != WLR_COLOR_TRANSFER_FUNCTION_GAMMA22) {
|
||||||
struct wlr_color_luminances src_lum, srgb_lum;
|
struct wlr_color_luminances src_lum, srgb_lum;
|
||||||
wlr_color_transfer_function_get_default_luminance(tf, &src_lum);
|
wlr_color_transfer_function_get_default_luminance(tf, &src_lum);
|
||||||
wlr_color_transfer_function_get_default_luminance(
|
wlr_color_transfer_function_get_default_luminance(
|
||||||
|
|
@ -954,19 +964,6 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
||||||
*ds = VK_NULL_HANDLE;
|
*ds = VK_NULL_HANDLE;
|
||||||
*ds_pool = NULL;
|
*ds_pool = NULL;
|
||||||
|
|
||||||
struct wlr_color_transform_lcms2 *tr_lcms2 = NULL;
|
|
||||||
struct wlr_color_transform_lut_3x1d *tr_lut_3x1d = NULL;
|
|
||||||
switch (tr->type) {
|
|
||||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
|
||||||
abort(); // unreachable
|
|
||||||
case COLOR_TRANSFORM_LCMS2:
|
|
||||||
tr_lcms2 = color_transform_lcms2_from_base(tr);
|
|
||||||
break;
|
|
||||||
case COLOR_TRANSFORM_LUT_3X1D:
|
|
||||||
tr_lut_3x1d = color_transform_lut_3x1d_from_base(tr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// R32G32B32 is not a required Vulkan format
|
// R32G32B32 is not a required Vulkan format
|
||||||
// TODO: use it when available
|
// TODO: use it when available
|
||||||
VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||||
|
|
@ -1064,11 +1061,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
||||||
b_index * sample_range,
|
b_index * sample_range,
|
||||||
};
|
};
|
||||||
float rgb_out[3];
|
float rgb_out[3];
|
||||||
if (tr_lcms2 != NULL) {
|
wlr_color_transform_eval(tr, rgb_out, rgb_in);
|
||||||
color_transform_lcms2_eval(tr_lcms2, rgb_out, rgb_in);
|
|
||||||
} else {
|
|
||||||
color_transform_lut_3x1d_eval(tr_lut_3x1d, rgb_out, rgb_in);
|
|
||||||
}
|
|
||||||
|
|
||||||
dst[dst_offset] = rgb_out[0];
|
dst[dst_offset] = rgb_out[0];
|
||||||
dst[dst_offset + 1] = rgb_out[1];
|
dst[dst_offset + 1] = rgb_out[1];
|
||||||
|
|
@ -1179,7 +1172,7 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is the default when unspecified
|
// This is the default when unspecified
|
||||||
inv_eotf = WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
inv_eotf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool using_linear_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
bool using_linear_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,8 @@ static void destroy_render_format_setup(struct wlr_vk_renderer *renderer,
|
||||||
vkDestroyPipeline(dev, setup->output_pipe_srgb, NULL);
|
vkDestroyPipeline(dev, setup->output_pipe_srgb, NULL);
|
||||||
vkDestroyPipeline(dev, setup->output_pipe_pq, NULL);
|
vkDestroyPipeline(dev, setup->output_pipe_pq, NULL);
|
||||||
vkDestroyPipeline(dev, setup->output_pipe_lut3d, NULL);
|
vkDestroyPipeline(dev, setup->output_pipe_lut3d, NULL);
|
||||||
|
vkDestroyPipeline(dev, setup->output_pipe_gamma22, NULL);
|
||||||
|
vkDestroyPipeline(dev, setup->output_pipe_bt1886, NULL);
|
||||||
|
|
||||||
struct wlr_vk_pipeline *pipeline, *tmp_pipeline;
|
struct wlr_vk_pipeline *pipeline, *tmp_pipeline;
|
||||||
wl_list_for_each_safe(pipeline, tmp_pipeline, &setup->pipelines, link) {
|
wl_list_for_each_safe(pipeline, tmp_pipeline, &setup->pipelines, link) {
|
||||||
|
|
@ -2345,6 +2347,16 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
||||||
&setup->output_pipe_pq, WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ)) {
|
&setup->output_pipe_pq, WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if (!init_blend_to_output_pipeline(
|
||||||
|
renderer, setup->render_pass, renderer->output_pipe_layout,
|
||||||
|
&setup->output_pipe_gamma22, WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (!init_blend_to_output_pipeline(
|
||||||
|
renderer, setup->render_pass, renderer->output_pipe_layout,
|
||||||
|
&setup->output_pipe_bt1886, WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(format->vk_srgb);
|
assert(format->vk_srgb);
|
||||||
VkAttachmentDescription attachment = {
|
VkAttachmentDescription attachment = {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ layout (constant_id = 0) const int OUTPUT_TRANSFORM = 0;
|
||||||
#define OUTPUT_TRANSFORM_INVERSE_SRGB 1
|
#define OUTPUT_TRANSFORM_INVERSE_SRGB 1
|
||||||
#define OUTPUT_TRANSFORM_INVERSE_ST2084_PQ 2
|
#define OUTPUT_TRANSFORM_INVERSE_ST2084_PQ 2
|
||||||
#define OUTPUT_TRANSFORM_LUT_3D 3
|
#define OUTPUT_TRANSFORM_LUT_3D 3
|
||||||
|
#define OUTPUT_TRANSFORM_INVERSE_GAMMA22 4
|
||||||
|
#define OUTPUT_TRANSFORM_INVERSE_BT1886 5
|
||||||
|
|
||||||
float linear_channel_to_srgb(float x) {
|
float linear_channel_to_srgb(float x) {
|
||||||
return max(min(x * 12.92, 0.04045), 1.055 * pow(x, 1. / 2.4) - 0.055);
|
return max(min(x * 12.92, 0.04045), 1.055 * pow(x, 1. / 2.4) - 0.055);
|
||||||
|
|
@ -46,6 +48,14 @@ vec3 linear_color_to_pq(vec3 color) {
|
||||||
return pow((vec3(c1) + c2 * pow_n) / (vec3(1) + c3 * pow_n), vec3(m));
|
return pow((vec3(c1) + c2 * pow_n) / (vec3(1) + c3 * pow_n), vec3(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 linear_color_to_bt1886(vec3 color) {
|
||||||
|
float lb = pow(0.0001, 1.0 / 2.4);
|
||||||
|
float lw = pow(1.0, 1.0 / 2.4);
|
||||||
|
float a = pow(lw - lb, 2.4);
|
||||||
|
float b = lb / (lw - lb);
|
||||||
|
return pow(color / a, vec3(1.0 / 2.4)) - vec3(b);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 in_color = subpassLoad(in_color).rgba;
|
vec4 in_color = subpassLoad(in_color).rgba;
|
||||||
|
|
||||||
|
|
@ -71,6 +81,10 @@ void main() {
|
||||||
} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_SRGB) {
|
} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_SRGB) {
|
||||||
// Produce sRGB encoded values
|
// Produce sRGB encoded values
|
||||||
rgb = linear_color_to_srgb(rgb);
|
rgb = linear_color_to_srgb(rgb);
|
||||||
|
} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_GAMMA22) {
|
||||||
|
rgb = pow(rgb, vec3(1. / 2.2));
|
||||||
|
} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_BT1886) {
|
||||||
|
rgb = linear_color_to_bt1886(rgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Back to pre-multiplied alpha
|
// Back to pre-multiplied alpha
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0;
|
||||||
#define TEXTURE_TRANSFORM_IDENTITY 0
|
#define TEXTURE_TRANSFORM_IDENTITY 0
|
||||||
#define TEXTURE_TRANSFORM_SRGB 1
|
#define TEXTURE_TRANSFORM_SRGB 1
|
||||||
#define TEXTURE_TRANSFORM_ST2084_PQ 2
|
#define TEXTURE_TRANSFORM_ST2084_PQ 2
|
||||||
|
#define TEXTURE_TRANSFORM_GAMMA22 3
|
||||||
|
#define TEXTURE_TRANSFORM_BT1886 4
|
||||||
|
|
||||||
float srgb_channel_to_linear(float x) {
|
float srgb_channel_to_linear(float x) {
|
||||||
return mix(x / 12.92,
|
return mix(x / 12.92,
|
||||||
|
|
@ -44,6 +46,14 @@ vec3 pq_color_to_linear(vec3 color) {
|
||||||
return pow(num / denom, vec3(inv_m1));
|
return pow(num / denom, vec3(inv_m1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 bt1886_color_to_linear(vec3 color) {
|
||||||
|
float lb = pow(0.0001, 1.0 / 2.4);
|
||||||
|
float lw = pow(1.0, 1.0 / 2.4);
|
||||||
|
float a = pow(lw - lb, 2.4);
|
||||||
|
float b = lb / (lw - lb);
|
||||||
|
return a * pow(color + vec3(b), vec3(2.4));
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 in_color = textureLod(tex, uv, 0);
|
vec4 in_color = textureLod(tex, uv, 0);
|
||||||
|
|
||||||
|
|
@ -60,6 +70,10 @@ void main() {
|
||||||
rgb = srgb_color_to_linear(rgb);
|
rgb = srgb_color_to_linear(rgb);
|
||||||
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_ST2084_PQ) {
|
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_ST2084_PQ) {
|
||||||
rgb = pq_color_to_linear(rgb);
|
rgb = pq_color_to_linear(rgb);
|
||||||
|
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_GAMMA22) {
|
||||||
|
rgb = pow(rgb, vec3(2.2));
|
||||||
|
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_BT1886) {
|
||||||
|
rgb = bt1886_color_to_linear(rgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
rgb *= data.luminance_multiplier;
|
rgb *= data.luminance_multiplier;
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,15 @@ static void output_apply_state(struct wlr_output *output,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||||
|
wlr_color_transform_unref(output->color_transform);
|
||||||
|
if (state->color_transform != NULL) {
|
||||||
|
output->color_transform = wlr_color_transform_ref(state->color_transform);
|
||||||
|
} else {
|
||||||
|
output->color_transform = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool geometry_updated = state->committed &
|
bool geometry_updated = state->committed &
|
||||||
(WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM |
|
(WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM |
|
||||||
WLR_OUTPUT_STATE_SUBPIXEL);
|
WLR_OUTPUT_STATE_SUBPIXEL);
|
||||||
|
|
@ -407,6 +416,7 @@ void wlr_output_finish(struct wlr_output *output) {
|
||||||
|
|
||||||
wlr_swapchain_destroy(output->cursor_swapchain);
|
wlr_swapchain_destroy(output->cursor_swapchain);
|
||||||
wlr_buffer_unlock(output->cursor_front_buffer);
|
wlr_buffer_unlock(output->cursor_front_buffer);
|
||||||
|
wlr_color_transform_unref(output->color_transform);
|
||||||
|
|
||||||
wlr_swapchain_destroy(output->swapchain);
|
wlr_swapchain_destroy(output->swapchain);
|
||||||
|
|
||||||
|
|
@ -423,6 +433,7 @@ void wlr_output_finish(struct wlr_output *output) {
|
||||||
free(output->make);
|
free(output->make);
|
||||||
free(output->model);
|
free(output->model);
|
||||||
free(output->serial);
|
free(output->serial);
|
||||||
|
free(output->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wlr_output_destroy(struct wlr_output *output) {
|
void wlr_output_destroy(struct wlr_output *output) {
|
||||||
|
|
@ -515,8 +526,7 @@ const struct wlr_output_image_description *output_pending_image_description(
|
||||||
* Returns a bitfield of the unchanged fields.
|
* Returns a bitfield of the unchanged fields.
|
||||||
*
|
*
|
||||||
* Some fields are not checked: damage always changes in-between frames, the
|
* Some fields are not checked: damage always changes in-between frames, the
|
||||||
* gamma LUT is too expensive to check, the contents of the buffer might have
|
* contents of the buffer might have changed, etc.
|
||||||
* changed, etc.
|
|
||||||
*/
|
*/
|
||||||
static uint32_t output_compare_state(struct wlr_output *output,
|
static uint32_t output_compare_state(struct wlr_output *output,
|
||||||
const struct wlr_output_state *state) {
|
const struct wlr_output_state *state) {
|
||||||
|
|
@ -562,6 +572,10 @@ static uint32_t output_compare_state(struct wlr_output *output,
|
||||||
output->subpixel == state->subpixel) {
|
output->subpixel == state->subpixel) {
|
||||||
fields |= WLR_OUTPUT_STATE_SUBPIXEL;
|
fields |= WLR_OUTPUT_STATE_SUBPIXEL;
|
||||||
}
|
}
|
||||||
|
if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) &&
|
||||||
|
output->color_transform == state->color_transform) {
|
||||||
|
fields |= WLR_OUTPUT_STATE_COLOR_TRANSFORM;
|
||||||
|
}
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,10 +37,12 @@ static struct wlr_output *get_surface_frame_pacing_output(struct wlr_surface *su
|
||||||
|
|
||||||
static bool get_tf_preference(enum wlr_color_transfer_function tf) {
|
static bool get_tf_preference(enum wlr_color_transfer_function tf) {
|
||||||
switch (tf) {
|
switch (tf) {
|
||||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||||
return 0;
|
return 0;
|
||||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||||
return 1;
|
return 1;
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +62,7 @@ static bool get_primaries_preference(enum wlr_color_named_primaries primaries) {
|
||||||
static void get_surface_preferred_image_description(struct wlr_surface *surface,
|
static void get_surface_preferred_image_description(struct wlr_surface *surface,
|
||||||
struct wlr_image_description_v1_data *out) {
|
struct wlr_image_description_v1_data *out) {
|
||||||
struct wlr_output_image_description preferred = {
|
struct wlr_output_image_description preferred = {
|
||||||
.transfer_function = WLR_COLOR_TRANSFER_FUNCTION_SRGB,
|
.transfer_function = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22,
|
||||||
.primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB,
|
.primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -248,7 +250,7 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
|
||||||
opacity = (float)alpha_modifier_state->multiplier;
|
opacity = (float)alpha_modifier_state->multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||||
enum wlr_color_named_primaries primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
enum wlr_color_named_primaries primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||||
const struct wlr_image_description_v1_data *img_desc =
|
const struct wlr_image_description_v1_data *img_desc =
|
||||||
wlr_surface_get_image_description_v1_data(surface);
|
wlr_surface_get_image_description_v1_data(surface);
|
||||||
|
|
|
||||||
|
|
@ -1530,6 +1530,8 @@ static void scene_handle_gamma_control_manager_v1_set_gamma(struct wl_listener *
|
||||||
|
|
||||||
output->gamma_lut_changed = true;
|
output->gamma_lut_changed = true;
|
||||||
output->gamma_lut = event->control;
|
output->gamma_lut = event->control;
|
||||||
|
wlr_color_transform_unref(output->gamma_lut_color_transform);
|
||||||
|
output->gamma_lut_color_transform = wlr_gamma_control_v1_get_color_transform(event->control);
|
||||||
wlr_output_schedule_frame(output->output);
|
wlr_output_schedule_frame(output->output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1547,6 +1549,8 @@ static void scene_handle_gamma_control_manager_v1_destroy(struct wl_listener *li
|
||||||
wl_list_for_each(output, &scene->outputs, link) {
|
wl_list_for_each(output, &scene->outputs, link) {
|
||||||
output->gamma_lut_changed = false;
|
output->gamma_lut_changed = false;
|
||||||
output->gamma_lut = NULL;
|
output->gamma_lut = NULL;
|
||||||
|
wlr_color_transform_unref(output->gamma_lut_color_transform);
|
||||||
|
output->gamma_lut_color_transform = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1766,6 +1770,10 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) {
|
||||||
wl_list_remove(&scene_output->output_damage.link);
|
wl_list_remove(&scene_output->output_damage.link);
|
||||||
wl_list_remove(&scene_output->output_needs_frame.link);
|
wl_list_remove(&scene_output->output_needs_frame.link);
|
||||||
wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
|
wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
|
||||||
|
wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
|
||||||
|
wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
|
||||||
|
wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
|
||||||
|
wlr_color_transform_unref(scene_output->prev_combined_color_transform);
|
||||||
wl_array_release(&scene_output->render_list);
|
wl_array_release(&scene_output->render_list);
|
||||||
free(scene_output);
|
free(scene_output);
|
||||||
}
|
}
|
||||||
|
|
@ -1925,6 +1933,27 @@ static void scene_buffer_send_dmabuf_feedback(const struct wlr_scene *scene,
|
||||||
wlr_linux_dmabuf_feedback_v1_finish(&feedback);
|
wlr_linux_dmabuf_feedback_v1_finish(&feedback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool color_management_is_scanout_allowed(const struct wlr_output_image_description *img_desc,
|
||||||
|
const struct wlr_scene_buffer *buffer) {
|
||||||
|
// Disallow scanout if the output has colorimetry information but buffer
|
||||||
|
// doesn't; allow it only if the output also lacks it.
|
||||||
|
if (buffer->transfer_function == 0 && buffer->primaries == 0) {
|
||||||
|
return img_desc == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the output has colorimetry information, the buffer must match it for
|
||||||
|
// direct scanout to be allowed.
|
||||||
|
if (img_desc != NULL) {
|
||||||
|
return img_desc->transfer_function == buffer->transfer_function &&
|
||||||
|
img_desc->primaries == buffer->primaries;
|
||||||
|
}
|
||||||
|
// If the output doesn't have colorimetry image description set, we can only
|
||||||
|
// scan out buffers with default colorimetry (gamma2.2 transfer and sRGB
|
||||||
|
// primaries) used in wlroots.
|
||||||
|
return buffer->transfer_function == WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 &&
|
||||||
|
buffer->primaries == WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||||
|
}
|
||||||
|
|
||||||
enum scene_direct_scanout_result {
|
enum scene_direct_scanout_result {
|
||||||
// This scene node is not a candidate for scanout
|
// This scene node is not a candidate for scanout
|
||||||
SCANOUT_INELIGIBLE,
|
SCANOUT_INELIGIBLE,
|
||||||
|
|
@ -1982,20 +2011,8 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct wlr_output_image_description *img_desc = output_pending_image_description(scene_output->output, state);
|
const struct wlr_output_image_description *img_desc = output_pending_image_description(scene_output->output, state);
|
||||||
if (buffer->transfer_function != 0 || buffer->primaries != 0) {
|
if (!color_management_is_scanout_allowed(img_desc, buffer)) {
|
||||||
if (img_desc == NULL || img_desc->transfer_function != buffer->transfer_function ||
|
return SCANOUT_INELIGIBLE;
|
||||||
img_desc->primaries != buffer->primaries) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (img_desc != NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer->transfer_function != 0 && buffer->transfer_function != WLR_COLOR_TRANSFER_FUNCTION_SRGB) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (buffer->primaries != 0 && buffer->primaries != WLR_COLOR_NAMED_PRIMARIES_SRGB) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want to ensure optimal buffer selection, but as direct-scanout can be enabled and disabled
|
// We want to ensure optimal buffer selection, but as direct-scanout can be enabled and disabled
|
||||||
|
|
@ -2095,16 +2112,15 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wlr_gamma_control_v1_apply(scene_output->gamma_lut, &gamma_pending)) {
|
wlr_output_state_set_color_transform(&gamma_pending, scene_output->gamma_lut_color_transform);
|
||||||
wlr_output_state_finish(&gamma_pending);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scene_output->gamma_lut_changed = false;
|
scene_output->gamma_lut_changed = false;
|
||||||
|
|
||||||
if (!wlr_output_test_state(scene_output->output, &gamma_pending)) {
|
if (!wlr_output_test_state(scene_output->output, &gamma_pending)) {
|
||||||
wlr_gamma_control_v1_send_failed_and_destroy(scene_output->gamma_lut);
|
wlr_gamma_control_v1_send_failed_and_destroy(scene_output->gamma_lut);
|
||||||
|
|
||||||
scene_output->gamma_lut = NULL;
|
scene_output->gamma_lut = NULL;
|
||||||
|
wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
|
||||||
|
scene_output->gamma_lut_color_transform = NULL;
|
||||||
wlr_output_state_finish(&gamma_pending);
|
wlr_output_state_finish(&gamma_pending);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -2113,6 +2129,41 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
|
||||||
wlr_output_state_finish(&gamma_pending);
|
wlr_output_state_finish(&gamma_pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct wlr_color_transform *scene_output_combine_color_transforms(
|
||||||
|
struct wlr_scene_output *scene_output, struct wlr_color_transform *supplied) {
|
||||||
|
struct wlr_color_transform *gamma_lut = scene_output->gamma_lut_color_transform;
|
||||||
|
assert(gamma_lut != NULL);
|
||||||
|
|
||||||
|
if (gamma_lut == scene_output->prev_gamma_lut_color_transform &&
|
||||||
|
supplied == scene_output->prev_supplied_color_transform) {
|
||||||
|
return wlr_color_transform_ref(scene_output->prev_combined_color_transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_color_transform *combined;
|
||||||
|
if (supplied == NULL) {
|
||||||
|
combined = wlr_color_transform_ref(gamma_lut);
|
||||||
|
} else {
|
||||||
|
struct wlr_color_transform *transforms[] = {
|
||||||
|
gamma_lut,
|
||||||
|
supplied,
|
||||||
|
};
|
||||||
|
size_t transforms_len = sizeof(transforms) / sizeof(transforms[0]);
|
||||||
|
combined = wlr_color_transform_init_pipeline(transforms, transforms_len);
|
||||||
|
if (combined == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
|
||||||
|
scene_output->prev_gamma_lut_color_transform = wlr_color_transform_ref(gamma_lut);
|
||||||
|
wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
|
||||||
|
scene_output->prev_supplied_color_transform = supplied ? wlr_color_transform_ref(supplied) : NULL;
|
||||||
|
wlr_color_transform_unref(scene_output->prev_combined_color_transform);
|
||||||
|
scene_output->prev_combined_color_transform = wlr_color_transform_ref(combined);
|
||||||
|
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
|
|
||||||
bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
struct wlr_output_state *state, const struct wlr_scene_output_state_options *options) {
|
struct wlr_output_state *state, const struct wlr_scene_output_state_options *options) {
|
||||||
struct wlr_scene_output_state_options default_options = {0};
|
struct wlr_scene_output_state_options default_options = {0};
|
||||||
|
|
@ -2136,6 +2187,16 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
enum wlr_scene_debug_damage_option debug_damage =
|
enum wlr_scene_debug_damage_option debug_damage =
|
||||||
scene_output->scene->debug_damage_option;
|
scene_output->scene->debug_damage_option;
|
||||||
|
|
||||||
|
bool render_gamma_lut = false;
|
||||||
|
if (wlr_output_get_gamma_size(output) == 0 && output->renderer->features.output_color_transform) {
|
||||||
|
if (scene_output->gamma_lut_color_transform != scene_output->prev_gamma_lut_color_transform) {
|
||||||
|
scene_output_damage_whole(scene_output);
|
||||||
|
}
|
||||||
|
if (scene_output->gamma_lut_color_transform != NULL) {
|
||||||
|
render_gamma_lut = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct render_data render_data = {
|
struct render_data render_data = {
|
||||||
.transform = output->transform,
|
.transform = output->transform,
|
||||||
.scale = output->scale,
|
.scale = output->scale,
|
||||||
|
|
@ -2236,7 +2297,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
// - There are no color transforms that need to be applied
|
// - There are no color transforms that need to be applied
|
||||||
// - Damage highlight debugging is not enabled
|
// - Damage highlight debugging is not enabled
|
||||||
enum scene_direct_scanout_result scanout_result = SCANOUT_INELIGIBLE;
|
enum scene_direct_scanout_result scanout_result = SCANOUT_INELIGIBLE;
|
||||||
if (options->color_transform == NULL && list_len == 1
|
if (options->color_transform == NULL && !render_gamma_lut && list_len == 1
|
||||||
&& debug_damage != WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
|
&& debug_damage != WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
|
||||||
scanout_result = scene_entry_try_direct_scanout(&list_data[0], state, &render_data);
|
scanout_result = scene_entry_try_direct_scanout(&list_data[0], state, &render_data);
|
||||||
}
|
}
|
||||||
|
|
@ -2310,6 +2371,17 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
color_transform = wlr_color_transform_ref(options->color_transform);
|
color_transform = wlr_color_transform_ref(options->color_transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (render_gamma_lut) {
|
||||||
|
struct wlr_color_transform *combined =
|
||||||
|
scene_output_combine_color_transforms(scene_output, color_transform);
|
||||||
|
wlr_color_transform_unref(color_transform);
|
||||||
|
if (combined == NULL) {
|
||||||
|
wlr_buffer_unlock(buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
color_transform = combined;
|
||||||
|
}
|
||||||
|
|
||||||
scene_output->in_point++;
|
scene_output->in_point++;
|
||||||
struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer,
|
struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer,
|
||||||
&(struct wlr_buffer_pass_options){
|
&(struct wlr_buffer_pass_options){
|
||||||
|
|
@ -2432,7 +2504,9 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
scene_output->in_point);
|
scene_output->in_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
scene_output_state_attempt_gamma(scene_output, state);
|
if (!render_gamma_lut) {
|
||||||
|
scene_output_state_attempt_gamma(scene_output, state);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ static void cm_output_handle_get_image_description(struct wl_client *client,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_image_description_v1_data data = {
|
struct wlr_image_description_v1_data data = {
|
||||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||||
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
||||||
};
|
};
|
||||||
const struct wlr_output_image_description *image_desc = cm_output->output->image_description;
|
const struct wlr_output_image_description *image_desc = cm_output->output->image_description;
|
||||||
|
|
@ -777,7 +777,7 @@ static void manager_handle_get_surface_feedback(struct wl_client *client,
|
||||||
|
|
||||||
surface_feedback->surface = surface;
|
surface_feedback->surface = surface;
|
||||||
surface_feedback->data = (struct wlr_image_description_v1_data){
|
surface_feedback->data = (struct wlr_image_description_v1_data){
|
||||||
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||||
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -993,6 +993,10 @@ wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_
|
||||||
return WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
|
return WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
|
||||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR:
|
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||||
return WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
return WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||||
|
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
return WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||||
|
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886:
|
||||||
|
return WLR_COLOR_TRANSFER_FUNCTION_BT1886;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
@ -1007,6 +1011,10 @@ wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function
|
||||||
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ;
|
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ;
|
||||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||||
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR;
|
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22;
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||||
|
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886;
|
||||||
}
|
}
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,9 @@ static void gamma_control_manager_get_gamma_control(struct wl_client *client,
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t gamma_size = wlr_output_get_gamma_size(output);
|
size_t gamma_size = wlr_output_get_gamma_size(output);
|
||||||
|
if (gamma_size == 0) {
|
||||||
|
gamma_size = manager->fallback_gamma_size;
|
||||||
|
}
|
||||||
if (gamma_size == 0) {
|
if (gamma_size == 0) {
|
||||||
zwlr_gamma_control_v1_send_failed(resource);
|
zwlr_gamma_control_v1_send_failed(resource);
|
||||||
return;
|
return;
|
||||||
|
|
@ -262,15 +265,24 @@ struct wlr_gamma_control_v1 *wlr_gamma_control_manager_v1_get_control(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_color_transform *wlr_gamma_control_v1_get_color_transform(
|
||||||
|
struct wlr_gamma_control_v1 *gamma_control) {
|
||||||
|
if (gamma_control == NULL || gamma_control->table == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16_t *r = gamma_control->table;
|
||||||
|
const uint16_t *g = gamma_control->table + gamma_control->ramp_size;
|
||||||
|
const uint16_t *b = gamma_control->table + 2 * gamma_control->ramp_size;
|
||||||
|
|
||||||
|
return wlr_color_transform_init_lut_3x1d(gamma_control->ramp_size, r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
|
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
|
||||||
struct wlr_output_state *output_state) {
|
struct wlr_output_state *output_state) {
|
||||||
struct wlr_color_transform *tr = NULL;
|
struct wlr_color_transform *tr = NULL;
|
||||||
if (gamma_control != NULL && gamma_control->table != NULL) {
|
if (gamma_control != NULL && gamma_control->table != NULL) {
|
||||||
const uint16_t *r = gamma_control->table;
|
tr = wlr_gamma_control_v1_get_color_transform(gamma_control);
|
||||||
const uint16_t *g = gamma_control->table + gamma_control->ramp_size;
|
|
||||||
const uint16_t *b = gamma_control->table + 2 * gamma_control->ramp_size;
|
|
||||||
|
|
||||||
tr = wlr_color_transform_init_lut_3x1d(gamma_control->ramp_size, r, g, b);
|
|
||||||
if (tr == NULL) {
|
if (tr == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ static void input_method_destroy(struct wlr_input_method_v2 *input_method) {
|
||||||
popup_surface, tmp, &input_method->popup_surfaces, link) {
|
popup_surface, tmp, &input_method->popup_surfaces, link) {
|
||||||
popup_surface_destroy(popup_surface);
|
popup_surface_destroy(popup_surface);
|
||||||
}
|
}
|
||||||
|
wlr_input_method_keyboard_grab_v2_destroy(input_method->keyboard_grab);
|
||||||
wl_signal_emit_mutable(&input_method->events.destroy, NULL);
|
wl_signal_emit_mutable(&input_method->events.destroy, NULL);
|
||||||
|
|
||||||
assert(wl_list_empty(&input_method->events.commit.listener_list));
|
assert(wl_list_empty(&input_method->events.commit.listener_list));
|
||||||
|
|
@ -65,7 +66,6 @@ static void input_method_destroy(struct wlr_input_method_v2 *input_method) {
|
||||||
|
|
||||||
wl_list_remove(wl_resource_get_link(input_method->resource));
|
wl_list_remove(wl_resource_get_link(input_method->resource));
|
||||||
wl_list_remove(&input_method->seat_client_destroy.link);
|
wl_list_remove(&input_method->seat_client_destroy.link);
|
||||||
wlr_input_method_keyboard_grab_v2_destroy(input_method->keyboard_grab);
|
|
||||||
input_state_reset(&input_method->pending);
|
input_state_reset(&input_method->pending);
|
||||||
input_state_reset(&input_method->current);
|
input_state_reset(&input_method->current);
|
||||||
free(input_method);
|
free(input_method);
|
||||||
|
|
@ -271,8 +271,7 @@ void wlr_input_method_keyboard_grab_v2_destroy(
|
||||||
if (!keyboard_grab) {
|
if (!keyboard_grab) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wl_signal_emit_mutable(&keyboard_grab->events.destroy, keyboard_grab);
|
wl_signal_emit_mutable(&keyboard_grab->events.destroy, NULL);
|
||||||
|
|
||||||
assert(wl_list_empty(&keyboard_grab->events.destroy.listener_list));
|
assert(wl_list_empty(&keyboard_grab->events.destroy.listener_list));
|
||||||
|
|
||||||
keyboard_grab->input_method->keyboard_grab = NULL;
|
keyboard_grab->input_method->keyboard_grab = NULL;
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ struct wlr_linux_drm_syncobj_surface_v1 {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_linux_drm_syncobj_surface_v1_commit {
|
struct wlr_linux_drm_syncobj_surface_v1_commit {
|
||||||
struct wlr_linux_drm_syncobj_surface_v1 *surface;
|
struct wlr_surface *surface;
|
||||||
struct wlr_drm_syncobj_timeline_waiter waiter;
|
struct wlr_drm_syncobj_timeline_waiter waiter;
|
||||||
uint32_t cached_seq;
|
uint32_t cached_seq;
|
||||||
|
|
||||||
|
|
@ -192,7 +192,7 @@ static struct wlr_linux_drm_syncobj_surface_v1 *surface_from_wlr_surface(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void surface_commit_destroy(struct wlr_linux_drm_syncobj_surface_v1_commit *commit) {
|
static void surface_commit_destroy(struct wlr_linux_drm_syncobj_surface_v1_commit *commit) {
|
||||||
wlr_surface_unlock_cached(commit->surface->surface, commit->cached_seq);
|
wlr_surface_unlock_cached(commit->surface, commit->cached_seq);
|
||||||
wl_list_remove(&commit->surface_destroy.link);
|
wl_list_remove(&commit->surface_destroy.link);
|
||||||
wlr_drm_syncobj_timeline_waiter_finish(&commit->waiter);
|
wlr_drm_syncobj_timeline_waiter_finish(&commit->waiter);
|
||||||
free(commit);
|
free(commit);
|
||||||
|
|
@ -237,7 +237,7 @@ static bool lock_surface_commit(struct wlr_linux_drm_syncobj_surface_v1 *surface
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
commit->surface = surface;
|
commit->surface = surface->surface;
|
||||||
commit->cached_seq = wlr_surface_lock_pending(surface->surface);
|
commit->cached_seq = wlr_surface_lock_pending(surface->surface);
|
||||||
|
|
||||||
commit->surface_destroy.notify = surface_commit_handle_surface_destroy;
|
commit->surface_destroy.notify = surface_commit_handle_surface_destroy;
|
||||||
|
|
|
||||||
13
util/box.c
13
util/box.c
|
|
@ -19,16 +19,15 @@ void wlr_box_closest_point(const struct wlr_box *box, double x, double y,
|
||||||
//
|
//
|
||||||
// In order to be consistent with e.g. wlr_box_contains_point(),
|
// In order to be consistent with e.g. wlr_box_contains_point(),
|
||||||
// this function returns a point inside the bottom and right edges
|
// this function returns a point inside the bottom and right edges
|
||||||
// of the box by at least 1/65536 of a unit (pixel). 1/65536 is
|
// of the box by at least 1/256 of a unit (pixel). 1/256 is
|
||||||
// small enough to avoid a "dead zone" with high-resolution mice
|
// small enough to avoid a "dead zone" with high-resolution mice
|
||||||
// but large enough to avoid rounding to zero (due to loss of
|
// but large enough to avoid rounding to zero in wl_fixed_from_double().
|
||||||
// significant digits) in simple floating-point calculations.
|
|
||||||
|
|
||||||
// find the closest x point
|
// find the closest x point
|
||||||
if (x < box->x) {
|
if (x < box->x) {
|
||||||
*dest_x = box->x;
|
*dest_x = box->x;
|
||||||
} else if (x > box->x + box->width - 1/65536.0) {
|
} else if (x > box->x + box->width - 1/256.0) {
|
||||||
*dest_x = box->x + box->width - 1/65536.0;
|
*dest_x = box->x + box->width - 1/256.0;
|
||||||
} else {
|
} else {
|
||||||
*dest_x = x;
|
*dest_x = x;
|
||||||
}
|
}
|
||||||
|
|
@ -36,8 +35,8 @@ void wlr_box_closest_point(const struct wlr_box *box, double x, double y,
|
||||||
// find closest y point
|
// find closest y point
|
||||||
if (y < box->y) {
|
if (y < box->y) {
|
||||||
*dest_y = box->y;
|
*dest_y = box->y;
|
||||||
} else if (y > box->y + box->height - 1/65536.0) {
|
} else if (y > box->y + box->height - 1/256.0) {
|
||||||
*dest_y = box->y + box->height - 1/65536.0;
|
*dest_y = box->y + box->height - 1/256.0;
|
||||||
} else {
|
} else {
|
||||||
*dest_y = y;
|
*dest_y = y;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,9 @@ static void handle_server_start(struct wl_listener *listener, void *data) {
|
||||||
static void xwayland_mark_ready(struct wlr_xwayland *xwayland) {
|
static void xwayland_mark_ready(struct wlr_xwayland *xwayland) {
|
||||||
assert(xwayland->server->wm_fd[0] >= 0);
|
assert(xwayland->server->wm_fd[0] >= 0);
|
||||||
xwayland->xwm = xwm_create(xwayland, xwayland->server->wm_fd[0]);
|
xwayland->xwm = xwm_create(xwayland, xwayland->server->wm_fd[0]);
|
||||||
|
// xwm_create takes ownership of wm_fd[0] under all circumstances
|
||||||
|
xwayland->server->wm_fd[0] = -1;
|
||||||
|
|
||||||
if (!xwayland->xwm) {
|
if (!xwayland->xwm) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2530,6 +2530,7 @@ void xwm_set_cursor(struct wlr_xwm *xwm, const uint8_t *pixels, uint32_t stride,
|
||||||
struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
|
struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
|
||||||
struct wlr_xwm *xwm = calloc(1, sizeof(*xwm));
|
struct wlr_xwm *xwm = calloc(1, sizeof(*xwm));
|
||||||
if (xwm == NULL) {
|
if (xwm == NULL) {
|
||||||
|
close(wm_fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2544,11 +2545,13 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
|
||||||
|
|
||||||
xwm->ping_timeout = 10000;
|
xwm->ping_timeout = 10000;
|
||||||
|
|
||||||
|
// xcb_connect_to_fd takes ownership of the FD regardless of success/failure
|
||||||
xwm->xcb_conn = xcb_connect_to_fd(wm_fd, NULL);
|
xwm->xcb_conn = xcb_connect_to_fd(wm_fd, NULL);
|
||||||
|
|
||||||
int rc = xcb_connection_has_error(xwm->xcb_conn);
|
int rc = xcb_connection_has_error(xwm->xcb_conn);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
wlr_log(WLR_ERROR, "xcb connect failed: %d", rc);
|
wlr_log(WLR_ERROR, "xcb connect failed: %d", rc);
|
||||||
|
xcb_disconnect(xwm->xcb_conn);
|
||||||
free(xwm);
|
free(xwm);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue