/** * Perform a video post-processing and compositing operation. */ VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer, VdpOutputSurface background_surface, VdpRect const *background_source_rect, VdpVideoMixerPictureStructure current_picture_structure, uint32_t video_surface_past_count, VdpVideoSurface const *video_surface_past, VdpVideoSurface video_surface_current, uint32_t video_surface_future_count, VdpVideoSurface const *video_surface_future, VdpRect const *video_source_rect, VdpOutputSurface destination_surface, VdpRect const *destination_rect, VdpRect const *destination_video_rect, uint32_t layer_count, VdpLayer const *layers) { enum vl_compositor_deinterlace deinterlace; struct u_rect rect, clip, *prect; unsigned i, layer = 0; struct pipe_video_buffer *video_buffer; vlVdpVideoMixer *vmixer; vlVdpSurface *surf; vlVdpOutputSurface *dst, *bg = NULL; struct vl_compositor *compositor; vmixer = vlGetDataHTAB(mixer); if (!vmixer) return VDP_STATUS_INVALID_HANDLE; compositor = &vmixer->device->compositor; surf = vlGetDataHTAB(video_surface_current); if (!surf) return VDP_STATUS_INVALID_HANDLE; video_buffer = surf->video_buffer; if (surf->device != vmixer->device) return VDP_STATUS_HANDLE_DEVICE_MISMATCH; if (vmixer->video_width > video_buffer->width || vmixer->video_height > video_buffer->height || vmixer->chroma_format != video_buffer->chroma_format) return VDP_STATUS_INVALID_SIZE; if (layer_count > vmixer->max_layers) return VDP_STATUS_INVALID_VALUE; dst = vlGetDataHTAB(destination_surface); if (!dst) return VDP_STATUS_INVALID_HANDLE; if (background_surface != VDP_INVALID_HANDLE) { bg = vlGetDataHTAB(background_surface); if (!bg) return VDP_STATUS_INVALID_HANDLE; } pipe_mutex_lock(vmixer->device->mutex); vlVdpResolveDelayedRendering(vmixer->device, NULL, NULL); vl_compositor_clear_layers(&vmixer->cstate); if (bg) vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer++, bg->sampler_view, RectToPipe(background_source_rect, &rect), NULL, NULL); switch (current_picture_structure) { case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD: deinterlace = VL_COMPOSITOR_BOB_TOP; break; case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD: deinterlace = VL_COMPOSITOR_BOB_BOTTOM; break; case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME: deinterlace = VL_COMPOSITOR_WEAVE; break; default: pipe_mutex_unlock(vmixer->device->mutex); return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE; } if (deinterlace != VL_COMPOSITOR_WEAVE && vmixer->deint.enabled && video_surface_past_count > 1 && video_surface_future_count > 0) { vlVdpSurface *prevprev = vlGetDataHTAB(video_surface_past[1]); vlVdpSurface *prev = vlGetDataHTAB(video_surface_past[0]); vlVdpSurface *next = vlGetDataHTAB(video_surface_future[0]); if (prevprev && prev && next && vl_deint_filter_check_buffers(vmixer->deint.filter, prevprev->video_buffer, prev->video_buffer, surf->video_buffer, next->video_buffer)) { vl_deint_filter_render(vmixer->deint.filter, prevprev->video_buffer, prev->video_buffer, surf->video_buffer, next->video_buffer, deinterlace == VL_COMPOSITOR_BOB_BOTTOM); deinterlace = VL_COMPOSITOR_WEAVE; video_buffer = vmixer->deint.filter->video_buffer; } } prect = RectToPipe(video_source_rect, &rect); if (!prect) { rect.x0 = 0; rect.y0 = 0; rect.x1 = surf->templat.width; rect.y1 = surf->templat.height; prect = ▭ } vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace); vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(destination_video_rect, &rect)); for (i = 0; i < layer_count; ++i) { vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface); if (!src) { pipe_mutex_unlock(vmixer->device->mutex); return VDP_STATUS_INVALID_HANDLE; } assert(layers->struct_version == VDP_LAYER_VERSION); vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer, src->sampler_view, RectToPipe(layers->source_rect, &rect), NULL, NULL); vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(layers->destination_rect, &rect)); ++layers; } vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &clip)); if (!vmixer->noise_reduction.filter && !vmixer->sharpness.filter) vlVdpSave4DelayedRendering(vmixer->device, destination_surface, &vmixer->cstate); else { vl_compositor_render(&vmixer->cstate, compositor, dst->surface, &dst->dirty_area, true); /* applying the noise reduction after scaling is actually not very clever, but currently we should avoid to copy around the image data once more. */ if (vmixer->noise_reduction.filter) vl_median_filter_render(vmixer->noise_reduction.filter, dst->sampler_view, dst->surface); if (vmixer->sharpness.filter) vl_matrix_filter_render(vmixer->sharpness.filter, dst->sampler_view, dst->surface); } pipe_mutex_unlock(vmixer->device->mutex); return VDP_STATUS_OK; }
/** * 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; }