Mesa (main): vulkan: add vk_spec_info_to_nir_spirv util method

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Jul 29 03:47:46 UTC 2021


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

Author: Alejandro Piñeiro <apinheiro at igalia.com>
Date:   Wed Jul 21 10:36:38 2021 +0200

vulkan: add vk_spec_info_to_nir_spirv util method

All vulkan drivers have been copying anv's code to convert
VkSpecializationInfo into nir_spirv_specialization.

Recently there was a Vulkan spec change on allowed values for
VkSpecializationInfo, and all drivers got affected.

This commits creates a new helper, and uses it on all Vulkan Mesa
drivers.

v2: use (uint8_t*) castings, instead of void*, to avoid C2036 with
    MSVC (detected by the CI, inspired on what radv was doing)

Reviewed-by: Samuel Pitoiset <samuel.pitoiset at gmail.com>
Reviewed-by: Jason Ekstrand <jason at jlekstrand.net>
Reviewed-by: Samuel Iglesias Gonsálvez <siglesias at igalia.com>
Reviewed-by: Boris Brezillon <boris.brezillon at collabora.com>
Reviewed-By: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Reviewed-by: Juan A. Suarez <jasuarez at igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12047>

---

 src/amd/vulkan/radv_shader.c                  | 51 +---------------------
 src/broadcom/vulkan/v3dv_pipeline.c           | 42 ------------------
 src/freedreno/vulkan/tu_shader.c              | 35 +--------------
 src/gallium/frontends/lavapipe/lvp_pipeline.c | 34 ++-------------
 src/intel/vulkan/anv_pipeline.c               | 50 +--------------------
 src/panfrost/vulkan/panvk_shader.c            | 38 ++--------------
 src/vulkan/util/meson.build                   |  2 +-
 src/vulkan/util/vk_util.c                     | 62 +++++++++++++++++++++++++++
 src/vulkan/util/vk_util.h                     |  6 +++
 9 files changed, 82 insertions(+), 238 deletions(-)

diff --git a/src/amd/vulkan/radv_shader.c b/src/amd/vulkan/radv_shader.c
index 513ec560a5e..c9f402870d8 100644
--- a/src/amd/vulkan/radv_shader.c
+++ b/src/amd/vulkan/radv_shader.c
@@ -461,55 +461,8 @@ radv_shader_compile_to_nir(struct radv_device *device, struct vk_shader_module *
          radv_print_spirv(module->data, module->size, stderr);
 
       uint32_t num_spec_entries = 0;
-      struct nir_spirv_specialization *spec_entries = NULL;
-      if (spec_info && spec_info->mapEntryCount > 0) {
-         num_spec_entries = spec_info->mapEntryCount;
-         spec_entries = calloc(num_spec_entries, sizeof(*spec_entries));
-         for (uint32_t i = 0; i < num_spec_entries; i++) {
-            VkSpecializationMapEntry entry = spec_info->pMapEntries[i];
-            const void *data = (uint8_t *)spec_info->pData + entry.offset;
-            assert((uint8_t *)data + entry.size <=
-                   (uint8_t *)spec_info->pData + spec_info->dataSize);
-
-            spec_entries[i].id = spec_info->pMapEntries[i].constantID;
-            switch (entry.size) {
-            case 8:
-               memcpy(&spec_entries[i].value.u64, data, sizeof(uint64_t));
-               break;
-            case 4:
-               memcpy(&spec_entries[i].value.u32, data, sizeof(uint32_t));
-               break;
-            case 2:
-               memcpy(&spec_entries[i].value.u16, data, sizeof(uint16_t));
-               break;
-            case 1:
-               memcpy(&spec_entries[i].value.u8, data, sizeof(uint8_t));
-               break;
-            case 0:
-               /* The Vulkan spec says:
-                *
-                *    "For a constantID specialization constant declared in a shader, size must match
-                *    the byte size of the constantID. If the specialization constant is of type
-                *    boolean, size must be the byte size of VkBool32."
-                *
-                * Therefore, since only scalars can be decorated as specialization constants, we can
-                * assume that if it doesn't have a size of 1, 2, 4, or 8, any use in a shader would
-                * be invalid usage.  The spec further says:
-                *
-                *    "If a constantID value is not a specialization constant ID used in the shader,
-                *    that map entry does not affect the behavior of the pipeline."
-                *
-                * so we should ignore any invalid specialization constants rather than crash or
-                * error out when we see one.
-                */
-               break;
-            default:
-               assert(!"Invalid spec constant size");
-               break;
-            }
-         }
-      }
-
+      struct nir_spirv_specialization *spec_entries =
+         vk_spec_info_to_nir_spirv(spec_info, &num_spec_entries);
       struct radv_shader_debug_data spirv_debug_data = {
          .device = device,
          .module = module,
diff --git a/src/broadcom/vulkan/v3dv_pipeline.c b/src/broadcom/vulkan/v3dv_pipeline.c
index d4e673163bd..4447e4d0d84 100644
--- a/src/broadcom/vulkan/v3dv_pipeline.c
+++ b/src/broadcom/vulkan/v3dv_pipeline.c
@@ -426,48 +426,6 @@ preprocess_nir(nir_shader *nir)
    nir_optimize(nir, false);
 }
 
-/* FIXME: This is basically the same code at anv, tu and radv. Move to common
- * place?
- */
-static struct nir_spirv_specialization*
-vk_spec_info_to_nir_spirv(const VkSpecializationInfo *spec_info,
-                          uint32_t *out_num_spec_entries)
-{
-   if (spec_info == NULL || spec_info->mapEntryCount == 0)
-      return NULL;
-
-   uint32_t num_spec_entries = spec_info->mapEntryCount;
-   struct nir_spirv_specialization *spec_entries = calloc(num_spec_entries, sizeof(*spec_entries));
-
-   for (uint32_t i = 0; i < num_spec_entries; i++) {
-      VkSpecializationMapEntry entry = spec_info->pMapEntries[i];
-      const void *data = spec_info->pData + entry.offset;
-      assert(data + entry.size <= spec_info->pData + spec_info->dataSize);
-
-      spec_entries[i].id = spec_info->pMapEntries[i].constantID;
-      switch (entry.size) {
-      case 8:
-         spec_entries[i].value.u64 = *(const uint64_t *)data;
-         break;
-      case 4:
-         spec_entries[i].value.u32 = *(const uint32_t *)data;
-         break;
-      case 2:
-         spec_entries[i].value.u16 = *(const uint16_t *)data;
-         break;
-      case 1:
-         spec_entries[i].value.u8 = *(const uint8_t *)data;
-         break;
-      default:
-         assert(!"Invalid spec constant size");
-         break;
-      }
-   }
-
-   *out_num_spec_entries = num_spec_entries;
-   return spec_entries;
-}
-
 static nir_shader *
 shader_module_compile_to_nir(struct v3dv_device *device,
                              struct v3dv_pipeline_stage *stage)
diff --git a/src/freedreno/vulkan/tu_shader.c b/src/freedreno/vulkan/tu_shader.c
index 1530d07c296..578bcdb041c 100644
--- a/src/freedreno/vulkan/tu_shader.c
+++ b/src/freedreno/vulkan/tu_shader.c
@@ -95,40 +95,9 @@ tu_spirv_to_nir(struct tu_device *dev,
 
    /* convert VkSpecializationInfo */
    const VkSpecializationInfo *spec_info = stage_info->pSpecializationInfo;
-   struct nir_spirv_specialization *spec = NULL;
    uint32_t num_spec = 0;
-   if (spec_info && spec_info->mapEntryCount) {
-      spec = calloc(spec_info->mapEntryCount, sizeof(*spec));
-      if (!spec)
-         return NULL;
-
-      for (uint32_t i = 0; i < spec_info->mapEntryCount; i++) {
-         const VkSpecializationMapEntry *entry = &spec_info->pMapEntries[i];
-         const void *data = spec_info->pData + entry->offset;
-         assert(data + entry->size <= spec_info->pData + spec_info->dataSize);
-         spec[i].id = entry->constantID;
-         switch (entry->size) {
-         case 8:
-            spec[i].value.u64 = *(const uint64_t *)data;
-            break;
-         case 4:
-            spec[i].value.u32 = *(const uint32_t *)data;
-            break;
-         case 2:
-            spec[i].value.u16 = *(const uint16_t *)data;
-            break;
-         case 1:
-            spec[i].value.u8 = *(const uint8_t *)data;
-            break;
-         default:
-            assert(!"Invalid spec constant size");
-            break;
-         }
-         spec[i].defined_on_module = false;
-      }
-
-      num_spec = spec_info->mapEntryCount;
-   }
+   struct nir_spirv_specialization *spec =
+      vk_spec_info_to_nir_spirv(spec_info, &num_spec);
 
    struct vk_shader_module *module =
       vk_shader_module_from_handle(stage_info->module);
diff --git a/src/gallium/frontends/lavapipe/lvp_pipeline.c b/src/gallium/frontends/lavapipe/lvp_pipeline.c
index 899587baec1..8be8701d9df 100644
--- a/src/gallium/frontends/lavapipe/lvp_pipeline.c
+++ b/src/gallium/frontends/lavapipe/lvp_pipeline.c
@@ -441,37 +441,9 @@ lvp_shader_compile_to_ir(struct lvp_pipeline *pipeline,
    assert(module->size % 4 == 0);
 
    uint32_t num_spec_entries = 0;
-   struct nir_spirv_specialization *spec_entries = NULL;
-   if (spec_info && spec_info->mapEntryCount > 0) {
-      num_spec_entries = spec_info->mapEntryCount;
-      spec_entries = calloc(num_spec_entries, sizeof(*spec_entries));
-      for (uint32_t i = 0; i < num_spec_entries; i++) {
-         VkSpecializationMapEntry entry = spec_info->pMapEntries[i];
-         const void *data =
-            (char *)spec_info->pData + entry.offset;
-         assert((const char *)((char *)data + entry.size) <=
-                (char *)spec_info->pData + spec_info->dataSize);
-
-         spec_entries[i].id = entry.constantID;
-         switch (entry.size) {
-         case 8:
-            spec_entries[i].value.u64 = *(const uint64_t *)data;
-            break;
-         case 4:
-            spec_entries[i].value.u32 = *(const uint32_t *)data;
-            break;
-         case 2:
-            spec_entries[i].value.u16 = *(const uint16_t *)data;
-            break;
-         case 1:
-            spec_entries[i].value.u8 = *(const uint8_t *)data;
-            break;
-         default:
-            assert(!"Invalid spec constant size");
-            break;
-         }
-      }
-   }
+   struct nir_spirv_specialization *spec_entries =
+      vk_spec_info_to_nir_spirv(spec_info, &num_spec_entries);
+
    struct lvp_device *pdevice = pipeline->device;
    const struct spirv_to_nir_options spirv_options = {
       .environment = NIR_SPIRV_VULKAN,
diff --git a/src/intel/vulkan/anv_pipeline.c b/src/intel/vulkan/anv_pipeline.c
index a3349a591b5..845976f4170 100644
--- a/src/intel/vulkan/anv_pipeline.c
+++ b/src/intel/vulkan/anv_pipeline.c
@@ -94,54 +94,8 @@ anv_shader_compile_to_nir(struct anv_device *device,
    assert(module->size % 4 == 0);
 
    uint32_t num_spec_entries = 0;
-   struct nir_spirv_specialization *spec_entries = NULL;
-   if (spec_info && spec_info->mapEntryCount > 0) {
-      num_spec_entries = spec_info->mapEntryCount;
-      spec_entries = calloc(num_spec_entries, sizeof(*spec_entries));
-      for (uint32_t i = 0; i < num_spec_entries; i++) {
-         VkSpecializationMapEntry entry = spec_info->pMapEntries[i];
-         const void *data = spec_info->pData + entry.offset;
-         assert(data + entry.size <= spec_info->pData + spec_info->dataSize);
-
-         spec_entries[i].id = spec_info->pMapEntries[i].constantID;
-         switch (entry.size) {
-         case 8:
-            spec_entries[i].value.u64 = *(const uint64_t *)data;
-            break;
-         case 4:
-            spec_entries[i].value.u32 = *(const uint32_t *)data;
-            break;
-         case 2:
-            spec_entries[i].value.u16 = *(const uint16_t *)data;
-            break;
-         case 1:
-            spec_entries[i].value.u8 = *(const uint8_t *)data;
-            break;
-         case 0:
-         default:
-            /* The Vulkan spec says:
-             *
-             *    "For a constantID specialization constant declared in a
-             *    shader, size must match the byte size of the constantID. If
-             *    the specialization constant is of type boolean, size must be
-             *    the byte size of VkBool32."
-             *
-             * Therefore, since only scalars can be decorated as
-             * specialization constants, we can assume that if it doesn't have
-             * a size of 1, 2, 4, or 8, any use in a shader would be invalid
-             * usage.  The spec further says:
-             *
-             *    "If a constantID value is not a specialization constant ID
-             *    used in the shader, that map entry does not affect the
-             *    behavior of the pipeline."
-             *
-             * so we should ignore any invalid specialization constants rather
-             * than crash or error out when we see one.
-             */
-            break;
-         }
-      }
-   }
+   struct nir_spirv_specialization *spec_entries =
+      vk_spec_info_to_nir_spirv(spec_info, &num_spec_entries);
 
    struct anv_spirv_debug_data spirv_debug_data = {
       .device = device,
diff --git a/src/panfrost/vulkan/panvk_shader.c b/src/panfrost/vulkan/panvk_shader.c
index 756ad24e011..a34e7f50da8 100644
--- a/src/panfrost/vulkan/panvk_shader.c
+++ b/src/panfrost/vulkan/panvk_shader.c
@@ -34,6 +34,8 @@
 #include "panfrost-quirks.h"
 #include "pan_shader.h"
 
+#include "vk_util.h"
+
 static nir_shader *
 panvk_spirv_to_nir(const void *code,
                    size_t codesize,
@@ -50,41 +52,9 @@ panvk_spirv_to_nir(const void *code,
    };
 
    /* convert VkSpecializationInfo */
-   struct nir_spirv_specialization *spec = NULL;
    uint32_t num_spec = 0;
-   if (spec_info && spec_info->mapEntryCount) {
-      spec = malloc(sizeof(*spec) * spec_info->mapEntryCount);
-      if (!spec)
-         return NULL;
-
-      for (uint32_t i = 0; i < spec_info->mapEntryCount; i++) {
-         const VkSpecializationMapEntry *entry = &spec_info->pMapEntries[i];
-         const void *data = spec_info->pData + entry->offset;
-         assert(data + entry->size <= spec_info->pData + spec_info->dataSize);
-         spec[i].id = entry->constantID;
-         switch (entry->size) {
-         case 8:
-            spec[i].value.u64 = *(const uint64_t *)data;
-            break;
-         case 4:
-            spec[i].value.u32 = *(const uint32_t *)data;
-            break;
-         case 2:
-            spec[i].value.u16 = *(const uint16_t *)data;
-            break;
-         case 1:
-            spec[i].value.u8 = *(const uint8_t *)data;
-            break;
-         default:
-            assert(!"Invalid spec constant size");
-            break;
-         }
-
-         spec[i].defined_on_module = false;
-      }
-
-      num_spec = spec_info->mapEntryCount;
-   }
+   struct nir_spirv_specialization *spec =
+      vk_spec_info_to_nir_spirv(spec_info, &num_spec);
 
    nir_shader *nir = spirv_to_nir(code, codesize / sizeof(uint32_t), spec,
                                   num_spec, stage, entry_point_name,
diff --git a/src/vulkan/util/meson.build b/src/vulkan/util/meson.build
index 3865d68f6c0..d8089775a88 100644
--- a/src/vulkan/util/meson.build
+++ b/src/vulkan/util/meson.build
@@ -113,7 +113,7 @@ libvulkan_util = static_library(
   [files_vulkan_util, vk_common_entrypoints, vk_dispatch_table,
    vk_enum_to_str, vk_extensions],
   include_directories : [inc_include, inc_src, inc_gallium],
-  dependencies : [vulkan_wsi_deps, idep_mesautil],
+  dependencies : [vulkan_wsi_deps, idep_mesautil, idep_nir_headers],
   # For glsl_type_singleton
   link_with : libcompiler,
   c_args : [vulkan_wsi_args],
diff --git a/src/vulkan/util/vk_util.c b/src/vulkan/util/vk_util.c
index 116a78fa212..68d444e1607 100644
--- a/src/vulkan/util/vk_util.c
+++ b/src/vulkan/util/vk_util.c
@@ -29,6 +29,8 @@
 #include "vk_util.h"
 #include "util/debug.h"
 
+#include "compiler/spirv/nir_spirv.h"
+
 uint32_t vk_get_driver_version(void)
 {
    const char *minor_string = strchr(PACKAGE_VERSION, '.');
@@ -79,3 +81,63 @@ vk_warn_non_conformant_implementation(const char *driver_name)
    fprintf(stderr, "WARNING: %s is not a conformant Vulkan implementation, "
                    "testing use only.\n", driver_name);
 }
+
+struct nir_spirv_specialization*
+vk_spec_info_to_nir_spirv(const VkSpecializationInfo *spec_info,
+                          uint32_t *out_num_spec_entries)
+{
+   if (spec_info == NULL || spec_info->mapEntryCount == 0)
+      return NULL;
+
+   uint32_t num_spec_entries = spec_info->mapEntryCount;
+   struct nir_spirv_specialization *spec_entries =
+      calloc(num_spec_entries, sizeof(*spec_entries));
+
+   for (uint32_t i = 0; i < num_spec_entries; i++) {
+      VkSpecializationMapEntry entry = spec_info->pMapEntries[i];
+      const void *data = (uint8_t *)spec_info->pData + entry.offset;
+      assert((uint8_t *)data + entry.size <=
+             (uint8_t *)spec_info->pData + spec_info->dataSize);
+
+      spec_entries[i].id = spec_info->pMapEntries[i].constantID;
+      switch (entry.size) {
+      case 8:
+         spec_entries[i].value.u64 = *(const uint64_t *)data;
+         break;
+      case 4:
+         spec_entries[i].value.u32 = *(const uint32_t *)data;
+         break;
+      case 2:
+         spec_entries[i].value.u16 = *(const uint16_t *)data;
+         break;
+      case 1:
+         spec_entries[i].value.u8 = *(const uint8_t *)data;
+         break;
+      case 0:
+      default:
+         /* The Vulkan spec says:
+          *
+          *    "For a constantID specialization constant declared in a
+          *    shader, size must match the byte size of the constantID. If
+          *    the specialization constant is of type boolean, size must be
+          *    the byte size of VkBool32."
+          *
+          * Therefore, since only scalars can be decorated as
+          * specialization constants, we can assume that if it doesn't have
+          * a size of 1, 2, 4, or 8, any use in a shader would be invalid
+          * usage.  The spec further says:
+          *
+          *    "If a constantID value is not a specialization constant ID
+          *    used in the shader, that map entry does not affect the
+          *    behavior of the pipeline."
+          *
+          * so we should ignore any invalid specialization constants rather
+          * than crash or error out when we see one.
+          */
+         break;
+      }
+   }
+
+   *out_num_spec_entries = num_spec_entries;
+   return spec_entries;
+}
diff --git a/src/vulkan/util/vk_util.h b/src/vulkan/util/vk_util.h
index 30132338944..5dbce23b53e 100644
--- a/src/vulkan/util/vk_util.h
+++ b/src/vulkan/util/vk_util.h
@@ -272,6 +272,12 @@ mesa_to_vk_shader_stage(gl_shader_stage mesa_stage)
         (_i)++, (_draw) = (const VkMultiDrawInfoEXT*)((const uint8_t*)(_draw) + (_stride)))
 
 
+struct nir_spirv_specialization;
+
+struct nir_spirv_specialization*
+vk_spec_info_to_nir_spirv(const VkSpecializationInfo *spec_info,
+                          uint32_t *out_num_spec_entries);
+
 #ifdef __cplusplus
 }
 #endif



More information about the mesa-commit mailing list