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
36 #include "vl/vl_winsys.h"
37 #include "vl/vl_video_buffer.h"
38
39 #include "va_private.h"
40
41 static const VAImageFormat formats[] =
42 {
43 {VA_FOURCC('N','V','1','2')},
44 {VA_FOURCC('I','4','2','0')},
45 {VA_FOURCC('Y','V','1','2')},
46 {VA_FOURCC('Y','U','Y','V')},
47 {VA_FOURCC('U','Y','V','Y')},
48 {.fourcc = VA_FOURCC('B','G','R','A'), .byte_order = VA_LSB_FIRST, 32, 32,
49 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000},
50 {.fourcc = VA_FOURCC('R','G','B','A'), .byte_order = VA_LSB_FIRST, 32, 32,
51 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
52 {.fourcc = VA_FOURCC('B','G','R','X'), .byte_order = VA_LSB_FIRST, 32, 24,
53 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
54 {.fourcc = VA_FOURCC('R','G','B','X'), .byte_order = VA_LSB_FIRST, 32, 24,
55 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000}
56 };
57
58 static void
vlVaVideoSurfaceSize(vlVaSurface * p_surf,int component,unsigned * width,unsigned * height)59 vlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
60 unsigned *width, unsigned *height)
61 {
62 *width = p_surf->templat.width;
63 *height = p_surf->templat.height;
64
65 vl_video_buffer_adjust_size(width, height, component,
66 p_surf->templat.chroma_format,
67 p_surf->templat.interlaced);
68 }
69
70 VAStatus
vlVaQueryImageFormats(VADriverContextP ctx,VAImageFormat * format_list,int * num_formats)71 vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats)
72 {
73 struct pipe_screen *pscreen;
74 enum pipe_format format;
75 int i;
76
77 STATIC_ASSERT(ARRAY_SIZE(formats) == VL_VA_MAX_IMAGE_FORMATS);
78
79 if (!ctx)
80 return VA_STATUS_ERROR_INVALID_CONTEXT;
81
82 if (!(format_list && num_formats))
83 return VA_STATUS_ERROR_INVALID_PARAMETER;
84
85 *num_formats = 0;
86 pscreen = VL_VA_PSCREEN(ctx);
87 for (i = 0; i < ARRAY_SIZE(formats); ++i) {
88 format = VaFourccToPipeFormat(formats[i].fourcc);
89 if (pscreen->is_video_format_supported(pscreen, format,
90 PIPE_VIDEO_PROFILE_UNKNOWN,
91 PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
92 format_list[(*num_formats)++] = formats[i];
93 }
94
95 return VA_STATUS_SUCCESS;
96 }
97
98 VAStatus
vlVaCreateImage(VADriverContextP ctx,VAImageFormat * format,int width,int height,VAImage * image)99 vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
100 {
101 VAStatus status;
102 vlVaDriver *drv;
103 VAImage *img;
104 int w, h;
105
106 if (!ctx)
107 return VA_STATUS_ERROR_INVALID_CONTEXT;
108
109 if (!(format && image && width && height))
110 return VA_STATUS_ERROR_INVALID_PARAMETER;
111
112 drv = VL_VA_DRIVER(ctx);
113
114 img = CALLOC(1, sizeof(VAImage));
115 if (!img)
116 return VA_STATUS_ERROR_ALLOCATION_FAILED;
117 pipe_mutex_lock(drv->mutex);
118 img->image_id = handle_table_add(drv->htab, img);
119 pipe_mutex_unlock(drv->mutex);
120
121 img->format = *format;
122 img->width = width;
123 img->height = height;
124 w = align(width, 2);
125 h = align(height, 2);
126
127 switch (format->fourcc) {
128 case VA_FOURCC('N','V','1','2'):
129 img->num_planes = 2;
130 img->pitches[0] = w;
131 img->offsets[0] = 0;
132 img->pitches[1] = w;
133 img->offsets[1] = w * h;
134 img->data_size = w * h * 3 / 2;
135 break;
136
137 case VA_FOURCC('I','4','2','0'):
138 case VA_FOURCC('Y','V','1','2'):
139 img->num_planes = 3;
140 img->pitches[0] = w;
141 img->offsets[0] = 0;
142 img->pitches[1] = w / 2;
143 img->offsets[1] = w * h;
144 img->pitches[2] = w / 2;
145 img->offsets[2] = w * h * 5 / 4;
146 img->data_size = w * h * 3 / 2;
147 break;
148
149 case VA_FOURCC('U','Y','V','Y'):
150 case VA_FOURCC('Y','U','Y','V'):
151 img->num_planes = 1;
152 img->pitches[0] = w * 2;
153 img->offsets[0] = 0;
154 img->data_size = w * h * 2;
155 break;
156
157 case VA_FOURCC('B','G','R','A'):
158 case VA_FOURCC('R','G','B','A'):
159 case VA_FOURCC('B','G','R','X'):
160 case VA_FOURCC('R','G','B','X'):
161 img->num_planes = 1;
162 img->pitches[0] = w * 4;
163 img->offsets[0] = 0;
164 img->data_size = w * h * 4;
165 break;
166
167 default:
168 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
169 }
170
171 status = vlVaCreateBuffer(ctx, 0, VAImageBufferType,
172 align(img->data_size, 16),
173 1, NULL, &img->buf);
174 if (status != VA_STATUS_SUCCESS)
175 return status;
176 *image = *img;
177
178 return status;
179 }
180
181 VAStatus
vlVaDeriveImage(VADriverContextP ctx,VASurfaceID surface,VAImage * image)182 vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
183 {
184 vlVaDriver *drv;
185 vlVaSurface *surf;
186 vlVaBuffer *img_buf;
187 VAImage *img;
188 struct pipe_surface **surfaces;
189 int w;
190 int h;
191 int i;
192
193 if (!ctx)
194 return VA_STATUS_ERROR_INVALID_CONTEXT;
195
196 drv = VL_VA_DRIVER(ctx);
197
198 if (!drv)
199 return VA_STATUS_ERROR_INVALID_CONTEXT;
200
201 surf = handle_table_get(drv->htab, surface);
202
203 if (!surf || !surf->buffer || surf->buffer->interlaced)
204 return VA_STATUS_ERROR_INVALID_SURFACE;
205
206 surfaces = surf->buffer->get_surfaces(surf->buffer);
207 if (!surfaces || !surfaces[0]->texture)
208 return VA_STATUS_ERROR_ALLOCATION_FAILED;
209
210 img = CALLOC(1, sizeof(VAImage));
211 if (!img)
212 return VA_STATUS_ERROR_ALLOCATION_FAILED;
213
214 img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
215 img->buf = VA_INVALID_ID;
216 img->width = surf->buffer->width;
217 img->height = surf->buffer->height;
218 img->num_palette_entries = 0;
219 img->entry_bytes = 0;
220 w = align(surf->buffer->width, 2);
221 h = align(surf->buffer->height, 2);
222
223 for (i = 0; i < ARRAY_SIZE(formats); ++i) {
224 if (img->format.fourcc == formats[i].fourcc) {
225 img->format = formats[i];
226 break;
227 }
228 }
229
230 switch (img->format.fourcc) {
231 case VA_FOURCC('U','Y','V','Y'):
232 case VA_FOURCC('Y','U','Y','V'):
233 img->num_planes = 1;
234 img->pitches[0] = w * 2;
235 img->offsets[0] = 0;
236 img->data_size = w * h * 2;
237 break;
238
239 case VA_FOURCC('B','G','R','A'):
240 case VA_FOURCC('R','G','B','A'):
241 case VA_FOURCC('B','G','R','X'):
242 case VA_FOURCC('R','G','B','X'):
243 img->num_planes = 1;
244 img->pitches[0] = w * 4;
245 img->offsets[0] = 0;
246 img->data_size = w * h * 4;
247 break;
248
249 default:
250 /* VaDeriveImage is designed for contiguous planes. */
251 FREE(img);
252 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
253 }
254
255 img_buf = CALLOC(1, sizeof(vlVaBuffer));
256 if (!img_buf) {
257 FREE(img);
258 return VA_STATUS_ERROR_ALLOCATION_FAILED;
259 }
260
261 pipe_mutex_lock(drv->mutex);
262 img->image_id = handle_table_add(drv->htab, img);
263
264 img_buf->type = VAImageBufferType;
265 img_buf->size = img->data_size;
266 img_buf->num_elements = 1;
267
268 pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
269
270 img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
271 pipe_mutex_unlock(drv->mutex);
272
273 *image = *img;
274
275 return VA_STATUS_SUCCESS;
276 }
277
278 VAStatus
vlVaDestroyImage(VADriverContextP ctx,VAImageID image)279 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
280 {
281 vlVaDriver *drv;
282 VAImage *vaimage;
283 VAStatus status;
284
285 if (!ctx)
286 return VA_STATUS_ERROR_INVALID_CONTEXT;
287
288 drv = VL_VA_DRIVER(ctx);
289 pipe_mutex_lock(drv->mutex);
290 vaimage = handle_table_get(drv->htab, image);
291 if (!vaimage) {
292 pipe_mutex_unlock(drv->mutex);
293 return VA_STATUS_ERROR_INVALID_IMAGE;
294 }
295
296 handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
297 pipe_mutex_unlock(drv->mutex);
298 status = vlVaDestroyBuffer(ctx, vaimage->buf);
299 FREE(vaimage);
300 return status;
301 }
302
303 VAStatus
vlVaSetImagePalette(VADriverContextP ctx,VAImageID image,unsigned char * palette)304 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
305 {
306 if (!ctx)
307 return VA_STATUS_ERROR_INVALID_CONTEXT;
308
309 return VA_STATUS_ERROR_UNIMPLEMENTED;
310 }
311
312 VAStatus
vlVaGetImage(VADriverContextP ctx,VASurfaceID surface,int x,int y,unsigned int width,unsigned int height,VAImageID image)313 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
314 unsigned int width, unsigned int height, VAImageID image)
315 {
316 vlVaDriver *drv;
317 vlVaSurface *surf;
318 vlVaBuffer *img_buf;
319 VAImage *vaimage;
320 struct pipe_sampler_view **views;
321 enum pipe_format format;
322 bool convert = false;
323 void *data[3];
324 unsigned pitches[3], i, j;
325
326 if (!ctx)
327 return VA_STATUS_ERROR_INVALID_CONTEXT;
328
329 drv = VL_VA_DRIVER(ctx);
330
331 pipe_mutex_lock(drv->mutex);
332 surf = handle_table_get(drv->htab, surface);
333 if (!surf || !surf->buffer) {
334 pipe_mutex_unlock(drv->mutex);
335 return VA_STATUS_ERROR_INVALID_SURFACE;
336 }
337
338 vaimage = handle_table_get(drv->htab, image);
339 if (!vaimage) {
340 pipe_mutex_unlock(drv->mutex);
341 return VA_STATUS_ERROR_INVALID_IMAGE;
342 }
343
344 img_buf = handle_table_get(drv->htab, vaimage->buf);
345 if (!img_buf) {
346 pipe_mutex_unlock(drv->mutex);
347 return VA_STATUS_ERROR_INVALID_BUFFER;
348 }
349
350 format = VaFourccToPipeFormat(vaimage->format.fourcc);
351 if (format == PIPE_FORMAT_NONE) {
352 pipe_mutex_unlock(drv->mutex);
353 return VA_STATUS_ERROR_OPERATION_FAILED;
354 }
355
356 if (format != surf->buffer->buffer_format) {
357 /* support NV12 to YV12 and IYUV conversion now only */
358 if ((format == PIPE_FORMAT_YV12 &&
359 surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
360 (format == PIPE_FORMAT_IYUV &&
361 surf->buffer->buffer_format == PIPE_FORMAT_NV12))
362 convert = true;
363 else {
364 pipe_mutex_unlock(drv->mutex);
365 return VA_STATUS_ERROR_OPERATION_FAILED;
366 }
367 }
368
369 views = surf->buffer->get_sampler_view_planes(surf->buffer);
370 if (!views) {
371 pipe_mutex_unlock(drv->mutex);
372 return VA_STATUS_ERROR_OPERATION_FAILED;
373 }
374
375 for (i = 0; i < vaimage->num_planes; i++) {
376 data[i] = img_buf->data + vaimage->offsets[i];
377 pitches[i] = vaimage->pitches[i];
378 }
379 if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
380 void *tmp_d;
381 unsigned tmp_p;
382 tmp_d = data[1];
383 data[1] = data[2];
384 data[2] = tmp_d;
385 tmp_p = pitches[1];
386 pitches[1] = pitches[2];
387 pitches[2] = tmp_p;
388 }
389
390 for (i = 0; i < vaimage->num_planes; i++) {
391 unsigned width, height;
392 if (!views[i]) continue;
393 vlVaVideoSurfaceSize(surf, i, &width, &height);
394 for (j = 0; j < views[i]->texture->array_size; ++j) {
395 struct pipe_box box = {0, 0, j, width, height, 1};
396 struct pipe_transfer *transfer;
397 uint8_t *map;
398 map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0,
399 PIPE_TRANSFER_READ, &box, &transfer);
400 if (!map) {
401 pipe_mutex_unlock(drv->mutex);
402 return VA_STATUS_ERROR_OPERATION_FAILED;
403 }
404
405 if (i == 1 && convert) {
406 u_copy_nv12_to_yv12(data, pitches, i, j,
407 transfer->stride, views[i]->texture->array_size,
408 map, box.width, box.height);
409 } else {
410 util_copy_rect(data[i] + pitches[i] * j,
411 views[i]->texture->format,
412 pitches[i] * views[i]->texture->array_size, 0, 0,
413 box.width, box.height, map, transfer->stride, 0, 0);
414 }
415 pipe_transfer_unmap(drv->pipe, transfer);
416 }
417 }
418 pipe_mutex_unlock(drv->mutex);
419
420 return VA_STATUS_SUCCESS;
421 }
422
423 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)424 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
425 int src_x, int src_y, unsigned int src_width, unsigned int src_height,
426 int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
427 {
428 vlVaDriver *drv;
429 vlVaSurface *surf;
430 vlVaBuffer *img_buf;
431 VAImage *vaimage;
432 struct pipe_sampler_view **views;
433 enum pipe_format format;
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 pipe_mutex_lock(drv->mutex);
442
443 surf = handle_table_get(drv->htab, surface);
444 if (!surf || !surf->buffer) {
445 pipe_mutex_unlock(drv->mutex);
446 return VA_STATUS_ERROR_INVALID_SURFACE;
447 }
448
449 vaimage = handle_table_get(drv->htab, image);
450 if (!vaimage) {
451 pipe_mutex_unlock(drv->mutex);
452 return VA_STATUS_ERROR_INVALID_IMAGE;
453 }
454
455 img_buf = handle_table_get(drv->htab, vaimage->buf);
456 if (!img_buf) {
457 pipe_mutex_unlock(drv->mutex);
458 return VA_STATUS_ERROR_INVALID_BUFFER;
459 }
460
461 if (img_buf->derived_surface.resource) {
462 /* Attempting to transfer derived image to surface */
463 pipe_mutex_unlock(drv->mutex);
464 return VA_STATUS_ERROR_UNIMPLEMENTED;
465 }
466
467 format = VaFourccToPipeFormat(vaimage->format.fourcc);
468
469 if (format == PIPE_FORMAT_NONE) {
470 pipe_mutex_unlock(drv->mutex);
471 return VA_STATUS_ERROR_OPERATION_FAILED;
472 }
473
474 if ((format != surf->buffer->buffer_format) &&
475 ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) &&
476 ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) {
477 struct pipe_video_buffer *tmp_buf;
478 struct pipe_video_buffer templat = surf->templat;
479
480 templat.buffer_format = format;
481 tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &templat);
482
483 if (!tmp_buf) {
484 pipe_mutex_unlock(drv->mutex);
485 return VA_STATUS_ERROR_ALLOCATION_FAILED;
486 }
487
488 surf->buffer->destroy(surf->buffer);
489 surf->buffer = tmp_buf;
490 surf->templat.buffer_format = format;
491 }
492
493 views = surf->buffer->get_sampler_view_planes(surf->buffer);
494 if (!views) {
495 pipe_mutex_unlock(drv->mutex);
496 return VA_STATUS_ERROR_OPERATION_FAILED;
497 }
498
499 for (i = 0; i < vaimage->num_planes; i++) {
500 data[i] = img_buf->data + vaimage->offsets[i];
501 pitches[i] = vaimage->pitches[i];
502 }
503 if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
504 void *tmp_d;
505 unsigned tmp_p;
506 tmp_d = data[1];
507 data[1] = data[2];
508 data[2] = tmp_d;
509 tmp_p = pitches[1];
510 pitches[1] = pitches[2];
511 pitches[2] = tmp_p;
512 }
513
514 for (i = 0; i < vaimage->num_planes; ++i) {
515 unsigned width, height;
516 if (!views[i]) continue;
517 vlVaVideoSurfaceSize(surf, i, &width, &height);
518 if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV)) &&
519 (surf->buffer->buffer_format == PIPE_FORMAT_NV12)) {
520 struct pipe_transfer *transfer = NULL;
521 uint8_t *map = NULL;
522 struct pipe_box dst_box_1 = {0, 0, 0, width, height, 1};
523 map = drv->pipe->transfer_map(drv->pipe,
524 views[i]->texture,
525 0,
526 PIPE_TRANSFER_DISCARD_RANGE,
527 &dst_box_1, &transfer);
528 if (map == NULL)
529 return VA_STATUS_ERROR_OPERATION_FAILED;
530
531 u_copy_yv12_img_to_nv12_surf ((ubyte * const*)data, map, width, height,
532 pitches[i], transfer->stride, i);
533 pipe_transfer_unmap(drv->pipe, transfer);
534 } else {
535 for (j = 0; j < views[i]->texture->array_size; ++j) {
536 struct pipe_box dst_box = {0, 0, j, width, height, 1};
537 drv->pipe->texture_subdata(drv->pipe, views[i]->texture, 0,
538 PIPE_TRANSFER_WRITE, &dst_box,
539 data[i] + pitches[i] * j,
540 pitches[i] * views[i]->texture->array_size, 0);
541 }
542 }
543 }
544 pipe_mutex_unlock(drv->mutex);
545
546 return VA_STATUS_SUCCESS;
547 }
548