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 <sys/time.h>
36 #include <unistd.h>
37 #include "dumb_bo.h"
38 #include "inputstr.h"
39 #include "xf86str.h"
40 #include "X11/Xatom.h"
41 #include "mi.h"
42 #include "micmap.h"
43 #include "xf86cmap.h"
44 #include "xf86DDC.h"
45 #include <drm_fourcc.h>
46 #include <drm_mode.h>
47
48 #include <xf86drm.h>
49 #include "xf86Crtc.h"
50 #include "drmmode_display.h"
51 #include "present.h"
52
53 #include <cursorstr.h>
54
55 #include <X11/extensions/dpmsconst.h>
56
57 #include "driver.h"
58
59 static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
60
61 static void drmmode_destroy_flip_fb(xf86CrtcPtr crtc);
62 static Bool drmmode_create_flip_fb(xf86CrtcPtr crtc);
63 static Bool drmmode_apply_transform(xf86CrtcPtr crtc);
64
65 static inline uint32_t *
formats_ptr(struct drm_format_modifier_blob * blob)66 formats_ptr(struct drm_format_modifier_blob *blob)
67 {
68 return (uint32_t *)(((char *)blob) + blob->formats_offset);
69 }
70
71 static inline struct drm_format_modifier *
modifiers_ptr(struct drm_format_modifier_blob * blob)72 modifiers_ptr(struct drm_format_modifier_blob *blob)
73 {
74 return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
75 }
76
77 static uint32_t
get_opaque_format(uint32_t format)78 get_opaque_format(uint32_t format)
79 {
80 switch (format) {
81 case DRM_FORMAT_ARGB8888:
82 return DRM_FORMAT_XRGB8888;
83 case DRM_FORMAT_ARGB2101010:
84 return DRM_FORMAT_XRGB2101010;
85 default:
86 return format;
87 }
88 }
89
90 Bool
drmmode_is_format_supported(ScrnInfoPtr scrn,uint32_t format,uint64_t modifier)91 drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier)
92 {
93 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
94 int c, i, j;
95
96 /* BO are imported as opaque surface, so let's pretend there is no alpha */
97 format = get_opaque_format(format);
98
99 for (c = 0; c < xf86_config->num_crtc; c++) {
100 xf86CrtcPtr crtc = xf86_config->crtc[c];
101 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
102 Bool found = FALSE;
103
104 if (!crtc->enabled)
105 continue;
106
107 if (drmmode_crtc->num_formats == 0)
108 continue;
109
110 for (i = 0; i < drmmode_crtc->num_formats; i++) {
111 drmmode_format_ptr iter = &drmmode_crtc->formats[i];
112
113 if (iter->format != format)
114 continue;
115
116 if (modifier == DRM_FORMAT_MOD_INVALID ||
117 iter->num_modifiers == 0) {
118 found = TRUE;
119 break;
120 }
121
122 for (j = 0; j < iter->num_modifiers; j++) {
123 if (iter->modifiers[j] == modifier) {
124 found = TRUE;
125 break;
126 }
127 }
128
129 break;
130 }
131
132 if (!found)
133 return FALSE;
134 }
135
136 return TRUE;
137 }
138
139 #ifdef GBM_BO_WITH_MODIFIERS
140 static uint32_t
get_modifiers_set(ScrnInfoPtr scrn,uint32_t format,uint64_t ** modifiers,Bool enabled_crtc_only,Bool exclude_multiplane)141 get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
142 Bool enabled_crtc_only, Bool exclude_multiplane)
143 {
144 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
145 modesettingPtr ms = modesettingPTR(scrn);
146 drmmode_ptr drmmode = &ms->drmmode;
147 int c, i, j, k, count_modifiers = 0;
148 uint64_t *tmp, *ret = NULL;
149
150 /* BOs are imported as opaque surfaces, so pretend the same thing here */
151 format = get_opaque_format(format);
152
153 *modifiers = NULL;
154 for (c = 0; c < xf86_config->num_crtc; c++) {
155 xf86CrtcPtr crtc = xf86_config->crtc[c];
156 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
157
158 if (enabled_crtc_only && !crtc->enabled)
159 continue;
160
161 for (i = 0; i < drmmode_crtc->num_formats; i++) {
162 drmmode_format_ptr iter = &drmmode_crtc->formats[i];
163
164 if (iter->format != format)
165 continue;
166
167 for (j = 0; j < iter->num_modifiers; j++) {
168 Bool found = FALSE;
169
170 /* Don't choose multi-plane formats for our screen pixmap.
171 * These will get used with frontbuffer rendering, which will
172 * lead to worse-than-tearing with multi-plane formats, as the
173 * primary and auxiliary planes go out of sync. */
174 if (exclude_multiplane &&
175 gbm_device_get_format_modifier_plane_count(drmmode->gbm,
176 format,
177 iter->modifiers[j]) > 1) {
178 continue;
179 }
180
181 for (k = 0; k < count_modifiers; k++) {
182 if (iter->modifiers[j] == ret[k])
183 found = TRUE;
184 }
185 if (!found) {
186 count_modifiers++;
187 tmp = realloc(ret, count_modifiers * sizeof(uint64_t));
188 if (!tmp) {
189 free(ret);
190 return 0;
191 }
192 ret = tmp;
193 ret[count_modifiers - 1] = iter->modifiers[j];
194 }
195 }
196 }
197 }
198
199 *modifiers = ret;
200 return count_modifiers;
201 }
202
203 static Bool
get_drawable_modifiers(DrawablePtr draw,uint32_t format,uint32_t * num_modifiers,uint64_t ** modifiers)204 get_drawable_modifiers(DrawablePtr draw, uint32_t format,
205 uint32_t *num_modifiers, uint64_t **modifiers)
206 {
207 ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
208 modesettingPtr ms = modesettingPTR(scrn);
209
210 if (!present_can_window_flip((WindowPtr) draw) ||
211 !ms->drmmode.pageflip || ms->drmmode.dri2_flipping || !scrn->vtSema) {
212 *num_modifiers = 0;
213 *modifiers = NULL;
214 return TRUE;
215 }
216
217 *num_modifiers = get_modifiers_set(scrn, format, modifiers, TRUE, FALSE);
218 return TRUE;
219 }
220 #endif
221
222 static Bool
drmmode_zaphod_string_matches(ScrnInfoPtr scrn,const char * s,char * output_name)223 drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
224 {
225 char **token = xstrtokenize(s, ", \t\n\r");
226 Bool ret = FALSE;
227
228 if (!token)
229 return FALSE;
230
231 for (int i = 0; token[i]; i++) {
232 if (strcmp(token[i], output_name) == 0)
233 ret = TRUE;
234
235 free(token[i]);
236 }
237
238 free(token);
239
240 return ret;
241 }
242
243 static uint64_t
drmmode_prop_get_value(drmmode_prop_info_ptr info,drmModeObjectPropertiesPtr props,uint64_t def)244 drmmode_prop_get_value(drmmode_prop_info_ptr info,
245 drmModeObjectPropertiesPtr props,
246 uint64_t def)
247 {
248 unsigned int i;
249
250 if (info->prop_id == 0)
251 return def;
252
253 for (i = 0; i < props->count_props; i++) {
254 unsigned int j;
255
256 if (props->props[i] != info->prop_id)
257 continue;
258
259 /* Simple (non-enum) types can return the value directly */
260 if (info->num_enum_values == 0)
261 return props->prop_values[i];
262
263 /* Map from raw value to enum value */
264 for (j = 0; j < info->num_enum_values; j++) {
265 if (!info->enum_values[j].valid)
266 continue;
267 if (info->enum_values[j].value != props->prop_values[i])
268 continue;
269
270 return j;
271 }
272 }
273
274 return def;
275 }
276
277 static uint32_t
drmmode_prop_info_update(drmmode_ptr drmmode,drmmode_prop_info_ptr info,unsigned int num_infos,drmModeObjectProperties * props)278 drmmode_prop_info_update(drmmode_ptr drmmode,
279 drmmode_prop_info_ptr info,
280 unsigned int num_infos,
281 drmModeObjectProperties *props)
282 {
283 drmModePropertyRes *prop;
284 uint32_t valid_mask = 0;
285 unsigned i, j;
286
287 assert(num_infos <= 32 && "update return type");
288
289 for (i = 0; i < props->count_props; i++) {
290 Bool props_incomplete = FALSE;
291 unsigned int k;
292
293 for (j = 0; j < num_infos; j++) {
294 if (info[j].prop_id == props->props[i])
295 break;
296 if (!info[j].prop_id)
297 props_incomplete = TRUE;
298 }
299
300 /* We've already discovered this property. */
301 if (j != num_infos)
302 continue;
303
304 /* We haven't found this property ID, but as we've already
305 * found all known properties, we don't need to look any
306 * further. */
307 if (!props_incomplete)
308 break;
309
310 prop = drmModeGetProperty(drmmode->fd, props->props[i]);
311 if (!prop)
312 continue;
313
314 for (j = 0; j < num_infos; j++) {
315 if (!strcmp(prop->name, info[j].name))
316 break;
317 }
318
319 /* We don't know/care about this property. */
320 if (j == num_infos) {
321 drmModeFreeProperty(prop);
322 continue;
323 }
324
325 info[j].prop_id = props->props[i];
326 info[j].value = props->prop_values[i];
327 valid_mask |= 1U << j;
328
329 if (info[j].num_enum_values == 0) {
330 drmModeFreeProperty(prop);
331 continue;
332 }
333
334 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
335 xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
336 "expected property %s to be an enum,"
337 " but it is not; ignoring\n", prop->name);
338 drmModeFreeProperty(prop);
339 continue;
340 }
341
342 for (k = 0; k < info[j].num_enum_values; k++) {
343 int l;
344
345 if (info[j].enum_values[k].valid)
346 continue;
347
348 for (l = 0; l < prop->count_enums; l++) {
349 if (!strcmp(prop->enums[l].name,
350 info[j].enum_values[k].name))
351 break;
352 }
353
354 if (l == prop->count_enums)
355 continue;
356
357 info[j].enum_values[k].valid = TRUE;
358 info[j].enum_values[k].value = prop->enums[l].value;
359 }
360
361 drmModeFreeProperty(prop);
362 }
363
364 return valid_mask;
365 }
366
367 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)368 drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
369 const drmmode_prop_info_rec *src,
370 unsigned int num_props,
371 Bool copy_prop_id)
372 {
373 unsigned int i;
374
375 memcpy(dst, src, num_props * sizeof(*dst));
376
377 for (i = 0; i < num_props; i++) {
378 unsigned int j;
379
380 if (copy_prop_id)
381 dst[i].prop_id = src[i].prop_id;
382 else
383 dst[i].prop_id = 0;
384
385 if (src[i].num_enum_values == 0)
386 continue;
387
388 dst[i].enum_values =
389 malloc(src[i].num_enum_values *
390 sizeof(*dst[i].enum_values));
391 if (!dst[i].enum_values)
392 goto err;
393
394 memcpy(dst[i].enum_values, src[i].enum_values,
395 src[i].num_enum_values * sizeof(*dst[i].enum_values));
396
397 for (j = 0; j < dst[i].num_enum_values; j++)
398 dst[i].enum_values[j].valid = FALSE;
399 }
400
401 return TRUE;
402
403 err:
404 while (i--)
405 free(dst[i].enum_values);
406 return FALSE;
407 }
408
409 static void
drmmode_prop_info_free(drmmode_prop_info_ptr info,int num_props)410 drmmode_prop_info_free(drmmode_prop_info_ptr info, int num_props)
411 {
412 int i;
413
414 for (i = 0; i < num_props; i++)
415 free(info[i].enum_values);
416 }
417
418 static void
419 drmmode_ConvertToKMode(xf86CrtcPtr crtc,
420 drmModeModeInfo * kmode, DisplayModePtr mode);
421
422
423 static int
plane_add_prop(drmModeAtomicReq * req,drmmode_crtc_private_ptr drmmode_crtc,enum drmmode_plane_property prop,uint64_t val)424 plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
425 enum drmmode_plane_property prop, uint64_t val)
426 {
427 drmmode_prop_info_ptr info = &drmmode_crtc->props_plane[prop];
428 int ret;
429
430 if (!info)
431 return -1;
432
433 ret = drmModeAtomicAddProperty(req, drmmode_crtc->plane_id,
434 info->prop_id, val);
435 return (ret <= 0) ? -1 : 0;
436 }
437
438 static int
plane_add_props(drmModeAtomicReq * req,xf86CrtcPtr crtc,uint32_t fb_id,int x,int y)439 plane_add_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
440 uint32_t fb_id, int x, int y)
441 {
442 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
443 int ret = 0;
444
445 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
446 fb_id);
447 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
448 fb_id ? drmmode_crtc->mode_crtc->crtc_id : 0);
449 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x << 16);
450 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y << 16);
451 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_W,
452 crtc->mode.HDisplay << 16);
453 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_H,
454 crtc->mode.VDisplay << 16);
455 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_X, 0);
456 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_Y, 0);
457 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_W,
458 crtc->mode.HDisplay);
459 ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_H,
460 crtc->mode.VDisplay);
461
462 return ret;
463 }
464
465 static int
crtc_add_prop(drmModeAtomicReq * req,drmmode_crtc_private_ptr drmmode_crtc,enum drmmode_crtc_property prop,uint64_t val)466 crtc_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
467 enum drmmode_crtc_property prop, uint64_t val)
468 {
469 drmmode_prop_info_ptr info = &drmmode_crtc->props[prop];
470 int ret;
471
472 if (!info)
473 return -1;
474
475 ret = drmModeAtomicAddProperty(req, drmmode_crtc->mode_crtc->crtc_id,
476 info->prop_id, val);
477 return (ret <= 0) ? -1 : 0;
478 }
479
480 static int
connector_add_prop(drmModeAtomicReq * req,drmmode_output_private_ptr drmmode_output,enum drmmode_connector_property prop,uint64_t val)481 connector_add_prop(drmModeAtomicReq *req, drmmode_output_private_ptr drmmode_output,
482 enum drmmode_connector_property prop, uint64_t val)
483 {
484 drmmode_prop_info_ptr info = &drmmode_output->props_connector[prop];
485 int ret;
486
487 if (!info)
488 return -1;
489
490 ret = drmModeAtomicAddProperty(req, drmmode_output->output_id,
491 info->prop_id, val);
492 return (ret <= 0) ? -1 : 0;
493 }
494
495 static int
drmmode_CompareKModes(drmModeModeInfo * kmode,drmModeModeInfo * other)496 drmmode_CompareKModes(drmModeModeInfo * kmode, drmModeModeInfo * other)
497 {
498 return memcmp(kmode, other, sizeof(*kmode));
499 }
500
501 static int
drm_mode_ensure_blob(xf86CrtcPtr crtc,drmModeModeInfo mode_info)502 drm_mode_ensure_blob(xf86CrtcPtr crtc, drmModeModeInfo mode_info)
503 {
504 modesettingPtr ms = modesettingPTR(crtc->scrn);
505 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
506 drmmode_mode_ptr mode;
507 int ret;
508
509 if (drmmode_crtc->current_mode &&
510 drmmode_CompareKModes(&drmmode_crtc->current_mode->mode_info, &mode_info) == 0)
511 return 0;
512
513 mode = calloc(sizeof(drmmode_mode_rec), 1);
514 if (!mode)
515 return -1;
516
517 mode->mode_info = mode_info;
518 ret = drmModeCreatePropertyBlob(ms->fd,
519 &mode->mode_info,
520 sizeof(mode->mode_info),
521 &mode->blob_id);
522 drmmode_crtc->current_mode = mode;
523 xorg_list_add(&mode->entry, &drmmode_crtc->mode_list);
524
525 return ret;
526 }
527
528 static int
crtc_add_dpms_props(drmModeAtomicReq * req,xf86CrtcPtr crtc,int new_dpms,Bool * active)529 crtc_add_dpms_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
530 int new_dpms, Bool *active)
531 {
532 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
533 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
534 Bool crtc_active = FALSE;
535 int i;
536 int ret = 0;
537
538 for (i = 0; i < xf86_config->num_output; i++) {
539 xf86OutputPtr output = xf86_config->output[i];
540 drmmode_output_private_ptr drmmode_output = output->driver_private;
541
542 if (output->crtc != crtc) {
543 if (drmmode_output->current_crtc == crtc) {
544 ret |= connector_add_prop(req, drmmode_output,
545 DRMMODE_CONNECTOR_CRTC_ID, 0);
546 }
547 continue;
548 }
549
550 if (drmmode_output->output_id == -1)
551 continue;
552
553 if (new_dpms == DPMSModeOn)
554 crtc_active = TRUE;
555
556 ret |= connector_add_prop(req, drmmode_output,
557 DRMMODE_CONNECTOR_CRTC_ID,
558 crtc_active ?
559 drmmode_crtc->mode_crtc->crtc_id : 0);
560 }
561
562 if (crtc_active) {
563 drmModeModeInfo kmode;
564
565 drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
566 ret |= drm_mode_ensure_blob(crtc, kmode);
567
568 ret |= crtc_add_prop(req, drmmode_crtc,
569 DRMMODE_CRTC_ACTIVE, 1);
570 ret |= crtc_add_prop(req, drmmode_crtc,
571 DRMMODE_CRTC_MODE_ID,
572 drmmode_crtc->current_mode->blob_id);
573 } else {
574 ret |= crtc_add_prop(req, drmmode_crtc,
575 DRMMODE_CRTC_ACTIVE, 0);
576 ret |= crtc_add_prop(req, drmmode_crtc,
577 DRMMODE_CRTC_MODE_ID, 0);
578 }
579
580 if (active)
581 *active = crtc_active;
582
583 return ret;
584 }
585
586 static void
drm_mode_destroy(xf86CrtcPtr crtc,drmmode_mode_ptr mode)587 drm_mode_destroy(xf86CrtcPtr crtc, drmmode_mode_ptr mode)
588 {
589 modesettingPtr ms = modesettingPTR(crtc->scrn);
590 if (mode->blob_id)
591 drmModeDestroyPropertyBlob(ms->fd, mode->blob_id);
592 xorg_list_del(&mode->entry);
593 free(mode);
594 }
595
596 static int
drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)597 drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)
598 {
599 modesettingPtr ms = modesettingPTR(crtc->scrn);
600
601 return ms->atomic_modeset;
602 }
603
604 static Bool
drmmode_crtc_get_fb_id(xf86CrtcPtr crtc,uint32_t * fb_id,int * x,int * y)605 drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y)
606 {
607 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
608 drmmode_ptr drmmode = drmmode_crtc->drmmode;
609 int ret;
610
611 *fb_id = 0;
612
613 if (drmmode_crtc->prime_pixmap) {
614 if (!drmmode->reverse_prime_offload_mode) {
615 msPixmapPrivPtr ppriv =
616 msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap);
617 *fb_id = ppriv->fb_id;
618 *x = 0;
619 } else
620 *x = drmmode_crtc->prime_pixmap_x;
621 *y = 0;
622 }
623 else if (drmmode_crtc->rotate_fb_id) {
624 *fb_id = drmmode_crtc->rotate_fb_id;
625 *x = *y = 0;
626 } else {
627 *fb_id = drmmode->fb_id;
628 *x = crtc->x;
629 *y = crtc->y;
630 }
631
632 if (*fb_id == 0) {
633 ret = drmmode_bo_import(drmmode, &drmmode->front_bo,
634 &drmmode->fb_id);
635 if (ret < 0) {
636 ErrorF("failed to add fb %d\n", ret);
637 return FALSE;
638 }
639 *fb_id = drmmode->fb_id;
640 }
641
642 return TRUE;
643 }
644
645 void
drmmode_set_dpms(ScrnInfoPtr scrn,int dpms,int flags)646 drmmode_set_dpms(ScrnInfoPtr scrn, int dpms, int flags)
647 {
648 modesettingPtr ms = modesettingPTR(scrn);
649 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
650 drmModeAtomicReq *req = drmModeAtomicAlloc();
651 uint32_t mode_flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
652 int ret = 0;
653 int i;
654
655 assert(ms->atomic_modeset);
656
657 if (!req)
658 return;
659
660 for (i = 0; i < xf86_config->num_output; i++) {
661 xf86OutputPtr output = xf86_config->output[i];
662 drmmode_output_private_ptr drmmode_output = output->driver_private;
663
664 if (output->crtc != NULL)
665 continue;
666
667 ret = connector_add_prop(req, drmmode_output,
668 DRMMODE_CONNECTOR_CRTC_ID, 0);
669 }
670
671 for (i = 0; i < xf86_config->num_crtc; i++) {
672 xf86CrtcPtr crtc = xf86_config->crtc[i];
673 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
674 Bool active = FALSE;
675
676 ret |= crtc_add_dpms_props(req, crtc, dpms, &active);
677
678 if (dpms == DPMSModeOn && active && drmmode_crtc->need_modeset) {
679 uint32_t fb_id;
680 int x, y;
681
682 if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
683 continue;
684 ret |= plane_add_props(req, crtc, fb_id, x, y);
685 drmmode_crtc->need_modeset = FALSE;
686 }
687 }
688
689 if (ret == 0)
690 drmModeAtomicCommit(ms->fd, req, mode_flags, NULL);
691 drmModeAtomicFree(req);
692
693 ms->pending_modeset = TRUE;
694 xf86DPMSSet(scrn, dpms, flags);
695 ms->pending_modeset = FALSE;
696 }
697
698 static int
drmmode_output_dpms_atomic(xf86OutputPtr output,int mode)699 drmmode_output_dpms_atomic(xf86OutputPtr output, int mode)
700 {
701 modesettingPtr ms = modesettingPTR(output->scrn);
702 drmmode_output_private_ptr drmmode_output = output->driver_private;
703 xf86CrtcPtr crtc = drmmode_output->current_crtc;
704 drmModeAtomicReq *req;
705 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
706 int ret = 0;
707
708 if (mode == DPMSModeOn && !crtc)
709 return 1;
710
711 assert(ms->atomic_modeset);
712
713 req = drmModeAtomicAlloc();
714 if (!req)
715 return 1;
716
717 if (crtc)
718 ret |= crtc_add_dpms_props(req, crtc, mode, NULL);
719
720 if (mode == DPMSModeOn) {
721 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
722 drmModeModeInfo kmode;
723
724 drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
725 ret |= drm_mode_ensure_blob(crtc, kmode);
726
727 ret |= connector_add_prop(req, drmmode_output,
728 DRMMODE_CONNECTOR_CRTC_ID,
729 drmmode_crtc->mode_crtc->crtc_id);
730 ret |= crtc_add_prop(req, drmmode_crtc,
731 DRMMODE_CRTC_ACTIVE, 1);
732 ret |= crtc_add_prop(req, drmmode_crtc,
733 DRMMODE_CRTC_MODE_ID,
734 drmmode_crtc->current_mode->blob_id);
735 } else {
736 ret |= connector_add_prop(req, drmmode_output,
737 DRMMODE_CONNECTOR_CRTC_ID, 0);
738 }
739
740 if (ret == 0)
741 ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
742
743 drmModeAtomicFree(req);
744 return ret;
745 }
746
747 static int
drmmode_crtc_disable(xf86CrtcPtr crtc)748 drmmode_crtc_disable(xf86CrtcPtr crtc)
749 {
750 modesettingPtr ms = modesettingPTR(crtc->scrn);
751 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
752 drmModeAtomicReq *req = drmModeAtomicAlloc();
753 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
754 int ret = 0;
755
756 assert(ms->atomic_modeset);
757
758 if (!req)
759 return 1;
760
761 ret |= crtc_add_prop(req, drmmode_crtc,
762 DRMMODE_CRTC_ACTIVE, 0);
763 ret |= crtc_add_prop(req, drmmode_crtc,
764 DRMMODE_CRTC_MODE_ID, 0);
765
766 if (ret == 0)
767 ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
768
769 drmModeAtomicFree(req);
770 return ret;
771 }
772
773 static Bool
drmmode_crtc_connected(xf86CrtcPtr crtc)774 drmmode_crtc_connected(xf86CrtcPtr crtc)
775 {
776 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
777 int i;
778
779 for (i = 0; i < xf86_config->num_output; i++) {
780 xf86OutputPtr output = xf86_config->output[i];
781 drmmode_output_private_ptr drmmode_output;
782 drmmode_output = output->driver_private;
783
784 if (output->crtc != crtc)
785 continue;
786
787 if (drmmode_output->status == XF86OutputStatusConnected)
788 return TRUE;
789 }
790
791 return FALSE;
792 }
793
794 static int
drmmode_crtc_modeset(xf86CrtcPtr crtc,uint32_t fb_id,uint32_t x,uint32_t y,uint32_t * output_ids,int output_count,drmModeModeInfoPtr mode)795 drmmode_crtc_modeset(xf86CrtcPtr crtc, uint32_t fb_id,
796 uint32_t x, uint32_t y, uint32_t *output_ids,
797 int output_count, drmModeModeInfoPtr mode)
798 {
799 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
800 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
801 drmmode_ptr drmmode = drmmode_crtc->drmmode;
802 struct dumb_bo *bo = NULL;
803 uint32_t new_fb_id = 0;
804 int sx, sy, sw, sh, dx, dy, dw, dh;
805 int ret, i;
806
807 sx = x;
808 sy = y;
809
810 if (crtc->driverIsPerformingTransform & XF86DriverTransformOutput) {
811 struct pixman_f_vector point;
812 int x1, y1, x2, y2;
813
814 point.v[2] = 1;
815
816 /* Convert output's area to framebuffer's area */
817 point.v[0] = 0;
818 point.v[1] = 0;
819 pixman_f_transform_point(&crtc->f_crtc_to_framebuffer, &point);
820 x2 = floor(point.v[0]);
821 y2 = floor(point.v[1]);
822
823 point.v[0] = crtc->mode.HDisplay;
824 point.v[1] = crtc->mode.VDisplay;
825 pixman_f_transform_point(&crtc->f_crtc_to_framebuffer, &point);
826 x1 = floor(point.v[0]);
827 y1 = floor(point.v[1]);
828
829 sw = max(x1, x2) - sx;
830 sh = max(y1, y2) - sy;
831
832 /* Convert framebuffer's area to output's area */
833 point.v[0] = sx;
834 point.v[1] = sy;
835 pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &point);
836 x1 = floor(point.v[0]);
837 y1 = floor(point.v[1]);
838
839 point.v[0] = sw;
840 point.v[1] = sh;
841 pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &point);
842 x2 = floor(point.v[0]);
843 y2 = floor(point.v[1]);
844
845 dx = min(x1, x2) * mode->hdisplay / crtc->mode.HDisplay;
846 dy = min(y1, y2) * mode->vdisplay / crtc->mode.VDisplay;
847 dw = mode->hdisplay - dx;
848 dh = mode->vdisplay - dy;
849 } else {
850 sw = crtc->mode.HDisplay;
851 sh = crtc->mode.VDisplay;
852 dx = 0;
853 dy = 0;
854 dw = mode->hdisplay;
855 dh = mode->vdisplay;
856 }
857
858 for (i = 0; i < xf86_config->num_output; i++) {
859 xf86OutputPtr output = xf86_config->output[i];
860 drmmode_output_private_ptr drmmode_output;
861
862 if (output->crtc != crtc)
863 continue;
864
865 /* NOTE: Only use the first output's padding */
866 drmmode_output = output->driver_private;
867 if (!output_count || drmmode_output->output_id != output_ids[0])
868 continue;
869
870 dx += drmmode_output->padding_top;
871 dw -= drmmode_output->padding_top;
872 dw -= drmmode_output->padding_bottom;
873 dy += drmmode_output->padding_left;
874 dh -= drmmode_output->padding_left;
875 dh -= drmmode_output->padding_right;
876 break;
877 }
878
879 /* prefer using the original FB */
880 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
881 fb_id, x, y, output_ids, output_count, mode);
882 if (!ret)
883 goto set_plane;
884
885 /* fallback to a new dummy FB */
886 bo = dumb_bo_create(drmmode->fd, mode->hdisplay, mode->vdisplay,
887 drmmode->kbpp);
888 if (!bo)
889 goto out;
890
891 ret = drmModeAddFB(drmmode->fd, mode->hdisplay, mode->vdisplay,
892 drmmode->scrn->depth, drmmode->kbpp,
893 bo->pitch, bo->handle, &new_fb_id);
894 if (ret < 0)
895 goto out;
896
897 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
898 new_fb_id, 0, 0, output_ids, output_count, mode);
899 if (ret < 0)
900 goto out;
901
902 set_plane:
903 ret = drmModeSetPlane(drmmode->fd, drmmode_crtc->plane_id,
904 drmmode_crtc->mode_crtc->crtc_id, fb_id, 0,
905 dx, dy, dw, dh,
906 sx << 16, sy << 16, sw << 16, sh << 16);
907 if (ret < 0)
908 goto out;
909
910 ret = 0;
911 out:
912 if (new_fb_id)
913 drmModeRmFB(drmmode->fd, new_fb_id);
914
915 if (bo)
916 dumb_bo_destroy(drmmode->fd, bo);
917 return ret;
918 }
919
920 static int
drmmode_crtc_set_mode(xf86CrtcPtr crtc,Bool test_only)921 drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only)
922 {
923 modesettingPtr ms = modesettingPTR(crtc->scrn);
924 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
925 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
926 drmmode_ptr drmmode = drmmode_crtc->drmmode;
927 ScreenPtr screen = crtc->scrn->pScreen;
928 drmModeModeInfo kmode;
929 int output_count = 0;
930 uint32_t *output_ids = NULL;
931 uint32_t fb_id;
932 int x, y;
933 int i, ret = 0;
934
935 if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
936 return 1;
937
938 #ifdef GLAMOR_HAS_GBM
939 /* Make sure any pending drawing will be visible in a new scanout buffer */
940 if (drmmode->glamor)
941 glamor_finish(screen);
942 #endif
943
944 if (ms->atomic_modeset) {
945 drmModeAtomicReq *req = drmModeAtomicAlloc();
946 Bool active;
947 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
948
949 if (!req)
950 return 1;
951
952 ret |= crtc_add_dpms_props(req, crtc, DPMSModeOn, &active);
953 ret |= plane_add_props(req, crtc, active ? fb_id : 0, x, y);
954
955 /* Orphaned CRTCs need to be disabled right now in atomic mode */
956 for (i = 0; i < xf86_config->num_crtc; i++) {
957 xf86CrtcPtr other_crtc = xf86_config->crtc[i];
958 drmmode_crtc_private_ptr other_drmmode_crtc = other_crtc->driver_private;
959 int lost_outputs = 0;
960 int remaining_outputs = 0;
961 int j;
962
963 if (other_crtc == crtc)
964 continue;
965
966 for (j = 0; j < xf86_config->num_output; j++) {
967 xf86OutputPtr output = xf86_config->output[j];
968 drmmode_output_private_ptr drmmode_output = output->driver_private;
969
970 if (drmmode_output->current_crtc == other_crtc) {
971 if (output->crtc == crtc)
972 lost_outputs++;
973 else
974 remaining_outputs++;
975 }
976 }
977
978 if (lost_outputs > 0 && remaining_outputs == 0) {
979 ret |= crtc_add_prop(req, other_drmmode_crtc,
980 DRMMODE_CRTC_ACTIVE, 0);
981 ret |= crtc_add_prop(req, other_drmmode_crtc,
982 DRMMODE_CRTC_MODE_ID, 0);
983 }
984 }
985
986 if (test_only)
987 flags |= DRM_MODE_ATOMIC_TEST_ONLY;
988
989 if (ret == 0)
990 ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
991
992 if (ret == 0 && !test_only) {
993 for (i = 0; i < xf86_config->num_output; i++) {
994 xf86OutputPtr output = xf86_config->output[i];
995 drmmode_output_private_ptr drmmode_output = output->driver_private;
996
997 if (output->crtc == crtc)
998 drmmode_output->current_crtc = crtc;
999 else if (drmmode_output->current_crtc == crtc)
1000 drmmode_output->current_crtc = NULL;
1001 }
1002 }
1003
1004 drmModeAtomicFree(req);
1005 return ret;
1006 }
1007
1008 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
1009 if (!output_ids)
1010 return -1;
1011
1012 for (i = 0; i < xf86_config->num_output; i++) {
1013 xf86OutputPtr output = xf86_config->output[i];
1014 drmmode_output_private_ptr drmmode_output;
1015
1016 if (output->crtc != crtc)
1017 continue;
1018
1019 drmmode_output = output->driver_private;
1020 if (drmmode_output->output_id == -1)
1021 continue;
1022 output_ids[output_count] = drmmode_output->output_id;
1023 output_count++;
1024 }
1025
1026 drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
1027
1028 ret = drmmode_crtc_modeset(crtc, fb_id, x, y,
1029 output_ids, output_count, &kmode);
1030
1031 free(output_ids);
1032 return ret;
1033 }
1034
1035 int
drmmode_crtc_flip(xf86CrtcPtr crtc,uint32_t fb_id,uint32_t flags,void * data)1036 drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data)
1037 {
1038 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1039 modesettingPtr ms = modesettingPTR(crtc->scrn);
1040 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1041 int ret, i, sx, sy, sw, sh, dx, dy, dw, dh;
1042 drmModeModeInfo kmode;
1043
1044 drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
1045
1046 if (fb_id == ms->drmmode.fb_id) {
1047 /* screen FB flip */
1048 sx = crtc->x;
1049 sy = crtc->y;
1050 } else {
1051 /* single crtc FB flip */
1052 sx = sy = 0;
1053 }
1054
1055 sw = crtc->mode.HDisplay;
1056 sh = crtc->mode.VDisplay;
1057 dx = dy = 0;
1058 dw = kmode.hdisplay;
1059 dh = kmode.vdisplay;
1060
1061 for (i = 0; i < xf86_config->num_output; i++) {
1062 xf86OutputPtr output = xf86_config->output[i];
1063 drmmode_output_private_ptr drmmode_output;
1064
1065 if (output->crtc != crtc)
1066 continue;
1067
1068 drmmode_output = output->driver_private;
1069 if (drmmode_output->output_id == -1)
1070 continue;
1071
1072 /* NOTE: Only use the first output's padding */
1073 dx += drmmode_output->padding_top;
1074 dw -= drmmode_output->padding_top;
1075 dw -= drmmode_output->padding_bottom;
1076 dy += drmmode_output->padding_left;
1077 dh -= drmmode_output->padding_left;
1078 dh -= drmmode_output->padding_right;
1079 break;
1080 }
1081
1082 ret = drmModeSetPlane(ms->fd, drmmode_crtc->plane_id,
1083 drmmode_crtc->mode_crtc->crtc_id, fb_id, 0,
1084 dx, dy, dw, dh,
1085 sx << 16, sy << 16, sw << 16, sh << 16);
1086 if (ret)
1087 return ret;
1088
1089 return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
1090 fb_id, flags, data);
1091 }
1092
1093 int
drmmode_bo_destroy(drmmode_ptr drmmode,drmmode_bo * bo)1094 drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
1095 {
1096 int ret;
1097
1098 #ifdef GLAMOR_HAS_GBM
1099 if (bo->gbm) {
1100 #ifdef GLAMOR_HAS_GBM_MAP
1101 if (bo->gbm_ptr) {
1102 gbm_bo_unmap(bo->gbm, bo->gbm_map_data);
1103 bo->gbm_ptr = NULL;
1104 }
1105 #endif
1106
1107 if (bo->owned_gbm)
1108 gbm_bo_destroy(bo->gbm);
1109
1110 bo->gbm = NULL;
1111 }
1112 #endif
1113
1114 if (bo->dumb) {
1115 ret = dumb_bo_destroy(drmmode->fd, bo->dumb);
1116 if (ret == 0)
1117 bo->dumb = NULL;
1118 }
1119
1120 return 0;
1121 }
1122
1123 uint32_t
drmmode_bo_get_pitch(drmmode_bo * bo)1124 drmmode_bo_get_pitch(drmmode_bo *bo)
1125 {
1126 #ifdef GLAMOR_HAS_GBM
1127 if (bo->gbm)
1128 return gbm_bo_get_stride(bo->gbm);
1129 #endif
1130
1131 return bo->dumb->pitch;
1132 }
1133
1134 static Bool
drmmode_bo_has_bo(drmmode_bo * bo)1135 drmmode_bo_has_bo(drmmode_bo *bo)
1136 {
1137 #ifdef GLAMOR_HAS_GBM
1138 if (bo->gbm)
1139 return TRUE;
1140 #endif
1141
1142 return bo->dumb != NULL;
1143 }
1144
1145 uint32_t
drmmode_bo_get_handle(drmmode_bo * bo)1146 drmmode_bo_get_handle(drmmode_bo *bo)
1147 {
1148 #ifdef GLAMOR_HAS_GBM
1149 if (bo->gbm)
1150 return gbm_bo_get_handle(bo->gbm).u32;
1151 #endif
1152
1153 return bo->dumb->handle;
1154 }
1155
1156 static void *
drmmode_bo_map(drmmode_ptr drmmode,drmmode_bo * bo)1157 drmmode_bo_map(drmmode_ptr drmmode, drmmode_bo *bo)
1158 {
1159 int ret;
1160
1161 #ifdef GLAMOR_HAS_GBM
1162 if (bo->gbm) {
1163 #ifdef GLAMOR_HAS_GBM_MAP
1164 uint32_t stride;
1165
1166 if (bo->gbm_ptr)
1167 return bo->gbm_ptr;
1168
1169 bo->gbm_ptr = gbm_bo_map(bo->gbm, 0, 0, bo->width, bo->height,
1170 GBM_BO_TRANSFER_READ_WRITE, &stride,
1171 &bo->gbm_map_data);
1172 return bo->gbm_ptr;
1173 #else
1174 return NULL;
1175 #endif
1176 }
1177 #endif
1178
1179 if (bo->dumb->ptr)
1180 return bo->dumb->ptr;
1181
1182 ret = dumb_bo_map(drmmode->fd, bo->dumb);
1183 if (ret)
1184 return NULL;
1185
1186 return bo->dumb->ptr;
1187 }
1188
1189 int
drmmode_bo_import(drmmode_ptr drmmode,drmmode_bo * bo,uint32_t * fb_id)1190 drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
1191 uint32_t *fb_id)
1192 {
1193 #ifdef GBM_BO_WITH_MODIFIERS
1194 modesettingPtr ms = modesettingPTR(drmmode->scrn);
1195 if (bo->gbm && ms->kms_has_modifiers &&
1196 gbm_bo_get_modifier(bo->gbm) != DRM_FORMAT_MOD_INVALID) {
1197 int num_fds;
1198
1199 num_fds = gbm_bo_get_plane_count(bo->gbm);
1200 if (num_fds > 0) {
1201 int i;
1202 uint32_t format;
1203 uint32_t handles[4];
1204 uint32_t strides[4];
1205 uint32_t offsets[4];
1206 uint64_t modifiers[4];
1207
1208 memset(handles, 0, sizeof(handles));
1209 memset(strides, 0, sizeof(strides));
1210 memset(offsets, 0, sizeof(offsets));
1211 memset(modifiers, 0, sizeof(modifiers));
1212
1213 format = gbm_bo_get_format(bo->gbm);
1214 format = get_opaque_format(format);
1215 for (i = 0; i < num_fds; i++) {
1216 handles[i] = gbm_bo_get_handle_for_plane(bo->gbm, i).u32;
1217 strides[i] = gbm_bo_get_stride_for_plane(bo->gbm, i);
1218 offsets[i] = gbm_bo_get_offset(bo->gbm, i);
1219 modifiers[i] = gbm_bo_get_modifier(bo->gbm);
1220 }
1221
1222 return drmModeAddFB2WithModifiers(drmmode->fd, bo->width, bo->height,
1223 format, handles, strides,
1224 offsets, modifiers, fb_id,
1225 DRM_MODE_FB_MODIFIERS);
1226 }
1227 }
1228 #endif
1229 return drmModeAddFB(drmmode->fd, bo->width, bo->height,
1230 drmmode->scrn->depth, drmmode->kbpp,
1231 drmmode_bo_get_pitch(bo),
1232 drmmode_bo_get_handle(bo), fb_id);
1233 }
1234
1235 static Bool
drmmode_create_bo(drmmode_ptr drmmode,drmmode_bo * bo,unsigned width,unsigned height,unsigned bpp)1236 drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
1237 unsigned width, unsigned height, unsigned bpp)
1238 {
1239 bo->width = width;
1240 bo->height = height;
1241
1242 #ifdef GLAMOR_HAS_GBM
1243 if (drmmode->glamor) {
1244 uint32_t format;
1245
1246 switch (drmmode->scrn->depth) {
1247 case 15:
1248 format = GBM_FORMAT_ARGB1555;
1249 break;
1250 case 16:
1251 format = GBM_FORMAT_RGB565;
1252 break;
1253 case 30:
1254 format = GBM_FORMAT_ARGB2101010;
1255 break;
1256 default:
1257 format = GBM_FORMAT_ARGB8888;
1258 break;
1259 }
1260
1261 #ifdef GBM_BO_WITH_MODIFIERS
1262 uint32_t num_modifiers;
1263 uint64_t *modifiers = NULL;
1264
1265 num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers,
1266 FALSE, TRUE);
1267 if (num_modifiers > 0 &&
1268 !(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
1269 bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height,
1270 format, modifiers,
1271 num_modifiers);
1272 free(modifiers);
1273 if (bo->gbm) {
1274 bo->used_modifiers = TRUE;
1275 return TRUE;
1276 }
1277 }
1278 #endif
1279
1280 bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format,
1281 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
1282 bo->gbm_ptr = NULL;
1283 bo->used_modifiers = FALSE;
1284 bo->owned_gbm = TRUE;
1285 return bo->gbm != NULL;
1286 }
1287 #endif
1288
1289 bo->dumb = dumb_bo_create(drmmode->fd, width, height, bpp);
1290 return bo->dumb != NULL;
1291 }
1292
1293 Bool
drmmode_SetSlaveBO(PixmapPtr ppix,drmmode_ptr drmmode,int fd_handle,int pitch,int size)1294 drmmode_SetSlaveBO(PixmapPtr ppix,
1295 drmmode_ptr drmmode, int fd_handle, int pitch, int size)
1296 {
1297 msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1298
1299 if (fd_handle == -1) {
1300 dumb_bo_destroy(drmmode->fd, ppriv->backing_bo);
1301 ppriv->backing_bo = NULL;
1302 return TRUE;
1303 }
1304
1305 ppriv->backing_bo =
1306 dumb_get_bo_from_fd(drmmode->fd, fd_handle, pitch, size);
1307 if (!ppriv->backing_bo)
1308 return FALSE;
1309
1310 close(fd_handle);
1311 return TRUE;
1312 }
1313
1314 static Bool
drmmode_SharedPixmapPresent(PixmapPtr ppix,xf86CrtcPtr crtc,drmmode_ptr drmmode)1315 drmmode_SharedPixmapPresent(PixmapPtr ppix, xf86CrtcPtr crtc,
1316 drmmode_ptr drmmode)
1317 {
1318 ScreenPtr master = crtc->randr_crtc->pScreen->current_master;
1319
1320 if (master->PresentSharedPixmap(ppix)) {
1321 /* Success, queue flip to back target */
1322 if (drmmode_SharedPixmapFlip(ppix, crtc, drmmode))
1323 return TRUE;
1324
1325 xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
1326 "drmmode_SharedPixmapFlip() failed, trying again next vblank\n");
1327
1328 return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
1329 }
1330
1331 /* Failed to present, try again on next vblank after damage */
1332 if (master->RequestSharedPixmapNotifyDamage) {
1333 msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1334
1335 /* Set flag first in case we are immediately notified */
1336 ppriv->wait_for_damage = TRUE;
1337
1338 if (master->RequestSharedPixmapNotifyDamage(ppix))
1339 return TRUE;
1340 else
1341 ppriv->wait_for_damage = FALSE;
1342 }
1343
1344 /* Damage notification not available, just try again on vblank */
1345 return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
1346 }
1347
1348 struct vblank_event_args {
1349 PixmapPtr frontTarget;
1350 PixmapPtr backTarget;
1351 xf86CrtcPtr crtc;
1352 drmmode_ptr drmmode;
1353 Bool flip;
1354 };
1355 static void
drmmode_SharedPixmapVBlankEventHandler(uint64_t frame,uint64_t usec,void * data)1356 drmmode_SharedPixmapVBlankEventHandler(uint64_t frame, uint64_t usec,
1357 void *data)
1358 {
1359 struct vblank_event_args *args = data;
1360
1361 drmmode_crtc_private_ptr drmmode_crtc = args->crtc->driver_private;
1362
1363 if (args->flip) {
1364 /* frontTarget is being displayed, update crtc to reflect */
1365 drmmode_crtc->prime_pixmap = args->frontTarget;
1366 drmmode_crtc->prime_pixmap_back = args->backTarget;
1367
1368 /* Safe to present on backTarget, no longer displayed */
1369 drmmode_SharedPixmapPresent(args->backTarget, args->crtc, args->drmmode);
1370 } else {
1371 /* backTarget is still being displayed, present on frontTarget */
1372 drmmode_SharedPixmapPresent(args->frontTarget, args->crtc, args->drmmode);
1373 }
1374
1375 free(args);
1376 }
1377
1378 static void
drmmode_SharedPixmapVBlankEventAbort(void * data)1379 drmmode_SharedPixmapVBlankEventAbort(void *data)
1380 {
1381 struct vblank_event_args *args = data;
1382
1383 msGetPixmapPriv(args->drmmode, args->frontTarget)->flip_seq = 0;
1384
1385 free(args);
1386 }
1387
1388 Bool
drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix,xf86CrtcPtr crtc,drmmode_ptr drmmode)1389 drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix, xf86CrtcPtr crtc,
1390 drmmode_ptr drmmode)
1391 {
1392 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1393 msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1394 struct vblank_event_args *event_args;
1395
1396 if (ppix == drmmode_crtc->prime_pixmap)
1397 return FALSE; /* Already flipped to this pixmap */
1398 if (ppix != drmmode_crtc->prime_pixmap_back)
1399 return FALSE; /* Pixmap is not a scanout pixmap for CRTC */
1400
1401 event_args = calloc(1, sizeof(*event_args));
1402 if (!event_args)
1403 return FALSE;
1404
1405 event_args->frontTarget = ppix;
1406 event_args->backTarget = drmmode_crtc->prime_pixmap;
1407 event_args->crtc = crtc;
1408 event_args->drmmode = drmmode;
1409 event_args->flip = FALSE;
1410
1411 ppriv->flip_seq =
1412 ms_drm_queue_alloc(crtc, event_args,
1413 drmmode_SharedPixmapVBlankEventHandler,
1414 drmmode_SharedPixmapVBlankEventAbort);
1415
1416 return ms_queue_vblank(crtc, MS_QUEUE_RELATIVE, 1, NULL, ppriv->flip_seq);
1417 }
1418
1419 Bool
drmmode_SharedPixmapFlip(PixmapPtr frontTarget,xf86CrtcPtr crtc,drmmode_ptr drmmode)1420 drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
1421 drmmode_ptr drmmode)
1422 {
1423 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1424 msPixmapPrivPtr ppriv_front = msGetPixmapPriv(drmmode, frontTarget);
1425
1426 struct vblank_event_args *event_args;
1427
1428 event_args = calloc(1, sizeof(*event_args));
1429 if (!event_args)
1430 return FALSE;
1431
1432 event_args->frontTarget = frontTarget;
1433 event_args->backTarget = drmmode_crtc->prime_pixmap;
1434 event_args->crtc = crtc;
1435 event_args->drmmode = drmmode;
1436 event_args->flip = TRUE;
1437
1438 ppriv_front->flip_seq =
1439 ms_drm_queue_alloc(crtc, event_args,
1440 drmmode_SharedPixmapVBlankEventHandler,
1441 drmmode_SharedPixmapVBlankEventAbort);
1442
1443 if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1444 ppriv_front->fb_id, DRM_MODE_PAGE_FLIP_EVENT,
1445 (void *)(intptr_t) ppriv_front->flip_seq) < 0) {
1446 ms_drm_abort_seq(crtc->scrn, ppriv_front->flip_seq);
1447 return FALSE;
1448 }
1449
1450 return TRUE;
1451 }
1452
1453 static Bool
drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1454 drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1455 {
1456 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1457
1458 if (!drmmode_crtc->enable_flipping)
1459 return FALSE;
1460
1461 if (drmmode_crtc->flipping_active)
1462 return TRUE;
1463
1464 drmmode_crtc->flipping_active =
1465 drmmode_SharedPixmapPresent(drmmode_crtc->prime_pixmap_back,
1466 crtc, drmmode);
1467
1468 return drmmode_crtc->flipping_active;
1469 }
1470
1471 static void
drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1472 drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1473 {
1474 uint32_t seq;
1475 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1476
1477 if (!drmmode_crtc->flipping_active)
1478 return;
1479
1480 drmmode_crtc->flipping_active = FALSE;
1481
1482 /* Abort page flip event handler on prime_pixmap */
1483 seq = msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap)->flip_seq;
1484 if (seq)
1485 ms_drm_abort_seq(crtc->scrn, seq);
1486
1487 /* Abort page flip event handler on prime_pixmap_back */
1488 seq = msGetPixmapPriv(drmmode,
1489 drmmode_crtc->prime_pixmap_back)->flip_seq;
1490 if (seq)
1491 ms_drm_abort_seq(crtc->scrn, seq);
1492 }
1493
1494 static Bool drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
1495 PixmapPtr *target);
1496
1497 Bool
drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode,PixmapPtr front,PixmapPtr back)1498 drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode,
1499 PixmapPtr front, PixmapPtr back)
1500 {
1501 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1502 ScrnInfoPtr scrn = crtc->scrn;
1503 modesettingPtr ms = modesettingPTR(scrn);
1504
1505 drmmode_crtc->enable_flipping = TRUE;
1506
1507 /* Set front scanout pixmap */
1508 drmmode_crtc->enable_flipping &=
1509 drmmode_set_target_scanout_pixmap(crtc, front,
1510 &drmmode_crtc->prime_pixmap);
1511 if (!drmmode_crtc->enable_flipping)
1512 return FALSE;
1513
1514 /* Set back scanout pixmap */
1515 drmmode_crtc->enable_flipping &=
1516 drmmode_set_target_scanout_pixmap(crtc, back,
1517 &drmmode_crtc->prime_pixmap_back);
1518 if (!drmmode_crtc->enable_flipping) {
1519 drmmode_set_target_scanout_pixmap(crtc, NULL,
1520 &drmmode_crtc->prime_pixmap);
1521 return FALSE;
1522 }
1523
1524 drmmode_set_desired_modes(scrn, &ms->drmmode, TRUE, TRUE);
1525
1526 return TRUE;
1527 }
1528
1529 void
drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1530 drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1531 {
1532 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1533 ScrnInfoPtr scrn = crtc->scrn;
1534 modesettingPtr ms = modesettingPTR(scrn);
1535
1536 drmmode_crtc->enable_flipping = FALSE;
1537
1538 drmmode_FiniSharedPixmapFlipping(crtc, drmmode);
1539
1540 drmmode_set_target_scanout_pixmap(crtc, NULL, &drmmode_crtc->prime_pixmap);
1541
1542 drmmode_set_target_scanout_pixmap(crtc, NULL,
1543 &drmmode_crtc->prime_pixmap_back);
1544
1545 drmmode_set_desired_modes(scrn, &ms->drmmode, TRUE, TRUE);
1546 }
1547
1548 static void
drmmode_ConvertFromKMode(xf86OutputPtr output,drmModeModeInfo * kmode,DisplayModePtr mode)1549 drmmode_ConvertFromKMode(xf86OutputPtr output,
1550 drmModeModeInfo * kmode, DisplayModePtr mode)
1551 {
1552 ScrnInfoPtr scrn = output->scrn;
1553 drmmode_output_private_ptr drmmode_output = output->driver_private;
1554
1555 memset(mode, 0, sizeof(DisplayModeRec));
1556 mode->status = MODE_OK;
1557
1558 mode->Clock = kmode->clock;
1559
1560 mode->HDisplay = kmode->hdisplay;
1561 mode->HSyncStart = kmode->hsync_start;
1562 mode->HSyncEnd = kmode->hsync_end;
1563 mode->HTotal = kmode->htotal;
1564 mode->HSkew = kmode->hskew;
1565
1566 mode->VDisplay = kmode->vdisplay;
1567 mode->VSyncStart = kmode->vsync_start;
1568 mode->VSyncEnd = kmode->vsync_end;
1569 mode->VTotal = kmode->vtotal;
1570 mode->VScan = kmode->vscan;
1571
1572 mode->Flags = kmode->flags; //& FLAG_BITS;
1573 mode->name = strdup(kmode->name);
1574
1575 if (kmode->type & DRM_MODE_TYPE_DRIVER)
1576 mode->type = M_T_DRIVER;
1577 if (kmode->type & DRM_MODE_TYPE_PREFERRED)
1578 mode->type |= M_T_PREFERRED;
1579 xf86SetModeCrtc(mode, scrn->adjustFlags);
1580
1581 /* HACK: Use virtual size for all modes */
1582 if (drmmode_output->virtual_width && drmmode_output->virtual_height) {
1583 mode->HDisplay = drmmode_output->virtual_width;
1584 mode->VDisplay = drmmode_output->virtual_height;
1585 }
1586 }
1587
1588 static void
drmmode_ConvertToKMode(xf86CrtcPtr crtc,drmModeModeInfo * kmode,DisplayModePtr mode)1589 drmmode_ConvertToKMode(xf86CrtcPtr crtc,
1590 drmModeModeInfo * kmode, DisplayModePtr mode)
1591 {
1592 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1593 int i, j;
1594
1595 /* HACK: Convert from virtual size */
1596 for (i = 0; i < xf86_config->num_output; i++) {
1597 xf86OutputPtr output = xf86_config->output[i];
1598 drmmode_output_private_ptr drmmode_output = output->driver_private;
1599 drmModeConnectorPtr koutput = drmmode_output->mode_output;
1600
1601 if (output->crtc != crtc)
1602 continue;
1603
1604 if (!drmmode_output->virtual_width || !drmmode_output->virtual_height)
1605 continue;
1606
1607 /* Search for original mode */
1608 for (j = 0; j < koutput->count_modes; j++) {
1609 drmModeModeInfoPtr scan = &koutput->modes[j];
1610 if (scan->clock == mode->Clock &&
1611 scan->hsync_start == mode->HSyncStart &&
1612 scan->hsync_end == mode->HSyncEnd &&
1613 scan->htotal == mode->HTotal &&
1614 scan->hskew == mode->HSkew &&
1615 scan->vsync_start == mode->VSyncStart &&
1616 scan->vsync_end == mode->VSyncEnd &&
1617 scan->vtotal == mode->VTotal &&
1618 scan->vscan == mode->VScan) {
1619 *kmode = *scan;
1620 return;
1621 }
1622 }
1623 }
1624
1625 memset(kmode, 0, sizeof(*kmode));
1626
1627 kmode->clock = mode->Clock;
1628 kmode->hdisplay = mode->HDisplay;
1629 kmode->hsync_start = mode->HSyncStart;
1630 kmode->hsync_end = mode->HSyncEnd;
1631 kmode->htotal = mode->HTotal;
1632 kmode->hskew = mode->HSkew;
1633
1634 kmode->vdisplay = mode->VDisplay;
1635 kmode->vsync_start = mode->VSyncStart;
1636 kmode->vsync_end = mode->VSyncEnd;
1637 kmode->vtotal = mode->VTotal;
1638 kmode->vscan = mode->VScan;
1639
1640 kmode->flags = mode->Flags; //& FLAG_BITS;
1641 if (mode->name)
1642 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
1643 kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0;
1644
1645 }
1646
1647 static void
drmmode_crtc_dpms(xf86CrtcPtr crtc,int mode)1648 drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
1649 {
1650 modesettingPtr ms = modesettingPTR(crtc->scrn);
1651 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1652 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1653
1654 /* XXX Check if DPMS mode is already the right one */
1655
1656 drmmode_crtc->dpms_mode = mode;
1657
1658 if (ms->atomic_modeset) {
1659 if (mode != DPMSModeOn && !ms->pending_modeset)
1660 drmmode_crtc_disable(crtc);
1661 } else if (crtc->enabled == FALSE) {
1662 drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1663 0, 0, 0, NULL, 0, NULL);
1664 }
1665 }
1666
1667 static Bool
drmmode_crtc_copy_fb(ScrnInfoPtr pScrn,drmmode_ptr drmmode,xf86CrtcPtr crtc)1668 drmmode_crtc_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
1669 xf86CrtcPtr crtc)
1670 {
1671 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1672 PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen);
1673 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1674 drmmode_prop_info_rec *props_plane = drmmode_crtc->props_plane;
1675 drmModeObjectProperties *props;
1676 PixmapPtr src = NULL, dst;
1677 drmModeFBPtr fbcon;
1678 struct dumb_bo *bo;
1679 GCPtr gc;
1680 int src_x, src_y, src_w, src_h, crtc_x, crtc_y, crtc_w, crtc_h;
1681 int fbcon_id, fb_width, fb_height, fb_pitch, fb_depth, fb_bpp;
1682 Bool ret = FALSE;
1683
1684 if (!drmmode_crtc->plane_id)
1685 return FALSE;
1686
1687 if (!(fbcon_id = drmmode_crtc->mode_crtc->buffer_id))
1688 return FALSE;
1689
1690 if (fbcon_id == drmmode->fb_id) {
1691 /* in some rare case there might be no fbcon and we might already
1692 * be the one with the current fb to avoid a false deadlck in
1693 * kernel ttm code just do nothing as anyway there is nothing
1694 * to do
1695 */
1696 return FALSE;
1697 }
1698
1699 props = drmModeObjectGetProperties(drmmode->fd, drmmode_crtc->plane_id,
1700 DRM_MODE_OBJECT_PLANE);
1701 if (!props) {
1702 xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
1703 "couldn't get plane properties\n");
1704 return FALSE;
1705 }
1706
1707 src_x = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_X],
1708 props, 0) >> 16;
1709 src_y = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_Y],
1710 props, 0) >> 16;
1711 src_w = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_W],
1712 props, 0) >> 16;
1713 src_h = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_H],
1714 props, 0) >> 16;
1715 crtc_x = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_X],
1716 props, 0) + crtc->x;
1717 crtc_y = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_Y],
1718 props, 0) + crtc->y;
1719 crtc_w = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_W],
1720 props, 0);
1721 crtc_h = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_H],
1722 props, 0);
1723 drmModeFreeObjectProperties(props);
1724
1725 if (!src_w || !src_h || src_w != crtc_w || src_h != crtc_h ||
1726 crtc_x + crtc_w > screen_pixmap->drawable.width ||
1727 crtc_y + crtc_h > screen_pixmap->drawable.height)
1728 return FALSE;
1729
1730 fbcon = drmModeGetFB(drmmode->fd, fbcon_id);
1731 if (!fbcon)
1732 return FALSE;
1733
1734 fb_width = fbcon->width;
1735 fb_height = fbcon->height;
1736 fb_pitch = fbcon->pitch;
1737 fb_depth = fbcon->depth;
1738 fb_bpp = fbcon->bpp;
1739
1740 bo = dumb_get_bo_from_handle(drmmode->fd, fbcon->handle, fbcon->pitch,
1741 fbcon->pitch * fbcon->height);
1742 drmModeFreeFB(fbcon);
1743 if (!bo)
1744 return FALSE;
1745
1746 if (dumb_bo_map(drmmode->fd, bo) < 0)
1747 goto out;
1748
1749 src = drmmode_create_pixmap_header(pScreen, fb_width,
1750 fb_height, fb_depth,
1751 fb_bpp, fb_pitch,
1752 bo->ptr);
1753 if (!src)
1754 goto out;
1755
1756 if (drmmode->exa) {
1757 if (!ms_exa_set_pixmap_bo(pScrn, src, bo, FALSE))
1758 goto out;
1759 }
1760 #ifdef GLAMOR_HAS_GBM
1761 else if (drmmode->glamor) {
1762 if (!glamor_egl_create_textured_pixmap(src, bo->handle, bo->pitch))
1763 goto out;
1764 }
1765 #endif
1766
1767 dst = pScreen->GetScreenPixmap(pScreen);
1768
1769 gc = GetScratchGC(pScrn->depth, pScreen);
1770 ValidateGC(&dst->drawable, gc);
1771
1772 (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, src_x, src_y,
1773 src_w, src_h, crtc_x, crtc_y);
1774
1775 FreeScratchGC(gc);
1776 ret = TRUE;
1777
1778 out:
1779 if (src)
1780 pScreen->DestroyPixmap(src);
1781 if (bo)
1782 dumb_bo_destroy(drmmode->fd, bo);
1783 return ret;
1784 }
1785
1786 void
drmmode_copy_fb(ScrnInfoPtr pScrn,drmmode_ptr drmmode)1787 drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1788 {
1789 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1790 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1791 Bool ret = FALSE;
1792 int i;
1793
1794 if (getenv("XSERVER_NO_BG_NONE"))
1795 return;
1796
1797 for (i = 0; i < xf86_config->num_crtc; i++)
1798 ret |= drmmode_crtc_copy_fb(pScrn, drmmode, xf86_config->crtc[i]);
1799
1800 if (!ret)
1801 return;
1802
1803 pScreen->canDoBGNoneRoot = TRUE;
1804 }
1805
1806 static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc,DisplayModePtr mode,Rotation rotation,int x,int y)1807 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
1808 Rotation rotation, int x, int y)
1809 {
1810 modesettingPtr ms = modesettingPTR(crtc->scrn);
1811 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1812 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1813 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1814 int saved_x, saved_y;
1815 Rotation saved_rotation;
1816 DisplayModeRec saved_mode;
1817 Bool ret = TRUE;
1818 Bool can_test;
1819 int i;
1820
1821 /* Ignore modeset when disconnected in hotplug reset mode */
1822 if (drmmode->hotplug_reset && !drmmode_crtc_connected(crtc))
1823 return 0;
1824
1825 saved_mode = crtc->mode;
1826 saved_x = crtc->x;
1827 saved_y = crtc->y;
1828 saved_rotation = crtc->rotation;
1829
1830 if (mode) {
1831 crtc->mode = *mode;
1832 crtc->x = x;
1833 crtc->y = y;
1834 crtc->rotation = rotation;
1835
1836 if (!drmmode_apply_transform(crtc))
1837 goto done;
1838
1839 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
1840 crtc->gamma_blue, crtc->gamma_size);
1841
1842 can_test = drmmode_crtc_can_test_mode(crtc);
1843 if (drmmode_crtc_set_mode(crtc, can_test)) {
1844 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1845 "failed to set mode: %s\n", strerror(errno));
1846 ret = FALSE;
1847 goto done;
1848 } else
1849 ret = TRUE;
1850
1851 if (crtc->scrn->pScreen)
1852 xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
1853
1854 ms->pending_modeset = TRUE;
1855 drmmode_crtc->need_modeset = FALSE;
1856 crtc->funcs->dpms(crtc, DPMSModeOn);
1857
1858 if (drmmode_crtc->prime_pixmap_back)
1859 drmmode_InitSharedPixmapFlipping(crtc, drmmode);
1860
1861 /* go through all the outputs and force DPMS them back on? */
1862 for (i = 0; i < xf86_config->num_output; i++) {
1863 xf86OutputPtr output = xf86_config->output[i];
1864 drmmode_output_private_ptr drmmode_output;
1865
1866 if (output->crtc != crtc)
1867 continue;
1868
1869 drmmode_output = output->driver_private;
1870 if (drmmode_output->output_id == -1)
1871 continue;
1872 output->funcs->dpms(output, DPMSModeOn);
1873 }
1874
1875 /* if we only tested the mode previously, really set it now */
1876 if (can_test)
1877 drmmode_crtc_set_mode(crtc, FALSE);
1878 ms->pending_modeset = FALSE;
1879 }
1880
1881 done:
1882 if (!ret) {
1883 crtc->x = saved_x;
1884 crtc->y = saved_y;
1885 crtc->rotation = saved_rotation;
1886 crtc->mode = saved_mode;
1887 } else
1888 crtc->active = TRUE;
1889
1890 return ret;
1891 }
1892
1893 static void
drmmode_set_cursor_colors(xf86CrtcPtr crtc,int bg,int fg)1894 drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
1895 {
1896
1897 }
1898
1899 static void
drmmode_set_cursor_position(xf86CrtcPtr crtc,int x,int y)1900 drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
1901 {
1902 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1903 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1904 drmModeModeInfo kmode;
1905
1906 drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
1907
1908 x = x * crtc->mode.HDisplay / kmode.hdisplay;
1909 y = y * crtc->mode.VDisplay / kmode.vdisplay;
1910
1911 drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
1912 }
1913
1914 static Bool
drmmode_set_cursor(xf86CrtcPtr crtc)1915 drmmode_set_cursor(xf86CrtcPtr crtc)
1916 {
1917 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1918 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1919 uint32_t handle = drmmode_crtc->cursor_bo->handle;
1920 modesettingPtr ms = modesettingPTR(crtc->scrn);
1921 CursorPtr cursor = xf86CurrentCursor(crtc->scrn->pScreen);
1922 int ret = -EINVAL;
1923
1924 if (cursor == NullCursor)
1925 return TRUE;
1926
1927 ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1928 handle, ms->cursor_width, ms->cursor_height,
1929 cursor->bits->xhot, cursor->bits->yhot);
1930
1931 /* -EINVAL can mean that an old kernel supports drmModeSetCursor but
1932 * not drmModeSetCursor2, though it can mean other things too. */
1933 if (ret == -EINVAL)
1934 ret = drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1935 handle, ms->cursor_width, ms->cursor_height);
1936
1937 /* -ENXIO normally means that the current drm driver supports neither
1938 * cursor_set nor cursor_set2. Disable hardware cursor support for
1939 * the rest of the session in that case. */
1940 if (ret == -ENXIO) {
1941 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1942 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
1943
1944 cursor_info->MaxWidth = cursor_info->MaxHeight = 0;
1945 drmmode_crtc->drmmode->sw_cursor = TRUE;
1946 }
1947
1948 if (ret)
1949 /* fallback to swcursor */
1950 return FALSE;
1951 return TRUE;
1952 }
1953
1954 static void drmmode_hide_cursor(xf86CrtcPtr crtc);
1955
1956 /*
1957 * The load_cursor_argb_check driver hook.
1958 *
1959 * Sets the hardware cursor by calling the drmModeSetCursor2 ioctl.
1960 * On failure, returns FALSE indicating that the X server should fall
1961 * back to software cursors.
1962 */
1963 static Bool
drmmode_load_cursor_argb_check(xf86CrtcPtr crtc,CARD32 * image)1964 drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 *image)
1965 {
1966 modesettingPtr ms = modesettingPTR(crtc->scrn);
1967 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1968 int i;
1969 uint32_t *ptr;
1970
1971 /* cursor should be mapped already */
1972 ptr = (uint32_t *) (drmmode_crtc->cursor_bo->ptr);
1973
1974 for (i = 0; i < ms->cursor_width * ms->cursor_height; i++)
1975 ptr[i] = image[i]; // cpu_to_le32(image[i]);
1976
1977 if (drmmode_crtc->cursor_up)
1978 return drmmode_set_cursor(crtc);
1979 return TRUE;
1980 }
1981
1982 static void
drmmode_hide_cursor(xf86CrtcPtr crtc)1983 drmmode_hide_cursor(xf86CrtcPtr crtc)
1984 {
1985 modesettingPtr ms = modesettingPTR(crtc->scrn);
1986 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1987 drmmode_ptr drmmode = drmmode_crtc->drmmode;
1988
1989 drmmode_crtc->cursor_up = FALSE;
1990 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
1991 ms->cursor_width, ms->cursor_height);
1992 }
1993
1994 static Bool
drmmode_show_cursor(xf86CrtcPtr crtc)1995 drmmode_show_cursor(xf86CrtcPtr crtc)
1996 {
1997 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1998 drmmode_crtc->cursor_up = TRUE;
1999 return drmmode_set_cursor(crtc);
2000 }
2001
2002 static void
drmmode_set_gamma_lut(drmmode_crtc_private_ptr drmmode_crtc,uint16_t * red,uint16_t * green,uint16_t * blue,int size)2003 drmmode_set_gamma_lut(drmmode_crtc_private_ptr drmmode_crtc,
2004 uint16_t * red, uint16_t * green, uint16_t * blue,
2005 int size)
2006 {
2007 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2008 drmmode_prop_info_ptr gamma_lut_info =
2009 &drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT];
2010 const uint32_t crtc_id = drmmode_crtc->mode_crtc->crtc_id;
2011 uint32_t blob_id;
2012 struct drm_color_lut lut[size];
2013
2014 assert(gamma_lut_info->prop_id != 0);
2015
2016 for (int i = 0; i < size; i++) {
2017 lut[i].red = red[i];
2018 lut[i].green = green[i];
2019 lut[i].blue = blue[i];
2020 }
2021
2022 if (drmModeCreatePropertyBlob(drmmode->fd, lut, sizeof(lut), &blob_id))
2023 return;
2024
2025 drmModeObjectSetProperty(drmmode->fd, crtc_id, DRM_MODE_OBJECT_CRTC,
2026 gamma_lut_info->prop_id, blob_id);
2027
2028 drmModeDestroyPropertyBlob(drmmode->fd, blob_id);
2029 }
2030
2031 static void
drmmode_crtc_gamma_set(xf86CrtcPtr crtc,uint16_t * red,uint16_t * green,uint16_t * blue,int size)2032 drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
2033 uint16_t * blue, int size)
2034 {
2035 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2036 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2037
2038 if (drmmode_crtc->use_gamma_lut) {
2039 drmmode_set_gamma_lut(drmmode_crtc, red, green, blue, size);
2040 } else {
2041 drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
2042 size, red, green, blue);
2043 }
2044 }
2045
2046 static Bool
drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)2047 drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix,
2048 PixmapPtr *target)
2049 {
2050 ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
2051 PixmapPtr screenpix = screen->GetScreenPixmap(screen);
2052 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
2053 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2054 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2055 int c, total_width = 0, max_height = 0, this_x = 0;
2056
2057 if (*target) {
2058 PixmapStopDirtyTracking(&(*target)->drawable, screenpix);
2059 if (drmmode->fb_id) {
2060 drmModeRmFB(drmmode->fd, drmmode->fb_id);
2061 drmmode->fb_id = 0;
2062 }
2063 drmmode_crtc->prime_pixmap_x = 0;
2064 *target = NULL;
2065 }
2066
2067 if (!ppix)
2068 return TRUE;
2069
2070 /* iterate over all the attached crtcs to work out the bounding box */
2071 for (c = 0; c < xf86_config->num_crtc; c++) {
2072 xf86CrtcPtr iter = xf86_config->crtc[c];
2073 if (!iter->enabled && iter != crtc)
2074 continue;
2075 if (iter == crtc) {
2076 this_x = total_width;
2077 total_width += ppix->drawable.width;
2078 if (max_height < ppix->drawable.height)
2079 max_height = ppix->drawable.height;
2080 } else {
2081 total_width += iter->mode.HDisplay;
2082 if (max_height < iter->mode.VDisplay)
2083 max_height = iter->mode.VDisplay;
2084 }
2085 }
2086
2087 if (total_width != screenpix->drawable.width ||
2088 max_height != screenpix->drawable.height) {
2089
2090 if (!drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height))
2091 return FALSE;
2092
2093 screenpix = screen->GetScreenPixmap(screen);
2094 screen->width = screenpix->drawable.width = total_width;
2095 screen->height = screenpix->drawable.height = max_height;
2096 }
2097 drmmode_crtc->prime_pixmap_x = this_x;
2098 PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0,
2099 RR_Rotate_0);
2100 *target = ppix;
2101 return TRUE;
2102 }
2103
2104 static Bool
drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)2105 drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix,
2106 PixmapPtr *target)
2107 {
2108 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2109 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2110 msPixmapPrivPtr ppriv;
2111 void *ptr;
2112
2113 if (*target) {
2114 ppriv = msGetPixmapPriv(drmmode, *target);
2115 drmModeRmFB(drmmode->fd, ppriv->fb_id);
2116 ppriv->fb_id = 0;
2117 if (ppriv->slave_damage) {
2118 DamageUnregister(ppriv->slave_damage);
2119 ppriv->slave_damage = NULL;
2120 }
2121 *target = NULL;
2122 }
2123
2124 if (!ppix)
2125 return TRUE;
2126
2127 ppriv = msGetPixmapPriv(drmmode, ppix);
2128 if (!ppriv->slave_damage) {
2129 ppriv->slave_damage = DamageCreate(NULL, NULL,
2130 DamageReportNone,
2131 TRUE,
2132 crtc->randr_crtc->pScreen,
2133 NULL);
2134 }
2135 ptr = drmmode_map_slave_bo(drmmode, ppriv);
2136 ppix->devPrivate.ptr = ptr;
2137 DamageRegister(&ppix->drawable, ppriv->slave_damage);
2138
2139 if (ppriv->fb_id == 0) {
2140 drmModeAddFB(drmmode->fd, ppix->drawable.width,
2141 ppix->drawable.height,
2142 ppix->drawable.depth,
2143 ppix->drawable.bitsPerPixel,
2144 ppix->devKind, ppriv->backing_bo->handle, &ppriv->fb_id);
2145 }
2146 *target = ppix;
2147 return TRUE;
2148 }
2149
2150 static Bool
drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)2151 drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
2152 PixmapPtr *target)
2153 {
2154 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2155 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2156
2157 if (drmmode->reverse_prime_offload_mode)
2158 return drmmode_set_target_scanout_pixmap_gpu(crtc, ppix, target);
2159 else
2160 return drmmode_set_target_scanout_pixmap_cpu(crtc, ppix, target);
2161 }
2162
2163 static Bool
drmmode_set_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix)2164 drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
2165 {
2166 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2167
2168 /* Use DisableSharedPixmapFlipping before switching to single buf */
2169 if (drmmode_crtc->enable_flipping)
2170 return FALSE;
2171
2172 return drmmode_set_target_scanout_pixmap(crtc, ppix,
2173 &drmmode_crtc->prime_pixmap);
2174 }
2175
2176 static void
drmmode_clear_pixmap(PixmapPtr pixmap)2177 drmmode_clear_pixmap(PixmapPtr pixmap)
2178 {
2179 ScreenPtr screen = pixmap->drawable.pScreen;
2180 GCPtr gc;
2181
2182 gc = GetScratchGC(pixmap->drawable.depth, screen);
2183 if (gc) {
2184 miClearDrawable(&pixmap->drawable, gc);
2185 FreeScratchGC(gc);
2186 }
2187 }
2188
2189 static void *
drmmode_shadow_allocate(xf86CrtcPtr crtc,int width,int height)2190 drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
2191 {
2192 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2193 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2194 int ret;
2195
2196 if (!drmmode_create_bo(drmmode, &drmmode_crtc->rotate_bo,
2197 width, height, drmmode->kbpp)) {
2198 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
2199 "Couldn't allocate shadow memory for rotated CRTC\n");
2200 return NULL;
2201 }
2202
2203 ret = drmmode_bo_import(drmmode, &drmmode_crtc->rotate_bo,
2204 &drmmode_crtc->rotate_fb_id);
2205
2206 if (ret) {
2207 ErrorF("failed to add rotate fb\n");
2208 drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
2209 return NULL;
2210 }
2211
2212 #ifdef GLAMOR_HAS_GBM
2213 if (drmmode->gbm)
2214 return drmmode_crtc->rotate_bo.gbm;
2215 #endif
2216 return drmmode_crtc->rotate_bo.dumb;
2217 }
2218
2219 PixmapPtr
drmmode_create_pixmap_header(ScreenPtr pScreen,int width,int height,int depth,int bitsPerPixel,int devKind,void * pPixData)2220 drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
2221 int depth, int bitsPerPixel, int devKind,
2222 void *pPixData)
2223 {
2224 PixmapPtr pixmap;
2225
2226 /* width and height of 0 means don't allocate any pixmap data */
2227 pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
2228
2229 if (pixmap) {
2230 if ((*pScreen->ModifyPixmapHeader)(pixmap, width, height, depth,
2231 bitsPerPixel, devKind, pPixData))
2232 return pixmap;
2233 (*pScreen->DestroyPixmap)(pixmap);
2234 }
2235 return NullPixmap;
2236 }
2237
2238 static Bool
2239 drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo);
2240
2241 static PixmapPtr
drmmode_shadow_create(xf86CrtcPtr crtc,void * data,int width,int height)2242 drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
2243 {
2244 ScrnInfoPtr scrn = crtc->scrn;
2245 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2246 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2247 uint32_t rotate_pitch;
2248 PixmapPtr rotate_pixmap;
2249 void *pPixData = NULL;
2250
2251 if (!data) {
2252 data = drmmode_shadow_allocate(crtc, width, height);
2253 if (!data) {
2254 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2255 "Couldn't allocate shadow pixmap for rotated CRTC\n");
2256 return NULL;
2257 }
2258 }
2259
2260 if (!drmmode_bo_has_bo(&drmmode_crtc->rotate_bo)) {
2261 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2262 "Couldn't allocate shadow pixmap for rotated CRTC\n");
2263 return NULL;
2264 }
2265
2266 pPixData = drmmode_bo_map(drmmode, &drmmode_crtc->rotate_bo);
2267 rotate_pitch = drmmode_bo_get_pitch(&drmmode_crtc->rotate_bo),
2268
2269 rotate_pixmap = drmmode_create_pixmap_header(scrn->pScreen,
2270 width, height,
2271 scrn->depth,
2272 drmmode->kbpp,
2273 rotate_pitch,
2274 pPixData);
2275
2276 if (rotate_pixmap == NULL) {
2277 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2278 "Couldn't allocate shadow pixmap for rotated CRTC\n");
2279 return NULL;
2280 }
2281
2282 drmmode_set_pixmap_bo(drmmode, rotate_pixmap, &drmmode_crtc->rotate_bo);
2283
2284 return rotate_pixmap;
2285 }
2286
2287 static void
drmmode_shadow_destroy(xf86CrtcPtr crtc,PixmapPtr rotate_pixmap,void * data)2288 drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
2289 {
2290 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2291 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2292
2293 if (rotate_pixmap) {
2294 rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap);
2295 }
2296
2297 if (data) {
2298 drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
2299 drmmode_crtc->rotate_fb_id = 0;
2300
2301 drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
2302 memset(&drmmode_crtc->rotate_bo, 0, sizeof drmmode_crtc->rotate_bo);
2303 }
2304 }
2305
2306 static void
drmmode_crtc_destroy(xf86CrtcPtr crtc)2307 drmmode_crtc_destroy(xf86CrtcPtr crtc)
2308 {
2309 drmmode_mode_ptr iterator, next;
2310 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2311 modesettingPtr ms = modesettingPTR(crtc->scrn);
2312
2313 if (!ms->atomic_modeset)
2314 return;
2315
2316 drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
2317 xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) {
2318 drm_mode_destroy(crtc, iterator);
2319 }
2320 }
2321
2322 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
2323 .dpms = drmmode_crtc_dpms,
2324 .set_mode_major = drmmode_set_mode_major,
2325 .set_cursor_colors = drmmode_set_cursor_colors,
2326 .set_cursor_position = drmmode_set_cursor_position,
2327 .show_cursor_check = drmmode_show_cursor,
2328 .hide_cursor = drmmode_hide_cursor,
2329 .load_cursor_argb_check = drmmode_load_cursor_argb_check,
2330
2331 .gamma_set = drmmode_crtc_gamma_set,
2332 .destroy = drmmode_crtc_destroy,
2333 .set_scanout_pixmap = drmmode_set_scanout_pixmap,
2334 .shadow_allocate = drmmode_shadow_allocate,
2335 .shadow_create = drmmode_shadow_create,
2336 .shadow_destroy = drmmode_shadow_destroy,
2337 };
2338
2339 static uint32_t
drmmode_crtc_vblank_pipe(int crtc_id)2340 drmmode_crtc_vblank_pipe(int crtc_id)
2341 {
2342 if (crtc_id > 1)
2343 return crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT;
2344 else if (crtc_id > 0)
2345 return DRM_VBLANK_SECONDARY;
2346 else
2347 return 0;
2348 }
2349
2350 static Bool
is_plane_assigned(ScrnInfoPtr scrn,int plane_id)2351 is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
2352 {
2353 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2354 int c;
2355
2356 for (c = 0; c < xf86_config->num_crtc; c++) {
2357 xf86CrtcPtr iter = xf86_config->crtc[c];
2358 drmmode_crtc_private_ptr drmmode_crtc = iter->driver_private;
2359 if (drmmode_crtc->plane_id == plane_id)
2360 return TRUE;
2361 }
2362
2363 return FALSE;
2364 }
2365
2366 /**
2367 * Populates the formats array, and the modifiers of each format for a drm_plane.
2368 */
2369 static Bool
populate_format_modifiers(xf86CrtcPtr crtc,const drmModePlane * kplane,uint32_t blob_id)2370 populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane,
2371 uint32_t blob_id)
2372 {
2373 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2374 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2375 unsigned i, j;
2376 drmModePropertyBlobRes *blob;
2377 struct drm_format_modifier_blob *fmt_mod_blob;
2378 uint32_t *blob_formats;
2379 struct drm_format_modifier *blob_modifiers;
2380
2381 if (!blob_id)
2382 return FALSE;
2383
2384 blob = drmModeGetPropertyBlob(drmmode->fd, blob_id);
2385 if (!blob)
2386 return FALSE;
2387
2388 fmt_mod_blob = blob->data;
2389 blob_formats = formats_ptr(fmt_mod_blob);
2390 blob_modifiers = modifiers_ptr(fmt_mod_blob);
2391
2392 assert(drmmode_crtc->num_formats == fmt_mod_blob->count_formats);
2393
2394 for (i = 0; i < fmt_mod_blob->count_formats; i++) {
2395 uint32_t num_modifiers = 0;
2396 uint64_t *modifiers = NULL;
2397 uint64_t *tmp;
2398 for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
2399 struct drm_format_modifier *mod = &blob_modifiers[j];
2400
2401 if ((i < mod->offset) || (i > mod->offset + 63))
2402 continue;
2403 if (!(mod->formats & (1 << (i - mod->offset))))
2404 continue;
2405
2406 if (!mod->modifier || mod->modifier == DRM_FORMAT_MOD_INVALID)
2407 continue;
2408
2409 num_modifiers++;
2410 tmp = realloc(modifiers, num_modifiers * sizeof(modifiers[0]));
2411 if (!tmp) {
2412 free(modifiers);
2413 drmModeFreePropertyBlob(blob);
2414 return FALSE;
2415 }
2416 modifiers = tmp;
2417 modifiers[num_modifiers - 1] = mod->modifier;
2418 }
2419
2420 drmmode_crtc->formats[i].format = blob_formats[i];
2421 drmmode_crtc->formats[i].modifiers = modifiers;
2422 drmmode_crtc->formats[i].num_modifiers = num_modifiers;
2423 }
2424
2425 drmModeFreePropertyBlob(blob);
2426
2427 return TRUE;
2428 }
2429
2430 static void
drmmode_crtc_create_planes(xf86CrtcPtr crtc,int num)2431 drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
2432 {
2433 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2434 drmmode_ptr drmmode = drmmode_crtc->drmmode;
2435 drmModePlaneRes *kplane_res;
2436 drmModePlane *kplane, *best_kplane = NULL;
2437 drmModeObjectProperties *props;
2438 uint32_t i, type, blob_id;
2439 int current_crtc, best_plane = 0;
2440
2441 static drmmode_prop_enum_info_rec plane_type_enums[] = {
2442 [DRMMODE_PLANE_TYPE_PRIMARY] = {
2443 .name = "Primary",
2444 },
2445 [DRMMODE_PLANE_TYPE_OVERLAY] = {
2446 .name = "Overlay",
2447 },
2448 [DRMMODE_PLANE_TYPE_CURSOR] = {
2449 .name = "Cursor",
2450 },
2451 };
2452 static const drmmode_prop_info_rec plane_props[] = {
2453 [DRMMODE_PLANE_TYPE] = {
2454 .name = "type",
2455 .enum_values = plane_type_enums,
2456 .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
2457 },
2458 [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
2459 [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
2460 [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", },
2461 [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
2462 [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
2463 [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
2464 [DRMMODE_PLANE_SRC_H] = { .name = "SRC_H", },
2465 [DRMMODE_PLANE_CRTC_X] = { .name = "CRTC_X", },
2466 [DRMMODE_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
2467 [DRMMODE_PLANE_CRTC_W] = { .name = "CRTC_W", },
2468 [DRMMODE_PLANE_CRTC_H] = { .name = "CRTC_H", },
2469 };
2470 drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
2471
2472 if (!drmmode_prop_info_copy(tmp_props, plane_props, DRMMODE_PLANE__COUNT, 0)) {
2473 xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2474 "failed to copy plane property info\n");
2475 drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2476 return;
2477 }
2478
2479 kplane_res = drmModeGetPlaneResources(drmmode->fd);
2480 if (!kplane_res) {
2481 xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2482 "failed to get plane resources: %s\n", strerror(errno));
2483 drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2484 return;
2485 }
2486
2487 for (i = 0; i < kplane_res->count_planes; i++) {
2488 int plane_id;
2489
2490 kplane = drmModeGetPlane(drmmode->fd, kplane_res->planes[i]);
2491 if (!kplane)
2492 continue;
2493
2494 if (!(kplane->possible_crtcs & (1 << num)) ||
2495 is_plane_assigned(drmmode->scrn, kplane->plane_id)) {
2496 drmModeFreePlane(kplane);
2497 continue;
2498 }
2499
2500 plane_id = kplane->plane_id;
2501
2502 props = drmModeObjectGetProperties(drmmode->fd, plane_id,
2503 DRM_MODE_OBJECT_PLANE);
2504 if (!props) {
2505 xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2506 "couldn't get plane properties\n");
2507 drmModeFreePlane(kplane);
2508 continue;
2509 }
2510
2511 drmmode_prop_info_update(drmmode, tmp_props, DRMMODE_PLANE__COUNT, props);
2512
2513 /* Only primary planes are important for atomic page-flipping */
2514 type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
2515 props, DRMMODE_PLANE_TYPE__COUNT);
2516 if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
2517 drmModeFreePlane(kplane);
2518 drmModeFreeObjectProperties(props);
2519 continue;
2520 }
2521
2522 /* Check if plane is already on this CRTC */
2523 current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
2524 props, 0);
2525 if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
2526 if (best_plane) {
2527 drmModeFreePlane(best_kplane);
2528 drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
2529 }
2530 best_plane = plane_id;
2531 best_kplane = kplane;
2532 blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
2533 props, 0);
2534 drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
2535 DRMMODE_PLANE__COUNT, 1);
2536 drmModeFreeObjectProperties(props);
2537 break;
2538 }
2539
2540 if (!best_plane) {
2541 best_plane = plane_id;
2542 best_kplane = kplane;
2543 blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
2544 props, 0);
2545 drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
2546 DRMMODE_PLANE__COUNT, 1);
2547 } else {
2548 drmModeFreePlane(kplane);
2549 }
2550
2551 drmModeFreeObjectProperties(props);
2552 }
2553
2554 drmmode_crtc->plane_id = best_plane;
2555 if (best_kplane) {
2556 drmmode_crtc->num_formats = best_kplane->count_formats;
2557 drmmode_crtc->formats = calloc(sizeof(drmmode_format_rec),
2558 best_kplane->count_formats);
2559 if (!populate_format_modifiers(crtc, best_kplane, blob_id)) {
2560 for (i = 0; i < best_kplane->count_formats; i++)
2561 drmmode_crtc->formats[i].format = best_kplane->formats[i];
2562 }
2563 drmModeFreePlane(best_kplane);
2564 }
2565
2566 drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2567 drmModeFreePlaneResources(kplane_res);
2568 }
2569
2570 static unsigned int
drmmode_crtc_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,drmModeResPtr mode_res,int num)2571 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
2572 {
2573 xf86CrtcPtr crtc;
2574 drmmode_crtc_private_ptr drmmode_crtc;
2575 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2576 modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
2577 modesettingPtr ms = modesettingPTR(pScrn);
2578 drmModeObjectPropertiesPtr props;
2579 static const drmmode_prop_info_rec crtc_props[] = {
2580 [DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" },
2581 [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" },
2582 [DRMMODE_CRTC_GAMMA_LUT] = { .name = "GAMMA_LUT" },
2583 [DRMMODE_CRTC_GAMMA_LUT_SIZE] = { .name = "GAMMA_LUT_SIZE" },
2584 };
2585 int o, found = 0;
2586
2587 /* only init possible crtcs for the outputs */
2588 for (o = 0; o < config->num_output; o++) {
2589 xf86OutputPtr output = config->output[o];
2590 drmmode_output_private_ptr drmmode_output = output->driver_private;
2591
2592 if (drmmode_output->possible_crtcs & (1 << num)) {
2593 output->possible_crtcs |= 1 << config->num_crtc;
2594 found = 1;
2595 }
2596 }
2597
2598 if (!found)
2599 return 0;
2600
2601 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
2602 if (crtc == NULL)
2603 return 0;
2604 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
2605 crtc->driver_private = drmmode_crtc;
2606 drmmode_crtc->mode_crtc =
2607 drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
2608 drmmode_crtc->drmmode = drmmode;
2609 drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
2610 xorg_list_init(&drmmode_crtc->mode_list);
2611
2612 if (drmmode->fb_flip_mode == DRMMODE_FB_FLIP_NONE)
2613 drmmode_crtc->can_flip_fb = FALSE;
2614 else
2615 drmmode_crtc->can_flip_fb = TRUE;
2616
2617 if (1 || ms->atomic_modeset) {
2618 props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
2619 DRM_MODE_OBJECT_CRTC);
2620 if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props,
2621 DRMMODE_CRTC__COUNT, 0)) {
2622 xf86CrtcDestroy(crtc);
2623 return 0;
2624 }
2625
2626 drmmode_prop_info_update(drmmode, drmmode_crtc->props,
2627 DRMMODE_CRTC__COUNT, props);
2628 drmModeFreeObjectProperties(props);
2629 drmmode_crtc_create_planes(crtc, num);
2630 }
2631
2632 /* Hide any cursors which may be active from previous users */
2633 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);
2634
2635 /* Mark num'th crtc as in use on this device. */
2636 ms_ent->assigned_crtcs |= (1 << num);
2637 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
2638 "Allocated crtc nr. %d to this screen.\n", num);
2639
2640 drmmode_crtc->use_gamma_lut =
2641 drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].prop_id &&
2642 drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].value &&
2643 xf86ReturnOptValBool(drmmode->Options, OPTION_USE_GAMMA_LUT, TRUE);
2644
2645 return 1;
2646 }
2647
2648 /*
2649 * Update all of the property values for an output
2650 */
2651 static void
drmmode_output_update_properties(xf86OutputPtr output)2652 drmmode_output_update_properties(xf86OutputPtr output)
2653 {
2654 drmmode_output_private_ptr drmmode_output = output->driver_private;
2655 int i, j, k;
2656 int err;
2657 drmModeConnectorPtr koutput;
2658
2659 /* Use the most recently fetched values from the kernel */
2660 koutput = drmmode_output->mode_output;
2661
2662 if (!koutput)
2663 return;
2664
2665 for (i = 0; i < drmmode_output->num_props; i++) {
2666 drmmode_prop_ptr p = &drmmode_output->props[i];
2667
2668 for (j = 0; koutput && j < koutput->count_props; j++) {
2669 if (koutput->props[j] == p->mode_prop->prop_id) {
2670
2671 /* Check to see if the property value has changed */
2672 if (koutput->prop_values[j] != p->value) {
2673
2674 p->value = koutput->prop_values[j];
2675
2676 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
2677 INT32 value = p->value;
2678
2679 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2680 XA_INTEGER, 32, PropModeReplace, 1,
2681 &value, FALSE, TRUE);
2682
2683 if (err != 0) {
2684 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2685 "RRChangeOutputProperty error, %d\n", err);
2686 }
2687 }
2688 else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
2689 for (k = 0; k < p->mode_prop->count_enums; k++)
2690 if (p->mode_prop->enums[k].value == p->value)
2691 break;
2692 if (k < p->mode_prop->count_enums) {
2693 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2694 XA_ATOM, 32, PropModeReplace, 1,
2695 &p->atoms[k + 1], FALSE, TRUE);
2696 if (err != 0) {
2697 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2698 "RRChangeOutputProperty error, %d\n", err);
2699 }
2700 }
2701 }
2702 }
2703 break;
2704 }
2705 }
2706 }
2707 }
2708
2709 static void
drmmode_output_change_status(xf86OutputPtr output,xf86OutputStatus status)2710 drmmode_output_change_status(xf86OutputPtr output, xf86OutputStatus status)
2711 {
2712 drmmode_output_private_ptr drmmode_output = output->driver_private;
2713 drmmode_ptr drmmode = drmmode_output->drmmode;
2714 drmmode_crtc_private_ptr drmmode_crtc;
2715 ScrnInfoPtr scrn = drmmode->scrn;
2716 xf86CrtcPtr crtc = output->crtc;
2717 Bool connected;
2718
2719 if (drmmode_output->status == status)
2720 return;
2721
2722 drmmode_output->status = status;
2723 connected = status == XF86OutputStatusConnected;
2724
2725 xf86DrvMsg(scrn->scrnIndex, X_INFO,
2726 "Output %s status changed to %s.\n", output->name,
2727 connected ? "connected" : "disconnected");
2728
2729 if (!crtc)
2730 return;
2731
2732 drmmode_crtc = crtc->driver_private;
2733
2734 if (!connected) {
2735 if (drmmode->hotplug_reset && !drmmode_crtc_connected(crtc)) {
2736 drmmode_crtc->need_modeset = TRUE;
2737
2738 drmModeSetCrtc(drmmode->fd,
2739 drmmode_crtc->mode_crtc->crtc_id,
2740 0, 0, 0, NULL, 0, NULL);
2741 }
2742 } else if (drmmode_crtc->need_modeset) {
2743 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
2744 crtc->x, crtc->y);
2745 }
2746 }
2747
2748 static xf86OutputStatus
drmmode_output_detect(xf86OutputPtr output)2749 drmmode_output_detect(xf86OutputPtr output)
2750 {
2751 /* go to the hw and retrieve a new output struct */
2752 drmmode_output_private_ptr drmmode_output = output->driver_private;
2753 drmmode_ptr drmmode = drmmode_output->drmmode;
2754 xf86OutputStatus status;
2755
2756 if (drmmode_output->output_id == -1)
2757 return XF86OutputStatusDisconnected;
2758
2759 drmModeFreeConnector(drmmode_output->mode_output);
2760
2761 drmmode_output->mode_output =
2762 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
2763
2764 if (!drmmode_output->mode_output) {
2765 drmmode_output->output_id = -1;
2766 return XF86OutputStatusDisconnected;
2767 }
2768
2769 drmmode_output_update_properties(output);
2770
2771 switch (drmmode_output->mode_output->connection) {
2772 case DRM_MODE_CONNECTED:
2773 status = XF86OutputStatusConnected;
2774 break;
2775 case DRM_MODE_DISCONNECTED:
2776 status = XF86OutputStatusDisconnected;
2777 break;
2778 default:
2779 case DRM_MODE_UNKNOWNCONNECTION:
2780 status = XF86OutputStatusUnknown;
2781 break;
2782 }
2783
2784 drmmode_output_change_status(output, status);
2785 return status;
2786 }
2787
2788 static Bool
drmmode_output_mode_valid(xf86OutputPtr output,DisplayModePtr pModes)2789 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
2790 {
2791 return MODE_OK;
2792 }
2793
2794 static int
koutput_get_prop_idx(int fd,drmModeConnectorPtr koutput,int type,const char * name)2795 koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
2796 int type, const char *name)
2797 {
2798 int idx = -1;
2799
2800 for (int i = 0; i < koutput->count_props; i++) {
2801 drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
2802
2803 if (!prop)
2804 continue;
2805
2806 if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
2807 idx = i;
2808
2809 drmModeFreeProperty(prop);
2810
2811 if (idx > -1)
2812 break;
2813 }
2814
2815 return idx;
2816 }
2817
2818 static int
koutput_get_prop_id(int fd,drmModeConnectorPtr koutput,int type,const char * name)2819 koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
2820 int type, const char *name)
2821 {
2822 int idx = koutput_get_prop_idx(fd, koutput, type, name);
2823
2824 return (idx > -1) ? koutput->props[idx] : -1;
2825 }
2826
2827 static drmModePropertyBlobPtr
koutput_get_prop_blob(int fd,drmModeConnectorPtr koutput,const char * name)2828 koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
2829 {
2830 drmModePropertyBlobPtr blob = NULL;
2831 int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
2832
2833 if (idx > -1)
2834 blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
2835
2836 return blob;
2837 }
2838
2839 static void
drmmode_output_attach_tile(xf86OutputPtr output)2840 drmmode_output_attach_tile(xf86OutputPtr output)
2841 {
2842 drmmode_output_private_ptr drmmode_output = output->driver_private;
2843 drmModeConnectorPtr koutput = drmmode_output->mode_output;
2844 drmmode_ptr drmmode = drmmode_output->drmmode;
2845 struct xf86CrtcTileInfo tile_info, *set = NULL;
2846
2847 if (!koutput) {
2848 xf86OutputSetTile(output, NULL);
2849 return;
2850 }
2851
2852 drmModeFreePropertyBlob(drmmode_output->tile_blob);
2853
2854 /* look for a TILE property */
2855 drmmode_output->tile_blob =
2856 koutput_get_prop_blob(drmmode->fd, koutput, "TILE");
2857
2858 if (drmmode_output->tile_blob) {
2859 if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE)
2860 set = &tile_info;
2861 }
2862 xf86OutputSetTile(output, set);
2863 }
2864
2865 static Bool
has_panel_fitter(xf86OutputPtr output)2866 has_panel_fitter(xf86OutputPtr output)
2867 {
2868 drmmode_output_private_ptr drmmode_output = output->driver_private;
2869 drmModeConnectorPtr koutput = drmmode_output->mode_output;
2870 drmmode_ptr drmmode = drmmode_output->drmmode;
2871 int idx;
2872
2873 /* Presume that if the output supports scaling, then we have a
2874 * panel fitter capable of adjust any mode to suit.
2875 */
2876 idx = koutput_get_prop_idx(drmmode->fd, koutput,
2877 DRM_MODE_PROP_ENUM, "scaling mode");
2878
2879 return (idx > -1);
2880 }
2881
2882 static DisplayModePtr
drmmode_output_add_gtf_modes(xf86OutputPtr output,DisplayModePtr Modes)2883 drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes)
2884 {
2885 xf86MonPtr mon = output->MonInfo;
2886 DisplayModePtr i, m, preferred = NULL;
2887 int max_x = 0, max_y = 0;
2888 float max_vrefresh = 0.0;
2889
2890 if (mon && gtf_supported(mon))
2891 return Modes;
2892
2893 if (!has_panel_fitter(output))
2894 return Modes;
2895
2896 for (m = Modes; m; m = m->next) {
2897 if (m->type & M_T_PREFERRED)
2898 preferred = m;
2899 max_x = max(max_x, m->HDisplay);
2900 max_y = max(max_y, m->VDisplay);
2901 max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
2902 }
2903
2904 max_vrefresh = max(max_vrefresh, 60.0);
2905 max_vrefresh *= (1 + SYNC_TOLERANCE);
2906
2907 m = xf86GetDefaultModes();
2908 xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
2909
2910 for (i = m; i; i = i->next) {
2911 if (xf86ModeVRefresh(i) > max_vrefresh)
2912 i->status = MODE_VSYNC;
2913 if (preferred &&
2914 i->HDisplay >= preferred->HDisplay &&
2915 i->VDisplay >= preferred->VDisplay &&
2916 xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred))
2917 i->status = MODE_VSYNC;
2918 }
2919
2920 xf86PruneInvalidModes(output->scrn, &m, FALSE);
2921
2922 return xf86ModesAdd(Modes, m);
2923 }
2924
2925 static DisplayModePtr
drmmode_output_get_modes(xf86OutputPtr output)2926 drmmode_output_get_modes(xf86OutputPtr output)
2927 {
2928 drmmode_output_private_ptr drmmode_output = output->driver_private;
2929 drmModeConnectorPtr koutput = drmmode_output->mode_output;
2930 drmmode_ptr drmmode = drmmode_output->drmmode;
2931 int i;
2932 DisplayModePtr Modes = NULL, Mode;
2933 xf86MonPtr mon = NULL;
2934
2935 if (!koutput)
2936 return NULL;
2937
2938 drmModeFreePropertyBlob(drmmode_output->edid_blob);
2939
2940 /* look for an EDID property */
2941 drmmode_output->edid_blob =
2942 koutput_get_prop_blob(drmmode->fd, koutput, "EDID");
2943
2944 if (!xf86ReturnOptValBool(drmmode->Options, OPTION_NO_EDID, FALSE) &&
2945 drmmode_output->edid_blob) {
2946 mon = xf86InterpretEDID(output->scrn->scrnIndex,
2947 drmmode_output->edid_blob->data);
2948 if (mon && drmmode_output->edid_blob->length > 128)
2949 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
2950 }
2951 xf86OutputSetEDID(output, mon);
2952
2953 drmmode_output_attach_tile(output);
2954
2955 /* modes should already be available */
2956 for (i = 0; i < koutput->count_modes; i++) {
2957 Mode = xnfalloc(sizeof(DisplayModeRec));
2958
2959 drmmode_ConvertFromKMode(output, &koutput->modes[i], Mode);
2960 Modes = xf86ModesAdd(Modes, Mode);
2961
2962 }
2963
2964 return drmmode_output_add_gtf_modes(output, Modes);
2965 }
2966
2967 static void
drmmode_output_destroy(xf86OutputPtr output)2968 drmmode_output_destroy(xf86OutputPtr output)
2969 {
2970 drmmode_output_private_ptr drmmode_output = output->driver_private;
2971 int i;
2972
2973 drmModeFreePropertyBlob(drmmode_output->edid_blob);
2974 drmModeFreePropertyBlob(drmmode_output->tile_blob);
2975
2976 for (i = 0; i < drmmode_output->num_props; i++) {
2977 drmModeFreeProperty(drmmode_output->props[i].mode_prop);
2978 free(drmmode_output->props[i].atoms);
2979 }
2980 free(drmmode_output->props);
2981 if (drmmode_output->mode_output) {
2982 for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
2983 drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
2984 }
2985 drmModeFreeConnector(drmmode_output->mode_output);
2986 }
2987 free(drmmode_output->mode_encoders);
2988 free(drmmode_output);
2989 output->driver_private = NULL;
2990 }
2991
2992 static void
drmmode_output_dpms(xf86OutputPtr output,int mode)2993 drmmode_output_dpms(xf86OutputPtr output, int mode)
2994 {
2995 modesettingPtr ms = modesettingPTR(output->scrn);
2996 drmmode_output_private_ptr drmmode_output = output->driver_private;
2997 drmmode_ptr drmmode = drmmode_output->drmmode;
2998 xf86CrtcPtr crtc = output->crtc;
2999 drmModeConnectorPtr koutput = drmmode_output->mode_output;
3000
3001 if (!koutput)
3002 return;
3003
3004 /* XXX Check if DPMS mode is already the right one */
3005
3006 drmmode_output->dpms = mode;
3007
3008 if (ms->atomic_modeset) {
3009 if (!ms->pending_modeset)
3010 drmmode_output_dpms_atomic(output, mode);
3011 } else {
3012 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
3013 drmmode_output->dpms_enum_id, mode);
3014 }
3015
3016 if (crtc) {
3017 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3018
3019 if (mode == DPMSModeOn) {
3020 if (drmmode_crtc->need_modeset)
3021 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
3022 crtc->x, crtc->y);
3023
3024 if (drmmode_crtc->enable_flipping)
3025 drmmode_InitSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
3026 } else {
3027 if (drmmode_crtc->enable_flipping)
3028 drmmode_FiniSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
3029 }
3030 }
3031
3032 return;
3033 }
3034
3035 static Bool
drmmode_property_ignore(drmModePropertyPtr prop)3036 drmmode_property_ignore(drmModePropertyPtr prop)
3037 {
3038 if (!prop)
3039 return TRUE;
3040 /* ignore blob prop */
3041 if (prop->flags & DRM_MODE_PROP_BLOB)
3042 return TRUE;
3043 /* ignore standard property */
3044 if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS") ||
3045 !strcmp(prop->name, "CRTC_ID"))
3046 return TRUE;
3047
3048 return FALSE;
3049 }
3050
3051 static void
drmmode_output_create_resources(xf86OutputPtr output)3052 drmmode_output_create_resources(xf86OutputPtr output)
3053 {
3054 drmmode_output_private_ptr drmmode_output = output->driver_private;
3055 drmModeConnectorPtr mode_output = drmmode_output->mode_output;
3056 drmmode_ptr drmmode = drmmode_output->drmmode;
3057 drmModePropertyPtr drmmode_prop;
3058 int i, j, err;
3059
3060 /* already created */
3061 if (drmmode_output->props)
3062 return;
3063
3064 drmmode_output->props =
3065 calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
3066 if (!drmmode_output->props)
3067 return;
3068
3069 drmmode_output->num_props = 0;
3070 for (i = 0, j = 0; i < mode_output->count_props; i++) {
3071 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
3072 if (drmmode_property_ignore(drmmode_prop)) {
3073 drmModeFreeProperty(drmmode_prop);
3074 continue;
3075 }
3076 drmmode_output->props[j].mode_prop = drmmode_prop;
3077 drmmode_output->props[j].value = mode_output->prop_values[i];
3078 drmmode_output->num_props++;
3079 j++;
3080 }
3081
3082 /* Create CONNECTOR_ID property */
3083 {
3084 Atom name = MakeAtom("CONNECTOR_ID", 12, TRUE);
3085 INT32 value = mode_output->connector_id;
3086
3087 if (name != BAD_RESOURCE) {
3088 err = RRConfigureOutputProperty(output->randr_output, name,
3089 FALSE, FALSE, TRUE,
3090 1, &value);
3091 if (err != 0) {
3092 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3093 "RRConfigureOutputProperty error, %d\n", err);
3094 }
3095 err = RRChangeOutputProperty(output->randr_output, name,
3096 XA_INTEGER, 32, PropModeReplace, 1,
3097 &value, FALSE, FALSE);
3098 if (err != 0) {
3099 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3100 "RRChangeOutputProperty error, %d\n", err);
3101 }
3102 }
3103 }
3104
3105 for (i = 0; i < drmmode_output->num_props; i++) {
3106 drmmode_prop_ptr p = &drmmode_output->props[i];
3107
3108 drmmode_prop = p->mode_prop;
3109
3110 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
3111 INT32 prop_range[2];
3112 INT32 value = p->value;
3113
3114 p->num_atoms = 1;
3115 p->atoms = calloc(p->num_atoms, sizeof(Atom));
3116 if (!p->atoms)
3117 continue;
3118 p->atoms[0] =
3119 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
3120 prop_range[0] = drmmode_prop->values[0];
3121 prop_range[1] = drmmode_prop->values[1];
3122 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
3123 FALSE, TRUE,
3124 drmmode_prop->
3125 flags & DRM_MODE_PROP_IMMUTABLE ?
3126 TRUE : FALSE, 2, prop_range);
3127 if (err != 0) {
3128 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3129 "RRConfigureOutputProperty error, %d\n", err);
3130 }
3131 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
3132 XA_INTEGER, 32, PropModeReplace, 1,
3133 &value, FALSE, TRUE);
3134 if (err != 0) {
3135 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3136 "RRChangeOutputProperty error, %d\n", err);
3137 }
3138 }
3139 else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
3140 p->num_atoms = drmmode_prop->count_enums + 1;
3141 p->atoms = calloc(p->num_atoms, sizeof(Atom));
3142 if (!p->atoms)
3143 continue;
3144 p->atoms[0] =
3145 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
3146 for (j = 1; j <= drmmode_prop->count_enums; j++) {
3147 struct drm_mode_property_enum *e = &drmmode_prop->enums[j - 1];
3148
3149 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
3150 }
3151 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
3152 FALSE, FALSE,
3153 drmmode_prop->
3154 flags & DRM_MODE_PROP_IMMUTABLE ?
3155 TRUE : FALSE, p->num_atoms - 1,
3156 (INT32 *) &p->atoms[1]);
3157 if (err != 0) {
3158 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3159 "RRConfigureOutputProperty error, %d\n", err);
3160 }
3161 for (j = 0; j < drmmode_prop->count_enums; j++)
3162 if (drmmode_prop->enums[j].value == p->value)
3163 break;
3164 /* there's always a matching value */
3165 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
3166 XA_ATOM, 32, PropModeReplace, 1,
3167 &p->atoms[j + 1], FALSE, TRUE);
3168 if (err != 0) {
3169 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3170 "RRChangeOutputProperty error, %d\n", err);
3171 }
3172 }
3173 }
3174 }
3175
3176 static Bool
drmmode_output_set_property(xf86OutputPtr output,Atom property,RRPropertyValuePtr value)3177 drmmode_output_set_property(xf86OutputPtr output, Atom property,
3178 RRPropertyValuePtr value)
3179 {
3180 drmmode_output_private_ptr drmmode_output = output->driver_private;
3181 drmmode_ptr drmmode = drmmode_output->drmmode;
3182 int i;
3183
3184 for (i = 0; i < drmmode_output->num_props; i++) {
3185 drmmode_prop_ptr p = &drmmode_output->props[i];
3186
3187 if (p->atoms[0] != property)
3188 continue;
3189
3190 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
3191 uint32_t val;
3192
3193 if (value->type != XA_INTEGER || value->format != 32 ||
3194 value->size != 1)
3195 return FALSE;
3196 val = *(uint32_t *) value->data;
3197
3198 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
3199 p->mode_prop->prop_id, (uint64_t) val);
3200 return TRUE;
3201 }
3202 else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
3203 Atom atom;
3204 const char *name;
3205 int j;
3206
3207 if (value->type != XA_ATOM || value->format != 32 ||
3208 value->size != 1)
3209 return FALSE;
3210 memcpy(&atom, value->data, 4);
3211 if (!(name = NameForAtom(atom)))
3212 return FALSE;
3213
3214 /* search for matching name string, then set its value down */
3215 for (j = 0; j < p->mode_prop->count_enums; j++) {
3216 if (!strcmp(p->mode_prop->enums[j].name, name)) {
3217 drmModeConnectorSetProperty(drmmode->fd,
3218 drmmode_output->output_id,
3219 p->mode_prop->prop_id,
3220 p->mode_prop->enums[j].value);
3221 return TRUE;
3222 }
3223 }
3224 }
3225 }
3226
3227 return TRUE;
3228 }
3229
3230 static Bool
drmmode_output_get_property(xf86OutputPtr output,Atom property)3231 drmmode_output_get_property(xf86OutputPtr output, Atom property)
3232 {
3233 return TRUE;
3234 }
3235
3236 static const xf86OutputFuncsRec drmmode_output_funcs = {
3237 .dpms = drmmode_output_dpms,
3238 .create_resources = drmmode_output_create_resources,
3239 .set_property = drmmode_output_set_property,
3240 .get_property = drmmode_output_get_property,
3241 .detect = drmmode_output_detect,
3242 .mode_valid = drmmode_output_mode_valid,
3243
3244 .get_modes = drmmode_output_get_modes,
3245 .destroy = drmmode_output_destroy
3246 };
3247
3248 static int subpixel_conv_table[7] = {
3249 0,
3250 SubPixelUnknown,
3251 SubPixelHorizontalRGB,
3252 SubPixelHorizontalBGR,
3253 SubPixelVerticalRGB,
3254 SubPixelVerticalBGR,
3255 SubPixelNone
3256 };
3257
3258 static const char *const output_names[] = {
3259 "None",
3260 "VGA",
3261 "DVI-I",
3262 "DVI-D",
3263 "DVI-A",
3264 "Composite",
3265 "SVIDEO",
3266 "LVDS",
3267 "Component",
3268 "DIN",
3269 "DP",
3270 "HDMI",
3271 "HDMI-B",
3272 "TV",
3273 "eDP",
3274 "Virtual",
3275 "DSI",
3276 "DPI",
3277 };
3278
find_output(ScrnInfoPtr pScrn,int id)3279 static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
3280 {
3281 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3282 int i;
3283 for (i = 0; i < xf86_config->num_output; i++) {
3284 xf86OutputPtr output = xf86_config->output[i];
3285 drmmode_output_private_ptr drmmode_output;
3286
3287 drmmode_output = output->driver_private;
3288 if (drmmode_output->output_id == id)
3289 return output;
3290 }
3291 return NULL;
3292 }
3293
parse_path_blob(drmModePropertyBlobPtr path_blob,int * conn_base_id,char ** path)3294 static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
3295 {
3296 char *conn;
3297 char conn_id[5];
3298 int id, len;
3299 char *blob_data;
3300
3301 if (!path_blob)
3302 return -1;
3303
3304 blob_data = path_blob->data;
3305 /* we only handle MST paths for now */
3306 if (strncmp(blob_data, "mst:", 4))
3307 return -1;
3308
3309 conn = strchr(blob_data + 4, '-');
3310 if (!conn)
3311 return -1;
3312 len = conn - (blob_data + 4);
3313 if (len + 1> 5)
3314 return -1;
3315 memcpy(conn_id, blob_data + 4, len);
3316 conn_id[len] = '\0';
3317 id = strtoul(conn_id, NULL, 10);
3318
3319 *conn_base_id = id;
3320
3321 *path = conn + 1;
3322 return 0;
3323 }
3324
3325 static void
drmmode_create_name(ScrnInfoPtr pScrn,drmModeConnectorPtr koutput,char * name,drmModePropertyBlobPtr path_blob)3326 drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
3327 drmModePropertyBlobPtr path_blob)
3328 {
3329 int ret;
3330 char *extra_path;
3331 int conn_id;
3332 xf86OutputPtr output;
3333
3334 ret = parse_path_blob(path_blob, &conn_id, &extra_path);
3335 if (ret == -1)
3336 goto fallback;
3337
3338 output = find_output(pScrn, conn_id);
3339 if (!output)
3340 goto fallback;
3341
3342 snprintf(name, 32, "%s-%s", output->name, extra_path);
3343 return;
3344
3345 fallback:
3346 if (koutput->connector_type >= ARRAY_SIZE(output_names))
3347 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id);
3348 else if (pScrn->is_gpu)
3349 snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id);
3350 else
3351 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id);
3352 }
3353
3354 static unsigned int
drmmode_output_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,drmModeResPtr mode_res,int num,Bool dynamic,int crtcshift)3355 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift)
3356 {
3357 xf86OutputPtr output;
3358 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3359 modesettingPtr ms = modesettingPTR(pScrn);
3360 drmModeConnectorPtr koutput;
3361 drmModeEncoderPtr *kencoders = NULL;
3362 drmmode_output_private_ptr drmmode_output;
3363 char name[32];
3364 int i;
3365 Bool nonDesktop = FALSE;
3366 drmModePropertyBlobPtr path_blob = NULL;
3367 const char *s;
3368 drmModeObjectPropertiesPtr props;
3369 static const drmmode_prop_info_rec connector_props[] = {
3370 [DRMMODE_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
3371 };
3372
3373 drmmode_prop_info_ptr crtc_info;
3374 unsigned int current_crtc;
3375
3376 koutput =
3377 drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
3378 if (!koutput)
3379 return 0;
3380
3381 path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH");
3382 i = koutput_get_prop_idx(drmmode->fd, koutput, DRM_MODE_PROP_RANGE, RR_PROPERTY_NON_DESKTOP);
3383 if (i >= 0)
3384 nonDesktop = koutput->prop_values[i] != 0;
3385
3386 drmmode_create_name(pScrn, koutput, name, path_blob);
3387
3388 if (path_blob)
3389 drmModeFreePropertyBlob(path_blob);
3390
3391 if (path_blob && dynamic) {
3392 /* see if we have an output with this name already
3393 and hook stuff up */
3394 for (i = 0; i < xf86_config->num_output; i++) {
3395 output = xf86_config->output[i];
3396
3397 if (strncmp(output->name, name, 32))
3398 continue;
3399
3400 drmmode_output = output->driver_private;
3401 drmmode_output->output_id = mode_res->connectors[num];
3402 drmmode_output->mode_output = koutput;
3403 output->non_desktop = nonDesktop;
3404 return 1;
3405 }
3406 }
3407
3408 kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
3409 if (!kencoders) {
3410 goto out_free_encoders;
3411 }
3412
3413 for (i = 0; i < koutput->count_encoders; i++) {
3414 kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
3415 if (!kencoders[i]) {
3416 goto out_free_encoders;
3417 }
3418 }
3419
3420 if (xf86IsEntityShared(pScrn->entityList[0])) {
3421 if ((s = xf86GetOptValString(drmmode->Options, OPTION_ZAPHOD_HEADS))) {
3422 if (!drmmode_zaphod_string_matches(pScrn, s, name))
3423 goto out_free_encoders;
3424 } else {
3425 if (!drmmode->is_secondary && (num != 0))
3426 goto out_free_encoders;
3427 else if (drmmode->is_secondary && (num != 1))
3428 goto out_free_encoders;
3429 }
3430 }
3431
3432 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
3433 if (!output) {
3434 goto out_free_encoders;
3435 }
3436
3437 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
3438 if (!drmmode_output) {
3439 xf86OutputDestroy(output);
3440 goto out_free_encoders;
3441 }
3442
3443 s = xf86GetOptValString(drmmode->Options, OPTION_VIRTUAL_SIZE);
3444 if (s)
3445 s = strstr(s, output->name);
3446 if (s) {
3447 int w, h;
3448 if (sscanf(s + strlen(output->name) + 1, "%dx%d", &w, &h) == 2 &&
3449 w > 0 && h > 0) {
3450 drmmode_output->virtual_width = w;
3451 drmmode_output->virtual_height = h;
3452 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3453 "Using virtual size %dx%d for connector: %s\n",
3454 drmmode_output->virtual_width,
3455 drmmode_output->virtual_height, output->name);
3456 }
3457 }
3458
3459 s = xf86GetOptValString(drmmode->Options, OPTION_PADDING);
3460 if (s)
3461 s = strstr(s, output->name);
3462 if (s) {
3463 int top, bottom, left, right;
3464 if (sscanf(s + strlen(output->name) + 1, "%d,%d,%d,%d",
3465 &top, &bottom, &left, &right) == 4) {
3466 if (top >= 0 && bottom >= 0 && left >= 0 && right >= 0) {
3467 drmmode_output->padding_top = top;
3468 drmmode_output->padding_bottom = bottom;
3469 drmmode_output->padding_left = left;
3470 drmmode_output->padding_right = right;
3471 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3472 "Using padding top:%d bottom:%d left:%d right:%d\n",
3473 drmmode_output->padding_top,
3474 drmmode_output->padding_bottom,
3475 drmmode_output->padding_left,
3476 drmmode_output->padding_right);
3477 }
3478 }
3479 }
3480
3481 drmmode_output->output_id = mode_res->connectors[num];
3482 drmmode_output->mode_output = koutput;
3483 drmmode_output->mode_encoders = kencoders;
3484 drmmode_output->drmmode = drmmode;
3485 output->mm_width = koutput->mmWidth;
3486 output->mm_height = koutput->mmHeight;
3487
3488 output->subpixel_order = subpixel_conv_table[koutput->subpixel];
3489 output->interlaceAllowed = TRUE;
3490 output->doubleScanAllowed = TRUE;
3491 output->driver_private = drmmode_output;
3492 output->non_desktop = nonDesktop;
3493
3494 drmmode_output->possible_crtcs = 0x7f;
3495 for (i = 0; i < koutput->count_encoders; i++) {
3496 drmmode_output->possible_crtcs &= kencoders[i]->possible_crtcs;
3497 }
3498
3499 if (!dynamic) {
3500 /* would be updated in crtc init */
3501 output->possible_crtcs = 0;
3502 } else {
3503 output->possible_crtcs = drmmode_output->possible_crtcs;
3504 }
3505
3506 /* work out the possible clones later */
3507 output->possible_clones = 0;
3508
3509 if (!drmmode_prop_info_copy(drmmode_output->props_connector,
3510 connector_props, DRMMODE_CONNECTOR__COUNT,
3511 0)) {
3512 goto out_free_encoders;
3513 }
3514 props = drmModeObjectGetProperties(drmmode->fd,
3515 drmmode_output->output_id,
3516 DRM_MODE_OBJECT_CONNECTOR);
3517 drmmode_prop_info_update(drmmode, drmmode_output->props_connector,
3518 DRMMODE_CONNECTOR__COUNT, props);
3519 crtc_info = &drmmode_output->props_connector[DRMMODE_CONNECTOR_CRTC_ID];
3520 current_crtc = drmmode_prop_get_value(crtc_info, props,
3521 DRMMODE_PLANE_TYPE__COUNT);
3522 drmModeFreeObjectProperties(props);
3523
3524 if (xf86ReturnOptValBool(drmmode->Options, OPTION_BIND_CURRENT, TRUE)) {
3525 for (i = 0; i < mode_res->count_crtcs; i++) {
3526 if (current_crtc == mode_res->crtcs[i]) {
3527 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
3528 "Bind output %d to current crtc %d.\n",
3529 drmmode_output->output_id, current_crtc);
3530 drmmode_output->possible_crtcs = 1 << i;
3531 break;
3532 }
3533 }
3534 }
3535
3536 if (!ms->atomic_modeset) {
3537 drmmode_output->dpms_enum_id =
3538 koutput_get_prop_id(drmmode->fd, koutput, DRM_MODE_PROP_ENUM,
3539 "DPMS");
3540 }
3541
3542 if (dynamic)
3543 output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
3544 return 1;
3545
3546 out_free_encoders:
3547 if (kencoders) {
3548 for (i = 0; i < koutput->count_encoders; i++)
3549 drmModeFreeEncoder(kencoders[i]);
3550 free(kencoders);
3551 }
3552 drmModeFreeConnector(koutput);
3553
3554 return 0;
3555 }
3556
3557 static uint32_t
find_clones(ScrnInfoPtr scrn,xf86OutputPtr output)3558 find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
3559 {
3560 drmmode_output_private_ptr drmmode_output =
3561 output->driver_private, clone_drmout;
3562 int i;
3563 xf86OutputPtr clone_output;
3564 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3565 int index_mask = 0;
3566
3567 if (drmmode_output->enc_clone_mask == 0)
3568 return index_mask;
3569
3570 for (i = 0; i < xf86_config->num_output; i++) {
3571 clone_output = xf86_config->output[i];
3572 clone_drmout = clone_output->driver_private;
3573 if (output == clone_output)
3574 continue;
3575
3576 if (clone_drmout->enc_mask == 0)
3577 continue;
3578 if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
3579 index_mask |= (1 << i);
3580 }
3581 return index_mask;
3582 }
3583
3584 static void
drmmode_clones_init(ScrnInfoPtr scrn,drmmode_ptr drmmode,drmModeResPtr mode_res)3585 drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
3586 {
3587 int i, j;
3588 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3589
3590 for (i = 0; i < xf86_config->num_output; i++) {
3591 xf86OutputPtr output = xf86_config->output[i];
3592 drmmode_output_private_ptr drmmode_output;
3593
3594 drmmode_output = output->driver_private;
3595 drmmode_output->enc_clone_mask = 0xff;
3596 /* and all the possible encoder clones for this output together */
3597 for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
3598 int k;
3599
3600 for (k = 0; k < mode_res->count_encoders; k++) {
3601 if (mode_res->encoders[k] ==
3602 drmmode_output->mode_encoders[j]->encoder_id)
3603 drmmode_output->enc_mask |= (1 << k);
3604 }
3605
3606 drmmode_output->enc_clone_mask &=
3607 drmmode_output->mode_encoders[j]->possible_clones;
3608 }
3609 }
3610
3611 for (i = 0; i < xf86_config->num_output; i++) {
3612 xf86OutputPtr output = xf86_config->output[i];
3613
3614 output->possible_clones = find_clones(scrn, output);
3615 }
3616 }
3617
3618 static Bool
drmmode_set_pixmap_bo(drmmode_ptr drmmode,PixmapPtr pixmap,drmmode_bo * bo)3619 drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo)
3620 {
3621 ScrnInfoPtr scrn = drmmode->scrn;
3622
3623 if (drmmode->exa)
3624 return ms_exa_set_pixmap_bo(scrn, pixmap, bo->dumb, FALSE);
3625
3626 #ifdef GLAMOR_HAS_GBM
3627 if (!drmmode->glamor)
3628 return TRUE;
3629
3630 if (!glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo->gbm,
3631 bo->used_modifiers)) {
3632 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create pixmap\n");
3633 return FALSE;
3634 }
3635 bo->owned_gbm = FALSE;
3636 #endif
3637
3638 return TRUE;
3639 }
3640
3641 Bool
drmmode_handle_new_screen_pixmap(drmmode_ptr drmmode)3642 drmmode_handle_new_screen_pixmap(drmmode_ptr drmmode)
3643 {
3644 ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn);
3645 PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
3646
3647 if (!drmmode_set_pixmap_bo(drmmode, screen_pixmap, &drmmode->front_bo))
3648 return FALSE;
3649
3650 return TRUE;
3651 }
3652
3653 static Bool
drmmode_xf86crtc_resize(ScrnInfoPtr scrn,int width,int height)3654 drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
3655 {
3656 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3657 modesettingPtr ms = modesettingPTR(scrn);
3658 drmmode_ptr drmmode = &ms->drmmode;
3659 drmmode_bo old_front;
3660 ScreenPtr screen = xf86ScrnToScreen(scrn);
3661 uint32_t old_fb_id;
3662 int i, pitch, old_width, old_height, old_pitch;
3663 int cpp = (scrn->bitsPerPixel + 7) / 8;
3664 int kcpp = (drmmode->kbpp + 7) / 8;
3665 PixmapPtr ppix = screen->GetScreenPixmap(screen);
3666 void *new_pixels = NULL;
3667
3668 if (scrn->virtualX == width && scrn->virtualY == height)
3669 return TRUE;
3670
3671 xf86DrvMsg(scrn->scrnIndex, X_INFO,
3672 "Allocate new frame buffer %dx%d stride\n", width, height);
3673
3674 old_width = scrn->virtualX;
3675 old_height = scrn->virtualY;
3676 old_pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
3677 old_front = drmmode->front_bo;
3678 old_fb_id = drmmode->fb_id;
3679 drmmode->fb_id = 0;
3680
3681 if (!drmmode_create_bo(drmmode, &drmmode->front_bo,
3682 width, height, drmmode->kbpp))
3683 goto fail;
3684
3685 pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
3686
3687 scrn->virtualX = width;
3688 scrn->virtualY = height;
3689 scrn->displayWidth = pitch / kcpp;
3690
3691 if (!drmmode->gbm && !drmmode->exa) {
3692 new_pixels = drmmode_map_front_bo(drmmode);
3693 if (!new_pixels)
3694 goto fail;
3695 }
3696
3697 if (drmmode->shadow_enable) {
3698 uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
3699 new_pixels = calloc(1, size);
3700 if (new_pixels == NULL)
3701 goto fail;
3702 free(drmmode->shadow_fb);
3703 drmmode->shadow_fb = new_pixels;
3704 }
3705
3706 if (drmmode->shadow_enable2) {
3707 uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
3708 void *fb2 = calloc(1, size);
3709 free(drmmode->shadow_fb2);
3710 drmmode->shadow_fb2 = fb2;
3711 }
3712
3713 screen->ModifyPixmapHeader(ppix, width, height, -1, -1,
3714 scrn->displayWidth * cpp, new_pixels);
3715
3716 if (!drmmode_handle_new_screen_pixmap(drmmode))
3717 goto fail;
3718
3719 drmmode_clear_pixmap(ppix);
3720
3721 for (i = 0; i < xf86_config->num_crtc; i++) {
3722 xf86CrtcPtr crtc = xf86_config->crtc[i];
3723
3724 if (!crtc->enabled)
3725 continue;
3726
3727 drmmode_set_mode_major(crtc, &crtc->mode,
3728 crtc->rotation, crtc->x, crtc->y);
3729 }
3730
3731 if (old_fb_id)
3732 drmModeRmFB(drmmode->fd, old_fb_id);
3733
3734 drmmode_bo_destroy(drmmode, &old_front);
3735
3736 return TRUE;
3737
3738 fail:
3739 drmmode_bo_destroy(drmmode, &drmmode->front_bo);
3740 drmmode->front_bo = old_front;
3741 scrn->virtualX = old_width;
3742 scrn->virtualY = old_height;
3743 scrn->displayWidth = old_pitch / kcpp;
3744 drmmode->fb_id = old_fb_id;
3745
3746 return FALSE;
3747 }
3748
3749 static void
drmmode_validate_leases(ScrnInfoPtr scrn)3750 drmmode_validate_leases(ScrnInfoPtr scrn)
3751 {
3752 ScreenPtr screen = scrn->pScreen;
3753 rrScrPrivPtr scr_priv;
3754 modesettingPtr ms = modesettingPTR(scrn);
3755 drmmode_ptr drmmode = &ms->drmmode;
3756 drmModeLesseeListPtr lessees;
3757 RRLeasePtr lease, next;
3758 int l;
3759
3760 /* Bail out if RandR wasn't initialized. */
3761 if (!dixPrivateKeyRegistered(rrPrivKey))
3762 return;
3763
3764 scr_priv = rrGetScrPriv(screen);
3765
3766 /* We can't talk to the kernel about leases when VT switched */
3767 if (!scrn->vtSema)
3768 return;
3769
3770 lessees = drmModeListLessees(drmmode->fd);
3771 if (!lessees)
3772 return;
3773
3774 xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
3775 drmmode_lease_private_ptr lease_private = lease->devPrivate;
3776
3777 for (l = 0; l < lessees->count; l++) {
3778 if (lessees->lessees[l] == lease_private->lessee_id)
3779 break;
3780 }
3781
3782 /* check to see if the lease has gone away */
3783 if (l == lessees->count) {
3784 free(lease_private);
3785 lease->devPrivate = NULL;
3786 xf86CrtcLeaseTerminated(lease);
3787 }
3788 }
3789
3790 free(lessees);
3791 }
3792
3793 static int
drmmode_create_lease(RRLeasePtr lease,int * fd)3794 drmmode_create_lease(RRLeasePtr lease, int *fd)
3795 {
3796 ScreenPtr screen = lease->screen;
3797 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3798 modesettingPtr ms = modesettingPTR(scrn);
3799 drmmode_ptr drmmode = &ms->drmmode;
3800 int ncrtc = lease->numCrtcs;
3801 int noutput = lease->numOutputs;
3802 int nobjects;
3803 int c, o;
3804 int i;
3805 int lease_fd;
3806 uint32_t *objects;
3807 drmmode_lease_private_ptr lease_private;
3808
3809 nobjects = ncrtc + noutput;
3810
3811 if (ms->atomic_modeset)
3812 nobjects += ncrtc; /* account for planes as well */
3813
3814 if (nobjects == 0)
3815 return BadValue;
3816
3817 lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
3818 if (!lease_private)
3819 return BadAlloc;
3820
3821 objects = xallocarray(nobjects, sizeof (uint32_t));
3822
3823 if (!objects) {
3824 free(lease_private);
3825 return BadAlloc;
3826 }
3827
3828 i = 0;
3829
3830 /* Add CRTC and plane ids */
3831 for (c = 0; c < ncrtc; c++) {
3832 xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
3833 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3834
3835 objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
3836 if (ms->atomic_modeset)
3837 objects[i++] = drmmode_crtc->plane_id;
3838 }
3839
3840 /* Add connector ids */
3841
3842 for (o = 0; o < noutput; o++) {
3843 xf86OutputPtr output = lease->outputs[o]->devPrivate;
3844 drmmode_output_private_ptr drmmode_output = output->driver_private;
3845
3846 objects[i++] = drmmode_output->mode_output->connector_id;
3847 }
3848
3849 /* call kernel to create lease */
3850 assert (i == nobjects);
3851
3852 lease_fd = drmModeCreateLease(drmmode->fd, objects, nobjects, 0, &lease_private->lessee_id);
3853
3854 free(objects);
3855
3856 if (lease_fd < 0) {
3857 free(lease_private);
3858 return BadMatch;
3859 }
3860
3861 lease->devPrivate = lease_private;
3862
3863 xf86CrtcLeaseStarted(lease);
3864
3865 *fd = lease_fd;
3866 return Success;
3867 }
3868
3869 static void
drmmode_terminate_lease(RRLeasePtr lease)3870 drmmode_terminate_lease(RRLeasePtr lease)
3871 {
3872 ScreenPtr screen = lease->screen;
3873 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3874 modesettingPtr ms = modesettingPTR(scrn);
3875 drmmode_ptr drmmode = &ms->drmmode;
3876 drmmode_lease_private_ptr lease_private = lease->devPrivate;
3877
3878 if (drmModeRevokeLease(drmmode->fd, lease_private->lessee_id) == 0) {
3879 free(lease_private);
3880 lease->devPrivate = NULL;
3881 xf86CrtcLeaseTerminated(lease);
3882 }
3883 }
3884
3885 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
3886 .resize = drmmode_xf86crtc_resize,
3887 .create_lease = drmmode_create_lease,
3888 .terminate_lease = drmmode_terminate_lease
3889 };
3890
3891 Bool
drmmode_pre_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int cpp)3892 drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
3893 {
3894 modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
3895 int i;
3896 int ret;
3897 uint64_t value = 0;
3898 unsigned int crtcs_needed = 0;
3899 drmModeResPtr mode_res;
3900 int crtcshift;
3901
3902 /* check for dumb capability */
3903 ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_BUFFER, &value);
3904 if (ret > 0 || value != 1) {
3905 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3906 "KMS doesn't support dumb interface\n");
3907 return FALSE;
3908 }
3909
3910 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
3911
3912 drmmode->scrn = pScrn;
3913 drmmode->cpp = cpp;
3914 mode_res = drmModeGetResources(drmmode->fd);
3915 if (!mode_res)
3916 return FALSE;
3917
3918 crtcshift = ffs(ms_ent->assigned_crtcs ^ 0xffffffff) - 1;
3919 for (i = 0; i < mode_res->count_connectors; i++)
3920 crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE,
3921 crtcshift);
3922
3923 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
3924 "Up to %d crtcs needed for screen.\n", crtcs_needed);
3925
3926 xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
3927 mode_res->max_height);
3928 for (i = 0; i < mode_res->count_crtcs; i++)
3929 if (!xf86IsEntityShared(pScrn->entityList[0]) ||
3930 (crtcs_needed && !(ms_ent->assigned_crtcs & (1 << i))))
3931 crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
3932
3933 /* All ZaphodHeads outputs provided with matching crtcs? */
3934 if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
3935 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3936 "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
3937 crtcs_needed);
3938
3939 /* workout clones */
3940 drmmode_clones_init(pScrn, drmmode, mode_res);
3941
3942 drmModeFreeResources(mode_res);
3943 xf86ProviderSetup(pScrn, NULL, "modesetting");
3944
3945 xf86InitialConfiguration(pScrn, TRUE);
3946
3947 return TRUE;
3948 }
3949
3950 Bool
drmmode_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3951 drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3952 {
3953 #ifdef GLAMOR_HAS_GBM
3954 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
3955
3956 if (drmmode->glamor) {
3957 if (!glamor_init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
3958 return FALSE;
3959 }
3960 #ifdef GBM_BO_WITH_MODIFIERS
3961 glamor_set_drawable_modifiers_func(pScreen, get_drawable_modifiers);
3962 #endif
3963 }
3964 #endif
3965
3966 return TRUE;
3967 }
3968
3969 void
drmmode_adjust_frame(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int x,int y)3970 drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
3971 {
3972 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3973 xf86OutputPtr output = config->output[config->compat_output];
3974 xf86CrtcPtr crtc = output->crtc;
3975
3976 if (crtc && crtc->enabled) {
3977 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
3978 }
3979 }
3980
3981 Bool
drmmode_set_desired_modes(ScrnInfoPtr pScrn,drmmode_ptr drmmode,Bool set_hw,Bool ign_err)3982 drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw,
3983 Bool ign_err)
3984 {
3985 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3986 Bool success = TRUE;
3987 int c;
3988
3989 for (c = 0; c < config->num_crtc; c++) {
3990 xf86CrtcPtr crtc = config->crtc[c];
3991 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3992 xf86OutputPtr output = NULL;
3993 int o;
3994
3995 /* Skip disabled CRTCs */
3996 if (!crtc->enabled) {
3997 if (set_hw) {
3998 drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
3999 0, 0, 0, NULL, 0, NULL);
4000 }
4001 continue;
4002 }
4003
4004 if (config->output[config->compat_output]->crtc == crtc)
4005 output = config->output[config->compat_output];
4006 else {
4007 for (o = 0; o < config->num_output; o++)
4008 if (config->output[o]->crtc == crtc) {
4009 output = config->output[o];
4010 break;
4011 }
4012 }
4013 /* paranoia */
4014 if (!output)
4015 continue;
4016
4017 /* Mark that we'll need to re-set the mode for sure */
4018 memset(&crtc->mode, 0, sizeof(crtc->mode));
4019 if (!crtc->desiredMode.CrtcHDisplay) {
4020 DisplayModePtr mode =
4021 xf86OutputFindClosestMode(output, pScrn->currentMode);
4022
4023 if (!mode)
4024 return FALSE;
4025 crtc->desiredMode = *mode;
4026 crtc->desiredRotation = RR_Rotate_0;
4027 crtc->desiredX = 0;
4028 crtc->desiredY = 0;
4029 }
4030
4031 if (set_hw) {
4032 if (!crtc->funcs->
4033 set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
4034 crtc->desiredX, crtc->desiredY)) {
4035 if (!ign_err)
4036 return FALSE;
4037 else {
4038 success = FALSE;
4039 crtc->enabled = FALSE;
4040 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4041 "Failed to set the desired mode on connector %s\n",
4042 output->name);
4043 }
4044 }
4045 } else {
4046 crtc->mode = crtc->desiredMode;
4047 crtc->rotation = crtc->desiredRotation;
4048 crtc->x = crtc->desiredX;
4049 crtc->y = crtc->desiredY;
4050 if (!drmmode_apply_transform(crtc))
4051 return FALSE;
4052 }
4053 }
4054
4055 /* Validate leases on VT re-entry */
4056 drmmode_validate_leases(pScrn);
4057
4058 return success;
4059 }
4060
4061 static void
drmmode_load_palette(ScrnInfoPtr pScrn,int numColors,int * indices,LOCO * colors,VisualPtr pVisual)4062 drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
4063 int *indices, LOCO * colors, VisualPtr pVisual)
4064 {
4065 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4066 uint16_t lut_r[256], lut_g[256], lut_b[256];
4067 int index, j, i;
4068 int c;
4069
4070 for (c = 0; c < xf86_config->num_crtc; c++) {
4071 xf86CrtcPtr crtc = xf86_config->crtc[c];
4072 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4073
4074 for (i = 0; i < 256; i++) {
4075 lut_r[i] = drmmode_crtc->lut_r[i] << 6;
4076 lut_g[i] = drmmode_crtc->lut_g[i] << 6;
4077 lut_b[i] = drmmode_crtc->lut_b[i] << 6;
4078 }
4079
4080 switch (pScrn->depth) {
4081 case 15:
4082 for (i = 0; i < numColors; i++) {
4083 index = indices[i];
4084 for (j = 0; j < 8; j++) {
4085 lut_r[index * 8 + j] = colors[index].red << 6;
4086 lut_g[index * 8 + j] = colors[index].green << 6;
4087 lut_b[index * 8 + j] = colors[index].blue << 6;
4088 }
4089 }
4090 break;
4091 case 16:
4092 for (i = 0; i < numColors; i++) {
4093 index = indices[i];
4094
4095 if (i <= 31) {
4096 for (j = 0; j < 8; j++) {
4097 lut_r[index * 8 + j] = colors[index].red << 6;
4098 lut_b[index * 8 + j] = colors[index].blue << 6;
4099 }
4100 }
4101
4102 for (j = 0; j < 4; j++) {
4103 lut_g[index * 4 + j] = colors[index].green << 6;
4104 }
4105 }
4106 break;
4107 default:
4108 for (i = 0; i < numColors; i++) {
4109 index = indices[i];
4110 lut_r[index] = colors[index].red << 6;
4111 lut_g[index] = colors[index].green << 6;
4112 lut_b[index] = colors[index].blue << 6;
4113 }
4114 break;
4115 }
4116
4117 /* Make the change through RandR */
4118 if (crtc->randr_crtc)
4119 RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
4120 else
4121 crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
4122 }
4123 }
4124
4125 static Bool
drmmode_crtc_upgrade_lut(xf86CrtcPtr crtc,int num)4126 drmmode_crtc_upgrade_lut(xf86CrtcPtr crtc, int num)
4127 {
4128 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4129 uint64_t size;
4130
4131 if (!drmmode_crtc->use_gamma_lut)
4132 return TRUE;
4133
4134 assert(drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].prop_id);
4135
4136 size = drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].value;
4137
4138 if (size != crtc->gamma_size) {
4139 ScrnInfoPtr pScrn = crtc->scrn;
4140 uint16_t *gamma = malloc(3 * size * sizeof(uint16_t));
4141
4142 if (gamma) {
4143 free(crtc->gamma_red);
4144
4145 crtc->gamma_size = size;
4146 crtc->gamma_red = gamma;
4147 crtc->gamma_green = gamma + size;
4148 crtc->gamma_blue = gamma + size * 2;
4149
4150 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
4151 "Gamma ramp set to %ld entries on CRTC %d\n",
4152 size, num);
4153 } else {
4154 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4155 "Failed to allocate memory for %ld gamma ramp entries "
4156 "on CRTC %d.\n",
4157 size, num);
4158 return FALSE;
4159 }
4160 }
4161
4162 return TRUE;
4163 }
4164
4165 Bool
drmmode_setup_colormap(ScreenPtr pScreen,ScrnInfoPtr pScrn)4166 drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
4167 {
4168 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4169 int i;
4170
4171 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4172 "Initializing kms color map for depth %d, %d bpc.\n",
4173 pScrn->depth, pScrn->rgbBits);
4174 if (!miCreateDefColormap(pScreen))
4175 return FALSE;
4176
4177 /* If the GAMMA_LUT property is available, replace the server's default
4178 * gamma ramps with ones of the appropriate size. */
4179 for (i = 0; i < xf86_config->num_crtc; i++)
4180 if (!drmmode_crtc_upgrade_lut(xf86_config->crtc[i], i))
4181 return FALSE;
4182
4183 /* Adapt color map size and depth to color depth of screen. */
4184 if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10,
4185 drmmode_load_palette, NULL,
4186 CMAP_PALETTED_TRUECOLOR |
4187 CMAP_RELOAD_ON_MODE_SWITCH))
4188 return FALSE;
4189 return TRUE;
4190 }
4191
4192 #define DRM_MODE_LINK_STATUS_GOOD 0
4193 #define DRM_MODE_LINK_STATUS_BAD 1
4194
4195 void
drmmode_update_kms_state(drmmode_ptr drmmode)4196 drmmode_update_kms_state(drmmode_ptr drmmode)
4197 {
4198 ScrnInfoPtr scrn = drmmode->scrn;
4199 drmModeResPtr mode_res;
4200 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
4201 int i, j;
4202 Bool found = FALSE;
4203 Bool changed = FALSE;
4204
4205 /* Try to re-set the mode on all the connectors with a BAD link-state:
4206 * This may happen if a link degrades and a new modeset is necessary, using
4207 * different link-training parameters. If the kernel found that the current
4208 * mode is not achievable anymore, it should have pruned the mode before
4209 * sending the hotplug event. Try to re-set the currently-set mode to keep
4210 * the display alive, this will fail if the mode has been pruned.
4211 * In any case, we will send randr events for the Desktop Environment to
4212 * deal with it, if it wants to.
4213 */
4214 for (i = 0; i < config->num_output; i++) {
4215 xf86OutputPtr output = config->output[i];
4216 drmmode_output_private_ptr drmmode_output = output->driver_private;
4217 xf86CrtcPtr crtc = output->crtc;
4218
4219 if (!crtc)
4220 continue;
4221
4222 /* Update output status */
4223 if (drmmode_output_detect(output) == XF86OutputStatusDisconnected)
4224 continue;
4225
4226 /* Get an updated view of the properties for the current connector and
4227 * look for the link-status property
4228 */
4229 for (j = 0; j < drmmode_output->num_props; j++) {
4230 drmmode_prop_ptr p = &drmmode_output->props[j];
4231
4232 if (!strcmp(p->mode_prop->name, "link-status")) {
4233 if (p->value == DRM_MODE_LINK_STATUS_BAD) {
4234 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4235 drmmode_crtc->need_modeset = TRUE;
4236
4237 /* Delay re-set to dpms-on */
4238 if (drmmode_output->dpms != DPMSModeOn)
4239 break;
4240
4241 /* the connector got a link failure, re-set the current mode */
4242 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
4243 crtc->x, crtc->y);
4244
4245 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
4246 "hotplug event: connector %u's link-state is BAD, "
4247 "tried resetting the current mode. You may be left"
4248 "with a black screen if this fails...\n",
4249 drmmode_output->mode_output->connector_id);
4250 }
4251 break;
4252 }
4253 }
4254 }
4255
4256 mode_res = drmModeGetResources(drmmode->fd);
4257 if (!mode_res)
4258 goto out;
4259
4260 if (mode_res->count_crtcs != config->num_crtc) {
4261 /* this triggers with Zaphod mode where we don't currently support connector hotplug or MST. */
4262 goto out_free_res;
4263 }
4264
4265 /* figure out if we have gotten rid of any connectors
4266 traverse old output list looking for outputs */
4267 for (i = 0; i < config->num_output; i++) {
4268 xf86OutputPtr output = config->output[i];
4269 drmmode_output_private_ptr drmmode_output;
4270
4271 drmmode_output = output->driver_private;
4272 found = FALSE;
4273 for (j = 0; j < mode_res->count_connectors; j++) {
4274 if (mode_res->connectors[j] == drmmode_output->output_id) {
4275 found = TRUE;
4276 break;
4277 }
4278 }
4279 if (found)
4280 continue;
4281
4282 drmModeFreeConnector(drmmode_output->mode_output);
4283 drmmode_output->mode_output = NULL;
4284 drmmode_output->output_id = -1;
4285
4286 changed = TRUE;
4287 }
4288
4289 /* find new output ids we don't have outputs for */
4290 for (i = 0; i < mode_res->count_connectors; i++) {
4291 found = FALSE;
4292
4293 for (j = 0; j < config->num_output; j++) {
4294 xf86OutputPtr output = config->output[j];
4295 drmmode_output_private_ptr drmmode_output;
4296
4297 drmmode_output = output->driver_private;
4298 if (mode_res->connectors[i] == drmmode_output->output_id) {
4299 found = TRUE;
4300 break;
4301 }
4302 }
4303 if (found)
4304 continue;
4305
4306 changed = TRUE;
4307 drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
4308 }
4309
4310 if (changed) {
4311 RRSetChanged(xf86ScrnToScreen(scrn));
4312 RRTellChanged(xf86ScrnToScreen(scrn));
4313 }
4314
4315 out_free_res:
4316
4317 /* Check to see if a lessee has disappeared */
4318 drmmode_validate_leases(scrn);
4319
4320 drmModeFreeResources(mode_res);
4321 out:
4322 RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
4323 }
4324
4325 #undef DRM_MODE_LINK_STATUS_BAD
4326 #undef DRM_MODE_LINK_STATUS_GOOD
4327
4328 #ifdef CONFIG_UDEV_KMS
4329
4330 static void
drmmode_handle_uevents(int fd,void * closure)4331 drmmode_handle_uevents(int fd, void *closure)
4332 {
4333 drmmode_ptr drmmode = closure;
4334 struct udev_device *dev;
4335 Bool found = FALSE;
4336
4337 while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) {
4338 udev_device_unref(dev);
4339 found = TRUE;
4340 }
4341 if (!found)
4342 return;
4343
4344 drmmode_update_kms_state(drmmode);
4345 }
4346
4347 #endif
4348
4349 void
drmmode_uevent_init(ScrnInfoPtr scrn,drmmode_ptr drmmode)4350 drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
4351 {
4352 #ifdef CONFIG_UDEV_KMS
4353 struct udev *u;
4354 struct udev_monitor *mon;
4355
4356 u = udev_new();
4357 if (!u)
4358 return;
4359 mon = udev_monitor_new_from_netlink(u, "udev");
4360 if (!mon) {
4361 udev_unref(u);
4362 return;
4363 }
4364
4365 if (udev_monitor_filter_add_match_subsystem_devtype(mon,
4366 "drm",
4367 "drm_minor") < 0 ||
4368 udev_monitor_enable_receiving(mon) < 0) {
4369 udev_monitor_unref(mon);
4370 udev_unref(u);
4371 return;
4372 }
4373
4374 drmmode->uevent_handler =
4375 xf86AddGeneralHandler(udev_monitor_get_fd(mon),
4376 drmmode_handle_uevents, drmmode);
4377
4378 drmmode->uevent_monitor = mon;
4379 #endif
4380 }
4381
4382 void
drmmode_uevent_fini(ScrnInfoPtr scrn,drmmode_ptr drmmode)4383 drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
4384 {
4385 #ifdef CONFIG_UDEV_KMS
4386 if (drmmode->uevent_handler) {
4387 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
4388
4389 xf86RemoveGeneralHandler(drmmode->uevent_handler);
4390
4391 udev_monitor_unref(drmmode->uevent_monitor);
4392 udev_unref(u);
4393 }
4394 #endif
4395 }
4396
4397 /* create front and cursor BOs */
4398 Bool
drmmode_create_initial_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)4399 drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
4400 {
4401 modesettingPtr ms = modesettingPTR(pScrn);
4402 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4403 int width;
4404 int height;
4405 int bpp = ms->drmmode.kbpp;
4406 int i;
4407 int cpp = (bpp + 7) / 8;
4408
4409 width = pScrn->virtualX;
4410 height = pScrn->virtualY;
4411
4412 if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, bpp))
4413 return FALSE;
4414 if (drmmode_bo_import(drmmode, &drmmode->front_bo, &drmmode->fb_id) < 0)
4415 return FALSE;
4416 pScrn->displayWidth = drmmode_bo_get_pitch(&drmmode->front_bo) / cpp;
4417
4418 width = ms->cursor_width;
4419 height = ms->cursor_height;
4420 bpp = 32;
4421 for (i = 0; i < xf86_config->num_crtc; i++) {
4422 xf86CrtcPtr crtc = xf86_config->crtc[i];
4423 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4424
4425 drmmode_crtc->cursor_bo =
4426 dumb_bo_create(drmmode->fd, width, height, bpp);
4427 }
4428 return TRUE;
4429 }
4430
4431 void *
drmmode_map_front_bo(drmmode_ptr drmmode)4432 drmmode_map_front_bo(drmmode_ptr drmmode)
4433 {
4434 return drmmode_bo_map(drmmode, &drmmode->front_bo);
4435 }
4436
4437 void *
drmmode_map_slave_bo(drmmode_ptr drmmode,msPixmapPrivPtr ppriv)4438 drmmode_map_slave_bo(drmmode_ptr drmmode, msPixmapPrivPtr ppriv)
4439 {
4440 int ret;
4441
4442 if (ppriv->backing_bo->ptr)
4443 return ppriv->backing_bo->ptr;
4444
4445 ret = dumb_bo_map(drmmode->fd, ppriv->backing_bo);
4446 if (ret)
4447 return NULL;
4448
4449 return ppriv->backing_bo->ptr;
4450 }
4451
4452 Bool
drmmode_map_cursor_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)4453 drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
4454 {
4455 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4456 int i, ret;
4457
4458 for (i = 0; i < xf86_config->num_crtc; i++) {
4459 xf86CrtcPtr crtc = xf86_config->crtc[i];
4460 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4461
4462 ret = dumb_bo_map(drmmode->fd, drmmode_crtc->cursor_bo);
4463 if (ret)
4464 return FALSE;
4465 }
4466 return TRUE;
4467 }
4468
4469 void
drmmode_free_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)4470 drmmode_free_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
4471 {
4472 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4473 int i;
4474
4475 if (drmmode->fb_id) {
4476 drmModeRmFB(drmmode->fd, drmmode->fb_id);
4477 drmmode->fb_id = 0;
4478 }
4479
4480 drmmode_bo_destroy(drmmode, &drmmode->front_bo);
4481
4482 for (i = 0; i < xf86_config->num_crtc; i++) {
4483 xf86CrtcPtr crtc = xf86_config->crtc[i];
4484 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4485
4486 dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor_bo);
4487 drmmode_destroy_flip_fb(crtc);
4488 }
4489 }
4490
4491 /* ugly workaround to see if we can create 32bpp */
4492 void
drmmode_get_default_bpp(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int * depth,int * bpp)4493 drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int *depth,
4494 int *bpp)
4495 {
4496 drmModeResPtr mode_res;
4497 uint64_t value;
4498 struct dumb_bo *bo;
4499 uint32_t fb_id;
4500 int ret;
4501
4502 /* 16 is fine */
4503 ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_PREFERRED_DEPTH, &value);
4504 if (!ret && (value == 16 || value == 8)) {
4505 *depth = value;
4506 *bpp = value;
4507 return;
4508 }
4509
4510 *depth = 24;
4511 mode_res = drmModeGetResources(drmmode->fd);
4512 if (!mode_res)
4513 return;
4514
4515 if (mode_res->min_width == 0)
4516 mode_res->min_width = 1;
4517 if (mode_res->min_height == 0)
4518 mode_res->min_height = 1;
4519 /*create a bo */
4520 bo = dumb_bo_create(drmmode->fd, mode_res->min_width, mode_res->min_height,
4521 32);
4522 if (!bo) {
4523 *bpp = 24;
4524 goto out;
4525 }
4526
4527 ret = drmModeAddFB(drmmode->fd, mode_res->min_width, mode_res->min_height,
4528 24, 32, bo->pitch, bo->handle, &fb_id);
4529
4530 if (ret) {
4531 *bpp = 24;
4532 dumb_bo_destroy(drmmode->fd, bo);
4533 goto out;
4534 }
4535
4536 drmModeRmFB(drmmode->fd, fb_id);
4537 *bpp = 32;
4538
4539 dumb_bo_destroy(drmmode->fd, bo);
4540 out:
4541 drmModeFreeResources(mode_res);
4542 return;
4543 }
4544
4545 /*
4546 * We hook the screen's cursor-sprite (swcursor) functions to see if a swcursor
4547 * is active. When a swcursor is active we disabe page-flipping.
4548 */
4549
drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,ScrnInfoPtr scrn,int x,int y)4550 static void drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,
4551 ScrnInfoPtr scrn, int x, int y)
4552 {
4553 modesettingPtr ms = modesettingPTR(scrn);
4554 CursorPtr cursor = sprite_priv->cursor;
4555 Bool sprite_visible = sprite_priv->sprite_visible;
4556
4557 if (cursor) {
4558 x -= cursor->bits->xhot;
4559 y -= cursor->bits->yhot;
4560
4561 sprite_priv->sprite_visible =
4562 x < scrn->virtualX && y < scrn->virtualY &&
4563 (x + cursor->bits->width > 0) &&
4564 (y + cursor->bits->height > 0);
4565 } else {
4566 sprite_priv->sprite_visible = FALSE;
4567 }
4568
4569 ms->drmmode.sprites_visible += sprite_priv->sprite_visible - sprite_visible;
4570 }
4571
drmmode_sprite_set_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)4572 static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
4573 CursorPtr pCursor, int x, int y)
4574 {
4575 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4576 modesettingPtr ms = modesettingPTR(scrn);
4577 msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
4578
4579 sprite_priv->cursor = pCursor;
4580 drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
4581
4582 ms->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
4583 }
4584
drmmode_sprite_move_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)4585 static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
4586 int x, int y)
4587 {
4588 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4589 modesettingPtr ms = modesettingPTR(scrn);
4590 msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
4591
4592 drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
4593
4594 ms->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
4595 }
4596
drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)4597 static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
4598 ScreenPtr pScreen,
4599 CursorPtr pCursor)
4600 {
4601 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4602 modesettingPtr ms = modesettingPTR(scrn);
4603
4604 return ms->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
4605 }
4606
drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)4607 static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
4608 ScreenPtr pScreen,
4609 CursorPtr pCursor)
4610 {
4611 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4612 modesettingPtr ms = modesettingPTR(scrn);
4613
4614 return ms->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
4615 }
4616
drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,ScreenPtr pScreen)4617 static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
4618 ScreenPtr pScreen)
4619 {
4620 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4621 modesettingPtr ms = modesettingPTR(scrn);
4622
4623 return ms->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
4624 }
4625
drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,ScreenPtr pScreen)4626 static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
4627 ScreenPtr pScreen)
4628 {
4629 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4630 modesettingPtr ms = modesettingPTR(scrn);
4631
4632 ms->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
4633 }
4634
4635 miPointerSpriteFuncRec drmmode_sprite_funcs = {
4636 .RealizeCursor = drmmode_sprite_realize_realize_cursor,
4637 .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
4638 .SetCursor = drmmode_sprite_set_cursor,
4639 .MoveCursor = drmmode_sprite_move_cursor,
4640 .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
4641 .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
4642 };
4643
4644 static void
drmmode_destroy_flip_fb(xf86CrtcPtr crtc)4645 drmmode_destroy_flip_fb(xf86CrtcPtr crtc)
4646 {
4647 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4648 drmmode_ptr drmmode = drmmode_crtc->drmmode;
4649 int i;
4650
4651 for (i = 0; i < ARRAY_SIZE(drmmode_crtc->flip_fb); i++) {
4652 drmmode_fb *fb = &drmmode_crtc->flip_fb[i];
4653
4654 if (fb->fb_id)
4655 drmModeRmFB(drmmode->fd, fb->fb_id);
4656 fb->fb_id = 0;
4657
4658 drmmode_bo_destroy(drmmode, &fb->bo);
4659
4660 if (fb->pixmap)
4661 fb->pixmap->drawable.pScreen->DestroyPixmap(fb->pixmap);
4662 fb->pixmap = NULL;
4663
4664 if (fb->damage)
4665 DamageDestroy(fb->damage);
4666 fb->damage = NULL;
4667 }
4668 }
4669
4670 static Bool
drmmode_create_flip_fb(xf86CrtcPtr crtc)4671 drmmode_create_flip_fb(xf86CrtcPtr crtc)
4672 {
4673 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4674 drmmode_ptr drmmode = drmmode_crtc->drmmode;
4675 int i, width, height, bpp;
4676
4677 width = crtc->mode.HDisplay;
4678 height = crtc->mode.VDisplay;
4679 bpp = drmmode->kbpp;
4680
4681 drmmode_destroy_flip_fb(crtc);
4682
4683 for (i = 0; i < ARRAY_SIZE(drmmode_crtc->flip_fb); i++) {
4684 drmmode_fb *fb = &drmmode_crtc->flip_fb[i];
4685
4686 if (!drmmode_create_bo(drmmode, &fb->bo, width, height, bpp))
4687 goto fail;
4688
4689 if (drmmode_bo_import(drmmode, &fb->bo, &fb->fb_id) < 0)
4690 goto fail;
4691 }
4692
4693 return TRUE;
4694
4695 fail:
4696 drmmode_destroy_flip_fb(crtc);
4697 return FALSE;
4698 }
4699
4700 static Bool
drmmode_apply_transform(xf86CrtcPtr crtc)4701 drmmode_apply_transform(xf86CrtcPtr crtc)
4702 {
4703 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4704 drmmode_ptr drmmode = drmmode_crtc->drmmode;
4705 BoxRec box = {
4706 .x1 = 0,
4707 .y1 = 0,
4708 .x2 = crtc->mode.HDisplay,
4709 .y2 = crtc->mode.VDisplay,
4710 };
4711 int w, h;
4712
4713 /* should always success */
4714 xf86CrtcRotate(crtc);
4715
4716 pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
4717 w = box.x2 - box.x1;
4718 h = box.y2 - box.y1;
4719
4720 if ((w == crtc->mode.HDisplay && h == crtc->mode.VDisplay) ||
4721 (w == crtc->mode.VDisplay && h == crtc->mode.HDisplay))
4722 drmmode_crtc->is_scale = FALSE;
4723 else
4724 drmmode_crtc->is_scale = TRUE;
4725
4726 /* fb flipping disabled or doing shared pixmap flipping */
4727 if (!drmmode_crtc->can_flip_fb || drmmode_crtc->enable_flipping)
4728 goto bail;
4729
4730 crtc->driverIsPerformingTransform |= XF86DriverTransformOutput;
4731
4732 /* should always success */
4733 xf86CrtcRotate(crtc);
4734
4735 if (!crtc->transform_in_use) {
4736 crtc->driverIsPerformingTransform &= ~XF86DriverTransformOutput;
4737
4738 if (drmmode->fb_flip_mode == DRMMODE_FB_FLIP_TRANSFORMED)
4739 goto bail;
4740 }
4741
4742 if (!drmmode_create_flip_fb(crtc)) {
4743 drmmode_crtc->can_flip_fb = FALSE;
4744 goto fail;
4745 }
4746
4747 drmmode_crtc->flip_fb_enabled = TRUE;
4748
4749 return TRUE;
4750
4751 fail:
4752 drmmode_crtc->can_flip_fb = FALSE;
4753
4754 bail:
4755 drmmode_destroy_flip_fb(crtc);
4756 drmmode_crtc->flip_fb_enabled = FALSE;
4757
4758 crtc->driverIsPerformingTransform &= ~XF86DriverTransformOutput;
4759 return xf86CrtcRotate(crtc);
4760 }
4761
4762 static void
drmmode_flip_damage_destroy(DamagePtr damage,void * closure)4763 drmmode_flip_damage_destroy(DamagePtr damage, void *closure)
4764 {
4765 drmmode_fb *fb = closure;
4766
4767 if (fb->pixmap)
4768 fb->pixmap->drawable.pScreen->DestroyPixmap(fb->pixmap);
4769 fb->pixmap = NULL;
4770
4771 fb->damage = NULL;
4772 }
4773
4774 static RegionPtr
drmmode_transform_region(xf86CrtcPtr crtc,RegionPtr src)4775 drmmode_transform_region(xf86CrtcPtr crtc, RegionPtr src)
4776 {
4777 #define MS_MAX_NUM_BOX 4
4778 RegionPtr region = RegionCreate(NULL, 0);
4779 BoxRec rects[MS_MAX_NUM_BOX];
4780 BoxPtr box, rect;
4781 Bool empty;
4782 int n, i;
4783
4784 if (!RegionNotEmpty(src))
4785 return region;
4786
4787 if (RegionNumRects(src) < MS_MAX_NUM_BOX) {
4788 n = RegionNumRects(src);
4789 box = RegionRects(src);
4790 } else {
4791 /* draw the extents rather than small rects */
4792 n = 1;
4793 box = RegionExtents(src);
4794 }
4795
4796 empty = TRUE;
4797 for (i = 0; i < n; i++) {
4798 rect = &rects[i];
4799
4800 rect->x1 = box[i].x1 - crtc->filter_width / 2;
4801 rect->x2 = box[i].x2 + crtc->filter_width / 2;
4802 rect->y1 = box[i].y1 - crtc->filter_height / 2;
4803 rect->y2 = box[i].y2 + crtc->filter_height / 2;
4804 pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, rect);
4805 rect->x1 = max(rect->x1, 0);
4806 rect->y1 = max(rect->y1, 0);
4807 rect->x2 = min(rect->x2, crtc->mode.HDisplay);
4808 rect->y2 = min(rect->y2, crtc->mode.VDisplay);
4809
4810 if (rect->x1 < rect->x2 && rect->y1 < rect->y2)
4811 empty = FALSE;
4812 }
4813
4814 if (empty)
4815 return region;
4816
4817 RegionInitBoxes(region, rects, n);
4818 return region;
4819 }
4820
4821 Bool
ms_copy_area(PixmapPtr pSrc,PixmapPtr pDst,pixman_f_transform_t * transform,RegionPtr clip)4822 ms_copy_area(PixmapPtr pSrc, PixmapPtr pDst,
4823 pixman_f_transform_t *transform, RegionPtr clip)
4824 {
4825 ScreenPtr screen = pSrc->drawable.pScreen;
4826 PictFormatPtr format = PictureWindowFormat(screen->root);
4827 PicturePtr src = NULL, dst = NULL;
4828 pixman_transform_t t;
4829 Bool ret = FALSE;
4830 BoxPtr box;
4831 int n, error;
4832
4833 src = CreatePicture(None, &pSrc->drawable,
4834 format, 0L, NULL, serverClient, &error);
4835 if (!src)
4836 return FALSE;
4837
4838 dst = CreatePicture(None, &pDst->drawable,
4839 format, 0L, NULL, serverClient, &error);
4840 if (!dst)
4841 goto out;
4842
4843 if (transform) {
4844 if (!pixman_transform_from_pixman_f_transform(&t, transform))
4845 goto out;
4846
4847 error = SetPictureTransform(src, &t);
4848 if (error)
4849 goto out;
4850 }
4851
4852 box = REGION_RECTS(clip);
4853 n = REGION_NUM_RECTS(clip);
4854
4855 while (n--) {
4856 CompositePicture(PictOpSrc,
4857 src, NULL, dst,
4858 box->x1, box->y1, 0, 0, box->x1,
4859 box->y1, box->x2 - box->x1,
4860 box->y2 - box->y1);
4861
4862 box++;
4863 }
4864
4865 ret = TRUE;
4866 out:
4867 if (src)
4868 FreePicture(src, None);
4869 if (dst)
4870 FreePicture(dst, None);
4871
4872 return ret;
4873 }
4874
4875 static Bool
drmmode_update_fb(xf86CrtcPtr crtc,drmmode_fb * fb)4876 drmmode_update_fb(xf86CrtcPtr crtc, drmmode_fb *fb)
4877 {
4878 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4879 ScrnInfoPtr scrn = crtc->scrn;
4880 modesettingPtr ms = modesettingPTR(scrn);
4881 drmmode_ptr drmmode = &ms->drmmode;
4882 ScreenPtr screen = xf86ScrnToScreen(scrn);
4883 SourceValidateProcPtr SourceValidate = screen->SourceValidate;
4884 RegionPtr dirty;
4885 Bool ret;
4886
4887 if (!fb->pixmap) {
4888 void *data = drmmode_bo_map(&ms->drmmode, &fb->bo);
4889 int pitch = drmmode_bo_get_pitch(&fb->bo);
4890 fb->pixmap = drmmode_create_pixmap_header(screen,
4891 fb->bo.width,
4892 fb->bo.height,
4893 scrn->depth,
4894 ms->drmmode.kbpp,
4895 pitch, data);
4896 if (!fb->pixmap)
4897 return FALSE;
4898
4899 if (!drmmode_set_pixmap_bo(&ms->drmmode, fb->pixmap, &fb->bo))
4900 return FALSE;
4901
4902 /* setup a damage to track dirty */
4903 fb->damage = DamageCreate(NULL, drmmode_flip_damage_destroy,
4904 DamageReportNone, TRUE, screen, fb);
4905 DamageRegister(&screen->root->drawable, fb->damage);
4906
4907 fb->need_clear = TRUE;
4908 }
4909
4910 /* scaled screens may not be able to map areas(due to precision) */
4911 if (drmmode_crtc->is_scale && drmmode->exa)
4912 fb->need_clear = TRUE;
4913
4914 dirty = NULL;
4915 if (fb->need_clear) {
4916 BoxRec rect = {
4917 .x1 = 0,
4918 .y1 = 0,
4919 .x2 = crtc->mode.HDisplay,
4920 .y2 = crtc->mode.VDisplay,
4921 };
4922
4923 dirty = RegionCreate(&rect, 1);
4924 } else {
4925 RegionPtr region = DamageRegion(fb->damage);
4926
4927 dirty = drmmode_transform_region(crtc, region);
4928 }
4929
4930 if (!RegionNotEmpty(dirty)) {
4931 ret = TRUE;
4932 goto out;
4933 }
4934
4935 screen->SourceValidate = miSourceValidate;
4936 if (drmmode->exa)
4937 ret = ms_exa_copy_area(screen->GetScreenPixmap(screen), fb->pixmap,
4938 &crtc->f_crtc_to_framebuffer, dirty);
4939 else
4940 ret = ms_copy_area(screen->GetScreenPixmap(screen), fb->pixmap,
4941 &crtc->f_crtc_to_framebuffer, dirty);
4942 screen->SourceValidate = SourceValidate;
4943
4944 #ifdef GLAMOR_HAS_GBM
4945 if (ms->drmmode.glamor)
4946 glamor_finish(screen);
4947 #endif
4948
4949 fb->need_clear = FALSE;
4950 DamageEmpty(fb->damage);
4951
4952 ret = TRUE;
4953 out:
4954 RegionDestroy(dirty);
4955 return ret;
4956 }
4957
4958 static void
drmmode_flip_fb_handler(modesettingPtr ms,uint64_t msc,uint64_t ust,void * data)4959 drmmode_flip_fb_handler(modesettingPtr ms, uint64_t msc,
4960 uint64_t ust, void *data)
4961 {
4962 drmmode_crtc_private_ptr drmmode_crtc = data;
4963
4964 drmmode_crtc->flipping = FALSE;
4965 }
4966
4967 static void
drmmode_flip_fb_abort(modesettingPtr ms,void * data)4968 drmmode_flip_fb_abort(modesettingPtr ms, void *data)
4969 {
4970 drmmode_crtc_private_ptr drmmode_crtc = data;
4971
4972 drmmode_crtc->flipping = FALSE;
4973 }
4974
4975 Bool
drmmode_flip_fb(xf86CrtcPtr crtc,int * timeout)4976 drmmode_flip_fb(xf86CrtcPtr crtc, int *timeout)
4977 {
4978 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4979 drmmode_ptr drmmode = drmmode_crtc->drmmode;
4980 ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn);
4981 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
4982 modesettingPtr ms = modesettingPTR(scrn);
4983 drmmode_fb *fb;
4984 struct timeval tv;
4985 uint64_t now_ms, diff_ms;
4986 int next_fb;
4987
4988 if (!drmmode_crtc || !crtc->active || !drmmode_crtc_connected(crtc) ||
4989 drmmode_crtc->dpms_mode != DPMSModeOn || drmmode_crtc->rotate_fb_id)
4990 return TRUE;
4991
4992 if (!drmmode_crtc->flip_fb_enabled)
4993 return TRUE;
4994
4995 gettimeofday(&tv, NULL);
4996 now_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
4997
4998 diff_ms = now_ms - drmmode_crtc->flipping_time_ms;
4999
5000 /* handle flip timeout */
5001 if (drmmode_crtc->flipping && diff_ms >= 50) {
5002 xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
5003 "crtc-%d flip timeout!\n", drmmode_crtc->mode_crtc->crtc_id);
5004 drmmode_crtc->flipping = FALSE;
5005 }
5006
5007 /* retry later if still flipping */
5008 if (drmmode_crtc->flipping ||
5009 drmmode->dri2_flipping || drmmode->present_flipping)
5010 goto retry;
5011
5012 if (drmmode_crtc->external_flipped) {
5013 /* delay to exit external flip mode */
5014 if (diff_ms < 100)
5015 goto retry;
5016 } else if (drmmode->fb_flip_rate) {
5017 /* limit flip rate */
5018 if (diff_ms < (1000 / drmmode->fb_flip_rate))
5019 goto retry;
5020 }
5021
5022 /* keep the current fb if not dirty */
5023 fb = &drmmode_crtc->flip_fb[drmmode_crtc->current_fb];
5024 if (fb->damage && !fb->need_clear) {
5025 RegionPtr region = DamageRegion(fb->damage);
5026 RegionPtr dirty;
5027 Bool ret;
5028
5029 dirty = drmmode_transform_region(crtc, region);
5030 if (dirty) {
5031 ret = RegionNotEmpty(dirty);
5032 RegionDestroy(dirty);
5033 if (!ret)
5034 return TRUE;
5035 }
5036 }
5037
5038 /* switch to the next fb */
5039 next_fb = drmmode_crtc->current_fb + 1;
5040 next_fb %= ARRAY_SIZE(drmmode_crtc->flip_fb);
5041 fb = &drmmode_crtc->flip_fb[next_fb];
5042 if (!drmmode_update_fb(crtc, fb)) {
5043 xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
5044 "crtc-%d failed to update fb!\n",
5045 drmmode_crtc->mode_crtc->crtc_id);
5046 return FALSE;
5047 }
5048
5049 if (!ms_do_pageflip_bo(screen, &fb->bo, drmmode_crtc,
5050 drmmode_crtc->vblank_pipe, crtc, ms->async_pageflip,
5051 drmmode_flip_fb_handler, drmmode_flip_fb_abort)) {
5052 /* HACK: Workaround commit random interrupted case */
5053 if (errno != EPERM) {
5054 xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
5055 "crtc-%d failed to flip(%s)!\n",
5056 drmmode_crtc->mode_crtc->crtc_id, strerror(errno));
5057 return FALSE;
5058 }
5059 }
5060
5061 drmmode_crtc->current_fb = next_fb;
5062
5063 drmmode_crtc->flipping = TRUE;
5064 drmmode_crtc->external_flipped = FALSE;
5065
5066 /* take out FB syncing time from framerate control */
5067 drmmode_crtc->flipping_time_ms = now_ms;
5068
5069 return TRUE;
5070
5071 retry:
5072 if (*timeout)
5073 *timeout = 3;
5074 return TRUE;
5075 }
5076