backend/native: Set CRTC gamma once per frame

Before we received new gamma updates via D-Bus and posted the update to
KMS directly. This won't be possible with atomic KMS, since one can only
update the state of a CRTC once per cycle.

Thus, to handle this, when configured by D-Bus, only cache the value,
and mark it as invalid. The next frame, the native renderer will pick
up the newly cached gamma value and configure the CRTCs accordingly.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1488>
This commit is contained in:
Jonas Ådahl 2020-10-10 11:47:58 +02:00 committed by Marge Bot
parent 7d8dd6cc75
commit 3ec5418104
7 changed files with 117 additions and 19 deletions

View File

@ -33,6 +33,7 @@
#include "backends/native/meta-kms-mode.h"
#include "backends/native/meta-kms-plane.h"
#include "backends/native/meta-kms-update.h"
#include "backends/native/meta-kms.h"
#include "backends/native/meta-monitor-manager-kms.h"
#define ALL_TRANSFORMS_MASK ((1 << META_MONITOR_N_TRANSFORMS) - 1)
@ -47,6 +48,8 @@ struct _MetaCrtcKms
gpointer cursor_renderer_private;
GDestroyNotify cursor_renderer_private_destroy_notify;
gboolean is_gamma_valid;
};
static GQuark kms_crtc_crtc_kms_quark;
@ -176,6 +179,39 @@ generate_crtc_connector_list (MetaGpu *gpu,
return connectors;
}
void
meta_crtc_kms_maybe_set_gamma (MetaCrtcKms *crtc_kms,
MetaKmsDevice *kms_device)
{
MetaGpu *gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms));
MetaBackend *backend = meta_gpu_get_backend (gpu);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerKms *monitor_manager_kms =
META_MONITOR_MANAGER_KMS (monitor_manager);
MetaKms *kms = meta_kms_device_get_kms (kms_device);
MetaKmsUpdate *kms_update;
MetaKmsCrtcGamma *gamma;
if (crtc_kms->is_gamma_valid)
return;
gamma = meta_monitor_manager_kms_get_cached_crtc_gamma (monitor_manager_kms,
crtc_kms);
if (!gamma)
return;
kms_update = meta_kms_ensure_pending_update (kms, kms_device);
meta_kms_update_set_crtc_gamma (kms_update,
meta_crtc_kms_get_kms_crtc (crtc_kms),
gamma->size,
gamma->red,
gamma->green,
gamma->blue);
crtc_kms->is_gamma_valid = TRUE;
}
void
meta_crtc_kms_set_mode (MetaCrtcKms *crtc_kms,
MetaKmsUpdate *kms_update)
@ -287,6 +323,12 @@ meta_crtc_kms_supports_format (MetaCrtcKms *crtc_kms,
drm_format);
}
void
meta_crtc_kms_invalidate_gamma (MetaCrtcKms *crtc_kms)
{
crtc_kms->is_gamma_valid = FALSE;
}
MetaCrtcKms *
meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc)
{

View File

@ -72,6 +72,11 @@ gboolean
meta_crtc_kms_supports_format (MetaCrtcKms *crtc_kms,
uint32_t drm_format);
void meta_crtc_kms_invalidate_gamma (MetaCrtcKms *crtc_kms);
void meta_crtc_kms_maybe_set_gamma (MetaCrtcKms *crtc_kms,
MetaKmsDevice *kms_device);
MetaCrtcKms * meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc);
MetaCrtcKms * meta_crtc_kms_new (MetaGpuKms *gpu_kms,

View File

@ -76,6 +76,8 @@ struct _MetaMonitorManagerKms
MetaMonitorManager parent_instance;
gulong kms_resources_changed_handler_id;
GHashTable *crtc_gamma_cache;
};
struct _MetaMonitorManagerKmsClass
@ -430,6 +432,17 @@ generate_gamma_ramp_string (size_t size,
return g_string_free (string, FALSE);
}
MetaKmsCrtcGamma *
meta_monitor_manager_kms_get_cached_crtc_gamma (MetaMonitorManagerKms *manager_kms,
MetaCrtcKms *crtc_kms)
{
uint64_t crtc_id;
crtc_id = meta_crtc_get_id (META_CRTC (crtc_kms));
return g_hash_table_lookup (manager_kms->crtc_gamma_cache,
GUINT_TO_POINTER (crtc_id));
}
static void
meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
MetaCrtc *crtc,
@ -438,32 +451,24 @@ meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
unsigned short *green,
unsigned short *blue)
{
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;
MetaKmsDevice *kms_device;
MetaKmsUpdate *kms_update;
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc);
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
g_autofree char *gamma_ramp_string = NULL;
MetaKmsUpdateFlag flags;
g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
MetaBackend *backend = meta_monitor_manager_get_backend (manager);
ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
kms_device = meta_kms_crtc_get_device (kms_crtc);
kms_update = meta_kms_ensure_pending_update (kms, kms_device);
meta_kms_update_set_crtc_gamma (kms_update, kms_crtc, size, red, green, blue);
g_hash_table_replace (manager_kms->crtc_gamma_cache,
GUINT_TO_POINTER (meta_crtc_get_id (crtc)),
meta_kms_crtc_gamma_new (kms_crtc, size,
red, green, blue));
gamma_ramp_string = generate_gamma_ramp_string (size, red, green, blue);
g_debug ("Setting CRTC (%" G_GUINT64_FORMAT ") gamma to %s",
meta_crtc_get_id (crtc), gamma_ramp_string);
flags = META_KMS_UPDATE_FLAG_NONE;
kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
if (meta_kms_feedback_get_result (kms_feedback) != META_KMS_FEEDBACK_PASSED)
{
g_warning ("Failed to set CRTC gamma: %s",
meta_kms_feedback_get_error (kms_feedback)->message);
}
meta_crtc_kms_invalidate_gamma (crtc_kms);
clutter_stage_schedule_update (stage);
}
static void
@ -595,6 +600,17 @@ meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager)
return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
}
static void
meta_monitor_manager_kms_dispose (GObject *object)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
g_clear_pointer (&manager_kms->crtc_gamma_cache,
g_hash_table_unref);
G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->dispose (object);
}
static gboolean
meta_monitor_manager_kms_initable_init (GInitable *initable,
GCancellable *cancellable,
@ -626,6 +642,11 @@ meta_monitor_manager_kms_initable_init (GInitable *initable,
return FALSE;
}
manager_kms->crtc_gamma_cache =
g_hash_table_new_full (NULL, NULL,
NULL,
(GDestroyNotify) meta_kms_crtc_gamma_free);
return TRUE;
}
@ -643,8 +664,11 @@ meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
static void
meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
object_class->dispose = meta_monitor_manager_kms_dispose;
manager_class->read_edid = meta_monitor_manager_kms_read_edid;
manager_class->read_current_state = meta_monitor_manager_kms_read_current_state;
manager_class->ensure_initial_config = meta_monitor_manager_kms_ensure_initial_config;

View File

@ -27,6 +27,8 @@
#include <xf86drmMode.h>
#include "backends/meta-monitor-manager-private.h"
#include "backends/native/meta-crtc-kms.h"
#include "backends/native/meta-kms-crtc.h"
typedef struct _MetaGpuKms MetaGpuKms;
@ -41,4 +43,7 @@ void meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms);
uint64_t meta_power_save_to_dpms_state (MetaPowerSave power_save);
MetaKmsCrtcGamma * meta_monitor_manager_kms_get_cached_crtc_gamma (MetaMonitorManagerKms *manager_kms,
MetaCrtcKms *crtc_kms);
#endif /* META_MONITOR_MANAGER_KMS_H */

View File

@ -3283,6 +3283,19 @@ meta_renderer_native_rebuild_views (MetaRenderer *renderer)
meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer));
}
void
meta_renderer_native_prepare_frame (MetaRendererNative *renderer_native,
MetaRendererView *view,
ClutterFrame *frame)
{
MetaCrtc *crtc = meta_renderer_view_get_crtc (view);
MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc);
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);;
meta_crtc_kms_maybe_set_gamma (crtc_kms, kms_device);
}
static void
add_onscreen_frame_info (MetaCrtc *crtc)
{

View File

@ -53,6 +53,10 @@ struct gbm_device * meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms);
MetaGpuKms * meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native);
void meta_renderer_native_prepare_frame (MetaRendererNative *renderer_native,
MetaRendererView *view,
ClutterFrame *frame);
void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native,
MetaRendererView *view,
ClutterFrame *frame);

View File

@ -112,11 +112,16 @@ meta_stage_native_prepare_frame (ClutterStageWindow *stage_window,
ClutterFrame *frame)
{
MetaBackend *backend = meta_get_backend ();
MetaRenderer *renderer = meta_backend_get_renderer (backend);
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
MetaCursorRendererNative *cursor_renderer_native =
META_CURSOR_RENDERER_NATIVE (cursor_renderer);
meta_renderer_native_prepare_frame (renderer_native,
META_RENDERER_VIEW (stage_view),
frame);
meta_cursor_renderer_native_prepare_frame (cursor_renderer_native,
META_RENDERER_VIEW (stage_view));
}