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