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