[Mesa-dev] [PATCH 11/11] anv/pipeline_cache: Rework to use multialloc and blob

Jason Ekstrand jason at jlekstrand.net
Wed Oct 11 20:38:51 UTC 2017


This gets rid of all of our hand-rolled size calculation and
serialization code and replaces it with safe "standards" that are used
elsewhere in anv and mesa.  This should be significantly safer than
rolling our own.
---
 src/intel/vulkan/anv_pipeline_cache.c | 298 ++++++++++++++++------------------
 src/intel/vulkan/anv_private.h        |   2 -
 2 files changed, 141 insertions(+), 159 deletions(-)

diff --git a/src/intel/vulkan/anv_pipeline_cache.c b/src/intel/vulkan/anv_pipeline_cache.c
index c3a62f5..f782d04 100644
--- a/src/intel/vulkan/anv_pipeline_cache.c
+++ b/src/intel/vulkan/anv_pipeline_cache.c
@@ -21,81 +21,64 @@
  * IN THE SOFTWARE.
  */
 
+#include "compiler/blob.h"
 #include "util/hash_table.h"
 #include "util/debug.h"
 #include "anv_private.h"
 
-static size_t
-anv_shader_bin_size(uint32_t prog_data_size, uint32_t nr_params,
-                    uint32_t key_size,
-                    uint32_t surface_count, uint32_t sampler_count)
-{
-   const uint32_t binding_data_size =
-      (surface_count + sampler_count) * sizeof(struct anv_pipeline_binding);
-
-   return align_u32(sizeof(struct anv_shader_bin), 8) +
-          align_u32(prog_data_size, 8) +
-          align_u32(nr_params * sizeof(void *), 8) +
-          align_u32(sizeof(uint32_t) + key_size, 8) +
-          align_u32(binding_data_size, 8);
-}
-
 struct anv_shader_bin *
 anv_shader_bin_create(struct anv_device *device,
                       const void *key_data, uint32_t key_size,
                       const void *kernel_data, uint32_t kernel_size,
-                      const struct brw_stage_prog_data *prog_data,
-                      uint32_t prog_data_size, const void *prog_data_param,
+                      const struct brw_stage_prog_data *prog_data_in,
+                      uint32_t prog_data_size, const void *prog_data_param_in,
                       const struct anv_pipeline_bind_map *bind_map)
 {
-   const size_t size =
-      anv_shader_bin_size(prog_data_size, prog_data->nr_params, key_size,
-                          bind_map->surface_count, bind_map->sampler_count);
-
-   struct anv_shader_bin *shader =
-      vk_alloc(&device->alloc, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
-   if (!shader)
+   struct anv_shader_bin *shader;
+   struct anv_shader_bin_key *key;
+   struct brw_stage_prog_data *prog_data;
+   const union gl_constant_value **prog_data_param;
+   struct anv_pipeline_binding *surface_to_descriptor, *sampler_to_descriptor;
+
+   ANV_MULTIALLOC(ma);
+   anv_multialloc_add(&ma, &shader, 1);
+   anv_multialloc_add_size(&ma, &key, sizeof(*key) + key_size);
+   anv_multialloc_add_size(&ma, &prog_data, prog_data_size);
+   anv_multialloc_add(&ma, &prog_data_param, prog_data_in->nr_params);
+   anv_multialloc_add(&ma, &surface_to_descriptor,
+                           bind_map->surface_count);
+   anv_multialloc_add(&ma, &sampler_to_descriptor,
+                           bind_map->sampler_count);
+
+   if (!anv_multialloc_alloc(&ma, &device->alloc,
+                             VK_SYSTEM_ALLOCATION_SCOPE_DEVICE))
       return NULL;
 
    shader->ref_cnt = 1;
 
+   key->size = key_size;
+   memcpy(key->data, key_data, key_size);
+   shader->key = key;
+
    shader->kernel =
       anv_state_pool_alloc(&device->instruction_state_pool, kernel_size, 64);
    memcpy(shader->kernel.map, kernel_data, kernel_size);
    shader->kernel_size = kernel_size;
-   shader->bind_map = *bind_map;
-   shader->prog_data_size = prog_data_size;
-
-   /* Now we fill out the floating data at the end */
-   void *data = shader;
-   data += align_u32(sizeof(struct anv_shader_bin), 8);
 
-   shader->prog_data = data;
-   struct brw_stage_prog_data *new_prog_data = data;
-   memcpy(data, prog_data, prog_data_size);
-   data += align_u32(prog_data_size, 8);
-
-   assert(prog_data->nr_pull_params == 0);
-   assert(prog_data->nr_image_params == 0);
-   new_prog_data->param = data;
-   uint32_t param_size = prog_data->nr_params * sizeof(void *);
-   memcpy(data, prog_data_param, param_size);
-   data += align_u32(param_size, 8);
-
-   shader->key = data;
-   struct anv_shader_bin_key *key = data;
-   key->size = key_size;
-   memcpy(key->data, key_data, key_size);
-   data += align_u32(sizeof(*key) + key_size, 8);
-
-   shader->bind_map.surface_to_descriptor = data;
-   memcpy(data, bind_map->surface_to_descriptor,
-          bind_map->surface_count * sizeof(struct anv_pipeline_binding));
-   data += bind_map->surface_count * sizeof(struct anv_pipeline_binding);
+   memcpy(prog_data, prog_data_in, prog_data_size);
+   memcpy(prog_data_param, prog_data_param_in,
+          prog_data->nr_params * sizeof(*prog_data_param));
+   prog_data->param = prog_data_param;
+   shader->prog_data = prog_data;
+   shader->prog_data_size = prog_data_size;
 
-   shader->bind_map.sampler_to_descriptor = data;
-   memcpy(data, bind_map->sampler_to_descriptor,
-          bind_map->sampler_count * sizeof(struct anv_pipeline_binding));
+   shader->bind_map = *bind_map;
+   typed_memcpy(surface_to_descriptor, bind_map->surface_to_descriptor,
+                bind_map->surface_count);
+   shader->bind_map.surface_to_descriptor = surface_to_descriptor;
+   typed_memcpy(sampler_to_descriptor, bind_map->sampler_to_descriptor,
+                bind_map->sampler_count);
+   shader->bind_map.sampler_to_descriptor = sampler_to_descriptor;
 
    return shader;
 }
@@ -109,29 +92,74 @@ anv_shader_bin_destroy(struct anv_device *device,
    vk_free(&device->alloc, shader);
 }
 
-static size_t
-anv_shader_bin_data_size(const struct anv_shader_bin *shader)
+static bool
+anv_shader_bin_write_to_blob(const struct anv_shader_bin *shader,
+                             struct blob *blob)
 {
-   return anv_shader_bin_size(shader->prog_data_size,
-                              shader->prog_data->nr_params, shader->key->size,
-                              shader->bind_map.surface_count,
-                              shader->bind_map.sampler_count) +
-          align_u32(shader->kernel_size, 8);
+   bool ok;
+
+   ok = blob_write_uint32(blob, shader->key->size);
+   ok = blob_write_bytes(blob, shader->key->data, shader->key->size);
+
+   ok = blob_write_uint32(blob, shader->kernel_size);
+   ok = blob_write_bytes(blob, shader->kernel.map, shader->kernel_size);
+
+   ok = blob_write_uint32(blob, shader->prog_data_size);
+   ok = blob_write_bytes(blob, shader->prog_data, shader->prog_data_size);
+   ok = blob_write_bytes(blob, shader->prog_data->param,
+                               shader->prog_data->nr_params *
+                               sizeof(*shader->prog_data->param));
+
+   ok = blob_write_uint32(blob, shader->bind_map.surface_count);
+   ok = blob_write_uint32(blob, shader->bind_map.sampler_count);
+   ok = blob_write_uint32(blob, shader->bind_map.image_count);
+   ok = blob_write_bytes(blob, shader->bind_map.surface_to_descriptor,
+                               shader->bind_map.surface_count *
+                               sizeof(*shader->bind_map.surface_to_descriptor));
+   ok = blob_write_bytes(blob, shader->bind_map.sampler_to_descriptor,
+                               shader->bind_map.sampler_count *
+                               sizeof(*shader->bind_map.sampler_to_descriptor));
+
+   return ok;
 }
 
-static void
-anv_shader_bin_write_data(const struct anv_shader_bin *shader, void *data)
+static struct anv_shader_bin *
+anv_shader_bin_create_from_blob(struct anv_device *device,
+                                struct blob_reader *blob)
 {
-   size_t struct_size =
-      anv_shader_bin_size(shader->prog_data_size,
-                          shader->prog_data->nr_params, shader->key->size,
-                          shader->bind_map.surface_count,
-                          shader->bind_map.sampler_count);
+   uint32_t key_size = blob_read_uint32(blob);
+   const void *key_data = blob_read_bytes(blob, key_size);
 
-   memcpy(data, shader, struct_size);
-   data += struct_size;
+   uint32_t kernel_size = blob_read_uint32(blob);
+   const void *kernel_data = blob_read_bytes(blob, kernel_size);
 
-   memcpy(data, shader->kernel.map, shader->kernel_size);
+   uint32_t prog_data_size = blob_read_uint32(blob);
+   const struct brw_stage_prog_data *prog_data =
+      blob_read_bytes(blob, prog_data_size);
+   if (blob->overrun)
+      return NULL;
+   const void *prog_data_param =
+      blob_read_bytes(blob, prog_data->nr_params * sizeof(*prog_data->param));
+
+   struct anv_pipeline_bind_map bind_map;
+   bind_map.surface_count = blob_read_uint32(blob);
+   bind_map.sampler_count = blob_read_uint32(blob);
+   bind_map.image_count = blob_read_uint32(blob);
+   bind_map.surface_to_descriptor = (void *)
+      blob_read_bytes(blob, bind_map.surface_count *
+                            sizeof(*bind_map.surface_to_descriptor));
+   bind_map.sampler_to_descriptor = (void *)
+      blob_read_bytes(blob, bind_map.sampler_count *
+                            sizeof(*bind_map.sampler_to_descriptor));
+
+   if (blob->overrun)
+      return NULL;
+
+   return anv_shader_bin_create(device,
+                                key_data, key_size,
+                                kernel_data, kernel_size,
+                                prog_data, prog_data_size, prog_data_param,
+                                &bind_map);
 }
 
 /* Remaining work:
@@ -308,14 +336,19 @@ anv_pipeline_cache_load(struct anv_pipeline_cache *cache,
 {
    struct anv_device *device = cache->device;
    struct anv_physical_device *pdevice = &device->instance->physicalDevice;
-   struct cache_header header;
 
    if (cache->cache == NULL)
       return;
 
-   if (size < sizeof(header))
+   struct blob_reader blob;
+   blob_reader_init(&blob, data, size);
+
+   struct cache_header header;
+   blob_copy_bytes(&blob, &header, sizeof(header));
+   uint32_t count = blob_read_uint32(&blob);
+   if (blob.overrun)
       return;
-   memcpy(&header, data, sizeof(header));
+
    if (header.header_size < sizeof(header))
       return;
    if (header.header_version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE)
@@ -327,56 +360,12 @@ anv_pipeline_cache_load(struct anv_pipeline_cache *cache,
    if (memcmp(header.uuid, pdevice->pipeline_cache_uuid, VK_UUID_SIZE) != 0)
       return;
 
-   const void *end = data + size;
-   const void *p = data + header.header_size;
-
-   /* Count is the total number of valid entries */
-   uint32_t count;
-   if (p + sizeof(count) >= end)
-      return;
-   memcpy(&count, p, sizeof(count));
-   p += align_u32(sizeof(count), 8);
-
    for (uint32_t i = 0; i < count; i++) {
-      struct anv_shader_bin bin;
-      if (p + sizeof(bin) > end)
-         break;
-      memcpy(&bin, p, sizeof(bin));
-      p += align_u32(sizeof(struct anv_shader_bin), 8);
-
-      const struct brw_stage_prog_data *prog_data = p;
-      p += align_u32(bin.prog_data_size, 8);
-      if (p > end)
-         break;
-
-      uint32_t param_size = prog_data->nr_params * sizeof(void *);
-      const void *prog_data_param = p;
-      p += align_u32(param_size, 8);
-
-      struct anv_shader_bin_key key;
-      if (p + sizeof(key) > end)
-         break;
-      memcpy(&key, p, sizeof(key));
-      const void *key_data = p + sizeof(key);
-      p += align_u32(sizeof(key) + key.size, 8);
-
-      /* We're going to memcpy this so getting rid of const is fine */
-      struct anv_pipeline_binding *bindings = (void *)p;
-      p += align_u32((bin.bind_map.surface_count + bin.bind_map.sampler_count) *
-                     sizeof(struct anv_pipeline_binding), 8);
-      bin.bind_map.surface_to_descriptor = bindings;
-      bin.bind_map.sampler_to_descriptor = bindings + bin.bind_map.surface_count;
-
-      const void *kernel_data = p;
-      p += align_u32(bin.kernel_size, 8);
-
-      if (p > end)
+      struct anv_shader_bin *bin =
+         anv_shader_bin_create_from_blob(device, &blob);
+      if (!bin)
          break;
-
-      anv_pipeline_cache_add_shader(cache, key_data, key.size,
-                                    kernel_data, bin.kernel_size,
-                                    prog_data, bin.prog_data_size,
-                                    prog_data_param, &bin.bind_map);
+      _mesa_hash_table_insert(cache->cache, bin->key, bin);
    }
 }
 
@@ -444,59 +433,54 @@ VkResult anv_GetPipelineCacheData(
    ANV_FROM_HANDLE(anv_device, device, _device);
    ANV_FROM_HANDLE(anv_pipeline_cache, cache, _cache);
    struct anv_physical_device *pdevice = &device->instance->physicalDevice;
-   struct cache_header *header;
 
-   if (pData == NULL) {
-      size_t size = align_u32(sizeof(*header), 8) +
-                    align_u32(sizeof(uint32_t), 8);
-
-      if (cache->cache) {
-         struct hash_entry *entry;
-         hash_table_foreach(cache->cache, entry)
-            size += anv_shader_bin_data_size(entry->data);
-      }
-
-      *pDataSize = size;
-      return VK_SUCCESS;
+   struct blob blob;
+   if (pData) {
+      blob_init_fixed(&blob, pData, *pDataSize);
+   } else {
+      blob_init_fixed(&blob, NULL, SIZE_MAX);
    }
 
-   if (*pDataSize < sizeof(*header)) {
+   struct cache_header header = {
+      .header_size = sizeof(struct cache_header),
+      .header_version = VK_PIPELINE_CACHE_HEADER_VERSION_ONE,
+      .vendor_id = 0x8086,
+      .device_id = device->chipset_id,
+   };
+   memcpy(header.uuid, pdevice->pipeline_cache_uuid, VK_UUID_SIZE);
+   blob_write_bytes(&blob, &header, sizeof(header));
+
+   uint32_t count = 0;
+   ssize_t count_offset = blob_reserve_uint32(&blob);
+   if (count_offset < 0) {
       *pDataSize = 0;
+      blob_finish(&blob);
       return VK_INCOMPLETE;
    }
 
-   void *p = pData, *end = pData + *pDataSize;
-   header = p;
-   header->header_size = sizeof(*header);
-   header->header_version = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
-   header->vendor_id = 0x8086;
-   header->device_id = device->chipset_id;
-   memcpy(header->uuid, pdevice->pipeline_cache_uuid, VK_UUID_SIZE);
-   p += align_u32(header->header_size, 8);
-
-   uint32_t *count = p;
-   p += align_u32(sizeof(*count), 8);
-   *count = 0;
-
    VkResult result = VK_SUCCESS;
    if (cache->cache) {
       struct hash_entry *entry;
       hash_table_foreach(cache->cache, entry) {
          struct anv_shader_bin *shader = entry->data;
-         size_t data_size = anv_shader_bin_data_size(entry->data);
-         if (p + data_size > end) {
+
+         size_t save_size = blob.size;
+         if (!anv_shader_bin_write_to_blob(shader, &blob)) {
+            /* If it fails reset to the previous size and bail */
+            blob.size = save_size;
             result = VK_INCOMPLETE;
             break;
          }
 
-         anv_shader_bin_write_data(shader, p);
-         p += data_size;
-
-         (*count)++;
+         count++;
       }
    }
 
-   *pDataSize = p - pData;
+   blob_overwrite_uint32(&blob, count_offset, count);
+
+   *pDataSize = blob.size;
+
+   blob_finish(&blob);
 
    return result;
 }
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index e8a845f..b33370c 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -2048,8 +2048,6 @@ struct anv_shader_bin {
    uint32_t prog_data_size;
 
    struct anv_pipeline_bind_map bind_map;
-
-   /* Prog data follows, then params, then the key, all aligned to 8-bytes */
 };
 
 struct anv_shader_bin *
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list