1 #include "ecore_drm2_private.h"
2
3 #define FLIP_TIMEOUT 1.0
4
5 static Eina_Bool
_fb2_create(Ecore_Drm2_Fb * fb)6 _fb2_create(Ecore_Drm2_Fb *fb)
7 {
8 uint32_t offsets[4] = { 0 };
9 int r;
10
11 r = sym_drmModeAddFB2(fb->fd, fb->w, fb->h, fb->format, fb->handles,
12 fb->strides, offsets, &fb->id, 0);
13
14 if (r)
15 return EINA_FALSE;
16
17 return EINA_TRUE;
18 }
19
20 EAPI Ecore_Drm2_Fb *
ecore_drm2_fb_create(Ecore_Drm2_Device * dev,int width,int height,int depth,int bpp,unsigned int format)21 ecore_drm2_fb_create(Ecore_Drm2_Device *dev, int width, int height, int depth, int bpp, unsigned int format)
22 {
23 Ecore_Drm2_Fb *fb;
24 struct drm_mode_create_dumb carg;
25 struct drm_mode_destroy_dumb darg;
26 struct drm_mode_map_dumb marg;
27 int ret;
28
29 EINA_SAFETY_ON_NULL_RETURN_VAL(dev, NULL);
30
31 fb = calloc(1, sizeof(Ecore_Drm2_Fb));
32 if (!fb) return NULL;
33
34 fb->fd = dev->fd;
35 fb->w = width;
36 fb->h = height;
37 fb->bpp = bpp;
38 fb->depth = depth;
39 fb->format = format;
40 fb->ref = 1;
41
42 memset(&carg, 0, sizeof(struct drm_mode_create_dumb));
43 carg.bpp = bpp;
44 carg.width = width;
45 carg.height = height;
46
47 ret = sym_drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg);
48 if (ret) goto err;
49
50 fb->handles[0] = carg.handle;
51 fb->sizes[0] = carg.size;
52 fb->strides[0] = carg.pitch;
53
54 if (!_fb2_create(fb))
55 {
56 ret =
57 sym_drmModeAddFB(dev->fd, width, height, depth, bpp,
58 fb->strides[0], fb->handles[0], &fb->id);
59 if (ret)
60 {
61 ERR("Could not add framebuffer: %m");
62 goto add_err;
63 }
64 }
65
66 memset(&marg, 0, sizeof(struct drm_mode_map_dumb));
67 marg.handle = fb->handles[0];
68 ret = sym_drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &marg);
69 if (ret)
70 {
71 ERR("Could not map framebuffer: %m");
72 goto map_err;
73 }
74
75 fb->mmap = mmap(NULL, fb->sizes[0], PROT_WRITE, MAP_SHARED, dev->fd, marg.offset);
76 if (fb->mmap == MAP_FAILED)
77 {
78 ERR("Could not mmap framebuffer memory: %m");
79 goto map_err;
80 }
81
82 return fb;
83
84 map_err:
85 sym_drmModeRmFB(dev->fd, fb->id);
86 add_err:
87 memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
88 darg.handle = fb->handles[0];
89 sym_drmIoctl(dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
90 err:
91 free(fb);
92 return NULL;
93 }
94
95 EAPI Ecore_Drm2_Fb *
ecore_drm2_fb_gbm_create(Ecore_Drm2_Device * dev,int width,int height,int depth,int bpp,unsigned int format,unsigned int handle,unsigned int stride,void * bo)96 ecore_drm2_fb_gbm_create(Ecore_Drm2_Device *dev, int width, int height, int depth, int bpp, unsigned int format, unsigned int handle, unsigned int stride, void *bo)
97 {
98 Ecore_Drm2_Fb *fb;
99
100 EINA_SAFETY_ON_NULL_RETURN_VAL(dev, NULL);
101
102 fb = calloc(1, sizeof(Ecore_Drm2_Fb));
103 if (!fb) return NULL;
104
105 fb->gbm = EINA_TRUE;
106 fb->gbm_bo = bo;
107
108 fb->fd = dev->fd;
109 fb->w = width;
110 fb->h = height;
111 fb->bpp = bpp;
112 fb->depth = depth;
113 fb->format = format;
114 fb->strides[0] = stride;
115 fb->sizes[0] = fb->strides[0] * fb->h;
116 fb->handles[0] = handle;
117 fb->ref = 1;
118
119 if (!_fb2_create(fb))
120 {
121 if (sym_drmModeAddFB(dev->fd, width, height, depth, bpp,
122 fb->strides[0], fb->handles[0], &fb->id))
123 {
124 ERR("Could not add framebuffer: %m");
125 goto err;
126 }
127 }
128 return fb;
129
130 err:
131 free(fb);
132 return NULL;
133 }
134
135 static void
_ecore_drm2_fb_destroy(Ecore_Drm2_Fb * fb)136 _ecore_drm2_fb_destroy(Ecore_Drm2_Fb *fb)
137 {
138 EINA_SAFETY_ON_NULL_RETURN(fb);
139
140 if (!fb->dead) WRN("Destroying an fb that hasn't been discarded");
141
142 if (fb->scanout_count)
143 WRN("Destroyed fb on scanout %d times.", fb->scanout_count);
144
145 if (fb->mmap) munmap(fb->mmap, fb->sizes[0]);
146
147 if (fb->id) sym_drmModeRmFB(fb->fd, fb->id);
148
149 if (!fb->gbm && !fb->dmabuf)
150 {
151 struct drm_mode_destroy_dumb darg;
152
153 memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
154 darg.handle = fb->handles[0];
155 sym_drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
156 }
157
158 free(fb);
159 }
160
161 void
_ecore_drm2_fb_ref(Ecore_Drm2_Fb * fb)162 _ecore_drm2_fb_ref(Ecore_Drm2_Fb *fb)
163 {
164 fb->ref++;
165 }
166
167 void
_ecore_drm2_fb_deref(Ecore_Drm2_Fb * fb)168 _ecore_drm2_fb_deref(Ecore_Drm2_Fb *fb)
169 {
170 fb->ref--;
171 if (fb->ref) return;
172
173 if (fb->status_handler)
174 fb->status_handler(fb, ECORE_DRM2_FB_STATUS_DELETED, fb->status_data);
175
176 _ecore_drm2_fb_destroy(fb);
177 }
178
179 EAPI void
ecore_drm2_fb_discard(Ecore_Drm2_Fb * fb)180 ecore_drm2_fb_discard(Ecore_Drm2_Fb *fb)
181 {
182 EINA_SAFETY_ON_NULL_RETURN(fb);
183 EINA_SAFETY_ON_TRUE_RETURN(fb->ref < 1);
184
185 fb->dead = EINA_TRUE;
186 _ecore_drm2_fb_deref(fb);
187 }
188
189 EAPI void *
ecore_drm2_fb_data_get(Ecore_Drm2_Fb * fb)190 ecore_drm2_fb_data_get(Ecore_Drm2_Fb *fb)
191 {
192 EINA_SAFETY_ON_NULL_RETURN_VAL(fb, NULL);
193 EINA_SAFETY_ON_TRUE_RETURN_VAL(fb->dead, NULL);
194 return fb->mmap;
195 }
196
197 EAPI unsigned int
ecore_drm2_fb_size_get(Ecore_Drm2_Fb * fb)198 ecore_drm2_fb_size_get(Ecore_Drm2_Fb *fb)
199 {
200 EINA_SAFETY_ON_NULL_RETURN_VAL(fb, 0);
201 EINA_SAFETY_ON_TRUE_RETURN_VAL(fb->dead, 0);
202 return fb->sizes[0];
203 }
204
205 EAPI unsigned int
ecore_drm2_fb_stride_get(Ecore_Drm2_Fb * fb)206 ecore_drm2_fb_stride_get(Ecore_Drm2_Fb *fb)
207 {
208 EINA_SAFETY_ON_NULL_RETURN_VAL(fb, 0);
209 EINA_SAFETY_ON_TRUE_RETURN_VAL(fb->dead, 0);
210
211 return fb->strides[0];
212 }
213
214 EAPI void
ecore_drm2_fb_dirty(Ecore_Drm2_Fb * fb,Eina_Rectangle * rects,unsigned int count)215 ecore_drm2_fb_dirty(Ecore_Drm2_Fb *fb, Eina_Rectangle *rects, unsigned int count)
216 {
217 EINA_SAFETY_ON_NULL_RETURN(fb);
218 EINA_SAFETY_ON_NULL_RETURN(rects);
219 EINA_SAFETY_ON_TRUE_RETURN(fb->dead);
220
221 #ifdef DRM_MODE_FEATURE_DIRTYFB
222 drmModeClip *clip;
223 unsigned int i = 0;
224 int ret;
225
226 clip = alloca(count * sizeof(drmModeClip));
227 for (i = 0; i < count; i++)
228 {
229 clip[i].x1 = rects[i].x;
230 clip[i].y1 = rects[i].y;
231 clip[i].x2 = rects[i].w;
232 clip[i].y2 = rects[i].h;
233 }
234
235 ret = sym_drmModeDirtyFB(fb->fd, fb->id, clip, count);
236 if ((ret) && (ret == -EINVAL))
237 WRN("Could not mark framebuffer as dirty: %m");
238 #endif
239 }
240
241 /* perhaps output is no longer a necessary parameter for this function */
242 void
_ecore_drm2_fb_buffer_release(Ecore_Drm2_Output * output EINA_UNUSED,Ecore_Drm2_Output_State * s)243 _ecore_drm2_fb_buffer_release(Ecore_Drm2_Output *output EINA_UNUSED, Ecore_Drm2_Output_State *s)
244 {
245 Ecore_Drm2_Fb *fb = s->fb;
246
247 if (fb->status_handler)
248 fb->status_handler(fb, ECORE_DRM2_FB_STATUS_RELEASE, fb->status_data);
249
250 _ecore_drm2_fb_deref(fb);
251 s->fb = NULL;
252 if (_ecore_drm2_use_atomic)
253 {
254 if (s->atomic_req)
255 sym_drmModeAtomicFree(s->atomic_req);
256 s->atomic_req = NULL;
257 }
258 }
259
260 static void
_cb_mainloop_async_timer_del(void * data)261 _cb_mainloop_async_timer_del(void *data)
262 {
263 Ecore_Drm2_Output *output = data;
264
265 ecore_timer_del(output->flip_timeout);
266 output->flip_timeout = NULL;
267 }
268
269 EAPI Eina_Bool
ecore_drm2_fb_flip_complete(Ecore_Drm2_Output * output)270 ecore_drm2_fb_flip_complete(Ecore_Drm2_Output *output)
271 {
272 Eina_Bool plane_scanout;
273 Ecore_Drm2_Fb *fb;
274
275 EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
276
277 if (output->flip_timeout)
278 {
279 // XXX: output ref++
280 ecore_main_loop_thread_safe_call_async
281 (_cb_mainloop_async_timer_del, output);
282 }
283 if (!output->pending.fb) fprintf(stderr, "XXX--XXX eeeeek pending fb is NULL so current would become null ----------------------------------\n");
284 if (output->current.fb && (output->current.fb != output->pending.fb))
285 _ecore_drm2_fb_buffer_release(output, &output->current);
286
287 output->current.fb = output->pending.fb;
288 output->pending.fb = NULL;
289
290 if (_ecore_drm2_use_atomic)
291 {
292 Eina_List *l, *ll;
293 Ecore_Drm2_Plane *plane;
294
295 output->current.atomic_req = output->pending.atomic_req;
296 output->pending.atomic_req = NULL;
297
298 EINA_LIST_FOREACH_SAFE(output->planes, l, ll, plane)
299 {
300 fb = plane->fb;
301 plane_scanout = plane->scanout;
302 if (!plane->dead)
303 {
304 /* First time this plane is scanned out */
305 if (!plane->scanout)
306 fb->scanout_count++;
307
308 plane->scanout = EINA_TRUE;
309 if (fb->status_handler && (fb->scanout_count == 1) &&
310 (plane_scanout != plane->scanout))
311 fb->status_handler(fb, ECORE_DRM2_FB_STATUS_SCANOUT_ON,
312 fb->status_data);
313 continue;
314 }
315 output->planes = eina_list_remove_list(output->planes, l);
316 free(plane);
317 if (!plane_scanout) continue;
318
319 fb->scanout_count--;
320 if (fb->status_handler && (fb->scanout_count == 0))
321 fb->status_handler(fb, ECORE_DRM2_FB_STATUS_SCANOUT_OFF,
322 fb->status_data);
323 }
324 }
325
326 EINA_LIST_FREE(output->fbs, fb)
327 _ecore_drm2_fb_deref(fb);
328 output->fbs = NULL;
329
330 return !!output->next.fb;
331 }
332
333 Eina_Bool
_fb_atomic_flip_test(Ecore_Drm2_Output * output)334 _fb_atomic_flip_test(Ecore_Drm2_Output *output)
335 {
336 int ret = 0;
337 Eina_List *l;
338 Ecore_Drm2_Crtc_State *cstate;
339 Ecore_Drm2_Plane_State *pstate;
340 Ecore_Drm2_Plane *plane;
341 drmModeAtomicReq *req = NULL;
342 uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_ATOMIC_ALLOW_MODESET |
343 DRM_MODE_ATOMIC_TEST_ONLY;
344
345 if (!_ecore_drm2_use_atomic) return EINA_FALSE;
346
347 req = sym_drmModeAtomicAlloc();
348 if (!req) return EINA_FALSE;
349
350 sym_drmModeAtomicSetCursor(req, 0);
351
352 cstate = output->crtc_state;
353
354 ret =
355 sym_drmModeAtomicAddProperty(req, cstate->obj_id, cstate->mode.id,
356 cstate->mode.value);
357 if (ret < 0) goto err;
358
359 ret =
360 sym_drmModeAtomicAddProperty(req, cstate->obj_id, cstate->active.id,
361 cstate->active.value);
362 if (ret < 0) goto err;
363
364 if (cstate->background.id)
365 {
366 ret =
367 sym_drmModeAtomicAddProperty(req, cstate->obj_id,
368 cstate->background.id,
369 cstate->background.value);
370 if (ret < 0) goto err;
371 }
372
373 EINA_LIST_FOREACH(output->planes, l, plane)
374 {
375 pstate = plane->state;
376
377 if (!pstate->in_use)
378 {
379 pstate->cid.value = 0;
380 pstate->fid.value = 0;
381 pstate->sw.value = 0;
382 pstate->sh.value = 0;
383 pstate->cx.value = 0;
384 pstate->cy.value = 0;
385 pstate->cw.value = 0;
386 pstate->ch.value = 0;
387 }
388
389 ret =
390 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
391 pstate->cid.id, pstate->cid.value);
392 if (ret < 0) goto err;
393
394 ret =
395 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
396 pstate->fid.id, pstate->fid.value);
397 if (ret < 0) goto err;
398
399 ret =
400 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
401 pstate->sx.id, pstate->sx.value);
402 if (ret < 0) goto err;
403
404 ret =
405 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
406 pstate->sy.id, pstate->sy.value);
407 if (ret < 0) goto err;
408
409 ret =
410 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
411 pstate->sw.id, pstate->sw.value);
412 if (ret < 0) goto err;
413
414 ret =
415 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
416 pstate->sh.id, pstate->sh.value);
417 if (ret < 0) goto err;
418
419 ret =
420 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
421 pstate->cx.id, pstate->cx.value);
422 if (ret < 0) goto err;
423
424 ret =
425 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
426 pstate->cy.id, pstate->cy.value);
427 if (ret < 0) goto err;
428
429 ret =
430 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
431 pstate->cw.id, pstate->cw.value);
432 if (ret < 0) goto err;
433
434 ret =
435 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
436 pstate->ch.id, pstate->ch.value);
437 if (ret < 0) goto err;
438
439 #if 0
440 /* XXX: Disable hardware plane rotation for now as this has broken
441 * recently. The break happens because of an invalid argument,
442 * ie: the value being sent from pstate->rotation_map ends up being
443 * incorrect for some reason. I suspect the breakage to be from
444 * kernel drivers (linux 4.20.0) but have not confirmed that version */
445 if ((pstate->rotation.id) &&
446 (pstate->type.value == DRM_PLANE_TYPE_PRIMARY))
447 {
448 DBG("Plane %d Atomic Rotation: %lu",
449 pstate->obj_id, pstate->rotation.value);
450 ret =
451 sym_drmModeAtomicAddProperty(req, pstate->obj_id,
452 pstate->rotation.id,
453 pstate->rotation_map[pstate->rotation.value]);
454 if (ret < 0) goto err;
455 }
456 #endif
457 }
458
459 ret =
460 sym_drmModeAtomicCommit(output->fd, req, flags, output);
461 if (ret < 0) goto err;
462
463 /* clear any previous request */
464 if (output->prep.atomic_req)
465 sym_drmModeAtomicFree(output->prep.atomic_req);
466
467 output->prep.atomic_req = req;
468 return EINA_TRUE;
469
470 err:
471 DBG("Failed Atomic Test: %m");
472 sym_drmModeAtomicFree(req);
473
474 return EINA_FALSE;
475 }
476
477 static int _fb_atomic_flip(Ecore_Drm2_Output *output);
478 static int _fb_flip(Ecore_Drm2_Output *output);
479
480 static Eina_Bool
_cb_flip_timeout(void * data)481 _cb_flip_timeout(void *data)
482 {
483 Ecore_Drm2_Output *output = data;
484
485 output->flip_timeout = NULL;
486 ERR("flip event callback timout %0.2fsec - try again", FLIP_TIMEOUT);
487 if (_ecore_drm2_use_atomic) _fb_atomic_flip(output);
488 else _fb_flip(output);
489 return EINA_FALSE;
490 }
491
492 static void
_cb_mainloop_async_timer_reset(void * data)493 _cb_mainloop_async_timer_reset(void *data)
494 {
495 Ecore_Drm2_Output *output = data;
496 if (output->flip_timeout) ecore_timer_del(output->flip_timeout);
497 output->flip_timeout = ecore_timer_add(FLIP_TIMEOUT, _cb_flip_timeout, output);
498 }
499
500 static int
_fb_atomic_flip(Ecore_Drm2_Output * output)501 _fb_atomic_flip(Ecore_Drm2_Output *output)
502 {
503 int res = 0;
504 uint32_t flags =
505 DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT |
506 DRM_MODE_ATOMIC_ALLOW_MODESET;
507
508 if (!_ecore_drm2_use_atomic) return -1;
509
510 /* If we have no req yet, we're flipping to current state.
511 * rebuild the current state in the prep state */
512 if (!output->prep.atomic_req) _fb_atomic_flip_test(output);
513
514 /* Still no req is a bad situation */
515 EINA_SAFETY_ON_NULL_RETURN_VAL(output->prep.atomic_req, -1);
516
517 // sometimes we get a EBUSY ... so try again a few times.
518 int i;
519 for (i = 0; i < 10; i++)
520 {
521 res =
522 sym_drmModeAtomicCommit(output->fd, output->prep.atomic_req, flags,
523 output);
524 if (res == 0) break;
525 else ERR("DRM atomic commit failed - retry #%i", i + 1);
526 usleep(100);
527 }
528
529 if (res < 0)
530 {
531 ERR("Failed Atomic Commit: %m");
532 return -1;
533 }
534 else
535 {
536 // XXX: output ref++
537 ecore_main_loop_thread_safe_call_async
538 (_cb_mainloop_async_timer_reset, output);
539 }
540
541 return 0;
542 }
543
544 static int
_fb_flip(Ecore_Drm2_Output * output)545 _fb_flip(Ecore_Drm2_Output *output)
546 {
547 Ecore_Drm2_Fb *fb;
548 Eina_Bool repeat;
549 int count = 0;
550 int ret = 0;
551
552 fb = output->prep.fb;
553 if (!fb)
554 {
555 fb = output->pending.fb;
556 ERR("Trying to flip NULL fb - fallback to pending fb");
557 }
558 if (!fb)
559 {
560 ERR("Pending fb is also NULL, give up flipping");
561 return ret;
562 }
563
564 if ((!output->current.fb) ||
565 (output->current.fb->strides[0] != fb->strides[0]))
566 {
567 ret =
568 sym_drmModeSetCrtc(fb->fd, output->crtc_id, fb->id,
569 0, 0, &output->conn_id, 1,
570 &output->current_mode->info);
571 if (ret)
572 {
573 ERR("Failed to set Mode %dx%d for Output %s: %m",
574 output->current_mode->width, output->current_mode->height,
575 output->name);
576 return ret;
577 }
578
579 if (output->current.fb)
580 _ecore_drm2_fb_buffer_release(output, &output->current);
581 output->current.fb = fb;
582 _ecore_drm2_fb_ref(output->current.fb);
583 output->next.fb = NULL;
584 /* We used to return here, but now that the ticker is fixed this
585 * can leave us hanging waiting for a tick to happen forever.
586 * Instead, we now fall through to the flip path to make sure
587 * even this first set can cause a flip callback.
588 */
589 }
590
591 do
592 {
593 static Eina_Bool bugged_about_bug = EINA_FALSE;
594 repeat = EINA_FALSE;
595 ret = sym_drmModePageFlip(fb->fd, output->crtc_id, fb->id,
596 DRM_MODE_PAGE_FLIP_EVENT, output);
597 /* Some drivers (RPI - looking at you) are broken and produce
598 * flip events before they are ready for another flip, so be
599 * a little robust in the face of badness and try a few times
600 * until we can flip or we give up (100 tries with a yield
601 * between each try). We can't expect everyone to run the
602 * latest bleeding edge kernel IF a workaround is possible
603 * in userspace, so do this.
604 * We only report this as an ERR once since if it will
605 * generate a huge amount of spam otherwise. */
606 if ((ret < 0) && (errno == EBUSY))
607 {
608 repeat = EINA_TRUE;
609 if (count == 0 && !bugged_about_bug)
610 {
611 ERR("Pageflip fail - EBUSY from drmModePageFlip - "
612 "This is either a kernel bug or an EFL one.");
613 bugged_about_bug = EINA_TRUE;
614 }
615 count++;
616 if (count > 500)
617 {
618 ERR("Pageflip EBUSY for %i tries - give up", count);
619 break;
620 }
621 usleep(100);
622 }
623 else
624 {
625 // XXX: output ref++
626 ecore_main_loop_thread_safe_call_async
627 (_cb_mainloop_async_timer_reset, output);
628 }
629 }
630 while (repeat);
631
632 if ((ret == 0) && (count > 0))
633 DBG("Pageflip finally succeeded after %i tries due to EBUSY", count);
634
635 if ((ret < 0) && (errno != EBUSY))
636 {
637 ERR("Pageflip Failed for Crtc %u on Connector %u: %m",
638 output->crtc_id, output->conn_id);
639 return ret;
640 }
641 else if (ret < 0)
642 {
643 output->next.fb = fb;
644 _ecore_drm2_fb_ref(output->next.fb);
645 }
646
647 return 0;
648 }
649
650 EAPI int
ecore_drm2_fb_flip(Ecore_Drm2_Fb * fb,Ecore_Drm2_Output * output)651 ecore_drm2_fb_flip(Ecore_Drm2_Fb *fb, Ecore_Drm2_Output *output)
652 {
653 int ret = -1;
654
655 EINA_SAFETY_ON_NULL_RETURN_VAL(output, -1);
656 EINA_SAFETY_ON_NULL_RETURN_VAL(output->current_mode, -1);
657
658 if (!output->enabled) return -1;
659
660 if (fb) _ecore_drm2_fb_ref(fb);
661
662 if (output->pending.fb)
663 {
664 if (output->next.fb)
665 _ecore_drm2_fb_buffer_release(output, &output->next);
666 output->next.fb = fb;
667 return 0;
668 }
669 if (!fb)
670 {
671 fb = output->next.fb;
672 output->next.fb = NULL;
673 }
674
675 /* So we can generate a tick by flipping to the current fb */
676 if (!fb) fb = output->current.fb;
677
678 if (output->next.fb)
679 _ecore_drm2_fb_buffer_release(output, &output->next);
680
681 /* If we don't have an fb to set by now, BAIL! */
682 if (!fb) return -1;
683
684 output->prep.fb = fb;
685
686 if (_ecore_drm2_use_atomic)
687 ret = _fb_atomic_flip(output);
688 else
689 ret = _fb_flip(output);
690
691 if (ret)
692 {
693 if (output->prep.fb != output->current.fb)
694 _ecore_drm2_fb_buffer_release(output, &output->prep);
695 return ret;
696 }
697 output->pending.fb = output->prep.fb;
698 output->prep.fb = NULL;
699
700 if (_ecore_drm2_use_atomic)
701 {
702 output->pending.atomic_req = output->prep.atomic_req;
703 output->prep.atomic_req = NULL;
704 }
705
706 return 0;
707 }
708
709 EAPI Eina_Bool
ecore_drm2_fb_busy_get(Ecore_Drm2_Fb * fb)710 ecore_drm2_fb_busy_get(Ecore_Drm2_Fb *fb)
711 {
712 EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
713 EINA_SAFETY_ON_TRUE_RETURN_VAL(fb->dead, EINA_FALSE);
714
715 return !!(fb->ref - 1);
716 }
717
718 EAPI Eina_Bool
ecore_drm2_fb_release(Ecore_Drm2_Output * o,Eina_Bool panic)719 ecore_drm2_fb_release(Ecore_Drm2_Output *o, Eina_Bool panic)
720 {
721 EINA_SAFETY_ON_NULL_RETURN_VAL(o, EINA_FALSE);
722
723 if (o->next.fb)
724 {
725 _ecore_drm2_fb_buffer_release(o, &o->next);
726 return EINA_TRUE;
727 }
728 if (!panic) return EINA_FALSE;
729
730 /* This has been demoted to DBG from WRN because we
731 * call this function to reclaim all buffers on a
732 * surface resize.
733 */
734 DBG("Buffer release request when no next buffer");
735 /* If we have to release these we're going to see tearing.
736 * Try to reclaim in decreasing order of visual awfulness
737 */
738 if (o->current.fb)
739 {
740 _ecore_drm2_fb_buffer_release(o, &o->current);
741 return EINA_TRUE;
742 }
743
744 if (o->pending.fb)
745 {
746 _ecore_drm2_fb_buffer_release(o, &o->pending);
747 return EINA_TRUE;
748 }
749
750 return EINA_FALSE;
751 }
752
753 EAPI void *
ecore_drm2_fb_bo_get(Ecore_Drm2_Fb * fb)754 ecore_drm2_fb_bo_get(Ecore_Drm2_Fb *fb)
755 {
756 EINA_SAFETY_ON_NULL_RETURN_VAL(fb, NULL);
757 EINA_SAFETY_ON_TRUE_RETURN_VAL(fb->dead, NULL);
758
759 return fb->gbm_bo;
760 }
761
762 EAPI Ecore_Drm2_Fb *
ecore_drm2_fb_dmabuf_import(Ecore_Drm2_Device * dev,int width,int height,int depth,int bpp,unsigned int format,unsigned int strides[4],int dmabuf_fd[4],int dmabuf_fd_count)763 ecore_drm2_fb_dmabuf_import(Ecore_Drm2_Device *dev, int width, int height, int depth, int bpp, unsigned int format, unsigned int strides[4], int dmabuf_fd[4], int dmabuf_fd_count)
764 {
765 int i;
766 Ecore_Drm2_Fb *fb;
767
768 EINA_SAFETY_ON_NULL_RETURN_VAL(dev, NULL);
769
770 fb = calloc(1, sizeof(Ecore_Drm2_Fb));
771 if (!fb) return NULL;
772
773 for (i = 0; i < dmabuf_fd_count; i++)
774 if (sym_drmPrimeFDToHandle(dev->fd, dmabuf_fd[i], &fb->handles[i]))
775 goto fail;
776
777 fb->dmabuf = EINA_TRUE;
778 fb->fd = dev->fd;
779 fb->w = width;
780 fb->h = height;
781 fb->bpp = bpp;
782 fb->depth = depth;
783 fb->format = format;
784 fb->ref = 1;
785
786 memcpy(&fb->strides, strides, sizeof(fb->strides));
787 if (_fb2_create(fb)) return fb;
788
789 fail:
790 free(fb);
791 return NULL;
792 }
793
794 EAPI void
ecore_drm2_fb_status_handler_set(Ecore_Drm2_Fb * fb,Ecore_Drm2_Fb_Status_Handler handler,void * data)795 ecore_drm2_fb_status_handler_set(Ecore_Drm2_Fb *fb, Ecore_Drm2_Fb_Status_Handler handler, void *data)
796 {
797 fb->status_handler = handler;
798 fb->status_data = data;
799 }
800