From cc1229e75e0c0c2cf5ae6d67bc7411c2631deb86 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Thu, 1 Feb 2018 20:27:35 +0100 Subject: [PATCH 1/8] Add atomic gamma setting --- backend/drm/atomic.c | 32 ++++++++++++++++++++++++++++++++ backend/drm/drm.c | 5 ++++- backend/drm/legacy.c | 8 ++++++++ backend/drm/properties.c | 1 + include/backend/drm/drm.h | 5 ++++- include/backend/drm/iface.h | 4 ++++ include/backend/drm/properties.h | 3 ++- 7 files changed, 55 insertions(+), 3 deletions(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 54024d86..a8003492 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -195,9 +196,40 @@ static bool atomic_crtc_move_cursor(struct wlr_drm_backend *drm, return atomic_end(drm->fd, &atom); } +static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, + struct wlr_drm_crtc *crtc, uint16_t *r, uint16_t *g, uint16_t *b, + uint32_t size) { + struct drm_color_lut *gamma = calloc(sizeof(struct drm_color_lut), size); + + for (uint32_t i = 0; i < size; i++) { + gamma[i].red = r[i]; + gamma[i].green = g[i]; + gamma[i].blue = b[i]; + } + + if (crtc->gamma_lut != 0) { + drmModeDestroyPropertyBlob(drm->fd, crtc->gamma_lut); + } + + if (drmModeCreatePropertyBlob(drm->fd, gamma, + sizeof(struct drm_color_lut) * size, &crtc->gamma_lut)) { + wlr_log_errno(L_ERROR, "Unable to create property blob"); + return false; + } + + free(gamma); + + struct atomic atom; + + atomic_begin(crtc, &atom); + atomic_add(&atom, crtc->id, crtc->props.gamma_lut, crtc->gamma_lut); + return atomic_end(drm->fd, &atom); +} + const struct wlr_drm_interface atomic_iface = { .conn_enable = atomic_conn_enable, .crtc_pageflip = atomic_crtc_pageflip, .crtc_set_cursor = atomic_crtc_set_cursor, .crtc_move_cursor = atomic_crtc_move_cursor, + .crtc_set_gamma = atomic_crtc_set_gamma, }; diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 08ced783..abcfcf8a 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -169,6 +169,9 @@ void wlr_drm_resources_free(struct wlr_drm_backend *drm) { if (crtc->mode_id) { drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id); } + if (crtc->gamma_lut) { + drmModeDestroyPropertyBlob(drm->fd, crtc->gamma_lut); + } } for (size_t i = 0; i < drm->num_planes; ++i) { struct wlr_drm_plane *plane = &drm->planes[i]; @@ -227,7 +230,7 @@ static void wlr_drm_connector_set_gamma(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; - drmModeCrtcSetGamma(drm->fd, conn->crtc->id, size, r, g, b); + drm->iface->crtc_set_gamma(drm, conn->crtc, r, g, b, size); } static uint32_t wlr_drm_connector_get_gamma_size(struct wlr_output *output) { diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index 61140cec..46911905 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -59,9 +59,17 @@ bool legacy_crtc_move_cursor(struct wlr_drm_backend *drm, return !drmModeMoveCursor(drm->fd, crtc->id, x, y); } +bool legacy_crtc_set_gamma(struct wlr_drm_backend *drm, + struct wlr_drm_crtc *crtc, uint16_t *r, uint16_t *g, uint16_t *b, + uint32_t size) { + return !drmModeCrtcSetGamma(drm->fd, crtc->id, size, r, g, b); +} + + const struct wlr_drm_interface legacy_iface = { .conn_enable = legacy_conn_enable, .crtc_pageflip = legacy_crtc_pageflip, .crtc_set_cursor = legacy_crtc_set_cursor, .crtc_move_cursor = legacy_crtc_move_cursor, + .crtc_set_gamma = legacy_crtc_set_gamma, }; diff --git a/backend/drm/properties.c b/backend/drm/properties.c index 5bec3243..c3efa96e 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -28,6 +28,7 @@ static const struct prop_info connector_info[] = { static const struct prop_info crtc_info[] = { #define INDEX(name) (offsetof(union wlr_drm_crtc_props, name) / sizeof(uint32_t)) { "ACTIVE", INDEX(active) }, + { "GAMMA_LUT", INDEX(gamma_lut) }, { "MODE_ID", INDEX(mode_id) }, { "rotation", INDEX(rotation) }, { "scaling mode", INDEX(scaling_mode) }, diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index af472ede..782764c8 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -39,7 +39,10 @@ struct wlr_drm_plane { struct wlr_drm_crtc { uint32_t id; - uint32_t mode_id; // atomic modesetting only + + // Atomic modesetting only + uint32_t mode_id; + uint32_t gamma_lut; drmModeAtomicReq *atomic; union { diff --git a/include/backend/drm/iface.h b/include/backend/drm/iface.h index 4a5d2e9d..228b313a 100644 --- a/include/backend/drm/iface.h +++ b/include/backend/drm/iface.h @@ -27,6 +27,10 @@ struct wlr_drm_interface { // Move the cursor on crtc bool (*crtc_move_cursor)(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, int x, int y); + // Set the gamma lut on crtc + bool (*crtc_set_gamma)(struct wlr_drm_backend *drm, + struct wlr_drm_crtc *crtc, uint16_t *r, uint16_t *g, uint16_t *b, + uint32_t size); }; extern const struct wlr_drm_interface atomic_iface; diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h index 7de386ea..119d24c3 100644 --- a/include/backend/drm/properties.h +++ b/include/backend/drm/properties.h @@ -32,8 +32,9 @@ union wlr_drm_crtc_props { uint32_t active; uint32_t mode_id; + uint32_t gamma_lut; }; - uint32_t props[4]; + uint32_t props[5]; }; union wlr_drm_plane_props { From ab011406add31c518f6f352189b1dc6246a74fdb Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Sun, 4 Feb 2018 21:03:44 +0100 Subject: [PATCH 2/8] Add atomic gamma lut size fetching Legacy gamma lut size now uses the new legacy_crtc member of wlr_drm_crtc. This was Previously doen using old_crtc in wlr_drm_connector, but since this refers to the crtc that was connected to the ouput, this could give the wrong result. --- backend/drm/atomic.c | 14 ++++++++++++++ backend/drm/drm.c | 6 ++++-- backend/drm/legacy.c | 5 +++++ backend/drm/properties.c | 11 ++++++----- include/backend/drm/drm.h | 3 +++ include/backend/drm/iface.h | 3 +++ include/backend/drm/properties.h | 3 ++- 7 files changed, 37 insertions(+), 8 deletions(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index a8003492..79765fef 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -226,10 +226,24 @@ static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, return atomic_end(drm->fd, &atom); } +static uint32_t atomic_crtc_get_gamma_size(struct wlr_drm_backend *drm, + struct wlr_drm_crtc *crtc) { + uint64_t gamma_lut_size; + + if (!wlr_drm_get_prop(drm->fd, crtc->id, crtc->props.gamma_lut_size, + &gamma_lut_size)) { + wlr_log(L_ERROR, "Unable to get gamma lut size"); + return 0; + } + + return (uint32_t) gamma_lut_size; +} + const struct wlr_drm_interface atomic_iface = { .conn_enable = atomic_conn_enable, .crtc_pageflip = atomic_crtc_pageflip, .crtc_set_cursor = atomic_crtc_set_cursor, .crtc_move_cursor = atomic_crtc_move_cursor, .crtc_set_gamma = atomic_crtc_set_gamma, + .crtc_get_gamma_size = atomic_crtc_get_gamma_size, }; diff --git a/backend/drm/drm.c b/backend/drm/drm.c index abcfcf8a..eef1e333 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -140,6 +140,7 @@ bool wlr_drm_resources_init(struct wlr_drm_backend *drm) { for (size_t i = 0; i < drm->num_crtcs; ++i) { struct wlr_drm_crtc *crtc = &drm->crtcs[i]; crtc->id = res->crtcs[i]; + crtc->legacy_crtc = drmModeGetCrtc(drm->fd, crtc->id); wlr_drm_get_crtc_props(drm->fd, crtc->id, &crtc->props); } @@ -166,6 +167,7 @@ void wlr_drm_resources_free(struct wlr_drm_backend *drm) { for (size_t i = 0; i < drm->num_crtcs; ++i) { struct wlr_drm_crtc *crtc = &drm->crtcs[i]; drmModeAtomicFree(crtc->atomic); + drmModeFreeCrtc(crtc->legacy_crtc); if (crtc->mode_id) { drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id); } @@ -235,8 +237,8 @@ static void wlr_drm_connector_set_gamma(struct wlr_output *output, static uint32_t wlr_drm_connector_get_gamma_size(struct wlr_output *output) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; - drmModeCrtc *crtc = conn->old_crtc; - return crtc ? crtc->gamma_size : 0; + struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; + return drm->iface->crtc_get_gamma_size(drm, conn->crtc); } void wlr_drm_connector_start_renderer(struct wlr_drm_connector *conn) { diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index 46911905..eec8c642 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -65,6 +65,10 @@ bool legacy_crtc_set_gamma(struct wlr_drm_backend *drm, return !drmModeCrtcSetGamma(drm->fd, crtc->id, size, r, g, b); } +uint32_t legacy_crtc_get_gamma_size(struct wlr_drm_backend *drm, + struct wlr_drm_crtc *crtc) { + return crtc->legacy_crtc->gamma_size; +} const struct wlr_drm_interface legacy_iface = { .conn_enable = legacy_conn_enable, @@ -72,4 +76,5 @@ const struct wlr_drm_interface legacy_iface = { .crtc_set_cursor = legacy_crtc_set_cursor, .crtc_move_cursor = legacy_crtc_move_cursor, .crtc_set_gamma = legacy_crtc_set_gamma, + .crtc_get_gamma_size = legacy_crtc_get_gamma_size, }; diff --git a/backend/drm/properties.c b/backend/drm/properties.c index c3efa96e..153e845e 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -27,11 +27,12 @@ static const struct prop_info connector_info[] = { static const struct prop_info crtc_info[] = { #define INDEX(name) (offsetof(union wlr_drm_crtc_props, name) / sizeof(uint32_t)) - { "ACTIVE", INDEX(active) }, - { "GAMMA_LUT", INDEX(gamma_lut) }, - { "MODE_ID", INDEX(mode_id) }, - { "rotation", INDEX(rotation) }, - { "scaling mode", INDEX(scaling_mode) }, + { "ACTIVE", INDEX(active) }, + { "GAMMA_LUT", INDEX(gamma_lut) }, + { "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) }, + { "MODE_ID", INDEX(mode_id) }, + { "rotation", INDEX(rotation) }, + { "scaling mode", INDEX(scaling_mode) }, #undef INDEX }; diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 782764c8..12530da6 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -45,6 +45,9 @@ struct wlr_drm_crtc { uint32_t gamma_lut; drmModeAtomicReq *atomic; + // Legacy only + drmModeCrtc *legacy_crtc; + union { struct { struct wlr_drm_plane *overlay; diff --git a/include/backend/drm/iface.h b/include/backend/drm/iface.h index 228b313a..15cdf1ab 100644 --- a/include/backend/drm/iface.h +++ b/include/backend/drm/iface.h @@ -31,6 +31,9 @@ struct wlr_drm_interface { bool (*crtc_set_gamma)(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, uint16_t *r, uint16_t *g, uint16_t *b, uint32_t size); + // Get the gamma lut size of a crtc + uint32_t (*crtc_get_gamma_size)(struct wlr_drm_backend *drm, + struct wlr_drm_crtc *crtc); }; extern const struct wlr_drm_interface atomic_iface; diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h index 119d24c3..3cf8cc87 100644 --- a/include/backend/drm/properties.h +++ b/include/backend/drm/properties.h @@ -33,8 +33,9 @@ union wlr_drm_crtc_props { uint32_t active; uint32_t mode_id; uint32_t gamma_lut; + uint32_t gamma_lut_size; }; - uint32_t props[5]; + uint32_t props[6]; }; union wlr_drm_plane_props { From f5e5d1983b96f848ed89bdd3b0ea9825efa75063 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Sun, 4 Feb 2018 21:50:52 +0100 Subject: [PATCH 3/8] Do not allow gamma control without a crtc --- backend/drm/drm.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index eef1e333..70e6a1cf 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -232,13 +232,21 @@ static void wlr_drm_connector_set_gamma(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; - drm->iface->crtc_set_gamma(drm, conn->crtc, r, g, b, size); + + if (conn->crtc) { + drm->iface->crtc_set_gamma(drm, conn->crtc, r, g, b, size); + } } static uint32_t wlr_drm_connector_get_gamma_size(struct wlr_output *output) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; - return drm->iface->crtc_get_gamma_size(drm, conn->crtc); + + if (conn->crtc) { + return drm->iface->crtc_get_gamma_size(drm, conn->crtc); + } + + return 0; } void wlr_drm_connector_start_renderer(struct wlr_drm_connector *conn) { From 2df97ed16aa66f2e5f54b847b4389d4b1af5cc40 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Fri, 9 Feb 2018 17:14:36 +0100 Subject: [PATCH 4/8] Set needs_swap on output when gamma changes --- backend/drm/drm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 70e6a1cf..15be16bc 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -232,10 +232,15 @@ static void wlr_drm_connector_set_gamma(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; + bool ok; if (conn->crtc) { - drm->iface->crtc_set_gamma(drm, conn->crtc, r, g, b, size); + ok = drm->iface->crtc_set_gamma(drm, conn->crtc, r, g, b, size); + if (ok) { + wlr_output_update_needs_swap(output); + } } + } static uint32_t wlr_drm_connector_get_gamma_size(struct wlr_output *output) { From b2f69416178d84e686e9024a262eaa1e18fdb966 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Fri, 9 Feb 2018 17:48:17 +0100 Subject: [PATCH 5/8] Free gamma when property blob creation fails --- backend/drm/atomic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 79765fef..164caf22 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -214,6 +214,7 @@ static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, if (drmModeCreatePropertyBlob(drm->fd, gamma, sizeof(struct drm_color_lut) * size, &crtc->gamma_lut)) { wlr_log_errno(L_ERROR, "Unable to create property blob"); + free(gamma); return false; } From 0232269a2d92e76dfe20cfbde0646798ab080e95 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Fri, 9 Feb 2018 19:35:44 +0100 Subject: [PATCH 6/8] Fix style --- backend/drm/atomic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 164caf22..10714e35 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -221,7 +221,6 @@ static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, free(gamma); struct atomic atom; - atomic_begin(crtc, &atom); atomic_add(&atom, crtc->id, crtc->props.gamma_lut, crtc->gamma_lut); return atomic_end(drm->fd, &atom); @@ -237,7 +236,7 @@ static uint32_t atomic_crtc_get_gamma_size(struct wlr_drm_backend *drm, return 0; } - return (uint32_t) gamma_lut_size; + return (uint32_t)gamma_lut_size; } const struct wlr_drm_interface atomic_iface = { From dd69d7b7640fd4f957cee27eb274152cf8311f0c Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Fri, 9 Feb 2018 19:37:01 +0100 Subject: [PATCH 7/8] Use VLA instead of heap alloc --- backend/drm/atomic.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 10714e35..166d60a0 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -199,7 +199,7 @@ static bool atomic_crtc_move_cursor(struct wlr_drm_backend *drm, static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, uint16_t *r, uint16_t *g, uint16_t *b, uint32_t size) { - struct drm_color_lut *gamma = calloc(sizeof(struct drm_color_lut), size); + struct drm_color_lut gamma[size]; for (uint32_t i = 0; i < size; i++) { gamma[i].red = r[i]; @@ -214,12 +214,9 @@ static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, if (drmModeCreatePropertyBlob(drm->fd, gamma, sizeof(struct drm_color_lut) * size, &crtc->gamma_lut)) { wlr_log_errno(L_ERROR, "Unable to create property blob"); - free(gamma); return false; } - free(gamma); - struct atomic atom; atomic_begin(crtc, &atom); atomic_add(&atom, crtc->id, crtc->props.gamma_lut, crtc->gamma_lut); From 7cb828ac70c0c41005a761d9011f8b0ca8904688 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Sat, 10 Feb 2018 10:24:49 +0100 Subject: [PATCH 8/8] Fallback gamma on legacy if properties don't exist --- backend/drm/atomic.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 166d60a0..526b2731 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -201,6 +201,12 @@ static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, uint32_t size) { struct drm_color_lut gamma[size]; + // Fallback to legacy gamma interface when gamma properties are not available + // (can happen on older intel gpu's that support gamma but not degamma) + if (crtc->props.gamma_lut == 0) { + return legacy_iface.crtc_set_gamma(drm, crtc, r, g, b, size); + } + for (uint32_t i = 0; i < size; i++) { gamma[i].red = r[i]; gamma[i].green = g[i]; @@ -227,6 +233,10 @@ static uint32_t atomic_crtc_get_gamma_size(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc) { uint64_t gamma_lut_size; + if (crtc->props.gamma_lut_size == 0) { + return legacy_iface.crtc_get_gamma_size(drm, crtc); + } + if (!wlr_drm_get_prop(drm->fd, crtc->id, crtc->props.gamma_lut_size, &gamma_lut_size)) { wlr_log(L_ERROR, "Unable to get gamma lut size");