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