/** loader_dri3_wait_for_msc * * Get the X server to send an event when the target msc/divisor/remainder is * reached. */ bool loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) { uint32_t msc_serial; msc_serial = ++draw->send_msc_serial; xcb_present_notify_msc(draw->conn, draw->drawable, msc_serial, target_msc, divisor, remainder); xcb_flush(draw->conn); /* Wait for the event */ if (draw->special_event) { while ((int32_t) (msc_serial - draw->recv_msc_serial) > 0) { if (!dri3_wait_for_event(draw)) return false; } } *ust = draw->notify_ust; *msc = draw->notify_msc; *sbc = draw->recv_sbc; return true; }
static uint64_t vl_dri3_screen_get_timestamp(struct vl_screen *vscreen, void *drawable) { struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen; assert(scrn); if (!dri3_set_drawable(scrn, (Drawable)drawable)) return 0; if (!scrn->last_ust) { xcb_present_notify_msc(scrn->conn, scrn->drawable, ++scrn->send_msc_serial, 0, 0, 0); xcb_flush(scrn->conn); while (scrn->special_event && scrn->send_msc_serial > scrn->recv_msc_serial) { if (!dri3_wait_present_events(scrn)) return 0; } } return scrn->last_ust; }
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 */ }