From: Jason Ekstrand Date: Thu, 25 Aug 2016 06:48:32 +0000 (-0700) Subject: anv: Add a struct for storing a compiled shader X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=689971847005219178f5a484dffecf9e5e515192;p=mesa.git anv: Add a struct for storing a compiled shader 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 Cc: "12.0" Acked-by: Kristian Høgsberg Kristensen --- diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c index 0d79ed92ac2..765dc6e38c9 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 3f111a1e4b7..abca9fe3313 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 6a8c6fc2bed..878bbaa7678 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -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;