surface.c revision b8e80941
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#include "pipe/p_video_codec.h" 31 32#include "state_tracker/drm_driver.h" 33 34#include "util/u_memory.h" 35#include "util/u_handle_table.h" 36#include "util/u_rect.h" 37#include "util/u_sampler.h" 38#include "util/u_surface.h" 39#include "util/u_video.h" 40 41#include "vl/vl_compositor.h" 42#include "vl/vl_video_buffer.h" 43#include "vl/vl_winsys.h" 44 45#include "va_private.h" 46 47#include <va/va_drmcommon.h> 48#include "drm-uapi/drm_fourcc.h" 49 50static const enum pipe_format vpp_surface_formats[] = { 51 PIPE_FORMAT_B8G8R8A8_UNORM, PIPE_FORMAT_R8G8B8A8_UNORM, 52 PIPE_FORMAT_B8G8R8X8_UNORM, PIPE_FORMAT_R8G8B8X8_UNORM 53}; 54 55VAStatus 56vlVaCreateSurfaces(VADriverContextP ctx, int width, int height, int format, 57 int num_surfaces, VASurfaceID *surfaces) 58{ 59 return vlVaCreateSurfaces2(ctx, format, width, height, surfaces, num_surfaces, 60 NULL, 0); 61} 62 63VAStatus 64vlVaDestroySurfaces(VADriverContextP ctx, VASurfaceID *surface_list, int num_surfaces) 65{ 66 vlVaDriver *drv; 67 int i; 68 69 if (!ctx) 70 return VA_STATUS_ERROR_INVALID_CONTEXT; 71 72 drv = VL_VA_DRIVER(ctx); 73 mtx_lock(&drv->mutex); 74 for (i = 0; i < num_surfaces; ++i) { 75 vlVaSurface *surf = handle_table_get(drv->htab, surface_list[i]); 76 if (!surf) { 77 mtx_unlock(&drv->mutex); 78 return VA_STATUS_ERROR_INVALID_SURFACE; 79 } 80 if (surf->buffer) 81 surf->buffer->destroy(surf->buffer); 82 util_dynarray_fini(&surf->subpics); 83 FREE(surf); 84 handle_table_remove(drv->htab, surface_list[i]); 85 } 86 mtx_unlock(&drv->mutex); 87 88 return VA_STATUS_SUCCESS; 89} 90 91VAStatus 92vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target) 93{ 94 vlVaDriver *drv; 95 vlVaContext *context; 96 vlVaSurface *surf; 97 98 if (!ctx) 99 return VA_STATUS_ERROR_INVALID_CONTEXT; 100 101 drv = VL_VA_DRIVER(ctx); 102 if (!drv) 103 return VA_STATUS_ERROR_INVALID_CONTEXT; 104 105 mtx_lock(&drv->mutex); 106 surf = handle_table_get(drv->htab, render_target); 107 108 if (!surf || !surf->buffer) { 109 mtx_unlock(&drv->mutex); 110 return VA_STATUS_ERROR_INVALID_SURFACE; 111 } 112 113 if (!surf->feedback) { 114 // No outstanding operation: nothing to do. 115 mtx_unlock(&drv->mutex); 116 return VA_STATUS_SUCCESS; 117 } 118 119 context = handle_table_get(drv->htab, surf->ctx); 120 if (!context) { 121 mtx_unlock(&drv->mutex); 122 return VA_STATUS_ERROR_INVALID_CONTEXT; 123 } 124 125 if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) { 126 if (u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC) { 127 int frame_diff; 128 if (context->desc.h264enc.frame_num_cnt >= surf->frame_num_cnt) 129 frame_diff = context->desc.h264enc.frame_num_cnt - surf->frame_num_cnt; 130 else 131 frame_diff = 0xFFFFFFFF - surf->frame_num_cnt + 1 + context->desc.h264enc.frame_num_cnt; 132 if ((frame_diff == 0) && 133 (surf->force_flushed == false) && 134 (context->desc.h264enc.frame_num_cnt % 2 != 0)) { 135 context->decoder->flush(context->decoder); 136 context->first_single_submitted = true; 137 } 138 } 139 context->decoder->get_feedback(context->decoder, surf->feedback, &(surf->coded_buf->coded_size)); 140 surf->feedback = NULL; 141 } 142 mtx_unlock(&drv->mutex); 143 return VA_STATUS_SUCCESS; 144} 145 146VAStatus 147vlVaQuerySurfaceStatus(VADriverContextP ctx, VASurfaceID render_target, VASurfaceStatus *status) 148{ 149 vlVaDriver *drv; 150 vlVaSurface *surf; 151 vlVaContext *context; 152 153 if (!ctx) 154 return VA_STATUS_ERROR_INVALID_CONTEXT; 155 156 drv = VL_VA_DRIVER(ctx); 157 if (!drv) 158 return VA_STATUS_ERROR_INVALID_CONTEXT; 159 160 mtx_lock(&drv->mutex); 161 162 surf = handle_table_get(drv->htab, render_target); 163 if (!surf || !surf->buffer) { 164 mtx_unlock(&drv->mutex); 165 return VA_STATUS_ERROR_INVALID_SURFACE; 166 } 167 168 context = handle_table_get(drv->htab, surf->ctx); 169 if (!context) { 170 mtx_unlock(&drv->mutex); 171 return VA_STATUS_ERROR_INVALID_CONTEXT; 172 } 173 174 if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) { 175 if(surf->feedback == NULL) 176 *status=VASurfaceReady; 177 else 178 *status=VASurfaceRendering; 179 } 180 181 mtx_unlock(&drv->mutex); 182 183 return VA_STATUS_SUCCESS; 184} 185 186VAStatus 187vlVaQuerySurfaceError(VADriverContextP ctx, VASurfaceID render_target, VAStatus error_status, void **error_info) 188{ 189 if (!ctx) 190 return VA_STATUS_ERROR_INVALID_CONTEXT; 191 192 return VA_STATUS_ERROR_UNIMPLEMENTED; 193} 194 195static void 196upload_sampler(struct pipe_context *pipe, struct pipe_sampler_view *dst, 197 const struct pipe_box *dst_box, const void *src, unsigned src_stride, 198 unsigned src_x, unsigned src_y) 199{ 200 struct pipe_transfer *transfer; 201 void *map; 202 203 map = pipe->transfer_map(pipe, dst->texture, 0, PIPE_TRANSFER_WRITE, 204 dst_box, &transfer); 205 if (!map) 206 return; 207 208 util_copy_rect(map, dst->texture->format, transfer->stride, 0, 0, 209 dst_box->width, dst_box->height, 210 src, src_stride, src_x, src_y); 211 212 pipe->transfer_unmap(pipe, transfer); 213} 214 215static VAStatus 216vlVaPutSubpictures(vlVaSurface *surf, vlVaDriver *drv, 217 struct pipe_surface *surf_draw, struct u_rect *dirty_area, 218 struct u_rect *src_rect, struct u_rect *dst_rect) 219{ 220 vlVaSubpicture *sub; 221 int i; 222 223 if (!(surf->subpics.data || surf->subpics.size)) 224 return VA_STATUS_SUCCESS; 225 226 for (i = 0; i < surf->subpics.size/sizeof(vlVaSubpicture *); i++) { 227 struct pipe_blend_state blend; 228 void *blend_state; 229 vlVaBuffer *buf; 230 struct pipe_box box; 231 struct u_rect *s, *d, sr, dr, c; 232 int sw, sh, dw, dh; 233 234 sub = ((vlVaSubpicture **)surf->subpics.data)[i]; 235 if (!sub) 236 continue; 237 238 buf = handle_table_get(drv->htab, sub->image->buf); 239 if (!buf) 240 return VA_STATUS_ERROR_INVALID_IMAGE; 241 242 box.x = 0; 243 box.y = 0; 244 box.z = 0; 245 box.width = sub->dst_rect.x1 - sub->dst_rect.x0; 246 box.height = sub->dst_rect.y1 - sub->dst_rect.y0; 247 box.depth = 1; 248 249 s = &sub->src_rect; 250 d = &sub->dst_rect; 251 sw = s->x1 - s->x0; 252 sh = s->y1 - s->y0; 253 dw = d->x1 - d->x0; 254 dh = d->y1 - d->y0; 255 c.x0 = MAX2(d->x0, s->x0); 256 c.y0 = MAX2(d->y0, s->y0); 257 c.x1 = MIN2(d->x0 + dw, src_rect->x1); 258 c.y1 = MIN2(d->y0 + dh, src_rect->y1); 259 sr.x0 = s->x0 + (c.x0 - d->x0)*(sw/(float)dw); 260 sr.y0 = s->y0 + (c.y0 - d->y0)*(sh/(float)dh); 261 sr.x1 = s->x0 + (c.x1 - d->x0)*(sw/(float)dw); 262 sr.y1 = s->y0 + (c.y1 - d->y0)*(sh/(float)dh); 263 264 s = src_rect; 265 d = dst_rect; 266 sw = s->x1 - s->x0; 267 sh = s->y1 - s->y0; 268 dw = d->x1 - d->x0; 269 dh = d->y1 - d->y0; 270 dr.x0 = d->x0 + c.x0*(dw/(float)sw); 271 dr.y0 = d->y0 + c.y0*(dh/(float)sh); 272 dr.x1 = d->x0 + c.x1*(dw/(float)sw); 273 dr.y1 = d->y0 + c.y1*(dh/(float)sh); 274 275 memset(&blend, 0, sizeof(blend)); 276 blend.independent_blend_enable = 0; 277 blend.rt[0].blend_enable = 1; 278 blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; 279 blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; 280 blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO; 281 blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; 282 blend.rt[0].rgb_func = PIPE_BLEND_ADD; 283 blend.rt[0].alpha_func = PIPE_BLEND_ADD; 284 blend.rt[0].colormask = PIPE_MASK_RGBA; 285 blend.logicop_enable = 0; 286 blend.logicop_func = PIPE_LOGICOP_CLEAR; 287 blend.dither = 0; 288 blend_state = drv->pipe->create_blend_state(drv->pipe, &blend); 289 290 vl_compositor_clear_layers(&drv->cstate); 291 vl_compositor_set_layer_blend(&drv->cstate, 0, blend_state, false); 292 upload_sampler(drv->pipe, sub->sampler, &box, buf->data, 293 sub->image->pitches[0], 0, 0); 294 vl_compositor_set_rgba_layer(&drv->cstate, &drv->compositor, 0, sub->sampler, 295 &sr, NULL, NULL); 296 vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dr); 297 vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, false); 298 drv->pipe->delete_blend_state(drv->pipe, blend_state); 299 } 300 301 return VA_STATUS_SUCCESS; 302} 303 304VAStatus 305vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short srcx, short srcy, 306 unsigned short srcw, unsigned short srch, short destx, short desty, 307 unsigned short destw, unsigned short desth, VARectangle *cliprects, 308 unsigned int number_cliprects, unsigned int flags) 309{ 310 vlVaDriver *drv; 311 vlVaSurface *surf; 312 struct pipe_screen *screen; 313 struct pipe_resource *tex; 314 struct pipe_surface surf_templ, *surf_draw; 315 struct vl_screen *vscreen; 316 struct u_rect src_rect, *dirty_area; 317 struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth}; 318 enum pipe_format format; 319 VAStatus status; 320 321 if (!ctx) 322 return VA_STATUS_ERROR_INVALID_CONTEXT; 323 324 drv = VL_VA_DRIVER(ctx); 325 mtx_lock(&drv->mutex); 326 surf = handle_table_get(drv->htab, surface_id); 327 if (!surf) { 328 mtx_unlock(&drv->mutex); 329 return VA_STATUS_ERROR_INVALID_SURFACE; 330 } 331 332 screen = drv->pipe->screen; 333 vscreen = drv->vscreen; 334 335 tex = vscreen->texture_from_drawable(vscreen, draw); 336 if (!tex) { 337 mtx_unlock(&drv->mutex); 338 return VA_STATUS_ERROR_INVALID_DISPLAY; 339 } 340 341 dirty_area = vscreen->get_dirty_area(vscreen); 342 343 memset(&surf_templ, 0, sizeof(surf_templ)); 344 surf_templ.format = tex->format; 345 surf_draw = drv->pipe->create_surface(drv->pipe, tex, &surf_templ); 346 if (!surf_draw) { 347 pipe_resource_reference(&tex, NULL); 348 mtx_unlock(&drv->mutex); 349 return VA_STATUS_ERROR_INVALID_DISPLAY; 350 } 351 352 src_rect.x0 = srcx; 353 src_rect.y0 = srcy; 354 src_rect.x1 = srcw + srcx; 355 src_rect.y1 = srch + srcy; 356 357 format = surf->buffer->buffer_format; 358 359 vl_compositor_clear_layers(&drv->cstate); 360 361 if (format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM || 362 format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM) { 363 struct pipe_sampler_view **views; 364 365 views = surf->buffer->get_sampler_view_planes(surf->buffer); 366 vl_compositor_set_rgba_layer(&drv->cstate, &drv->compositor, 0, views[0], &src_rect, NULL, NULL); 367 } else 368 vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, surf->buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE); 369 370 vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect); 371 vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, true); 372 373 status = vlVaPutSubpictures(surf, drv, surf_draw, dirty_area, &src_rect, &dst_rect); 374 if (status) { 375 mtx_unlock(&drv->mutex); 376 return status; 377 } 378 379 /* flush before calling flush_frontbuffer so that rendering is flushed 380 * to back buffer so the texture can be copied in flush_frontbuffer 381 */ 382 drv->pipe->flush(drv->pipe, NULL, 0); 383 384 screen->flush_frontbuffer(screen, tex, 0, 0, 385 vscreen->get_private(vscreen), NULL); 386 387 388 pipe_resource_reference(&tex, NULL); 389 pipe_surface_reference(&surf_draw, NULL); 390 mtx_unlock(&drv->mutex); 391 392 return VA_STATUS_SUCCESS; 393} 394 395VAStatus 396vlVaLockSurface(VADriverContextP ctx, VASurfaceID surface, unsigned int *fourcc, 397 unsigned int *luma_stride, unsigned int *chroma_u_stride, unsigned int *chroma_v_stride, 398 unsigned int *luma_offset, unsigned int *chroma_u_offset, unsigned int *chroma_v_offset, 399 unsigned int *buffer_name, void **buffer) 400{ 401 if (!ctx) 402 return VA_STATUS_ERROR_INVALID_CONTEXT; 403 404 return VA_STATUS_ERROR_UNIMPLEMENTED; 405} 406 407VAStatus 408vlVaUnlockSurface(VADriverContextP ctx, VASurfaceID surface) 409{ 410 if (!ctx) 411 return VA_STATUS_ERROR_INVALID_CONTEXT; 412 413 return VA_STATUS_ERROR_UNIMPLEMENTED; 414} 415 416VAStatus 417vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config_id, 418 VASurfaceAttrib *attrib_list, unsigned int *num_attribs) 419{ 420 vlVaDriver *drv; 421 vlVaConfig *config; 422 VASurfaceAttrib *attribs; 423 struct pipe_screen *pscreen; 424 int i, j; 425 426 STATIC_ASSERT(ARRAY_SIZE(vpp_surface_formats) <= VL_VA_MAX_IMAGE_FORMATS); 427 428 if (config_id == VA_INVALID_ID) 429 return VA_STATUS_ERROR_INVALID_CONFIG; 430 431 if (!attrib_list && !num_attribs) 432 return VA_STATUS_ERROR_INVALID_PARAMETER; 433 434 if (!attrib_list) { 435 *num_attribs = VL_VA_MAX_IMAGE_FORMATS + VASurfaceAttribCount; 436 return VA_STATUS_SUCCESS; 437 } 438 439 if (!ctx) 440 return VA_STATUS_ERROR_INVALID_CONTEXT; 441 442 drv = VL_VA_DRIVER(ctx); 443 444 if (!drv) 445 return VA_STATUS_ERROR_INVALID_CONTEXT; 446 447 mtx_lock(&drv->mutex); 448 config = handle_table_get(drv->htab, config_id); 449 mtx_unlock(&drv->mutex); 450 451 if (!config) 452 return VA_STATUS_ERROR_INVALID_CONFIG; 453 454 pscreen = VL_VA_PSCREEN(ctx); 455 456 if (!pscreen) 457 return VA_STATUS_ERROR_INVALID_CONTEXT; 458 459 attribs = CALLOC(VL_VA_MAX_IMAGE_FORMATS + VASurfaceAttribCount, 460 sizeof(VASurfaceAttrib)); 461 462 if (!attribs) 463 return VA_STATUS_ERROR_ALLOCATION_FAILED; 464 465 i = 0; 466 467 /* vlVaCreateConfig returns PIPE_VIDEO_PROFILE_UNKNOWN 468 * only for VAEntrypointVideoProc. */ 469 if (config->profile == PIPE_VIDEO_PROFILE_UNKNOWN) { 470 if (config->rt_format & VA_RT_FORMAT_RGB32) { 471 for (j = 0; j < ARRAY_SIZE(vpp_surface_formats); ++j) { 472 attribs[i].type = VASurfaceAttribPixelFormat; 473 attribs[i].value.type = VAGenericValueTypeInteger; 474 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE; 475 attribs[i].value.value.i = PipeFormatToVaFourcc(vpp_surface_formats[j]); 476 i++; 477 } 478 } 479 } 480 if (config->rt_format & VA_RT_FORMAT_YUV420) { 481 attribs[i].type = VASurfaceAttribPixelFormat; 482 attribs[i].value.type = VAGenericValueTypeInteger; 483 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE; 484 attribs[i].value.value.i = VA_FOURCC_NV12; 485 i++; 486 } 487 if (config->rt_format & VA_RT_FORMAT_YUV420_10BPP) { 488 attribs[i].type = VASurfaceAttribPixelFormat; 489 attribs[i].value.type = VAGenericValueTypeInteger; 490 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE; 491 attribs[i].value.value.i = VA_FOURCC_P010; 492 i++; 493 attribs[i].type = VASurfaceAttribPixelFormat; 494 attribs[i].value.type = VAGenericValueTypeInteger; 495 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE; 496 attribs[i].value.value.i = VA_FOURCC_P016; 497 i++; 498 } 499 500 attribs[i].type = VASurfaceAttribMemoryType; 501 attribs[i].value.type = VAGenericValueTypeInteger; 502 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE; 503 attribs[i].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA | 504 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; 505 i++; 506 507 attribs[i].type = VASurfaceAttribExternalBufferDescriptor; 508 attribs[i].value.type = VAGenericValueTypePointer; 509 attribs[i].flags = VA_SURFACE_ATTRIB_SETTABLE; 510 attribs[i].value.value.p = NULL; /* ignore */ 511 i++; 512 513 if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_UNKNOWN) { 514 attribs[i].type = VASurfaceAttribMaxWidth; 515 attribs[i].value.type = VAGenericValueTypeInteger; 516 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE; 517 attribs[i].value.value.i = 518 pscreen->get_video_param(pscreen, 519 config->profile, config->entrypoint, 520 PIPE_VIDEO_CAP_MAX_WIDTH); 521 i++; 522 523 attribs[i].type = VASurfaceAttribMaxHeight; 524 attribs[i].value.type = VAGenericValueTypeInteger; 525 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE; 526 attribs[i].value.value.i = 527 pscreen->get_video_param(pscreen, 528 config->profile, config->entrypoint, 529 PIPE_VIDEO_CAP_MAX_HEIGHT); 530 i++; 531 } else { 532 attribs[i].type = VASurfaceAttribMaxWidth; 533 attribs[i].value.type = VAGenericValueTypeInteger; 534 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE; 535 attribs[i].value.value.i = vl_video_buffer_max_size(pscreen); 536 i++; 537 538 attribs[i].type = VASurfaceAttribMaxHeight; 539 attribs[i].value.type = VAGenericValueTypeInteger; 540 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE; 541 attribs[i].value.value.i = vl_video_buffer_max_size(pscreen); 542 i++; 543 } 544 545 if (i > *num_attribs) { 546 *num_attribs = i; 547 FREE(attribs); 548 return VA_STATUS_ERROR_MAX_NUM_EXCEEDED; 549 } 550 551 *num_attribs = i; 552 memcpy(attrib_list, attribs, i * sizeof(VASurfaceAttrib)); 553 FREE(attribs); 554 555 return VA_STATUS_SUCCESS; 556} 557 558static VAStatus 559surface_from_external_memory(VADriverContextP ctx, vlVaSurface *surface, 560 VASurfaceAttribExternalBuffers *memory_attribute, 561 unsigned index, struct pipe_video_buffer *templat) 562{ 563 vlVaDriver *drv; 564 struct pipe_screen *pscreen; 565 struct pipe_resource res_templ; 566 struct winsys_handle whandle; 567 struct pipe_resource *resources[VL_NUM_COMPONENTS]; 568 const enum pipe_format *resource_formats = NULL; 569 VAStatus result; 570 int i; 571 572 pscreen = VL_VA_PSCREEN(ctx); 573 drv = VL_VA_DRIVER(ctx); 574 575 if (!memory_attribute || !memory_attribute->buffers || 576 index > memory_attribute->num_buffers) 577 return VA_STATUS_ERROR_INVALID_PARAMETER; 578 579 if (surface->templat.width != memory_attribute->width || 580 surface->templat.height != memory_attribute->height || 581 memory_attribute->num_planes < 1) 582 return VA_STATUS_ERROR_INVALID_PARAMETER; 583 584 if (memory_attribute->num_planes > VL_NUM_COMPONENTS) 585 return VA_STATUS_ERROR_INVALID_PARAMETER; 586 587 resource_formats = vl_video_buffer_formats(pscreen, templat->buffer_format); 588 if (!resource_formats) 589 return VA_STATUS_ERROR_INVALID_PARAMETER; 590 591 memset(&res_templ, 0, sizeof(res_templ)); 592 res_templ.target = PIPE_TEXTURE_2D; 593 res_templ.last_level = 0; 594 res_templ.depth0 = 1; 595 res_templ.array_size = 1; 596 res_templ.width0 = memory_attribute->width; 597 res_templ.height0 = memory_attribute->height; 598 res_templ.bind = PIPE_BIND_SAMPLER_VIEW; 599 res_templ.usage = PIPE_USAGE_DEFAULT; 600 601 memset(&whandle, 0, sizeof(struct winsys_handle)); 602 whandle.type = WINSYS_HANDLE_TYPE_FD; 603 whandle.handle = memory_attribute->buffers[index]; 604 605 // Create a resource for each plane. 606 memset(resources, 0, sizeof resources); 607 for (i = 0; i < memory_attribute->num_planes; i++) { 608 res_templ.format = resource_formats[i]; 609 if (res_templ.format == PIPE_FORMAT_NONE) { 610 result = VA_STATUS_ERROR_INVALID_PARAMETER; 611 goto fail; 612 } 613 614 whandle.stride = memory_attribute->pitches[i]; 615 whandle.offset = memory_attribute->offsets[i]; 616 resources[i] = pscreen->resource_from_handle(pscreen, &res_templ, &whandle, 617 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE); 618 if (!resources[i]) { 619 result = VA_STATUS_ERROR_ALLOCATION_FAILED; 620 goto fail; 621 } 622 } 623 624 surface->buffer = vl_video_buffer_create_ex2(drv->pipe, templat, resources); 625 if (!surface->buffer) { 626 result = VA_STATUS_ERROR_ALLOCATION_FAILED; 627 goto fail; 628 } 629 return VA_STATUS_SUCCESS; 630 631fail: 632 for (i = 0; i < VL_NUM_COMPONENTS; i++) 633 pipe_resource_reference(&resources[i], NULL); 634 return result; 635} 636 637VAStatus 638vlVaHandleSurfaceAllocate(vlVaDriver *drv, vlVaSurface *surface, 639 struct pipe_video_buffer *templat) 640{ 641 struct pipe_surface **surfaces; 642 unsigned i; 643 644 surface->buffer = drv->pipe->create_video_buffer(drv->pipe, templat); 645 if (!surface->buffer) 646 return VA_STATUS_ERROR_ALLOCATION_FAILED; 647 648 surfaces = surface->buffer->get_surfaces(surface->buffer); 649 for (i = 0; i < VL_MAX_SURFACES; ++i) { 650 union pipe_color_union c = {}; 651 652 if (!surfaces[i]) 653 continue; 654 655 if (i > !!surface->buffer->interlaced) 656 c.f[0] = c.f[1] = c.f[2] = c.f[3] = 0.5f; 657 658 drv->pipe->clear_render_target(drv->pipe, surfaces[i], &c, 0, 0, 659 surfaces[i]->width, surfaces[i]->height, 660 false); 661 } 662 drv->pipe->flush(drv->pipe, NULL, 0); 663 664 return VA_STATUS_SUCCESS; 665} 666 667VAStatus 668vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format, 669 unsigned int width, unsigned int height, 670 VASurfaceID *surfaces, unsigned int num_surfaces, 671 VASurfaceAttrib *attrib_list, unsigned int num_attribs) 672{ 673 vlVaDriver *drv; 674 VASurfaceAttribExternalBuffers *memory_attribute; 675 struct pipe_video_buffer templat; 676 struct pipe_screen *pscreen; 677 int i; 678 int memory_type; 679 int expected_fourcc; 680 VAStatus vaStatus; 681 vlVaSurface *surf; 682 683 if (!ctx) 684 return VA_STATUS_ERROR_INVALID_CONTEXT; 685 686 if (!(width && height)) 687 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT; 688 689 drv = VL_VA_DRIVER(ctx); 690 691 if (!drv) 692 return VA_STATUS_ERROR_INVALID_CONTEXT; 693 694 pscreen = VL_VA_PSCREEN(ctx); 695 696 if (!pscreen) 697 return VA_STATUS_ERROR_INVALID_CONTEXT; 698 699 /* Default. */ 700 memory_attribute = NULL; 701 memory_type = VA_SURFACE_ATTRIB_MEM_TYPE_VA; 702 expected_fourcc = 0; 703 704 for (i = 0; i < num_attribs && attrib_list; i++) { 705 if ((attrib_list[i].type == VASurfaceAttribPixelFormat) && 706 (attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE)) { 707 if (attrib_list[i].value.type != VAGenericValueTypeInteger) 708 return VA_STATUS_ERROR_INVALID_PARAMETER; 709 expected_fourcc = attrib_list[i].value.value.i; 710 } 711 712 if ((attrib_list[i].type == VASurfaceAttribMemoryType) && 713 (attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE)) { 714 715 if (attrib_list[i].value.type != VAGenericValueTypeInteger) 716 return VA_STATUS_ERROR_INVALID_PARAMETER; 717 718 switch (attrib_list[i].value.value.i) { 719 case VA_SURFACE_ATTRIB_MEM_TYPE_VA: 720 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: 721 memory_type = attrib_list[i].value.value.i; 722 break; 723 default: 724 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE; 725 } 726 } 727 728 if ((attrib_list[i].type == VASurfaceAttribExternalBufferDescriptor) && 729 (attrib_list[i].flags == VA_SURFACE_ATTRIB_SETTABLE)) { 730 if (attrib_list[i].value.type != VAGenericValueTypePointer) 731 return VA_STATUS_ERROR_INVALID_PARAMETER; 732 memory_attribute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p; 733 } 734 } 735 736 if (VA_RT_FORMAT_YUV420 != format && 737 VA_RT_FORMAT_YUV422 != format && 738 VA_RT_FORMAT_YUV444 != format && 739 VA_RT_FORMAT_YUV420_10BPP != format && 740 VA_RT_FORMAT_RGB32 != format) { 741 return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; 742 } 743 744 switch (memory_type) { 745 case VA_SURFACE_ATTRIB_MEM_TYPE_VA: 746 break; 747 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: 748 if (!memory_attribute) 749 return VA_STATUS_ERROR_INVALID_PARAMETER; 750 751 expected_fourcc = memory_attribute->pixel_format; 752 break; 753 default: 754 assert(0); 755 } 756 757 memset(&templat, 0, sizeof(templat)); 758 759 templat.buffer_format = pscreen->get_video_param( 760 pscreen, 761 PIPE_VIDEO_PROFILE_UNKNOWN, 762 PIPE_VIDEO_ENTRYPOINT_BITSTREAM, 763 PIPE_VIDEO_CAP_PREFERED_FORMAT 764 ); 765 templat.interlaced = pscreen->get_video_param( 766 pscreen, 767 PIPE_VIDEO_PROFILE_UNKNOWN, 768 PIPE_VIDEO_ENTRYPOINT_BITSTREAM, 769 PIPE_VIDEO_CAP_PREFERS_INTERLACED 770 ); 771 772 if (expected_fourcc) { 773 enum pipe_format expected_format = VaFourccToPipeFormat(expected_fourcc); 774 775 if (expected_format != templat.buffer_format || memory_attribute) 776 templat.interlaced = 0; 777 778 templat.buffer_format = expected_format; 779 } 780 781 templat.chroma_format = ChromaToPipe(format); 782 783 templat.width = width; 784 templat.height = height; 785 786 memset(surfaces, VA_INVALID_ID, num_surfaces * sizeof(VASurfaceID)); 787 788 mtx_lock(&drv->mutex); 789 for (i = 0; i < num_surfaces; i++) { 790 surf = CALLOC(1, sizeof(vlVaSurface)); 791 if (!surf) { 792 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; 793 goto no_res; 794 } 795 796 surf->templat = templat; 797 798 switch (memory_type) { 799 case VA_SURFACE_ATTRIB_MEM_TYPE_VA: 800 /* The application will clear the TILING flag when the surface is 801 * intended to be exported as dmabuf. Adding shared flag because not 802 * null memory_attribute means VASurfaceAttribExternalBuffers is used. 803 */ 804 if (memory_attribute && 805 !(memory_attribute->flags & VA_SURFACE_EXTBUF_DESC_ENABLE_TILING)) 806 templat.bind = PIPE_BIND_LINEAR | PIPE_BIND_SHARED; 807 808 vaStatus = vlVaHandleSurfaceAllocate(drv, surf, &templat); 809 if (vaStatus != VA_STATUS_SUCCESS) 810 goto free_surf; 811 break; 812 813 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: 814 vaStatus = surface_from_external_memory(ctx, surf, memory_attribute, i, &templat); 815 if (vaStatus != VA_STATUS_SUCCESS) 816 goto free_surf; 817 break; 818 819 default: 820 assert(0); 821 } 822 823 util_dynarray_init(&surf->subpics, NULL); 824 surfaces[i] = handle_table_add(drv->htab, surf); 825 if (!surfaces[i]) { 826 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; 827 goto destroy_surf; 828 } 829 } 830 mtx_unlock(&drv->mutex); 831 832 return VA_STATUS_SUCCESS; 833 834destroy_surf: 835 surf->buffer->destroy(surf->buffer); 836 837free_surf: 838 FREE(surf); 839 840no_res: 841 mtx_unlock(&drv->mutex); 842 if (i) 843 vlVaDestroySurfaces(ctx, surfaces, i); 844 845 return vaStatus; 846} 847 848VAStatus 849vlVaQueryVideoProcFilters(VADriverContextP ctx, VAContextID context, 850 VAProcFilterType *filters, unsigned int *num_filters) 851{ 852 unsigned int num = 0; 853 854 if (!ctx) 855 return VA_STATUS_ERROR_INVALID_CONTEXT; 856 857 if (!num_filters || !filters) 858 return VA_STATUS_ERROR_INVALID_PARAMETER; 859 860 filters[num++] = VAProcFilterDeinterlacing; 861 862 *num_filters = num; 863 864 return VA_STATUS_SUCCESS; 865} 866 867VAStatus 868vlVaQueryVideoProcFilterCaps(VADriverContextP ctx, VAContextID context, 869 VAProcFilterType type, void *filter_caps, 870 unsigned int *num_filter_caps) 871{ 872 unsigned int i; 873 874 if (!ctx) 875 return VA_STATUS_ERROR_INVALID_CONTEXT; 876 877 if (!filter_caps || !num_filter_caps) 878 return VA_STATUS_ERROR_INVALID_PARAMETER; 879 880 i = 0; 881 882 switch (type) { 883 case VAProcFilterNone: 884 break; 885 case VAProcFilterDeinterlacing: { 886 VAProcFilterCapDeinterlacing *deint = filter_caps; 887 888 if (*num_filter_caps < 3) { 889 *num_filter_caps = 3; 890 return VA_STATUS_ERROR_MAX_NUM_EXCEEDED; 891 } 892 893 deint[i++].type = VAProcDeinterlacingBob; 894 deint[i++].type = VAProcDeinterlacingWeave; 895 deint[i++].type = VAProcDeinterlacingMotionAdaptive; 896 break; 897 } 898 899 case VAProcFilterNoiseReduction: 900 case VAProcFilterSharpening: 901 case VAProcFilterColorBalance: 902 case VAProcFilterSkinToneEnhancement: 903 return VA_STATUS_ERROR_UNIMPLEMENTED; 904 default: 905 assert(0); 906 } 907 908 *num_filter_caps = i; 909 910 return VA_STATUS_SUCCESS; 911} 912 913static VAProcColorStandardType vpp_input_color_standards[] = { 914 VAProcColorStandardBT601 915}; 916 917static VAProcColorStandardType vpp_output_color_standards[] = { 918 VAProcColorStandardBT601 919}; 920 921VAStatus 922vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context, 923 VABufferID *filters, unsigned int num_filters, 924 VAProcPipelineCaps *pipeline_cap) 925{ 926 unsigned int i = 0; 927 928 if (!ctx) 929 return VA_STATUS_ERROR_INVALID_CONTEXT; 930 931 if (!pipeline_cap) 932 return VA_STATUS_ERROR_INVALID_PARAMETER; 933 934 if (num_filters && !filters) 935 return VA_STATUS_ERROR_INVALID_PARAMETER; 936 937 pipeline_cap->pipeline_flags = 0; 938 pipeline_cap->filter_flags = 0; 939 pipeline_cap->num_forward_references = 0; 940 pipeline_cap->num_backward_references = 0; 941 pipeline_cap->num_input_color_standards = ARRAY_SIZE(vpp_input_color_standards); 942 pipeline_cap->input_color_standards = vpp_input_color_standards; 943 pipeline_cap->num_output_color_standards = ARRAY_SIZE(vpp_output_color_standards); 944 pipeline_cap->output_color_standards = vpp_output_color_standards; 945 946 for (i = 0; i < num_filters; i++) { 947 vlVaBuffer *buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, filters[i]); 948 VAProcFilterParameterBufferBase *filter; 949 950 if (!buf || buf->type != VAProcFilterParameterBufferType) 951 return VA_STATUS_ERROR_INVALID_BUFFER; 952 953 filter = buf->data; 954 switch (filter->type) { 955 case VAProcFilterDeinterlacing: { 956 VAProcFilterParameterBufferDeinterlacing *deint = buf->data; 957 if (deint->algorithm == VAProcDeinterlacingMotionAdaptive) { 958 pipeline_cap->num_forward_references = 2; 959 pipeline_cap->num_backward_references = 1; 960 } 961 break; 962 } 963 default: 964 return VA_STATUS_ERROR_UNIMPLEMENTED; 965 } 966 } 967 968 return VA_STATUS_SUCCESS; 969} 970 971#if VA_CHECK_VERSION(1, 1, 0) 972VAStatus 973vlVaExportSurfaceHandle(VADriverContextP ctx, 974 VASurfaceID surface_id, 975 uint32_t mem_type, 976 uint32_t flags, 977 void *descriptor) 978{ 979 vlVaDriver *drv; 980 vlVaSurface *surf; 981 struct pipe_surface **surfaces; 982 struct pipe_screen *screen; 983 VAStatus ret; 984 unsigned int usage; 985 int i, p; 986 987 VADRMPRIMESurfaceDescriptor *desc = descriptor; 988 989 if (mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2) 990 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE; 991 if (flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS) 992 return VA_STATUS_ERROR_INVALID_SURFACE; 993 994 drv = VL_VA_DRIVER(ctx); 995 screen = VL_VA_PSCREEN(ctx); 996 mtx_lock(&drv->mutex); 997 998 surf = handle_table_get(drv->htab, surface_id); 999 if (!surf || !surf->buffer) { 1000 mtx_unlock(&drv->mutex); 1001 return VA_STATUS_ERROR_INVALID_SURFACE; 1002 } 1003 1004 if (surf->buffer->interlaced) { 1005 struct pipe_video_buffer *interlaced = surf->buffer; 1006 struct u_rect src_rect, dst_rect; 1007 1008 surf->templat.interlaced = false; 1009 1010 ret = vlVaHandleSurfaceAllocate(drv, surf, &surf->templat); 1011 if (ret != VA_STATUS_SUCCESS) { 1012 mtx_unlock(&drv->mutex); 1013 return VA_STATUS_ERROR_ALLOCATION_FAILED; 1014 } 1015 1016 src_rect.x0 = dst_rect.x0 = 0; 1017 src_rect.y0 = dst_rect.y0 = 0; 1018 src_rect.x1 = dst_rect.x1 = surf->templat.width; 1019 src_rect.y1 = dst_rect.y1 = surf->templat.height; 1020 1021 vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor, 1022 interlaced, surf->buffer, 1023 &src_rect, &dst_rect, 1024 VL_COMPOSITOR_WEAVE); 1025 1026 interlaced->destroy(interlaced); 1027 } 1028 1029 surfaces = surf->buffer->get_surfaces(surf->buffer); 1030 1031 usage = 0; 1032 if (flags & VA_EXPORT_SURFACE_WRITE_ONLY) 1033 usage |= PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE; 1034 1035 desc->fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format); 1036 desc->width = surf->buffer->width; 1037 desc->height = surf->buffer->height; 1038 1039 for (p = 0; p < VL_MAX_SURFACES; p++) { 1040 struct winsys_handle whandle; 1041 struct pipe_resource *resource; 1042 uint32_t drm_format; 1043 1044 if (!surfaces[p]) 1045 break; 1046 1047 resource = surfaces[p]->texture; 1048 1049 switch (resource->format) { 1050 case PIPE_FORMAT_R8_UNORM: 1051 drm_format = DRM_FORMAT_R8; 1052 break; 1053 case PIPE_FORMAT_R8G8_UNORM: 1054 drm_format = DRM_FORMAT_GR88; 1055 break; 1056 case PIPE_FORMAT_R16_UNORM: 1057 drm_format = DRM_FORMAT_R16; 1058 break; 1059 case PIPE_FORMAT_R16G16_UNORM: 1060 drm_format = DRM_FORMAT_GR1616; 1061 break; 1062 case PIPE_FORMAT_B8G8R8A8_UNORM: 1063 drm_format = DRM_FORMAT_ARGB8888; 1064 break; 1065 case PIPE_FORMAT_R8G8B8A8_UNORM: 1066 drm_format = DRM_FORMAT_ABGR8888; 1067 break; 1068 case PIPE_FORMAT_B8G8R8X8_UNORM: 1069 drm_format = DRM_FORMAT_XRGB8888; 1070 break; 1071 case PIPE_FORMAT_R8G8B8X8_UNORM: 1072 drm_format = DRM_FORMAT_XBGR8888; 1073 break; 1074 default: 1075 ret = VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE; 1076 goto fail; 1077 } 1078 1079 memset(&whandle, 0, sizeof(whandle)); 1080 whandle.type = WINSYS_HANDLE_TYPE_FD; 1081 1082 if (!screen->resource_get_handle(screen, drv->pipe, resource, 1083 &whandle, usage)) { 1084 ret = VA_STATUS_ERROR_INVALID_SURFACE; 1085 goto fail; 1086 } 1087 1088 desc->objects[p].fd = (int)whandle.handle; 1089 desc->objects[p].size = 0; 1090 desc->objects[p].drm_format_modifier = whandle.modifier; 1091 1092 desc->layers[p].drm_format = drm_format; 1093 desc->layers[p].num_planes = 1; 1094 desc->layers[p].object_index[0] = p; 1095 desc->layers[p].offset[0] = whandle.offset; 1096 desc->layers[p].pitch[0] = whandle.stride; 1097 } 1098 1099 desc->num_objects = p; 1100 desc->num_layers = p; 1101 1102 mtx_unlock(&drv->mutex); 1103 1104 return VA_STATUS_SUCCESS; 1105 1106fail: 1107 for (i = 0; i < p; i++) 1108 close(desc->objects[i].fd); 1109 1110 mtx_unlock(&drv->mutex); 1111 1112 return ret; 1113} 1114#endif 1115