/** * Enter a surface into the presentation queue. */ VdpStatus vlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue, VdpOutputSurface surface, uint32_t clip_width, uint32_t clip_height, VdpTime earliest_presentation_time) { static int dump_window = -1; vlVdpPresentationQueue *pq; vlVdpOutputSurface *surf; struct pipe_context *pipe; struct pipe_resource *tex; struct pipe_surface surf_templ, *surf_draw; struct u_rect src_rect, dst_clip, *dirty_area; struct vl_compositor *compositor; struct vl_compositor_state *cstate; pq = vlGetDataHTAB(presentation_queue); if (!pq) return VDP_STATUS_INVALID_HANDLE; surf = vlGetDataHTAB(surface); if (!surf) return VDP_STATUS_INVALID_HANDLE; pipe = pq->device->context; compositor = &pq->device->compositor; cstate = &pq->cstate; pipe_mutex_lock(pq->device->mutex); tex = vl_screen_texture_from_drawable(pq->device->vscreen, pq->drawable); if (!tex) { pipe_mutex_unlock(pq->device->mutex); return VDP_STATUS_INVALID_HANDLE; } dirty_area = vl_screen_get_dirty_area(pq->device->vscreen); memset(&surf_templ, 0, sizeof(surf_templ)); surf_templ.format = tex->format; surf_templ.usage = PIPE_BIND_RENDER_TARGET; surf_draw = pipe->create_surface(pipe, tex, &surf_templ); surf->timestamp = (vlVdpTime)earliest_presentation_time; dst_clip.x0 = 0; dst_clip.y0 = 0; dst_clip.x1 = clip_width ? clip_width : surf_draw->width; dst_clip.y1 = clip_height ? clip_height : surf_draw->height; if (pq->device->delayed_rendering.surface == surface && dst_clip.x1 == surf_draw->width && dst_clip.y1 == surf_draw->height) { // TODO: we correctly support the clipping here, but not the pq background color in the clipped area.... cstate = pq->device->delayed_rendering.cstate; vl_compositor_set_dst_clip(cstate, &dst_clip); vlVdpResolveDelayedRendering(pq->device, surf_draw, dirty_area); } else { vlVdpResolveDelayedRendering(pq->device, NULL, NULL); src_rect.x0 = 0; src_rect.y0 = 0; src_rect.x1 = surf_draw->width; src_rect.y1 = surf_draw->height; vl_compositor_clear_layers(cstate); vl_compositor_set_rgba_layer(cstate, compositor, 0, surf->sampler_view, &src_rect, NULL, NULL); vl_compositor_set_dst_clip(cstate, &dst_clip); 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, vl_screen_get_private(pq->device->vscreen) ); pipe->screen->fence_reference(pipe->screen, &surf->fence, NULL); pipe->flush(pipe, &surf->fence); if (dump_window == -1) { dump_window = debug_get_num_option("VDPAU_DUMP", 0); } if (dump_window) { static unsigned int framenum = 0; char cmd[256]; if (framenum) { sprintf(cmd, "xwd -id %d -silent -out vdpau_frame_%08d.xwd", (int)pq->drawable, framenum); if (system(cmd) != 0) VDPAU_MSG(VDPAU_ERR, "[VDPAU] Dumping surface %d failed.\n", surface); } framenum++; } pipe_resource_reference(&tex, NULL); pipe_surface_reference(&surf_draw, NULL); pipe_mutex_unlock(pq->device->mutex); return VDP_STATUS_OK; }
VAStatus vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short srcx, short srcy, unsigned short srcw, unsigned short srch, short destx, short desty, unsigned short destw, unsigned short desth, VARectangle *cliprects, unsigned int number_cliprects, unsigned int flags) { vlVaDriver *drv; vlVaSurface *surf; struct pipe_screen *screen; struct pipe_resource *tex; struct pipe_surface surf_templ, *surf_draw; struct u_rect src_rect, *dirty_area; struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth}; VAStatus status; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); surf = handle_table_get(drv->htab, surface_id); if (!surf) return VA_STATUS_ERROR_INVALID_SURFACE; screen = drv->pipe->screen; if(surf->fence) { screen->fence_finish(screen, surf->fence, PIPE_TIMEOUT_INFINITE); screen->fence_reference(screen, &surf->fence, NULL); } tex = vl_screen_texture_from_drawable(drv->vscreen, (Drawable)draw); if (!tex) return VA_STATUS_ERROR_INVALID_DISPLAY; dirty_area = vl_screen_get_dirty_area(drv->vscreen); memset(&surf_templ, 0, sizeof(surf_templ)); surf_templ.format = tex->format; surf_draw = drv->pipe->create_surface(drv->pipe, tex, &surf_templ); if (!surf_draw) { pipe_resource_reference(&tex, NULL); return VA_STATUS_ERROR_INVALID_DISPLAY; } src_rect.x0 = srcx; src_rect.y0 = srcy; src_rect.x1 = srcw + srcx; src_rect.y1 = srch + srcy; vl_compositor_clear_layers(&drv->cstate); vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, surf->buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE); vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect); vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, true); status = vlVaPutSubpictures(surf, drv, surf_draw, dirty_area, &src_rect, &dst_rect); if (status) return status; screen->flush_frontbuffer ( screen, tex, 0, 0, vl_screen_get_private(drv->vscreen), NULL ); screen->fence_reference(screen, &surf->fence, NULL); drv->pipe->flush(drv->pipe, &surf->fence, 0); pipe_resource_reference(&tex, NULL); pipe_surface_reference(&surf_draw, NULL); return VA_STATUS_SUCCESS; }
PUBLIC Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable, short srcx, short srcy, unsigned short srcw, unsigned short srch, short destx, short desty, unsigned short destw, unsigned short desth, int flags) { static int dump_window = -1; struct pipe_context *pipe; struct vl_compositor *compositor; struct vl_compositor_state *cstate; XvMCSurfacePrivate *surface_priv; XvMCContextPrivate *context_priv; XvMCSubpicturePrivate *subpicture_priv; XvMCContext *context; struct u_rect src_rect = {srcx, srcx + srcw, srcy, srcy + srch}; struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth}; struct pipe_resource *tex; struct pipe_surface surf_templ, *surf; struct u_rect *dirty_area; XVMC_MSG(XVMC_TRACE, "[XvMC] Displaying surface %p.\n", surface); assert(dpy); if (!surface || !surface->privData) return XvMCBadSurface; surface_priv = surface->privData; context = surface_priv->context; context_priv = context->privData; assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE); assert(srcx + srcw - 1 < surface->width); assert(srcy + srch - 1 < surface->height); subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL; pipe = context_priv->pipe; compositor = &context_priv->compositor; cstate = &context_priv->cstate; tex = vl_screen_texture_from_drawable(context_priv->vscreen, drawable); dirty_area = vl_screen_get_dirty_area(context_priv->vscreen); memset(&surf_templ, 0, sizeof(surf_templ)); surf_templ.format = tex->format; surf = pipe->create_surface(pipe, tex, &surf_templ); if (!surf) return BadDrawable; /* * Some apps (mplayer) hit these asserts because they call * this function after the window has been resized by the WM * but before they've handled the corresponding XEvent and * know about the new dimensions. The output should be clipped * until the app updates destw and desth. */ /* assert(destx + destw - 1 < drawable_surface->width); assert(desty + desth - 1 < drawable_surface->height); */ RecursiveEndFrame(surface_priv); context_priv->decoder->flush(context_priv->decoder); vl_compositor_clear_layers(cstate); vl_compositor_set_buffer_layer(cstate, compositor, 0, surface_priv->video_buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE); if (subpicture_priv) { XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p has subpicture %p.\n", surface, surface_priv->subpicture); assert(subpicture_priv->surface == surface); if (subpicture_priv->palette) vl_compositor_set_palette_layer(cstate, compositor, 1, subpicture_priv->sampler, subpicture_priv->palette, &subpicture_priv->src_rect, &subpicture_priv->dst_rect, true); else vl_compositor_set_rgba_layer(cstate, compositor, 1, subpicture_priv->sampler, &subpicture_priv->src_rect, &subpicture_priv->dst_rect, NULL); surface_priv->subpicture = NULL; subpicture_priv->surface = NULL; } // Workaround for r600g, there seems to be a bug in the fence refcounting code pipe->screen->fence_reference(pipe->screen, &surface_priv->fence, NULL); vl_compositor_set_layer_dst_area(cstate, 0, &dst_rect); vl_compositor_set_layer_dst_area(cstate, 1, &dst_rect); vl_compositor_render(cstate, compositor, surf, dirty_area, true); pipe->flush(pipe, &surface_priv->fence, 0); XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface); pipe->screen->flush_frontbuffer ( pipe->screen, tex, 0, 0, vl_screen_get_private(context_priv->vscreen) ); if(dump_window == -1) { dump_window = debug_get_num_option("XVMC_DUMP", 0); } if(dump_window) { static unsigned int framenum = 0; char cmd[256]; sprintf(cmd, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable, ++framenum); if (system(cmd) != 0) XVMC_MSG(XVMC_ERR, "[XvMC] Dumping surface %p failed.\n", surface); } XVMC_MSG(XVMC_TRACE, "[XvMC] Pushed surface %p to front buffer.\n", surface); return Success; }