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 if (!ctx)
227 return VA_STATUS_ERROR_INVALID_CONTEXT;
228
229 drv = VL_VA_DRIVER(ctx);
230
231 if (!drv)
232 return VA_STATUS_ERROR_INVALID_CONTEXT;
233
234 screen = VL_VA_PSCREEN(ctx);
235
236 if (!screen)
237 return VA_STATUS_ERROR_INVALID_CONTEXT;
238
239 surf = handle_table_get(drv->htab, surface);
240
241 if (!surf || !surf->buffer)
242 return VA_STATUS_ERROR_INVALID_SURFACE;
243
244 if (surf->buffer->interlaced) {
245 for (i = 0; i < ARRAY_SIZE(derive_interlaced_allowlist); i++)
246 if ((strcmp(derive_interlaced_allowlist[i], proc) == 0))
247 break;
248
249 if (i >= ARRAY_SIZE(derive_interlaced_allowlist) ||
250 !screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN,
251 PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
252 PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE))
253 return VA_STATUS_ERROR_OPERATION_FAILED;
254 }
255
256 surfaces = surf->buffer->get_surfaces(surf->buffer);
257 if (!surfaces || !surfaces[0]->texture)
258 return VA_STATUS_ERROR_ALLOCATION_FAILED;
259
260 img = CALLOC(1, sizeof(VAImage));
261 if (!img)
262 return VA_STATUS_ERROR_ALLOCATION_FAILED;
263
264 img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
265 img->buf = VA_INVALID_ID;
266 /* Use the visible dimensions. */
267 img->width = surf->templat.width;
268 img->height = surf->templat.height;
269 img->num_palette_entries = 0;
270 img->entry_bytes = 0;
271 /* Image data size is computed using internal dimensions. */
272 w = align(surf->buffer->width, 2);
273 h = align(surf->buffer->height, 2);
274
275 for (i = 0; i < ARRAY_SIZE(formats); ++i) {
276 if (img->format.fourcc == formats[i].fourcc) {
277 img->format = formats[i];
278 break;
279 }
280 }
281
282 mtx_lock(&drv->mutex);
283 if (screen->resource_get_info) {
284 screen->resource_get_info(screen, surfaces[0]->texture, &stride,
285 &offset);
286 if (!stride)
287 offset = 0;
288 }
289
290 img->num_planes = 1;
291 img->offsets[0] = offset;
292
293 switch (img->format.fourcc) {
294 case VA_FOURCC('U','Y','V','Y'):
295 case VA_FOURCC('Y','U','Y','V'):
296 img->pitches[0] = stride > 0 ? stride : w * 2;
297 assert(img->pitches[0] >= (w * 2));
298 img->data_size = img->pitches[0] * h;
299 break;
300
301 case VA_FOURCC('B','G','R','A'):
302 case VA_FOURCC('R','G','B','A'):
303 case VA_FOURCC('B','G','R','X'):
304 case VA_FOURCC('R','G','B','X'):
305 img->pitches[0] = stride > 0 ? stride : w * 4;
306 assert(img->pitches[0] >= (w * 4));
307 img->data_size = img->pitches[0] * h;
308 break;
309
310 case VA_FOURCC('N','V','1','2'):
311 case VA_FOURCC('P','0','1','0'):
312 case VA_FOURCC('P','0','1','6'):
313 if (surf->buffer->interlaced) {
314 struct u_rect src_rect, dst_rect;
315 struct pipe_video_buffer new_template;
316
317 new_template = surf->templat;
318 new_template.interlaced = false;
319 new_buffer = drv->pipe->create_video_buffer(drv->pipe, &new_template);
320
321 /* not all devices support non-interlaced buffers */
322 if (!new_buffer) {
323 status = VA_STATUS_ERROR_OPERATION_FAILED;
324 goto exit_on_error;
325 }
326
327 /* convert the interlaced to the progressive */
328 src_rect.x0 = dst_rect.x0 = 0;
329 src_rect.x1 = dst_rect.x1 = surf->templat.width;
330 src_rect.y0 = dst_rect.y0 = 0;
331 src_rect.y1 = dst_rect.y1 = surf->templat.height;
332
333 vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
334 surf->buffer, new_buffer,
335 &src_rect, &dst_rect,
336 VL_COMPOSITOR_WEAVE);
337
338 /* recalculate the values now that we have a new surface */
339 surfaces = surf->buffer->get_surfaces(new_buffer);
340 if (screen->resource_get_info) {
341 screen->resource_get_info(screen, surfaces[0]->texture, &stride,
342 &offset);
343 if (!stride)
344 offset = 0;
345 }
346
347 w = align(new_buffer->width, 2);
348 h = align(new_buffer->height, 2);
349 }
350
351 img->num_planes = 2;
352 img->pitches[0] = stride > 0 ? stride : w;
353 img->pitches[1] = stride > 0 ? stride : w;
354 img->offsets[1] = (stride > 0 ? stride : w) * h;
355 img->data_size = (stride > 0 ? stride : w) * h * 3 / 2;
356 break;
357
358 default:
359 /* VaDeriveImage only supports contiguous planes. But there is now a
360 more generic api vlVaExportSurfaceHandle. */
361 status = VA_STATUS_ERROR_OPERATION_FAILED;
362 goto exit_on_error;
363 }
364
365 img_buf = CALLOC(1, sizeof(vlVaBuffer));
366 if (!img_buf) {
367 status = VA_STATUS_ERROR_ALLOCATION_FAILED;
368 goto exit_on_error;
369 }
370
371 img->image_id = handle_table_add(drv->htab, img);
372
373 img_buf->type = VAImageBufferType;
374 img_buf->size = img->data_size;
375 img_buf->num_elements = 1;
376
377 pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
378 img_buf->derived_image_buffer = new_buffer;
379
380 img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
381 mtx_unlock(&drv->mutex);
382
383 *image = *img;
384
385 return VA_STATUS_SUCCESS;
386
387 exit_on_error:
388 FREE(img);
389 mtx_unlock(&drv->mutex);
390 return status;
391 }
392
393 VAStatus
vlVaDestroyImage(VADriverContextP ctx,VAImageID image)394 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
395 {
396 vlVaDriver *drv;
397 VAImage *vaimage;
398 VAStatus status;
399
400 if (!ctx)
401 return VA_STATUS_ERROR_INVALID_CONTEXT;
402
403 drv = VL_VA_DRIVER(ctx);
404 mtx_lock(&drv->mutex);
405 vaimage = handle_table_get(drv->htab, image);
406 if (!vaimage) {
407 mtx_unlock(&drv->mutex);
408 return VA_STATUS_ERROR_INVALID_IMAGE;
409 }
410
411 handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
412 mtx_unlock(&drv->mutex);
413 status = vlVaDestroyBuffer(ctx, vaimage->buf);
414 FREE(vaimage);
415 return status;
416 }
417
418 VAStatus
vlVaSetImagePalette(VADriverContextP ctx,VAImageID image,unsigned char * palette)419 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
420 {
421 if (!ctx)
422 return VA_STATUS_ERROR_INVALID_CONTEXT;
423
424 return VA_STATUS_ERROR_UNIMPLEMENTED;
425 }
426
427 VAStatus
vlVaGetImage(VADriverContextP ctx,VASurfaceID surface,int x,int y,unsigned int width,unsigned int height,VAImageID image)428 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
429 unsigned int width, unsigned int height, VAImageID image)
430 {
431 vlVaDriver *drv;
432 vlVaSurface *surf;
433 vlVaBuffer *img_buf;
434 VAImage *vaimage;
435 struct pipe_sampler_view **views;
436 enum pipe_format format;
437 bool convert = false;
438 void *data[3];
439 unsigned pitches[3], i, j;
440
441 if (!ctx)
442 return VA_STATUS_ERROR_INVALID_CONTEXT;
443
444 drv = VL_VA_DRIVER(ctx);
445
446 mtx_lock(&drv->mutex);
447 surf = handle_table_get(drv->htab, surface);
448 if (!surf || !surf->buffer) {
449 mtx_unlock(&drv->mutex);
450 return VA_STATUS_ERROR_INVALID_SURFACE;
451 }
452
453 vaimage = handle_table_get(drv->htab, image);
454 if (!vaimage) {
455 mtx_unlock(&drv->mutex);
456 return VA_STATUS_ERROR_INVALID_IMAGE;
457 }
458
459 if (x < 0 || y < 0) {
460 mtx_unlock(&drv->mutex);
461 return VA_STATUS_ERROR_INVALID_PARAMETER;
462 }
463
464 if (x + width > surf->templat.width ||
465 y + height > surf->templat.height) {
466 mtx_unlock(&drv->mutex);
467 return VA_STATUS_ERROR_INVALID_PARAMETER;
468 }
469
470 if (width > vaimage->width ||
471 height > vaimage->height) {
472 mtx_unlock(&drv->mutex);
473 return VA_STATUS_ERROR_INVALID_PARAMETER;
474 }
475
476 img_buf = handle_table_get(drv->htab, vaimage->buf);
477 if (!img_buf) {
478 mtx_unlock(&drv->mutex);
479 return VA_STATUS_ERROR_INVALID_BUFFER;
480 }
481
482 format = VaFourccToPipeFormat(vaimage->format.fourcc);
483 if (format == PIPE_FORMAT_NONE) {
484 mtx_unlock(&drv->mutex);
485 return VA_STATUS_ERROR_OPERATION_FAILED;
486 }
487
488
489 if (format != surf->buffer->buffer_format) {
490 /* support NV12 to YV12 and IYUV conversion now only */
491 if ((format == PIPE_FORMAT_YV12 &&
492 surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
493 (format == PIPE_FORMAT_IYUV &&
494 surf->buffer->buffer_format == PIPE_FORMAT_NV12))
495 convert = true;
496 else if (format == PIPE_FORMAT_NV12 &&
497 (surf->buffer->buffer_format == PIPE_FORMAT_P010 ||
498 surf->buffer->buffer_format == PIPE_FORMAT_P016)) {
499 mtx_unlock(&drv->mutex);
500 return VA_STATUS_ERROR_OPERATION_FAILED;
501 }
502 else {
503 mtx_unlock(&drv->mutex);
504 return VA_STATUS_ERROR_OPERATION_FAILED;
505 }
506 }
507
508 views = surf->buffer->get_sampler_view_planes(surf->buffer);
509 if (!views) {
510 mtx_unlock(&drv->mutex);
511 return VA_STATUS_ERROR_OPERATION_FAILED;
512 }
513
514 for (i = 0; i < vaimage->num_planes; i++) {
515 data[i] = img_buf->data + vaimage->offsets[i];
516 pitches[i] = vaimage->pitches[i];
517 }
518 if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
519 void *tmp_d;
520 unsigned tmp_p;
521 tmp_d = data[1];
522 data[1] = data[2];
523 data[2] = tmp_d;
524 tmp_p = pitches[1];
525 pitches[1] = pitches[2];
526 pitches[2] = tmp_p;
527 }
528
529 for (i = 0; i < vaimage->num_planes; i++) {
530 unsigned box_w = align(width, 2);
531 unsigned box_h = align(height, 2);
532 unsigned box_x = x & ~1;
533 unsigned box_y = y & ~1;
534 if (!views[i]) continue;
535 vl_video_buffer_adjust_size(&box_w, &box_h, i,
536 pipe_format_to_chroma_format(surf->templat.buffer_format),
537 surf->templat.interlaced);
538 vl_video_buffer_adjust_size(&box_x, &box_y, i,
539 pipe_format_to_chroma_format(surf->templat.buffer_format),
540 surf->templat.interlaced);
541 for (j = 0; j < views[i]->texture->array_size; ++j) {
542 struct pipe_box box = {box_x, box_y, j, box_w, box_h, 1};
543 struct pipe_transfer *transfer;
544 uint8_t *map;
545 map = drv->pipe->texture_map(drv->pipe, views[i]->texture, 0,
546 PIPE_MAP_READ, &box, &transfer);
547 if (!map) {
548 mtx_unlock(&drv->mutex);
549 return VA_STATUS_ERROR_OPERATION_FAILED;
550 }
551
552 if (i == 1 && convert) {
553 u_copy_nv12_to_yv12(data, pitches, i, j,
554 transfer->stride, views[i]->texture->array_size,
555 map, box.width, box.height);
556 } else {
557 util_copy_rect(data[i] + pitches[i] * j,
558 views[i]->texture->format,
559 pitches[i] * views[i]->texture->array_size, 0, 0,
560 box.width, box.height, map, transfer->stride, 0, 0);
561 }
562 pipe_texture_unmap(drv->pipe, transfer);
563 }
564 }
565 mtx_unlock(&drv->mutex);
566
567 return VA_STATUS_SUCCESS;
568 }
569
570 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)571 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
572 int src_x, int src_y, unsigned int src_width, unsigned int src_height,
573 int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
574 {
575 vlVaDriver *drv;
576 vlVaSurface *surf;
577 vlVaBuffer *img_buf;
578 VAImage *vaimage;
579 struct pipe_sampler_view **views;
580 enum pipe_format format;
581 void *data[3];
582 unsigned pitches[3], i, j;
583
584 if (!ctx)
585 return VA_STATUS_ERROR_INVALID_CONTEXT;
586
587 drv = VL_VA_DRIVER(ctx);
588 mtx_lock(&drv->mutex);
589
590 surf = handle_table_get(drv->htab, surface);
591 if (!surf || !surf->buffer) {
592 mtx_unlock(&drv->mutex);
593 return VA_STATUS_ERROR_INVALID_SURFACE;
594 }
595
596 vaimage = handle_table_get(drv->htab, image);
597 if (!vaimage) {
598 mtx_unlock(&drv->mutex);
599 return VA_STATUS_ERROR_INVALID_IMAGE;
600 }
601
602 img_buf = handle_table_get(drv->htab, vaimage->buf);
603 if (!img_buf) {
604 mtx_unlock(&drv->mutex);
605 return VA_STATUS_ERROR_INVALID_BUFFER;
606 }
607
608 if (img_buf->derived_surface.resource) {
609 /* Attempting to transfer derived image to surface */
610 mtx_unlock(&drv->mutex);
611 return VA_STATUS_ERROR_UNIMPLEMENTED;
612 }
613
614 format = VaFourccToPipeFormat(vaimage->format.fourcc);
615
616 if (format == PIPE_FORMAT_NONE) {
617 mtx_unlock(&drv->mutex);
618 return VA_STATUS_ERROR_OPERATION_FAILED;
619 }
620
621 if ((format != surf->buffer->buffer_format) &&
622 ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) &&
623 ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) {
624 struct pipe_video_buffer *tmp_buf;
625
626 surf->templat.buffer_format = format;
627 if (format == PIPE_FORMAT_YUYV || format == PIPE_FORMAT_UYVY ||
628 format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
629 format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM)
630 surf->templat.interlaced = false;
631 tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
632
633 if (!tmp_buf) {
634 mtx_unlock(&drv->mutex);
635 return VA_STATUS_ERROR_ALLOCATION_FAILED;
636 }
637
638 surf->buffer->destroy(surf->buffer);
639 surf->buffer = tmp_buf;
640 }
641
642 views = surf->buffer->get_sampler_view_planes(surf->buffer);
643 if (!views) {
644 mtx_unlock(&drv->mutex);
645 return VA_STATUS_ERROR_OPERATION_FAILED;
646 }
647
648 for (i = 0; i < vaimage->num_planes; i++) {
649 data[i] = img_buf->data + vaimage->offsets[i];
650 pitches[i] = vaimage->pitches[i];
651 }
652 if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
653 void *tmp_d;
654 unsigned tmp_p;
655 tmp_d = data[1];
656 data[1] = data[2];
657 data[2] = tmp_d;
658 tmp_p = pitches[1];
659 pitches[1] = pitches[2];
660 pitches[2] = tmp_p;
661 }
662
663 for (i = 0; i < vaimage->num_planes; ++i) {
664 unsigned width, height;
665 struct pipe_resource *tex;
666
667 if (!views[i]) continue;
668 tex = views[i]->texture;
669
670 vlVaVideoSurfaceSize(surf, i, &width, &height);
671 for (j = 0; j < tex->array_size; ++j) {
672 struct pipe_box dst_box = {0, 0, j, width, height, 1};
673
674 if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV))
675 && (surf->buffer->buffer_format == PIPE_FORMAT_NV12)
676 && i == 1) {
677 struct pipe_transfer *transfer = NULL;
678 uint8_t *map = NULL;
679
680 map = drv->pipe->texture_map(drv->pipe,
681 tex,
682 0,
683 PIPE_MAP_WRITE |
684 PIPE_MAP_DISCARD_RANGE,
685 &dst_box, &transfer);
686 if (map == NULL) {
687 mtx_unlock(&drv->mutex);
688 return VA_STATUS_ERROR_OPERATION_FAILED;
689 }
690
691 u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j,
692 transfer->stride, tex->array_size,
693 map, dst_box.width, dst_box.height);
694 pipe_texture_unmap(drv->pipe, transfer);
695 } else {
696 drv->pipe->texture_subdata(drv->pipe, tex, 0,
697 PIPE_MAP_WRITE, &dst_box,
698 data[i] + pitches[i] * j,
699 pitches[i] * views[i]->texture->array_size, 0);
700 }
701 }
702 }
703 drv->pipe->flush(drv->pipe, NULL, 0);
704 mtx_unlock(&drv->mutex);
705
706 return VA_STATUS_SUCCESS;
707 }
708