[Mesa-dev] [PATCH v2 5/6] anv: Add a struct for storing a compiled shader

Jason Ekstrand jason at jlekstrand.net
Sat Aug 27 01:19:33 UTC 2016


This new anv_shader_bin struct stores the compiled kernel (as an anv_state)
as well as all of the metadata that is generated at shader compile time.
The struct is very similar to the old cache_entry struct except that it
is reference counted and stores the actual pipeline_bind_map.  Similarly to
cache_entry, much of the actual data is floating-size and stored after the
main struct.  Unlike cache_entry, which was storred in GPU-accessable
memory, the storage for anv_shader_bin kernels comes from a state pool.
The struct itself is reference-counted so that it can be used by multiple
pipelines at a time without fear of allocation issues.

Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
---
 src/intel/vulkan/anv_device.c         |   3 +
 src/intel/vulkan/anv_pipeline_cache.c | 110 ++++++++++++++++++++++++++++++++++
 src/intel/vulkan/anv_private.h        |  49 ++++++++++++++-
 3 files changed, 161 insertions(+), 1 deletion(-)

diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 0d79ed9..765dc6e 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -879,6 +879,8 @@ VkResult anv_CreateDevice(
                        &device->dynamic_state_block_pool);
 
    anv_block_pool_init(&device->instruction_block_pool, device, 128 * 1024);
+   anv_state_pool_init(&device->instruction_state_pool,
+                       &device->instruction_block_pool);
    anv_pipeline_cache_init(&device->default_pipeline_cache, device);
 
    anv_block_pool_init(&device->surface_state_block_pool, device, 4096);
@@ -954,6 +956,7 @@ void anv_DestroyDevice(
    anv_bo_pool_finish(&device->batch_bo_pool);
    anv_state_pool_finish(&device->dynamic_state_pool);
    anv_block_pool_finish(&device->dynamic_state_block_pool);
+   anv_state_pool_finish(&device->instruction_state_pool);
    anv_block_pool_finish(&device->instruction_block_pool);
    anv_state_pool_finish(&device->surface_state_pool);
    anv_block_pool_finish(&device->surface_state_block_pool);
diff --git a/src/intel/vulkan/anv_pipeline_cache.c b/src/intel/vulkan/anv_pipeline_cache.c
index 3f111a1..abca9fe 100644
--- a/src/intel/vulkan/anv_pipeline_cache.c
+++ b/src/intel/vulkan/anv_pipeline_cache.c
@@ -25,6 +25,116 @@
 #include "util/debug.h"
 #include "anv_private.h"
 
+struct shader_bin_key {
+   uint32_t size;
+   uint8_t data[0];
+};
+
+static size_t
+anv_shader_bin_size(uint32_t prog_data_size, 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(sizeof(uint32_t) + key_size, 8) +
+          align_u32(binding_data_size, 8);
+}
+
+static inline const struct shader_bin_key *
+anv_shader_bin_get_key(const struct anv_shader_bin *shader)
+{
+   const void *data = shader;
+   data += align_u32(sizeof(struct anv_shader_bin), 8);
+   data += align_u32(shader->prog_data_size, 8);
+   return data;
+}
+
+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 void *prog_data, uint32_t prog_data_size,
+                      const struct anv_pipeline_bind_map *bind_map)
+{
+   const size_t size =
+      anv_shader_bin_size(prog_data_size, key_size,
+                          bind_map->surface_count, bind_map->sampler_count);
+
+   struct anv_shader_bin *shader =
+      anv_alloc(&device->alloc, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
+   if (!shader)
+      return NULL;
+
+   shader->ref_cnt = 1;
+
+   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);
+
+   memcpy(data, prog_data, prog_data_size);
+   data += align_u32(prog_data_size, 8);
+
+   struct 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);
+
+   shader->bind_map.sampler_to_descriptor = data;
+   memcpy(data, bind_map->sampler_to_descriptor,
+          bind_map->sampler_count * sizeof(struct anv_pipeline_binding));
+
+   return shader;
+}
+
+void
+anv_shader_bin_destroy(struct anv_device *device,
+                       struct anv_shader_bin *shader)
+{
+   assert(shader->ref_cnt == 0);
+   anv_state_pool_free(&device->instruction_state_pool, shader->kernel);
+   anv_free(&device->alloc, shader);
+}
+
+static size_t
+anv_shader_bin_data_size(const struct anv_shader_bin *shader)
+{
+   return anv_shader_bin_size(shader->prog_data_size,
+                              anv_shader_bin_get_key(shader)->size,
+                              shader->bind_map.surface_count,
+                              shader->bind_map.sampler_count) +
+          align_u32(shader->kernel_size, 8);
+}
+
+static void
+anv_shader_bin_write_data(const struct anv_shader_bin *shader, void *data)
+{
+   size_t struct_size =
+      anv_shader_bin_size(shader->prog_data_size,
+                          anv_shader_bin_get_key(shader)->size,
+                          shader->bind_map.surface_count,
+                          shader->bind_map.sampler_count);
+
+   memcpy(data, shader, struct_size);
+   data += struct_size;
+
+   memcpy(data, shader->kernel.map, shader->kernel_size);
+}
+
 /* Remaining work:
  *
  * - Compact binding table layout so it's tight and not dependent on
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index 4ebb635..4b44597 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -400,7 +400,7 @@ struct anv_fixed_size_state_pool {
 };
 
 #define ANV_MIN_STATE_SIZE_LOG2 6
-#define ANV_MAX_STATE_SIZE_LOG2 10
+#define ANV_MAX_STATE_SIZE_LOG2 16
 
 #define ANV_STATE_BUCKETS (ANV_MAX_STATE_SIZE_LOG2 - ANV_MIN_STATE_SIZE_LOG2)
 
@@ -704,6 +704,7 @@ struct anv_device {
     struct anv_state_pool                       dynamic_state_pool;
 
     struct anv_block_pool                       instruction_block_pool;
+    struct anv_state_pool                       instruction_state_pool;
     struct anv_pipeline_cache                   default_pipeline_cache;
 
     struct anv_block_pool                       surface_state_block_pool;
@@ -1463,6 +1464,52 @@ struct anv_pipeline_bind_map {
    struct anv_pipeline_binding *                sampler_to_descriptor;
 };
 
+struct anv_shader_bin {
+   uint32_t ref_cnt;
+
+   struct anv_state kernel;
+   uint32_t kernel_size;
+
+   struct anv_pipeline_bind_map bind_map;
+
+   uint32_t prog_data_size;
+
+   /* Prog data follows, then the key, both aligned to 8-bytes */
+};
+
+struct anv_shader_bin *
+anv_shader_bin_create(struct anv_device *device,
+                      const void *key, uint32_t key_size,
+                      const void *kernel, uint32_t kernel_size,
+                      const void *prog_data, uint32_t prog_data_size,
+                      const struct anv_pipeline_bind_map *bind_map);
+
+void
+anv_shader_bin_destroy(struct anv_device *device, struct anv_shader_bin *shader);
+
+static inline void
+anv_shader_bin_ref(struct anv_shader_bin *shader)
+{
+   assert(shader->ref_cnt >= 1);
+   __sync_fetch_and_add(&shader->ref_cnt, 1);
+}
+
+static inline void
+anv_shader_bin_unref(struct anv_device *device, struct anv_shader_bin *shader)
+{
+   assert(shader->ref_cnt >= 1);
+   if (__sync_fetch_and_add(&shader->ref_cnt, -1) == 1)
+      anv_shader_bin_destroy(device, shader);
+}
+
+static inline const struct brw_stage_prog_data *
+anv_shader_bin_get_prog_data(const struct anv_shader_bin *shader)
+{
+   const void *data = shader;
+   data += align_u32(sizeof(struct anv_shader_bin), 8);
+   return data;
+}
+
 struct anv_pipeline {
    struct anv_device *                          device;
    struct anv_batch                             batch;
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list