示例#1
0
static void
vl_dri3_screen_destroy(struct vl_screen *vscreen)
{
   struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
   int i;

   assert(vscreen);

   dri3_flush_present_events(scrn);

   if (scrn->front_buffer) {
      dri3_free_front_buffer(scrn, scrn->front_buffer);
      scrn->front_buffer = NULL;
      return;
   }

   for (i = 0; i < BACK_BUFFER_NUM; ++i) {
      if (scrn->back_buffers[i]) {
         dri3_free_back_buffer(scrn, scrn->back_buffers[i]);
         scrn->back_buffers[i] = NULL;
      }
   }

   if (scrn->special_event)
      xcb_unregister_for_special_event(scrn->conn, scrn->special_event);
   scrn->base.pscreen->destroy(scrn->base.pscreen);
   pipe_loader_release(&scrn->base.dev, 1);
   FREE(scrn);

   return;
}
示例#2
0
static bool
dri3_set_drawable(struct vl_dri3_screen *scrn, Drawable drawable)
{
   xcb_get_geometry_cookie_t geom_cookie;
   xcb_get_geometry_reply_t *geom_reply;
   xcb_void_cookie_t cookie;
   xcb_generic_error_t *error;
   xcb_present_event_t peid;
   bool ret = true;

   assert(drawable);

   if (scrn->drawable == drawable)
      return true;

   scrn->drawable = drawable;

   geom_cookie = xcb_get_geometry(scrn->conn, scrn->drawable);
   geom_reply = xcb_get_geometry_reply(scrn->conn, geom_cookie, NULL);
   if (!geom_reply)
      return false;

   scrn->width = geom_reply->width;
   scrn->height = geom_reply->height;
   scrn->depth = geom_reply->depth;
   free(geom_reply);

   if (scrn->special_event) {
      xcb_unregister_for_special_event(scrn->conn, scrn->special_event);
      scrn->special_event = NULL;
   }

   scrn->is_pixmap = false;
   peid = xcb_generate_id(scrn->conn);
   cookie =
      xcb_present_select_input_checked(scrn->conn, peid, scrn->drawable,
                      XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
                      XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
                      XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);

   error = xcb_request_check(scrn->conn, cookie);
   if (error) {
      if (error->error_code != BadWindow)
         ret = false;
      else {
         scrn->is_pixmap = true;
         if (scrn->front_buffer) {
            dri3_free_front_buffer(scrn, scrn->front_buffer);
            scrn->front_buffer = NULL;
         }
      }
      free(error);
   } else
      scrn->special_event =
         xcb_register_for_special_xge(scrn->conn, &xcb_present_id, peid, 0);

   dri3_flush_present_events(scrn);

   return ret;
}
示例#3
0
static void
vl_dri3_screen_destroy(struct vl_screen *vscreen)
{
   struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
   int i;

   assert(vscreen);

   dri3_flush_present_events(scrn);

   if (scrn->front_buffer) {
      dri3_free_front_buffer(scrn, scrn->front_buffer);
      scrn->front_buffer = NULL;
   }

   for (i = 0; i < BACK_BUFFER_NUM; ++i) {
      if (scrn->back_buffers[i]) {
         dri3_free_back_buffer(scrn, scrn->back_buffers[i]);
         scrn->back_buffers[i] = NULL;
      }
   }

   if (scrn->special_event) {
      xcb_void_cookie_t cookie =
         xcb_present_select_input_checked(scrn->conn, scrn->eid,
                                          scrn->drawable,
                                          XCB_PRESENT_EVENT_MASK_NO_EVENT);

      xcb_discard_reply(scrn->conn, cookie.sequence);
      xcb_unregister_for_special_event(scrn->conn, scrn->special_event);
   }
   scrn->pipe->destroy(scrn->pipe);
   scrn->base.pscreen->destroy(scrn->base.pscreen);
   pipe_loader_release(&scrn->base.dev, 1);
   FREE(scrn);

   return;
}
示例#4
0
/** loader_dri3_update_drawable
 *
 * Called the first time we use the drawable and then
 * after we receive present configure notify events to
 * track the geometry of the drawable
 */
static int
dri3_update_drawable(__DRIdrawable *driDrawable,
                     struct loader_dri3_drawable *draw)
{
   if (draw->first_init) {
      xcb_get_geometry_cookie_t                 geom_cookie;
      xcb_get_geometry_reply_t                  *geom_reply;
      xcb_void_cookie_t                         cookie;
      xcb_generic_error_t                       *error;
      xcb_present_query_capabilities_cookie_t   present_capabilities_cookie;
      xcb_present_query_capabilities_reply_t    *present_capabilities_reply;

      draw->first_init = false;

      /* Try to select for input on the window.
       *
       * If the drawable is a window, this will get our events
       * delivered.
       *
       * Otherwise, we'll get a BadWindow error back from this request which
       * will let us know that the drawable is a pixmap instead.
       */

      draw->eid = xcb_generate_id(draw->conn);
      cookie =
         xcb_present_select_input_checked(draw->conn, draw->eid, draw->drawable,
                                          XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
                                          XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
                                          XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);

      present_capabilities_cookie =
         xcb_present_query_capabilities(draw->conn, draw->drawable);

      /* Create an XCB event queue to hold present events outside of the usual
       * application event queue
       */
      draw->special_event = xcb_register_for_special_xge(draw->conn,
                                                         &xcb_present_id,
                                                         draw->eid,
                                                         draw->stamp);
      geom_cookie = xcb_get_geometry(draw->conn, draw->drawable);

      geom_reply = xcb_get_geometry_reply(draw->conn, geom_cookie, NULL);

      if (!geom_reply)
         return false;

      draw->width = geom_reply->width;
      draw->height = geom_reply->height;
      draw->depth = geom_reply->depth;
      draw->vtable->set_drawable_size(draw, draw->width, draw->height);

      free(geom_reply);

      draw->is_pixmap = false;

      /* Check to see if our select input call failed. If it failed with a
       * BadWindow error, then assume the drawable is a pixmap. Destroy the
       * special event queue created above and mark the drawable as a pixmap
       */

      error = xcb_request_check(draw->conn, cookie);

      present_capabilities_reply =
          xcb_present_query_capabilities_reply(draw->conn,
                                               present_capabilities_cookie,
                                               NULL);

      if (present_capabilities_reply) {
         draw->present_capabilities = present_capabilities_reply->capabilities;
         free(present_capabilities_reply);
      } else
         draw->present_capabilities = 0;

      if (error) {
         if (error->error_code != BadWindow) {
            free(error);
            return false;
         }
         draw->is_pixmap = true;
         xcb_unregister_for_special_event(draw->conn, draw->special_event);
         draw->special_event = NULL;
      }
   }
   dri3_flush_present_events(draw);
   return true;
}
示例#5
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;
}