1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2021, Jeffy Chen <jeffy.chen@rock-chips.com>
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
5*4882a593Smuzhiyun * it under the terms of the GNU General Public License as published by
6*4882a593Smuzhiyun * the Free Software Foundation; either version 2 of the License, or
7*4882a593Smuzhiyun * (at your option) any later version.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
10*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12*4882a593Smuzhiyun * GNU General Public License for more details.
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <errno.h>
16*4882a593Smuzhiyun #include <fcntl.h>
17*4882a593Smuzhiyun #include <inttypes.h>
18*4882a593Smuzhiyun #include <pthread.h>
19*4882a593Smuzhiyun #include <stdlib.h>
20*4882a593Smuzhiyun #include <string.h>
21*4882a593Smuzhiyun #include <unistd.h>
22*4882a593Smuzhiyun #include <sys/mman.h>
23*4882a593Smuzhiyun #include <sys/stat.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include <xf86drm.h>
26*4882a593Smuzhiyun #include <xf86drmMode.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <gbm.h>
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include "drm_common.h"
31*4882a593Smuzhiyun #include "drm_egl.h"
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define DRM_CURSOR_CONFIG_FILE "/etc/drm-cursor.conf"
34*4882a593Smuzhiyun #define OPT_DEBUG "debug="
35*4882a593Smuzhiyun #define OPT_LOG_FILE "log-file="
36*4882a593Smuzhiyun #define OPT_HIDE "hide="
37*4882a593Smuzhiyun #define OPT_ALLOW_OVERLAY "allow-overlay="
38*4882a593Smuzhiyun #define OPT_PREFER_AFBC "prefer-afbc="
39*4882a593Smuzhiyun #define OPT_PREFER_PLANE "prefer-plane="
40*4882a593Smuzhiyun #define OPT_PREFER_PLANES "prefer-planes="
41*4882a593Smuzhiyun #define OPT_CRTC_BLOCKLIST "crtc-blocklist="
42*4882a593Smuzhiyun #define OPT_NUM_SURFACES "num-surfaces="
43*4882a593Smuzhiyun #define OPT_MAX_FPS "max-fps="
44*4882a593Smuzhiyun #define OPT_ATOMIC "atomic="
45*4882a593Smuzhiyun #define OPT_SCALE "scale="
46*4882a593Smuzhiyun #define OPT_SCALE_FROM "scale-from="
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun #define DRM_MAX_CRTCS 8
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun typedef enum {
51*4882a593Smuzhiyun PLANE_PROP_type = 0,
52*4882a593Smuzhiyun PLANE_PROP_IN_FORMATS,
53*4882a593Smuzhiyun PLANE_PROP_zpos,
54*4882a593Smuzhiyun PLANE_PROP_ZPOS,
55*4882a593Smuzhiyun PLANE_PROP_ASYNC_COMMIT,
56*4882a593Smuzhiyun PLANE_PROP_CRTC_ID,
57*4882a593Smuzhiyun PLANE_PROP_FB_ID,
58*4882a593Smuzhiyun PLANE_PROP_SRC_X,
59*4882a593Smuzhiyun PLANE_PROP_SRC_Y,
60*4882a593Smuzhiyun PLANE_PROP_SRC_W,
61*4882a593Smuzhiyun PLANE_PROP_SRC_H,
62*4882a593Smuzhiyun PLANE_PROP_CRTC_X,
63*4882a593Smuzhiyun PLANE_PROP_CRTC_Y,
64*4882a593Smuzhiyun PLANE_PROP_CRTC_W,
65*4882a593Smuzhiyun PLANE_PROP_CRTC_H,
66*4882a593Smuzhiyun PLANE_PROP_MAX,
67*4882a593Smuzhiyun } drm_plane_prop;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun static const char *drm_plane_prop_names[] = {
70*4882a593Smuzhiyun [PLANE_PROP_type] = "type",
71*4882a593Smuzhiyun [PLANE_PROP_IN_FORMATS] = "IN_FORMATS",
72*4882a593Smuzhiyun [PLANE_PROP_zpos] = "zpos",
73*4882a593Smuzhiyun [PLANE_PROP_ZPOS] = "ZPOS",
74*4882a593Smuzhiyun [PLANE_PROP_ASYNC_COMMIT] = "ASYNC_COMMIT",
75*4882a593Smuzhiyun [PLANE_PROP_CRTC_ID] = "CRTC_ID",
76*4882a593Smuzhiyun [PLANE_PROP_FB_ID] = "FB_ID",
77*4882a593Smuzhiyun [PLANE_PROP_SRC_X] = "SRC_X",
78*4882a593Smuzhiyun [PLANE_PROP_SRC_Y] = "SRC_Y",
79*4882a593Smuzhiyun [PLANE_PROP_SRC_W] = "SRC_W",
80*4882a593Smuzhiyun [PLANE_PROP_SRC_H] = "SRC_H",
81*4882a593Smuzhiyun [PLANE_PROP_CRTC_X] = "CRTC_X",
82*4882a593Smuzhiyun [PLANE_PROP_CRTC_Y] = "CRTC_Y",
83*4882a593Smuzhiyun [PLANE_PROP_CRTC_W] = "CRTC_W",
84*4882a593Smuzhiyun [PLANE_PROP_CRTC_H] = "CRTC_H",
85*4882a593Smuzhiyun };
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun typedef struct {
88*4882a593Smuzhiyun uint32_t plane_id;
89*4882a593Smuzhiyun int cursor_plane;
90*4882a593Smuzhiyun int can_afbc;
91*4882a593Smuzhiyun int can_linear;
92*4882a593Smuzhiyun drmModePlane *plane;
93*4882a593Smuzhiyun drmModeObjectProperties *props;
94*4882a593Smuzhiyun int prop_ids[PLANE_PROP_MAX];
95*4882a593Smuzhiyun } drm_plane;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun #define REQ_SET_CURSOR (1 << 0)
98*4882a593Smuzhiyun #define REQ_MOVE_CURSOR (1 << 1)
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun typedef struct {
101*4882a593Smuzhiyun uint32_t handle;
102*4882a593Smuzhiyun uint32_t fb;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun int width;
105*4882a593Smuzhiyun int height;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun int scaled_w;
108*4882a593Smuzhiyun int scaled_h;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun int x;
111*4882a593Smuzhiyun int y;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun int scaled_x;
114*4882a593Smuzhiyun int scaled_y;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun int off_x;
117*4882a593Smuzhiyun int off_y;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun int hot_x;
120*4882a593Smuzhiyun int hot_y;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun int request;
123*4882a593Smuzhiyun } drm_cursor_state;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun typedef enum {
126*4882a593Smuzhiyun IDLE = 0,
127*4882a593Smuzhiyun FATAL_ERROR,
128*4882a593Smuzhiyun PENDING,
129*4882a593Smuzhiyun } drm_thread_state;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun typedef struct {
132*4882a593Smuzhiyun uint32_t crtc_id;
133*4882a593Smuzhiyun uint32_t crtc_pipe;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun int width;
136*4882a593Smuzhiyun int height;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun drm_plane *plane;
139*4882a593Smuzhiyun uint32_t prefer_plane_id;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun drm_cursor_state cursor_next;
142*4882a593Smuzhiyun drm_cursor_state cursor_curr;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun pthread_t thread;
145*4882a593Smuzhiyun pthread_cond_t cond;
146*4882a593Smuzhiyun pthread_mutex_t mutex;
147*4882a593Smuzhiyun drm_thread_state state;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun void *egl_ctx;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun int verified;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun int use_afbc_modifier;
154*4882a593Smuzhiyun int blocked;
155*4882a593Smuzhiyun int async_commit;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun uint64_t last_update_time;
158*4882a593Smuzhiyun } drm_crtc;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun typedef struct {
161*4882a593Smuzhiyun int fd;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun drm_crtc crtcs[DRM_MAX_CRTCS];
164*4882a593Smuzhiyun int num_crtcs;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun drmModePlaneResPtr pres;
167*4882a593Smuzhiyun drmModeRes *res;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun int prefer_afbc_modifier;
170*4882a593Smuzhiyun int allow_overlay;
171*4882a593Smuzhiyun int num_surfaces;
172*4882a593Smuzhiyun int inited;
173*4882a593Smuzhiyun int atomic;
174*4882a593Smuzhiyun int hide;
175*4882a593Smuzhiyun uint64_t min_interval;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun float scale_x, scale_y;
178*4882a593Smuzhiyun float scale_from;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun char *configs;
181*4882a593Smuzhiyun } drm_ctx;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun static drm_ctx g_drm_ctx = { 0, };
184*4882a593Smuzhiyun drm_private int g_drm_debug = 0;
185*4882a593Smuzhiyun drm_private FILE *g_log_fp = NULL;
186*4882a593Smuzhiyun
drm_curr_time(void)187*4882a593Smuzhiyun static inline uint64_t drm_curr_time(void)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun struct timeval tv;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun gettimeofday(&tv, NULL);
192*4882a593Smuzhiyun return tv.tv_sec + tv.tv_usec / 1000;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
drm_plane_get_prop(drm_ctx * ctx,drm_plane * plane,drm_plane_prop p)195*4882a593Smuzhiyun static int drm_plane_get_prop(drm_ctx *ctx, drm_plane *plane, drm_plane_prop p)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun drmModePropertyPtr prop;
198*4882a593Smuzhiyun uint32_t i;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun if (plane->prop_ids[p])
201*4882a593Smuzhiyun return plane->prop_ids[p];
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun for (i = 0; i < plane->props->count_props; i++) {
204*4882a593Smuzhiyun prop = drmModeGetProperty(ctx->fd, plane->props->props[i]);
205*4882a593Smuzhiyun if (prop && !strcmp(prop->name, drm_plane_prop_names[p])) {
206*4882a593Smuzhiyun drmModeFreeProperty(prop);
207*4882a593Smuzhiyun plane->prop_ids[p] = i;
208*4882a593Smuzhiyun return i;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun drmModeFreeProperty(prop);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun return -1;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
drm_atomic_add_plane_prop(drm_ctx * ctx,drmModeAtomicReq * request,drm_plane * plane,drm_plane_prop p,uint64_t value)216*4882a593Smuzhiyun static int drm_atomic_add_plane_prop(drm_ctx *ctx, drmModeAtomicReq *request,
217*4882a593Smuzhiyun drm_plane *plane, drm_plane_prop p,
218*4882a593Smuzhiyun uint64_t value)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun int prop_idx = drm_plane_get_prop(ctx, plane, p);
221*4882a593Smuzhiyun if (prop_idx < 0)
222*4882a593Smuzhiyun return -1;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun return drmModeAtomicAddProperty(request, plane->plane_id,
225*4882a593Smuzhiyun plane->props->props[prop_idx], value);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
drm_set_plane(drm_ctx * ctx,drm_crtc * crtc,drm_plane * plane,uint32_t fb,int x,int y,int w,int h)228*4882a593Smuzhiyun static int drm_set_plane(drm_ctx *ctx, drm_crtc *crtc, drm_plane *plane,
229*4882a593Smuzhiyun uint32_t fb, int x, int y, int w, int h)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun drmModeAtomicReq *req;
232*4882a593Smuzhiyun int ret = 0;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun if (plane->cursor_plane || crtc->async_commit || !ctx->atomic)
235*4882a593Smuzhiyun goto legacy;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun req = drmModeAtomicAlloc();
238*4882a593Smuzhiyun if (!req)
239*4882a593Smuzhiyun goto legacy;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (!fb) {
242*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane, PLANE_PROP_CRTC_ID, 0);
243*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane, PLANE_PROP_FB_ID, 0);
244*4882a593Smuzhiyun } else {
245*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane,
246*4882a593Smuzhiyun PLANE_PROP_CRTC_ID, crtc->crtc_id);
247*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane, PLANE_PROP_FB_ID, fb);
248*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane, PLANE_PROP_SRC_X, 0);
249*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane, PLANE_PROP_SRC_Y, 0);
250*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane,
251*4882a593Smuzhiyun PLANE_PROP_SRC_W, w << 16);
252*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req,
253*4882a593Smuzhiyun plane, PLANE_PROP_SRC_H, h << 16);
254*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane, PLANE_PROP_CRTC_X, x);
255*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane, PLANE_PROP_CRTC_Y, y);
256*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane, PLANE_PROP_CRTC_W, w);
257*4882a593Smuzhiyun ret |= drm_atomic_add_plane_prop(ctx, req, plane, PLANE_PROP_CRTC_H, h);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun ret |= drmModeAtomicCommit(ctx->fd, req, DRM_MODE_ATOMIC_NONBLOCK, NULL);
261*4882a593Smuzhiyun drmModeAtomicFree(req);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun if (ret >= 0)
264*4882a593Smuzhiyun return 0;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun legacy:
267*4882a593Smuzhiyun if (ret < 0 && ctx->atomic) {
268*4882a593Smuzhiyun DRM_ERROR("CRTC[%d]: failed to do atomic commit (%d)\n",
269*4882a593Smuzhiyun crtc->crtc_id, errno);
270*4882a593Smuzhiyun ctx->atomic = 0;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun return drmModeSetPlane(ctx->fd, plane->plane_id, crtc->crtc_id, fb, 0,
273*4882a593Smuzhiyun x, y, w, h, 0, 0, w << 16, h << 16);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
drm_plane_get_prop_value(drm_ctx * ctx,drm_plane * plane,drm_plane_prop p,uint64_t * value)276*4882a593Smuzhiyun static int drm_plane_get_prop_value(drm_ctx *ctx, drm_plane *plane,
277*4882a593Smuzhiyun drm_plane_prop p, uint64_t *value)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun int prop_idx = drm_plane_get_prop(ctx, plane, p);
280*4882a593Smuzhiyun if (prop_idx < 0)
281*4882a593Smuzhiyun return -1;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun *value = plane->props->prop_values[prop_idx];
284*4882a593Smuzhiyun return 0;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
drm_plane_set_prop_max(drm_ctx * ctx,drm_plane * plane,drm_plane_prop p)287*4882a593Smuzhiyun static int drm_plane_set_prop_max(drm_ctx *ctx, drm_plane *plane,
288*4882a593Smuzhiyun drm_plane_prop p)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun drmModePropertyPtr prop;
291*4882a593Smuzhiyun int prop_idx = drm_plane_get_prop(ctx, plane, p);
292*4882a593Smuzhiyun if (prop_idx < 0)
293*4882a593Smuzhiyun return -1;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun prop = drmModeGetProperty(ctx->fd, plane->props->props[prop_idx]);
296*4882a593Smuzhiyun drmModeObjectSetProperty (ctx->fd, plane->plane_id,
297*4882a593Smuzhiyun DRM_MODE_OBJECT_PLANE,
298*4882a593Smuzhiyun plane->props->props[prop_idx],
299*4882a593Smuzhiyun prop->values[prop->count_values - 1]);
300*4882a593Smuzhiyun DRM_DEBUG("set plane %d prop: %s to max: %"PRIu64"\n",
301*4882a593Smuzhiyun plane->plane_id, drm_plane_prop_names[p],
302*4882a593Smuzhiyun prop->values[prop->count_values - 1]);
303*4882a593Smuzhiyun drmModeFreeProperty(prop);
304*4882a593Smuzhiyun return 0;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
drm_free_plane(drm_plane * plane)307*4882a593Smuzhiyun static void drm_free_plane(drm_plane *plane)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun drmModeFreeObjectProperties(plane->props);
310*4882a593Smuzhiyun drmModeFreePlane(plane->plane);
311*4882a593Smuzhiyun free(plane);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
drm_plane_update_format(drm_ctx * ctx,drm_plane * plane)314*4882a593Smuzhiyun static void drm_plane_update_format(drm_ctx *ctx, drm_plane *plane)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun drmModePropertyBlobPtr blob;
317*4882a593Smuzhiyun struct drm_format_modifier_blob *header;
318*4882a593Smuzhiyun struct drm_format_modifier *modifiers;
319*4882a593Smuzhiyun uint32_t *formats;
320*4882a593Smuzhiyun uint64_t value;
321*4882a593Smuzhiyun uint32_t i, j;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun plane->can_afbc = plane->can_linear = 0;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun /* Check formats */
326*4882a593Smuzhiyun for (i = 0; i < plane->plane->count_formats; i++) {
327*4882a593Smuzhiyun if (plane->plane->formats[i] == DRM_FORMAT_ARGB8888)
328*4882a593Smuzhiyun break;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun if (i == plane->plane->count_formats)
331*4882a593Smuzhiyun return;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (drm_plane_get_prop_value(ctx, plane, PLANE_PROP_IN_FORMATS, &value) < 0) {
334*4882a593Smuzhiyun /* No in_formats */
335*4882a593Smuzhiyun plane->can_linear = 1;
336*4882a593Smuzhiyun return;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun blob = drmModeGetPropertyBlob(ctx->fd, value);
340*4882a593Smuzhiyun if (!blob)
341*4882a593Smuzhiyun return;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun header = blob->data;
344*4882a593Smuzhiyun formats = (uint32_t *) ((char *) header + header->formats_offset);
345*4882a593Smuzhiyun modifiers = (struct drm_format_modifier *)
346*4882a593Smuzhiyun ((char *) header + header->modifiers_offset);
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun /* Check in_formats */
349*4882a593Smuzhiyun for (i = 0; i < header->count_formats; i++) {
350*4882a593Smuzhiyun if (formats[i] == DRM_FORMAT_ARGB8888)
351*4882a593Smuzhiyun break;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun if (i == header->count_formats)
354*4882a593Smuzhiyun goto out;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun if (!header->count_modifiers) {
357*4882a593Smuzhiyun plane->can_linear = 1;
358*4882a593Smuzhiyun goto out;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun /* Check modifiers */
362*4882a593Smuzhiyun for (j = 0; j < header->count_modifiers; j++) {
363*4882a593Smuzhiyun struct drm_format_modifier *mod = &modifiers[j];
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun if ((i < mod->offset) || (i > mod->offset + 63))
366*4882a593Smuzhiyun continue;
367*4882a593Smuzhiyun if (!(mod->formats & (1 << (i - mod->offset))))
368*4882a593Smuzhiyun continue;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun if (mod->modifier == DRM_AFBC_MODIFIER)
371*4882a593Smuzhiyun plane->can_afbc = 1;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if (mod->modifier == DRM_FORMAT_MOD_LINEAR)
374*4882a593Smuzhiyun plane->can_linear = 1;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun out:
378*4882a593Smuzhiyun drmModeFreePropertyBlob(blob);
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
drm_get_plane(drm_ctx * ctx,uint32_t plane_id)381*4882a593Smuzhiyun static drm_plane *drm_get_plane(drm_ctx *ctx, uint32_t plane_id)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun drm_plane *plane = calloc(1, sizeof(*plane));
384*4882a593Smuzhiyun if (!plane)
385*4882a593Smuzhiyun return NULL;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun plane->plane_id = plane_id;
388*4882a593Smuzhiyun plane->plane = drmModeGetPlane(ctx->fd, plane_id);
389*4882a593Smuzhiyun if (!plane->plane)
390*4882a593Smuzhiyun goto err;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun plane->props = drmModeObjectGetProperties(ctx->fd, plane_id,
393*4882a593Smuzhiyun DRM_MODE_OBJECT_PLANE);
394*4882a593Smuzhiyun if (!plane->props)
395*4882a593Smuzhiyun goto err;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun drm_plane_update_format(ctx, plane);
398*4882a593Smuzhiyun return plane;
399*4882a593Smuzhiyun err:
400*4882a593Smuzhiyun drm_free_plane(plane);
401*4882a593Smuzhiyun return NULL;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
drm_load_configs(drm_ctx * ctx)404*4882a593Smuzhiyun static void drm_load_configs(drm_ctx *ctx)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun struct stat st;
407*4882a593Smuzhiyun const char *file = DRM_CURSOR_CONFIG_FILE;
408*4882a593Smuzhiyun char *ptr, *tmp;
409*4882a593Smuzhiyun int fd;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun if (stat(file, &st) < 0)
412*4882a593Smuzhiyun return;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun fd = open(file, O_RDONLY);
415*4882a593Smuzhiyun if (fd < 0)
416*4882a593Smuzhiyun return;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
419*4882a593Smuzhiyun if (ptr == MAP_FAILED)
420*4882a593Smuzhiyun goto out_close_fd;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun ctx->configs = malloc(st.st_size + 1);
423*4882a593Smuzhiyun if (!ctx->configs)
424*4882a593Smuzhiyun goto out_unmap;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun memcpy(ctx->configs, ptr, st.st_size);
427*4882a593Smuzhiyun ctx->configs[st.st_size] = '\0';
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun tmp = ctx->configs;
430*4882a593Smuzhiyun while ((tmp = strchr(tmp, '#'))) {
431*4882a593Smuzhiyun while (*tmp != '\n' && *tmp != '\0')
432*4882a593Smuzhiyun *tmp++ = '\n';
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun out_unmap:
436*4882a593Smuzhiyun munmap(ptr, st.st_size);
437*4882a593Smuzhiyun out_close_fd:
438*4882a593Smuzhiyun close(fd);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
drm_get_config(drm_ctx * ctx,const char * name)441*4882a593Smuzhiyun static const char *drm_get_config(drm_ctx *ctx, const char *name)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun static char buf[4096];
444*4882a593Smuzhiyun const char *config;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun if (!ctx->configs)
447*4882a593Smuzhiyun return NULL;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun config = strstr(ctx->configs, name);
450*4882a593Smuzhiyun if (!config)
451*4882a593Smuzhiyun return NULL;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun if (config[strlen(name)] == '\n' || config[strlen(name)] == '\r')
454*4882a593Smuzhiyun return NULL;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun sscanf(config + strlen(name), "%4095s", buf);
457*4882a593Smuzhiyun return buf;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
drm_get_config_int(drm_ctx * ctx,const char * name,int def)460*4882a593Smuzhiyun static int drm_get_config_int(drm_ctx *ctx, const char *name, int def)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun const char *config = drm_get_config(ctx, name);
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if (config)
465*4882a593Smuzhiyun return atoi(config);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun return def;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
drm_get_ctx(int fd)470*4882a593Smuzhiyun static drm_ctx *drm_get_ctx(int fd)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun drm_ctx *ctx = &g_drm_ctx;
473*4882a593Smuzhiyun uint32_t prefer_planes[DRM_MAX_CRTCS] = { 0, };
474*4882a593Smuzhiyun uint32_t prefer_plane = 0;
475*4882a593Smuzhiyun uint32_t i, max_fps, count_crtcs;
476*4882a593Smuzhiyun const char *config;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun if (fd < 0)
479*4882a593Smuzhiyun return ctx;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun if (ctx->inited) {
482*4882a593Smuzhiyun /* Make sure the ctx's fd is the same as the input fd */
483*4882a593Smuzhiyun int flags = fcntl(ctx->fd, F_GETFL, 0);
484*4882a593Smuzhiyun if (fcntl(fd, F_GETFL, 0) == flags) {
485*4882a593Smuzhiyun fcntl(ctx->fd, F_SETFL, flags ^ O_NONBLOCK);
486*4882a593Smuzhiyun if (fcntl(fd, F_GETFL, 0) != flags) {
487*4882a593Smuzhiyun fcntl(ctx->fd, F_SETFL, flags);
488*4882a593Smuzhiyun return ctx;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun close(ctx->fd);
493*4882a593Smuzhiyun ctx->fd = dup(fd);
494*4882a593Smuzhiyun return ctx;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun /* Failed already */
498*4882a593Smuzhiyun if (ctx->fd < 0)
499*4882a593Smuzhiyun return NULL;
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun ctx->fd = dup(fd);
502*4882a593Smuzhiyun if (ctx->fd < 0)
503*4882a593Smuzhiyun return NULL;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun drm_load_configs(ctx);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun g_drm_debug = drm_get_config_int(ctx, OPT_DEBUG, 0);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun if (getenv("DRM_DEBUG") || !access("/tmp/.drm_cursor_debug", F_OK))
510*4882a593Smuzhiyun g_drm_debug = 1;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun if (!(config = getenv("DRM_CURSOR_LOG_FILE")))
513*4882a593Smuzhiyun config = drm_get_config(ctx, OPT_LOG_FILE);
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun g_log_fp = fopen(config ? config : "/var/log/drm-cursor.log", "wb+");
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun ctx->atomic = drm_get_config_int(ctx, OPT_ATOMIC, 1);
518*4882a593Smuzhiyun DRM_INFO("atomic drm API %s\n", ctx->atomic ? "enabled" : "disabled");
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun ctx->hide = drm_get_config_int(ctx, OPT_HIDE, 0);
521*4882a593Smuzhiyun if (ctx->hide)
522*4882a593Smuzhiyun DRM_INFO("invisible cursors\n");
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun #ifdef PREFER_AFBC_MODIFIER
525*4882a593Smuzhiyun ctx->prefer_afbc_modifier = 1;
526*4882a593Smuzhiyun #endif
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun ctx->prefer_afbc_modifier =
529*4882a593Smuzhiyun drm_get_config_int(ctx, OPT_PREFER_AFBC, ctx->prefer_afbc_modifier);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun if (ctx->prefer_afbc_modifier)
532*4882a593Smuzhiyun DRM_DEBUG("prefer ARM AFBC modifier\n");
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun ctx->allow_overlay = drm_get_config_int(ctx, OPT_ALLOW_OVERLAY, 0);
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun if (ctx->allow_overlay)
537*4882a593Smuzhiyun DRM_DEBUG("allow overlay planes\n");
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun drmSetClientCap(ctx->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun ctx->num_surfaces = drm_get_config_int(ctx, OPT_NUM_SURFACES, 8);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun max_fps = drm_get_config_int(ctx, OPT_MAX_FPS, 0);
544*4882a593Smuzhiyun if (max_fps <= 0)
545*4882a593Smuzhiyun max_fps = 60;
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun ctx->min_interval = 1000 / max_fps;
548*4882a593Smuzhiyun if (ctx->min_interval)
549*4882a593Smuzhiyun ctx->min_interval--;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun DRM_INFO("max fps: %d\n", max_fps);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun config = drm_get_config(ctx, OPT_SCALE_FROM);
554*4882a593Smuzhiyun if (config) {
555*4882a593Smuzhiyun int w, h, screen_w, screen_h;
556*4882a593Smuzhiyun if (config &&
557*4882a593Smuzhiyun sscanf(config, "%dx%d/%dx%d", &w, &h, &screen_w, &screen_h) == 4) {
558*4882a593Smuzhiyun ctx->scale_from = 1.0 * w * h / screen_w / screen_h;
559*4882a593Smuzhiyun DRM_INFO("scale from: %s\n", config);
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun } else {
562*4882a593Smuzhiyun config = drm_get_config(ctx, OPT_SCALE);
563*4882a593Smuzhiyun if (config && sscanf(config, "%fx%f", &ctx->scale_x, &ctx->scale_y) == 2)
564*4882a593Smuzhiyun DRM_INFO("scale: %s\n", config);
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun ctx->res = drmModeGetResources(ctx->fd);
568*4882a593Smuzhiyun if (!ctx->res)
569*4882a593Smuzhiyun goto err_free_configs;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun ctx->pres = drmModeGetPlaneResources(ctx->fd);
572*4882a593Smuzhiyun if (!ctx->pres)
573*4882a593Smuzhiyun goto err_free_res;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun count_crtcs = ctx->res->count_crtcs;
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun /* Allow specifying prefer plane */
578*4882a593Smuzhiyun if ((config = getenv("DRM_CURSOR_PREFER_PLANE")))
579*4882a593Smuzhiyun prefer_plane = atoi(config);
580*4882a593Smuzhiyun else
581*4882a593Smuzhiyun prefer_plane = drm_get_config_int(ctx, OPT_PREFER_PLANE, 0);
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun /* Allow specifying prefer planes */
584*4882a593Smuzhiyun if (!(config = getenv("DRM_CURSOR_PREFER_PLANES")))
585*4882a593Smuzhiyun config = drm_get_config(ctx, OPT_PREFER_PLANES);
586*4882a593Smuzhiyun for (i = 0; config && i < count_crtcs; i++) {
587*4882a593Smuzhiyun prefer_planes[i] = atoi(config);
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun config = strchr(config, ',');
590*4882a593Smuzhiyun if (config)
591*4882a593Smuzhiyun config++;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun /* Fetch all CRTCs */
595*4882a593Smuzhiyun for (i = 0; i < count_crtcs; i++) {
596*4882a593Smuzhiyun drmModeCrtcPtr c = drmModeGetCrtc(ctx->fd, ctx->res->crtcs[i]);
597*4882a593Smuzhiyun drm_crtc *crtc = &ctx->crtcs[ctx->num_crtcs];
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun if (!c)
600*4882a593Smuzhiyun continue;
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun crtc->crtc_id = c->crtc_id;
603*4882a593Smuzhiyun crtc->crtc_pipe = i;
604*4882a593Smuzhiyun crtc->prefer_plane_id = prefer_planes[i] ? prefer_planes[i] : prefer_plane;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun DRM_DEBUG("found %d CRTC: %d(%d) (%dx%d) prefer plane: %d\n",
607*4882a593Smuzhiyun ctx->num_crtcs, c->crtc_id, i, c->width, c->height,
608*4882a593Smuzhiyun crtc->prefer_plane_id);
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun ctx->num_crtcs++;
611*4882a593Smuzhiyun drmModeFreeCrtc(c);
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun DRM_DEBUG("found %d CRTCs\n", ctx->num_crtcs);
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun if (!ctx->num_crtcs)
617*4882a593Smuzhiyun goto err_free_pres;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun config = drm_get_config(ctx, OPT_CRTC_BLOCKLIST);
620*4882a593Smuzhiyun for (i = 0; config && i < count_crtcs; i++) {
621*4882a593Smuzhiyun uint32_t crtc_id = atoi(config);
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun for (int j = 0; j < ctx->num_crtcs; j++) {
624*4882a593Smuzhiyun drm_crtc *crtc = &ctx->crtcs[j];
625*4882a593Smuzhiyun if (crtc->crtc_id != crtc_id)
626*4882a593Smuzhiyun continue;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun DRM_DEBUG("CRTC: %d blocked\n", crtc_id);
629*4882a593Smuzhiyun crtc->blocked = 1;
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun config = strchr(config, ',');
633*4882a593Smuzhiyun if (config)
634*4882a593Smuzhiyun config++;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun if (g_drm_debug) {
638*4882a593Smuzhiyun /* Dump planes for debugging */
639*4882a593Smuzhiyun for (i = 0; i < ctx->pres->count_planes; i++) {
640*4882a593Smuzhiyun drm_plane *plane = drm_get_plane(ctx, ctx->pres->planes[i]);
641*4882a593Smuzhiyun char *type;
642*4882a593Smuzhiyun uint64_t value = 0;
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun if (!plane)
645*4882a593Smuzhiyun continue;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun drm_plane_get_prop_value(ctx, plane, PLANE_PROP_type, &value);
648*4882a593Smuzhiyun switch (value) {
649*4882a593Smuzhiyun case DRM_PLANE_TYPE_PRIMARY:
650*4882a593Smuzhiyun type = "primary";
651*4882a593Smuzhiyun break;
652*4882a593Smuzhiyun case DRM_PLANE_TYPE_OVERLAY:
653*4882a593Smuzhiyun type = "overlay";
654*4882a593Smuzhiyun break;
655*4882a593Smuzhiyun case DRM_PLANE_TYPE_CURSOR:
656*4882a593Smuzhiyun type = "cursor ";
657*4882a593Smuzhiyun break;
658*4882a593Smuzhiyun default:
659*4882a593Smuzhiyun type = "unknown";
660*4882a593Smuzhiyun break;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun DRM_DEBUG("found plane: %d[%s] crtcs: 0x%x %s%s\n",
664*4882a593Smuzhiyun plane->plane_id, type, plane->plane->possible_crtcs,
665*4882a593Smuzhiyun plane->can_linear ? "(ARGB)" : "",
666*4882a593Smuzhiyun plane->can_afbc ? "(AFBC)" : "");
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun drm_free_plane(plane);
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun DRM_INFO("using libdrm-cursor (%s)\n", LIBDRM_CURSOR_VERSION);
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun ctx->inited = 1;
675*4882a593Smuzhiyun return ctx;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun err_free_pres:
678*4882a593Smuzhiyun drmModeFreePlaneResources(ctx->pres);
679*4882a593Smuzhiyun err_free_res:
680*4882a593Smuzhiyun drmModeFreeResources(ctx->res);
681*4882a593Smuzhiyun err_free_configs:
682*4882a593Smuzhiyun free(ctx->configs);
683*4882a593Smuzhiyun close(ctx->fd);
684*4882a593Smuzhiyun ctx->fd = -1;
685*4882a593Smuzhiyun return NULL;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun #define drm_crtc_bind_plane_force(ctx, crtc, plane) \
689*4882a593Smuzhiyun drm_crtc_bind_plane(ctx, crtc, plane, 1)
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun #define drm_crtc_bind_plane_cursor(ctx, crtc, plane) \
692*4882a593Smuzhiyun drm_crtc_bind_plane(ctx, crtc, plane, 0)
693*4882a593Smuzhiyun
drm_crtc_bind_plane(drm_ctx * ctx,drm_crtc * crtc,uint32_t plane_id,int allow_overlay)694*4882a593Smuzhiyun static int drm_crtc_bind_plane(drm_ctx *ctx, drm_crtc *crtc, uint32_t plane_id,
695*4882a593Smuzhiyun int allow_overlay)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun drm_plane *plane;
698*4882a593Smuzhiyun uint64_t value;
699*4882a593Smuzhiyun int i;
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun /* CRTC already assigned */
702*4882a593Smuzhiyun if (crtc->plane)
703*4882a593Smuzhiyun return 1;
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun /* Plane already assigned */
706*4882a593Smuzhiyun for (i = 0; i < ctx->num_crtcs; i++) {
707*4882a593Smuzhiyun if (ctx->crtcs[i].plane && ctx->crtcs[i].plane->plane_id == plane_id)
708*4882a593Smuzhiyun return -1;
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun plane = drm_get_plane(ctx, plane_id);
712*4882a593Smuzhiyun if (!plane)
713*4882a593Smuzhiyun return -1;
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun /* Unable to use */
716*4882a593Smuzhiyun if (!plane->can_afbc && !plane->can_linear)
717*4882a593Smuzhiyun goto err;
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun /* Not for this CRTC */
720*4882a593Smuzhiyun if (!(plane->plane->possible_crtcs & (1 << crtc->crtc_pipe)))
721*4882a593Smuzhiyun goto err;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun /* Not using primary planes */
724*4882a593Smuzhiyun if (drm_plane_get_prop_value(ctx, plane, PLANE_PROP_type, &value) < 0)
725*4882a593Smuzhiyun goto err;
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun if (value == DRM_PLANE_TYPE_PRIMARY)
728*4882a593Smuzhiyun goto err;
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun /* Check for overlay plane */
731*4882a593Smuzhiyun if (!allow_overlay && value == DRM_PLANE_TYPE_OVERLAY)
732*4882a593Smuzhiyun goto err;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun plane->cursor_plane = value == DRM_PLANE_TYPE_CURSOR;
735*4882a593Smuzhiyun if (plane->cursor_plane)
736*4882a593Smuzhiyun DRM_INFO("CRTC[%d]: using cursor plane\n", crtc->crtc_id);
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun if (ctx->prefer_afbc_modifier && plane->can_afbc)
739*4882a593Smuzhiyun crtc->use_afbc_modifier = 1;
740*4882a593Smuzhiyun else if (!plane->can_linear)
741*4882a593Smuzhiyun crtc->use_afbc_modifier = 1;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: bind plane: %d%s\n", crtc->crtc_id, plane->plane_id,
744*4882a593Smuzhiyun crtc->use_afbc_modifier ? "(AFBC)" : "");
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun crtc->plane = plane;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun return 0;
749*4882a593Smuzhiyun err:
750*4882a593Smuzhiyun drm_free_plane(plane);
751*4882a593Smuzhiyun return -1;
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
drm_crtc_valid(drm_crtc * crtc)754*4882a593Smuzhiyun static int drm_crtc_valid(drm_crtc *crtc)
755*4882a593Smuzhiyun {
756*4882a593Smuzhiyun return (crtc->width > 0 && crtc->height > 0) ? 0 : -1;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
drm_update_crtc(drm_ctx * ctx,drm_crtc * crtc)759*4882a593Smuzhiyun static int drm_update_crtc(drm_ctx *ctx, drm_crtc *crtc)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun drmModeCrtcPtr c;
762*4882a593Smuzhiyun int was_connected, connected;
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun c = drmModeGetCrtc(ctx->fd, crtc->crtc_id);
765*4882a593Smuzhiyun if (!c)
766*4882a593Smuzhiyun return -1;
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun was_connected = drm_crtc_valid(crtc) >= 0;
769*4882a593Smuzhiyun crtc->width = c->width;
770*4882a593Smuzhiyun crtc->height = c->height;
771*4882a593Smuzhiyun connected = drm_crtc_valid(crtc) >= 0;
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun drmModeFreeCrtc(c);
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun if (connected != was_connected)
776*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: %s!\n", crtc->crtc_id, \
777*4882a593Smuzhiyun connected ? "connected" : "disconnected");
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun return drm_crtc_valid(crtc);
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun
drm_crtc_update_offsets(drm_ctx * ctx,drm_crtc * crtc,drm_cursor_state * cursor_state)782*4882a593Smuzhiyun static int drm_crtc_update_offsets(drm_ctx *ctx, drm_crtc *crtc,
783*4882a593Smuzhiyun drm_cursor_state *cursor_state)
784*4882a593Smuzhiyun {
785*4882a593Smuzhiyun int x, y, off_x, off_y, width, height, area_w, area_h;
786*4882a593Smuzhiyun float scale_x, scale_y;
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun if (drm_update_crtc(ctx, crtc) < 0)
789*4882a593Smuzhiyun return -1;
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun width = cursor_state->width;
792*4882a593Smuzhiyun height = cursor_state->height;
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun if (ctx->scale_from) {
795*4882a593Smuzhiyun scale_x = scale_y =
796*4882a593Smuzhiyun ctx->scale_from * crtc->width * crtc->height / width / height;
797*4882a593Smuzhiyun } else {
798*4882a593Smuzhiyun scale_x = ctx->scale_x ? ctx->scale_x : 1.0;
799*4882a593Smuzhiyun scale_y = ctx->scale_y ? ctx->scale_y : 1.0;
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun width *= scale_x;
803*4882a593Smuzhiyun height *= scale_y;
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun x = cursor_state->x + cursor_state->hot_x - cursor_state->hot_x * scale_x;
806*4882a593Smuzhiyun y = cursor_state->y + cursor_state->hot_y - cursor_state->hot_y * scale_y;
807*4882a593Smuzhiyun area_w = crtc->width - width;
808*4882a593Smuzhiyun area_h = crtc->height - height;
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun off_x = off_y = 0;
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun if (x < 0)
813*4882a593Smuzhiyun off_x = x;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun if (y < 0)
816*4882a593Smuzhiyun off_y = y;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun if (x > area_w)
819*4882a593Smuzhiyun off_x = x - area_w;
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun if (y > area_h)
822*4882a593Smuzhiyun off_y = y - area_h;
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun cursor_state->scaled_x = x;
825*4882a593Smuzhiyun cursor_state->scaled_y = y;
826*4882a593Smuzhiyun cursor_state->off_x = off_x;
827*4882a593Smuzhiyun cursor_state->off_y = off_y;
828*4882a593Smuzhiyun cursor_state->scaled_w = width;
829*4882a593Smuzhiyun cursor_state->scaled_h = height;
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun return 0;
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun #define drm_crtc_disable_cursor(ctx, crtc) \
835*4882a593Smuzhiyun drm_crtc_update_cursor(ctx, crtc, NULL)
836*4882a593Smuzhiyun
drm_crtc_update_cursor(drm_ctx * ctx,drm_crtc * crtc,drm_cursor_state * cursor_state)837*4882a593Smuzhiyun static int drm_crtc_update_cursor(drm_ctx *ctx, drm_crtc *crtc,
838*4882a593Smuzhiyun drm_cursor_state *cursor_state)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun drm_plane *plane = crtc->plane;
841*4882a593Smuzhiyun uint32_t old_fb = crtc->cursor_curr.fb;
842*4882a593Smuzhiyun uint32_t fb;
843*4882a593Smuzhiyun int x, y, w, h, ret;
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun /* Disable */
846*4882a593Smuzhiyun if (!cursor_state) {
847*4882a593Smuzhiyun if (old_fb) {
848*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: disabling cursor\n", crtc->crtc_id);
849*4882a593Smuzhiyun drm_set_plane(ctx, crtc, plane, 0, 0, 0, 0, 0);
850*4882a593Smuzhiyun drmModeRmFB(ctx->fd, old_fb);
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun memset(&crtc->cursor_curr, 0, sizeof(drm_cursor_state));
854*4882a593Smuzhiyun return 0;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun /* Unchanged */
858*4882a593Smuzhiyun if (crtc->cursor_curr.fb == cursor_state->fb &&
859*4882a593Smuzhiyun crtc->cursor_curr.scaled_x == cursor_state->scaled_x &&
860*4882a593Smuzhiyun crtc->cursor_curr.scaled_y == cursor_state->scaled_y &&
861*4882a593Smuzhiyun crtc->cursor_curr.off_x == cursor_state->off_x &&
862*4882a593Smuzhiyun crtc->cursor_curr.off_y == cursor_state->off_y) {
863*4882a593Smuzhiyun crtc->cursor_curr = *cursor_state;
864*4882a593Smuzhiyun return 0;
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun fb = cursor_state->fb;
868*4882a593Smuzhiyun x = cursor_state->scaled_x - cursor_state->off_x;
869*4882a593Smuzhiyun y = cursor_state->scaled_y - cursor_state->off_y;
870*4882a593Smuzhiyun w = cursor_state->scaled_w;
871*4882a593Smuzhiyun h = cursor_state->scaled_h;
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: setting fb: %d (%dx%d) on plane: %d at (%d,%d)\n",
874*4882a593Smuzhiyun crtc->crtc_id, fb, w, h, plane->plane_id, x, y);
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun ret = drm_set_plane(ctx, crtc, plane, fb, x, y, w, h);
877*4882a593Smuzhiyun if (ret)
878*4882a593Smuzhiyun DRM_ERROR("CRTC[%d]: failed to set plane (%d)\n", crtc->crtc_id, errno);
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun if (old_fb && old_fb != fb) {
881*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: remove FB: %d\n", crtc->crtc_id, old_fb);
882*4882a593Smuzhiyun drmModeRmFB(ctx->fd, old_fb);
883*4882a593Smuzhiyun }
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun crtc->cursor_curr = *cursor_state;
886*4882a593Smuzhiyun return ret;
887*4882a593Smuzhiyun }
888*4882a593Smuzhiyun
drm_crtc_create_fb(drm_ctx * ctx,drm_crtc * crtc,drm_cursor_state * cursor_state)889*4882a593Smuzhiyun static int drm_crtc_create_fb(drm_ctx *ctx, drm_crtc *crtc,
890*4882a593Smuzhiyun drm_cursor_state *cursor_state)
891*4882a593Smuzhiyun {
892*4882a593Smuzhiyun uint32_t handle = cursor_state->handle;
893*4882a593Smuzhiyun int width = cursor_state->width;
894*4882a593Smuzhiyun int height = cursor_state->height;
895*4882a593Smuzhiyun int scaled_w = cursor_state->scaled_w;
896*4882a593Smuzhiyun int scaled_h = cursor_state->scaled_h;
897*4882a593Smuzhiyun int off_x = cursor_state->off_x;
898*4882a593Smuzhiyun int off_y = cursor_state->off_y;
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: convert FB from %d (%dx%d) to (%dx%d) offset: (%d,%d)\n",
901*4882a593Smuzhiyun crtc->crtc_id, handle, width, height,
902*4882a593Smuzhiyun scaled_w, scaled_h, off_x, off_y);
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun if (!crtc->egl_ctx) {
905*4882a593Smuzhiyun uint64_t modifier;
906*4882a593Smuzhiyun int format;
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun if (crtc->use_afbc_modifier) {
909*4882a593Smuzhiyun /* Mali only support AFBC with BGR formats now */
910*4882a593Smuzhiyun format = GBM_FORMAT_ABGR8888;
911*4882a593Smuzhiyun modifier = DRM_AFBC_MODIFIER;
912*4882a593Smuzhiyun } else {
913*4882a593Smuzhiyun format = GBM_FORMAT_ARGB8888;
914*4882a593Smuzhiyun modifier = 0;
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun crtc->egl_ctx = egl_init_ctx(ctx->fd, ctx->num_surfaces, format, modifier);
918*4882a593Smuzhiyun if (!crtc->egl_ctx) {
919*4882a593Smuzhiyun DRM_ERROR("CRTC[%d]: failed to init egl ctx\n", crtc->crtc_id);
920*4882a593Smuzhiyun return -1;
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun }
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun cursor_state->fb =
925*4882a593Smuzhiyun egl_convert_fb(ctx->fd, crtc->egl_ctx, handle, width, height,
926*4882a593Smuzhiyun scaled_w, scaled_h, off_x, off_y);
927*4882a593Smuzhiyun if (!cursor_state->fb) {
928*4882a593Smuzhiyun DRM_ERROR("CRTC[%d]: failed to create FB\n", crtc->crtc_id);
929*4882a593Smuzhiyun return -1;
930*4882a593Smuzhiyun }
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: created FB: %d\n", crtc->crtc_id, cursor_state->fb);
933*4882a593Smuzhiyun return 0;
934*4882a593Smuzhiyun }
935*4882a593Smuzhiyun
drm_crtc_thread_fn(void * data)936*4882a593Smuzhiyun static void *drm_crtc_thread_fn(void *data)
937*4882a593Smuzhiyun {
938*4882a593Smuzhiyun drm_ctx *ctx = drm_get_ctx(-1);
939*4882a593Smuzhiyun drm_crtc *crtc = data;
940*4882a593Smuzhiyun drm_plane *plane = crtc->plane;
941*4882a593Smuzhiyun drm_cursor_state cursor_state;
942*4882a593Smuzhiyun uint64_t duration;
943*4882a593Smuzhiyun char name[256];
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: thread started\n", crtc->crtc_id);
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun /**
948*4882a593Smuzhiyun * The new DRM driver doesn't allow setting atomic cap for Xorg.
949*4882a593Smuzhiyun * Let's use a custom thread name to workaround that.
950*4882a593Smuzhiyun */
951*4882a593Smuzhiyun snprintf(name, sizeof(name), "drm-cursor[%d]", crtc->crtc_id);
952*4882a593Smuzhiyun pthread_setname_np(crtc->thread, name);
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun if (!plane->cursor_plane) {
955*4882a593Smuzhiyun drmSetClientCap(ctx->fd, DRM_CLIENT_CAP_ATOMIC, 1);
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun /* Reflush props with atomic cap enabled */
958*4882a593Smuzhiyun drmModeFreeObjectProperties(plane->props);
959*4882a593Smuzhiyun plane->props = drmModeObjectGetProperties(ctx->fd, plane->plane_id,
960*4882a593Smuzhiyun DRM_MODE_OBJECT_PLANE);
961*4882a593Smuzhiyun if (!plane->props)
962*4882a593Smuzhiyun goto error;
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun /* Set maximum ZPOS */
965*4882a593Smuzhiyun drm_plane_set_prop_max(ctx, plane, PLANE_PROP_zpos);
966*4882a593Smuzhiyun drm_plane_set_prop_max(ctx, plane, PLANE_PROP_ZPOS);
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun /* Set async commit for Rockchip BSP kernel */
969*4882a593Smuzhiyun crtc->async_commit =
970*4882a593Smuzhiyun !drm_plane_set_prop_max(ctx, plane, PLANE_PROP_ASYNC_COMMIT);
971*4882a593Smuzhiyun if (crtc->async_commit)
972*4882a593Smuzhiyun DRM_INFO("CRTC[%d]: using async commit\n", crtc->crtc_id);
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun crtc->last_update_time = drm_curr_time();
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun while (1) {
978*4882a593Smuzhiyun /* Wait for new cursor state */
979*4882a593Smuzhiyun pthread_mutex_lock(&crtc->mutex);
980*4882a593Smuzhiyun while (crtc->state != PENDING)
981*4882a593Smuzhiyun pthread_cond_wait(&crtc->cond, &crtc->mutex);
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun cursor_state = crtc->cursor_next;
984*4882a593Smuzhiyun crtc->cursor_next.request = 0;
985*4882a593Smuzhiyun crtc->state = IDLE;
986*4882a593Smuzhiyun cursor_state.request |= crtc->cursor_curr.request; /* For retry */
987*4882a593Smuzhiyun pthread_mutex_unlock(&crtc->mutex);
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun /* For edge moving */
990*4882a593Smuzhiyun if (drm_crtc_update_offsets(ctx, crtc, &cursor_state) < 0) {
991*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: unavailable!\n", crtc->crtc_id);
992*4882a593Smuzhiyun drm_crtc_disable_cursor(ctx, crtc);
993*4882a593Smuzhiyun goto retry;
994*4882a593Smuzhiyun }
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun if (cursor_state.request & REQ_SET_CURSOR) {
997*4882a593Smuzhiyun cursor_state.request = 0;
998*4882a593Smuzhiyun
999*4882a593Smuzhiyun /* Handle set-cursor */
1000*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: set new cursor %d (%dx%d)\n",
1001*4882a593Smuzhiyun crtc->crtc_id, cursor_state.handle,
1002*4882a593Smuzhiyun cursor_state.width, cursor_state.height);
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun if (!cursor_state.handle) {
1005*4882a593Smuzhiyun drm_crtc_disable_cursor(ctx, crtc);
1006*4882a593Smuzhiyun goto next;
1007*4882a593Smuzhiyun }
1008*4882a593Smuzhiyun
1009*4882a593Smuzhiyun if (drm_crtc_create_fb(ctx, crtc, &cursor_state) < 0)
1010*4882a593Smuzhiyun goto error;
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun if (drm_crtc_update_cursor(ctx, crtc, &cursor_state) < 0) {
1013*4882a593Smuzhiyun DRM_ERROR("CRTC[%d]: failed to set cursor\n", crtc->crtc_id);
1014*4882a593Smuzhiyun goto error;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun } else if (cursor_state.request & REQ_MOVE_CURSOR) {
1017*4882a593Smuzhiyun cursor_state.request = 0;
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun /* Handle move-cursor */
1020*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: move cursor to (%d[%d],%d[%d])\n",
1021*4882a593Smuzhiyun crtc->crtc_id, cursor_state.scaled_x, -cursor_state.off_x,
1022*4882a593Smuzhiyun cursor_state.scaled_y, -cursor_state.off_y);
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun if (!crtc->cursor_curr.handle) {
1025*4882a593Smuzhiyun /* Pre-moving */
1026*4882a593Smuzhiyun crtc->cursor_curr = cursor_state;
1027*4882a593Smuzhiyun goto next;
1028*4882a593Smuzhiyun } else if (crtc->cursor_curr.off_x != cursor_state.off_x ||
1029*4882a593Smuzhiyun crtc->cursor_curr.off_y != cursor_state.off_y) {
1030*4882a593Smuzhiyun /* Edge moving */
1031*4882a593Smuzhiyun if (drm_crtc_create_fb(ctx, crtc, &cursor_state) < 0)
1032*4882a593Smuzhiyun goto error;
1033*4882a593Smuzhiyun } else {
1034*4882a593Smuzhiyun /* Normal moving */
1035*4882a593Smuzhiyun cursor_state.fb = crtc->cursor_curr.fb;
1036*4882a593Smuzhiyun }
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun if (drm_crtc_update_cursor(ctx, crtc, &cursor_state) < 0) {
1039*4882a593Smuzhiyun DRM_ERROR("CRTC[%d]: failed to move cursor\n", crtc->crtc_id);
1040*4882a593Smuzhiyun goto error;
1041*4882a593Smuzhiyun }
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun if (!crtc->verified && crtc->cursor_curr.fb) {
1045*4882a593Smuzhiyun pthread_mutex_lock(&crtc->mutex);
1046*4882a593Smuzhiyun DRM_INFO("CRTC[%d]: it works!\n", crtc->crtc_id);
1047*4882a593Smuzhiyun crtc->verified = 1;
1048*4882a593Smuzhiyun pthread_cond_signal(&crtc->cond);
1049*4882a593Smuzhiyun pthread_mutex_unlock(&crtc->mutex);
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun next:
1053*4882a593Smuzhiyun duration = drm_curr_time() - crtc->last_update_time;
1054*4882a593Smuzhiyun if (duration < ctx->min_interval)
1055*4882a593Smuzhiyun usleep((ctx->min_interval - duration) * 1000);
1056*4882a593Smuzhiyun crtc->last_update_time = drm_curr_time();;
1057*4882a593Smuzhiyun continue;
1058*4882a593Smuzhiyun retry:
1059*4882a593Smuzhiyun /* Force setting cursor in next request */
1060*4882a593Smuzhiyun pthread_mutex_lock(&crtc->mutex);
1061*4882a593Smuzhiyun crtc->cursor_curr.request = REQ_SET_CURSOR;
1062*4882a593Smuzhiyun pthread_cond_signal(&crtc->cond);
1063*4882a593Smuzhiyun pthread_mutex_unlock(&crtc->mutex);
1064*4882a593Smuzhiyun goto next;
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun error:
1068*4882a593Smuzhiyun if (crtc->egl_ctx)
1069*4882a593Smuzhiyun egl_free_ctx(crtc->egl_ctx);
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun drm_crtc_disable_cursor(ctx, crtc);
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun pthread_mutex_lock(&crtc->mutex);
1074*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: thread error\n", crtc->crtc_id);
1075*4882a593Smuzhiyun crtc->state = FATAL_ERROR;
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun if (crtc->plane) {
1078*4882a593Smuzhiyun drm_free_plane(crtc->plane);
1079*4882a593Smuzhiyun crtc->plane = NULL;
1080*4882a593Smuzhiyun }
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun pthread_cond_signal(&crtc->cond);
1083*4882a593Smuzhiyun pthread_mutex_unlock(&crtc->mutex);
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun return NULL;
1086*4882a593Smuzhiyun }
1087*4882a593Smuzhiyun
drm_crtc_prepare(drm_ctx * ctx,drm_crtc * crtc)1088*4882a593Smuzhiyun static int drm_crtc_prepare(drm_ctx *ctx, drm_crtc *crtc)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun uint32_t i;
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun /* Update CRTC if unavailable */
1093*4882a593Smuzhiyun if (drm_crtc_valid(crtc) < 0)
1094*4882a593Smuzhiyun drm_update_crtc(ctx, crtc);
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun /* CRTC already assigned */
1097*4882a593Smuzhiyun if (crtc->plane)
1098*4882a593Smuzhiyun return 1;
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun /* Try specific plane */
1101*4882a593Smuzhiyun if (crtc->prefer_plane_id)
1102*4882a593Smuzhiyun drm_crtc_bind_plane_force(ctx, crtc, crtc->prefer_plane_id);
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun /* Try cursor plane */
1105*4882a593Smuzhiyun for (i = 0; !crtc->plane && i < ctx->pres->count_planes; i++)
1106*4882a593Smuzhiyun drm_crtc_bind_plane_cursor(ctx, crtc, ctx->pres->planes[i]);
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun /* Fallback to any available overlay plane */
1109*4882a593Smuzhiyun if (ctx->allow_overlay) {
1110*4882a593Smuzhiyun for (i = ctx->pres->count_planes; !crtc->plane && i; i--)
1111*4882a593Smuzhiyun drm_crtc_bind_plane_force(ctx, crtc, ctx->pres->planes[i - 1]);
1112*4882a593Smuzhiyun }
1113*4882a593Smuzhiyun
1114*4882a593Smuzhiyun if (!crtc->plane) {
1115*4882a593Smuzhiyun DRM_ERROR("CRTC[%d]: failed to find any plane\n", crtc->crtc_id);
1116*4882a593Smuzhiyun return -1;
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun
1119*4882a593Smuzhiyun crtc->state = IDLE;
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun pthread_cond_init(&crtc->cond, NULL);
1122*4882a593Smuzhiyun pthread_mutex_init(&crtc->mutex, NULL);
1123*4882a593Smuzhiyun pthread_create(&crtc->thread, NULL, drm_crtc_thread_fn, crtc);
1124*4882a593Smuzhiyun
1125*4882a593Smuzhiyun return 0;
1126*4882a593Smuzhiyun }
1127*4882a593Smuzhiyun
drm_get_crtc(drm_ctx * ctx,uint32_t crtc_id)1128*4882a593Smuzhiyun static drm_crtc *drm_get_crtc(drm_ctx *ctx, uint32_t crtc_id)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun drm_crtc *crtc = NULL;
1131*4882a593Smuzhiyun int i;
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun for (i = 0; i < ctx->num_crtcs; i++) {
1134*4882a593Smuzhiyun crtc = &ctx->crtcs[i];
1135*4882a593Smuzhiyun if (!crtc_id && drm_update_crtc(ctx, crtc) < 0)
1136*4882a593Smuzhiyun continue;
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun if (crtc->blocked)
1139*4882a593Smuzhiyun continue;
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun if (!crtc_id || crtc->crtc_id == crtc_id)
1142*4882a593Smuzhiyun break;
1143*4882a593Smuzhiyun }
1144*4882a593Smuzhiyun
1145*4882a593Smuzhiyun if (i == ctx->num_crtcs) {
1146*4882a593Smuzhiyun DRM_ERROR("CRTC[%d]: not available\n", crtc_id);
1147*4882a593Smuzhiyun return NULL;
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun return crtc;
1151*4882a593Smuzhiyun }
1152*4882a593Smuzhiyun
drm_set_cursor(int fd,uint32_t crtc_id,uint32_t handle,uint32_t width,uint32_t height,int hot_x,int hot_y)1153*4882a593Smuzhiyun static int drm_set_cursor(int fd, uint32_t crtc_id, uint32_t handle,
1154*4882a593Smuzhiyun uint32_t width, uint32_t height,
1155*4882a593Smuzhiyun int hot_x, int hot_y)
1156*4882a593Smuzhiyun {
1157*4882a593Smuzhiyun drm_crtc *crtc;
1158*4882a593Smuzhiyun drm_ctx *ctx;
1159*4882a593Smuzhiyun drm_cursor_state *cursor_next;
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun ctx = drm_get_ctx(fd);
1162*4882a593Smuzhiyun if (!ctx)
1163*4882a593Smuzhiyun return -1;
1164*4882a593Smuzhiyun
1165*4882a593Smuzhiyun if (ctx->hide)
1166*4882a593Smuzhiyun return 0;
1167*4882a593Smuzhiyun
1168*4882a593Smuzhiyun crtc = drm_get_crtc(ctx, crtc_id);
1169*4882a593Smuzhiyun if (!crtc)
1170*4882a593Smuzhiyun return -1;
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun if (drm_crtc_prepare(ctx, crtc) < 0)
1173*4882a593Smuzhiyun return -1;
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: request setting new cursor %d (%dx%d)\n",
1176*4882a593Smuzhiyun crtc->crtc_id, handle, width, height);
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun pthread_mutex_lock(&crtc->mutex);
1179*4882a593Smuzhiyun if (crtc->state == FATAL_ERROR) {
1180*4882a593Smuzhiyun pthread_mutex_unlock(&crtc->mutex);
1181*4882a593Smuzhiyun DRM_ERROR("CRTC[%d]: failed to set cursor\n", crtc->crtc_id);
1182*4882a593Smuzhiyun return -1;
1183*4882a593Smuzhiyun }
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun /* Update next cursor state and notify the thread */
1186*4882a593Smuzhiyun cursor_next = &crtc->cursor_next;
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun crtc->cursor_curr.request = 0;
1189*4882a593Smuzhiyun cursor_next->request = REQ_SET_CURSOR;
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun cursor_next->fb = 0;
1192*4882a593Smuzhiyun cursor_next->handle = handle;
1193*4882a593Smuzhiyun cursor_next->width = width;
1194*4882a593Smuzhiyun cursor_next->height = height;
1195*4882a593Smuzhiyun cursor_next->hot_x = hot_x;
1196*4882a593Smuzhiyun cursor_next->hot_y = hot_y;
1197*4882a593Smuzhiyun crtc->state = PENDING;
1198*4882a593Smuzhiyun pthread_cond_signal(&crtc->cond);
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun if (handle) {
1201*4882a593Smuzhiyun /**
1202*4882a593Smuzhiyun * Wait for verified or fatal error or retry.
1203*4882a593Smuzhiyun * HACK: Fake retry as successed.
1204*4882a593Smuzhiyun */
1205*4882a593Smuzhiyun while (!crtc->verified && crtc->state != FATAL_ERROR && \
1206*4882a593Smuzhiyun !crtc->cursor_curr.request)
1207*4882a593Smuzhiyun pthread_cond_wait(&crtc->cond, &crtc->mutex);
1208*4882a593Smuzhiyun }
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun pthread_mutex_unlock(&crtc->mutex);
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun if (crtc->state == FATAL_ERROR) {
1213*4882a593Smuzhiyun DRM_ERROR("CRTC[%d]: failed to set cursor\n", crtc->crtc_id);
1214*4882a593Smuzhiyun return -1;
1215*4882a593Smuzhiyun }
1216*4882a593Smuzhiyun
1217*4882a593Smuzhiyun return 0;
1218*4882a593Smuzhiyun }
1219*4882a593Smuzhiyun
drm_move_cursor(int fd,uint32_t crtc_id,int x,int y)1220*4882a593Smuzhiyun static int drm_move_cursor(int fd, uint32_t crtc_id, int x, int y)
1221*4882a593Smuzhiyun {
1222*4882a593Smuzhiyun drm_ctx *ctx;
1223*4882a593Smuzhiyun drm_crtc *crtc;
1224*4882a593Smuzhiyun drm_cursor_state *cursor_next;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun ctx = drm_get_ctx(fd);
1227*4882a593Smuzhiyun if (!ctx)
1228*4882a593Smuzhiyun return -1;
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun if (ctx->hide)
1231*4882a593Smuzhiyun return 0;
1232*4882a593Smuzhiyun
1233*4882a593Smuzhiyun crtc = drm_get_crtc(ctx, crtc_id);
1234*4882a593Smuzhiyun if (!crtc)
1235*4882a593Smuzhiyun return -1;
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun if (crtc->state == FATAL_ERROR || drm_crtc_prepare(ctx, crtc) < 0)
1238*4882a593Smuzhiyun return -1;
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun if (drm_crtc_valid(crtc) < 0)
1241*4882a593Smuzhiyun return -1;
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun DRM_DEBUG("CRTC[%d]: request moving cursor to (%d,%d) in (%dx%d)\n",
1244*4882a593Smuzhiyun crtc->crtc_id, x, y, crtc->width, crtc->height);
1245*4882a593Smuzhiyun
1246*4882a593Smuzhiyun pthread_mutex_lock(&crtc->mutex);
1247*4882a593Smuzhiyun if (crtc->state == FATAL_ERROR) {
1248*4882a593Smuzhiyun pthread_mutex_unlock(&crtc->mutex);
1249*4882a593Smuzhiyun return -1;
1250*4882a593Smuzhiyun }
1251*4882a593Smuzhiyun
1252*4882a593Smuzhiyun /* Update next cursor state and notify the thread */
1253*4882a593Smuzhiyun cursor_next = &crtc->cursor_next;
1254*4882a593Smuzhiyun
1255*4882a593Smuzhiyun cursor_next->request |= REQ_MOVE_CURSOR;
1256*4882a593Smuzhiyun cursor_next->fb = 0;
1257*4882a593Smuzhiyun cursor_next->x = x;
1258*4882a593Smuzhiyun cursor_next->y = y;
1259*4882a593Smuzhiyun crtc->state = PENDING;
1260*4882a593Smuzhiyun pthread_cond_signal(&crtc->cond);
1261*4882a593Smuzhiyun pthread_mutex_unlock(&crtc->mutex);
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun return 0;
1264*4882a593Smuzhiyun }
1265*4882a593Smuzhiyun
1266*4882a593Smuzhiyun /* Hook functions */
1267*4882a593Smuzhiyun
drmModeSetCursor2(int fd,uint32_t crtcId,uint32_t bo_handle,uint32_t width,uint32_t height,int32_t hot_x,int32_t hot_y)1268*4882a593Smuzhiyun int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle,
1269*4882a593Smuzhiyun uint32_t width, uint32_t height,
1270*4882a593Smuzhiyun int32_t hot_x, int32_t hot_y)
1271*4882a593Smuzhiyun {
1272*4882a593Smuzhiyun /* Init log file */
1273*4882a593Smuzhiyun drm_get_ctx(fd);
1274*4882a593Smuzhiyun
1275*4882a593Smuzhiyun DRM_DEBUG("fd: %d crtc: %d handle: %d size: %dx%d (%d, %d)\n",
1276*4882a593Smuzhiyun fd, crtcId, bo_handle, width, height, hot_x, hot_y);
1277*4882a593Smuzhiyun return drm_set_cursor(fd, crtcId, bo_handle, width, height, hot_x, hot_y);
1278*4882a593Smuzhiyun }
1279*4882a593Smuzhiyun
drmModeSetCursor(int fd,uint32_t crtcId,uint32_t bo_handle,uint32_t width,uint32_t height)1280*4882a593Smuzhiyun int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle,
1281*4882a593Smuzhiyun uint32_t width, uint32_t height)
1282*4882a593Smuzhiyun {
1283*4882a593Smuzhiyun drm_ctx *ctx;
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun ctx = drm_get_ctx(fd);
1286*4882a593Smuzhiyun if (!ctx)
1287*4882a593Smuzhiyun return -1;
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun DRM_DEBUG("fd: %d crtc: %d handle: %d size: %dx%d\n",
1290*4882a593Smuzhiyun fd, crtcId, bo_handle, width, height);
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun if (bo_handle && width && height &&
1293*4882a593Smuzhiyun (ctx->scale_from || ctx->scale_x || ctx->scale_y))
1294*4882a593Smuzhiyun DRM_INFO("CRTC[%d]: scaling without hotspots, use drmModeSetCursor2()!\n",
1295*4882a593Smuzhiyun crtcId);
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun return drm_set_cursor(fd, crtcId, bo_handle, width, height, 0, 0);
1298*4882a593Smuzhiyun }
1299*4882a593Smuzhiyun
drmModeMoveCursor(int fd,uint32_t crtcId,int x,int y)1300*4882a593Smuzhiyun int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
1301*4882a593Smuzhiyun {
1302*4882a593Smuzhiyun DRM_DEBUG("fd: %d crtc: %d position: %d,%d\n", fd, crtcId, x, y);
1303*4882a593Smuzhiyun return drm_move_cursor(fd, crtcId, x, y);
1304*4882a593Smuzhiyun }
1305