1 /*
2 * Copyright © 2007 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Dave Airlie <airlied@redhat.com>
25 *
26 */
27
28 #ifdef HAVE_DIX_CONFIG_H
29 #include "dix-config.h"
30 #endif
31
32 #include <errno.h>
33 #include <sys/ioctl.h>
34 #include <sys/mman.h>
35 #include <unistd.h>
36 #include "dumb_bo.h"
37 #include "inputstr.h"
38 #include "xf86str.h"
39 #include "X11/Xatom.h"
40 #include "mi.h"
41 #include "micmap.h"
42 #include "xf86cmap.h"
43 #include "xf86DDC.h"
44 #include <drm_fourcc.h>
45 #include <drm_mode.h>
46
47 #include <xf86drm.h>
48 #include "xf86Crtc.h"
49 #include "drmmode_display.h"
50 #include "present.h"
51
52 #include <cursorstr.h>
53
54 #include <X11/extensions/dpmsconst.h>
55
56 #include "driver.h"
57
58 static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
59 static PixmapPtr drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
60 int depth, int bitsPerPixel, int devKind,
61 void *pPixData);
62
63 static inline uint32_t *
formats_ptr(struct drm_format_modifier_blob * blob)64 formats_ptr(struct drm_format_modifier_blob *blob)
65 {
66 return (uint32_t *)(((char *)blob) + blob->formats_offset);
67 }
68
69 static inline struct drm_format_modifier *
modifiers_ptr(struct drm_format_modifier_blob * blob)70 modifiers_ptr(struct drm_format_modifier_blob *blob)
71 {
72 return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
73 }
74
75 static uint32_t
get_opaque_format(uint32_t format)76 get_opaque_format(uint32_t format)
77 {
78 switch (format) {
79 case DRM_FORMAT_ARGB8888:
80 return DRM_FORMAT_XRGB8888;
81 case DRM_FORMAT_ARGB2101010:
82 return DRM_FORMAT_XRGB2101010;
83 default:
84 return format;
85 }
86 }
87
88 Bool
drmmode_is_format_supported(ScrnInfoPtr scrn,uint32_t format,uint64_t modifier)89 drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier)
90 {
91 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
92 int c, i, j;
93
94 /* BO are imported as opaque surface, so let's pretend there is no alpha */
95 format = get_opaque_format(format);
96
97 for (c = 0; c < xf86_config->num_crtc; c++) {
98 xf86CrtcPtr crtc = xf86_config->crtc[c];
99 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
100 Bool found = FALSE;
101
102 if (!crtc->enabled)
103 continue;
104
105 if (drmmode_crtc->num_formats == 0)
106 continue;
107
108 for (i = 0; i < drmmode_crtc->num_formats; i++) {
109 drmmode_format_ptr iter = &drmmode_crtc->formats[i];
110
111 if (iter->format != format)
112 continue;
113
114 if (modifier == DRM_FORMAT_MOD_INVALID ||
115 iter->num_modifiers == 0) {
116 found = TRUE;
117 break;
118 }
119
120 for (j = 0; j < iter->num_modifiers; j++) {
121 if (iter->modifiers[j] == modifier) {
122 found = TRUE;
123 break;
124 }
125 }
126
127 break;
128 }
129
130 if (!found)
131 return FALSE;
132 }
133
134 return TRUE;
135 }
136
137 #ifdef GBM_BO_WITH_MODIFIERS
138 static uint32_t
get_modifiers_set(ScrnInfoPtr scrn,uint32_t format,uint64_t ** modifiers,Bool enabled_crtc_only,Bool exclude_multiplane)139 get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
140 Bool enabled_crtc_only, Bool exclude_multiplane)
141 {
142 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
143 modesettingPtr ms = modesettingPTR(scrn);
144 drmmode_ptr drmmode = &ms->drmmode;
145 int c, i, j, k, count_modifiers = 0;
146 uint64_t *tmp, *ret = NULL;
147
148 /* BOs are imported as opaque surfaces, so pretend the same thing here */
149 format = get_opaque_format(format);
150
151 *modifiers = NULL;
152 for (c = 0; c < xf86_config->num_crtc; c++) {
153 xf86CrtcPtr crtc = xf86_config->crtc[c];
154 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
155
156 if (enabled_crtc_only && !crtc->enabled)
157 continue;
158
159 for (i = 0; i < drmmode_crtc->num_formats; i++) {
160 drmmode_format_ptr iter = &drmmode_crtc->formats[i];
161
162 if (iter->format != format)
163 continue;
164
165 for (j = 0; j < iter->num_modifiers; j++) {
166 Bool found = FALSE;
167
168 /* Don't choose multi-plane formats for our screen pixmap.
169 * These will get used with frontbuffer rendering, which will
170 * lead to worse-than-tearing with multi-plane formats, as the
171 * primary and auxiliary planes go out of sync. */
172 if (exclude_multiplane &&
173 gbm_device_get_format_modifier_plane_count(drmmode->gbm,
174 format,
175 iter->modifiers[j]) > 1) {
176 continue;
177 }
178
179 for (k = 0; k < count_modifiers; k++) {
180 if (iter->modifiers[j] == ret[k])
181 found = TRUE;
182 }
183 if (!found) {
184 count_modifiers++;
185 tmp = realloc(ret, count_modifiers * sizeof(uint64_t));
186 if (!tmp) {
187 free(ret);
188 return 0;
189 }
190 ret = tmp;
191 ret[count_modifiers - 1] = iter->modifiers[j];
192 }
193 }
194 }
195 }
196
197 *modifiers = ret;
198 return count_modifiers;
199 }
200
201 static Bool
get_drawable_modifiers(DrawablePtr draw,uint32_t format,uint32_t * num_modifiers,uint64_t ** modifiers)202 get_drawable_modifiers(DrawablePtr draw, uint32_t format,
203 uint32_t *num_modifiers, uint64_t **modifiers)
204 {
205 ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
206 modesettingPtr ms = modesettingPTR(scrn);
207
208 if (!present_can_window_flip((WindowPtr) draw) ||
209 !ms->drmmode.pageflip || ms->drmmode.dri2_flipping || !scrn->vtSema) {
210 *num_modifiers = 0;
211 *modifiers = NULL;
212 return TRUE;
213 }
214
215 *num_modifiers = get_modifiers_set(scrn, format, modifiers, TRUE, FALSE);
216 return TRUE;
217 }
218 #endif
219
220 static Bool
drmmode_zaphod_string_matches(ScrnInfoPtr scrn,const char * s,char * output_name)221 drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
222 {
223 char **token = xstrtokenize(s, ", \t\n\r");
224 Bool ret = FALSE;
225
226 if (!token)
227 return FALSE;
228
229 for (int i = 0; token[i]; i++) {
230 if (strcmp(token[i], output_name) == 0)
231 ret = TRUE;
232
233 free(token[i]);
234 }
235
236 free(token);
237
238 return ret;
239 }
240
241 static uint64_t
drmmode_prop_get_value(drmmode_prop_info_ptr info,drmModeObjectPropertiesPtr props,uint64_t def)242 drmmode_prop_get_value(drmmode_prop_info_ptr info,
243 drmModeObjectPropertiesPtr props,
244 uint64_t def)
245 {
246 unsigned int i;
247
248 if (info->prop_id == 0)
249 return def;
250
251 for (i = 0; i < props->count_props; i++) {
252 unsigned int j;
253
254 if (props->props[i] != info->prop_id)
255 continue;
256
257 /* Simple (non-enum) types can return the value directly */
258 if (info->num_enum_values == 0)
259 return props->prop_values[i];
260
261 /* Map from raw value to enum value */
262 for (j = 0; j < info->num_enum_values; j++) {
263 if (!info->enum_values[j].valid)
264 continue;
265 if (info->enum_values[j].value != props->prop_values[i])
266 continue;
267
268 return j;
269 }
270 }
271
272 return def;
273 }
274
275 static uint32_t
drmmode_prop_info_update(drmmode_ptr drmmode,drmmode_prop_info_ptr info,unsigned int num_infos,drmModeObjectProperties * props)276 drmmode_prop_info_update(drmmode_ptr drmmode,
277 drmmode_prop_info_ptr info,
278 unsigned int num_infos,
279 drmModeObjectProperties *props)
280 {
281 drmModePropertyRes *prop;
282 uint32_t valid_mask = 0;
283 unsigned i, j;
284
285 assert(num_infos <= 32 && "update return type");
286
287 for (i = 0; i < props->count_props; i++) {
288 Bool props_incomplete = FALSE;
289 unsigned int k;
290
291 for (j = 0; j < num_infos; j++) {
292 if (info[j].prop_id == props->props[i])
293 break;
294 if (!info[j].prop_id)
295 props_incomplete = TRUE;
296 }
297
298 /* We've already discovered this property. */
299 if (j != num_infos)
300 continue;
301
302 /* We haven't found this property ID, but as we've already
303 * found all known properties, we don't need to look any
304 * further. */
305 if (!props_incomplete)
306 break;
307
308 prop = drmModeGetProperty(drmmode->fd, props->props[i]);
309 if (!prop)
310 continue;
311
312 for (j = 0; j < num_infos; j++) {
313 if (!strcmp(prop->name, info[j].name))
314 break;
315 }
316
317 /* We don't know/care about this property. */
318 if (j == num_infos) {
319 drmModeFreeProperty(prop);
320 continue;
321 }
322
323 info[j].prop_id = props->props[i];
324 valid_mask |= 1U << j;
325
326 if (info[j].num_enum_values == 0) {
327 drmModeFreeProperty(prop);
328 continue;
329 }
330
331 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
332 xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
333 "expected property %s to be an enum,"
334 " but it is not; ignoring\n", prop->name);
335 drmModeFreeProperty(prop);
336 continue;
337 }
338
339 for (k = 0; k < info[j].num_enum_values; k++) {
340 int l;
341
342 if (info[j].enum_values[k].valid)
343 continue;
344
345 for (l = 0; l < prop->count_enums; l++) {
346 if (!strcmp(prop->enums[l].name,
347 info[j].enum_values[k].name))
348 break;
349 }
350
351 if (l == prop->count_enums)
352 continue;
353
354 info[j].enum_values[k].valid = TRUE;
355 info[j].enum_values[k].value = prop->enums[l].value;
356 }
357
358 drmModeFreeProperty(prop);
359 }
360
361 return valid_mask;
362 }
363
364 static Bool
drmmode_prop_info_copy(drmmode_prop_info_ptr dst,const drmmode_prop_info_rec * src,unsigned int num_props,Bool copy_prop_id)365 drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
366 const drmmode_prop_info_rec *src,
367 unsigned int num_props,
368 Bool copy_prop_id)
369 {
370 unsigned int i;
371
372 memcpy(dst, src, num_props * sizeof(*dst));
373
374 for (i = 0; i < num_props; i++) {
375 unsigned int j;
376
377 if (copy_prop_id)
378 dst[i].prop_id = src[i].prop_id;
379 else
380 dst[i].prop_id = 0;
381
382 if (src[i].num_enum_values == 0)
383 continue;
384
385 dst[i].enum_values =
386 malloc(src[i].num_enum_values *
387 sizeof(*dst[i].enum_values));
388 if (!dst[i].enum_values)
389 goto err;
390
391 memcpy(dst[i].enum_values, src[i].enum_values,
392 src[i].num_enum_values * sizeof(*dst[i].enum_values));
393
394 for (j = 0; j < dst[i].num_enum_values; j++)
395 dst[i].enum_values[j].valid = FALSE;
396 }
397
398 return TRUE;
399
400 err:
401 while (i--)
402 free(dst[i].enum_values);
403 return FALSE;
404 }
405
406 static void
drmmode_prop_info_free(drmmode_prop_info_ptr info,int num_props)407 drmmode_prop_info_free(drmmode_prop_info_ptr info, int num_props)
408 {
409 int i;
410
411 for (i = 0; i < num_props; i++)
412 free(info[i].enum_values);
413 }
414
415 static void
416 drmmode_ConvertToKMode(ScrnInfoPtr scrn,
417 drmModeModeInfo * kmode, DisplayModePtr mode);
418
419
420 static int
plane_add_prop(drmModeAtomicReq * req,drmmode_crtc_private_ptr drmmode_crtc,enum drmmode_plane_property prop,uint64_t val)421 plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
422 enum drmmode_plane_property prop, uint64_t val)
423 {
424 drmmode_prop_info_ptr info = &drmmode_crtc->props_plane[prop];
425 int ret;
426
427 if (!info)
428 return -1;
429
430 ret = drmModeAtomicAddProperty(req, drmmode_crtc->plane_id,
431 info->prop_id, val);
432 return (ret <= 0) ? -1 : 0;
433 }
434
435 static int
plane_add_props(drmModeAtomicReq * req,xf86CrtcPtr crtc,uint32_t fb_id,int x,int y)436 plane_add_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
437 uint32_t fb_id, int x, int y)
438 {
439 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
440 int ret = 0;
441
442 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
443 fb_id);
444 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
445 fb_id ? drmmode_crtc->mode_crtc->crtc_id : 0);
446 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x << 16);
447 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y << 16);
448 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_W,
449 crtc->mode.HDisplay << 16);
450 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_H,
451 crtc->mode.VDisplay << 16);
452 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_X, 0);
453 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_Y, 0);
454 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_W,
455 crtc->mode.HDisplay);
456 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_H,
457 crtc->mode.VDisplay);
458
459 return ret;
460 }
461
462 static int
crtc_add_prop(drmModeAtomicReq * req,drmmode_crtc_private_ptr drmmode_crtc,enum drmmode_crtc_property prop,uint64_t val)463 crtc_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
464 enum drmmode_crtc_property prop, uint64_t val)
465 {
466 drmmode_prop_info_ptr info = &drmmode_crtc->props[prop];
467 int ret;
468
469 if (!info)
470 return -1;
471
472 ret = drmModeAtomicAddProperty(req, drmmode_crtc->mode_crtc->crtc_id,
473 info->prop_id, val);
474 return (ret <= 0) ? -1 : 0;
475 }
476
477 static int
connector_add_prop(drmModeAtomicReq * req,drmmode_output_private_ptr drmmode_output,enum drmmode_connector_property prop,uint64_t val)478 connector_add_prop(drmModeAtomicReq *req, drmmode_output_private_ptr drmmode_output,
479 enum drmmode_connector_property prop, uint64_t val)
480 {
481 drmmode_prop_info_ptr info = &drmmode_output->props_connector[prop];
482 int ret;
483
484 if (!info)
485 return -1;
486
487 ret = drmModeAtomicAddProperty(req, drmmode_output->output_id,
488 info->prop_id, val);
489 return (ret <= 0) ? -1 : 0;
490 }
491
492 static int
drmmode_CompareKModes(drmModeModeInfo * kmode,drmModeModeInfo * other)493 drmmode_CompareKModes(drmModeModeInfo * kmode, drmModeModeInfo * other)
494 {
495 return memcmp(kmode, other, sizeof(*kmode));
496 }
497
498 static int
drm_mode_ensure_blob(xf86CrtcPtr crtc,drmModeModeInfo mode_info)499 drm_mode_ensure_blob(xf86CrtcPtr crtc, drmModeModeInfo mode_info)
500 {
501 modesettingPtr ms = modesettingPTR(crtc->scrn);
502 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
503 drmmode_mode_ptr mode;
504 int ret;
505
506 if (drmmode_crtc->current_mode &&
507 drmmode_CompareKModes(&drmmode_crtc->current_mode->mode_info, &mode_info) == 0)
508 return 0;
509
510 mode = calloc(sizeof(drmmode_mode_rec), 1);
511 if (!mode)
512 return -1;
513
514 mode->mode_info = mode_info;
515 ret = drmModeCreatePropertyBlob(ms->fd,
516 &mode->mode_info,
517 sizeof(mode->mode_info),
518 &mode->blob_id);
519 drmmode_crtc->current_mode = mode;
520 xorg_list_add(&mode->entry, &drmmode_crtc->mode_list);
521
522 return ret;
523 }
524
525 static int
crtc_add_dpms_props(drmModeAtomicReq * req,xf86CrtcPtr crtc,int new_dpms,Bool * active)526 crtc_add_dpms_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
527 int new_dpms, Bool *active)
528 {
529 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
530 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
531 Bool crtc_active = FALSE;
532 int i;
533 int ret = 0;
534
535 for (i = 0; i < xf86_config->num_output; i++) {
536 xf86OutputPtr output = xf86_config->output[i];
537 drmmode_output_private_ptr drmmode_output = output->driver_private;
538
539 if (output->crtc != crtc) {
540 if (drmmode_output->current_crtc == crtc) {
541 ret |= connector_add_prop(req, drmmode_output,
542 DRMMODE_CONNECTOR_CRTC_ID, 0);
543 }
544 continue;
545 }
546
547 if (drmmode_output->output_id == -1)
548 continue;
549
550 if (new_dpms == DPMSModeOn)
551 crtc_active = TRUE;
552
553 ret |= connector_add_prop(req, drmmode_output,
554 DRMMODE_CONNECTOR_CRTC_ID,
555 crtc_active ?
556 drmmode_crtc->mode_crtc->crtc_id : 0);
557 }
558
559 if (crtc_active) {
560 drmModeModeInfo kmode;
561
562 drmmode_ConvertToKMode(crtc->scrn, &kmode, &crtc->mode);
563 ret |= drm_mode_ensure_blob(crtc, kmode);
564
565 ret |= crtc_add_prop(req, drmmode_crtc,
566 DRMMODE_CRTC_ACTIVE, 1);
567 ret |= crtc_add_prop(req, drmmode_crtc,
568 DRMMODE_CRTC_MODE_ID,
569 drmmode_crtc->current_mode->blob_id);
570 } else {
571 ret |= crtc_add_prop(req, drmmode_crtc,
572 DRMMODE_CRTC_ACTIVE, 0);
573 ret |= crtc_add_prop(req, drmmode_crtc,
574 DRMMODE_CRTC_MODE_ID, 0);
575 }
576
577 if (active)
578 *active = crtc_active;
579
580 return ret;
581 }
582
583 static void
drm_mode_destroy(xf86CrtcPtr crtc,drmmode_mode_ptr mode)584 drm_mode_destroy(xf86CrtcPtr crtc, drmmode_mode_ptr mode)
585 {
586 modesettingPtr ms = modesettingPTR(crtc->scrn);
587 if (mode->blob_id)
588 drmModeDestroyPropertyBlob(ms->fd, mode->blob_id);
589 xorg_list_del(&mode->entry);
590 free(mode);
591 }
592
593 static int
drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)594 drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)
595 {
596 modesettingPtr ms = modesettingPTR(crtc->scrn);
597
598 return ms->atomic_modeset;
599 }
600
601 static Bool
drmmode_crtc_get_fb_id(xf86CrtcPtr crtc,uint32_t * fb_id,int * x,int * y)602 drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y)
603 {
604 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
605 drmmode_ptr drmmode = drmmode_crtc->drmmode;
606 int ret;
607
608 *fb_id = 0;
609
610 if (drmmode_crtc->prime_pixmap) {
611 if (!drmmode->reverse_prime_offload_mode) {
612 msPixmapPrivPtr ppriv =
613 msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap);
614 *fb_id = ppriv->fb_id;
615 *x = 0;
616 } else
617 *x = drmmode_crtc->prime_pixmap_x;
618 *y = 0;
619 }
620 else if (drmmode_crtc->rotate_fb_id) {
621 *fb_id = drmmode_crtc->rotate_fb_id;
622 *x = *y = 0;
623 }
624 else {
625 *fb_id = drmmode->fb_id;
626 *x = crtc->x;
627 *y = crtc->y;
628 }
629
630 if (*fb_id == 0) {
631 ret = drmmode_bo_import(drmmode, &drmmode->front_bo,
632 &drmmode->fb_id);
633 if (ret < 0) {
634 ErrorF("failed to add fb %d\n", ret);
635 return FALSE;
636 }
637 *fb_id = drmmode->fb_id;
638 }
639
640 return TRUE;
641 }
642
643 void
drmmode_set_dpms(ScrnInfoPtr scrn,int dpms,int flags)644 drmmode_set_dpms(ScrnInfoPtr scrn, int dpms, int flags)
645 {
646 modesettingPtr ms = modesettingPTR(scrn);
647 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
648 drmModeAtomicReq *req = drmModeAtomicAlloc();
649 uint32_t mode_flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
650 int ret = 0;
651 int i;
652
653 assert(ms->atomic_modeset);
654
655 if (!req)
656 return;
657
658 for (i = 0; i < xf86_config->num_output; i++) {
659 xf86OutputPtr output = xf86_config->output[i];
660 drmmode_output_private_ptr drmmode_output = output->driver_private;
661
662 if (output->crtc != NULL)
663 continue;
664
665 ret = connector_add_prop(req, drmmode_output,
666 DRMMODE_CONNECTOR_CRTC_ID, 0);
667 }
668
669 for (i = 0; i < xf86_config->num_crtc; i++) {
670 xf86CrtcPtr crtc = xf86_config->crtc[i];
671 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
672 Bool active = FALSE;
673
674 ret |= crtc_add_dpms_props(req, crtc, dpms, &active);
675
676 if (dpms == DPMSModeOn && active && drmmode_crtc->need_modeset) {
677 uint32_t fb_id;
678 int x, y;
679
680 if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
681 continue;
682 ret |= plane_add_props(req, crtc, fb_id, x, y);
683 drmmode_crtc->need_modeset = FALSE;
684 }
685 }
686
687 if (ret == 0)
688 drmModeAtomicCommit(ms->fd, req, mode_flags, NULL);
689 drmModeAtomicFree(req);
690
691 ms->pending_modeset = TRUE;
692 xf86DPMSSet(scrn, dpms, flags);
693 ms->pending_modeset = FALSE;
694 }
695
696 static int
drmmode_output_disable(xf86OutputPtr output)697 drmmode_output_disable(xf86OutputPtr output)
698 {
699 modesettingPtr ms = modesettingPTR(output->scrn);
700 drmmode_output_private_ptr drmmode_output = output->driver_private;
701 xf86CrtcPtr crtc = drmmode_output->current_crtc;
702 drmModeAtomicReq *req = drmModeAtomicAlloc();
703 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
704 int ret = 0;
705
706 assert(ms->atomic_modeset);
707
708 if (!req)
709 return 1;
710
711 ret |= connector_add_prop(req, drmmode_output,
712 DRMMODE_CONNECTOR_CRTC_ID, 0);
713 if (crtc)
714 ret |= crtc_add_dpms_props(req, crtc, DPMSModeOff, NULL);
715
716 if (ret == 0)
717 ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
718
719 if (ret == 0)
720 drmmode_output->current_crtc = NULL;
721
722 drmModeAtomicFree(req);
723 return ret;
724 }
725
726 static int
drmmode_crtc_disable(xf86CrtcPtr crtc)727 drmmode_crtc_disable(xf86CrtcPtr crtc)
728 {
729 modesettingPtr ms = modesettingPTR(crtc->scrn);
730 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
731 drmModeAtomicReq *req = drmModeAtomicAlloc();
732 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
733 int ret = 0;
734
735 assert(ms->atomic_modeset);
736
737 if (!req)
738 return 1;
739
740 ret |= crtc_add_prop(req, drmmode_crtc,
741 DRMMODE_CRTC_ACTIVE, 0);
742 ret |= crtc_add_prop(req, drmmode_crtc,
743 DRMMODE_CRTC_MODE_ID, 0);
744
745 if (ret == 0)
746 ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
747
748 drmModeAtomicFree(req);
749 return ret;
750 }
751
752 static int
drmmode_crtc_set_mode(xf86CrtcPtr crtc,Bool test_only)753 drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only)
754 {
755 modesettingPtr ms = modesettingPTR(crtc->scrn);
756 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
757 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
758 drmmode_ptr drmmode = drmmode_crtc->drmmode;
759 ScreenPtr screen = crtc->scrn->pScreen;
760 drmModeModeInfo kmode;
761 int output_count = 0;
762 uint32_t *output_ids = NULL;
763 uint32_t fb_id;
764 int x, y;
765 int i, ret = 0;
766
767 if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
768 return 1;
769
770 #ifdef GLAMOR_HAS_GBM
771 /* Make sure any pending drawing will be visible in a new scanout buffer */
772 if (drmmode->glamor)
773 glamor_finish(screen);
774 #endif
775
776 if (ms->atomic_modeset) {
777 drmModeAtomicReq *req = drmModeAtomicAlloc();
778 Bool active;
779 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
780
781 if (!req)
782 return 1;
783
784 ret |= crtc_add_dpms_props(req, crtc, DPMSModeOn, &active);
785 ret |= plane_add_props(req, crtc, active ? fb_id : 0, x, y);
786
787 /* Orphaned CRTCs need to be disabled right now in atomic mode */
788 for (i = 0; i < xf86_config->num_crtc; i++) {
789 xf86CrtcPtr other_crtc = xf86_config->crtc[i];
790 drmmode_crtc_private_ptr other_drmmode_crtc = other_crtc->driver_private;
791 int lost_outputs = 0;
792 int remaining_outputs = 0;
793 int j;
794
795 if (other_crtc == crtc)
796 continue;
797
798 for (j = 0; j < xf86_config->num_output; j++) {
799 xf86OutputPtr output = xf86_config->output[j];
800 drmmode_output_private_ptr drmmode_output = output->driver_private;
801
802 if (drmmode_output->current_crtc == other_crtc) {
803 if (output->crtc == crtc)
804 lost_outputs++;
805 else
806 remaining_outputs++;
807 }
808 }
809
810 if (lost_outputs > 0 && remaining_outputs == 0) {
811 ret |= crtc_add_prop(req, other_drmmode_crtc,
812 DRMMODE_CRTC_ACTIVE, 0);
813 ret |= crtc_add_prop(req, other_drmmode_crtc,
814 DRMMODE_CRTC_MODE_ID, 0);
815 }
816 }
817
818 if (test_only)
819 flags |= DRM_MODE_ATOMIC_TEST_ONLY;
820
821 if (ret == 0)
822 ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
823
824 if (ret == 0 && !test_only) {
825 for (i = 0; i < xf86_config->num_output; i++) {
826 xf86OutputPtr output = xf86_config->output[i];
827 drmmode_output_private_ptr drmmode_output = output->driver_private;
828
829 if (output->crtc == crtc)
830 drmmode_output->current_crtc = crtc;
831 else if (drmmode_output->current_crtc == crtc)
832 drmmode_output->current_crtc = NULL;
833 }
834 }
835
836 drmModeAtomicFree(req);
837 return ret;
838 }
839
840 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
841 if (!output_ids)
842 return -1;
843
844 for (i = 0; i < xf86_config->num_output; i++) {
845 xf86OutputPtr output = xf86_config->output[i];
846 drmmode_output_private_ptr drmmode_output;
847
848 if (output->crtc != crtc)
849 continue;
850
851 drmmode_output = output->driver_private;
852 if (drmmode_output->output_id == -1)
853 continue;
854 output_ids[output_count] = drmmode_output->output_id;
855 output_count++;
856 }
857
858 drmmode_ConvertToKMode(crtc->scrn, &kmode, &crtc->mode);
859 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
860 fb_id, x, y, output_ids, output_count, &kmode);
861
862 free(output_ids);
863 return ret;
864 }
865
866 int
drmmode_crtc_flip(xf86CrtcPtr crtc,uint32_t fb_id,uint32_t flags,void * data)867 drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data)
868 {
869 modesettingPtr ms = modesettingPTR(crtc->scrn);
870 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
871 int ret;
872
873 if (ms->atomic_modeset) {
874 drmModeAtomicReq *req = drmModeAtomicAlloc();
875
876 if (!req)
877 return 1;
878
879 ret = plane_add_props(req, crtc, fb_id, crtc->x, crtc->y);
880 flags |= DRM_MODE_ATOMIC_NONBLOCK;
881 if (ret == 0)
882 ret = drmModeAtomicCommit(ms->fd, req, flags, data);
883 drmModeAtomicFree(req);
884 return ret;
885 }
886
887 return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
888 fb_id, flags, data);
889 }
890
891 int
drmmode_bo_destroy(drmmode_ptr drmmode,drmmode_bo * bo)892 drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
893 {
894 int ret;
895
896 #ifdef GLAMOR_HAS_GBM
897 if (bo->gbm) {
898 gbm_bo_destroy(bo->gbm);
899 bo->gbm = NULL;
900 }
901 #endif
902
903 if (bo->dumb) {
904 ret = dumb_bo_destroy(drmmode->fd, bo->dumb);
905 if (ret == 0)
906 bo->dumb = NULL;
907 }
908
909 return 0;
910 }
911
912 uint32_t
drmmode_bo_get_pitch(drmmode_bo * bo)913 drmmode_bo_get_pitch(drmmode_bo *bo)
914 {
915 #ifdef GLAMOR_HAS_GBM
916 if (bo->gbm)
917 return gbm_bo_get_stride(bo->gbm);
918 #endif
919
920 return bo->dumb->pitch;
921 }
922
923 static Bool
drmmode_bo_has_bo(drmmode_bo * bo)924 drmmode_bo_has_bo(drmmode_bo *bo)
925 {
926 #ifdef GLAMOR_HAS_GBM
927 if (bo->gbm)
928 return TRUE;
929 #endif
930
931 return bo->dumb != NULL;
932 }
933
934 uint32_t
drmmode_bo_get_handle(drmmode_bo * bo)935 drmmode_bo_get_handle(drmmode_bo *bo)
936 {
937 #ifdef GLAMOR_HAS_GBM
938 if (bo->gbm)
939 return gbm_bo_get_handle(bo->gbm).u32;
940 #endif
941
942 return bo->dumb->handle;
943 }
944
945 static void *
drmmode_bo_map(drmmode_ptr drmmode,drmmode_bo * bo)946 drmmode_bo_map(drmmode_ptr drmmode, drmmode_bo *bo)
947 {
948 int ret;
949
950 #ifdef GLAMOR_HAS_GBM
951 if (bo->gbm)
952 return NULL;
953 #endif
954
955 if (bo->dumb->ptr)
956 return bo->dumb->ptr;
957
958 ret = dumb_bo_map(drmmode->fd, bo->dumb);
959 if (ret)
960 return NULL;
961
962 return bo->dumb->ptr;
963 }
964
965 int
drmmode_bo_import(drmmode_ptr drmmode,drmmode_bo * bo,uint32_t * fb_id)966 drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
967 uint32_t *fb_id)
968 {
969 #ifdef GBM_BO_WITH_MODIFIERS
970 modesettingPtr ms = modesettingPTR(drmmode->scrn);
971 if (bo->gbm && ms->kms_has_modifiers &&
972 gbm_bo_get_modifier(bo->gbm) != DRM_FORMAT_MOD_INVALID) {
973 int num_fds;
974
975 num_fds = gbm_bo_get_plane_count(bo->gbm);
976 if (num_fds > 0) {
977 int i;
978 uint32_t format;
979 uint32_t handles[4];
980 uint32_t strides[4];
981 uint32_t offsets[4];
982 uint64_t modifiers[4];
983
984 memset(handles, 0, sizeof(handles));
985 memset(strides, 0, sizeof(strides));
986 memset(offsets, 0, sizeof(offsets));
987 memset(modifiers, 0, sizeof(modifiers));
988
989 format = gbm_bo_get_format(bo->gbm);
990 format = get_opaque_format(format);
991 for (i = 0; i < num_fds; i++) {
992 handles[i] = gbm_bo_get_handle_for_plane(bo->gbm, i).u32;
993 strides[i] = gbm_bo_get_stride_for_plane(bo->gbm, i);
994 offsets[i] = gbm_bo_get_offset(bo->gbm, i);
995 modifiers[i] = gbm_bo_get_modifier(bo->gbm);
996 }
997
998 return drmModeAddFB2WithModifiers(drmmode->fd, bo->width, bo->height,
999 format, handles, strides,
1000 offsets, modifiers, fb_id,
1001 DRM_MODE_FB_MODIFIERS);
1002 }
1003 }
1004 #endif
1005 return drmModeAddFB(drmmode->fd, bo->width, bo->height,
1006 drmmode->scrn->depth, drmmode->kbpp,
1007 drmmode_bo_get_pitch(bo),
1008 drmmode_bo_get_handle(bo), fb_id);
1009 }
1010
1011 static Bool
drmmode_create_bo(drmmode_ptr drmmode,drmmode_bo * bo,unsigned width,unsigned height,unsigned bpp)1012 drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
1013 unsigned width, unsigned height, unsigned bpp)
1014 {
1015 bo->width = width;
1016 bo->height = height;
1017
1018 #ifdef GLAMOR_HAS_GBM
1019 if (drmmode->glamor) {
1020 uint32_t format;
1021
1022 if (drmmode->scrn->depth == 30)
1023 format = GBM_FORMAT_ARGB2101010;
1024 else
1025 format = GBM_FORMAT_ARGB8888;
1026
1027 #ifdef GBM_BO_WITH_MODIFIERS
1028 uint32_t num_modifiers;
1029 uint64_t *modifiers = NULL;
1030
1031 num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers,
1032 FALSE, TRUE);
1033 if (num_modifiers > 0 &&
1034 !(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
1035 bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height,
1036 format, modifiers,
1037 num_modifiers);
1038 free(modifiers);
1039 if (bo->gbm) {
1040 bo->used_modifiers = TRUE;
1041 return TRUE;
1042 }
1043 }
1044 #endif
1045
1046 bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format,
1047 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
1048 bo->used_modifiers = FALSE;
1049 return bo->gbm != NULL;
1050 }
1051 #endif
1052
1053 bo->dumb = dumb_bo_create(drmmode->fd, width, height, bpp);
1054 return bo->dumb != NULL;
1055 }
1056
1057 Bool
drmmode_SetSlaveBO(PixmapPtr ppix,drmmode_ptr drmmode,int fd_handle,int pitch,int size)1058 drmmode_SetSlaveBO(PixmapPtr ppix,
1059 drmmode_ptr drmmode, int fd_handle, int pitch, int size)
1060 {
1061 msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1062
1063 if (fd_handle == -1) {
1064 dumb_bo_destroy(drmmode->fd, ppriv->backing_bo);
1065 ppriv->backing_bo = NULL;
1066 return TRUE;
1067 }
1068
1069 ppriv->backing_bo =
1070 dumb_get_bo_from_fd(drmmode->fd, fd_handle, pitch, size);
1071 if (!ppriv->backing_bo)
1072 return FALSE;
1073
1074 close(fd_handle);
1075 return TRUE;
1076 }
1077
1078 static Bool
drmmode_SharedPixmapPresent(PixmapPtr ppix,xf86CrtcPtr crtc,drmmode_ptr drmmode)1079 drmmode_SharedPixmapPresent(PixmapPtr ppix, xf86CrtcPtr crtc,
1080 drmmode_ptr drmmode)
1081 {
1082 ScreenPtr master = crtc->randr_crtc->pScreen->current_master;
1083
1084 if (master->PresentSharedPixmap(ppix)) {
1085 /* Success, queue flip to back target */
1086 if (drmmode_SharedPixmapFlip(ppix, crtc, drmmode))
1087 return TRUE;
1088
1089 xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
1090 "drmmode_SharedPixmapFlip() failed, trying again next vblank\n");
1091
1092 return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
1093 }
1094
1095 /* Failed to present, try again on next vblank after damage */
1096 if (master->RequestSharedPixmapNotifyDamage) {
1097 msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1098
1099 /* Set flag first in case we are immediately notified */
1100 ppriv->wait_for_damage = TRUE;
1101
1102 if (master->RequestSharedPixmapNotifyDamage(ppix))
1103 return TRUE;
1104 else
1105 ppriv->wait_for_damage = FALSE;
1106 }
1107
1108 /* Damage notification not available, just try again on vblank */
1109 return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
1110 }
1111
1112 struct vblank_event_args {
1113 PixmapPtr frontTarget;
1114 PixmapPtr backTarget;
1115 xf86CrtcPtr crtc;
1116 drmmode_ptr drmmode;
1117 Bool flip;
1118 };
1119 static void
drmmode_SharedPixmapVBlankEventHandler(uint64_t frame,uint64_t usec,void * data)1120 drmmode_SharedPixmapVBlankEventHandler(uint64_t frame, uint64_t usec,
1121 void *data)
1122 {
1123 struct vblank_event_args *args = data;
1124
1125 drmmode_crtc_private_ptr drmmode_crtc = args->crtc->driver_private;
1126
1127 if (args->flip) {
1128 /* frontTarget is being displayed, update crtc to reflect */
1129 drmmode_crtc->prime_pixmap = args->frontTarget;
1130 drmmode_crtc->prime_pixmap_back = args->backTarget;
1131
1132 /* Safe to present on backTarget, no longer displayed */
1133 drmmode_SharedPixmapPresent(args->backTarget, args->crtc, args->drmmode);
1134 } else {
1135 /* backTarget is still being displayed, present on frontTarget */
1136 drmmode_SharedPixmapPresent(args->frontTarget, args->crtc, args->drmmode);
1137 }
1138
1139 free(args);
1140 }
1141
1142 static void
drmmode_SharedPixmapVBlankEventAbort(void * data)1143 drmmode_SharedPixmapVBlankEventAbort(void *data)
1144 {
1145 struct vblank_event_args *args = data;
1146
1147 msGetPixmapPriv(args->drmmode, args->frontTarget)->flip_seq = 0;
1148
1149 free(args);
1150 }
1151
1152 Bool
drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix,xf86CrtcPtr crtc,drmmode_ptr drmmode)1153 drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix, xf86CrtcPtr crtc,
1154 drmmode_ptr drmmode)
1155 {
1156 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1157 msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1158 struct vblank_event_args *event_args;
1159
1160 if (ppix == drmmode_crtc->prime_pixmap)
1161 return FALSE; /* Already flipped to this pixmap */
1162 if (ppix != drmmode_crtc->prime_pixmap_back)
1163 return FALSE; /* Pixmap is not a scanout pixmap for CRTC */
1164
1165 event_args = calloc(1, sizeof(*event_args));
1166 if (!event_args)
1167 return FALSE;
1168
1169 event_args->frontTarget = ppix;
1170 event_args->backTarget = drmmode_crtc->prime_pixmap;
1171 event_args->crtc = crtc;
1172 event_args->drmmode = drmmode;
1173 event_args->flip = FALSE;
1174
1175 ppriv->flip_seq =
1176 ms_drm_queue_alloc(crtc, event_args,
1177 drmmode_SharedPixmapVBlankEventHandler,
1178 drmmode_SharedPixmapVBlankEventAbort);
1179
1180 return ms_queue_vblank(crtc, MS_QUEUE_RELATIVE, 1, NULL, ppriv->flip_seq);
1181 }
1182
1183 Bool
drmmode_SharedPixmapFlip(PixmapPtr frontTarget,xf86CrtcPtr crtc,drmmode_ptr drmmode)1184 drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
1185 drmmode_ptr drmmode)
1186 {
1187 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1188 msPixmapPrivPtr ppriv_front = msGetPixmapPriv(drmmode, frontTarget);
1189
1190 struct vblank_event_args *event_args;
1191
1192 event_args = calloc(1, sizeof(*event_args));
1193 if (!event_args)
1194 return FALSE;
1195
1196 event_args->frontTarget = frontTarget;
1197 event_args->backTarget = drmmode_crtc->prime_pixmap;
1198 event_args->crtc = crtc;
1199 event_args->drmmode = drmmode;
1200 event_args->flip = TRUE;
1201
1202 ppriv_front->flip_seq =
1203 ms_drm_queue_alloc(crtc, event_args,
1204 drmmode_SharedPixmapVBlankEventHandler,
1205 drmmode_SharedPixmapVBlankEventAbort);
1206
1207 if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1208 ppriv_front->fb_id, DRM_MODE_PAGE_FLIP_EVENT,
1209 (void *)(intptr_t) ppriv_front->flip_seq) < 0) {
1210 ms_drm_abort_seq(crtc->scrn, ppriv_front->flip_seq);
1211 return FALSE;
1212 }
1213
1214 return TRUE;
1215 }
1216
1217 static Bool
drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1218 drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1219 {
1220 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1221
1222 if (!drmmode_crtc->enable_flipping)
1223 return FALSE;
1224
1225 if (drmmode_crtc->flipping_active)
1226 return TRUE;
1227
1228 drmmode_crtc->flipping_active =
1229 drmmode_SharedPixmapPresent(drmmode_crtc->prime_pixmap_back,
1230 crtc, drmmode);
1231
1232 return drmmode_crtc->flipping_active;
1233 }
1234
1235 static void
drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1236 drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1237 {
1238 uint32_t seq;
1239 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1240
1241 if (!drmmode_crtc->flipping_active)
1242 return;
1243
1244 drmmode_crtc->flipping_active = FALSE;
1245
1246 /* Abort page flip event handler on prime_pixmap */
1247 seq = msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap)->flip_seq;
1248 if (seq)
1249 ms_drm_abort_seq(crtc->scrn, seq);
1250
1251 /* Abort page flip event handler on prime_pixmap_back */
1252 seq = msGetPixmapPriv(drmmode,
1253 drmmode_crtc->prime_pixmap_back)->flip_seq;
1254 if (seq)
1255 ms_drm_abort_seq(crtc->scrn, seq);
1256 }
1257
1258 static Bool drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
1259 PixmapPtr *target);
1260
1261 Bool
drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode,PixmapPtr front,PixmapPtr back)1262 drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode,
1263 PixmapPtr front, PixmapPtr back)
1264 {
1265 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1266
1267 drmmode_crtc->enable_flipping = TRUE;
1268
1269 /* Set front scanout pixmap */
1270 drmmode_crtc->enable_flipping &=
1271 drmmode_set_target_scanout_pixmap(crtc, front,
1272 &drmmode_crtc->prime_pixmap);
1273 if (!drmmode_crtc->enable_flipping)
1274 return FALSE;
1275
1276 /* Set back scanout pixmap */
1277 drmmode_crtc->enable_flipping &=
1278 drmmode_set_target_scanout_pixmap(crtc, back,
1279 &drmmode_crtc->prime_pixmap_back);
1280 if (!drmmode_crtc->enable_flipping) {
1281 drmmode_set_target_scanout_pixmap(crtc, NULL,
1282 &drmmode_crtc->prime_pixmap);
1283 return FALSE;
1284 }
1285
1286 return TRUE;
1287 }
1288
1289 void
drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1290 drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1291 {
1292 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1293
1294 drmmode_crtc->enable_flipping = FALSE;
1295
1296 drmmode_FiniSharedPixmapFlipping(crtc, drmmode);
1297
1298 drmmode_set_target_scanout_pixmap(crtc, NULL, &drmmode_crtc->prime_pixmap);
1299
1300 drmmode_set_target_scanout_pixmap(crtc, NULL,
1301 &drmmode_crtc->prime_pixmap_back);
1302 }
1303
1304 static void
drmmode_ConvertFromKMode(ScrnInfoPtr scrn,drmModeModeInfo * kmode,DisplayModePtr mode)1305 drmmode_ConvertFromKMode(ScrnInfoPtr scrn,
1306 drmModeModeInfo * kmode, DisplayModePtr mode)
1307 {
1308 memset(mode, 0, sizeof(DisplayModeRec));
1309 mode->status = MODE_OK;
1310
1311 mode->Clock = kmode->clock;
1312
1313 mode->HDisplay = kmode->hdisplay;
1314 mode->HSyncStart = kmode->hsync_start;
1315 mode->HSyncEnd = kmode->hsync_end;
1316 mode->HTotal = kmode->htotal;
1317 mode->HSkew = kmode->hskew;
1318
1319 mode->VDisplay = kmode->vdisplay;
1320 mode->VSyncStart = kmode->vsync_start;
1321 mode->VSyncEnd = kmode->vsync_end;
1322 mode->VTotal = kmode->vtotal;
1323 mode->VScan = kmode->vscan;
1324
1325 mode->Flags = kmode->flags; //& FLAG_BITS;
1326 mode->name = strdup(kmode->name);
1327
1328 if (kmode->type & DRM_MODE_TYPE_DRIVER)
1329 mode->type = M_T_DRIVER;
1330 if (kmode->type & DRM_MODE_TYPE_PREFERRED)
1331 mode->type |= M_T_PREFERRED;
1332 xf86SetModeCrtc(mode, scrn->adjustFlags);
1333 }
1334
1335 static void
drmmode_ConvertToKMode(ScrnInfoPtr scrn,drmModeModeInfo * kmode,DisplayModePtr mode)1336 drmmode_ConvertToKMode(ScrnInfoPtr scrn,
1337 drmModeModeInfo * kmode, DisplayModePtr mode)
1338 {
1339 memset(kmode, 0, sizeof(*kmode));
1340
1341 kmode->clock = mode->Clock;
1342 kmode->hdisplay = mode->HDisplay;
1343 kmode->hsync_start = mode->HSyncStart;
1344 kmode->hsync_end = mode->HSyncEnd;
1345 kmode->htotal = mode->HTotal;
1346 kmode->hskew = mode->HSkew;
1347
1348 kmode->vdisplay = mode->VDisplay;
1349 kmode->vsync_start = mode->VSyncStart;
1350 kmode->vsync_end = mode->VSyncEnd;
1351 kmode->vtotal = mode->VTotal;
1352 kmode->vscan = mode->VScan;
1353
1354 kmode->flags = mode->Flags; //& FLAG_BITS;
1355 if (mode->name)
1356 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
1357 kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0;
1358
1359 }
1360
1361 static void
drmmode_crtc_dpms(xf86CrtcPtr crtc,int mode)1362 drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
1363 {
1364 modesettingPtr ms = modesettingPTR(crtc->scrn);
1365 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1366 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1367
1368 /* XXX Check if DPMS mode is already the right one */
1369
1370 drmmode_crtc->dpms_mode = mode;
1371
1372 if (ms->atomic_modeset) {
1373 if (mode != DPMSModeOn && !ms->pending_modeset)
1374 drmmode_crtc_disable(crtc);
1375 } else if (crtc->enabled == FALSE) {
1376 drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1377 0, 0, 0, NULL, 0, NULL);
1378 }
1379 }
1380
1381 #ifdef GLAMOR_HAS_GBM
1382 static PixmapPtr
create_pixmap_for_fbcon(drmmode_ptr drmmode,ScrnInfoPtr pScrn,int fbcon_id)1383 create_pixmap_for_fbcon(drmmode_ptr drmmode, ScrnInfoPtr pScrn, int fbcon_id)
1384 {
1385 PixmapPtr pixmap = drmmode->fbcon_pixmap;
1386 drmModeFBPtr fbcon;
1387 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1388 Bool ret;
1389
1390 if (pixmap)
1391 return pixmap;
1392
1393 fbcon = drmModeGetFB(drmmode->fd, fbcon_id);
1394 if (fbcon == NULL)
1395 return NULL;
1396
1397 if (fbcon->depth != pScrn->depth ||
1398 fbcon->width != pScrn->virtualX ||
1399 fbcon->height != pScrn->virtualY)
1400 goto out_free_fb;
1401
1402 pixmap = drmmode_create_pixmap_header(pScreen, fbcon->width,
1403 fbcon->height, fbcon->depth,
1404 fbcon->bpp, fbcon->pitch, NULL);
1405 if (!pixmap)
1406 goto out_free_fb;
1407
1408 ret = glamor_egl_create_textured_pixmap(pixmap, fbcon->handle, fbcon->pitch);
1409 if (!ret) {
1410 FreePixmap(pixmap);
1411 pixmap = NULL;
1412 }
1413
1414 drmmode->fbcon_pixmap = pixmap;
1415 out_free_fb:
1416 drmModeFreeFB(fbcon);
1417 return pixmap;
1418 }
1419 #endif
1420
1421 void
drmmode_copy_fb(ScrnInfoPtr pScrn,drmmode_ptr drmmode)1422 drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1423 {
1424 #ifdef GLAMOR_HAS_GBM
1425 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1426 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1427 PixmapPtr src, dst;
1428 int fbcon_id = 0;
1429 GCPtr gc;
1430 int i;
1431
1432 for (i = 0; i < xf86_config->num_crtc; i++) {
1433 drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
1434 if (drmmode_crtc->mode_crtc->buffer_id)
1435 fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
1436 }
1437
1438 if (!fbcon_id)
1439 return;
1440
1441 if (fbcon_id == drmmode->fb_id) {
1442 /* in some rare case there might be no fbcon and we might already
1443 * be the one with the current fb to avoid a false deadlck in
1444 * kernel ttm code just do nothing as anyway there is nothing
1445 * to do
1446 */
1447 return;
1448 }
1449
1450 src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
1451 if (!src)
1452 return;
1453
1454 dst = pScreen->GetScreenPixmap(pScreen);
1455
1456 gc = GetScratchGC(pScrn->depth, pScreen);
1457 ValidateGC(&dst->drawable, gc);
1458
1459 (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0,
1460 pScrn->virtualX, pScrn->virtualY, 0, 0);
1461
1462 FreeScratchGC(gc);
1463
1464 pScreen->canDoBGNoneRoot = TRUE;
1465
1466 if (drmmode->fbcon_pixmap)
1467 pScrn->pScreen->DestroyPixmap(drmmode->fbcon_pixmap);
1468 drmmode->fbcon_pixmap = NULL;
1469 #endif
1470 }
1471
1472 static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc,DisplayModePtr mode,Rotation rotation,int x,int y)1473 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
1474 Rotation rotation, int x, int y)
1475 {
1476 modesettingPtr ms = modesettingPTR(crtc->scrn);
1477 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1478 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1479 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1480 int saved_x, saved_y;
1481 Rotation saved_rotation;
1482 DisplayModeRec saved_mode;
1483 Bool ret = TRUE;
1484 Bool can_test;
1485 int i;
1486
1487 saved_mode = crtc->mode;
1488 saved_x = crtc->x;
1489 saved_y = crtc->y;
1490 saved_rotation = crtc->rotation;
1491
1492 if (mode) {
1493 crtc->mode = *mode;
1494 crtc->x = x;
1495 crtc->y = y;
1496 crtc->rotation = rotation;
1497
1498 if (!xf86CrtcRotate(crtc)) {
1499 goto done;
1500 }
1501
1502 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
1503 crtc->gamma_blue, crtc->gamma_size);
1504
1505 can_test = drmmode_crtc_can_test_mode(crtc);
1506 if (drmmode_crtc_set_mode(crtc, can_test)) {
1507 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1508 "failed to set mode: %s\n", strerror(errno));
1509 ret = FALSE;
1510 goto done;
1511 } else
1512 ret = TRUE;
1513
1514 if (crtc->scrn->pScreen)
1515 xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
1516
1517 ms->pending_modeset = TRUE;
1518 drmmode_crtc->need_modeset = FALSE;
1519 crtc->funcs->dpms(crtc, DPMSModeOn);
1520
1521 if (drmmode_crtc->prime_pixmap_back)
1522 drmmode_InitSharedPixmapFlipping(crtc, drmmode);
1523
1524 /* go through all the outputs and force DPMS them back on? */
1525 for (i = 0; i < xf86_config->num_output; i++) {
1526 xf86OutputPtr output = xf86_config->output[i];
1527 drmmode_output_private_ptr drmmode_output;
1528
1529 if (output->crtc != crtc)
1530 continue;
1531
1532 drmmode_output = output->driver_private;
1533 if (drmmode_output->output_id == -1)
1534 continue;
1535 output->funcs->dpms(output, DPMSModeOn);
1536 }
1537
1538 /* if we only tested the mode previously, really set it now */
1539 if (can_test)
1540 drmmode_crtc_set_mode(crtc, FALSE);
1541 ms->pending_modeset = FALSE;
1542 }
1543
1544 done:
1545 if (!ret) {
1546 crtc->x = saved_x;
1547 crtc->y = saved_y;
1548 crtc->rotation = saved_rotation;
1549 crtc->mode = saved_mode;
1550 } else
1551 crtc->active = TRUE;
1552
1553 return ret;
1554 }
1555
1556 static void
drmmode_set_cursor_colors(xf86CrtcPtr crtc,int bg,int fg)1557 drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
1558 {
1559
1560 }
1561
1562 static void
drmmode_set_cursor_position(xf86CrtcPtr crtc,int x,int y)1563 drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
1564 {
1565 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1566 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1567
1568 drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
1569 }
1570
1571 static Bool
drmmode_set_cursor(xf86CrtcPtr crtc)1572 drmmode_set_cursor(xf86CrtcPtr crtc)
1573 {
1574 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1575 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1576 uint32_t handle = drmmode_crtc->cursor_bo->handle;
1577 modesettingPtr ms = modesettingPTR(crtc->scrn);
1578 CursorPtr cursor = xf86CurrentCursor(crtc->scrn->pScreen);
1579 int ret = -EINVAL;
1580
1581 if (cursor == NullCursor)
1582 return TRUE;
1583
1584 ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1585 handle, ms->cursor_width, ms->cursor_height,
1586 cursor->bits->xhot, cursor->bits->yhot);
1587
1588 /* -EINVAL can mean that an old kernel supports drmModeSetCursor but
1589 * not drmModeSetCursor2, though it can mean other things too. */
1590 if (ret == -EINVAL)
1591 ret = drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1592 handle, ms->cursor_width, ms->cursor_height);
1593
1594 /* -ENXIO normally means that the current drm driver supports neither
1595 * cursor_set nor cursor_set2. Disable hardware cursor support for
1596 * the rest of the session in that case. */
1597 if (ret == -ENXIO) {
1598 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1599 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
1600
1601 cursor_info->MaxWidth = cursor_info->MaxHeight = 0;
1602 drmmode_crtc->drmmode->sw_cursor = TRUE;
1603 }
1604
1605 if (ret)
1606 /* fallback to swcursor */
1607 return FALSE;
1608 return TRUE;
1609 }
1610
1611 static void drmmode_hide_cursor(xf86CrtcPtr crtc);
1612
1613 /*
1614 * The load_cursor_argb_check driver hook.
1615 *
1616 * Sets the hardware cursor by calling the drmModeSetCursor2 ioctl.
1617 * On failure, returns FALSE indicating that the X server should fall
1618 * back to software cursors.
1619 */
1620 static Bool
drmmode_load_cursor_argb_check(xf86CrtcPtr crtc,CARD32 * image)1621 drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 *image)
1622 {
1623 modesettingPtr ms = modesettingPTR(crtc->scrn);
1624 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1625 int i;
1626 uint32_t *ptr;
1627
1628 /* cursor should be mapped already */
1629 ptr = (uint32_t *) (drmmode_crtc->cursor_bo->ptr);
1630
1631 for (i = 0; i < ms->cursor_width * ms->cursor_height; i++)
1632 ptr[i] = image[i]; // cpu_to_le32(image[i]);
1633
1634 if (drmmode_crtc->cursor_up)
1635 return drmmode_set_cursor(crtc);
1636 return TRUE;
1637 }
1638
1639 static void
drmmode_hide_cursor(xf86CrtcPtr crtc)1640 drmmode_hide_cursor(xf86CrtcPtr crtc)
1641 {
1642 modesettingPtr ms = modesettingPTR(crtc->scrn);
1643 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1644 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1645
1646 drmmode_crtc->cursor_up = FALSE;
1647 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
1648 ms->cursor_width, ms->cursor_height);
1649 }
1650
1651 static Bool
drmmode_show_cursor(xf86CrtcPtr crtc)1652 drmmode_show_cursor(xf86CrtcPtr crtc)
1653 {
1654 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1655 drmmode_crtc->cursor_up = TRUE;
1656 return drmmode_set_cursor(crtc);
1657 }
1658
1659 static void
drmmode_crtc_gamma_set(xf86CrtcPtr crtc,uint16_t * red,uint16_t * green,uint16_t * blue,int size)1660 drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
1661 uint16_t * blue, int size)
1662 {
1663 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1664 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1665
1666 drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1667 size, red, green, blue);
1668 }
1669
1670 static Bool
drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)1671 drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix,
1672 PixmapPtr *target)
1673 {
1674 ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
1675 PixmapPtr screenpix = screen->GetScreenPixmap(screen);
1676 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1677 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1678 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1679 int c, total_width = 0, max_height = 0, this_x = 0;
1680
1681 if (*target) {
1682 PixmapStopDirtyTracking(&(*target)->drawable, screenpix);
1683 if (drmmode->fb_id) {
1684 drmModeRmFB(drmmode->fd, drmmode->fb_id);
1685 drmmode->fb_id = 0;
1686 }
1687 drmmode_crtc->prime_pixmap_x = 0;
1688 *target = NULL;
1689 }
1690
1691 if (!ppix)
1692 return TRUE;
1693
1694 /* iterate over all the attached crtcs to work out the bounding box */
1695 for (c = 0; c < xf86_config->num_crtc; c++) {
1696 xf86CrtcPtr iter = xf86_config->crtc[c];
1697 if (!iter->enabled && iter != crtc)
1698 continue;
1699 if (iter == crtc) {
1700 this_x = total_width;
1701 total_width += ppix->drawable.width;
1702 if (max_height < ppix->drawable.height)
1703 max_height = ppix->drawable.height;
1704 } else {
1705 total_width += iter->mode.HDisplay;
1706 if (max_height < iter->mode.VDisplay)
1707 max_height = iter->mode.VDisplay;
1708 }
1709 }
1710
1711 if (total_width != screenpix->drawable.width ||
1712 max_height != screenpix->drawable.height) {
1713
1714 if (!drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height))
1715 return FALSE;
1716
1717 screenpix = screen->GetScreenPixmap(screen);
1718 screen->width = screenpix->drawable.width = total_width;
1719 screen->height = screenpix->drawable.height = max_height;
1720 }
1721 drmmode_crtc->prime_pixmap_x = this_x;
1722 PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0,
1723 RR_Rotate_0);
1724 *target = ppix;
1725 return TRUE;
1726 }
1727
1728 static Bool
drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)1729 drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix,
1730 PixmapPtr *target)
1731 {
1732 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1733 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1734 msPixmapPrivPtr ppriv;
1735 void *ptr;
1736
1737 if (*target) {
1738 ppriv = msGetPixmapPriv(drmmode, *target);
1739 drmModeRmFB(drmmode->fd, ppriv->fb_id);
1740 ppriv->fb_id = 0;
1741 if (ppriv->slave_damage) {
1742 DamageUnregister(ppriv->slave_damage);
1743 ppriv->slave_damage = NULL;
1744 }
1745 *target = NULL;
1746 }
1747
1748 if (!ppix)
1749 return TRUE;
1750
1751 ppriv = msGetPixmapPriv(drmmode, ppix);
1752 if (!ppriv->slave_damage) {
1753 ppriv->slave_damage = DamageCreate(NULL, NULL,
1754 DamageReportNone,
1755 TRUE,
1756 crtc->randr_crtc->pScreen,
1757 NULL);
1758 }
1759 ptr = drmmode_map_slave_bo(drmmode, ppriv);
1760 ppix->devPrivate.ptr = ptr;
1761 DamageRegister(&ppix->drawable, ppriv->slave_damage);
1762
1763 if (ppriv->fb_id == 0) {
1764 drmModeAddFB(drmmode->fd, ppix->drawable.width,
1765 ppix->drawable.height,
1766 ppix->drawable.depth,
1767 ppix->drawable.bitsPerPixel,
1768 ppix->devKind, ppriv->backing_bo->handle, &ppriv->fb_id);
1769 }
1770 *target = ppix;
1771 return TRUE;
1772 }
1773
1774 static Bool
drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)1775 drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
1776 PixmapPtr *target)
1777 {
1778 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1779 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1780
1781 if (drmmode->reverse_prime_offload_mode)
1782 return drmmode_set_target_scanout_pixmap_gpu(crtc, ppix, target);
1783 else
1784 return drmmode_set_target_scanout_pixmap_cpu(crtc, ppix, target);
1785 }
1786
1787 static Bool
drmmode_set_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix)1788 drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
1789 {
1790 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1791
1792 /* Use DisableSharedPixmapFlipping before switching to single buf */
1793 if (drmmode_crtc->enable_flipping)
1794 return FALSE;
1795
1796 return drmmode_set_target_scanout_pixmap(crtc, ppix,
1797 &drmmode_crtc->prime_pixmap);
1798 }
1799
1800 static void
drmmode_clear_pixmap(PixmapPtr pixmap)1801 drmmode_clear_pixmap(PixmapPtr pixmap)
1802 {
1803 ScreenPtr screen = pixmap->drawable.pScreen;
1804 GCPtr gc;
1805
1806 gc = GetScratchGC(pixmap->drawable.depth, screen);
1807 if (gc) {
1808 miClearDrawable(&pixmap->drawable, gc);
1809 FreeScratchGC(gc);
1810 }
1811 }
1812
1813 static void *
drmmode_shadow_allocate(xf86CrtcPtr crtc,int width,int height)1814 drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
1815 {
1816 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1817 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1818 int ret;
1819
1820 if (!drmmode_create_bo(drmmode, &drmmode_crtc->rotate_bo,
1821 width, height, drmmode->kbpp)) {
1822 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1823 "Couldn't allocate shadow memory for rotated CRTC\n");
1824 return NULL;
1825 }
1826
1827 ret = drmmode_bo_import(drmmode, &drmmode_crtc->rotate_bo,
1828 &drmmode_crtc->rotate_fb_id);
1829
1830 if (ret) {
1831 ErrorF("failed to add rotate fb\n");
1832 drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
1833 return NULL;
1834 }
1835
1836 #ifdef GLAMOR_HAS_GBM
1837 if (drmmode->gbm)
1838 return drmmode_crtc->rotate_bo.gbm;
1839 #endif
1840 return drmmode_crtc->rotate_bo.dumb;
1841 }
1842
1843 static PixmapPtr
drmmode_create_pixmap_header(ScreenPtr pScreen,int width,int height,int depth,int bitsPerPixel,int devKind,void * pPixData)1844 drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
1845 int depth, int bitsPerPixel, int devKind,
1846 void *pPixData)
1847 {
1848 PixmapPtr pixmap;
1849
1850 /* width and height of 0 means don't allocate any pixmap data */
1851 pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
1852
1853 if (pixmap) {
1854 if ((*pScreen->ModifyPixmapHeader)(pixmap, width, height, depth,
1855 bitsPerPixel, devKind, pPixData))
1856 return pixmap;
1857 (*pScreen->DestroyPixmap)(pixmap);
1858 }
1859 return NullPixmap;
1860 }
1861
1862 static Bool
1863 drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo);
1864
1865 static PixmapPtr
drmmode_shadow_create(xf86CrtcPtr crtc,void * data,int width,int height)1866 drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1867 {
1868 ScrnInfoPtr scrn = crtc->scrn;
1869 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1870 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1871 uint32_t rotate_pitch;
1872 PixmapPtr rotate_pixmap;
1873 void *pPixData = NULL;
1874
1875 if (!data) {
1876 data = drmmode_shadow_allocate(crtc, width, height);
1877 if (!data) {
1878 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1879 "Couldn't allocate shadow pixmap for rotated CRTC\n");
1880 return NULL;
1881 }
1882 }
1883
1884 if (!drmmode_bo_has_bo(&drmmode_crtc->rotate_bo)) {
1885 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1886 "Couldn't allocate shadow pixmap for rotated CRTC\n");
1887 return NULL;
1888 }
1889
1890 pPixData = drmmode_bo_map(drmmode, &drmmode_crtc->rotate_bo);
1891 rotate_pitch = drmmode_bo_get_pitch(&drmmode_crtc->rotate_bo),
1892
1893 rotate_pixmap = drmmode_create_pixmap_header(scrn->pScreen,
1894 width, height,
1895 scrn->depth,
1896 drmmode->kbpp,
1897 rotate_pitch,
1898 pPixData);
1899
1900 if (rotate_pixmap == NULL) {
1901 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1902 "Couldn't allocate shadow pixmap for rotated CRTC\n");
1903 return NULL;
1904 }
1905
1906 drmmode_set_pixmap_bo(drmmode, rotate_pixmap, &drmmode_crtc->rotate_bo);
1907
1908 return rotate_pixmap;
1909 }
1910
1911 static void
drmmode_shadow_destroy(xf86CrtcPtr crtc,PixmapPtr rotate_pixmap,void * data)1912 drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
1913 {
1914 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1915 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1916
1917 if (rotate_pixmap) {
1918 rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap);
1919 }
1920
1921 if (data) {
1922 drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
1923 drmmode_crtc->rotate_fb_id = 0;
1924
1925 drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
1926 memset(&drmmode_crtc->rotate_bo, 0, sizeof drmmode_crtc->rotate_bo);
1927 }
1928 }
1929
1930 static void
drmmode_crtc_destroy(xf86CrtcPtr crtc)1931 drmmode_crtc_destroy(xf86CrtcPtr crtc)
1932 {
1933 drmmode_mode_ptr iterator, next;
1934 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1935 modesettingPtr ms = modesettingPTR(crtc->scrn);
1936
1937 if (!ms->atomic_modeset)
1938 return;
1939
1940 drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
1941 xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) {
1942 drm_mode_destroy(crtc, iterator);
1943 }
1944 }
1945
1946 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
1947 .dpms = drmmode_crtc_dpms,
1948 .set_mode_major = drmmode_set_mode_major,
1949 .set_cursor_colors = drmmode_set_cursor_colors,
1950 .set_cursor_position = drmmode_set_cursor_position,
1951 .show_cursor_check = drmmode_show_cursor,
1952 .hide_cursor = drmmode_hide_cursor,
1953 .load_cursor_argb_check = drmmode_load_cursor_argb_check,
1954
1955 .gamma_set = drmmode_crtc_gamma_set,
1956 .destroy = drmmode_crtc_destroy,
1957 .set_scanout_pixmap = drmmode_set_scanout_pixmap,
1958 .shadow_allocate = drmmode_shadow_allocate,
1959 .shadow_create = drmmode_shadow_create,
1960 .shadow_destroy = drmmode_shadow_destroy,
1961 };
1962
1963 static uint32_t
drmmode_crtc_vblank_pipe(int crtc_id)1964 drmmode_crtc_vblank_pipe(int crtc_id)
1965 {
1966 if (crtc_id > 1)
1967 return crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT;
1968 else if (crtc_id > 0)
1969 return DRM_VBLANK_SECONDARY;
1970 else
1971 return 0;
1972 }
1973
1974 static Bool
is_plane_assigned(ScrnInfoPtr scrn,int plane_id)1975 is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
1976 {
1977 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1978 int c;
1979
1980 for (c = 0; c < xf86_config->num_crtc; c++) {
1981 xf86CrtcPtr iter = xf86_config->crtc[c];
1982 drmmode_crtc_private_ptr drmmode_crtc = iter->driver_private;
1983 if (drmmode_crtc->plane_id == plane_id)
1984 return TRUE;
1985 }
1986
1987 return FALSE;
1988 }
1989
1990 /**
1991 * Populates the formats array, and the modifiers of each format for a drm_plane.
1992 */
1993 static Bool
populate_format_modifiers(xf86CrtcPtr crtc,const drmModePlane * kplane,uint32_t blob_id)1994 populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane,
1995 uint32_t blob_id)
1996 {
1997 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1998 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1999 unsigned i, j;
2000 drmModePropertyBlobRes *blob;
2001 struct drm_format_modifier_blob *fmt_mod_blob;
2002 uint32_t *blob_formats;
2003 struct drm_format_modifier *blob_modifiers;
2004
2005 if (!blob_id)
2006 return FALSE;
2007
2008 blob = drmModeGetPropertyBlob(drmmode->fd, blob_id);
2009 if (!blob)
2010 return FALSE;
2011
2012 fmt_mod_blob = blob->data;
2013 blob_formats = formats_ptr(fmt_mod_blob);
2014 blob_modifiers = modifiers_ptr(fmt_mod_blob);
2015
2016 assert(drmmode_crtc->num_formats == fmt_mod_blob->count_formats);
2017
2018 for (i = 0; i < fmt_mod_blob->count_formats; i++) {
2019 uint32_t num_modifiers = 0;
2020 uint64_t *modifiers = NULL;
2021 uint64_t *tmp;
2022 for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
2023 struct drm_format_modifier *mod = &blob_modifiers[j];
2024
2025 if ((i < mod->offset) || (i > mod->offset + 63))
2026 continue;
2027 if (!(mod->formats & (1 << (i - mod->offset))))
2028 continue;
2029
2030 num_modifiers++;
2031 tmp = realloc(modifiers, num_modifiers * sizeof(modifiers[0]));
2032 if (!tmp) {
2033 free(modifiers);
2034 drmModeFreePropertyBlob(blob);
2035 return FALSE;
2036 }
2037 modifiers = tmp;
2038 modifiers[num_modifiers - 1] = mod->modifier;
2039 }
2040
2041 drmmode_crtc->formats[i].format = blob_formats[i];
2042 drmmode_crtc->formats[i].modifiers = modifiers;
2043 drmmode_crtc->formats[i].num_modifiers = num_modifiers;
2044 }
2045
2046 drmModeFreePropertyBlob(blob);
2047
2048 return TRUE;
2049 }
2050
2051 static void
drmmode_crtc_create_planes(xf86CrtcPtr crtc,int num)2052 drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
2053 {
2054 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2055 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2056 drmModePlaneRes *kplane_res;
2057 drmModePlane *kplane, *best_kplane = NULL;
2058 drmModeObjectProperties *props;
2059 uint32_t i, type, blob_id;
2060 int current_crtc, best_plane = 0;
2061
2062 static drmmode_prop_enum_info_rec plane_type_enums[] = {
2063 [DRMMODE_PLANE_TYPE_PRIMARY] = {
2064 .name = "Primary",
2065 },
2066 [DRMMODE_PLANE_TYPE_OVERLAY] = {
2067 .name = "Overlay",
2068 },
2069 [DRMMODE_PLANE_TYPE_CURSOR] = {
2070 .name = "Cursor",
2071 },
2072 };
2073 static const drmmode_prop_info_rec plane_props[] = {
2074 [DRMMODE_PLANE_TYPE] = {
2075 .name = "type",
2076 .enum_values = plane_type_enums,
2077 .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
2078 },
2079 [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
2080 [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
2081 [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", },
2082 [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
2083 [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
2084 [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
2085 [DRMMODE_PLANE_SRC_H] = { .name = "SRC_H", },
2086 [DRMMODE_PLANE_CRTC_X] = { .name = "CRTC_X", },
2087 [DRMMODE_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
2088 [DRMMODE_PLANE_CRTC_W] = { .name = "CRTC_W", },
2089 [DRMMODE_PLANE_CRTC_H] = { .name = "CRTC_H", },
2090 };
2091 drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
2092
2093 if (!drmmode_prop_info_copy(tmp_props, plane_props, DRMMODE_PLANE__COUNT, 0)) {
2094 xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2095 "failed to copy plane property info\n");
2096 drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2097 return;
2098 }
2099
2100 kplane_res = drmModeGetPlaneResources(drmmode->fd);
2101 if (!kplane_res) {
2102 xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2103 "failed to get plane resources: %s\n", strerror(errno));
2104 drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2105 return;
2106 }
2107
2108 for (i = 0; i < kplane_res->count_planes; i++) {
2109 int plane_id;
2110
2111 kplane = drmModeGetPlane(drmmode->fd, kplane_res->planes[i]);
2112 if (!kplane)
2113 continue;
2114
2115 if (!(kplane->possible_crtcs & (1 << num)) ||
2116 is_plane_assigned(drmmode->scrn, kplane->plane_id)) {
2117 drmModeFreePlane(kplane);
2118 continue;
2119 }
2120
2121 plane_id = kplane->plane_id;
2122
2123 props = drmModeObjectGetProperties(drmmode->fd, plane_id,
2124 DRM_MODE_OBJECT_PLANE);
2125 if (!props) {
2126 xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2127 "couldn't get plane properties\n");
2128 drmModeFreePlane(kplane);
2129 continue;
2130 }
2131
2132 drmmode_prop_info_update(drmmode, tmp_props, DRMMODE_PLANE__COUNT, props);
2133
2134 /* Only primary planes are important for atomic page-flipping */
2135 type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
2136 props, DRMMODE_PLANE_TYPE__COUNT);
2137 if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
2138 drmModeFreePlane(kplane);
2139 drmModeFreeObjectProperties(props);
2140 continue;
2141 }
2142
2143 /* Check if plane is already on this CRTC */
2144 current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
2145 props, 0);
2146 if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
2147 if (best_plane) {
2148 drmModeFreePlane(best_kplane);
2149 drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
2150 }
2151 best_plane = plane_id;
2152 best_kplane = kplane;
2153 blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
2154 props, 0);
2155 drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
2156 DRMMODE_PLANE__COUNT, 1);
2157 drmModeFreeObjectProperties(props);
2158 break;
2159 }
2160
2161 if (!best_plane) {
2162 best_plane = plane_id;
2163 best_kplane = kplane;
2164 blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
2165 props, 0);
2166 drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
2167 DRMMODE_PLANE__COUNT, 1);
2168 } else {
2169 drmModeFreePlane(kplane);
2170 }
2171
2172 drmModeFreeObjectProperties(props);
2173 }
2174
2175 drmmode_crtc->plane_id = best_plane;
2176 if (best_kplane) {
2177 drmmode_crtc->num_formats = best_kplane->count_formats;
2178 drmmode_crtc->formats = calloc(sizeof(drmmode_format_rec),
2179 best_kplane->count_formats);
2180 if (!populate_format_modifiers(crtc, best_kplane, blob_id)) {
2181 for (i = 0; i < best_kplane->count_formats; i++)
2182 drmmode_crtc->formats[i].format = best_kplane->formats[i];
2183 }
2184 drmModeFreePlane(best_kplane);
2185 }
2186
2187 drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2188 drmModeFreePlaneResources(kplane_res);
2189 }
2190
2191 static unsigned int
drmmode_crtc_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,drmModeResPtr mode_res,int num)2192 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
2193 {
2194 xf86CrtcPtr crtc;
2195 drmmode_crtc_private_ptr drmmode_crtc;
2196 modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
2197 modesettingPtr ms = modesettingPTR(pScrn);
2198 drmModeObjectPropertiesPtr props;
2199 static const drmmode_prop_info_rec crtc_props[] = {
2200 [DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" },
2201 [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" },
2202 };
2203
2204 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
2205 if (crtc == NULL)
2206 return 0;
2207 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
2208 crtc->driver_private = drmmode_crtc;
2209 drmmode_crtc->mode_crtc =
2210 drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
2211 drmmode_crtc->drmmode = drmmode;
2212 drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
2213 xorg_list_init(&drmmode_crtc->mode_list);
2214
2215 if (ms->atomic_modeset) {
2216 props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
2217 DRM_MODE_OBJECT_CRTC);
2218 if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props,
2219 DRMMODE_CRTC__COUNT, 0)) {
2220 xf86CrtcDestroy(crtc);
2221 return 0;
2222 }
2223
2224 drmmode_prop_info_update(drmmode, drmmode_crtc->props,
2225 DRMMODE_CRTC__COUNT, props);
2226 drmModeFreeObjectProperties(props);
2227 drmmode_crtc_create_planes(crtc, num);
2228 }
2229
2230 /* Hide any cursors which may be active from previous users */
2231 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);
2232
2233 /* Mark num'th crtc as in use on this device. */
2234 ms_ent->assigned_crtcs |= (1 << num);
2235 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
2236 "Allocated crtc nr. %d to this screen.\n", num);
2237
2238 return 1;
2239 }
2240
2241 /*
2242 * Update all of the property values for an output
2243 */
2244 static void
drmmode_output_update_properties(xf86OutputPtr output)2245 drmmode_output_update_properties(xf86OutputPtr output)
2246 {
2247 drmmode_output_private_ptr drmmode_output = output->driver_private;
2248 int i, j, k;
2249 int err;
2250 drmModeConnectorPtr koutput;
2251
2252 /* Use the most recently fetched values from the kernel */
2253 koutput = drmmode_output->mode_output;
2254
2255 if (!koutput)
2256 return;
2257
2258 for (i = 0; i < drmmode_output->num_props; i++) {
2259 drmmode_prop_ptr p = &drmmode_output->props[i];
2260
2261 for (j = 0; koutput && j < koutput->count_props; j++) {
2262 if (koutput->props[j] == p->mode_prop->prop_id) {
2263
2264 /* Check to see if the property value has changed */
2265 if (koutput->prop_values[j] != p->value) {
2266
2267 p->value = koutput->prop_values[j];
2268
2269 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
2270 INT32 value = p->value;
2271
2272 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2273 XA_INTEGER, 32, PropModeReplace, 1,
2274 &value, FALSE, TRUE);
2275
2276 if (err != 0) {
2277 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2278 "RRChangeOutputProperty error, %d\n", err);
2279 }
2280 }
2281 else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
2282 for (k = 0; k < p->mode_prop->count_enums; k++)
2283 if (p->mode_prop->enums[k].value == p->value)
2284 break;
2285 if (k < p->mode_prop->count_enums) {
2286 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2287 XA_ATOM, 32, PropModeReplace, 1,
2288 &p->atoms[k + 1], FALSE, TRUE);
2289 if (err != 0) {
2290 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2291 "RRChangeOutputProperty error, %d\n", err);
2292 }
2293 }
2294 }
2295 }
2296 break;
2297 }
2298 }
2299 }
2300 }
2301
2302 static xf86OutputStatus
drmmode_output_detect(xf86OutputPtr output)2303 drmmode_output_detect(xf86OutputPtr output)
2304 {
2305 /* go to the hw and retrieve a new output struct */
2306 drmmode_output_private_ptr drmmode_output = output->driver_private;
2307 drmmode_ptr drmmode = drmmode_output->drmmode;
2308 xf86OutputStatus status;
2309
2310 if (drmmode_output->output_id == -1)
2311 return XF86OutputStatusDisconnected;
2312
2313 drmModeFreeConnector(drmmode_output->mode_output);
2314
2315 drmmode_output->mode_output =
2316 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
2317
2318 if (!drmmode_output->mode_output) {
2319 drmmode_output->output_id = -1;
2320 return XF86OutputStatusDisconnected;
2321 }
2322
2323 drmmode_output_update_properties(output);
2324
2325 switch (drmmode_output->mode_output->connection) {
2326 case DRM_MODE_CONNECTED:
2327 status = XF86OutputStatusConnected;
2328 break;
2329 case DRM_MODE_DISCONNECTED:
2330 status = XF86OutputStatusDisconnected;
2331 break;
2332 default:
2333 case DRM_MODE_UNKNOWNCONNECTION:
2334 status = XF86OutputStatusUnknown;
2335 break;
2336 }
2337 return status;
2338 }
2339
2340 static Bool
drmmode_output_mode_valid(xf86OutputPtr output,DisplayModePtr pModes)2341 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
2342 {
2343 return MODE_OK;
2344 }
2345
2346 static int
koutput_get_prop_idx(int fd,drmModeConnectorPtr koutput,int type,const char * name)2347 koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
2348 int type, const char *name)
2349 {
2350 int idx = -1;
2351
2352 for (int i = 0; i < koutput->count_props; i++) {
2353 drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
2354
2355 if (!prop)
2356 continue;
2357
2358 if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
2359 idx = i;
2360
2361 drmModeFreeProperty(prop);
2362
2363 if (idx > -1)
2364 break;
2365 }
2366
2367 return idx;
2368 }
2369
2370 static int
koutput_get_prop_id(int fd,drmModeConnectorPtr koutput,int type,const char * name)2371 koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
2372 int type, const char *name)
2373 {
2374 int idx = koutput_get_prop_idx(fd, koutput, type, name);
2375
2376 return (idx > -1) ? koutput->props[idx] : -1;
2377 }
2378
2379 static drmModePropertyBlobPtr
koutput_get_prop_blob(int fd,drmModeConnectorPtr koutput,const char * name)2380 koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
2381 {
2382 drmModePropertyBlobPtr blob = NULL;
2383 int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
2384
2385 if (idx > -1)
2386 blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
2387
2388 return blob;
2389 }
2390
2391 static void
drmmode_output_attach_tile(xf86OutputPtr output)2392 drmmode_output_attach_tile(xf86OutputPtr output)
2393 {
2394 drmmode_output_private_ptr drmmode_output = output->driver_private;
2395 drmModeConnectorPtr koutput = drmmode_output->mode_output;
2396 drmmode_ptr drmmode = drmmode_output->drmmode;
2397 struct xf86CrtcTileInfo tile_info, *set = NULL;
2398
2399 if (!koutput) {
2400 xf86OutputSetTile(output, NULL);
2401 return;
2402 }
2403
2404 drmModeFreePropertyBlob(drmmode_output->tile_blob);
2405
2406 /* look for a TILE property */
2407 drmmode_output->tile_blob =
2408 koutput_get_prop_blob(drmmode->fd, koutput, "TILE");
2409
2410 if (drmmode_output->tile_blob) {
2411 if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE)
2412 set = &tile_info;
2413 }
2414 xf86OutputSetTile(output, set);
2415 }
2416
2417 static Bool
has_panel_fitter(xf86OutputPtr output)2418 has_panel_fitter(xf86OutputPtr output)
2419 {
2420 drmmode_output_private_ptr drmmode_output = output->driver_private;
2421 drmModeConnectorPtr koutput = drmmode_output->mode_output;
2422 drmmode_ptr drmmode = drmmode_output->drmmode;
2423 int idx;
2424
2425 /* Presume that if the output supports scaling, then we have a
2426 * panel fitter capable of adjust any mode to suit.
2427 */
2428 idx = koutput_get_prop_idx(drmmode->fd, koutput,
2429 DRM_MODE_PROP_ENUM, "scaling mode");
2430
2431 return (idx > -1);
2432 }
2433
2434 static DisplayModePtr
drmmode_output_add_gtf_modes(xf86OutputPtr output,DisplayModePtr Modes)2435 drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes)
2436 {
2437 xf86MonPtr mon = output->MonInfo;
2438 DisplayModePtr i, m, preferred = NULL;
2439 int max_x = 0, max_y = 0;
2440 float max_vrefresh = 0.0;
2441
2442 if (mon && gtf_supported(mon))
2443 return Modes;
2444
2445 if (!has_panel_fitter(output))
2446 return Modes;
2447
2448 for (m = Modes; m; m = m->next) {
2449 if (m->type & M_T_PREFERRED)
2450 preferred = m;
2451 max_x = max(max_x, m->HDisplay);
2452 max_y = max(max_y, m->VDisplay);
2453 max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
2454 }
2455
2456 max_vrefresh = max(max_vrefresh, 60.0);
2457 max_vrefresh *= (1 + SYNC_TOLERANCE);
2458
2459 m = xf86GetDefaultModes();
2460 xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
2461
2462 for (i = m; i; i = i->next) {
2463 if (xf86ModeVRefresh(i) > max_vrefresh)
2464 i->status = MODE_VSYNC;
2465 if (preferred &&
2466 i->HDisplay >= preferred->HDisplay &&
2467 i->VDisplay >= preferred->VDisplay &&
2468 xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred))
2469 i->status = MODE_VSYNC;
2470 }
2471
2472 xf86PruneInvalidModes(output->scrn, &m, FALSE);
2473
2474 return xf86ModesAdd(Modes, m);
2475 }
2476
2477 static DisplayModePtr
drmmode_output_get_modes(xf86OutputPtr output)2478 drmmode_output_get_modes(xf86OutputPtr output)
2479 {
2480 drmmode_output_private_ptr drmmode_output = output->driver_private;
2481 drmModeConnectorPtr koutput = drmmode_output->mode_output;
2482 drmmode_ptr drmmode = drmmode_output->drmmode;
2483 int i;
2484 DisplayModePtr Modes = NULL, Mode;
2485 xf86MonPtr mon = NULL;
2486
2487 if (!koutput)
2488 return NULL;
2489
2490 drmModeFreePropertyBlob(drmmode_output->edid_blob);
2491
2492 /* look for an EDID property */
2493 drmmode_output->edid_blob =
2494 koutput_get_prop_blob(drmmode->fd, koutput, "EDID");
2495
2496 if (drmmode_output->edid_blob) {
2497 mon = xf86InterpretEDID(output->scrn->scrnIndex,
2498 drmmode_output->edid_blob->data);
2499 if (mon && drmmode_output->edid_blob->length > 128)
2500 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
2501 }
2502 xf86OutputSetEDID(output, mon);
2503
2504 drmmode_output_attach_tile(output);
2505
2506 /* modes should already be available */
2507 for (i = 0; i < koutput->count_modes; i++) {
2508 Mode = xnfalloc(sizeof(DisplayModeRec));
2509
2510 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
2511 Modes = xf86ModesAdd(Modes, Mode);
2512
2513 }
2514
2515 return drmmode_output_add_gtf_modes(output, Modes);
2516 }
2517
2518 static void
drmmode_output_destroy(xf86OutputPtr output)2519 drmmode_output_destroy(xf86OutputPtr output)
2520 {
2521 drmmode_output_private_ptr drmmode_output = output->driver_private;
2522 int i;
2523
2524 drmModeFreePropertyBlob(drmmode_output->edid_blob);
2525 drmModeFreePropertyBlob(drmmode_output->tile_blob);
2526
2527 for (i = 0; i < drmmode_output->num_props; i++) {
2528 drmModeFreeProperty(drmmode_output->props[i].mode_prop);
2529 free(drmmode_output->props[i].atoms);
2530 }
2531 free(drmmode_output->props);
2532 if (drmmode_output->mode_output) {
2533 for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
2534 drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
2535 }
2536 drmModeFreeConnector(drmmode_output->mode_output);
2537 }
2538 free(drmmode_output->mode_encoders);
2539 free(drmmode_output);
2540 output->driver_private = NULL;
2541 }
2542
2543 static void
drmmode_output_dpms(xf86OutputPtr output,int mode)2544 drmmode_output_dpms(xf86OutputPtr output, int mode)
2545 {
2546 modesettingPtr ms = modesettingPTR(output->scrn);
2547 drmmode_output_private_ptr drmmode_output = output->driver_private;
2548 drmmode_ptr drmmode = drmmode_output->drmmode;
2549 xf86CrtcPtr crtc = output->crtc;
2550 drmModeConnectorPtr koutput = drmmode_output->mode_output;
2551
2552 if (!koutput)
2553 return;
2554
2555 /* XXX Check if DPMS mode is already the right one */
2556
2557 drmmode_output->dpms = mode;
2558
2559 if (ms->atomic_modeset) {
2560 if (mode != DPMSModeOn && !ms->pending_modeset)
2561 drmmode_output_disable(output);
2562 } else {
2563 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
2564 drmmode_output->dpms_enum_id, mode);
2565 }
2566
2567 if (crtc) {
2568 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2569
2570 if (mode == DPMSModeOn) {
2571 if (drmmode_crtc->need_modeset)
2572 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
2573 crtc->x, crtc->y);
2574
2575 if (drmmode_crtc->enable_flipping)
2576 drmmode_InitSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
2577 } else {
2578 if (drmmode_crtc->enable_flipping)
2579 drmmode_FiniSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
2580 }
2581 }
2582
2583 return;
2584 }
2585
2586 static Bool
drmmode_property_ignore(drmModePropertyPtr prop)2587 drmmode_property_ignore(drmModePropertyPtr prop)
2588 {
2589 if (!prop)
2590 return TRUE;
2591 /* ignore blob prop */
2592 if (prop->flags & DRM_MODE_PROP_BLOB)
2593 return TRUE;
2594 /* ignore standard property */
2595 if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS") ||
2596 !strcmp(prop->name, "CRTC_ID"))
2597 return TRUE;
2598
2599 return FALSE;
2600 }
2601
2602 static void
drmmode_output_create_resources(xf86OutputPtr output)2603 drmmode_output_create_resources(xf86OutputPtr output)
2604 {
2605 drmmode_output_private_ptr drmmode_output = output->driver_private;
2606 drmModeConnectorPtr mode_output = drmmode_output->mode_output;
2607 drmmode_ptr drmmode = drmmode_output->drmmode;
2608 drmModePropertyPtr drmmode_prop;
2609 int i, j, err;
2610
2611 drmmode_output->props =
2612 calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
2613 if (!drmmode_output->props)
2614 return;
2615
2616 drmmode_output->num_props = 0;
2617 for (i = 0, j = 0; i < mode_output->count_props; i++) {
2618 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
2619 if (drmmode_property_ignore(drmmode_prop)) {
2620 drmModeFreeProperty(drmmode_prop);
2621 continue;
2622 }
2623 drmmode_output->props[j].mode_prop = drmmode_prop;
2624 drmmode_output->props[j].value = mode_output->prop_values[i];
2625 drmmode_output->num_props++;
2626 j++;
2627 }
2628
2629 /* Create CONNECTOR_ID property */
2630 {
2631 Atom name = MakeAtom("CONNECTOR_ID", 12, TRUE);
2632 INT32 value = mode_output->connector_id;
2633
2634 if (name != BAD_RESOURCE) {
2635 err = RRConfigureOutputProperty(output->randr_output, name,
2636 FALSE, FALSE, TRUE,
2637 1, &value);
2638 if (err != 0) {
2639 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2640 "RRConfigureOutputProperty error, %d\n", err);
2641 }
2642 err = RRChangeOutputProperty(output->randr_output, name,
2643 XA_INTEGER, 32, PropModeReplace, 1,
2644 &value, FALSE, FALSE);
2645 if (err != 0) {
2646 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2647 "RRChangeOutputProperty error, %d\n", err);
2648 }
2649 }
2650 }
2651
2652 for (i = 0; i < drmmode_output->num_props; i++) {
2653 drmmode_prop_ptr p = &drmmode_output->props[i];
2654
2655 drmmode_prop = p->mode_prop;
2656
2657 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
2658 INT32 prop_range[2];
2659 INT32 value = p->value;
2660
2661 p->num_atoms = 1;
2662 p->atoms = calloc(p->num_atoms, sizeof(Atom));
2663 if (!p->atoms)
2664 continue;
2665 p->atoms[0] =
2666 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
2667 prop_range[0] = drmmode_prop->values[0];
2668 prop_range[1] = drmmode_prop->values[1];
2669 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
2670 FALSE, TRUE,
2671 drmmode_prop->
2672 flags & DRM_MODE_PROP_IMMUTABLE ?
2673 TRUE : FALSE, 2, prop_range);
2674 if (err != 0) {
2675 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2676 "RRConfigureOutputProperty error, %d\n", err);
2677 }
2678 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2679 XA_INTEGER, 32, PropModeReplace, 1,
2680 &value, FALSE, TRUE);
2681 if (err != 0) {
2682 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2683 "RRChangeOutputProperty error, %d\n", err);
2684 }
2685 }
2686 else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
2687 p->num_atoms = drmmode_prop->count_enums + 1;
2688 p->atoms = calloc(p->num_atoms, sizeof(Atom));
2689 if (!p->atoms)
2690 continue;
2691 p->atoms[0] =
2692 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
2693 for (j = 1; j <= drmmode_prop->count_enums; j++) {
2694 struct drm_mode_property_enum *e = &drmmode_prop->enums[j - 1];
2695
2696 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
2697 }
2698 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
2699 FALSE, FALSE,
2700 drmmode_prop->
2701 flags & DRM_MODE_PROP_IMMUTABLE ?
2702 TRUE : FALSE, p->num_atoms - 1,
2703 (INT32 *) &p->atoms[1]);
2704 if (err != 0) {
2705 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2706 "RRConfigureOutputProperty error, %d\n", err);
2707 }
2708 for (j = 0; j < drmmode_prop->count_enums; j++)
2709 if (drmmode_prop->enums[j].value == p->value)
2710 break;
2711 /* there's always a matching value */
2712 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2713 XA_ATOM, 32, PropModeReplace, 1,
2714 &p->atoms[j + 1], FALSE, TRUE);
2715 if (err != 0) {
2716 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2717 "RRChangeOutputProperty error, %d\n", err);
2718 }
2719 }
2720 }
2721 }
2722
2723 static Bool
drmmode_output_set_property(xf86OutputPtr output,Atom property,RRPropertyValuePtr value)2724 drmmode_output_set_property(xf86OutputPtr output, Atom property,
2725 RRPropertyValuePtr value)
2726 {
2727 drmmode_output_private_ptr drmmode_output = output->driver_private;
2728 drmmode_ptr drmmode = drmmode_output->drmmode;
2729 int i;
2730
2731 for (i = 0; i < drmmode_output->num_props; i++) {
2732 drmmode_prop_ptr p = &drmmode_output->props[i];
2733
2734 if (p->atoms[0] != property)
2735 continue;
2736
2737 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
2738 uint32_t val;
2739
2740 if (value->type != XA_INTEGER || value->format != 32 ||
2741 value->size != 1)
2742 return FALSE;
2743 val = *(uint32_t *) value->data;
2744
2745 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
2746 p->mode_prop->prop_id, (uint64_t) val);
2747 return TRUE;
2748 }
2749 else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
2750 Atom atom;
2751 const char *name;
2752 int j;
2753
2754 if (value->type != XA_ATOM || value->format != 32 ||
2755 value->size != 1)
2756 return FALSE;
2757 memcpy(&atom, value->data, 4);
2758 if (!(name = NameForAtom(atom)))
2759 return FALSE;
2760
2761 /* search for matching name string, then set its value down */
2762 for (j = 0; j < p->mode_prop->count_enums; j++) {
2763 if (!strcmp(p->mode_prop->enums[j].name, name)) {
2764 drmModeConnectorSetProperty(drmmode->fd,
2765 drmmode_output->output_id,
2766 p->mode_prop->prop_id,
2767 p->mode_prop->enums[j].value);
2768 return TRUE;
2769 }
2770 }
2771 }
2772 }
2773
2774 return TRUE;
2775 }
2776
2777 static Bool
drmmode_output_get_property(xf86OutputPtr output,Atom property)2778 drmmode_output_get_property(xf86OutputPtr output, Atom property)
2779 {
2780 return TRUE;
2781 }
2782
2783 static const xf86OutputFuncsRec drmmode_output_funcs = {
2784 .dpms = drmmode_output_dpms,
2785 .create_resources = drmmode_output_create_resources,
2786 .set_property = drmmode_output_set_property,
2787 .get_property = drmmode_output_get_property,
2788 .detect = drmmode_output_detect,
2789 .mode_valid = drmmode_output_mode_valid,
2790
2791 .get_modes = drmmode_output_get_modes,
2792 .destroy = drmmode_output_destroy
2793 };
2794
2795 static int subpixel_conv_table[7] = {
2796 0,
2797 SubPixelUnknown,
2798 SubPixelHorizontalRGB,
2799 SubPixelHorizontalBGR,
2800 SubPixelVerticalRGB,
2801 SubPixelVerticalBGR,
2802 SubPixelNone
2803 };
2804
2805 static const char *const output_names[] = {
2806 "None",
2807 "VGA",
2808 "DVI-I",
2809 "DVI-D",
2810 "DVI-A",
2811 "Composite",
2812 "SVIDEO",
2813 "LVDS",
2814 "Component",
2815 "DIN",
2816 "DP",
2817 "HDMI",
2818 "HDMI-B",
2819 "TV",
2820 "eDP",
2821 "Virtual",
2822 "DSI",
2823 "DPI",
2824 };
2825
find_output(ScrnInfoPtr pScrn,int id)2826 static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
2827 {
2828 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2829 int i;
2830 for (i = 0; i < xf86_config->num_output; i++) {
2831 xf86OutputPtr output = xf86_config->output[i];
2832 drmmode_output_private_ptr drmmode_output;
2833
2834 drmmode_output = output->driver_private;
2835 if (drmmode_output->output_id == id)
2836 return output;
2837 }
2838 return NULL;
2839 }
2840
parse_path_blob(drmModePropertyBlobPtr path_blob,int * conn_base_id,char ** path)2841 static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
2842 {
2843 char *conn;
2844 char conn_id[5];
2845 int id, len;
2846 char *blob_data;
2847
2848 if (!path_blob)
2849 return -1;
2850
2851 blob_data = path_blob->data;
2852 /* we only handle MST paths for now */
2853 if (strncmp(blob_data, "mst:", 4))
2854 return -1;
2855
2856 conn = strchr(blob_data + 4, '-');
2857 if (!conn)
2858 return -1;
2859 len = conn - (blob_data + 4);
2860 if (len + 1> 5)
2861 return -1;
2862 memcpy(conn_id, blob_data + 4, len);
2863 conn_id[len] = '\0';
2864 id = strtoul(conn_id, NULL, 10);
2865
2866 *conn_base_id = id;
2867
2868 *path = conn + 1;
2869 return 0;
2870 }
2871
2872 static void
drmmode_create_name(ScrnInfoPtr pScrn,drmModeConnectorPtr koutput,char * name,drmModePropertyBlobPtr path_blob)2873 drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
2874 drmModePropertyBlobPtr path_blob)
2875 {
2876 int ret;
2877 char *extra_path;
2878 int conn_id;
2879 xf86OutputPtr output;
2880
2881 ret = parse_path_blob(path_blob, &conn_id, &extra_path);
2882 if (ret == -1)
2883 goto fallback;
2884
2885 output = find_output(pScrn, conn_id);
2886 if (!output)
2887 goto fallback;
2888
2889 snprintf(name, 32, "%s-%s", output->name, extra_path);
2890 return;
2891
2892 fallback:
2893 if (koutput->connector_type >= ARRAY_SIZE(output_names))
2894 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id);
2895 else if (pScrn->is_gpu)
2896 snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id);
2897 else
2898 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id);
2899 }
2900
2901 static unsigned int
drmmode_output_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,drmModeResPtr mode_res,int num,Bool dynamic,int crtcshift)2902 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift)
2903 {
2904 xf86OutputPtr output;
2905 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2906 modesettingPtr ms = modesettingPTR(pScrn);
2907 drmModeConnectorPtr koutput;
2908 drmModeEncoderPtr *kencoders = NULL;
2909 drmmode_output_private_ptr drmmode_output;
2910 char name[32];
2911 int i;
2912 Bool nonDesktop = FALSE;
2913 drmModePropertyBlobPtr path_blob = NULL;
2914 const char *s;
2915 drmModeObjectPropertiesPtr props;
2916 static const drmmode_prop_info_rec connector_props[] = {
2917 [DRMMODE_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
2918 };
2919
2920 koutput =
2921 drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
2922 if (!koutput)
2923 return 0;
2924
2925 path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH");
2926 i = koutput_get_prop_idx(drmmode->fd, koutput, DRM_MODE_PROP_RANGE, RR_PROPERTY_NON_DESKTOP);
2927 if (i >= 0)
2928 nonDesktop = koutput->prop_values[i] != 0;
2929
2930 drmmode_create_name(pScrn, koutput, name, path_blob);
2931
2932 if (path_blob)
2933 drmModeFreePropertyBlob(path_blob);
2934
2935 if (path_blob && dynamic) {
2936 /* see if we have an output with this name already
2937 and hook stuff up */
2938 for (i = 0; i < xf86_config->num_output; i++) {
2939 output = xf86_config->output[i];
2940
2941 if (strncmp(output->name, name, 32))
2942 continue;
2943
2944 drmmode_output = output->driver_private;
2945 drmmode_output->output_id = mode_res->connectors[num];
2946 drmmode_output->mode_output = koutput;
2947 output->non_desktop = nonDesktop;
2948 return 1;
2949 }
2950 }
2951
2952 kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
2953 if (!kencoders) {
2954 goto out_free_encoders;
2955 }
2956
2957 for (i = 0; i < koutput->count_encoders; i++) {
2958 kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
2959 if (!kencoders[i]) {
2960 goto out_free_encoders;
2961 }
2962 }
2963
2964 if (xf86IsEntityShared(pScrn->entityList[0])) {
2965 if ((s = xf86GetOptValString(drmmode->Options, OPTION_ZAPHOD_HEADS))) {
2966 if (!drmmode_zaphod_string_matches(pScrn, s, name))
2967 goto out_free_encoders;
2968 } else {
2969 if (!drmmode->is_secondary && (num != 0))
2970 goto out_free_encoders;
2971 else if (drmmode->is_secondary && (num != 1))
2972 goto out_free_encoders;
2973 }
2974 }
2975
2976 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
2977 if (!output) {
2978 goto out_free_encoders;
2979 }
2980
2981 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
2982 if (!drmmode_output) {
2983 xf86OutputDestroy(output);
2984 goto out_free_encoders;
2985 }
2986
2987 drmmode_output->output_id = mode_res->connectors[num];
2988 drmmode_output->mode_output = koutput;
2989 drmmode_output->mode_encoders = kencoders;
2990 drmmode_output->drmmode = drmmode;
2991 output->mm_width = koutput->mmWidth;
2992 output->mm_height = koutput->mmHeight;
2993
2994 output->subpixel_order = subpixel_conv_table[koutput->subpixel];
2995 output->interlaceAllowed = TRUE;
2996 output->doubleScanAllowed = TRUE;
2997 output->driver_private = drmmode_output;
2998 output->non_desktop = nonDesktop;
2999
3000 output->possible_crtcs = 0;
3001 for (i = 0; i < koutput->count_encoders; i++) {
3002 output->possible_crtcs |= (kencoders[i]->possible_crtcs >> crtcshift) & 0x7f;
3003 }
3004 /* work out the possible clones later */
3005 output->possible_clones = 0;
3006
3007 if (ms->atomic_modeset) {
3008 if (!drmmode_prop_info_copy(drmmode_output->props_connector,
3009 connector_props, DRMMODE_CONNECTOR__COUNT,
3010 0)) {
3011 goto out_free_encoders;
3012 }
3013 props = drmModeObjectGetProperties(drmmode->fd,
3014 drmmode_output->output_id,
3015 DRM_MODE_OBJECT_CONNECTOR);
3016 drmmode_prop_info_update(drmmode, drmmode_output->props_connector,
3017 DRMMODE_CONNECTOR__COUNT, props);
3018 } else {
3019 drmmode_output->dpms_enum_id =
3020 koutput_get_prop_id(drmmode->fd, koutput, DRM_MODE_PROP_ENUM,
3021 "DPMS");
3022 }
3023
3024 if (dynamic) {
3025 output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
3026 if (output->randr_output) {
3027 drmmode_output_create_resources(output);
3028 RRPostPendingProperties(output->randr_output);
3029 }
3030 }
3031
3032 return 1;
3033
3034 out_free_encoders:
3035 if (kencoders) {
3036 for (i = 0; i < koutput->count_encoders; i++)
3037 drmModeFreeEncoder(kencoders[i]);
3038 free(kencoders);
3039 }
3040 drmModeFreeConnector(koutput);
3041
3042 return 0;
3043 }
3044
3045 static uint32_t
find_clones(ScrnInfoPtr scrn,xf86OutputPtr output)3046 find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
3047 {
3048 drmmode_output_private_ptr drmmode_output =
3049 output->driver_private, clone_drmout;
3050 int i;
3051 xf86OutputPtr clone_output;
3052 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3053 int index_mask = 0;
3054
3055 if (drmmode_output->enc_clone_mask == 0)
3056 return index_mask;
3057
3058 for (i = 0; i < xf86_config->num_output; i++) {
3059 clone_output = xf86_config->output[i];
3060 clone_drmout = clone_output->driver_private;
3061 if (output == clone_output)
3062 continue;
3063
3064 if (clone_drmout->enc_mask == 0)
3065 continue;
3066 if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
3067 index_mask |= (1 << i);
3068 }
3069 return index_mask;
3070 }
3071
3072 static void
drmmode_clones_init(ScrnInfoPtr scrn,drmmode_ptr drmmode,drmModeResPtr mode_res)3073 drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
3074 {
3075 int i, j;
3076 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3077
3078 for (i = 0; i < xf86_config->num_output; i++) {
3079 xf86OutputPtr output = xf86_config->output[i];
3080 drmmode_output_private_ptr drmmode_output;
3081
3082 drmmode_output = output->driver_private;
3083 drmmode_output->enc_clone_mask = 0xff;
3084 /* and all the possible encoder clones for this output together */
3085 for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
3086 int k;
3087
3088 for (k = 0; k < mode_res->count_encoders; k++) {
3089 if (mode_res->encoders[k] ==
3090 drmmode_output->mode_encoders[j]->encoder_id)
3091 drmmode_output->enc_mask |= (1 << k);
3092 }
3093
3094 drmmode_output->enc_clone_mask &=
3095 drmmode_output->mode_encoders[j]->possible_clones;
3096 }
3097 }
3098
3099 for (i = 0; i < xf86_config->num_output; i++) {
3100 xf86OutputPtr output = xf86_config->output[i];
3101
3102 output->possible_clones = find_clones(scrn, output);
3103 }
3104 }
3105
3106 static Bool
drmmode_set_pixmap_bo(drmmode_ptr drmmode,PixmapPtr pixmap,drmmode_bo * bo)3107 drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo)
3108 {
3109 #ifdef GLAMOR_HAS_GBM
3110 ScrnInfoPtr scrn = drmmode->scrn;
3111
3112 if (!drmmode->glamor)
3113 return TRUE;
3114
3115 if (!glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo->gbm,
3116 bo->used_modifiers)) {
3117 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create pixmap\n");
3118 return FALSE;
3119 }
3120 #endif
3121
3122 return TRUE;
3123 }
3124
3125 Bool
drmmode_glamor_handle_new_screen_pixmap(drmmode_ptr drmmode)3126 drmmode_glamor_handle_new_screen_pixmap(drmmode_ptr drmmode)
3127 {
3128 ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn);
3129 PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
3130
3131 if (!drmmode_set_pixmap_bo(drmmode, screen_pixmap, &drmmode->front_bo))
3132 return FALSE;
3133
3134 return TRUE;
3135 }
3136
3137 static Bool
drmmode_xf86crtc_resize(ScrnInfoPtr scrn,int width,int height)3138 drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
3139 {
3140 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3141 modesettingPtr ms = modesettingPTR(scrn);
3142 drmmode_ptr drmmode = &ms->drmmode;
3143 drmmode_bo old_front;
3144 ScreenPtr screen = xf86ScrnToScreen(scrn);
3145 uint32_t old_fb_id;
3146 int i, pitch, old_width, old_height, old_pitch;
3147 int cpp = (scrn->bitsPerPixel + 7) / 8;
3148 int kcpp = (drmmode->kbpp + 7) / 8;
3149 PixmapPtr ppix = screen->GetScreenPixmap(screen);
3150 void *new_pixels = NULL;
3151
3152 if (scrn->virtualX == width && scrn->virtualY == height)
3153 return TRUE;
3154
3155 xf86DrvMsg(scrn->scrnIndex, X_INFO,
3156 "Allocate new frame buffer %dx%d stride\n", width, height);
3157
3158 old_width = scrn->virtualX;
3159 old_height = scrn->virtualY;
3160 old_pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
3161 old_front = drmmode->front_bo;
3162 old_fb_id = drmmode->fb_id;
3163 drmmode->fb_id = 0;
3164
3165 if (!drmmode_create_bo(drmmode, &drmmode->front_bo,
3166 width, height, drmmode->kbpp))
3167 goto fail;
3168
3169 pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
3170
3171 scrn->virtualX = width;
3172 scrn->virtualY = height;
3173 scrn->displayWidth = pitch / kcpp;
3174
3175 if (!drmmode->gbm) {
3176 new_pixels = drmmode_map_front_bo(drmmode);
3177 if (!new_pixels)
3178 goto fail;
3179 }
3180
3181 if (drmmode->shadow_enable) {
3182 uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
3183 new_pixels = calloc(1, size);
3184 if (new_pixels == NULL)
3185 goto fail;
3186 free(drmmode->shadow_fb);
3187 drmmode->shadow_fb = new_pixels;
3188 }
3189
3190 if (drmmode->shadow_enable2) {
3191 uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
3192 void *fb2 = calloc(1, size);
3193 free(drmmode->shadow_fb2);
3194 drmmode->shadow_fb2 = fb2;
3195 }
3196
3197 screen->ModifyPixmapHeader(ppix, width, height, -1, -1,
3198 scrn->displayWidth * cpp, new_pixels);
3199
3200 if (!drmmode_glamor_handle_new_screen_pixmap(drmmode))
3201 goto fail;
3202
3203 drmmode_clear_pixmap(ppix);
3204
3205 for (i = 0; i < xf86_config->num_crtc; i++) {
3206 xf86CrtcPtr crtc = xf86_config->crtc[i];
3207
3208 if (!crtc->enabled)
3209 continue;
3210
3211 drmmode_set_mode_major(crtc, &crtc->mode,
3212 crtc->rotation, crtc->x, crtc->y);
3213 }
3214
3215 if (old_fb_id)
3216 drmModeRmFB(drmmode->fd, old_fb_id);
3217
3218 drmmode_bo_destroy(drmmode, &old_front);
3219
3220 return TRUE;
3221
3222 fail:
3223 drmmode_bo_destroy(drmmode, &drmmode->front_bo);
3224 drmmode->front_bo = old_front;
3225 scrn->virtualX = old_width;
3226 scrn->virtualY = old_height;
3227 scrn->displayWidth = old_pitch / kcpp;
3228 drmmode->fb_id = old_fb_id;
3229
3230 return FALSE;
3231 }
3232
3233 static void
drmmode_validate_leases(ScrnInfoPtr scrn)3234 drmmode_validate_leases(ScrnInfoPtr scrn)
3235 {
3236 ScreenPtr screen = scrn->pScreen;
3237 rrScrPrivPtr scr_priv;
3238 modesettingPtr ms = modesettingPTR(scrn);
3239 drmmode_ptr drmmode = &ms->drmmode;
3240 drmModeLesseeListPtr lessees;
3241 RRLeasePtr lease, next;
3242 int l;
3243
3244 /* Bail out if RandR wasn't initialized. */
3245 if (!dixPrivateKeyRegistered(rrPrivKey))
3246 return;
3247
3248 scr_priv = rrGetScrPriv(screen);
3249
3250 /* We can't talk to the kernel about leases when VT switched */
3251 if (!scrn->vtSema)
3252 return;
3253
3254 lessees = drmModeListLessees(drmmode->fd);
3255 if (!lessees)
3256 return;
3257
3258 xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
3259 drmmode_lease_private_ptr lease_private = lease->devPrivate;
3260
3261 for (l = 0; l < lessees->count; l++) {
3262 if (lessees->lessees[l] == lease_private->lessee_id)
3263 break;
3264 }
3265
3266 /* check to see if the lease has gone away */
3267 if (l == lessees->count) {
3268 free(lease_private);
3269 lease->devPrivate = NULL;
3270 xf86CrtcLeaseTerminated(lease);
3271 }
3272 }
3273
3274 free(lessees);
3275 }
3276
3277 static int
drmmode_create_lease(RRLeasePtr lease,int * fd)3278 drmmode_create_lease(RRLeasePtr lease, int *fd)
3279 {
3280 ScreenPtr screen = lease->screen;
3281 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3282 modesettingPtr ms = modesettingPTR(scrn);
3283 drmmode_ptr drmmode = &ms->drmmode;
3284 int ncrtc = lease->numCrtcs;
3285 int noutput = lease->numOutputs;
3286 int nobjects;
3287 int c, o;
3288 int i;
3289 int lease_fd;
3290 uint32_t *objects;
3291 drmmode_lease_private_ptr lease_private;
3292
3293 nobjects = ncrtc + noutput;
3294
3295 if (ms->atomic_modeset)
3296 nobjects += ncrtc; /* account for planes as well */
3297
3298 if (nobjects == 0)
3299 return BadValue;
3300
3301 lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
3302 if (!lease_private)
3303 return BadAlloc;
3304
3305 objects = xallocarray(nobjects, sizeof (uint32_t));
3306
3307 if (!objects) {
3308 free(lease_private);
3309 return BadAlloc;
3310 }
3311
3312 i = 0;
3313
3314 /* Add CRTC and plane ids */
3315 for (c = 0; c < ncrtc; c++) {
3316 xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
3317 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3318
3319 objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
3320 if (ms->atomic_modeset)
3321 objects[i++] = drmmode_crtc->plane_id;
3322 }
3323
3324 /* Add connector ids */
3325
3326 for (o = 0; o < noutput; o++) {
3327 xf86OutputPtr output = lease->outputs[o]->devPrivate;
3328 drmmode_output_private_ptr drmmode_output = output->driver_private;
3329
3330 objects[i++] = drmmode_output->mode_output->connector_id;
3331 }
3332
3333 /* call kernel to create lease */
3334 assert (i == nobjects);
3335
3336 lease_fd = drmModeCreateLease(drmmode->fd, objects, nobjects, 0, &lease_private->lessee_id);
3337
3338 free(objects);
3339
3340 if (lease_fd < 0) {
3341 free(lease_private);
3342 return BadMatch;
3343 }
3344
3345 lease->devPrivate = lease_private;
3346
3347 xf86CrtcLeaseStarted(lease);
3348
3349 *fd = lease_fd;
3350 return Success;
3351 }
3352
3353 static void
drmmode_terminate_lease(RRLeasePtr lease)3354 drmmode_terminate_lease(RRLeasePtr lease)
3355 {
3356 ScreenPtr screen = lease->screen;
3357 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3358 modesettingPtr ms = modesettingPTR(scrn);
3359 drmmode_ptr drmmode = &ms->drmmode;
3360 drmmode_lease_private_ptr lease_private = lease->devPrivate;
3361
3362 if (drmModeRevokeLease(drmmode->fd, lease_private->lessee_id) == 0) {
3363 free(lease_private);
3364 lease->devPrivate = NULL;
3365 xf86CrtcLeaseTerminated(lease);
3366 }
3367 }
3368
3369 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
3370 .resize = drmmode_xf86crtc_resize,
3371 .create_lease = drmmode_create_lease,
3372 .terminate_lease = drmmode_terminate_lease
3373 };
3374
3375 Bool
drmmode_pre_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int cpp)3376 drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
3377 {
3378 modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
3379 int i;
3380 int ret;
3381 uint64_t value = 0;
3382 unsigned int crtcs_needed = 0;
3383 drmModeResPtr mode_res;
3384 int crtcshift;
3385
3386 /* check for dumb capability */
3387 ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_BUFFER, &value);
3388 if (ret > 0 || value != 1) {
3389 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3390 "KMS doesn't support dumb interface\n");
3391 return FALSE;
3392 }
3393
3394 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
3395
3396 drmmode->scrn = pScrn;
3397 drmmode->cpp = cpp;
3398 mode_res = drmModeGetResources(drmmode->fd);
3399 if (!mode_res)
3400 return FALSE;
3401
3402 crtcshift = ffs(ms_ent->assigned_crtcs ^ 0xffffffff) - 1;
3403 for (i = 0; i < mode_res->count_connectors; i++)
3404 crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE,
3405 crtcshift);
3406
3407 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
3408 "Up to %d crtcs needed for screen.\n", crtcs_needed);
3409
3410 xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
3411 mode_res->max_height);
3412 for (i = 0; i < mode_res->count_crtcs; i++)
3413 if (!xf86IsEntityShared(pScrn->entityList[0]) ||
3414 (crtcs_needed && !(ms_ent->assigned_crtcs & (1 << i))))
3415 crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
3416
3417 /* All ZaphodHeads outputs provided with matching crtcs? */
3418 if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
3419 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3420 "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
3421 crtcs_needed);
3422
3423 /* workout clones */
3424 drmmode_clones_init(pScrn, drmmode, mode_res);
3425
3426 drmModeFreeResources(mode_res);
3427 xf86ProviderSetup(pScrn, NULL, "modesetting");
3428
3429 xf86InitialConfiguration(pScrn, TRUE);
3430
3431 return TRUE;
3432 }
3433
3434 Bool
drmmode_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3435 drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3436 {
3437 #ifdef GLAMOR_HAS_GBM
3438 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
3439
3440 if (drmmode->glamor) {
3441 if (!glamor_init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
3442 return FALSE;
3443 }
3444 #ifdef GBM_BO_WITH_MODIFIERS
3445 glamor_set_drawable_modifiers_func(pScreen, get_drawable_modifiers);
3446 #endif
3447 }
3448 #endif
3449
3450 return TRUE;
3451 }
3452
3453 void
drmmode_adjust_frame(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int x,int y)3454 drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
3455 {
3456 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3457 xf86OutputPtr output = config->output[config->compat_output];
3458 xf86CrtcPtr crtc = output->crtc;
3459
3460 if (crtc && crtc->enabled) {
3461 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
3462 }
3463 }
3464
3465 Bool
drmmode_set_desired_modes(ScrnInfoPtr pScrn,drmmode_ptr drmmode,Bool set_hw,Bool ign_err)3466 drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw,
3467 Bool ign_err)
3468 {
3469 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3470 Bool success = TRUE;
3471 int c;
3472
3473 for (c = 0; c < config->num_crtc; c++) {
3474 xf86CrtcPtr crtc = config->crtc[c];
3475 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3476 xf86OutputPtr output = NULL;
3477 int o;
3478
3479 /* Skip disabled CRTCs */
3480 if (!crtc->enabled) {
3481 if (set_hw) {
3482 drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
3483 0, 0, 0, NULL, 0, NULL);
3484 }
3485 continue;
3486 }
3487
3488 if (config->output[config->compat_output]->crtc == crtc)
3489 output = config->output[config->compat_output];
3490 else {
3491 for (o = 0; o < config->num_output; o++)
3492 if (config->output[o]->crtc == crtc) {
3493 output = config->output[o];
3494 break;
3495 }
3496 }
3497 /* paranoia */
3498 if (!output)
3499 continue;
3500
3501 /* Mark that we'll need to re-set the mode for sure */
3502 memset(&crtc->mode, 0, sizeof(crtc->mode));
3503 if (!crtc->desiredMode.CrtcHDisplay) {
3504 DisplayModePtr mode =
3505 xf86OutputFindClosestMode(output, pScrn->currentMode);
3506
3507 if (!mode)
3508 return FALSE;
3509 crtc->desiredMode = *mode;
3510 crtc->desiredRotation = RR_Rotate_0;
3511 crtc->desiredX = 0;
3512 crtc->desiredY = 0;
3513 }
3514
3515 if (set_hw) {
3516 if (!crtc->funcs->
3517 set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
3518 crtc->desiredX, crtc->desiredY)) {
3519 if (!ign_err)
3520 return FALSE;
3521 else {
3522 success = FALSE;
3523 crtc->enabled = FALSE;
3524 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3525 "Failed to set the desired mode on connector %s\n",
3526 output->name);
3527 }
3528 }
3529 } else {
3530 crtc->mode = crtc->desiredMode;
3531 crtc->rotation = crtc->desiredRotation;
3532 crtc->x = crtc->desiredX;
3533 crtc->y = crtc->desiredY;
3534 if (!xf86CrtcRotate(crtc))
3535 return FALSE;
3536 }
3537 }
3538
3539 /* Validate leases on VT re-entry */
3540 drmmode_validate_leases(pScrn);
3541
3542 return success;
3543 }
3544
3545 static void
drmmode_load_palette(ScrnInfoPtr pScrn,int numColors,int * indices,LOCO * colors,VisualPtr pVisual)3546 drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
3547 int *indices, LOCO * colors, VisualPtr pVisual)
3548 {
3549 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3550 uint16_t lut_r[256], lut_g[256], lut_b[256];
3551 int index, j, i;
3552 int c;
3553
3554 for (c = 0; c < xf86_config->num_crtc; c++) {
3555 xf86CrtcPtr crtc = xf86_config->crtc[c];
3556 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3557
3558 for (i = 0; i < 256; i++) {
3559 lut_r[i] = drmmode_crtc->lut_r[i] << 6;
3560 lut_g[i] = drmmode_crtc->lut_g[i] << 6;
3561 lut_b[i] = drmmode_crtc->lut_b[i] << 6;
3562 }
3563
3564 switch (pScrn->depth) {
3565 case 15:
3566 for (i = 0; i < numColors; i++) {
3567 index = indices[i];
3568 for (j = 0; j < 8; j++) {
3569 lut_r[index * 8 + j] = colors[index].red << 6;
3570 lut_g[index * 8 + j] = colors[index].green << 6;
3571 lut_b[index * 8 + j] = colors[index].blue << 6;
3572 }
3573 }
3574 break;
3575 case 16:
3576 for (i = 0; i < numColors; i++) {
3577 index = indices[i];
3578
3579 if (i <= 31) {
3580 for (j = 0; j < 8; j++) {
3581 lut_r[index * 8 + j] = colors[index].red << 6;
3582 lut_b[index * 8 + j] = colors[index].blue << 6;
3583 }
3584 }
3585
3586 for (j = 0; j < 4; j++) {
3587 lut_g[index * 4 + j] = colors[index].green << 6;
3588 }
3589 }
3590 break;
3591 default:
3592 for (i = 0; i < numColors; i++) {
3593 index = indices[i];
3594 lut_r[index] = colors[index].red << 6;
3595 lut_g[index] = colors[index].green << 6;
3596 lut_b[index] = colors[index].blue << 6;
3597 }
3598 break;
3599 }
3600
3601 /* Make the change through RandR */
3602 if (crtc->randr_crtc)
3603 RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
3604 else
3605 crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
3606 }
3607 }
3608
3609 Bool
drmmode_setup_colormap(ScreenPtr pScreen,ScrnInfoPtr pScrn)3610 drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
3611 {
3612 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
3613 "Initializing kms color map for depth %d, %d bpc.\n",
3614 pScrn->depth, pScrn->rgbBits);
3615 if (!miCreateDefColormap(pScreen))
3616 return FALSE;
3617
3618 /* Adapt color map size and depth to color depth of screen. */
3619 if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10,
3620 drmmode_load_palette, NULL,
3621 CMAP_PALETTED_TRUECOLOR |
3622 CMAP_RELOAD_ON_MODE_SWITCH))
3623 return FALSE;
3624 return TRUE;
3625 }
3626
3627 #define DRM_MODE_LINK_STATUS_GOOD 0
3628 #define DRM_MODE_LINK_STATUS_BAD 1
3629
3630 void
drmmode_update_kms_state(drmmode_ptr drmmode)3631 drmmode_update_kms_state(drmmode_ptr drmmode)
3632 {
3633 ScrnInfoPtr scrn = drmmode->scrn;
3634 drmModeResPtr mode_res;
3635 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3636 int i, j;
3637 Bool found = FALSE;
3638 Bool changed = FALSE;
3639
3640 /* Try to re-set the mode on all the connectors with a BAD link-state:
3641 * This may happen if a link degrades and a new modeset is necessary, using
3642 * different link-training parameters. If the kernel found that the current
3643 * mode is not achievable anymore, it should have pruned the mode before
3644 * sending the hotplug event. Try to re-set the currently-set mode to keep
3645 * the display alive, this will fail if the mode has been pruned.
3646 * In any case, we will send randr events for the Desktop Environment to
3647 * deal with it, if it wants to.
3648 */
3649 for (i = 0; i < config->num_output; i++) {
3650 xf86OutputPtr output = config->output[i];
3651 drmmode_output_private_ptr drmmode_output = output->driver_private;
3652
3653 drmmode_output_detect(output);
3654
3655 /* Get an updated view of the properties for the current connector and
3656 * look for the link-status property
3657 */
3658 for (j = 0; j < drmmode_output->num_props; j++) {
3659 drmmode_prop_ptr p = &drmmode_output->props[j];
3660
3661 if (!strcmp(p->mode_prop->name, "link-status")) {
3662 if (p->value == DRM_MODE_LINK_STATUS_BAD) {
3663 xf86CrtcPtr crtc = output->crtc;
3664 if (!crtc)
3665 continue;
3666
3667 /* the connector got a link failure, re-set the current mode */
3668 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
3669 crtc->x, crtc->y);
3670
3671 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
3672 "hotplug event: connector %u's link-state is BAD, "
3673 "tried resetting the current mode. You may be left"
3674 "with a black screen if this fails...\n",
3675 drmmode_output->mode_output->connector_id);
3676 }
3677 break;
3678 }
3679 }
3680 }
3681
3682 mode_res = drmModeGetResources(drmmode->fd);
3683 if (!mode_res)
3684 goto out;
3685
3686 if (mode_res->count_crtcs != config->num_crtc) {
3687 /* this triggers with Zaphod mode where we don't currently support connector hotplug or MST. */
3688 goto out_free_res;
3689 }
3690
3691 /* figure out if we have gotten rid of any connectors
3692 traverse old output list looking for outputs */
3693 for (i = 0; i < config->num_output; i++) {
3694 xf86OutputPtr output = config->output[i];
3695 drmmode_output_private_ptr drmmode_output;
3696
3697 drmmode_output = output->driver_private;
3698 found = FALSE;
3699 for (j = 0; j < mode_res->count_connectors; j++) {
3700 if (mode_res->connectors[j] == drmmode_output->output_id) {
3701 found = TRUE;
3702 break;
3703 }
3704 }
3705 if (found)
3706 continue;
3707
3708 drmModeFreeConnector(drmmode_output->mode_output);
3709 drmmode_output->mode_output = NULL;
3710 drmmode_output->output_id = -1;
3711
3712 changed = TRUE;
3713 }
3714
3715 /* find new output ids we don't have outputs for */
3716 for (i = 0; i < mode_res->count_connectors; i++) {
3717 found = FALSE;
3718
3719 for (j = 0; j < config->num_output; j++) {
3720 xf86OutputPtr output = config->output[j];
3721 drmmode_output_private_ptr drmmode_output;
3722
3723 drmmode_output = output->driver_private;
3724 if (mode_res->connectors[i] == drmmode_output->output_id) {
3725 found = TRUE;
3726 break;
3727 }
3728 }
3729 if (found)
3730 continue;
3731
3732 changed = TRUE;
3733 drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
3734 }
3735
3736 if (changed) {
3737 RRSetChanged(xf86ScrnToScreen(scrn));
3738 RRTellChanged(xf86ScrnToScreen(scrn));
3739 }
3740
3741 out_free_res:
3742
3743 /* Check to see if a lessee has disappeared */
3744 drmmode_validate_leases(scrn);
3745
3746 drmModeFreeResources(mode_res);
3747 out:
3748 RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
3749 }
3750
3751 #undef DRM_MODE_LINK_STATUS_BAD
3752 #undef DRM_MODE_LINK_STATUS_GOOD
3753
3754 #ifdef CONFIG_UDEV_KMS
3755
3756 static void
drmmode_handle_uevents(int fd,void * closure)3757 drmmode_handle_uevents(int fd, void *closure)
3758 {
3759 drmmode_ptr drmmode = closure;
3760 struct udev_device *dev;
3761 Bool found = FALSE;
3762
3763 while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) {
3764 udev_device_unref(dev);
3765 found = TRUE;
3766 }
3767 if (!found)
3768 return;
3769
3770 drmmode_update_kms_state(drmmode);
3771 }
3772
3773 #endif
3774
3775 void
drmmode_uevent_init(ScrnInfoPtr scrn,drmmode_ptr drmmode)3776 drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3777 {
3778 #ifdef CONFIG_UDEV_KMS
3779 struct udev *u;
3780 struct udev_monitor *mon;
3781
3782 u = udev_new();
3783 if (!u)
3784 return;
3785 mon = udev_monitor_new_from_netlink(u, "udev");
3786 if (!mon) {
3787 udev_unref(u);
3788 return;
3789 }
3790
3791 if (udev_monitor_filter_add_match_subsystem_devtype(mon,
3792 "drm",
3793 "drm_minor") < 0 ||
3794 udev_monitor_enable_receiving(mon) < 0) {
3795 udev_monitor_unref(mon);
3796 udev_unref(u);
3797 return;
3798 }
3799
3800 drmmode->uevent_handler =
3801 xf86AddGeneralHandler(udev_monitor_get_fd(mon),
3802 drmmode_handle_uevents, drmmode);
3803
3804 drmmode->uevent_monitor = mon;
3805 #endif
3806 }
3807
3808 void
drmmode_uevent_fini(ScrnInfoPtr scrn,drmmode_ptr drmmode)3809 drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3810 {
3811 #ifdef CONFIG_UDEV_KMS
3812 if (drmmode->uevent_handler) {
3813 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
3814
3815 xf86RemoveGeneralHandler(drmmode->uevent_handler);
3816
3817 udev_monitor_unref(drmmode->uevent_monitor);
3818 udev_unref(u);
3819 }
3820 #endif
3821 }
3822
3823 /* create front and cursor BOs */
3824 Bool
drmmode_create_initial_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3825 drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3826 {
3827 modesettingPtr ms = modesettingPTR(pScrn);
3828 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3829 int width;
3830 int height;
3831 int bpp = ms->drmmode.kbpp;
3832 int i;
3833 int cpp = (bpp + 7) / 8;
3834
3835 width = pScrn->virtualX;
3836 height = pScrn->virtualY;
3837
3838 if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, bpp))
3839 return FALSE;
3840 pScrn->displayWidth = drmmode_bo_get_pitch(&drmmode->front_bo) / cpp;
3841
3842 width = ms->cursor_width;
3843 height = ms->cursor_height;
3844 bpp = 32;
3845 for (i = 0; i < xf86_config->num_crtc; i++) {
3846 xf86CrtcPtr crtc = xf86_config->crtc[i];
3847 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3848
3849 drmmode_crtc->cursor_bo =
3850 dumb_bo_create(drmmode->fd, width, height, bpp);
3851 }
3852 return TRUE;
3853 }
3854
3855 void *
drmmode_map_front_bo(drmmode_ptr drmmode)3856 drmmode_map_front_bo(drmmode_ptr drmmode)
3857 {
3858 return drmmode_bo_map(drmmode, &drmmode->front_bo);
3859 }
3860
3861 void *
drmmode_map_slave_bo(drmmode_ptr drmmode,msPixmapPrivPtr ppriv)3862 drmmode_map_slave_bo(drmmode_ptr drmmode, msPixmapPrivPtr ppriv)
3863 {
3864 int ret;
3865
3866 if (ppriv->backing_bo->ptr)
3867 return ppriv->backing_bo->ptr;
3868
3869 ret = dumb_bo_map(drmmode->fd, ppriv->backing_bo);
3870 if (ret)
3871 return NULL;
3872
3873 return ppriv->backing_bo->ptr;
3874 }
3875
3876 Bool
drmmode_map_cursor_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3877 drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3878 {
3879 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3880 int i, ret;
3881
3882 for (i = 0; i < xf86_config->num_crtc; i++) {
3883 xf86CrtcPtr crtc = xf86_config->crtc[i];
3884 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3885
3886 ret = dumb_bo_map(drmmode->fd, drmmode_crtc->cursor_bo);
3887 if (ret)
3888 return FALSE;
3889 }
3890 return TRUE;
3891 }
3892
3893 void
drmmode_free_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3894 drmmode_free_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3895 {
3896 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3897 int i;
3898
3899 if (drmmode->fb_id) {
3900 drmModeRmFB(drmmode->fd, drmmode->fb_id);
3901 drmmode->fb_id = 0;
3902 }
3903
3904 drmmode_bo_destroy(drmmode, &drmmode->front_bo);
3905
3906 for (i = 0; i < xf86_config->num_crtc; i++) {
3907 xf86CrtcPtr crtc = xf86_config->crtc[i];
3908 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3909
3910 dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor_bo);
3911 }
3912 }
3913
3914 /* ugly workaround to see if we can create 32bpp */
3915 void
drmmode_get_default_bpp(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int * depth,int * bpp)3916 drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int *depth,
3917 int *bpp)
3918 {
3919 drmModeResPtr mode_res;
3920 uint64_t value;
3921 struct dumb_bo *bo;
3922 uint32_t fb_id;
3923 int ret;
3924
3925 /* 16 is fine */
3926 ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_PREFERRED_DEPTH, &value);
3927 if (!ret && (value == 16 || value == 8)) {
3928 *depth = value;
3929 *bpp = value;
3930 return;
3931 }
3932
3933 *depth = 24;
3934 mode_res = drmModeGetResources(drmmode->fd);
3935 if (!mode_res)
3936 return;
3937
3938 if (mode_res->min_width == 0)
3939 mode_res->min_width = 1;
3940 if (mode_res->min_height == 0)
3941 mode_res->min_height = 1;
3942 /*create a bo */
3943 bo = dumb_bo_create(drmmode->fd, mode_res->min_width, mode_res->min_height,
3944 32);
3945 if (!bo) {
3946 *bpp = 24;
3947 goto out;
3948 }
3949
3950 ret = drmModeAddFB(drmmode->fd, mode_res->min_width, mode_res->min_height,
3951 24, 32, bo->pitch, bo->handle, &fb_id);
3952
3953 if (ret) {
3954 *bpp = 24;
3955 dumb_bo_destroy(drmmode->fd, bo);
3956 goto out;
3957 }
3958
3959 drmModeRmFB(drmmode->fd, fb_id);
3960 *bpp = 32;
3961
3962 dumb_bo_destroy(drmmode->fd, bo);
3963 out:
3964 drmModeFreeResources(mode_res);
3965 return;
3966 }
3967
3968 /*
3969 * We hook the screen's cursor-sprite (swcursor) functions to see if a swcursor
3970 * is active. When a swcursor is active we disabe page-flipping.
3971 */
3972
drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,ScrnInfoPtr scrn,int x,int y)3973 static void drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,
3974 ScrnInfoPtr scrn, int x, int y)
3975 {
3976 modesettingPtr ms = modesettingPTR(scrn);
3977 CursorPtr cursor = sprite_priv->cursor;
3978 Bool sprite_visible = sprite_priv->sprite_visible;
3979
3980 if (cursor) {
3981 x -= cursor->bits->xhot;
3982 y -= cursor->bits->yhot;
3983
3984 sprite_priv->sprite_visible =
3985 x < scrn->virtualX && y < scrn->virtualY &&
3986 (x + cursor->bits->width > 0) &&
3987 (y + cursor->bits->height > 0);
3988 } else {
3989 sprite_priv->sprite_visible = FALSE;
3990 }
3991
3992 ms->drmmode.sprites_visible += sprite_priv->sprite_visible - sprite_visible;
3993 }
3994
drmmode_sprite_set_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)3995 static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
3996 CursorPtr pCursor, int x, int y)
3997 {
3998 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
3999 modesettingPtr ms = modesettingPTR(scrn);
4000 msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
4001
4002 sprite_priv->cursor = pCursor;
4003 drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
4004
4005 ms->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
4006 }
4007
drmmode_sprite_move_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)4008 static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
4009 int x, int y)
4010 {
4011 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4012 modesettingPtr ms = modesettingPTR(scrn);
4013 msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
4014
4015 drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
4016
4017 ms->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
4018 }
4019
drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)4020 static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
4021 ScreenPtr pScreen,
4022 CursorPtr pCursor)
4023 {
4024 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4025 modesettingPtr ms = modesettingPTR(scrn);
4026
4027 return ms->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
4028 }
4029
drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)4030 static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
4031 ScreenPtr pScreen,
4032 CursorPtr pCursor)
4033 {
4034 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4035 modesettingPtr ms = modesettingPTR(scrn);
4036
4037 return ms->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
4038 }
4039
drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,ScreenPtr pScreen)4040 static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
4041 ScreenPtr pScreen)
4042 {
4043 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4044 modesettingPtr ms = modesettingPTR(scrn);
4045
4046 return ms->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
4047 }
4048
drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,ScreenPtr pScreen)4049 static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
4050 ScreenPtr pScreen)
4051 {
4052 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4053 modesettingPtr ms = modesettingPTR(scrn);
4054
4055 ms->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
4056 }
4057
4058 miPointerSpriteFuncRec drmmode_sprite_funcs = {
4059 .RealizeCursor = drmmode_sprite_realize_realize_cursor,
4060 .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
4061 .SetCursor = drmmode_sprite_set_cursor,
4062 .MoveCursor = drmmode_sprite_move_cursor,
4063 .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
4064 .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
4065 };
4066