38b31516adcd831a8baa1a7b840c33f7d15841e0
[mesa.git] / src / gallium / state_trackers / va / surface.c
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
32 #include "state_tracker/drm_driver.h"
33
34 #include "util/u_memory.h"
35 #include "util/u_handle_table.h"
36 #include "util/u_rect.h"
37 #include "util/u_sampler.h"
38 #include "util/u_surface.h"
39
40 #include "vl/vl_compositor.h"
41 #include "vl/vl_video_buffer.h"
42 #include "vl/vl_winsys.h"
43
44 #include "va_private.h"
45
46 DEBUG_GET_ONCE_BOOL_OPTION(nointerlace, "VAAPI_DISABLE_INTERLACE", FALSE);
47
48 #include <va/va_drmcommon.h>
49
50 static const enum pipe_format vpp_surface_formats[] = {
51 PIPE_FORMAT_B8G8R8A8_UNORM, PIPE_FORMAT_R8G8B8A8_UNORM,
52 PIPE_FORMAT_B8G8R8X8_UNORM, PIPE_FORMAT_R8G8B8X8_UNORM
53 };
54
55 VAStatus
56 vlVaCreateSurfaces(VADriverContextP ctx, int width, int height, int format,
57 int num_surfaces, VASurfaceID *surfaces)
58 {
59 return vlVaCreateSurfaces2(ctx, format, width, height, surfaces, num_surfaces,
60 NULL, 0);
61 }
62
63 VAStatus
64 vlVaDestroySurfaces(VADriverContextP ctx, VASurfaceID *surface_list, int num_surfaces)
65 {
66 vlVaDriver *drv;
67 int i;
68
69 if (!ctx)
70 return VA_STATUS_ERROR_INVALID_CONTEXT;
71
72 drv = VL_VA_DRIVER(ctx);
73 pipe_mutex_lock(drv->mutex);
74 for (i = 0; i < num_surfaces; ++i) {
75 vlVaSurface *surf = handle_table_get(drv->htab, surface_list[i]);
76 if (!surf) {
77 pipe_mutex_unlock(drv->mutex);
78 return VA_STATUS_ERROR_INVALID_SURFACE;
79 }
80 if (surf->buffer)
81 surf->buffer->destroy(surf->buffer);
82 util_dynarray_fini(&surf->subpics);
83 FREE(surf);
84 handle_table_remove(drv->htab, surface_list[i]);
85 }
86 pipe_mutex_unlock(drv->mutex);
87
88 return VA_STATUS_SUCCESS;
89 }
90
91 VAStatus
92 vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target)
93 {
94 vlVaDriver *drv;
95 vlVaContext *context;
96 vlVaSurface *surf;
97 void *pbuff;
98
99 if (!ctx)
100 return VA_STATUS_ERROR_INVALID_CONTEXT;
101
102 drv = VL_VA_DRIVER(ctx);
103 if (!drv)
104 return VA_STATUS_ERROR_INVALID_CONTEXT;
105
106 pipe_mutex_lock(drv->mutex);
107 surf = handle_table_get(drv->htab, render_target);
108
109 if (!surf || !surf->buffer) {
110 pipe_mutex_unlock(drv->mutex);
111 return VA_STATUS_ERROR_INVALID_SURFACE;
112 }
113
114 if (!surf->feedback) {
115 // No outstanding operation: nothing to do.
116 pipe_mutex_unlock(drv->mutex);
117 return VA_STATUS_SUCCESS;
118 }
119
120 context = handle_table_get(drv->htab, surf->ctx);
121 if (!context) {
122 pipe_mutex_unlock(drv->mutex);
123 return VA_STATUS_ERROR_INVALID_CONTEXT;
124 }
125
126 if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
127 int frame_diff;
128 if (context->desc.h264enc.frame_num_cnt >= surf->frame_num_cnt)
129 frame_diff = context->desc.h264enc.frame_num_cnt - surf->frame_num_cnt;
130 else
131 frame_diff = 0xFFFFFFFF - surf->frame_num_cnt + 1 + context->desc.h264enc.frame_num_cnt;
132 if ((frame_diff == 0) &&
133 (surf->force_flushed == false) &&
134 (context->desc.h264enc.frame_num_cnt % 2 != 0)) {
135 context->decoder->flush(context->decoder);
136 context->first_single_submitted = true;
137 }
138 context->decoder->get_feedback(context->decoder, surf->feedback, &(surf->coded_buf->coded_size));
139 surf->feedback = NULL;
140 }
141 pipe_mutex_unlock(drv->mutex);
142 return VA_STATUS_SUCCESS;
143 }
144
145 VAStatus
146 vlVaQuerySurfaceStatus(VADriverContextP ctx, VASurfaceID render_target, VASurfaceStatus *status)
147 {
148 if (!ctx)
149 return VA_STATUS_ERROR_INVALID_CONTEXT;
150
151 return VA_STATUS_SUCCESS;
152 }
153
154 VAStatus
155 vlVaQuerySurfaceError(VADriverContextP ctx, VASurfaceID render_target, VAStatus error_status, void **error_info)
156 {
157 if (!ctx)
158 return VA_STATUS_ERROR_INVALID_CONTEXT;
159
160 return VA_STATUS_ERROR_UNIMPLEMENTED;
161 }
162
163 static void
164 upload_sampler(struct pipe_context *pipe, struct pipe_sampler_view *dst,
165 const struct pipe_box *dst_box, const void *src, unsigned src_stride,
166 unsigned src_x, unsigned src_y)
167 {
168 struct pipe_transfer *transfer;
169 void *map;
170
171 map = pipe->transfer_map(pipe, dst->texture, 0, PIPE_TRANSFER_WRITE,
172 dst_box, &transfer);
173 if (!map)
174 return;
175
176 util_copy_rect(map, dst->texture->format, transfer->stride, 0, 0,
177 dst_box->width, dst_box->height,
178 src, src_stride, src_x, src_y);
179
180 pipe->transfer_unmap(pipe, transfer);
181 }
182
183 static VAStatus
184 vlVaPutSubpictures(vlVaSurface *surf, vlVaDriver *drv,
185 struct pipe_surface *surf_draw, struct u_rect *dirty_area,
186 struct u_rect *src_rect, struct u_rect *dst_rect)
187 {
188 vlVaSubpicture *sub;
189 int i;
190
191 if (!(surf->subpics.data || surf->subpics.size))
192 return VA_STATUS_SUCCESS;
193
194 for (i = 0; i < surf->subpics.size/sizeof(vlVaSubpicture *); i++) {
195 struct pipe_blend_state blend;
196 void *blend_state;
197 vlVaBuffer *buf;
198 struct pipe_box box;
199 struct u_rect *s, *d, sr, dr, c;
200 int sw, sh, dw, dh;
201
202 sub = ((vlVaSubpicture **)surf->subpics.data)[i];
203 if (!sub)
204 continue;
205
206 buf = handle_table_get(drv->htab, sub->image->buf);
207 if (!buf)
208 return VA_STATUS_ERROR_INVALID_IMAGE;
209
210 box.x = 0;
211 box.y = 0;
212 box.z = 0;
213 box.width = sub->dst_rect.x1 - sub->dst_rect.x0;
214 box.height = sub->dst_rect.y1 - sub->dst_rect.y0;
215 box.depth = 1;
216
217 s = &sub->src_rect;
218 d = &sub->dst_rect;
219 sw = s->x1 - s->x0;
220 sh = s->y1 - s->y0;
221 dw = d->x1 - d->x0;
222 dh = d->y1 - d->y0;
223 c.x0 = MAX2(d->x0, s->x0);
224 c.y0 = MAX2(d->y0, s->y0);
225 c.x1 = MIN2(d->x0 + dw, src_rect->x1);
226 c.y1 = MIN2(d->y0 + dh, src_rect->y1);
227 sr.x0 = s->x0 + (c.x0 - d->x0)*(sw/(float)dw);
228 sr.y0 = s->y0 + (c.y0 - d->y0)*(sh/(float)dh);
229 sr.x1 = s->x0 + (c.x1 - d->x0)*(sw/(float)dw);
230 sr.y1 = s->y0 + (c.y1 - d->y0)*(sh/(float)dh);
231
232 s = src_rect;
233 d = dst_rect;
234 sw = s->x1 - s->x0;
235 sh = s->y1 - s->y0;
236 dw = d->x1 - d->x0;
237 dh = d->y1 - d->y0;
238 dr.x0 = d->x0 + c.x0*(dw/(float)sw);
239 dr.y0 = d->y0 + c.y0*(dh/(float)sh);
240 dr.x1 = d->x0 + c.x1*(dw/(float)sw);
241 dr.y1 = d->y0 + c.y1*(dh/(float)sh);
242
243 memset(&blend, 0, sizeof(blend));
244 blend.independent_blend_enable = 0;
245 blend.rt[0].blend_enable = 1;
246 blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
247 blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
248 blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
249 blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
250 blend.rt[0].rgb_func = PIPE_BLEND_ADD;
251 blend.rt[0].alpha_func = PIPE_BLEND_ADD;
252 blend.rt[0].colormask = PIPE_MASK_RGBA;
253 blend.logicop_enable = 0;
254 blend.logicop_func = PIPE_LOGICOP_CLEAR;
255 blend.dither = 0;
256 blend_state = drv->pipe->create_blend_state(drv->pipe, &blend);
257
258 vl_compositor_clear_layers(&drv->cstate);
259 vl_compositor_set_layer_blend(&drv->cstate, 0, blend_state, false);
260 upload_sampler(drv->pipe, sub->sampler, &box, buf->data,
261 sub->image->pitches[0], 0, 0);
262 vl_compositor_set_rgba_layer(&drv->cstate, &drv->compositor, 0, sub->sampler,
263 &sr, NULL, NULL);
264 vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dr);
265 vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, false);
266 drv->pipe->delete_blend_state(drv->pipe, blend_state);
267 }
268
269 return VA_STATUS_SUCCESS;
270 }
271
272 VAStatus
273 vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short srcx, short srcy,
274 unsigned short srcw, unsigned short srch, short destx, short desty,
275 unsigned short destw, unsigned short desth, VARectangle *cliprects,
276 unsigned int number_cliprects, unsigned int flags)
277 {
278 vlVaDriver *drv;
279 vlVaSurface *surf;
280 struct pipe_screen *screen;
281 struct pipe_resource *tex;
282 struct pipe_surface surf_templ, *surf_draw;
283 struct vl_screen *vscreen;
284 struct u_rect src_rect, *dirty_area;
285 struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth};
286 VAStatus status;
287
288 if (!ctx)
289 return VA_STATUS_ERROR_INVALID_CONTEXT;
290
291 drv = VL_VA_DRIVER(ctx);
292 pipe_mutex_lock(drv->mutex);
293 surf = handle_table_get(drv->htab, surface_id);
294 if (!surf) {
295 pipe_mutex_unlock(drv->mutex);
296 return VA_STATUS_ERROR_INVALID_SURFACE;
297 }
298
299 screen = drv->pipe->screen;
300 vscreen = drv->vscreen;
301
302 tex = vscreen->texture_from_drawable(vscreen, draw);
303 if (!tex) {
304 pipe_mutex_unlock(drv->mutex);
305 return VA_STATUS_ERROR_INVALID_DISPLAY;
306 }
307
308 dirty_area = vscreen->get_dirty_area(vscreen);
309
310 memset(&surf_templ, 0, sizeof(surf_templ));
311 surf_templ.format = tex->format;
312 surf_draw = drv->pipe->create_surface(drv->pipe, tex, &surf_templ);
313 if (!surf_draw) {
314 pipe_resource_reference(&tex, NULL);
315 pipe_mutex_unlock(drv->mutex);
316 return VA_STATUS_ERROR_INVALID_DISPLAY;
317 }
318
319 src_rect.x0 = srcx;
320 src_rect.y0 = srcy;
321 src_rect.x1 = srcw + srcx;
322 src_rect.y1 = srch + srcy;
323
324 vl_compositor_clear_layers(&drv->cstate);
325 vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, surf->buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE);
326 vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);
327 vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, true);
328
329 status = vlVaPutSubpictures(surf, drv, surf_draw, dirty_area, &src_rect, &dst_rect);
330 if (status) {
331 pipe_mutex_unlock(drv->mutex);
332 return status;
333 }
334
335 /* flush before calling flush_frontbuffer so that rendering is flushed
336 * to back buffer so the texture can be copied in flush_frontbuffer
337 */
338 drv->pipe->flush(drv->pipe, NULL, 0);
339
340 screen->flush_frontbuffer(screen, tex, 0, 0,
341 vscreen->get_private(vscreen), NULL);
342
343
344 pipe_resource_reference(&tex, NULL);
345 pipe_surface_reference(&surf_draw, NULL);
346 pipe_mutex_unlock(drv->mutex);
347
348 return VA_STATUS_SUCCESS;
349 }
350
351 VAStatus
352 vlVaLockSurface(VADriverContextP ctx, VASurfaceID surface, unsigned int *fourcc,
353 unsigned int *luma_stride, unsigned int *chroma_u_stride, unsigned int *chroma_v_stride,
354 unsigned int *luma_offset, unsigned int *chroma_u_offset, unsigned int *chroma_v_offset,
355 unsigned int *buffer_name, void **buffer)
356 {
357 if (!ctx)
358 return VA_STATUS_ERROR_INVALID_CONTEXT;
359
360 return VA_STATUS_ERROR_UNIMPLEMENTED;
361 }
362
363 VAStatus
364 vlVaUnlockSurface(VADriverContextP ctx, VASurfaceID surface)
365 {
366 if (!ctx)
367 return VA_STATUS_ERROR_INVALID_CONTEXT;
368
369 return VA_STATUS_ERROR_UNIMPLEMENTED;
370 }
371
372 VAStatus
373 vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config_id,
374 VASurfaceAttrib *attrib_list, unsigned int *num_attribs)
375 {
376 vlVaDriver *drv;
377 vlVaConfig *config;
378 VASurfaceAttrib *attribs;
379 struct pipe_screen *pscreen;
380 int i, j;
381
382 STATIC_ASSERT(ARRAY_SIZE(vpp_surface_formats) <= VL_VA_MAX_IMAGE_FORMATS);
383
384 if (config_id == VA_INVALID_ID)
385 return VA_STATUS_ERROR_INVALID_CONFIG;
386
387 if (!attrib_list && !num_attribs)
388 return VA_STATUS_ERROR_INVALID_PARAMETER;
389
390 if (!attrib_list) {
391 *num_attribs = VL_VA_MAX_IMAGE_FORMATS + VASurfaceAttribCount;
392 return VA_STATUS_SUCCESS;
393 }
394
395 if (!ctx)
396 return VA_STATUS_ERROR_INVALID_CONTEXT;
397
398 drv = VL_VA_DRIVER(ctx);
399
400 if (!drv)
401 return VA_STATUS_ERROR_INVALID_CONTEXT;
402
403 pipe_mutex_lock(drv->mutex);
404 config = handle_table_get(drv->htab, config_id);
405 pipe_mutex_unlock(drv->mutex);
406
407 if (!config)
408 return VA_STATUS_ERROR_INVALID_CONFIG;
409
410 pscreen = VL_VA_PSCREEN(ctx);
411
412 if (!pscreen)
413 return VA_STATUS_ERROR_INVALID_CONTEXT;
414
415 attribs = CALLOC(VL_VA_MAX_IMAGE_FORMATS + VASurfaceAttribCount,
416 sizeof(VASurfaceAttrib));
417
418 if (!attribs)
419 return VA_STATUS_ERROR_ALLOCATION_FAILED;
420
421 i = 0;
422
423 /* vlVaCreateConfig returns PIPE_VIDEO_PROFILE_UNKNOWN
424 * only for VAEntrypointVideoProc. */
425 if (config->profile == PIPE_VIDEO_PROFILE_UNKNOWN) {
426 if (config->rt_format & VA_RT_FORMAT_RGB32) {
427 for (j = 0; j < ARRAY_SIZE(vpp_surface_formats); ++j) {
428 attribs[i].type = VASurfaceAttribPixelFormat;
429 attribs[i].value.type = VAGenericValueTypeInteger;
430 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
431 attribs[i].value.value.i = PipeFormatToVaFourcc(vpp_surface_formats[j]);
432 i++;
433 }
434 }
435 if (config->rt_format & VA_RT_FORMAT_YUV420) {
436 attribs[i].type = VASurfaceAttribPixelFormat;
437 attribs[i].value.type = VAGenericValueTypeInteger;
438 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
439 attribs[i].value.value.i = VA_FOURCC_NV12;
440 i++;
441 }
442 } else {
443 /* Assume VAEntrypointVLD for now. */
444 attribs[i].type = VASurfaceAttribPixelFormat;
445 attribs[i].value.type = VAGenericValueTypeInteger;
446 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
447 attribs[i].value.value.i = VA_FOURCC_NV12;
448 i++;
449 }
450
451 attribs[i].type = VASurfaceAttribMemoryType;
452 attribs[i].value.type = VAGenericValueTypeInteger;
453 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
454 attribs[i].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA |
455 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
456 i++;
457
458 attribs[i].type = VASurfaceAttribExternalBufferDescriptor;
459 attribs[i].value.type = VAGenericValueTypePointer;
460 attribs[i].flags = VA_SURFACE_ATTRIB_SETTABLE;
461 attribs[i].value.value.p = NULL; /* ignore */
462 i++;
463
464 attribs[i].type = VASurfaceAttribMaxWidth;
465 attribs[i].value.type = VAGenericValueTypeInteger;
466 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
467 attribs[i].value.value.i = vl_video_buffer_max_size(pscreen);
468 i++;
469
470 attribs[i].type = VASurfaceAttribMaxHeight;
471 attribs[i].value.type = VAGenericValueTypeInteger;
472 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
473 attribs[i].value.value.i = vl_video_buffer_max_size(pscreen);
474 i++;
475
476 if (i > *num_attribs) {
477 *num_attribs = i;
478 FREE(attribs);
479 return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
480 }
481
482 *num_attribs = i;
483 memcpy(attrib_list, attribs, i * sizeof(VASurfaceAttrib));
484 FREE(attribs);
485
486 return VA_STATUS_SUCCESS;
487 }
488
489 static VAStatus
490 suface_from_external_memory(VADriverContextP ctx, vlVaSurface *surface,
491 VASurfaceAttribExternalBuffers *memory_attibute,
492 int index, VASurfaceID *surfaces,
493 struct pipe_video_buffer *templat)
494 {
495 vlVaDriver *drv;
496 struct pipe_screen *pscreen;
497 struct pipe_resource *resource;
498 struct pipe_resource res_templ;
499 struct winsys_handle whandle;
500 struct pipe_resource *resources[VL_NUM_COMPONENTS];
501
502 if (!ctx)
503 return VA_STATUS_ERROR_INVALID_PARAMETER;
504
505 pscreen = VL_VA_PSCREEN(ctx);
506 drv = VL_VA_DRIVER(ctx);
507
508 if (!memory_attibute || !memory_attibute->buffers ||
509 index > memory_attibute->num_buffers)
510 return VA_STATUS_ERROR_INVALID_PARAMETER;
511
512 if (surface->templat.width != memory_attibute->width ||
513 surface->templat.height != memory_attibute->height ||
514 memory_attibute->num_planes < 1)
515 return VA_STATUS_ERROR_INVALID_PARAMETER;
516
517 switch (memory_attibute->pixel_format) {
518 case VA_FOURCC_RGBA:
519 case VA_FOURCC_RGBX:
520 case VA_FOURCC_BGRA:
521 case VA_FOURCC_BGRX:
522 if (memory_attibute->num_planes != 1)
523 return VA_STATUS_ERROR_INVALID_PARAMETER;
524 break;
525 default:
526 return VA_STATUS_ERROR_INVALID_PARAMETER;
527 }
528
529 memset(&res_templ, 0, sizeof(res_templ));
530 res_templ.target = PIPE_TEXTURE_2D;
531 res_templ.last_level = 0;
532 res_templ.depth0 = 1;
533 res_templ.array_size = 1;
534 res_templ.width0 = memory_attibute->width;
535 res_templ.height0 = memory_attibute->height;
536 res_templ.format = surface->templat.buffer_format;
537 res_templ.bind = PIPE_BIND_SAMPLER_VIEW;
538 res_templ.usage = PIPE_USAGE_DEFAULT;
539
540 memset(&whandle, 0, sizeof(struct winsys_handle));
541 whandle.type = DRM_API_HANDLE_TYPE_FD;
542 whandle.handle = memory_attibute->buffers[index];
543 whandle.stride = memory_attibute->pitches[index];
544
545 resource = pscreen->resource_from_handle(pscreen, &res_templ, &whandle,
546 PIPE_HANDLE_USAGE_READ_WRITE);
547
548 if (!resource)
549 return VA_STATUS_ERROR_ALLOCATION_FAILED;
550
551 memset(resources, 0, sizeof resources);
552 resources[0] = resource;
553
554 surface->buffer = vl_video_buffer_create_ex2(drv->pipe, templat, resources);
555 if (!surface->buffer)
556 return VA_STATUS_ERROR_ALLOCATION_FAILED;
557
558 util_dynarray_init(&surface->subpics);
559 surfaces[index] = handle_table_add(drv->htab, surface);
560
561 if (!surfaces[index]) {
562 surface->buffer->destroy(surface->buffer);
563 return VA_STATUS_ERROR_ALLOCATION_FAILED;
564 }
565
566 return VA_STATUS_SUCCESS;
567 }
568
569 VAStatus
570 vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
571 unsigned int width, unsigned int height,
572 VASurfaceID *surfaces, unsigned int num_surfaces,
573 VASurfaceAttrib *attrib_list, unsigned int num_attribs)
574 {
575 vlVaDriver *drv;
576 VASurfaceAttribExternalBuffers *memory_attibute;
577 struct pipe_video_buffer templat;
578 struct pipe_screen *pscreen;
579 int i;
580 int memory_type;
581 int expected_fourcc;
582 VAStatus vaStatus;
583
584 if (!ctx)
585 return VA_STATUS_ERROR_INVALID_CONTEXT;
586
587 if (!(width && height))
588 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
589
590 drv = VL_VA_DRIVER(ctx);
591
592 if (!drv)
593 return VA_STATUS_ERROR_INVALID_CONTEXT;
594
595 pscreen = VL_VA_PSCREEN(ctx);
596
597 if (!pscreen)
598 return VA_STATUS_ERROR_INVALID_CONTEXT;
599
600 /* Default. */
601 memory_attibute = NULL;
602 memory_type = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
603 expected_fourcc = 0;
604
605 for (i = 0; i < num_attribs && attrib_list; i++) {
606 if ((attrib_list[i].type == VASurfaceAttribPixelFormat) &&
607 (attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE)) {
608 if (attrib_list[i].value.type != VAGenericValueTypeInteger)
609 return VA_STATUS_ERROR_INVALID_PARAMETER;
610 expected_fourcc = attrib_list[i].value.value.i;
611 }
612
613 if ((attrib_list[i].type == VASurfaceAttribMemoryType) &&
614 (attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE)) {
615
616 if (attrib_list[i].value.type != VAGenericValueTypeInteger)
617 return VA_STATUS_ERROR_INVALID_PARAMETER;
618
619 switch (attrib_list[i].value.value.i) {
620 case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
621 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
622 memory_type = attrib_list[i].value.value.i;
623 break;
624 default:
625 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
626 }
627 }
628
629 if ((attrib_list[i].type == VASurfaceAttribExternalBufferDescriptor) &&
630 (attrib_list[i].flags == VA_SURFACE_ATTRIB_SETTABLE)) {
631 if (attrib_list[i].value.type != VAGenericValueTypePointer)
632 return VA_STATUS_ERROR_INVALID_PARAMETER;
633 memory_attibute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p;
634 }
635 }
636
637 if (VA_RT_FORMAT_YUV420 != format &&
638 VA_RT_FORMAT_YUV422 != format &&
639 VA_RT_FORMAT_YUV444 != format &&
640 VA_RT_FORMAT_RGB32 != format) {
641 return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
642 }
643
644 switch (memory_type) {
645 case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
646 break;
647 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
648 if (!memory_attibute)
649 return VA_STATUS_ERROR_INVALID_PARAMETER;
650
651 expected_fourcc = memory_attibute->pixel_format;
652 break;
653 default:
654 assert(0);
655 }
656
657 memset(&templat, 0, sizeof(templat));
658
659 templat.buffer_format = pscreen->get_video_param(
660 pscreen,
661 PIPE_VIDEO_PROFILE_UNKNOWN,
662 PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
663 PIPE_VIDEO_CAP_PREFERED_FORMAT
664 );
665 templat.interlaced = pscreen->get_video_param(
666 pscreen,
667 PIPE_VIDEO_PROFILE_UNKNOWN,
668 PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
669 PIPE_VIDEO_CAP_PREFERS_INTERLACED
670 );
671
672 if (expected_fourcc) {
673 enum pipe_format expected_format = VaFourccToPipeFormat(expected_fourcc);
674
675 if (expected_format != templat.buffer_format || memory_attibute)
676 templat.interlaced = 0;
677
678 templat.buffer_format = expected_format;
679 }
680
681 templat.chroma_format = ChromaToPipe(format);
682
683 templat.width = width;
684 templat.height = height;
685 if (debug_get_option_nointerlace())
686 templat.interlaced = false;
687
688 memset(surfaces, VA_INVALID_ID, num_surfaces * sizeof(VASurfaceID));
689
690 pipe_mutex_lock(drv->mutex);
691 for (i = 0; i < num_surfaces; i++) {
692 vlVaSurface *surf = CALLOC(1, sizeof(vlVaSurface));
693 if (!surf)
694 goto no_res;
695
696 surf->templat = templat;
697
698 switch (memory_type) {
699 case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
700 /* The application will clear the TILING flag when the surface is
701 * intended to be exported as dmabuf. Adding shared flag because not
702 * null memory_attibute means VASurfaceAttribExternalBuffers is used.
703 */
704 if (memory_attibute &&
705 !(memory_attibute->flags & VA_SURFACE_EXTBUF_DESC_ENABLE_TILING))
706 templat.bind = PIPE_BIND_LINEAR | PIPE_BIND_SHARED;
707
708 surf->buffer = drv->pipe->create_video_buffer(drv->pipe, &templat);
709 if (!surf->buffer) {
710 FREE(surf);
711 goto no_res;
712 }
713 util_dynarray_init(&surf->subpics);
714 surfaces[i] = handle_table_add(drv->htab, surf);
715 break;
716 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
717 vaStatus = suface_from_external_memory(ctx, surf, memory_attibute, i, surfaces, &templat);
718 if (vaStatus != VA_STATUS_SUCCESS) {
719 FREE(surf);
720 goto no_res;
721 }
722 break;
723 default:
724 assert(0);
725 }
726 }
727 pipe_mutex_unlock(drv->mutex);
728
729 return VA_STATUS_SUCCESS;
730
731 no_res:
732 pipe_mutex_unlock(drv->mutex);
733 if (i)
734 vlVaDestroySurfaces(ctx, surfaces, i);
735
736 return VA_STATUS_ERROR_ALLOCATION_FAILED;
737 }
738
739 VAStatus
740 vlVaQueryVideoProcFilters(VADriverContextP ctx, VAContextID context,
741 VAProcFilterType *filters, unsigned int *num_filters)
742 {
743 unsigned int num = 0;
744
745 if (!ctx)
746 return VA_STATUS_ERROR_INVALID_CONTEXT;
747
748 if (!num_filters || !filters)
749 return VA_STATUS_ERROR_INVALID_PARAMETER;
750
751 filters[num++] = VAProcFilterDeinterlacing;
752
753 *num_filters = num;
754
755 return VA_STATUS_SUCCESS;
756 }
757
758 VAStatus
759 vlVaQueryVideoProcFilterCaps(VADriverContextP ctx, VAContextID context,
760 VAProcFilterType type, void *filter_caps,
761 unsigned int *num_filter_caps)
762 {
763 unsigned int i;
764
765 if (!ctx)
766 return VA_STATUS_ERROR_INVALID_CONTEXT;
767
768 if (!filter_caps || !num_filter_caps)
769 return VA_STATUS_ERROR_INVALID_PARAMETER;
770
771 i = 0;
772
773 switch (type) {
774 case VAProcFilterNone:
775 break;
776 case VAProcFilterDeinterlacing: {
777 VAProcFilterCapDeinterlacing *deint = filter_caps;
778
779 if (*num_filter_caps < 3) {
780 *num_filter_caps = 3;
781 return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
782 }
783
784 deint[i++].type = VAProcDeinterlacingBob;
785 deint[i++].type = VAProcDeinterlacingWeave;
786 deint[i++].type = VAProcDeinterlacingMotionAdaptive;
787 break;
788 }
789
790 case VAProcFilterNoiseReduction:
791 case VAProcFilterSharpening:
792 case VAProcFilterColorBalance:
793 case VAProcFilterSkinToneEnhancement:
794 return VA_STATUS_ERROR_UNIMPLEMENTED;
795 default:
796 assert(0);
797 }
798
799 *num_filter_caps = i;
800
801 return VA_STATUS_SUCCESS;
802 }
803
804 static VAProcColorStandardType vpp_input_color_standards[] = {
805 VAProcColorStandardBT601
806 };
807
808 static VAProcColorStandardType vpp_output_color_standards[] = {
809 VAProcColorStandardBT601
810 };
811
812 VAStatus
813 vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context,
814 VABufferID *filters, unsigned int num_filters,
815 VAProcPipelineCaps *pipeline_cap)
816 {
817 unsigned int i = 0;
818
819 if (!ctx)
820 return VA_STATUS_ERROR_INVALID_CONTEXT;
821
822 if (!pipeline_cap)
823 return VA_STATUS_ERROR_INVALID_PARAMETER;
824
825 if (num_filters && !filters)
826 return VA_STATUS_ERROR_INVALID_PARAMETER;
827
828 pipeline_cap->pipeline_flags = 0;
829 pipeline_cap->filter_flags = 0;
830 pipeline_cap->num_forward_references = 0;
831 pipeline_cap->num_backward_references = 0;
832 pipeline_cap->num_input_color_standards = ARRAY_SIZE(vpp_input_color_standards);
833 pipeline_cap->input_color_standards = vpp_input_color_standards;
834 pipeline_cap->num_output_color_standards = ARRAY_SIZE(vpp_output_color_standards);
835 pipeline_cap->output_color_standards = vpp_output_color_standards;
836
837 for (i = 0; i < num_filters; i++) {
838 vlVaBuffer *buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, filters[i]);
839 VAProcFilterParameterBufferBase *filter;
840
841 if (!buf || buf->type != VAProcFilterParameterBufferType)
842 return VA_STATUS_ERROR_INVALID_BUFFER;
843
844 filter = buf->data;
845 switch (filter->type) {
846 case VAProcFilterDeinterlacing: {
847 VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
848 if (deint->algorithm == VAProcDeinterlacingMotionAdaptive) {
849 pipeline_cap->num_forward_references = 1;
850 pipeline_cap->num_backward_references = 2;
851 }
852 break;
853 }
854 default:
855 return VA_STATUS_ERROR_UNIMPLEMENTED;
856 }
857 }
858
859 return VA_STATUS_SUCCESS;
860 }