compositor: add dpms and backlight support

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@intel.com>
This commit is contained in:
Tiago Vignatti 2012-02-29 19:53:50 +02:00 committed by Kristian Høgsberg
parent 2ea094422a
commit 8e53c7f566
8 changed files with 182 additions and 12 deletions

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -1387,12 +1387,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);
}
}
@ -2514,6 +2525,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);

View file

@ -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 {

View file

@ -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;
@ -1833,6 +1839,34 @@ switcher_binding(struct wl_input_device *device, uint32_t time,
switcher_next(switcher);
}
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)
{
@ -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;