Commit fbf6511e authored by Bas Nieuwenhuizen's avatar Bas Nieuwenhuizen Committed by Marge Bot
Browse files

gallium/va: Add support for PRIME_2 import.



That way we can actually import surfaces with modifiers & metadata
planes.

Tested with patches for ffmpeg to use this with kmsgrab & modifiers.

For AMD & multiplanar formats we always have 1 format plane = 1
memory plane, even with modifiers.

Intel (non Gallium) does have 1 format plane is 2 memory planes
for some modifiers with NV12. Currently with Gallium we don't really
have info about layer/plane ordering so this manually orders things
so that they align with Intel.

This shouldn't impact other drivers as without modifiers with metadata
planes this should give equivalent behavior to the old import path.
Reviewed-and-Tested-by: Leo Liu's avatarLeo Liu <leo.liu@amd.com>
Part-of: <!10815>
parent 243475b9
Pipeline #338599 waiting for manual action with stages
......@@ -503,7 +503,8 @@ vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config_id,
attribs[i].value.type = VAGenericValueTypeInteger;
attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
attribs[i].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA |
VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME |
VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2;
i++;
attribs[i].type = VASurfaceAttribExternalBufferDescriptor;
......@@ -655,6 +656,127 @@ fail:
return result;
}
static VAStatus
surface_from_prime_2(VADriverContextP ctx, vlVaSurface *surface,
VADRMPRIMESurfaceDescriptor *desc,
struct pipe_video_buffer *templat)
{
vlVaDriver *drv;
struct pipe_screen *pscreen;
struct pipe_resource res_templ;
struct winsys_handle whandle;
struct pipe_resource *resources[VL_NUM_COMPONENTS];
enum pipe_format resource_formats[VL_NUM_COMPONENTS];
unsigned num_format_planes, expected_planes, input_planes, plane;
VAStatus result;
num_format_planes = util_format_get_num_planes(templat->buffer_format);
pscreen = VL_VA_PSCREEN(ctx);
drv = VL_VA_DRIVER(ctx);
if (!desc || desc->num_layers >= 4 ||desc->num_objects == 0)
return VA_STATUS_ERROR_INVALID_PARAMETER;
if (surface->templat.width != desc->width ||
surface->templat.height != desc->height ||
desc->num_layers < 1)
return VA_STATUS_ERROR_INVALID_PARAMETER;
if (desc->num_layers != num_format_planes)
return VA_STATUS_ERROR_INVALID_PARAMETER;
input_planes = 0;
for (unsigned i = 0; i < desc->num_layers; ++i) {
if (desc->layers[i].num_planes == 0 || desc->layers[i].num_planes > 4)
return VA_STATUS_ERROR_INVALID_PARAMETER;
for (unsigned j = 0; j < desc->layers[i].num_planes; ++j)
if (desc->layers[i].object_index[j] >= desc->num_objects)
return VA_STATUS_ERROR_INVALID_PARAMETER;
input_planes += desc->layers[i].num_planes;
}
expected_planes = num_format_planes;
if (desc->objects[0].drm_format_modifier != DRM_FORMAT_MOD_INVALID &&
pscreen->is_dmabuf_modifier_supported &&
pscreen->is_dmabuf_modifier_supported(pscreen, desc->objects[0].drm_format_modifier,
templat->buffer_format, NULL) &&
pscreen->get_dmabuf_modifier_planes)
expected_planes = pscreen->get_dmabuf_modifier_planes(pscreen, desc->objects[0].drm_format_modifier,
templat->buffer_format);
if (input_planes != expected_planes)
return VA_STATUS_ERROR_INVALID_PARAMETER;
vl_get_video_buffer_formats(pscreen, templat->buffer_format, resource_formats);
memset(&res_templ, 0, sizeof(res_templ));
res_templ.target = PIPE_TEXTURE_2D;
res_templ.last_level = 0;
res_templ.depth0 = 1;
res_templ.array_size = 1;
res_templ.width0 = desc->width;
res_templ.height0 = desc->height;
res_templ.bind = PIPE_BIND_SAMPLER_VIEW;
res_templ.usage = PIPE_USAGE_DEFAULT;
res_templ.format = templat->buffer_format;
memset(&whandle, 0, sizeof(struct winsys_handle));
whandle.type = WINSYS_HANDLE_TYPE_FD;
whandle.format = templat->buffer_format;
whandle.modifier = desc->objects[0].drm_format_modifier;
// Create a resource for each plane.
memset(resources, 0, sizeof resources);
/* This does a backwards walk to set the next pointers. It interleaves so
* that the main planes always come first and then the first compression metadata
* plane of each main plane etc. */
plane = input_planes - 1;
for (int layer_plane = 3; layer_plane >= 0; --layer_plane) {
for (int layer = desc->num_layers - 1; layer >= 0; --layer) {
if (layer_plane >= desc->layers[layer].num_planes)
continue;
if (plane < num_format_planes)
res_templ.format = resource_formats[plane];
whandle.stride = desc->layers[layer].pitch[layer_plane];
whandle.offset = desc->layers[layer].offset[layer_plane];
whandle.handle = desc->objects[desc->layers[layer].object_index[layer_plane]].fd;
whandle.plane = plane;
resources[plane] = pscreen->resource_from_handle(pscreen, &res_templ, &whandle,
PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
if (!resources[plane]) {
result = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto fail;
}
/* After the resource gets created the resource now owns the next reference. */
res_templ.next = NULL;
if (plane)
pipe_resource_reference(&res_templ.next, resources[plane]);
--plane;
}
}
surface->buffer = vl_video_buffer_create_ex2(drv->pipe, templat, resources);
if (!surface->buffer) {
result = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto fail;
}
return VA_STATUS_SUCCESS;
fail:
pipe_resource_reference(&res_templ.next, NULL);
for (int i = 0; i < VL_NUM_COMPONENTS; i++)
pipe_resource_reference(&resources[i], NULL);
return result;
}
VAStatus
vlVaHandleSurfaceAllocate(vlVaDriver *drv, vlVaSurface *surface,
struct pipe_video_buffer *templat,
......@@ -704,6 +826,7 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
{
vlVaDriver *drv;
VASurfaceAttribExternalBuffers *memory_attribute;
VADRMPRIMESurfaceDescriptor *prime_desc;
#ifdef HAVE_VA_SURFACE_ATTRIB_DRM_FORMAT_MODIFIERS
const VADRMFormatModifierList *modifier_list;
#endif
......@@ -736,6 +859,7 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
/* Default. */
memory_attribute = NULL;
prime_desc = NULL;
memory_type = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
expected_fourcc = 0;
modifiers = NULL;
......@@ -758,6 +882,7 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
switch (attrib_list[i].value.value.i) {
case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2:
memory_type = attrib_list[i].value.value.i;
break;
default:
......@@ -767,7 +892,10 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
case VASurfaceAttribExternalBufferDescriptor:
if (attrib_list[i].value.type != VAGenericValueTypePointer)
return VA_STATUS_ERROR_INVALID_PARAMETER;
memory_attribute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p;
if (memory_type == VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2)
prime_desc = (VADRMPRIMESurfaceDescriptor *)attrib_list[i].value.value.p;
else
memory_attribute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p;
break;
#ifdef HAVE_VA_SURFACE_ATTRIB_DRM_FORMAT_MODIFIERS
case VASurfaceAttribDRMFormatModifiers:
......@@ -809,6 +937,12 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
expected_fourcc = memory_attribute->pixel_format;
break;
case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2:
if (!prime_desc)
return VA_STATUS_ERROR_INVALID_PARAMETER;
expected_fourcc = prime_desc->fourcc;
break;
default:
assert(0);
}
......@@ -878,6 +1012,11 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
goto free_surf;
break;
case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2:
vaStatus = surface_from_prime_2(ctx, surf, prime_desc, &templat);
if (vaStatus != VA_STATUS_SUCCESS)
goto free_surf;
break;
default:
assert(0);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment