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:
@@ -199,6 +199,52 @@ d3d12_get_typeless_format(enum pipe_format format)
|
||||
return typeless_formats[format];
|
||||
}
|
||||
|
||||
enum pipe_format
|
||||
d3d12_get_pipe_format(DXGI_FORMAT format)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(formats); ++i) {
|
||||
if (formats[i] == format) {
|
||||
return (enum pipe_format)i;
|
||||
}
|
||||
}
|
||||
return PIPE_FORMAT_NONE;
|
||||
}
|
||||
|
||||
enum pipe_format
|
||||
d3d12_get_default_pipe_format(DXGI_FORMAT format)
|
||||
{
|
||||
#define TYPELESS_TO(channels, suffix) \
|
||||
case DXGI_FORMAT_##channels##_TYPELESS: \
|
||||
return PIPE_FORMAT_##channels##_##suffix
|
||||
|
||||
switch (format) {
|
||||
TYPELESS_TO(R8, UNORM);
|
||||
TYPELESS_TO(R8G8, UNORM);
|
||||
TYPELESS_TO(R8G8B8A8, UNORM);
|
||||
TYPELESS_TO(B8G8R8X8, UNORM);
|
||||
TYPELESS_TO(B8G8R8A8, UNORM);
|
||||
TYPELESS_TO(R16, FLOAT);
|
||||
TYPELESS_TO(R16G16, FLOAT);
|
||||
TYPELESS_TO(R16G16B16A16, FLOAT);
|
||||
TYPELESS_TO(R32, FLOAT);
|
||||
TYPELESS_TO(R32G32, FLOAT);
|
||||
TYPELESS_TO(R32G32B32, FLOAT);
|
||||
TYPELESS_TO(R32G32B32A32, FLOAT);
|
||||
case DXGI_FORMAT_BC1_TYPELESS:
|
||||
return PIPE_FORMAT_DXT1_RGBA;
|
||||
case DXGI_FORMAT_BC2_TYPELESS:
|
||||
return PIPE_FORMAT_DXT3_RGBA;
|
||||
case DXGI_FORMAT_BC3_TYPELESS:
|
||||
return PIPE_FORMAT_DXT5_RGBA;
|
||||
case DXGI_FORMAT_BC4_TYPELESS:
|
||||
return PIPE_FORMAT_RGTC1_UNORM;
|
||||
case DXGI_FORMAT_BC5_TYPELESS:
|
||||
return PIPE_FORMAT_RGTC2_UNORM;
|
||||
default:
|
||||
return PIPE_FORMAT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
DXGI_FORMAT
|
||||
d3d12_get_resource_rt_format(enum pipe_format f)
|
||||
{
|
||||
|
@@ -39,6 +39,13 @@ d3d12_get_format(enum pipe_format format);
|
||||
DXGI_FORMAT
|
||||
d3d12_get_typeless_format(enum pipe_format format);
|
||||
|
||||
/* These two are only used for importing external resources without a provided template */
|
||||
enum pipe_format
|
||||
d3d12_get_pipe_format(DXGI_FORMAT format);
|
||||
|
||||
enum pipe_format
|
||||
d3d12_get_default_pipe_format(DXGI_FORMAT format);
|
||||
|
||||
DXGI_FORMAT
|
||||
d3d12_get_resource_srv_format(enum pipe_format f, enum pipe_texture_target target);
|
||||
|
||||
|
@@ -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