Skip to content

Commit

Permalink
Merge pull request #32 from eric-ch/s9-oxt-1653
Browse files Browse the repository at this point in the history
S9: OXT-1653: Attend crashes related to external display handling.
  • Loading branch information
jean-edouard authored Jul 25, 2019
2 parents 5d286ba + 4ea6510 commit 6cb6c9a
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 84 deletions.
4 changes: 2 additions & 2 deletions plugins/drm/src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ SRCS = drm-plugin.c \
hotplug.c \
backlight.c

noinst_HEADERS = drm-plugin.h utils.h list.h project.h prototypes.h
HDRS = drm-plugin.h utils.h list.h project.h prototypes.h

plugindir = ${libdir}/surfman
plugin_LTLIBRARIES = drm-plugin.la

drm_plugin_la_SOURCES = ${SRCS}
drm_plugin_la_SOURCES = ${SRCS} ${HDRS}
drm_plugin_la_LDFLAGS = -module
drm_plugin_la_CFLAGS = ${LIBUDEV_CFLAGS} ${LIBDRM_CFLAGS} ${LIBSURFMAN_CFLAGS} -W -Wall -Werror -g
drm_plugin_la_CPPFLAGS = ${LIBUDEV_CFLAGS} ${LIBDRM_CFLAGS} ${LIBSURFMAN_CFLAGS}
Expand Down
121 changes: 52 additions & 69 deletions plugins/drm/src/device-intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,52 +99,54 @@ static int should_avoid_scaling(struct drm_monitor *monitor, struct drm_framebuf
* - We are not able to scale down.
* - We can manage scaled up framebuffer using planes or direct modesetting,
* but it is more flexible using planes. */
static inline drmModeModeInfoPtr __find_mode(struct framebuffer *fb,
drmModeModeInfoPtr modes,
unsigned int count,
drmModeModeInfoPtr *fallback_mode)
static inline int __find_mode(struct framebuffer *fb,
drmModeModeInfoPtr modes, unsigned int count,
drmModeModeInfoPtr mode,
drmModeModeInfoPtr fallback_mode)
{
unsigned int i;
unsigned int dh, dw, dl, odl = ~0L; /* delta-width, delta-height, delta-length, old_delta-lenght. */

*fallback_mode = NULL;
for (i = 0; i < count; ++i) {
if ((modes[i].hdisplay == fb->width) &&
(modes[i].vdisplay == fb->height)) {
/* Found compatible mode. */
return &modes[i];
memcpy(mode, &modes[i], sizeof (modes[i]));
return 0;

}
if ((modes[i].hdisplay > fb->width) && (modes[i].vdisplay > fb->height)) {
/* Lets avoid to crop. */
*fallback_mode = &modes[i];
memcpy(fallback_mode, &modes[i], sizeof (modes[i]));
odl = 0;
} else {
dh = max(modes[i].hdisplay, fb->width) - min(modes[i].hdisplay, fb->width);
dw = max(modes[i].vdisplay, fb->height) - min(modes[i].vdisplay, fb->height);
dl = dh * dh + dw * dw;
if (dl < odl) {
*fallback_mode = &modes[i];
memcpy(fallback_mode, &modes[i], sizeof (modes[i]));
odl = dl;
}
}
}
return NULL;
return -1;
}

static inline drmModeModeInfoPtr __find_mode_cropped(struct framebuffer *fb,
drmModeModeInfoPtr modes,
unsigned int count)
static int __find_mode_cropped(struct framebuffer *fb,
drmModeModeInfoPtr modes, unsigned int count,
drmModeModeInfoPtr mode)
{
unsigned int i;

for (i = 0; i < count; ++i) {
if ((modes[i].hdisplay <= fb->width) &&
(modes[i].vdisplay <= fb->height)) {
/* Found compatible mode. */
return &modes[i];
memcpy(mode, &modes[i], sizeof (modes[i]));
return 0;
}
}
return &modes[0];
return -1;
}

/* Helper with DRM plumbings to create a plane. */
Expand Down Expand Up @@ -381,25 +383,22 @@ static int drm_connector_set_scaling(int fd, drmModeConnector *connector, int sc
* @return The newly-create mode pointer, or NULL if allocation fails.
* This should be freed with free() when it is no longer needed.
*/
static drmModeModeInfoPtr __create_mode_for_framebuffer(struct drm_monitor * monitor, struct drm_framebuffer * drmfb) {

//Allocate a new ModeInfo object...
drmModeModeInfoPtr mode = malloc(sizeof(drmModeModeInfo));
static int __create_mode_for_framebuffer(struct drm_monitor *monitor,
struct drm_framebuffer *drmfb,
drmModeModeInfoPtr mode) {

// If we weren't able to allocate a block of memory for the mode, fail.
if(!mode) {
return NULL;
}
// Upscaling cannot exceed the largest mode supported by the display.
if (monitor->prefered_mode.hdisplay < drmfb->fb.width ||
monitor->prefered_mode.vdisplay < drmfb->fb.height)
return -1;

//... fill it with the monitor's preferred mode...
memcpy(mode, &monitor->prefered_mode, sizeof(drmModeModeInfo));
memcpy(mode, &monitor->prefered_mode, sizeof (drmModeModeInfo));

//... and override the width and height to match those of the target fb.
//Override the width and height to match those of the target fb.
mode->hdisplay = drmfb->fb.width;
mode->vdisplay = drmfb->fb.height;

//... and return our newly-created mode.
return mode;
return 0;
}


Expand All @@ -410,8 +409,7 @@ static int i915_modeset(struct drm_monitor *monitor, struct drm_framebuffer *drm
{
int rc = 0;
drmModeConnector *con;
drmModeModeInfoPtr mode, fallback_mode;
drmModeModeInfoPtr synthetic_mode = NULL;
drmModeModeInfo mode = { 0 }, fallback_mode = { 0 };
unsigned int crtc_x = 0, crtc_y = 0;

con = drmModeGetConnector(monitor->device->fd, monitor->connector);
Expand All @@ -421,29 +419,17 @@ static int i915_modeset(struct drm_monitor *monitor, struct drm_framebuffer *drm
monitor->connector, monitor->device->devnode, strerror(errno));
return rc;
}
mode = __find_mode(&drmfb->fb, con->modes, con->count_modes, &fallback_mode);
if (!mode) {
if (__find_mode(&drmfb->fb, con->modes, con->count_modes,
&mode, &fallback_mode)) {

//If the monitor doesn't directly support the relevant mode, but
//is connected via a connection that supports panel fitting, we can
//use that to scale to the monitor's preferred mdoe.
if(supports_panel_fitting(monitor->device->fd, con)) {

DRM_INF("It seems like we have a panel fitter...");
if (supports_panel_fitting(monitor->device->fd, con) &&
__create_mode_for_framebuffer(monitor, drmfb, &mode) >= 0) {

//Adopt the monitor's preferred mode.
mode = synthetic_mode = __create_mode_for_framebuffer(monitor, drmfb);

//If we weren't able to allocate a synthetic mode, we have a very poor chance of recovering;
//we'll bail out as best we can.
if(!synthetic_mode) {
DRM_INF("... but we failed to allocate space for a new panel-fitting mode! Bailing out.");
goto fail_setcrtc;
}

DRM_INF("... using mode (%dx%d) to display a (%d x %d) framebuffer via the panel fitter.",
mode->hdisplay, mode->vdisplay, drmfb->fb.width, drmfb->fb.height);

DRM_INF("Using mode (%dx%d) to display a (%d x %d) framebuffer via the panel fitter.",
mode.hdisplay, mode.vdisplay, drmfb->fb.width, drmfb->fb.height);
//Use the DRM franmebuffer as is-- it should match our panel-fitting "synthetic"
//mode.
monitor->framebuffer = drmfb;
Expand All @@ -458,17 +444,17 @@ static int i915_modeset(struct drm_monitor *monitor, struct drm_framebuffer *drm
/* The monitor does not handle this mode, but if the framebuffer is smaller we can stick it in a
* plane on top of a blanked framebuffer.
* Lets try to use a blanked framebuffer as small as possible. */
if (fallback_mode) {
if (fallback_mode.hdisplay != 0) {

monitor->plane = i915_plane_new(drmfb, monitor->crtc);
if (monitor->plane) {
/* XXX: I couldn't setup a plane without an underlying (useless) framebuffer.
* We allocate it here. */
monitor->framebuffer = __dumb_framebuffer_create(monitor->device, fallback_mode->hdisplay,
fallback_mode->vdisplay, drmfb->fb.depth,
monitor->framebuffer = __dumb_framebuffer_create(monitor->device, fallback_mode.hdisplay,
fallback_mode.vdisplay, drmfb->fb.depth,
drmfb->fb.bpp);
if (monitor->framebuffer) {
mode = fallback_mode;
memcpy(&mode, &fallback_mode, sizeof (mode));
goto modeset; /* We're ready to modeset and compose the plane on top. */
}
/* Give up using a plane. */
Expand All @@ -482,20 +468,26 @@ static int i915_modeset(struct drm_monitor *monitor, struct drm_framebuffer *drm

/* We couldn't setup a plane if the framebuffer is bigger or equal than the mode we might pull
* this out by cropping at least on one dimension. Otherwise there's no point.*/
mode = __find_mode_cropped(&drmfb->fb, con->modes, con->count_modes);
if (drmfb->fb.width > mode->hdisplay) {
crtc_x = (drmfb->fb.width - mode->hdisplay) / 2;
}
if (drmfb->fb.height > mode->vdisplay) {
crtc_y = (drmfb->fb.height - mode->vdisplay) / 2;
if (__find_mode_cropped(&drmfb->fb, con->modes, con->count_modes, &mode) != 0) {
DRM_WRN("Failed to find compatibility mode for device \"%s\".", monitor->device->devnode);
rc = -EINVAL;
goto fail_setmaster;
}
if (drmfb->fb.width > mode.hdisplay)
crtc_x = (drmfb->fb.width - mode.hdisplay) / 2;
if (drmfb->fb.height > mode.vdisplay)
crtc_y = (drmfb->fb.height - mode.vdisplay) / 2;
}
monitor->framebuffer = drmfb;

modeset:
rc = drm_device_set_master(monitor->device);

/* Connector was yanked, bail out. */
if (con->connection != DRM_MODE_CONNECTED) {
rc = -ENOENT;
goto fail_setmaster;
}

rc = drm_device_set_master(monitor->device);
if (rc) {
DRM_ERR("Cannot perform modeset operation while something else is mastering `%s' (%s).",
monitor->device->devnode, strerror(-rc));
Expand All @@ -504,7 +496,7 @@ static int i915_modeset(struct drm_monitor *monitor, struct drm_framebuffer *drm

if (drmModeSetCrtc(monitor->device->fd, monitor->crtc, monitor->framebuffer->id,
crtc_x, crtc_y,
&(monitor->connector), 1, mode)) {
&(monitor->connector), 1, &mode)) {
rc = -errno;
DRM_ERR("Cannot display framebuffer %u in connector %u (%s).",
monitor->framebuffer->id, monitor->connector, strerror(errno));
Expand Down Expand Up @@ -537,11 +529,6 @@ static int i915_modeset(struct drm_monitor *monitor, struct drm_framebuffer *drm
}

drm_device_drop_master(monitor->device);

//If we've created a new mode, destroy the object that holds it.
if(synthetic_mode) {
free(synthetic_mode);
}

return 0;

Expand All @@ -554,10 +541,6 @@ static int i915_modeset(struct drm_monitor *monitor, struct drm_framebuffer *drm
fail_setmaster:
drmModeFreeConnector(con);

if(synthetic_mode) {
free(synthetic_mode);
}

return rc;
}

Expand Down
2 changes: 2 additions & 0 deletions plugins/drm/src/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ INTERNAL struct drm_plane *drm_device_add_plane(struct drm_device *device, uint3
p = drm_device_find_plane(device, plane);
if (!p) {
p = calloc(1, sizeof (*p));
if (!p)
return NULL;
p->id = plane;
p->device = device;
list_add_tail(&p->l, &device->planes);
Expand Down
8 changes: 8 additions & 0 deletions plugins/drm/src/drm-plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,18 @@ INTERNAL int drmp_get_monitors(surfman_plugin_t *plugin, surfman_monitor_t *moni
(void) plugin;
struct drm_device *d, *dd;
unsigned int j = 0;
int rc;

list_for_each_entry_safe(d, dd, &devices, l) {
struct drm_monitor *m, *mm;

rc = drm_monitors_scan(d);
if (rc < 0) {
DRM_WRN("Failed to scan for monitors on device %s (%s).",
d->devnode, strerror(-rc));
continue;
}

DRM_DBG("Device %s monitors:", d->devnode);
list_for_each_entry_safe(m, mm, &(d->monitors), l_dev) {
if (j >= size) {
Expand Down
19 changes: 6 additions & 13 deletions plugins/drm/src/hotplug.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,26 @@ static void hotplug_event_handler(int fd, short event, void *priv)
{
struct hotplug *hotplug = priv;
struct udev_device *dev;
struct drm_device *d, *dd;
const char *devnode;

(void) fd;
(void) event;

/* Notify surfman to rescan monitors.
* This will trigger a callback to the plugin on Surfman's terms. */
surfman_plugin.notify |= SURFMAN_NOTIFY_MONITOR_RESCAN;

dev = udev_monitor_receive_device(hotplug->monitor);
if (!dev) {
DRM_WRN("Could not recover the device which triggered this udev event (%s).",
strerror(errno));
return;
}

devnode = udev_device_get_devnode(dev);
DRM_DBG("%s: %s (%s) triggred `%s' event.", udev_device_get_subsystem(dev),
udev_device_get_sysname(dev), devnode, udev_device_get_action(dev));

/* TODO: Who knows... some cardX might appear, but we'll see that later. */
if (devnode) {
/* TODO: Those lists will require some sync mecanisms someday... */
list_for_each_entry_safe(d, dd, &devices, l) {
if (!strcmp(d->devnode, devnode)) {
drm_monitors_scan(d);
break;
}
}
}
udev_device_unref(dev);
surfman_plugin.notify |= SURFMAN_NOTIFY_MONITOR_RESCAN;
return;
}

Expand Down
5 changes: 5 additions & 0 deletions surfman/src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,11 @@ display_update_monitors (struct plugin *p,
{
struct monitor_info *info = get_monitor_info (p, monitors[i]);

/* The plugin does not recognize the monitor, or it was yanked quickly
* after being plugged. */
if (info == NULL)
continue;

for (j = 0; j < DISPLAY_MONITOR_MAX; j++)
{
if (display[j].plugin == p &&
Expand Down

0 comments on commit 6cb6c9a

Please sign in to comment.