anv/pipeline: Add skeleton support for spilling to bindless
authorJason Ekstrand <jason.ekstrand@intel.com>
Mon, 25 Feb 2019 19:59:07 +0000 (13:59 -0600)
committerJason Ekstrand <jason@jlekstrand.net>
Fri, 19 Apr 2019 19:56:42 +0000 (19:56 +0000)
If the number of surfaces or samplers exceeds what we can put in a
table, we will want to spill out to bindless.  There is no bindless
support yet but this gets us the basic framework that will be used by
later commits.

Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
src/intel/vulkan/anv_descriptor_set.c
src/intel/vulkan/anv_device.c
src/intel/vulkan/anv_nir_apply_pipeline_layout.c
src/intel/vulkan/anv_private.h

index 004d3f2f77f80d02d77cf05fa11dc430ac7fcaf7..90a02997a8dcc00fa15047771e23f8b7a3da199c 100644 (file)
@@ -125,22 +125,60 @@ anv_descriptor_type_size(const struct anv_physical_device *pdevice,
    return anv_descriptor_data_size(anv_descriptor_data_for_type(pdevice, type));
 }
 
+static bool
+anv_descriptor_data_supports_bindless(const struct anv_physical_device *pdevice,
+                                      enum anv_descriptor_data data,
+                                      bool sampler)
+{
+   return false;
+}
+
+bool
+anv_descriptor_supports_bindless(const struct anv_physical_device *pdevice,
+                                 const struct anv_descriptor_set_binding_layout *binding,
+                                 bool sampler)
+{
+   return anv_descriptor_data_supports_bindless(pdevice, binding->data,
+                                                sampler);
+}
+
+bool
+anv_descriptor_requires_bindless(const struct anv_physical_device *pdevice,
+                                 const struct anv_descriptor_set_binding_layout *binding,
+                                 bool sampler)
+{
+   if (pdevice->always_use_bindless)
+      return anv_descriptor_supports_bindless(pdevice, binding, sampler);
+
+   return false;
+}
+
 void anv_GetDescriptorSetLayoutSupport(
-    VkDevice                                    device,
+    VkDevice                                    _device,
     const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
     VkDescriptorSetLayoutSupport*               pSupport)
 {
+   ANV_FROM_HANDLE(anv_device, device, _device);
+   const struct anv_physical_device *pdevice =
+      &device->instance->physicalDevice;
+
    uint32_t surface_count[MESA_SHADER_STAGES] = { 0, };
 
    for (uint32_t b = 0; b < pCreateInfo->bindingCount; b++) {
       const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[b];
 
+      enum anv_descriptor_data desc_data =
+         anv_descriptor_data_for_type(pdevice, binding->descriptorType);
+
       switch (binding->descriptorType) {
       case VK_DESCRIPTOR_TYPE_SAMPLER:
          /* There is no real limit on samplers */
          break;
 
       case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+         if (anv_descriptor_data_supports_bindless(pdevice, desc_data, false))
+            break;
+
          if (binding->pImmutableSamplers) {
             for (uint32_t i = 0; i < binding->descriptorCount; i++) {
                ANV_FROM_HANDLE(anv_sampler, sampler,
@@ -155,6 +193,9 @@ void anv_GetDescriptorSetLayoutSupport(
          break;
 
       default:
+         if (anv_descriptor_data_supports_bindless(pdevice, desc_data, false))
+            break;
+
          anv_foreach_stage(s, binding->stageFlags)
             surface_count[s] += binding->descriptorCount;
          break;
index 71de8865986752212fc8c172ab8a21f2ec256b0e..2f1260dae2f8b690afac3beb5bf6cc6352b8c234 100644 (file)
@@ -276,6 +276,8 @@ anv_physical_device_init_uuids(struct anv_physical_device *device)
    _mesa_sha1_update(&sha1_ctx, build_id_data(note), build_id_len);
    _mesa_sha1_update(&sha1_ctx, &device->chipset_id,
                      sizeof(device->chipset_id));
+   _mesa_sha1_update(&sha1_ctx, &device->always_use_bindless,
+                     sizeof(device->always_use_bindless));
    _mesa_sha1_final(&sha1_ctx, sha1);
    memcpy(device->pipeline_cache_uuid, sha1, VK_UUID_SIZE);
 
@@ -451,6 +453,10 @@ anv_physical_device_init(struct anv_physical_device *device,
    device->has_context_isolation =
       anv_gem_get_param(fd, I915_PARAM_HAS_CONTEXT_ISOLATION);
 
+   device->always_use_bindless =
+      env_var_as_boolean("ANV_ALWAYS_BINDLESS", false);
+
+
    /* Starting with Gen10, the timestamp frequency of the command streamer may
     * vary from one part to another. We can query the value from the kernel.
     */
index 74f70806586ff24b31bf7fb40b49f911435f4892..ea02ed1be781d70d5d52592ef1ae9405240f73af 100644 (file)
 #include "nir/nir_builder.h"
 #include "compiler/brw_nir.h"
 
+/* Sampler tables don't actually have a maximum size but we pick one just so
+ * that we don't end up emitting too much state on-the-fly.
+ */
+#define MAX_SAMPLER_TABLE_SIZE 128
+#define BINDLESS_OFFSET        255
+
 struct apply_pipeline_layout_state {
    const struct anv_physical_device *pdevice;
 
@@ -600,11 +606,21 @@ anv_nir_apply_pipeline_layout(const struct anv_physical_device *pdevice,
                &layout->set[set].layout->binding[b];
 
          /* Do a fixed-point calculation to generate a score based on the
-          * number of uses and the binding array size.
+          * number of uses and the binding array size.  We shift by 7 instead
+          * of 8 because we're going to use the top bit below to make
+          * everything which does not support bindless super higher priority
+          * than things which do.
           */
          uint16_t score = ((uint16_t)state.set[set].use_count[b] << 7) /
                           binding->array_size;
 
+         /* If the descriptor type doesn't support bindless then put it at the
+          * beginning so we guarantee it gets a slot.
+          */
+         if (!anv_descriptor_supports_bindless(pdevice, binding, true) ||
+             !anv_descriptor_supports_bindless(pdevice, binding, false))
+            score |= 1 << 15;
+
          infos[used_binding_count++] = (struct binding_info) {
             .set = set,
             .binding = b,
@@ -624,37 +640,57 @@ anv_nir_apply_pipeline_layout(const struct anv_physical_device *pdevice,
       struct anv_descriptor_set_binding_layout *binding =
             &layout->set[set].layout->binding[b];
 
+      const uint32_t array_size = binding->array_size;
+
       if (binding->data & ANV_DESCRIPTOR_SURFACE_STATE) {
-         state.set[set].surface_offsets[b] = map->surface_count;
-         struct anv_sampler **samplers = binding->immutable_samplers;
-         for (unsigned i = 0; i < binding->array_size; i++) {
-            uint8_t planes = samplers ? samplers[i]->n_planes : 1;
-            for (uint8_t p = 0; p < planes; p++) {
-               map->surface_to_descriptor[map->surface_count++] =
-                  (struct anv_pipeline_binding) {
-                     .set = set,
-                     .binding = b,
-                     .index = i,
-                     .plane = p,
-                  };
+         if (map->surface_count + array_size > MAX_BINDING_TABLE_SIZE ||
+             anv_descriptor_requires_bindless(pdevice, binding, false)) {
+            /* If this descriptor doesn't fit in the binding table or if it
+             * requires bindless for some reason, flag it as bindless.
+             */
+            assert(anv_descriptor_supports_bindless(pdevice, binding, false));
+            state.set[set].surface_offsets[b] = BINDLESS_OFFSET;
+         } else {
+            state.set[set].surface_offsets[b] = map->surface_count;
+            struct anv_sampler **samplers = binding->immutable_samplers;
+            for (unsigned i = 0; i < binding->array_size; i++) {
+               uint8_t planes = samplers ? samplers[i]->n_planes : 1;
+               for (uint8_t p = 0; p < planes; p++) {
+                  map->surface_to_descriptor[map->surface_count++] =
+                     (struct anv_pipeline_binding) {
+                        .set = set,
+                        .binding = b,
+                        .index = i,
+                        .plane = p,
+                     };
+               }
             }
          }
+         assert(map->surface_count <= MAX_BINDING_TABLE_SIZE);
       }
-      assert(map->surface_count <= MAX_BINDING_TABLE_SIZE);
 
       if (binding->data & ANV_DESCRIPTOR_SAMPLER_STATE) {
-         state.set[set].sampler_offsets[b] = map->sampler_count;
-         struct anv_sampler **samplers = binding->immutable_samplers;
-         for (unsigned i = 0; i < binding->array_size; i++) {
-            uint8_t planes = samplers ? samplers[i]->n_planes : 1;
-            for (uint8_t p = 0; p < planes; p++) {
-               map->sampler_to_descriptor[map->sampler_count++] =
-                  (struct anv_pipeline_binding) {
-                     .set = set,
-                     .binding = b,
-                     .index = i,
-                     .plane = p,
-                  };
+         if (map->sampler_count + array_size > MAX_SAMPLER_TABLE_SIZE ||
+             anv_descriptor_requires_bindless(pdevice, binding, true)) {
+            /* If this descriptor doesn't fit in the binding table or if it
+             * requires bindless for some reason, flag it as bindless.
+             */
+            assert(anv_descriptor_supports_bindless(pdevice, binding, true));
+            state.set[set].sampler_offsets[b] = BINDLESS_OFFSET;
+         } else {
+            state.set[set].sampler_offsets[b] = map->sampler_count;
+            struct anv_sampler **samplers = binding->immutable_samplers;
+            for (unsigned i = 0; i < binding->array_size; i++) {
+               uint8_t planes = samplers ? samplers[i]->n_planes : 1;
+               for (uint8_t p = 0; p < planes; p++) {
+                  map->sampler_to_descriptor[map->sampler_count++] =
+                     (struct anv_pipeline_binding) {
+                        .set = set,
+                        .binding = b,
+                        .index = i,
+                        .plane = p,
+                     };
+               }
             }
          }
       }
@@ -676,6 +712,9 @@ anv_nir_apply_pipeline_layout(const struct anv_physical_device *pdevice,
       if (state.set[set].use_count[binding] == 0)
          continue;
 
+      if (state.set[set].surface_offsets[binding] >= MAX_BINDING_TABLE_SIZE)
+         continue;
+
       struct anv_pipeline_binding *pipe_binding =
          &map->surface_to_descriptor[state.set[set].surface_offsets[binding]];
       for (unsigned i = 0; i < array_size; i++) {
index 5ae71b4e8c45bba7d2a465247df80cd21480e2fc..4f22a405d0d4bd33cc8fddc53ad558087da6e4ea 100644 (file)
@@ -949,6 +949,7 @@ struct anv_physical_device {
     bool                                        has_context_priority;
     bool                                        use_softpin;
     bool                                        has_context_isolation;
+    bool                                        always_use_bindless;
 
     struct anv_device_extension_table           supported_extensions;
 
@@ -1565,6 +1566,14 @@ unsigned anv_descriptor_size(const struct anv_descriptor_set_binding_layout *lay
 unsigned anv_descriptor_type_size(const struct anv_physical_device *pdevice,
                                   VkDescriptorType type);
 
+bool anv_descriptor_supports_bindless(const struct anv_physical_device *pdevice,
+                                      const struct anv_descriptor_set_binding_layout *binding,
+                                      bool sampler);
+
+bool anv_descriptor_requires_bindless(const struct anv_physical_device *pdevice,
+                                      const struct anv_descriptor_set_binding_layout *binding,
+                                      bool sampler);
+
 struct anv_descriptor_set_layout {
    /* Descriptor set layouts can be destroyed at almost any time */
    uint32_t ref_cnt;