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