static void Memory_InitTable(global_memory *GlobalMemory, memory *Memory, uint64 Size, memory_table_list TableName, char *Name, uint64 Block_ElementSize = 0) { memory_table *Table = &Memory->Slot[TableName]; Table->Name = Name; Table->Address = (ptrsize *)((uint8 *)GlobalMemory->Address + GlobalMemory->CurrentPosition); Table->Size = Size; Table->Block_ElementSize = Block_ElementSize; GlobalMemory->CurrentPosition += Size; } static uint32 Memory_Block_AllocateNew(memory *Memory, memory_table_list TableName) { memory_table *Table = &Memory->Slot[TableName]; Assert(Table->Block_ElementSize != 0); bool32 Empty = 0; uint32 Index = 0; uint8 *Address_Playhead = (uint8 *)Table->Address; while (*Address_Playhead != 0) { Address_Playhead += Table->Block_ElementSize; Index++; } Arbitrary_Zero(Address_Playhead, Table->Block_ElementSize); return Index; } static void * Memory_Block_AddressAtIndex(memory *Memory, memory_table_list TableName, uint32 Index) { memory_table *Table = &Memory->Slot[TableName]; Assert(Table->Block_ElementSize != 0); uint8 *Address = (uint8 *)Table->Address + (Table->Block_ElementSize * Index); return (void *)Address; } static uint16 Memory_Block_IndexAtAddress(memory *Memory, memory_table_list TableName, void *Address) { memory_table *Table = &Memory->Slot[TableName]; return ((uint8 *)Address - (uint8 *)Table->Address) / Table->Block_ElementSize; } static void * Memory_Block_AllocateAddress(memory *Memory, memory_table_list TableName) { uint16 FileIndex = Memory_Block_AllocateNew(Memory, TableName); return Memory_Block_AddressAtIndex(Memory, TableName, FileIndex); } // IMPORTANT(fox): All block data has to start with a uint8 Occupied variable! static bool32 Block_Loop(memory *Memory, memory_table_list TableName, uint32 TotalCount, int *HasIncremented, int *CurrentCount, int *Index, void *Extra = NULL) { for (;;) { if (*CurrentCount == TotalCount) { return 0; } if (*HasIncremented) { *HasIncremented = 0; (*Index)++; } uint8 *Occupied; if (!Extra) { Occupied = (uint8 *)Memory_Block_AddressAtIndex(Memory, TableName, *Index); } else { Occupied = (uint8 *)Bezier_Lookup(Memory, (property_channel *)Extra, *Index); } if (*Occupied) { *HasIncremented = 1; (*CurrentCount)++; return 1; } (*Index)++; Assert(*CurrentCount <= TotalCount); Assert(*Index <= TotalCount*100); // This can get triggered normally if 100+ items are added and the first 99 in memory are deleted. } Assert(0); return 0; } static bool32 Block_Loop(memory *Memory, property_channel *Property, uint32 TotalCount, int *HasIncremented, int *CurrentCount, int *Index) { for (;;) { if (*CurrentCount == TotalCount) { return 0; } if (*HasIncremented) { *HasIncremented = 0; (*Index)++; } uint8 *Occupied = (uint8 *)Bezier_Lookup(Memory, Property, *Index); if (*Occupied) { *HasIncremented = 1; (*CurrentCount)++; return 1; } (*Index)++; Assert(*CurrentCount <= TotalCount); Assert(*Index <= TotalCount*100); // This can get triggered normally if 100+ items are added and the first 99 in memory are deleted. } Assert(0); return 0; } static uint32 Memory_Block_PrincipalBitmap_AllocateNew(project_data *File, project_state *State, memory *Memory) { uint32 LastVal = 0; uint32 LastBlock = 0; uint32 c = 0; uint32 r = 0; while (r < File->Source_Count) { block_source Source = *(block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, c); if (Source.Occupied != 0) { LastBlock = (Source.Bitmap_Index > LastBlock) ? Source.Bitmap_Index : LastBlock; LastVal = r; r++; } c++; } block_source Source = *(block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, r); uint32 BlockSize = ((Source.Width * Source.Height * Source.BytesPerPixel) / BitmapBlockSize) + 1; uint32 Blocks_Max = Memory->Slot[B_CachedBitmaps].Size / BitmapBlockSize; Assert(Blocks_Max > (LastBlock + BlockSize)); return LastBlock + BlockSize; } static uint32 Memory_Block_Bitmap_AllocateNew(project_state *State, memory *Memory, cache_entry Entry, uint64 NewSize) { uint32 LastVal = 0; uint32 LastBlock = 0; uint32 c = 0; cache_entry *EntryArray = State->Render.Entry; while (EntryArray[c].IsOccupied != 0) { if (EntryArray[c].Block_StartIndex > LastBlock) { LastBlock = EntryArray[c].Block_StartIndex; LastVal = c; } c++; } cache_entry LastEntry = EntryArray[LastVal]; uint32 LastEntry_BlockCount = 0; switch (EntryArray[LastVal].Type) { case cache_entry_type_comp: { block_composition Comp = *(block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, LastEntry.TypeInfo); uint64 Size = Comp.Width * Comp.Height * Comp.BytesPerPixel; LastEntry_BlockCount = (Size / BitmapBlockSize) + 1; } break; case cache_entry_type_source: { block_source Source = *(block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, LastEntry.TypeInfo); uint64 Size = Source.Width * Source.Height * Source.BytesPerPixel; LastEntry_BlockCount = (Size / BitmapBlockSize) + 1; } break; case cache_entry_type_layer: { Assert(0); } break; case cache_entry_type_assert: { Assert(0); } break; default: { Assert(0); } break; } uint32 Blocks_Max = Memory->Slot[B_CachedBitmaps].Size / BitmapBlockSize; Assert(Blocks_Max > LastBlock); return LastBlock + LastEntry_BlockCount; /* uint32 Blocks_Needed = (NewSize / BitmapBlockSize) + 1; uint32 Block_Index_Available = 0; */ } static void Memory_Cache_Invalidate(project_state *State, memory *Memory, cache_entry_type Type, uint32 TypeInfo, uint32 TypeInfo_Sub) { cache_entry *EntryArray = State->Render.Entry; int c = 0; int count = Memory->EntryCount; while (count != 0) { if (EntryArray[c].Type == Type && EntryArray[c].TypeInfo == TypeInfo) { EntryArray[c].IsOccupied = false; Memory->EntryCount--; } c++; count--; } } static cache_entry * Memory_Cache_Search(project_state *State, memory *Memory, cache_entry_type Type, uint32 TypeInfo, uint32 TypeInfo_Sub) { cache_entry *EntryArray = State->Render.Entry; int c = 0; int count = Memory->EntryCount; while (count != 0) { if (EntryArray[c].Type == Type && EntryArray[c].TypeInfo == TypeInfo && EntryArray[c].TypeInfo_Sub == TypeInfo_Sub) { return &EntryArray[c]; } c++; count--; } if (c != 0) EntryArray[c].Block_StartIndex = Memory_Block_Bitmap_AllocateNew(State, Memory, EntryArray[c], 0); EntryArray[c].IsOccupied = true; EntryArray[c].Type = Type; EntryArray[c].TypeInfo = TypeInfo; EntryArray[c].TypeInfo_Sub = TypeInfo_Sub; Memory->EntryCount++; return &EntryArray[c]; } static void * Memory_Block_Bitmap_AddressAtIndex(memory *Memory, uint32 Index) { memory_table *Table = &Memory->Slot[B_CachedBitmaps]; uint8 *Address = (uint8 *)Table->Address + Index*BitmapBlockSize; return (void *)Address; } static void * Memory_PushScratch(memory *Memory, uint64 Size) { memory_table *Table = &Memory->Slot[B_ScratchSpace]; uint8 *Address = ((uint8 *)Table->Address + Memory->ScratchPos); Memory->ScratchPos += Size; #if DEBUG Debug.ScratchSize[Debug.ScratchState] = Size; Debug.ScratchState++; #endif return (void *)Address; } static void Memory_PopScratch(memory *Memory, uint64 Size) { memory_table *Table = &Memory->Slot[B_ScratchSpace]; Memory->ScratchPos -= Size; #if DEBUG Debug.ScratchState--; Assert(Debug.ScratchSize[Debug.ScratchState] == Size); #endif } static void * Memory_AddressAtOffset(memory *Memory, memory_table_list TableName, uint64 Offset) { memory_table *Table = &Memory->Slot[TableName]; return (void *)((uint8 *)Table->Address + Offset); } #if 0 static void* AllocateMemory(memory *Memory, uint64 Size, memory_table_list TableName) { void *Address; memory_table *Table = &Memory->Slot[TableName]; if (Table->CurrentPosition + Size > Table->Size) { return NULL; } Address = (ptrsize *)((uint8 *)Table->Address + Table->CurrentPosition); Table->CurrentPosition += Size; return Address; } // Returns the address without advancing static void* Memory_GetAddressAt(memory *Memory, uint64 Size, memory_table_list TableName) { void *Address; memory_table *Table = &Memory->Slot[TableName]; if (Table->CurrentPosition + Size > Table->Size) { return NULL; } Address = (ptrsize *)((uint8 *)Table->Address + Table->CurrentPosition + Size); return Address; } // Returns the address and THEN advances static void* Memory_Advance(memory *Memory, uint64 Size, memory_table_list TableName) { return AllocateMemory(Memory, Size, TableName); } // Rewinds and THEN returns the address static void* Memory_Rewind(memory *Memory, uint64 Size, memory_table_list TableName) { void *Address; memory_table *Table = &Memory->Slot[TableName]; if (Table->CurrentPosition - Size < 0) { return NULL; } Table->CurrentPosition -= Size; Address = (ptrsize *)((uint8 *)Table->Address + Table->CurrentPosition); return Address; } // Returns 0-1 range wherever Pointer is in relation to StartingPointer to Size*Amount. static real32 Memory_NormalizedPosition(void *StartingPointer, uint32 Amount, uint32 Size, void *Pointer) { real32 Result = 0; uint64 TotalSize = Amount*Size; uint64 PointerLocationSize = (uint8 *)Pointer - (uint8 *)StartingPointer; Result = (real32)PointerLocationSize / (real32)TotalSize; return Result; } static void Debug_Memory_Assert_Cohesion(memory *Memory, memory_table *Table) { #if DEBUG for (uint32 i = 0; i < Table->NumberOfPointers; i++) { cached_bitmap *CurrentBitmap = &Memory->Bitmap[i]; Assert(CurrentBitmap->Data); for (uint32 a = 0; a < Table->NumberOfPointers; a++) { if (a == i) { continue; } cached_bitmap *OtherBitmap = &Memory->Bitmap[a]; if (OtherBitmap->Data == CurrentBitmap->Data) { Assert(0); } } } #else #endif } static cached_bitmap * Memory_RollingBitmap(memory *Memory, source *Source, uint32 FrameToSeek) { uint16 Width = Source->Info.Width; uint16 Height = Source->Info.Height; uint16 BytesPerPixel = Source->Info.BytesPerPixel; memory_table *Table = &Memory->Slot[B_LoadedBitmaps]; // First check whether we'd run over the buffer at the current // position, and reset the position if so. uint64 Size = Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel); if (Table->CurrentPosition + Size > Table->Size) { Table->CurrentPosition = 0; Table->PointerIndex = 0; } cached_bitmap *Bitmap = &Memory->Bitmap[Table->PointerIndex]; // If there are no pointers in front of us, we don't have to free any space // and just need to increment the number of pointers. if (Table->PointerIndex != Table->NumberOfPointers) { // Next, if there's a pointer in front of the current position, // check whether it's far away enough so that the size fits. bool32 BS = true; if (Bitmap->Data) { uint64 BytesBetween = (uint8 *)Bitmap->Data - ((uint8 *)Table->Address + Table->CurrentPosition); if (BytesBetween > Size) { uint32 StopAt = Table->NumberOfPointers - 1; while (StopAt > Table->PointerIndex - 1) { Memory->Bitmap[StopAt + 1] = Memory->Bitmap[StopAt]; StopAt--; } Table->NumberOfPointers++; BS = false; } } // If it doesn't fit, then we need to dereference the pointers // until we have enough space. if ((Table->PointerIndex < Table->NumberOfPointers) && BS) { bool32 Avail = false; void *AddressStart = (void *)((uint8 *)Table->Address + Table->CurrentPosition); uint32 Amount = 0; while(!Avail) { // Bail out if we're on the last index, as we don't need to do anything else. // TODO(fox): This could be simplified if we compared // pointer start plus data instead of just the start. if (Table->PointerIndex != Table->NumberOfPointers - 1) { void *Data2 = Memory->Bitmap[Table->PointerIndex+1].Data; uint64 BytesBetween = (uint8 *)Data2 - (uint8 *)AddressStart; if (BytesBetween < Size) { uint32 StopAt = Table->PointerIndex; while (StopAt < Table->NumberOfPointers - 1) { Memory->Bitmap[StopAt] = Memory->Bitmap[StopAt + 1]; StopAt++; } Amount++; Table->NumberOfPointers--; if (Amount > 2) { Amount += 0; } } else { Avail = true; } } else { Avail = true; } } } } else { Table->NumberOfPointers++; } Bitmap->Data = AllocateMemory(Memory, Size, B_LoadedBitmaps); if (!Bitmap->Data) { Assert(0); } Bitmap->SourceOwner = Source; Bitmap->Frame = FrameToSeek; Table->PointerIndex++; // No two pointers on the table should hold the same data // address or be empty. Debug_Memory_Assert_Cohesion(Memory, Table); return Bitmap; } #endif