d3d12: Improve planar resource support to handle video requirements

Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16286>
This commit is contained in:
Sil Vilerino
2022-05-02 10:14:29 -07:00
committed by Marge Bot
parent 6dbe05ffda
commit 739283da13
4 changed files with 307 additions and 27 deletions

View File

@@ -251,14 +251,14 @@ direct_copy_supported(struct d3d12_screen *screen,
inline static unsigned
get_subresource_id(enum pipe_texture_target target, unsigned subres, unsigned stride,
unsigned z, unsigned *updated_z)
unsigned z, unsigned *updated_z, unsigned array_size, unsigned plane_slice)
{
if (d3d12_subresource_id_uses_layer(target)) {
subres += stride * z;
if (updated_z)
*updated_z = 0;
}
return subres;
return subres + plane_slice * array_size * stride;
}
static void
@@ -317,12 +317,12 @@ copy_subregion_no_barriers(struct d3d12_context *ctx,
continue;
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
src_loc.SubresourceIndex = get_subresource_id(src->base.b.target, src_level, src_subres_stride, src_z, &src_z) +
src_loc.SubresourceIndex = get_subresource_id(src->base.b.target, src_level, src_subres_stride, src_z, &src_z, src_array_size, src->plane_slice) +
subres * stencil_src_res_offset;
src_loc.pResource = d3d12_resource_resource(src);
dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst_loc.SubresourceIndex = get_subresource_id(dst->base.b.target, dst_level, dst_subres_stride, dstz, &dstz) +
dst_loc.SubresourceIndex = get_subresource_id(dst->base.b.target, dst_level, dst_subres_stride, dstz, &dstz, dst_array_size, dst->plane_slice) +
subres * stencil_dst_res_offset;
dst_loc.pResource = d3d12_resource_resource(dst);
@@ -412,9 +412,9 @@ d3d12_direct_copy(struct d3d12_context *ctx,
struct d3d12_batch *batch = d3d12_current_batch(ctx);
unsigned src_subres = get_subresource_id(src->base.b.target, src_level, src->base.b.last_level + 1,
psrc_box->z, nullptr);
psrc_box->z, nullptr, src->base.b.array_size, src->plane_slice);
unsigned dst_subres = get_subresource_id(dst->base.b.target, dst_level, dst->base.b.last_level + 1,
pdst_box->z, nullptr);
pdst_box->z, nullptr, dst->base.b.array_size, dst->plane_slice);
if (D3D12_DEBUG_BLIT & d3d12_debug)
debug_printf("BLIT: Direct copy from subres %d to subres %d\n",

View File

@@ -303,6 +303,7 @@ convert_planar_resource(struct d3d12_resource *res)
plane_res->base.b.next = next;
next = &plane_res->base.b;
plane_res->plane_slice = plane;
plane_res->base.b.format = util_format_get_plane_format(res->base.b.format, plane);
plane_res->base.b.width0 = util_format_get_plane_width(res->base.b.format, plane, res->base.b.width0);
plane_res->base.b.height0 = util_format_get_plane_height(res->base.b.format, plane, res->base.b.height0);
@@ -317,6 +318,7 @@ convert_planar_resource(struct d3d12_resource *res)
assert(plane_res->base.b.width0 == footprint->Width);
assert(plane_res->base.b.height0 == footprint->Height);
assert(plane_res->base.b.depth0 == footprint->Depth);
assert(plane_res->first_plane == &res->base.b);
#endif
}
}
@@ -331,6 +333,8 @@ d3d12_resource_create(struct pipe_screen *pscreen,
res->base.b = *templ;
res->overall_format = templ->format;
res->plane_slice = 0;
res->first_plane = &res->base.b;
if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
debug_printf("D3D12: Create %sresource %s@%d %dx%dx%d as:%d mip:%d\n",
@@ -550,6 +554,8 @@ d3d12_resource_from_handle(struct pipe_screen *pscreen,
handle->format = res->overall_format;
res->dxgi_format = d3d12_get_format(res->overall_format);
res->plane_slice = handle->plane;
res->first_plane = &res->base.b;
if (!res->bo) {
res->bo = d3d12_bo_wrap_res(screen, d3d12_res, res->overall_format, d3d12_permanently_resident);
@@ -609,6 +615,151 @@ d3d12_resource_get_handle(struct pipe_screen *pscreen,
}
}
struct pipe_resource *
d3d12_resource_from_resource(struct pipe_screen *pscreen,
ID3D12Resource* input_res)
{
D3D12_RESOURCE_DESC input_desc = input_res->GetDesc();
struct winsys_handle handle;
memset(&handle, 0, sizeof(handle));
handle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
handle.format = d3d12_get_pipe_format(input_desc.Format);
handle.com_obj = input_res;
struct pipe_resource templ;
memset(&templ, 0, sizeof(templ));
if(input_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) {
templ.target = PIPE_BUFFER;
} else {
templ.target = (input_desc.DepthOrArraySize > 1) ? PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D;
}
templ.format = d3d12_get_pipe_format(input_desc.Format);
templ.width0 = input_desc.Width;
templ.height0 = input_desc.Height;
templ.depth0 = input_desc.DepthOrArraySize;
templ.array_size = input_desc.DepthOrArraySize;
templ.flags = 0;
return d3d12_resource_from_handle(
pscreen,
&templ,
&handle,
PIPE_USAGE_DEFAULT
);
}
/**
* On Map/Unmap operations, we readback or flush all the underlying planes
* of planar resources. The map/unmap operation from the caller is
* expected to be done for res->plane_slice plane only, but some
* callers expect adjacent allocations for next contiguous plane access
*
* In this function, we take the res and box the caller passed, and the plane_* properties
* that are currently being readback/flushed, and adjust the d3d12_transfer ptrans
* accordingly for the GPU copy operation between planes.
*/
static void d3d12_adjust_transfer_dimensions_for_plane(const struct d3d12_resource *res,
unsigned plane_slice,
unsigned plane_stride,
unsigned plane_layer_stride,
unsigned plane_offset,
const struct pipe_box* original_box,
struct pipe_transfer *ptrans/*inout*/)
{
/* Adjust strides, offsets to the corresponding plane*/
ptrans->stride = plane_stride;
ptrans->layer_stride = plane_layer_stride;
ptrans->offset = plane_offset;
/* Find multipliers such that:*/
/* first_plane.width = width_multiplier * planes[res->plane_slice].width*/
/* first_plane.height = height_multiplier * planes[res->plane_slice].height*/
float width_multiplier = res->first_plane->width0 / (float) util_format_get_plane_width(res->overall_format, res->plane_slice, res->first_plane->width0);
float height_multiplier = res->first_plane->height0 / (float) util_format_get_plane_height(res->overall_format, res->plane_slice, res->first_plane->height0);
/* Normalize box back to overall dimensions (first plane)*/
ptrans->box.width = width_multiplier * original_box->width;
ptrans->box.height = height_multiplier * original_box->height;
ptrans->box.x = width_multiplier * original_box->x;
ptrans->box.y = height_multiplier * original_box->y;
/* Now adjust dimensions to plane_slice*/
ptrans->box.width = util_format_get_plane_width(res->overall_format, plane_slice, ptrans->box.width);
ptrans->box.height = util_format_get_plane_height(res->overall_format, plane_slice, ptrans->box.height);
ptrans->box.x = util_format_get_plane_width(res->overall_format, plane_slice, ptrans->box.x);
ptrans->box.y = util_format_get_plane_height(res->overall_format, plane_slice, ptrans->box.y);
}
static
void d3d12_resource_get_planes_info(pipe_resource *pres,
unsigned num_planes,
pipe_resource **planes,
unsigned *strides,
unsigned *layer_strides,
unsigned *offsets,
unsigned *staging_res_size)
{
struct d3d12_resource* res = d3d12_resource(pres);
*staging_res_size = 0;
struct pipe_resource *cur_plane_resource = res->first_plane;
for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
planes[plane_slice] = cur_plane_resource;
int width = util_format_get_plane_width(res->base.b.format, plane_slice, res->first_plane->width0);
int height = util_format_get_plane_height(res->base.b.format, plane_slice, res->first_plane->height0);
strides[plane_slice] = align(util_format_get_stride(cur_plane_resource->format, width),
D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
layer_strides[plane_slice] = align(util_format_get_2d_size(cur_plane_resource->format,
strides[plane_slice],
height),
D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
offsets[plane_slice] = *staging_res_size;
*staging_res_size += layer_strides[plane_slice];
cur_plane_resource = cur_plane_resource->next;
}
}
/**
* Get stride and offset for the given pipe resource without the need to get
* a winsys_handle.
*/
void
d3d12_resource_get_info(struct pipe_screen *pscreen,
struct pipe_resource *pres,
unsigned *stride,
unsigned *offset)
{
struct d3d12_resource* res = d3d12_resource(pres);
unsigned num_planes = util_format_get_num_planes(res->overall_format);
pipe_resource* planes[num_planes];
unsigned int strides[num_planes];
unsigned int layer_strides[num_planes];
unsigned int offsets[num_planes];
unsigned staging_res_size = 0;
d3d12_resource_get_planes_info(
pres,
num_planes,
planes,
strides,
layer_strides,
offsets,
&staging_res_size
);
if(stride) {
*stride = strides[res->plane_slice];
}
if(offset) {
*offset = offsets[res->plane_slice];
}
}
void
d3d12_screen_resource_init(struct pipe_screen *pscreen)
{
@@ -616,6 +767,7 @@ d3d12_screen_resource_init(struct pipe_screen *pscreen)
pscreen->resource_from_handle = d3d12_resource_from_handle;
pscreen->resource_get_handle = d3d12_resource_get_handle;
pscreen->resource_destroy = d3d12_resource_destroy;
pscreen->resource_get_info = d3d12_resource_get_info;
}
unsigned int
@@ -636,7 +788,7 @@ get_subresource_id(struct d3d12_resource *res, unsigned resid,
unsigned layer_stride = res->base.b.last_level + 1;
return resid * resource_stride + z * layer_stride +
base_level;
base_level + res->plane_slice * resource_stride;
}
static D3D12_TEXTURE_COPY_LOCATION
@@ -674,6 +826,7 @@ fill_buffer_location(struct d3d12_context *ctx,
buf_loc.pResource = d3d12_resource_underlying(staging_res, &offset);
buf_loc.PlacedFootprint = footprint;
buf_loc.PlacedFootprint.Offset += offset;
buf_loc.PlacedFootprint.Offset += trans->base.b.offset;
if (util_format_has_depth(util_format_description(res->base.b.format)) &&
screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
@@ -1286,6 +1439,72 @@ d3d12_transfer_map(struct pipe_context *pctx,
} else {
ptr = nullptr;
}
} else if(util_format_is_yuv(res->overall_format)) {
/* Get planes information*/
unsigned num_planes = util_format_get_num_planes(res->overall_format);
pipe_resource* planes[num_planes];
unsigned int strides[num_planes];
unsigned int layer_strides[num_planes];
unsigned int offsets[num_planes];
unsigned staging_res_size = 0;
d3d12_resource_get_planes_info(
pres,
num_planes,
planes,
strides,
layer_strides,
offsets,
&staging_res_size
);
/* Allocate a buffer for all the planes to fit in adjacent memory*/
pipe_resource_usage staging_usage = (usage & (PIPE_MAP_READ | PIPE_MAP_READ_WRITE)) ?
PIPE_USAGE_STAGING : PIPE_USAGE_STREAM;
trans->staging_res = pipe_buffer_create(pctx->screen, 0,
staging_usage,
staging_res_size);
if (!trans->staging_res)
return NULL;
struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
/* Readback contents into the buffer allocation now if map was intended for read*/
/* Read all planes if readback needed*/
if (usage & PIPE_MAP_READ) {
pipe_box original_box = ptrans->box;
for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
/* Adjust strides, offsets, box to the corresponding plane for the copytexture operation*/
d3d12_adjust_transfer_dimensions_for_plane(res,
plane_slice,
strides[plane_slice],
layer_strides[plane_slice],
offsets[plane_slice],
&original_box,
ptrans/*inout*/);
/* Perform the readback*/
if(!transfer_image_to_buf(ctx, d3d12_resource(planes[plane_slice]), staging_res, trans, 0)){
return NULL;
}
}
d3d12_flush_cmdlist_and_wait(ctx);
}
/* Map the whole staging buffer containing all the planes contiguously*/
/* Just offset the resulting ptr to the according plane offset*/
range.End = staging_res_size - range.Begin;
uint8_t* all_planes_map = (uint8_t*) d3d12_bo_map(staging_res->bo, &range);
ptrans->stride = strides[res->plane_slice];
ptrans->layer_stride = layer_strides[res->plane_slice];
ptr = all_planes_map + offsets[res->plane_slice];
} else {
ptrans->stride = align(util_format_get_stride(pres->format, box->width),
D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
@@ -1364,6 +1583,7 @@ static void
d3d12_transfer_unmap(struct pipe_context *pctx,
struct pipe_transfer *ptrans)
{
struct d3d12_context *ctx = d3d12_context(pctx);
struct d3d12_resource *res = d3d12_resource(ptrans->resource);
struct d3d12_transfer *trans = (struct d3d12_transfer *)ptrans;
D3D12_RANGE range = { 0, 0 };
@@ -1373,27 +1593,81 @@ d3d12_transfer_unmap(struct pipe_context *pctx,
write_zs_surface(pctx, res, trans);
free(trans->data);
} else if (trans->staging_res) {
struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
if(util_format_is_yuv(res->overall_format)) {
if (trans->base.b.usage & PIPE_MAP_WRITE) {
assert(ptrans->box.x >= 0);
range.Begin = res->base.b.target == PIPE_BUFFER ?
(unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
range.End = staging_res->base.b.width0 - range.Begin;
/* Get planes information*/
unsigned num_planes = util_format_get_num_planes(res->overall_format);
pipe_resource* planes[num_planes];
unsigned int strides[num_planes];
unsigned int layer_strides[num_planes];
unsigned int offsets[num_planes];
unsigned staging_res_size = 0;
d3d12_resource_get_planes_info(
ptrans->resource,
num_planes,
planes,
strides,
layer_strides,
offsets,
&staging_res_size
);
/* Flush the changed contents into the GPU texture*/
/* In theory we should just flush only the contents for the plane*/
/* requested in res->plane_slice, but the VAAPI frontend has this*/
/* behaviour in which they assume that mapping the first plane of*/
/* NV12, P010, etc resources will will give them a buffer containing*/
/* both Y and UV planes contigously in vaDeriveImage and then vaMapBuffer*/
/* so, flush them all*/
struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
if (trans->base.b.usage & PIPE_MAP_WRITE) {
assert(ptrans->box.x >= 0);
range.Begin = res->base.b.target == PIPE_BUFFER ?
(unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
range.End = staging_res->base.b.width0 - range.Begin;
d3d12_bo_unmap(staging_res->bo, &range);
pipe_box original_box = ptrans->box;
for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
/* Adjust strides, offsets to the corresponding plane for the copytexture operation*/
d3d12_adjust_transfer_dimensions_for_plane(res,
plane_slice,
strides[plane_slice],
layer_strides[plane_slice],
offsets[plane_slice],
&original_box,
ptrans/*inout*/);
transfer_buf_to_image(ctx, d3d12_resource(planes[plane_slice]), staging_res, trans, 0);
}
}
pipe_resource_reference(&trans->staging_res, NULL);
} else {
struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
if (trans->base.b.usage & PIPE_MAP_WRITE) {
assert(ptrans->box.x >= 0);
range.Begin = res->base.b.target == PIPE_BUFFER ?
(unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
range.End = staging_res->base.b.width0 - range.Begin;
}
d3d12_bo_unmap(staging_res->bo, &range);
if (trans->base.b.usage & PIPE_MAP_WRITE) {
struct d3d12_context *ctx = d3d12_context(pctx);
if (res->base.b.target == PIPE_BUFFER) {
uint64_t dst_offset = trans->base.b.box.x;
uint64_t src_offset = dst_offset % BUFFER_MAP_ALIGNMENT;
transfer_buf_to_buf(ctx, staging_res, res, src_offset, dst_offset, ptrans->box.width);
} else
transfer_buf_to_image(ctx, res, staging_res, trans, 0);
}
pipe_resource_reference(&trans->staging_res, NULL);
}
d3d12_bo_unmap(staging_res->bo, &range);
if (trans->base.b.usage & PIPE_MAP_WRITE) {
struct d3d12_context *ctx = d3d12_context(pctx);
if (res->base.b.target == PIPE_BUFFER) {
uint64_t dst_offset = trans->base.b.box.x;
uint64_t src_offset = dst_offset % BUFFER_MAP_ALIGNMENT;
transfer_buf_to_buf(ctx, staging_res, res, src_offset, dst_offset, ptrans->box.width);
} else
transfer_buf_to_image(ctx, res, staging_res, trans, 0);
}
pipe_resource_reference(&trans->staging_res, NULL);
} else {
if (trans->base.b.usage & PIPE_MAP_WRITE) {
range.Begin = ptrans->box.x;

View File

@@ -45,6 +45,8 @@ struct d3d12_resource {
struct d3d12_bo *bo;
DXGI_FORMAT dxgi_format;
enum pipe_format overall_format;
unsigned int plane_slice;
struct pipe_resource* first_plane;
unsigned mip_levels;
struct sw_displaytarget *dt;
unsigned dt_stride;
@@ -127,4 +129,8 @@ d3d12_screen_resource_init(struct pipe_screen *pscreen);
void
d3d12_context_resource_init(struct pipe_context *pctx);
struct pipe_resource *
d3d12_resource_from_resource(struct pipe_screen *pscreen,
ID3D12Resource* inputRes);
#endif

View File

@@ -194,7 +194,7 @@ initialize_rtv(struct pipe_context *pctx,
tpl->u.tex.first_layer);
desc.Texture2D.MipSlice = tpl->u.tex.level;
desc.Texture2D.PlaneSlice = 0;
desc.Texture2D.PlaneSlice = res->plane_slice;
break;
case D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY: