• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian.
4  * Copyright 2014 Advanced Micro Devices, Inc.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 #include "pipe/p_screen.h"
30 #include "pipe/p_video_codec.h"
31 #include "util/u_memory.h"
32 #include "util/u_handle_table.h"
33 #include "util/u_video.h"
34 #include "vl/vl_deint_filter.h"
35 #include "vl/vl_winsys.h"
36 
37 #include "va_private.h"
38 #ifdef HAVE_DRISW_KMS
39 #include "loader/loader.h"
40 #endif
41 
42 #include <va/va_drmcommon.h>
43 
44 static struct VADriverVTable vtable =
45 {
46    &vlVaTerminate,
47    &vlVaQueryConfigProfiles,
48    &vlVaQueryConfigEntrypoints,
49    &vlVaGetConfigAttributes,
50    &vlVaCreateConfig,
51    &vlVaDestroyConfig,
52    &vlVaQueryConfigAttributes,
53    &vlVaCreateSurfaces,
54    &vlVaDestroySurfaces,
55    &vlVaCreateContext,
56    &vlVaDestroyContext,
57    &vlVaCreateBuffer,
58    &vlVaBufferSetNumElements,
59    &vlVaMapBuffer,
60    &vlVaUnmapBuffer,
61    &vlVaDestroyBuffer,
62    &vlVaBeginPicture,
63    &vlVaRenderPicture,
64    &vlVaEndPicture,
65    &vlVaSyncSurface,
66    &vlVaQuerySurfaceStatus,
67    &vlVaQuerySurfaceError,
68    &vlVaPutSurface,
69    &vlVaQueryImageFormats,
70    &vlVaCreateImage,
71    &vlVaDeriveImage,
72    &vlVaDestroyImage,
73    &vlVaSetImagePalette,
74    &vlVaGetImage,
75    &vlVaPutImage,
76    &vlVaQuerySubpictureFormats,
77    &vlVaCreateSubpicture,
78    &vlVaDestroySubpicture,
79    &vlVaSubpictureImage,
80    &vlVaSetSubpictureChromakey,
81    &vlVaSetSubpictureGlobalAlpha,
82    &vlVaAssociateSubpicture,
83    &vlVaDeassociateSubpicture,
84    &vlVaQueryDisplayAttributes,
85    &vlVaGetDisplayAttributes,
86    &vlVaSetDisplayAttributes,
87    &vlVaBufferInfo,
88    &vlVaLockSurface,
89    &vlVaUnlockSurface,
90    NULL, /* DEPRECATED VaGetSurfaceAttributes */
91    &vlVaCreateSurfaces2,
92    &vlVaQuerySurfaceAttributes,
93    &vlVaAcquireBufferHandle,
94    &vlVaReleaseBufferHandle,
95 #if VA_CHECK_VERSION(1, 1, 0)
96    NULL, /* vaCreateMFContext */
97    NULL, /* vaMFAddContext */
98    NULL, /* vaMFReleaseContext */
99    NULL, /* vaMFSubmit */
100    NULL, /* vaCreateBuffer2 */
101    NULL, /* vaQueryProcessingRate */
102    &vlVaExportSurfaceHandle,
103 #endif
104 };
105 
106 static struct VADriverVTableVPP vtable_vpp =
107 {
108    1,
109    &vlVaQueryVideoProcFilters,
110    &vlVaQueryVideoProcFilterCaps,
111    &vlVaQueryVideoProcPipelineCaps
112 };
113 
114 PUBLIC VAStatus
VA_DRIVER_INIT_FUNC(VADriverContextP ctx)115 VA_DRIVER_INIT_FUNC(VADriverContextP ctx)
116 {
117    vlVaDriver *drv;
118 
119    if (!ctx)
120       return VA_STATUS_ERROR_INVALID_CONTEXT;
121 
122    drv = CALLOC(1, sizeof(vlVaDriver));
123    if (!drv)
124       return VA_STATUS_ERROR_ALLOCATION_FAILED;
125 
126    switch (ctx->display_type) {
127    case VA_DISPLAY_ANDROID:
128       FREE(drv);
129       return VA_STATUS_ERROR_UNIMPLEMENTED;
130    case VA_DISPLAY_GLX:
131    case VA_DISPLAY_X11:
132       drv->vscreen = vl_dri3_screen_create(ctx->native_dpy, ctx->x11_screen);
133       if (!drv->vscreen)
134          drv->vscreen = vl_dri2_screen_create(ctx->native_dpy, ctx->x11_screen);
135       if (!drv->vscreen)
136          drv->vscreen = vl_xlib_swrast_screen_create(ctx->native_dpy, ctx->x11_screen);
137       break;
138    case VA_DISPLAY_WAYLAND:
139    case VA_DISPLAY_DRM:
140    case VA_DISPLAY_DRM_RENDERNODES: {
141       const struct drm_state *drm_info = (struct drm_state *) ctx->drm_state;
142 
143       if (!drm_info || drm_info->fd < 0) {
144          FREE(drv);
145          return VA_STATUS_ERROR_INVALID_PARAMETER;
146       }
147 #ifdef HAVE_DRISW_KMS
148       char* drm_driver_name = loader_get_driver_for_fd(drm_info->fd);
149       if(drm_driver_name) {
150          if (strcmp(drm_driver_name, "vgem") == 0)
151             drv->vscreen = vl_vgem_drm_screen_create(drm_info->fd);
152          FREE(drm_driver_name);
153       }
154 #endif
155       if(!drv->vscreen)
156          drv->vscreen = vl_drm_screen_create(drm_info->fd);
157       break;
158    }
159    default:
160       FREE(drv);
161       return VA_STATUS_ERROR_INVALID_DISPLAY;
162    }
163 
164    if (!drv->vscreen)
165       goto error_screen;
166 
167    drv->pipe = pipe_create_multimedia_context(drv->vscreen->pscreen);
168    if (!drv->pipe)
169       goto error_pipe;
170 
171    drv->htab = handle_table_create();
172    if (!drv->htab)
173       goto error_htab;
174 
175    if (!vl_compositor_init(&drv->compositor, drv->pipe))
176       goto error_compositor;
177    if (!vl_compositor_init_state(&drv->cstate, drv->pipe))
178       goto error_compositor_state;
179 
180    vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, &drv->csc);
181    if (!vl_compositor_set_csc_matrix(&drv->cstate, (const vl_csc_matrix *)&drv->csc, 1.0f, 0.0f))
182       goto error_csc_matrix;
183    (void) mtx_init(&drv->mutex, mtx_plain);
184 
185    ctx->pDriverData = (void *)drv;
186    ctx->version_major = 0;
187    ctx->version_minor = 1;
188    *ctx->vtable = vtable;
189    *ctx->vtable_vpp = vtable_vpp;
190    ctx->max_profiles = PIPE_VIDEO_PROFILE_MAX - PIPE_VIDEO_PROFILE_UNKNOWN - 1;
191    ctx->max_entrypoints = 2;
192    ctx->max_attributes = 1;
193    ctx->max_image_formats = VL_VA_MAX_IMAGE_FORMATS;
194    ctx->max_subpic_formats = 1;
195    ctx->max_display_attributes = 0;
196 
197    snprintf(drv->vendor_string, sizeof(drv->vendor_string),
198             "Mesa Gallium driver " PACKAGE_VERSION " for %s",
199             drv->vscreen->pscreen->get_name(drv->vscreen->pscreen));
200    ctx->str_vendor = drv->vendor_string;
201 
202    return VA_STATUS_SUCCESS;
203 
204 error_csc_matrix:
205    vl_compositor_cleanup_state(&drv->cstate);
206 
207 error_compositor_state:
208    vl_compositor_cleanup(&drv->compositor);
209 
210 error_compositor:
211    handle_table_destroy(drv->htab);
212 
213 error_htab:
214    drv->pipe->destroy(drv->pipe);
215 
216 error_pipe:
217    drv->vscreen->destroy(drv->vscreen);
218 
219 error_screen:
220    FREE(drv);
221    return VA_STATUS_ERROR_ALLOCATION_FAILED;
222 }
223 
224 VAStatus
vlVaCreateContext(VADriverContextP ctx,VAConfigID config_id,int picture_width,int picture_height,int flag,VASurfaceID * render_targets,int num_render_targets,VAContextID * context_id)225 vlVaCreateContext(VADriverContextP ctx, VAConfigID config_id, int picture_width,
226                   int picture_height, int flag, VASurfaceID *render_targets,
227                   int num_render_targets, VAContextID *context_id)
228 {
229    vlVaDriver *drv;
230    vlVaContext *context;
231    vlVaConfig *config;
232    int is_vpp;
233    int max_supported_width,max_supported_height;
234 
235    if (!ctx)
236       return VA_STATUS_ERROR_INVALID_CONTEXT;
237 
238    drv = VL_VA_DRIVER(ctx);
239    mtx_lock(&drv->mutex);
240    config = handle_table_get(drv->htab, config_id);
241    mtx_unlock(&drv->mutex);
242 
243    if (!config)
244       return VA_STATUS_ERROR_INVALID_CONFIG;
245 
246    is_vpp = config->profile == PIPE_VIDEO_PROFILE_UNKNOWN && !picture_width &&
247             !picture_height && !flag && !render_targets && !num_render_targets;
248 
249    if (!(picture_width && picture_height) && !is_vpp)
250       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
251 
252    context = CALLOC(1, sizeof(vlVaContext));
253    if (!context)
254       return VA_STATUS_ERROR_ALLOCATION_FAILED;
255 
256    if (is_vpp && !drv->vscreen->pscreen->get_video_param(drv->vscreen->pscreen,
257                                                          PIPE_VIDEO_PROFILE_UNKNOWN,
258                                                          PIPE_VIDEO_ENTRYPOINT_PROCESSING,
259                                                          PIPE_VIDEO_CAP_SUPPORTED)) {
260       context->decoder = NULL;
261    } else {
262       if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_PROCESSING) {
263          max_supported_width = drv->vscreen->pscreen->get_video_param(drv->vscreen->pscreen,
264                         config->profile, config->entrypoint,
265                         PIPE_VIDEO_CAP_MAX_WIDTH);
266          max_supported_height = drv->vscreen->pscreen->get_video_param(drv->vscreen->pscreen,
267                         config->profile, config->entrypoint,
268                         PIPE_VIDEO_CAP_MAX_HEIGHT);
269 
270          if (picture_width > max_supported_width || picture_height > max_supported_height) {
271             FREE(context);
272             return VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED;
273          }
274       }
275       context->templat.profile = config->profile;
276       context->templat.entrypoint = config->entrypoint;
277       context->templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
278       context->templat.width = picture_width;
279       context->templat.height = picture_height;
280       context->templat.expect_chunked_decode = true;
281 
282       switch (u_reduce_video_profile(context->templat.profile)) {
283       case PIPE_VIDEO_FORMAT_MPEG12:
284       case PIPE_VIDEO_FORMAT_VC1:
285       case PIPE_VIDEO_FORMAT_MPEG4:
286          context->templat.max_references = 2;
287          break;
288 
289       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
290          context->templat.max_references = 0;
291          if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE) {
292             context->desc.h264.pps = CALLOC_STRUCT(pipe_h264_pps);
293             if (!context->desc.h264.pps) {
294                FREE(context);
295                return VA_STATUS_ERROR_ALLOCATION_FAILED;
296             }
297             context->desc.h264.pps->sps = CALLOC_STRUCT(pipe_h264_sps);
298             if (!context->desc.h264.pps->sps) {
299                FREE(context->desc.h264.pps);
300                FREE(context);
301                return VA_STATUS_ERROR_ALLOCATION_FAILED;
302             }
303          }
304          break;
305 
306      case PIPE_VIDEO_FORMAT_HEVC:
307          if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE) {
308             context->desc.h265.pps = CALLOC_STRUCT(pipe_h265_pps);
309             if (!context->desc.h265.pps) {
310                FREE(context);
311                return VA_STATUS_ERROR_ALLOCATION_FAILED;
312             }
313             context->desc.h265.pps->sps = CALLOC_STRUCT(pipe_h265_sps);
314             if (!context->desc.h265.pps->sps) {
315                FREE(context->desc.h265.pps);
316                FREE(context);
317                return VA_STATUS_ERROR_ALLOCATION_FAILED;
318             }
319          }
320          break;
321 
322       case PIPE_VIDEO_FORMAT_VP9:
323          break;
324 
325       default:
326          break;
327       }
328    }
329 
330    context->desc.base.profile = config->profile;
331    context->desc.base.entry_point = config->entrypoint;
332    if (config->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
333       switch (u_reduce_video_profile(context->templat.profile)) {
334       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
335          context->desc.h264enc.rate_ctrl[0].rate_ctrl_method = config->rc;
336          context->desc.h264enc.frame_idx = util_hash_table_create_ptr_keys();
337          break;
338       case PIPE_VIDEO_FORMAT_HEVC:
339          context->desc.h265enc.rc.rate_ctrl_method = config->rc;
340          context->desc.h265enc.frame_idx = util_hash_table_create_ptr_keys();
341          break;
342       default:
343          break;
344       }
345    }
346 
347    mtx_lock(&drv->mutex);
348    *context_id = handle_table_add(drv->htab, context);
349    mtx_unlock(&drv->mutex);
350 
351    return VA_STATUS_SUCCESS;
352 }
353 
354 VAStatus
vlVaDestroyContext(VADriverContextP ctx,VAContextID context_id)355 vlVaDestroyContext(VADriverContextP ctx, VAContextID context_id)
356 {
357    vlVaDriver *drv;
358    vlVaContext *context;
359 
360    if (!ctx)
361       return VA_STATUS_ERROR_INVALID_CONTEXT;
362 
363    drv = VL_VA_DRIVER(ctx);
364    mtx_lock(&drv->mutex);
365    context = handle_table_get(drv->htab, context_id);
366    if (!context) {
367       mtx_unlock(&drv->mutex);
368       return VA_STATUS_ERROR_INVALID_CONTEXT;
369    }
370 
371    if (context->decoder) {
372       if (context->desc.base.entry_point == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
373          if (u_reduce_video_profile(context->decoder->profile) ==
374              PIPE_VIDEO_FORMAT_MPEG4_AVC) {
375             if (context->desc.h264enc.frame_idx)
376                _mesa_hash_table_destroy(context->desc.h264enc.frame_idx, NULL);
377          }
378          if (u_reduce_video_profile(context->decoder->profile) ==
379              PIPE_VIDEO_FORMAT_HEVC) {
380             if (context->desc.h265enc.frame_idx)
381                _mesa_hash_table_destroy(context->desc.h265enc.frame_idx, NULL);
382          }
383       } else {
384          if (u_reduce_video_profile(context->decoder->profile) ==
385                PIPE_VIDEO_FORMAT_MPEG4_AVC) {
386             FREE(context->desc.h264.pps->sps);
387             FREE(context->desc.h264.pps);
388          }
389          if (u_reduce_video_profile(context->decoder->profile) ==
390                PIPE_VIDEO_FORMAT_HEVC) {
391             FREE(context->desc.h265.pps->sps);
392             FREE(context->desc.h265.pps);
393          }
394       }
395       context->decoder->destroy(context->decoder);
396    }
397    if (context->blit_cs)
398       drv->pipe->delete_compute_state(drv->pipe, context->blit_cs);
399    if (context->deint) {
400       vl_deint_filter_cleanup(context->deint);
401       FREE(context->deint);
402    }
403    FREE(context);
404    handle_table_remove(drv->htab, context_id);
405    mtx_unlock(&drv->mutex);
406 
407    return VA_STATUS_SUCCESS;
408 }
409 
410 VAStatus
vlVaTerminate(VADriverContextP ctx)411 vlVaTerminate(VADriverContextP ctx)
412 {
413    vlVaDriver *drv;
414 
415    if (!ctx)
416       return VA_STATUS_ERROR_INVALID_CONTEXT;
417 
418    drv = ctx->pDriverData;
419    vl_compositor_cleanup_state(&drv->cstate);
420    vl_compositor_cleanup(&drv->compositor);
421    drv->pipe->destroy(drv->pipe);
422    drv->vscreen->destroy(drv->vscreen);
423    handle_table_destroy(drv->htab);
424    mtx_destroy(&drv->mutex);
425    FREE(drv);
426 
427    return VA_STATUS_SUCCESS;
428 }
429