Exemplo n.º 1
0
static void
vl_dri3_flush_frontbuffer(struct pipe_screen *screen,
                          struct pipe_resource *resource,
                          unsigned level, unsigned layer,
                          void *context_private, struct pipe_box *sub_box)
{
   struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)context_private;
   uint32_t options = XCB_PRESENT_OPTION_NONE;
   struct vl_dri3_buffer *back;
   struct pipe_box src_box;
   xcb_xfixes_region_t region;
   xcb_rectangle_t rectangle;

   back = scrn->back_buffers[scrn->cur_back];
   if (!back)
       return;

   while (scrn->special_event && scrn->recv_sbc < scrn->send_sbc)
      if (!dri3_wait_present_events(scrn))
         return;

   rectangle.x = 0;
   rectangle.y = 0;
   rectangle.width = (scrn->output_texture) ? scrn->clip_width : scrn->width;
   rectangle.height = (scrn->output_texture) ? scrn->clip_height : scrn->height;

   region = xcb_generate_id(scrn->conn);
   xcb_xfixes_create_region(scrn->conn, region, 2, &rectangle);

   if (scrn->is_different_gpu) {
      u_box_origin_2d(back->width, back->height, &src_box);
      scrn->pipe->resource_copy_region(scrn->pipe,
                                       back->linear_texture,
                                       0, 0, 0, 0,
                                       back->texture,
                                       0, &src_box);

      scrn->pipe->flush(scrn->pipe, NULL, 0);
   }
   xshmfence_reset(back->shm_fence);
   back->busy = true;

   xcb_present_pixmap(scrn->conn,
                      scrn->drawable,
                      back->pixmap,
                      (uint32_t)(++scrn->send_sbc),
                      0, region, 0, 0,
                      None, None,
                      back->sync_fence,
                      options,
                      scrn->next_msc,
                      0, 0, 0, NULL);

   xcb_flush(scrn->conn);

   return;
}
Exemplo n.º 2
0
static VkResult
x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index,
                   uint32_t target_msc)
{
   struct x11_image *image = &chain->images[image_index];

   assert(image_index < chain->image_count);

   uint32_t options = XCB_PRESENT_OPTION_NONE;

   int64_t divisor = 0;
   int64_t remainder = 0;

   if (chain->base.present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR)
      options |= XCB_PRESENT_OPTION_ASYNC;

   xshmfence_reset(image->shm_fence);

   ++chain->send_sbc;
   xcb_void_cookie_t cookie =
      xcb_present_pixmap(chain->conn,
                         chain->window,
                         image->pixmap,
                         (uint32_t) chain->send_sbc,
                         0,                                    /* valid */
                         0,                                    /* update */
                         0,                                    /* x_off */
                         0,                                    /* y_off */
                         XCB_NONE,                             /* target_crtc */
                         XCB_NONE,
                         image->sync_fence,
                         options,
                         target_msc,
                         divisor,
                         remainder, 0, NULL);
   xcb_discard_reply(chain->conn, cookie.sequence);
   image->busy = true;

   xcb_flush(chain->conn);

   return VK_SUCCESS;
}
Exemplo n.º 3
0
static void
vl_dri3_flush_frontbuffer(struct pipe_screen *screen,
                          struct pipe_resource *resource,
                          unsigned level, unsigned layer,
                          void *context_private, struct pipe_box *sub_box)
{
   struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)context_private;
   uint32_t options = XCB_PRESENT_OPTION_NONE;
   struct vl_dri3_buffer *back;

   back = scrn->back_buffers[scrn->cur_back];
   if (!back)
       return;

   if (scrn->flushed) {
      while (scrn->special_event && scrn->recv_sbc < scrn->send_sbc)
         if (!dri3_wait_present_events(scrn))
            return;
   }

   xshmfence_reset(back->shm_fence);
   back->busy = true;

   xcb_present_pixmap(scrn->conn,
                      scrn->drawable,
                      back->pixmap,
                      (uint32_t)(++scrn->send_sbc),
                      0, 0, 0, 0,
                      None, None,
                      back->sync_fence,
                      options,
                      scrn->next_msc,
                      0, 0, 0, NULL);

   xcb_flush(scrn->conn);

   scrn->flushed = true;

   return;
}
Exemplo n.º 4
0
/** loader_dri3_swap_buffers_msc
 *
 * Make the current back buffer visible using the present extension
 */
int64_t
loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
                             int64_t target_msc, int64_t divisor,
                             int64_t remainder, unsigned flush_flags,
                             bool force_copy)
{
   struct loader_dri3_buffer *back;
   __DRIcontext *dri_context;
   int64_t ret = 0;
   uint32_t options = XCB_PRESENT_OPTION_NONE;
   int swap_interval;

   dri_context = draw->vtable->get_dri_context(draw);
   swap_interval = draw->vtable->get_swap_interval(draw);

   draw->vtable->flush_drawable(draw, flush_flags);

   back = draw->buffers[LOADER_DRI3_BACK_ID(draw->cur_back)];
   if (draw->is_different_gpu && back) {
      /* Update the linear buffer before presenting the pixmap */
      draw->ext->image->blitImage(dri_context,
                                  back->linear_buffer,
                                  back->image,
                                  0, 0, back->width,
                                  back->height,
                                  0, 0, back->width,
                                  back->height, __BLIT_FLAG_FLUSH);
      /* Update the fake front */
      if (draw->have_fake_front)
         draw->ext->image->blitImage(dri_context,
                                     draw->buffers[LOADER_DRI3_FRONT_ID]->image,
                                     back->image,
                                     0, 0, draw->width, draw->height,
                                     0, 0, draw->width, draw->height,
                                     __BLIT_FLAG_FLUSH);
   }

   dri3_flush_present_events(draw);

   if (back && !draw->is_pixmap) {
      dri3_fence_reset(draw->conn, back);

      /* Compute when we want the frame shown by taking the last known
       * successful MSC and adding in a swap interval for each outstanding swap
       * request. target_msc=divisor=remainder=0 means "Use glXSwapBuffers()
       * semantic"
       */
      ++draw->send_sbc;
      if (target_msc == 0 && divisor == 0 && remainder == 0)
         target_msc = draw->msc + swap_interval *
                      (draw->send_sbc - draw->recv_sbc);
      else if (divisor == 0 && remainder > 0) {
         /* From the GLX_OML_sync_control spec:
          *     "If <divisor> = 0, the swap will occur when MSC becomes
          *      greater than or equal to <target_msc>."
          *
          * Note that there's no mention of the remainder.  The Present
          * extension throws BadValue for remainder != 0 with divisor == 0, so
          * just drop the passed in value.
          */
         remainder = 0;
      }

      /* From the GLX_EXT_swap_control spec
       * and the EGL 1.4 spec (page 53):
       *
       *     "If <interval> is set to a value of 0, buffer swaps are not
       *      synchronized to a video frame."
       *
       * Implementation note: It is possible to enable triple buffering
       * behaviour by not using XCB_PRESENT_OPTION_ASYNC, but this should not be
       * the default.
       */
      if (swap_interval == 0)
          options |= XCB_PRESENT_OPTION_ASYNC;
      if (force_copy)
          options |= XCB_PRESENT_OPTION_COPY;

      back->busy = 1;
      back->last_swap = draw->send_sbc;
      xcb_present_pixmap(draw->conn,
                         draw->drawable,
                         back->pixmap,
                         (uint32_t) draw->send_sbc,
                         0,                                    /* valid */
                         0,                                    /* update */
                         0,                                    /* x_off */
                         0,                                    /* y_off */
                         None,                                 /* target_crtc */
                         None,
                         back->sync_fence,
                         options,
                         target_msc,
                         divisor,
                         remainder, 0, NULL);
      ret = (int64_t) draw->send_sbc;

      /* If there's a fake front, then copy the source back buffer
       * to the fake front to keep it up to date. This needs
       * to reset the fence and make future users block until
       * the X server is done copying the bits
       */
      if (draw->have_fake_front && !draw->is_different_gpu) {
         dri3_fence_reset(draw->conn, draw->buffers[LOADER_DRI3_FRONT_ID]);
         dri3_copy_area(draw->conn,
                        back->pixmap,
                        draw->buffers[LOADER_DRI3_FRONT_ID]->pixmap,
                        dri3_drawable_gc(draw),
                        0, 0, 0, 0,
                        draw->width, draw->height);
         dri3_fence_trigger(draw->conn, draw->buffers[LOADER_DRI3_FRONT_ID]);
      }
      xcb_flush(draw->conn);
      if (draw->stamp)
         ++(*draw->stamp);
   }

   (draw->ext->flush->invalidate)(draw->dri_drawable);

   return ret;
}
Exemplo n.º 5
0
Arquivo: dri3.c Projeto: sarnex/wine
static void PRESENTForceReleases(PRESENTpriv *present_priv)
{
    PRESENTPixmapPriv *current = NULL;

    if (!present_priv->window)
        return;

    /* There should be no other thread listening for events here.
     * This can happen when hDestWindowOverride changes without reset.
     * This case should never happen, but can happen in theory.*/
    if (present_priv->xcb_wait) {
        xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 0, 0, 0, 0);
        xcb_flush(present_priv->xcb_connection);
        pthread_mutex_lock(&present_priv->mutex_xcb_wait);
        pthread_mutex_unlock(&present_priv->mutex_xcb_wait);
        /* the problem here is that we don't have access to the event the other thread got.
         * It is either presented event, idle event or notify event.
         */
        while (present_priv->pixmap_present_pending >= 2)
            PRESENTwait_events(present_priv, FALSE);
        PRESENTflush_events(present_priv, TRUE);
        /* Remaining events to come can be a pair of present/idle,
         * or an idle, or nothing. To be sure we are after all pixmaps
         * have been presented, add an event to the queue that can only
         * be after the present event, then if we receive an event more,
         * we are sure all pixmaps were presented */
        present_priv->notify_with_serial_pending = TRUE;
        xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 1, present_priv->last_target + 5, 0, 0);
        xcb_flush(present_priv->xcb_connection);
        while (present_priv->notify_with_serial_pending)
            PRESENTwait_events(present_priv, FALSE);
        /* Now we are sure we are not expecting any new event */
    } else {
        while (present_priv->pixmap_present_pending) /* wait all sent pixmaps are presented */
            PRESENTwait_events(present_priv, FALSE);
        PRESENTflush_events(present_priv, TRUE); /* may be remaining idle event */
        /* Since idle events are send with the complete events when it is not flips,
         * we are not expecting any new event here */
    }

    current = present_priv->first_present_priv;
    while (current) {
        if (!current->released) {
            if (!current->last_present_was_flip && !present_priv->xcb_wait) {
                ERR("ERROR: a pixmap seems not released by PRESENT for no reason. Code bug.\n");
            } else {
                /* Present the same pixmap with a non-valid part to force the copy mode and the releases */
                xcb_xfixes_region_t valid, update;
                xcb_rectangle_t rect_update;
                rect_update.x = 0;
                rect_update.y = 0;
                rect_update.width = 8;
                rect_update.height = 1;
                valid = xcb_generate_id(present_priv->xcb_connection);
                update = xcb_generate_id(present_priv->xcb_connection);
                xcb_xfixes_create_region(present_priv->xcb_connection, valid, 1, &rect_update);
                xcb_xfixes_create_region(present_priv->xcb_connection, update, 1, &rect_update);
                /* here we know the pixmap has been presented. Thus if it is on screen,
                 * the following request can only make it released by the server if it is not */
                xcb_present_pixmap(present_priv->xcb_connection, present_priv->window,
                                   current->pixmap, 0, valid, update, 0, 0, None, None,
                                   None, XCB_PRESENT_OPTION_COPY | XCB_PRESENT_OPTION_ASYNC, 0, 0, 0, 0, NULL);
                xcb_flush(present_priv->xcb_connection);
                PRESENTwait_events(present_priv, FALSE); /* by assumption this can only be idle event */
                PRESENTflush_events(present_priv, TRUE); /* Shoudln't be needed */
            }
        }
        current = current->next;
    }
    /* Now all pixmaps are released (possibility if xcb_wait is true that one is not aware yet),
     * and we don't expect any new Present event to come from Xserver */
}