anv/pipeline_cache: Rework to use multialloc and blob
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. Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
This commit is contained in:
parent
2d29dd9ee4
commit
b8ab78d1af
|
@ -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;
|
||||
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;
|
||||
|
||||
struct anv_shader_bin *shader =
|
||||
vk_alloc(&device->alloc, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
|
||||
if (!shader)
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
|
||||
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)
|
||||
struct anv_shader_bin *bin =
|
||||
anv_shader_bin_create_from_blob(device, &blob);
|
||||
if (!bin)
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 *
|
||||
|
|
Loading…
Reference in New Issue