Mesa (main): d3d12: Validate opened D3D12 resource matches pipe template

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Nov 19 23:20:52 UTC 2021


Module: Mesa
Branch: main
Commit: b8f41c5c4ee3ebe3c4082a3ddba4a41b8e788d48
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=b8f41c5c4ee3ebe3c4082a3ddba4a41b8e788d48

Author: Jesse Natalie <jenatali at microsoft.com>
Date:   Wed Sep 22 14:47:50 2021 -0700

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 at microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13054>

---

 src/gallium/drivers/d3d12/d3d12_format.c     |  46 +++++++++
 src/gallium/drivers/d3d12/d3d12_format.h     |   7 ++
 src/gallium/drivers/d3d12/d3d12_resource.cpp | 134 +++++++++++++++++++++++++--
 3 files changed, 178 insertions(+), 9 deletions(-)

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



More information about the mesa-commit mailing list