diff --git a/src/backends/native/meta-kms-connector-private.h b/src/backends/native/meta-kms-connector-private.h index 77f9e476a..a9201f3f4 100644 --- a/src/backends/native/meta-kms-connector-private.h +++ b/src/backends/native/meta-kms-connector-private.h @@ -29,6 +29,8 @@ typedef enum _MetaKmsConnectorProp META_KMS_CONNECTOR_PROP_UNDERSCAN, META_KMS_CONNECTOR_PROP_UNDERSCAN_HBORDER, META_KMS_CONNECTOR_PROP_UNDERSCAN_VBORDER, + META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE, + META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_HW_STATE, META_KMS_CONNECTOR_N_PROPS } MetaKmsConnectorProp; diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c index 4f1b38da5..b317cf935 100644 --- a/src/backends/native/meta-kms-connector.c +++ b/src/backends/native/meta-kms-connector.c @@ -19,6 +19,7 @@ #include "config.h" +#include "backends/meta-output.h" #include "backends/native/meta-kms-connector.h" #include "backends/native/meta-kms-connector-private.h" @@ -59,6 +60,14 @@ struct _MetaKmsConnector G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT) +typedef enum _MetaKmsPrivacyScreenHwState +{ + META_KMS_PRIVACY_SCREEN_HW_STATE_DISABLED, + META_KMS_PRIVACY_SCREEN_HW_STATE_ENABLED, + META_KMS_PRIVACY_SCREEN_HW_STATE_DISABLED_LOCKED, + META_KMS_PRIVACY_SCREEN_HW_STATE_ENABLED_LOCKED, +} MetaKmsPrivacyScreenHwState; + MetaKmsDevice * meta_kms_connector_get_device (MetaKmsConnector *connector) { @@ -132,6 +141,20 @@ meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector) return underscan_prop_id != 0; } +gboolean +meta_kms_connector_is_privacy_screen_supported (MetaKmsConnector *connector) +{ + return meta_kms_connector_get_prop_id (connector, + META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_HW_STATE) != 0; +} + +static gboolean +has_privacy_screen_software_toggle (MetaKmsConnector *connector) +{ + return meta_kms_connector_get_prop_id (connector, + META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE) != 0; +} + static void sync_fd_held (MetaKmsConnector *connector, MetaKmsImplDevice *impl_device) @@ -181,9 +204,44 @@ set_panel_orientation (MetaKmsConnectorState *state, } } +static void +set_privacy_screen (MetaKmsConnectorState *state, + MetaKmsConnector *connector, + drmModePropertyPtr prop, + uint64_t value) +{ + if (!meta_kms_connector_is_privacy_screen_supported (connector)) + return; + + switch (value) + { + case META_KMS_PRIVACY_SCREEN_HW_STATE_DISABLED: + state->privacy_screen_state = META_PRIVACY_SCREEN_DISABLED; + break; + case META_KMS_PRIVACY_SCREEN_HW_STATE_DISABLED_LOCKED: + state->privacy_screen_state = META_PRIVACY_SCREEN_DISABLED; + state->privacy_screen_state |= META_PRIVACY_SCREEN_LOCKED; + break; + case META_KMS_PRIVACY_SCREEN_HW_STATE_ENABLED: + state->privacy_screen_state = META_PRIVACY_SCREEN_ENABLED; + break; + case META_KMS_PRIVACY_SCREEN_HW_STATE_ENABLED_LOCKED: + state->privacy_screen_state = META_PRIVACY_SCREEN_ENABLED; + state->privacy_screen_state |= META_PRIVACY_SCREEN_LOCKED; + break; + default: + state->privacy_screen_state = META_PRIVACY_SCREEN_DISABLED; + g_warning ("Unknown privacy screen state: %" G_GUINT64_FORMAT, value); + } + + if (!has_privacy_screen_software_toggle (connector)) + state->privacy_screen_state |= META_PRIVACY_SCREEN_LOCKED; +} + static void state_set_properties (MetaKmsConnectorState *state, MetaKmsImplDevice *impl_device, + MetaKmsConnector *connector, drmModeConnector *drm_connector) { int fd; @@ -216,6 +274,10 @@ state_set_properties (MetaKmsConnectorState *state, else if ((prop->flags & DRM_MODE_PROP_RANGE) && strcmp (prop->name, "non-desktop") == 0) state->non_desktop = drm_connector->prop_values[i]; + else if (prop->prop_id == meta_kms_connector_get_prop_id (connector, + META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_HW_STATE)) + set_privacy_screen (state, connector, prop, + drm_connector->prop_values[i]); drmModeFreeProperty (prop); } @@ -554,9 +616,25 @@ meta_kms_connector_state_changes (MetaKmsConnectorState *state, if (!kms_modes_equal (state->modes, new_state->modes)) return META_KMS_UPDATE_CHANGE_FULL; + if (state->privacy_screen_state != new_state->privacy_screen_state) + return META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN; + return META_KMS_UPDATE_CHANGE_NONE; } +static void +meta_kms_connector_update_state_changes (MetaKmsConnector *connector, + MetaKmsUpdateChanges changes, + MetaKmsConnectorState *new_state) +{ + MetaKmsConnectorState *current_state = connector->current_state; + + g_return_if_fail (changes != META_KMS_UPDATE_CHANGE_FULL); + + if (changes & META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN) + current_state->privacy_screen_state = new_state->privacy_screen_state; +} + static MetaKmsUpdateChanges meta_kms_connector_read_state (MetaKmsConnector *connector, MetaKmsImplDevice *impl_device, @@ -593,7 +671,7 @@ meta_kms_connector_read_state (MetaKmsConnector *connector, state_set_blobs (state, connector, impl_device, drm_connector); - state_set_properties (state, impl_device, drm_connector); + state_set_properties (state, impl_device, connector, drm_connector); state->subpixel_order = drm_subpixel_order_to_cogl_subpixel_order (drm_connector->subpixel); @@ -615,14 +693,18 @@ meta_kms_connector_read_state (MetaKmsConnector *connector, else connector_changes = meta_kms_connector_state_changes (current_state, state); - if (connector_changes == META_KMS_UPDATE_CHANGE_NONE) + changes |= connector_changes; + + if (!(changes & META_KMS_UPDATE_CHANGE_FULL)) { + meta_kms_connector_update_state_changes (connector, + connector_changes, + state); connector->current_state = g_steal_pointer (¤t_state); } else { connector->current_state = g_steal_pointer (&state); - changes |= connector_changes; } out: @@ -686,6 +768,36 @@ meta_kms_connector_predict_state (MetaKmsConnector *connector, } } + if (has_privacy_screen_software_toggle (connector)) + { + GList *connector_updates; + + connector_updates = meta_kms_update_get_connector_updates (update); + for (l = connector_updates; l; l = l->next) + { + MetaKmsConnectorUpdate *connector_update = l->data; + + if (connector_update->connector != connector) + continue; + + if (connector_update->privacy_screen.has_update && + !(current_state->privacy_screen_state & + META_PRIVACY_SCREEN_LOCKED)) + { + if (connector_update->privacy_screen.is_enabled) + { + current_state->privacy_screen_state = + META_PRIVACY_SCREEN_ENABLED; + } + else + { + current_state->privacy_screen_state = + META_PRIVACY_SCREEN_DISABLED; + } + } + } + } + impl_device = meta_kms_device_get_impl_device (connector->device); sync_fd_held (connector, impl_device); } @@ -724,6 +836,16 @@ init_properties (MetaKmsConnector *connector, .name = "underscan vborder", .type = DRM_MODE_PROP_RANGE, }, + [META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE] = + { + .name = "privacy-screen sw-state", + .type = DRM_MODE_PROP_ENUM, + }, + [META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_HW_STATE] = + { + .name = "privacy-screen hw-state", + .type = DRM_MODE_PROP_ENUM, + }, } }; diff --git a/src/backends/native/meta-kms-connector.h b/src/backends/native/meta-kms-connector.h index a3a7136c5..397753b43 100644 --- a/src/backends/native/meta-kms-connector.h +++ b/src/backends/native/meta-kms-connector.h @@ -49,6 +49,7 @@ typedef struct _MetaKmsConnectorState gboolean has_scaling; gboolean non_desktop; + MetaPrivacyScreenState privacy_screen_state; CoglSubpixelOrder subpixel_order; @@ -74,4 +75,6 @@ const MetaKmsConnectorState * meta_kms_connector_get_current_state (MetaKmsConne gboolean meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector); +gboolean meta_kms_connector_is_privacy_screen_supported (MetaKmsConnector *connector); + #endif /* META_KMS_CONNECTOR_H */ diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c index bcb41e8ad..bf1abf572 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -196,6 +196,22 @@ process_connector_update (MetaKmsImplDevice *impl_device, return FALSE; } + if (connector_update->privacy_screen.has_update) + { + meta_topic (META_DEBUG_KMS, + "[atomic] Toggling privacy screen to %d on connector %u (%s)", + connector_update->privacy_screen.is_enabled, + meta_kms_connector_get_id (connector), + meta_kms_impl_device_get_path (impl_device)); + + if (!add_connector_property (impl_device, + connector, req, + META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE, + connector_update->privacy_screen.is_enabled, + error)) + return FALSE; + } + return TRUE; } diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c index 5017d86bf..e201e80fb 100644 --- a/src/backends/native/meta-kms-impl-device-simple.c +++ b/src/backends/native/meta-kms-impl-device-simple.c @@ -260,6 +260,22 @@ process_connector_update (MetaKmsImplDevice *impl_device, return FALSE; } + if (connector_update->privacy_screen.has_update) + { + meta_topic (META_DEBUG_KMS, + "[simple] Toggling privacy screen to %d on connector %u (%s)", + connector_update->privacy_screen.is_enabled, + meta_kms_connector_get_id (connector), + meta_kms_impl_device_get_path (impl_device)); + + if (!set_connector_property (impl_device, + connector, + META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE, + connector_update->privacy_screen.is_enabled, + error)) + return FALSE; + } + return TRUE; } diff --git a/src/backends/native/meta-kms-types.h b/src/backends/native/meta-kms-types.h index 5e9a4b3e7..4ba2003a5 100644 --- a/src/backends/native/meta-kms-types.h +++ b/src/backends/native/meta-kms-types.h @@ -69,6 +69,7 @@ typedef enum _MetaKmsUpdateChanges META_KMS_UPDATE_CHANGE_NONE = 0, META_KMS_UPDATE_CHANGE_GAMMA = 1 << 0, META_KMS_UPDATE_CHANGE_NO_DEVICES = 1 << 1, + META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN = 1 << 2, META_KMS_UPDATE_CHANGE_FULL = -1, } MetaKmsUpdateChanges; diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h index c375f7ead..44c950ea2 100644 --- a/src/backends/native/meta-kms-update-private.h +++ b/src/backends/native/meta-kms-update-private.h @@ -77,6 +77,11 @@ typedef struct _MetaKmsConnectorUpdate uint64_t hborder; uint64_t vborder; } underscanning; + + struct { + gboolean has_update; + gboolean is_enabled; + } privacy_screen; } MetaKmsConnectorUpdate; typedef struct _MetaKmsPageFlipListener diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c index f61e740d7..18999210f 100644 --- a/src/backends/native/meta-kms-update.c +++ b/src/backends/native/meta-kms-update.c @@ -349,6 +349,21 @@ meta_kms_update_unset_underscanning (MetaKmsUpdate *update, connector_update->underscanning.is_active = FALSE; } +void +meta_kms_update_set_privacy_screen (MetaKmsUpdate *update, + MetaKmsConnector *connector, + gboolean enabled) +{ + MetaKmsConnectorUpdate *connector_update; + + g_assert (meta_kms_connector_get_device (connector) == update->device); + g_assert (!update->power_save); + + connector_update = ensure_connector_update (update, connector); + connector_update->privacy_screen.has_update = TRUE; + connector_update->privacy_screen.is_enabled = enabled; +} + void meta_kms_update_set_power_save (MetaKmsUpdate *update) { diff --git a/src/backends/native/meta-kms-update.h b/src/backends/native/meta-kms-update.h index 89f4146ef..0c3028b52 100644 --- a/src/backends/native/meta-kms-update.h +++ b/src/backends/native/meta-kms-update.h @@ -101,6 +101,10 @@ void meta_kms_update_set_underscanning (MetaKmsUpdate *update, void meta_kms_update_unset_underscanning (MetaKmsUpdate *update, MetaKmsConnector *connector); +void meta_kms_update_set_privacy_screen (MetaKmsUpdate *update, + MetaKmsConnector *connector, + gboolean enabled); + void meta_kms_update_set_power_save (MetaKmsUpdate *update); void meta_kms_update_mode_set (MetaKmsUpdate *update, diff --git a/src/backends/native/meta-monitor-manager-native.c b/src/backends/native/meta-monitor-manager-native.c index bfa04b719..4cd02468f 100644 --- a/src/backends/native/meta-monitor-manager-native.c +++ b/src/backends/native/meta-monitor-manager-native.c @@ -37,6 +37,8 @@ #include "backends/meta-monitor.h" #include "config.h" +#include "backends/native/meta-kms-device.h" +#include "backends/native/meta-kms-types.h" #include "backends/native/meta-monitor-manager-native.h" #include @@ -518,6 +520,9 @@ on_kms_resources_changed (MetaKms *kms, return; } + if (changes == META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN) + return; + handle_hotplug_event (manager); } @@ -696,6 +701,65 @@ allocate_virtual_monitor_id (MetaMonitorManagerNative *manager_native) } } +static void +on_kms_privacy_screen_update_result (const MetaKmsFeedback *kms_feedback, + gpointer user_data) +{ + MetaMonitorManager *manager = user_data; + MetaBackend *backend = meta_monitor_manager_get_backend (manager); + MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend)); + + if (meta_kms_feedback_get_result (kms_feedback) == META_KMS_FEEDBACK_FAILED) + return; + + on_kms_resources_changed (kms, + META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN, + manager); +} + +static gboolean +meta_monitor_manager_native_set_privacy_screen_enabled (MetaMonitorManager *manager, + gboolean enabled) +{ + MetaMonitorManagerClass *manager_class; + MetaBackend *backend = meta_monitor_manager_get_backend (manager); + MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend)); + gboolean any_update = FALSE; + GList *l; + + manager_class = + META_MONITOR_MANAGER_CLASS (meta_monitor_manager_native_parent_class); + + if (!manager_class->set_privacy_screen_enabled (manager, enabled)) + return FALSE; + + for (l = meta_kms_get_devices (kms); l; l = l->next) + { + MetaKmsDevice *kms_device = l->data; + MetaKmsUpdate *kms_update; + + kms_update = meta_kms_get_pending_update (kms, kms_device); + + if (kms_update) + { + meta_kms_update_remove_result_listeners ( + kms_update, on_kms_privacy_screen_update_result, manager); + meta_kms_update_add_result_listener ( + kms_update, on_kms_privacy_screen_update_result, manager); + any_update = TRUE; + } + } + + if (any_update) + { + ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); + + clutter_stage_schedule_update (stage); + } + + return TRUE; +} + static MetaVirtualMonitor * meta_monitor_manager_native_create_virtual_monitor (MetaMonitorManager *manager, const MetaVirtualMonitorInfo *info, @@ -819,6 +883,8 @@ meta_monitor_manager_native_class_init (MetaMonitorManagerNativeClass *klass) meta_monitor_manager_native_get_crtc_gamma; manager_class->set_crtc_gamma = meta_monitor_manager_native_set_crtc_gamma; + manager_class->set_privacy_screen_enabled = + meta_monitor_manager_native_set_privacy_screen_enabled; manager_class->is_transform_handled = meta_monitor_manager_native_is_transform_handled; manager_class->calculate_monitor_mode_scale = diff --git a/src/backends/native/meta-output-kms.c b/src/backends/native/meta-output-kms.c index 4359b1161..fb658f29d 100644 --- a/src/backends/native/meta-output-kms.c +++ b/src/backends/native/meta-output-kms.c @@ -29,6 +29,7 @@ #include #include "backends/meta-crtc.h" +#include "backends/native/meta-kms.h" #include "backends/native/meta-kms-connector.h" #include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms-mode.h" @@ -96,6 +97,47 @@ meta_output_kms_set_underscan (MetaOutputKms *output_kms, } } +static MetaPrivacyScreenState +meta_output_kms_get_privacy_screen_state (MetaOutput *output) +{ + MetaOutputKms *output_kms = META_OUTPUT_KMS (output); + const MetaKmsConnectorState *connector_state; + + connector_state = + meta_kms_connector_get_current_state (output_kms->kms_connector); + + return connector_state->privacy_screen_state; +} + +static gboolean +meta_output_kms_set_privacy_screen_enabled (MetaOutput *output, + gboolean enabled, + GError **error) +{ + MetaGpu *gpu; + MetaKms *kms; + MetaKmsDevice *kms_device; + MetaKmsUpdate *kms_update; + MetaOutputKms *output_kms = META_OUTPUT_KMS (output); + MetaKmsConnector *connector = meta_output_kms_get_kms_connector (output_kms); + + if (!meta_kms_connector_is_privacy_screen_supported (connector)) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "No privacy screen support"); + return FALSE; + } + + gpu = meta_output_get_gpu (META_OUTPUT (output_kms)); + kms_device = meta_gpu_kms_get_kms_device (META_GPU_KMS (gpu)); + kms = meta_kms_device_get_kms (kms_device); + kms_update = meta_kms_ensure_pending_update (kms, kms_device); + + meta_kms_update_set_privacy_screen (kms_update, connector, enabled); + + return TRUE; +} + uint32_t meta_output_kms_get_connector_id (MetaOutputKms *output_kms) { @@ -425,6 +467,12 @@ static void meta_output_kms_class_init (MetaOutputKmsClass *klass) { MetaOutputNativeClass *output_native_class = META_OUTPUT_NATIVE_CLASS (klass); + MetaOutputClass *output_class = META_OUTPUT_CLASS (klass); + + output_class->get_privacy_screen_state = + meta_output_kms_get_privacy_screen_state; + output_class->set_privacy_screen_enabled = + meta_output_kms_set_privacy_screen_enabled; output_native_class->read_edid = meta_output_kms_read_edid; } diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index be7bbce1f..d63ac23bf 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -58,6 +58,7 @@ #include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms.h" #include "backends/native/meta-onscreen-native.h" +#include "backends/native/meta-output-kms.h" #include "backends/native/meta-render-device-gbm.h" #include "backends/native/meta-render-device-surfaceless.h" #include "backends/native/meta-renderer-native-private.h"