wlroots-hyprland/include/backend/drm/drm.h
Vincent Vanlaer 7bc43413ed Allow cursor render surface to be used as fb
In order for a surface to be used as a cursor plane framebuffer, it
appears that requiring the buffer to be linear is sufficient.

GBM_BO_USE_SCANOUT is added in case GBM_BO_USE_LINEAR isn't sufficient
on untested hardware.

Fixes #1323

Removed wlr_drm_plane.cursor_bo as it does not serve any purpose
anymore.

Relevant analysis (taken from the PR description):

While trying to implement a fix for #1323, I found that when exporting
the rendered surface into a DMA-BUF and reimporting it with
`GBM_BO_USE_CURSOR`, the resulting object does not appear to be valid.
After some digging (turning on drm-kms debugging and switching to legacy
mode), I managed to extract the following error: ```
[drm:__setplane_check.isra.1 [drm]] Invalid pixel format AR24
little-endian (0x34325241), modifier 0x100000000000001 ``` The format
itself refers to ARGB8888 which is the same format as
`renderer->gbm_format` used in master to create the cursor bo. However,
using `gbm_bo_create` with `GBM_BO_USE_CURSOR` results in a modifier of
0. A modifier of zero represents a linear buffer while the modifier of
the surface that is rendered to is  `I915_FORMAT_MOD_X_TILED` (see
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/uapi/drm/drm_fourcc.h?h=v4.20.6#n263).
In order to fix this mismatch in modifier, I added the
`GBM_BO_USE_LINEAR` to the render surface and everything started to work
just fine. I wondered however, whether the export and import is really
necessary. I then decided to test if the back buffer of the render
surface works as well, and at least on my hardware (Intel HD 530 and
Intel UHD 620) it does. This is the patch in this PR and this requires
no exporting and importing.

I have to note that I cheated in order to import DMA_BUFs into a cursor
bo when doing the first tests, since on import the Intel drivers check
that the cursor is 64x64. This is strange since cursor sizes other than
64x64 have been around for quite some time now
(https://lists.freedesktop.org/archives/mesa-commit/2014-June/050268.html).
Removing this check made everything work fine. I later (while writing
this PR) found out that `__DRI_IMAGE_USE_CURSOR` (to which
`GBM_BO_USE_CURSOR` translates) has been deprecated in mesa
(https://gitlab.freedesktop.org/mesa/mesa/blob/master/include/GL/internal/dri_interface.h#L1296),
which makes me wonder what the usecase of `GBM_BO_USE_CURSOR` is. The
reason we never encountered this is that when specifying
`GBM_BO_USE_WRITE`, a dumb buffer is created trough DRM and the usage
flag never reaches the Intel driver directly. The relevant code is in
https://gitlab.freedesktop.org/mesa/mesa/blob/master/src/gbm/backends/dri/gbm_dri.c#L1011-1089
. From this it seems that as long as the size, format and modifiers are
right, any surface can be used as a cursor.
2019-02-04 20:47:07 +01:00

163 lines
3.5 KiB
C

#ifndef BACKEND_DRM_DRM_H
#define BACKEND_DRM_DRM_H
#include <EGL/egl.h>
#include <gbm.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include <wayland-server.h>
#include <wayland-util.h>
#include <wlr/backend/drm.h>
#include <wlr/backend/session.h>
#include <wlr/render/egl.h>
#include <xf86drmMode.h>
#include "iface.h"
#include "properties.h"
#include "renderer.h"
struct wlr_drm_plane {
uint32_t type;
uint32_t id;
uint32_t possible_crtcs;
struct wlr_drm_surface surf;
struct wlr_drm_surface mgpu_surf;
uint32_t drm_format; // ARGB8888 or XRGB8888
// Only used by cursor
float matrix[9];
bool cursor_enabled;
int32_t cursor_hotspot_x, cursor_hotspot_y;
union wlr_drm_plane_props props;
};
struct wlr_drm_crtc {
uint32_t id;
// Atomic modesetting only
uint32_t mode_id;
uint32_t gamma_lut;
drmModeAtomicReq *atomic;
// Legacy only
drmModeCrtc *legacy_crtc;
union {
struct {
struct wlr_drm_plane *overlay;
struct wlr_drm_plane *primary;
struct wlr_drm_plane *cursor;
};
struct wlr_drm_plane *planes[3];
};
union wlr_drm_crtc_props props;
struct wl_list connectors;
uint16_t *gamma_table;
size_t gamma_table_size;
};
struct wlr_drm_backend {
struct wlr_backend backend;
struct wlr_drm_backend *parent;
const struct wlr_drm_interface *iface;
clockid_t clock;
int fd;
size_t num_crtcs;
struct wlr_drm_crtc *crtcs;
size_t num_planes;
struct wlr_drm_plane *planes;
union {
struct {
size_t num_overlay_planes;
size_t num_primary_planes;
size_t num_cursor_planes;
};
size_t num_type_planes[3];
};
union {
struct {
struct wlr_drm_plane *overlay_planes;
struct wlr_drm_plane *primary_planes;
struct wlr_drm_plane *cursor_planes;
};
struct wlr_drm_plane *type_planes[3];
};
struct wl_display *display;
struct wl_event_source *drm_event;
struct wl_listener display_destroy;
struct wl_listener session_signal;
struct wl_listener drm_invalidated;
struct wl_list outputs;
struct wlr_drm_renderer renderer;
struct wlr_session *session;
};
enum wlr_drm_connector_state {
// Connector is available but no output is plugged in
WLR_DRM_CONN_DISCONNECTED,
// An output just has been plugged in and is waiting for a modeset
WLR_DRM_CONN_NEEDS_MODESET,
WLR_DRM_CONN_CLEANUP,
WLR_DRM_CONN_CONNECTED,
// Connector disappeared, waiting for being destroyed on next page-flip
WLR_DRM_CONN_DISAPPEARED,
};
struct wlr_drm_mode {
struct wlr_output_mode wlr_mode;
drmModeModeInfo drm_mode;
};
struct wlr_drm_connector {
struct wlr_output output;
enum wlr_drm_connector_state state;
struct wlr_output_mode *desired_mode;
bool desired_enabled;
uint32_t id;
struct wlr_drm_crtc *crtc;
uint32_t possible_crtc;
union wlr_drm_connector_props props;
uint32_t width, height;
int32_t cursor_x, cursor_y;
drmModeCrtc *old_crtc;
bool pageflip_pending;
struct wl_event_source *retry_pageflip;
struct wl_list link;
};
struct wlr_drm_backend *get_drm_backend_from_backend(
struct wlr_backend *wlr_backend);
bool check_drm_features(struct wlr_drm_backend *drm);
bool init_drm_resources(struct wlr_drm_backend *drm);
void finish_drm_resources(struct wlr_drm_backend *drm);
void restore_drm_outputs(struct wlr_drm_backend *drm);
void scan_drm_connectors(struct wlr_drm_backend *state);
int handle_drm_event(int fd, uint32_t mask, void *data);
bool enable_drm_connector(struct wlr_output *output, bool enable);
bool set_drm_connector_gamma(struct wlr_output *output, size_t size,
const uint16_t *r, const uint16_t *g, const uint16_t *b);
#endif