compositor-drm: Add drm-backend log debug scope
Add a 'drm-debug' scope which prints verbose information about the DRM backend's repaint cycle, including the decision tree on how views are assigned (or not) to planes. Signed-off-by: Daniel Stone <daniels@collabora.com>
This commit is contained in:
+258
-27
@@ -51,6 +51,7 @@
|
|||||||
|
|
||||||
#include "compositor.h"
|
#include "compositor.h"
|
||||||
#include "compositor-drm.h"
|
#include "compositor-drm.h"
|
||||||
|
#include "weston-debug.h"
|
||||||
#include "shared/helpers.h"
|
#include "shared/helpers.h"
|
||||||
#include "shared/timespec-util.h"
|
#include "shared/timespec-util.h"
|
||||||
#include "gl-renderer.h"
|
#include "gl-renderer.h"
|
||||||
@@ -73,6 +74,42 @@
|
|||||||
#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
|
#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A small wrapper to print information into the 'drm-backend' debug scope.
|
||||||
|
*
|
||||||
|
* The following conventions are used to print variables:
|
||||||
|
*
|
||||||
|
* - fixed uint32_t values, including Weston object IDs such as weston_output
|
||||||
|
* IDs, DRM object IDs such as CRTCs or properties, and GBM/DRM formats:
|
||||||
|
* "%lu (0x%lx)" (unsigned long) value, (unsigned long) value
|
||||||
|
*
|
||||||
|
* - fixed uint64_t values, such as DRM property values (including object IDs
|
||||||
|
* when used as a value):
|
||||||
|
* "%llu (0x%llx)" (unsigned long long) value, (unsigned long long) value
|
||||||
|
*
|
||||||
|
* - non-fixed-width signed int:
|
||||||
|
* "%d" value
|
||||||
|
*
|
||||||
|
* - non-fixed-width unsigned int:
|
||||||
|
* "%u (0x%x)" value, value
|
||||||
|
*
|
||||||
|
* - non-fixed-width unsigned long:
|
||||||
|
* "%lu (0x%lx)" value, value
|
||||||
|
*
|
||||||
|
* Either the integer or hexadecimal forms may be omitted if it is known that
|
||||||
|
* one representation is not useful (e.g. width/height in hex are rarely what
|
||||||
|
* you want).
|
||||||
|
*
|
||||||
|
* This is to avoid implicit widening or narrowing when we use fixed-size
|
||||||
|
* types: uint32_t can be resolved by either unsigned int or unsigned long
|
||||||
|
* on a 32-bit system but only unsigned int on a 64-bit system, with uint64_t
|
||||||
|
* being unsigned long long on a 32-bit system and unsigned long on a 64-bit
|
||||||
|
* system. To avoid confusing side effects, we explicitly cast to the widest
|
||||||
|
* possible type and use a matching format specifier.
|
||||||
|
*/
|
||||||
|
#define drm_debug(b, ...) \
|
||||||
|
weston_debug_scope_printf((b)->debug, __VA_ARGS__)
|
||||||
|
|
||||||
#define MAX_CLONED_CONNECTORS 4
|
#define MAX_CLONED_CONNECTORS 4
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -302,6 +339,8 @@ struct drm_backend {
|
|||||||
bool shutting_down;
|
bool shutting_down;
|
||||||
|
|
||||||
bool aspect_ratio_supported;
|
bool aspect_ratio_supported;
|
||||||
|
|
||||||
|
struct weston_debug_scope *debug;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drm_mode {
|
struct drm_mode {
|
||||||
@@ -2357,6 +2396,10 @@ crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
|
|||||||
|
|
||||||
ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
|
ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
|
||||||
val);
|
val);
|
||||||
|
drm_debug(output->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
|
||||||
|
(unsigned long) output->crtc_id,
|
||||||
|
(unsigned long) info->prop_id, info->name,
|
||||||
|
(unsigned long long) val, (unsigned long long) val);
|
||||||
return (ret <= 0) ? -1 : 0;
|
return (ret <= 0) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2372,6 +2415,10 @@ connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
|
|||||||
|
|
||||||
ret = drmModeAtomicAddProperty(req, head->connector_id,
|
ret = drmModeAtomicAddProperty(req, head->connector_id,
|
||||||
info->prop_id, val);
|
info->prop_id, val);
|
||||||
|
drm_debug(head->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
|
||||||
|
(unsigned long) head->connector_id,
|
||||||
|
(unsigned long) info->prop_id, info->name,
|
||||||
|
(unsigned long long) val, (unsigned long long) val);
|
||||||
return (ret <= 0) ? -1 : 0;
|
return (ret <= 0) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2387,6 +2434,10 @@ plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
|
|||||||
|
|
||||||
ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
|
ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
|
||||||
val);
|
val);
|
||||||
|
drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
|
||||||
|
(unsigned long) plane->plane_id,
|
||||||
|
(unsigned long) info->prop_id, info->name,
|
||||||
|
(unsigned long long) val, (unsigned long long) val);
|
||||||
return (ret <= 0) ? -1 : 0;
|
return (ret <= 0) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2405,6 +2456,9 @@ drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
weston_log("failed to create mode property blob: %m\n");
|
weston_log("failed to create mode property blob: %m\n");
|
||||||
|
|
||||||
|
drm_debug(backend, "\t\t\t[atomic] created new mode blob %lu for %s",
|
||||||
|
(unsigned long) mode->blob_id, mode->mode_info.name);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2414,17 +2468,23 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
|
|||||||
uint32_t *flags)
|
uint32_t *flags)
|
||||||
{
|
{
|
||||||
struct drm_output *output = state->output;
|
struct drm_output *output = state->output;
|
||||||
struct drm_backend *backend = to_drm_backend(output->base.compositor);
|
struct drm_backend *b = to_drm_backend(output->base.compositor);
|
||||||
struct drm_plane_state *plane_state;
|
struct drm_plane_state *plane_state;
|
||||||
struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
|
struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
|
||||||
struct drm_head *head;
|
struct drm_head *head;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (state->dpms != output->state_cur->dpms)
|
drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
|
||||||
|
(*flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "testing" : "applying",
|
||||||
|
(unsigned long) output->base.id, output->base.name);
|
||||||
|
|
||||||
|
if (state->dpms != output->state_cur->dpms) {
|
||||||
|
drm_debug(b, "\t\t\t[atomic] DPMS state differs, modeset OK\n");
|
||||||
*flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
*flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||||
|
}
|
||||||
|
|
||||||
if (state->dpms == WESTON_DPMS_ON) {
|
if (state->dpms == WESTON_DPMS_ON) {
|
||||||
ret = drm_mode_ensure_blob(backend, current_mode);
|
ret = drm_mode_ensure_blob(b, current_mode);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -2522,6 +2582,9 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
|
|||||||
uint32_t *unused;
|
uint32_t *unused;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
drm_debug(b, "\t\t[atomic] previous state invalid; "
|
||||||
|
"starting with fresh state\n");
|
||||||
|
|
||||||
/* If we need to reset all our state (e.g. because we've
|
/* If we need to reset all our state (e.g. because we've
|
||||||
* just started, or just been VT-switched in), explicitly
|
* just started, or just been VT-switched in), explicitly
|
||||||
* disable all the CRTCs and connectors we aren't using. */
|
* disable all the CRTCs and connectors we aren't using. */
|
||||||
@@ -2534,9 +2597,16 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
|
|||||||
|
|
||||||
head = to_drm_head(head_base);
|
head = to_drm_head(head_base);
|
||||||
|
|
||||||
|
drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
|
||||||
|
head_base->name);
|
||||||
|
|
||||||
info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
|
info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
|
||||||
err = drmModeAtomicAddProperty(req, head->connector_id,
|
err = drmModeAtomicAddProperty(req, head->connector_id,
|
||||||
info->prop_id, 0);
|
info->prop_id, 0);
|
||||||
|
drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
|
||||||
|
(unsigned long) head->connector_id,
|
||||||
|
(unsigned long) info->prop_id,
|
||||||
|
info->name);
|
||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
@@ -2573,12 +2643,21 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drm_debug(b, "\t\t[atomic] disabling unused CRTC %lu\n",
|
||||||
|
(unsigned long) *unused);
|
||||||
|
|
||||||
|
drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> 0\n",
|
||||||
|
(unsigned long) *unused,
|
||||||
|
(unsigned long) info->prop_id, info->name);
|
||||||
err = drmModeAtomicAddProperty(req, *unused,
|
err = drmModeAtomicAddProperty(req, *unused,
|
||||||
info->prop_id, 0);
|
info->prop_id, 0);
|
||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
||||||
info = &infos[WDRM_CRTC_MODE_ID];
|
info = &infos[WDRM_CRTC_MODE_ID];
|
||||||
|
drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> 0\n",
|
||||||
|
(unsigned long) *unused,
|
||||||
|
(unsigned long) info->prop_id, info->name);
|
||||||
err = drmModeAtomicAddProperty(req, *unused,
|
err = drmModeAtomicAddProperty(req, *unused,
|
||||||
info->prop_id, 0);
|
info->prop_id, 0);
|
||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
@@ -2590,6 +2669,8 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
|
|||||||
/* Disable all the planes; planes which are being used will
|
/* Disable all the planes; planes which are being used will
|
||||||
* override this state in the output-state application. */
|
* override this state in the output-state application. */
|
||||||
wl_list_for_each(plane, &b->plane_list, link) {
|
wl_list_for_each(plane, &b->plane_list, link) {
|
||||||
|
drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
|
||||||
|
(unsigned long) plane->plane_id);
|
||||||
plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
|
plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
|
||||||
plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
|
plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
|
||||||
}
|
}
|
||||||
@@ -2972,6 +3053,14 @@ drm_repaint_begin(struct weston_compositor *compositor)
|
|||||||
ret = drm_pending_state_alloc(b);
|
ret = drm_pending_state_alloc(b);
|
||||||
b->repaint_data = ret;
|
b->repaint_data = ret;
|
||||||
|
|
||||||
|
if (weston_debug_scope_is_enabled(b->debug)) {
|
||||||
|
char *dbg = weston_compositor_print_scene_graph(compositor);
|
||||||
|
drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
|
||||||
|
ret);
|
||||||
|
drm_debug(b, "%s", dbg);
|
||||||
|
free(dbg);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2991,6 +3080,7 @@ drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
|
|||||||
struct drm_pending_state *pending_state = repaint_data;
|
struct drm_pending_state *pending_state = repaint_data;
|
||||||
|
|
||||||
drm_pending_state_apply(pending_state);
|
drm_pending_state_apply(pending_state);
|
||||||
|
drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
|
||||||
b->repaint_data = NULL;
|
b->repaint_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3007,6 +3097,7 @@ drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
|
|||||||
struct drm_pending_state *pending_state = repaint_data;
|
struct drm_pending_state *pending_state = repaint_data;
|
||||||
|
|
||||||
drm_pending_state_free(pending_state);
|
drm_pending_state_free(pending_state);
|
||||||
|
drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
|
||||||
b->repaint_data = NULL;
|
b->repaint_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3050,12 +3141,21 @@ drm_output_prepare_overlay_view(struct drm_output_state *output_state,
|
|||||||
struct drm_fb *fb;
|
struct drm_fb *fb;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
enum {
|
||||||
|
NO_PLANES,
|
||||||
|
NO_PLANES_WITH_FORMAT,
|
||||||
|
NO_PLANES_ACCEPTED,
|
||||||
|
PLACED_ON_PLANE,
|
||||||
|
} availability = NO_PLANES;
|
||||||
|
|
||||||
assert(!b->sprites_are_broken);
|
assert(!b->sprites_are_broken);
|
||||||
|
|
||||||
fb = drm_fb_get_from_view(output_state, ev);
|
fb = drm_fb_get_from_view(output_state, ev);
|
||||||
if (!fb)
|
if (!fb) {
|
||||||
|
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
|
||||||
|
" couldn't get fb\n", ev);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
wl_list_for_each(p, &b->plane_list, link) {
|
wl_list_for_each(p, &b->plane_list, link) {
|
||||||
if (p->type != WDRM_PLANE_TYPE_OVERLAY)
|
if (p->type != WDRM_PLANE_TYPE_OVERLAY)
|
||||||
@@ -3064,6 +3164,15 @@ drm_output_prepare_overlay_view(struct drm_output_state *output_state,
|
|||||||
if (!drm_plane_is_available(p, output))
|
if (!drm_plane_is_available(p, output))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
state = drm_output_state_get_plane(output_state, p);
|
||||||
|
if (state->fb) {
|
||||||
|
state = NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (availability == NO_PLANES)
|
||||||
|
availability = NO_PLANES_WITH_FORMAT;
|
||||||
|
|
||||||
/* Check whether the format is supported */
|
/* Check whether the format is supported */
|
||||||
for (i = 0; i < p->count_formats; i++) {
|
for (i = 0; i < p->count_formats; i++) {
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
@@ -3084,15 +3193,14 @@ drm_output_prepare_overlay_view(struct drm_output_state *output_state,
|
|||||||
if (i == p->count_formats)
|
if (i == p->count_formats)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
state = drm_output_state_get_plane(output_state, p);
|
if (availability == NO_PLANES_WITH_FORMAT)
|
||||||
if (state->fb) {
|
availability = NO_PLANES_ACCEPTED;
|
||||||
state = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->ev = ev;
|
state->ev = ev;
|
||||||
state->output = output;
|
state->output = output;
|
||||||
if (!drm_plane_state_coords_for_view(state, ev)) {
|
if (!drm_plane_state_coords_for_view(state, ev)) {
|
||||||
|
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
|
||||||
|
"unsuitable transform\n", ev);
|
||||||
drm_plane_state_put_back(state);
|
drm_plane_state_put_back(state);
|
||||||
state = NULL;
|
state = NULL;
|
||||||
continue;
|
continue;
|
||||||
@@ -3100,6 +3208,8 @@ drm_output_prepare_overlay_view(struct drm_output_state *output_state,
|
|||||||
if (!b->atomic_modeset &&
|
if (!b->atomic_modeset &&
|
||||||
(state->src_w != state->dest_w << 16 ||
|
(state->src_w != state->dest_w << 16 ||
|
||||||
state->src_h != state->dest_h << 16)) {
|
state->src_h != state->dest_h << 16)) {
|
||||||
|
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
|
||||||
|
"no scaling without atomic\n", ev);
|
||||||
drm_plane_state_put_back(state);
|
drm_plane_state_put_back(state);
|
||||||
state = NULL;
|
state = NULL;
|
||||||
continue;
|
continue;
|
||||||
@@ -3113,17 +3223,48 @@ drm_output_prepare_overlay_view(struct drm_output_state *output_state,
|
|||||||
|
|
||||||
/* In planes-only mode, we don't have an incremental state to
|
/* In planes-only mode, we don't have an incremental state to
|
||||||
* test against, so we just hope it'll work. */
|
* test against, so we just hope it'll work. */
|
||||||
if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY)
|
if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
|
||||||
|
drm_debug(b, "\t\t\t\t[overlay] provisionally placing "
|
||||||
|
"view %p on overlay %lu in planes-only mode\n",
|
||||||
|
ev, (unsigned long) p->plane_id);
|
||||||
|
availability = PLACED_ON_PLANE;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = drm_pending_state_test(output_state->pending_state);
|
ret = drm_pending_state_test(output_state->pending_state);
|
||||||
if (ret == 0)
|
if (ret == 0) {
|
||||||
|
drm_debug(b, "\t\t\t\t[overlay] provisionally placing "
|
||||||
|
"view %p on overlay %d in mixed mode\n",
|
||||||
|
ev, p->plane_id);
|
||||||
|
availability = PLACED_ON_PLANE;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay %lu "
|
||||||
|
"in mixed mode: kernel test failed\n",
|
||||||
|
ev, (unsigned long) p->plane_id);
|
||||||
|
|
||||||
drm_plane_state_put_back(state);
|
drm_plane_state_put_back(state);
|
||||||
state = NULL;
|
state = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (availability) {
|
||||||
|
case NO_PLANES:
|
||||||
|
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
|
||||||
|
"no free overlay planes\n", ev);
|
||||||
|
break;
|
||||||
|
case NO_PLANES_WITH_FORMAT:
|
||||||
|
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
|
||||||
|
"no free overlay planes matching format 0x%lx, "
|
||||||
|
"modifier 0x%llx\n",
|
||||||
|
ev, (unsigned long) fb->format,
|
||||||
|
(unsigned long long) fb->modifier);
|
||||||
|
break;
|
||||||
|
case NO_PLANES_ACCEPTED:
|
||||||
|
case PLACED_ON_PLANE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
drm_fb_unref(fb);
|
drm_fb_unref(fb);
|
||||||
return state;
|
return state;
|
||||||
@@ -3192,13 +3333,23 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
|
|||||||
if (b->gbm == NULL)
|
if (b->gbm == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (ev->surface->buffer_ref.buffer == NULL)
|
if (ev->surface->buffer_ref.buffer == NULL) {
|
||||||
|
drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
|
||||||
|
"(no buffer available)\n", ev);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
|
shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
|
||||||
if (!shmbuf)
|
if (!shmbuf) {
|
||||||
|
drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
|
||||||
|
"(buffer isn't SHM)\n", ev);
|
||||||
return NULL;
|
return NULL;
|
||||||
if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888)
|
}
|
||||||
|
if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888) {
|
||||||
|
drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
|
||||||
|
"(format 0x%lx unsuitable)\n",
|
||||||
|
ev, (unsigned long) wl_shm_buffer_get_format(shmbuf));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
plane_state =
|
plane_state =
|
||||||
drm_output_state_get_plane(output_state, output->cursor_plane);
|
drm_output_state_get_plane(output_state, output->cursor_plane);
|
||||||
@@ -3216,8 +3367,11 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
|
|||||||
plane_state->src_w > (unsigned) b->cursor_width << 16 ||
|
plane_state->src_w > (unsigned) b->cursor_width << 16 ||
|
||||||
plane_state->src_h > (unsigned) b->cursor_height << 16 ||
|
plane_state->src_h > (unsigned) b->cursor_height << 16 ||
|
||||||
plane_state->src_w != plane_state->dest_w << 16 ||
|
plane_state->src_w != plane_state->dest_w << 16 ||
|
||||||
plane_state->src_h != plane_state->dest_h << 16)
|
plane_state->src_h != plane_state->dest_h << 16) {
|
||||||
|
drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
|
||||||
|
"(positioning requires cropping or scaling)\n", ev);
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Since we're setting plane state up front, we need to work out
|
/* Since we're setting plane state up front, we need to work out
|
||||||
* whether or not we need to upload a new cursor. We can't use the
|
* whether or not we need to upload a new cursor. We can't use the
|
||||||
@@ -3240,8 +3394,10 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
|
|||||||
plane_state->fb =
|
plane_state->fb =
|
||||||
drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
|
drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
|
||||||
|
|
||||||
if (needs_update)
|
if (needs_update) {
|
||||||
|
drm_debug(b, "\t\t\t\t[cursor] copying new content to cursor BO\n");
|
||||||
cursor_bo_update(plane_state, ev);
|
cursor_bo_update(plane_state, ev);
|
||||||
|
}
|
||||||
|
|
||||||
/* The cursor API is somewhat special: in cursor_bo_update(), we upload
|
/* The cursor API is somewhat special: in cursor_bo_update(), we upload
|
||||||
* a buffer which is always cursor_width x cursor_height, even if the
|
* a buffer which is always cursor_width x cursor_height, even if the
|
||||||
@@ -3252,6 +3408,9 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
|
|||||||
plane_state->dest_w = b->cursor_width;
|
plane_state->dest_w = b->cursor_width;
|
||||||
plane_state->dest_h = b->cursor_height;
|
plane_state->dest_h = b->cursor_height;
|
||||||
|
|
||||||
|
drm_debug(b, "\t\t\t\t[cursor] provisionally assigned view %p to cursor\n",
|
||||||
|
ev);
|
||||||
|
|
||||||
return plane_state;
|
return plane_state;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -3347,18 +3506,32 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||||||
if (!scanout_fb ||
|
if (!scanout_fb ||
|
||||||
(scanout_fb->type != BUFFER_GBM_SURFACE &&
|
(scanout_fb->type != BUFFER_GBM_SURFACE &&
|
||||||
scanout_fb->type != BUFFER_PIXMAN_DUMB)) {
|
scanout_fb->type != BUFFER_PIXMAN_DUMB)) {
|
||||||
|
drm_debug(b, "\t\t[state] cannot propose mixed mode: "
|
||||||
|
"for output %s (%lu): no previous renderer "
|
||||||
|
"fb\n",
|
||||||
|
output->base.name,
|
||||||
|
(unsigned long) output->base.id);
|
||||||
drm_output_state_free(state);
|
drm_output_state_free(state);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scanout_fb->width != output_base->current_mode->width ||
|
if (scanout_fb->width != output_base->current_mode->width ||
|
||||||
scanout_fb->height != output_base->current_mode->height) {
|
scanout_fb->height != output_base->current_mode->height) {
|
||||||
|
drm_debug(b, "\t\t[state] cannot propose mixed mode "
|
||||||
|
"for output %s (%lu): previous fb has "
|
||||||
|
"different size\n",
|
||||||
|
output->base.name,
|
||||||
|
(unsigned long) output->base.id);
|
||||||
drm_output_state_free(state);
|
drm_output_state_free(state);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
scanout_state = drm_plane_state_duplicate(state,
|
scanout_state = drm_plane_state_duplicate(state,
|
||||||
plane->state_cur);
|
plane->state_cur);
|
||||||
|
drm_debug(b, "\t\t[state] using renderer FB ID %lu for mixed "
|
||||||
|
"mode for output %s (%lu)\n",
|
||||||
|
(unsigned long) scanout_fb->fb_id, output->base.name,
|
||||||
|
(unsigned long) output->base.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3384,18 +3557,32 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||||||
bool totally_occluded = false;
|
bool totally_occluded = false;
|
||||||
bool overlay_occluded = false;
|
bool overlay_occluded = false;
|
||||||
|
|
||||||
|
drm_debug(b, "\t\t\t[view] evaluating view %p for "
|
||||||
|
"output %s (%lu)\n",
|
||||||
|
ev, output->base.name,
|
||||||
|
(unsigned long) output->base.id);
|
||||||
|
|
||||||
/* If this view doesn't touch our output at all, there's no
|
/* If this view doesn't touch our output at all, there's no
|
||||||
* reason to do anything with it. */
|
* reason to do anything with it. */
|
||||||
if (!(ev->output_mask & (1u << output->base.id)))
|
if (!(ev->output_mask & (1u << output->base.id))) {
|
||||||
|
drm_debug(b, "\t\t\t\t[view] ignoring view %p "
|
||||||
|
"(not on our output)\n", ev);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* We only assign planes to views which are exclusively present
|
/* We only assign planes to views which are exclusively present
|
||||||
* on our output. */
|
* on our output. */
|
||||||
if (ev->output_mask != (1u << output->base.id))
|
if (ev->output_mask != (1u << output->base.id)) {
|
||||||
|
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
|
||||||
|
"(on multiple outputs)\n", ev);
|
||||||
force_renderer = true;
|
force_renderer = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ev->surface->buffer_ref.buffer)
|
if (!ev->surface->buffer_ref.buffer) {
|
||||||
|
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
|
||||||
|
"(no buffer available)\n", ev);
|
||||||
force_renderer = true;
|
force_renderer = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Ignore views we know to be totally occluded. */
|
/* Ignore views we know to be totally occluded. */
|
||||||
pixman_region32_init(&clipped_view);
|
pixman_region32_init(&clipped_view);
|
||||||
@@ -3408,6 +3595,8 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||||||
&occluded_region);
|
&occluded_region);
|
||||||
totally_occluded = !pixman_region32_not_empty(&surface_overlap);
|
totally_occluded = !pixman_region32_not_empty(&surface_overlap);
|
||||||
if (totally_occluded) {
|
if (totally_occluded) {
|
||||||
|
drm_debug(b, "\t\t\t\t[view] ignoring view %p "
|
||||||
|
"(occluded on our output)\n", ev);
|
||||||
pixman_region32_fini(&surface_overlap);
|
pixman_region32_fini(&surface_overlap);
|
||||||
pixman_region32_fini(&clipped_view);
|
pixman_region32_fini(&clipped_view);
|
||||||
continue;
|
continue;
|
||||||
@@ -3418,8 +3607,11 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||||||
* be part of, or occluded by, it, and cannot go on a plane. */
|
* be part of, or occluded by, it, and cannot go on a plane. */
|
||||||
pixman_region32_intersect(&surface_overlap, &renderer_region,
|
pixman_region32_intersect(&surface_overlap, &renderer_region,
|
||||||
&clipped_view);
|
&clipped_view);
|
||||||
if (pixman_region32_not_empty(&surface_overlap))
|
if (pixman_region32_not_empty(&surface_overlap)) {
|
||||||
|
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
|
||||||
|
"(occluded by renderer views)\n", ev);
|
||||||
force_renderer = true;
|
force_renderer = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* We do not control the stacking order of overlay planes;
|
/* We do not control the stacking order of overlay planes;
|
||||||
* the scanout plane is strictly stacked bottom and the cursor
|
* the scanout plane is strictly stacked bottom and the cursor
|
||||||
@@ -3428,8 +3620,11 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||||||
* planes overlapping each other. */
|
* planes overlapping each other. */
|
||||||
pixman_region32_intersect(&surface_overlap, &occluded_region,
|
pixman_region32_intersect(&surface_overlap, &occluded_region,
|
||||||
&clipped_view);
|
&clipped_view);
|
||||||
if (pixman_region32_not_empty(&surface_overlap))
|
if (pixman_region32_not_empty(&surface_overlap)) {
|
||||||
|
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
|
||||||
|
"(occluded by other overlay planes)\n", ev);
|
||||||
overlay_occluded = true;
|
overlay_occluded = true;
|
||||||
|
}
|
||||||
pixman_region32_fini(&surface_overlap);
|
pixman_region32_fini(&surface_overlap);
|
||||||
|
|
||||||
/* The cursor plane is 'special' in the sense that we can still
|
/* The cursor plane is 'special' in the sense that we can still
|
||||||
@@ -3441,10 +3636,16 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||||||
/* If sprites are disabled or the view is not fully opaque, we
|
/* If sprites are disabled or the view is not fully opaque, we
|
||||||
* must put the view into the renderer - unless it has already
|
* must put the view into the renderer - unless it has already
|
||||||
* been placed in the cursor plane, which can handle alpha. */
|
* been placed in the cursor plane, which can handle alpha. */
|
||||||
if (!ps && !planes_ok)
|
if (!ps && !planes_ok) {
|
||||||
|
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
|
||||||
|
"(precluded by mode)\n", ev);
|
||||||
force_renderer = true;
|
force_renderer = true;
|
||||||
if (!ps && !drm_view_is_opaque(ev))
|
}
|
||||||
|
if (!ps && !drm_view_is_opaque(ev)) {
|
||||||
|
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
|
||||||
|
"(view not fully opaque)\n", ev);
|
||||||
force_renderer = true;
|
force_renderer = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Only try to place scanout surfaces in planes-only mode; in
|
/* Only try to place scanout surfaces in planes-only mode; in
|
||||||
* mixed mode, we have already failed to place a view on the
|
* mixed mode, we have already failed to place a view on the
|
||||||
@@ -3477,6 +3678,9 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||||||
* check if this is OK, and add ourselves to the renderer
|
* check if this is OK, and add ourselves to the renderer
|
||||||
* region if so. */
|
* region if so. */
|
||||||
if (!renderer_ok) {
|
if (!renderer_ok) {
|
||||||
|
drm_debug(b, "\t\t[view] failing state generation: "
|
||||||
|
"placing view %p to renderer not allowed\n",
|
||||||
|
ev);
|
||||||
pixman_region32_fini(&clipped_view);
|
pixman_region32_fini(&clipped_view);
|
||||||
goto err_region;
|
goto err_region;
|
||||||
}
|
}
|
||||||
@@ -3496,8 +3700,11 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||||||
|
|
||||||
/* Check to see if this state will actually work. */
|
/* Check to see if this state will actually work. */
|
||||||
ret = drm_pending_state_test(state->pending_state);
|
ret = drm_pending_state_test(state->pending_state);
|
||||||
if (ret != 0)
|
if (ret != 0) {
|
||||||
|
drm_debug(b, "\t\t[view] failing state generation: "
|
||||||
|
"atomic test not OK\n");
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Counterpart to duplicating scanout state at the top of this
|
/* Counterpart to duplicating scanout state at the top of this
|
||||||
* function: if we have taken a renderer framebuffer and placed it in
|
* function: if we have taken a renderer framebuffer and placed it in
|
||||||
@@ -3530,12 +3737,24 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
|
|||||||
struct weston_view *ev;
|
struct weston_view *ev;
|
||||||
struct weston_plane *primary = &output_base->compositor->primary_plane;
|
struct weston_plane *primary = &output_base->compositor->primary_plane;
|
||||||
|
|
||||||
|
drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n",
|
||||||
|
output_base->name, (unsigned long) output_base->id);
|
||||||
|
|
||||||
if (!b->sprites_are_broken) {
|
if (!b->sprites_are_broken) {
|
||||||
state = drm_output_propose_state(output_base, pending_state,
|
state = drm_output_propose_state(output_base, pending_state,
|
||||||
DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
|
DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
|
||||||
if (!state)
|
if (!state) {
|
||||||
|
drm_debug(b, "\t[repaint] could not build planes-only "
|
||||||
|
"state, trying mixed\n");
|
||||||
state = drm_output_propose_state(output_base, pending_state,
|
state = drm_output_propose_state(output_base, pending_state,
|
||||||
DRM_OUTPUT_PROPOSE_STATE_MIXED);
|
DRM_OUTPUT_PROPOSE_STATE_MIXED);
|
||||||
|
}
|
||||||
|
if (!state) {
|
||||||
|
drm_debug(b, "\t[repaint] could not build mixed-mode "
|
||||||
|
"state, trying renderer-only\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
drm_debug(b, "\t[state] no overlay plane support\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state)
|
if (!state)
|
||||||
@@ -3582,10 +3801,16 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_plane)
|
if (target_plane) {
|
||||||
|
drm_debug(b, "\t[repaint] view %p on %s plane %lu\n",
|
||||||
|
ev, plane_type_enums[target_plane->type].name,
|
||||||
|
(unsigned long) target_plane->plane_id);
|
||||||
weston_view_move_to_plane(ev, &target_plane->base);
|
weston_view_move_to_plane(ev, &target_plane->base);
|
||||||
else
|
} else {
|
||||||
|
drm_debug(b, "\t[repaint] view %p using renderer "
|
||||||
|
"composition\n", ev);
|
||||||
weston_view_move_to_plane(ev, primary);
|
weston_view_move_to_plane(ev, primary);
|
||||||
|
}
|
||||||
|
|
||||||
if (!target_plane ||
|
if (!target_plane ||
|
||||||
target_plane->type == WDRM_PLANE_TYPE_CURSOR) {
|
target_plane->type == WDRM_PLANE_TYPE_CURSOR) {
|
||||||
@@ -6264,6 +6489,8 @@ drm_destroy(struct weston_compositor *ec)
|
|||||||
|
|
||||||
destroy_sprites(b);
|
destroy_sprites(b);
|
||||||
|
|
||||||
|
weston_debug_scope_destroy(b->debug);
|
||||||
|
b->debug = NULL;
|
||||||
weston_compositor_shutdown(ec);
|
weston_compositor_shutdown(ec);
|
||||||
|
|
||||||
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
|
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
|
||||||
@@ -6725,6 +6952,10 @@ drm_backend_create(struct weston_compositor *compositor,
|
|||||||
b->pageflip_timeout = config->pageflip_timeout;
|
b->pageflip_timeout = config->pageflip_timeout;
|
||||||
b->use_pixman_shadow = config->use_pixman_shadow;
|
b->use_pixman_shadow = config->use_pixman_shadow;
|
||||||
|
|
||||||
|
b->debug = weston_compositor_add_debug_scope(compositor, "drm-backend",
|
||||||
|
"Debug messages from DRM/KMS backend\n",
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
compositor->backend = &b->base;
|
compositor->backend = &b->base;
|
||||||
|
|
||||||
if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
|
if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user