17ec681f3Smrg/************************************************************************** 27ec681f3Smrg * 37ec681f3Smrg * Copyright 2010 Thomas Balling Sørensen. 47ec681f3Smrg * All Rights Reserved. 57ec681f3Smrg * 67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77ec681f3Smrg * copy of this software and associated documentation files (the 87ec681f3Smrg * "Software"), to deal in the Software without restriction, including 97ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish, 107ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to 117ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to 127ec681f3Smrg * the following conditions: 137ec681f3Smrg * 147ec681f3Smrg * The above copyright notice and this permission notice (including the 157ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions 167ec681f3Smrg * of the Software. 177ec681f3Smrg * 187ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 197ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 207ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 217ec681f3Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 227ec681f3Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 237ec681f3Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 247ec681f3Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 257ec681f3Smrg * 267ec681f3Smrg **************************************************************************/ 277ec681f3Smrg 287ec681f3Smrg#include <stdio.h> 297ec681f3Smrg#include <vdpau/vdpau.h> 307ec681f3Smrg 317ec681f3Smrg#include "util/u_debug.h" 327ec681f3Smrg#include "util/u_memory.h" 337ec681f3Smrg 347ec681f3Smrg#include "vdpau_private.h" 357ec681f3Smrg 367ec681f3Smrg/** 377ec681f3Smrg * Create a VdpPresentationQueue. 387ec681f3Smrg */ 397ec681f3SmrgVdpStatus 407ec681f3SmrgvlVdpPresentationQueueCreate(VdpDevice device, 417ec681f3Smrg VdpPresentationQueueTarget presentation_queue_target, 427ec681f3Smrg VdpPresentationQueue *presentation_queue) 437ec681f3Smrg{ 447ec681f3Smrg vlVdpPresentationQueue *pq = NULL; 457ec681f3Smrg VdpStatus ret; 467ec681f3Smrg 477ec681f3Smrg if (!presentation_queue) 487ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 497ec681f3Smrg 507ec681f3Smrg vlVdpDevice *dev = vlGetDataHTAB(device); 517ec681f3Smrg if (!dev) 527ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 537ec681f3Smrg 547ec681f3Smrg vlVdpPresentationQueueTarget *pqt = vlGetDataHTAB(presentation_queue_target); 557ec681f3Smrg if (!pqt) 567ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 577ec681f3Smrg 587ec681f3Smrg if (dev != pqt->device) 597ec681f3Smrg return VDP_STATUS_HANDLE_DEVICE_MISMATCH; 607ec681f3Smrg 617ec681f3Smrg pq = CALLOC(1, sizeof(vlVdpPresentationQueue)); 627ec681f3Smrg if (!pq) 637ec681f3Smrg return VDP_STATUS_RESOURCES; 647ec681f3Smrg 657ec681f3Smrg DeviceReference(&pq->device, dev); 667ec681f3Smrg pq->drawable = pqt->drawable; 677ec681f3Smrg 687ec681f3Smrg mtx_lock(&dev->mutex); 697ec681f3Smrg if (!vl_compositor_init_state(&pq->cstate, dev->context)) { 707ec681f3Smrg mtx_unlock(&dev->mutex); 717ec681f3Smrg ret = VDP_STATUS_ERROR; 727ec681f3Smrg goto no_compositor; 737ec681f3Smrg } 747ec681f3Smrg mtx_unlock(&dev->mutex); 757ec681f3Smrg 767ec681f3Smrg *presentation_queue = vlAddDataHTAB(pq); 777ec681f3Smrg if (*presentation_queue == 0) { 787ec681f3Smrg ret = VDP_STATUS_ERROR; 797ec681f3Smrg goto no_handle; 807ec681f3Smrg } 817ec681f3Smrg 827ec681f3Smrg return VDP_STATUS_OK; 837ec681f3Smrg 847ec681f3Smrgno_handle: 857ec681f3Smrgno_compositor: 867ec681f3Smrg DeviceReference(&pq->device, NULL); 877ec681f3Smrg FREE(pq); 887ec681f3Smrg return ret; 897ec681f3Smrg} 907ec681f3Smrg 917ec681f3Smrg/** 927ec681f3Smrg * Destroy a VdpPresentationQueue. 937ec681f3Smrg */ 947ec681f3SmrgVdpStatus 957ec681f3SmrgvlVdpPresentationQueueDestroy(VdpPresentationQueue presentation_queue) 967ec681f3Smrg{ 977ec681f3Smrg vlVdpPresentationQueue *pq; 987ec681f3Smrg 997ec681f3Smrg pq = vlGetDataHTAB(presentation_queue); 1007ec681f3Smrg if (!pq) 1017ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 1027ec681f3Smrg 1037ec681f3Smrg mtx_lock(&pq->device->mutex); 1047ec681f3Smrg vl_compositor_cleanup_state(&pq->cstate); 1057ec681f3Smrg mtx_unlock(&pq->device->mutex); 1067ec681f3Smrg 1077ec681f3Smrg vlRemoveDataHTAB(presentation_queue); 1087ec681f3Smrg DeviceReference(&pq->device, NULL); 1097ec681f3Smrg FREE(pq); 1107ec681f3Smrg 1117ec681f3Smrg return VDP_STATUS_OK; 1127ec681f3Smrg} 1137ec681f3Smrg 1147ec681f3Smrg/** 1157ec681f3Smrg * Configure the background color setting. 1167ec681f3Smrg */ 1177ec681f3SmrgVdpStatus 1187ec681f3SmrgvlVdpPresentationQueueSetBackgroundColor(VdpPresentationQueue presentation_queue, 1197ec681f3Smrg VdpColor *const background_color) 1207ec681f3Smrg{ 1217ec681f3Smrg vlVdpPresentationQueue *pq; 1227ec681f3Smrg union pipe_color_union color; 1237ec681f3Smrg 1247ec681f3Smrg if (!background_color) 1257ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 1267ec681f3Smrg 1277ec681f3Smrg pq = vlGetDataHTAB(presentation_queue); 1287ec681f3Smrg if (!pq) 1297ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 1307ec681f3Smrg 1317ec681f3Smrg color.f[0] = background_color->red; 1327ec681f3Smrg color.f[1] = background_color->green; 1337ec681f3Smrg color.f[2] = background_color->blue; 1347ec681f3Smrg color.f[3] = background_color->alpha; 1357ec681f3Smrg 1367ec681f3Smrg mtx_lock(&pq->device->mutex); 1377ec681f3Smrg vl_compositor_set_clear_color(&pq->cstate, &color); 1387ec681f3Smrg mtx_unlock(&pq->device->mutex); 1397ec681f3Smrg 1407ec681f3Smrg return VDP_STATUS_OK; 1417ec681f3Smrg} 1427ec681f3Smrg 1437ec681f3Smrg/** 1447ec681f3Smrg * Retrieve the current background color setting. 1457ec681f3Smrg */ 1467ec681f3SmrgVdpStatus 1477ec681f3SmrgvlVdpPresentationQueueGetBackgroundColor(VdpPresentationQueue presentation_queue, 1487ec681f3Smrg VdpColor *const background_color) 1497ec681f3Smrg{ 1507ec681f3Smrg vlVdpPresentationQueue *pq; 1517ec681f3Smrg union pipe_color_union color; 1527ec681f3Smrg 1537ec681f3Smrg if (!background_color) 1547ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 1557ec681f3Smrg 1567ec681f3Smrg pq = vlGetDataHTAB(presentation_queue); 1577ec681f3Smrg if (!pq) 1587ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 1597ec681f3Smrg 1607ec681f3Smrg mtx_lock(&pq->device->mutex); 1617ec681f3Smrg vl_compositor_get_clear_color(&pq->cstate, &color); 1627ec681f3Smrg mtx_unlock(&pq->device->mutex); 1637ec681f3Smrg 1647ec681f3Smrg background_color->red = color.f[0]; 1657ec681f3Smrg background_color->green = color.f[1]; 1667ec681f3Smrg background_color->blue = color.f[2]; 1677ec681f3Smrg background_color->alpha = color.f[3]; 1687ec681f3Smrg 1697ec681f3Smrg return VDP_STATUS_OK; 1707ec681f3Smrg} 1717ec681f3Smrg 1727ec681f3Smrg/** 1737ec681f3Smrg * Retrieve the presentation queue's "current" time. 1747ec681f3Smrg */ 1757ec681f3SmrgVdpStatus 1767ec681f3SmrgvlVdpPresentationQueueGetTime(VdpPresentationQueue presentation_queue, 1777ec681f3Smrg VdpTime *current_time) 1787ec681f3Smrg{ 1797ec681f3Smrg vlVdpPresentationQueue *pq; 1807ec681f3Smrg 1817ec681f3Smrg if (!current_time) 1827ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 1837ec681f3Smrg 1847ec681f3Smrg pq = vlGetDataHTAB(presentation_queue); 1857ec681f3Smrg if (!pq) 1867ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 1877ec681f3Smrg 1887ec681f3Smrg mtx_lock(&pq->device->mutex); 1897ec681f3Smrg *current_time = pq->device->vscreen->get_timestamp(pq->device->vscreen, 1907ec681f3Smrg (void *)pq->drawable); 1917ec681f3Smrg mtx_unlock(&pq->device->mutex); 1927ec681f3Smrg 1937ec681f3Smrg return VDP_STATUS_OK; 1947ec681f3Smrg} 1957ec681f3Smrg 1967ec681f3Smrg/** 1977ec681f3Smrg * Enter a surface into the presentation queue. 1987ec681f3Smrg */ 1997ec681f3SmrgVdpStatus 2007ec681f3SmrgvlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue, 2017ec681f3Smrg VdpOutputSurface surface, 2027ec681f3Smrg uint32_t clip_width, 2037ec681f3Smrg uint32_t clip_height, 2047ec681f3Smrg VdpTime earliest_presentation_time) 2057ec681f3Smrg{ 2067ec681f3Smrg static int dump_window = -1; 2077ec681f3Smrg 2087ec681f3Smrg vlVdpPresentationQueue *pq; 2097ec681f3Smrg vlVdpOutputSurface *surf; 2107ec681f3Smrg 2117ec681f3Smrg struct pipe_context *pipe; 2127ec681f3Smrg struct pipe_resource *tex; 2137ec681f3Smrg struct pipe_surface surf_templ, *surf_draw = NULL; 2147ec681f3Smrg struct u_rect src_rect, dst_clip, *dirty_area; 2157ec681f3Smrg 2167ec681f3Smrg struct vl_compositor *compositor; 2177ec681f3Smrg struct vl_compositor_state *cstate; 2187ec681f3Smrg struct vl_screen *vscreen; 2197ec681f3Smrg 2207ec681f3Smrg pq = vlGetDataHTAB(presentation_queue); 2217ec681f3Smrg if (!pq) 2227ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 2237ec681f3Smrg 2247ec681f3Smrg surf = vlGetDataHTAB(surface); 2257ec681f3Smrg if (!surf) 2267ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 2277ec681f3Smrg 2287ec681f3Smrg pipe = pq->device->context; 2297ec681f3Smrg compositor = &pq->device->compositor; 2307ec681f3Smrg cstate = &pq->cstate; 2317ec681f3Smrg vscreen = pq->device->vscreen; 2327ec681f3Smrg 2337ec681f3Smrg mtx_lock(&pq->device->mutex); 2347ec681f3Smrg if (vscreen->set_back_texture_from_output && surf->send_to_X) 2357ec681f3Smrg vscreen->set_back_texture_from_output(vscreen, surf->surface->texture, clip_width, clip_height); 2367ec681f3Smrg tex = vscreen->texture_from_drawable(vscreen, (void *)pq->drawable); 2377ec681f3Smrg if (!tex) { 2387ec681f3Smrg mtx_unlock(&pq->device->mutex); 2397ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 2407ec681f3Smrg } 2417ec681f3Smrg 2427ec681f3Smrg if (!vscreen->set_back_texture_from_output || !surf->send_to_X) { 2437ec681f3Smrg dirty_area = vscreen->get_dirty_area(vscreen); 2447ec681f3Smrg 2457ec681f3Smrg memset(&surf_templ, 0, sizeof(surf_templ)); 2467ec681f3Smrg surf_templ.format = tex->format; 2477ec681f3Smrg surf_draw = pipe->create_surface(pipe, tex, &surf_templ); 2487ec681f3Smrg 2497ec681f3Smrg dst_clip.x0 = 0; 2507ec681f3Smrg dst_clip.y0 = 0; 2517ec681f3Smrg dst_clip.x1 = clip_width ? clip_width : surf_draw->width; 2527ec681f3Smrg dst_clip.y1 = clip_height ? clip_height : surf_draw->height; 2537ec681f3Smrg 2547ec681f3Smrg src_rect.x0 = 0; 2557ec681f3Smrg src_rect.y0 = 0; 2567ec681f3Smrg src_rect.x1 = surf_draw->width; 2577ec681f3Smrg src_rect.y1 = surf_draw->height; 2587ec681f3Smrg 2597ec681f3Smrg vl_compositor_clear_layers(cstate); 2607ec681f3Smrg vl_compositor_set_rgba_layer(cstate, compositor, 0, surf->sampler_view, &src_rect, NULL, NULL); 2617ec681f3Smrg vl_compositor_set_dst_clip(cstate, &dst_clip); 2627ec681f3Smrg vl_compositor_render(cstate, compositor, surf_draw, dirty_area, true); 2637ec681f3Smrg } 2647ec681f3Smrg 2657ec681f3Smrg vscreen->set_next_timestamp(vscreen, earliest_presentation_time); 2667ec681f3Smrg 2677ec681f3Smrg // flush before calling flush_frontbuffer so that rendering is flushed 2687ec681f3Smrg // to back buffer so the texture can be copied in flush_frontbuffer 2697ec681f3Smrg pipe->screen->fence_reference(pipe->screen, &surf->fence, NULL); 2707ec681f3Smrg pipe->flush(pipe, &surf->fence, 0); 2717ec681f3Smrg pipe->screen->flush_frontbuffer(pipe->screen, pipe, tex, 0, 0, 2727ec681f3Smrg vscreen->get_private(vscreen), NULL); 2737ec681f3Smrg 2747ec681f3Smrg pq->last_surf = surf; 2757ec681f3Smrg 2767ec681f3Smrg if (dump_window == -1) { 2777ec681f3Smrg dump_window = debug_get_num_option("VDPAU_DUMP", 0); 2787ec681f3Smrg } 2797ec681f3Smrg 2807ec681f3Smrg if (dump_window) { 2817ec681f3Smrg static unsigned int framenum = 0; 2827ec681f3Smrg char cmd[256]; 2837ec681f3Smrg 2847ec681f3Smrg if (framenum) { 2857ec681f3Smrg sprintf(cmd, "xwd -id %d -silent -out vdpau_frame_%08d.xwd", (int)pq->drawable, framenum); 2867ec681f3Smrg if (system(cmd) != 0) 2877ec681f3Smrg VDPAU_MSG(VDPAU_ERR, "[VDPAU] Dumping surface %d failed.\n", surface); 2887ec681f3Smrg } 2897ec681f3Smrg framenum++; 2907ec681f3Smrg } 2917ec681f3Smrg 2927ec681f3Smrg if (!vscreen->set_back_texture_from_output || !surf->send_to_X) { 2937ec681f3Smrg pipe_resource_reference(&tex, NULL); 2947ec681f3Smrg pipe_surface_reference(&surf_draw, NULL); 2957ec681f3Smrg } 2967ec681f3Smrg mtx_unlock(&pq->device->mutex); 2977ec681f3Smrg 2987ec681f3Smrg return VDP_STATUS_OK; 2997ec681f3Smrg} 3007ec681f3Smrg 3017ec681f3Smrg/** 3027ec681f3Smrg * Wait for a surface to finish being displayed. 3037ec681f3Smrg */ 3047ec681f3SmrgVdpStatus 3057ec681f3SmrgvlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_queue, 3067ec681f3Smrg VdpOutputSurface surface, 3077ec681f3Smrg VdpTime *first_presentation_time) 3087ec681f3Smrg{ 3097ec681f3Smrg vlVdpPresentationQueue *pq; 3107ec681f3Smrg vlVdpOutputSurface *surf; 3117ec681f3Smrg struct pipe_screen *screen; 3127ec681f3Smrg 3137ec681f3Smrg if (!first_presentation_time) 3147ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 3157ec681f3Smrg 3167ec681f3Smrg pq = vlGetDataHTAB(presentation_queue); 3177ec681f3Smrg if (!pq) 3187ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 3197ec681f3Smrg 3207ec681f3Smrg surf = vlGetDataHTAB(surface); 3217ec681f3Smrg if (!surf) 3227ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 3237ec681f3Smrg 3247ec681f3Smrg mtx_lock(&pq->device->mutex); 3257ec681f3Smrg if (surf->fence) { 3267ec681f3Smrg screen = pq->device->vscreen->pscreen; 3277ec681f3Smrg screen->fence_finish(screen, NULL, surf->fence, PIPE_TIMEOUT_INFINITE); 3287ec681f3Smrg screen->fence_reference(screen, &surf->fence, NULL); 3297ec681f3Smrg } 3307ec681f3Smrg mtx_unlock(&pq->device->mutex); 3317ec681f3Smrg 3327ec681f3Smrg return vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time); 3337ec681f3Smrg} 3347ec681f3Smrg 3357ec681f3Smrg/** 3367ec681f3Smrg * Poll the current queue status of a surface. 3377ec681f3Smrg */ 3387ec681f3SmrgVdpStatus 3397ec681f3SmrgvlVdpPresentationQueueQuerySurfaceStatus(VdpPresentationQueue presentation_queue, 3407ec681f3Smrg VdpOutputSurface surface, 3417ec681f3Smrg VdpPresentationQueueStatus *status, 3427ec681f3Smrg VdpTime *first_presentation_time) 3437ec681f3Smrg{ 3447ec681f3Smrg vlVdpPresentationQueue *pq; 3457ec681f3Smrg vlVdpOutputSurface *surf; 3467ec681f3Smrg struct pipe_screen *screen; 3477ec681f3Smrg 3487ec681f3Smrg if (!(status && first_presentation_time)) 3497ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 3507ec681f3Smrg 3517ec681f3Smrg pq = vlGetDataHTAB(presentation_queue); 3527ec681f3Smrg if (!pq) 3537ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 3547ec681f3Smrg 3557ec681f3Smrg surf = vlGetDataHTAB(surface); 3567ec681f3Smrg if (!surf) 3577ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 3587ec681f3Smrg 3597ec681f3Smrg *first_presentation_time = 0; 3607ec681f3Smrg 3617ec681f3Smrg if (!surf->fence) { 3627ec681f3Smrg if (pq->last_surf == surf) 3637ec681f3Smrg *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE; 3647ec681f3Smrg else 3657ec681f3Smrg *status = VDP_PRESENTATION_QUEUE_STATUS_IDLE; 3667ec681f3Smrg } else { 3677ec681f3Smrg mtx_lock(&pq->device->mutex); 3687ec681f3Smrg screen = pq->device->vscreen->pscreen; 3697ec681f3Smrg if (screen->fence_finish(screen, NULL, surf->fence, 0)) { 3707ec681f3Smrg screen->fence_reference(screen, &surf->fence, NULL); 3717ec681f3Smrg *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE; 3727ec681f3Smrg mtx_unlock(&pq->device->mutex); 3737ec681f3Smrg 3747ec681f3Smrg // We actually need to query the timestamp of the last VSYNC event from the hardware 3757ec681f3Smrg vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time); 3767ec681f3Smrg *first_presentation_time += 1; 3777ec681f3Smrg } else { 3787ec681f3Smrg *status = VDP_PRESENTATION_QUEUE_STATUS_QUEUED; 3797ec681f3Smrg mtx_unlock(&pq->device->mutex); 3807ec681f3Smrg } 3817ec681f3Smrg } 3827ec681f3Smrg 3837ec681f3Smrg return VDP_STATUS_OK; 3847ec681f3Smrg} 385