mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
Compare commits
174 commits
0.19.0-rc2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
604fcdb1db | ||
|
|
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 | ||
|
|
a30c102163 | ||
|
|
bfcb4211f6 | ||
|
|
f10dd1da1c | ||
|
|
97f6946c8d | ||
|
|
74217a4d93 | ||
|
|
3665b53e29 | ||
|
|
9b97e2607d | ||
|
|
d421538b4a | ||
|
|
c6133f9912 | ||
|
|
6204fc3278 | ||
|
|
51d051497d | ||
|
|
8713ac72fb | ||
|
|
95b2771bfd | ||
|
|
da820070f4 | ||
|
|
b066fd6b5a | ||
|
|
8fb4e4dabb | ||
|
|
bb50c7a5a4 | ||
|
|
221b37355f | ||
|
|
37992cf3b8 | ||
|
|
6c78225160 | ||
|
|
83a5bdf5d5 | ||
|
|
afe427d149 | ||
|
|
a08acfcee0 | ||
|
|
af43d3b9e7 | ||
|
|
aaeffe9769 | ||
|
|
fae4c5097d | ||
|
|
170f7e0706 | ||
|
|
2d5492c737 | ||
|
|
536100488f | ||
|
|
62c86fb975 | ||
|
|
c2327248f8 | ||
|
|
c9f0dbc159 | ||
|
|
f04ef79f61 | ||
|
|
13a62a23a2 | ||
|
|
af34aaad53 | ||
|
|
2420bfef0b | ||
|
|
70add22e74 | ||
|
|
f36f856cdb | ||
|
|
aef4de2ced | ||
|
|
e57dd9c5ef | ||
|
|
d4e4c9f64b | ||
|
|
22db307e4c | ||
|
|
156d47c866 | ||
|
|
80f33cd350 | ||
|
|
7dd8fdf76c | ||
|
|
648aee65ad | ||
|
|
86976870bd | ||
|
|
bd8454d3bc | ||
|
|
e9450a9947 | ||
|
|
78aaaaf7b6 |
122 changed files with 3672 additions and 920 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/iface.h"
|
||||
#include "backend/drm/util.h"
|
||||
#include "render/color.h"
|
||||
|
||||
static char *atomic_commit_flags_str(uint32_t flags) {
|
||||
const char *const l[] = {
|
||||
|
|
@ -177,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:
|
||||
|
|
@ -251,19 +331,25 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
}
|
||||
|
||||
uint32_t gamma_lut = crtc->gamma_lut;
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
size_t dim = 0;
|
||||
uint16_t *lut = NULL;
|
||||
if (state->base->color_transform != NULL) {
|
||||
struct wlr_color_transform_lut_3x1d *tr =
|
||||
color_transform_lut_3x1d_from_base(state->base->color_transform);
|
||||
dim = tr->dim;
|
||||
lut = tr->lut_3x1d;
|
||||
}
|
||||
|
||||
// Fallback to legacy gamma interface when gamma properties are not
|
||||
// available (can happen on older Intel GPUs that support gamma but not
|
||||
// degamma).
|
||||
if (crtc->props.gamma_lut == 0) {
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc,
|
||||
state->base->gamma_lut_size,
|
||||
state->base->gamma_lut)) {
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!create_gamma_lut_blob(drm, state->base->gamma_lut_size,
|
||||
state->base->gamma_lut, &gamma_lut)) {
|
||||
if (!create_gamma_lut_blob(drm, dim, lut, &gamma_lut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -295,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;
|
||||
}
|
||||
|
||||
|
|
@ -314,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;
|
||||
|
|
@ -328,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) {
|
||||
|
|
@ -337,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) {
|
||||
|
|
@ -428,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) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/iface.h"
|
||||
#include "backend/drm/util.h"
|
||||
#include "render/color.h"
|
||||
#include "types/wlr_output.h"
|
||||
#include "util/env.h"
|
||||
#include "config.h"
|
||||
|
|
@ -37,11 +38,12 @@ static const uint32_t COMMIT_OUTPUT_STATE =
|
|||
WLR_OUTPUT_STATE_BUFFER |
|
||||
WLR_OUTPUT_STATE_MODE |
|
||||
WLR_OUTPUT_STATE_ENABLED |
|
||||
WLR_OUTPUT_STATE_GAMMA_LUT |
|
||||
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED |
|
||||
WLR_OUTPUT_STATE_LAYERS |
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE;
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
|
||||
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;
|
||||
|
|
@ -170,7 +172,7 @@ static bool init_plane(struct wlr_drm_backend *drm,
|
|||
}
|
||||
|
||||
p->type = type;
|
||||
p->id = drm_plane->plane_id;
|
||||
p->id = id;
|
||||
p->props = props;
|
||||
p->initial_crtc_id = drm_plane->crtc_id;
|
||||
|
||||
|
|
@ -856,6 +858,19 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
|
|||
}
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) && state->color_transform != NULL &&
|
||||
state->color_transform->type != COLOR_TRANSFORM_LUT_3X1D) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Only 3x1D LUT color transforms are supported");
|
||||
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.
|
||||
|
|
@ -1531,14 +1546,14 @@ static struct wlr_drm_connector *create_drm_connector(struct wlr_drm_backend *dr
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const char *conn_name =
|
||||
const char *conn_type_name =
|
||||
drmModeGetConnectorTypeName(drm_conn->connector_type);
|
||||
if (conn_name == NULL) {
|
||||
conn_name = "Unknown";
|
||||
if (conn_type_name == NULL) {
|
||||
conn_type_name = "Unknown";
|
||||
}
|
||||
|
||||
snprintf(wlr_conn->name, sizeof(wlr_conn->name),
|
||||
"%s-%"PRIu32, conn_name, drm_conn->connector_type_id);
|
||||
"%s-%"PRIu32, conn_type_name, drm_conn->connector_type_id);
|
||||
|
||||
wlr_conn->possible_crtcs =
|
||||
drmModeConnectorGetPossibleCrtcs(drm->fd, drm_conn);
|
||||
|
|
@ -1702,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);
|
||||
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 @@
|
|||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/iface.h"
|
||||
#include "backend/drm/util.h"
|
||||
#include "render/color.h"
|
||||
#include "types/wlr_output.h"
|
||||
|
||||
static bool legacy_fb_props_match(struct wlr_drm_fb *fb1,
|
||||
|
|
@ -124,9 +125,17 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
|
|||
}
|
||||
}
|
||||
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc,
|
||||
state->base->gamma_lut_size, state->base->gamma_lut)) {
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
size_t dim = 0;
|
||||
uint16_t *lut = NULL;
|
||||
if (state->base->color_transform != NULL) {
|
||||
struct wlr_color_transform_lut_3x1d *tr =
|
||||
color_transform_lut_3x1d_from_base(state->base->color_transform);
|
||||
dim = tr->dim;
|
||||
lut = tr->lut_3x1d;
|
||||
}
|
||||
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,17 +331,16 @@ static bool add_connector(drmModeAtomicReq *req,
|
|||
if (crtc->props.vrr_enabled != 0) {
|
||||
ok = ok && add_prop(req, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
|
||||
}
|
||||
struct wlr_fbox src_box;
|
||||
struct wlr_box dst_box;
|
||||
output_state_get_buffer_src_box(state->base, &src_box);
|
||||
output_state_get_buffer_dst_box(state->base, &dst_box);
|
||||
|
||||
ok = ok &&
|
||||
set_plane_props(crtc->primary, crtc->primary->liftoff_layer,
|
||||
state->primary_fb, 0, &dst_box, &src_box);
|
||||
ok = ok &&
|
||||
set_plane_props(crtc->primary, crtc->liftoff_composition_layer,
|
||||
state->primary_fb, 0, &dst_box, &src_box);
|
||||
ok = ok && set_plane_props(crtc->primary,
|
||||
crtc->primary->liftoff_layer, state->primary_fb, 0,
|
||||
&state->primary_viewport.dst_box,
|
||||
&state->primary_viewport.src_box);
|
||||
ok = ok && set_plane_props(crtc->primary,
|
||||
crtc->liftoff_composition_layer, state->primary_fb, 0,
|
||||
&state->primary_viewport.dst_box,
|
||||
&state->primary_viewport.src_box);
|
||||
|
||||
liftoff_layer_set_property(crtc->primary->liftoff_layer,
|
||||
"FB_DAMAGE_CLIPS", state->fb_damage_clips);
|
||||
liftoff_layer_set_property(crtc->liftoff_composition_layer,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ void init_device_tablet_pad(struct wlr_libinput_input_device *dev) {
|
|||
struct udev_device *udev = libinput_device_get_udev_device(handle);
|
||||
char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *));
|
||||
*dst = strdup(udev_device_get_syspath(udev));
|
||||
udev_device_unref(udev);
|
||||
|
||||
int groups = libinput_device_tablet_pad_get_num_mode_groups(handle);
|
||||
for (int i = 0; i < groups; ++i) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ void init_device_tablet(struct wlr_libinput_input_device *dev) {
|
|||
struct udev_device *udev = libinput_device_get_udev_device(dev->handle);
|
||||
char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *));
|
||||
*dst = strdup(udev_device_get_syspath(udev));
|
||||
udev_device_unref(udev);
|
||||
|
||||
wl_list_init(&dev->tablet_tools);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,6 +534,11 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -540,7 +546,8 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
if (pci) {
|
||||
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
||||
if (id && strcmp(id, "1") == 0) {
|
||||
is_boot_vga = true;
|
||||
is_primary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -554,7 +561,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
udev_device_unref(dev);
|
||||
|
||||
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,8 +6,10 @@
|
|||
#include <wlr/util/addon.h>
|
||||
|
||||
enum wlr_color_transform_type {
|
||||
COLOR_TRANSFORM_SRGB,
|
||||
COLOR_TRANSFORM_LUT_3D,
|
||||
COLOR_TRANSFORM_INVERSE_EOTF,
|
||||
COLOR_TRANSFORM_LCMS2,
|
||||
COLOR_TRANSFORM_LUT_3X1D,
|
||||
COLOR_TRANSFORM_PIPELINE,
|
||||
};
|
||||
|
||||
struct wlr_color_transform {
|
||||
|
|
@ -17,32 +19,65 @@ struct wlr_color_transform {
|
|||
enum wlr_color_transform_type type;
|
||||
};
|
||||
|
||||
/**
|
||||
* The formula is approximated via a 3D look-up table. A 3D LUT is a
|
||||
* three-dimensional array where each element is an RGB triplet. The flat lut_3d
|
||||
* array has a length of dim_len³.
|
||||
*
|
||||
* Color channel values in the range [0.0, 1.0] are mapped linearly to
|
||||
* 3D LUT indices such that 0.0 maps exactly to the first element and 1.0 maps
|
||||
* exactly to the last element in each dimension.
|
||||
*
|
||||
* The offset of the RGB triplet given red, green and blue indices r_index,
|
||||
* g_index and b_index is:
|
||||
*
|
||||
* offset = 3 * (r_index + dim_len * g_index + dim_len * dim_len * b_index)
|
||||
*/
|
||||
struct wlr_color_transform_lut3d {
|
||||
struct wlr_color_transform_inverse_eotf {
|
||||
struct wlr_color_transform base;
|
||||
|
||||
float *lut_3d;
|
||||
size_t dim_len;
|
||||
enum wlr_color_transfer_function tf;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a wlr_color_transform_lut3d from a generic wlr_color_transform.
|
||||
* Asserts that the base type is COLOR_TRANSFORM_LUT_3D
|
||||
* The formula is approximated via three 1D look-up tables. The flat lut_3x1d
|
||||
* array has a length of 3 * dim.
|
||||
*
|
||||
* The offset of a color value for a given channel and color index is:
|
||||
*
|
||||
* offset = channel_index * dim + color_index
|
||||
*/
|
||||
struct wlr_color_transform_lut3d *wlr_color_transform_lut3d_from_base(
|
||||
struct wlr_color_transform_lut_3x1d {
|
||||
struct wlr_color_transform base;
|
||||
|
||||
uint16_t *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.
|
||||
*/
|
||||
struct wlr_color_transform_lcms2 *color_transform_lcms2_from_base(
|
||||
struct wlr_color_transform *tr);
|
||||
|
||||
void color_transform_lcms2_finish(struct wlr_color_transform_lcms2 *tr);
|
||||
|
||||
/**
|
||||
* Evaluate a LCMS2 color transform for a given RGB triplet.
|
||||
*/
|
||||
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
|
||||
* COLOR_TRANSFORM_LUT_3X1D.
|
||||
*/
|
||||
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
||||
struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -516,6 +552,7 @@ struct wlr_vk_color_transform {
|
|||
struct wl_list link; // wlr_vk_renderer, list of all color transforms
|
||||
|
||||
struct {
|
||||
size_t dim;
|
||||
VkImage image;
|
||||
VkImageView image_view;
|
||||
VkDeviceMemory memory;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <wlr/types/wlr_keyboard.h>
|
||||
|
||||
bool keyboard_key_update(struct wlr_keyboard *keyboard,
|
||||
void keyboard_key_update(struct wlr_keyboard *keyboard,
|
||||
struct wlr_keyboard_key_event *event);
|
||||
|
||||
bool keyboard_modifier_update(struct wlr_keyboard *keyboard);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
|
||||
|
||||
void scene_node_get_size(struct wlr_scene_node *node, int *width, int *height);
|
||||
|
||||
void scene_surface_set_clip(struct wlr_scene_surface *surface, struct wlr_box *clip);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
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
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
#define WLR_RENDER_COLOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/**
|
||||
|
|
@ -26,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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -73,10 +128,25 @@ 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
|
||||
* is the number of elements in each individual LUT. Returns NULL on failure.
|
||||
*/
|
||||
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.
|
||||
|
|
@ -89,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 {
|
||||
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 {
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
|
||||
struct wlr_scene_node;
|
||||
struct wlr_allocator;
|
||||
struct wlr_renderer;
|
||||
|
||||
/**
|
||||
* A screen capture source.
|
||||
*
|
||||
|
|
@ -79,6 +83,31 @@ struct wlr_ext_output_image_capture_source_manager_v1 {
|
|||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface exposing one screen capture source per foreign toplevel.
|
||||
*/
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 {
|
||||
struct wl_global *global;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
struct wl_signal new_request; // struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request {
|
||||
struct wlr_ext_foreign_toplevel_handle_v1 *toplevel_handle;
|
||||
struct wl_client *client;
|
||||
|
||||
struct {
|
||||
uint32_t new_id;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
* Obtain a struct wlr_ext_image_capture_source_v1 from an ext_image_capture_source_v1
|
||||
* resource.
|
||||
|
|
@ -91,4 +120,15 @@ struct wlr_ext_image_capture_source_v1 *wlr_ext_image_capture_source_v1_from_res
|
|||
struct wlr_ext_output_image_capture_source_manager_v1 *wlr_ext_output_image_capture_source_manager_v1_create(
|
||||
struct wl_display *display, uint32_t version);
|
||||
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *
|
||||
wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(struct wl_display *display, uint32_t version);
|
||||
|
||||
bool wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept(
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *request,
|
||||
struct wlr_ext_image_capture_source_v1 *source);
|
||||
|
||||
struct wlr_ext_image_capture_source_v1 *wlr_ext_image_capture_source_v1_create_with_scene_node(
|
||||
struct wlr_scene_node *node, struct wl_event_loop *event_loop,
|
||||
struct wlr_allocator *allocator, struct wlr_renderer *renderer);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -16,12 +16,14 @@
|
|||
#include <wlr/types/wlr_input_device.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#define WLR_LED_COUNT 3
|
||||
#define WLR_LED_COUNT 5
|
||||
|
||||
enum wlr_keyboard_led {
|
||||
WLR_LED_NUM_LOCK = 1 << 0,
|
||||
WLR_LED_CAPS_LOCK = 1 << 1,
|
||||
WLR_LED_SCROLL_LOCK = 1 << 2,
|
||||
WLR_LED_COMPOSE = 1 << 3,
|
||||
WLR_LED_KANA = 1 << 4,
|
||||
};
|
||||
|
||||
#define WLR_MODIFIER_COUNT 8
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -68,12 +69,13 @@ enum wlr_output_state_field {
|
|||
WLR_OUTPUT_STATE_SCALE = 1 << 4,
|
||||
WLR_OUTPUT_STATE_TRANSFORM = 1 << 5,
|
||||
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED = 1 << 6,
|
||||
WLR_OUTPUT_STATE_GAMMA_LUT = 1 << 7,
|
||||
WLR_OUTPUT_STATE_RENDER_FORMAT = 1 << 8,
|
||||
WLR_OUTPUT_STATE_SUBPIXEL = 1 << 9,
|
||||
WLR_OUTPUT_STATE_LAYERS = 1 << 10,
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE = 1 << 11,
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE = 1 << 12,
|
||||
WLR_OUTPUT_STATE_RENDER_FORMAT = 1 << 7,
|
||||
WLR_OUTPUT_STATE_SUBPIXEL = 1 << 8,
|
||||
WLR_OUTPUT_STATE_LAYERS = 1 << 9,
|
||||
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.
|
||||
*/
|
||||
|
|
@ -122,9 +148,6 @@ struct wlr_output_state {
|
|||
int32_t refresh; // mHz, may be zero
|
||||
} custom_mode;
|
||||
|
||||
uint16_t *gamma_lut;
|
||||
size_t gamma_lut_size;
|
||||
|
||||
struct wlr_output_layer_state *layers;
|
||||
size_t layers_len;
|
||||
|
||||
|
|
@ -132,6 +155,10 @@ struct wlr_output_state {
|
|||
uint64_t wait_point;
|
||||
struct wlr_drm_syncobj_timeline *signal_timeline;
|
||||
uint64_t signal_point;
|
||||
|
||||
struct wlr_color_transform *color_transform;
|
||||
|
||||
struct wlr_output_image_description *image_description;
|
||||
};
|
||||
|
||||
struct wlr_output_impl;
|
||||
|
|
@ -167,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
|
||||
|
|
@ -235,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;
|
||||
};
|
||||
|
||||
|
|
@ -245,13 +278,13 @@ struct wlr_output_event_damage {
|
|||
|
||||
struct wlr_output_event_precommit {
|
||||
struct wlr_output *output;
|
||||
struct timespec *when;
|
||||
struct timespec when;
|
||||
const struct wlr_output_state *state;
|
||||
};
|
||||
|
||||
struct wlr_output_event_commit {
|
||||
struct wlr_output *output;
|
||||
struct timespec *when;
|
||||
struct timespec when;
|
||||
const struct wlr_output_state *state;
|
||||
};
|
||||
|
||||
|
|
@ -527,17 +560,6 @@ void wlr_output_state_set_subpixel(struct wlr_output_state *state,
|
|||
*/
|
||||
void wlr_output_state_set_buffer(struct wlr_output_state *state,
|
||||
struct wlr_buffer *buffer);
|
||||
/**
|
||||
* Sets the gamma table for an output. `r`, `g` and `b` are gamma ramps for
|
||||
* red, green and blue. `size` is the length of the ramps and must not exceed
|
||||
* the value returned by wlr_output_get_gamma_size().
|
||||
*
|
||||
* Providing zero-sized ramps resets the gamma table.
|
||||
*
|
||||
* This state will be applied once wlr_output_commit_state() is called.
|
||||
*/
|
||||
bool wlr_output_state_set_gamma_lut(struct wlr_output_state *state,
|
||||
size_t ramp_size, const uint16_t *r, const uint16_t *g, const uint16_t *b);
|
||||
/**
|
||||
* Sets the damage region for an output. This is used as a hint to the backend
|
||||
* and can be used to reduce power consumption or increase performance on some
|
||||
|
|
@ -586,6 +608,19 @@ void wlr_output_state_set_wait_timeline(struct wlr_output_state *state,
|
|||
*/
|
||||
void wlr_output_state_set_signal_timeline(struct wlr_output_state *state,
|
||||
struct wlr_drm_syncobj_timeline *timeline, uint64_t dst_point);
|
||||
/**
|
||||
* Set the color transform for an output.
|
||||
*
|
||||
* The color transform is applied after blending output layers.
|
||||
*/
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ struct wlr_presentation_event {
|
|||
struct wlr_backend;
|
||||
|
||||
struct wlr_presentation *wlr_presentation_create(struct wl_display *display,
|
||||
struct wlr_backend *backend, int version);
|
||||
struct wlr_backend *backend, uint32_t version);
|
||||
/**
|
||||
* Mark the current surface's buffer as sampled.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -123,6 +126,10 @@ struct wlr_scene_surface {
|
|||
struct {
|
||||
struct wlr_box clip;
|
||||
|
||||
// Output used for frame pacing (surface frame callbacks, presentation
|
||||
// time feedback, etc), may be NULL
|
||||
struct wlr_output *frame_pacing_output;
|
||||
|
||||
struct wlr_addon addon;
|
||||
|
||||
struct wl_listener outputs_update;
|
||||
|
|
@ -152,6 +159,11 @@ struct wlr_scene_output_sample_event {
|
|||
bool direct_scanout;
|
||||
};
|
||||
|
||||
struct wlr_scene_frame_done_event {
|
||||
struct wlr_scene_output *output;
|
||||
struct timespec when;
|
||||
};
|
||||
|
||||
/** A scene-graph node displaying a buffer */
|
||||
struct wlr_scene_buffer {
|
||||
struct wlr_scene_node node;
|
||||
|
|
@ -164,7 +176,7 @@ struct wlr_scene_buffer {
|
|||
struct wl_signal output_enter; // struct wlr_scene_output
|
||||
struct wl_signal output_leave; // struct wlr_scene_output
|
||||
struct wl_signal output_sample; // struct wlr_scene_output_sample_event
|
||||
struct wl_signal frame_done; // struct timespec
|
||||
struct wl_signal frame_done; // struct wlr_scene_frame_done_event
|
||||
} events;
|
||||
|
||||
// May be NULL
|
||||
|
|
@ -173,8 +185,7 @@ struct wlr_scene_buffer {
|
|||
/**
|
||||
* The output that the largest area of this buffer is displayed on.
|
||||
* This may be NULL if the buffer is not currently displayed on any
|
||||
* outputs. This is the output that should be used for frame callbacks,
|
||||
* presentation feedback, etc.
|
||||
* outputs.
|
||||
*/
|
||||
struct wlr_scene_output *primary_output;
|
||||
|
||||
|
|
@ -184,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;
|
||||
|
|
@ -239,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;
|
||||
|
|
@ -356,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.
|
||||
*/
|
||||
|
|
@ -416,6 +441,12 @@ struct wlr_scene_rect *wlr_scene_rect_from_node(struct wlr_scene_node *node);
|
|||
struct wlr_scene_surface *wlr_scene_surface_try_from_buffer(
|
||||
struct wlr_scene_buffer *scene_buffer);
|
||||
|
||||
/**
|
||||
* Call wlr_surface_send_frame_done() if the surface is visible.
|
||||
*/
|
||||
void wlr_scene_surface_send_frame_done(struct wlr_scene_surface *scene_surface,
|
||||
const struct timespec *when);
|
||||
|
||||
/**
|
||||
* Add a node displaying a solid-colored rectangle to the scene-graph.
|
||||
*
|
||||
|
|
@ -527,11 +558,17 @@ 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.
|
||||
*/
|
||||
void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer,
|
||||
struct timespec *now);
|
||||
struct wlr_scene_frame_done_event *event);
|
||||
|
||||
/**
|
||||
* Add a viewport for the specified output to the scene-graph.
|
||||
|
|
@ -552,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 {
|
||||
|
|
@ -74,8 +74,8 @@ struct wlr_text_input_manager_v3 {
|
|||
struct wl_list text_inputs; // wlr_text_input_v3.link
|
||||
|
||||
struct {
|
||||
struct wl_signal text_input; // struct wlr_text_input_v3
|
||||
struct wl_signal destroy; // struct wlr_text_input_manager_v3
|
||||
struct wl_signal new_text_input; // struct wlr_text_input_v3
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ struct wlr_xdg_activation_token_v1 {
|
|||
};
|
||||
|
||||
struct wlr_xdg_activation_v1 {
|
||||
struct wl_global *global;
|
||||
uint32_t token_timeout_msec; // token timeout in milliseconds (0 to disable)
|
||||
|
||||
struct wl_list tokens; // wlr_xdg_activation_token_v1.link
|
||||
|
|
@ -51,7 +52,6 @@ struct wlr_xdg_activation_v1 {
|
|||
|
||||
struct {
|
||||
struct wl_display *display;
|
||||
struct wl_global *global;
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -141,6 +141,7 @@ enum wlr_xdg_surface_role {
|
|||
struct wlr_xdg_toplevel_state {
|
||||
bool maximized, fullscreen, resizing, activated, suspended;
|
||||
uint32_t tiled; // enum wlr_edges
|
||||
uint32_t constrained; // enum wlr_edges
|
||||
int32_t width, height;
|
||||
int32_t max_width, max_height;
|
||||
int32_t min_width, min_height;
|
||||
|
|
@ -168,6 +169,7 @@ struct wlr_xdg_toplevel_configure {
|
|||
// The following fields must always be set to reflect the current state
|
||||
bool maximized, fullscreen, resizing, activated, suspended;
|
||||
uint32_t tiled; // enum wlr_edges
|
||||
uint32_t constrained; // enum wlr_edges
|
||||
int32_t width, height;
|
||||
|
||||
// Only for WLR_XDG_TOPLEVEL_CONFIGURE_BOUNDS
|
||||
|
|
@ -454,6 +456,14 @@ uint32_t wlr_xdg_toplevel_set_wm_capabilities(struct wlr_xdg_toplevel *toplevel,
|
|||
uint32_t wlr_xdg_toplevel_set_suspended(struct wlr_xdg_toplevel *toplevel,
|
||||
bool suspended);
|
||||
|
||||
/**
|
||||
* Request that this toplevel consider itself constrained and doesn't attempt to
|
||||
* resize from some edges. `constrained_edges` is a bitfield of enum wlr_edges.
|
||||
* Returns the associated configure serial.
|
||||
*/
|
||||
uint32_t wlr_xdg_toplevel_set_constrained(struct wlr_xdg_toplevel *toplevel,
|
||||
uint32_t constrained_edges);
|
||||
|
||||
/**
|
||||
* Request that this toplevel closes.
|
||||
*/
|
||||
|
|
|
|||
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
|
||||
|
|
@ -146,7 +146,6 @@ struct wlr_xwayland_surface {
|
|||
char *role;
|
||||
char *startup_id;
|
||||
pid_t pid;
|
||||
bool has_utf8_title;
|
||||
|
||||
struct wl_list children; // wlr_xwayland_surface.parent_link
|
||||
struct wlr_xwayland_surface *parent;
|
||||
|
|
@ -222,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 */
|
||||
|
|
@ -232,6 +232,8 @@ struct wlr_xwayland_surface {
|
|||
void *data;
|
||||
|
||||
struct {
|
||||
char *wm_name, *net_wm_name;
|
||||
|
||||
struct wl_listener surface_commit;
|
||||
struct wl_listener surface_map;
|
||||
struct wl_listener surface_unmap;
|
||||
|
|
@ -400,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,
|
||||
|
|
@ -115,6 +116,7 @@ struct wlr_xwm {
|
|||
xcb_connection_t *xcb_conn;
|
||||
xcb_screen_t *screen;
|
||||
xcb_window_t window;
|
||||
xcb_window_t no_focus_window;
|
||||
xcb_visualid_t visual_id;
|
||||
xcb_colormap_t colormap;
|
||||
xcb_render_pictformat_t render_format_id;
|
||||
|
|
@ -162,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);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
project(
|
||||
'wlroots',
|
||||
'c',
|
||||
version: '0.19.0-rc2',
|
||||
version: '0.20.0-dev',
|
||||
license: 'MIT',
|
||||
meson_version: '>=1.3',
|
||||
default_options: [
|
||||
|
|
@ -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',
|
||||
|
|
@ -105,8 +105,8 @@ drm = dependency('libdrm',
|
|||
'tests=false',
|
||||
],
|
||||
)
|
||||
xkbcommon = dependency(
|
||||
'xkbcommon',
|
||||
xkbcommon = dependency('xkbcommon',
|
||||
version: '>=1.8.0',
|
||||
fallback: 'libxkbcommon',
|
||||
default_options: [
|
||||
'enable-tools=false',
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
wayland_protos = dependency('wayland-protocols',
|
||||
version: '>=1.41',
|
||||
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 ""
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
#include <wlr/util/log.h>
|
||||
#include <xf86drm.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "render/allocator/gbm.h"
|
||||
#include "render/drm_format_set.h"
|
||||
|
||||
|
|
@ -39,40 +38,12 @@ static bool export_gbm_bo(struct gbm_bo *bo,
|
|||
attribs.modifier = gbm_bo_get_modifier(bo);
|
||||
|
||||
int i;
|
||||
int32_t handle = -1;
|
||||
for (i = 0; i < attribs.n_planes; ++i) {
|
||||
#if HAVE_GBM_BO_GET_FD_FOR_PLANE
|
||||
(void)handle;
|
||||
|
||||
attribs.fd[i] = gbm_bo_get_fd_for_plane(bo, i);
|
||||
if (attribs.fd[i] < 0) {
|
||||
wlr_log(WLR_ERROR, "gbm_bo_get_fd_for_plane failed");
|
||||
goto error_fd;
|
||||
}
|
||||
#else
|
||||
// GBM is lacking a function to get a FD for a given plane. Instead,
|
||||
// check all planes have the same handle. We can't use
|
||||
// drmPrimeHandleToFD because that messes up handle ref'counting in
|
||||
// the user-space driver.
|
||||
union gbm_bo_handle plane_handle = gbm_bo_get_handle_for_plane(bo, i);
|
||||
if (plane_handle.s32 < 0) {
|
||||
wlr_log(WLR_ERROR, "gbm_bo_get_handle_for_plane failed");
|
||||
goto error_fd;
|
||||
}
|
||||
if (i == 0) {
|
||||
handle = plane_handle.s32;
|
||||
} else if (plane_handle.s32 != handle) {
|
||||
wlr_log(WLR_ERROR, "Failed to export GBM BO: "
|
||||
"all planes don't have the same GEM handle");
|
||||
goto error_fd;
|
||||
}
|
||||
|
||||
attribs.fd[i] = gbm_bo_get_fd(bo);
|
||||
if (attribs.fd[i] < 0) {
|
||||
wlr_log(WLR_ERROR, "gbm_bo_get_fd failed");
|
||||
goto error_fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
attribs.offset[i] = gbm_bo_get_offset(bo, i);
|
||||
attribs.stride[i] = gbm_bo_get_stride_for_plane(bo, i);
|
||||
|
|
@ -126,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);
|
||||
|
|
@ -141,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 "
|
||||
|
|
|
|||
|
|
@ -13,15 +13,12 @@ wlr_files += files(
|
|||
|
||||
gbm = disabler()
|
||||
if 'gbm' in allocators or 'auto' in allocators
|
||||
gbm = dependency('gbm', version: '>=17.1.0', required: 'gbm' in allocators)
|
||||
gbm = dependency('gbm', version: '>=21.1', required: 'gbm' in allocators)
|
||||
endif
|
||||
if gbm.found()
|
||||
wlr_files += files('gbm.c')
|
||||
wlr_deps += gbm
|
||||
features += { 'gbm-allocator': true }
|
||||
|
||||
has = cc.has_function('gbm_bo_get_fd_for_plane', dependencies: [gbm])
|
||||
internal_config.set10('HAVE_GBM_BO_GET_FD_FOR_PLANE', has)
|
||||
endif
|
||||
|
||||
udmabuf = false
|
||||
|
|
|
|||
219
render/color.c
219
render/color.c
|
|
@ -21,25 +21,92 @@ static const struct wlr_color_primaries COLOR_PRIMARIES_BT2020 = { // code point
|
|||
.white = { 0.3127, 0.3290 },
|
||||
};
|
||||
|
||||
struct wlr_color_transform *wlr_color_transform_init_srgb(void) {
|
||||
struct wlr_color_transform *tx = calloc(1, sizeof(struct wlr_color_transform));
|
||||
void wlr_color_transform_init(struct wlr_color_transform *tr, enum wlr_color_transform_type type) {
|
||||
*tr = (struct wlr_color_transform){
|
||||
.type = type,
|
||||
.ref_count = 1,
|
||||
};
|
||||
wlr_addon_set_init(&tr->addons);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
tx->type = COLOR_TRANSFORM_SRGB;
|
||||
tx->ref_count = 1;
|
||||
wlr_addon_set_init(&tx->addons);
|
||||
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,
|
||||
const uint16_t *r, const uint16_t *g, const uint16_t *b) {
|
||||
uint16_t *lut_3x1d = malloc(3 * dim * sizeof(lut_3x1d[0]));
|
||||
if (lut_3x1d == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&lut_3x1d[0 * dim], r, dim * sizeof(lut_3x1d[0]));
|
||||
memcpy(&lut_3x1d[1 * dim], g, dim * sizeof(lut_3x1d[0]));
|
||||
memcpy(&lut_3x1d[2 * dim], b, dim * sizeof(lut_3x1d[0]));
|
||||
|
||||
struct wlr_color_transform_lut_3x1d *tx = calloc(1, sizeof(*tx));
|
||||
if (!tx) {
|
||||
free(lut_3x1d);
|
||||
return NULL;
|
||||
}
|
||||
wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_LUT_3X1D);
|
||||
tx->lut_3x1d = lut_3x1d;
|
||||
tx->dim = 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_LUT_3D:;
|
||||
struct wlr_color_transform_lut3d *lut3d =
|
||||
wlr_color_transform_lut3d_from_base(tr);
|
||||
free(lut3d->lut_3d);
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
color_transform_lcms2_finish(color_transform_lcms2_from_base(tr));
|
||||
break;
|
||||
case COLOR_TRANSFORM_LUT_3X1D:;
|
||||
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);
|
||||
|
|
@ -62,11 +129,126 @@ void wlr_color_transform_unref(struct wlr_color_transform *tr) {
|
|||
}
|
||||
}
|
||||
|
||||
struct wlr_color_transform_lut3d *wlr_color_transform_lut3d_from_base(
|
||||
struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_base(
|
||||
struct wlr_color_transform *tr) {
|
||||
assert(tr->type == COLOR_TRANSFORM_LUT_3D);
|
||||
struct wlr_color_transform_lut3d *lut3d = wl_container_of(tr, lut3d, base);
|
||||
return lut3d;
|
||||
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);
|
||||
struct wlr_color_transform_lut_3x1d *lut_3x1d = wl_container_of(tr, lut_3x1d, 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) {
|
||||
i = len - 1;
|
||||
}
|
||||
return (float) lut[i] / UINT16_MAX;
|
||||
}
|
||||
|
||||
static float lut_1d_eval(const uint16_t *lut, size_t len, float x) {
|
||||
double pos = x * (len - 1);
|
||||
double int_part;
|
||||
double frac_part = modf(pos, &int_part);
|
||||
size_t i = (size_t) int_part;
|
||||
double a = lut_1d_get(lut, len, i);
|
||||
double b = lut_1d_get(lut, len, i + 1);
|
||||
return a * (1 - frac_part) + b * frac_part;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
@ -139,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,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <wlr/render/color.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "render/color.h"
|
||||
|
||||
struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
|
||||
const void *data, size_t size) {
|
||||
|
|
@ -7,3 +8,17 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
|
|||
"LCMS2 is compile-time disabled");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_color_transform_lcms2 *color_transform_lcms2_from_base(
|
||||
struct wlr_color_transform *tr) {
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
void color_transform_lcms2_finish(struct wlr_color_transform_lcms2 *tr) {
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
void color_transform_lcms2_eval(struct wlr_color_transform_lcms2 *tr,
|
||||
float out[static 3], const float in[static 3]) {
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,17 @@
|
|||
#include <assert.h>
|
||||
#include <lcms2.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/render/color.h>
|
||||
#include "render/color.h"
|
||||
|
||||
struct wlr_color_transform_lcms2 {
|
||||
struct wlr_color_transform base;
|
||||
|
||||
cmsContext ctx;
|
||||
cmsHTRANSFORM lcms;
|
||||
};
|
||||
|
||||
static const cmsCIExyY srgb_whitepoint = { 0.3127, 0.3291, 1 };
|
||||
|
||||
static const cmsCIExyYTRIPLE srgb_primaries = {
|
||||
|
|
@ -18,7 +26,7 @@ static void handle_lcms_error(cmsContext ctx, cmsUInt32Number code, const char *
|
|||
|
||||
struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
|
||||
const void *data, size_t size) {
|
||||
struct wlr_color_transform_lut3d *tx = NULL;
|
||||
struct wlr_color_transform_lcms2 *tx = NULL;
|
||||
|
||||
cmsContext ctx = cmsCreateContext(NULL, NULL);
|
||||
if (ctx == NULL) {
|
||||
|
|
@ -31,18 +39,18 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
|
|||
cmsHPROFILE icc_profile = cmsOpenProfileFromMemTHR(ctx, data, size);
|
||||
if (icc_profile == NULL) {
|
||||
wlr_log(WLR_ERROR, "cmsOpenProfileFromMemTHR failed");
|
||||
goto out_ctx;
|
||||
goto error_ctx;
|
||||
}
|
||||
|
||||
if (cmsGetDeviceClass(icc_profile) != cmsSigDisplayClass) {
|
||||
wlr_log(WLR_ERROR, "ICC profile must have the Display device class");
|
||||
goto out_icc_profile;
|
||||
goto error_icc_profile;
|
||||
}
|
||||
|
||||
cmsToneCurve *linear_tone_curve = cmsBuildGamma(ctx, 1);
|
||||
if (linear_tone_curve == NULL) {
|
||||
wlr_log(WLR_ERROR, "cmsBuildGamma failed");
|
||||
goto out_icc_profile;
|
||||
goto error_icc_profile;
|
||||
}
|
||||
|
||||
cmsToneCurve *linear_tf[] = {
|
||||
|
|
@ -52,68 +60,54 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
|
|||
};
|
||||
cmsHPROFILE srgb_profile = cmsCreateRGBProfileTHR(ctx, &srgb_whitepoint,
|
||||
&srgb_primaries, linear_tf);
|
||||
cmsFreeToneCurve(linear_tone_curve);
|
||||
if (srgb_profile == NULL) {
|
||||
wlr_log(WLR_ERROR, "cmsCreateRGBProfileTHR failed");
|
||||
goto out_linear_tone_curve;
|
||||
goto error_icc_profile;
|
||||
}
|
||||
|
||||
cmsHTRANSFORM lcms_tr = cmsCreateTransformTHR(ctx,
|
||||
srgb_profile, TYPE_RGB_FLT, icc_profile, TYPE_RGB_FLT,
|
||||
INTENT_RELATIVE_COLORIMETRIC, 0);
|
||||
cmsCloseProfile(srgb_profile);
|
||||
cmsCloseProfile(icc_profile);
|
||||
if (lcms_tr == NULL) {
|
||||
wlr_log(WLR_ERROR, "cmsCreateTransformTHR failed");
|
||||
goto out_srgb_profile;
|
||||
goto error_ctx;
|
||||
}
|
||||
|
||||
size_t dim_len = 33;
|
||||
float *lut_3d = calloc(3 * dim_len * dim_len * dim_len, sizeof(float));
|
||||
if (lut_3d == NULL) {
|
||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||
goto out_lcms_tr;
|
||||
}
|
||||
|
||||
float factor = 1.0f / (dim_len - 1);
|
||||
for (size_t b_index = 0; b_index < dim_len; b_index++) {
|
||||
for (size_t g_index = 0; g_index < dim_len; g_index++) {
|
||||
for (size_t r_index = 0; r_index < dim_len; r_index++) {
|
||||
float rgb_in[3] = {
|
||||
r_index * factor,
|
||||
g_index * factor,
|
||||
b_index * factor,
|
||||
};
|
||||
float rgb_out[3];
|
||||
// TODO: use a single call to cmsDoTransform for the entire calculation?
|
||||
// this does require allocating an extra temp buffer
|
||||
cmsDoTransform(lcms_tr, rgb_in, rgb_out, 1);
|
||||
|
||||
size_t offset = 3 * (r_index + dim_len * g_index + dim_len * dim_len * b_index);
|
||||
// TODO: maybe clamp values to [0.0, 1.0] here?
|
||||
lut_3d[offset] = rgb_out[0];
|
||||
lut_3d[offset + 1] = rgb_out[1];
|
||||
lut_3d[offset + 2] = rgb_out[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tx = calloc(1, sizeof(struct wlr_color_transform_lut3d));
|
||||
tx = calloc(1, sizeof(*tx));
|
||||
if (!tx) {
|
||||
goto out_lcms_tr;
|
||||
}
|
||||
tx->base.type = COLOR_TRANSFORM_LUT_3D;
|
||||
tx->dim_len = dim_len;
|
||||
tx->lut_3d = lut_3d;
|
||||
tx->base.ref_count = 1;
|
||||
wlr_addon_set_init(&tx->base.addons);
|
||||
|
||||
out_lcms_tr:
|
||||
cmsDeleteTransform(lcms_tr);
|
||||
out_linear_tone_curve:
|
||||
cmsFreeToneCurve(linear_tone_curve);
|
||||
out_srgb_profile:
|
||||
cmsCloseProfile(srgb_profile);
|
||||
out_icc_profile:
|
||||
cmsCloseProfile(icc_profile);
|
||||
out_ctx:
|
||||
cmsDeleteContext(ctx);
|
||||
return &tx->base;
|
||||
goto error_ctx;
|
||||
}
|
||||
wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_LCMS2);
|
||||
|
||||
tx->ctx = ctx;
|
||||
tx->lcms = lcms_tr;
|
||||
|
||||
return &tx->base;
|
||||
|
||||
error_icc_profile:
|
||||
cmsCloseProfile(icc_profile);
|
||||
error_ctx:
|
||||
cmsDeleteContext(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void color_transform_lcms2_finish(struct wlr_color_transform_lcms2 *tr) {
|
||||
cmsDeleteTransform(tr->lcms);
|
||||
cmsDeleteContext(tr->ctx);
|
||||
}
|
||||
|
||||
struct wlr_color_transform_lcms2 *color_transform_lcms2_from_base(
|
||||
struct wlr_color_transform *tr) {
|
||||
assert(tr->type == COLOR_TRANSFORM_LCMS2);
|
||||
struct wlr_color_transform_lcms2 *lcms2 = wl_container_of(tr, lcms2, base);
|
||||
return lcms2;
|
||||
}
|
||||
|
||||
void color_transform_lcms2_eval(struct wlr_color_transform_lcms2 *tr,
|
||||
float out[static 3], const float in[static 3]) {
|
||||
cmsDoTransform(tr->lcms, in, out, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ bool wlr_drm_syncobj_timeline_import_sync_file(struct wlr_drm_syncobj_timeline *
|
|||
uint32_t syncobj_handle;
|
||||
if (drmSyncobjCreate(timeline->drm_fd, 0, &syncobj_handle) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "drmSyncobjCreate failed");
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (drmSyncobjImportSyncFile(timeline->drm_fd, syncobj_handle,
|
||||
|
|
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ void wlr_render_pass_add_texture(struct wlr_render_pass *render_pass,
|
|||
if (!wlr_fbox_empty(&options->src_box)) {
|
||||
const struct wlr_fbox *box = &options->src_box;
|
||||
assert(box->x >= 0 && box->y >= 0 &&
|
||||
box->x + box->width <= options->texture->width &&
|
||||
box->y + box->height <= options->texture->height);
|
||||
(uint32_t)(box->x + box->width) <= options->texture->width &&
|
||||
(uint32_t)(box->y + box->height) <= options->texture->height);
|
||||
}
|
||||
|
||||
render_pass->impl->add_texture(render_pass, options);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ bool begin_pixman_data_ptr_access(struct wlr_buffer *wlr_buffer, pixman_image_t
|
|||
|
||||
pixman_image_t *new_image = pixman_image_create_bits_no_clear(format,
|
||||
wlr_buffer->width, wlr_buffer->height, data, stride);
|
||||
if (image == NULL) {
|
||||
if (new_image == NULL) {
|
||||
wlr_buffer_end_data_ptr_access(wlr_buffer);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ static void swapchain_handle_allocator_destroy(struct wl_listener *listener,
|
|||
struct wlr_swapchain *wlr_swapchain_create(
|
||||
struct wlr_allocator *alloc, int width, int height,
|
||||
const struct wlr_drm_format *format) {
|
||||
assert(width > 0 && height > 0);
|
||||
|
||||
struct wlr_swapchain *swapchain = calloc(1, sizeof(*swapchain));
|
||||
if (swapchain == NULL) {
|
||||
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,25 +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_LUT_3D) {
|
||||
struct wlr_color_transform_lut3d *lut3d =
|
||||
wlr_color_transform_lut3d_from_base(pass->color_transform);
|
||||
dim = lut3d->dim_len;
|
||||
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,
|
||||
|
|
@ -204,16 +265,13 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
sizeof(frag_pcr_data), &frag_pcr_data);
|
||||
|
||||
VkDescriptorSet lut_ds;
|
||||
if (pass->color_transform && pass->color_transform->type == COLOR_TRANSFORM_LUT_3D) {
|
||||
struct wlr_vk_color_transform *transform =
|
||||
get_color_transform(pass->color_transform, renderer);
|
||||
assert(transform);
|
||||
if (transform != NULL) {
|
||||
lut_ds = transform->lut_3d.ds;
|
||||
} else {
|
||||
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]);
|
||||
|
|
@ -343,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) {
|
||||
if (!pass->render_buffer_out->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;
|
||||
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,
|
||||
|
|
@ -480,7 +534,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
|||
.semaphore = renderer->timeline_semaphore,
|
||||
.value = render_timeline_point,
|
||||
};
|
||||
if (renderer->dev->implicit_sync_interop) {
|
||||
if (renderer->dev->implicit_sync_interop || pass->signal_timeline != NULL) {
|
||||
if (render_cb->binary_semaphore == VK_NULL_HANDLE) {
|
||||
VkExportSemaphoreCreateInfo export_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
|
||||
|
|
@ -563,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;
|
||||
}
|
||||
|
||||
|
|
@ -623,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 },
|
||||
|
|
@ -641,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,
|
||||
|
|
@ -724,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,
|
||||
});
|
||||
|
|
@ -747,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,
|
||||
|
|
@ -761,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);
|
||||
|
|
@ -840,7 +951,7 @@ void vk_color_transform_destroy(struct wlr_addon *addon) {
|
|||
}
|
||||
|
||||
static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
||||
const struct wlr_color_transform_lut3d *lut_3d,
|
||||
struct wlr_color_transform *tr, size_t dim_len,
|
||||
VkImage *image, VkImageView *image_view,
|
||||
VkDeviceMemory *memory, VkDescriptorSet *ds,
|
||||
struct wlr_vk_descriptor_pool **ds_pool) {
|
||||
|
|
@ -866,7 +977,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.extent = (VkExtent3D) { lut_3d->dim_len, lut_3d->dim_len, lut_3d->dim_len },
|
||||
.extent = (VkExtent3D) { dim_len, dim_len, dim_len },
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
};
|
||||
|
|
@ -927,7 +1038,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
}
|
||||
|
||||
size_t bytes_per_block = 4 * sizeof(float);
|
||||
size_t size = lut_3d->dim_len * lut_3d->dim_len * lut_3d->dim_len * bytes_per_block;
|
||||
size_t size = dim_len * dim_len * dim_len * bytes_per_block;
|
||||
struct wlr_vk_buffer_span span = vulkan_get_stage_span(renderer,
|
||||
size, bytes_per_block);
|
||||
if (!span.buffer || span.alloc.size != size) {
|
||||
|
|
@ -935,18 +1046,26 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
goto fail_imageview;
|
||||
}
|
||||
|
||||
float sample_range = 1.0f / (dim_len - 1);
|
||||
char *map = (char *)span.buffer->cpu_mapping + span.alloc.start;
|
||||
float *dst = (float *)map;
|
||||
size_t dim_len = lut_3d->dim_len;
|
||||
for (size_t b_index = 0; b_index < dim_len; b_index++) {
|
||||
for (size_t g_index = 0; g_index < dim_len; g_index++) {
|
||||
for (size_t r_index = 0; r_index < dim_len; r_index++) {
|
||||
size_t sample_index = r_index + dim_len * g_index + dim_len * dim_len * b_index;
|
||||
size_t src_offset = 3 * sample_index;
|
||||
size_t dst_offset = 4 * sample_index;
|
||||
dst[dst_offset] = lut_3d->lut_3d[src_offset];
|
||||
dst[dst_offset + 1] = lut_3d->lut_3d[src_offset + 1];
|
||||
dst[dst_offset + 2] = lut_3d->lut_3d[src_offset + 2];
|
||||
|
||||
float rgb_in[3] = {
|
||||
r_index * sample_range,
|
||||
g_index * sample_range,
|
||||
b_index * sample_range,
|
||||
};
|
||||
float rgb_out[3];
|
||||
wlr_color_transform_eval(tr, rgb_out, rgb_in);
|
||||
|
||||
dst[dst_offset] = rgb_out[0];
|
||||
dst[dst_offset + 1] = rgb_out[1];
|
||||
dst[dst_offset + 2] = rgb_out[2];
|
||||
dst[dst_offset + 3] = 1.0;
|
||||
}
|
||||
}
|
||||
|
|
@ -959,9 +1078,9 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
VkBufferImageCopy copy = {
|
||||
.bufferOffset = span.alloc.start,
|
||||
.imageExtent.width = lut_3d->dim_len,
|
||||
.imageExtent.height = lut_3d->dim_len,
|
||||
.imageExtent.depth = lut_3d->dim_len,
|
||||
.imageExtent.width = dim_len,
|
||||
.imageExtent.height = dim_len,
|
||||
.imageExtent.depth = dim_len,
|
||||
.imageSubresource.layerCount = 1,
|
||||
.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
};
|
||||
|
|
@ -1012,9 +1131,10 @@ static struct wlr_vk_color_transform *vk_color_transform_create(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (transform->type == COLOR_TRANSFORM_LUT_3D) {
|
||||
if (!create_3d_lut_image(renderer,
|
||||
wlr_color_transform_lut3d_from_base(transform),
|
||||
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,
|
||||
&vk_transform->lut_3d.image,
|
||||
&vk_transform->lut_3d.image_view,
|
||||
&vk_transform->lut_3d.memory,
|
||||
|
|
@ -1040,30 +1160,69 @@ 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 (!using_srgb_pathway && !buffer->plain.image_view) {
|
||||
if (!buffer->two_pass.out.image_view) {
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs);
|
||||
if (!vulkan_setup_plain_framebuffer(buffer, &attribs)) {
|
||||
if (!vulkan_setup_two_pass_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));
|
||||
if (pass == NULL) {
|
||||
|
|
@ -1072,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);
|
||||
}
|
||||
|
|
@ -1080,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);
|
||||
|
||||
|
|
@ -1116,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){
|
||||
|
|
@ -1138,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,16 +66,35 @@ static struct wlr_vk_descriptor_pool *alloc_ds(
|
|||
struct wl_list *pool_list, size_t *last_pool_size) {
|
||||
VkResult res;
|
||||
|
||||
bool found = false;
|
||||
VkDescriptorSetAllocateInfo ds_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = layout,
|
||||
};
|
||||
|
||||
struct wlr_vk_descriptor_pool *pool;
|
||||
wl_list_for_each(pool, pool_list, link) {
|
||||
if (pool->free > 0) {
|
||||
found = true;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) { // create new pool
|
||||
pool = calloc(1, sizeof(*pool));
|
||||
if (!pool) {
|
||||
wlr_log_errno(WLR_ERROR, "allocation failed");
|
||||
|
|
@ -111,14 +130,8 @@ static struct wlr_vk_descriptor_pool *alloc_ds(
|
|||
|
||||
*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,
|
||||
};
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -989,6 +1023,8 @@ bool vulkan_sync_render_buffer(struct wlr_vk_renderer *renderer,
|
|||
return vulkan_wait_command_buffer(cb, renderer);
|
||||
}
|
||||
|
||||
assert(cb->binary_semaphore != VK_NULL_HANDLE);
|
||||
|
||||
// Note: vkGetSemaphoreFdKHR implicitly resets the semaphore
|
||||
const VkSemaphoreGetFdInfoKHR get_fence_fd_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
|
||||
|
|
@ -1462,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,
|
||||
},
|
||||
};
|
||||
|
|
@ -1478,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,
|
||||
};
|
||||
|
||||
|
|
@ -1556,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),
|
||||
|
|
@ -1569,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,
|
||||
};
|
||||
|
||||
|
|
@ -1751,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 = {
|
||||
|
|
@ -1770,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,
|
||||
|
|
@ -1813,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,
|
||||
|
|
@ -1868,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 = {
|
||||
|
|
@ -1888,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,
|
||||
|
|
@ -2181,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,
|
||||
|
|
@ -2219,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,
|
||||
|
|
@ -2234,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 |
|
||||
|
|
@ -2276,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,
|
||||
};
|
||||
|
||||
|
|
@ -2291,6 +2327,11 @@ 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)) {
|
||||
|
|
@ -2301,6 +2342,21 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
&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_bt1886, WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886)) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
assert(format->vk_srgb);
|
||||
VkAttachmentDescription attachment = {
|
||||
|
|
@ -2325,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 |
|
||||
|
|
@ -2360,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,
|
||||
};
|
||||
|
||||
|
|
@ -2428,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);
|
||||
|
|
@ -2499,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
|
||||
|
|
@ -2514,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,26 @@ void main() {
|
|||
rgb = in_color.rgb / alpha;
|
||||
}
|
||||
|
||||
rgb *= data.luminance_multiplier;
|
||||
|
||||
rgb = mat3(data.matrix) * rgb;
|
||||
|
||||
if (OUTPUT_TRANSFORM != OUTPUT_TRANSFORM_IDENTITY) {
|
||||
rgb = max(rgb, vec3(0));
|
||||
}
|
||||
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,64 @@ 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_IDENTITY) {
|
||||
rgb = max(rgb, vec3(0));
|
||||
}
|
||||
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,27 +1,18 @@
|
|||
PKG_CONFIG?=pkg-config
|
||||
WAYLAND_PROTOCOLS!=$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols
|
||||
WAYLAND_SCANNER!=$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner
|
||||
|
||||
PKGS="wlroots-0.19" wayland-server xkbcommon
|
||||
PKGS="wlroots-0.20" wayland-server xkbcommon
|
||||
CFLAGS_PKG_CONFIG!=$(PKG_CONFIG) --cflags $(PKGS)
|
||||
CFLAGS+=$(CFLAGS_PKG_CONFIG)
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
111
types/ext_image_capture_source_v1/foreign_toplevel.c
Normal file
111
types/ext_image_capture_source_v1/foreign_toplevel.c
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/interfaces/wlr_ext_image_capture_source_v1.h>
|
||||
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
|
||||
#include "ext-image-capture-source-v1-protocol.h"
|
||||
|
||||
#define FOREIGN_TOPLEVEL_IMAGE_SOURCE_MANAGER_V1_VERSION 1
|
||||
|
||||
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 *
|
||||
foreign_toplevel_manager_from_resource(struct wl_resource *resource) {
|
||||
assert(wl_resource_instance_of(resource,
|
||||
&ext_foreign_toplevel_image_capture_source_manager_v1_interface,
|
||||
&foreign_toplevel_manager_impl));
|
||||
return wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
bool wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept(
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *request,
|
||||
struct wlr_ext_image_capture_source_v1 *source) {
|
||||
return wlr_ext_image_capture_source_v1_create_resource(source, request->client, request->new_id);
|
||||
}
|
||||
|
||||
static void foreign_toplevel_manager_handle_create_source(struct wl_client *client,
|
||||
struct wl_resource *manager_resource, uint32_t new_id,
|
||||
struct wl_resource *foreign_toplevel_resource) {
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *manager =
|
||||
foreign_toplevel_manager_from_resource(manager_resource);
|
||||
struct wlr_ext_foreign_toplevel_handle_v1 *toplevel_handle =
|
||||
wlr_ext_foreign_toplevel_handle_v1_from_resource(foreign_toplevel_resource);
|
||||
if (toplevel_handle == NULL) {
|
||||
wlr_ext_image_capture_source_v1_create_resource(NULL, client, new_id);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *request =
|
||||
calloc(1, sizeof(*request));
|
||||
if (request == NULL) {
|
||||
wl_resource_post_no_memory(manager_resource);
|
||||
return;
|
||||
}
|
||||
|
||||
request->toplevel_handle = toplevel_handle;
|
||||
request->client = client;
|
||||
request->new_id = new_id;
|
||||
|
||||
wl_signal_emit_mutable(&manager->events.new_request, request);
|
||||
}
|
||||
|
||||
static void foreign_toplevel_manager_handle_destroy(struct wl_client *client,
|
||||
struct wl_resource *manager_resource) {
|
||||
wl_resource_destroy(manager_resource);
|
||||
}
|
||||
|
||||
static const struct ext_foreign_toplevel_image_capture_source_manager_v1_interface foreign_toplevel_manager_impl = {
|
||||
.create_source = foreign_toplevel_manager_handle_create_source,
|
||||
.destroy = foreign_toplevel_manager_handle_destroy,
|
||||
};
|
||||
|
||||
static void foreign_toplevel_manager_bind(struct wl_client *client, void *data,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *manager = data;
|
||||
|
||||
struct wl_resource *resource = wl_resource_create(client,
|
||||
&ext_foreign_toplevel_image_capture_source_manager_v1_interface, version, id);
|
||||
if (!resource) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(resource, &foreign_toplevel_manager_impl, manager, NULL);
|
||||
}
|
||||
|
||||
static void foreign_toplevel_manager_handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_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));
|
||||
assert(wl_list_empty(&manager->events.new_request.listener_list));
|
||||
wl_list_remove(&manager->display_destroy.link);
|
||||
wl_global_destroy(manager->global);
|
||||
free(manager);
|
||||
}
|
||||
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *
|
||||
wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(struct wl_display *display,
|
||||
uint32_t version) {
|
||||
assert(version <= FOREIGN_TOPLEVEL_IMAGE_SOURCE_MANAGER_V1_VERSION);
|
||||
|
||||
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *manager =
|
||||
calloc(1, sizeof(*manager));
|
||||
if (manager == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
manager->global = wl_global_create(display,
|
||||
&ext_foreign_toplevel_image_capture_source_manager_v1_interface,
|
||||
version, manager, foreign_toplevel_manager_bind);
|
||||
if (manager->global == NULL) {
|
||||
free(manager);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_signal_init(&manager->events.destroy);
|
||||
wl_signal_init(&manager->events.new_request);
|
||||
|
||||
manager->display_destroy.notify = foreign_toplevel_manager_handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &manager->display_destroy);
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ struct wlr_ext_output_image_capture_source_v1 {
|
|||
struct wlr_ext_output_image_capture_source_v1_frame_event {
|
||||
struct wlr_ext_image_capture_source_v1_frame_event base;
|
||||
struct wlr_buffer *buffer;
|
||||
struct timespec *when;
|
||||
struct timespec when;
|
||||
};
|
||||
|
||||
static void output_source_start(struct wlr_ext_image_capture_source_v1 *base,
|
||||
|
|
@ -85,7 +85,7 @@ static void output_source_copy_frame(struct wlr_ext_image_capture_source_v1 *bas
|
|||
if (wlr_ext_image_copy_capture_frame_v1_copy_buffer(frame,
|
||||
event->buffer, source->output->renderer)) {
|
||||
wlr_ext_image_copy_capture_frame_v1_ready(frame,
|
||||
source->output->transform, event->when);
|
||||
source->output->transform, &event->when);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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 = {
|
||||
|
|
|
|||
325
types/ext_image_capture_source_v1/scene.c
Normal file
325
types/ext_image_capture_source_v1/scene.c
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/backend/interface.h>
|
||||
#include <wlr/interfaces/wlr_ext_image_capture_source_v1.h>
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "types/wlr_output.h"
|
||||
#include "types/wlr_scene.h"
|
||||
|
||||
struct scene_node_source {
|
||||
struct wlr_ext_image_capture_source_v1 base;
|
||||
|
||||
struct wlr_scene_node *node;
|
||||
|
||||
struct wlr_backend backend;
|
||||
struct wlr_output output;
|
||||
struct wlr_scene_output *scene_output;
|
||||
|
||||
struct wl_event_source *idle_frame;
|
||||
|
||||
struct wl_listener node_destroy;
|
||||
struct wl_listener scene_output_destroy;
|
||||
struct wl_listener output_frame;
|
||||
};
|
||||
|
||||
struct scene_node_source_frame_event {
|
||||
struct wlr_ext_image_capture_source_v1_frame_event base;
|
||||
struct wlr_buffer *buffer;
|
||||
struct timespec when;
|
||||
};
|
||||
|
||||
static size_t last_output_num = 0;
|
||||
|
||||
static void _get_scene_node_extents(struct wlr_scene_node *node, struct wlr_box *box, int lx, int ly) {
|
||||
switch (node->type) {
|
||||
case WLR_SCENE_NODE_TREE:;
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
_get_scene_node_extents(child, box, lx + child->x, ly + child->y);
|
||||
}
|
||||
break;
|
||||
case WLR_SCENE_NODE_RECT:
|
||||
case WLR_SCENE_NODE_BUFFER:;
|
||||
struct wlr_box node_box = { .x = lx, .y = ly };
|
||||
scene_node_get_size(node, &node_box.width, &node_box.height);
|
||||
|
||||
if (node_box.x < box->x) {
|
||||
box->x = node_box.x;
|
||||
}
|
||||
if (node_box.y < box->y) {
|
||||
box->y = node_box.y;
|
||||
}
|
||||
if (node_box.x + node_box.width > box->x + box->width) {
|
||||
box->width = node_box.x + node_box.width - box->x;
|
||||
}
|
||||
if (node_box.y + node_box.height > box->y + box->height) {
|
||||
box->height = node_box.y + node_box.height - box->y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_scene_node_extents(struct wlr_scene_node *node, struct wlr_box *box) {
|
||||
*box = (struct wlr_box){ .x = INT_MAX, .y = INT_MAX };
|
||||
int lx = 0, ly = 0;
|
||||
wlr_scene_node_coords(node, &lx, &ly);
|
||||
_get_scene_node_extents(node, box, lx, ly);
|
||||
}
|
||||
|
||||
static void source_render(struct scene_node_source *source) {
|
||||
struct wlr_scene_output *scene_output = source->scene_output;
|
||||
|
||||
struct wlr_box extents;
|
||||
get_scene_node_extents(source->node, &extents);
|
||||
|
||||
if (extents.width == 0 || extents.height == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_scene_output_set_position(scene_output, extents.x, extents.y);
|
||||
|
||||
struct wlr_output_state state;
|
||||
wlr_output_state_init(&state);
|
||||
wlr_output_state_set_enabled(&state, true);
|
||||
wlr_output_state_set_custom_mode(&state, extents.width, extents.height, 0);
|
||||
bool ok = wlr_scene_output_build_state(scene_output, &state, NULL) &&
|
||||
wlr_output_commit_state(scene_output->output, &state);
|
||||
wlr_output_state_finish(&state);
|
||||
|
||||
if (!ok) {
|
||||
// TODO: send failure
|
||||
return;
|
||||
}
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_scene_output_send_frame_done(scene_output, &now);
|
||||
}
|
||||
|
||||
static void source_start(struct wlr_ext_image_capture_source_v1 *base, bool with_cursors) {
|
||||
struct scene_node_source *source = wl_container_of(base, source, base);
|
||||
source_render(source);
|
||||
}
|
||||
|
||||
static void source_stop(struct wlr_ext_image_capture_source_v1 *base) {
|
||||
struct scene_node_source *source = wl_container_of(base, source, base);
|
||||
|
||||
struct wlr_output_state state;
|
||||
wlr_output_state_init(&state);
|
||||
wlr_output_state_set_enabled(&state, false);
|
||||
wlr_output_commit_state(&source->output, &state);
|
||||
wlr_output_state_finish(&state);
|
||||
}
|
||||
|
||||
static void source_schedule_frame(struct wlr_ext_image_capture_source_v1 *base) {
|
||||
struct scene_node_source *source = wl_container_of(base, source, base);
|
||||
wlr_output_update_needs_frame(&source->output);
|
||||
}
|
||||
|
||||
static void source_copy_frame(struct wlr_ext_image_capture_source_v1 *base,
|
||||
struct wlr_ext_image_copy_capture_frame_v1 *frame,
|
||||
struct wlr_ext_image_capture_source_v1_frame_event *base_event) {
|
||||
struct scene_node_source *source = wl_container_of(base, source, base);
|
||||
struct scene_node_source_frame_event *event = wl_container_of(base_event, event, base);
|
||||
|
||||
if (wlr_ext_image_copy_capture_frame_v1_copy_buffer(frame,
|
||||
event->buffer, source->output.renderer)) {
|
||||
wlr_ext_image_copy_capture_frame_v1_ready(frame,
|
||||
source->output.transform, &event->when);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wlr_ext_image_capture_source_v1_interface source_impl = {
|
||||
.start = source_start,
|
||||
.stop = source_stop,
|
||||
.schedule_frame = source_schedule_frame,
|
||||
.copy_frame = source_copy_frame,
|
||||
};
|
||||
|
||||
static const struct wlr_backend_impl backend_impl = {0};
|
||||
|
||||
static void source_update_buffer_constraints(struct scene_node_source *source,
|
||||
const struct wlr_output_state *state) {
|
||||
struct wlr_output *output = &source->output;
|
||||
|
||||
if (!wlr_output_configure_primary_swapchain(output, state, &output->swapchain)) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_ext_image_capture_source_v1_set_constraints_from_swapchain(&source->base,
|
||||
output->swapchain, output->renderer);
|
||||
}
|
||||
|
||||
static void source_handle_idle_frame(void *data) {
|
||||
struct scene_node_source *source = data;
|
||||
source->idle_frame = NULL;
|
||||
wlr_output_send_frame(&source->output);
|
||||
}
|
||||
|
||||
static bool output_test(struct wlr_output *output, const struct wlr_output_state *state) {
|
||||
struct scene_node_source *source = wl_container_of(output, source, output);
|
||||
|
||||
uint32_t supported =
|
||||
WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
|
||||
WLR_OUTPUT_STATE_BUFFER |
|
||||
WLR_OUTPUT_STATE_ENABLED |
|
||||
WLR_OUTPUT_STATE_MODE;
|
||||
if ((state->committed & ~supported) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
int pending_width, pending_height;
|
||||
output_pending_resolution(output, state,
|
||||
&pending_width, &pending_height);
|
||||
if (state->buffer->width != pending_width ||
|
||||
state->buffer->height != pending_height) {
|
||||
return false;
|
||||
}
|
||||
struct wlr_fbox src_box;
|
||||
output_state_get_buffer_src_box(state, &src_box);
|
||||
if (src_box.x != 0.0 || src_box.y != 0.0 ||
|
||||
src_box.width != (double)state->buffer->width ||
|
||||
src_box.height != (double)state->buffer->height) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool output_commit(struct wlr_output *output, const struct wlr_output_state *state) {
|
||||
struct scene_node_source *source = wl_container_of(output, source, output);
|
||||
|
||||
if (source->idle_frame != NULL) {
|
||||
wlr_log(WLR_DEBUG, "Failed to commit capture output: a frame is still pending");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && !state->enabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_MODE) {
|
||||
source_update_buffer_constraints(source, state);
|
||||
}
|
||||
|
||||
if (!(state->committed & WLR_OUTPUT_STATE_BUFFER)) {
|
||||
wlr_log(WLR_DEBUG, "Failed to commit capture output: missing buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_buffer *buffer = state->buffer;
|
||||
|
||||
pixman_region32_t full_damage;
|
||||
pixman_region32_init_rect(&full_damage, 0, 0, buffer->width, buffer->height);
|
||||
|
||||
const pixman_region32_t *damage;
|
||||
if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
|
||||
damage = &state->damage;
|
||||
} else {
|
||||
damage = &full_damage;
|
||||
}
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
struct scene_node_source_frame_event frame_event = {
|
||||
.base = { .damage = damage },
|
||||
.buffer = buffer,
|
||||
.when = now,
|
||||
};
|
||||
wl_signal_emit_mutable(&source->base.events.frame, &frame_event.base);
|
||||
|
||||
pixman_region32_fini(&full_damage);
|
||||
|
||||
source->idle_frame =
|
||||
wl_event_loop_add_idle(output->event_loop, source_handle_idle_frame, source);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct wlr_output_impl output_impl = {
|
||||
.test = output_test,
|
||||
.commit = output_commit,
|
||||
};
|
||||
|
||||
static void source_destroy(struct scene_node_source *source) {
|
||||
wl_list_remove(&source->node_destroy.link);
|
||||
wl_list_remove(&source->scene_output_destroy.link);
|
||||
wl_list_remove(&source->output_frame.link);
|
||||
wlr_ext_image_capture_source_v1_finish(&source->base);
|
||||
wlr_scene_output_destroy(source->scene_output);
|
||||
wlr_output_finish(&source->output);
|
||||
wlr_backend_finish(&source->backend);
|
||||
free(source);
|
||||
}
|
||||
|
||||
static void source_handle_node_destroy(struct wl_listener *listener, void *data) {
|
||||
struct scene_node_source *source = wl_container_of(listener, source, node_destroy);
|
||||
source_destroy(source);
|
||||
}
|
||||
|
||||
static void source_handle_scene_output_destroy(struct wl_listener *listener, void *data) {
|
||||
struct scene_node_source *source = wl_container_of(listener, source, scene_output_destroy);
|
||||
source->scene_output = NULL;
|
||||
wl_list_remove(&source->scene_output_destroy.link);
|
||||
wl_list_init(&source->scene_output_destroy.link);
|
||||
}
|
||||
|
||||
static void source_handle_output_frame(struct wl_listener *listener, void *data) {
|
||||
struct scene_node_source *source = wl_container_of(listener, source, output_frame);
|
||||
if (source->scene_output == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wlr_scene_output_needs_frame(source->scene_output)) {
|
||||
return;
|
||||
}
|
||||
|
||||
source_render(source);
|
||||
}
|
||||
|
||||
struct wlr_ext_image_capture_source_v1 *wlr_ext_image_capture_source_v1_create_with_scene_node(
|
||||
struct wlr_scene_node *node, struct wl_event_loop *event_loop,
|
||||
struct wlr_allocator *allocator, struct wlr_renderer *renderer) {
|
||||
struct scene_node_source *source = calloc(1, sizeof(*source));
|
||||
if (source == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
source->node = node;
|
||||
|
||||
wlr_ext_image_capture_source_v1_init(&source->base, &source_impl);
|
||||
|
||||
wlr_backend_init(&source->backend, &backend_impl);
|
||||
source->backend.buffer_caps = WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_SHM;
|
||||
|
||||
wlr_output_init(&source->output, &source->backend, &output_impl, event_loop, NULL);
|
||||
|
||||
size_t output_num = ++last_output_num;
|
||||
char name[64];
|
||||
snprintf(name, sizeof(name), "CAPTURE-%zu", output_num);
|
||||
wlr_output_set_name(&source->output, name);
|
||||
|
||||
wlr_output_init_render(&source->output, allocator, renderer);
|
||||
|
||||
struct wlr_scene *scene = scene_node_get_root(node);
|
||||
source->scene_output = wlr_scene_output_create(scene, &source->output);
|
||||
|
||||
source->node_destroy.notify = source_handle_node_destroy;
|
||||
wl_signal_add(&node->events.destroy, &source->node_destroy);
|
||||
|
||||
source->scene_output_destroy.notify = source_handle_scene_output_destroy;
|
||||
wl_signal_add(&source->scene_output->events.destroy, &source->scene_output_destroy);
|
||||
|
||||
source->output_frame.notify = source_handle_output_frame;
|
||||
wl_signal_add(&source->output.events.frame, &source->output_frame);
|
||||
|
||||
return &source->base;
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@ wlr_files += files(
|
|||
'data_device/wlr_drag.c',
|
||||
'ext_image_capture_source_v1/base.c',
|
||||
'ext_image_capture_source_v1/output.c',
|
||||
'ext_image_capture_source_v1/foreign_toplevel.c',
|
||||
'ext_image_capture_source_v1/scene.c',
|
||||
'output/cursor.c',
|
||||
'output/output.c',
|
||||
'output/render.c',
|
||||
|
|
@ -37,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',
|
||||
|
|
@ -101,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->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);
|
||||
}
|
||||
|
||||
output_cursor_damage_whole(cursor);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,20 +16,9 @@
|
|||
|
||||
static void send_geometry(struct wl_resource *resource) {
|
||||
struct wlr_output *output = wlr_output_from_resource(resource);
|
||||
|
||||
const char *make = output->make;
|
||||
if (make == NULL) {
|
||||
make = "Unknown";
|
||||
}
|
||||
|
||||
const char *model = output->model;
|
||||
if (model == NULL) {
|
||||
model = "Unknown";
|
||||
}
|
||||
|
||||
wl_output_send_geometry(resource, 0, 0,
|
||||
output->phys_width, output->phys_height, output->subpixel,
|
||||
make, model, output->transform);
|
||||
"Unknown", "Unknown", output->transform);
|
||||
}
|
||||
|
||||
static void send_current_mode(struct wl_resource *resource) {
|
||||
|
|
@ -244,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);
|
||||
|
|
@ -409,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);
|
||||
|
||||
|
|
@ -502,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.
|
||||
|
|
@ -509,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) {
|
||||
|
|
@ -556,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;
|
||||
}
|
||||
|
||||
|
|
@ -638,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");
|
||||
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 (!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_GAMMA_LUT) {
|
||||
wlr_log(WLR_DEBUG, "Tried to set the gamma lut on 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 (state->committed & WLR_OUTPUT_STATE_LAYERS) {
|
||||
|
|
@ -680,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;
|
||||
}
|
||||
|
||||
|
|
@ -728,7 +755,7 @@ bool output_prepare_commit(struct wlr_output *output, const struct wlr_output_st
|
|||
|
||||
struct wlr_output_event_precommit pre_event = {
|
||||
.output = output,
|
||||
.when = &now,
|
||||
.when = now,
|
||||
.state = state,
|
||||
};
|
||||
wl_signal_emit_mutable(&output->events.precommit, &pre_event);
|
||||
|
|
@ -745,12 +772,14 @@ 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 = {
|
||||
.output = output,
|
||||
.when = &now,
|
||||
.when = now,
|
||||
.state = state,
|
||||
};
|
||||
wl_signal_emit_mutable(&output->events.commit, &event);
|
||||
|
|
@ -787,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);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/render/color.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "types/wlr_output.h"
|
||||
|
||||
|
|
@ -16,9 +17,9 @@ void wlr_output_state_finish(struct wlr_output_state *state) {
|
|||
// reads it after output_state_finish().
|
||||
state->buffer = NULL;
|
||||
pixman_region32_fini(&state->damage);
|
||||
free(state->gamma_lut);
|
||||
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,
|
||||
|
|
@ -88,28 +89,6 @@ void wlr_output_state_set_damage(struct wlr_output_state *state,
|
|||
pixman_region32_copy(&state->damage, damage);
|
||||
}
|
||||
|
||||
bool wlr_output_state_set_gamma_lut(struct wlr_output_state *state,
|
||||
size_t ramp_size, const uint16_t *r, const uint16_t *g, const uint16_t *b) {
|
||||
uint16_t *gamma_lut = NULL;
|
||||
if (ramp_size > 0) {
|
||||
gamma_lut = realloc(state->gamma_lut, 3 * ramp_size * sizeof(uint16_t));
|
||||
if (gamma_lut == NULL) {
|
||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||
return false;
|
||||
}
|
||||
memcpy(gamma_lut, r, ramp_size * sizeof(uint16_t));
|
||||
memcpy(gamma_lut + ramp_size, g, ramp_size * sizeof(uint16_t));
|
||||
memcpy(gamma_lut + 2 * ramp_size, b, ramp_size * sizeof(uint16_t));
|
||||
} else {
|
||||
free(state->gamma_lut);
|
||||
}
|
||||
|
||||
state->committed |= WLR_OUTPUT_STATE_GAMMA_LUT;
|
||||
state->gamma_lut_size = ramp_size;
|
||||
state->gamma_lut = gamma_lut;
|
||||
return true;
|
||||
}
|
||||
|
||||
void wlr_output_state_set_layers(struct wlr_output_state *state,
|
||||
struct wlr_output_layer_state *layers, size_t layers_len) {
|
||||
state->committed |= WLR_OUTPUT_STATE_LAYERS;
|
||||
|
|
@ -133,22 +112,51 @@ void wlr_output_state_set_signal_timeline(struct wlr_output_state *state,
|
|||
state->signal_point = dst_point;
|
||||
}
|
||||
|
||||
void wlr_output_state_set_color_transform(struct wlr_output_state *state,
|
||||
struct wlr_color_transform *tr) {
|
||||
state->committed |= WLR_OUTPUT_STATE_COLOR_TRANSFORM;
|
||||
wlr_color_transform_unref(state->color_transform);
|
||||
if (tr) {
|
||||
state->color_transform = wlr_color_transform_ref(tr);
|
||||
} else {
|
||||
state->color_transform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
copy.committed &= ~(WLR_OUTPUT_STATE_BUFFER |
|
||||
WLR_OUTPUT_STATE_DAMAGE |
|
||||
WLR_OUTPUT_STATE_GAMMA_LUT |
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE);
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
|
||||
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};
|
||||
pixman_region32_init(©.damage);
|
||||
copy.gamma_lut = NULL;
|
||||
copy.gamma_lut_size = 0;
|
||||
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,15 +168,6 @@ bool wlr_output_state_copy(struct wlr_output_state *dst,
|
|||
wlr_output_state_set_damage(©, &src->damage);
|
||||
}
|
||||
|
||||
if (src->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
|
||||
const uint16_t *r = src->gamma_lut;
|
||||
const uint16_t *g = src->gamma_lut + src->gamma_lut_size;
|
||||
const uint16_t *b = src->gamma_lut + 2 * src->gamma_lut_size;
|
||||
if (!wlr_output_state_set_gamma_lut(©, src->gamma_lut_size, r, g, b)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (src->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
|
||||
wlr_output_state_set_wait_timeline(©, src->wait_timeline,
|
||||
src->wait_point);
|
||||
|
|
@ -178,11 +177,20 @@ bool wlr_output_state_copy(struct wlr_output_state *dst,
|
|||
src->signal_point);
|
||||
}
|
||||
|
||||
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(©);
|
||||
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>
|
||||
|
|
@ -11,19 +12,99 @@
|
|||
#include <wlr/util/transform.h>
|
||||
#include "types/wlr_scene.h"
|
||||
|
||||
static double get_surface_preferred_buffer_scale(struct wlr_surface *surface) {
|
||||
double scale = 1;
|
||||
struct wlr_surface_output *surface_output;
|
||||
wl_list_for_each(surface_output, &surface->current_outputs, link) {
|
||||
if (surface_output->output->scale > scale) {
|
||||
scale = surface_output->output->scale;
|
||||
}
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
static struct wlr_output *get_surface_frame_pacing_output(struct wlr_surface *surface) {
|
||||
struct wlr_output *frame_pacing_output = NULL;
|
||||
struct wlr_surface_output *surface_output;
|
||||
wl_list_for_each(surface_output, &surface->current_outputs, link) {
|
||||
if (frame_pacing_output == NULL ||
|
||||
surface_output->output->refresh > frame_pacing_output->refresh) {
|
||||
frame_pacing_output = surface_output->output;
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
if (surface->buffer->primary_output == NULL) {
|
||||
return;
|
||||
}
|
||||
double scale = surface->buffer->primary_output->output->scale;
|
||||
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));
|
||||
wlr_surface_set_preferred_buffer_transform(surface->surface,
|
||||
surface->buffer->primary_output->output->transform);
|
||||
|
||||
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(
|
||||
|
|
@ -49,15 +130,15 @@ static void handle_scene_buffer_output_sample(
|
|||
struct wlr_scene_surface *surface =
|
||||
wl_container_of(listener, surface, output_sample);
|
||||
const struct wlr_scene_output_sample_event *event = data;
|
||||
struct wlr_scene_output *scene_output = event->output;
|
||||
if (surface->buffer->primary_output != scene_output) {
|
||||
struct wlr_output *output = event->output->output;
|
||||
if (surface->frame_pacing_output != output) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->direct_scanout) {
|
||||
wlr_presentation_surface_scanned_out_on_output(surface->surface, scene_output->output);
|
||||
wlr_presentation_surface_scanned_out_on_output(surface->surface, output);
|
||||
} else {
|
||||
wlr_presentation_surface_textured_on_output(surface->surface, scene_output->output);
|
||||
wlr_presentation_surface_textured_on_output(surface->surface, output);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,9 +146,19 @@ static void handle_scene_buffer_frame_done(
|
|||
struct wl_listener *listener, void *data) {
|
||||
struct wlr_scene_surface *surface =
|
||||
wl_container_of(listener, surface, frame_done);
|
||||
struct timespec *now = data;
|
||||
struct wlr_scene_frame_done_event *event = data;
|
||||
if (surface->frame_pacing_output != event->output->output) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_surface_send_frame_done(surface->surface, now);
|
||||
wlr_surface_send_frame_done(surface->surface, &event->when);
|
||||
}
|
||||
|
||||
void wlr_scene_surface_send_frame_done(struct wlr_scene_surface *scene_surface,
|
||||
const struct timespec *when) {
|
||||
if (!pixman_region32_empty(&scene_surface->buffer->node.visible)) {
|
||||
wlr_surface_send_frame_done(scene_surface->surface, when);
|
||||
}
|
||||
}
|
||||
|
||||
static void scene_surface_handle_surface_destroy(
|
||||
|
|
@ -96,9 +187,12 @@ static void scene_buffer_unmark_client_buffer(struct wlr_scene_buffer *scene_buf
|
|||
return;
|
||||
}
|
||||
|
||||
assert(buffer->n_ignore_locks > 0);
|
||||
// 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) {
|
||||
return a < b ? a : b;
|
||||
|
|
@ -156,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) {
|
||||
// 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);
|
||||
|
|
@ -186,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"
|
||||
|
|
@ -210,8 +212,6 @@ struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent) {
|
|||
return tree;
|
||||
}
|
||||
|
||||
static void scene_node_get_size(struct wlr_scene_node *node, int *lx, int *ly);
|
||||
|
||||
typedef bool (*scene_node_box_iterator_func_t)(struct wlr_scene_node *node,
|
||||
int sx, int sy, void *data);
|
||||
|
||||
|
|
@ -426,6 +426,8 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
|
|||
size_t count = 0;
|
||||
uint64_t active_outputs = 0;
|
||||
|
||||
uint32_t visible_area = region_area(&node->visible);
|
||||
|
||||
// let's update the outputs in two steps:
|
||||
// - the primary outputs
|
||||
// - the enter/leave signals
|
||||
|
|
@ -453,9 +455,12 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
|
|||
pixman_region32_init(&intersection);
|
||||
pixman_region32_intersect_rect(&intersection, &node->visible,
|
||||
output_box.x, output_box.y, output_box.width, output_box.height);
|
||||
|
||||
if (!pixman_region32_empty(&intersection)) {
|
||||
uint32_t overlap = region_area(&intersection);
|
||||
pixman_region32_fini(&intersection);
|
||||
|
||||
// If the overlap accounts for less than 10% of the visible node area,
|
||||
// ignore this output
|
||||
if (overlap >= 0.1 * visible_area) {
|
||||
if (overlap >= largest_overlap) {
|
||||
largest_overlap = overlap;
|
||||
scene_buffer->primary_output = scene_output;
|
||||
|
|
@ -464,8 +469,6 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
|
|||
active_outputs |= 1ull << scene_output->index;
|
||||
count++;
|
||||
}
|
||||
|
||||
pixman_region32_fini(&intersection);
|
||||
}
|
||||
|
||||
if (old_primary_output != scene_buffer->primary_output) {
|
||||
|
|
@ -1071,9 +1074,9 @@ void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer,
|
|||
}
|
||||
|
||||
void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer,
|
||||
struct timespec *now) {
|
||||
struct wlr_scene_frame_done_event *event) {
|
||||
if (!pixman_region32_empty(&scene_buffer->node.visible)) {
|
||||
wl_signal_emit_mutable(&scene_buffer->events.frame_done, now);
|
||||
wl_signal_emit_mutable(&scene_buffer->events.frame_done, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1098,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) {
|
||||
|
|
@ -1120,8 +1143,7 @@ static struct wlr_texture *scene_buffer_get_texture(
|
|||
return texture;
|
||||
}
|
||||
|
||||
static void scene_node_get_size(struct wlr_scene_node *node,
|
||||
int *width, int *height) {
|
||||
void scene_node_get_size(struct wlr_scene_node *node, int *width, int *height) {
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -1867,12 +1919,41 @@ static void scene_buffer_send_dmabuf_feedback(const struct wlr_scene *scene,
|
|||
return;
|
||||
}
|
||||
|
||||
enum wl_output_transform preferred_buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
if (options->scanout_primary_output != NULL) {
|
||||
preferred_buffer_transform = options->scanout_primary_output->transform;
|
||||
}
|
||||
|
||||
// TODO: also send wl_surface.preferred_buffer_transform when running with
|
||||
// pure software rendering
|
||||
wlr_surface_set_preferred_buffer_transform(surface->surface, preferred_buffer_transform);
|
||||
wlr_linux_dmabuf_v1_set_surface_feedback(scene->linux_dmabuf_v1,
|
||||
surface->surface, &feedback);
|
||||
|
||||
wlr_linux_dmabuf_feedback_v1_finish(&feedback);
|
||||
}
|
||||
|
||||
static bool color_management_is_scanout_allowed(const struct wlr_output_image_description *img_desc,
|
||||
const struct wlr_scene_buffer *buffer) {
|
||||
// Disallow scanout if the output has colorimetry information but buffer
|
||||
// doesn't; allow it only if the output also lacks it.
|
||||
if (buffer->transfer_function == 0 && buffer->primaries == 0) {
|
||||
return img_desc == NULL;
|
||||
}
|
||||
|
||||
// If the output has colorimetry information, the buffer must match it for
|
||||
// direct scanout to be allowed.
|
||||
if (img_desc != NULL) {
|
||||
return img_desc->transfer_function == buffer->transfer_function &&
|
||||
img_desc->primaries == buffer->primaries;
|
||||
}
|
||||
// If the output doesn't have colorimetry image description set, we can only
|
||||
// scan out buffers with default colorimetry (gamma2.2 transfer and sRGB
|
||||
// primaries) used in wlroots.
|
||||
return buffer->transfer_function == WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 &&
|
||||
buffer->primaries == WLR_COLOR_NAMED_PRIMARIES_SRGB;
|
||||
}
|
||||
|
||||
enum scene_direct_scanout_result {
|
||||
// This scene node is not a candidate for scanout
|
||||
SCANOUT_INELIGIBLE,
|
||||
|
|
@ -1929,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.
|
||||
|
|
@ -2026,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;
|
||||
}
|
||||
|
|
@ -2044,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};
|
||||
|
|
@ -2067,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,
|
||||
|
|
@ -2167,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);
|
||||
}
|
||||
|
|
@ -2227,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;
|
||||
|
|
@ -2347,7 +2504,9 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
scene_output->in_point);
|
||||
}
|
||||
|
||||
if (!render_gamma_lut) {
|
||||
scene_output_state_attempt_gamma(scene_output, state);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2376,10 +2535,11 @@ static void scene_node_send_frame_done(struct wlr_scene_node *node,
|
|||
if (node->type == WLR_SCENE_NODE_BUFFER) {
|
||||
struct wlr_scene_buffer *scene_buffer =
|
||||
wlr_scene_buffer_from_node(node);
|
||||
|
||||
if (scene_buffer->primary_output == scene_output) {
|
||||
wlr_scene_buffer_send_frame_done(scene_buffer, now);
|
||||
}
|
||||
struct wlr_scene_frame_done_event event = {
|
||||
.output = scene_output,
|
||||
.when = *now,
|
||||
};
|
||||
wlr_scene_buffer_send_frame_done(scene_buffer, &event);
|
||||
} else if (node->type == WLR_SCENE_NODE_TREE) {
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
|
|
|
|||
|
|
@ -103,7 +103,10 @@ void destroy_tablet_tool_v2(struct wl_resource *resource) {
|
|||
}
|
||||
|
||||
if (client->tool && client->tool->current_client == client) {
|
||||
wl_list_remove(&client->tool->surface_destroy.link);
|
||||
wl_list_init(&client->tool->surface_destroy.link);
|
||||
client->tool->current_client = NULL;
|
||||
client->tool->focused_surface = NULL;
|
||||
}
|
||||
|
||||
wl_list_remove(&client->seat_link);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -650,7 +647,7 @@ static void output_cursor_output_handle_output_commit(
|
|||
struct wlr_surface *surface = output_cursor->cursor->state->surface;
|
||||
if (surface && output_cursor->output_cursor->visible &&
|
||||
(event->state->committed & WLR_OUTPUT_STATE_BUFFER)) {
|
||||
wlr_surface_send_frame_done(surface, event->when);
|
||||
wlr_surface_send_frame_done(surface, &event->when);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@
|
|||
#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 1
|
||||
#define CURSOR_SHAPE_MANAGER_V1_VERSION 2
|
||||
|
||||
struct wlr_cursor_shape_device_v1 {
|
||||
struct wl_resource *resource;
|
||||
|
|
@ -46,7 +48,8 @@ static void device_handle_set_shape(struct wl_client *client, struct wl_resource
|
|||
return;
|
||||
}
|
||||
|
||||
if (shape == 0 || shape > WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT) {
|
||||
uint32_t version = wl_resource_get_version(device_resource);
|
||||
if (!wp_cursor_shape_device_v1_shape_is_valid(shape, version)) {
|
||||
wl_resource_post_error(device_resource, WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE,
|
||||
"Invalid shape %"PRIu32, shape);
|
||||
return;
|
||||
|
|
@ -256,6 +259,8 @@ static const char *const shape_names[] = {
|
|||
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL] = "all-scroll",
|
||||
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN] = "zoom-in",
|
||||
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT] = "zoom-out",
|
||||
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK] = "dnd-ask",
|
||||
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE] = "all-resize",
|
||||
};
|
||||
|
||||
const char *wlr_cursor_shape_v1_name(enum wp_cursor_shape_device_v1_shape shape) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -85,11 +85,11 @@ static void frame_output_handle_commit(struct wl_listener *listener,
|
|||
attribs.fd[i], size, attribs.offset[i], attribs.stride[i], i);
|
||||
}
|
||||
|
||||
time_t tv_sec = event->when->tv_sec;
|
||||
time_t tv_sec = event->when.tv_sec;
|
||||
uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0;
|
||||
uint32_t tv_sec_lo = tv_sec & 0xFFFFFFFF;
|
||||
zwlr_export_dmabuf_frame_v1_send_ready(frame->resource,
|
||||
tv_sec_hi, tv_sec_lo, event->when->tv_nsec);
|
||||
tv_sec_hi, tv_sec_lo, event->when.tv_nsec);
|
||||
frame_destroy(frame);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -273,12 +273,27 @@ static void toplevel_handle_output_bind(struct wl_listener *listener,
|
|||
toplevel_update_idle_source(toplevel_output->toplevel);
|
||||
}
|
||||
|
||||
static void toplevel_output_destroy(
|
||||
struct wlr_foreign_toplevel_handle_v1_output *toplevel_output) {
|
||||
wl_list_remove(&toplevel_output->link);
|
||||
wl_list_remove(&toplevel_output->output_bind.link);
|
||||
wl_list_remove(&toplevel_output->output_destroy.link);
|
||||
free(toplevel_output);
|
||||
}
|
||||
|
||||
static void toplevel_output_leave(
|
||||
struct wlr_foreign_toplevel_handle_v1_output *toplevel_output) {
|
||||
struct wlr_foreign_toplevel_handle_v1 *toplevel = toplevel_output->toplevel;
|
||||
struct wlr_output *output = toplevel_output->output;
|
||||
toplevel_send_output(toplevel, output, false);
|
||||
toplevel_output_destroy(toplevel_output);
|
||||
}
|
||||
|
||||
static void toplevel_handle_output_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct wlr_foreign_toplevel_handle_v1_output *toplevel_output =
|
||||
wl_container_of(listener, toplevel_output, output_destroy);
|
||||
wlr_foreign_toplevel_handle_v1_output_leave(toplevel_output->toplevel,
|
||||
toplevel_output->output);
|
||||
toplevel_output_leave(toplevel_output);
|
||||
}
|
||||
|
||||
void wlr_foreign_toplevel_handle_v1_output_enter(
|
||||
|
|
@ -310,34 +325,19 @@ void wlr_foreign_toplevel_handle_v1_output_enter(
|
|||
toplevel_send_output(toplevel, output, true);
|
||||
}
|
||||
|
||||
static void toplevel_output_destroy(
|
||||
struct wlr_foreign_toplevel_handle_v1_output *toplevel_output) {
|
||||
wl_list_remove(&toplevel_output->link);
|
||||
wl_list_remove(&toplevel_output->output_bind.link);
|
||||
wl_list_remove(&toplevel_output->output_destroy.link);
|
||||
free(toplevel_output);
|
||||
}
|
||||
|
||||
void wlr_foreign_toplevel_handle_v1_output_leave(
|
||||
struct wlr_foreign_toplevel_handle_v1 *toplevel,
|
||||
struct wlr_output *output) {
|
||||
struct wlr_foreign_toplevel_handle_v1_output *toplevel_output_iterator;
|
||||
struct wlr_foreign_toplevel_handle_v1_output *toplevel_output = NULL;
|
||||
|
||||
wl_list_for_each(toplevel_output_iterator, &toplevel->outputs, link) {
|
||||
if (toplevel_output_iterator->output == output) {
|
||||
toplevel_output = toplevel_output_iterator;
|
||||
break;
|
||||
toplevel_output_leave(toplevel_output_iterator);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (toplevel_output) {
|
||||
toplevel_send_output(toplevel, output, false);
|
||||
toplevel_output_destroy(toplevel_output);
|
||||
} else {
|
||||
// XXX: log an error? crash?
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_array_from_toplevel_state(struct wl_array *states,
|
||||
uint32_t data[], uint32_t state, uint32_t version) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue