st/va: use vl_video_buffer_adjust_size
[mesa.git] / src / gallium / state_trackers / va / image.c
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
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
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
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
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
279 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
280 {
281 vlVaDriver *drv;
282 VAImage *vaimage;
283
284 if (!ctx)
285 return VA_STATUS_ERROR_INVALID_CONTEXT;
286
287 drv = VL_VA_DRIVER(ctx);
288 pipe_mutex_lock(drv->mutex);
289 vaimage = handle_table_get(drv->htab, image);
290 if (!vaimage) {
291 pipe_mutex_unlock(drv->mutex);
292 return VA_STATUS_ERROR_INVALID_IMAGE;
293 }
294
295 handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
296 pipe_mutex_unlock(drv->mutex);
297 FREE(vaimage);
298 return vlVaDestroyBuffer(ctx, vaimage->buf);
299 }
300
301 VAStatus
302 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
303 {
304 if (!ctx)
305 return VA_STATUS_ERROR_INVALID_CONTEXT;
306
307 return VA_STATUS_ERROR_UNIMPLEMENTED;
308 }
309
310 VAStatus
311 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
312 unsigned int width, unsigned int height, VAImageID image)
313 {
314 vlVaDriver *drv;
315 vlVaSurface *surf;
316 vlVaBuffer *img_buf;
317 VAImage *vaimage;
318 struct pipe_sampler_view **views;
319 enum pipe_format format;
320 bool convert = false;
321 void *data[3];
322 unsigned pitches[3], i, j;
323
324 if (!ctx)
325 return VA_STATUS_ERROR_INVALID_CONTEXT;
326
327 drv = VL_VA_DRIVER(ctx);
328
329 pipe_mutex_lock(drv->mutex);
330 surf = handle_table_get(drv->htab, surface);
331 if (!surf || !surf->buffer) {
332 pipe_mutex_unlock(drv->mutex);
333 return VA_STATUS_ERROR_INVALID_SURFACE;
334 }
335
336 vaimage = handle_table_get(drv->htab, image);
337 if (!vaimage) {
338 pipe_mutex_unlock(drv->mutex);
339 return VA_STATUS_ERROR_INVALID_IMAGE;
340 }
341
342 img_buf = handle_table_get(drv->htab, vaimage->buf);
343 if (!img_buf) {
344 pipe_mutex_unlock(drv->mutex);
345 return VA_STATUS_ERROR_INVALID_BUFFER;
346 }
347
348 format = VaFourccToPipeFormat(vaimage->format.fourcc);
349 if (format == PIPE_FORMAT_NONE) {
350 pipe_mutex_unlock(drv->mutex);
351 return VA_STATUS_ERROR_OPERATION_FAILED;
352 }
353
354 if (format != surf->buffer->buffer_format) {
355 /* support NV12 to YV12 and IYUV conversion now only */
356 if ((format == PIPE_FORMAT_YV12 &&
357 surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
358 (format == PIPE_FORMAT_IYUV &&
359 surf->buffer->buffer_format == PIPE_FORMAT_NV12))
360 convert = true;
361 else {
362 pipe_mutex_unlock(drv->mutex);
363 return VA_STATUS_ERROR_OPERATION_FAILED;
364 }
365 }
366
367 views = surf->buffer->get_sampler_view_planes(surf->buffer);
368 if (!views) {
369 pipe_mutex_unlock(drv->mutex);
370 return VA_STATUS_ERROR_OPERATION_FAILED;
371 }
372
373 for (i = 0; i < vaimage->num_planes; i++) {
374 data[i] = img_buf->data + vaimage->offsets[i];
375 pitches[i] = vaimage->pitches[i];
376 }
377 if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
378 void *tmp_d;
379 unsigned tmp_p;
380 tmp_d = data[1];
381 data[1] = data[2];
382 data[2] = tmp_d;
383 tmp_p = pitches[1];
384 pitches[1] = pitches[2];
385 pitches[2] = tmp_p;
386 }
387
388 for (i = 0; i < vaimage->num_planes; i++) {
389 unsigned width, height;
390 if (!views[i]) continue;
391 vlVaVideoSurfaceSize(surf, i, &width, &height);
392 for (j = 0; j < views[i]->texture->array_size; ++j) {
393 struct pipe_box box = {0, 0, j, width, height, 1};
394 struct pipe_transfer *transfer;
395 uint8_t *map;
396 map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0,
397 PIPE_TRANSFER_READ, &box, &transfer);
398 if (!map) {
399 pipe_mutex_unlock(drv->mutex);
400 return VA_STATUS_ERROR_OPERATION_FAILED;
401 }
402
403 if (i == 1 && convert) {
404 u_copy_nv12_to_yv12(data, pitches, i, j,
405 transfer->stride, views[i]->texture->array_size,
406 map, box.width, box.height);
407 } else {
408 util_copy_rect(data[i] + pitches[i] * j,
409 views[i]->texture->format,
410 pitches[i] * views[i]->texture->array_size, 0, 0,
411 box.width, box.height, map, transfer->stride, 0, 0);
412 }
413 pipe_transfer_unmap(drv->pipe, transfer);
414 }
415 }
416 pipe_mutex_unlock(drv->mutex);
417
418 return VA_STATUS_SUCCESS;
419 }
420
421 VAStatus
422 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
423 int src_x, int src_y, unsigned int src_width, unsigned int src_height,
424 int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
425 {
426 vlVaDriver *drv;
427 vlVaSurface *surf;
428 vlVaBuffer *img_buf;
429 VAImage *vaimage;
430 struct pipe_sampler_view **views;
431 enum pipe_format format;
432 void *data[3];
433 unsigned pitches[3], i, j;
434
435 if (!ctx)
436 return VA_STATUS_ERROR_INVALID_CONTEXT;
437
438 drv = VL_VA_DRIVER(ctx);
439 pipe_mutex_lock(drv->mutex);
440
441 surf = handle_table_get(drv->htab, surface);
442 if (!surf || !surf->buffer) {
443 pipe_mutex_unlock(drv->mutex);
444 return VA_STATUS_ERROR_INVALID_SURFACE;
445 }
446
447 vaimage = handle_table_get(drv->htab, image);
448 if (!vaimage) {
449 pipe_mutex_unlock(drv->mutex);
450 return VA_STATUS_ERROR_INVALID_IMAGE;
451 }
452
453 img_buf = handle_table_get(drv->htab, vaimage->buf);
454 if (!img_buf) {
455 pipe_mutex_unlock(drv->mutex);
456 return VA_STATUS_ERROR_INVALID_BUFFER;
457 }
458
459 if (img_buf->derived_surface.resource) {
460 /* Attempting to transfer derived image to surface */
461 pipe_mutex_unlock(drv->mutex);
462 return VA_STATUS_ERROR_UNIMPLEMENTED;
463 }
464
465 format = VaFourccToPipeFormat(vaimage->format.fourcc);
466
467 if (format == PIPE_FORMAT_NONE) {
468 pipe_mutex_unlock(drv->mutex);
469 return VA_STATUS_ERROR_OPERATION_FAILED;
470 }
471
472 if (format != surf->buffer->buffer_format) {
473 struct pipe_video_buffer *tmp_buf;
474 enum pipe_format old_surf_format = surf->templat.buffer_format;
475
476 surf->templat.buffer_format = format;
477 tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
478
479 if (!tmp_buf) {
480 surf->templat.buffer_format = old_surf_format;
481 pipe_mutex_unlock(drv->mutex);
482 return VA_STATUS_ERROR_ALLOCATION_FAILED;
483 }
484
485 surf->buffer->destroy(surf->buffer);
486 surf->buffer = tmp_buf;
487 }
488
489 views = surf->buffer->get_sampler_view_planes(surf->buffer);
490 if (!views) {
491 pipe_mutex_unlock(drv->mutex);
492 return VA_STATUS_ERROR_OPERATION_FAILED;
493 }
494
495 for (i = 0; i < vaimage->num_planes; i++) {
496 data[i] = img_buf->data + vaimage->offsets[i];
497 pitches[i] = vaimage->pitches[i];
498 }
499 if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
500 void *tmp_d;
501 unsigned tmp_p;
502 tmp_d = data[1];
503 data[1] = data[2];
504 data[2] = tmp_d;
505 tmp_p = pitches[1];
506 pitches[1] = pitches[2];
507 pitches[2] = tmp_p;
508 }
509
510 for (i = 0; i < vaimage->num_planes; ++i) {
511 unsigned width, height;
512 if (!views[i]) continue;
513 vlVaVideoSurfaceSize(surf, i, &width, &height);
514 for (j = 0; j < views[i]->texture->array_size; ++j) {
515 struct pipe_box dst_box = {0, 0, j, width, height, 1};
516 drv->pipe->transfer_inline_write(drv->pipe, views[i]->texture, 0,
517 PIPE_TRANSFER_WRITE, &dst_box,
518 data[i] + pitches[i] * j,
519 pitches[i] * views[i]->texture->array_size, 0);
520 }
521 }
522 pipe_mutex_unlock(drv->mutex);
523
524 return VA_STATUS_SUCCESS;
525 }