[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