From 4e4cfa682d4e8fcec110fef031d8eb415676b027 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Tue, 12 Nov 2024 15:55:44 +0100 Subject: [PATCH] frontends/va: Use transfer stride and offset in DeriveImage This should use the stride and offset from transfer, because the values from resource_get_info may not match the mapped memory if the driver uses staging texture for transfer. This also gives us data size and we don't need to calculate it for each format. Unfortunately we only know the values when mapping the buffer, but VAAPI requires the values when creating the image and at that point we don't know the usage yet (read/write). Do a dummy map of all planes first time DeriveImage is called for each surface and cache the values for subsequent calls. Reviewed-by: Ruijing Dong Part-of: --- src/gallium/frontends/va/image.c | 103 ++++++++------------------ src/gallium/frontends/va/va_private.h | 3 + 2 files changed, 33 insertions(+), 73 deletions(-) diff --git a/src/gallium/frontends/va/image.c b/src/gallium/frontends/va/image.c index 22713776d10..0a53c048af0 100644 --- a/src/gallium/frontends/va/image.c +++ b/src/gallium/frontends/va/image.c @@ -254,11 +254,7 @@ vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image) VAStatus status; struct pipe_screen *screen; struct pipe_resource *buf_resources[VL_NUM_COMPONENTS]; - int w; - int h; int i; - unsigned stride = 0; - unsigned offset = 0; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; @@ -316,9 +312,7 @@ vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image) img->height = surf->templat.height; img->num_palette_entries = 0; img->entry_bytes = 0; - /* Image data size is computed using internal dimensions. */ - w = align(surf->buffer->width, 2); - h = align(surf->buffer->height, 2); + img->num_planes = util_format_get_num_planes(surf->buffer->buffer_format); for (i = 0; i < ARRAY_SIZE(formats); ++i) { if (img->format.fourcc == formats[i].fourcc) { @@ -327,75 +321,38 @@ vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image) } } - if (screen->resource_get_info) { - screen->resource_get_info(screen, buf_resources[0], &stride, - &offset); - if (!stride) - offset = 0; + if (!surf->data_size) { + unsigned offset = 0; + struct pipe_transfer *transfer; + + for (i = 0; i < img->num_planes; i++) { + struct pipe_box box = { + .width = buf_resources[i]->width0, + .height = buf_resources[i]->height0, + .depth = buf_resources[i]->depth0, + }; + + void *ptr = drv->pipe->texture_map(drv->pipe, buf_resources[i], + 0, 0, &box, &transfer); + if (!ptr) { + status = VA_STATUS_ERROR_OPERATION_FAILED; + goto exit_on_error; + } + + surf->strides[i] = transfer->stride; + surf->offsets[i] = offset; + offset += transfer->layer_stride; + + drv->pipe->texture_unmap(drv->pipe, transfer); + } + surf->data_size = offset; } - img->num_planes = 1; - img->offsets[0] = offset; - - switch (img->format.fourcc) { - case VA_FOURCC('U','Y','V','Y'): - case VA_FOURCC('Y','U','Y','V'): - img->pitches[0] = stride > 0 ? stride : w * 2; - assert(img->pitches[0] >= (w * 2)); - img->data_size = img->pitches[0] * h; - break; - - case VA_FOURCC('B','G','R','A'): - case VA_FOURCC('R','G','B','A'): - case VA_FOURCC('B','G','R','X'): - case VA_FOURCC('R','G','B','X'): - case VA_FOURCC('A','R','3','0'): - case VA_FOURCC('A','B','3','0'): - case VA_FOURCC('X','R','3','0'): - case VA_FOURCC('X','B','3','0'): - img->pitches[0] = stride > 0 ? stride : w * 4; - assert(img->pitches[0] >= (w * 4)); - img->data_size = img->pitches[0] * h; - break; - - case VA_FOURCC('N','V','1','2'): - case VA_FOURCC('P','0','1','0'): - case VA_FOURCC('P','0','1','2'): - case VA_FOURCC('P','0','1','6'): - { - /* In some gallium platforms, the stride and offset are different*/ - /* for the Y and UV planes, query them independently.*/ - if (screen->resource_get_info) { - /* resource_get_info is called above for buf_resources[0] and */ - /* saved results in stride, offset, reuse those values to avoid a new call to: */ - /* screen->resource_get_info(screen, buf_resources[0], &img->pitches[0],*/ - /* &img->offsets[0]);*/ - img->pitches[0] = stride; - img->offsets[0] = offset; - - screen->resource_get_info(screen, buf_resources[1], &img->pitches[1], - &img->offsets[1]); - if (!img->pitches[1]) - img->offsets[1] = 0; - } - - img->num_planes = 2; - if(screen->resource_get_info) { - img->data_size = (img->pitches[0] * h) + (img->pitches[1] * h / 2); - } else { - /* Use stride = w as default if screen->resource_get_info was not available */ - img->pitches[0] = w; - img->pitches[1] = w; - img->offsets[1] = w * h; - img->data_size = w * h * 3 / 2; - } - } break; - default: - /* VaDeriveImage only supports contiguous planes. But there is now a - more generic api vlVaExportSurfaceHandle. */ - status = VA_STATUS_ERROR_OPERATION_FAILED; - goto exit_on_error; + for (i = 0; i < img->num_planes; i++) { + img->pitches[i] = surf->strides[i]; + img->offsets[i] = surf->offsets[i]; } + img->data_size = surf->data_size; img_buf = CALLOC(1, sizeof(vlVaBuffer)); if (!img_buf) { diff --git a/src/gallium/frontends/va/va_private.h b/src/gallium/frontends/va/va_private.h index 640af03747d..96e332e97d8 100644 --- a/src/gallium/frontends/va/va_private.h +++ b/src/gallium/frontends/va/va_private.h @@ -460,6 +460,9 @@ typedef struct vlVaSurface { struct pipe_fence_handle *pipe_fence; /* pipe_context fence */ struct vlVaSurface *efc_surface; /* input surface for EFC */ bool is_dpb; + unsigned int strides[3]; + unsigned int offsets[3]; + unsigned int data_size; } vlVaSurface; typedef struct {