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