[PATCH] compositor: add dpms and backlight support

Tiago Vignatti tiago.vignatti at intel.com
Wed Feb 29 09:53:50 PST 2012


DPMS kicks in only when wscreensaver is launched, in the moment that shell
call lock() for the second time. Backlight control internals are managed by
libbacklight:

	http://cgit.freedesktop.org/~vignatti/libbacklight/

Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
---

Thanks Jesse and Kristian for the comments. I've updated the patch addressing
most of the issues.

 configure.ac             |    2 +-
 src/compositor-drm.c     |  114 ++++++++++++++++++++++++++++++++++++++++++----
 src/compositor-openwfd.c |    2 +
 src/compositor-wayland.c |    2 +
 src/compositor-x11.c     |    2 +
 src/compositor.c         |   12 +++++
 src/compositor.h         |   13 +++++
 src/shell.c              |   47 ++++++++++++++++++-
 8 files changed, 182 insertions(+), 12 deletions(-)

diff --git a/configure.ac b/configure.ac
index ba42a04..6b54bb3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -73,7 +73,7 @@ AC_ARG_ENABLE(drm-compositor, [  --enable-drm-compositor],,
 AM_CONDITIONAL(ENABLE_DRM_COMPOSITOR, test x$enable_drm_compositor = xyes)
 if test x$enable_drm_compositor = xyes; then
   AC_DEFINE([BUILD_DRM_COMPOSITOR], [1], [Build the DRM compositor])
-  PKG_CHECK_MODULES(DRM_COMPOSITOR, [libudev >= 136 libdrm >= 2.4.30 gbm])
+  PKG_CHECK_MODULES(DRM_COMPOSITOR, [libbacklight libudev >= 136 libdrm >= 2.4.30 gbm])
 fi
 
 
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 38ff02b..cfaad15 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -35,6 +35,7 @@
 #include <drm_fourcc.h>
 
 #include <gbm.h>
+#include <libbacklight.h>
 
 #include "compositor.h"
 #include "evdev.h"
@@ -86,6 +87,7 @@ struct drm_output {
 	struct wl_listener scanout_buffer_destroy_listener;
 	struct wl_buffer *pending_scanout_buffer;
 	struct wl_listener pending_scanout_buffer_destroy_listener;
+	struct backlight *backlight;
 };
 
 /*
@@ -697,6 +699,9 @@ drm_output_destroy(struct weston_output *output_base)
 	drmModeCrtcPtr origcrtc = output->original_crtc;
 	int i;
 
+	if (output->backlight)
+		backlight_destroy(output->backlight);
+
 	/* Turn off hardware cursor */
 	drm_output_set_cursor(&output->base, NULL);
 
@@ -907,11 +912,92 @@ sprite_handle_pending_buffer_destroy(struct wl_listener *listener,
 	sprite->pending_surface = NULL;
 }
 
+/* returns a value between 1-10 range, where higher is brighter */
+static uint32_t
+drm_get_backlight(struct drm_output *output)
+{
+	long brightness, max_brightness, norm;
+
+	brightness = backlight_get_brightness(output->backlight);
+	max_brightness = backlight_get_max_brightness(output->backlight);
+
+	/* convert it on a scale of 1 to 10 */
+	norm = 1 + ((brightness) * 9)/(max_brightness);
+
+	return (uint32_t) norm;
+}
+
+/* values accepted are between 1-10 range */
+static void
+drm_set_backlight(struct weston_output *output_base, uint32_t value)
+{
+	struct drm_output *output = (struct drm_output *) output_base;
+	long max_brightness, new_brightness;
+
+	if (!output->backlight)
+		return;
+
+	if (value < 1 || value > 10)
+		return;
+
+	max_brightness = backlight_get_max_brightness(output->backlight);
+
+	/* get denormalized value */
+	new_brightness = ((value - 1) * (max_brightness)) / 9;
+
+	backlight_set_brightness(output->backlight, new_brightness);
+}
+
+static drmModePropertyPtr
+drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
+{
+	drmModePropertyPtr props;
+	int i;
+
+	for (i = 0; i < connector->count_props; i++) {
+		props = drmModeGetProperty(fd, connector->props[i]);
+		if (!props)
+			continue;
+
+		if (!strcmp(props->name, name))
+			return props;
+
+		drmModeFreeProperty(props);
+	}
+
+	return NULL;
+}
+
+static void
+drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
+{
+	struct drm_output *output = (struct drm_output *) output_base;
+	struct weston_compositor *ec = output_base->compositor;
+	struct drm_compositor *c = (struct drm_compositor *) ec;
+	drmModeConnectorPtr connector;
+	drmModePropertyPtr prop;
+
+	connector = drmModeGetConnector(c->drm.fd, output->connector_id);
+	if (!connector)
+		return;
+
+	prop = drm_get_prop(c->drm.fd, connector, "DPMS");
+	if (!prop) {
+		drmModeFreeConnector(connector);
+		return;
+	}
+
+	drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
+				    prop->prop_id, level);
+	drmModeFreeProperty(prop);
+	drmModeFreeConnector(connector);
+}
+
 static int
 create_output_for_connector(struct drm_compositor *ec,
 			    drmModeRes *resources,
 			    drmModeConnector *connector,
-			    int x, int y)
+			    int x, int y, struct udev_device *drm_device)
 {
 	struct drm_output *output;
 	struct drm_mode *drm_mode, *next;
@@ -1026,6 +1112,13 @@ create_output_for_connector(struct drm_compositor *ec,
 		goto err_fb;
 	}
 
+	output->backlight = backlight_init(drm_device,
+					   connector->connector_type);
+	if (output->backlight) {
+		output->base.set_backlight = drm_set_backlight;
+		output->base.backlight_current = drm_get_backlight(output);
+	}
+
 	weston_output_init(&output->base, &ec->base, x, y,
 			 connector->mmWidth, connector->mmHeight, 0);
 
@@ -1040,6 +1133,7 @@ create_output_for_connector(struct drm_compositor *ec,
 	output->base.repaint = drm_output_repaint;
 	output->base.destroy = drm_output_destroy;
 	output->base.assign_planes = drm_assign_planes;
+	output->base.set_dpms = drm_set_dpms;
 
 	return 0;
 
@@ -1148,7 +1242,8 @@ destroy_sprites(struct drm_compositor *compositor)
 }
 
 static int
-create_outputs(struct drm_compositor *ec, int option_connector)
+create_outputs(struct drm_compositor *ec, int option_connector,
+	       struct udev_device *drm_device)
 {
 	drmModeConnector *connector;
 	drmModeRes *resources;
@@ -1178,7 +1273,8 @@ create_outputs(struct drm_compositor *ec, int option_connector)
 		    (option_connector == 0 ||
 		     connector->connector_id == option_connector)) {
 			if (create_output_for_connector(ec, resources,
-							connector, x, y) < 0) {
+							connector, x, y,
+							drm_device) < 0) {
 				drmModeFreeConnector(connector);
 				continue;
 			}
@@ -1202,7 +1298,7 @@ create_outputs(struct drm_compositor *ec, int option_connector)
 }
 
 static void
-update_outputs(struct drm_compositor *ec)
+update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 {
 	drmModeConnector *connector;
 	drmModeRes *resources;
@@ -1245,7 +1341,8 @@ update_outputs(struct drm_compositor *ec)
 				x = 0;
 			y = 0;
 			create_output_for_connector(ec, resources,
-						    connector, x, y);
+						    connector, x, y,
+						    drm_device);
 			printf("connector %d connected\n", connector_id);
 
 		}
@@ -1301,7 +1398,7 @@ udev_drm_event(int fd, uint32_t mask, void *data)
 	event = udev_monitor_receive_device(ec->udev_monitor);
 
 	if (udev_event_is_hotplug(event))
-		update_outputs(ec);
+		update_outputs(ec, event);
 
 	udev_device_unref(event);
 
@@ -1469,8 +1566,6 @@ drm_compositor_create(struct wl_display *display,
 		return NULL;
 	}
 
-	udev_device_unref(drm_device);
-
 	ec->base.destroy = drm_destroy;
 
 	ec->base.focus = 1;
@@ -1487,11 +1582,12 @@ drm_compositor_create(struct wl_display *display,
 	wl_list_init(&ec->sprite_list);
 	create_sprites(ec);
 
-	if (create_outputs(ec, connector) < 0) {
+	if (create_outputs(ec, connector, drm_device) < 0) {
 		fprintf(stderr, "failed to create output for %s\n", path);
 		return NULL;
 	}
 
+	udev_device_unref(drm_device);
 	udev_enumerate_unref(e);
 	path = NULL;
 
diff --git a/src/compositor-openwfd.c b/src/compositor-openwfd.c
index 8dce304..eae1e66 100644
--- a/src/compositor-openwfd.c
+++ b/src/compositor-openwfd.c
@@ -407,6 +407,8 @@ create_output_for_port(struct wfd_compositor *ec,
 	output->base.set_hardware_cursor = wfd_output_set_cursor;
 	output->base.destroy = wfd_output_destroy;
 	output->base.assign_planes = NULL;
+	output->base.set_backlight = NULL;
+	output->base.set_dpms = NULL;
 
 	wl_list_insert(ec->base.output_list.prev, &output->base.link);
 
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index a42e76f..f8b5a32 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -435,6 +435,8 @@ wayland_compositor_create_output(struct wayland_compositor *c,
 	output->base.repaint = wayland_output_repaint;
 	output->base.destroy = wayland_output_destroy;
 	output->base.assign_planes = NULL;
+	output->base.set_backlight = NULL;
+	output->base.set_dpms = NULL;
 
 	wl_list_insert(c->base.output_list.prev, &output->base.link);
 
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index 7243329..53998d2 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -441,6 +441,8 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
 	output->base.repaint = x11_output_repaint;
 	output->base.destroy = x11_output_destroy;
 	output->base.assign_planes = NULL;
+	output->base.set_backlight = NULL;
+	output->base.set_dpms = NULL;
 
 	wl_list_insert(c->base.output_list.prev, &output->base.link);
 
diff --git a/src/compositor.c b/src/compositor.c
index 74c40da..8f09550 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1386,12 +1386,23 @@ weston_compositor_wake(struct weston_compositor *compositor)
 				     compositor->idle_time * 1000);
 }
 
+static void
+weston_compositor_dpms_on(struct weston_compositor *compositor)
+{
+        struct weston_output *output;
+
+        wl_list_for_each(output, &compositor->output_list, link)
+		if (output->set_dpms)
+			output->set_dpms(output, WESTON_DPMS_ON);
+}
+
 WL_EXPORT void
 weston_compositor_activity(struct weston_compositor *compositor)
 {
 	if (compositor->state == WESTON_COMPOSITOR_ACTIVE) {
 		weston_compositor_wake(compositor);
 	} else {
+		weston_compositor_dpms_on(compositor);
 		compositor->shell->unlock(compositor->shell);
 	}
 }
@@ -2513,6 +2524,7 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
+	weston_compositor_dpms_on(ec);
 	weston_compositor_wake(ec);
 	if (setjmp(segv_jmp_buf) == 0)
 		wl_display_run(display);
diff --git a/src/compositor.h b/src/compositor.h
index dd9cb20..8c57e4f 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -62,6 +62,14 @@ struct weston_output_zoom {
 	float trans_x, trans_y;
 };
 
+/* bit compatible with drm definitions. */
+enum dpms_enum {
+	WESTON_DPMS_ON,
+	WESTON_DPMS_STANDBY,
+	WESTON_DPMS_SUSPEND,
+	WESTON_DPMS_OFF
+};
+
 struct weston_output {
 	struct wl_list link;
 	struct weston_compositor *compositor;
@@ -86,6 +94,11 @@ struct weston_output {
 	void (*repaint)(struct weston_output *output);
 	void (*destroy)(struct weston_output *output);
 	void (*assign_planes)(struct weston_output *output);
+
+	/* backlight values are on 1-10 range, where higher is brighter */
+	uint32_t backlight_current;
+	void (*set_backlight)(struct weston_output *output, uint32_t value);
+	void (*set_dpms)(struct weston_output *output, enum dpms_enum level);
 };
 
 struct weston_input_device {
diff --git a/src/shell.c b/src/shell.c
index a28302b..01e5cf6 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1311,10 +1311,16 @@ lock(struct weston_shell *base)
 	struct weston_surface *tmp;
 	struct weston_input_device *device;
 	struct shell_surface *shsurf;
+	struct weston_output *output;
 	uint32_t time;
 
-	if (shell->locked)
+	if (shell->locked) {
+		wl_list_for_each(output, &shell->compositor->output_list, link)
+			/* TODO: find a way to jump to other DPMS levels */
+			if (output->set_dpms)
+				output->set_dpms(output, WESTON_DPMS_STANDBY);
 		return;
+	}
 
 	shell->locked = true;
 
@@ -1834,6 +1840,34 @@ switcher_binding(struct wl_input_device *device, uint32_t time,
 }
 
 static void
+backlight_binding(struct wl_input_device *device, uint32_t time,
+		  uint32_t key, uint32_t button, uint32_t state, void *data)
+{
+	struct weston_compositor *compositor = data;
+	struct weston_output *output;
+
+	/* TODO: we're limiting to simple use cases, where we assume just
+	 * control on the primary display. We'd have to extend later if we
+	 * ever get support for setting backlights on random desktop LCD
+	 * panels though */
+	output = get_default_output(compositor);
+	if (!output)
+		return;
+
+	if (!output->set_backlight)
+		return;
+
+	if ((key == KEY_F9 || key == KEY_BRIGHTNESSDOWN) &&
+	    output->backlight_current > 1)
+		output->backlight_current--;
+	else if ((key == KEY_F10 || key == KEY_BRIGHTNESSUP) &&
+	    output->backlight_current < 10)
+		output->backlight_current++;
+
+	output->set_backlight(output, output->backlight_current);
+}
+
+static void
 shell_destroy(struct weston_shell *base)
 {
 	struct wl_shell *shell = container_of(base, struct wl_shell, shell);
@@ -1905,10 +1939,19 @@ shell_init(struct weston_compositor *ec)
 	weston_compositor_add_binding(ec, 0, BTN_LEFT,
 				      MODIFIER_SUPER | MODIFIER_ALT,
 				      rotate_binding, NULL);
-
 	weston_compositor_add_binding(ec, KEY_TAB, 0, MODIFIER_SUPER,
 				      switcher_binding, ec);
 
+	/* brightness */
+	weston_compositor_add_binding(ec, KEY_F9, 0, MODIFIER_CTRL,
+				      backlight_binding, ec);
+	weston_compositor_add_binding(ec, KEY_BRIGHTNESSDOWN, 0, 0,
+				      backlight_binding, ec);
+	weston_compositor_add_binding(ec, KEY_F10, 0, MODIFIER_CTRL,
+				      backlight_binding, ec);
+	weston_compositor_add_binding(ec, KEY_BRIGHTNESSUP, 0, 0,
+				      backlight_binding, ec);
+
 	ec->shell = &shell->shell;
 
 	return 0;
-- 
1.7.5.4



More information about the wayland-devel mailing list