drm-backend: move CRTC data from struct drm_output to new struct drm_crtc
There are no 'struct drm_output' for CRTCs that are not active. Also, CRTC data lives in 'struct drm_output'. This is causing us some trouble, as the DRM-backend needs to program those unnactive CRTCs to be off. If the DRM-backend had the reference for every CRTC (being active or not), it would make certain functions (e.g. drm_pending_state_apply_atomic()) more simple and efficient. Move CRTC data from 'struct drm_output' to 'struct drm_crtc', as this is the first step to allow the DRM-backend to have references for every CRTC. Also, add list of CRTCs to DRM-backend object. Now the DRM-backend is responsible for allocating/deallocating the CRTC objects. The outputs will only reference, init and fini the CRTCs in this list. Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
parent
ad41a88535
commit
b00d1a2efb
@ -275,6 +275,9 @@ struct drm_backend {
|
||||
|
||||
bool state_invalid;
|
||||
|
||||
/* drm_crtc::link */
|
||||
struct wl_list crtc_list;
|
||||
|
||||
/* CRTC IDs not used by any enabled output. */
|
||||
struct wl_array unused_crtcs;
|
||||
|
||||
@ -483,15 +486,25 @@ struct drm_head {
|
||||
uint32_t inherited_crtc_id; /**< Original CRTC assignment */
|
||||
};
|
||||
|
||||
struct drm_output {
|
||||
struct weston_output base;
|
||||
struct drm_crtc {
|
||||
/* drm_backend::crtc_list */
|
||||
struct wl_list link;
|
||||
struct drm_backend *backend;
|
||||
|
||||
/* The output driven by the CRTC */
|
||||
struct drm_output *output;
|
||||
|
||||
uint32_t crtc_id; /* object ID to pass to DRM functions */
|
||||
int pipe; /* index of CRTC in resource array / bitmasks */
|
||||
|
||||
/* Holds the properties for the CRTC */
|
||||
struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
|
||||
};
|
||||
|
||||
struct drm_output {
|
||||
struct weston_output base;
|
||||
struct drm_backend *backend;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
bool page_flip_pending;
|
||||
bool atomic_complete_pending;
|
||||
@ -573,8 +586,8 @@ drm_output_get_plane_type_name(struct drm_plane *p)
|
||||
}
|
||||
}
|
||||
|
||||
struct drm_output *
|
||||
drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id);
|
||||
struct drm_crtc *
|
||||
drm_crtc_find(struct drm_backend *b, uint32_t crtc_id);
|
||||
|
||||
struct drm_head *
|
||||
drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id);
|
||||
|
@ -38,6 +38,49 @@
|
||||
#include "drm-internal.h"
|
||||
#include "renderer-gl/gl-renderer.h"
|
||||
|
||||
#define POISON_PTR ((void *)8)
|
||||
|
||||
/**
|
||||
* Create a drm_crtc for virtual output
|
||||
*
|
||||
* It will leave its ID and pipe zeroed, as virtual outputs should not use real
|
||||
* CRTC's. Also, as this is a fake CRTC, it will not try to populate props.
|
||||
*/
|
||||
static struct drm_crtc *
|
||||
drm_virtual_crtc_create(struct drm_backend *b, struct drm_output *output)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
crtc = zalloc(sizeof(*crtc));
|
||||
if (!crtc)
|
||||
return NULL;
|
||||
|
||||
crtc->backend = b;
|
||||
crtc->output = output;
|
||||
|
||||
crtc->crtc_id = 0;
|
||||
crtc->pipe = 0;
|
||||
|
||||
/* Poisoning the pointers as CRTC's of virtual outputs should not be
|
||||
* added to the DRM-backend CRTC list. With this we can assure (in
|
||||
* function drm_virtual_crtc_destroy()) that this did not happen. */
|
||||
crtc->link.prev = POISON_PTR;
|
||||
crtc->link.next = POISON_PTR;
|
||||
|
||||
return crtc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy drm_crtc created by drm_virtual_crtc_create()
|
||||
*/
|
||||
static void
|
||||
drm_virtual_crtc_destroy(struct drm_crtc *crtc)
|
||||
{
|
||||
assert(crtc->link.prev == POISON_PTR);
|
||||
assert(crtc->link.next == POISON_PTR);
|
||||
free(crtc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a drm_plane for virtual output
|
||||
*
|
||||
@ -184,6 +227,7 @@ drm_virtual_output_deinit(struct weston_output *base)
|
||||
drm_output_fini_egl(output);
|
||||
|
||||
drm_virtual_plane_destroy(output->scanout_plane);
|
||||
drm_virtual_crtc_destroy(output->crtc);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -267,11 +311,18 @@ static struct weston_output *
|
||||
drm_virtual_output_create(struct weston_compositor *c, char *name)
|
||||
{
|
||||
struct drm_output *output;
|
||||
struct drm_backend *b = to_drm_backend(c);
|
||||
|
||||
output = zalloc(sizeof *output);
|
||||
if (!output)
|
||||
return NULL;
|
||||
|
||||
output->crtc = drm_virtual_crtc_create(b, output);
|
||||
if (!output->crtc) {
|
||||
free(output);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
output->virtual = true;
|
||||
output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING;
|
||||
|
||||
|
@ -208,17 +208,17 @@ drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
|
||||
|
||||
/* Check whether the plane can be used with this CRTC; possible_crtcs
|
||||
* is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
|
||||
return !!(plane->possible_crtcs & (1 << output->pipe));
|
||||
return !!(plane->possible_crtcs & (1 << output->crtc->pipe));
|
||||
}
|
||||
|
||||
struct drm_output *
|
||||
drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
|
||||
struct drm_crtc *
|
||||
drm_crtc_find(struct drm_backend *b, uint32_t crtc_id)
|
||||
{
|
||||
struct drm_output *output;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
wl_list_for_each(output, &b->compositor->output_list, base.link) {
|
||||
if (output->crtc_id == crtc_id)
|
||||
return output;
|
||||
wl_list_for_each(crtc, &b->crtc_list, link) {
|
||||
if (crtc->crtc_id == crtc_id)
|
||||
return crtc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -506,12 +506,12 @@ err:
|
||||
* using DRM_BLANK_HIGH_CRTC_MASK.
|
||||
*/
|
||||
static unsigned int
|
||||
drm_waitvblank_pipe(struct drm_output *output)
|
||||
drm_waitvblank_pipe(struct drm_crtc *crtc)
|
||||
{
|
||||
if (output->pipe > 1)
|
||||
return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
|
||||
if (crtc->pipe > 1)
|
||||
return (crtc->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
|
||||
DRM_VBLANK_HIGH_CRTC_MASK;
|
||||
else if (output->pipe > 0)
|
||||
else if (crtc->pipe > 0)
|
||||
return DRM_VBLANK_SECONDARY;
|
||||
else
|
||||
return 0;
|
||||
@ -552,7 +552,7 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
|
||||
assert(scanout_plane->state_cur->output == output);
|
||||
|
||||
/* Try to get current msc and timestamp via instant query */
|
||||
vbl.request.type |= drm_waitvblank_pipe(output);
|
||||
vbl.request.type |= drm_waitvblank_pipe(output->crtc);
|
||||
ret = drmWaitVBlank(backend->drm.fd, &vbl);
|
||||
|
||||
/* Error ret or zero timestamp means failure to get valid timestamp */
|
||||
@ -818,7 +818,7 @@ drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
|
||||
drmModeFreeObjectProperties(props);
|
||||
}
|
||||
else {
|
||||
plane->possible_crtcs = (1 << output->pipe);
|
||||
plane->possible_crtcs = (1 << output->crtc->pipe);
|
||||
plane->plane_id = 0;
|
||||
plane->count_formats = 1;
|
||||
plane->formats[0].format = format;
|
||||
@ -929,7 +929,7 @@ drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
|
||||
if (found_elsewhere)
|
||||
continue;
|
||||
|
||||
plane->possible_crtcs = (1 << output->pipe);
|
||||
plane->possible_crtcs = (1 << output->crtc->pipe);
|
||||
return plane;
|
||||
}
|
||||
|
||||
@ -1435,8 +1435,8 @@ drm_output_init_gamma_size(struct drm_output *output)
|
||||
drmModeCrtc *crtc;
|
||||
|
||||
assert(output->base.compositor);
|
||||
assert(output->crtc_id != 0);
|
||||
crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
|
||||
assert(output->crtc);
|
||||
crtc = drmModeGetCrtc(backend->drm.fd, output->crtc->crtc_id);
|
||||
if (!crtc)
|
||||
return -1;
|
||||
|
||||
@ -1467,39 +1467,25 @@ drm_head_get_possible_crtcs_mask(struct drm_head *head)
|
||||
return possible_crtcs;
|
||||
}
|
||||
|
||||
static int
|
||||
drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < resources->count_crtcs; i++) {
|
||||
if (resources->crtcs[i] == crtc_id)
|
||||
return i;
|
||||
}
|
||||
|
||||
assert(0 && "unknown crtc id");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Pick a CRTC that might be able to drive all attached connectors
|
||||
*
|
||||
* @param output The output whose attached heads to include.
|
||||
* @param resources The DRM KMS resources.
|
||||
* @return CRTC index, or -1 on failure or not found.
|
||||
* @return CRTC object to pick, or NULL on failure or not found.
|
||||
*/
|
||||
static int
|
||||
drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
|
||||
static struct drm_crtc *
|
||||
drm_output_pick_crtc(struct drm_output *output)
|
||||
{
|
||||
struct drm_backend *backend;
|
||||
struct weston_head *base;
|
||||
struct drm_head *head;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc *best_crtc = NULL;
|
||||
struct drm_crtc *fallback_crtc = NULL;
|
||||
struct drm_crtc *existing_crtc[32];
|
||||
uint32_t possible_crtcs = 0xffffffff;
|
||||
int existing_crtc[32];
|
||||
unsigned j, n = 0;
|
||||
unsigned n = 0;
|
||||
uint32_t crtc_id;
|
||||
int best_crtc_index = -1;
|
||||
int fallback_crtc_index = -1;
|
||||
int i;
|
||||
unsigned int i;
|
||||
bool match;
|
||||
|
||||
backend = to_drm_backend(output->base.compositor);
|
||||
@ -1515,30 +1501,28 @@ drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
|
||||
|
||||
crtc_id = head->inherited_crtc_id;
|
||||
if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
|
||||
existing_crtc[n++] = drm_crtc_get_index(resources,
|
||||
crtc_id);
|
||||
existing_crtc[n++] = drm_crtc_find(backend, crtc_id);
|
||||
}
|
||||
|
||||
/* Find a crtc that could drive each connector individually at least,
|
||||
* and prefer existing routings. */
|
||||
for (i = 0; i < resources->count_crtcs; i++) {
|
||||
crtc_id = resources->crtcs[i];
|
||||
wl_list_for_each(crtc, &backend->crtc_list, link) {
|
||||
|
||||
/* Could the crtc not drive each connector? */
|
||||
if (!(possible_crtcs & (1 << i)))
|
||||
if (!(possible_crtcs & (1 << crtc->pipe)))
|
||||
continue;
|
||||
|
||||
/* Is the crtc already in use? */
|
||||
if (drm_output_find_by_crtc(backend, crtc_id))
|
||||
if (crtc->output)
|
||||
continue;
|
||||
|
||||
/* Try to preserve the existing CRTC -> connector routing;
|
||||
* it makes initialisation faster, and also since we have a
|
||||
* very dumb picking algorithm, may preserve a better
|
||||
* choice. */
|
||||
for (j = 0; j < n; j++) {
|
||||
if (existing_crtc[j] == i)
|
||||
return i;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (existing_crtc[i] == crtc)
|
||||
return crtc;
|
||||
}
|
||||
|
||||
/* Check if any other head had existing routing to this CRTC.
|
||||
@ -1555,22 +1539,22 @@ drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
|
||||
if (weston_head_is_enabled(&head->base))
|
||||
continue;
|
||||
|
||||
if (head->inherited_crtc_id == crtc_id) {
|
||||
if (head->inherited_crtc_id == crtc->crtc_id) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
best_crtc_index = i;
|
||||
best_crtc = crtc;
|
||||
|
||||
fallback_crtc_index = i;
|
||||
fallback_crtc = crtc;
|
||||
}
|
||||
|
||||
if (best_crtc_index != -1)
|
||||
return best_crtc_index;
|
||||
if (best_crtc)
|
||||
return best_crtc;
|
||||
|
||||
if (fallback_crtc_index != -1)
|
||||
return fallback_crtc_index;
|
||||
if (fallback_crtc)
|
||||
return fallback_crtc;
|
||||
|
||||
/* Likely possible_crtcs was empty due to asking for clones,
|
||||
* but since the DRM documentation says the kernel lies, let's
|
||||
@ -1578,72 +1562,142 @@ drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
|
||||
* be sure if something doesn't work. */
|
||||
|
||||
/* First pick any existing assignment. */
|
||||
for (j = 0; j < n; j++) {
|
||||
crtc_id = resources->crtcs[existing_crtc[j]];
|
||||
if (!drm_output_find_by_crtc(backend, crtc_id))
|
||||
return existing_crtc[j];
|
||||
for (i = 0; i < n; i++) {
|
||||
crtc = existing_crtc[i];
|
||||
if (!crtc->output)
|
||||
return crtc;
|
||||
}
|
||||
|
||||
/* Otherwise pick any available crtc. */
|
||||
for (i = 0; i < resources->count_crtcs; i++) {
|
||||
crtc_id = resources->crtcs[i];
|
||||
|
||||
if (!drm_output_find_by_crtc(backend, crtc_id))
|
||||
return i;
|
||||
wl_list_for_each(crtc, &backend->crtc_list, link) {
|
||||
if (!crtc->output)
|
||||
return crtc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Create an "empty" drm_crtc. It will only set its ID, pipe and props. After
|
||||
* all, it adds the object to the DRM-backend CRTC list.
|
||||
*/
|
||||
static struct drm_crtc *
|
||||
drm_crtc_create(struct drm_backend *b, uint32_t crtc_id, uint32_t pipe)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
drmModeObjectPropertiesPtr props;
|
||||
|
||||
props = drmModeObjectGetProperties(b->drm.fd, crtc_id,
|
||||
DRM_MODE_OBJECT_CRTC);
|
||||
if (!props) {
|
||||
weston_log("failed to get CRTC properties\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
crtc = zalloc(sizeof(*crtc));
|
||||
if (!crtc)
|
||||
goto ret;
|
||||
|
||||
drm_property_info_populate(b, crtc_props, crtc->props_crtc,
|
||||
WDRM_CRTC__COUNT, props);
|
||||
crtc->backend = b;
|
||||
crtc->crtc_id = crtc_id;
|
||||
crtc->pipe = pipe;
|
||||
crtc->output = NULL;
|
||||
|
||||
/* Add it to the last position of the DRM-backend CRTC list */
|
||||
wl_list_insert(b->crtc_list.prev, &crtc->link);
|
||||
|
||||
ret:
|
||||
drmModeFreeObjectProperties(props);
|
||||
return crtc;
|
||||
}
|
||||
|
||||
/** Destroy a drm_crtc object that was created with drm_crtc_create(). It will
|
||||
* also remove it from the DRM-backend CRTC list.
|
||||
*/
|
||||
static void
|
||||
drm_crtc_destroy(struct drm_crtc *crtc)
|
||||
{
|
||||
/* TODO: address the issue below to be able to remove the comment
|
||||
* from the assert.
|
||||
*
|
||||
* https://gitlab.freedesktop.org/wayland/weston/-/issues/421
|
||||
*/
|
||||
|
||||
//assert(!crtc->output);
|
||||
|
||||
wl_list_remove(&crtc->link);
|
||||
drm_property_info_free(crtc->props_crtc, WDRM_CRTC__COUNT);
|
||||
free(crtc);
|
||||
}
|
||||
|
||||
/** Find all CRTCs of the fd and create drm_crtc objects for them.
|
||||
*
|
||||
* The CRTCs are saved in a list of the drm_backend and will keep there until
|
||||
* the fd gets closed.
|
||||
*
|
||||
* @param b The DRM-backend structure.
|
||||
* @return 0 on success (at least one CRTC in the list), -1 on failure.
|
||||
*/
|
||||
static int
|
||||
drm_backend_create_crtc_list(struct drm_backend *b)
|
||||
{
|
||||
drmModeRes *resources;
|
||||
struct drm_crtc *crtc, *crtc_tmp;
|
||||
int i;
|
||||
|
||||
resources = drmModeGetResources(b->drm.fd);
|
||||
if (!resources) {
|
||||
weston_log("drmModeGetResources failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Iterate through all CRTCs */
|
||||
for (i = 0; i < resources->count_crtcs; i++) {
|
||||
|
||||
/* Let's create an object for the CRTC and add it to the list */
|
||||
crtc = drm_crtc_create(b, resources->crtcs[i], i);
|
||||
if (!crtc)
|
||||
goto err;
|
||||
}
|
||||
|
||||
drmModeFreeResources(resources);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link)
|
||||
drm_crtc_destroy(crtc);
|
||||
drmModeFreeResources(resources);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Allocate a CRTC for the output
|
||||
*
|
||||
* @param output The output with no allocated CRTC.
|
||||
* @param resources DRM KMS resources.
|
||||
* @return 0 on success, -1 on failure.
|
||||
*
|
||||
* Finds a free CRTC that might drive the attached connectors, reserves the CRTC
|
||||
* for the output, and loads the CRTC properties.
|
||||
*
|
||||
* Populates the cursor and scanout planes.
|
||||
/** Pick a CRTC and reserve it for the output.
|
||||
*
|
||||
* On failure, the output remains without a CRTC.
|
||||
*
|
||||
* @param output The output with no CRTC associated.
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
static int
|
||||
drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
|
||||
drm_output_attach_crtc(struct drm_output *output)
|
||||
{
|
||||
struct drm_backend *b = to_drm_backend(output->base.compositor);
|
||||
drmModeObjectPropertiesPtr props;
|
||||
int i;
|
||||
|
||||
assert(output->crtc_id == 0);
|
||||
|
||||
i = drm_output_pick_crtc(output, resources);
|
||||
if (i < 0) {
|
||||
output->crtc = drm_output_pick_crtc(output);
|
||||
if (!output->crtc) {
|
||||
weston_log("Output '%s': No available CRTCs.\n",
|
||||
output->base.name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
output->crtc_id = resources->crtcs[i];
|
||||
output->pipe = i;
|
||||
|
||||
props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
|
||||
DRM_MODE_OBJECT_CRTC);
|
||||
if (!props) {
|
||||
weston_log("failed to get CRTC properties\n");
|
||||
goto err_crtc;
|
||||
}
|
||||
drm_property_info_populate(b, crtc_props, output->props_crtc,
|
||||
WDRM_CRTC__COUNT, props);
|
||||
drmModeFreeObjectProperties(props);
|
||||
|
||||
output->scanout_plane =
|
||||
drm_output_find_special_plane(b, output,
|
||||
WDRM_PLANE_TYPE_PRIMARY);
|
||||
if (!output->scanout_plane) {
|
||||
weston_log("Failed to find primary plane for output %s\n",
|
||||
output->base.name);
|
||||
goto err_crtc;
|
||||
output->crtc = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Without universal planes, we can't discover which formats are
|
||||
@ -1658,27 +1712,24 @@ drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
|
||||
drm_output_find_special_plane(b, output,
|
||||
WDRM_PLANE_TYPE_CURSOR);
|
||||
|
||||
wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
|
||||
/* Reserve the CRTC for the output */
|
||||
output->crtc->output = output;
|
||||
wl_array_remove_uint32(&b->unused_crtcs, output->crtc->crtc_id);
|
||||
|
||||
return 0;
|
||||
|
||||
err_crtc:
|
||||
output->crtc_id = 0;
|
||||
output->pipe = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Free the CRTC from the output
|
||||
/** Release reservation of the CRTC.
|
||||
*
|
||||
* @param output The output whose CRTC to deallocate.
|
||||
* Make the CRTC free to be reserved and used by another output.
|
||||
*
|
||||
* The CRTC reserved for the given output becomes free to use again.
|
||||
* @param output The output that will release its CRTC.
|
||||
*/
|
||||
static void
|
||||
drm_output_fini_crtc(struct drm_output *output)
|
||||
drm_output_detach_crtc(struct drm_output *output)
|
||||
{
|
||||
struct drm_backend *b = to_drm_backend(output->base.compositor);
|
||||
struct drm_crtc *crtc = output->crtc;
|
||||
uint32_t *unused;
|
||||
|
||||
/* If the compositor is already shutting down, the planes have already
|
||||
@ -1706,17 +1757,15 @@ drm_output_fini_crtc(struct drm_output *output)
|
||||
}
|
||||
}
|
||||
|
||||
drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
|
||||
|
||||
assert(output->crtc_id != 0);
|
||||
|
||||
unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
|
||||
*unused = output->crtc_id;
|
||||
*unused = crtc->crtc_id;
|
||||
|
||||
/* Force resetting unused CRTCs */
|
||||
b->state_invalid = true;
|
||||
|
||||
output->crtc_id = 0;
|
||||
crtc->output = NULL;
|
||||
output->crtc = NULL;
|
||||
|
||||
output->cursor_plane = NULL;
|
||||
output->scanout_plane = NULL;
|
||||
}
|
||||
@ -1726,18 +1775,11 @@ drm_output_enable(struct weston_output *base)
|
||||
{
|
||||
struct drm_output *output = to_drm_output(base);
|
||||
struct drm_backend *b = to_drm_backend(base->compositor);
|
||||
drmModeRes *resources;
|
||||
int ret;
|
||||
|
||||
assert(!output->virtual);
|
||||
|
||||
resources = drmModeGetResources(b->drm.fd);
|
||||
if (!resources) {
|
||||
weston_log("drmModeGetResources failed\n");
|
||||
return -1;
|
||||
}
|
||||
ret = drm_output_init_crtc(output, resources);
|
||||
drmModeFreeResources(resources);
|
||||
ret = drm_output_attach_crtc(output);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
@ -1778,14 +1820,13 @@ drm_output_enable(struct weston_output *base)
|
||||
&b->compositor->primary_plane);
|
||||
|
||||
weston_log("Output %s (crtc %d) video modes:\n",
|
||||
output->base.name, output->crtc_id);
|
||||
output->base.name, output->crtc->crtc_id);
|
||||
drm_output_print_modes(output);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
drm_output_fini_crtc(output);
|
||||
|
||||
drm_output_detach_crtc(output);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1812,11 +1853,11 @@ drm_output_deinit(struct weston_output *base)
|
||||
wl_list_remove(&output->cursor_plane->base.link);
|
||||
wl_list_init(&output->cursor_plane->base.link);
|
||||
/* Turn off hardware cursor */
|
||||
drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
|
||||
drmModeSetCursor(b->drm.fd, output->crtc->crtc_id, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
drm_output_fini_crtc(output);
|
||||
drm_output_detach_crtc(output);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1891,10 +1932,14 @@ drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
|
||||
wl_array_init(&b->unused_crtcs);
|
||||
|
||||
for (i = 0; i < resources->count_crtcs; i++) {
|
||||
struct drm_output *output;
|
||||
struct drm_output *output = NULL;
|
||||
struct drm_crtc *crtc;
|
||||
uint32_t *crtc_id;
|
||||
|
||||
output = drm_output_find_by_crtc(b, resources->crtcs[i]);
|
||||
crtc = drm_crtc_find(b, resources->crtcs[i]);
|
||||
if (crtc)
|
||||
output = crtc->output;
|
||||
|
||||
if (output && output->base.enabled)
|
||||
continue;
|
||||
|
||||
@ -2177,6 +2222,8 @@ drm_output_create(struct weston_compositor *compositor, const char *name)
|
||||
return NULL;
|
||||
|
||||
output->backend = b;
|
||||
output->crtc = NULL;
|
||||
|
||||
#ifdef BUILD_DRM_GBM
|
||||
output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
|
||||
#endif
|
||||
@ -2410,6 +2457,7 @@ drm_destroy(struct weston_compositor *ec)
|
||||
{
|
||||
struct drm_backend *b = to_drm_backend(ec);
|
||||
struct weston_head *base, *next;
|
||||
struct drm_crtc *crtc, *crtc_tmp;
|
||||
|
||||
udev_input_destroy(&b->input);
|
||||
|
||||
@ -2424,6 +2472,9 @@ drm_destroy(struct weston_compositor *ec)
|
||||
b->debug = NULL;
|
||||
weston_compositor_shutdown(ec);
|
||||
|
||||
wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link)
|
||||
drm_crtc_destroy(crtc);
|
||||
|
||||
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
|
||||
drm_head_destroy(to_drm_head(base));
|
||||
|
||||
@ -2451,6 +2502,7 @@ session_notify(struct wl_listener *listener, void *data)
|
||||
struct drm_backend *b = to_drm_backend(compositor);
|
||||
struct drm_plane *plane;
|
||||
struct drm_output *output;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
if (compositor->session_active) {
|
||||
weston_log("activating session\n");
|
||||
@ -2473,23 +2525,22 @@ session_notify(struct wl_listener *listener, void *data)
|
||||
* pending frame callbacks. */
|
||||
|
||||
wl_list_for_each(output, &compositor->output_list, base.link) {
|
||||
crtc = output->crtc;
|
||||
output->base.repaint_needed = false;
|
||||
if (output->cursor_plane)
|
||||
drmModeSetCursor(b->drm.fd, output->crtc_id,
|
||||
drmModeSetCursor(b->drm.fd, crtc->crtc_id,
|
||||
0, 0, 0);
|
||||
}
|
||||
|
||||
output = container_of(compositor->output_list.next,
|
||||
struct drm_output, base.link);
|
||||
crtc = output->crtc;
|
||||
|
||||
wl_list_for_each(plane, &b->plane_list, link) {
|
||||
if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
|
||||
continue;
|
||||
|
||||
drmModeSetPlane(b->drm.fd,
|
||||
plane->plane_id,
|
||||
output->crtc_id, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0);
|
||||
drmModeSetPlane(b->drm.fd, plane->plane_id, crtc->crtc_id,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2923,6 +2974,12 @@ drm_backend_create(struct weston_compositor *compositor,
|
||||
|
||||
weston_setup_vt_switch_bindings(compositor);
|
||||
|
||||
wl_list_init(&b->crtc_list);
|
||||
if (drm_backend_create_crtc_list(b) == -1) {
|
||||
weston_log("Failed to create CRTC list for DRM-backend\n");
|
||||
goto err_udev_dev;
|
||||
}
|
||||
|
||||
wl_list_init(&b->plane_list);
|
||||
create_sprites(b);
|
||||
|
||||
|
@ -533,7 +533,7 @@ drm_output_set_gamma(struct weston_output *output_base,
|
||||
return;
|
||||
|
||||
rc = drmModeCrtcSetGamma(backend->drm.fd,
|
||||
output->crtc_id,
|
||||
output->crtc->crtc_id,
|
||||
size, r, g, b);
|
||||
if (rc)
|
||||
weston_log("set gamma failed: %s\n", strerror(errno));
|
||||
@ -568,7 +568,8 @@ drm_output_assign_state(struct drm_output_state *state,
|
||||
output->state_cur = state;
|
||||
|
||||
if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
|
||||
drm_debug(b, "\t[CRTC:%u] setting pending flip\n", output->crtc_id);
|
||||
drm_debug(b, "\t[CRTC:%u] setting pending flip\n",
|
||||
output->crtc->crtc_id);
|
||||
output->atomic_complete_pending = true;
|
||||
}
|
||||
|
||||
@ -608,6 +609,7 @@ drm_output_set_cursor(struct drm_output_state *output_state)
|
||||
{
|
||||
struct drm_output *output = output_state->output;
|
||||
struct drm_backend *b = to_drm_backend(output->base.compositor);
|
||||
struct drm_crtc *crtc = output->crtc;
|
||||
struct drm_plane *plane = output->cursor_plane;
|
||||
struct drm_plane_state *state;
|
||||
uint32_t handle;
|
||||
@ -622,7 +624,7 @@ drm_output_set_cursor(struct drm_output_state *output_state)
|
||||
if (!state->fb) {
|
||||
pixman_region32_fini(&plane->base.damage);
|
||||
pixman_region32_init(&plane->base.damage);
|
||||
drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
|
||||
drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -631,7 +633,7 @@ drm_output_set_cursor(struct drm_output_state *output_state)
|
||||
|
||||
handle = output->gbm_cursor_handle[output->current_cursor];
|
||||
if (plane->state_cur->fb != state->fb) {
|
||||
if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
|
||||
if (drmModeSetCursor(b->drm.fd, crtc->crtc_id, handle,
|
||||
b->cursor_width, b->cursor_height)) {
|
||||
weston_log("failed to set cursor: %s\n",
|
||||
strerror(errno));
|
||||
@ -642,7 +644,7 @@ drm_output_set_cursor(struct drm_output_state *output_state)
|
||||
pixman_region32_fini(&plane->base.damage);
|
||||
pixman_region32_init(&plane->base.damage);
|
||||
|
||||
if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
|
||||
if (drmModeMoveCursor(b->drm.fd, crtc->crtc_id,
|
||||
state->dest_x, state->dest_y)) {
|
||||
weston_log("failed to move cursor: %s\n", strerror(errno));
|
||||
goto err;
|
||||
@ -652,7 +654,7 @@ drm_output_set_cursor(struct drm_output_state *output_state)
|
||||
|
||||
err:
|
||||
b->cursors_are_broken = true;
|
||||
drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
|
||||
drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -661,6 +663,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
|
||||
struct drm_output *output = state->output;
|
||||
struct drm_backend *backend = to_drm_backend(output->base.compositor);
|
||||
struct drm_plane *scanout_plane = output->scanout_plane;
|
||||
struct drm_crtc *crtc = output->crtc;
|
||||
struct drm_property_info *dpms_prop;
|
||||
struct drm_plane_state *scanout_state;
|
||||
struct drm_mode *mode;
|
||||
@ -690,14 +693,14 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
|
||||
|
||||
if (state->dpms != WESTON_DPMS_ON) {
|
||||
if (output->cursor_plane) {
|
||||
ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
|
||||
ret = drmModeSetCursor(backend->drm.fd, crtc->crtc_id,
|
||||
0, 0, 0);
|
||||
if (ret)
|
||||
weston_log("drmModeSetCursor failed disable: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
|
||||
ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id, 0, 0, 0,
|
||||
NULL, 0, NULL);
|
||||
if (ret)
|
||||
weston_log("drmModeSetCrtc failed disabling: %s\n",
|
||||
@ -736,7 +739,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
|
||||
scanout_plane->state_cur->fb->strides[0] !=
|
||||
scanout_state->fb->strides[0]) {
|
||||
|
||||
ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
|
||||
ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id,
|
||||
scanout_state->fb->fb_id,
|
||||
0, 0,
|
||||
connectors, n_conn,
|
||||
@ -749,10 +752,10 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
|
||||
|
||||
pinfo = scanout_state->fb->format;
|
||||
drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
|
||||
output->crtc_id, scanout_state->plane->plane_id,
|
||||
crtc->crtc_id, scanout_state->plane->plane_id,
|
||||
pinfo ? pinfo->drm_format_name : "UNKNOWN");
|
||||
|
||||
if (drmModePageFlip(backend->drm.fd, output->crtc_id,
|
||||
if (drmModePageFlip(backend->drm.fd, crtc->crtc_id,
|
||||
scanout_state->fb->fb_id,
|
||||
DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
|
||||
weston_log("queueing pageflip failed: %s\n", strerror(errno));
|
||||
@ -795,19 +798,19 @@ err:
|
||||
}
|
||||
|
||||
static int
|
||||
crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
|
||||
crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc,
|
||||
enum wdrm_crtc_property prop, uint64_t val)
|
||||
{
|
||||
struct drm_property_info *info = &output->props_crtc[prop];
|
||||
struct drm_property_info *info = &crtc->props_crtc[prop];
|
||||
int ret;
|
||||
|
||||
if (info->prop_id == 0)
|
||||
return -1;
|
||||
|
||||
ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
|
||||
ret = drmModeAtomicAddProperty(req, crtc->crtc_id, info->prop_id,
|
||||
val);
|
||||
drm_debug(output->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
|
||||
(unsigned long) output->crtc_id,
|
||||
drm_debug(crtc->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
|
||||
(unsigned long) crtc->crtc_id,
|
||||
(unsigned long) info->prop_id, info->name,
|
||||
(unsigned long long) val, (unsigned long long) val);
|
||||
return (ret <= 0) ? -1 : 0;
|
||||
@ -939,6 +942,7 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
|
||||
{
|
||||
struct drm_output *output = state->output;
|
||||
struct drm_backend *b = to_drm_backend(output->base.compositor);
|
||||
struct drm_crtc *crtc = output->crtc;
|
||||
struct drm_plane_state *plane_state;
|
||||
struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
|
||||
struct drm_head *head;
|
||||
@ -958,19 +962,19 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
|
||||
ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID,
|
||||
current_mode->blob_id);
|
||||
ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
|
||||
ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 1);
|
||||
|
||||
/* No need for the DPMS property, since it is implicit in
|
||||
* routing and CRTC activity. */
|
||||
wl_list_for_each(head, &output->base.head_list, base.output_link) {
|
||||
ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
|
||||
output->crtc_id);
|
||||
crtc->crtc_id);
|
||||
}
|
||||
} else {
|
||||
ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
|
||||
ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
|
||||
ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0);
|
||||
ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0);
|
||||
|
||||
/* No need for the DPMS property, since it is implicit in
|
||||
* routing and CRTC activity. */
|
||||
@ -993,7 +997,7 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
|
||||
ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
|
||||
plane_state->fb ? plane_state->fb->fb_id : 0);
|
||||
ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
|
||||
plane_state->fb ? output->crtc_id : 0);
|
||||
plane_state->fb ? crtc->crtc_id : 0);
|
||||
ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
|
||||
plane_state->src_x);
|
||||
ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
|
||||
@ -1391,11 +1395,17 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
|
||||
unsigned int usec, unsigned int crtc_id, void *data)
|
||||
{
|
||||
struct drm_backend *b = data;
|
||||
struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_output *output;
|
||||
uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
|
||||
WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
|
||||
WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
|
||||
|
||||
crtc = drm_crtc_find(b, crtc_id);
|
||||
assert(crtc);
|
||||
|
||||
output = crtc->output;
|
||||
|
||||
/* During the initial modeset, we can disable CRTCs which we don't
|
||||
* actually handle during normal operation; this will give us events
|
||||
* for unknown outputs. Ignore them. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user