/** * Composite a sub-rectangle of a VdpBitmapSurface into a sub-rectangle of * a VdpOutputSurface; Output Surface object VdpOutputSurface. */ VdpStatus vlVdpOutputSurfaceRenderBitmapSurface(VdpOutputSurface destination_surface, VdpRect const *destination_rect, VdpBitmapSurface source_surface, VdpRect const *source_rect, VdpColor const *colors, VdpOutputSurfaceRenderBlendState const *blend_state, uint32_t flags) { vlVdpOutputSurface *dst_vlsurface; vlVdpBitmapSurface *src_vlsurface; struct pipe_context *context; struct vl_compositor *compositor; struct vl_compositor_state *cstate; struct u_rect src_rect, dst_rect; struct vertex4f vlcolors[4]; void *blend; dst_vlsurface = vlGetDataHTAB(destination_surface); if (!dst_vlsurface) return VDP_STATUS_INVALID_HANDLE; src_vlsurface = vlGetDataHTAB(source_surface); if (!src_vlsurface) return VDP_STATUS_INVALID_HANDLE; if (dst_vlsurface->device != src_vlsurface->device) return VDP_STATUS_HANDLE_DEVICE_MISMATCH; context = dst_vlsurface->device->context; compositor = &dst_vlsurface->device->compositor; cstate = &dst_vlsurface->cstate; pipe_mutex_lock(dst_vlsurface->device->mutex); vlVdpResolveDelayedRendering(dst_vlsurface->device, NULL, NULL); blend = BlenderToPipe(context, blend_state); vl_compositor_clear_layers(cstate); vl_compositor_set_layer_blend(cstate, 0, blend, false); vl_compositor_set_rgba_layer(cstate, compositor, 0, src_vlsurface->sampler_view, RectToPipe(source_rect, &src_rect), NULL, ColorsToPipe(colors, flags, vlcolors)); vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect)); vl_compositor_render(cstate, compositor, dst_vlsurface->surface, NULL); context->delete_blend_state(context, blend); pipe_mutex_unlock(dst_vlsurface->device->mutex); return VDP_STATUS_OK; }
/** * Composite a sub-rectangle of a VdpOutputSurface into a sub-rectangle of * another VdpOutputSurface; Output Surface object VdpOutputSurface. */ VdpStatus vlVdpOutputSurfaceRenderOutputSurface(VdpOutputSurface destination_surface, VdpRect const *destination_rect, VdpOutputSurface source_surface, VdpRect const *source_rect, VdpColor const *colors, VdpOutputSurfaceRenderBlendState const *blend_state, uint32_t flags) { vlVdpOutputSurface *dst_vlsurface; vlVdpOutputSurface *src_vlsurface; struct pipe_context *context; struct vl_compositor *compositor; struct pipe_video_rect src_rect; struct pipe_video_rect dst_rect; void *blend; VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Composing output surfaces\n"); dst_vlsurface = vlGetDataHTAB(destination_surface); if (!dst_vlsurface) return VDP_STATUS_INVALID_HANDLE; src_vlsurface = vlGetDataHTAB(source_surface); if (!src_vlsurface) return VDP_STATUS_INVALID_HANDLE; if (dst_vlsurface->device != src_vlsurface->device) return VDP_STATUS_HANDLE_DEVICE_MISMATCH; context = dst_vlsurface->device->context->pipe; compositor = &dst_vlsurface->device->compositor; blend = BlenderToPipe(context, blend_state); vl_compositor_clear_layers(compositor); vl_compositor_set_layer_blend(compositor, 0, blend, false); vl_compositor_set_rgba_layer(compositor, 0, src_vlsurface->sampler_view, RectToPipe(source_rect, &src_rect), NULL); vl_compositor_render(compositor, dst_vlsurface->surface, RectToPipe(destination_rect, &dst_rect), NULL, false); context->delete_blend_state(context, blend); return VDP_STATUS_OK; }
/** * Copy image data from application memory in a specific YCbCr format to * a VdpOutputSurface. */ VdpStatus vlVdpOutputSurfacePutBitsYCbCr(VdpOutputSurface surface, VdpYCbCrFormat source_ycbcr_format, void const *const *source_data, uint32_t const *source_pitches, VdpRect const *destination_rect, VdpCSCMatrix const *csc_matrix) { vlVdpOutputSurface *vlsurface; struct vl_compositor *compositor; struct vl_compositor_state *cstate; struct pipe_context *pipe; enum pipe_format format; struct pipe_video_buffer vtmpl, *vbuffer; struct u_rect dst_rect; struct pipe_sampler_view **sampler_views; unsigned i; vlsurface = vlGetDataHTAB(surface); if (!vlsurface) return VDP_STATUS_INVALID_HANDLE; pipe = vlsurface->device->context; compositor = &vlsurface->device->compositor; cstate = &vlsurface->cstate; format = FormatYCBCRToPipe(source_ycbcr_format); if (format == PIPE_FORMAT_NONE) return VDP_STATUS_INVALID_Y_CB_CR_FORMAT; if (!source_data || !source_pitches) return VDP_STATUS_INVALID_POINTER; pipe_mutex_lock(vlsurface->device->mutex); vlVdpResolveDelayedRendering(vlsurface->device, NULL, NULL); memset(&vtmpl, 0, sizeof(vtmpl)); vtmpl.buffer_format = format; vtmpl.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; if (destination_rect) { vtmpl.width = abs(destination_rect->x0-destination_rect->x1); vtmpl.height = abs(destination_rect->y0-destination_rect->y1); } else { vtmpl.width = vlsurface->surface->texture->width0; vtmpl.height = vlsurface->surface->texture->height0; } vbuffer = pipe->create_video_buffer(pipe, &vtmpl); if (!vbuffer) { pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_RESOURCES; } sampler_views = vbuffer->get_sampler_view_planes(vbuffer); if (!sampler_views) { vbuffer->destroy(vbuffer); pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_RESOURCES; } for (i = 0; i < 3; ++i) { struct pipe_sampler_view *sv = sampler_views[i]; if (!sv) continue; struct pipe_box dst_box = { 0, 0, 0, sv->texture->width0, sv->texture->height0, 1 }; pipe->transfer_inline_write(pipe, sv->texture, 0, PIPE_TRANSFER_WRITE, &dst_box, source_data[i], source_pitches[i], 0); } if (!csc_matrix) { vl_csc_matrix csc; vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &csc); vl_compositor_set_csc_matrix(cstate, (const vl_csc_matrix*)&csc); } else { vl_compositor_set_csc_matrix(cstate, csc_matrix); } vl_compositor_clear_layers(cstate); vl_compositor_set_buffer_layer(cstate, compositor, 0, vbuffer, NULL, NULL, VL_COMPOSITOR_WEAVE); vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect)); vl_compositor_render(cstate, compositor, vlsurface->surface, NULL); vbuffer->destroy(vbuffer); pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_OK; }
/** * Copy image data from application memory in a specific indexed format to * a VdpOutputSurface. */ VdpStatus vlVdpOutputSurfacePutBitsIndexed(VdpOutputSurface surface, VdpIndexedFormat source_indexed_format, void const *const *source_data, uint32_t const *source_pitch, VdpRect const *destination_rect, VdpColorTableFormat color_table_format, void const *color_table) { vlVdpOutputSurface *vlsurface; struct pipe_context *context; struct vl_compositor *compositor; struct vl_compositor_state *cstate; enum pipe_format index_format; enum pipe_format colortbl_format; struct pipe_resource *res, res_tmpl; struct pipe_sampler_view sv_tmpl; struct pipe_sampler_view *sv_idx = NULL, *sv_tbl = NULL; struct pipe_box box; struct u_rect dst_rect; vlsurface = vlGetDataHTAB(surface); if (!vlsurface) return VDP_STATUS_INVALID_HANDLE; context = vlsurface->device->context; compositor = &vlsurface->device->compositor; cstate = &vlsurface->cstate; index_format = FormatIndexedToPipe(source_indexed_format); if (index_format == PIPE_FORMAT_NONE) return VDP_STATUS_INVALID_INDEXED_FORMAT; if (!source_data || !source_pitch) return VDP_STATUS_INVALID_POINTER; colortbl_format = FormatColorTableToPipe(color_table_format); if (colortbl_format == PIPE_FORMAT_NONE) return VDP_STATUS_INVALID_COLOR_TABLE_FORMAT; if (!color_table) return VDP_STATUS_INVALID_POINTER; memset(&res_tmpl, 0, sizeof(res_tmpl)); res_tmpl.target = PIPE_TEXTURE_2D; res_tmpl.format = index_format; if (destination_rect) { res_tmpl.width0 = abs(destination_rect->x0-destination_rect->x1); res_tmpl.height0 = abs(destination_rect->y0-destination_rect->y1); } else { res_tmpl.width0 = vlsurface->surface->texture->width0; res_tmpl.height0 = vlsurface->surface->texture->height0; } res_tmpl.depth0 = 1; res_tmpl.array_size = 1; res_tmpl.usage = PIPE_USAGE_STAGING; res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW; pipe_mutex_lock(vlsurface->device->mutex); vlVdpResolveDelayedRendering(vlsurface->device, NULL, NULL); res = context->screen->resource_create(context->screen, &res_tmpl); if (!res) goto error_resource; box.x = box.y = box.z = 0; box.width = res->width0; box.height = res->height0; box.depth = res->depth0; context->transfer_inline_write(context, res, 0, PIPE_TRANSFER_WRITE, &box, source_data[0], source_pitch[0], source_pitch[0] * res->height0); memset(&sv_tmpl, 0, sizeof(sv_tmpl)); u_sampler_view_default_template(&sv_tmpl, res, res->format); sv_idx = context->create_sampler_view(context, res, &sv_tmpl); pipe_resource_reference(&res, NULL); if (!sv_idx) goto error_resource; memset(&res_tmpl, 0, sizeof(res_tmpl)); res_tmpl.target = PIPE_TEXTURE_1D; res_tmpl.format = colortbl_format; res_tmpl.width0 = 1 << util_format_get_component_bits( index_format, UTIL_FORMAT_COLORSPACE_RGB, 0); res_tmpl.height0 = 1; res_tmpl.depth0 = 1; res_tmpl.array_size = 1; res_tmpl.usage = PIPE_USAGE_STAGING; res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW; res = context->screen->resource_create(context->screen, &res_tmpl); if (!res) goto error_resource; box.x = box.y = box.z = 0; box.width = res->width0; box.height = res->height0; box.depth = res->depth0; context->transfer_inline_write(context, res, 0, PIPE_TRANSFER_WRITE, &box, color_table, util_format_get_stride(colortbl_format, res->width0), 0); memset(&sv_tmpl, 0, sizeof(sv_tmpl)); u_sampler_view_default_template(&sv_tmpl, res, res->format); sv_tbl = context->create_sampler_view(context, res, &sv_tmpl); pipe_resource_reference(&res, NULL); if (!sv_tbl) goto error_resource; vl_compositor_clear_layers(cstate); vl_compositor_set_palette_layer(cstate, compositor, 0, sv_idx, sv_tbl, NULL, NULL, false); vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect)); vl_compositor_render(cstate, compositor, vlsurface->surface, NULL); pipe_sampler_view_reference(&sv_idx, NULL); pipe_sampler_view_reference(&sv_tbl, NULL); pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_OK; error_resource: pipe_sampler_view_reference(&sv_idx, NULL); pipe_sampler_view_reference(&sv_tbl, NULL); pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_RESOURCES; }
/** * 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; }