From: Christian König Date: Thu, 1 Mar 2012 11:42:20 +0000 (+0100) Subject: st/vdpau: implement support for high-precision output timing X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1d0c357a9733238985cbe029b174173ef927ac70;p=mesa.git st/vdpau: implement support for high-precision output timing Signed-off-by: Christian König --- diff --git a/src/gallium/state_trackers/vdpau/presentation.c b/src/gallium/state_trackers/vdpau/presentation.c index 397bd372577..cd00e54a988 100644 --- a/src/gallium/state_trackers/vdpau/presentation.c +++ b/src/gallium/state_trackers/vdpau/presentation.c @@ -26,9 +26,6 @@ **************************************************************************/ #include -#include -#include - #include #include "util/u_debug.h" @@ -169,7 +166,6 @@ vlVdpPresentationQueueGetTime(VdpPresentationQueue presentation_queue, VdpTime *current_time) { vlVdpPresentationQueue *pq; - struct timespec ts; if (!current_time) return VDP_STATUS_INVALID_POINTER; @@ -178,8 +174,7 @@ vlVdpPresentationQueueGetTime(VdpPresentationQueue presentation_queue, if (!pq) return VDP_STATUS_INVALID_HANDLE; - clock_gettime(CLOCK_REALTIME, &ts); - *current_time = (uint64_t)ts.tv_sec * 1000000000LL + (uint64_t)ts.tv_nsec; + *current_time = vl_screen_get_timestamp(pq->device->vscreen, pq->drawable); return VDP_STATUS_OK; } @@ -260,6 +255,7 @@ vlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue, vl_compositor_render(cstate, compositor, surf_draw, dirty_area); } + vl_screen_set_next_timestamp(pq->device->vscreen, earliest_presentation_time); pipe->screen->flush_frontbuffer ( pipe->screen, tex, 0, 0, @@ -316,10 +312,7 @@ vlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_qu screen->fence_finish(screen, surf->fence, 0); } - // We actually need to query the timestamp of the last VSYNC event from the hardware - vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time); - - return VDP_STATUS_OK; + return vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time); } /** diff --git a/src/gallium/winsys/g3dvl/dri/dri_winsys.c b/src/gallium/winsys/g3dvl/dri/dri_winsys.c index c1e4a54bc49..c65c82c8b05 100644 --- a/src/gallium/winsys/g3dvl/dri/dri_winsys.c +++ b/src/gallium/winsys/g3dvl/dri/dri_winsys.c @@ -62,10 +62,54 @@ struct vl_dri_screen xcb_dri2_swap_buffers_cookie_t swap_cookie; xcb_dri2_wait_sbc_cookie_t wait_cookie; xcb_dri2_get_buffers_cookie_t buffers_cookie; + + int64_t last_ust, ns_frame, last_msc, next_msc, skew_msc; }; static const unsigned int attachments[1] = { XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT }; +static void +vl_dri2_handle_stamps(struct vl_dri_screen* scrn, + uint32_t ust_hi, uint32_t ust_lo, + uint32_t msc_hi, uint32_t msc_lo) +{ + int64_t ust = ((((uint64_t)ust_hi) << 32) | ust_lo) * 1000; + int64_t msc = (((uint64_t)msc_hi) << 32) | msc_lo; + + if (scrn->last_ust && scrn->last_msc && (ust > scrn->last_ust) && (msc > scrn->last_msc)) + scrn->ns_frame = (ust - scrn->last_ust) / (msc - scrn->last_msc); + + if (scrn->next_msc && (scrn->next_msc < msc)) + scrn->skew_msc++; + + scrn->last_ust = ust; + scrn->last_msc = msc; +} + +static xcb_dri2_get_buffers_reply_t* +vl_dri2_get_flush_reply(struct vl_dri_screen *scrn) +{ + xcb_dri2_wait_sbc_reply_t *wait_sbc_reply; + + assert(scrn); + + if (!scrn->flushed) + return NULL; + + scrn->flushed = false; + + free(xcb_dri2_swap_buffers_reply(scrn->conn, scrn->swap_cookie, NULL)); + + wait_sbc_reply = xcb_dri2_wait_sbc_reply(scrn->conn, scrn->wait_cookie, NULL); + if (!wait_sbc_reply) + return NULL; + vl_dri2_handle_stamps(scrn, wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo, + wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo); + free(wait_sbc_reply); + + return xcb_dri2_get_buffers_reply(scrn->conn, scrn->buffers_cookie, NULL); +} + static void vl_dri2_flush_frontbuffer(struct pipe_screen *screen, struct pipe_resource *resource, @@ -73,20 +117,22 @@ vl_dri2_flush_frontbuffer(struct pipe_screen *screen, void *context_private) { struct vl_dri_screen *scrn = (struct vl_dri_screen*)context_private; + uint32_t msc_hi, msc_lo; assert(screen); assert(resource); assert(context_private); - if (scrn->flushed) - free(xcb_dri2_swap_buffers_reply(scrn->conn, scrn->swap_cookie, NULL)); - else - scrn->flushed = true; + free(vl_dri2_get_flush_reply(scrn)); + + msc_hi = scrn->next_msc >> 32; + msc_lo = scrn->next_msc & 0xFFFFFFFF; - scrn->swap_cookie = xcb_dri2_swap_buffers_unchecked(scrn->conn, scrn->drawable, 0, 0, 0, 0, 0, 0); + scrn->swap_cookie = xcb_dri2_swap_buffers_unchecked(scrn->conn, scrn->drawable, msc_hi, msc_lo, 0, 0, 0, 0); scrn->wait_cookie = xcb_dri2_wait_sbc_unchecked(scrn->conn, scrn->drawable, 0, 0); scrn->buffers_cookie = xcb_dri2_get_buffers_unchecked(scrn->conn, scrn->drawable, 1, 1, attachments); + scrn->flushed = true; scrn->current_buffer = !scrn->current_buffer; } @@ -95,12 +141,31 @@ vl_dri2_destroy_drawable(struct vl_dri_screen *scrn) { xcb_void_cookie_t destroy_cookie; if (scrn->drawable) { + free(vl_dri2_get_flush_reply(scrn)); destroy_cookie = xcb_dri2_destroy_drawable_checked(scrn->conn, scrn->drawable); /* ignore any error here, since the drawable can be destroyed long ago */ free(xcb_request_check(scrn->conn, destroy_cookie)); } } +static void +vl_dri2_set_drawable(struct vl_dri_screen *scrn, Drawable drawable) +{ + assert(scrn); + assert(drawable); + + if (scrn->drawable == drawable) + return; + + vl_dri2_destroy_drawable(scrn); + + xcb_dri2_create_drawable(scrn->conn, drawable); + scrn->current_buffer = false; + vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]); + vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]); + scrn->drawable = drawable; +} + struct pipe_resource* vl_screen_texture_from_drawable(struct vl_screen *vscreen, Drawable drawable) { @@ -114,42 +179,23 @@ vl_screen_texture_from_drawable(struct vl_screen *vscreen, Drawable drawable) assert(scrn); - if (scrn->flushed) { - free(xcb_dri2_swap_buffers_reply(scrn->conn, scrn->swap_cookie, NULL)); - free(xcb_dri2_wait_sbc_reply(scrn->conn, scrn->wait_cookie, NULL)); + vl_dri2_set_drawable(scrn, drawable); + reply = vl_dri2_get_flush_reply(scrn); + if (!reply) { + xcb_dri2_get_buffers_cookie_t cookie; + cookie = xcb_dri2_get_buffers_unchecked(scrn->conn, drawable, 1, 1, attachments); + reply = xcb_dri2_get_buffers_reply(scrn->conn, cookie, NULL); } - - if (scrn->drawable != drawable) { - vl_dri2_destroy_drawable(scrn); - xcb_dri2_create_drawable(scrn->conn, drawable); - scrn->current_buffer = false; - vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]); - vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]); - scrn->drawable = drawable; - - if (scrn->flushed) { - free(xcb_dri2_get_buffers_reply(scrn->conn, scrn->buffers_cookie, NULL)); - scrn->flushed = false; - } - } - - if (!scrn->flushed) - scrn->buffers_cookie = xcb_dri2_get_buffers_unchecked(scrn->conn, drawable, 1, 1, attachments); - else - scrn->flushed = false; - - reply = xcb_dri2_get_buffers_reply(scrn->conn, scrn->buffers_cookie, NULL); if (!reply) return NULL; + assert(reply->count == 1); buffers = xcb_dri2_get_buffers_buffers(reply); if (!buffers) { free(reply); return NULL; } - assert(reply->count == 1); - if (reply->width != scrn->width || reply->height != scrn->height) { vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]); vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]); @@ -192,6 +238,40 @@ vl_screen_get_dirty_area(struct vl_screen *vscreen) return &scrn->dirty_areas[scrn->current_buffer]; } +uint64_t +vl_screen_get_timestamp(struct vl_screen *vscreen, Drawable drawable) +{ + struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen; + xcb_dri2_get_msc_cookie_t cookie; + xcb_dri2_get_msc_reply_t *reply; + + assert(scrn); + + vl_dri2_set_drawable(scrn, drawable); + if (!scrn->last_ust) { + cookie = xcb_dri2_get_msc_unchecked(scrn->conn, drawable); + reply = xcb_dri2_get_msc_reply(scrn->conn, cookie, NULL); + + if (reply) { + vl_dri2_handle_stamps(scrn, reply->ust_hi, reply->ust_lo, + reply->msc_hi, reply->msc_lo); + free(reply); + } + } + return scrn->last_ust; +} + +void +vl_screen_set_next_timestamp(struct vl_screen *vscreen, uint64_t stamp) +{ + struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen; + assert(scrn); + if (stamp && scrn->last_ust && scrn->ns_frame && scrn->last_msc) + scrn->next_msc = ((int64_t)stamp - scrn->last_ust) / scrn->ns_frame + scrn->last_msc + scrn->skew_msc; + else + scrn->next_msc = 0; +} + void* vl_screen_get_private(struct vl_screen *vscreen) { diff --git a/src/gallium/winsys/g3dvl/vl_winsys.h b/src/gallium/winsys/g3dvl/vl_winsys.h index 281a391266d..174f780001f 100644 --- a/src/gallium/winsys/g3dvl/vl_winsys.h +++ b/src/gallium/winsys/g3dvl/vl_winsys.h @@ -51,6 +51,12 @@ vl_screen_texture_from_drawable(struct vl_screen *vscreen, Drawable drawable); struct u_rect * vl_screen_get_dirty_area(struct vl_screen *vscreen); +uint64_t +vl_screen_get_timestamp(struct vl_screen *vscreen, Drawable drawable); + +void +vl_screen_set_next_timestamp(struct vl_screen *vscreen, uint64_t stamp); + void* vl_screen_get_private(struct vl_screen *vscreen); diff --git a/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c b/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c index a4f5326d8c0..1d5d1eaf748 100644 --- a/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c +++ b/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c @@ -25,6 +25,8 @@ * **************************************************************************/ +#include + #include "pipe/p_state.h" #include "util/u_memory.h" @@ -100,6 +102,20 @@ vl_screen_get_dirty_area(struct vl_screen *vscreen) return &xsp_screen->dirty_area; } +uint64_t +vl_screen_get_timestamp(struct vl_screen *vscreen, Drawable drawable) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t)tv.tv_sec * 1000000000LL + (uint64_t)tv.tv_usec * 1000LL; +} + +void +vl_screen_set_next_timestamp(struct vl_screen *vscreen, uint64_t stamp) +{ + /* not supported on softpipe and so only a dummy */ +} + void* vl_screen_get_private(struct vl_screen *vscreen) {