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
31 #include "util/u_memory.h"
32 #include "util/u_handle_table.h"
33 #include "util/u_surface.h"
34 #include "util/u_video.h"
35 #include "util/u_process.h"
36
37 #include "vl/vl_winsys.h"
38 #include "vl/vl_video_buffer.h"
39
40 #include "va_private.h"
41
42 static const VAImageFormat formats[] =
43 {
44 {VA_FOURCC('N','V','1','2')},
45 {VA_FOURCC('P','0','1','0')},
46 {VA_FOURCC('P','0','1','6')},
47 {VA_FOURCC('I','4','2','0')},
48 {VA_FOURCC('Y','V','1','2')},
49 {VA_FOURCC('Y','U','Y','V')},
50 {VA_FOURCC('Y','U','Y','2')},
51 {VA_FOURCC('U','Y','V','Y')},
52 {.fourcc = VA_FOURCC('B','G','R','A'), .byte_order = VA_LSB_FIRST, 32, 32,
53 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000},
54 {.fourcc = VA_FOURCC('R','G','B','A'), .byte_order = VA_LSB_FIRST, 32, 32,
55 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
56 {.fourcc = VA_FOURCC('B','G','R','X'), .byte_order = VA_LSB_FIRST, 32, 24,
57 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
58 {.fourcc = VA_FOURCC('R','G','B','X'), .byte_order = VA_LSB_FIRST, 32, 24,
59 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000}
60 };
61
62 static void
vlVaVideoSurfaceSize(vlVaSurface * p_surf,int component,unsigned * width,unsigned * height)63 vlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
64 unsigned *width, unsigned *height)
65 {
66 *width = p_surf->templat.width;
67 *height = p_surf->templat.height;
68
69 vl_video_buffer_adjust_size(width, height, component,
70 pipe_format_to_chroma_format(p_surf->templat.buffer_format),
71 p_surf->templat.interlaced);
72 }
73
74 VAStatus
vlVaQueryImageFormats(VADriverContextP ctx,VAImageFormat * format_list,int * num_formats)75 vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats)
76 {
77 struct pipe_screen *pscreen;
78 enum pipe_format format;
79 int i;
80
81 STATIC_ASSERT(ARRAY_SIZE(formats) == VL_VA_MAX_IMAGE_FORMATS);
82
83 if (!ctx)
84 return VA_STATUS_ERROR_INVALID_CONTEXT;
85
86 if (!(format_list && num_formats))
87 return VA_STATUS_ERROR_INVALID_PARAMETER;
88
89 *num_formats = 0;
90 pscreen = VL_VA_PSCREEN(ctx);
91 for (i = 0; i < ARRAY_SIZE(formats); ++i) {
92 format = VaFourccToPipeFormat(formats[i].fourcc);
93 if (pscreen->is_video_format_supported(pscreen, format,
94 PIPE_VIDEO_PROFILE_UNKNOWN,
95 PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
96 format_list[(*num_formats)++] = formats[i];
97 }
98
99 return VA_STATUS_SUCCESS;
100 }
101
102 VAStatus
vlVaCreateImage(VADriverContextP ctx,VAImageFormat * format,int width,int height,VAImage * image)103 vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
104 {
105 VAStatus status;
106 vlVaDriver *drv;
107 VAImage *img;
108 int w, h;
109
110 if (!ctx)
111 return VA_STATUS_ERROR_INVALID_CONTEXT;
112
113 if (!(format && image && width && height))
114 return VA_STATUS_ERROR_INVALID_PARAMETER;
115
116 drv = VL_VA_DRIVER(ctx);
117
118 img = CALLOC(1, sizeof(VAImage));
119 if (!img)
120 return VA_STATUS_ERROR_ALLOCATION_FAILED;
121 mtx_lock(&drv->mutex);
122 img->image_id = handle_table_add(drv->htab, img);
123 mtx_unlock(&drv->mutex);
124
125 img->format = *format;
126 img->width = width;
127 img->height = height;
128 w = align(width, 2);
129 h = align(height, 2);
130
131 switch (format->fourcc) {
132 case VA_FOURCC('N','V','1','2'):
133 img->num_planes = 2;
134 img->pitches[0] = w;
135 img->offsets[0] = 0;
136 img->pitches[1] = w;
137 img->offsets[1] = w * h;
138 img->data_size = w * h * 3 / 2;
139 break;
140
141 case VA_FOURCC('P','0','1','0'):
142 case VA_FOURCC('P','0','1','6'):
143 img->num_planes = 2;
144 img->pitches[0] = w * 2;
145 img->offsets[0] = 0;
146 img->pitches[1] = w * 2;
147 img->offsets[1] = w * h * 2;
148 img->data_size = w * h * 3;
149 break;
150
151 case VA_FOURCC('I','4','2','0'):
152 case VA_FOURCC('Y','V','1','2'):
153 img->num_planes = 3;
154 img->pitches[0] = w;
155 img->offsets[0] = 0;
156 img->pitches[1] = w / 2;
157 img->offsets[1] = w * h;
158 img->pitches[2] = w / 2;
159 img->offsets[2] = w * h * 5 / 4;
160 img->data_size = w * h * 3 / 2;
161 break;
162
163 case VA_FOURCC('U','Y','V','Y'):
164 case VA_FOURCC('Y','U','Y','V'):
165 case VA_FOURCC('Y','U','Y','2'):
166 img->num_planes = 1;
167 img->pitches[0] = w * 2;
168 img->offsets[0] = 0;
169 img->data_size = w * h * 2;
170 break;
171
172 case VA_FOURCC('B','G','R','A'):
173 case VA_FOURCC('R','G','B','A'):
174 case VA_FOURCC('B','G','R','X'):
175 case VA_FOURCC('R','G','B','X'):
176 img->num_planes = 1;
177 img->pitches[0] = w * 4;
178 img->offsets[0] = 0;
179 img->data_size = w * h * 4;
180 break;
181
182 default:
183 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
184 }
185
186 status = vlVaCreateBuffer(ctx, 0, VAImageBufferType,
187 align(img->data_size, 16),
188 1, NULL, &img->buf);
189 if (status != VA_STATUS_SUCCESS)
190 return status;
191 *image = *img;
192
193 return status;
194 }
195
196 VAStatus
vlVaDeriveImage(VADriverContextP ctx,VASurfaceID surface,VAImage * image)197 vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
198 {
199 vlVaDriver *drv;
200 vlVaSurface *surf;
201 vlVaBuffer *img_buf;
202 VAImage *img;
203 VAStatus status;
204 struct pipe_screen *screen;
205 struct pipe_surface **surfaces;
206 struct pipe_video_buffer *new_buffer = NULL;
207 int w;
208 int h;
209 int i;
210 unsigned stride = 0;
211 unsigned offset = 0;
212
213 /* This function is used by some programs to test for hardware decoding, but on
214 * AMD devices, the buffers default to interlaced, which causes this function to fail.
215 * Some programs expect this function to fail, while others, assume this means
216 * hardware acceleration is not available and give up without trying the fall-back
217 * vaCreateImage + vaPutImage
218 */
219 const char *proc = util_get_process_name();
220 const char *derive_interlaced_allowlist[] = {
221 "vlc",
222 "h264encode",
223 "hevcencode"
224 };
225
226 const char *derive_progressive_disallowlist[] = {
227 "ffmpeg"
228 };
229
230 if (!ctx)
231 return VA_STATUS_ERROR_INVALID_CONTEXT;
232
233 drv = VL_VA_DRIVER(ctx);
234
235 if (!drv)
236 return VA_STATUS_ERROR_INVALID_CONTEXT;
237
238 screen = VL_VA_PSCREEN(ctx);
239
240 if (!screen)
241 return VA_STATUS_ERROR_INVALID_CONTEXT;
242
243 surf = handle_table_get(drv->htab, surface);
244
245 if (!surf || !surf->buffer)
246 return VA_STATUS_ERROR_INVALID_SURFACE;
247
248 if (surf->buffer->interlaced) {
249 for (i = 0; i < ARRAY_SIZE(derive_interlaced_allowlist); i++)
250 if ((strcmp(derive_interlaced_allowlist[i], proc) == 0))
251 break;
252
253 if (i >= ARRAY_SIZE(derive_interlaced_allowlist) ||
254 !screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN,
255 PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
256 PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE))
257 return VA_STATUS_ERROR_OPERATION_FAILED;
258 } else {
259 if(!screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN,
260 PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
261 PIPE_VIDEO_SUPPORTS_CONTIGUOUS_PLANES_MAP))
262 for (i = 0; i < ARRAY_SIZE(derive_progressive_disallowlist); i++)
263 if ((strcmp(derive_progressive_disallowlist[i], proc) == 0))
264 return VA_STATUS_ERROR_OPERATION_FAILED;
265 }
266
267 surfaces = surf->buffer->get_surfaces(surf->buffer);
268 if (!surfaces || !surfaces[0]->texture)
269 return VA_STATUS_ERROR_ALLOCATION_FAILED;
270
271 img = CALLOC(1, sizeof(VAImage));
272 if (!img)
273 return VA_STATUS_ERROR_ALLOCATION_FAILED;
274
275 img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
276 img->buf = VA_INVALID_ID;
277 /* Use the visible dimensions. */
278 img->width = surf->templat.width;
279 img->height = surf->templat.height;
280 img->num_palette_entries = 0;
281 img->entry_bytes = 0;
282 /* Image data size is computed using internal dimensions. */
283 w = align(surf->buffer->width, 2);
284 h = align(surf->buffer->height, 2);
285
286 for (i = 0; i < ARRAY_SIZE(formats); ++i) {
287 if (img->format.fourcc == formats[i].fourcc) {
288 img->format = formats[i];
289 break;
290 }
291 }
292
293 mtx_lock(&drv->mutex);
294 if (screen->resource_get_info) {
295 screen->resource_get_info(screen, surfaces[0]->texture, &stride,
296 &offset);
297 if (!stride)
298 offset = 0;
299 }
300
301 img->num_planes = 1;
302 img->offsets[0] = offset;
303
304 switch (img->format.fourcc) {
305 case VA_FOURCC('U','Y','V','Y'):
306 case VA_FOURCC('Y','U','Y','V'):
307 img->pitches[0] = stride > 0 ? stride : w * 2;
308 assert(img->pitches[0] >= (w * 2));
309 img->data_size = img->pitches[0] * h;
310 break;
311
312 case VA_FOURCC('B','G','R','A'):
313 case VA_FOURCC('R','G','B','A'):
314 case VA_FOURCC('B','G','R','X'):
315 case VA_FOURCC('R','G','B','X'):
316 img->pitches[0] = stride > 0 ? stride : w * 4;
317 assert(img->pitches[0] >= (w * 4));
318 img->data_size = img->pitches[0] * h;
319 break;
320
321 case VA_FOURCC('N','V','1','2'):
322 case VA_FOURCC('P','0','1','0'):
323 case VA_FOURCC('P','0','1','6'):
324 {
325 /* In some gallium platforms, the stride and offset are different*/
326 /* for the Y and UV planes, query them independently.*/
327 if (screen->resource_get_info) {
328 /* resource_get_info is called above for surfaces[0]->texture and */
329 /* saved results in stride, offset, reuse those values to avoid a new call to: */
330 /* screen->resource_get_info(screen, surfaces[0]->texture, &img->pitches[0],*/
331 /* &img->offsets[0]);*/
332 img->pitches[0] = stride;
333 img->offsets[0] = offset;
334
335 screen->resource_get_info(screen, surfaces[1]->texture, &img->pitches[1],
336 &img->offsets[1]);
337 if (!img->pitches[1])
338 img->offsets[1] = 0;
339 }
340
341 if (surf->buffer->interlaced) {
342 struct u_rect src_rect, dst_rect;
343 struct pipe_video_buffer new_template;
344
345 new_template = surf->templat;
346 new_template.interlaced = false;
347 new_buffer = drv->pipe->create_video_buffer(drv->pipe, &new_template);
348
349 /* not all devices support non-interlaced buffers */
350 if (!new_buffer) {
351 status = VA_STATUS_ERROR_OPERATION_FAILED;
352 goto exit_on_error;
353 }
354
355 /* convert the interlaced to the progressive */
356 src_rect.x0 = dst_rect.x0 = 0;
357 src_rect.x1 = dst_rect.x1 = surf->templat.width;
358 src_rect.y0 = dst_rect.y0 = 0;
359 src_rect.y1 = dst_rect.y1 = surf->templat.height;
360
361 vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
362 surf->buffer, new_buffer,
363 &src_rect, &dst_rect,
364 VL_COMPOSITOR_WEAVE);
365
366 /* recalculate the values now that we have a new surface */
367 surfaces = surf->buffer->get_surfaces(new_buffer);
368 if (screen->resource_get_info) {
369 screen->resource_get_info(screen, surfaces[0]->texture, &img->pitches[0],
370 &img->offsets[0]);
371 if (!img->pitches[0])
372 img->offsets[0] = 0;
373
374 screen->resource_get_info(screen, surfaces[1]->texture, &img->pitches[1],
375 &img->offsets[1]);
376 if (!img->pitches[1])
377 img->offsets[1] = 0;
378 }
379
380 w = align(new_buffer->width, 2);
381 h = align(new_buffer->height, 2);
382 }
383
384 img->num_planes = 2;
385 if(screen->resource_get_info) {
386 /* Note this block might use h and w from the recalculated size if it entered
387 the interlaced branch above.*/
388 img->data_size = (img->pitches[0] * h) + (img->pitches[1] * h / 2);
389 } else {
390 /* Use stride = w as default if screen->resource_get_info was not available */
391 img->pitches[0] = w;
392 img->pitches[1] = w;
393 img->offsets[1] = w * h;
394 img->data_size = w * h * 3 / 2;
395 }
396 } break;
397 default:
398 /* VaDeriveImage only supports contiguous planes. But there is now a
399 more generic api vlVaExportSurfaceHandle. */
400 status = VA_STATUS_ERROR_OPERATION_FAILED;
401 goto exit_on_error;
402 }
403
404 img_buf = CALLOC(1, sizeof(vlVaBuffer));
405 if (!img_buf) {
406 status = VA_STATUS_ERROR_ALLOCATION_FAILED;
407 goto exit_on_error;
408 }
409
410 img->image_id = handle_table_add(drv->htab, img);
411
412 img_buf->type = VAImageBufferType;
413 img_buf->size = img->data_size;
414 img_buf->num_elements = 1;
415
416 pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
417 img_buf->derived_image_buffer = new_buffer;
418
419 img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
420 mtx_unlock(&drv->mutex);
421
422 *image = *img;
423
424 return VA_STATUS_SUCCESS;
425
426 exit_on_error:
427 FREE(img);
428 mtx_unlock(&drv->mutex);
429 return status;
430 }
431
432 VAStatus
vlVaDestroyImage(VADriverContextP ctx,VAImageID image)433 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
434 {
435 vlVaDriver *drv;
436 VAImage *vaimage;
437 VAStatus status;
438
439 if (!ctx)
440 return VA_STATUS_ERROR_INVALID_CONTEXT;
441
442 drv = VL_VA_DRIVER(ctx);
443 mtx_lock(&drv->mutex);
444 vaimage = handle_table_get(drv->htab, image);
445 if (!vaimage) {
446 mtx_unlock(&drv->mutex);
447 return VA_STATUS_ERROR_INVALID_IMAGE;
448 }
449
450 handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
451 mtx_unlock(&drv->mutex);
452 status = vlVaDestroyBuffer(ctx, vaimage->buf);
453 FREE(vaimage);
454 return status;
455 }
456
457 VAStatus
vlVaSetImagePalette(VADriverContextP ctx,VAImageID image,unsigned char * palette)458 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
459 {
460 if (!ctx)
461 return VA_STATUS_ERROR_INVALID_CONTEXT;
462
463 return VA_STATUS_ERROR_UNIMPLEMENTED;
464 }
465
466 VAStatus
vlVaGetImage(VADriverContextP ctx,VASurfaceID surface,int x,int y,unsigned int width,unsigned int height,VAImageID image)467 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
468 unsigned int width, unsigned int height, VAImageID image)
469 {
470 vlVaDriver *drv;
471 vlVaSurface *surf;
472 vlVaBuffer *img_buf;
473 VAImage *vaimage;
474 struct pipe_sampler_view **views;
475 enum pipe_format format;
476 bool convert = false;
477 void *data[3];
478 unsigned pitches[3], i, j;
479
480 if (!ctx)
481 return VA_STATUS_ERROR_INVALID_CONTEXT;
482
483 drv = VL_VA_DRIVER(ctx);
484
485 mtx_lock(&drv->mutex);
486 surf = handle_table_get(drv->htab, surface);
487 if (!surf || !surf->buffer) {
488 mtx_unlock(&drv->mutex);
489 return VA_STATUS_ERROR_INVALID_SURFACE;
490 }
491
492 vaimage = handle_table_get(drv->htab, image);
493 if (!vaimage) {
494 mtx_unlock(&drv->mutex);
495 return VA_STATUS_ERROR_INVALID_IMAGE;
496 }
497
498 if (x < 0 || y < 0) {
499 mtx_unlock(&drv->mutex);
500 return VA_STATUS_ERROR_INVALID_PARAMETER;
501 }
502
503 if (x + width > surf->templat.width ||
504 y + height > surf->templat.height) {
505 mtx_unlock(&drv->mutex);
506 return VA_STATUS_ERROR_INVALID_PARAMETER;
507 }
508
509 if (width > vaimage->width ||
510 height > vaimage->height) {
511 mtx_unlock(&drv->mutex);
512 return VA_STATUS_ERROR_INVALID_PARAMETER;
513 }
514
515 img_buf = handle_table_get(drv->htab, vaimage->buf);
516 if (!img_buf) {
517 mtx_unlock(&drv->mutex);
518 return VA_STATUS_ERROR_INVALID_BUFFER;
519 }
520
521 format = VaFourccToPipeFormat(vaimage->format.fourcc);
522 if (format == PIPE_FORMAT_NONE) {
523 mtx_unlock(&drv->mutex);
524 return VA_STATUS_ERROR_OPERATION_FAILED;
525 }
526
527
528 if (format != surf->buffer->buffer_format) {
529 /* support NV12 to YV12 and IYUV conversion now only */
530 if ((format == PIPE_FORMAT_YV12 &&
531 surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
532 (format == PIPE_FORMAT_IYUV &&
533 surf->buffer->buffer_format == PIPE_FORMAT_NV12))
534 convert = true;
535 else if (format == PIPE_FORMAT_NV12 &&
536 (surf->buffer->buffer_format == PIPE_FORMAT_P010 ||
537 surf->buffer->buffer_format == PIPE_FORMAT_P016)) {
538 mtx_unlock(&drv->mutex);
539 return VA_STATUS_ERROR_OPERATION_FAILED;
540 }
541 else {
542 mtx_unlock(&drv->mutex);
543 return VA_STATUS_ERROR_OPERATION_FAILED;
544 }
545 }
546
547 views = surf->buffer->get_sampler_view_planes(surf->buffer);
548 if (!views) {
549 mtx_unlock(&drv->mutex);
550 return VA_STATUS_ERROR_OPERATION_FAILED;
551 }
552
553 for (i = 0; i < vaimage->num_planes; i++) {
554 data[i] = img_buf->data + vaimage->offsets[i];
555 pitches[i] = vaimage->pitches[i];
556 }
557 if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
558 void *tmp_d;
559 unsigned tmp_p;
560 tmp_d = data[1];
561 data[1] = data[2];
562 data[2] = tmp_d;
563 tmp_p = pitches[1];
564 pitches[1] = pitches[2];
565 pitches[2] = tmp_p;
566 }
567
568 for (i = 0; i < vaimage->num_planes; i++) {
569 unsigned box_w = align(width, 2);
570 unsigned box_h = align(height, 2);
571 unsigned box_x = x & ~1;
572 unsigned box_y = y & ~1;
573 if (!views[i]) continue;
574 vl_video_buffer_adjust_size(&box_w, &box_h, i,
575 pipe_format_to_chroma_format(surf->templat.buffer_format),
576 surf->templat.interlaced);
577 vl_video_buffer_adjust_size(&box_x, &box_y, i,
578 pipe_format_to_chroma_format(surf->templat.buffer_format),
579 surf->templat.interlaced);
580 for (j = 0; j < views[i]->texture->array_size; ++j) {
581 struct pipe_box box = {box_x, box_y, j, box_w, box_h, 1};
582 struct pipe_transfer *transfer;
583 uint8_t *map;
584 map = drv->pipe->texture_map(drv->pipe, views[i]->texture, 0,
585 PIPE_MAP_READ, &box, &transfer);
586 if (!map) {
587 mtx_unlock(&drv->mutex);
588 return VA_STATUS_ERROR_OPERATION_FAILED;
589 }
590
591 if (i == 1 && convert) {
592 u_copy_nv12_to_yv12(data, pitches, i, j,
593 transfer->stride, views[i]->texture->array_size,
594 map, box.width, box.height);
595 } else {
596 util_copy_rect(data[i] + pitches[i] * j,
597 views[i]->texture->format,
598 pitches[i] * views[i]->texture->array_size, 0, 0,
599 box.width, box.height, map, transfer->stride, 0, 0);
600 }
601 pipe_texture_unmap(drv->pipe, transfer);
602 }
603 }
604 mtx_unlock(&drv->mutex);
605
606 return VA_STATUS_SUCCESS;
607 }
608
609 VAStatus
vlVaPutImage(VADriverContextP ctx,VASurfaceID surface,VAImageID image,int src_x,int src_y,unsigned int src_width,unsigned int src_height,int dest_x,int dest_y,unsigned int dest_width,unsigned int dest_height)610 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
611 int src_x, int src_y, unsigned int src_width, unsigned int src_height,
612 int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
613 {
614 vlVaDriver *drv;
615 vlVaSurface *surf;
616 vlVaBuffer *img_buf;
617 VAImage *vaimage;
618 struct pipe_sampler_view **views;
619 enum pipe_format format;
620 void *data[3];
621 unsigned pitches[3], i, j;
622
623 if (!ctx)
624 return VA_STATUS_ERROR_INVALID_CONTEXT;
625
626 drv = VL_VA_DRIVER(ctx);
627 mtx_lock(&drv->mutex);
628
629 surf = handle_table_get(drv->htab, surface);
630 if (!surf || !surf->buffer) {
631 mtx_unlock(&drv->mutex);
632 return VA_STATUS_ERROR_INVALID_SURFACE;
633 }
634
635 vaimage = handle_table_get(drv->htab, image);
636 if (!vaimage) {
637 mtx_unlock(&drv->mutex);
638 return VA_STATUS_ERROR_INVALID_IMAGE;
639 }
640
641 img_buf = handle_table_get(drv->htab, vaimage->buf);
642 if (!img_buf) {
643 mtx_unlock(&drv->mutex);
644 return VA_STATUS_ERROR_INVALID_BUFFER;
645 }
646
647 if (img_buf->derived_surface.resource) {
648 /* Attempting to transfer derived image to surface */
649 mtx_unlock(&drv->mutex);
650 return VA_STATUS_ERROR_UNIMPLEMENTED;
651 }
652
653 format = VaFourccToPipeFormat(vaimage->format.fourcc);
654
655 if (format == PIPE_FORMAT_NONE) {
656 mtx_unlock(&drv->mutex);
657 return VA_STATUS_ERROR_OPERATION_FAILED;
658 }
659
660 if ((format != surf->buffer->buffer_format) &&
661 ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) &&
662 ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) {
663 struct pipe_video_buffer *tmp_buf;
664
665 surf->templat.buffer_format = format;
666 if (format == PIPE_FORMAT_YUYV || format == PIPE_FORMAT_UYVY ||
667 format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
668 format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM)
669 surf->templat.interlaced = false;
670 tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
671
672 if (!tmp_buf) {
673 mtx_unlock(&drv->mutex);
674 return VA_STATUS_ERROR_ALLOCATION_FAILED;
675 }
676
677 surf->buffer->destroy(surf->buffer);
678 surf->buffer = tmp_buf;
679 }
680
681 views = surf->buffer->get_sampler_view_planes(surf->buffer);
682 if (!views) {
683 mtx_unlock(&drv->mutex);
684 return VA_STATUS_ERROR_OPERATION_FAILED;
685 }
686
687 for (i = 0; i < vaimage->num_planes; i++) {
688 data[i] = img_buf->data + vaimage->offsets[i];
689 pitches[i] = vaimage->pitches[i];
690 }
691 if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
692 void *tmp_d;
693 unsigned tmp_p;
694 tmp_d = data[1];
695 data[1] = data[2];
696 data[2] = tmp_d;
697 tmp_p = pitches[1];
698 pitches[1] = pitches[2];
699 pitches[2] = tmp_p;
700 }
701
702 for (i = 0; i < vaimage->num_planes; ++i) {
703 unsigned width, height;
704 struct pipe_resource *tex;
705
706 if (!views[i]) continue;
707 tex = views[i]->texture;
708
709 vlVaVideoSurfaceSize(surf, i, &width, &height);
710 for (j = 0; j < tex->array_size; ++j) {
711 struct pipe_box dst_box = {0, 0, j, width, height, 1};
712
713 if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV))
714 && (surf->buffer->buffer_format == PIPE_FORMAT_NV12)
715 && i == 1) {
716 struct pipe_transfer *transfer = NULL;
717 uint8_t *map = NULL;
718
719 map = drv->pipe->texture_map(drv->pipe,
720 tex,
721 0,
722 PIPE_MAP_WRITE |
723 PIPE_MAP_DISCARD_RANGE,
724 &dst_box, &transfer);
725 if (map == NULL) {
726 mtx_unlock(&drv->mutex);
727 return VA_STATUS_ERROR_OPERATION_FAILED;
728 }
729
730 u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j,
731 transfer->stride, tex->array_size,
732 map, dst_box.width, dst_box.height);
733 pipe_texture_unmap(drv->pipe, transfer);
734 } else {
735 drv->pipe->texture_subdata(drv->pipe, tex, 0,
736 PIPE_MAP_WRITE, &dst_box,
737 data[i] + pitches[i] * j,
738 pitches[i] * views[i]->texture->array_size, 0);
739 }
740 }
741 }
742 drv->pipe->flush(drv->pipe, NULL, 0);
743 mtx_unlock(&drv->mutex);
744
745 return VA_STATUS_SUCCESS;
746 }
747