From ceb1baf939d727e280ee464bb62c5b82ab4fe5cc Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Tue, 24 Jun 2025 13:36:50 -0700 Subject: [PATCH] intel/mda: Handle non-contiguous object versions in mda.tar files Allow archives to have interleaved entries where different object versions don't appear together. This gives more flexibility to the drivers when producing the mda.tar files. Acked-by: Kenneth Graunke Acked-by: Lionel Landwerlin Part-of: --- src/intel/mda/mda.c | 131 +++++++++++++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 38 deletions(-) diff --git a/src/intel/mda/mda.c b/src/intel/mda/mda.c index eb95aa05482..2c3e1e55c21 100644 --- a/src/intel/mda/mda.c +++ b/src/intel/mda/mda.c @@ -187,60 +187,115 @@ parse_mesa_archive(void *mem_ctx, const char *filename) tar_reader tr = {0}; tar_reader_init_from_bytes(&tr, ma->contents.data, ma->contents.len); - object *cur_object = NULL; - tar_reader_entry entry = {0}; - { - if (!tar_reader_next(&tr, &entry) || entry.error) { - fprintf(stderr, "mda: wrong archive, missing mesa.txt\n"); - return NULL; + bool found_mesa_txt = false; + while (tar_reader_next(&tr, &entry)) { + slice fullpath; + if (!slice_is_empty(entry.prefix)) { + char *fullpath_str = ralloc_asprintf(ma, "%.*s/%.*s", + SLICE_FMT(entry.prefix), + SLICE_FMT(entry.name)); + fullpath = slice_from_cstr(fullpath_str); + } else { + fullpath = entry.name; } - const char *mesa_txt = slice_to_cstr(ma, entry.name); - if (strcmp(mesa_txt, "mesa.txt")) { - fprintf(stderr, "mda: wrong archive, missing mesa.txt\n"); - return NULL; + slice mda_mesa_txt = slice_from_cstr("mda/mesa.txt"); + if (slice_equal(fullpath, mda_mesa_txt)) { + ma->info = slice_to_cstr(ma, entry.contents); + found_mesa_txt = true; + break; } - - ma->info = slice_to_cstr(ma, entry.contents); } + if (!found_mesa_txt) { + fprintf(stderr, "mda: wrong archive, missing mesa.txt\n"); + return NULL; + } + + /* Now that we found mesa. Reset header. */ + tar_reader_init_from_bytes(&tr, ma->contents.data, ma->contents.len); + + struct hash_table *lookup = slice_hash_table_create(ma); + while (tar_reader_next(&tr, &entry)) { - slice prefix = entry.prefix; - slice name = entry.name; - - slice_cut_result cut = slice_cut(name, '/'); - slice version_name; - if (cut.found) { - name = cut.before; - version_name = cut.after; + slice fullpath; + if (!slice_is_empty(entry.prefix)) { + char *fullpath_str = ralloc_asprintf(ma, "%.*s/%.*s", + SLICE_FMT(entry.prefix), + SLICE_FMT(entry.name)); + fullpath = slice_from_cstr(fullpath_str); } else { - version_name = slice_from_cstr(""); + fullpath = entry.name; } - assert(prefix.len > 4); - assert(slice_starts_with(prefix, slice_from_cstr("mda/"))); - prefix = slice_strip_prefix(prefix, slice_from_cstr("mda/")); + /* Ignore directory entries. */ + if (slice_is_empty(entry.contents)) + continue; - if (!cur_object || !slice_equal(prefix, cur_object->prefix) || !slice_equal(name, cur_object->name)) { + /* Already processed this before. */ + if (slice_equal_cstr(fullpath, "mda/mesa.txt")) + continue; + + /* Normalize path: strip leading "mda/" if present */ + slice mda_prefix = slice_from_cstr("mda/"); + fullpath = slice_strip_prefix(fullpath, mda_prefix); + + slice_cut_result first_cut = slice_cut(fullpath, '/'); + if (!first_cut.found) + continue; + + slice prefix_normalized = first_cut.before; + slice_cut_result second_cut = slice_cut(first_cut.after, '/'); + + slice key_slice, object_name, version_name; + + if (second_cut.found) { + /* Normal format: "0/OBJECT-NAME/version-name". */ + object_name = second_cut.before; + version_name = second_cut.after; + key_slice = slice_substr_to(fullpath, + second_cut.before.data + second_cut.before.len - fullpath.data); + } else { + /* Single version format: "0/SPIRV". */ + object_name = first_cut.after; + version_name = slice_from_cstr("binary"); + key_slice = fullpath; + } + + struct hash_entry *hash_entry = slice_hash_table_search(lookup, key_slice); + int obj_index = hash_entry ? (intptr_t)hash_entry->data : -1; + object *obj; + + if (obj_index == -1) { ma->objects = rerzalloc(ma, ma->objects, object, ma->objects_count, ma->objects_count + 1); - cur_object = &ma->objects[ma->objects_count++]; - cur_object->prefix = prefix; - cur_object->name = name; - cur_object->ma = ma; - cur_object->fullname = slice_from_cstr(ralloc_asprintf(ma, "%.*s/%.*s/%.*s", SLICE_FMT(ma->filename), SLICE_FMT(prefix), SLICE_FMT(name))); + obj_index = ma->objects_count++; + obj = &ma->objects[obj_index]; + obj->prefix = prefix_normalized; + obj->name = object_name; + obj->ma = ma; + char *fullname_str = ralloc_asprintf(ma, "%.*s/%.*s/%.*s", + SLICE_FMT(ma->filename), + SLICE_FMT(prefix_normalized), + SLICE_FMT(object_name)); + obj->fullname = slice_from_cstr(fullname_str); + obj->versions = NULL; + obj->versions_count = 0; + + slice_hash_table_insert(lookup, key_slice, (void *)(intptr_t)obj_index); + } else { + obj = &ma->objects[obj_index]; } - /* Add version to object (same for new or existing) */ - cur_object->versions = rerzalloc(ma, cur_object->versions, content, - cur_object->versions_count, cur_object->versions_count + 1); - int s = cur_object->versions_count++; + obj->versions = rerzalloc(ma, obj->versions, content, + obj->versions_count, obj->versions_count + 1); + int s = obj->versions_count++; - cur_object->versions[s].name = version_name; - cur_object->versions[s].data = entry.contents; - char *version_fullname_str = ralloc_asprintf(ma, "%.*s/%.*s", SLICE_FMT(cur_object->fullname), SLICE_FMT(version_name)); - cur_object->versions[s].fullname = slice_from_cstr(version_fullname_str); + obj->versions[s].name = version_name; + obj->versions[s].data = entry.contents; + char *version_fullname_str = ralloc_asprintf(ma, "%.*s/%.*s", SLICE_FMT(obj->fullname), SLICE_FMT(version_name)); + obj->versions[s].fullname = slice_from_cstr(version_fullname_str); } return ma;