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
44static 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
106static struct VADriverVTableVPP vtable_vpp =
107{
108   1,
109   &vlVaQueryVideoProcFilters,
110   &vlVaQueryVideoProcFilterCaps,
111   &vlVaQueryVideoProcPipelineCaps
112};
113
114PUBLIC VAStatus
115VA_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
204error_csc_matrix:
205   vl_compositor_cleanup_state(&drv->cstate);
206
207error_compositor_state:
208   vl_compositor_cleanup(&drv->compositor);
209
210error_compositor:
211   handle_table_destroy(drv->htab);
212
213error_htab:
214   drv->pipe->destroy(drv->pipe);
215
216error_pipe:
217   drv->vscreen->destroy(drv->vscreen);
218
219error_screen:
220   FREE(drv);
221   return VA_STATUS_ERROR_ALLOCATION_FAILED;
222}
223
224VAStatus
225vlVaCreateContext(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
354VAStatus
355vlVaDestroyContext(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
410VAStatus
411vlVaTerminate(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