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",