diff --git a/src/gallium/frontends/va/picture.c b/src/gallium/frontends/va/picture.c index 725c28a620e..75df3e32ba4 100644 --- a/src/gallium/frontends/va/picture.c +++ b/src/gallium/frontends/va/picture.c @@ -1083,6 +1083,8 @@ vlVaEndPicture(VADriverContextP ctx, VAContextID context_id) coded_buf->associated_encode_input_surf = context->target_id; } else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) { context->desc.base.fence = &surf->fence; + } else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING) { + context->desc.base.fence = &surf->fence; } context->decoder->end_frame(context->decoder, context->target, &context->desc.base); diff --git a/src/gallium/frontends/va/postproc.c b/src/gallium/frontends/va/postproc.c index 347ec0c2026..127621e4532 100644 --- a/src/gallium/frontends/va/postproc.c +++ b/src/gallium/frontends/va/postproc.c @@ -490,6 +490,11 @@ vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *contex src_region = vlVaRegionDefault(param->surface_region, src_surface, &def_src_region); dst_region = vlVaRegionDefault(param->output_region, dst_surface, &def_dst_region); + /* Insert a GPU Wait on the input surface fence to ensure + any pending work is finished before performing the VPBlit */ + if (src_surface->fence && drv->pipe->fence_server_sync) + drv->pipe->fence_server_sync(drv->pipe, src_surface->fence); + /* If the driver supports video engine post proc, attempt to do that * if it fails, fallback to the other existing implementations below */ @@ -503,6 +508,7 @@ vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *contex return VA_STATUS_ERROR_ALLOCATION_FAILED; } + context->desc.vidproc.src_surface_fence = src_surface->fence; /* Perform VPBlit, if fail, fallback to other implementations below */ if (VA_STATUS_SUCCESS == vlVaVidEngineBlit(drv, context, src_region, dst_region, src, context->target, deinterlace, param)) diff --git a/src/gallium/frontends/va/surface.c b/src/gallium/frontends/va/surface.c index 48e93d31fbb..96d382561b2 100644 --- a/src/gallium/frontends/va/surface.c +++ b/src/gallium/frontends/va/surface.c @@ -137,7 +137,18 @@ vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target) return VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT; } - if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) { + if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING) { + int ret = 0; + + if (context->decoder->get_processor_fence) + ret = context->decoder->get_processor_fence(context->decoder, + surf->fence, + PIPE_DEFAULT_DECODER_FEEDBACK_TIMEOUT_NS); + + mtx_unlock(&drv->mutex); + // Assume that the GPU has hung otherwise. + return ret ? VA_STATUS_SUCCESS : VA_STATUS_ERROR_TIMEDOUT; + } else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) { int ret = 0; if (context->decoder->get_decoder_fence) @@ -234,6 +245,25 @@ vlVaQuerySurfaceStatus(VADriverContextP ctx, VASurfaceID render_target, VASurfac ret = context->decoder->get_decoder_fence(context->decoder, surf->fence, 0); + if (ret) + *status = VASurfaceReady; + else + /* An approach could be to just tell the client that this is not + * implemented, but this breaks other code. Compromise by at least + * conservatively setting the status to VASurfaceRendering if we can't + * query the hardware. Note that we _must_ set the status here, otherwise + * it comes out of the function unchanged. As we are returning + * VA_STATUS_SUCCESS, the client would be within his/her rights to use a + * potentially uninitialized/invalid status value unknowingly. + */ + *status = VASurfaceRendering; + } else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING) { + int ret = 0; + + if (context->decoder->get_processor_fence) + ret = context->decoder->get_processor_fence(context->decoder, + surf->fence, 0); + if (ret) *status = VASurfaceReady; else diff --git a/src/gallium/include/pipe/p_video_codec.h b/src/gallium/include/pipe/p_video_codec.h index bda37e396dd..114461603c0 100644 --- a/src/gallium/include/pipe/p_video_codec.h +++ b/src/gallium/include/pipe/p_video_codec.h @@ -133,6 +133,21 @@ struct pipe_video_codec int (*get_decoder_fence)(struct pipe_video_codec *codec, struct pipe_fence_handle *fence, uint64_t timeout); + + /** + * Get processor fence. + * + * Can be used to query the status of the previous process job denoted by + * 'fence' given 'timeout'. + * + * A pointer to a fence pointer can be passed to the codecs before the + * end_frame vfunc and the codec should then be responsible for allocating a + * fence on command stream submission. + */ + int (*get_processor_fence)(struct pipe_video_codec *codec, + struct pipe_fence_handle *fence, + uint64_t timeout); + /** * Update target buffer address. * diff --git a/src/gallium/include/pipe/p_video_state.h b/src/gallium/include/pipe/p_video_state.h index 5e61d58ff41..deae42d1cf7 100644 --- a/src/gallium/include/pipe/p_video_state.h +++ b/src/gallium/include/pipe/p_video_state.h @@ -187,7 +187,7 @@ struct pipe_picture_desc uint32_t key_size; enum pipe_format input_format; enum pipe_format output_format; - /* A fence used on PIPE_VIDEO_ENTRYPOINT_DECODE to signal job completion */ + /* A fence used on PIPE_VIDEO_ENTRYPOINT_DECODE/PROCESSING to signal job completion */ struct pipe_fence_handle **fence; }; @@ -1379,6 +1379,9 @@ struct pipe_vpp_desc struct u_rect dst_region; enum pipe_video_vpp_orientation orientation; struct pipe_vpp_blend blend; + + /* Fence to wait on for the src surface */ + struct pipe_fence_handle *src_surface_fence; };