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