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 41static 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 58static void 59vlVaVideoSurfaceSize(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 70VAStatus 71vlVaQueryImageFormats(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 98VAStatus 99vlVaCreateImage(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 181VAStatus 182vlVaDeriveImage(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 278VAStatus 279vlVaDestroyImage(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 303VAStatus 304vlVaSetImagePalette(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 312VAStatus 313vlVaGetImage(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 423VAStatus 424vlVaPutImage(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