mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
Compare commits
125 commits
46ec79ec27
...
2c7b47ef41
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c7b47ef41 | ||
|
|
879243e370 | ||
|
|
989cffe70d | ||
|
|
3e08e3be4a | ||
|
|
91f4890ec2 | ||
|
|
74ce6c22a5 | ||
|
|
0b58bddf13 | ||
|
|
3d36ab9211 | ||
|
|
d786e07899 | ||
|
|
6d63871f05 | ||
|
|
19c5d22beb | ||
|
|
06275103f2 | ||
|
|
03e7966650 | ||
|
|
5529aae3e6 | ||
|
|
6e1c8748ff | ||
|
|
d8fb7adcf0 | ||
|
|
c2d9ae2142 | ||
|
|
6978509f64 | ||
|
|
2252854297 | ||
|
|
dde07b6840 | ||
|
|
406aa5f7f5 | ||
|
|
2ec4012559 | ||
|
|
d039ad8da3 | ||
|
|
3f0d338643 | ||
|
|
60d72724cd | ||
|
|
7cb3393e75 | ||
|
|
26c1476827 | ||
|
|
138210f01c | ||
|
|
845a7a581d | ||
|
|
108d94f798 | ||
|
|
aaf82ee332 | ||
|
|
d1c88e9497 | ||
|
|
3e88a79e6f | ||
|
|
b2d09cdee9 | ||
|
|
35eba5f2fe | ||
|
|
a91f96b391 | ||
|
|
6fee3623e4 | ||
|
|
7f6d66ea62 | ||
|
|
54374b6fe6 | ||
|
|
dd7f543189 | ||
|
|
d7ae9a866b | ||
|
|
462046ffdc | ||
|
|
bd566225ea | ||
|
|
b62c6878e1 | ||
|
|
fd069ad4f2 | ||
|
|
5e5842cb1a | ||
|
|
cdd2c7e006 | ||
|
|
905465b0fa | ||
|
|
102a6bd415 | ||
|
|
06aacb2a6f | ||
|
|
0166fd9eb7 | ||
|
|
423afc3fc9 | ||
|
|
122310a2de | ||
|
|
b799ffc6ae | ||
|
|
e95117b700 | ||
|
|
1a18e47efa | ||
|
|
bbd9a49bdf | ||
|
|
7bf5ff4c02 | ||
|
|
b0c886ec77 | ||
|
|
7431d840d0 | ||
|
|
bb1f8673b3 | ||
|
|
ad1b2f2819 | ||
|
|
812675ba34 | ||
|
|
7392b3313a | ||
|
|
07e92fb868 | ||
|
|
12316417b0 | ||
|
|
dd3c63f5e6 | ||
|
|
c8b7600adc | ||
|
|
51a78cb0ed | ||
| 1beb25a1c8 | |||
|
|
2f2c0dfcc6 | ||
|
|
47a90d6f1a | ||
|
|
db5e9ca04c | ||
|
|
efb17980a8 | ||
|
|
be5e266211 | ||
|
|
80c7e0f772 | ||
|
|
ccec4116b3 | ||
|
|
d2007d7dc1 | ||
|
|
a4eb2cff46 | ||
|
|
eff620770c | ||
|
|
f5dc6416f0 | ||
|
|
c14aa1d0b8 | ||
|
|
c39b3ce7a3 | ||
|
|
f4327f52cf | ||
|
|
6aa654b728 | ||
|
|
31b78a4f3a | ||
|
|
58c3680d96 | ||
|
|
48bd1831fe | ||
|
|
8c7041c4e8 | ||
|
|
aecb867098 | ||
|
|
bf40f396bf | ||
|
|
2498036e67 | ||
|
|
e76f8ac2b3 | ||
|
|
6d8bb66f98 | ||
|
|
f5e7caf599 | ||
|
|
98af337175 | ||
|
|
0c272a3842 | ||
|
|
071773cb27 | ||
|
|
ae85c31176 | ||
|
|
fa1feb447f | ||
|
|
a8144088df | ||
|
|
3a51a5c623 | ||
|
|
56d95c2ecb | ||
|
|
ec422ac389 | ||
|
|
7a1161438c | ||
|
|
4efec11721 | ||
|
|
8d1c6e42ac | ||
|
|
b1a9dab03e | ||
|
|
dd3d9be41e | ||
|
|
c8d94000a6 | ||
|
|
0ee0452af0 | ||
|
|
f5a0992686 | ||
|
|
7b6eec530c | ||
|
|
b482e9089b | ||
|
|
dc258b2237 | ||
|
|
4470683591 | ||
|
|
8430a1922d | ||
|
|
f024d1b8c8 | ||
|
|
e64de4d55f | ||
|
|
f3524de980 | ||
|
|
a5706e2fb9 | ||
|
|
1df2274f6c | ||
|
|
30c6efedf1 | ||
|
|
2ea0e386c4 | ||
|
|
2e53932337 |
93 changed files with 2692 additions and 573 deletions
|
|
@ -41,9 +41,10 @@ tasks:
|
|||
cd wlroots/build-gcc/tinywl
|
||||
sudo modprobe vkms
|
||||
udevadm settle
|
||||
card="/dev/dri/$(ls /sys/devices/faux/vkms/drm/ | grep ^card)"
|
||||
export WLR_BACKENDS=drm
|
||||
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
|
||||
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 ]
|
||||
|
|
|
|||
|
|
@ -485,5 +485,10 @@ bool wlr_backend_commit(struct wlr_backend *backend,
|
|||
output_apply_commit(state->output, &state->base);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < states_len; i++) {
|
||||
const struct wlr_backend_output_state *state = &states[i];
|
||||
output_send_commit_event(state->output, &state->base);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,6 +178,85 @@ bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
|
|||
return true;
|
||||
}
|
||||
|
||||
static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) {
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
abort(); // unsupported
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return 2;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
abort(); // unsupported
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
abort(); // unsupported
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
abort(); // unsupported
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static uint16_t convert_cta861_color_coord(double v) {
|
||||
if (v < 0) {
|
||||
v = 0;
|
||||
}
|
||||
if (v > 1) {
|
||||
v = 1;
|
||||
}
|
||||
return (uint16_t)round(v * 50000);
|
||||
}
|
||||
|
||||
static bool create_hdr_output_metadata_blob(struct wlr_drm_backend *drm,
|
||||
const struct wlr_output_image_description *img_desc, uint32_t *blob_id) {
|
||||
if (img_desc == NULL) {
|
||||
*blob_id = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct hdr_output_metadata metadata = {
|
||||
.metadata_type = 0,
|
||||
.hdmi_metadata_type1 = {
|
||||
.eotf = convert_cta861_eotf(img_desc->transfer_function),
|
||||
.metadata_type = 0,
|
||||
.display_primaries = {
|
||||
{
|
||||
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.red.x),
|
||||
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.red.y),
|
||||
},
|
||||
{
|
||||
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.green.x),
|
||||
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.green.y),
|
||||
},
|
||||
{
|
||||
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.blue.x),
|
||||
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.blue.y),
|
||||
},
|
||||
},
|
||||
.white_point = {
|
||||
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.white.x),
|
||||
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.white.y),
|
||||
},
|
||||
.max_display_mastering_luminance = img_desc->mastering_luminance.max,
|
||||
.min_display_mastering_luminance = img_desc->mastering_luminance.min * 0.0001,
|
||||
.max_cll = img_desc->max_cll,
|
||||
.max_fall = img_desc->max_fall,
|
||||
},
|
||||
};
|
||||
if (drmModeCreatePropertyBlob(drm->fd, &metadata, sizeof(metadata), blob_id) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to create HDR_OUTPUT_METADATA property");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t convert_primaries_to_colorspace(uint32_t primaries) {
|
||||
switch (primaries) {
|
||||
case 0:
|
||||
return 0; // Default
|
||||
case WLR_COLOR_NAMED_PRIMARIES_BT2020:
|
||||
return 9; // BT2020_RGB
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static uint64_t max_bpc_for_format(uint32_t format) {
|
||||
switch (format) {
|
||||
case DRM_FORMAT_XRGB2101010:
|
||||
|
|
@ -302,11 +381,25 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
vrr_enabled = state->base->adaptive_sync_enabled;
|
||||
}
|
||||
|
||||
uint32_t colorspace = conn->colorspace;
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
|
||||
colorspace = convert_primaries_to_colorspace(
|
||||
state->base->image_description ? state->base->image_description->primaries : 0);
|
||||
}
|
||||
|
||||
uint32_t hdr_output_metadata = conn->hdr_output_metadata;
|
||||
if ((state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
|
||||
!create_hdr_output_metadata_blob(drm, state->base->image_description, &hdr_output_metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state->mode_id = mode_id;
|
||||
state->gamma_lut = gamma_lut;
|
||||
state->fb_damage_clips = fb_damage_clips;
|
||||
state->primary_in_fence_fd = in_fence_fd;
|
||||
state->vrr_enabled = vrr_enabled;
|
||||
state->colorspace = colorspace;
|
||||
state->hdr_output_metadata = hdr_output_metadata;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -321,6 +414,7 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
|
|||
crtc->own_mode_id = true;
|
||||
commit_blob(drm, &crtc->mode_id, state->mode_id);
|
||||
commit_blob(drm, &crtc->gamma_lut, state->gamma_lut);
|
||||
commit_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
|
||||
|
||||
conn->output.adaptive_sync_status = state->vrr_enabled ?
|
||||
WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED : WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
|
||||
|
|
@ -335,6 +429,8 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
|
|||
state->base->signal_point, state->out_fence_fd);
|
||||
close(state->out_fence_fd);
|
||||
}
|
||||
|
||||
conn->colorspace = state->colorspace;
|
||||
}
|
||||
|
||||
void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) {
|
||||
|
|
@ -344,6 +440,7 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state)
|
|||
|
||||
rollback_blob(drm, &crtc->mode_id, state->mode_id);
|
||||
rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut);
|
||||
rollback_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
|
||||
|
||||
destroy_blob(drm, state->fb_damage_clips);
|
||||
if (state->primary_in_fence_fd >= 0) {
|
||||
|
|
@ -435,6 +532,12 @@ static void atomic_connector_add(struct atomic *atom,
|
|||
if (modeset && active && conn->props.max_bpc != 0 && conn->max_bpc_bounds[1] != 0) {
|
||||
atomic_add(atom, conn->id, conn->props.max_bpc, pick_max_bpc(conn, state->primary_fb));
|
||||
}
|
||||
if (conn->props.colorspace != 0) {
|
||||
atomic_add(atom, conn->id, conn->props.colorspace, state->colorspace);
|
||||
}
|
||||
if (conn->props.hdr_output_metadata != 0) {
|
||||
atomic_add(atom, conn->id, conn->props.hdr_output_metadata, state->hdr_output_metadata);
|
||||
}
|
||||
atomic_add(atom, crtc->id, crtc->props.mode_id, state->mode_id);
|
||||
atomic_add(atom, crtc->id, crtc->props.active, active);
|
||||
if (active) {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ static const uint32_t COMMIT_OUTPUT_STATE =
|
|||
WLR_OUTPUT_STATE_LAYERS |
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
|
||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM;
|
||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION;
|
||||
|
||||
static const uint32_t SUPPORTED_OUTPUT_STATE =
|
||||
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
|
||||
|
|
@ -864,6 +865,12 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
|
||||
conn->backend->iface != &atomic_iface) {
|
||||
wlr_log(WLR_DEBUG, "Image descriptions are only supported by the atomic interface");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (test_only && conn->backend->mgpu_renderer.wlr_rend) {
|
||||
// If we're running as a secondary GPU, we can't perform an atomic
|
||||
// commit without blitting a buffer.
|
||||
|
|
@ -1710,7 +1717,11 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
|||
size_t edid_len = 0;
|
||||
uint8_t *edid = get_drm_prop_blob(drm->fd,
|
||||
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);
|
||||
|
||||
char *subconnector = NULL;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ hwdata = dependency(
|
|||
|
||||
libdisplay_info = dependency(
|
||||
'libdisplay-info',
|
||||
version: '>=0.2.0',
|
||||
required: 'drm' in backends,
|
||||
fallback: 'libdisplay-info',
|
||||
not_found_message: 'Required for the DRM backend.',
|
||||
|
|
|
|||
|
|
@ -22,8 +22,10 @@ struct prop_info {
|
|||
static const struct prop_info connector_info[] = {
|
||||
#define INDEX(name) (offsetof(struct wlr_drm_connector_props, name) / sizeof(uint32_t))
|
||||
{ "CRTC_ID", INDEX(crtc_id) },
|
||||
{ "Colorspace", INDEX(colorspace) },
|
||||
{ "DPMS", INDEX(dpms) },
|
||||
{ "EDID", INDEX(edid) },
|
||||
{ "HDR_OUTPUT_METADATA", INDEX(hdr_output_metadata) },
|
||||
{ "PATH", INDEX(path) },
|
||||
{ "content type", INDEX(content_type) },
|
||||
{ "link-status", INDEX(link_status) },
|
||||
|
|
|
|||
|
|
@ -83,6 +83,17 @@ void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data)
|
|||
output->model = di_info_get_model(info);
|
||||
output->serial = di_info_get_serial(info);
|
||||
|
||||
const struct di_supported_signal_colorimetry *colorimetry = di_info_get_supported_signal_colorimetry(info);
|
||||
bool has_bt2020 = colorimetry->bt2020_cycc || colorimetry->bt2020_ycc || colorimetry->bt2020_rgb;
|
||||
if (conn->props.colorspace != 0 && has_bt2020) {
|
||||
output->supported_primaries |= WLR_COLOR_NAMED_PRIMARIES_BT2020;
|
||||
}
|
||||
|
||||
const struct di_hdr_static_metadata *hdr_static_metadata = di_info_get_hdr_static_metadata(info);
|
||||
if (conn->props.hdr_output_metadata != 0 && hdr_static_metadata->type1 && hdr_static_metadata->pq) {
|
||||
output->supported_transfer_functions |= WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
}
|
||||
|
||||
di_info_destroy(info);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.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);
|
||||
wl_list_remove(&dev->link);
|
||||
|
|
@ -516,8 +519,6 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
break;
|
||||
}
|
||||
|
||||
bool is_boot_vga = false;
|
||||
|
||||
const char *path = udev_list_entry_get_name(entry);
|
||||
struct udev_device *dev = udev_device_new_from_syspath(session->udev, path);
|
||||
if (!dev) {
|
||||
|
|
@ -533,14 +534,20 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
continue;
|
||||
}
|
||||
|
||||
// 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);
|
||||
bool is_primary = false;
|
||||
const char *boot_display = udev_device_get_sysattr_value(dev, "boot_display");
|
||||
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) {
|
||||
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
||||
if (id && strcmp(id, "1") == 0) {
|
||||
is_boot_vga = true;
|
||||
if (pci) {
|
||||
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
||||
if (id && strcmp(id, "1") == 0) {
|
||||
is_primary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -554,7 +561,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
udev_device_unref(dev);
|
||||
|
||||
ret[i] = wlr_dev;
|
||||
if (is_boot_vga) {
|
||||
if (is_primary) {
|
||||
struct wlr_device *tmp = ret[0];
|
||||
ret[0] = ret[i];
|
||||
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) {
|
||||
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;
|
||||
if (mask & WL_EVENT_READABLE) {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
wlr_log(WLR_ERROR, "Failed to dispatch remote Wayland display");
|
||||
wlr_backend_destroy(&wl->backend);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,8 @@ struct wlr_drm_connector_state {
|
|||
uint32_t fb_damage_clips;
|
||||
int primary_in_fence_fd, out_fence_fd;
|
||||
bool vrr_enabled;
|
||||
uint32_t colorspace;
|
||||
uint32_t hdr_output_metadata;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -212,6 +214,10 @@ struct wlr_drm_connector {
|
|||
// Last committed page-flip
|
||||
struct wlr_drm_page_flip *pending_page_flip;
|
||||
|
||||
// Atomic modesetting only
|
||||
uint32_t colorspace;
|
||||
uint32_t hdr_output_metadata;
|
||||
|
||||
int32_t refresh;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ struct wlr_drm_connector_props {
|
|||
// atomic-modesetting only
|
||||
|
||||
uint32_t crtc_id;
|
||||
uint32_t colorspace;
|
||||
uint32_t hdr_output_metadata;
|
||||
};
|
||||
|
||||
struct wlr_drm_crtc_props {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@
|
|||
#include <wlr/util/addon.h>
|
||||
|
||||
enum wlr_color_transform_type {
|
||||
COLOR_TRANSFORM_SRGB,
|
||||
COLOR_TRANSFORM_INVERSE_EOTF,
|
||||
COLOR_TRANSFORM_LCMS2,
|
||||
COLOR_TRANSFORM_LUT_3X1D,
|
||||
COLOR_TRANSFORM_PIPELINE,
|
||||
};
|
||||
|
||||
struct wlr_color_transform {
|
||||
|
|
@ -18,8 +19,11 @@ struct wlr_color_transform {
|
|||
enum wlr_color_transform_type type;
|
||||
};
|
||||
|
||||
void wlr_color_transform_init(struct wlr_color_transform *tr,
|
||||
enum wlr_color_transform_type type);
|
||||
struct wlr_color_transform_inverse_eotf {
|
||||
struct wlr_color_transform base;
|
||||
|
||||
enum wlr_color_transfer_function tf;
|
||||
};
|
||||
|
||||
/**
|
||||
* The formula is approximated via three 1D look-up tables. The flat lut_3x1d
|
||||
|
|
@ -36,6 +40,16 @@ struct wlr_color_transform_lut_3x1d {
|
|||
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,
|
||||
enum wlr_color_transform_type type);
|
||||
|
||||
/**
|
||||
* Get a struct wlr_color_transform_lcms2 from a generic struct wlr_color_transform.
|
||||
* Asserts that the base type is COLOR_TRANSFORM_LCMS2.
|
||||
|
|
@ -51,6 +65,13 @@ void color_transform_lcms2_finish(struct wlr_color_transform_lcms2 *tr);
|
|||
void color_transform_lcms2_eval(struct wlr_color_transform_lcms2 *tr,
|
||||
float out[static 3], const float in[static 3]);
|
||||
|
||||
/**
|
||||
* Gets a wlr_color_transform_inverse_eotf from a generic wlr_color_transform.
|
||||
* Asserts that the base type is COLOR_TRANSFORM_INVERSE_EOTF
|
||||
*/
|
||||
struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_base(
|
||||
struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
* Get a struct wlr_color_transform_lut_3x1d from a generic
|
||||
* struct wlr_color_transform. Asserts that the base type is
|
||||
|
|
@ -59,12 +80,6 @@ void color_transform_lcms2_eval(struct wlr_color_transform_lcms2 *tr,
|
|||
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
||||
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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <vulkan/vulkan.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/render/color.h>
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
#include <wlr/render/interface.h>
|
||||
#include <wlr/util/addon.h>
|
||||
|
|
@ -151,6 +152,9 @@ struct wlr_vk_pipeline_layout {
|
|||
enum wlr_vk_texture_transform {
|
||||
WLR_VK_TEXTURE_TRANSFORM_IDENTITY = 0,
|
||||
WLR_VK_TEXTURE_TRANSFORM_SRGB = 1,
|
||||
WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2,
|
||||
WLR_VK_TEXTURE_TRANSFORM_GAMMA22 = 3,
|
||||
WLR_VK_TEXTURE_TRANSFORM_BT1886 = 4,
|
||||
};
|
||||
|
||||
enum wlr_vk_shader_source {
|
||||
|
|
@ -161,8 +165,12 @@ enum wlr_vk_shader_source {
|
|||
// Constants used to pick the color transform for the blend-to-output
|
||||
// fragment shader. Must match those in shaders/output.frag
|
||||
enum wlr_vk_output_transform {
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 0,
|
||||
WLR_VK_OUTPUT_TRANSFORM_LUT3D = 1,
|
||||
WLR_VK_OUTPUT_TRANSFORM_IDENTITY = 0,
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 1,
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ = 2,
|
||||
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 {
|
||||
|
|
@ -191,13 +199,24 @@ struct wlr_vk_render_format_setup {
|
|||
bool use_blending_buffer;
|
||||
VkRenderPass render_pass;
|
||||
|
||||
VkPipeline output_pipe_identity;
|
||||
VkPipeline output_pipe_srgb;
|
||||
VkPipeline output_pipe_pq;
|
||||
VkPipeline output_pipe_lut3d;
|
||||
VkPipeline output_pipe_gamma22;
|
||||
VkPipeline output_pipe_bt1886;
|
||||
|
||||
struct wlr_vk_renderer *renderer;
|
||||
struct wl_list pipelines; // struct wlr_vk_pipeline.link
|
||||
};
|
||||
|
||||
// Final output framebuffer and image view
|
||||
struct wlr_vk_render_buffer_out {
|
||||
VkImageView image_view;
|
||||
VkFramebuffer framebuffer;
|
||||
bool transitioned;
|
||||
};
|
||||
|
||||
// Renderer-internal represenation of an wlr_buffer imported for rendering.
|
||||
struct wlr_vk_render_buffer {
|
||||
struct wlr_buffer *wlr_buffer;
|
||||
|
|
@ -209,36 +228,40 @@ struct wlr_vk_render_buffer {
|
|||
uint32_t mem_count;
|
||||
VkImage image;
|
||||
|
||||
// Framebuffer and image view for rendering directly onto the buffer image,
|
||||
// without any color transform.
|
||||
struct {
|
||||
struct wlr_vk_render_buffer_out out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
} linear;
|
||||
|
||||
// Framebuffer and image view for rendering directly onto the buffer image.
|
||||
// This requires that the image support an _SRGB VkFormat, and does
|
||||
// not work with color transforms.
|
||||
struct {
|
||||
struct wlr_vk_render_buffer_out out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
VkImageView image_view;
|
||||
VkFramebuffer framebuffer;
|
||||
bool transitioned;
|
||||
} srgb;
|
||||
|
||||
// Framebuffer, image view, and blending image to render indirectly
|
||||
// onto the buffer image. This works for general image types and permits
|
||||
// color transforms.
|
||||
struct {
|
||||
struct wlr_vk_render_buffer_out out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
|
||||
VkImageView image_view;
|
||||
VkFramebuffer framebuffer;
|
||||
bool transitioned;
|
||||
|
||||
VkImage blend_image;
|
||||
VkImageView blend_image_view;
|
||||
VkDeviceMemory blend_memory;
|
||||
VkDescriptorSet blend_descriptor_set;
|
||||
struct wlr_vk_descriptor_pool *blend_attachment_pool;
|
||||
bool blend_transitioned;
|
||||
} plain;
|
||||
} two_pass;
|
||||
};
|
||||
|
||||
bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf, bool srgb);
|
||||
bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf);
|
||||
|
||||
struct wlr_vk_command_buffer {
|
||||
|
|
@ -334,7 +357,15 @@ struct wlr_vk_vert_pcr_data {
|
|||
float uv_size[2];
|
||||
};
|
||||
|
||||
struct wlr_vk_frag_texture_pcr_data {
|
||||
float matrix[4][4]; // only a 3x3 subset is used
|
||||
float alpha;
|
||||
float luminance_multiplier;
|
||||
};
|
||||
|
||||
struct wlr_vk_frag_output_pcr_data {
|
||||
float matrix[4][4]; // only a 3x3 subset is used
|
||||
float luminance_multiplier;
|
||||
float lut_3d_offset;
|
||||
float lut_3d_scale;
|
||||
};
|
||||
|
|
@ -342,6 +373,7 @@ struct wlr_vk_frag_output_pcr_data {
|
|||
struct wlr_vk_texture_view {
|
||||
struct wl_list link; // struct wlr_vk_texture.views
|
||||
const struct wlr_vk_pipeline_layout *layout;
|
||||
bool srgb;
|
||||
|
||||
VkDescriptorSet ds;
|
||||
VkImageView image_view;
|
||||
|
|
@ -356,7 +388,7 @@ struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout(
|
|||
const struct wlr_vk_pipeline_layout_key *key);
|
||||
struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(
|
||||
struct wlr_vk_texture *texture,
|
||||
const struct wlr_vk_pipeline_layout *layout);
|
||||
const struct wlr_vk_pipeline_layout *layout, bool srgb);
|
||||
|
||||
// Creates a vulkan renderer for the given device.
|
||||
struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev);
|
||||
|
|
@ -381,14 +413,19 @@ struct wlr_vk_render_pass {
|
|||
struct wlr_render_pass base;
|
||||
struct wlr_vk_renderer *renderer;
|
||||
struct wlr_vk_render_buffer *render_buffer;
|
||||
struct wlr_vk_render_buffer_out *render_buffer_out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
struct wlr_vk_command_buffer *command_buffer;
|
||||
struct rect_union updated_region;
|
||||
VkPipeline bound_pipeline;
|
||||
float projection[9];
|
||||
bool failed;
|
||||
bool srgb_pathway; // if false, rendering via intermediate blending buffer
|
||||
bool two_pass; // rendering via intermediate blending buffer
|
||||
struct wlr_color_transform *color_transform;
|
||||
|
||||
bool has_primaries;
|
||||
struct wlr_color_primaries primaries;
|
||||
|
||||
struct wlr_drm_syncobj_timeline *signal_timeline;
|
||||
uint64_t signal_point;
|
||||
|
||||
|
|
@ -453,13 +490,12 @@ struct wlr_vk_texture {
|
|||
VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
|
||||
VkImage image;
|
||||
const struct wlr_vk_format *format;
|
||||
enum wlr_vk_texture_transform transform;
|
||||
struct wlr_vk_command_buffer *last_used_cb; // to track when it can be destroyed
|
||||
bool dmabuf_imported;
|
||||
bool owned; // if dmabuf_imported: whether we have ownership of the image
|
||||
bool transitioned; // if dma_imported: whether we transitioned it away from preinit
|
||||
bool has_alpha; // whether the image is has alpha channel
|
||||
bool using_mutable_srgb; // is this accessed through _SRGB format view
|
||||
bool using_mutable_srgb; // can be accessed through _SRGB format view
|
||||
struct wl_list foreign_link; // wlr_vk_renderer.foreign_textures
|
||||
struct wl_list destroy_link; // wlr_vk_command_buffer.destroy_textures
|
||||
struct wl_list link; // wlr_vk_renderer.textures
|
||||
|
|
@ -468,7 +504,7 @@ struct wlr_vk_texture {
|
|||
struct wlr_buffer *buffer;
|
||||
struct wlr_addon buffer_addon;
|
||||
|
||||
struct wl_list views; // struct wlr_vk_texture_ds.link
|
||||
struct wl_list views; // struct wlr_vk_texture_view.link
|
||||
};
|
||||
|
||||
struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ void output_pending_resolution(struct wlr_output *output,
|
|||
const struct wlr_output_state *state, int *width, int *height);
|
||||
bool output_pending_enabled(struct wlr_output *output,
|
||||
const struct wlr_output_state *state);
|
||||
const struct wlr_output_image_description *output_pending_image_description(
|
||||
struct wlr_output *output, const struct wlr_output_state *state);
|
||||
|
||||
bool output_pick_format(struct wlr_output *output,
|
||||
const struct wlr_drm_format_set *display_formats,
|
||||
|
|
@ -25,6 +27,7 @@ void output_defer_present(struct wlr_output *output, struct wlr_output_event_pre
|
|||
|
||||
bool output_prepare_commit(struct wlr_output *output, const struct wlr_output_state *state);
|
||||
void output_apply_commit(struct wlr_output *output, const struct wlr_output_state *state);
|
||||
void output_send_commit_event(struct wlr_output *output, const struct wlr_output_state *state);
|
||||
|
||||
void output_state_get_buffer_src_box(const struct wlr_output_state *state,
|
||||
struct wlr_fbox *out);
|
||||
|
|
|
|||
14
include/util/mem.h
Normal file
14
include/util/mem.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef UTIL_MEM_H
|
||||
#define UTIL_MEM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* Allocate a new block of memory and copy *src to it, then store the address
|
||||
* of the new allocation in *out. Returns true if it worked, or false if
|
||||
* allocation failed.
|
||||
*/
|
||||
bool memdup(void *out, const void *src, size_t size);
|
||||
|
||||
#endif // UTIL_MEM_H
|
||||
|
|
@ -27,6 +27,60 @@ enum wlr_color_named_primaries {
|
|||
enum wlr_color_transfer_function {
|
||||
WLR_COLOR_TRANSFER_FUNCTION_SRGB = 1 << 0,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 = 1 << 3,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_BT1886 = 1 << 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies alpha blending modes. Note that premultiplied_electrical
|
||||
* is the default, so there is no "none" or "unset" value.
|
||||
*/
|
||||
enum wlr_alpha_mode {
|
||||
WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL,
|
||||
WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_OPTICAL,
|
||||
WLR_COLOR_ALPHA_MODE_STRAIGHT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Well-known color encodings, each representing a set of matrix coefficients
|
||||
* used to convert that particular YCbCr encoding to RGB. NONE means the
|
||||
* value is unset or unknown.
|
||||
*/
|
||||
enum wlr_color_encoding {
|
||||
WLR_COLOR_ENCODING_NONE,
|
||||
WLR_COLOR_ENCODING_IDENTITY,
|
||||
WLR_COLOR_ENCODING_BT709,
|
||||
WLR_COLOR_ENCODING_FCC,
|
||||
WLR_COLOR_ENCODING_BT601,
|
||||
WLR_COLOR_ENCODING_SMPTE240,
|
||||
WLR_COLOR_ENCODING_BT2020,
|
||||
WLR_COLOR_ENCODING_BT2020_CL,
|
||||
WLR_COLOR_ENCODING_ICTCP,
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies whether a particular color-encoding uses full- or limited-range
|
||||
* values. NONE means the value is unset or unknown.
|
||||
*/
|
||||
enum wlr_color_range {
|
||||
WLR_COLOR_RANGE_NONE,
|
||||
WLR_COLOR_RANGE_LIMITED,
|
||||
WLR_COLOR_RANGE_FULL,
|
||||
};
|
||||
|
||||
/**
|
||||
* Chroma sample locations, corresponding to Chroma420SampleLocType code
|
||||
* points in H.273. NONE means the value is unset or unknown.
|
||||
*/
|
||||
enum wlr_color_chroma_location {
|
||||
WLR_COLOR_CHROMA_LOCATION_NONE,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE0,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE1,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE2,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE3,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE4,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE5,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -74,10 +128,11 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
|
|||
const void *data, size_t size);
|
||||
|
||||
/**
|
||||
* Initialize a color transformation to apply sRGB encoding.
|
||||
* Returns NULL on failure.
|
||||
* Initialize a color transformation to apply EOTF⁻¹ encoding. Returns
|
||||
* NULL on failure.
|
||||
*/
|
||||
struct wlr_color_transform *wlr_color_transform_init_srgb(void);
|
||||
struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
|
||||
enum wlr_color_transfer_function tf);
|
||||
|
||||
/**
|
||||
* Initialize a color transformation to apply three 1D look-up tables. dim
|
||||
|
|
@ -86,6 +141,13 @@ struct wlr_color_transform *wlr_color_transform_init_srgb(void);
|
|||
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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
|
@ -97,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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <pixman.h>
|
||||
#include <stdint.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/render/color.h>
|
||||
#include <wlr/util/box.h>
|
||||
|
||||
struct wlr_renderer;
|
||||
|
|
@ -30,9 +31,12 @@ struct wlr_render_timer;
|
|||
struct wlr_buffer_pass_options {
|
||||
/* Timer to measure the duration of the render pass */
|
||||
struct wlr_render_timer *timer;
|
||||
/* Color transform to apply to the output of the render pass,
|
||||
* leave NULL to indicate sRGB/no custom transform */
|
||||
/* Color transform to apply to the output of the render pass.
|
||||
* Leave NULL to indicate the default transform (Gamma 2.2 encoding for
|
||||
* sRGB monitors) */
|
||||
struct wlr_color_transform *color_transform;
|
||||
/** Primaries describing the color volume of the destination buffer */
|
||||
const struct wlr_color_primaries *primaries;
|
||||
|
||||
/* Signal a timeline synchronization point when the render pass completes.
|
||||
*
|
||||
|
|
@ -99,6 +103,10 @@ struct wlr_render_texture_options {
|
|||
enum wlr_scale_filter_mode filter_mode;
|
||||
/* Blend mode */
|
||||
enum wlr_render_blend_mode blend_mode;
|
||||
/* Transfer function the source texture is encoded with */
|
||||
enum wlr_color_transfer_function transfer_function;
|
||||
/* Primaries describing the color volume of the source texture */
|
||||
const struct wlr_color_primaries *primaries;
|
||||
|
||||
/* Wait for a timeline synchronization point before texturing.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ struct wlr_renderer {
|
|||
} events;
|
||||
|
||||
struct {
|
||||
/**
|
||||
* Whether color transforms are supported for input textures
|
||||
*/
|
||||
bool input_color_transform;
|
||||
/**
|
||||
* Does the renderer support color transforms on its output?
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@
|
|||
#ifndef WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
|
||||
#define WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
|
||||
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/render/color.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/color-management-v1-enum.h>
|
||||
|
||||
#include "color-management-v1-protocol.h"
|
||||
#include <wlr/render/color.h>
|
||||
|
||||
struct wlr_surface;
|
||||
|
||||
|
|
@ -58,6 +58,10 @@ struct wlr_color_manager_v1_options {
|
|||
struct wlr_color_manager_v1 {
|
||||
struct wl_global *global;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wlr_color_manager_v1_features features;
|
||||
|
||||
|
|
@ -89,4 +93,30 @@ void wlr_color_manager_v1_set_surface_preferred_image_description(
|
|||
struct wlr_color_manager_v1 *manager, struct wlr_surface *surface,
|
||||
const struct wlr_image_description_v1_data *data);
|
||||
|
||||
/**
|
||||
* Convert a protocol transfer function to enum wlr_color_transfer_function.
|
||||
* Aborts if there is no matching wlroots entry.
|
||||
*/
|
||||
enum wlr_color_transfer_function
|
||||
wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_function tf);
|
||||
|
||||
/**
|
||||
* Convert an enum wlr_color_transfer_function value into a protocol transfer function.
|
||||
*/
|
||||
enum wp_color_manager_v1_transfer_function
|
||||
wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function tf);
|
||||
|
||||
/**
|
||||
* Convert a protocol named primaries to enum wlr_color_named_primaries.
|
||||
* Aborts if there is no matching wlroots entry.
|
||||
*/
|
||||
enum wlr_color_named_primaries
|
||||
wlr_color_manager_v1_primaries_to_wlr(enum wp_color_manager_v1_primaries primaries);
|
||||
|
||||
/**
|
||||
* Convert an enum wlr_color_named_primaries value into protocol primaries.
|
||||
*/
|
||||
enum wp_color_manager_v1_primaries
|
||||
wlr_color_manager_v1_primaries_from_wlr(enum wlr_color_named_primaries primaries);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
93
include/wlr/types/wlr_color_representation_v1.h
Normal file
93
include/wlr/types/wlr_color_representation_v1.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
|
||||
#define WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/color-representation-v1-enum.h>
|
||||
#include <wlr/render/color.h>
|
||||
|
||||
struct wlr_surface;
|
||||
|
||||
// Supported coefficients and range are always paired together
|
||||
struct wlr_color_representation_v1_coeffs_and_range {
|
||||
enum wp_color_representation_surface_v1_coefficients coeffs;
|
||||
enum wp_color_representation_surface_v1_range range;
|
||||
};
|
||||
|
||||
struct wlr_color_representation_manager_v1 {
|
||||
struct wl_global *global;
|
||||
|
||||
struct {
|
||||
// Manager is being destroyed
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
enum wp_color_representation_surface_v1_alpha_mode
|
||||
*supported_alpha_modes;
|
||||
size_t supported_alpha_modes_len;
|
||||
|
||||
struct wlr_color_representation_v1_coeffs_and_range
|
||||
*supported_coeffs_and_ranges;
|
||||
size_t supported_coeffs_and_ranges_len;
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
// Options used when initialising a wlr_color_representation_manager_v1
|
||||
struct wlr_color_representation_v1_options {
|
||||
enum wp_color_representation_surface_v1_alpha_mode
|
||||
*supported_alpha_modes;
|
||||
size_t supported_alpha_modes_len;
|
||||
|
||||
const struct wlr_color_representation_v1_coeffs_and_range
|
||||
*supported_coeffs_and_ranges;
|
||||
size_t supported_coeffs_and_ranges_len;
|
||||
};
|
||||
|
||||
struct wlr_color_representation_manager_v1 *wlr_color_representation_manager_v1_create(
|
||||
struct wl_display *display, uint32_t version,
|
||||
const struct wlr_color_representation_v1_options *options);
|
||||
|
||||
// This is all the color-representation state which can be attached to a
|
||||
// surface, double-buffered and made current on commit
|
||||
struct wlr_color_representation_v1_surface_state {
|
||||
// The enum premultiplied_electrical has value zero and is defined
|
||||
// to be the default if unspecified.
|
||||
enum wp_color_representation_surface_v1_alpha_mode alpha_mode;
|
||||
|
||||
// If zero then indicates unset, otherwise values correspond to
|
||||
// enum wp_color_representation_surface_v1_coefficients
|
||||
uint32_t coefficients;
|
||||
|
||||
// If zero then indicates unset, otherwise values correspond to
|
||||
// enum wp_color_representation_surface_v1_range
|
||||
uint32_t range;
|
||||
|
||||
// If zero then indicates unset, otherwise values correspond to
|
||||
// enum wp_color_representation_surface_v1_chroma_location
|
||||
uint32_t chroma_location;
|
||||
};
|
||||
|
||||
// Get the current color representation state committed to a surface
|
||||
const struct wlr_color_representation_v1_surface_state *wlr_color_representation_v1_get_surface_state(
|
||||
struct wlr_surface *surface);
|
||||
|
||||
enum wlr_alpha_mode wlr_color_representation_v1_alpha_mode_to_wlr(
|
||||
enum wp_color_representation_surface_v1_alpha_mode wp_val);
|
||||
enum wlr_color_encoding wlr_color_representation_v1_color_encoding_to_wlr(
|
||||
enum wp_color_representation_surface_v1_coefficients wp_val);
|
||||
enum wlr_color_range wlr_color_representation_v1_color_range_to_wlr(
|
||||
enum wp_color_representation_surface_v1_range wp_val);
|
||||
enum wlr_color_chroma_location wlr_color_representation_v1_chroma_location_to_wlr(
|
||||
enum wp_color_representation_surface_v1_chroma_location wp_val);
|
||||
|
||||
#endif // WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#define WLR_TYPES_WLR_CONTENT_TYPE_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include "content-type-v1-protocol.h"
|
||||
#include <wayland-protocols/content-type-v1-enum.h>
|
||||
|
||||
struct wlr_surface;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#define WLR_TYPES_WLR_CURSOR_SHAPE_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include "cursor-shape-v1-protocol.h"
|
||||
#include <wayland-protocols/cursor-shape-v1-enum.h>
|
||||
|
||||
/**
|
||||
* Manager for the cursor-shape-v1 protocol.
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
|
||||
/**
|
||||
* Deprecated: this protocol is legacy and superseded by ext-data-control-v1.
|
||||
* The implementation will be dropped in a future wlroots version.
|
||||
*
|
||||
* Consider using `wlr_ext_data_control_manager_v1` as a replacement.
|
||||
*/
|
||||
struct wlr_data_control_manager_v1 {
|
||||
struct wl_global *global;
|
||||
struct wl_list devices; // wlr_data_control_device_v1.link
|
||||
|
|
|
|||
|
|
@ -62,8 +62,6 @@ struct wlr_drm_lease_connector_v1 {
|
|||
|
||||
struct wlr_output *output;
|
||||
struct wlr_drm_lease_device_v1 *device;
|
||||
/** NULL if no client is currently leasing this connector */
|
||||
struct wlr_drm_lease_v1 *active_lease;
|
||||
|
||||
struct wl_list link; // wlr_drm_lease_device_v1.connectors
|
||||
|
||||
|
|
@ -93,9 +91,6 @@ struct wlr_drm_lease_v1 {
|
|||
|
||||
struct wlr_drm_lease_device_v1 *device;
|
||||
|
||||
struct wlr_drm_lease_connector_v1 **connectors;
|
||||
size_t n_connectors;
|
||||
|
||||
struct wl_list link; // wlr_drm_lease_device_v1.leases
|
||||
|
||||
void *data;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ struct wlr_ext_data_control_manager_v1 {
|
|||
struct wl_signal new_device; // wlr_ext_data_control_device_v1
|
||||
} events;
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_ext_data_control_device_v1 {
|
||||
|
|
@ -33,9 +35,11 @@ struct wlr_ext_data_control_device_v1 {
|
|||
struct wl_resource *selection_offer_resource; // current selection offer
|
||||
struct wl_resource *primary_selection_offer_resource; // current primary selection offer
|
||||
|
||||
struct wl_listener seat_destroy;
|
||||
struct wl_listener seat_set_selection;
|
||||
struct wl_listener seat_set_primary_selection;
|
||||
struct {
|
||||
struct wl_listener seat_destroy;
|
||||
struct wl_listener seat_set_selection;
|
||||
struct wl_listener seat_set_primary_selection;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_ext_data_control_manager_v1 *wlr_ext_data_control_manager_v1_create(
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
#define WLR_TYPES_WLR_EXT_IMAGE_COPY_CAPTURE_V1_H
|
||||
|
||||
#include <pixman.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <wayland-protocols/ext-image-copy-capture-v1-enum.h>
|
||||
#include <time.h>
|
||||
#include "ext-image-copy-capture-v1-protocol.h"
|
||||
|
||||
struct wlr_renderer;
|
||||
|
||||
|
|
|
|||
28
include/wlr/types/wlr_fixes.h
Normal file
28
include/wlr/types/wlr_fixes.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_TYPES_WLR_FIXES_H
|
||||
#define WLR_TYPES_WLR_FIXES_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
struct wlr_fixes {
|
||||
struct wl_global *global;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_fixes *wlr_fixes_create(struct wl_display *display, uint32_t version);
|
||||
|
||||
#endif
|
||||
|
|
@ -10,6 +10,11 @@ struct wlr_gamma_control_manager_v1 {
|
|||
struct wl_global *global;
|
||||
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 wl_signal destroy;
|
||||
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);
|
||||
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -48,10 +48,10 @@ struct wlr_input_method_v2 {
|
|||
struct wl_list link;
|
||||
|
||||
struct {
|
||||
struct wl_signal commit; // struct wlr_input_method_v2
|
||||
struct wl_signal commit;
|
||||
struct wl_signal new_popup_surface; // struct wlr_input_popup_surface_v2
|
||||
struct wl_signal grab_keyboard; // struct wlr_input_method_keyboard_grab_v2
|
||||
struct wl_signal destroy; // struct wlr_input_method_v2
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
|
|
@ -94,8 +94,8 @@ struct wlr_input_method_manager_v2 {
|
|||
struct wl_list input_methods; // struct wlr_input_method_v2.link
|
||||
|
||||
struct {
|
||||
struct wl_signal input_method; // struct wlr_input_method_v2
|
||||
struct wl_signal destroy; // struct wlr_input_method_manager_v2
|
||||
struct wl_signal new_input_method; // struct wlr_input_method_v2
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <time.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wlr/render/color.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/util/addon.h>
|
||||
|
|
@ -74,6 +75,7 @@ enum wlr_output_state_field {
|
|||
WLR_OUTPUT_STATE_WAIT_TIMELINE = 1 << 10,
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE = 1 << 11,
|
||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM = 1 << 12,
|
||||
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION = 1 << 13,
|
||||
};
|
||||
|
||||
enum wlr_output_state_mode_type {
|
||||
|
|
@ -81,6 +83,30 @@ enum wlr_output_state_mode_type {
|
|||
WLR_OUTPUT_STATE_MODE_CUSTOM,
|
||||
};
|
||||
|
||||
/**
|
||||
* Colorimetric image description.
|
||||
*
|
||||
* Carries information about the color encoding used for a struct wlr_buffer.
|
||||
*
|
||||
* Supported primaries are advertised in wlr_output.supported_primaries.
|
||||
* Supported transfer functions are advertised in
|
||||
* wlr_output.supported_transfer_functions.
|
||||
*
|
||||
* mastering_display_primaries, mastering_luminance, max_cll and max_fall are
|
||||
* optional. Luminances are given in cd/m².
|
||||
*/
|
||||
struct wlr_output_image_description {
|
||||
enum wlr_color_named_primaries primaries;
|
||||
enum wlr_color_transfer_function transfer_function;
|
||||
|
||||
struct wlr_color_primaries mastering_display_primaries;
|
||||
struct {
|
||||
double min, max;
|
||||
} mastering_luminance;
|
||||
double max_cll; // max content light level
|
||||
double max_fall; // max frame-average light level
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds the double-buffered output state.
|
||||
*/
|
||||
|
|
@ -131,6 +157,8 @@ struct wlr_output_state {
|
|||
uint64_t signal_point;
|
||||
|
||||
struct wlr_color_transform *color_transform;
|
||||
|
||||
struct wlr_output_image_description *image_description;
|
||||
};
|
||||
|
||||
struct wlr_output_impl;
|
||||
|
|
@ -166,12 +194,16 @@ struct wlr_output {
|
|||
int32_t width, height;
|
||||
int32_t refresh; // mHz, may be zero
|
||||
|
||||
uint32_t supported_primaries; // bitfield of enum wlr_color_named_primaries
|
||||
uint32_t supported_transfer_functions; // bitfield of enum wlr_color_transfer_function
|
||||
|
||||
bool enabled;
|
||||
float scale;
|
||||
enum wl_output_subpixel subpixel;
|
||||
enum wl_output_transform transform;
|
||||
enum wlr_output_adaptive_sync_status adaptive_sync_status;
|
||||
uint32_t render_format;
|
||||
const struct wlr_output_image_description *image_description;
|
||||
|
||||
// Indicates whether making changes to adaptive sync status is supported.
|
||||
// If false, changes to adaptive sync status is guaranteed to fail. If
|
||||
|
|
@ -234,6 +266,8 @@ struct wlr_output {
|
|||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
struct wlr_output_image_description image_description_value;
|
||||
struct wlr_color_transform *color_transform;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
|
|
@ -582,6 +616,12 @@ void wlr_output_state_set_signal_timeline(struct wlr_output_state *state,
|
|||
void wlr_output_state_set_color_transform(struct wlr_output_state *state,
|
||||
struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
* Set the colorimetry image description.
|
||||
*/
|
||||
bool wlr_output_state_set_image_description(struct wlr_output_state *state,
|
||||
const struct wlr_output_image_description *image_desc);
|
||||
|
||||
/**
|
||||
* Copies the output state from src to dst. It is safe to then
|
||||
* wlr_output_state_finish() src and have dst still be valid.
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/pointer-constraints-unstable-v1-enum.h>
|
||||
#include <pixman.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include "pointer-constraints-unstable-v1-protocol.h"
|
||||
|
||||
struct wlr_seat;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ struct wlr_scene_output_layout;
|
|||
struct wlr_presentation;
|
||||
struct wlr_linux_dmabuf_v1;
|
||||
struct wlr_gamma_control_manager_v1;
|
||||
struct wlr_color_manager_v1;
|
||||
struct wlr_output_state;
|
||||
|
||||
typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)(
|
||||
|
|
@ -102,11 +103,13 @@ struct wlr_scene {
|
|||
// May be NULL
|
||||
struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
|
||||
struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1;
|
||||
struct wlr_color_manager_v1 *color_manager_v1;
|
||||
|
||||
struct {
|
||||
struct wl_listener linux_dmabuf_v1_destroy;
|
||||
struct wl_listener gamma_control_manager_v1_destroy;
|
||||
struct wl_listener gamma_control_manager_v1_set_gamma;
|
||||
struct wl_listener color_manager_v1_destroy;
|
||||
|
||||
enum wlr_scene_debug_damage_option debug_damage_option;
|
||||
bool direct_scanout;
|
||||
|
|
@ -192,6 +195,8 @@ struct wlr_scene_buffer {
|
|||
int dst_width, dst_height;
|
||||
enum wl_output_transform transform;
|
||||
pixman_region32_t opaque_region;
|
||||
enum wlr_color_transfer_function transfer_function;
|
||||
enum wlr_color_named_primaries primaries;
|
||||
|
||||
struct {
|
||||
uint64_t active_outputs;
|
||||
|
|
@ -247,6 +252,11 @@ struct wlr_scene_output {
|
|||
|
||||
bool gamma_lut_changed;
|
||||
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_damage;
|
||||
|
|
@ -364,6 +374,13 @@ void wlr_scene_set_linux_dmabuf_v1(struct wlr_scene *scene,
|
|||
void wlr_scene_set_gamma_control_manager_v1(struct wlr_scene *scene,
|
||||
struct wlr_gamma_control_manager_v1 *gamma_control);
|
||||
|
||||
/**
|
||||
* Handles color_management_v1 feedback for all surfaces in the scene.
|
||||
*
|
||||
* Asserts that a struct wlr_color_manager_v1 hasn't already been set for the scene.
|
||||
*/
|
||||
void wlr_scene_set_color_manager_v1(struct wlr_scene *scene, struct wlr_color_manager_v1 *manager);
|
||||
|
||||
/**
|
||||
* Add a node displaying nothing but its children.
|
||||
*/
|
||||
|
|
@ -541,6 +558,12 @@ void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer,
|
|||
void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_scale_filter_mode filter_mode);
|
||||
|
||||
void wlr_scene_buffer_set_transfer_function(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_transfer_function transfer_function);
|
||||
|
||||
void wlr_scene_buffer_set_primaries(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_named_primaries primaries);
|
||||
|
||||
/**
|
||||
* Calls the buffer's frame_done signal.
|
||||
*/
|
||||
|
|
@ -566,6 +589,11 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output,
|
|||
|
||||
struct wlr_scene_output_state_options {
|
||||
struct wlr_scene_timer *timer;
|
||||
|
||||
/**
|
||||
* Color transform to apply before the output's color transform. Cannot be
|
||||
* used when the output has a non-NULL image description set.
|
||||
*/
|
||||
struct wlr_color_transform *color_transform;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@
|
|||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/util/box.h>
|
||||
|
||||
/**
|
||||
* Deprecated: this protocol is deprecated and superseded by ext-image-copy-capture-v1.
|
||||
* The implementation will be dropped in a future wlroots version.
|
||||
*
|
||||
* Consider using `wlr_ext_image_capture_source_v1` instead.
|
||||
*/
|
||||
|
||||
struct wlr_screencopy_manager_v1 {
|
||||
struct wl_global *global;
|
||||
struct wl_list frames; // wlr_screencopy_frame_v1.link
|
||||
|
|
|
|||
|
|
@ -10,10 +10,9 @@
|
|||
#define WLR_TYPES_WLR_TABLET_V2_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/tablet-v2-enum.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
|
||||
#include "tablet-v2-protocol.h"
|
||||
|
||||
/* This can probably be even lower,the tools don't have a lot of buttons */
|
||||
#define WLR_TABLET_V2_TOOL_BUTTONS_CAP 16
|
||||
|
||||
|
|
|
|||
|
|
@ -11,11 +11,9 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <wayland-protocols/tearing-control-v1-enum.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
|
||||
#include "tearing-control-v1-protocol.h"
|
||||
|
||||
struct wlr_tearing_control_v1 {
|
||||
struct wl_client *client;
|
||||
struct wl_list link;
|
||||
|
|
|
|||
|
|
@ -57,10 +57,10 @@ struct wlr_text_input_v3 {
|
|||
struct wl_list link;
|
||||
|
||||
struct {
|
||||
struct wl_signal enable; // struct wlr_text_input_v3
|
||||
struct wl_signal commit; // struct wlr_text_input_v3
|
||||
struct wl_signal disable; // struct wlr_text_input_v3
|
||||
struct wl_signal destroy; // struct wlr_text_input_v3
|
||||
struct wl_signal enable;
|
||||
struct wl_signal commit;
|
||||
struct wl_signal disable;
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
|
|
@ -75,7 +75,7 @@ struct wlr_text_input_manager_v3 {
|
|||
|
||||
struct {
|
||||
struct wl_signal new_text_input; // struct wlr_text_input_v3
|
||||
struct wl_signal destroy; // struct wlr_text_input_manager_v3
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@
|
|||
#define WLR_TYPES_WLR_XDG_SHELL_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/xdg-shell-enum.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include "xdg-shell-protocol.h"
|
||||
|
||||
struct wlr_xdg_shell {
|
||||
struct wl_global *global;
|
||||
|
|
|
|||
41
include/wlr/types/wlr_xdg_toplevel_tag_v1.h
Normal file
41
include/wlr/types/wlr_xdg_toplevel_tag_v1.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_TYPES_WLR_XDG_TOPLEVEL_TAG_V1_H
|
||||
#define WLR_TYPES_WLR_XDG_TOPLEVEL_TAG_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
struct wlr_xdg_toplevel_tag_manager_v1 {
|
||||
struct wl_global *global;
|
||||
|
||||
struct {
|
||||
struct wl_signal set_tag; // struct wlr_xdg_toplevel_tag_manager_v1_set_tag_event
|
||||
struct wl_signal set_description; // struct wlr_xdg_toplevel_tag_manager_v1_set_description_event
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_xdg_toplevel_tag_manager_v1_set_tag_event {
|
||||
struct wlr_xdg_toplevel *toplevel;
|
||||
const char *tag;
|
||||
};
|
||||
|
||||
struct wlr_xdg_toplevel_tag_manager_v1_set_description_event {
|
||||
struct wlr_xdg_toplevel *toplevel;
|
||||
const char *description;
|
||||
};
|
||||
|
||||
struct wlr_xdg_toplevel_tag_manager_v1 *wlr_xdg_toplevel_tag_manager_v1_create(
|
||||
struct wl_display *display, uint32_t version);
|
||||
|
||||
#endif
|
||||
|
|
@ -221,6 +221,7 @@ struct wlr_xwayland_surface {
|
|||
struct wl_signal set_override_redirect;
|
||||
struct wl_signal set_geometry;
|
||||
struct wl_signal set_opacity;
|
||||
struct wl_signal set_icon;
|
||||
struct wl_signal focus_in;
|
||||
struct wl_signal grab_focus;
|
||||
/* can be used to set initial maximized/fullscreen geometry */
|
||||
|
|
@ -401,6 +402,15 @@ enum wlr_xwayland_icccm_input_model wlr_xwayland_surface_icccm_input_model(
|
|||
void wlr_xwayland_set_workareas(struct wlr_xwayland *wlr_xwayland,
|
||||
const struct wlr_box *workareas, size_t num_workareas);
|
||||
|
||||
/**
|
||||
* Fetches the icon set via the _NET_WM_ICON property.
|
||||
*
|
||||
* Returns true on success. The caller is responsible for freeing the reply
|
||||
* using xcb_ewmh_get_wm_icon_reply_wipe().
|
||||
*/
|
||||
bool wlr_xwayland_surface_fetch_icon(
|
||||
const struct wlr_xwayland_surface *xsurface,
|
||||
xcb_ewmh_get_wm_icon_reply_t *icon_reply);
|
||||
|
||||
/**
|
||||
* Get the XCB connection of the XWM.
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ enum atom_name {
|
|||
NET_WM_STATE,
|
||||
NET_WM_STRUT_PARTIAL,
|
||||
NET_WM_WINDOW_TYPE,
|
||||
NET_WM_ICON,
|
||||
WM_TAKE_FOCUS,
|
||||
WINDOW,
|
||||
NET_ACTIVE_WINDOW,
|
||||
|
|
@ -163,6 +164,7 @@ struct wlr_xwm {
|
|||
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);
|
||||
|
||||
void xwm_destroy(struct wlr_xwm *xwm);
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ internal_features = {
|
|||
internal_config = configuration_data()
|
||||
|
||||
wayland_kwargs = {
|
||||
'version': '>=1.23.1',
|
||||
'version': '>=1.24.0',
|
||||
'fallback': 'wayland',
|
||||
'default_options': [
|
||||
'tests=false',
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
wayland_protos = dependency('wayland-protocols',
|
||||
version: '>=1.43',
|
||||
version: '>=1.44',
|
||||
fallback: 'wayland-protocols',
|
||||
default_options: ['tests=false'],
|
||||
)
|
||||
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
||||
wlr_deps += wayland_protos
|
||||
|
||||
wayland_scanner_dep = dependency('wayland-scanner',
|
||||
kwargs: wayland_kwargs,
|
||||
|
|
@ -25,6 +26,7 @@ protocols = {
|
|||
# Staging upstream protocols
|
||||
'alpha-modifier-v1': wl_protocol_dir / 'staging/alpha-modifier/alpha-modifier-v1.xml',
|
||||
'color-management-v1': wl_protocol_dir / 'staging/color-management/color-management-v1.xml',
|
||||
'color-representation-v1': wl_protocol_dir / 'staging/color-representation/color-representation-v1.xml',
|
||||
'content-type-v1': wl_protocol_dir / 'staging/content-type/content-type-v1.xml',
|
||||
'cursor-shape-v1': wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
|
||||
'drm-lease-v1': wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml',
|
||||
|
|
@ -42,6 +44,7 @@ protocols = {
|
|||
'xdg-dialog-v1': wl_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
|
||||
'xdg-system-bell-v1': wl_protocol_dir / 'staging/xdg-system-bell/xdg-system-bell-v1.xml',
|
||||
'xdg-toplevel-icon-v1': wl_protocol_dir / 'staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml',
|
||||
'xdg-toplevel-tag-v1': wl_protocol_dir / 'staging/xdg-toplevel-tag/xdg-toplevel-tag-v1.xml',
|
||||
'xwayland-shell-v1': wl_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml',
|
||||
'tearing-control-v1': wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
<request name="capture_output">
|
||||
<description summary="capture a frame from an output">
|
||||
Capture the next frame of a an entire output.
|
||||
Capture the next frame of an entire output.
|
||||
</description>
|
||||
<arg name="frame" type="new_id" interface="zwlr_export_dmabuf_frame_v1"/>
|
||||
<arg name="overlay_cursor" type="int"
|
||||
|
|
@ -136,7 +136,7 @@
|
|||
<arg name="stride" type="uint"
|
||||
summary="line size in bytes"/>
|
||||
<arg name="plane_index" type="uint"
|
||||
summary="index of the the plane the data in the object applies to"/>
|
||||
summary="index of the plane the data in the object applies to"/>
|
||||
</event>
|
||||
|
||||
<event name="ready">
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
</description>
|
||||
</request>
|
||||
|
||||
<event name="finished">
|
||||
<event name="finished" type="destructor">
|
||||
<description summary="the compositor has finished with the toplevel manager">
|
||||
This event indicates that the compositor is done sending events to the
|
||||
zwlr_foreign_toplevel_manager_v1. The server will destroy the object
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
tables. At any time the compositor can send a failed event indicating that
|
||||
this object is no longer valid.
|
||||
|
||||
There must always be at most one gamma control object per output, which
|
||||
There can only be at most one gamma control object per output, which
|
||||
has exclusive access to this particular output. When the gamma control
|
||||
object is destroyed, the gamma table is restored to its original value.
|
||||
</description>
|
||||
|
|
|
|||
|
|
@ -156,8 +156,8 @@
|
|||
not assume that the name is a reflection of an underlying DRM
|
||||
connector, X11 connection, etc.
|
||||
|
||||
If the compositor implements the xdg-output protocol and this head is
|
||||
enabled, the xdg_output.name event must report the same name.
|
||||
If this head matches a wl_output, the wl_output.name event must report
|
||||
the same name.
|
||||
|
||||
The name event is sent after a wlr_output_head object is created. This
|
||||
event is only sent once per object, and the name does not change over
|
||||
|
|
@ -176,8 +176,8 @@
|
|||
the make, model, serial of the underlying DRM connector or the display
|
||||
name of the underlying X11 connection, etc.
|
||||
|
||||
If the compositor implements xdg-output and this head is enabled,
|
||||
the xdg_output.description must report the same description.
|
||||
If this head matches a wl_output, the wl_output.description event must
|
||||
report the same name.
|
||||
|
||||
The description event is sent after a wlr_output_head object is created.
|
||||
This event is only sent once per object, and the description does not
|
||||
|
|
@ -191,6 +191,10 @@
|
|||
This event describes the physical size of the head. This event is only
|
||||
sent if the head has a physical size (e.g. is not a projector or a
|
||||
virtual device).
|
||||
|
||||
The physical size event is sent after a wlr_output_head object is created. This
|
||||
event is only sent once per object, and the physical size does not change over
|
||||
the lifetime of the wlr_output_head object.
|
||||
</description>
|
||||
<arg name="width" type="int" summary="width in millimeters of the output"/>
|
||||
<arg name="height" type="int" summary="height in millimeters of the output"/>
|
||||
|
|
@ -264,9 +268,6 @@
|
|||
<description summary="head manufacturer">
|
||||
This event describes the manufacturer of the head.
|
||||
|
||||
This must report the same make as the wl_output interface does in its
|
||||
geometry event.
|
||||
|
||||
Together with the model and serial_number events the purpose is to
|
||||
allow clients to recognize heads from previous sessions and for example
|
||||
load head-specific configurations back.
|
||||
|
|
@ -278,6 +279,10 @@
|
|||
identify the head by available information from other events but should
|
||||
be aware that there is an increased risk of false positives.
|
||||
|
||||
If sent, the make event is sent after a wlr_output_head object is
|
||||
created and only sent once per object. The make does not change over
|
||||
the lifetime of the wlr_output_head object.
|
||||
|
||||
It is not recommended to display the make string in UI to users. For
|
||||
that the string provided by the description event should be preferred.
|
||||
</description>
|
||||
|
|
@ -288,9 +293,6 @@
|
|||
<description summary="head model">
|
||||
This event describes the model of the head.
|
||||
|
||||
This must report the same model as the wl_output interface does in its
|
||||
geometry event.
|
||||
|
||||
Together with the make and serial_number events the purpose is to
|
||||
allow clients to recognize heads from previous sessions and for example
|
||||
load head-specific configurations back.
|
||||
|
|
@ -302,6 +304,10 @@
|
|||
identify the head by available information from other events but should
|
||||
be aware that there is an increased risk of false positives.
|
||||
|
||||
If sent, the model event is sent after a wlr_output_head object is
|
||||
created and only sent once per object. The model does not change over
|
||||
the lifetime of the wlr_output_head object.
|
||||
|
||||
It is not recommended to display the model string in UI to users. For
|
||||
that the string provided by the description event should be preferred.
|
||||
</description>
|
||||
|
|
@ -323,6 +329,10 @@
|
|||
available information from other events but should be aware that there
|
||||
is an increased risk of false positives.
|
||||
|
||||
If sent, the serial number event is sent after a wlr_output_head object
|
||||
is created and only sent once per object. The serial number does not
|
||||
change over the lifetime of the wlr_output_head object.
|
||||
|
||||
It is not recommended to display the serial_number string in UI to
|
||||
users. For that the string provided by the description event should be
|
||||
preferred.
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
|
||||
<request name="get_output_power">
|
||||
<description summary="get a power management for an output">
|
||||
Create a output power management mode control that can be used to
|
||||
Create an output power management mode control that can be used to
|
||||
adjust the power management mode for a given output.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
</enum>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_mode" value="1" summary="inexistent power save mode"/>
|
||||
<entry name="invalid_mode" value="1" summary="nonexistent power save mode"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_mode">
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
supported buffer type. The "buffer_done" event is sent afterwards to
|
||||
indicate that all supported buffer types have been enumerated. The client
|
||||
will then be able to send a "copy" request. If the capture is successful,
|
||||
the compositor will send a "flags" followed by a "ready" event.
|
||||
the compositor will send a "flags" event followed by a "ready" event.
|
||||
|
||||
For objects version 2 or lower, wl_shm buffers are always supported, ie.
|
||||
the "buffer" event is guaranteed to be sent.
|
||||
|
|
@ -114,12 +114,12 @@
|
|||
|
||||
<request name="copy">
|
||||
<description summary="copy the frame">
|
||||
Copy the frame to the supplied buffer. The buffer must have a the
|
||||
Copy the frame to the supplied buffer. The buffer must have the
|
||||
correct size, see zwlr_screencopy_frame_v1.buffer and
|
||||
zwlr_screencopy_frame_v1.linux_dmabuf. The buffer needs to have a
|
||||
supported format.
|
||||
|
||||
If the frame is successfully copied, a "flags" and a "ready" events are
|
||||
If the frame is successfully copied, "flags" and "ready" events are
|
||||
sent. Otherwise, a "failed" event is sent.
|
||||
</description>
|
||||
<arg name="buffer" type="object" interface="wl_buffer"/>
|
||||
|
|
@ -147,8 +147,7 @@
|
|||
<event name="ready">
|
||||
<description summary="indicates frame is available for reading">
|
||||
Called as soon as the frame is copied, indicating it is available
|
||||
for reading. This event includes the time at which presentation happened
|
||||
at.
|
||||
for reading. This event includes the time at which the presentation took place.
|
||||
|
||||
The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
|
||||
each component being an unsigned 32-bit value. Whole seconds are in
|
||||
|
|
|
|||
32
release.sh
Executable file
32
release.sh
Executable file
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh -eu
|
||||
|
||||
prev=$(git describe --tags --abbrev=0)
|
||||
next=$(meson rewrite kwargs info project / | jq -r '.kwargs["project#/"].version')
|
||||
|
||||
case "$next" in
|
||||
*-dev)
|
||||
echo "This is a development version"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$prev" = "$next" ]; then
|
||||
echo "Version not bumped in meson.build"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git diff-index --quiet HEAD -- meson.build; then
|
||||
echo "meson.build not committed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
shortlog="$(git shortlog --no-merges "$prev..")"
|
||||
(echo "wlroots $next"; echo ""; echo "$shortlog") | git tag "$next" -ase -F -
|
||||
|
||||
prefix=wlroots-$next
|
||||
archive=$prefix.tar.gz
|
||||
git archive --prefix="$prefix/" -o "$archive" "$next"
|
||||
gpg --output "$archive".sig --detach-sig "$archive"
|
||||
|
||||
git push --follow-tags
|
||||
glab release create "$next" "$archive" "$archive.sig" --notes ""
|
||||
|
|
@ -97,7 +97,6 @@ static struct wlr_gbm_buffer *create_buffer(struct wlr_gbm_allocator *alloc,
|
|||
}
|
||||
wlr_buffer_init(&buffer->base, &buffer_impl, width, height);
|
||||
buffer->gbm_bo = bo;
|
||||
wl_list_insert(&alloc->buffers, &buffer->link);
|
||||
|
||||
if (!export_gbm_bo(bo, &buffer->dmabuf)) {
|
||||
free(buffer);
|
||||
|
|
@ -112,6 +111,8 @@ static struct wlr_gbm_buffer *create_buffer(struct wlr_gbm_allocator *alloc,
|
|||
buffer->dmabuf.modifier = fallback_modifier;
|
||||
}
|
||||
|
||||
wl_list_insert(&alloc->buffers, &buffer->link);
|
||||
|
||||
char *format_name = drmGetFormatName(buffer->dmabuf.format);
|
||||
char *modifier_name = drmGetFormatModifierName(buffer->dmabuf.modifier);
|
||||
wlr_log(WLR_DEBUG, "Allocated %dx%d GBM buffer "
|
||||
|
|
|
|||
149
render/color.c
149
render/color.c
|
|
@ -29,13 +29,15 @@ void wlr_color_transform_init(struct wlr_color_transform *tr, enum wlr_color_tra
|
|||
wlr_addon_set_init(&tr->addons);
|
||||
}
|
||||
|
||||
struct wlr_color_transform *wlr_color_transform_init_srgb(void) {
|
||||
struct wlr_color_transform *tx = calloc(1, sizeof(*tx));
|
||||
struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
|
||||
enum wlr_color_transfer_function tf) {
|
||||
struct wlr_color_transform_inverse_eotf *tx = calloc(1, sizeof(*tx));
|
||||
if (!tx) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_color_transform_init(tx, COLOR_TRANSFORM_SRGB);
|
||||
return tx;
|
||||
wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_INVERSE_EOTF);
|
||||
tx->tf = tf;
|
||||
return &tx->base;
|
||||
}
|
||||
|
||||
struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
|
||||
|
|
@ -60,9 +62,36 @@ struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
|
|||
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) {
|
||||
switch (tr->type) {
|
||||
case COLOR_TRANSFORM_SRGB:
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||
break;
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
color_transform_lcms2_finish(color_transform_lcms2_from_base(tr));
|
||||
|
|
@ -71,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);
|
||||
free(lut_3x1d->lut_3x1d);
|
||||
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);
|
||||
free(tr);
|
||||
|
|
@ -92,6 +129,13 @@ void wlr_color_transform_unref(struct wlr_color_transform *tr) {
|
|||
}
|
||||
}
|
||||
|
||||
struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_base(
|
||||
struct wlr_color_transform *tr) {
|
||||
assert(tr->type == COLOR_TRANSFORM_INVERSE_EOTF);
|
||||
struct wlr_color_transform_inverse_eotf *inverse_eotf = wl_container_of(tr, inverse_eotf, base);
|
||||
return inverse_eotf;
|
||||
}
|
||||
|
||||
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
||||
struct wlr_color_transform *tr) {
|
||||
assert(tr->type == COLOR_TRANSFORM_LUT_3X1D);
|
||||
|
|
@ -99,8 +143,67 @@ struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
|||
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) {
|
||||
if (i > len) {
|
||||
if (i >= len) {
|
||||
i = len - 1;
|
||||
}
|
||||
return (float) lut[i] / UINT16_MAX;
|
||||
|
|
@ -116,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;
|
||||
}
|
||||
|
||||
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]) {
|
||||
for (size_t i = 0; i < 3; 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,
|
||||
enum wlr_color_named_primaries named) {
|
||||
switch (named) {
|
||||
|
|
@ -193,6 +321,13 @@ void wlr_color_transfer_function_get_default_luminance(enum wlr_color_transfer_f
|
|||
.reference = 203,
|
||||
};
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
*lum = (struct wlr_color_luminances){
|
||||
.min = 0.01,
|
||||
.max = 100,
|
||||
.reference = 100,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
*lum = (struct wlr_color_luminances){
|
||||
.min = 0.2,
|
||||
|
|
|
|||
20
render/egl.c
20
render/egl.c
|
|
@ -260,7 +260,8 @@ static struct wlr_egl *egl_create(void) {
|
|||
return egl;
|
||||
}
|
||||
|
||||
static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display) {
|
||||
static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display,
|
||||
bool allow_software) {
|
||||
egl->display = display;
|
||||
|
||||
EGLint major, minor;
|
||||
|
|
@ -326,9 +327,8 @@ static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display) {
|
|||
|
||||
// The only way a non-DRM device is selected is when the user
|
||||
// explicitly picks software rendering
|
||||
if (check_egl_ext(device_exts_str, "EGL_MESA_device_software") &&
|
||||
egl->exts.EXT_device_drm) {
|
||||
if (env_parse_bool("WLR_RENDERER_ALLOW_SOFTWARE")) {
|
||||
if (check_egl_ext(device_exts_str, "EGL_MESA_device_software")) {
|
||||
if (allow_software || env_parse_bool("WLR_RENDERER_ALLOW_SOFTWARE")) {
|
||||
wlr_log(WLR_INFO, "Using software rendering");
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Software rendering detected, please use "
|
||||
|
|
@ -382,7 +382,7 @@ static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display) {
|
|||
}
|
||||
|
||||
static bool egl_init(struct wlr_egl *egl, EGLenum platform,
|
||||
void *remote_display) {
|
||||
void *remote_display, bool allow_software) {
|
||||
EGLint display_attribs[3] = {0};
|
||||
size_t display_attribs_len = 0;
|
||||
|
||||
|
|
@ -401,7 +401,7 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!egl_init_display(egl, display)) {
|
||||
if (!egl_init_display(egl, display, allow_software)) {
|
||||
if (egl->exts.KHR_display_reference) {
|
||||
eglTerminate(display);
|
||||
}
|
||||
|
|
@ -556,6 +556,8 @@ static int open_render_node(int drm_fd) {
|
|||
}
|
||||
|
||||
struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
|
||||
bool allow_software = drm_fd < 0;
|
||||
|
||||
struct wlr_egl *egl = egl_create();
|
||||
if (egl == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to create EGL context");
|
||||
|
|
@ -569,7 +571,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
|
|||
*/
|
||||
EGLDeviceEXT egl_device = get_egl_device_from_drm_fd(egl, drm_fd);
|
||||
if (egl_device != EGL_NO_DEVICE_EXT) {
|
||||
if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) {
|
||||
if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device, allow_software)) {
|
||||
wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_DEVICE_EXT");
|
||||
return egl;
|
||||
}
|
||||
|
|
@ -594,7 +596,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (egl_init(egl, EGL_PLATFORM_GBM_KHR, egl->gbm_device)) {
|
||||
if (egl_init(egl, EGL_PLATFORM_GBM_KHR, egl->gbm_device, allow_software)) {
|
||||
wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_GBM_KHR");
|
||||
return egl;
|
||||
}
|
||||
|
|
@ -633,7 +635,7 @@ struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!egl_init_display(egl, display)) {
|
||||
if (!egl_init_display(egl, display, true)) {
|
||||
free(egl);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,28 +57,33 @@ static void convert_pixman_box_to_vk_rect(const pixman_box32_t *box, VkRect2D *r
|
|||
}
|
||||
|
||||
static float color_to_linear(float non_linear) {
|
||||
// See https://www.w3.org/Graphics/Color/srgb
|
||||
return (non_linear > 0.04045) ?
|
||||
pow((non_linear + 0.055) / 1.055, 2.4) :
|
||||
non_linear / 12.92;
|
||||
return pow(non_linear, 2.2);
|
||||
}
|
||||
|
||||
static float color_to_linear_premult(float non_linear, float alpha) {
|
||||
return (alpha == 0) ? 0 : color_to_linear(non_linear / alpha) * alpha;
|
||||
}
|
||||
|
||||
static void mat3_to_mat4(const float mat3[9], float mat4[4][4]) {
|
||||
memset(mat4, 0, sizeof(float) * 16);
|
||||
mat4[0][0] = mat3[0];
|
||||
mat4[0][1] = mat3[1];
|
||||
mat4[0][3] = mat3[2];
|
||||
static void encode_proj_matrix(const float mat3[9], float mat4[4][4]) {
|
||||
float result[4][4] = {
|
||||
{ mat3[0], mat3[1], 0, mat3[2] },
|
||||
{ mat3[3], mat3[4], 0, mat3[5] },
|
||||
{ 0, 0, 1, 0 },
|
||||
{ 0, 0, 0, 1 },
|
||||
};
|
||||
|
||||
mat4[1][0] = mat3[3];
|
||||
mat4[1][1] = mat3[4];
|
||||
mat4[1][3] = mat3[5];
|
||||
memcpy(mat4, result, sizeof(result));
|
||||
}
|
||||
|
||||
mat4[2][2] = 1.f;
|
||||
mat4[3][3] = 1.f;
|
||||
static void encode_color_matrix(const float mat3[9], float mat4[4][4]) {
|
||||
float result[4][4] = {
|
||||
{ mat3[0], mat3[1], mat3[2], 0 },
|
||||
{ mat3[3], mat3[4], mat3[5], 0 },
|
||||
{ mat3[6], mat3[7], mat3[8], 0 },
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
memcpy(mat4, result, sizeof(result));
|
||||
}
|
||||
|
||||
static void render_pass_destroy(struct wlr_vk_render_pass *pass) {
|
||||
|
|
@ -141,6 +146,11 @@ static VkSemaphore render_pass_wait_sync_file(struct wlr_vk_render_pass *pass,
|
|||
return *sem_ptr;
|
||||
}
|
||||
|
||||
static float get_luminance_multiplier(const struct wlr_color_luminances *src_lum,
|
||||
const struct wlr_color_luminances *dst_lum) {
|
||||
return (dst_lum->reference / src_lum->reference) * (src_lum->max / dst_lum->max);
|
||||
}
|
||||
|
||||
static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
||||
struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass);
|
||||
struct wlr_vk_renderer *renderer = pass->renderer;
|
||||
|
|
@ -162,7 +172,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
assert(stage_cb != NULL);
|
||||
renderer->stage.cb = NULL;
|
||||
|
||||
if (!pass->srgb_pathway) {
|
||||
if (pass->two_pass) {
|
||||
// Apply output shader to map blend image to actual output image
|
||||
vkCmdNextSubpass(render_cb->vk, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
|
|
@ -178,26 +188,76 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
.uv_off = { 0, 0 },
|
||||
.uv_size = { 1, 1 },
|
||||
};
|
||||
encode_proj_matrix(final_matrix, vert_pcr_data.mat4);
|
||||
|
||||
struct wlr_vk_color_transform *transform = NULL;
|
||||
size_t dim = 1;
|
||||
if (pass->color_transform && pass->color_transform->type != COLOR_TRANSFORM_SRGB) {
|
||||
if (pass->color_transform && pass->color_transform->type != COLOR_TRANSFORM_INVERSE_EOTF) {
|
||||
transform = get_color_transform(pass->color_transform, renderer);
|
||||
assert(transform);
|
||||
dim = transform->lut_3d.dim;
|
||||
}
|
||||
|
||||
struct wlr_vk_frag_output_pcr_data frag_pcr_data = {
|
||||
.luminance_multiplier = 1,
|
||||
.lut_3d_offset = 0.5f / dim,
|
||||
.lut_3d_scale = (float)(dim - 1) / dim,
|
||||
};
|
||||
mat3_to_mat4(final_matrix, vert_pcr_data.mat4);
|
||||
|
||||
if (pass->color_transform) {
|
||||
bind_pipeline(pass, render_buffer->plain.render_setup->output_pipe_lut3d);
|
||||
float matrix[9];
|
||||
if (pass->has_primaries) {
|
||||
struct wlr_color_primaries srgb;
|
||||
wlr_color_primaries_from_named(&srgb, WLR_COLOR_NAMED_PRIMARIES_SRGB);
|
||||
|
||||
float srgb_to_xyz[9];
|
||||
wlr_color_primaries_to_xyz(&srgb, srgb_to_xyz);
|
||||
float dst_primaries_to_xyz[9];
|
||||
wlr_color_primaries_to_xyz(&pass->primaries, dst_primaries_to_xyz);
|
||||
float xyz_to_dst_primaries[9];
|
||||
matrix_invert(xyz_to_dst_primaries, dst_primaries_to_xyz);
|
||||
|
||||
wlr_matrix_multiply(matrix, xyz_to_dst_primaries, srgb_to_xyz);
|
||||
} else {
|
||||
bind_pipeline(pass, render_buffer->plain.render_setup->output_pipe_srgb);
|
||||
wlr_matrix_identity(matrix);
|
||||
}
|
||||
encode_color_matrix(matrix, frag_pcr_data.matrix);
|
||||
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
if (pass->color_transform && pass->color_transform->type != COLOR_TRANSFORM_INVERSE_EOTF) {
|
||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_lut3d;
|
||||
} else {
|
||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
if (pass->color_transform && pass->color_transform->type == COLOR_TRANSFORM_INVERSE_EOTF) {
|
||||
struct wlr_color_transform_inverse_eotf *inverse_eotf =
|
||||
wlr_color_transform_inverse_eotf_from_base(pass->color_transform);
|
||||
tf = inverse_eotf->tf;
|
||||
}
|
||||
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_identity;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_srgb;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
pipeline = render_buffer->two_pass.render_setup->output_pipe_pq;
|
||||
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;
|
||||
wlr_color_transfer_function_get_default_luminance(
|
||||
WLR_COLOR_TRANSFER_FUNCTION_SRGB, &srgb_lum);
|
||||
wlr_color_transfer_function_get_default_luminance(tf, &dst_lum);
|
||||
frag_pcr_data.luminance_multiplier = get_luminance_multiplier(&srgb_lum, &dst_lum);
|
||||
}
|
||||
bind_pipeline(pass, pipeline);
|
||||
vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout,
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
|
||||
vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout,
|
||||
|
|
@ -211,7 +271,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
lut_ds = renderer->output_ds_lut3d_dummy;
|
||||
}
|
||||
VkDescriptorSet ds[] = {
|
||||
render_buffer->plain.blend_descriptor_set, // set 0
|
||||
render_buffer->two_pass.blend_descriptor_set, // set 0
|
||||
lut_ds, // set 1
|
||||
};
|
||||
size_t ds_len = sizeof(ds) / sizeof(ds[0]);
|
||||
|
|
@ -341,30 +401,26 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
|
||||
// also add acquire/release barriers for the current render buffer
|
||||
VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
if (pass->srgb_pathway) {
|
||||
if (!render_buffer->srgb.transitioned) {
|
||||
src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
render_buffer->srgb.transitioned = true;
|
||||
}
|
||||
} else {
|
||||
if (!render_buffer->plain.transitioned) {
|
||||
src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
render_buffer->plain.transitioned = true;
|
||||
}
|
||||
if (!pass->render_buffer_out->transitioned) {
|
||||
src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
pass->render_buffer_out->transitioned = true;
|
||||
}
|
||||
|
||||
if (pass->two_pass) {
|
||||
// The render pass changes the blend image layout from
|
||||
// color attachment to read only, so on each frame, before
|
||||
// the render pass starts, we change it back
|
||||
VkImageLayout blend_src_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
if (!render_buffer->plain.blend_transitioned) {
|
||||
if (!render_buffer->two_pass.blend_transitioned) {
|
||||
blend_src_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
render_buffer->plain.blend_transitioned = true;
|
||||
render_buffer->two_pass.blend_transitioned = true;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier blend_acq_barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = render_buffer->plain.blend_image,
|
||||
.image = render_buffer->two_pass.blend_image,
|
||||
.oldLayout = blend_src_layout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
|
|
@ -561,7 +617,7 @@ error:
|
|||
|
||||
static void render_pass_mark_box_updated(struct wlr_vk_render_pass *pass,
|
||||
const struct wlr_box *box) {
|
||||
if (pass->srgb_pathway) {
|
||||
if (!pass->two_pass) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -621,11 +677,8 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
|
|||
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, proj);
|
||||
wlr_matrix_multiply(matrix, pass->projection, matrix);
|
||||
|
||||
struct wlr_vk_render_format_setup *setup = pass->srgb_pathway ?
|
||||
pass->render_buffer->srgb.render_setup :
|
||||
pass->render_buffer->plain.render_setup;
|
||||
struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline(
|
||||
setup,
|
||||
pass->render_setup,
|
||||
&(struct wlr_vk_pipeline_key) {
|
||||
.source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR,
|
||||
.layout = { .ycbcr_format = NULL },
|
||||
|
|
@ -639,7 +692,7 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
|
|||
.uv_off = { 0, 0 },
|
||||
.uv_size = { 1, 1 },
|
||||
};
|
||||
mat3_to_mat4(matrix, vert_pcr_data.mat4);
|
||||
encode_proj_matrix(matrix, vert_pcr_data.mat4);
|
||||
|
||||
bind_pipeline(pass, pipe->vk);
|
||||
vkCmdPushConstants(cb, pipe->layout->vk,
|
||||
|
|
@ -722,20 +775,47 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
|||
src_box.height / options->texture->height,
|
||||
},
|
||||
};
|
||||
mat3_to_mat4(matrix, vert_pcr_data.mat4);
|
||||
encode_proj_matrix(matrix, vert_pcr_data.mat4);
|
||||
|
||||
enum wlr_color_transfer_function tf = options->transfer_function;
|
||||
if (tf == 0) {
|
||||
tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
}
|
||||
|
||||
bool srgb_image_view = false;
|
||||
enum wlr_vk_texture_transform tex_transform = 0;
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
if (texture->using_mutable_srgb) {
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY;
|
||||
srgb_image_view = true;
|
||||
} else {
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_SRGB;
|
||||
}
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
tex_transform = WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ;
|
||||
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_render_format_setup *setup = pass->srgb_pathway ?
|
||||
pass->render_buffer->srgb.render_setup :
|
||||
pass->render_buffer->plain.render_setup;
|
||||
struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline(
|
||||
setup,
|
||||
pass->render_setup,
|
||||
&(struct wlr_vk_pipeline_key) {
|
||||
.source = WLR_VK_SHADER_SOURCE_TEXTURE,
|
||||
.layout = {
|
||||
.ycbcr_format = texture->format->is_ycbcr ? texture->format : NULL,
|
||||
.filter_mode = options->filter_mode,
|
||||
},
|
||||
.texture_transform = texture->transform,
|
||||
.texture_transform = tex_transform,
|
||||
.blend_mode = !texture->has_alpha && alpha == 1.0 ?
|
||||
WLR_RENDER_BLEND_MODE_NONE : options->blend_mode,
|
||||
});
|
||||
|
|
@ -745,12 +825,45 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
|||
}
|
||||
|
||||
struct wlr_vk_texture_view *view =
|
||||
vulkan_texture_get_or_create_view(texture, pipe->layout);
|
||||
vulkan_texture_get_or_create_view(texture, pipe->layout, srgb_image_view);
|
||||
if (!view) {
|
||||
pass->failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
float color_matrix[9];
|
||||
if (options->primaries != NULL) {
|
||||
struct wlr_color_primaries srgb;
|
||||
wlr_color_primaries_from_named(&srgb, WLR_COLOR_NAMED_PRIMARIES_SRGB);
|
||||
|
||||
float src_primaries_to_xyz[9];
|
||||
wlr_color_primaries_to_xyz(options->primaries, src_primaries_to_xyz);
|
||||
float srgb_to_xyz[9];
|
||||
wlr_color_primaries_to_xyz(&srgb, srgb_to_xyz);
|
||||
float xyz_to_srgb[9];
|
||||
matrix_invert(xyz_to_srgb, srgb_to_xyz);
|
||||
|
||||
wlr_matrix_multiply(color_matrix, xyz_to_srgb, src_primaries_to_xyz);
|
||||
} else {
|
||||
wlr_matrix_identity(color_matrix);
|
||||
}
|
||||
|
||||
float luminance_multiplier = 1;
|
||||
if (tf != WLR_COLOR_TRANSFER_FUNCTION_SRGB
|
||||
&& tf != WLR_COLOR_TRANSFER_FUNCTION_GAMMA22) {
|
||||
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(
|
||||
WLR_COLOR_TRANSFER_FUNCTION_SRGB, &srgb_lum);
|
||||
luminance_multiplier = get_luminance_multiplier(&src_lum, &srgb_lum);
|
||||
}
|
||||
|
||||
struct wlr_vk_frag_texture_pcr_data frag_pcr_data = {
|
||||
.alpha = alpha,
|
||||
.luminance_multiplier = luminance_multiplier,
|
||||
};
|
||||
encode_color_matrix(color_matrix, frag_pcr_data.matrix);
|
||||
|
||||
bind_pipeline(pass, pipe->vk);
|
||||
|
||||
vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
|
|
@ -759,8 +872,8 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
|
|||
vkCmdPushConstants(cb, pipe->layout->vk,
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
|
||||
vkCmdPushConstants(cb, pipe->layout->vk,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float),
|
||||
&alpha);
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data),
|
||||
sizeof(frag_pcr_data), &frag_pcr_data);
|
||||
|
||||
pixman_region32_t clip;
|
||||
get_clip_region(pass, options->clip, &clip);
|
||||
|
|
@ -851,19 +964,6 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
*ds = VK_NULL_HANDLE;
|
||||
*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_SRGB:
|
||||
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
|
||||
// TODO: use it when available
|
||||
VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
|
|
@ -961,11 +1061,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
b_index * sample_range,
|
||||
};
|
||||
float rgb_out[3];
|
||||
if (tr_lcms2 != NULL) {
|
||||
color_transform_lcms2_eval(tr_lcms2, rgb_out, rgb_in);
|
||||
} else {
|
||||
color_transform_lut_3x1d_eval(tr_lut_3x1d, rgb_out, rgb_in);
|
||||
}
|
||||
wlr_color_transform_eval(tr, rgb_out, rgb_in);
|
||||
|
||||
dst[dst_offset] = rgb_out[0];
|
||||
dst[dst_offset + 1] = rgb_out[1];
|
||||
|
|
@ -1035,7 +1131,7 @@ static struct wlr_vk_color_transform *vk_color_transform_create(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (transform->type != COLOR_TRANSFORM_SRGB) {
|
||||
if (transform->type != COLOR_TRANSFORM_INVERSE_EOTF) {
|
||||
vk_transform->lut_3d.dim = 33;
|
||||
if (!create_3d_lut_image(renderer, transform,
|
||||
vk_transform->lut_3d.dim,
|
||||
|
|
@ -1064,29 +1160,68 @@ static const struct wlr_addon_interface vk_color_transform_impl = {
|
|||
|
||||
struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *renderer,
|
||||
struct wlr_vk_render_buffer *buffer, const struct wlr_buffer_pass_options *options) {
|
||||
bool using_srgb_pathway;
|
||||
uint32_t inv_eotf;
|
||||
if (options != NULL && options->color_transform != NULL) {
|
||||
using_srgb_pathway = false;
|
||||
if (options->color_transform->type == COLOR_TRANSFORM_INVERSE_EOTF) {
|
||||
struct wlr_color_transform_inverse_eotf *tr =
|
||||
wlr_color_transform_inverse_eotf_from_base(options->color_transform);
|
||||
inv_eotf = tr->tf;
|
||||
} else {
|
||||
// Color transform is not an inverse EOTF
|
||||
inv_eotf = 0;
|
||||
}
|
||||
} else {
|
||||
// This is the default when unspecified
|
||||
inv_eotf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
}
|
||||
|
||||
if (!get_color_transform(options->color_transform, renderer)) {
|
||||
bool using_linear_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
bool using_srgb_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_SRGB &&
|
||||
buffer->srgb.out.framebuffer != VK_NULL_HANDLE;
|
||||
bool using_two_pass_pathway = !using_linear_pathway && !using_srgb_pathway;
|
||||
|
||||
if (using_linear_pathway && !buffer->linear.out.image_view) {
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs);
|
||||
if (!vulkan_setup_one_pass_framebuffer(buffer, &attribs, false)) {
|
||||
wlr_log(WLR_ERROR, "Failed to set up blend image");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (using_two_pass_pathway) {
|
||||
if (options != NULL && options->color_transform != NULL &&
|
||||
!get_color_transform(options->color_transform, renderer)) {
|
||||
/* Try to create a new color transform */
|
||||
if (!vk_color_transform_create(renderer, options->color_transform)) {
|
||||
wlr_log(WLR_ERROR, "Failed to create color transform");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Use srgb pathway if it is the default/has already been set up
|
||||
using_srgb_pathway = buffer->srgb.framebuffer != VK_NULL_HANDLE;
|
||||
|
||||
if (!buffer->two_pass.out.image_view) {
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs);
|
||||
if (!vulkan_setup_two_pass_framebuffer(buffer, &attribs)) {
|
||||
wlr_log(WLR_ERROR, "Failed to set up blend image");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!using_srgb_pathway && !buffer->plain.image_view) {
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs);
|
||||
if (!vulkan_setup_plain_framebuffer(buffer, &attribs)) {
|
||||
wlr_log(WLR_ERROR, "Failed to set up blend image");
|
||||
return NULL;
|
||||
}
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
struct wlr_vk_render_buffer_out *buffer_out;
|
||||
if (using_two_pass_pathway) {
|
||||
render_setup = buffer->two_pass.render_setup;
|
||||
buffer_out = &buffer->two_pass.out;
|
||||
} else if (using_srgb_pathway) {
|
||||
render_setup = buffer->srgb.render_setup;
|
||||
buffer_out = &buffer->srgb.out;
|
||||
} else if (using_linear_pathway) {
|
||||
render_setup = buffer->linear.render_setup;
|
||||
buffer_out = &buffer->linear.out;
|
||||
} else {
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
struct wlr_vk_render_pass *pass = calloc(1, sizeof(*pass));
|
||||
|
|
@ -1096,7 +1231,7 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
|
|||
|
||||
wlr_render_pass_init(&pass->base, &render_pass_impl);
|
||||
pass->renderer = renderer;
|
||||
pass->srgb_pathway = using_srgb_pathway;
|
||||
pass->two_pass = using_two_pass_pathway;
|
||||
if (options != NULL && options->color_transform != NULL) {
|
||||
pass->color_transform = wlr_color_transform_ref(options->color_transform);
|
||||
}
|
||||
|
|
@ -1104,6 +1239,10 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
|
|||
pass->signal_timeline = wlr_drm_syncobj_timeline_ref(options->signal_timeline);
|
||||
pass->signal_point = options->signal_point;
|
||||
}
|
||||
if (options != NULL && options->primaries != NULL) {
|
||||
pass->has_primaries = true;
|
||||
pass->primaries = *options->primaries;
|
||||
}
|
||||
|
||||
rect_union_init(&pass->updated_region);
|
||||
|
||||
|
|
@ -1140,14 +1279,9 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
|
|||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
.renderArea = rect,
|
||||
.clearValueCount = 0,
|
||||
.renderPass = render_setup->render_pass,
|
||||
.framebuffer = buffer_out->framebuffer,
|
||||
};
|
||||
if (pass->srgb_pathway) {
|
||||
rp_info.renderPass = buffer->srgb.render_setup->render_pass;
|
||||
rp_info.framebuffer = buffer->srgb.framebuffer;
|
||||
} else {
|
||||
rp_info.renderPass = buffer->plain.render_setup->render_pass;
|
||||
rp_info.framebuffer = buffer->plain.framebuffer;
|
||||
}
|
||||
vkCmdBeginRenderPass(cb->vk, &rp_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vkCmdSetViewport(cb->vk, 0, 1, &(VkViewport){
|
||||
|
|
@ -1162,6 +1296,8 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
|
|||
|
||||
wlr_buffer_lock(buffer->wlr_buffer);
|
||||
pass->render_buffer = buffer;
|
||||
pass->render_buffer_out = buffer_out;
|
||||
pass->render_setup = render_setup;
|
||||
pass->command_buffer = cb;
|
||||
return pass;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,59 +66,72 @@ static struct wlr_vk_descriptor_pool *alloc_ds(
|
|||
struct wl_list *pool_list, size_t *last_pool_size) {
|
||||
VkResult res;
|
||||
|
||||
bool found = false;
|
||||
struct wlr_vk_descriptor_pool *pool;
|
||||
wl_list_for_each(pool, pool_list, link) {
|
||||
if (pool->free > 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) { // create new pool
|
||||
pool = calloc(1, sizeof(*pool));
|
||||
if (!pool) {
|
||||
wlr_log_errno(WLR_ERROR, "allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t count = 2 * (*last_pool_size);
|
||||
if (!count) {
|
||||
count = start_descriptor_pool_size;
|
||||
}
|
||||
|
||||
pool->free = count;
|
||||
VkDescriptorPoolSize pool_size = {
|
||||
.descriptorCount = count,
|
||||
.type = type,
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo dpool_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.maxSets = count,
|
||||
.poolSizeCount = 1,
|
||||
.pPoolSizes = &pool_size,
|
||||
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
||||
};
|
||||
|
||||
res = vkCreateDescriptorPool(renderer->dev->dev, &dpool_info, NULL,
|
||||
&pool->pool);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateDescriptorPool", res);
|
||||
free(pool);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*last_pool_size = count;
|
||||
wl_list_insert(pool_list, &pool->link);
|
||||
}
|
||||
|
||||
VkDescriptorSetAllocateInfo ds_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = layout,
|
||||
.descriptorPool = pool->pool,
|
||||
};
|
||||
|
||||
struct wlr_vk_descriptor_pool *pool;
|
||||
wl_list_for_each(pool, pool_list, link) {
|
||||
if (pool->free > 0) {
|
||||
ds_info.descriptorPool = pool->pool;
|
||||
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
|
||||
switch (res) {
|
||||
case VK_ERROR_FRAGMENTED_POOL:
|
||||
case VK_ERROR_OUT_OF_POOL_MEMORY:
|
||||
// Descriptor sets with more than one descriptor can cause us
|
||||
// to run out of pool memory early or lead to fragmentation
|
||||
// that makes the pool unable to service our allocation
|
||||
// request. Try the next pool or allocate a new one.
|
||||
continue;
|
||||
case VK_SUCCESS:
|
||||
--pool->free;
|
||||
return pool;
|
||||
default:
|
||||
wlr_vk_error("vkAllocateDescriptorSets", res);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pool = calloc(1, sizeof(*pool));
|
||||
if (!pool) {
|
||||
wlr_log_errno(WLR_ERROR, "allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t count = 2 * (*last_pool_size);
|
||||
if (!count) {
|
||||
count = start_descriptor_pool_size;
|
||||
}
|
||||
|
||||
pool->free = count;
|
||||
VkDescriptorPoolSize pool_size = {
|
||||
.descriptorCount = count,
|
||||
.type = type,
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo dpool_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.maxSets = count,
|
||||
.poolSizeCount = 1,
|
||||
.pPoolSizes = &pool_size,
|
||||
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
||||
};
|
||||
|
||||
res = vkCreateDescriptorPool(renderer->dev->dev, &dpool_info, NULL,
|
||||
&pool->pool);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateDescriptorPool", res);
|
||||
free(pool);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*last_pool_size = count;
|
||||
wl_list_insert(pool_list, &pool->link);
|
||||
|
||||
ds_info.descriptorPool = pool->pool;
|
||||
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkAllocateDescriptorSets", res);
|
||||
|
|
@ -158,8 +171,12 @@ static void destroy_render_format_setup(struct wlr_vk_renderer *renderer,
|
|||
|
||||
VkDevice dev = renderer->dev->dev;
|
||||
vkDestroyRenderPass(dev, setup->render_pass, NULL);
|
||||
vkDestroyPipeline(dev, setup->output_pipe_identity, NULL);
|
||||
vkDestroyPipeline(dev, setup->output_pipe_srgb, NULL);
|
||||
vkDestroyPipeline(dev, setup->output_pipe_pq, 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;
|
||||
wl_list_for_each_safe(pipeline, tmp_pipeline, &setup->pipelines, link) {
|
||||
|
|
@ -589,6 +606,12 @@ void vulkan_reset_command_buffer(struct wlr_vk_command_buffer *cb) {
|
|||
}
|
||||
}
|
||||
|
||||
static void finish_render_buffer_out(struct wlr_vk_render_buffer_out *out,
|
||||
VkDevice dev) {
|
||||
vkDestroyFramebuffer(dev, out->framebuffer, NULL);
|
||||
vkDestroyImageView(dev, out->image_view, NULL);
|
||||
}
|
||||
|
||||
static void destroy_render_buffer(struct wlr_vk_render_buffer *buffer) {
|
||||
wl_list_remove(&buffer->link);
|
||||
wlr_addon_finish(&buffer->addon);
|
||||
|
|
@ -602,17 +625,16 @@ static void destroy_render_buffer(struct wlr_vk_render_buffer *buffer) {
|
|||
wlr_vk_error("vkQueueWaitIdle", res);
|
||||
}
|
||||
|
||||
vkDestroyFramebuffer(dev, buffer->srgb.framebuffer, NULL);
|
||||
vkDestroyImageView(dev, buffer->srgb.image_view, NULL);
|
||||
finish_render_buffer_out(&buffer->linear.out, dev);
|
||||
finish_render_buffer_out(&buffer->srgb.out, dev);
|
||||
|
||||
vkDestroyFramebuffer(dev, buffer->plain.framebuffer, NULL);
|
||||
vkDestroyImageView(dev, buffer->plain.image_view, NULL);
|
||||
vkDestroyImage(dev, buffer->plain.blend_image, NULL);
|
||||
vkFreeMemory(dev, buffer->plain.blend_memory, NULL);
|
||||
vkDestroyImageView(dev, buffer->plain.blend_image_view, NULL);
|
||||
if (buffer->plain.blend_attachment_pool) {
|
||||
vulkan_free_ds(buffer->renderer, buffer->plain.blend_attachment_pool,
|
||||
buffer->plain.blend_descriptor_set);
|
||||
finish_render_buffer_out(&buffer->two_pass.out, dev);
|
||||
vkDestroyImage(dev, buffer->two_pass.blend_image, NULL);
|
||||
vkFreeMemory(dev, buffer->two_pass.blend_memory, NULL);
|
||||
vkDestroyImageView(dev, buffer->two_pass.blend_image_view, NULL);
|
||||
if (buffer->two_pass.blend_attachment_pool) {
|
||||
vulkan_free_ds(buffer->renderer, buffer->two_pass.blend_attachment_pool,
|
||||
buffer->two_pass.blend_descriptor_set);
|
||||
}
|
||||
|
||||
vkDestroyImage(dev, buffer->image, NULL);
|
||||
|
|
@ -633,7 +655,7 @@ static struct wlr_addon_interface render_buffer_addon_impl = {
|
|||
.destroy = handle_render_buffer_destroy,
|
||||
};
|
||||
|
||||
bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf) {
|
||||
struct wlr_vk_renderer *renderer = buffer->renderer;
|
||||
VkResult res;
|
||||
|
|
@ -661,15 +683,15 @@ bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
},
|
||||
};
|
||||
|
||||
res = vkCreateImageView(dev, &view_info, NULL, &buffer->plain.image_view);
|
||||
res = vkCreateImageView(dev, &view_info, NULL, &buffer->two_pass.out.image_view);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateImageView failed", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
buffer->plain.render_setup = find_or_create_render_setup(
|
||||
buffer->two_pass.render_setup = find_or_create_render_setup(
|
||||
renderer, &fmt->format, true);
|
||||
if (!buffer->plain.render_setup) {
|
||||
if (!buffer->two_pass.render_setup) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
@ -689,14 +711,14 @@ bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
|
||||
};
|
||||
|
||||
res = vkCreateImage(dev, &img_info, NULL, &buffer->plain.blend_image);
|
||||
res = vkCreateImage(dev, &img_info, NULL, &buffer->two_pass.blend_image);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateImage failed", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
VkMemoryRequirements mem_reqs;
|
||||
vkGetImageMemoryRequirements(dev, buffer->plain.blend_image, &mem_reqs);
|
||||
vkGetImageMemoryRequirements(dev, buffer->two_pass.blend_image, &mem_reqs);
|
||||
|
||||
int mem_type_index = vulkan_find_mem_type(renderer->dev,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mem_reqs.memoryTypeBits);
|
||||
|
|
@ -711,13 +733,13 @@ bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
.memoryTypeIndex = mem_type_index,
|
||||
};
|
||||
|
||||
res = vkAllocateMemory(dev, &mem_info, NULL, &buffer->plain.blend_memory);
|
||||
res = vkAllocateMemory(dev, &mem_info, NULL, &buffer->two_pass.blend_memory);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkAllocatorMemory failed", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
res = vkBindImageMemory(dev, buffer->plain.blend_image, buffer->plain.blend_memory, 0);
|
||||
res = vkBindImageMemory(dev, buffer->two_pass.blend_image, buffer->two_pass.blend_memory, 0);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkBindMemory failed", res);
|
||||
goto error;
|
||||
|
|
@ -725,7 +747,7 @@ bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
|
||||
VkImageViewCreateInfo blend_view_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = buffer->plain.blend_image,
|
||||
.image = buffer->two_pass.blend_image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = img_info.format,
|
||||
.components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
|
|
@ -741,50 +763,50 @@ bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
},
|
||||
};
|
||||
|
||||
res = vkCreateImageView(dev, &blend_view_info, NULL, &buffer->plain.blend_image_view);
|
||||
res = vkCreateImageView(dev, &blend_view_info, NULL, &buffer->two_pass.blend_image_view);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateImageView failed", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
buffer->plain.blend_attachment_pool = vulkan_alloc_blend_ds(renderer,
|
||||
&buffer->plain.blend_descriptor_set);
|
||||
if (!buffer->plain.blend_attachment_pool) {
|
||||
buffer->two_pass.blend_attachment_pool = vulkan_alloc_blend_ds(renderer,
|
||||
&buffer->two_pass.blend_descriptor_set);
|
||||
if (!buffer->two_pass.blend_attachment_pool) {
|
||||
wlr_log(WLR_ERROR, "failed to allocate descriptor");
|
||||
goto error;
|
||||
}
|
||||
|
||||
VkDescriptorImageInfo ds_attach_info = {
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.imageView = buffer->plain.blend_image_view,
|
||||
.imageView = buffer->two_pass.blend_image_view,
|
||||
.sampler = VK_NULL_HANDLE,
|
||||
};
|
||||
VkWriteDescriptorSet ds_write = {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
||||
.dstSet = buffer->plain.blend_descriptor_set,
|
||||
.dstSet = buffer->two_pass.blend_descriptor_set,
|
||||
.dstBinding = 0,
|
||||
.pImageInfo = &ds_attach_info,
|
||||
};
|
||||
vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL);
|
||||
|
||||
VkImageView attachments[2] = {
|
||||
buffer->plain.blend_image_view,
|
||||
buffer->plain.image_view
|
||||
VkImageView attachments[] = {
|
||||
buffer->two_pass.blend_image_view,
|
||||
buffer->two_pass.out.image_view,
|
||||
};
|
||||
VkFramebufferCreateInfo fb_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.attachmentCount = 2,
|
||||
.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),
|
||||
.pAttachments = attachments,
|
||||
.flags = 0u,
|
||||
.width = dmabuf->width,
|
||||
.height = dmabuf->height,
|
||||
.layers = 1u,
|
||||
.renderPass = buffer->plain.render_setup->render_pass,
|
||||
.renderPass = buffer->two_pass.render_setup->render_pass,
|
||||
};
|
||||
|
||||
res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->plain.framebuffer);
|
||||
res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->two_pass.out.framebuffer);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateFramebuffer", res);
|
||||
goto error;
|
||||
|
|
@ -798,8 +820,8 @@ error:
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool vulkan_setup_srgb_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf) {
|
||||
bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf, bool srgb) {
|
||||
struct wlr_vk_renderer *renderer = buffer->renderer;
|
||||
VkResult res;
|
||||
VkDevice dev = renderer->dev->dev;
|
||||
|
|
@ -808,14 +830,18 @@ static bool vulkan_setup_srgb_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
renderer->dev, dmabuf->format);
|
||||
assert(fmt);
|
||||
|
||||
assert(fmt->format.vk_srgb);
|
||||
// Set up the srgb framebuffer by default; plain framebuffer and
|
||||
VkFormat vk_fmt = srgb ? fmt->format.vk_srgb : fmt->format.vk;
|
||||
assert(vk_fmt != VK_FORMAT_UNDEFINED);
|
||||
|
||||
struct wlr_vk_render_buffer_out *out = srgb ? &buffer->srgb.out : &buffer->linear.out;
|
||||
|
||||
// Set up the srgb framebuffer by default; two-pass framebuffer and
|
||||
// blending image will be set up later if necessary
|
||||
VkImageViewCreateInfo view_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = buffer->image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = fmt->format.vk_srgb,
|
||||
.format = vk_fmt,
|
||||
.components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.components.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.components.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
|
|
@ -829,35 +855,43 @@ static bool vulkan_setup_srgb_framebuffer(struct wlr_vk_render_buffer *buffer,
|
|||
},
|
||||
};
|
||||
|
||||
res = vkCreateImageView(dev, &view_info, NULL, &buffer->srgb.image_view);
|
||||
res = vkCreateImageView(dev, &view_info, NULL, &out->image_view);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateImageView failed", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
buffer->srgb.render_setup = find_or_create_render_setup(
|
||||
renderer, &fmt->format, false);
|
||||
if (!buffer->srgb.render_setup) {
|
||||
struct wlr_vk_render_format_setup *render_setup =
|
||||
find_or_create_render_setup(renderer, &fmt->format, false);
|
||||
if (!render_setup) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo fb_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &buffer->srgb.image_view,
|
||||
.pAttachments = &out->image_view,
|
||||
.flags = 0u,
|
||||
.width = dmabuf->width,
|
||||
.height = dmabuf->height,
|
||||
.layers = 1u,
|
||||
.renderPass = buffer->srgb.render_setup->render_pass,
|
||||
.renderPass = render_setup->render_pass,
|
||||
};
|
||||
|
||||
res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->srgb.framebuffer);
|
||||
res = vkCreateFramebuffer(dev, &fb_info, NULL, &out->framebuffer);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateFramebuffer", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (srgb) {
|
||||
buffer->srgb.render_setup = render_setup;
|
||||
} else {
|
||||
buffer->linear.render_setup = render_setup;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
// cleaning up everything is the caller's responsibility,
|
||||
// since it will need to do this anyway if framebuffer setup fails
|
||||
|
|
@ -901,12 +935,12 @@ static struct wlr_vk_render_buffer *create_render_buffer(
|
|||
}
|
||||
|
||||
if (using_mutable_srgb) {
|
||||
if (!vulkan_setup_srgb_framebuffer(buffer, &dmabuf)) {
|
||||
if (!vulkan_setup_one_pass_framebuffer(buffer, &dmabuf, true)) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
// Set up the plain framebuffer & blending image
|
||||
if (!vulkan_setup_plain_framebuffer(buffer, &dmabuf)) {
|
||||
// Set up the two-pass framebuffer & blending image
|
||||
if (!vulkan_setup_two_pass_framebuffer(buffer, &dmabuf)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
|
@ -1464,14 +1498,14 @@ static bool init_tex_layouts(struct wlr_vk_renderer *renderer,
|
|||
return false;
|
||||
}
|
||||
|
||||
VkPushConstantRange pc_ranges[2] = {
|
||||
VkPushConstantRange pc_ranges[] = {
|
||||
{
|
||||
.size = sizeof(struct wlr_vk_vert_pcr_data),
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
},
|
||||
{
|
||||
.offset = pc_ranges[0].size,
|
||||
.size = sizeof(float) * 4, // alpha or color
|
||||
.size = sizeof(struct wlr_vk_frag_texture_pcr_data),
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
},
|
||||
};
|
||||
|
|
@ -1480,7 +1514,7 @@ static bool init_tex_layouts(struct wlr_vk_renderer *renderer,
|
|||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = out_ds_layout,
|
||||
.pushConstantRangeCount = 2,
|
||||
.pushConstantRangeCount = sizeof(pc_ranges) / sizeof(pc_ranges[0]),
|
||||
.pPushConstantRanges = pc_ranges,
|
||||
};
|
||||
|
||||
|
|
@ -1558,7 +1592,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
|
|||
}
|
||||
|
||||
// pipeline layout -- standard vertex uniforms, no shader uniforms
|
||||
VkPushConstantRange pc_ranges[2] = {
|
||||
VkPushConstantRange pc_ranges[] = {
|
||||
{
|
||||
.offset = 0,
|
||||
.size = sizeof(struct wlr_vk_vert_pcr_data),
|
||||
|
|
@ -1571,16 +1605,16 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
|
|||
},
|
||||
};
|
||||
|
||||
VkDescriptorSetLayout out_ds_layouts[2] = {
|
||||
VkDescriptorSetLayout out_ds_layouts[] = {
|
||||
renderer->output_ds_srgb_layout,
|
||||
renderer->output_ds_lut3d_layout,
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo pl_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 2,
|
||||
.setLayoutCount = sizeof(out_ds_layouts) / sizeof(out_ds_layouts[0]),
|
||||
.pSetLayouts = out_ds_layouts,
|
||||
.pushConstantRangeCount = 2,
|
||||
.pushConstantRangeCount = sizeof(pc_ranges) / sizeof(pc_ranges[0]),
|
||||
.pPushConstantRanges = pc_ranges,
|
||||
};
|
||||
|
||||
|
|
@ -1753,14 +1787,14 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline(
|
|||
.scissorCount = 1,
|
||||
};
|
||||
|
||||
VkDynamicState dynStates[2] = {
|
||||
VkDynamicState dyn_states[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
};
|
||||
VkPipelineDynamicStateCreateInfo dynamic = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pDynamicStates = dynStates,
|
||||
.dynamicStateCount = 2,
|
||||
.pDynamicStates = dyn_states,
|
||||
.dynamicStateCount = sizeof(dyn_states) / sizeof(dyn_states[0]),
|
||||
};
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertex = {
|
||||
|
|
@ -1772,7 +1806,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline(
|
|||
.layout = pipeline_layout->vk,
|
||||
.renderPass = setup->render_pass,
|
||||
.subpass = 0,
|
||||
.stageCount = 2,
|
||||
.stageCount = sizeof(stages) / sizeof(stages[0]),
|
||||
.pStages = stages,
|
||||
|
||||
.pInputAssemblyState = &assembly,
|
||||
|
|
@ -1815,7 +1849,7 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer,
|
|||
.pData = &output_transform_type,
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo tex_stages[2] = {
|
||||
VkPipelineShaderStageCreateInfo tex_stages[] = {
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
|
|
@ -1870,14 +1904,14 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer,
|
|||
.scissorCount = 1,
|
||||
};
|
||||
|
||||
VkDynamicState dynStates[2] = {
|
||||
VkDynamicState dyn_states[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
};
|
||||
VkPipelineDynamicStateCreateInfo dynamic = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pDynamicStates = dynStates,
|
||||
.dynamicStateCount = 2,
|
||||
.pDynamicStates = dyn_states,
|
||||
.dynamicStateCount = sizeof(dyn_states) / sizeof(dyn_states[0]),
|
||||
};
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertex = {
|
||||
|
|
@ -1890,7 +1924,7 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer,
|
|||
.layout = pipe_layout,
|
||||
.renderPass = rp,
|
||||
.subpass = 1, // second subpass!
|
||||
.stageCount = 2,
|
||||
.stageCount = sizeof(tex_stages) / sizeof(tex_stages[0]),
|
||||
.pStages = tex_stages,
|
||||
.pInputAssemblyState = &assembly,
|
||||
.pRasterizationState = &rasterization,
|
||||
|
|
@ -2183,7 +2217,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
VkResult res;
|
||||
|
||||
if (use_blending_buffer) {
|
||||
VkAttachmentDescription attachments[2] = {
|
||||
VkAttachmentDescription attachments[] = {
|
||||
{
|
||||
.format = VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
|
|
@ -2221,7 +2255,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
|
||||
VkSubpassDescription subpasses[2] = {
|
||||
VkSubpassDescription subpasses[] = {
|
||||
{
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.colorAttachmentCount = 1,
|
||||
|
|
@ -2236,7 +2270,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
}
|
||||
};
|
||||
|
||||
VkSubpassDependency deps[3] = {
|
||||
VkSubpassDependency deps[] = {
|
||||
{
|
||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_HOST_BIT |
|
||||
|
|
@ -2278,11 +2312,11 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.attachmentCount = 2u,
|
||||
.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),
|
||||
.pAttachments = attachments,
|
||||
.subpassCount = 2u,
|
||||
.subpassCount = sizeof(subpasses) / sizeof(subpasses[0]),
|
||||
.pSubpasses = subpasses,
|
||||
.dependencyCount = 3u,
|
||||
.dependencyCount = sizeof(deps) / sizeof(deps[0]),
|
||||
.pDependencies = deps,
|
||||
};
|
||||
|
||||
|
|
@ -2293,14 +2327,34 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
}
|
||||
|
||||
// this is only well defined if render pass has a 2nd subpass
|
||||
if (!init_blend_to_output_pipeline(
|
||||
renderer, setup->render_pass, renderer->output_pipe_layout,
|
||||
&setup->output_pipe_identity, WLR_VK_OUTPUT_TRANSFORM_IDENTITY)) {
|
||||
goto error;
|
||||
}
|
||||
if (!init_blend_to_output_pipeline(
|
||||
renderer, setup->render_pass, renderer->output_pipe_layout,
|
||||
&setup->output_pipe_lut3d, WLR_VK_OUTPUT_TRANSFORM_LUT3D)) {
|
||||
goto error;
|
||||
}
|
||||
if (!init_blend_to_output_pipeline(
|
||||
renderer, setup->render_pass, renderer->output_pipe_layout,
|
||||
&setup->output_pipe_srgb, WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB)) {
|
||||
goto error;
|
||||
}
|
||||
if (!init_blend_to_output_pipeline(
|
||||
renderer, setup->render_pass, renderer->output_pipe_layout,
|
||||
&setup->output_pipe_pq, WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ)) {
|
||||
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_srgb, WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB)) {
|
||||
&setup->output_pipe_bt1886, WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886)) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -2327,7 +2381,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
.pColorAttachments = &color_ref,
|
||||
};
|
||||
|
||||
VkSubpassDependency deps[2] = {
|
||||
VkSubpassDependency deps[] = {
|
||||
{
|
||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_HOST_BIT |
|
||||
|
|
@ -2362,7 +2416,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
.pAttachments = &attachment,
|
||||
.subpassCount = 1,
|
||||
.pSubpasses = &subpass,
|
||||
.dependencyCount = 2u,
|
||||
.dependencyCount = sizeof(deps) / sizeof(deps[0]),
|
||||
.pDependencies = deps,
|
||||
};
|
||||
|
||||
|
|
@ -2430,6 +2484,7 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev
|
|||
|
||||
renderer->dev = dev;
|
||||
wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl, WLR_BUFFER_CAP_DMABUF);
|
||||
renderer->wlr_renderer.features.input_color_transform = true;
|
||||
renderer->wlr_renderer.features.output_color_transform = true;
|
||||
wl_list_init(&renderer->stage.buffers);
|
||||
wl_list_init(&renderer->foreign_textures);
|
||||
|
|
@ -2501,14 +2556,13 @@ struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) {
|
|||
if (!phdev) {
|
||||
// We rather fail here than doing some guesswork
|
||||
wlr_log(WLR_ERROR, "Could not match drm and vulkan device");
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
struct wlr_vk_device *dev = vulkan_device_create(ini, phdev);
|
||||
if (!dev) {
|
||||
wlr_log(WLR_ERROR, "Failed to create vulkan device");
|
||||
vulkan_instance_destroy(ini);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Do not use the drm_fd that was passed in: we should prefer the render
|
||||
|
|
@ -2516,6 +2570,10 @@ struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) {
|
|||
dev->drm_fd = vulkan_open_phdev_drm_fd(phdev);
|
||||
|
||||
return vulkan_renderer_create_for_device(dev);
|
||||
|
||||
error:
|
||||
vulkan_instance_destroy(ini);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VkInstance wlr_vk_renderer_get_instance(struct wlr_renderer *renderer) {
|
||||
|
|
|
|||
|
|
@ -8,16 +8,22 @@ layout(location = 0) in vec2 uv;
|
|||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
/* struct wlr_vk_frag_output_pcr_data */
|
||||
layout(push_constant) uniform UBO {
|
||||
layout(offset = 80) float lut_3d_offset;
|
||||
layout(push_constant, row_major) uniform UBO {
|
||||
layout(offset = 80) mat4 matrix;
|
||||
float luminance_multiplier;
|
||||
float lut_3d_offset;
|
||||
float lut_3d_scale;
|
||||
} data;
|
||||
|
||||
layout (constant_id = 0) const int OUTPUT_TRANSFORM = 0;
|
||||
|
||||
// Matches enum wlr_vk_output_transform
|
||||
#define OUTPUT_TRANSFORM_INVERSE_SRGB 0
|
||||
#define OUTPUT_TRANSFORM_LUT_3D 1
|
||||
#define OUTPUT_TRANSFORM_IDENTITY 0
|
||||
#define OUTPUT_TRANSFORM_INVERSE_SRGB 1
|
||||
#define OUTPUT_TRANSFORM_INVERSE_ST2084_PQ 2
|
||||
#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) {
|
||||
return max(min(x * 12.92, 0.04045), 1.055 * pow(x, 1. / 2.4) - 0.055);
|
||||
|
|
@ -31,6 +37,25 @@ vec3 linear_color_to_srgb(vec3 color) {
|
|||
);
|
||||
}
|
||||
|
||||
vec3 linear_color_to_pq(vec3 color) {
|
||||
// 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;
|
||||
vec3 pow_n = pow(clamp(color, vec3(0), vec3(1)), vec3(n));
|
||||
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() {
|
||||
vec4 in_color = subpassLoad(in_color).rgba;
|
||||
|
||||
|
|
@ -43,13 +68,23 @@ void main() {
|
|||
rgb = in_color.rgb / alpha;
|
||||
}
|
||||
|
||||
rgb *= data.luminance_multiplier;
|
||||
|
||||
rgb = mat3(data.matrix) * rgb;
|
||||
|
||||
if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_LUT_3D) {
|
||||
// Apply 3D LUT
|
||||
vec3 pos = data.lut_3d_offset + rgb * data.lut_3d_scale;
|
||||
rgb = texture(lut_3d, pos).rgb;
|
||||
} else { // OUTPUT_TRANSFORM_INVERSE_SRGB
|
||||
} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_ST2084_PQ) {
|
||||
rgb = linear_color_to_pq(rgb);
|
||||
} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_SRGB) {
|
||||
// Produce sRGB encoded values
|
||||
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
|
||||
|
|
|
|||
|
|
@ -5,8 +5,11 @@ layout(set = 0, binding = 0) uniform sampler2D tex;
|
|||
layout(location = 0) in vec2 uv;
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
layout(push_constant) uniform UBO {
|
||||
layout(offset = 80) float alpha;
|
||||
// struct wlr_vk_frag_texture_pcr_data
|
||||
layout(push_constant, row_major) uniform UBO {
|
||||
layout(offset = 80) mat4 matrix;
|
||||
float alpha;
|
||||
float luminance_multiplier;
|
||||
} data;
|
||||
|
||||
layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0;
|
||||
|
|
@ -14,6 +17,9 @@ layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0;
|
|||
// Matches enum wlr_vk_texture_transform
|
||||
#define TEXTURE_TRANSFORM_IDENTITY 0
|
||||
#define TEXTURE_TRANSFORM_SRGB 1
|
||||
#define TEXTURE_TRANSFORM_ST2084_PQ 2
|
||||
#define TEXTURE_TRANSFORM_GAMMA22 3
|
||||
#define TEXTURE_TRANSFORM_BT1886 4
|
||||
|
||||
float srgb_channel_to_linear(float x) {
|
||||
return mix(x / 12.92,
|
||||
|
|
@ -21,27 +27,61 @@ float srgb_channel_to_linear(float x) {
|
|||
x > 0.04045);
|
||||
}
|
||||
|
||||
vec4 srgb_color_to_linear(vec4 color) {
|
||||
if (color.a == 0) {
|
||||
return vec4(0);
|
||||
}
|
||||
color.rgb /= color.a;
|
||||
color.rgb = vec3(
|
||||
vec3 srgb_color_to_linear(vec3 color) {
|
||||
return vec3(
|
||||
srgb_channel_to_linear(color.r),
|
||||
srgb_channel_to_linear(color.g),
|
||||
srgb_channel_to_linear(color.b)
|
||||
);
|
||||
color.rgb *= color.a;
|
||||
return color;
|
||||
}
|
||||
|
||||
vec3 pq_color_to_linear(vec3 color) {
|
||||
float inv_m1 = 1 / 0.1593017578125;
|
||||
float inv_m2 = 1 / 78.84375;
|
||||
float c1 = 0.8359375;
|
||||
float c2 = 18.8515625;
|
||||
float c3 = 18.6875;
|
||||
vec3 num = max(pow(color, vec3(inv_m2)) - c1, 0);
|
||||
vec3 denom = c2 - c3 * pow(color, vec3(inv_m2));
|
||||
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() {
|
||||
vec4 val = textureLod(tex, uv, 0);
|
||||
if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_SRGB) {
|
||||
out_color = srgb_color_to_linear(val);
|
||||
} else { // TEXTURE_TRANSFORM_IDENTITY
|
||||
out_color = val;
|
||||
vec4 in_color = textureLod(tex, uv, 0);
|
||||
|
||||
// Convert from pre-multiplied alpha to straight alpha
|
||||
float alpha = in_color.a;
|
||||
vec3 rgb;
|
||||
if (alpha == 0) {
|
||||
rgb = vec3(0);
|
||||
} else {
|
||||
rgb = in_color.rgb / alpha;
|
||||
}
|
||||
|
||||
if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_SRGB) {
|
||||
rgb = srgb_color_to_linear(rgb);
|
||||
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_ST2084_PQ) {
|
||||
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 = mat3(data.matrix) * rgb;
|
||||
|
||||
// Back to pre-multiplied alpha
|
||||
out_color = vec4(rgb * alpha, alpha);
|
||||
|
||||
out_color *= data.alpha;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,10 +269,12 @@ static struct wlr_vk_texture *vulkan_texture_create(
|
|||
}
|
||||
|
||||
struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_texture *texture,
|
||||
const struct wlr_vk_pipeline_layout *pipeline_layout) {
|
||||
const struct wlr_vk_pipeline_layout *pipeline_layout, bool srgb) {
|
||||
assert(texture->using_mutable_srgb || !srgb);
|
||||
|
||||
struct wlr_vk_texture_view *view;
|
||||
wl_list_for_each(view, &texture->views, link) {
|
||||
if (view->layout == pipeline_layout) {
|
||||
if (view->layout == pipeline_layout && view->srgb == srgb) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
|
@ -283,6 +285,7 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text
|
|||
}
|
||||
|
||||
view->layout = pipeline_layout;
|
||||
view->srgb = srgb;
|
||||
|
||||
VkResult res;
|
||||
VkDevice dev = texture->renderer->dev->dev;
|
||||
|
|
@ -290,8 +293,7 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text
|
|||
VkImageViewCreateInfo view_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = texture->using_mutable_srgb ? texture->format->vk_srgb
|
||||
: texture->format->vk,
|
||||
.format = srgb ? texture->format->vk_srgb : texture->format->vk,
|
||||
.components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.components.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.components.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
|
|
@ -353,10 +355,10 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text
|
|||
|
||||
static void texture_set_format(struct wlr_vk_texture *texture,
|
||||
const struct wlr_vk_format *format, bool has_mutable_srgb) {
|
||||
assert(!(format->is_ycbcr && has_mutable_srgb));
|
||||
|
||||
texture->format = format;
|
||||
texture->using_mutable_srgb = has_mutable_srgb;
|
||||
texture->transform = !format->is_ycbcr && has_mutable_srgb ?
|
||||
WLR_VK_TEXTURE_TRANSFORM_IDENTITY : WLR_VK_TEXTURE_TRANSFORM_SRGB;
|
||||
|
||||
const struct wlr_pixel_format_info *format_info =
|
||||
drm_get_pixel_format_info(format->drm);
|
||||
|
|
@ -397,14 +399,14 @@ static struct wlr_texture *vulkan_texture_from_pixels(
|
|||
|
||||
texture_set_format(texture, &fmt->format, fmt->shm.has_mutable_srgb);
|
||||
|
||||
VkFormat view_formats[2] = {
|
||||
VkFormat view_formats[] = {
|
||||
fmt->format.vk,
|
||||
fmt->format.vk_srgb,
|
||||
};
|
||||
VkImageFormatListCreateInfoKHR list_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
|
||||
.pViewFormats = view_formats,
|
||||
.viewFormatCount = 2,
|
||||
.viewFormatCount = sizeof(view_formats) / sizeof(view_formats[0]),
|
||||
};
|
||||
VkImageCreateInfo img_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
|
|
@ -598,14 +600,14 @@ VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
|
|||
};
|
||||
eimg.pNext = &mod_info;
|
||||
|
||||
VkFormat view_formats[2] = {
|
||||
VkFormat view_formats[] = {
|
||||
fmt->format.vk,
|
||||
fmt->format.vk_srgb,
|
||||
};
|
||||
VkImageFormatListCreateInfoKHR list_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
|
||||
.pViewFormats = view_formats,
|
||||
.viewFormatCount = 2,
|
||||
.viewFormatCount = sizeof(view_formats) / sizeof(view_formats[0]),
|
||||
};
|
||||
if (mod->has_mutable_srgb) {
|
||||
mod_info.pNext = &list_info;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
PKG_CONFIG?=pkg-config
|
||||
WAYLAND_PROTOCOLS!=$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols
|
||||
WAYLAND_SCANNER!=$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner
|
||||
|
||||
PKGS="wlroots-0.20" wayland-server xkbcommon
|
||||
CFLAGS_PKG_CONFIG!=$(PKG_CONFIG) --cflags $(PKGS)
|
||||
|
|
@ -9,19 +7,12 @@ LIBS!=$(PKG_CONFIG) --libs $(PKGS)
|
|||
|
||||
all: tinywl
|
||||
|
||||
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
||||
# protocols, which are specified in XML. wlroots requires you to rig these up
|
||||
# to your build system yourself and provide them in the include path.
|
||||
xdg-shell-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
||||
|
||||
tinywl.o: tinywl.c xdg-shell-protocol.h
|
||||
tinywl.o: tinywl.c
|
||||
$(CC) -c $< -g -Werror $(CFLAGS) -I. -DWLR_USE_UNSTABLE -o $@
|
||||
tinywl: tinywl.o
|
||||
$(CC) $^ $> -g -Werror $(CFLAGS) $(LDFLAGS) $(LIBS) -o $@
|
||||
|
||||
clean:
|
||||
rm -f tinywl tinywl.o xdg-shell-protocol.h
|
||||
rm -f tinywl tinywl.o
|
||||
|
||||
.PHONY: all clean
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
executable(
|
||||
'tinywl',
|
||||
['tinywl.c', protocols_server_header['xdg-shell']],
|
||||
'tinywl.c',
|
||||
dependencies: wlroots,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ struct tinywl_server {
|
|||
struct wlr_seat *seat;
|
||||
struct wl_listener new_input;
|
||||
struct wl_listener request_cursor;
|
||||
struct wl_listener pointer_focus_change;
|
||||
struct wl_listener request_set_selection;
|
||||
struct wl_list keyboards;
|
||||
enum tinywl_cursor_mode cursor_mode;
|
||||
|
|
@ -333,6 +334,18 @@ static void seat_request_cursor(struct wl_listener *listener, void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
static void seat_pointer_focus_change(struct wl_listener *listener, void *data) {
|
||||
struct tinywl_server *server = wl_container_of(
|
||||
listener, server, pointer_focus_change);
|
||||
/* This event is raised when the pointer focus is changed, including when the
|
||||
* client is closed. We set the cursor image to its default if target surface
|
||||
* is NULL */
|
||||
struct wlr_seat_pointer_focus_change_event *event = data;
|
||||
if (event->new_surface == NULL) {
|
||||
wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "default");
|
||||
}
|
||||
}
|
||||
|
||||
static void seat_request_set_selection(struct wl_listener *listener, void *data) {
|
||||
/* This event is raised by the seat when a client wants to set the selection,
|
||||
* usually when the user copies something. wlroots allows compositors to
|
||||
|
|
@ -1018,6 +1031,9 @@ int main(int argc, char *argv[]) {
|
|||
server.request_cursor.notify = seat_request_cursor;
|
||||
wl_signal_add(&server.seat->events.request_set_cursor,
|
||||
&server.request_cursor);
|
||||
server.pointer_focus_change.notify = seat_pointer_focus_change;
|
||||
wl_signal_add(&server.seat->pointer_state.events.focus_change,
|
||||
&server.pointer_focus_change);
|
||||
server.request_set_selection.notify = seat_request_set_selection;
|
||||
wl_signal_add(&server.seat->events.request_set_selection,
|
||||
&server.request_set_selection);
|
||||
|
|
@ -1069,6 +1085,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
wl_list_remove(&server.new_input.link);
|
||||
wl_list_remove(&server.request_cursor.link);
|
||||
wl_list_remove(&server.pointer_focus_change.link);
|
||||
wl_list_remove(&server.request_set_selection.link);
|
||||
|
||||
wl_list_remove(&server.new_output.link);
|
||||
|
|
|
|||
|
|
@ -308,6 +308,14 @@ static void drag_handle_touch_motion(struct wlr_seat_touch_grab *grab,
|
|||
wl_fixed_from_double(point->sx),
|
||||
wl_fixed_from_double(point->sy));
|
||||
}
|
||||
|
||||
struct wlr_drag_motion_event event = {
|
||||
.drag = drag,
|
||||
.time = time,
|
||||
.sx = point->sx,
|
||||
.sy = point->sy,
|
||||
};
|
||||
wl_signal_emit_mutable(&drag->events.motion, &event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "ext-image-capture-source-v1-protocol.h"
|
||||
#include "render/wlr_renderer.h"
|
||||
|
||||
static void source_handle_destroy(struct wl_client *client,
|
||||
struct wl_resource *source_resource) {
|
||||
|
|
@ -96,6 +97,12 @@ static uint32_t get_swapchain_shm_format(struct wlr_swapchain *swapchain,
|
|||
return format;
|
||||
}
|
||||
|
||||
static void add_drm_format(struct wlr_drm_format_set *set, const struct wlr_drm_format *fmt) {
|
||||
for (size_t i = 0; i < fmt->len; i++) {
|
||||
wlr_drm_format_set_add(set, fmt->format, fmt->modifiers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool wlr_ext_image_capture_source_v1_set_constraints_from_swapchain(struct wlr_ext_image_capture_source_v1 *source,
|
||||
struct wlr_swapchain *swapchain, struct wlr_renderer *renderer) {
|
||||
source->width = swapchain->width;
|
||||
|
|
@ -130,9 +137,21 @@ bool wlr_ext_image_capture_source_v1_set_constraints_from_swapchain(struct wlr_e
|
|||
wlr_drm_format_set_finish(&source->dmabuf_formats);
|
||||
source->dmabuf_formats = (struct wlr_drm_format_set){0};
|
||||
|
||||
for (size_t i = 0; i < swapchain->format.len; i++) {
|
||||
wlr_drm_format_set_add(&source->dmabuf_formats,
|
||||
swapchain->format.format, swapchain->format.modifiers[i]);
|
||||
add_drm_format(&source->dmabuf_formats, &swapchain->format);
|
||||
|
||||
const struct wlr_drm_format_set *render_formats =
|
||||
wlr_renderer_get_render_formats(renderer);
|
||||
assert(render_formats != NULL);
|
||||
|
||||
// Not all clients support fancy formats. Always ensure we provide
|
||||
// support for ARGB8888 and XRGB8888 for simple clients.
|
||||
uint32_t fallback_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888 };
|
||||
for (size_t i = 0; i < sizeof(fallback_formats) / sizeof(fallback_formats[0]); i++) {
|
||||
const struct wlr_drm_format *fmt =
|
||||
wlr_drm_format_set_get(render_formats, fallback_formats[i]);
|
||||
if (fmt != NULL && swapchain->format.format != fmt->format) {
|
||||
add_drm_format(&source->dmabuf_formats, fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,6 @@
|
|||
|
||||
#define FOREIGN_TOPLEVEL_IMAGE_SOURCE_MANAGER_V1_VERSION 1
|
||||
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_v1 {
|
||||
struct wlr_ext_image_capture_source_v1 base;
|
||||
};
|
||||
|
||||
static const struct ext_foreign_toplevel_image_capture_source_manager_v1_interface foreign_toplevel_manager_impl;
|
||||
|
||||
static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *
|
||||
|
|
|
|||
|
|
@ -283,7 +283,8 @@ static void output_cursor_source_copy_frame(struct wlr_ext_image_capture_source_
|
|||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
wlr_ext_image_copy_capture_frame_v1_ready(frame, WL_OUTPUT_TRANSFORM_NORMAL, &now);
|
||||
wlr_ext_image_copy_capture_frame_v1_ready(frame,
|
||||
cursor_source->output->transform, &now);
|
||||
}
|
||||
|
||||
static const struct wlr_ext_image_capture_source_v1_interface output_cursor_source_impl = {
|
||||
|
|
|
|||
|
|
@ -39,18 +39,20 @@ wlr_files += files(
|
|||
'buffer/resource.c',
|
||||
'wlr_alpha_modifier_v1.c',
|
||||
'wlr_color_management_v1.c',
|
||||
'wlr_color_representation_v1.c',
|
||||
'wlr_compositor.c',
|
||||
'wlr_content_type_v1.c',
|
||||
'wlr_cursor_shape_v1.c',
|
||||
'wlr_cursor.c',
|
||||
'wlr_cursor_shape_v1.c',
|
||||
'wlr_damage_ring.c',
|
||||
'wlr_data_control_v1.c',
|
||||
'wlr_drm.c',
|
||||
'wlr_export_dmabuf_v1.c',
|
||||
'wlr_foreign_toplevel_management_v1.c',
|
||||
'wlr_ext_image_copy_capture_v1.c',
|
||||
'wlr_ext_foreign_toplevel_list_v1.c',
|
||||
'wlr_ext_data_control_v1.c',
|
||||
'wlr_ext_foreign_toplevel_list_v1.c',
|
||||
'wlr_ext_image_copy_capture_v1.c',
|
||||
'wlr_fixes.c',
|
||||
'wlr_foreign_toplevel_management_v1.c',
|
||||
'wlr_fractional_scale_v1.c',
|
||||
'wlr_gamma_control_v1.c',
|
||||
'wlr_idle_inhibit_v1.c',
|
||||
|
|
@ -103,6 +105,7 @@ wlr_files += files(
|
|||
'wlr_xdg_output_v1.c',
|
||||
'wlr_xdg_system_bell_v1.c',
|
||||
'wlr_xdg_toplevel_icon_v1.c',
|
||||
'wlr_xdg_toplevel_tag_v1.c',
|
||||
)
|
||||
|
||||
if features.get('drm-backend')
|
||||
|
|
|
|||
|
|
@ -288,18 +288,10 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
|
|||
static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
|
||||
struct wlr_output *output = cursor->output;
|
||||
|
||||
if (!output->impl->set_cursor ||
|
||||
output->software_cursor_locks > 0) {
|
||||
if (!output->impl->set_cursor || output->software_cursor_locks > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_output_cursor *hwcur = output->hardware_cursor;
|
||||
if (hwcur != NULL && hwcur != cursor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
output->hardware_cursor = NULL;
|
||||
|
||||
struct wlr_texture *texture = cursor->texture;
|
||||
|
||||
// If the cursor was hidden or was a software cursor, the hardware
|
||||
|
|
@ -424,12 +416,15 @@ bool output_cursor_set_texture(struct wlr_output_cursor *cursor,
|
|||
wl_list_init(&cursor->renderer_destroy.link);
|
||||
}
|
||||
|
||||
if (output_cursor_attempt_hardware(cursor)) {
|
||||
return true;
|
||||
if (output->hardware_cursor == NULL || output->hardware_cursor == cursor) {
|
||||
if (output_cursor_attempt_hardware(cursor)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "Falling back to software cursor on output '%s'", output->name);
|
||||
output_disable_hardware_cursor(output);
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "Falling back to software cursor on output '%s'", output->name);
|
||||
output_disable_hardware_cursor(output);
|
||||
output_cursor_damage_whole(cursor);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,6 +233,24 @@ static void output_apply_state(struct wlr_output *output,
|
|||
output->transform = state->transform;
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
|
||||
if (state->image_description != NULL) {
|
||||
output->image_description_value = *state->image_description;
|
||||
output->image_description = &output->image_description_value;
|
||||
} else {
|
||||
output->image_description = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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 &
|
||||
(WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_SUBPIXEL);
|
||||
|
|
@ -398,6 +416,7 @@ void wlr_output_finish(struct wlr_output *output) {
|
|||
|
||||
wlr_swapchain_destroy(output->cursor_swapchain);
|
||||
wlr_buffer_unlock(output->cursor_front_buffer);
|
||||
wlr_color_transform_unref(output->color_transform);
|
||||
|
||||
wlr_swapchain_destroy(output->swapchain);
|
||||
|
||||
|
|
@ -491,6 +510,14 @@ bool output_pending_enabled(struct wlr_output *output,
|
|||
return output->enabled;
|
||||
}
|
||||
|
||||
const struct wlr_output_image_description *output_pending_image_description(
|
||||
struct wlr_output *output, const struct wlr_output_state *state) {
|
||||
if (state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
|
||||
return state->image_description;
|
||||
}
|
||||
return output->image_description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare a struct wlr_output_state with the current state of a struct
|
||||
* wlr_output.
|
||||
|
|
@ -498,8 +525,7 @@ bool output_pending_enabled(struct wlr_output *output,
|
|||
* Returns a bitfield of the unchanged fields.
|
||||
*
|
||||
* 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
|
||||
* changed, etc.
|
||||
* contents of the buffer might have changed, etc.
|
||||
*/
|
||||
static uint32_t output_compare_state(struct wlr_output *output,
|
||||
const struct wlr_output_state *state) {
|
||||
|
|
@ -545,6 +571,10 @@ static uint32_t output_compare_state(struct wlr_output *output,
|
|||
output->subpixel == 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;
|
||||
}
|
||||
|
||||
|
|
@ -627,29 +657,25 @@ static bool output_basic_test(struct wlr_output *output,
|
|||
}
|
||||
}
|
||||
|
||||
if (!enabled && state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
wlr_log(WLR_DEBUG, "Tried to commit a buffer on a disabled output");
|
||||
return false;
|
||||
}
|
||||
if (!enabled && state->committed & WLR_OUTPUT_STATE_MODE) {
|
||||
wlr_log(WLR_DEBUG, "Tried to modeset a disabled output");
|
||||
return false;
|
||||
}
|
||||
if (!enabled && state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) {
|
||||
wlr_log(WLR_DEBUG, "Tried to enable adaptive sync on a disabled output");
|
||||
return false;
|
||||
}
|
||||
if (!enabled && state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) {
|
||||
wlr_log(WLR_DEBUG, "Tried to set format for a disabled output");
|
||||
return false;
|
||||
}
|
||||
if (!enabled && state->committed & WLR_OUTPUT_STATE_SUBPIXEL) {
|
||||
wlr_log(WLR_DEBUG, "Tried to set the subpixel layout on a disabled output");
|
||||
return false;
|
||||
}
|
||||
if (!enabled && state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
wlr_log(WLR_DEBUG, "Tried to set a color transform on a disabled output");
|
||||
return false;
|
||||
const struct {
|
||||
enum wlr_output_state_field field;
|
||||
const char *name;
|
||||
} needs_enabled[] = {
|
||||
{ WLR_OUTPUT_STATE_BUFFER, "buffer" },
|
||||
{ WLR_OUTPUT_STATE_MODE, "mode" },
|
||||
{ WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED, "adaptive sync" },
|
||||
{ WLR_OUTPUT_STATE_RENDER_FORMAT, "render format" },
|
||||
{ WLR_OUTPUT_STATE_SUBPIXEL, "subpixel" },
|
||||
{ WLR_OUTPUT_STATE_COLOR_TRANSFORM, "color transform" },
|
||||
{ WLR_OUTPUT_STATE_IMAGE_DESCRIPTION, "image description" },
|
||||
};
|
||||
if (!enabled) {
|
||||
for (size_t i = 0; i < sizeof(needs_enabled) / sizeof(needs_enabled[0]); i++) {
|
||||
if (state->committed & needs_enabled[i].field) {
|
||||
wlr_log(WLR_DEBUG, "Tried to set %s on a disabled output", needs_enabled[i].name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
|
||||
|
|
@ -669,6 +695,18 @@ static bool output_basic_test(struct wlr_output *output,
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
|
||||
state->image_description != NULL) {
|
||||
if (!(output->supported_primaries & state->image_description->primaries)) {
|
||||
wlr_log(WLR_DEBUG, "Unsupported image description primaries");
|
||||
return false;
|
||||
}
|
||||
if (!(output->supported_transfer_functions & state->image_description->transfer_function)) {
|
||||
wlr_log(WLR_DEBUG, "Unsupported image description transfer function");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -734,7 +772,9 @@ void output_apply_commit(struct wlr_output *output, const struct wlr_output_stat
|
|||
}
|
||||
|
||||
output_apply_state(output, state);
|
||||
}
|
||||
|
||||
void output_send_commit_event(struct wlr_output *output, const struct wlr_output_state *state) {
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
struct wlr_output_event_commit event = {
|
||||
|
|
@ -776,6 +816,7 @@ bool wlr_output_commit_state(struct wlr_output *output,
|
|||
}
|
||||
|
||||
output_apply_commit(output, &pending);
|
||||
output_send_commit_event(output, &pending);
|
||||
|
||||
if (new_back_buffer) {
|
||||
wlr_buffer_unlock(pending.buffer);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ void wlr_output_state_finish(struct wlr_output_state *state) {
|
|||
pixman_region32_fini(&state->damage);
|
||||
wlr_drm_syncobj_timeline_unref(state->wait_timeline);
|
||||
wlr_drm_syncobj_timeline_unref(state->signal_timeline);
|
||||
free(state->image_description);
|
||||
}
|
||||
|
||||
void wlr_output_state_set_enabled(struct wlr_output_state *state,
|
||||
|
|
@ -122,6 +123,23 @@ void wlr_output_state_set_color_transform(struct wlr_output_state *state,
|
|||
}
|
||||
}
|
||||
|
||||
bool wlr_output_state_set_image_description(struct wlr_output_state *state,
|
||||
const struct wlr_output_image_description *image_desc) {
|
||||
struct wlr_output_image_description *copy = NULL;
|
||||
if (image_desc != NULL) {
|
||||
copy = malloc(sizeof(*copy));
|
||||
if (copy == NULL) {
|
||||
return false;
|
||||
}
|
||||
*copy = *image_desc;
|
||||
}
|
||||
|
||||
state->committed |= WLR_OUTPUT_STATE_IMAGE_DESCRIPTION;
|
||||
free(state->image_description);
|
||||
state->image_description = copy;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wlr_output_state_copy(struct wlr_output_state *dst,
|
||||
const struct wlr_output_state *src) {
|
||||
struct wlr_output_state copy = *src;
|
||||
|
|
@ -129,7 +147,8 @@ bool wlr_output_state_copy(struct wlr_output_state *dst,
|
|||
WLR_OUTPUT_STATE_DAMAGE |
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
|
||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM);
|
||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION);
|
||||
copy.buffer = NULL;
|
||||
copy.buffer_src_box = (struct wlr_fbox){0};
|
||||
copy.buffer_dst_box = (struct wlr_box){0};
|
||||
|
|
@ -137,6 +156,7 @@ bool wlr_output_state_copy(struct wlr_output_state *dst,
|
|||
copy.wait_timeline = NULL;
|
||||
copy.signal_timeline = NULL;
|
||||
copy.color_transform = NULL;
|
||||
copy.image_description = NULL;
|
||||
|
||||
if (src->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
wlr_output_state_set_buffer(©, src->buffer);
|
||||
|
|
@ -160,8 +180,17 @@ bool wlr_output_state_copy(struct wlr_output_state *dst,
|
|||
if (src->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
wlr_output_state_set_color_transform(©, src->color_transform);
|
||||
}
|
||||
if (src->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
|
||||
if (!wlr_output_state_set_image_description(©, src->image_description)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
wlr_output_state_finish(dst);
|
||||
*dst = copy;
|
||||
return true;
|
||||
|
||||
err:
|
||||
wlr_output_state_finish(dst);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/types/wlr_alpha_modifier_v1.h>
|
||||
#include <wlr/types/wlr_color_management_v1.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||
|
|
@ -34,16 +35,76 @@ static struct wlr_output *get_surface_frame_pacing_output(struct wlr_surface *su
|
|||
return frame_pacing_output;
|
||||
}
|
||||
|
||||
static bool get_tf_preference(enum wlr_color_transfer_function tf) {
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
return 0;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return 1;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
return -1;
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static bool get_primaries_preference(enum wlr_color_named_primaries primaries) {
|
||||
switch (primaries) {
|
||||
case WLR_COLOR_NAMED_PRIMARIES_SRGB:
|
||||
return 0;
|
||||
case WLR_COLOR_NAMED_PRIMARIES_BT2020:
|
||||
return 1;
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static void get_surface_preferred_image_description(struct wlr_surface *surface,
|
||||
struct wlr_image_description_v1_data *out) {
|
||||
struct wlr_output_image_description preferred = {
|
||||
.transfer_function = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22,
|
||||
.primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB,
|
||||
};
|
||||
|
||||
struct wlr_surface_output *surface_output;
|
||||
wl_list_for_each(surface_output, &surface->current_outputs, link) {
|
||||
const struct wlr_output_image_description *img_desc =
|
||||
surface_output->output->image_description;
|
||||
if (img_desc == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (get_tf_preference(preferred.transfer_function) < get_tf_preference(img_desc->transfer_function)) {
|
||||
preferred.transfer_function = img_desc->transfer_function;
|
||||
}
|
||||
if (get_primaries_preference(preferred.primaries) < get_primaries_preference(img_desc->primaries)) {
|
||||
preferred.primaries = img_desc->primaries;
|
||||
}
|
||||
}
|
||||
|
||||
*out = (struct wlr_image_description_v1_data){
|
||||
.tf_named = wlr_color_manager_v1_transfer_function_from_wlr(preferred.transfer_function),
|
||||
.primaries_named = wlr_color_manager_v1_primaries_from_wlr(preferred.primaries),
|
||||
};
|
||||
}
|
||||
|
||||
static void handle_scene_buffer_outputs_update(
|
||||
struct wl_listener *listener, void *data) {
|
||||
struct wlr_scene_surface *surface =
|
||||
wl_container_of(listener, surface, outputs_update);
|
||||
struct wlr_scene *scene = scene_node_get_root(&surface->buffer->node);
|
||||
|
||||
surface->frame_pacing_output = get_surface_frame_pacing_output(surface->surface);
|
||||
|
||||
double scale = get_surface_preferred_buffer_scale(surface->surface);
|
||||
wlr_fractional_scale_v1_notify_scale(surface->surface, scale);
|
||||
wlr_surface_set_preferred_buffer_scale(surface->surface, ceil(scale));
|
||||
|
||||
if (scene->color_manager_v1 != NULL) {
|
||||
struct wlr_image_description_v1_data img_desc = {0};
|
||||
get_surface_preferred_image_description(surface->surface, &img_desc);
|
||||
wlr_color_manager_v1_set_surface_preferred_image_description(scene->color_manager_v1,
|
||||
surface->surface, &img_desc);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_scene_buffer_output_enter(
|
||||
|
|
@ -126,8 +187,11 @@ static void scene_buffer_unmark_client_buffer(struct wlr_scene_buffer *scene_buf
|
|||
return;
|
||||
}
|
||||
|
||||
assert(buffer->n_ignore_locks > 0);
|
||||
buffer->n_ignore_locks--;
|
||||
// If the buffer was a single-pixel buffer where we cached its color
|
||||
// then it won't have been marked as damage-allowed.
|
||||
if (buffer->n_ignore_locks > 0) {
|
||||
buffer->n_ignore_locks--;
|
||||
}
|
||||
}
|
||||
|
||||
static int min(int a, int b) {
|
||||
|
|
@ -186,16 +250,41 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
|
|||
opacity = (float)alpha_modifier_state->multiplier;
|
||||
}
|
||||
|
||||
enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
|
||||
enum wlr_color_named_primaries primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||
const struct wlr_image_description_v1_data *img_desc =
|
||||
wlr_surface_get_image_description_v1_data(surface);
|
||||
if (img_desc != NULL) {
|
||||
tf = wlr_color_manager_v1_transfer_function_to_wlr(img_desc->tf_named);
|
||||
primaries = wlr_color_manager_v1_primaries_to_wlr(img_desc->primaries_named);
|
||||
}
|
||||
|
||||
wlr_scene_buffer_set_opaque_region(scene_buffer, &opaque);
|
||||
wlr_scene_buffer_set_source_box(scene_buffer, &src_box);
|
||||
wlr_scene_buffer_set_dest_size(scene_buffer, width, height);
|
||||
wlr_scene_buffer_set_transform(scene_buffer, state->transform);
|
||||
wlr_scene_buffer_set_opacity(scene_buffer, opacity);
|
||||
wlr_scene_buffer_set_transfer_function(scene_buffer, tf);
|
||||
wlr_scene_buffer_set_primaries(scene_buffer, primaries);
|
||||
|
||||
scene_buffer_unmark_client_buffer(scene_buffer);
|
||||
|
||||
if (surface->buffer) {
|
||||
client_buffer_mark_next_can_damage(surface->buffer);
|
||||
// If we've cached the buffer's single-pixel buffer color
|
||||
// then any in-place updates to the texture wouldn't be
|
||||
// reflected in rendering. So only allow in-place texture
|
||||
// updates if it's not a single pixel buffer. Note that we
|
||||
// can't use the cached scene_buffer->is_single_pixel_buffer
|
||||
// because that's only set later on.
|
||||
bool is_single_pixel_buffer = false;
|
||||
if (surface->buffer->source != NULL) {
|
||||
struct wlr_single_pixel_buffer_v1 *spb =
|
||||
wlr_single_pixel_buffer_v1_try_from_buffer(surface->buffer->source);
|
||||
is_single_pixel_buffer = spb != NULL;
|
||||
}
|
||||
if (!is_single_pixel_buffer) {
|
||||
client_buffer_mark_next_can_damage(surface->buffer);
|
||||
}
|
||||
|
||||
struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
|
||||
wlr_linux_drm_syncobj_v1_get_surface_state(surface);
|
||||
|
|
@ -216,7 +305,8 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
|
|||
&surface->buffer->base, &options);
|
||||
|
||||
if (syncobj_surface_state != NULL &&
|
||||
(surface->current.committed & WLR_SURFACE_STATE_BUFFER)) {
|
||||
(surface->current.committed & WLR_SURFACE_STATE_BUFFER) &&
|
||||
surface->buffer->source != NULL) {
|
||||
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
|
||||
surface->buffer->source);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <wlr/render/swapchain.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_color_management_v1.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_damage_ring.h>
|
||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||
|
|
@ -14,6 +15,7 @@
|
|||
#include <wlr/util/log.h>
|
||||
#include <wlr/util/region.h>
|
||||
#include <wlr/util/transform.h>
|
||||
#include "render/color.h"
|
||||
#include "types/wlr_output.h"
|
||||
#include "types/wlr_scene.h"
|
||||
#include "util/array.h"
|
||||
|
|
@ -1099,6 +1101,26 @@ void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer,
|
|||
scene_node_update(&scene_buffer->node, NULL);
|
||||
}
|
||||
|
||||
void wlr_scene_buffer_set_transfer_function(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_transfer_function transfer_function) {
|
||||
if (scene_buffer->transfer_function == transfer_function) {
|
||||
return;
|
||||
}
|
||||
|
||||
scene_buffer->transfer_function = transfer_function;
|
||||
scene_node_update(&scene_buffer->node, NULL);
|
||||
}
|
||||
|
||||
void wlr_scene_buffer_set_primaries(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_named_primaries primaries) {
|
||||
if (scene_buffer->primaries == primaries) {
|
||||
return;
|
||||
}
|
||||
|
||||
scene_buffer->primaries = primaries;
|
||||
scene_node_update(&scene_buffer->node, NULL);
|
||||
}
|
||||
|
||||
static struct wlr_texture *scene_buffer_get_texture(
|
||||
struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) {
|
||||
if (scene_buffer->buffer == NULL || scene_buffer->texture != NULL) {
|
||||
|
|
@ -1435,6 +1457,11 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
|
|||
wlr_output_transform_invert(scene_buffer->transform);
|
||||
transform = wlr_output_transform_compose(transform, data->transform);
|
||||
|
||||
struct wlr_color_primaries primaries = {0};
|
||||
if (scene_buffer->primaries != 0) {
|
||||
wlr_color_primaries_from_named(&primaries, scene_buffer->primaries);
|
||||
}
|
||||
|
||||
wlr_render_pass_add_texture(data->render_pass, &(struct wlr_render_texture_options) {
|
||||
.texture = texture,
|
||||
.src_box = scene_buffer->src_box,
|
||||
|
|
@ -1446,6 +1473,8 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
|
|||
.blend_mode = !data->output->scene->calculate_visibility ||
|
||||
!pixman_region32_empty(&opaque) ?
|
||||
WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE,
|
||||
.transfer_function = scene_buffer->transfer_function,
|
||||
.primaries = scene_buffer->primaries != 0 ? &primaries : NULL,
|
||||
.wait_timeline = scene_buffer->wait_timeline,
|
||||
.wait_point = scene_buffer->wait_point,
|
||||
});
|
||||
|
|
@ -1501,6 +1530,8 @@ static void scene_handle_gamma_control_manager_v1_set_gamma(struct wl_listener *
|
|||
|
||||
output->gamma_lut_changed = true;
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -1518,6 +1549,8 @@ static void scene_handle_gamma_control_manager_v1_destroy(struct wl_listener *li
|
|||
wl_list_for_each(output, &scene->outputs, link) {
|
||||
output->gamma_lut_changed = false;
|
||||
output->gamma_lut = NULL;
|
||||
wlr_color_transform_unref(output->gamma_lut_color_transform);
|
||||
output->gamma_lut_color_transform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1534,6 +1567,21 @@ void wlr_scene_set_gamma_control_manager_v1(struct wlr_scene *scene,
|
|||
wl_signal_add(&gamma_control->events.set_gamma, &scene->gamma_control_manager_v1_set_gamma);
|
||||
}
|
||||
|
||||
static void scene_handle_color_manager_v1_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_scene *scene = wl_container_of(listener, scene, color_manager_v1_destroy);
|
||||
wl_list_remove(&scene->color_manager_v1_destroy.link);
|
||||
wl_list_init(&scene->color_manager_v1_destroy.link);
|
||||
scene->color_manager_v1 = NULL;
|
||||
}
|
||||
|
||||
void wlr_scene_set_color_manager_v1(struct wlr_scene *scene, struct wlr_color_manager_v1 *manager) {
|
||||
assert(scene->color_manager_v1 == NULL);
|
||||
scene->color_manager_v1 = manager;
|
||||
|
||||
scene->color_manager_v1_destroy.notify = scene_handle_color_manager_v1_destroy;
|
||||
wl_signal_add(&manager->events.destroy, &scene->color_manager_v1_destroy);
|
||||
}
|
||||
|
||||
static void scene_output_handle_destroy(struct wlr_addon *addon) {
|
||||
struct wlr_scene_output *scene_output =
|
||||
wl_container_of(addon, scene_output, addon);
|
||||
|
|
@ -1722,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_needs_frame.link);
|
||||
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);
|
||||
free(scene_output);
|
||||
}
|
||||
|
|
@ -1881,6 +1933,27 @@ static void scene_buffer_send_dmabuf_feedback(const struct wlr_scene *scene,
|
|||
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 {
|
||||
// This scene node is not a candidate for scanout
|
||||
SCANOUT_INELIGIBLE,
|
||||
|
|
@ -1937,6 +2010,11 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
|
|||
return SCANOUT_INELIGIBLE;
|
||||
}
|
||||
|
||||
const struct wlr_output_image_description *img_desc = output_pending_image_description(scene_output->output, state);
|
||||
if (!color_management_is_scanout_allowed(img_desc, buffer)) {
|
||||
return SCANOUT_INELIGIBLE;
|
||||
}
|
||||
|
||||
// We want to ensure optimal buffer selection, but as direct-scanout can be enabled and disabled
|
||||
// on a frame-by-frame basis, we wait for a few frames to send the new format recommendations.
|
||||
// Maybe we should only send feedback in this case if tests fail.
|
||||
|
|
@ -2034,16 +2112,15 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
|
|||
return;
|
||||
}
|
||||
|
||||
if (!wlr_gamma_control_v1_apply(scene_output->gamma_lut, &gamma_pending)) {
|
||||
wlr_output_state_finish(&gamma_pending);
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_output_state_set_color_transform(&gamma_pending, scene_output->gamma_lut_color_transform);
|
||||
scene_output->gamma_lut_changed = false;
|
||||
|
||||
if (!wlr_output_test_state(scene_output->output, &gamma_pending)) {
|
||||
wlr_gamma_control_v1_send_failed_and_destroy(scene_output->gamma_lut);
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
|
@ -2052,6 +2129,41 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
|
|||
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,
|
||||
struct wlr_output_state *state, const struct wlr_scene_output_state_options *options) {
|
||||
struct wlr_scene_output_state_options default_options = {0};
|
||||
|
|
@ -2075,6 +2187,16 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
enum wlr_scene_debug_damage_option debug_damage =
|
||||
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 = {
|
||||
.transform = output->transform,
|
||||
.scale = output->scale,
|
||||
|
|
@ -2175,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
|
||||
// - Damage highlight debugging is not enabled
|
||||
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) {
|
||||
scanout_result = scene_entry_try_direct_scanout(&list_data[0], state, &render_data);
|
||||
}
|
||||
|
|
@ -2235,14 +2357,41 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
timer->pre_render_duration = timespec_to_nsec(&duration);
|
||||
}
|
||||
|
||||
struct wlr_color_transform *color_transform = NULL;
|
||||
const struct wlr_color_primaries *primaries = NULL;
|
||||
struct wlr_color_primaries primaries_value;
|
||||
const struct wlr_output_image_description *img_desc = output_pending_image_description(output, state);
|
||||
if (img_desc != NULL) {
|
||||
color_transform = wlr_color_transform_init_linear_to_inverse_eotf(img_desc->transfer_function);
|
||||
wlr_color_primaries_from_named(&primaries_value, img_desc->primaries);
|
||||
primaries = &primaries_value;
|
||||
}
|
||||
if (options->color_transform != NULL) {
|
||||
assert(color_transform == NULL);
|
||||
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++;
|
||||
struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer,
|
||||
&(struct wlr_buffer_pass_options){
|
||||
.timer = timer ? timer->render_timer : NULL,
|
||||
.color_transform = options->color_transform,
|
||||
.color_transform = color_transform,
|
||||
.primaries = primaries,
|
||||
.signal_timeline = scene_output->in_timeline,
|
||||
.signal_point = scene_output->in_point,
|
||||
});
|
||||
wlr_color_transform_unref(color_transform);
|
||||
if (render_pass == NULL) {
|
||||
wlr_buffer_unlock(buffer);
|
||||
return false;
|
||||
|
|
@ -2355,7 +2504,9 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <time.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "types/wlr_seat.h"
|
||||
|
||||
|
|
@ -416,6 +417,11 @@ void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat,
|
|||
grab->seat = wlr_seat;
|
||||
wlr_seat->pointer_state.grab = grab;
|
||||
|
||||
// Preserve drag grab priority
|
||||
if (wlr_seat->drag && grab != &wlr_seat->drag->pointer_grab) {
|
||||
return;
|
||||
}
|
||||
|
||||
wl_signal_emit_mutable(&wlr_seat->events.pointer_grab_begin, grab);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <wlr/types/wlr_color_management_v1.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/util/addon.h>
|
||||
|
||||
#include "color-management-v1-protocol.h"
|
||||
#include "render/color.h"
|
||||
#include "util/mem.h"
|
||||
|
||||
#define COLOR_MANAGEMENT_V1_VERSION 1
|
||||
|
||||
|
|
@ -62,30 +65,6 @@ static void resource_handle_destroy(struct wl_client *client, struct wl_resource
|
|||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static enum wlr_color_named_primaries named_primaries_to_wlr(
|
||||
enum wp_color_manager_v1_primaries primaries) {
|
||||
switch (primaries) {
|
||||
case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB:
|
||||
return WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||
case WP_COLOR_MANAGER_V1_PRIMARIES_BT2020:
|
||||
return WLR_COLOR_NAMED_PRIMARIES_BT2020;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static enum wlr_color_transfer_function transfer_function_to_wlr(
|
||||
enum wp_color_manager_v1_transfer_function tf) {
|
||||
switch (tf) {
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t encode_cie1931_coord(float value) {
|
||||
return round(value * 1000 * 1000);
|
||||
}
|
||||
|
|
@ -127,10 +106,12 @@ static void image_desc_handle_get_information(struct wl_client *client,
|
|||
}
|
||||
|
||||
struct wlr_color_primaries primaries;
|
||||
wlr_color_primaries_from_named(&primaries, named_primaries_to_wlr(image_desc->data.primaries_named));
|
||||
wlr_color_primaries_from_named(&primaries,
|
||||
wlr_color_manager_v1_primaries_to_wlr(image_desc->data.primaries_named));
|
||||
|
||||
struct wlr_color_luminances luminances;
|
||||
wlr_color_transfer_function_get_default_luminance(transfer_function_to_wlr(image_desc->data.tf_named), &luminances);
|
||||
wlr_color_transfer_function_get_default_luminance(
|
||||
wlr_color_manager_v1_transfer_function_to_wlr(image_desc->data.tf_named), &luminances);
|
||||
|
||||
wp_image_description_info_v1_send_primaries_named(resource, image_desc->data.primaries_named);
|
||||
wp_image_description_info_v1_send_primaries(resource,
|
||||
|
|
@ -231,9 +212,14 @@ static void cm_output_handle_get_image_description(struct wl_client *client,
|
|||
}
|
||||
|
||||
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,
|
||||
};
|
||||
const struct wlr_output_image_description *image_desc = cm_output->output->image_description;
|
||||
if (image_desc != NULL) {
|
||||
data.tf_named = wlr_color_manager_v1_transfer_function_from_wlr(image_desc->transfer_function);
|
||||
data.primaries_named = wlr_color_manager_v1_primaries_from_wlr(image_desc->primaries);
|
||||
}
|
||||
image_desc_create_ready(cm_output->manager, cm_output_resource, id, &data, true);
|
||||
}
|
||||
|
||||
|
|
@ -306,6 +292,13 @@ static void cm_surface_handle_set_image_description(struct wl_client *client,
|
|||
|
||||
struct wlr_image_description_v1 *image_desc = image_desc_from_resource(image_desc_resource);
|
||||
|
||||
if (image_desc == NULL) {
|
||||
wl_resource_post_error(cm_surface_resource,
|
||||
WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_IMAGE_DESCRIPTION,
|
||||
"Image description to be set is invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < cm_surface->manager->render_intents_len; i++) {
|
||||
if (cm_surface->manager->render_intents[i] == render_intent) {
|
||||
|
|
@ -673,29 +666,35 @@ static void manager_handle_get_output(struct wl_client *client,
|
|||
struct wlr_color_manager_v1 *manager = manager_from_resource(manager_resource);
|
||||
struct wlr_output *output = wlr_output_from_resource(output_resource);
|
||||
|
||||
uint32_t version = wl_resource_get_version(manager_resource);
|
||||
struct wl_resource *cm_output_resource = wl_resource_create(client,
|
||||
&wp_color_management_output_v1_interface, version, id);
|
||||
if (!cm_output_resource) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(cm_output_resource, &cm_output_impl,
|
||||
NULL, cm_output_handle_resource_destroy);
|
||||
|
||||
if (output == NULL) {
|
||||
return; // leave the wp_color_management_output_v1 resource inert
|
||||
}
|
||||
|
||||
struct wlr_color_management_output_v1 *cm_output = calloc(1, sizeof(*cm_output));
|
||||
if (cm_output == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
cm_output->resource = cm_output_resource;
|
||||
cm_output->manager = manager;
|
||||
|
||||
uint32_t version = wl_resource_get_version(manager_resource);
|
||||
cm_output->resource = wl_resource_create(client,
|
||||
&wp_color_management_output_v1_interface, version, id);
|
||||
if (!cm_output->resource) {
|
||||
wl_client_post_no_memory(client);
|
||||
free(cm_output);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(cm_output->resource, &cm_output_impl,
|
||||
cm_output, cm_output_handle_resource_destroy);
|
||||
cm_output->output = output;
|
||||
|
||||
cm_output->output_destroy.notify = cm_output_handle_output_destroy;
|
||||
wl_signal_add(&output->events.destroy, &cm_output->output_destroy);
|
||||
|
||||
wl_list_insert(&manager->outputs, &cm_output->link);
|
||||
wl_resource_set_user_data(cm_output->resource, cm_output);
|
||||
}
|
||||
|
||||
static struct wlr_color_management_surface_v1 *cm_surface_from_surface(struct wlr_surface *surface) {
|
||||
|
|
@ -778,7 +777,7 @@ static void manager_handle_get_surface_feedback(struct wl_client *client,
|
|||
|
||||
surface_feedback->surface = surface;
|
||||
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,
|
||||
};
|
||||
|
||||
|
|
@ -888,6 +887,8 @@ static void manager_bind(struct wl_client *client, void *data,
|
|||
|
||||
static void manager_handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_color_manager_v1 *manager = wl_container_of(listener, manager, display_destroy);
|
||||
wl_signal_emit_mutable(&manager->events.destroy, NULL);
|
||||
assert(wl_list_empty(&manager->events.destroy.listener_list));
|
||||
wl_list_remove(&manager->display_destroy.link);
|
||||
wl_global_destroy(manager->global);
|
||||
free(manager->render_intents);
|
||||
|
|
@ -896,17 +897,6 @@ static void manager_handle_display_destroy(struct wl_listener *listener, void *d
|
|||
free(manager);
|
||||
}
|
||||
|
||||
static bool memdup(void *out, const void *src, size_t size) {
|
||||
void *dst = malloc(size);
|
||||
if (dst == NULL) {
|
||||
return false;
|
||||
}
|
||||
memcpy(dst, src, size);
|
||||
void **dst_ptr = out;
|
||||
*dst_ptr = dst;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct wlr_color_manager_v1 *wlr_color_manager_v1_create(struct wl_display *display,
|
||||
uint32_t version, const struct wlr_color_manager_v1_options *options) {
|
||||
assert(version <= COLOR_MANAGEMENT_V1_VERSION);
|
||||
|
|
@ -946,6 +936,7 @@ struct wlr_color_manager_v1 *wlr_color_manager_v1_create(struct wl_display *disp
|
|||
manager->transfer_functions_len = options->transfer_functions_len;
|
||||
manager->primaries_len = options->primaries_len;
|
||||
|
||||
wl_signal_init(&manager->events.destroy);
|
||||
wl_list_init(&manager->outputs);
|
||||
wl_list_init(&manager->surface_feedbacks);
|
||||
|
||||
|
|
@ -992,3 +983,61 @@ void wlr_color_manager_v1_set_surface_preferred_image_description(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum wlr_color_transfer_function
|
||||
wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_function tf) {
|
||||
switch (tf) {
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_SRGB;
|
||||
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
case WP_COLOR_MANAGER_V1_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:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
enum wp_color_manager_v1_transfer_function
|
||||
wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function tf) {
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
case WLR_COLOR_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();
|
||||
}
|
||||
|
||||
enum wlr_color_named_primaries
|
||||
wlr_color_manager_v1_primaries_to_wlr(enum wp_color_manager_v1_primaries primaries) {
|
||||
switch (primaries) {
|
||||
case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB:
|
||||
return WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||
case WP_COLOR_MANAGER_V1_PRIMARIES_BT2020:
|
||||
return WLR_COLOR_NAMED_PRIMARIES_BT2020;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
enum wp_color_manager_v1_primaries
|
||||
wlr_color_manager_v1_primaries_from_wlr(enum wlr_color_named_primaries primaries) {
|
||||
switch (primaries) {
|
||||
case WLR_COLOR_NAMED_PRIMARIES_SRGB:
|
||||
return WP_COLOR_MANAGER_V1_PRIMARIES_SRGB;
|
||||
case WLR_COLOR_NAMED_PRIMARIES_BT2020:
|
||||
return WP_COLOR_MANAGER_V1_PRIMARIES_BT2020;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
|
|
|||
410
types/wlr_color_representation_v1.c
Normal file
410
types/wlr_color_representation_v1.c
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_color_representation_v1.h>
|
||||
#include <wlr/util/addon.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "color-representation-v1-protocol.h"
|
||||
#include "util/mem.h"
|
||||
|
||||
#define WP_COLOR_REPRESENTATION_VERSION 1
|
||||
|
||||
enum wlr_alpha_mode wlr_color_representation_v1_alpha_mode_to_wlr(
|
||||
enum wp_color_representation_surface_v1_alpha_mode wp_val) {
|
||||
switch (wp_val) {
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL:
|
||||
return WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_PREMULTIPLIED_OPTICAL:
|
||||
return WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_OPTICAL;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_STRAIGHT:
|
||||
return WLR_COLOR_ALPHA_MODE_STRAIGHT;
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
enum wlr_color_encoding wlr_color_representation_v1_color_encoding_to_wlr(
|
||||
enum wp_color_representation_surface_v1_coefficients wp_val) {
|
||||
switch (wp_val) {
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY:
|
||||
return WLR_COLOR_ENCODING_IDENTITY;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT709:
|
||||
return WLR_COLOR_ENCODING_BT709;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_FCC:
|
||||
return WLR_COLOR_ENCODING_FCC;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT601:
|
||||
return WLR_COLOR_ENCODING_BT601;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_SMPTE240:
|
||||
return WLR_COLOR_ENCODING_SMPTE240;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT2020:
|
||||
return WLR_COLOR_ENCODING_BT2020;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT2020_CL:
|
||||
return WLR_COLOR_ENCODING_BT2020_CL;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_ICTCP:
|
||||
return WLR_COLOR_ENCODING_ICTCP;
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
enum wlr_color_range wlr_color_representation_v1_color_range_to_wlr(
|
||||
enum wp_color_representation_surface_v1_range wp_val) {
|
||||
switch (wp_val) {
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_LIMITED:
|
||||
return WLR_COLOR_RANGE_LIMITED;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_FULL:
|
||||
return WLR_COLOR_RANGE_FULL;
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
enum wlr_color_chroma_location wlr_color_representation_v1_chroma_location_to_wlr(
|
||||
enum wp_color_representation_surface_v1_chroma_location wp_val) {
|
||||
switch (wp_val) {
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_0:
|
||||
return WLR_COLOR_CHROMA_LOCATION_TYPE0;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_1:
|
||||
return WLR_COLOR_CHROMA_LOCATION_TYPE1;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_2:
|
||||
return WLR_COLOR_CHROMA_LOCATION_TYPE2;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_3:
|
||||
return WLR_COLOR_CHROMA_LOCATION_TYPE3;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_4:
|
||||
return WLR_COLOR_CHROMA_LOCATION_TYPE4;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_5:
|
||||
return WLR_COLOR_CHROMA_LOCATION_TYPE5;
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
struct wlr_color_representation_v1 {
|
||||
struct wl_resource *resource;
|
||||
struct wlr_surface *surface;
|
||||
|
||||
struct wlr_color_representation_manager_v1 *manager;
|
||||
|
||||
// Associate the wlr_color_representation_v1 with a wlr_surface
|
||||
struct wlr_addon addon;
|
||||
|
||||
struct wlr_surface_synced synced;
|
||||
struct wlr_color_representation_v1_surface_state pending, current;
|
||||
};
|
||||
|
||||
static const struct wp_color_representation_surface_v1_interface color_repr_impl;
|
||||
|
||||
static struct wlr_color_representation_v1 *color_repr_from_resource(
|
||||
struct wl_resource *resource) {
|
||||
assert(wl_resource_instance_of(resource,
|
||||
&wp_color_representation_surface_v1_interface,
|
||||
&color_repr_impl));
|
||||
return wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
static void color_repr_handle_destroy(struct wl_client *client,
|
||||
struct wl_resource *resource) {
|
||||
// Actual destroying is done by the resource-destroy handler
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void color_repr_handle_set_alpha_mode(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t alpha_mode) {
|
||||
struct wlr_color_representation_v1 *color_repr =
|
||||
color_repr_from_resource(resource);
|
||||
if (color_repr == NULL) {
|
||||
wl_resource_post_error(resource, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT,
|
||||
"Associated surface has been destroyed, object is inert");
|
||||
return;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < color_repr->manager->supported_alpha_modes_len; i++) {
|
||||
if (color_repr->manager->supported_alpha_modes[i] == alpha_mode) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
wl_resource_post_error(resource,
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_ALPHA_MODE,
|
||||
"Unsupported alpha mode");
|
||||
return;
|
||||
}
|
||||
|
||||
color_repr->pending.alpha_mode = alpha_mode;
|
||||
}
|
||||
|
||||
static void color_repr_handle_set_coefficients_and_range(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t coefficients,
|
||||
uint32_t range) {
|
||||
struct wlr_color_representation_v1 *color_repr =
|
||||
color_repr_from_resource(resource);
|
||||
if (color_repr == NULL) {
|
||||
wl_resource_post_error(resource, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT,
|
||||
"Associated surface has been destroyed, object is inert");
|
||||
return;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < color_repr->manager->supported_coeffs_and_ranges_len; i++) {
|
||||
struct wlr_color_representation_v1_coeffs_and_range *supported =
|
||||
&color_repr->manager->supported_coeffs_and_ranges[i];
|
||||
if (supported->coeffs == coefficients && supported->range == range) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
wl_resource_post_error(resource,
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_COEFFICIENTS,
|
||||
"Unsupported coefficients/range pair");
|
||||
return;
|
||||
}
|
||||
|
||||
color_repr->pending.coefficients = coefficients;
|
||||
color_repr->pending.range = range;
|
||||
}
|
||||
|
||||
static void color_repr_handle_set_chroma_location(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t chroma_location) {
|
||||
struct wlr_color_representation_v1 *color_repr =
|
||||
color_repr_from_resource(resource);
|
||||
if (color_repr == NULL) {
|
||||
wl_resource_post_error(resource, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT,
|
||||
"Associated surface has been destroyed, object is inert");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t version = wl_resource_get_version(resource);
|
||||
if (!wp_color_representation_surface_v1_chroma_location_is_valid(
|
||||
version, chroma_location)) {
|
||||
wlr_log(WLR_ERROR, "Client sent chroma location which isn't a valid enum value");
|
||||
// TODO: Post actual error once
|
||||
// https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/429
|
||||
// is merged and wlroots depends on a new enough wayland-protocols.
|
||||
wl_client_post_implementation_error(resource->client,
|
||||
"Chroma location is not a valid enum value");
|
||||
return;
|
||||
}
|
||||
|
||||
// In this protocol there's no concept of supported chroma locations
|
||||
// from a client point-of-view. The compositor should just ignore any
|
||||
// chroma locations it doesn't know what to do with.
|
||||
|
||||
color_repr->pending.chroma_location = chroma_location;
|
||||
}
|
||||
|
||||
static const struct wp_color_representation_surface_v1_interface color_repr_impl = {
|
||||
.destroy = color_repr_handle_destroy,
|
||||
.set_alpha_mode = color_repr_handle_set_alpha_mode,
|
||||
.set_coefficients_and_range = color_repr_handle_set_coefficients_and_range,
|
||||
.set_chroma_location = color_repr_handle_set_chroma_location,
|
||||
};
|
||||
|
||||
static void color_repr_destroy(struct wlr_color_representation_v1 *color_repr) {
|
||||
if (color_repr == NULL) {
|
||||
return;
|
||||
}
|
||||
wlr_surface_synced_finish(&color_repr->synced);
|
||||
wlr_addon_finish(&color_repr->addon);
|
||||
wl_resource_set_user_data(color_repr->resource, NULL);
|
||||
free(color_repr);
|
||||
}
|
||||
|
||||
static void color_repr_addon_destroy(struct wlr_addon *addon) {
|
||||
struct wlr_color_representation_v1 *color_repr =
|
||||
wl_container_of(addon, color_repr, addon);
|
||||
color_repr_destroy(color_repr);
|
||||
}
|
||||
|
||||
static const struct wlr_addon_interface surface_addon_impl = {
|
||||
.name = "wlr_color_representation_v1",
|
||||
.destroy = color_repr_addon_destroy,
|
||||
};
|
||||
|
||||
static void color_repr_handle_resource_destroy(struct wl_resource *resource) {
|
||||
struct wlr_color_representation_v1 *color_repr =
|
||||
color_repr_from_resource(resource);
|
||||
color_repr_destroy(color_repr);
|
||||
}
|
||||
|
||||
static void color_repr_manager_handle_destroy(struct wl_client *client,
|
||||
struct wl_resource *resource) {
|
||||
// Actual destroying is done by the resource-destroy handler
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static const struct wlr_surface_synced_impl surface_synced_impl = {
|
||||
.state_size = sizeof(struct wlr_color_representation_v1_surface_state),
|
||||
};
|
||||
|
||||
static struct wlr_color_representation_v1 *color_repr_from_surface(
|
||||
struct wlr_surface *surface) {
|
||||
struct wlr_addon *addon = wlr_addon_find(&surface->addons, NULL, &surface_addon_impl);
|
||||
if (addon == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct wlr_color_representation_v1 *color_repr = wl_container_of(addon, color_repr, addon);
|
||||
return color_repr;
|
||||
}
|
||||
|
||||
static const struct wp_color_representation_manager_v1_interface color_repr_manager_impl;
|
||||
|
||||
static struct wlr_color_representation_manager_v1 *manager_from_resource(
|
||||
struct wl_resource *resource) {
|
||||
assert(wl_resource_instance_of(resource,
|
||||
&wp_color_representation_manager_v1_interface,
|
||||
&color_repr_manager_impl));
|
||||
return wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
static void color_repr_manager_handle_get_surface(struct wl_client *client,
|
||||
struct wl_resource *manager_resource,
|
||||
uint32_t color_repr_id,
|
||||
struct wl_resource *surface_resource) {
|
||||
struct wlr_surface *surface = wlr_surface_from_resource(surface_resource);
|
||||
|
||||
// Check if there's already a color-representation attached to
|
||||
// this surface
|
||||
if (color_repr_from_surface(surface) != NULL) {
|
||||
wl_resource_post_error(manager_resource,
|
||||
WP_COLOR_REPRESENTATION_MANAGER_V1_ERROR_SURFACE_EXISTS,
|
||||
"wp_color_representation_surface_v1 already exists for this surface");
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_color_representation_v1 *color_repr = calloc(1, sizeof(*color_repr));
|
||||
if (!color_repr) {
|
||||
wl_resource_post_no_memory(manager_resource);
|
||||
return;
|
||||
}
|
||||
|
||||
color_repr->manager = manager_from_resource(manager_resource);
|
||||
|
||||
if (!wlr_surface_synced_init(&color_repr->synced, surface,
|
||||
&surface_synced_impl, &color_repr->pending, &color_repr->current)) {
|
||||
free(color_repr);
|
||||
wl_resource_post_no_memory(manager_resource);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t version = wl_resource_get_version(manager_resource);
|
||||
color_repr->resource = wl_resource_create(client,
|
||||
&wp_color_representation_surface_v1_interface, version, color_repr_id);
|
||||
if (color_repr->resource == NULL) {
|
||||
wlr_surface_synced_finish(&color_repr->synced);
|
||||
free(color_repr);
|
||||
wl_resource_post_no_memory(manager_resource);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(color_repr->resource,
|
||||
&color_repr_impl, color_repr, color_repr_handle_resource_destroy);
|
||||
|
||||
wlr_addon_init(&color_repr->addon, &surface->addons, NULL, &surface_addon_impl);
|
||||
}
|
||||
|
||||
static const struct wp_color_representation_manager_v1_interface color_repr_manager_impl = {
|
||||
.destroy = color_repr_manager_handle_destroy,
|
||||
.get_surface = color_repr_manager_handle_get_surface,
|
||||
};
|
||||
|
||||
static void send_supported(struct wlr_color_representation_manager_v1 *manager,
|
||||
struct wl_resource *resource) {
|
||||
for (size_t i = 0; i < manager->supported_alpha_modes_len; i++) {
|
||||
wp_color_representation_manager_v1_send_supported_alpha_mode(
|
||||
resource, manager->supported_alpha_modes[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < manager->supported_coeffs_and_ranges_len; i++) {
|
||||
struct wlr_color_representation_v1_coeffs_and_range *supported =
|
||||
&manager->supported_coeffs_and_ranges[i];
|
||||
wp_color_representation_manager_v1_send_supported_coefficients_and_ranges(
|
||||
resource, supported->coeffs, supported->range);
|
||||
}
|
||||
|
||||
// Note that there is no event for supported chroma locations in the
|
||||
// v1 protocol.
|
||||
|
||||
wp_color_representation_manager_v1_send_done(resource);
|
||||
}
|
||||
|
||||
static void manager_bind(struct wl_client *client, void *data,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wlr_color_representation_manager_v1 *manager = data;
|
||||
|
||||
struct wl_resource *resource = wl_resource_create(client,
|
||||
&wp_color_representation_manager_v1_interface,
|
||||
version, id);
|
||||
if (resource == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(resource, &color_repr_manager_impl, manager, NULL);
|
||||
|
||||
send_supported(manager, resource);
|
||||
}
|
||||
|
||||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_color_representation_manager_v1 *manager =
|
||||
wl_container_of(listener, manager, display_destroy);
|
||||
|
||||
wl_signal_emit_mutable(&manager->events.destroy, NULL);
|
||||
|
||||
assert(wl_list_empty(&manager->events.destroy.listener_list));
|
||||
|
||||
wl_list_remove(&manager->display_destroy.link);
|
||||
wl_global_destroy(manager->global);
|
||||
free(manager);
|
||||
}
|
||||
|
||||
struct wlr_color_representation_manager_v1 *wlr_color_representation_manager_v1_create(
|
||||
struct wl_display *display, uint32_t version,
|
||||
const struct wlr_color_representation_v1_options *options) {
|
||||
assert(version <= WP_COLOR_REPRESENTATION_VERSION);
|
||||
|
||||
struct wlr_color_representation_manager_v1 *manager = calloc(1, sizeof(*manager));
|
||||
if (manager == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
ok &= memdup(&manager->supported_alpha_modes,
|
||||
options->supported_alpha_modes,
|
||||
sizeof(options->supported_alpha_modes[0]) * options->supported_alpha_modes_len);
|
||||
manager->supported_alpha_modes_len = options->supported_alpha_modes_len;
|
||||
ok &= memdup(&manager->supported_coeffs_and_ranges,
|
||||
options->supported_coeffs_and_ranges,
|
||||
sizeof(options->supported_coeffs_and_ranges[0]) * options->supported_coeffs_and_ranges_len);
|
||||
manager->supported_coeffs_and_ranges_len = options->supported_coeffs_and_ranges_len;
|
||||
if (!ok) {
|
||||
goto err_options;
|
||||
}
|
||||
|
||||
manager->global = wl_global_create(display,
|
||||
&wp_color_representation_manager_v1_interface,
|
||||
version, manager, manager_bind);
|
||||
if (manager->global == NULL) {
|
||||
goto err_options;
|
||||
}
|
||||
|
||||
wl_signal_init(&manager->events.destroy);
|
||||
|
||||
manager->display_destroy.notify = handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &manager->display_destroy);
|
||||
|
||||
return manager;
|
||||
|
||||
err_options:
|
||||
free(manager->supported_alpha_modes);
|
||||
free(manager->supported_coeffs_and_ranges);
|
||||
free(manager);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct wlr_color_representation_v1_surface_state *wlr_color_representation_v1_get_surface_state(
|
||||
struct wlr_surface *surface) {
|
||||
struct wlr_color_representation_v1 *color_repr = color_repr_from_surface(surface);
|
||||
if (color_repr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return &color_repr->current;
|
||||
}
|
||||
|
|
@ -882,11 +882,7 @@ void wlr_surface_reject_pending(struct wlr_surface *surface, struct wl_resource
|
|||
va_list args;
|
||||
va_start(args, msg);
|
||||
|
||||
// XXX: libwayland could expose wl_resource_post_error_vargs() instead
|
||||
char buffer[128]; // Matches the size of the buffer used in libwayland
|
||||
vsnprintf(buffer, sizeof(buffer), msg, args);
|
||||
|
||||
wl_resource_post_error(resource, code, "%s", buffer);
|
||||
wl_resource_post_error_vargs(resource, code, msg, args);
|
||||
surface->pending_rejected = true;
|
||||
|
||||
va_end(args);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#include <wlr/types/wlr_content_type_v1.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
|
||||
#include "content-type-v1-protocol.h"
|
||||
|
||||
#define CONTENT_TYPE_VERSION 1
|
||||
|
||||
struct wlr_content_type_v1_surface {
|
||||
|
|
|
|||
|
|
@ -530,10 +530,6 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_
|
|||
struct wlr_cursor *cur = output_cursor->cursor;
|
||||
struct wlr_output *output = output_cursor->output_cursor->output;
|
||||
|
||||
if (!output->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor_output_cursor_reset_image(output_cursor);
|
||||
|
||||
if (cur->state->buffer != NULL) {
|
||||
|
|
@ -589,10 +585,11 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_
|
|||
&src_box, dst_width, dst_height, surface->current.transform,
|
||||
hotspot_x, hotspot_y, wait_timeline, wait_point);
|
||||
|
||||
if (syncobj_surface_state != NULL && surface->buffer != NULL &&
|
||||
if (syncobj_surface_state != NULL &&
|
||||
surface->buffer != NULL && surface->buffer->source != NULL &&
|
||||
(surface->current.committed & WLR_SURFACE_STATE_BUFFER)) {
|
||||
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
|
||||
&surface->buffer->base);
|
||||
surface->buffer->source);
|
||||
}
|
||||
|
||||
if (output_cursor->output_cursor->visible) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include <wlr/types/wlr_cursor_shape_v1.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_tablet_tool.h>
|
||||
|
||||
#include "cursor-shape-v1-protocol.h"
|
||||
#include "types/wlr_tablet_v2.h"
|
||||
|
||||
#define CURSOR_SHAPE_MANAGER_V1_VERSION 2
|
||||
|
|
|
|||
|
|
@ -68,10 +68,6 @@ static void drm_lease_connector_v1_destroy(
|
|||
|
||||
wlr_log(WLR_DEBUG, "Destroying connector %s", connector->output->name);
|
||||
|
||||
if (connector->active_lease) {
|
||||
wlr_drm_lease_terminate(connector->active_lease->drm_lease);
|
||||
}
|
||||
|
||||
struct wl_resource *resource, *tmp;
|
||||
wl_resource_for_each_safe(resource, tmp, &connector->resources) {
|
||||
wp_drm_lease_connector_v1_send_withdrawn(resource);
|
||||
|
|
@ -140,14 +136,9 @@ static void lease_handle_destroy(struct wl_listener *listener, void *data) {
|
|||
|
||||
wl_list_remove(&lease->destroy.link);
|
||||
|
||||
for (size_t i = 0; i < lease->n_connectors; ++i) {
|
||||
lease->connectors[i]->active_lease = NULL;
|
||||
}
|
||||
|
||||
wl_list_remove(&lease->link);
|
||||
wl_resource_set_user_data(lease->resource, NULL);
|
||||
|
||||
free(lease->connectors);
|
||||
free(lease);
|
||||
}
|
||||
|
||||
|
|
@ -180,20 +171,6 @@ struct wlr_drm_lease_v1 *wlr_drm_lease_request_v1_grant(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
lease->connectors = calloc(request->n_connectors, sizeof(*lease->connectors));
|
||||
if (!lease->connectors) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate lease connectors list");
|
||||
close(fd);
|
||||
wp_drm_lease_v1_send_finished(lease->resource);
|
||||
free(lease);
|
||||
return NULL;
|
||||
}
|
||||
lease->n_connectors = request->n_connectors;
|
||||
for (size_t i = 0; i < request->n_connectors; ++i) {
|
||||
lease->connectors[i] = request->connectors[i];
|
||||
lease->connectors[i]->active_lease = lease;
|
||||
}
|
||||
|
||||
lease->destroy.notify = lease_handle_destroy;
|
||||
wl_signal_add(&lease->drm_lease->events.destroy, &lease->destroy);
|
||||
|
||||
|
|
@ -338,16 +315,6 @@ static void drm_lease_request_v1_handle_submit(
|
|||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < request->n_connectors; ++i) {
|
||||
struct wlr_drm_lease_connector_v1 *conn = request->connectors[i];
|
||||
if (conn->active_lease) {
|
||||
wlr_log(WLR_ERROR, "Failed to create lease, connector %s has "
|
||||
"already been leased", conn->output->name);
|
||||
wp_drm_lease_v1_send_finished(lease_resource);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
request->lease_resource = lease_resource;
|
||||
|
||||
wl_signal_emit_mutable(&request->device->manager->events.request,
|
||||
|
|
@ -440,10 +407,6 @@ static struct wp_drm_lease_connector_v1_interface lease_connector_impl = {
|
|||
static void drm_lease_connector_v1_send_to_client(
|
||||
struct wlr_drm_lease_connector_v1 *connector,
|
||||
struct wl_resource *resource) {
|
||||
if (connector->active_lease) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wl_client *client = wl_resource_get_client(resource);
|
||||
|
||||
uint32_t version = wl_resource_get_version(resource);
|
||||
|
|
@ -490,10 +453,12 @@ static void lease_device_bind(struct wl_client *wl_client, void *data,
|
|||
if (!device) {
|
||||
wlr_log(WLR_DEBUG, "Failed to bind lease device, "
|
||||
"the wlr_drm_lease_device_v1 has been destroyed");
|
||||
wl_list_init(wl_resource_get_link(device_resource));
|
||||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_user_data(device_resource, device);
|
||||
wl_list_insert(&device->resources, wl_resource_get_link(device_resource));
|
||||
|
||||
int fd = wlr_drm_backend_get_non_master_fd(device->backend);
|
||||
if (fd < 0) {
|
||||
|
|
@ -505,8 +470,6 @@ static void lease_device_bind(struct wl_client *wl_client, void *data,
|
|||
wp_drm_lease_device_v1_send_drm_fd(device_resource, fd);
|
||||
close(fd);
|
||||
|
||||
wl_list_insert(&device->resources, wl_resource_get_link(device_resource));
|
||||
|
||||
struct wlr_drm_lease_connector_v1 *connector;
|
||||
wl_list_for_each(connector, &device->connectors, link) {
|
||||
drm_lease_connector_v1_send_to_client(connector, device_resource);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include "ext-image-copy-capture-v1-protocol.h"
|
||||
#include "render/pixel_format.h"
|
||||
|
||||
#define IMAGE_COPY_CAPTURE_MANAGER_V1_VERSION 1
|
||||
|
|
|
|||
65
types/wlr_fixes.c
Normal file
65
types/wlr_fixes.c
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#include <assert.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <wlr/types/wlr_fixes.h>
|
||||
|
||||
#define FIXES_VERSION 1
|
||||
|
||||
static void fixes_destroy(struct wl_client *client, struct wl_resource *resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void fixes_destroy_registry(struct wl_client *client, struct wl_resource *resource,
|
||||
struct wl_resource *registry) {
|
||||
wl_resource_destroy(registry);
|
||||
}
|
||||
|
||||
static const struct wl_fixes_interface fixes_impl = {
|
||||
.destroy = fixes_destroy,
|
||||
.destroy_registry = fixes_destroy_registry,
|
||||
};
|
||||
|
||||
static void fixes_bind(struct wl_client *wl_client, void *data, uint32_t version, uint32_t id) {
|
||||
struct wlr_fixes *fixes = data;
|
||||
|
||||
struct wl_resource *resource = wl_resource_create(wl_client, &wl_fixes_interface, version, id);
|
||||
if (resource == NULL) {
|
||||
wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(resource, &fixes_impl, fixes, NULL);
|
||||
}
|
||||
|
||||
static void fixes_handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_fixes *fixes = wl_container_of(listener, fixes, display_destroy);
|
||||
wl_signal_emit_mutable(&fixes->events.destroy, NULL);
|
||||
|
||||
assert(wl_list_empty(&fixes->events.destroy.listener_list));
|
||||
|
||||
wl_list_remove(&fixes->display_destroy.link);
|
||||
wl_global_destroy(fixes->global);
|
||||
free(fixes);
|
||||
}
|
||||
|
||||
struct wlr_fixes *wlr_fixes_create(struct wl_display *display, uint32_t version) {
|
||||
assert(version <= FIXES_VERSION);
|
||||
|
||||
struct wlr_fixes *fixes = calloc(1, sizeof(*fixes));
|
||||
if (fixes == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fixes->global = wl_global_create(display, &wl_fixes_interface, version, fixes, fixes_bind);
|
||||
if (fixes->global == NULL) {
|
||||
free(fixes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_signal_init(&fixes->events.destroy);
|
||||
|
||||
fixes->display_destroy.notify = fixes_handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &fixes->display_destroy);
|
||||
|
||||
return fixes;
|
||||
}
|
||||
|
|
@ -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);
|
||||
if (gamma_size == 0) {
|
||||
gamma_size = manager->fallback_gamma_size;
|
||||
}
|
||||
if (gamma_size == 0) {
|
||||
zwlr_gamma_control_v1_send_failed(resource);
|
||||
return;
|
||||
|
|
@ -262,15 +265,24 @@ struct wlr_gamma_control_v1 *wlr_gamma_control_manager_v1_get_control(
|
|||
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,
|
||||
struct wlr_output_state *output_state) {
|
||||
struct wlr_color_transform *tr = NULL;
|
||||
if (gamma_control != NULL && gamma_control->table != 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;
|
||||
|
||||
tr = wlr_color_transform_init_lut_3x1d(gamma_control->ramp_size, r, g, b);
|
||||
tr = wlr_gamma_control_v1_get_color_transform(gamma_control);
|
||||
if (tr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ static void input_method_destroy(struct wlr_input_method_v2 *input_method) {
|
|||
popup_surface, tmp, &input_method->popup_surfaces, link) {
|
||||
popup_surface_destroy(popup_surface);
|
||||
}
|
||||
wl_signal_emit_mutable(&input_method->events.destroy, input_method);
|
||||
wlr_input_method_keyboard_grab_v2_destroy(input_method->keyboard_grab);
|
||||
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.new_popup_surface.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(&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->current);
|
||||
free(input_method);
|
||||
|
|
@ -102,7 +102,7 @@ static void im_commit(struct wl_client *client, struct wl_resource *resource,
|
|||
input_method->current = input_method->pending;
|
||||
input_method->pending = (struct wlr_input_method_v2_state){0};
|
||||
|
||||
wl_signal_emit_mutable(&input_method->events.commit, input_method);
|
||||
wl_signal_emit_mutable(&input_method->events.commit, NULL);
|
||||
}
|
||||
|
||||
static void im_commit_string(struct wl_client *client,
|
||||
|
|
@ -271,8 +271,7 @@ void wlr_input_method_keyboard_grab_v2_destroy(
|
|||
if (!keyboard_grab) {
|
||||
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));
|
||||
|
||||
keyboard_grab->input_method->keyboard_grab = NULL;
|
||||
|
|
@ -575,7 +574,7 @@ static void manager_get_input_method(struct wl_client *client,
|
|||
wl_resource_set_user_data(im_resource, input_method);
|
||||
wl_list_insert(&im_manager->input_methods,
|
||||
wl_resource_get_link(input_method->resource));
|
||||
wl_signal_emit_mutable(&im_manager->events.input_method, input_method);
|
||||
wl_signal_emit_mutable(&im_manager->events.new_input_method, input_method);
|
||||
}
|
||||
|
||||
static void manager_destroy(struct wl_client *client,
|
||||
|
|
@ -606,9 +605,9 @@ static void input_method_manager_bind(struct wl_client *wl_client, void *data,
|
|||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_input_method_manager_v2 *manager =
|
||||
wl_container_of(listener, manager, display_destroy);
|
||||
wl_signal_emit_mutable(&manager->events.destroy, manager);
|
||||
wl_signal_emit_mutable(&manager->events.destroy, NULL);
|
||||
|
||||
assert(wl_list_empty(&manager->events.input_method.listener_list));
|
||||
assert(wl_list_empty(&manager->events.new_input_method.listener_list));
|
||||
assert(wl_list_empty(&manager->events.destroy.listener_list));
|
||||
|
||||
wl_list_remove(&manager->display_destroy.link);
|
||||
|
|
@ -623,7 +622,7 @@ struct wlr_input_method_manager_v2 *wlr_input_method_manager_v2_create(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
wl_signal_init(&im_manager->events.input_method);
|
||||
wl_signal_init(&im_manager->events.new_input_method);
|
||||
wl_signal_init(&im_manager->events.destroy);
|
||||
|
||||
wl_list_init(&im_manager->input_methods);
|
||||
|
|
|
|||
|
|
@ -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 *surface;
|
||||
struct wlr_surface *surface;
|
||||
struct wlr_drm_syncobj_timeline_waiter waiter;
|
||||
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) {
|
||||
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);
|
||||
wlr_drm_syncobj_timeline_waiter_finish(&commit->waiter);
|
||||
free(commit);
|
||||
|
|
@ -237,7 +237,7 @@ static bool lock_surface_commit(struct wlr_linux_drm_syncobj_surface_v1 *surface
|
|||
return false;
|
||||
}
|
||||
|
||||
commit->surface = surface;
|
||||
commit->surface = surface->surface;
|
||||
commit->cached_seq = wlr_surface_lock_pending(surface->surface);
|
||||
|
||||
commit->surface_destroy.notify = surface_commit_handle_surface_destroy;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "pointer-constraints-unstable-v1-protocol.h"
|
||||
|
||||
static const struct zwp_locked_pointer_v1_interface locked_pointer_impl;
|
||||
static const struct zwp_confined_pointer_v1_interface confined_pointer_impl;
|
||||
static const struct zwp_pointer_constraints_v1_interface pointer_constraints_impl;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ static void manager_create_transient_seat(struct wl_client *client,
|
|||
wl_resource_set_implementation(seat->resource, &transient_seat_impl,
|
||||
seat, transient_seat_handle_resource_destroy);
|
||||
|
||||
wl_list_init(&seat->seat_destroy.link);
|
||||
wl_signal_emit_mutable(&manager->events.create_seat, seat);
|
||||
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ static void manager_handle_create_icon(struct wl_client *client, struct wl_resou
|
|||
|
||||
struct wl_resource *icon_resource = wl_resource_create(client,
|
||||
&xdg_toplevel_icon_v1_interface, wl_resource_get_version(resource), id);
|
||||
if (resource == NULL) {
|
||||
if (icon_resource == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
free(icon);
|
||||
return;
|
||||
|
|
|
|||
104
types/wlr_xdg_toplevel_tag_v1.c
Normal file
104
types/wlr_xdg_toplevel_tag_v1.c
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/types/wlr_xdg_toplevel_tag_v1.h>
|
||||
|
||||
#include "xdg-toplevel-tag-v1-protocol.h"
|
||||
|
||||
#define MANAGER_VERSION 1
|
||||
|
||||
static const struct xdg_toplevel_tag_manager_v1_interface manager_impl;
|
||||
|
||||
static struct wlr_xdg_toplevel_tag_manager_v1 *manager_from_resource(
|
||||
struct wl_resource *resource) {
|
||||
assert(wl_resource_instance_of(resource, &xdg_toplevel_tag_manager_v1_interface, &manager_impl));
|
||||
return wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
static void manager_handle_set_tag(struct wl_client *client, struct wl_resource *manager_resource,
|
||||
struct wl_resource *toplevel_resource, const char *tag) {
|
||||
struct wlr_xdg_toplevel_tag_manager_v1 *manager = manager_from_resource(manager_resource);
|
||||
struct wlr_xdg_toplevel *toplevel = wlr_xdg_toplevel_from_resource(toplevel_resource);
|
||||
|
||||
struct wlr_xdg_toplevel_tag_manager_v1_set_tag_event event = {
|
||||
.toplevel = toplevel,
|
||||
.tag = tag,
|
||||
};
|
||||
wl_signal_emit_mutable(&manager->events.set_tag, &event);
|
||||
}
|
||||
|
||||
static void manager_handle_set_description(struct wl_client *client, struct wl_resource *manager_resource,
|
||||
struct wl_resource *toplevel_resource, const char *description) {
|
||||
struct wlr_xdg_toplevel_tag_manager_v1 *manager = manager_from_resource(manager_resource);
|
||||
struct wlr_xdg_toplevel *toplevel = wlr_xdg_toplevel_from_resource(toplevel_resource);
|
||||
|
||||
struct wlr_xdg_toplevel_tag_manager_v1_set_description_event event = {
|
||||
.toplevel = toplevel,
|
||||
.description = description,
|
||||
};
|
||||
wl_signal_emit_mutable(&manager->events.set_description, &event);
|
||||
}
|
||||
|
||||
static void manager_handle_destroy(struct wl_client *client, struct wl_resource *manager_resource) {
|
||||
wl_resource_destroy(manager_resource);
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_tag_manager_v1_interface manager_impl = {
|
||||
.destroy = manager_handle_destroy,
|
||||
.set_toplevel_tag = manager_handle_set_tag,
|
||||
.set_toplevel_description = manager_handle_set_description,
|
||||
};
|
||||
|
||||
static void manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) {
|
||||
struct wlr_xdg_toplevel_tag_manager_v1 *manager = data;
|
||||
|
||||
struct wl_resource *resource = wl_resource_create(client,
|
||||
&xdg_toplevel_tag_manager_v1_interface, version, id);
|
||||
if (resource == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(resource, &manager_impl, manager, NULL);
|
||||
}
|
||||
|
||||
static void manager_handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_xdg_toplevel_tag_manager_v1 *manager =
|
||||
wl_container_of(listener, manager, display_destroy);
|
||||
|
||||
wl_signal_emit_mutable(&manager->events.destroy, NULL);
|
||||
|
||||
assert(wl_list_empty(&manager->events.set_tag.listener_list));
|
||||
assert(wl_list_empty(&manager->events.set_description.listener_list));
|
||||
assert(wl_list_empty(&manager->events.destroy.listener_list));
|
||||
|
||||
wl_list_remove(&manager->display_destroy.link);
|
||||
wl_global_destroy(manager->global);
|
||||
free(manager);
|
||||
}
|
||||
|
||||
struct wlr_xdg_toplevel_tag_manager_v1 *wlr_xdg_toplevel_tag_manager_v1_create(
|
||||
struct wl_display *display, uint32_t version) {
|
||||
assert(version <= MANAGER_VERSION);
|
||||
|
||||
struct wlr_xdg_toplevel_tag_manager_v1 *manager = calloc(1, sizeof(*manager));
|
||||
if (manager == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
manager->global = wl_global_create(display, &xdg_toplevel_tag_manager_v1_interface,
|
||||
version, manager, manager_bind);
|
||||
if (manager->global == NULL) {
|
||||
free(manager);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_signal_init(&manager->events.set_tag);
|
||||
wl_signal_init(&manager->events.set_description);
|
||||
wl_signal_init(&manager->events.destroy);
|
||||
|
||||
manager->display_destroy.notify = manager_handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &manager->display_destroy);
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
#include "types/wlr_xdg_shell.h"
|
||||
|
||||
void handle_xdg_popup_ack_configure(
|
||||
|
|
@ -52,6 +53,18 @@ static void xdg_popup_grab_end(struct wlr_xdg_popup_grab *popup_grab) {
|
|||
static void xdg_pointer_grab_enter(struct wlr_seat_pointer_grab *grab,
|
||||
struct wlr_surface *surface, double sx, double sy) {
|
||||
struct wlr_xdg_popup_grab *popup_grab = grab->data;
|
||||
struct wlr_seat *seat = grab->seat;
|
||||
|
||||
// Forward to drag grab if active
|
||||
if (seat->drag && seat->drag->pointer_grab.interface &&
|
||||
seat->drag->pointer_grab.interface->enter) {
|
||||
if (grab != &seat->drag->pointer_grab) {
|
||||
seat->drag->pointer_grab.interface->enter(&seat->drag->pointer_grab,
|
||||
surface, sx, sy);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (wl_resource_get_client(surface->resource) == popup_grab->client) {
|
||||
wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
|
||||
} else {
|
||||
|
|
@ -65,13 +78,33 @@ static void xdg_pointer_grab_clear_focus(struct wlr_seat_pointer_grab *grab) {
|
|||
|
||||
static void xdg_pointer_grab_motion(struct wlr_seat_pointer_grab *grab,
|
||||
uint32_t time, double sx, double sy) {
|
||||
struct wlr_seat *seat = grab->seat;
|
||||
|
||||
if (seat->drag && seat->drag->pointer_grab.interface &&
|
||||
seat->drag->pointer_grab.interface->motion) {
|
||||
if (grab != &seat->drag->pointer_grab) {
|
||||
seat->drag->pointer_grab.interface->motion(&seat->drag->pointer_grab,
|
||||
time, sx, sy);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
|
||||
}
|
||||
|
||||
static uint32_t xdg_pointer_grab_button(struct wlr_seat_pointer_grab *grab,
|
||||
uint32_t time, uint32_t button, uint32_t state) {
|
||||
uint32_t serial =
|
||||
wlr_seat_pointer_send_button(grab->seat, time, button, state);
|
||||
struct wlr_seat *seat = grab->seat;
|
||||
|
||||
if (seat->drag && seat->drag->pointer_grab.interface &&
|
||||
seat->drag->pointer_grab.interface->button) {
|
||||
if (grab != &seat->drag->pointer_grab) {
|
||||
return seat->drag->pointer_grab.interface->button(&seat->drag->pointer_grab,
|
||||
time, button, state);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t serial = wlr_seat_pointer_send_button(grab->seat, time, button, state);
|
||||
if (serial) {
|
||||
return serial;
|
||||
} else {
|
||||
|
|
@ -84,11 +117,32 @@ static void xdg_pointer_grab_axis(struct wlr_seat_pointer_grab *grab,
|
|||
uint32_t time, enum wl_pointer_axis orientation, double value,
|
||||
int32_t value_discrete, enum wl_pointer_axis_source source,
|
||||
enum wl_pointer_axis_relative_direction relative_direction) {
|
||||
struct wlr_seat *seat = grab->seat;
|
||||
|
||||
if (seat->drag && seat->drag->pointer_grab.interface &&
|
||||
seat->drag->pointer_grab.interface->axis) {
|
||||
if (grab != &seat->drag->pointer_grab) {
|
||||
seat->drag->pointer_grab.interface->axis(&seat->drag->pointer_grab,
|
||||
time, orientation, value, value_discrete, source, relative_direction);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_seat_pointer_send_axis(grab->seat, time, orientation, value,
|
||||
value_discrete, source, relative_direction);
|
||||
}
|
||||
|
||||
static void xdg_pointer_grab_frame(struct wlr_seat_pointer_grab *grab) {
|
||||
struct wlr_seat *seat = grab->seat;
|
||||
|
||||
if (seat->drag && seat->drag->pointer_grab.interface &&
|
||||
seat->drag->pointer_grab.interface->frame) {
|
||||
if (grab != &seat->drag->pointer_grab) {
|
||||
seat->drag->pointer_grab.interface->frame(&seat->drag->pointer_grab);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_seat_pointer_send_frame(grab->seat);
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +164,11 @@ static void xdg_keyboard_grab_enter(struct wlr_seat_keyboard_grab *grab,
|
|||
struct wlr_surface *surface, const uint32_t keycodes[], size_t num_keycodes,
|
||||
const struct wlr_keyboard_modifiers *modifiers) {
|
||||
// keyboard focus should remain on the popup
|
||||
if (grab->seat->drag) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers);
|
||||
}
|
||||
|
||||
static void xdg_keyboard_grab_clear_focus(struct wlr_seat_keyboard_grab *grab) {
|
||||
|
|
|
|||
20
util/box.c
20
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(),
|
||||
// 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
|
||||
// but large enough to avoid rounding to zero (due to loss of
|
||||
// significant digits) in simple floating-point calculations.
|
||||
// but large enough to avoid rounding to zero in wl_fixed_from_double().
|
||||
|
||||
// find the closest x point
|
||||
if (x < box->x) {
|
||||
*dest_x = box->x;
|
||||
} else if (x > box->x + box->width - 1/65536.0) {
|
||||
*dest_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/256.0;
|
||||
} else {
|
||||
*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
|
||||
if (y < box->y) {
|
||||
*dest_y = box->y;
|
||||
} else if (y > box->y + box->height - 1/65536.0) {
|
||||
*dest_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/256.0;
|
||||
} else {
|
||||
*dest_y = y;
|
||||
}
|
||||
|
|
@ -67,7 +66,12 @@ bool wlr_box_intersection(struct wlr_box *dest, const struct wlr_box *box_a,
|
|||
dest->width = x2 - x1;
|
||||
dest->height = y2 - y1;
|
||||
|
||||
return !wlr_box_empty(dest);
|
||||
if (wlr_box_empty(dest)) {
|
||||
*dest = (struct wlr_box){0};
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wlr_box_contains_point(const struct wlr_box *box, double x, double y) {
|
||||
|
|
|
|||
16
util/mem.c
Normal file
16
util/mem.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util/mem.h"
|
||||
|
||||
bool memdup(void *out, const void *src, size_t size) {
|
||||
void *dst = malloc(size);
|
||||
if (dst == NULL) {
|
||||
return false;
|
||||
}
|
||||
memcpy(dst, src, size);
|
||||
void **dst_ptr = out;
|
||||
*dst_ptr = dst;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ wlr_files += files(
|
|||
'global.c',
|
||||
'log.c',
|
||||
'matrix.c',
|
||||
'mem.c',
|
||||
'rect_union.c',
|
||||
'region.c',
|
||||
'set.c',
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ static void handle_server_start(struct wl_listener *listener, void *data) {
|
|||
static void xwayland_mark_ready(struct wlr_xwayland *xwayland) {
|
||||
assert(xwayland->server->wm_fd[0] >= 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) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -69,6 +72,11 @@ static void handle_shell_destroy(struct wl_listener *listener, void *data) {
|
|||
struct wlr_xwayland *xwayland =
|
||||
wl_container_of(listener, xwayland, shell_destroy);
|
||||
xwayland->shell_v1 = NULL;
|
||||
wl_list_remove(&xwayland->shell_destroy.link);
|
||||
// Will remove this list in handle_shell_destroy().
|
||||
// This ensures the link is always initialized and
|
||||
// avoids the need to keep check conditions in sync.
|
||||
wl_list_init(&xwayland->shell_destroy.link);
|
||||
}
|
||||
|
||||
void wlr_xwayland_destroy(struct wlr_xwayland *xwayland) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ static const char *const atom_map[ATOM_LAST] = {
|
|||
[NET_WM_STATE] = "_NET_WM_STATE",
|
||||
[NET_WM_STRUT_PARTIAL] = "_NET_WM_STRUT_PARTIAL",
|
||||
[NET_WM_WINDOW_TYPE] = "_NET_WM_WINDOW_TYPE",
|
||||
[NET_WM_ICON] = "_NET_WM_ICON",
|
||||
[WM_TAKE_FOCUS] = "WM_TAKE_FOCUS",
|
||||
[WINDOW] = "WINDOW",
|
||||
[NET_ACTIVE_WINDOW] = "_NET_ACTIVE_WINDOW",
|
||||
|
|
@ -241,6 +242,7 @@ static struct wlr_xwayland_surface *xwayland_surface_create(
|
|||
wl_signal_init(&surface->events.set_override_redirect);
|
||||
wl_signal_init(&surface->events.set_geometry);
|
||||
wl_signal_init(&surface->events.set_opacity);
|
||||
wl_signal_init(&surface->events.set_icon);
|
||||
wl_signal_init(&surface->events.focus_in);
|
||||
wl_signal_init(&surface->events.grab_focus);
|
||||
wl_signal_init(&surface->events.map_request);
|
||||
|
|
@ -602,6 +604,7 @@ static void xwayland_surface_destroy(struct wlr_xwayland_surface *xsurface) {
|
|||
assert(wl_list_empty(&xsurface->events.set_override_redirect.listener_list));
|
||||
assert(wl_list_empty(&xsurface->events.set_geometry.listener_list));
|
||||
assert(wl_list_empty(&xsurface->events.set_opacity.listener_list));
|
||||
assert(wl_list_empty(&xsurface->events.set_icon.listener_list));
|
||||
assert(wl_list_empty(&xsurface->events.focus_in.listener_list));
|
||||
assert(wl_list_empty(&xsurface->events.grab_focus.listener_list));
|
||||
assert(wl_list_empty(&xsurface->events.map_request.listener_list));
|
||||
|
|
@ -1078,6 +1081,8 @@ static void read_surface_property(struct wlr_xwm *xwm,
|
|||
// intentionally ignored
|
||||
} else if (property == xwm->atoms[NET_WM_WINDOW_TYPE]) {
|
||||
read_surface_window_type(xwm, xsurface, reply);
|
||||
} else if (property == xwm->atoms[NET_WM_ICON]) {
|
||||
wl_signal_emit_mutable(&xsurface->events.set_icon, NULL);
|
||||
} else if (property == xwm->atoms[WM_PROTOCOLS]) {
|
||||
read_surface_protocols(xwm, xsurface, reply);
|
||||
} else if (property == xwm->atoms[NET_WM_STATE]) {
|
||||
|
|
@ -1131,6 +1136,38 @@ static const struct wlr_addon_interface surface_addon_impl = {
|
|||
.destroy = xwayland_surface_handle_addon_destroy,
|
||||
};
|
||||
|
||||
bool wlr_xwayland_surface_fetch_icon(
|
||||
const struct wlr_xwayland_surface *xsurface,
|
||||
xcb_ewmh_get_wm_icon_reply_t *icon_reply) {
|
||||
struct wlr_xwm *xwm = xsurface->xwm;
|
||||
|
||||
xcb_get_property_cookie_t cookie = xcb_get_property(xwm->xcb_conn, 0,
|
||||
xsurface->window_id, xwm->atoms[NET_WM_ICON], XCB_ATOM_CARDINAL,
|
||||
0, UINT32_MAX);
|
||||
xcb_get_property_reply_t *reply =
|
||||
xcb_get_property_reply(xwm->xcb_conn, cookie, NULL);
|
||||
if (!reply) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!xcb_ewmh_get_wm_icon_from_reply(icon_reply, reply)) {
|
||||
free(reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static xcb_get_property_cookie_t get_property(struct wlr_xwm *xwm,
|
||||
xcb_window_t window_id, xcb_atom_t atom) {
|
||||
uint32_t len = 2048;
|
||||
if (atom == xwm->atoms[NET_WM_ICON]) {
|
||||
/* Compositors need to fetch icon data wlr_xwayland_surface_fetch_icon() */
|
||||
len = 0;
|
||||
}
|
||||
return xcb_get_property(xwm->xcb_conn, 0, window_id, atom, XCB_ATOM_ANY, 0, len);
|
||||
}
|
||||
|
||||
static void xwayland_surface_associate(struct wlr_xwm *xwm,
|
||||
struct wlr_xwayland_surface *xsurface, struct wlr_surface *surface) {
|
||||
assert(xsurface->surface == NULL);
|
||||
|
|
@ -1165,12 +1202,12 @@ static void xwayland_surface_associate(struct wlr_xwm *xwm,
|
|||
xwm->atoms[NET_WM_STRUT_PARTIAL],
|
||||
xwm->atoms[NET_WM_WINDOW_TYPE],
|
||||
xwm->atoms[NET_WM_NAME],
|
||||
xwm->atoms[NET_WM_ICON],
|
||||
};
|
||||
|
||||
xcb_get_property_cookie_t cookies[sizeof(props) / sizeof(props[0])] = {0};
|
||||
for (size_t i = 0; i < sizeof(props) / sizeof(props[0]); i++) {
|
||||
cookies[i] = xcb_get_property(xwm->xcb_conn, 0, xsurface->window_id,
|
||||
props[i], XCB_ATOM_ANY, 0, 2048);
|
||||
cookies[i] = get_property(xwm, xsurface->window_id, props[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(props) / sizeof(props[0]); i++) {
|
||||
|
|
@ -1398,8 +1435,7 @@ static void xwm_handle_property_notify(struct wlr_xwm *xwm,
|
|||
return;
|
||||
}
|
||||
|
||||
xcb_get_property_cookie_t cookie =
|
||||
xcb_get_property(xwm->xcb_conn, 0, xsurface->window_id, ev->atom, XCB_ATOM_ANY, 0, 2048);
|
||||
xcb_get_property_cookie_t cookie = get_property(xwm, xsurface->window_id, ev->atom);
|
||||
xcb_get_property_reply_t *reply =
|
||||
xcb_get_property_reply(xwm->xcb_conn, cookie, NULL);
|
||||
if (reply == NULL) {
|
||||
|
|
@ -2494,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 = calloc(1, sizeof(*xwm));
|
||||
if (xwm == NULL) {
|
||||
close(wm_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -2508,11 +2545,13 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
|
|||
|
||||
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);
|
||||
|
||||
int rc = xcb_connection_has_error(xwm->xcb_conn);
|
||||
if (rc) {
|
||||
wlr_log(WLR_ERROR, "xcb connect failed: %d", rc);
|
||||
xcb_disconnect(xwm->xcb_conn);
|
||||
free(xwm);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue