> -----Original Message-----
> From: amd-gfx [mailto:amd-gfx-boun...@lists.freedesktop.org] On Behalf
> Of Michel Dänzer
> Sent: Wednesday, May 10, 2017 5:06 AM
> To: amd-gfx@lists.freedesktop.org
> Subject: [PATCH xf86-video-ati 2/2] Use reference counting for tracking KMS
> framebuffer lifetimes
> 
> From: Michel Dänzer <michel.daen...@amd.com>
> 
> References are held by the pixmaps corresponding to the FBs (so
> the same KMS FB can be reused as long as the pixmap exists) and by the
> CRTCs scanning out from them (so a KMS FB is only destroyed once it's
> not being scanned out anymore, preventing intermittent black screens and
> worse issues due to a CRTC turning off when it should be on).
> 
> v2:
> * Only increase reference count in drmmode_fb_reference if it was sane
>   before
> * Make drmmode_fb_reference's indentation match the rest of
>   drmmode_display.h
> 
> Reviewed-by: Alex Deucher <alexander.deuc...@amd.com> # v1
> Signed-off-by: Michel Dänzer <michel.daen...@amd.com>

Series is:
Reviewed-by: Alex Deucher <alexander.deuc...@amd.com>

> ---
>  src/drmmode_display.c  | 147 +++++++++++++++++++++-----------------------
> -----
>  src/drmmode_display.h  |  39 +++++++++++--
>  src/radeon.h           |  73 ++++++++++++++++++++++++
>  src/radeon_bo_helper.h |   3 -
>  src/radeon_exa.c       |   2 +
>  src/radeon_kms.c       |  64 ++++++++++++++++++---
>  src/radeon_present.c   |   8 ---
>  7 files changed, 226 insertions(+), 110 deletions(-)
> 
> diff --git a/src/drmmode_display.c b/src/drmmode_display.c
> index a101ac233..ec3072621 100644
> --- a/src/drmmode_display.c
> +++ b/src/drmmode_display.c
> @@ -375,6 +375,7 @@ drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
> 
>               drmModeSetCrtc(drmmode->fd, drmmode_crtc-
> >mode_crtc->crtc_id,
>                              0, 0, 0, NULL, 0, NULL);
> +             drmmode_fb_reference(drmmode->fd, &drmmode_crtc-
> >fb, NULL);
>       } else if (drmmode_crtc->dpms_mode != DPMSModeOn)
>               crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc-
> >rotation,
>                                           crtc->x, crtc->y);
> @@ -447,8 +448,9 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn,
> drmmode_ptr drmmode)
>  {
>       xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
>       RADEONInfoPtr info = RADEONPTR(pScrn);
> -     PixmapPtr src, dst;
>       ScreenPtr pScreen = pScrn->pScreen;
> +     PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen);
> +     struct drmmode_fb *fb = radeon_pixmap_get_fb(dst);
>       int fbcon_id = 0;
>       Bool force;
>       GCPtr gc;
> @@ -464,7 +466,7 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn,
> drmmode_ptr drmmode)
>       if (!fbcon_id)
>               return;
> 
> -     if (fbcon_id == drmmode->fb_id) {
> +     if (fbcon_id == fb->handle) {
>               /* in some rare case there might be no fbcon and we might
> already
>                * be the one with the current fb to avoid a false deadlck in
>                * kernel ttm code just do nothing as anyway there is nothing
> @@ -477,8 +479,6 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn,
> drmmode_ptr drmmode)
>       if (!src)
>               return;
> 
> -     dst = pScreen->GetScreenPixmap(pScreen);
> -
>       gc = GetScratchGC(pScrn->depth, pScreen);
>       ValidateGC(&dst->drawable, gc);
> 
> @@ -505,8 +505,6 @@ drmmode_crtc_scanout_destroy(drmmode_ptr
> drmmode,
>       }
> 
>       if (scanout->bo) {
> -             drmModeRmFB(drmmode->fd, scanout->fb_id);
> -             scanout->fb_id = 0;
>               radeon_bo_unmap(scanout->bo);
>               radeon_bo_unref(scanout->bo);
>               scanout->bo = NULL;
> @@ -571,15 +569,9 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc,
> struct drmmode_scanout *scanout,
>       scanout->bo = radeon_alloc_pixmap_bo(pScrn, width, height, pScrn-
> >depth,
>                                            tiling, pScrn->bitsPerPixel,
>                                            &pitch, &surface, &tiling);
> -     if (scanout->bo == NULL)
> -             goto error;
> -
> -     if (drmModeAddFB(drmmode->fd, width, height, pScrn->depth,
> -                        pScrn->bitsPerPixel, pitch,
> -                        scanout->bo->handle,
> -                        &scanout->fb_id) != 0) {
> -             ErrorF("failed to add scanout fb\n");
> -             goto error;
> +     if (!scanout->bo) {
> +             ErrorF("failed to create CRTC scanout BO\n");
> +             return NULL;
>       }
> 
>       scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
> @@ -587,13 +579,17 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc,
> struct drmmode_scanout *scanout,
>                                                pScrn->depth,
>                                                pScrn->bitsPerPixel,
>                                                pitch, scanout->bo, NULL);
> -     if (scanout->pixmap) {
> +     if (!scanout->pixmap) {
> +             ErrorF("failed to create CRTC scanout pixmap\n");
> +             goto error;
> +     }
> +
> +     if (radeon_pixmap_get_fb(scanout->pixmap)) {
>               scanout->width = width;
>               scanout->height = height;
>       } else {
> -             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
> -                        "Couldn't allocate scanout pixmap for CRTC\n");
> -error:
> +             ErrorF("failed to create CRTC scanout FB\n");
> +error:
>               drmmode_crtc_scanout_destroy(drmmode, scanout);
>       }
> 
> @@ -706,8 +702,8 @@ drmmode_handle_transform(xf86CrtcPtr crtc)
> 
>  static void
>  drmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr
> mode,
> -                               unsigned scanout_id, int *fb_id, int *x,
> -                               int *y)
> +                               unsigned scanout_id, struct drmmode_fb
> **fb,
> +                               int *x, int *y)
>  {
>       ScrnInfoPtr scrn = crtc->scrn;
>       ScreenPtr screen = scrn->pScreen;
> @@ -759,7 +755,7 @@ drmmode_crtc_prime_scanout_update(xf86CrtcPtr
> crtc, DisplayModePtr mode,
>               }
>       }
> 
> -     *fb_id = drmmode_crtc->scanout[scanout_id].fb_id;
> +     *fb = radeon_pixmap_get_fb(drmmode_crtc-
> >scanout[scanout_id].pixmap);
>       *x = *y = 0;
>       drmmode_crtc->scanout_id = scanout_id;
>  }
> @@ -768,7 +764,8 @@ drmmode_crtc_prime_scanout_update(xf86CrtcPtr
> crtc, DisplayModePtr mode,
> 
>  static void
>  drmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
> -                         unsigned scanout_id, int *fb_id, int *x, int *y)
> +                         unsigned scanout_id, struct drmmode_fb **fb, int
> *x,
> +                         int *y)
>  {
>       ScrnInfoPtr scrn = crtc->scrn;
>       ScreenPtr screen = scrn->pScreen;
> @@ -804,7 +801,7 @@ drmmode_crtc_scanout_update(xf86CrtcPtr crtc,
> DisplayModePtr mode,
>               box->x2 = max(box->x2, scrn->virtualX);
>               box->y2 = max(box->y2, scrn->virtualY);
> 
> -             *fb_id = drmmode_crtc->scanout[scanout_id].fb_id;
> +             *fb = radeon_pixmap_get_fb(drmmode_crtc-
> >scanout[scanout_id].pixmap);
>               *x = *y = 0;
> 
>               radeon_scanout_do_update(crtc, scanout_id);
> @@ -841,7 +838,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc,
> DisplayModePtr mode,
>       int output_count = 0;
>       Bool ret = FALSE;
>       int i;
> -     int fb_id;
> +     struct drmmode_fb *fb = NULL;
>       drmModeModeInfo kmode;
> 
>       /* The root window contents may be undefined before the
> WindowExposures
> @@ -889,15 +886,14 @@ drmmode_set_mode_major(xf86CrtcPtr crtc,
> DisplayModePtr mode,
> 
>               drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
> 
> -             fb_id = drmmode->fb_id;
>  #ifdef RADEON_PIXMAP_SHARING
>               if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
>                       drmmode_crtc_prime_scanout_update(crtc, mode,
> scanout_id,
> -                                                       &fb_id, &x, &y);
> +                                                       &fb, &x, &y);
>               } else
>  #endif
> -             if (drmmode_crtc->rotate.fb_id) {
> -                     fb_id = drmmode_crtc->rotate.fb_id;
> +             if (drmmode_crtc->rotate.pixmap) {
> +                     fb = radeon_pixmap_get_fb(drmmode_crtc-
> >rotate.pixmap);
>                       x = y = 0;
> 
>               } else if (!radeon_is_gpu_screen(pScreen) &&
> @@ -907,22 +903,24 @@ drmmode_set_mode_major(xf86CrtcPtr crtc,
> DisplayModePtr mode,
>  #endif
>                           info->shadow_primary)) {
>                       drmmode_crtc_scanout_update(crtc, mode,
> scanout_id,
> -                                                 &fb_id, &x, &y);
> +                                                 &fb, &x, &y);
>               }
> 
> -             if (fb_id == 0) {
> -                     if (drmModeAddFB(drmmode->fd,
> -                                      pScrn->virtualX,
> -                                      pScrn->virtualY,
> -                                      pScrn->depth, pScrn->bitsPerPixel,
> -                                      pScrn->displayWidth * info-
> >pixel_bytes,
> -                                      info->front_bo->handle,
> -                                      &drmmode->fb_id) < 0) {
> -                             ErrorF("failed to add fb\n");
> -                             goto done;
> -                     }
> -
> -                     fb_id = drmmode->fb_id;
> +             if (!fb)
> +                     fb = radeon_pixmap_get_fb(pScreen-
> >GetWindowPixmap(pScreen->root));
> +             if (!fb) {
> +                     fb = radeon_fb_create(drmmode->fd, pScrn-
> >virtualX,
> +                                           pScrn->virtualY, pScrn->depth,
> +                                           pScrn->bitsPerPixel,
> +                                           pScrn->displayWidth * info-
> >pixel_bytes,
> +                                           info->front_bo->handle);
> +                     /* Prevent refcnt of ad-hoc FBs from reaching 2 */
> +                     drmmode_fb_reference(drmmode->fd,
> &drmmode_crtc->fb, NULL);
> +                     drmmode_crtc->fb = fb;
> +             }
> +             if (!fb) {
> +                     ErrorF("failed to add FB for modeset\n");
> +                     goto done;
>               }
> 
>               /* Wait for any pending flip to finish */
> @@ -932,13 +930,15 @@ drmmode_set_mode_major(xf86CrtcPtr crtc,
> DisplayModePtr mode,
> 
>               if (drmModeSetCrtc(drmmode->fd,
>                                  drmmode_crtc->mode_crtc->crtc_id,
> -                                fb_id, x, y, output_ids,
> +                                fb->handle, x, y, output_ids,
>                                  output_count, &kmode) != 0) {
>                       xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
>                                  "failed to set mode: %s\n", strerror(errno));
>                       goto done;
> -             } else
> +             } else {
>                       ret = TRUE;
> +                     drmmode_fb_reference(drmmode->fd,
> &drmmode_crtc->fb, fb);
> +             }
> 
>               if (pScreen)
>                       xf86CrtcSetScreenSubpixelOrder(pScreen);
> @@ -983,7 +983,9 @@ done:
>       } else {
>               crtc->active = TRUE;
> 
> -             if (fb_id != drmmode_crtc->scanout[scanout_id].fb_id)
> +             if (drmmode_crtc->scanout[scanout_id].pixmap &&
> +                 fb != radeon_pixmap_get_fb(drmmode_crtc->
> +                                            scanout[scanout_id].pixmap))
>                       drmmode_crtc_scanout_free(drmmode_crtc);
>               else if (!drmmode_crtc->tear_free) {
>                       drmmode_crtc_scanout_destroy(drmmode,
> @@ -2157,13 +2159,9 @@ static Bool
>  drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
>  {
>       xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
> -     drmmode_crtc_private_ptr
> -                 drmmode_crtc = xf86_config->crtc[0]->driver_private;
> -     drmmode_ptr drmmode = drmmode_crtc->drmmode;
>       RADEONInfoPtr info = RADEONPTR(scrn);
>       struct radeon_bo *old_front = NULL;
>       ScreenPtr   screen = xf86ScrnToScreen(scrn);
> -     uint32_t    old_fb_id;
>       int         i, pitch, old_width, old_height, old_pitch;
>       int aligned_height;
>       uint32_t screen_size;
> @@ -2263,8 +2261,6 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int
> width, int height)
>       old_width = scrn->virtualX;
>       old_height = scrn->virtualY;
>       old_pitch = scrn->displayWidth;
> -     old_fb_id = drmmode->fb_id;
> -     drmmode->fb_id = 0;
>       old_front = info->front_bo;
> 
>       scrn->virtualX = width;
> @@ -2346,8 +2342,6 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int
> width, int height)
>                                      crtc->rotation, crtc->x, crtc->y);
>       }
> 
> -     if (old_fb_id)
> -             drmModeRmFB(drmmode->fd, old_fb_id);
>       if (old_front)
>               radeon_bo_unref(old_front);
> 
> @@ -2361,7 +2355,6 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int
> width, int height)
>       scrn->virtualX = old_width;
>       scrn->virtualY = old_height;
>       scrn->displayWidth = old_pitch;
> -     drmmode->fb_id = old_fb_id;
> 
>       return FALSE;
>  }
> @@ -2375,7 +2368,7 @@ drmmode_clear_pending_flip(xf86CrtcPtr crtc)
>  {
>       drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
> 
> -     drmmode_crtc->flip_pending = FALSE;
> +     drmmode_crtc->flip_pending = NULL;
> 
>       if (!crtc->enabled ||
>           (drmmode_crtc->pending_dpms_mode != DPMSModeOn &&
> @@ -2419,7 +2412,7 @@ drmmode_flip_abort(xf86CrtcPtr crtc, void
> *event_data)
>  static void
>  drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void
> *event_data)
>  {
> -     RADEONInfoPtr info = RADEONPTR(crtc->scrn);
> +     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
>       drmmode_flipdata_ptr flipdata = event_data;
> 
>       /* Is this the event whose info shall be delivered to higher level? */
> @@ -2439,12 +2432,11 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t
> frame, uint64_t usec, void *even
>               else
>                       flipdata->handler(crtc, frame, usec, flipdata-
> >event_data);
> 
> -             /* Release framebuffer */
> -             drmModeRmFB(info->drmmode.fd, flipdata->old_fb_id);
> -
>               free(flipdata);
>       }
> 
> +     drmmode_fb_reference(drmmode_crtc->drmmode->fd,
> &drmmode_crtc->fb,
> +                          drmmode_crtc->flip_pending);
>       drmmode_clear_pending_flip(crtc);
>  }
> 
> @@ -2701,6 +2693,8 @@ Bool drmmode_set_desired_modes(ScrnInfoPtr
> pScrn, drmmode_ptr drmmode,
>                               drmModeSetCrtc(drmmode->fd,
>                                              drmmode_crtc->mode_crtc-
> >crtc_id,
>                                              0, 0, 0, NULL, 0, NULL);
> +                             drmmode_fb_reference(drmmode->fd,
> +                                                  &drmmode_crtc->fb,
> NULL);
>                       }
>                       continue;
>               }
> @@ -2960,18 +2954,11 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn,
> ClientPtr client,
>       xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
>       xf86CrtcPtr crtc = NULL;
>       drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]-
> >driver_private;
> -     drmmode_ptr drmmode = drmmode_crtc->drmmode;
>       int i;
>       uint32_t flip_flags = flip_sync == FLIP_ASYNC ?
> DRM_MODE_PAGE_FLIP_ASYNC : 0;
>       drmmode_flipdata_ptr flipdata;
>       uintptr_t drm_queue_seq = 0;
> -     uint32_t new_front_handle;
> -
> -     if (!radeon_get_pixmap_handle(new_front, &new_front_handle)) {
> -             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
> -                        "flip queue: failed to get new front handle\n");
> -             return FALSE;
> -     }
> +     struct drmmode_fb *fb;
> 
>          flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
>          if (!flipdata) {
> @@ -2980,15 +2967,11 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn,
> ClientPtr client,
>               goto error;
>          }
> 
> -     /*
> -      * Create a new handle for the back buffer
> -      */
> -     flipdata->old_fb_id = drmmode->fb_id;
> -     if (drmModeAddFB(drmmode->fd, new_front->drawable.width,
> -                      new_front->drawable.height, scrn->depth,
> -                      scrn->bitsPerPixel, new_front->devKind,
> -                      new_front_handle, &drmmode->fb_id))
> +     fb = radeon_pixmap_get_fb(new_front);
> +     if (!fb) {
> +             ErrorF("Failed to get FB for flip\n");
>               goto error;
> +     }
> 
>       /*
>        * Queue flips on all enabled CRTCs
> @@ -3032,7 +3015,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn,
> ClientPtr client,
>               if (drmmode_crtc->hw_id == ref_crtc_hw_id) {
>                       if
> (drmmode_page_flip_target_absolute(pRADEONEnt,
>                                                             drmmode_crtc,
> -                                                           drmmode->fb_id,
> +                                                           fb->handle,
>                                                             flip_flags,
>                                                             drm_queue_seq,
>                                                             target_msc) != 0)
> @@ -3040,13 +3023,13 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn,
> ClientPtr client,
>               } else {
>                       if
> (drmmode_page_flip_target_relative(pRADEONEnt,
>                                                             drmmode_crtc,
> -                                                           drmmode->fb_id,
> +                                                           fb->handle,
>                                                             flip_flags,
>                                                             drm_queue_seq,
> 0) != 0)
>                               goto flip_error;
>               }
> 
> -             drmmode_crtc->flip_pending = TRUE;
> +             drmmode_crtc->flip_pending = fb;
>               drm_queue_seq = 0;
>       }
> 
> @@ -3058,12 +3041,6 @@ flip_error:
>                  strerror(errno));
> 
>  error:
> -     if (flipdata && flipdata->flip_count <= 1 &&
> -         drmmode->fb_id != flipdata->old_fb_id) {
> -             drmModeRmFB(drmmode->fd, drmmode->fb_id);
> -             drmmode->fb_id = flipdata->old_fb_id;
> -     }
> -
>       if (drm_queue_seq)
>               radeon_drm_abort_entry(drm_queue_seq);
>       else if (crtc)
> diff --git a/src/drmmode_display.h b/src/drmmode_display.h
> index 35d64179d..14d1cb034 100644
> --- a/src/drmmode_display.h
> +++ b/src/drmmode_display.h
> @@ -41,7 +41,6 @@
> 
>  typedef struct {
>    int fd;
> -  unsigned fb_id;
>    drmModeFBPtr mode_fb;
>    int cpp;
>    struct radeon_bo_manager *bufmgr;
> @@ -60,7 +59,6 @@ typedef struct {
>  } drmmode_rec, *drmmode_ptr;
> 
>  typedef struct {
> -  unsigned old_fb_id;
>    int flip_count;
>    void *event_data;
>    unsigned int fe_frame;
> @@ -70,10 +68,14 @@ typedef struct {
>    radeon_drm_abort_proc abort;
>  } drmmode_flipdata_rec, *drmmode_flipdata_ptr;
> 
> +struct drmmode_fb {
> +     int refcnt;
> +     uint32_t handle;
> +};
> +
>  struct drmmode_scanout {
>      struct radeon_bo *bo;
>      PixmapPtr pixmap;
> -    unsigned fb_id;
>      int width, height;
>  };
> 
> @@ -102,8 +104,10 @@ typedef struct {
>       * modeset)
>       */
>      Bool need_modeset;
> -    /* A flip is pending for this CRTC */
> -    Bool flip_pending;
> +    /* A flip to this FB is pending for this CRTC */
> +    struct drmmode_fb *flip_pending;
> +    /* The FB currently being scanned out by this CRTC, if any */
> +    struct drmmode_fb *fb;
>  } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
> 
>  typedef struct {
> @@ -135,6 +139,31 @@ enum drmmode_flip_sync {
>  };
> 
> 
> +static inline void
> +drmmode_fb_reference(int drm_fd, struct drmmode_fb **old, struct
> drmmode_fb *new)
> +{
> +    if (new) {
> +     if (new->refcnt <= 0)
> +         ErrorF("New FB's refcnt was %d in %s\n", new->refcnt, __func__);
> +     else
> +         new->refcnt++;
> +    }
> +
> +    if (*old) {
> +     if ((*old)->refcnt <= 0) {
> +         ErrorF("Old FB's refcnt was %d in %s\n", (*old)->refcnt, __func__);
> +     } else {
> +         if (--(*old)->refcnt == 0) {
> +             drmModeRmFB(drm_fd, (*old)->handle);
> +             free(*old);
> +         }
> +     }
> +    }
> +
> +    *old = new;
> +}
> +
> +
>  extern int drmmode_page_flip_target_absolute(RADEONEntPtr
> pRADEONEnt,
>                                            drmmode_crtc_private_ptr
> drmmode_crtc,
>                                            int fb_id, uint32_t flags,
> diff --git a/src/radeon.h b/src/radeon.h
> index 2cb188e1f..febe580b6 100644
> --- a/src/radeon.h
> +++ b/src/radeon.h
> @@ -288,6 +288,7 @@ struct radeon_pixmap {
>       uint_fast32_t gpu_write;
> 
>       struct radeon_bo *bo;
> +     struct drmmode_fb *fb;
> 
>       uint32_t tiling_flags;
> 
> @@ -313,6 +314,7 @@ static inline void
> radeon_set_pixmap_private(PixmapPtr pixmap, struct radeon_pix
> 
>  struct radeon_exa_pixmap_priv {
>      struct radeon_bo *bo;
> +    struct drmmode_fb *fb;
>      uint32_t tiling_flags;
>      struct radeon_surface surface;
>      Bool bo_mapped;
> @@ -609,6 +611,9 @@ extern void  RADEONCopySwap(uint8_t *dst, uint8_t
> *src, unsigned int size, int s
>  extern void RADEONInit3DEngine(ScrnInfoPtr pScrn);
>  extern int radeon_cs_space_remaining(ScrnInfoPtr pScrn);
> 
> +/* radeon_bo_helper.c */
> +extern Bool radeon_get_pixmap_handle(PixmapPtr pixmap, uint32_t
> *handle);
> +
>  /* radeon_commonfuncs.c */
>  extern void RADEONWaitForVLine(ScrnInfoPtr pScrn, PixmapPtr pPix,
>                              xf86CrtcPtr crtc, int start, int stop);
> @@ -706,6 +711,8 @@ static inline Bool radeon_set_pixmap_bo(PixmapPtr
> pPix, struct radeon_bo *bo)
>               radeon_bo_unref(priv->bo);
>           }
> 
> +         drmmode_fb_reference(info->drmmode.fd, &priv->fb, NULL);
> +
>           if (!bo) {
>               free(priv);
>               priv = NULL;
> @@ -790,6 +797,72 @@ static inline Bool
> radeon_get_pixmap_shared(PixmapPtr pPix)
>      return FALSE;
>  }
> 
> +static inline struct drmmode_fb*
> +radeon_fb_create(int drm_fd, uint32_t width, uint32_t height, uint8_t
> depth,
> +              uint8_t bpp, uint32_t pitch, uint32_t handle)
> +{
> +    struct drmmode_fb *fb  = malloc(sizeof(*fb));
> +
> +    if (!fb)
> +     return NULL;
> +
> +    fb->refcnt = 1;
> +    if (drmModeAddFB(drm_fd, width, height, depth, bpp, pitch, handle,
> +                  &fb->handle) == 0)
> +     return fb;
> +
> +    free(fb);
> +    return NULL;
> +}
> +
> +static inline struct drmmode_fb*
> +radeon_pixmap_create_fb(int drm_fd, PixmapPtr pix)
> +{
> +    uint32_t handle;
> +
> +    if (!radeon_get_pixmap_handle(pix, &handle))
> +     return NULL;
> +
> +    return radeon_fb_create(drm_fd, pix->drawable.width, pix-
> >drawable.height,
> +                         pix->drawable.depth, pix->drawable.bitsPerPixel,
> +                         pix->devKind, handle);
> +}
> +
> +static inline struct drmmode_fb*
> +radeon_pixmap_get_fb(PixmapPtr pix)
> +{
> +    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pix-
> >drawable.pScreen));
> +
> +#ifdef USE_GLAMOR
> +    if (info->use_glamor) {
> +     struct radeon_pixmap *priv = radeon_get_pixmap_private(pix);
> +
> +     if (!priv)
> +         return NULL;
> +
> +     if (!priv->fb)
> +         priv->fb = radeon_pixmap_create_fb(info->drmmode.fd, pix);
> +
> +     return priv->fb;
> +    } else
> +#endif
> +    if (info->accelOn)
> +    {
> +     struct radeon_exa_pixmap_priv *driver_priv =
> +         exaGetPixmapDriverPrivate(pix);
> +
> +     if (!driver_priv)
> +         return NULL;
> +
> +     if (!driver_priv->fb)
> +         driver_priv->fb = radeon_pixmap_create_fb(info->drmmode.fd,
> pix);
> +
> +     return driver_priv->fb;
> +    }
> +
> +    return NULL;
> +}
> +
>  #define CP_PACKET0(reg, n)                                           \
>       (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
>  #define CP_PACKET1(reg0, reg1)
>       \
> diff --git a/src/radeon_bo_helper.h b/src/radeon_bo_helper.h
> index f1aed5516..771342502 100644
> --- a/src/radeon_bo_helper.h
> +++ b/src/radeon_bo_helper.h
> @@ -28,9 +28,6 @@ radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width,
> int height, int depth,
>                      int usage_hint, int bitsPerPixel, int *new_pitch,
>                      struct radeon_surface *new_surface, uint32_t
> *new_tiling);
> 
> -extern Bool
> -radeon_get_pixmap_handle(PixmapPtr pixmap, uint32_t *handle);
> -
>  extern uint32_t
>  radeon_get_pixmap_tiling_flags(PixmapPtr pPix);
> 
> diff --git a/src/radeon_exa.c b/src/radeon_exa.c
> index 1e457a8bb..d8dd7fdce 100644
> --- a/src/radeon_exa.c
> +++ b/src/radeon_exa.c
> @@ -300,6 +300,7 @@ void *RADEONEXACreatePixmap2(ScreenPtr pScreen,
> int width, int height,
> 
>  void RADEONEXADestroyPixmap(ScreenPtr pScreen, void *driverPriv)
>  {
> +    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pScreen));
>      struct radeon_exa_pixmap_priv *driver_priv = driverPriv;
> 
>      if (!driverPriv)
> @@ -307,6 +308,7 @@ void RADEONEXADestroyPixmap(ScreenPtr pScreen,
> void *driverPriv)
> 
>      if (driver_priv->bo)
>       radeon_bo_unref(driver_priv->bo);
> +    drmmode_fb_reference(info->drmmode.fd, &driver_priv->fb, NULL);
>      free(driverPriv);
>  }
> 
> diff --git a/src/radeon_kms.c b/src/radeon_kms.c
> index b3427c462..2b410eb3d 100644
> --- a/src/radeon_kms.c
> +++ b/src/radeon_kms.c
> @@ -772,6 +772,17 @@ radeon_prime_scanout_flip_abort(xf86CrtcPtr crtc,
> void *event_data)
>  }
> 
>  static void
> +radeon_prime_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc,
> uint64_t usec,
> +                               void *event_data)
> +{
> +    drmmode_crtc_private_ptr drmmode_crtc = event_data;
> +
> +    drmmode_fb_reference(drmmode_crtc->drmmode->fd,
> &drmmode_crtc->fb,
> +                      drmmode_crtc->flip_pending);
> +    radeon_prime_scanout_flip_abort(crtc, event_data);
> +}
> +
> +static void
>  radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
>  {
>      ScreenPtr screen = ent->slave_dst->drawable.pScreen;
> @@ -798,7 +809,8 @@ radeon_prime_scanout_flip(PixmapDirtyUpdatePtr
> ent)
>      drm_queue_seq = radeon_drm_queue_alloc(crtc,
> 
> RADEON_DRM_QUEUE_CLIENT_DEFAULT,
> 
> RADEON_DRM_QUEUE_ID_DEFAULT,
> -                                        drmmode_crtc, NULL,
> +                                        drmmode_crtc,
> +
> radeon_prime_scanout_flip_handler,
>                                          radeon_prime_scanout_flip_abort);
>      if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
>       xf86DrvMsg(scrn->scrnIndex, X_WARNING,
> @@ -806,8 +818,17 @@ radeon_prime_scanout_flip(PixmapDirtyUpdatePtr
> ent)
>       return;
>      }
> 
> +    drmmode_crtc->flip_pending =
> +     radeon_pixmap_get_fb(drmmode_crtc-
> >scanout[scanout_id].pixmap);
> +    if (!drmmode_crtc->flip_pending) {
> +     xf86DrvMsg(scrn->scrnIndex, X_WARNING,
> +                "Failed to get FB for PRIME flip.\n");
> +     radeon_drm_abort_entry(drm_queue_seq);
> +     return;
> +    }
> +
>      if (drmmode_page_flip_target_relative(pRADEONEnt, drmmode_crtc,
> -                                       drmmode_crtc-
> >scanout[scanout_id].fb_id,
> +                                       drmmode_crtc->flip_pending-
> >handle,
>                                         0, drm_queue_seq, 0) != 0) {
>       xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s:
> %s\n",
>                  __func__, strerror(errno));
> @@ -817,7 +838,6 @@ radeon_prime_scanout_flip(PixmapDirtyUpdatePtr
> ent)
> 
>      drmmode_crtc->scanout_id = scanout_id;
>      drmmode_crtc->scanout_update_pending = TRUE;
> -    drmmode_crtc->flip_pending = TRUE;
>  }
> 
>  static void
> @@ -1053,10 +1073,14 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
>  static void
>  radeon_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
>  {
> -    drmmode_crtc_private_ptr drmmode_crtc = event_data;
> +    radeon_prime_scanout_flip_abort(crtc, event_data);
> +}
> 
> -    drmmode_crtc->scanout_update_pending = FALSE;
> -    drmmode_clear_pending_flip(crtc);
> +static void
> +radeon_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec,
> +                         void *event_data)
> +{
> +    radeon_prime_scanout_flip_handler(crtc, msc, usec, event_data);
>  }
> 
>  static void
> @@ -1080,7 +1104,8 @@ radeon_scanout_flip(ScreenPtr pScreen,
> RADEONInfoPtr info,
>      drm_queue_seq = radeon_drm_queue_alloc(xf86_crtc,
> 
> RADEON_DRM_QUEUE_CLIENT_DEFAULT,
> 
> RADEON_DRM_QUEUE_ID_DEFAULT,
> -                                        drmmode_crtc, NULL,
> +                                        drmmode_crtc,
> +                                        radeon_scanout_flip_handler,
>                                          radeon_scanout_flip_abort);
>      if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
>       xf86DrvMsg(scrn->scrnIndex, X_WARNING,
> @@ -1088,8 +1113,17 @@ radeon_scanout_flip(ScreenPtr pScreen,
> RADEONInfoPtr info,
>       return;
>      }
> 
> +    drmmode_crtc->flip_pending =
> +     radeon_pixmap_get_fb(drmmode_crtc-
> >scanout[scanout_id].pixmap);
> +    if (!drmmode_crtc->flip_pending) {
> +     xf86DrvMsg(scrn->scrnIndex, X_WARNING,
> +                "Failed to get FB for scanout flip.\n");
> +     radeon_drm_abort_entry(drm_queue_seq);
> +     return;
> +    }
> +
>      if (drmmode_page_flip_target_relative(pRADEONEnt, drmmode_crtc,
> -                                       drmmode_crtc-
> >scanout[scanout_id].fb_id,
> +                                       drmmode_crtc->flip_pending-
> >handle,
>                                         0, drm_queue_seq, 0) != 0) {
>       xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s:
> %s\n",
>                  __func__, strerror(errno));
> @@ -1099,7 +1133,6 @@ radeon_scanout_flip(ScreenPtr pScreen,
> RADEONInfoPtr info,
> 
>      drmmode_crtc->scanout_id = scanout_id;
>      drmmode_crtc->scanout_update_pending = TRUE;
> -    drmmode_crtc->flip_pending = TRUE;
>  }
> 
>  static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
> @@ -1114,6 +1147,19 @@ static void
> RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
>      (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
>      pScreen->BlockHandler = RADEONBlockHandler_KMS;
> 
> +    if (!pScrn->vtSema) {
> +     radeon_cs_flush_indirect(pScrn);
> +
> +     for (c = 0; c < xf86_config->num_crtc; c++) {
> +         drmmode_crtc_private_ptr drmmode_crtc =
> +             xf86_config->crtc[c]->driver_private;
> +
> +         drmmode_fb_reference(info->drmmode.fd, &drmmode_crtc->fb,
> NULL);
> +     }
> +
> +     return;
> +    }
> +
>      if (!radeon_is_gpu_screen(pScreen))
>      {
>       for (c = 0; c < xf86_config->num_crtc; c++) {
> diff --git a/src/radeon_present.c b/src/radeon_present.c
> index 90632d0ec..635d10861 100644
> --- a/src/radeon_present.c
> +++ b/src/radeon_present.c
> @@ -373,7 +373,6 @@ radeon_present_unflip(ScreenPtr screen, uint64_t
> event_id)
>      enum drmmode_flip_sync flip_sync =
>       (radeon_present_screen_info.capabilities & PresentCapabilityAsync)
> ?
>       FLIP_ASYNC : FLIP_VSYNC;
> -    int old_fb_id;
>      int i;
> 
>      radeon_cs_flush_indirect(scrn);
> @@ -396,12 +395,6 @@ radeon_present_unflip(ScreenPtr screen, uint64_t
> event_id)
>       return;
> 
>  modeset:
> -    /* info->drmmode.fb_id still points to the FB for the last flipped BO.
> -     * Clear it, drmmode_set_mode_major will re-create it
> -     */
> -    old_fb_id = info->drmmode.fb_id;
> -    info->drmmode.fb_id = 0;
> -
>      radeon_bo_wait(info->front_bo);
>      for (i = 0; i < config->num_crtc; i++) {
>       xf86CrtcPtr crtc = config->crtc[i];
> @@ -417,7 +410,6 @@ modeset:
>           drmmode_crtc->need_modeset = TRUE;
>      }
> 
> -    drmModeRmFB(info->drmmode.fd, old_fb_id);
>      present_event_notify(event_id, 0, 0);
> 
>      info->drmmode.present_flipping = FALSE;
> --
> 2.11.0
> 
> _______________________________________________
> amd-gfx mailing list
> amd-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to