Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6d3c4d7 authored by Gerd Hoffmann's avatar Gerd Hoffmann
Browse files

qxl: hook monitors_config updates into crtc, not encoder.

The encoder callbacks are only called in case the video mode changes.
So any layout changes without mode changes will go unnoticed.

Add qxl_crtc_update_monitors_config(), based on the old
qxl_write_monitors_config_for_encoder() function.  Hook it into the
enable, disable and flush atomic crtc callbacks.  Remove monitors_config
updates from all other places.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1544322


Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
Reviewed-by: default avatarDave Airlie <airlied@redhat.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20180420071904.24276-4-kraxel@redhat.com
parent 998010bf
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -371,6 +371,7 @@ void qxl_io_flush_surfaces(struct qxl_device *qdev)
void qxl_io_destroy_primary(struct qxl_device *qdev)
{
	wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC);
	qdev->primary_created = false;
}

void qxl_io_create_primary(struct qxl_device *qdev,
@@ -396,6 +397,7 @@ void qxl_io_create_primary(struct qxl_device *qdev,
	create->type = QXL_SURF_TYPE_PRIMARY;

	wait_for_io_cmd(qdev, 0, QXL_IO_CREATE_PRIMARY_ASYNC);
	qdev->primary_created = true;
}

void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id)
+64 −92
Original line number Diff line number Diff line
@@ -281,6 +281,66 @@ static void qxl_send_monitors_config(struct qxl_device *qdev)
	qxl_io_monitors_config(qdev);
}

static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
					    const char *reason)
{
	struct drm_device *dev = crtc->dev;
	struct qxl_device *qdev = dev->dev_private;
	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
	struct qxl_head head;
	int oldcount, i = qcrtc->index;

	if (!qdev->primary_created) {
		DRM_DEBUG_KMS("no primary surface, skip (%s)\n", reason);
		return;
	}

	if (!qdev->monitors_config ||
	    qdev->monitors_config->max_allowed <= i)
		return;

	head.id = i;
	head.flags = 0;
	oldcount = qdev->monitors_config->count;
	if (crtc->state->active) {
		struct drm_display_mode *mode = &crtc->mode;
		head.width = mode->hdisplay;
		head.height = mode->vdisplay;
		head.x = crtc->x;
		head.y = crtc->y;
		if (qdev->monitors_config->count < i + 1)
			qdev->monitors_config->count = i + 1;
	} else if (i > 0) {
		head.width = 0;
		head.height = 0;
		head.x = 0;
		head.y = 0;
		if (qdev->monitors_config->count == i + 1)
			qdev->monitors_config->count = i;
	} else {
		DRM_DEBUG_KMS("inactive head 0, skip (%s)\n", reason);
		return;
	}

	if (head.width  == qdev->monitors_config->heads[i].width  &&
	    head.height == qdev->monitors_config->heads[i].height &&
	    head.x      == qdev->monitors_config->heads[i].x      &&
	    head.y      == qdev->monitors_config->heads[i].y      &&
	    oldcount    == qdev->monitors_config->count)
		return;

	DRM_DEBUG_KMS("head %d, %dx%d, at +%d+%d, %s (%s)\n",
		      i, head.width, head.height, head.x, head.y,
		      crtc->state->active ? "on" : "off", reason);
	if (oldcount != qdev->monitors_config->count)
		DRM_DEBUG_KMS("active heads %d -> %d (%d total)\n",
			      oldcount, qdev->monitors_config->count,
			      qdev->monitors_config->max_allowed);

	qdev->monitors_config->heads[i] = head;
	qxl_send_monitors_config(qdev);
}

static void qxl_crtc_atomic_flush(struct drm_crtc *crtc,
				  struct drm_crtc_state *old_crtc_state)
{
@@ -296,6 +356,8 @@ static void qxl_crtc_atomic_flush(struct drm_crtc *crtc,
		drm_crtc_send_vblank_event(crtc, event);
		spin_unlock_irqrestore(&dev->event_lock, flags);
	}

	qxl_crtc_update_monitors_config(crtc, "flush");
}

static void qxl_crtc_destroy(struct drm_crtc *crtc)
@@ -401,55 +463,20 @@ static bool qxl_crtc_mode_fixup(struct drm_crtc *crtc,
	return true;
}

static void qxl_monitors_config_set(struct qxl_device *qdev,
				    int index,
				    unsigned x, unsigned y,
				    unsigned width, unsigned height,
				    unsigned surf_id)
{
	DRM_DEBUG_KMS("%d:%dx%d+%d+%d\n", index, width, height, x, y);
	qdev->monitors_config->heads[index].x = x;
	qdev->monitors_config->heads[index].y = y;
	qdev->monitors_config->heads[index].width = width;
	qdev->monitors_config->heads[index].height = height;
	qdev->monitors_config->heads[index].surface_id = surf_id;

}

static void qxl_mode_set_nofb(struct drm_crtc *crtc)
{
	struct qxl_device *qdev = crtc->dev->dev_private;
	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
	struct drm_display_mode *mode = &crtc->mode;

	DRM_DEBUG("Mode set (%d,%d)\n",
		  mode->hdisplay, mode->vdisplay);

	qxl_monitors_config_set(qdev, qcrtc->index, 0, 0,
				mode->hdisplay,	mode->vdisplay, 0);

}

static void qxl_crtc_atomic_enable(struct drm_crtc *crtc,
				   struct drm_crtc_state *old_state)
{
	DRM_DEBUG("\n");
	qxl_crtc_update_monitors_config(crtc, "enable");
}

static void qxl_crtc_atomic_disable(struct drm_crtc *crtc,
				    struct drm_crtc_state *old_state)
{
	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
	struct qxl_device *qdev = crtc->dev->dev_private;

	qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0);

	qxl_send_monitors_config(qdev);
	qxl_crtc_update_monitors_config(crtc, "disable");
}

static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = {
	.mode_fixup = qxl_crtc_mode_fixup,
	.mode_set_nofb = qxl_mode_set_nofb,
	.atomic_flush = qxl_crtc_atomic_flush,
	.atomic_enable = qxl_crtc_atomic_enable,
	.atomic_disable = qxl_crtc_atomic_disable,
@@ -939,61 +966,8 @@ static void qxl_enc_prepare(struct drm_encoder *encoder)
	DRM_DEBUG("\n");
}

static void qxl_write_monitors_config_for_encoder(struct qxl_device *qdev,
		struct drm_encoder *encoder)
{
	int i;
	struct qxl_output *output = drm_encoder_to_qxl_output(encoder);
	struct qxl_head *head;
	struct drm_display_mode *mode;

	BUG_ON(!encoder);
	/* TODO: ugly, do better */
	i = output->index;
	if (!qdev->monitors_config ||
	    qdev->monitors_config->max_allowed <= i) {
		DRM_ERROR(
		"head number too large or missing monitors config: %p, %d",
		qdev->monitors_config,
		qdev->monitors_config ?
			qdev->monitors_config->max_allowed : -1);
		return;
	}
	if (!encoder->crtc) {
		DRM_ERROR("missing crtc on encoder %p\n", encoder);
		return;
	}
	if (i != 0)
		DRM_DEBUG("missing for multiple monitors: no head holes\n");
	head = &qdev->monitors_config->heads[i];
	head->id = i;
	if (encoder->crtc->enabled) {
		mode = &encoder->crtc->mode;
		head->width = mode->hdisplay;
		head->height = mode->vdisplay;
		head->x = encoder->crtc->x;
		head->y = encoder->crtc->y;
		if (qdev->monitors_config->count < i + 1)
			qdev->monitors_config->count = i + 1;
	} else {
		head->width = 0;
		head->height = 0;
		head->x = 0;
		head->y = 0;
	}
	DRM_DEBUG_KMS("setting head %d to +%d+%d %dx%d out of %d\n",
		      i, head->x, head->y, head->width, head->height, qdev->monitors_config->count);
	head->flags = 0;
	/* TODO - somewhere else to call this for multiple monitors
	 * (config_commit?) */
	qxl_send_monitors_config(qdev);
}

static void qxl_enc_commit(struct drm_encoder *encoder)
{
	struct qxl_device *qdev = encoder->dev->dev_private;

	qxl_write_monitors_config_for_encoder(qdev, encoder);
	DRM_DEBUG("\n");
}

@@ -1080,8 +1054,6 @@ static enum drm_connector_status qxl_conn_detect(
		     qxl_head_enabled(&qdev->client_monitors_config->heads[output->index]);

	DRM_DEBUG("#%d connected: %d\n", output->index, connected);
	if (!connected)
		qxl_monitors_config_set(qdev, output->index, 0, 0, 0, 0, 0);

	return connected ? connector_status_connected
			 : connector_status_disconnected;