diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c index 5006a1816..2dd2b8da4 100644 --- a/src/backends/native/meta-kms-crtc.c +++ b/src/backends/native/meta-kms-crtc.c @@ -40,6 +40,17 @@ struct _MetaKmsCrtc G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT) +void +meta_kms_crtc_set_gamma (MetaKmsCrtc *crtc, + MetaKmsUpdate *update, + int size, + const uint16_t *red, + const uint16_t *green, + const uint16_t *blue) +{ + meta_kms_update_set_crtc_gamma (update, crtc, size, red, green, blue); +} + MetaKmsDevice * meta_kms_crtc_get_device (MetaKmsCrtc *crtc) { @@ -64,6 +75,36 @@ meta_kms_crtc_get_idx (MetaKmsCrtc *crtc) return crtc->idx; } +static void +read_gamma_state (MetaKmsCrtc *crtc, + MetaKmsImplDevice *impl_device, + drmModeCrtc *drm_crtc) +{ + MetaKmsCrtcState *current_state = &crtc->current_state; + + if (current_state->gamma.size != drm_crtc->gamma_size) + { + current_state->gamma.size = drm_crtc->gamma_size; + + current_state->gamma.red = g_realloc_n (current_state->gamma.red, + drm_crtc->gamma_size, + sizeof (uint16_t)); + current_state->gamma.green = g_realloc_n (current_state->gamma.green, + drm_crtc->gamma_size, + sizeof (uint16_t)); + current_state->gamma.blue = g_realloc_n (current_state->gamma.blue, + drm_crtc->gamma_size, + sizeof (uint16_t)); + } + + drmModeCrtcGetGamma (meta_kms_impl_device_get_fd (impl_device), + crtc->id, + current_state->gamma.size, + current_state->gamma.red, + current_state->gamma.green, + current_state->gamma.blue); +} + static void meta_kms_crtc_read_state (MetaKmsCrtc *crtc, MetaKmsImplDevice *impl_device, @@ -79,6 +120,8 @@ meta_kms_crtc_read_state (MetaKmsCrtc *crtc, .is_drm_mode_valid = drm_crtc->mode_valid, .drm_mode = drm_crtc->mode, }; + + read_gamma_state (crtc, impl_device, drm_crtc); } void @@ -109,6 +152,18 @@ meta_kms_crtc_new (MetaKmsImplDevice *impl_device, return crtc; } +static void +meta_kms_crtc_finalize (GObject *object) +{ + MetaKmsCrtc *crtc = META_KMS_CRTC (object); + + g_clear_pointer (&crtc->current_state.gamma.red, g_free); + g_clear_pointer (&crtc->current_state.gamma.green, g_free); + g_clear_pointer (&crtc->current_state.gamma.blue, g_free); + + G_OBJECT_CLASS (meta_kms_crtc_parent_class)->finalize (object); +} + static void meta_kms_crtc_init (MetaKmsCrtc *crtc) { @@ -117,4 +172,7 @@ meta_kms_crtc_init (MetaKmsCrtc *crtc) static void meta_kms_crtc_class_init (MetaKmsCrtcClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_kms_crtc_finalize; } diff --git a/src/backends/native/meta-kms-crtc.h b/src/backends/native/meta-kms-crtc.h index 9d0ceadd9..39a89a751 100644 --- a/src/backends/native/meta-kms-crtc.h +++ b/src/backends/native/meta-kms-crtc.h @@ -36,6 +36,14 @@ typedef struct _MetaKmsCrtcState uint32_t common_possible_crtcs; uint32_t common_possible_clones; uint32_t encoder_device_idxs; + + struct { + uint16_t *red; + uint16_t *green; + uint16_t *blue; + + int size; + } gamma; } MetaKmsCrtcState; #define META_TYPE_KMS_CRTC (meta_kms_crtc_get_type ()) @@ -43,6 +51,13 @@ G_DECLARE_FINAL_TYPE (MetaKmsCrtc, meta_kms_crtc, META, KMS_CRTC, GObject) +void meta_kms_crtc_set_gamma (MetaKmsCrtc *crtc, + MetaKmsUpdate *update, + int size, + const uint16_t *red, + const uint16_t *green, + const uint16_t *blue); + MetaKmsDevice * meta_kms_crtc_get_device (MetaKmsCrtc *crtc); const MetaKmsCrtcState * meta_kms_crtc_get_current_state (MetaKmsCrtc *crtc); diff --git a/src/backends/native/meta-kms-impl-simple.c b/src/backends/native/meta-kms-impl-simple.c index b62599354..929dd950a 100644 --- a/src/backends/native/meta-kms-impl-simple.c +++ b/src/backends/native/meta-kms-impl-simple.c @@ -284,6 +284,35 @@ process_mode_set (MetaKmsImpl *impl, return TRUE; } +static gboolean +process_crtc_gamma (MetaKmsImpl *impl, + MetaKmsCrtcGamma *gamma, + GError **error) +{ + MetaKmsCrtc *crtc = gamma->crtc; + MetaKmsDevice *device = meta_kms_crtc_get_device (crtc); + MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device); + int fd; + int ret; + + fd = meta_kms_impl_device_get_fd (impl_device); + ret = drmModeCrtcSetGamma (fd, meta_kms_crtc_get_id (crtc), + gamma->size, + gamma->red, + gamma->green, + gamma->blue); + if (ret != 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), + "drmModeCrtcSetGamma on CRTC %u failed: %s", + meta_kms_crtc_get_id (crtc), + g_strerror (-ret)); + return FALSE; + } + + return TRUE; +} + static gboolean is_timestamp_earlier_than (uint64_t ts1, uint64_t ts2) @@ -708,6 +737,14 @@ meta_kms_impl_simple_process_update (MetaKmsImpl *impl, goto discard_page_flips; } + for (l = meta_kms_update_get_crtc_gammas (update); l; l = l->next) + { + MetaKmsCrtcGamma *gamma = l->data; + + if (!process_crtc_gamma (impl, gamma, error)) + goto discard_page_flips; + } + for (l = meta_kms_update_get_page_flips (update); l; l = l->next) { MetaKmsPageFlip *page_flip = l->data; diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h index 32bb68bb8..fe320e9b3 100644 --- a/src/backends/native/meta-kms-update-private.h +++ b/src/backends/native/meta-kms-update-private.h @@ -59,6 +59,15 @@ typedef struct _MetaKmsConnectorProperty uint64_t value; } MetaKmsConnectorProperty; +typedef struct _MetaKmsCrtcGamma +{ + MetaKmsCrtc *crtc; + int size; + uint16_t *red; + uint16_t *green; + uint16_t *blue; +} MetaKmsCrtcGamma; + typedef struct _MetaKmsPageFlip { MetaKmsCrtc *crtc; @@ -77,6 +86,13 @@ void meta_kms_update_set_connector_property (MetaKmsUpdate *update, uint32_t prop_id, uint64_t value); +void meta_kms_update_set_crtc_gamma (MetaKmsUpdate *update, + MetaKmsCrtc *crtc, + int size, + const uint16_t *red, + const uint16_t *green, + const uint16_t *blue); + void meta_kms_plane_assignment_set_plane_property (MetaKmsPlaneAssignment *plane_assignment, uint32_t prop_id, uint64_t value); @@ -89,6 +105,8 @@ GList * meta_kms_update_get_page_flips (MetaKmsUpdate *update); GList * meta_kms_update_get_connector_properties (MetaKmsUpdate *update); +GList * meta_kms_update_get_crtc_gammas (MetaKmsUpdate *update); + gboolean meta_kms_update_has_mode_set (MetaKmsUpdate *update); #endif /* META_KMS_UPDATE_PRIVATE_H */ diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c index 95b2464b6..b6658e7c8 100644 --- a/src/backends/native/meta-kms-update.c +++ b/src/backends/native/meta-kms-update.c @@ -34,6 +34,7 @@ struct _MetaKmsUpdate GList *plane_assignments; GList *page_flips; GList *connector_properties; + GList *crtc_gammas; }; static MetaKmsProperty * @@ -142,6 +143,39 @@ meta_kms_update_set_connector_property (MetaKmsUpdate *update, prop); } +static void +meta_kms_crtc_gamma_free (MetaKmsCrtcGamma *gamma) +{ + g_free (gamma->red); + g_free (gamma->green); + g_free (gamma->blue); + g_free (gamma); +} + +void +meta_kms_update_set_crtc_gamma (MetaKmsUpdate *update, + MetaKmsCrtc *crtc, + int size, + const uint16_t *red, + const uint16_t *green, + const uint16_t *blue) +{ + MetaKmsCrtcGamma *gamma; + + g_assert (!meta_kms_update_is_sealed (update)); + + gamma = g_new0 (MetaKmsCrtcGamma, 1); + *gamma = (MetaKmsCrtcGamma) { + .crtc = crtc, + .size = size, + .red = g_memdup (red, size * sizeof *red), + .green = g_memdup (green, size * sizeof *green), + .blue = g_memdup (blue, size * sizeof *blue), + }; + + update->crtc_gammas = g_list_prepend (update->crtc_gammas, gamma); +} + void meta_kms_update_page_flip (MetaKmsUpdate *update, MetaKmsCrtc *crtc, @@ -225,6 +259,12 @@ meta_kms_update_get_connector_properties (MetaKmsUpdate *update) return update->connector_properties; } +GList * +meta_kms_update_get_crtc_gammas (MetaKmsUpdate *update) +{ + return update->crtc_gammas; +} + gboolean meta_kms_update_has_mode_set (MetaKmsUpdate *update) { @@ -258,6 +298,7 @@ meta_kms_update_free (MetaKmsUpdate *update) (GDestroyNotify) meta_kms_mode_set_free); g_list_free_full (update->page_flips, g_free); g_list_free_full (update->connector_properties, g_free); + g_list_free_full (update->crtc_gammas, (GDestroyNotify) meta_kms_crtc_gamma_free); g_free (update); } diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index 7f094ab42..9bac13576 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -367,20 +367,16 @@ meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager *manager, unsigned short **green, unsigned short **blue) { - MetaGpu *gpu = meta_crtc_get_gpu (crtc); - int kms_fd = meta_gpu_kms_get_fd (META_GPU_KMS (gpu)); - drmModeCrtc *kms_crtc; + MetaKmsCrtc *kms_crtc; + const MetaKmsCrtcState *crtc_state; - kms_crtc = drmModeGetCrtc (kms_fd, crtc->crtc_id); + kms_crtc = meta_crtc_kms_get_kms_crtc (crtc); + crtc_state = meta_kms_crtc_get_current_state (kms_crtc); - *size = kms_crtc->gamma_size; - *red = g_new (unsigned short, *size); - *green = g_new (unsigned short, *size); - *blue = g_new (unsigned short, *size); - - drmModeCrtcGetGamma (kms_fd, crtc->crtc_id, *size, *red, *green, *blue); - - drmModeFreeCrtc (kms_crtc); + *size = crtc_state->gamma.size; + *red = g_memdup (crtc_state->gamma.red, *size * sizeof **red); + *green = g_memdup (crtc_state->gamma.green, *size * sizeof **green); + *blue = g_memdup (crtc_state->gamma.blue, *size * sizeof **blue); } static char * @@ -453,20 +449,25 @@ meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager, unsigned short *green, unsigned short *blue) { - MetaGpu *gpu = meta_crtc_get_gpu (crtc); - int kms_fd = meta_gpu_kms_get_fd (META_GPU_KMS (gpu)); + MetaBackend *backend = meta_monitor_manager_get_backend (manager); + MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); + MetaKms *kms = meta_backend_native_get_kms (backend_native); + MetaKmsCrtc *kms_crtc; g_autofree char *gamma_ramp_string = NULL; - int ret; + MetaKmsUpdate *kms_update; + g_autoptr (GError) error = NULL; gamma_ramp_string = generate_gamma_ramp_string (size, red, green, blue); g_debug ("Setting CRTC (%ld) gamma to %s", crtc->crtc_id, gamma_ramp_string); - ret = drmModeCrtcSetGamma (kms_fd, crtc->crtc_id, size, red, green, blue); - if (ret != 0) - { - g_warning ("Failed to set CRTC (%ld) Gamma: %s", - crtc->crtc_id, g_strerror (-ret)); - } + kms_update = meta_kms_ensure_pending_update (kms); + + kms_crtc = meta_crtc_kms_get_kms_crtc (crtc); + meta_kms_crtc_set_gamma (kms_crtc, kms_update, + size, red, green, blue); + + if (!meta_kms_post_pending_update_sync (kms, &error)) + g_warning ("Failed to CRTC gamma: %s", error->message); } static void