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:
@@ -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
|
||||
|
Reference in New Issue
Block a user