tar layer refactor

This commit is contained in:
jacob 2025-07-30 23:31:46 -05:00
parent 35564cceef
commit 3f2abf5b3e
5 changed files with 114 additions and 88 deletions

View File

@ -335,7 +335,7 @@ Global struct {
struct swapchain *first_free_swapchain; struct swapchain *first_free_swapchain;
/* Shader bytecode archive */ /* Shader bytecode archive */
struct tar_archive dxc_archive; TAR_Archive dxc_archive;
/* Pipeline cache */ /* Pipeline cache */
P_Mutex pipelines_mutex; P_Mutex pipelines_mutex;
@ -419,7 +419,7 @@ void gp_startup(void)
if (embedded_data.len <= 0) { if (embedded_data.len <= 0) {
P_Panic(Lit("No embedded shaders found")); P_Panic(Lit("No embedded shaders found"));
} }
G.dxc_archive = tar_parse(G.pipelines_arena, embedded_data, Lit("")); G.dxc_archive = TAR_ArchiveFromString(G.pipelines_arena, embedded_data, Lit(""));
/* Initialize dx12 */ /* Initialize dx12 */
/* TODO: Parallelize phases */ /* TODO: Parallelize phases */
@ -956,9 +956,9 @@ internal P_JobDef(pipeline_alloc_job, job)
String error_str = ZI; String error_str = ZI;
String vs_dxc = desc->vs_dxc.len > 0 ? desc->vs_dxc : tar_get(&G.dxc_archive, CatString(scratch.arena, pipeline_name, Lit(".vs")))->data; String vs_dxc = desc->vs_dxc.len > 0 ? desc->vs_dxc : TAR_EntryFromName(&G.dxc_archive, CatString(scratch.arena, pipeline_name, Lit(".vs")))->data;
String ps_dxc = desc->ps_dxc.len > 0 ? desc->ps_dxc : tar_get(&G.dxc_archive, CatString(scratch.arena, pipeline_name, Lit(".ps")))->data; String ps_dxc = desc->ps_dxc.len > 0 ? desc->ps_dxc : TAR_EntryFromName(&G.dxc_archive, CatString(scratch.arena, pipeline_name, Lit(".ps")))->data;
String cs_dxc = desc->cs_dxc.len > 0 ? desc->cs_dxc : tar_get(&G.dxc_archive, CatString(scratch.arena, pipeline_name, Lit(".cs")))->data; String cs_dxc = desc->cs_dxc.len > 0 ? desc->cs_dxc : TAR_EntryFromName(&G.dxc_archive, CatString(scratch.arena, pipeline_name, Lit(".cs")))->data;
if (success && vs_dxc.len > 0 && ps_dxc.len <= 0) { if (success && vs_dxc.len > 0 && ps_dxc.len <= 0) {
error_str = Lit("Pipeline has vertex shader without pixel shader"); error_str = Lit("Pipeline has vertex shader without pixel shader");
success = 0; success = 0;

View File

@ -15,7 +15,7 @@ R_StartupReceipt R_Startup(void)
{ {
P_Panic(Lit("No embedded resources found")); P_Panic(Lit("No embedded resources found"));
} }
g->archive = tar_parse(g->arena, embedded_data, Lit("")); g->archive = TAR_ArchiveFromString(g->arena, embedded_data, Lit(""));
#else #else
/* Ensure we have the right working directory */ /* Ensure we have the right working directory */
if (!P_IsDir(Lit("res"))) if (!P_IsDir(Lit("res")))
@ -36,7 +36,7 @@ R_Resource R_OpenResource(String name)
#if RESOURCES_EMBEDDED #if RESOURCES_EMBEDDED
R_SharedState *g = &R_shared_state; R_SharedState *g = &R_shared_state;
R_Resource result = ZI; R_Resource result = ZI;
struct tar_entry *entry = tar_get(&g->archive, name); TAR_Entry *entry = TAR_EntryFromName(&g->archive, name);
result._data = entry->data; result._data = entry->data;
result._name = entry->file_name; result._name = entry->file_name;
result._exists = entry->valid; result._exists = entry->valid;

View File

@ -24,7 +24,7 @@ Struct(R_SharedState)
{ {
Arena *arena; Arena *arena;
#if RESOURCES_EMBEDDED #if RESOURCES_EMBEDDED
struct tar_archive archive; TAR_Archive archive;
#endif #endif
}; };

View File

@ -1,53 +1,10 @@
#define ARCHIVE_LOOKUP_TABLE_CAPACITY_FACTOR 2.0 Readonly TAR_Entry TAR_nil_entry = ZI;
/* File types: u64 TAR_U64FromOctString(String str)
* '0' or (ASCII NUL) Normal file
* '1' Hard link
* '2' Symbolic link
* '3' Character special
* '4' Block special
* '5' Directory
* '6' FIFO
* '7' Contiguous file
* 'g' Global extended header with meta data(POSIX.1 - 2001)
* 'x' Extended header with metadata for the next file in the archive(POSIX.1 - 2001)
* 'A'-'Z' Vendor specific extensions(POSIX.1 - 1988)
*/
#define TAR_TYPE_FILE '0'
#define TAR_TYPE_DIRECTORY '5'
#define TAR_TYPE_PAX_HEADER_X 'x'
#define TAR_TYPE_PAX_HEADER_G 'g'
Packed(struct tar_header {
/* Pre-posix */
u8 file_name[100];
u8 file_mode[8];
u8 owner_id[8];
u8 group_id[8];
u8 file_size[12];
u8 last_modified[12];
u8 checksum[8];
/* Both */
u8 file_type;
u8 linked_file_name[100];
/* UStar */
u8 ustar_indicator[6];
u8 ustar_version[2];
u8 owner_user_name[32];
u8 owner_group_name[32];
u8 device_major_number[8];
u8 device_minor_number[8];
u8 file_name_prefix[155];
u8 padding[12];
});
internal u64 str_oct_to_u64(String str)
{ {
u64 n = 0; u64 n = 0;
for (u64 i = 0; i < str.len; ++i) { for (u64 i = 0; i < str.len; ++i)
{
n *= 8; n *= 8;
n += (u64)(str.text[i]) - '0'; n += (u64)(str.text[i]) - '0';
} }
@ -59,27 +16,30 @@ internal u64 str_oct_to_u64(String str)
* NOTE: The resulting archive merely points into the supplied tar data, no * NOTE: The resulting archive merely points into the supplied tar data, no
* copying is done. Accessing the archive assumes that the data string is still valid. * copying is done. Accessing the archive assumes that the data string is still valid.
*/ */
struct tar_archive tar_parse(Arena *arena, String data, String prefix) TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
{ {
__prof; __prof;
struct tar_archive archive = ZI; TAR_Archive archive = ZI;
BB_Buff bb = BitbuffFromString(data); BB_Buff bb = BitbuffFromString(data);
BB_Reader br = BB_ReaderFromBuffNoDebug(&bb); BB_Reader br = BB_ReaderFromBuffNoDebug(&bb);
u64 num_files = 0; u64 num_files = 0;
while (BB_NumBytesRemaining(&br) > 1024) { while (BB_NumBytesRemaining(&br) > 1024)
{
struct tar_header header = ZI; TAR_Header header = ZI;
BB_ReadBytes(&br, StringFromStruct(&header)); BB_ReadBytes(&br, StringFromStruct(&header));
if (!EqString(StringFromArray(header.ustar_indicator), Lit("ustar\0"))) { if (!EqString(StringFromArray(header.ustar_indicator), Lit("ustar\0")))
{
/* Invalid header */ /* Invalid header */
Assert(0); Assert(0);
continue; continue;
} }
if (header.file_name_prefix[0] != 0) { if (header.file_name_prefix[0] != 0)
{
/* Header file name prefix not supported */ /* Header file name prefix not supported */
Assert(0); Assert(0);
continue; continue;
@ -87,9 +47,10 @@ struct tar_archive tar_parse(Arena *arena, String data, String prefix)
String file_size_oct_str = { .len = 11, .text = header.file_size }; String file_size_oct_str = { .len = 11, .text = header.file_size };
u64 file_size = str_oct_to_u64(file_size_oct_str); u64 file_size = TAR_U64FromOctString(file_size_oct_str);
u8 *file_data_ptr = BB_ReadBytesRaw(&br, file_size); u8 *file_data_ptr = BB_ReadBytesRaw(&br, file_size);
if (!file_data_ptr) { if (!file_data_ptr)
{
file_size = 0; file_size = 0;
} }
String file_data = STRING(file_size, file_data_ptr); String file_data = STRING(file_size, file_data_ptr);
@ -98,23 +59,25 @@ struct tar_archive tar_parse(Arena *arena, String data, String prefix)
u64 remaining = (512 - (file_size % 512)) % 512; u64 remaining = (512 - (file_size % 512)) % 512;
BB_SeekBytes(&br, remaining); BB_SeekBytes(&br, remaining);
b32 is_dir = header.file_type == TAR_TYPE_DIRECTORY; b32 is_dir = header.file_type == TAR_FileKind_Directory;
if (!is_dir && header.file_type != TAR_TYPE_FILE) { if (!is_dir && header.file_type != TAR_FileKind_File)
{
/* Unsupported type */ /* Unsupported type */
Assert(header.file_type == TAR_TYPE_PAX_HEADER_X || Assert(header.file_type == TAR_FileKind_PaxHeaderX ||
header.file_type == TAR_TYPE_PAX_HEADER_G); header.file_type == TAR_FileKind_PaxHeaderG);
continue; continue;
} }
String file_name_cstr = StringFromCstrNoLimit((char *)header.file_name); String file_name_cstr = StringFromCstrNoLimit((char *)header.file_name);
if (file_name_cstr.len >= 2) { if (file_name_cstr.len >= 2)
{
/* Chop off './' prefix */ /* Chop off './' prefix */
file_name_cstr.len -= 2; file_name_cstr.len -= 2;
file_name_cstr.text += 2; file_name_cstr.text += 2;
} }
String file_name = CatString(arena, prefix, file_name_cstr); String file_name = CatString(arena, prefix, file_name_cstr);
struct tar_entry *entry = PushStruct(arena, struct tar_entry); TAR_Entry *entry = PushStruct(arena, TAR_Entry);
entry->valid = 1; entry->valid = 1;
entry->is_dir = is_dir; entry->is_dir = is_dir;
entry->file_name = file_name; entry->file_name = file_name;
@ -126,8 +89,9 @@ struct tar_archive tar_parse(Arena *arena, String data, String prefix)
} }
/* Build lookup table */ /* Build lookup table */
archive.lookup = InitDict(arena, (u64)((f64)num_files * ARCHIVE_LOOKUP_TABLE_CAPACITY_FACTOR)); archive.lookup = InitDict(arena, (u64)((f64)num_files * TAR_ArchiveLookupTableCapacityFactor));
for (struct tar_entry *entry = archive.head; entry; entry = entry->next) { for (TAR_Entry *entry = archive.head; entry; entry = entry->next)
{
u64 hash = HashFnv64(Fnv64Basis, entry->file_name); u64 hash = HashFnv64(Fnv64Basis, entry->file_name);
SetDictValue(arena, archive.lookup, hash, (u64)entry); SetDictValue(arena, archive.lookup, hash, (u64)entry);
} }
@ -135,20 +99,25 @@ struct tar_archive tar_parse(Arena *arena, String data, String prefix)
/* Build hierarchy */ /* Build hierarchy */
/* NOTE: This is a separate pass because tar entry order is not guaranteed /* NOTE: This is a separate pass because tar entry order is not guaranteed
* (IE file entries may be encountered before their parent directory entry) */ * (IE file entries may be encountered before their parent directory entry) */
for (struct tar_entry *entry = archive.head; entry; entry = entry->next) { for (TAR_Entry *entry = archive.head; entry; entry = entry->next)
{
/* Enter into hierarchy */ /* Enter into hierarchy */
if (!entry->is_dir) { if (!entry->is_dir)
{
/* Find parent entry */ /* Find parent entry */
struct tar_entry *parent_entry = 0; TAR_Entry *parent_entry = 0;
for (String parent_dir_name = entry->file_name; parent_dir_name.len > 0; --parent_dir_name.len) { for (String parent_dir_name = entry->file_name; parent_dir_name.len > 0; --parent_dir_name.len)
if (parent_dir_name.text[parent_dir_name.len - 1] == '/') { {
if (parent_dir_name.text[parent_dir_name.len - 1] == '/')
{
u64 hash = HashFnv64(Fnv64Basis, parent_dir_name); u64 hash = HashFnv64(Fnv64Basis, parent_dir_name);
parent_entry = (struct tar_entry *)DictValueFromHash(archive.lookup, hash); parent_entry = (TAR_Entry *)DictValueFromHash(archive.lookup, hash);
break; break;
} }
} }
/* Insert child into parent's list */ /* Insert child into parent's list */
if (parent_entry) { if (parent_entry)
{
entry->next_child = parent_entry->next_child; entry->next_child = parent_entry->next_child;
parent_entry->next_child = entry; parent_entry->next_child = entry;
} }
@ -158,10 +127,10 @@ struct tar_archive tar_parse(Arena *arena, String data, String prefix)
return archive; return archive;
} }
Readonly Global struct tar_entry g_nil_tar_entry = ZI; Readonly Global TAR_Entry g_nil_tar_entry = ZI;
struct tar_entry *tar_get(struct tar_archive *archive, String name) TAR_Entry *TAR_EntryFromName(TAR_Archive *archive, String name)
{ {
u64 hash = HashFnv64(Fnv64Basis, name); u64 hash = HashFnv64(Fnv64Basis, name);
struct tar_entry *lookup = (struct tar_entry *)DictValueFromHash(archive->lookup, hash); TAR_Entry *lookup = (TAR_Entry *)DictValueFromHash(archive->lookup, hash);
return lookup ? lookup : &g_nil_tar_entry; return lookup ? lookup : &g_nil_tar_entry;
} }

View File

@ -1,17 +1,74 @@
struct tar_entry { ////////////////////////////////
//~ Archive types
#define TAR_ArchiveLookupTableCapacityFactor 2.0
Struct(TAR_Entry)
{
b32 valid; b32 valid;
String file_name; String file_name;
String data; String data;
b32 is_dir; b32 is_dir;
struct tar_entry *next; TAR_Entry *next;
struct tar_entry *next_child; /* If entry is dir, points to first child. Otherwise points to next sibling. */ TAR_Entry *next_child; /* If entry is dir, points to first child. Otherwise points to next sibling. */
}; };
struct tar_archive { Struct(TAR_Archive)
{
Dict *lookup; Dict *lookup;
struct tar_entry *head; TAR_Entry *head;
}; };
struct tar_archive tar_parse(Arena *arena, String data, String prefix); extern Readonly TAR_Entry TAR_nil_entry;
struct tar_entry *tar_get(struct tar_archive *archive, String name);
////////////////////////////////
//~ Header types
typedef u8 TAR_FileKind; enum
{
TAR_FileKind_File = '0',
TAR_FileKind_HardLink = '1',
TAR_FileKind_SymLink = '2',
TAR_FileKind_CharacterSpecial = '3',
TAR_FileKind_BlockSpecial = '4',
TAR_FileKind_Directory = '5',
TAR_FileKind_Fifo = '6',
TAR_FileKind_ContiguousFile = '7',
TAR_FileKind_PaxHeaderG = 'g',
TAR_FileKind_PaxHeaderX = 'x'
};
Packed(Struct(TAR_Header)
{
/* Pre-posix */
u8 file_name[100];
u8 file_mode[8];
u8 owner_id[8];
u8 group_id[8];
u8 file_size[12];
u8 last_modified[12];
u8 checksum[8];
/* Both */
u8 file_type;
u8 linked_file_name[100];
/* UStar */
u8 ustar_indicator[6];
u8 ustar_version[2];
u8 owner_user_name[32];
u8 owner_group_name[32];
u8 device_major_number[8];
u8 device_minor_number[8];
u8 file_name_prefix[155];
u8 padding[12];
});
////////////////////////////////
//~ Archive operations
u64 TAR_U64FromOctString(String str);
TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix);
TAR_Entry *TAR_EntryFromName(TAR_Archive *archive, String name);