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