d3d12: Validate opened D3D12 resource matches pipe template

Unlike Linux dma-bufs, D3D12 resources are strongly typed, and
can't necessarily just reinterpret the memory arbitrarily.

Allow importing resources with no description coming from the frontend,
and populate the resource desc from the driver instead. If there was
a template, make sure that it matches the incoming resource.

Reviewed-by: Bill Kristiansen <billkris@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13054>
This commit is contained in:
Jesse Natalie
2021-09-22 14:47:50 -07:00
committed by Marge Bot
parent 9740141b2e
commit b8f41c5c4e
3 changed files with 178 additions and 9 deletions

View File

@@ -306,16 +306,14 @@ d3d12_resource_from_handle(struct pipe_screen *pscreen,
if (!res)
return NULL;
res->base.b = *templ;
pipe_reference_init(&res->base.b.reference, 1);
res->base.b.screen = pscreen;
res->dxgi_format = templ->target == PIPE_BUFFER ? DXGI_FORMAT_UNKNOWN :
d3d12_get_format(templ->format);
ID3D12Resource *d3d12_res = nullptr;
if (handle->type == WINSYS_HANDLE_TYPE_D3D12_RES) {
res->bo = d3d12_bo_wrap_res((ID3D12Resource *)handle->com_obj, templ->format);
d3d12_res = (ID3D12Resource *)handle->com_obj;
} else {
struct d3d12_screen *screen = d3d12_screen(pscreen);
ID3D12Resource *d3d12_res = nullptr;
#ifdef _WIN32
HANDLE d3d_handle = handle->handle;
@@ -323,16 +321,134 @@ d3d12_resource_from_handle(struct pipe_screen *pscreen,
HANDLE d3d_handle = (HANDLE)(intptr_t)handle->handle;
#endif
screen->dev->OpenSharedHandle(d3d_handle, IID_PPV_ARGS(&d3d12_res));
if (!d3d12_res) {
FREE(res);
return NULL;
}
D3D12_RESOURCE_DESC incoming_res_desc;
if (!d3d12_res)
goto invalid;
incoming_res_desc = d3d12_res->GetDesc();
if (incoming_res_desc.Width > UINT32_MAX ||
incoming_res_desc.Height > UINT16_MAX) {
debug_printf("d3d12: Importing resource too large\n");
goto invalid;
}
res->base.b.width0 = incoming_res_desc.Width;
res->base.b.height0 = incoming_res_desc.Height;
res->base.b.depth0 = 1;
res->base.b.array_size = 1;
switch (incoming_res_desc.Dimension) {
case D3D12_RESOURCE_DIMENSION_BUFFER:
res->base.b.target = PIPE_BUFFER;
res->base.b.bind = PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_CONSTANT_BUFFER |
PIPE_BIND_INDEX_BUFFER | PIPE_BIND_STREAM_OUTPUT | PIPE_BIND_SHADER_BUFFER |
PIPE_BIND_COMMAND_ARGS_BUFFER | PIPE_BIND_QUERY_BUFFER;
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
res->base.b.target = incoming_res_desc.DepthOrArraySize > 1 ?
PIPE_TEXTURE_1D_ARRAY : PIPE_TEXTURE_1D;
res->base.b.array_size = incoming_res_desc.DepthOrArraySize;
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
res->base.b.target = incoming_res_desc.DepthOrArraySize > 1 ?
PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D;
res->base.b.array_size = incoming_res_desc.DepthOrArraySize;
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
res->base.b.target = PIPE_TEXTURE_3D;
res->base.b.depth0 = incoming_res_desc.DepthOrArraySize;
break;
default:
unreachable("Invalid dimension");
break;
}
res->base.b.nr_samples = incoming_res_desc.SampleDesc.Count;
res->base.b.last_level = incoming_res_desc.MipLevels - 1;
res->base.b.usage = PIPE_USAGE_DEFAULT;
if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
res->base.b.bind |= PIPE_BIND_RENDER_TARGET | PIPE_BIND_BLENDABLE | PIPE_BIND_DISPLAY_TARGET;
if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
res->base.b.bind |= PIPE_BIND_DEPTH_STENCIL;
if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
res->base.b.bind |= PIPE_BIND_SHADER_IMAGE;
if ((incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE) == D3D12_RESOURCE_FLAG_NONE)
res->base.b.bind |= PIPE_BIND_SAMPLER_VIEW;
if (templ) {
if (res->base.b.target == PIPE_TEXTURE_2D_ARRAY &&
(templ->target == PIPE_TEXTURE_CUBE ||
templ->target == PIPE_TEXTURE_CUBE_ARRAY)) {
if (res->base.b.array_size < 6) {
debug_printf("d3d12: Importing cube resource with too few array layers\n");
goto invalid;
}
res->base.b.target = templ->target;
res->base.b.array_size /= 6;
}
unsigned templ_samples = MAX2(templ->nr_samples, 1);
if (res->base.b.target != templ->target ||
res->base.b.width0 != templ->width0 ||
res->base.b.height0 != templ->height0 ||
res->base.b.depth0 != templ->depth0 ||
res->base.b.array_size != templ->array_size ||
incoming_res_desc.SampleDesc.Count != templ_samples ||
res->base.b.last_level != templ->last_level) {
debug_printf("d3d12: Importing resource with mismatched dimensions: "
"plane: %d, target: %d vs %d, width: %d vs %d, height: %d vs %d, "
"depth: %d vs %d, array_size: %d vs %d, samples: %d vs %d, mips: %d vs %d\n",
handle->plane,
res->base.b.target, templ->target,
res->base.b.width0, templ->width0,
res->base.b.height0, templ->height0,
res->base.b.depth0, templ->depth0,
res->base.b.array_size, templ->array_size,
incoming_res_desc.SampleDesc.Count, templ_samples,
res->base.b.last_level + 1, templ->last_level + 1);
goto invalid;
}
if (incoming_res_desc.Format != d3d12_get_format(templ->format) &&
incoming_res_desc.Format != d3d12_get_typeless_format(templ->format)) {
debug_printf("d3d12: Importing resource with mismatched format: "
"could be DXGI format %d or %d, but is %d\n",
d3d12_get_format(templ->format),
d3d12_get_typeless_format(templ->format),
incoming_res_desc.Format);
goto invalid;
}
if (templ->bind & ~res->base.b.bind) {
debug_printf("d3d12: Imported resource doesn't have necessary bind flags\n");
goto invalid;
}
res->bo = d3d12_bo_wrap_res(d3d12_res, templ->format);
res->base.b.format = templ->format;
} else {
/* Search the pipe format lookup table for an entry */
res->base.b.format = d3d12_get_pipe_format(incoming_res_desc.Format);
if (res->base.b.format == PIPE_FORMAT_NONE) {
/* Convert from typeless to a reasonable default */
res->base.b.format = d3d12_get_default_pipe_format(incoming_res_desc.Format);
if (res->base.b.format == PIPE_FORMAT_NONE) {
debug_printf("d3d12: Unable to deduce non-typeless resource format %d\n", incoming_res_desc.Format);
goto invalid;
}
}
}
res->dxgi_format = d3d12_get_format(res->base.b.format);
res->bo = d3d12_bo_wrap_res(d3d12_res, res->base.b.format);
init_valid_range(res);
threaded_resource_init(&res->base.b, false, 0);
return &res->base.b;
invalid:
if (d3d12_res)
d3d12_res->Release();
FREE(res);
return NULL;
}
static bool