
If we did a mode set, the gamma may have been changed by the kernel, and if we didn't also update the gamma in the same transaction, we have no way to predict the current gamma ramp state. In this case, read the gamma state directly from KMS. This should be relatively harmless regarding the race conditions the state prediction was meant to solve, as the worst case is we get none or out of date gamma ramps; and since this is for when gamma ramps are not updated at mode setting time, we'd get intermediate gamma state to begin with, so it's not worse than what we currently do anyway. Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/851 https://gitlab.gnome.org/GNOME/mutter/merge_requests/840
282 lines
7.5 KiB
C
282 lines
7.5 KiB
C
/*
|
|
* Copyright (C) 2019 Red Hat
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "backends/native/meta-kms-crtc.h"
|
|
#include "backends/native/meta-kms-crtc-private.h"
|
|
|
|
#include "backends/native/meta-kms-device-private.h"
|
|
#include "backends/native/meta-kms-impl-device.h"
|
|
#include "backends/native/meta-kms-update-private.h"
|
|
|
|
struct _MetaKmsCrtc
|
|
{
|
|
GObject parent;
|
|
|
|
MetaKmsDevice *device;
|
|
|
|
uint32_t id;
|
|
int idx;
|
|
|
|
MetaKmsCrtcState current_state;
|
|
};
|
|
|
|
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)
|
|
{
|
|
return crtc->device;
|
|
}
|
|
|
|
const MetaKmsCrtcState *
|
|
meta_kms_crtc_get_current_state (MetaKmsCrtc *crtc)
|
|
{
|
|
return &crtc->current_state;
|
|
}
|
|
|
|
uint32_t
|
|
meta_kms_crtc_get_id (MetaKmsCrtc *crtc)
|
|
{
|
|
return crtc->id;
|
|
}
|
|
|
|
int
|
|
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,
|
|
drmModeCrtc *drm_crtc)
|
|
{
|
|
crtc->current_state.rect = (MetaRectangle) {
|
|
.x = drm_crtc->x,
|
|
.y = drm_crtc->y,
|
|
.width = drm_crtc->width,
|
|
.height = drm_crtc->height,
|
|
};
|
|
|
|
crtc->current_state.is_drm_mode_valid = drm_crtc->mode_valid;
|
|
crtc->current_state.drm_mode = drm_crtc->mode;
|
|
|
|
read_gamma_state (crtc, impl_device, drm_crtc);
|
|
}
|
|
|
|
void
|
|
meta_kms_crtc_update_state (MetaKmsCrtc *crtc)
|
|
{
|
|
MetaKmsImplDevice *impl_device;
|
|
drmModeCrtc *drm_crtc;
|
|
|
|
impl_device = meta_kms_device_get_impl_device (crtc->device);
|
|
drm_crtc = drmModeGetCrtc (meta_kms_impl_device_get_fd (impl_device),
|
|
crtc->id);
|
|
if (!drm_crtc)
|
|
{
|
|
crtc->current_state.rect = (MetaRectangle) { };
|
|
crtc->current_state.is_drm_mode_valid = FALSE;
|
|
return;
|
|
}
|
|
|
|
meta_kms_crtc_read_state (crtc, impl_device, drm_crtc);
|
|
drmModeFreeCrtc (drm_crtc);
|
|
}
|
|
|
|
static void
|
|
clear_gamma_state (MetaKmsCrtc *crtc)
|
|
{
|
|
crtc->current_state.gamma.size = 0;
|
|
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);
|
|
}
|
|
|
|
void
|
|
meta_kms_crtc_predict_state (MetaKmsCrtc *crtc,
|
|
MetaKmsUpdate *update)
|
|
{
|
|
gboolean is_gamma_valid;
|
|
GList *mode_sets;
|
|
GList *crtc_gammas;
|
|
GList *l;
|
|
|
|
is_gamma_valid = TRUE;
|
|
|
|
mode_sets = meta_kms_update_get_mode_sets (update);
|
|
for (l = mode_sets; l; l = l->next)
|
|
{
|
|
MetaKmsModeSet *mode_set = l->data;
|
|
|
|
if (mode_set->crtc != crtc)
|
|
continue;
|
|
|
|
if (mode_set->drm_mode)
|
|
{
|
|
MetaKmsPlaneAssignment *plane_assignment;
|
|
|
|
plane_assignment =
|
|
meta_kms_update_get_primary_plane_assignment (update, crtc);
|
|
|
|
crtc->current_state.rect =
|
|
meta_fixed_16_rectangle_to_rectangle (plane_assignment->src_rect);
|
|
crtc->current_state.is_drm_mode_valid = TRUE;
|
|
crtc->current_state.drm_mode = *mode_set->drm_mode;
|
|
}
|
|
else
|
|
{
|
|
crtc->current_state.rect = (MetaRectangle) { 0 };
|
|
crtc->current_state.is_drm_mode_valid = FALSE;
|
|
crtc->current_state.drm_mode = (drmModeModeInfo) { 0 };
|
|
}
|
|
|
|
is_gamma_valid = FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
crtc_gammas = meta_kms_update_get_crtc_gammas (update);
|
|
for (l = crtc_gammas; l; l = l->next)
|
|
{
|
|
MetaKmsCrtcGamma *gamma = l->data;
|
|
|
|
if (gamma->crtc != crtc)
|
|
continue;
|
|
|
|
crtc->current_state.gamma.size = gamma->size;
|
|
crtc->current_state.gamma.red =
|
|
g_memdup (gamma->red, gamma->size * sizeof (uint16_t));
|
|
crtc->current_state.gamma.green =
|
|
g_memdup (gamma->green, gamma->size * sizeof (uint16_t));
|
|
crtc->current_state.gamma.blue =
|
|
g_memdup (gamma->blue, gamma->size * sizeof (uint16_t));
|
|
|
|
is_gamma_valid = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (!is_gamma_valid)
|
|
{
|
|
if (crtc->current_state.is_drm_mode_valid)
|
|
{
|
|
MetaKmsImplDevice *impl_device;
|
|
drmModeCrtc *drm_crtc;
|
|
|
|
impl_device = meta_kms_device_get_impl_device (crtc->device);
|
|
drm_crtc = drmModeGetCrtc (meta_kms_impl_device_get_fd (impl_device),
|
|
crtc->id);
|
|
if (drm_crtc)
|
|
{
|
|
read_gamma_state (crtc, impl_device, drm_crtc);
|
|
drmModeFreeCrtc (drm_crtc);
|
|
}
|
|
else
|
|
{
|
|
clear_gamma_state (crtc);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
clear_gamma_state (crtc);
|
|
}
|
|
}
|
|
}
|
|
|
|
MetaKmsCrtc *
|
|
meta_kms_crtc_new (MetaKmsImplDevice *impl_device,
|
|
drmModeCrtc *drm_crtc,
|
|
int idx)
|
|
{
|
|
MetaKmsCrtc *crtc;
|
|
|
|
crtc = g_object_new (META_TYPE_KMS_CRTC, NULL);
|
|
crtc->device = meta_kms_impl_device_get_device (impl_device);
|
|
crtc->id = drm_crtc->crtc_id;
|
|
crtc->idx = idx;
|
|
|
|
return crtc;
|
|
}
|
|
|
|
static void
|
|
meta_kms_crtc_finalize (GObject *object)
|
|
{
|
|
MetaKmsCrtc *crtc = META_KMS_CRTC (object);
|
|
|
|
clear_gamma_state (crtc);
|
|
|
|
G_OBJECT_CLASS (meta_kms_crtc_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
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;
|
|
}
|