gallium/util: replace pipe_mutex_unlock() with mtx_unlock()
[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 mtx_lock(&drv->mutex);
118 img->image_id = handle_table_add(drv->htab, img);
119 mtx_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 mtx_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 mtx_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 VAStatus status;
284
285 if (!ctx)
286 return VA_STATUS_ERROR_INVALID_CONTEXT;
287
288 drv = VL_VA_DRIVER(ctx);
289 mtx_lock(&drv->mutex);
290 vaimage = handle_table_get(drv->htab, image);
291 if (!vaimage) {
292 mtx_unlock(&drv->mutex);
293 return VA_STATUS_ERROR_INVALID_IMAGE;
294 }
295
296 handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
297 mtx_unlock(&drv->mutex);
298 status = vlVaDestroyBuffer(ctx, vaimage->buf);
299 FREE(vaimage);
300 return status;
301 }
302
303 VAStatus
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
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 mtx_lock(&drv->mutex);
332 surf = handle_table_get(drv->htab, surface);
333 if (!surf || !surf->buffer) {
334 mtx_unlock(&drv->mutex);
335 return VA_STATUS_ERROR_INVALID_SURFACE;
336 }
337
338 vaimage = handle_table_get(drv->htab, image);
339 if (!vaimage) {
340 mtx_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 mtx_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 mtx_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 mtx_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 mtx_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 mtx_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 mtx_unlock(&drv->mutex);
419
420 return VA_STATUS_SUCCESS;
421 }
422
423 VAStatus
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 mtx_lock(&drv->mutex);
442
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 img_buf = handle_table_get(drv->htab, vaimage->buf);
456 if (!img_buf) {
457 mtx_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 mtx_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 mtx_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 mtx_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 mtx_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 struct pipe_resource *tex;
517
518 if (!views[i]) continue;
519 tex = views[i]->texture;
520
521 vlVaVideoSurfaceSize(surf, i, &width, &height);
522 for (j = 0; j < tex->array_size; ++j) {
523 struct pipe_box dst_box = {0, 0, j, width, height, 1};
524
525 if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV))
526 && (surf->buffer->buffer_format == PIPE_FORMAT_NV12)
527 && i == 1) {
528 struct pipe_transfer *transfer = NULL;
529 uint8_t *map = NULL;
530
531 map = drv->pipe->transfer_map(drv->pipe,
532 tex,
533 0,
534 PIPE_TRANSFER_WRITE |
535 PIPE_TRANSFER_DISCARD_RANGE,
536 &dst_box, &transfer);
537 if (map == NULL)
538 return VA_STATUS_ERROR_OPERATION_FAILED;
539
540 u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j,
541 transfer->stride, tex->array_size,
542 map, dst_box.width, dst_box.height);
543 pipe_transfer_unmap(drv->pipe, transfer);
544 } else {
545 drv->pipe->texture_subdata(drv->pipe, tex, 0,
546 PIPE_TRANSFER_WRITE, &dst_box,
547 data[i] + pitches[i] * j,
548 pitches[i] * views[i]->texture->array_size, 0);
549 }
550 }
551 }
552 mtx_unlock(&drv->mutex);
553
554 return VA_STATUS_SUCCESS;
555 }