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