diff --git a/src/gallium/drivers/d3d12/d3d12_format.c b/src/gallium/drivers/d3d12/d3d12_format.c index ff11cab1b49..b0537a97c34 100644 --- a/src/gallium/drivers/d3d12/d3d12_format.c +++ b/src/gallium/drivers/d3d12/d3d12_format.c @@ -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) { diff --git a/src/gallium/drivers/d3d12/d3d12_format.h b/src/gallium/drivers/d3d12/d3d12_format.h index ace42ad914d..d9e0f99d8ef 100644 --- a/src/gallium/drivers/d3d12/d3d12_format.h +++ b/src/gallium/drivers/d3d12/d3d12_format.h @@ -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); diff --git a/src/gallium/drivers/d3d12/d3d12_resource.cpp b/src/gallium/drivers/d3d12/d3d12_resource.cpp index 94d8892ef4d..aa9283b0f78 100644 --- a/src/gallium/drivers/d3d12/d3d12_resource.cpp +++ b/src/gallium/drivers/d3d12/d3d12_resource.cpp @@ -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