diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c index e782f1444e08da81bf2b108874ef85d810748be1..bdafba4780ef631b19b1f0c770244b7324227d31 100644 --- a/src/backends/meta-monitor-config-manager.c +++ b/src/backends/meta-monitor-config-manager.c @@ -286,7 +286,9 @@ assign_monitor_crtc (MetaMonitor *monitor, .output = output, .is_primary = assign_output_as_primary, .is_presentation = assign_output_as_presentation, - .is_underscanning = data->monitor_config->enable_underscanning + .is_underscanning = data->monitor_config->enable_underscanning, + .has_max_bpc = data->monitor_config->has_max_bpc, + .max_bpc = data->monitor_config->max_bpc }; g_ptr_array_add (data->crtc_assignments, crtc_assignment); @@ -694,6 +696,9 @@ create_monitor_config (MetaMonitor *monitor, .enable_underscanning = meta_monitor_is_underscanning (monitor) }; + monitor_config->has_max_bpc = + meta_monitor_get_max_bpc (monitor, &monitor_config->max_bpc); + return monitor_config; } @@ -1041,7 +1046,9 @@ clone_monitor_config_list (GList *monitor_configs_in) .monitor_spec = meta_monitor_spec_clone (monitor_config_in->monitor_spec), .mode_spec = g_memdup2 (monitor_config_in->mode_spec, sizeof (MetaMonitorModeSpec)), - .enable_underscanning = monitor_config_in->enable_underscanning + .enable_underscanning = monitor_config_in->enable_underscanning, + .has_max_bpc = monitor_config_in->has_max_bpc, + .max_bpc = monitor_config_in->max_bpc }; monitor_configs_out = g_list_append (monitor_configs_out, monitor_config_out); diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h index a789e2f0882d7175bd9065eb726f9d66d2603c73..bf45b23276c0aa1f704a243fee96789bda4f571b 100644 --- a/src/backends/meta-monitor-config-manager.h +++ b/src/backends/meta-monitor-config-manager.h @@ -34,6 +34,8 @@ typedef struct _MetaMonitorConfig MetaMonitorSpec *monitor_spec; MetaMonitorModeSpec *mode_spec; gboolean enable_underscanning; + gboolean has_max_bpc; + unsigned int max_bpc; } MetaMonitorConfig; typedef struct _MetaLogicalMonitorConfig diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c index 4f6d03d6704e3800d8715885541e55e2faf24f14..377d8debf08354a9dde51aa7bbba6c2c99aa85bc 100644 --- a/src/backends/meta-monitor-config-store.c +++ b/src/backends/meta-monitor-config-store.c @@ -167,6 +167,7 @@ typedef enum STATE_MONITOR_MODE_RATE, STATE_MONITOR_MODE_FLAG, STATE_MONITOR_UNDERSCANNING, + STATE_MONITOR_MAXBPC, STATE_DISABLED, STATE_POLICY, STATE_STORES, @@ -451,6 +452,10 @@ handle_start_element (GMarkupParseContext *context, { parser->state = STATE_MONITOR_UNDERSCANNING; } + else if (g_str_equal (element_name, "maxbpc")) + { + parser->state = STATE_MONITOR_MAXBPC; + } else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, @@ -544,6 +549,13 @@ handle_start_element (GMarkupParseContext *context, return; } + case STATE_MONITOR_MAXBPC: + { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Invalid element '%s' under maxbpc", element_name); + return; + } + case STATE_DISABLED: { if (!g_str_equal (element_name, "monitorspec")) @@ -818,6 +830,14 @@ handle_end_element (GMarkupParseContext *context, return; } + case STATE_MONITOR_MAXBPC: + { + g_assert (g_str_equal (element_name, "maxbpc")); + + parser->state = STATE_MONITOR; + return; + } + case STATE_MONITOR: { MetaLogicalMonitorConfig *logical_monitor_config; @@ -1309,6 +1329,29 @@ handle_text (GMarkupParseContext *context, return; } + case STATE_MONITOR_MAXBPC: + { + int signed_max_bpc; + + if (read_int (text, text_len, &signed_max_bpc, error)) + { + if (signed_max_bpc >= 0) + { + parser->current_monitor_config->has_max_bpc = TRUE; + parser->current_monitor_config->max_bpc = signed_max_bpc; + } + else + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Invalid negative maxbpc value \"%s\"", + text); + } + } + + return; + } + case STATE_STORE: { MetaConfigStore store; @@ -1480,6 +1523,12 @@ append_monitors (GString *buffer, g_string_append (buffer, " \n"); if (monitor_config->enable_underscanning) g_string_append (buffer, " yes\n"); + + if (monitor_config->has_max_bpc) + { + g_string_append_printf (buffer, " %u\n", + monitor_config->max_bpc); + } g_string_append (buffer, " \n"); } } diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index 6bbcfd0e9822967753e8969f1bfdb5d45bd446f4..c8255ba0c4641a4157b59d9d6c6930b1746b7087 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -101,6 +101,8 @@ struct _MetaOutputAssignment gboolean is_primary; gboolean is_presentation; gboolean is_underscanning; + gboolean has_max_bpc; + unsigned int max_bpc; }; /* diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c index b7abd9b4b687e413bd5e22eb7463c972957b1eae..3ad02ee3ad240238e4ccc9e976a7384b6f1be6c9 100644 --- a/src/backends/meta-monitor.c +++ b/src/backends/meta-monitor.c @@ -358,6 +358,17 @@ meta_monitor_is_underscanning (MetaMonitor *monitor) return meta_output_is_underscanning (output); } +gboolean +meta_monitor_get_max_bpc (MetaMonitor *monitor, + unsigned int *max_bpc) +{ + MetaOutput *output; + + output = meta_monitor_get_main_output (monitor); + + return meta_output_get_max_bpc (output, max_bpc); +} + gboolean meta_monitor_is_laptop_panel (MetaMonitor *monitor) { diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h index d8a90097fef877c5ecc9ce07d5afb7cd522cfe45..4d61f1d4bc4c5938d8ce5946ad306ed2f72caf5b 100644 --- a/src/backends/meta-monitor.h +++ b/src/backends/meta-monitor.h @@ -118,6 +118,9 @@ gboolean meta_monitor_supports_underscanning (MetaMonitor *monitor); gboolean meta_monitor_is_underscanning (MetaMonitor *monitor); +gboolean meta_monitor_get_max_bpc (MetaMonitor *monitor, + unsigned int *max_bpc); + gboolean meta_monitor_is_laptop_panel (MetaMonitor *monitor); gboolean meta_monitor_is_same_as (MetaMonitor *monitor, diff --git a/src/backends/meta-output.c b/src/backends/meta-output.c index 9d9454fdfeb75f6a0fe6c7a5b86df52dac4fe43a..a02feca90f491d9e301861dd42b1c319c93f1a6b 100644 --- a/src/backends/meta-output.c +++ b/src/backends/meta-output.c @@ -55,6 +55,9 @@ typedef struct _MetaOutputPrivate gboolean is_underscanning; + gboolean has_max_bpc; + unsigned int max_bpc; + int backlight; } MetaOutputPrivate; @@ -177,6 +180,18 @@ meta_output_is_underscanning (MetaOutput *output) return priv->is_underscanning; } +gboolean +meta_output_get_max_bpc (MetaOutput *output, + unsigned int *max_bpc) +{ + MetaOutputPrivate *priv = meta_output_get_instance_private (output); + + if (priv->has_max_bpc && max_bpc) + *max_bpc = priv->max_bpc; + + return priv->has_max_bpc; +} + void meta_output_set_backlight (MetaOutput *output, int backlight) @@ -235,6 +250,10 @@ meta_output_assign_crtc (MetaOutput *output, priv->is_primary = output_assignment->is_primary; priv->is_presentation = output_assignment->is_presentation; priv->is_underscanning = output_assignment->is_underscanning; + + priv->has_max_bpc = output_assignment->has_max_bpc; + if (priv->has_max_bpc) + priv->max_bpc = output_assignment->max_bpc; } void diff --git a/src/backends/meta-output.h b/src/backends/meta-output.h index cbacabace968ce9b23d2565a4ac718b2b9e0207b..9970a7a450b077f9c19f2ff6971eee196b8cd71e 100644 --- a/src/backends/meta-output.h +++ b/src/backends/meta-output.h @@ -107,6 +107,9 @@ typedef struct _MetaOutputInfo gboolean supports_underscanning; gboolean supports_color_transform; + unsigned int max_bpc_min; + unsigned int max_bpc_max; + /* * Get a new preferred mode on hotplug events, to handle dynamic guest * resizing. @@ -182,6 +185,10 @@ gboolean meta_output_is_presentation (MetaOutput *output); META_EXPORT_TEST gboolean meta_output_is_underscanning (MetaOutput *output); +META_EXPORT_TEST +gboolean meta_output_get_max_bpc (MetaOutput *output, + unsigned int *max_bpc); + void meta_output_set_backlight (MetaOutput *output, int backlight); diff --git a/src/backends/native/meta-kms-connector-private.h b/src/backends/native/meta-kms-connector-private.h index e1d9b44cd52eacbbab8aa3911eaf93f43ed34c20..73757a8fca1e6053953481d0e21f5b7961fe5167 100644 --- a/src/backends/native/meta-kms-connector-private.h +++ b/src/backends/native/meta-kms-connector-private.h @@ -39,6 +39,7 @@ typedef enum _MetaKmsConnectorProp META_KMS_CONNECTOR_PROP_SCALING_MODE, META_KMS_CONNECTOR_PROP_PANEL_ORIENTATION, META_KMS_CONNECTOR_PROP_NON_DESKTOP, + META_KMS_CONNECTOR_PROP_MAX_BPC, 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 724f96e36fa90f6f26e35b33d41368863c5576ea..2bc3372917ab6722b5874cea9b3f96c41adb2abf 100644 --- a/src/backends/native/meta-kms-connector.c +++ b/src/backends/native/meta-kms-connector.c @@ -190,6 +190,19 @@ has_privacy_screen_software_toggle (MetaKmsConnector *connector) META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE) != 0; } +const MetaKmsRange * +meta_kms_connector_get_max_bpc (MetaKmsConnector *connector) +{ + const MetaKmsRange *range = NULL; + + if (connector->current_state && + meta_kms_connector_get_prop_id (connector, + META_KMS_CONNECTOR_PROP_MAX_BPC)) + range = &connector->current_state->max_bpc; + + return range; +} + static void sync_fd_held (MetaKmsConnector *connector, MetaKmsImplDevice *impl_device) @@ -308,6 +321,14 @@ state_set_properties (MetaKmsConnectorState *state, prop = &props[META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_HW_STATE]; if (prop->prop_id) set_privacy_screen (state, connector, prop); + + prop = &props[META_KMS_CONNECTOR_PROP_MAX_BPC]; + if (prop->prop_id) + { + state->max_bpc.value = prop->value; + state->max_bpc.min_value = prop->range_min; + state->max_bpc.max_value = prop->range_max; + } } static CoglSubpixelOrder @@ -622,6 +643,11 @@ meta_kms_connector_state_changes (MetaKmsConnectorState *state, if (!kms_modes_equal (state->modes, new_state->modes)) return META_KMS_RESOURCE_CHANGE_FULL; + if (state->max_bpc.value != new_state->max_bpc.value || + state->max_bpc.min_value != new_state->max_bpc.min_value || + state->max_bpc.max_value != new_state->max_bpc.max_value) + return META_KMS_RESOURCE_CHANGE_FULL; + if (state->privacy_screen_state != new_state->privacy_screen_state) return META_KMS_RESOURCE_CHANGE_PRIVACY_SCREEN; @@ -940,6 +966,11 @@ init_properties (MetaKmsConnector *connector, .name = "non-desktop", .type = DRM_MODE_PROP_RANGE, }, + [META_KMS_CONNECTOR_PROP_MAX_BPC] = + { + .name = "max bpc", + .type = DRM_MODE_PROP_RANGE, + }, }, .dpms_enum = { [META_KMS_CONNECTOR_DPMS_ON] = diff --git a/src/backends/native/meta-kms-connector.h b/src/backends/native/meta-kms-connector.h index c2b763548e89b3dfa2112da96eb0b866a859705f..bbd59d34230ed88f7164f0d3eb1eced1cd260a90 100644 --- a/src/backends/native/meta-kms-connector.h +++ b/src/backends/native/meta-kms-connector.h @@ -59,6 +59,8 @@ typedef struct _MetaKmsConnectorState gboolean hotplug_mode_update; MetaMonitorTransform panel_orientation_transform; + + MetaKmsRange max_bpc; } MetaKmsConnectorState; META_EXPORT_TEST @@ -83,4 +85,6 @@ gboolean meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connec gboolean meta_kms_connector_is_privacy_screen_supported (MetaKmsConnector *connector); +const MetaKmsRange * meta_kms_connector_get_max_bpc (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 b1925f984348f9e652e4691085bccca1d5344879..7b7f7fc1fb130311c0d401b42f00267534f86ce1 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -218,6 +218,22 @@ process_connector_update (MetaKmsImplDevice *impl_device, return FALSE; } + if (connector_update->max_bpc.has_update) + { + meta_topic (META_DEBUG_KMS, + "[atomic] Setting max BPC to %u on connector %u (%s)", + (unsigned int) connector_update->max_bpc.value, + 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_MAX_BPC, + connector_update->max_bpc.value, + 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 e4a8d5f1bf40a5ab512c3b7853e69e77987aa01c..648de51c65063bd248ce4f100b8182bbddbde27f 100644 --- a/src/backends/native/meta-kms-impl-device-simple.c +++ b/src/backends/native/meta-kms-impl-device-simple.c @@ -250,6 +250,22 @@ process_connector_update (MetaKmsImplDevice *impl_device, return FALSE; } + if (connector_update->max_bpc.has_update) + { + meta_topic (META_DEBUG_KMS, + "[simple] Setting max BPC to %u on connector %u (%s)", + (unsigned int) connector_update->max_bpc.value, + 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_MAX_BPC, + connector_update->max_bpc.value, + error)) + return FALSE; + } + return TRUE; } diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index dc2ac31ef4e71cf630872564948e8e3d9b9de2c9..b1dd321a7f1a9c0b9cfad5e17a4666a7df50822c 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -690,6 +690,20 @@ meta_kms_impl_device_update_prop_table (MetaKmsImplDevice *impl_device, update_prop_value (prop, prop_value); + if (prop->type == DRM_MODE_PROP_RANGE) + { + if (drm_prop->count_values == 2) + { + prop->range_min = drm_prop->values[0]; + prop->range_max = drm_prop->values[1]; + } + else + { + g_warning ("DRM property '%s' is a range with %d values, ignoring", + drm_prop->name, drm_prop->count_values); + } + } + drmModeFreeProperty (drm_prop); } } diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h index c5ac131cc2d32e9fe81b7dddeed0eb3cd30a2f9e..a45d24bedb65a2c9ca2e6065e3f08d6df11f0442 100644 --- a/src/backends/native/meta-kms-impl-device.h +++ b/src/backends/native/meta-kms-impl-device.h @@ -64,6 +64,9 @@ struct _MetaKmsProp MetaKmsEnum *enum_values; uint64_t default_value; + uint64_t range_min; + uint64_t range_max; + uint32_t prop_id; uint64_t value; }; diff --git a/src/backends/native/meta-kms-types.h b/src/backends/native/meta-kms-types.h index a2e2f8ded3e308a56c2d4ee58c5125d988bd433b..81fcad0e66645b13988af42bd8b0be3d676ea93f 100644 --- a/src/backends/native/meta-kms-types.h +++ b/src/backends/native/meta-kms-types.h @@ -89,4 +89,11 @@ typedef enum _MetaKmsPropType META_KMS_PROP_TYPE_FIXED_16, } MetaKmsPropType; +typedef struct _MetaKmsRange +{ + uint64_t value; + uint64_t min_value; + uint64_t max_value; +} MetaKmsRange; + #endif /* META_KMS_IMPL_TYPES_H */ diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h index 9dab7c133cca6b76975634bec6cedd1a21aedbe0..3a648ba0da60488d6d358118ce50b89e8e1c6d8f 100644 --- a/src/backends/native/meta-kms-update-private.h +++ b/src/backends/native/meta-kms-update-private.h @@ -82,6 +82,11 @@ typedef struct _MetaKmsConnectorUpdate gboolean has_update; gboolean is_enabled; } privacy_screen; + + struct { + gboolean has_update; + uint64_t value; + } max_bpc; } MetaKmsConnectorUpdate; typedef struct _MetaKmsPageFlipListener diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c index 042714d0aa519b4dfefb79771fda3c06643bd6ae..4c34000ef5d562e28b76a1084901ef3e8cf721b7 100644 --- a/src/backends/native/meta-kms-update.c +++ b/src/backends/native/meta-kms-update.c @@ -356,6 +356,20 @@ meta_kms_update_set_privacy_screen (MetaKmsUpdate *update, connector_update->privacy_screen.is_enabled = enabled; } +void +meta_kms_update_set_max_bpc (MetaKmsUpdate *update, + MetaKmsConnector *connector, + uint64_t max_bpc) +{ + MetaKmsConnectorUpdate *connector_update; + + g_assert (meta_kms_connector_get_device (connector) == update->device); + + connector_update = ensure_connector_update (update, connector); + connector_update->max_bpc.value = max_bpc; + connector_update->max_bpc.has_update = TRUE; +} + void meta_kms_crtc_gamma_free (MetaKmsCrtcGamma *gamma) { diff --git a/src/backends/native/meta-kms-update.h b/src/backends/native/meta-kms-update.h index f31e36aad3e5b1ed5f21910bc14866964b8a8291..d5557d7ced3fa2fe9d810fd01051e2161521bdf3 100644 --- a/src/backends/native/meta-kms-update.h +++ b/src/backends/native/meta-kms-update.h @@ -107,6 +107,10 @@ void meta_kms_update_set_privacy_screen (MetaKmsUpdate *update, MetaKmsConnector *connector, gboolean enabled); +void meta_kms_update_set_max_bpc (MetaKmsUpdate *update, + MetaKmsConnector *connector, + uint64_t max_bpc); + META_EXPORT_TEST void meta_kms_update_set_power_save (MetaKmsUpdate *update); diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c index 36d6e291eb2d3a48d138d0b2b3f962d88c225236..a107a99bb37ea007d67462d07765605bfa0ca7ef 100644 --- a/src/backends/native/meta-onscreen-native.c +++ b/src/backends/native/meta-onscreen-native.c @@ -533,6 +533,8 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen, meta_crtc_kms_set_mode (crtc_kms, kms_update); meta_output_kms_set_underscan (META_OUTPUT_KMS (onscreen_native->output), kms_update); + meta_output_kms_set_max_bpc (META_OUTPUT_KMS (onscreen_native->output), + kms_update); } static void diff --git a/src/backends/native/meta-output-kms.c b/src/backends/native/meta-output-kms.c index 5e572e27b275bae6e285d071a287c21852d184ca..2062a20cf70e66082c06adb6728b6f1a268e490f 100644 --- a/src/backends/native/meta-output-kms.c +++ b/src/backends/native/meta-output-kms.c @@ -97,6 +97,36 @@ meta_output_kms_set_underscan (MetaOutputKms *output_kms, } } +void +meta_output_kms_set_max_bpc (MetaOutputKms *output_kms, + MetaKmsUpdate *kms_update) +{ + MetaKmsConnector *kms_connector = output_kms->kms_connector; + const MetaKmsRange *range; + + range = meta_kms_connector_get_max_bpc (kms_connector); + if (range) + { + MetaOutput *output = META_OUTPUT (output_kms); + unsigned int max_bpc; + + if (!meta_output_get_max_bpc (output, &max_bpc)) + return; + + if (max_bpc >= range->min_value && max_bpc <= range->max_value) + { + meta_kms_update_set_max_bpc (kms_update, kms_connector, max_bpc); + } + else + { + g_warning ("Ignoring out of range value %u for max bpc (%u-%u)", + max_bpc, + (unsigned) range->min_value, + (unsigned) range->max_value); + } + } +} + static MetaPrivacyScreenState meta_output_kms_get_privacy_screen_state (MetaOutput *output) { @@ -362,6 +392,7 @@ meta_output_kms_new (MetaGpuKms *gpu_kms, const MetaKmsConnectorState *connector_state; GArray *crtcs; GList *l; + const MetaKmsRange *max_bpc_range; gpu_id = meta_gpu_kms_get_id (gpu_kms); connector_id = meta_kms_connector_get_id (kms_connector); @@ -409,6 +440,13 @@ meta_output_kms_new (MetaGpuKms *gpu_kms, output_info->supports_underscanning = meta_kms_connector_is_underscanning_supported (kms_connector); + max_bpc_range = meta_kms_connector_get_max_bpc (kms_connector); + if (max_bpc_range) + { + output_info->max_bpc_min = max_bpc_range->min_value; + output_info->max_bpc_max = max_bpc_range->max_value; + } + meta_output_info_parse_edid (output_info, connector_state->edid_data); drm_connector_type = meta_kms_connector_get_connector_type (kms_connector); diff --git a/src/backends/native/meta-output-kms.h b/src/backends/native/meta-output-kms.h index 52acc6032a02baeebc6caec21c5207c7dc9f416f..1e35dbb17d3da5085b960c5fb8957b13510f5044 100644 --- a/src/backends/native/meta-output-kms.h +++ b/src/backends/native/meta-output-kms.h @@ -40,6 +40,9 @@ void meta_output_kms_set_power_save_mode (MetaOutputKms *output_kms, void meta_output_kms_set_underscan (MetaOutputKms *output_kms, MetaKmsUpdate *kms_update); +void meta_output_kms_set_max_bpc (MetaOutputKms *output_kms, + MetaKmsUpdate *kms_update); + gboolean meta_output_kms_can_clone (MetaOutputKms *output_kms, MetaOutputKms *other_output_kms); diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 5f1369d3d729ea96cb94830a7432243c3920b3c6..6c9a289bcca2f9b6d54da0eca90a67e51da5e4f2 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -274,6 +274,7 @@ is_output_assignment_changed (MetaOutput *output, for (i = 0; i < n_output_assignments; i++) { MetaOutputAssignment *output_assignment = output_assignments[i]; + unsigned int max_bpc; if (output_assignment->output != output) continue; @@ -289,6 +290,17 @@ is_output_assignment_changed (MetaOutput *output, output_assignment->is_underscanning) return TRUE; + if (meta_output_get_max_bpc (output, &max_bpc)) + { + if (!output_assignment->has_max_bpc || + max_bpc != output_assignment->max_bpc) + return TRUE; + } + else if (output_assignment->has_max_bpc) + { + return TRUE; + } + output_is_found = TRUE; } diff --git a/src/backends/x11/meta-output-xrandr.c b/src/backends/x11/meta-output-xrandr.c index 6fde5667e4e99025079342c8eac003c2b61c1220..37a377e48cc3ed8d292573022f9ae0f2dd34dcb4 100644 --- a/src/backends/x11/meta-output-xrandr.c +++ b/src/backends/x11/meta-output-xrandr.c @@ -145,11 +145,28 @@ output_set_underscanning_xrandr (MetaOutput *output, } } +static void +output_set_max_bpc_xrandr (MetaOutput *output, + unsigned int max_bpc) +{ + Display *xdisplay = xdisplay_from_output (output); + Atom prop = XInternAtom (xdisplay, "max bpc", False); + uint32_t value = max_bpc; + + xcb_randr_change_output_property (XGetXCBConnection (xdisplay), + (XID) meta_output_get_id (output), + prop, XCB_ATOM_INTEGER, 32, + XCB_PROP_MODE_REPLACE, + 1, &value); +} + void meta_output_xrandr_apply_mode (MetaOutputXrandr *output_xrandr) { MetaOutput *output = META_OUTPUT (output_xrandr); Display *xdisplay = xdisplay_from_output (output); + const MetaOutputInfo *output_info = meta_output_get_info (output); + unsigned int max_bpc; if (meta_output_is_primary (output)) { @@ -164,6 +181,13 @@ meta_output_xrandr_apply_mode (MetaOutputXrandr *output_xrandr) output_set_underscanning_xrandr (output, meta_output_is_underscanning (output)); } + + if (meta_output_get_max_bpc (output, &max_bpc) && + max_bpc >= output_info->max_bpc_min && + max_bpc <= output_info->max_bpc_max) + { + output_set_max_bpc_xrandr (output, max_bpc); + } } static int @@ -347,6 +371,33 @@ output_get_underscanning_xrandr (MetaOutput *output) return (strcmp (str, "on") == 0); } +static gboolean +output_get_max_bpc_xrandr (MetaOutput *output, + unsigned int *max_bpc) +{ + Display *xdisplay = xdisplay_from_output (output); + Atom atom, actual_type; + int actual_format; + unsigned long nitems, bytes_after; + g_autofree unsigned char *buffer = NULL; + + atom = XInternAtom (xdisplay, "max bpc", False); + XRRGetOutputProperty (xdisplay, + (XID) meta_output_get_id (output), + atom, + 0, G_MAXLONG, False, False, XCB_ATOM_INTEGER, + &actual_type, &actual_format, + &nitems, &bytes_after, &buffer); + + if (actual_type != XCB_ATOM_INTEGER || actual_format != 32 || nitems < 1) + return FALSE; + + if (max_bpc) + *max_bpc = *((uint32_t*) buffer); + + return TRUE; +} + static gboolean output_get_supports_underscanning_xrandr (Display *xdisplay, RROutput output_id) @@ -392,6 +443,36 @@ output_get_supports_underscanning_xrandr (Display *xdisplay, return supports_underscanning; } +static gboolean +output_get_max_bpc_range_xrandr (Display *xdisplay, + RROutput output_id, + unsigned int *min, + unsigned int *max) +{ + Atom atom; + XRRPropertyInfo *property_info; + long *values; + + atom = XInternAtom (xdisplay, "max bpc", False); + + meta_clutter_x11_trap_x_errors (); + property_info = XRRQueryOutputProperty (xdisplay, + (XID) output_id, + atom); + meta_clutter_x11_untrap_x_errors (); + + if (!property_info || property_info->num_values != 2) + return FALSE; + + values = (long *) property_info->values; + if (min) + *min = values[0]; + if (max) + *max = values[1]; + + return TRUE; +} + static gboolean output_get_supports_color_transform_xrandr (Display *xdisplay, RROutput output_id) @@ -934,6 +1015,10 @@ meta_output_xrandr_new (MetaGpuXrandr *gpu_xrandr, output_info->supports_underscanning = output_get_supports_underscanning_xrandr (xdisplay, output_id); + output_get_max_bpc_range_xrandr (xdisplay, + output_id, + &output_info->max_bpc_min, + &output_info->max_bpc_max); output_info->supports_color_transform = output_get_supports_color_transform_xrandr (xdisplay, output_id); output_info_init_backlight_limits_xrandr (output_info, xdisplay, output_id); @@ -954,6 +1039,9 @@ meta_output_xrandr_new (MetaGpuXrandr *gpu_xrandr, .is_presentation = output_get_presentation_xrandr (output), .is_underscanning = output_get_underscanning_xrandr (output), }; + output_assignment.has_max_bpc = + output_get_max_bpc_xrandr (output, &output_assignment.max_bpc); + meta_output_assign_crtc (output, assigned_crtc, &output_assignment); } else diff --git a/src/tests/meta-monitor-test-utils.c b/src/tests/meta-monitor-test-utils.c index aab9e18589bdd3b9a5596bacbe937add7ef11b37..2cb41cd13c9be3658db8abee76b02498cb58a3cc 100644 --- a/src/tests/meta-monitor-test-utils.c +++ b/src/tests/meta-monitor-test-utils.c @@ -387,11 +387,17 @@ meta_check_monitor_configuration (MetaContext *context, { MetaOutput *output = l_output->data; uint64_t winsys_id = expect->monitors[i].outputs[j]; + unsigned int output_max_bpc; g_assert (output == output_from_winsys_id (backend, winsys_id)); g_assert_cmpint (expect->monitors[i].is_underscanning, ==, meta_output_is_underscanning (output)); + + if (!meta_output_get_max_bpc (output, &output_max_bpc)) + output_max_bpc = 0; + + g_assert_cmpint (expect->monitors[i].max_bpc, ==, output_max_bpc); } meta_monitor_get_physical_dimensions (monitor, &width_mm, &height_mm); @@ -778,6 +784,8 @@ meta_create_monitor_test_setup (MetaBackend *backend, output_assignment = (MetaOutputAssignment) { .is_underscanning = setup->outputs[i].is_underscanning, + .has_max_bpc = !!setup->outputs[i].max_bpc, + .max_bpc = setup->outputs[i].max_bpc, }; meta_output_assign_crtc (output, crtc, &output_assignment); } diff --git a/src/tests/meta-monitor-test-utils.h b/src/tests/meta-monitor-test-utils.h index 988a4115e89284ca087b717652d259c069c27ab8..ceae9d52aa753c4b39e591fd91dc79375bece427 100644 --- a/src/tests/meta-monitor-test-utils.h +++ b/src/tests/meta-monitor-test-utils.h @@ -106,6 +106,7 @@ typedef struct _MonitorTestCaseOutput float scale; gboolean is_laptop_panel; gboolean is_underscanning; + unsigned int max_bpc; const char *serial; MetaMonitorTransform panel_orientation_transform; gboolean hotplug_mode; @@ -157,6 +158,7 @@ typedef struct _MonitorTestCaseMonitor int width_mm; int height_mm; gboolean is_underscanning; + unsigned int max_bpc; } MonitorTestCaseMonitor; typedef struct _MonitorTestCaseLogicalMonitor diff --git a/src/tests/monitor-configs/max-bpc.xml b/src/tests/monitor-configs/max-bpc.xml new file mode 100644 index 0000000000000000000000000000000000000000..c98e6605cc2f9aa01ceb0b9db7bac1bc0dc07a38 --- /dev/null +++ b/src/tests/monitor-configs/max-bpc.xml @@ -0,0 +1,23 @@ + + + + 0 + 0 + yes + + + DP-1 + MetaProduct's Inc. + MetaMonitor + 0x123456 + + + 1024 + 768 + 60.000495910644531 + + 12 + + + + diff --git a/src/tests/monitor-store-unit-tests.c b/src/tests/monitor-store-unit-tests.c index 38f4bc52fc31b147cd4306bbe0238fea1db2d716..f8fd2b26288bfe6d4442aedc0e0ff602d8c11fad 100644 --- a/src/tests/monitor-store-unit-tests.c +++ b/src/tests/monitor-store-unit-tests.c @@ -48,6 +48,7 @@ typedef struct _MonitorStoreTestCaseMonitor const char *serial; MonitorStoreTestCaseMonitorMode mode; gboolean is_underscanning; + unsigned int max_bpc; } MonitorStoreTestCaseMonitor; typedef struct _MonitorStoreTestCaseLogicalMonitor @@ -196,6 +197,12 @@ check_monitor_store_configuration (MetaMonitorConfigStore *config_store, g_assert_cmpint (monitor_config->enable_underscanning, ==, test_monitor->is_underscanning); + g_assert_cmpint (monitor_config->has_max_bpc, + ==, + !!test_monitor->max_bpc); + g_assert_cmpint (monitor_config->max_bpc, + ==, + test_monitor->max_bpc); } } } @@ -446,6 +453,51 @@ meta_test_monitor_store_underscanning (void) check_monitor_store_configurations (&expect); } +static void +meta_test_monitor_store_max_bpc (void) +{ + MonitorStoreTestExpect expect = { + .configurations = { + { + .logical_monitors = { + { + .layout = { + .x = 0, + .y = 0, + .width = 1024, + .height = 768 + }, + .scale = 1, + .is_primary = TRUE, + .is_presentation = FALSE, + .monitors = { + { + .connector = "DP-1", + .vendor = "MetaProduct's Inc.", + .product = "MetaMonitor", + .serial = "0x123456", + .max_bpc = 12, + .mode = { + .width = 1024, + .height = 768, + .refresh_rate = 60.000495910644531 + } + } + }, + .n_monitors = 1, + }, + }, + .n_logical_monitors = 1 + } + }, + .n_configurations = 1 + }; + + meta_set_custom_monitor_config (test_context, "max-bpc.xml"); + + check_monitor_store_configurations (&expect); +} + static void meta_test_monitor_store_scale (void) { @@ -1013,6 +1065,8 @@ init_monitor_store_tests (void) meta_test_monitor_store_primary); g_test_add_func ("/backends/monitor-store/underscanning", meta_test_monitor_store_underscanning); + g_test_add_func ("/backends/monitor-store/max-bpc", + meta_test_monitor_store_max_bpc); g_test_add_func ("/backends/monitor-store/scale", meta_test_monitor_store_scale); g_test_add_func ("/backends/monitor-store/fractional-scale", diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c index ed81afbf1ecfc84805696f328d86fa03f3fde9e0..8e34c8b22c0add9ee82eff0c587f8d5ba1b58656 100644 --- a/src/tests/monitor-unit-tests.c +++ b/src/tests/monitor-unit-tests.c @@ -3276,6 +3276,100 @@ meta_test_monitor_underscanning_config (void) check_monitor_test_clients_state (); } +static void +meta_test_monitor_max_bpc_config (void) +{ + MonitorTestCase test_case = { + .setup = { + .modes = { + { + .width = 1024, + .height = 768, + .refresh_rate = 60.0 + } + }, + .n_modes = 1, + .outputs = { + { + .crtc = 0, + .modes = { 0 }, + .n_modes = 1, + .preferred_mode = 0, + .possible_crtcs = { 0 }, + .n_possible_crtcs = 1, + .width_mm = 222, + .height_mm = 125, + .max_bpc = 8, + } + }, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0 + } + }, + .n_crtcs = 1 + }, + + .expect = { + .monitors = { + { + .outputs = { 0 }, + .n_outputs = 1, + .modes = { + { + .width = 1024, + .height = 768, + .refresh_rate = 60.0, + .crtc_modes = { + { + .output = 0, + .crtc_mode = 0 + } + } + } + }, + .n_modes = 1, + .current_mode = 0, + .width_mm = 222, + .height_mm = 125, + .max_bpc = 8, + } + }, + .n_monitors = 1, + .logical_monitors = { + { + .monitors = { 0 }, + .n_monitors = 1, + .layout = { .x = 0, .y = 0, .width = 1024, .height = 768 }, + .scale = 1 + } + }, + .n_logical_monitors = 1, + .primary_logical_monitor = 0, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0, + } + }, + .n_crtcs = 1, + .screen_width = 1024, + .screen_height = 768 + } + }; + MetaMonitorTestSetup *test_setup; + + test_setup = meta_create_monitor_test_setup (test_backend, + &test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + META_TEST_LOG_CALL ("Checking monitor configuration", + meta_check_monitor_configuration (test_context, + &test_case.expect)); + check_monitor_test_clients_state (); +} + static void meta_test_monitor_preferred_non_first_mode (void) { @@ -9366,6 +9460,8 @@ init_monitor_tests (void) meta_test_monitor_no_outputs); add_monitor_test ("/backends/monitor/underscanning-config", meta_test_monitor_underscanning_config); + add_monitor_test ("/backends/monitor/max-bpc-config", + meta_test_monitor_max_bpc_config); add_monitor_test ("/backends/monitor/preferred-non-first-mode", meta_test_monitor_preferred_non_first_mode); add_monitor_test ("/backends/monitor/non-upright-panel",