diff --git a/build.bat b/build.bat index ece25327..15d2661d 100644 --- a/build.bat +++ b/build.bat @@ -11,7 +11,7 @@ set meta_build_cmd=cl.exe ../src/meta/meta.c -Od -Z7 -nologo -diagnostics:column set meta_rebuild_code=1317212284 if "%--force_meta_build%"=="1" ( - if exist meta.exe del meta.exe + if exist meta.exe del meta.exe ) echo build_cmd: %program_build_cmd% @@ -19,48 +19,48 @@ echo build_cmd: %program_build_cmd% ::- Try to activate Visual Studio if devenv not detected :: Taken from wcap: https://github.com/mmozeiko/wcap/blob/aa25ccb806d7a6e1c0bfdcca863aabcd8e9badfa/build.cmd#L21-L29 if "%PROCESSOR_ARCHITECTURE%" equ "AMD64" ( - set HOST_ARCH=x64 + set HOST_ARCH=x64 ) else if "%PROCESSOR_ARCHITECTURE%" equ "ARM64" ( - set HOST_ARCH=arm64 + set HOST_ARCH=arm64 ) where /Q cl.exe || ( - echo ************************************************************************** - echo WARNING: cl.exe not found, attempting to locate Visual Studio installation + echo ************************************************************************** + echo WARNING: cl.exe not found, attempting to locate Visual Studio installation - set __VSCMD_ARG_NO_LOGO=1 - for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i - if "!VS!" equ "" ( - echo ERROR: Visual Studio installation not found - exit /b 1 - ) - echo Visual Studio installation located, activating development environment... - call "!VS!\Common7\Tools\VsDevCmd.bat" -arch=%HOST_ARCH% -host_arch=%HOST_ARCH% -startdir=none -no_logo || exit /b 1 - echo Visual studio development environment activated - echo ************************************************************************** + set __VSCMD_ARG_NO_LOGO=1 + for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i + if "!VS!" equ "" ( + echo ERROR: Visual Studio installation not found + exit /b 1 + ) + echo Visual Studio installation located, activating development environment... + call "!VS!\Common7\Tools\VsDevCmd.bat" -arch=%HOST_ARCH% -host_arch=%HOST_ARCH% -startdir=none -no_logo || exit /b 1 + echo Visual studio development environment activated + echo ************************************************************************** ) ::- Meta build :meta_build if not exist meta.exe ( - echo ====== Meta build ===== - %meta_build_cmd% - set "rc=!errorlevel!" - if !rc! NEQ 0 ( - if exist meta.exe del meta.exe - exit /b !rc! - ) + echo ====== Meta build ===== + %meta_build_cmd% + set "rc=!errorlevel!" + if !rc! NEQ 0 ( + if exist meta.exe del meta.exe + exit /b !rc! + ) ) ::- Program build if not "%--no_program_build%"=="1" ( - echo ======== Build ======== - %program_build_cmd% - set "rc=!errorlevel!" - if !rc! NEQ 0 ( - if !rc! EQU %meta_rebuild_code% ( - del meta.exe - goto meta_build - ) - exit /b !rc! + echo ======== Build ======== + %program_build_cmd% + set "rc=!errorlevel!" + if !rc! NEQ 0 ( + if !rc! EQU %meta_rebuild_code% ( + del meta.exe + goto meta_build ) + exit /b !rc! + ) ) diff --git a/src/ase/ase.c b/src/ase/ase.c index 7324773e..7aaa1000 100644 --- a/src/ase/ase.c +++ b/src/ase/ase.c @@ -1,86 +1,86 @@ /* Aseprite (.ase) file parser - * - * DEFLATE decoder based on Handmade Hero's png parser - */ +* +* DEFLATE decoder based on Handmade Hero's png parser +*/ //////////////////////////////////////////////////////////// //~ Shared constants Global Readonly u32 ASE_huff_hclen_order[] = { - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; Global Readonly ASE_HuffEntry ASE_huff_length_table[] = { - {3, 0}, /* 257 */ - {4, 0}, /* 258 */ - {5, 0}, /* 259 */ - {6, 0}, /* 260 */ - {7, 0}, /* 261 */ - {8, 0}, /* 262 */ - {9, 0}, /* 263 */ - {10, 0}, /* 264 */ - {11, 1}, /* 265 */ - {13, 1}, /* 266 */ - {15, 1}, /* 267 */ - {17, 1}, /* 268 */ - {19, 2}, /* 269 */ - {23, 2}, /* 270 */ - {27, 2}, /* 271 */ - {31, 2}, /* 272 */ - {35, 3}, /* 273 */ - {43, 3}, /* 274 */ - {51, 3}, /* 275 */ - {59, 3}, /* 276 */ - {67, 4}, /* 277 */ - {83, 4}, /* 278 */ - {99, 4}, /* 279 */ - {115, 4}, /* 280 */ - {131, 5}, /* 281 */ - {163, 5}, /* 282 */ - {195, 5}, /* 283 */ - {227, 5}, /* 284 */ - {258, 0}, /* 285 */ + {3, 0}, /* 257 */ + {4, 0}, /* 258 */ + {5, 0}, /* 259 */ + {6, 0}, /* 260 */ + {7, 0}, /* 261 */ + {8, 0}, /* 262 */ + {9, 0}, /* 263 */ + {10, 0}, /* 264 */ + {11, 1}, /* 265 */ + {13, 1}, /* 266 */ + {15, 1}, /* 267 */ + {17, 1}, /* 268 */ + {19, 2}, /* 269 */ + {23, 2}, /* 270 */ + {27, 2}, /* 271 */ + {31, 2}, /* 272 */ + {35, 3}, /* 273 */ + {43, 3}, /* 274 */ + {51, 3}, /* 275 */ + {59, 3}, /* 276 */ + {67, 4}, /* 277 */ + {83, 4}, /* 278 */ + {99, 4}, /* 279 */ + {115, 4}, /* 280 */ + {131, 5}, /* 281 */ + {163, 5}, /* 282 */ + {195, 5}, /* 283 */ + {227, 5}, /* 284 */ + {258, 0}, /* 285 */ }; Global Readonly ASE_HuffEntry ASE_huff_dist_table[] = { - {1, 0}, /* 0 */ - {2, 0}, /* 1 */ - {3, 0}, /* 2 */ - {4, 0}, /* 3 */ - {5, 1}, /* 4 */ - {7, 1}, /* 5 */ - {9, 2}, /* 6 */ - {13, 2}, /* 7 */ - {17, 3}, /* 8 */ - {25, 3}, /* 9 */ - {33, 4}, /* 10 */ - {49, 4}, /* 11 */ - {65, 5}, /* 12 */ - {97, 5}, /* 13 */ - {129, 6}, /* 14 */ - {193, 6}, /* 15 */ - {257, 7}, /* 16 */ - {385, 7}, /* 17 */ - {513, 8}, /* 18 */ - {769, 8}, /* 19 */ - {1025, 9}, /* 20 */ - {1537, 9}, /* 21 */ - {2049, 10}, /* 22 */ - {3073, 10}, /* 23 */ - {4097, 11}, /* 24 */ - {6145, 11}, /* 25 */ - {8193, 12}, /* 26 */ - {12289, 12}, /* 27 */ - {16385, 13}, /* 28 */ - {24577, 13}, /* 29 */ + {1, 0}, /* 0 */ + {2, 0}, /* 1 */ + {3, 0}, /* 2 */ + {4, 0}, /* 3 */ + {5, 1}, /* 4 */ + {7, 1}, /* 5 */ + {9, 2}, /* 6 */ + {13, 2}, /* 7 */ + {17, 3}, /* 8 */ + {25, 3}, /* 9 */ + {33, 4}, /* 10 */ + {49, 4}, /* 11 */ + {65, 5}, /* 12 */ + {97, 5}, /* 13 */ + {129, 6}, /* 14 */ + {193, 6}, /* 15 */ + {257, 7}, /* 16 */ + {385, 7}, /* 17 */ + {513, 8}, /* 18 */ + {769, 8}, /* 19 */ + {1025, 9}, /* 20 */ + {1537, 9}, /* 21 */ + {2049, 10}, /* 22 */ + {3073, 10}, /* 23 */ + {4097, 11}, /* 24 */ + {6145, 11}, /* 25 */ + {8193, 12}, /* 26 */ + {12289, 12}, /* 27 */ + {16385, 13}, /* 28 */ + {24577, 13}, /* 29 */ }; Global Readonly u32 ASE_huff_bl_counts[][2] = { - {143, 8}, - {255, 9}, - {279, 7}, - {287, 8}, - {319, 5}, + {143, 8}, + {255, 9}, + {279, 7}, + {287, 8}, + {319, 5}, }; //////////////////////////////////////////////////////////// @@ -88,30 +88,30 @@ Global Readonly u32 ASE_huff_bl_counts[][2] = { u32 ASE_PeekBits(ASE_Bitbuff *bb, u32 nbits) { - Assert(nbits <= 32); + Assert(nbits <= 32); - u64 cur_byte = bb->cur_bit >> 3; - u8 bit_index = bb->cur_bit % 8; - u64 nbytes = (nbits + bit_index + 7) >> 3; + u64 cur_byte = bb->cur_bit >> 3; + u8 bit_index = bb->cur_bit % 8; + u64 nbytes = (nbits + bit_index + 7) >> 3; - u64 val64 = 0; - CopyBytes(&val64, &bb->data[cur_byte], nbytes); - u32 val32 = (u32)(val64 >> bit_index); - val32 &= U32Max >> (32 - nbits); + u64 val64 = 0; + CopyBytes(&val64, &bb->data[cur_byte], nbytes); + u32 val32 = (u32)(val64 >> bit_index); + val32 &= U32Max >> (32 - nbits); - return val32; + return val32; } u32 ASE_ConsumeBits(ASE_Bitbuff *bb, u32 nbits) { - u32 val = ASE_PeekBits(bb, nbits); - bb->cur_bit += nbits; - return val; + u32 val = ASE_PeekBits(bb, nbits); + bb->cur_bit += nbits; + return val; } void ASE_SkipBits(ASE_Bitbuff *bb, u32 nbits) { - bb->cur_bit += nbits; + bb->cur_bit += nbits; } //////////////////////////////////////////////////////////// @@ -119,280 +119,280 @@ void ASE_SkipBits(ASE_Bitbuff *bb, u32 nbits) u32 ASE_ReverseBits(u32 v, u32 bit_count) { - /* 7 & 15 seem to be the most common bit_counts, so a - * more optimal path is layed out for them. */ - if (bit_count == 15) - { - u32 b1 = v & 0xFF; - b1 = (b1 & 0xF0) >> 4 | (b1 & 0x0F) << 4; - b1 = (b1 & 0xCC) >> 2 | (b1 & 0x33) << 2; - b1 = (b1 & 0xAA) >> 1 | (b1 & 0x55) << 1; + /* 7 & 15 seem to be the most common bit_counts, so a + * more optimal path is layed out for them. */ + if (bit_count == 15) + { + u32 b1 = v & 0xFF; + b1 = (b1 & 0xF0) >> 4 | (b1 & 0x0F) << 4; + b1 = (b1 & 0xCC) >> 2 | (b1 & 0x33) << 2; + b1 = (b1 & 0xAA) >> 1 | (b1 & 0x55) << 1; - u32 b2 = (v & 0xFF00) >> 8; - b2 = (b2 & 0xF0) >> 4 | (b2 & 0x0F) << 4; - b2 = (b2 & 0xCC) >> 2 | (b2 & 0x33) << 2; - b2 = (b2 & 0xAA) >> 1 | (b2 & 0x55) << 1; - b2 >>= 1; + u32 b2 = (v & 0xFF00) >> 8; + b2 = (b2 & 0xF0) >> 4 | (b2 & 0x0F) << 4; + b2 = (b2 & 0xCC) >> 2 | (b2 & 0x33) << 2; + b2 = (b2 & 0xAA) >> 1 | (b2 & 0x55) << 1; + b2 >>= 1; - return (b1 << 7) | b2; - } - else if (bit_count == 7) - { - v = (v & 0xF0) >> 4 | (v & 0x0F) << 4; - v = (v & 0xCC) >> 2 | (v & 0x33) << 2; - v = (v & 0xAA) >> 1 | (v & 0x55) << 1; - return v >> 1; + return (b1 << 7) | b2; + } + else if (bit_count == 7) + { + v = (v & 0xF0) >> 4 | (v & 0x0F) << 4; + v = (v & 0xCC) >> 2 | (v & 0x33) << 2; + v = (v & 0xAA) >> 1 | (v & 0x55) << 1; + return v >> 1; - } - else + } + else + { + u32 result = 0; + for (u32 i = 0; i <= (bit_count / 2); ++i) { - u32 result = 0; - for (u32 i = 0; i <= (bit_count / 2); ++i) - { - u32 inv = (bit_count - (i + 1)); - result |= ((v >> i) & 0x1) << inv; - result |= ((v >> inv) & 0x1) << i; - } - return result; + u32 inv = (bit_count - (i + 1)); + result |= ((v >> i) & 0x1) << inv; + result |= ((v >> inv) & 0x1) << i; } + return result; + } } ASE_HuffDict ASE_InitHuffDict(Arena *arena, u32 max_code_bits, u32 *bl_counts, u32 bl_counts_count) { - ASE_HuffDict result = Zi; - result.max_code_bits = max_code_bits; - result.entries_count = (1 << max_code_bits); - result.entries = PushStructsNoZero(arena, ASE_HuffEntry, result.entries_count); + ASE_HuffDict result = Zi; + result.max_code_bits = max_code_bits; + result.entries_count = (1 << max_code_bits); + result.entries = PushStructsNoZero(arena, ASE_HuffEntry, result.entries_count); - u32 code_length_hist[ASE_HuffBitCount] = Zi; - for (u32 i = 0; i < bl_counts_count; ++i) + u32 code_length_hist[ASE_HuffBitCount] = Zi; + for (u32 i = 0; i < bl_counts_count; ++i) + { + u32 count = bl_counts[i]; + Assert(count <= countof(code_length_hist)); + ++code_length_hist[count]; + } + + u32 next_code[ASE_HuffBitCount] = Zi; + next_code[0] = 0; + code_length_hist[0] = 0; + for (u32 i = 1; i < countof(next_code); ++i) + { + next_code[i] = ((next_code[i - 1] + code_length_hist[i - 1]) << 1); + } + + for (u32 i = 0; i < bl_counts_count; ++i) + { + u32 code_bits = bl_counts[i]; + if (code_bits) { - u32 count = bl_counts[i]; - Assert(count <= countof(code_length_hist)); - ++code_length_hist[count]; + Assert(code_bits < countof(next_code)); + u32 code = next_code[code_bits]++; + u32 arbitrary_bits = result.max_code_bits - code_bits; + u32 entry_count = (1 << arbitrary_bits); + for (u32 entry_index = 0; entry_index < entry_count; ++entry_index) + { + /* TODO: Optimize this. It's bloating up the loading times. */ + u32 base_index = (code << arbitrary_bits) | entry_index; + u32 index = ASE_ReverseBits(base_index, result.max_code_bits); + ASE_HuffEntry *entry = &result.entries[index]; + entry->symbol = (u16)i; + entry->bits_used = (u16)code_bits; + } } + } - u32 next_code[ASE_HuffBitCount] = Zi; - next_code[0] = 0; - code_length_hist[0] = 0; - for (u32 i = 1; i < countof(next_code); ++i) - { - next_code[i] = ((next_code[i - 1] + code_length_hist[i - 1]) << 1); - } - - for (u32 i = 0; i < bl_counts_count; ++i) - { - u32 code_bits = bl_counts[i]; - if (code_bits) - { - Assert(code_bits < countof(next_code)); - u32 code = next_code[code_bits]++; - u32 arbitrary_bits = result.max_code_bits - code_bits; - u32 entry_count = (1 << arbitrary_bits); - for (u32 entry_index = 0; entry_index < entry_count; ++entry_index) - { - /* TODO: Optimize this. It's bloating up the loading times. */ - u32 base_index = (code << arbitrary_bits) | entry_index; - u32 index = ASE_ReverseBits(base_index, result.max_code_bits); - ASE_HuffEntry *entry = &result.entries[index]; - entry->symbol = (u16)i; - entry->bits_used = (u16)code_bits; - } - } - } - - return result; + return result; } u16 ASE_DecodeHuffDict(ASE_HuffDict *huffman, ASE_Bitbuff *bb) { - u32 index = ASE_PeekBits(bb, huffman->max_code_bits); - Assert(index < huffman->entries_count); + u32 index = ASE_PeekBits(bb, huffman->max_code_bits); + Assert(index < huffman->entries_count); - ASE_HuffEntry *entry = &huffman->entries[index]; - u16 result = entry->symbol; - ASE_SkipBits(bb, entry->bits_used); - Assert(entry->bits_used > 0); - return result; + ASE_HuffEntry *entry = &huffman->entries[index]; + u16 result = entry->symbol; + ASE_SkipBits(bb, entry->bits_used); + Assert(entry->bits_used > 0); + return result; } void ASE_Inflate(u8 *dst, u8 *encoded) { - TempArena scratch = BeginScratchNoConflict(); + TempArena scratch = BeginScratchNoConflict(); - ASE_Bitbuff bb = { .data = encoded }; + ASE_Bitbuff bb = { .data = encoded }; - /* ZLIB header */ - u32 cm = ASE_ConsumeBits(&bb, 4); - u32 cinfo = ASE_ConsumeBits(&bb, 4); - Assert(cm == 8); - Assert(cinfo == 7); + /* ZLIB header */ + u32 cm = ASE_ConsumeBits(&bb, 4); + u32 cinfo = ASE_ConsumeBits(&bb, 4); + Assert(cm == 8); + Assert(cinfo == 7); - u32 fcheck = ASE_ConsumeBits(&bb, 5); - u32 fdict = ASE_ConsumeBits(&bb, 1); - u32 flevl = ASE_ConsumeBits(&bb, 2); - Assert(fdict == 0); + u32 fcheck = ASE_ConsumeBits(&bb, 5); + u32 fdict = ASE_ConsumeBits(&bb, 1); + u32 flevl = ASE_ConsumeBits(&bb, 2); + Assert(fdict == 0); - u8 cmf = (u8)(cm | (cinfo << 4)); - u8 flg = fcheck | (fdict << 5) | (flevl << 6); - Assert(((cmf * 256) + flg) % 31 == 0); + u8 cmf = (u8)(cm | (cinfo << 4)); + u8 flg = fcheck | (fdict << 5) | (flevl << 6); + Assert(((cmf * 256) + flg) % 31 == 0); - u8 bfinal = 0; - while (!bfinal) + u8 bfinal = 0; + while (!bfinal) + { + bfinal = ASE_ConsumeBits(&bb, 1); + u8 btype = ASE_ConsumeBits(&bb, 2); + switch (btype) { - bfinal = ASE_ConsumeBits(&bb, 1); - u8 btype = ASE_ConsumeBits(&bb, 2); - switch (btype) + case ASE_BlockType_Uncompressed: + { + ASE_SkipBits(&bb, (8 - (bb.cur_bit % 8)) % 8); + i16 len = ASE_ConsumeBits(&bb, 16); + i16 nlen = ASE_ConsumeBits(&bb, 16); + Assert(len == ~nlen); /* Validation */ + while (len-- > 0) { - case ASE_BlockType_Uncompressed: - { - ASE_SkipBits(&bb, (8 - (bb.cur_bit % 8)) % 8); - i16 len = ASE_ConsumeBits(&bb, 16); - i16 nlen = ASE_ConsumeBits(&bb, 16); - Assert(len == ~nlen); /* Validation */ - while (len-- > 0) - { - *dst++ = ASE_ConsumeBits(&bb, 8); - } - } break; - - case ASE_BlockType_CompressedFixed: - case ASE_BlockType_CompressedDynamic: - { - TempArena temp = BeginTempArena(scratch.arena); - u32 lit_len_dist_table[512] = Zi; - u32 hlit; - u32 hdist; - - if (btype == ASE_BlockType_CompressedDynamic) - { - /* Dynamic table */ - - /* Read huffman table */ - hlit = ASE_ConsumeBits(&bb, 5) + 257; - hdist = ASE_ConsumeBits(&bb, 5) + 1; - u32 hclen = ASE_ConsumeBits(&bb, 4) + 4; - - /* Init dict huffman (hclen) */ - u32 hclen_bl_counts[19] = Zi; - for (u32 i = 0; i < hclen; ++i) - { - u32 code = ASE_huff_hclen_order[i]; - hclen_bl_counts[code] = ASE_ConsumeBits(&bb, 3); - } - ASE_HuffDict dict_huffman = ASE_InitHuffDict(temp.arena, 7, hclen_bl_counts, countof(hclen_bl_counts)); - - /* Decode dict huffman */ - u32 lit_len_count = 0; - u32 len_count = hlit + hdist; - Assert(len_count <= countof(lit_len_dist_table)); - while (lit_len_count < len_count) - { - u32 rep_count = 1; - u32 rep_val = 0; - u32 encoded_len = ASE_DecodeHuffDict(&dict_huffman, &bb); - if (encoded_len <= 15) - { - rep_val = encoded_len; - } - else if (encoded_len == 16) - { - rep_count = 3 + ASE_ConsumeBits(&bb, 2); - Assert(lit_len_count > 0); - rep_val = lit_len_dist_table[lit_len_count - 1]; - } - else if (encoded_len == 17) - { - rep_count = 3 + ASE_ConsumeBits(&bb, 3); - } - else if (encoded_len == 18) - { - rep_count = 11 + ASE_ConsumeBits(&bb, 7); - } - else - { - /* Invalid len */ - Assert(0); - } - - while (rep_count--) - { - lit_len_dist_table[lit_len_count++] = rep_val; - } - } - Assert(lit_len_count == len_count); - } - else - { - /* Fixed table */ - hlit = 288; - hdist = 32; - u32 index = 0; - for (u32 i = 0; i < countof(ASE_huff_bl_counts); ++i) - { - u32 bit_count = ASE_huff_bl_counts[i][1]; - u32 last_valuie = ASE_huff_bl_counts[i][0]; - while (index <= last_valuie) - { - lit_len_dist_table[index++] = bit_count; - } - } - } - - /* Decode */ - ASE_HuffDict lit_len_huffman = ASE_InitHuffDict(temp.arena, 15, lit_len_dist_table, hlit); - ASE_HuffDict dist_huffman = ASE_InitHuffDict(temp.arena, 15, lit_len_dist_table + hlit, hdist); - - for (;;) - { - u32 lit_len = ASE_DecodeHuffDict(&lit_len_huffman, &bb); - if (lit_len <= 255) - { - *dst++ = lit_len & 0xFF; - } - else if (lit_len >= 257) - { - u32 length_index = (lit_len - 257); - ASE_HuffEntry length_entry = ASE_huff_length_table[length_index]; - u32 length = length_entry.symbol; - if (length_entry.bits_used > 0) - { - u32 extra_bits = ASE_ConsumeBits(&bb, length_entry.bits_used); - length += extra_bits; - } - - u32 dist_index = ASE_DecodeHuffDict(&dist_huffman, &bb); - ASE_HuffEntry dist_entry = ASE_huff_dist_table[dist_index]; - u32 distance = dist_entry.symbol; - if (dist_entry.bits_used > 0) - { - u32 extra_bits = ASE_ConsumeBits(&bb, dist_entry.bits_used); - distance += extra_bits; - } - u8 *src = dst - distance; - while (length--) - { - *dst++ = *src++; - } - } - else - { - break; - } - } - - EndTempArena(temp); - } break; - - case ASE_BlockType_Reserved: - { - /* TODO */ - Assert(0); - } break; + *dst++ = ASE_ConsumeBits(&bb, 8); } - } + } break; - EndScratch(scratch); + case ASE_BlockType_CompressedFixed: + case ASE_BlockType_CompressedDynamic: + { + TempArena temp = BeginTempArena(scratch.arena); + u32 lit_len_dist_table[512] = Zi; + u32 hlit; + u32 hdist; + + if (btype == ASE_BlockType_CompressedDynamic) + { + /* Dynamic table */ + + /* Read huffman table */ + hlit = ASE_ConsumeBits(&bb, 5) + 257; + hdist = ASE_ConsumeBits(&bb, 5) + 1; + u32 hclen = ASE_ConsumeBits(&bb, 4) + 4; + + /* Init dict huffman (hclen) */ + u32 hclen_bl_counts[19] = Zi; + for (u32 i = 0; i < hclen; ++i) + { + u32 code = ASE_huff_hclen_order[i]; + hclen_bl_counts[code] = ASE_ConsumeBits(&bb, 3); + } + ASE_HuffDict dict_huffman = ASE_InitHuffDict(temp.arena, 7, hclen_bl_counts, countof(hclen_bl_counts)); + + /* Decode dict huffman */ + u32 lit_len_count = 0; + u32 len_count = hlit + hdist; + Assert(len_count <= countof(lit_len_dist_table)); + while (lit_len_count < len_count) + { + u32 rep_count = 1; + u32 rep_val = 0; + u32 encoded_len = ASE_DecodeHuffDict(&dict_huffman, &bb); + if (encoded_len <= 15) + { + rep_val = encoded_len; + } + else if (encoded_len == 16) + { + rep_count = 3 + ASE_ConsumeBits(&bb, 2); + Assert(lit_len_count > 0); + rep_val = lit_len_dist_table[lit_len_count - 1]; + } + else if (encoded_len == 17) + { + rep_count = 3 + ASE_ConsumeBits(&bb, 3); + } + else if (encoded_len == 18) + { + rep_count = 11 + ASE_ConsumeBits(&bb, 7); + } + else + { + /* Invalid len */ + Assert(0); + } + + while (rep_count--) + { + lit_len_dist_table[lit_len_count++] = rep_val; + } + } + Assert(lit_len_count == len_count); + } + else + { + /* Fixed table */ + hlit = 288; + hdist = 32; + u32 index = 0; + for (u32 i = 0; i < countof(ASE_huff_bl_counts); ++i) + { + u32 bit_count = ASE_huff_bl_counts[i][1]; + u32 last_valuie = ASE_huff_bl_counts[i][0]; + while (index <= last_valuie) + { + lit_len_dist_table[index++] = bit_count; + } + } + } + + /* Decode */ + ASE_HuffDict lit_len_huffman = ASE_InitHuffDict(temp.arena, 15, lit_len_dist_table, hlit); + ASE_HuffDict dist_huffman = ASE_InitHuffDict(temp.arena, 15, lit_len_dist_table + hlit, hdist); + + for (;;) + { + u32 lit_len = ASE_DecodeHuffDict(&lit_len_huffman, &bb); + if (lit_len <= 255) + { + *dst++ = lit_len & 0xFF; + } + else if (lit_len >= 257) + { + u32 length_index = (lit_len - 257); + ASE_HuffEntry length_entry = ASE_huff_length_table[length_index]; + u32 length = length_entry.symbol; + if (length_entry.bits_used > 0) + { + u32 extra_bits = ASE_ConsumeBits(&bb, length_entry.bits_used); + length += extra_bits; + } + + u32 dist_index = ASE_DecodeHuffDict(&dist_huffman, &bb); + ASE_HuffEntry dist_entry = ASE_huff_dist_table[dist_index]; + u32 distance = dist_entry.symbol; + if (dist_entry.bits_used > 0) + { + u32 extra_bits = ASE_ConsumeBits(&bb, dist_entry.bits_used); + distance += extra_bits; + } + u8 *src = dst - distance; + while (length--) + { + *dst++ = *src++; + } + } + else + { + break; + } + } + + EndTempArena(temp); + } break; + + case ASE_BlockType_Reserved: + { + /* TODO */ + Assert(0); + } break; + } + } + + EndScratch(scratch); } //////////////////////////////////////////////////////////// @@ -400,18 +400,18 @@ void ASE_Inflate(u8 *dst, u8 *encoded) void ASE_PushError(Arena *arena, ASE_ErrorList *list, String msg_src) { - ASE_Error *e = PushStruct(arena, ASE_Error); - e->msg = PushString(arena, msg_src); - if (!list->first) - { - list->first = e; - } - else - { - list->last->next = e; - } - list->last = e; - ++list->count; + ASE_Error *e = PushStruct(arena, ASE_Error); + e->msg = PushString(arena, msg_src); + if (!list->first) + { + list->first = e; + } + else + { + list->last->next = e; + } + list->last = e; + ++list->count; } //////////////////////////////////////////////////////////// @@ -419,61 +419,61 @@ void ASE_PushError(Arena *arena, ASE_ErrorList *list, String msg_src) u32 ASE_BlendMulU8(u32 a, u32 b) { - u32 t = (a * b) + 0x80; - return ((t >> 8) + t) >> 8; + u32 t = (a * b) + 0x80; + return ((t >> 8) + t) >> 8; } u32 ASE_Blend(u32 src, u32 dst, u8 opacity) { - u32 dst_r = (dst & 0xff); - u32 dst_g = (dst >> 8) & 0xff; - u32 dst_b = (dst >> 16) & 0xff; - u32 dst_a = (dst >> 24) & 0xff; + u32 dst_r = (dst & 0xff); + u32 dst_g = (dst >> 8) & 0xff; + u32 dst_b = (dst >> 16) & 0xff; + u32 dst_a = (dst >> 24) & 0xff; - u32 src_r = (src & 0xff); - u32 src_g = (src >> 8) & 0xff; - u32 src_b = (src >> 16) & 0xff; - u32 src_a = (src >> 24) & 0xff; + u32 src_r = (src & 0xff); + u32 src_g = (src >> 8) & 0xff; + u32 src_b = (src >> 16) & 0xff; + u32 src_a = (src >> 24) & 0xff; - src_a = (u8)ASE_BlendMulU8(src_a, opacity); - u32 a = src_a + dst_a - ASE_BlendMulU8(src_a, dst_a); - u32 r, g, b; - if (a == 0) - { - r = g = b = 0; - } - else - { - r = dst_r + (src_r - dst_r) * src_a / a; - g = dst_g + (src_g - dst_g) * src_a / a; - b = dst_b + (src_b - dst_b) * src_a / a; - } + src_a = (u8)ASE_BlendMulU8(src_a, opacity); + u32 a = src_a + dst_a - ASE_BlendMulU8(src_a, dst_a); + u32 r, g, b; + if (a == 0) + { + r = g = b = 0; + } + else + { + r = dst_r + (src_r - dst_r) * src_a / a; + g = dst_g + (src_g - dst_g) * src_a / a; + b = dst_b + (src_b - dst_b) * src_a / a; + } - return r | (g << 8) | (b << 16) | (a << 24); + return r | (g << 8) | (b << 16) | (a << 24); } void ASE_MakeDimensionsSquareish(ASE_Header *header, u32 *frames_x, u32 *frames_y, u64 *image_width, u64 *image_height) { - /* Try and get image resolution into as much of a square as possible by - * separating frames into multiple rows. */ - while (*frames_x > 1) + /* Try and get image resolution into as much of a square as possible by + * separating frames into multiple rows. */ + while (*frames_x > 1) + { + u64 new_frames_x = *frames_x - 1; + u64 new_frames_y = ((header->frames - 1) / new_frames_x) + 1; + u64 new_image_width = header->width * new_frames_x; + u64 new_image_height = header->height * new_frames_y; + if (new_image_width >= new_image_height) { - u64 new_frames_x = *frames_x - 1; - u64 new_frames_y = ((header->frames - 1) / new_frames_x) + 1; - u64 new_image_width = header->width * new_frames_x; - u64 new_image_height = header->height * new_frames_y; - if (new_image_width >= new_image_height) - { - *frames_x = new_frames_x; - *frames_y = new_frames_y; - *image_width = new_image_width; - *image_height = new_image_height; - } - else - { - break; - } + *frames_x = new_frames_x; + *frames_y = new_frames_y; + *image_width = new_image_width; + *image_height = new_image_height; } + else + { + break; + } + } } //////////////////////////////////////////////////////////// @@ -481,291 +481,295 @@ void ASE_MakeDimensionsSquareish(ASE_Header *header, u32 *frames_x, u32 *frames_ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded) { - TempArena scratch = BeginScratch(arena); - ASE_DecodedImage result = Zi; + TempArena scratch = BeginScratch(arena); + ASE_DecodedImage result = Zi; - BB_Buff bb = BB_BuffFromString(encoded); - BB_Reader br = BB_ReaderFromBuffNoDebug(&bb); - ASE_Header ase_header; - BB_ReadBytes(&br, StringFromStruct(&ase_header)); + BB_Buff bb = BB_BuffFromString(encoded); + BB_Reader br = BB_ReaderFromBuffNoDebug(&bb); + ASE_Header ase_header; + BB_ReadBytes(&br, StringFromStruct(&ase_header)); - if (ase_header.magic != 0xA5E0) + if (ase_header.magic != 0xA5E0) + { + ASE_PushError(arena, &result.errors, Lit("Not a valid aseprite file")); + goto abort; + } + + if (ase_header.color_depth != 32) + { + String msg = StringF( + scratch.arena, + "Only 32 bit rgba color mode is supported (got %F)", + FmtUint(ase_header.color_depth) + ); + ASE_PushError(arena, &result.errors, msg); + goto abort; + } + + u64 frame_width = ase_header.width; + u64 frame_height = ase_header.height; + + u32 frames_x = ase_header.frames; + u32 frames_y = 1; + u64 image_width = frame_width * frames_x; + u64 image_height = frame_height * frames_y; + ASE_MakeDimensionsSquareish(&ase_header, &frames_x, &frames_y, &image_width, &image_height); + + result.width = image_width; + result.height = image_height; + /* TODO: Optimize this. Naive memzero is bloating the decode time for large images. */ + result.pixels = PushStructs(arena, u32, image_width * image_height); + + u32 num_layers = 0; + ASE_Layer *layer_head = 0; + + Ace_Cel *cel_head = 0; + Ace_Cel *cel_tail = 0; + + //- Iterate frames + u32 num_frames = 0; + for (u16 i = 0; i < ase_header.frames; ++i) + { + ASE_FrameHeader frame_header; + BB_ReadBytes(&br, StringFromStruct(&frame_header)); + + u32 num_chunks = frame_header.chunks_new; + if (num_chunks == 0) { - ASE_PushError(arena, &result.errors, Lit("Not a valid aseprite file")); - goto abort; + Assert(frame_header.chunks_old != 0xFFFF); + num_chunks = frame_header.chunks_old; } - if (ase_header.color_depth != 32) + //- Iterate chunks in frame + for (u32 j = 0; j < num_chunks; ++j) { - String msg = StringF(scratch.arena, - "Only 32 bit rgba color mode is supported (got %F)", - FmtUint(ase_header.color_depth)); - ASE_PushError(arena, &result.errors, msg); - goto abort; - } + u32 chunk_size = BB_ReadUBits(&br, 32); + ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16); - u64 frame_width = ase_header.width; - u64 frame_height = ase_header.height; + /* Chunk size includes size & type */ + Assert(chunk_size >= 6); + chunk_size -= 6; - u32 frames_x = ase_header.frames; - u32 frames_y = 1; - u64 image_width = frame_width * frames_x; - u64 image_height = frame_height * frames_y; - ASE_MakeDimensionsSquareish(&ase_header, &frames_x, &frames_y, &image_width, &image_height); + u64 chunk_end_pos = BB_GetCurrentReaderByte(&br) + chunk_size; - result.width = image_width; - result.height = image_height; - /* TODO: Optimize this. Naive memzero is bloating the decode time for large images. */ - result.pixels = PushStructs(arena, u32, image_width * image_height); - - u32 num_layers = 0; - ASE_Layer *layer_head = 0; - - Ace_Cel *cel_head = 0; - Ace_Cel *cel_tail = 0; - - //- Iterate frames - u32 num_frames = 0; - for (u16 i = 0; i < ase_header.frames; ++i) - { - ASE_FrameHeader frame_header; - BB_ReadBytes(&br, StringFromStruct(&frame_header)); - - u32 num_chunks = frame_header.chunks_new; - if (num_chunks == 0) + switch (chunk_type) + { + default: { - Assert(frame_header.chunks_old != 0xFFFF); - num_chunks = frame_header.chunks_old; - } + BB_ReadSeekToByte(&br, chunk_end_pos); + } break; - //- Iterate chunks in frame - for (u32 j = 0; j < num_chunks; ++j) + //- Decode layer + case ASE_ChunkKind_Layer: { - u32 chunk_size = BB_ReadUBits(&br, 32); - ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16); + ASE_Layer *layer = PushStruct(scratch.arena, ASE_Layer); + layer->next = layer_head; + layer_head = layer; - /* Chunk size includes size & type */ - Assert(chunk_size >= 6); - chunk_size -= 6; + layer->flags = BB_ReadUBits(&br, 16); + layer->type = BB_ReadUBits(&br, 16); + layer->child_level = BB_ReadUBits(&br, 16); - u64 chunk_end_pos = BB_GetCurrentReaderByte(&br) + chunk_size; + /* Ignoring layer default width & height */ + BB_ReadSeekBytes(&br, sizeof(u16) * 2); - switch (chunk_type) + layer->blend_mode = BB_ReadUBits(&br, 16); + if (layer->blend_mode != 0) + { + ASE_PushError( + arena, + &result.errors, + Lit("Layer has unsupported blend mode (only 'Normal' mode is supported). Tip: Try using 'merge down' to create a normal layer as a workaround") + ); + goto abort; + } + + layer->opacity = BB_ReadUBits(&br, 8); + if (!(ase_header.flags & 1)) + { + layer->opacity = 255; + } + + BB_ReadSeekBytes(&br, sizeof(u8) * 3); + + u16 str_len = BB_ReadUBits(&br, 16); + layer->name = (String) { str_len, PushStructsNoZero(scratch.arena, u8, str_len) }; + BB_ReadBytes(&br, layer->name); + + if (layer->type == 2) + { + layer->tileset_index = BB_ReadUBits(&br, 32); + } + + layer->index = num_layers++; + } break; + + //- Decode cel + case ASE_ChunkKind_Cel: + { + Ace_Cel *cel = PushStruct(scratch.arena, Ace_Cel); + if (cel_tail) + { + cel_tail->next = cel; + } + else + { + cel_head = cel; + } + cel_tail = cel; + + cel->layer_index = BB_ReadUBits(&br, 16); + cel->x_pos = BB_ReadIBits(&br, 16); + cel->y_pos = BB_ReadIBits(&br, 16); + cel->opacity = BB_ReadUBits(&br, 8); + cel->type = BB_ReadUBits(&br, 16); + cel->z_index = BB_ReadIBits(&br, 16); + BB_ReadSeekBytes(&br, sizeof(u8) * 5); + + cel->frame_index = num_frames; + + switch (cel->type) + { + case ASE_CelKind_RawImage: { - default: - { - BB_ReadSeekToByte(&br, chunk_end_pos); - } break; + /* Unsupported */ + BB_ReadSeekToByte(&br, chunk_end_pos); + } break; - //- Decode layer - case ASE_ChunkKind_Layer: - { - ASE_Layer *layer = PushStruct(scratch.arena, ASE_Layer); - layer->next = layer_head; - layer_head = layer; + case ASE_CelKind_Linked: + { + cel->frame_pos = BB_ReadUBits(&br, 16); + /* Actual linking happens later after iteration */ + } break; - layer->flags = BB_ReadUBits(&br, 16); - layer->type = BB_ReadUBits(&br, 16); - layer->child_level = BB_ReadUBits(&br, 16); + case ASE_CelKind_CompressedImage: + { + cel->width = BB_ReadUBits(&br, 16); + cel->height = BB_ReadUBits(&br, 16); - /* Ignoring layer default width & height */ - BB_ReadSeekBytes(&br, sizeof(u16) * 2); + cel->pixels = PushStructsNoZero(scratch.arena, u32, cel->width * cel->height); + u8 *huffman_encoded = BB_ReadBytesRaw(&br, chunk_end_pos - BB_GetCurrentReaderByte(&br)); + if (huffman_encoded) + { + ASE_Inflate((u8 *)cel->pixels, huffman_encoded); + } + } break; - layer->blend_mode = BB_ReadUBits(&br, 16); - if (layer->blend_mode != 0) - { - ASE_PushError(arena, - &result.errors, - Lit("Layer has unsupported blend mode (only 'Normal' mode is supported). Tip: Try using 'merge down' to create a normal layer as a workaround")); - goto abort; - } - - layer->opacity = BB_ReadUBits(&br, 8); - if (!(ase_header.flags & 1)) - { - layer->opacity = 255; - } - - BB_ReadSeekBytes(&br, sizeof(u8) * 3); - - u16 str_len = BB_ReadUBits(&br, 16); - layer->name = (String) { str_len, PushStructsNoZero(scratch.arena, u8, str_len) }; - BB_ReadBytes(&br, layer->name); - - if (layer->type == 2) - { - layer->tileset_index = BB_ReadUBits(&br, 32); - } - - layer->index = num_layers++; - } break; - - //- Decode cel - case ASE_ChunkKind_Cel: - { - Ace_Cel *cel = PushStruct(scratch.arena, Ace_Cel); - if (cel_tail) - { - cel_tail->next = cel; - } - else - { - cel_head = cel; - } - cel_tail = cel; - - cel->layer_index = BB_ReadUBits(&br, 16); - cel->x_pos = BB_ReadIBits(&br, 16); - cel->y_pos = BB_ReadIBits(&br, 16); - cel->opacity = BB_ReadUBits(&br, 8); - cel->type = BB_ReadUBits(&br, 16); - cel->z_index = BB_ReadIBits(&br, 16); - BB_ReadSeekBytes(&br, sizeof(u8) * 5); - - cel->frame_index = num_frames; - - switch (cel->type) - { - case ASE_CelKind_RawImage: - { - /* Unsupported */ - BB_ReadSeekToByte(&br, chunk_end_pos); - } break; - - case ASE_CelKind_Linked: - { - cel->frame_pos = BB_ReadUBits(&br, 16); - /* Actual linking happens later after iteration */ - } break; - - case ASE_CelKind_CompressedImage: - { - cel->width = BB_ReadUBits(&br, 16); - cel->height = BB_ReadUBits(&br, 16); - - cel->pixels = PushStructsNoZero(scratch.arena, u32, cel->width * cel->height); - u8 *huffman_encoded = BB_ReadBytesRaw(&br, chunk_end_pos - BB_GetCurrentReaderByte(&br)); - if (huffman_encoded) - { - ASE_Inflate((u8 *)cel->pixels, huffman_encoded); - } - } break; - - case ASE_CelKind_CompressedTilemap: - { - /* Unsupported */ - ASE_PushError(arena, &result.errors, Lit("Tilemaps are not supported")); - goto abort; - } break; - } - } break; - } - } - ++num_frames; + case ASE_CelKind_CompressedTilemap: + { + /* Unsupported */ + ASE_PushError(arena, &result.errors, Lit("Tilemaps are not supported")); + goto abort; + } break; + } + } break; + } } + ++num_frames; + } - //- Create ordered layers array - ASE_Layer **layers_ordered = PushStructsNoZero(scratch.arena, ASE_Layer *, num_layers); - for (ASE_Layer *layer = layer_head; layer; layer = layer->next) + //- Create ordered layers array + ASE_Layer **layers_ordered = PushStructsNoZero(scratch.arena, ASE_Layer *, num_layers); + for (ASE_Layer *layer = layer_head; layer; layer = layer->next) + { + layers_ordered[layer->index] = layer; + } + + //- Link cels + Ace_Cel **cels_ordered = PushStructsNoZero(scratch.arena, Ace_Cel *, num_frames * num_layers); + for (Ace_Cel *cel = cel_head; cel; cel = cel->next) + { + cels_ordered[(cel->frame_index * num_layers) + cel->layer_index] = cel; + if (cel->type == ASE_CelKind_Linked) { - layers_ordered[layer->index] = layer; + Ace_Cel *ref_cel = cels_ordered[(cel->frame_pos * num_layers) + cel->layer_index]; + cel->width = ref_cel->width; + cel->height = ref_cel->height; + cel->pixels = ref_cel->pixels; } + } - //- Link cels - Ace_Cel **cels_ordered = PushStructsNoZero(scratch.arena, Ace_Cel *, num_frames * num_layers); + //- Assemble image from cels + { for (Ace_Cel *cel = cel_head; cel; cel = cel->next) { - cels_ordered[(cel->frame_index * num_layers) + cel->layer_index] = cel; - if (cel->type == ASE_CelKind_Linked) + ASE_Layer *layer = layers_ordered[cel->layer_index]; + /* Only draw visible layers */ + if (layer->flags & 1) + { + u8 opacity = (cel->opacity / 255.0f) * (layer->opacity / 255.0f) * 255.0f; + + i32 cel_width = cel->width; + i32 cel_height = cel->height; + + i32 cel_left = 0; + i32 cel_right = cel_width; + i32 cel_top = 0; + i32 cel_bottom = cel_height; + + i32 frame_left = cel->x_pos; + i32 frame_top = cel->y_pos; + + i32 image_left = frame_left + ((cel->frame_index % frames_x) * frame_width); + i32 image_top = frame_top + ((cel->frame_index / frames_x) * frame_height); + + /* Adjust bounds to ensure pixels outside of frame boundaries + * aren't (aseprite keeps chunks outside of frame around in + * project file). */ { - Ace_Cel *ref_cel = cels_ordered[(cel->frame_pos * num_layers) + cel->layer_index]; - cel->width = ref_cel->width; - cel->height = ref_cel->height; - cel->pixels = ref_cel->pixels; + i32 frame_right = cel_width + frame_left; + i32 frame_bottom = frame_top + cel_height; + if (frame_left < 0) + { + cel_left += -frame_left; + frame_left = 0; + } + if (frame_top < 0) + { + cel_top += -frame_top; + frame_top = 0; + } + if (frame_right > (i32)frame_width) + { + cel_right -= (frame_right - frame_width); + frame_right = frame_width; + } + if (frame_bottom > (i32)frame_height) + { + cel_bottom -= (frame_bottom - frame_height); + frame_bottom = frame_height; + } } - } - //- Assemble image from cels - { - for (Ace_Cel *cel = cel_head; cel; cel = cel->next) + for (i32 cel_y = cel_top; cel_y < cel_bottom; ++cel_y) { - ASE_Layer *layer = layers_ordered[cel->layer_index]; - /* Only draw visible layers */ - if (layer->flags & 1) - { - u8 opacity = (cel->opacity / 255.0f) * (layer->opacity / 255.0f) * 255.0f; - - i32 cel_width = cel->width; - i32 cel_height = cel->height; - - i32 cel_left = 0; - i32 cel_right = cel_width; - i32 cel_top = 0; - i32 cel_bottom = cel_height; - - i32 frame_left = cel->x_pos; - i32 frame_top = cel->y_pos; - - i32 image_left = frame_left + ((cel->frame_index % frames_x) * frame_width); - i32 image_top = frame_top + ((cel->frame_index / frames_x) * frame_height); - - /* Adjust bounds to ensure pixels outside of frame boundaries - * aren't (aseprite keeps chunks outside of frame around in - * project file). */ - { - i32 frame_right = cel_width + frame_left; - i32 frame_bottom = frame_top + cel_height; - if (frame_left < 0) - { - cel_left += -frame_left; - frame_left = 0; - } - if (frame_top < 0) - { - cel_top += -frame_top; - frame_top = 0; - } - if (frame_right > (i32)frame_width) - { - cel_right -= (frame_right - frame_width); - frame_right = frame_width; - } - if (frame_bottom > (i32)frame_height) - { - cel_bottom -= (frame_bottom - frame_height); - frame_bottom = frame_height; - } - } - - for (i32 cel_y = cel_top; cel_y < cel_bottom; ++cel_y) - { - i32 image_y = image_top + cel_y; - i32 cel_stride = cel_y * cel_width; - i32 image_stride = image_y * image_width; - for (i32 cel_x = cel_left; cel_x < cel_right; ++cel_x) - { - i32 image_x = image_left + cel_x; - u32 cel_pixel = cel->pixels[cel_x + cel_stride]; - u32 *image_pixel = &result.pixels[image_x + image_stride]; - *image_pixel = ASE_Blend(cel_pixel, *image_pixel, opacity); - } - } - } + i32 image_y = image_top + cel_y; + i32 cel_stride = cel_y * cel_width; + i32 image_stride = image_y * image_width; + for (i32 cel_x = cel_left; cel_x < cel_right; ++cel_x) + { + i32 image_x = image_left + cel_x; + u32 cel_pixel = cel->pixels[cel_x + cel_stride]; + u32 *image_pixel = &result.pixels[image_x + image_stride]; + *image_pixel = ASE_Blend(cel_pixel, *image_pixel, opacity); + } } + } } + } - /* Assert all data was read */ - Assert(BB_NumBytesRemaining(&br) == 0); + /* Assert all data was read */ + Assert(BB_NumBytesRemaining(&br) == 0); -abort: + abort: - if (result.errors.count <= 0) - { - result.ok = 1; - } + if (result.errors.count <= 0) + { + result.ok = 1; + } - EndScratch(scratch); - return result; + EndScratch(scratch); + return result; } //////////////////////////////////////////////////////////// @@ -773,184 +777,184 @@ abort: ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded) { - ASE_DecodedSheet result = Zi; + ASE_DecodedSheet result = Zi; - BB_Buff bb = BB_BuffFromString(encoded); - BB_Reader br = BB_ReaderFromBuffNoDebug(&bb); - ASE_Header ase_header; - BB_ReadBytes(&br, StringFromStruct(&ase_header)); + BB_Buff bb = BB_BuffFromString(encoded); + BB_Reader br = BB_ReaderFromBuffNoDebug(&bb); + ASE_Header ase_header; + BB_ReadBytes(&br, StringFromStruct(&ase_header)); - if (ase_header.magic != 0xA5E0) + if (ase_header.magic != 0xA5E0) + { + ASE_PushError(arena, &result.errors, Lit("Not a valid aseprite file")); + goto abort; + } + + u64 frame_width = ase_header.width; + u64 frame_height = ase_header.height; + + u32 frames_x = ase_header.frames; + u32 frames_y = 1; + u64 image_width = frame_width * frames_x; + u64 image_height = frame_height * frames_y; + ASE_MakeDimensionsSquareish(&ase_header, &frames_x, &frames_y, &image_width, &image_height); + + u32 num_frames = 0; + ASE_Frame *first_frame = 0; + + u32 num_spans = 0; + ASE_Span *first_span = 0; + + u32 num_slice_keys = 0; + ASE_SliceKey *first_slice_key = 0; + + //- Iterate frames + for (u16 i = 0; i < ase_header.frames; ++i) + { + ASE_FrameHeader frame_header; + BB_ReadBytes(&br, StringFromStruct(&frame_header)); + + u32 num_chunks = frame_header.chunks_new; + if (num_chunks == 0) { - ASE_PushError(arena, &result.errors, Lit("Not a valid aseprite file")); - goto abort; + Assert(frame_header.chunks_old != 0xFFFF); + num_chunks = frame_header.chunks_old; } - u64 frame_width = ase_header.width; - u64 frame_height = ase_header.height; + ASE_Frame *frame = PushStruct(arena, ASE_Frame); + frame->next = first_frame; + first_frame = frame; - u32 frames_x = ase_header.frames; - u32 frames_y = 1; - u64 image_width = frame_width * frames_x; - u64 image_height = frame_height * frames_y; - ASE_MakeDimensionsSquareish(&ase_header, &frames_x, &frames_y, &image_width, &image_height); + frame->index = i; + frame->duration = frame_header.frame_duration_ms / 1000.0; - u32 num_frames = 0; - ASE_Frame *first_frame = 0; + u32 frame_tile_x = i % frames_x; + u32 frame_tile_y = i / frames_x; - u32 num_spans = 0; - ASE_Span *first_span = 0; + Vec2I32 frame_p0 = VEC2I32(frame_tile_x * frame_width, frame_tile_y * frame_height); + Vec2I32 frame_p1 = AddVec2I32(frame_p0, VEC2I32(frame_width, frame_height)); + frame->rect.p0 = frame_p0; + frame->rect.p1 = frame_p1; - u32 num_slice_keys = 0; - ASE_SliceKey *first_slice_key = 0; + frame->index = i; + frame->duration = frame_header.frame_duration_ms / 1000.0; - //- Iterate frames - for (u16 i = 0; i < ase_header.frames; ++i) + //- Iterate chunks in frame + for (u32 j = 0; j < num_chunks; ++j) { - ASE_FrameHeader frame_header; - BB_ReadBytes(&br, StringFromStruct(&frame_header)); + u32 chunk_size = BB_ReadUBits(&br, 32); + ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16); - u32 num_chunks = frame_header.chunks_new; - if (num_chunks == 0) + /* Chunk size includes size & type */ + Assert(chunk_size >= 6); + chunk_size -= 6; + + u64 chunk_end_pos = BB_GetCurrentReaderByte(&br) + chunk_size; + + switch (chunk_type) + { + default: { - Assert(frame_header.chunks_old != 0xFFFF); - num_chunks = frame_header.chunks_old; - } + BB_ReadSeekToByte(&br, chunk_end_pos); + } break; - ASE_Frame *frame = PushStruct(arena, ASE_Frame); - frame->next = first_frame; - first_frame = frame; - - frame->index = i; - frame->duration = frame_header.frame_duration_ms / 1000.0; - - u32 frame_tile_x = i % frames_x; - u32 frame_tile_y = i / frames_x; - - Vec2I32 frame_p0 = VEC2I32(frame_tile_x * frame_width, frame_tile_y * frame_height); - Vec2I32 frame_p1 = AddVec2I32(frame_p0, VEC2I32(frame_width, frame_height)); - frame->rect.p0 = frame_p0; - frame->rect.p1 = frame_p1; - - frame->index = i; - frame->duration = frame_header.frame_duration_ms / 1000.0; - - //- Iterate chunks in frame - for (u32 j = 0; j < num_chunks; ++j) + //- Decode tags + case ASE_ChunkKind_Tags: { - u32 chunk_size = BB_ReadUBits(&br, 32); - ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16); + u16 frame_span_count = BB_ReadUBits(&br, 16); + BB_ReadSeekBytes(&br, 8); - /* Chunk size includes size & type */ - Assert(chunk_size >= 6); - chunk_size -= 6; + for (u16 k = 0; k < frame_span_count; ++k) + { + ASE_Span *span = PushStruct(arena, ASE_Span); + span->next = first_span; + first_span = span; - u64 chunk_end_pos = BB_GetCurrentReaderByte(&br) + chunk_size; + span->start = BB_ReadUBits(&br, 16); + span->end = BB_ReadUBits(&br, 16); + BB_ReadSeekBytes(&br, 13); - switch (chunk_type) + u16 str_len = BB_ReadUBits(&br, 16); + span->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) }; + BB_ReadBytes(&br, span->name); + + ++num_spans; + } + + } break; + + //- Decode slice + case ASE_ChunkKind_Slice: + { + ASE_SliceKey *slice_key = PushStruct(arena, ASE_SliceKey); + slice_key->next = first_slice_key; + first_slice_key = slice_key; + + u32 num_slices = BB_ReadUBits(&br, 32); + slice_key->num_slices = num_slices; + + u32 flags = BB_ReadUBits(&br, 32); + BB_ReadSeekBytes(&br, 4); + + u16 str_len = BB_ReadUBits(&br, 16); + slice_key->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) }; + BB_ReadBytes(&br, slice_key->name); + + for (u32 k = 0; k < num_slices; ++k) + { + ASE_Slice *slice = PushStruct(arena, ASE_Slice); + slice->next = slice_key->first_slice; + slice_key->first_slice = slice; + + u32 start = BB_ReadUBits(&br, 32); + i32 x = BB_ReadIBits(&br, 32); + i32 y = BB_ReadIBits(&br, 32); + u32 width = BB_ReadUBits(&br, 32); + u32 height = BB_ReadUBits(&br, 32); + if (flags & 0x01) { - default: - { - BB_ReadSeekToByte(&br, chunk_end_pos); - } break; - - //- Decode tags - case ASE_ChunkKind_Tags: - { - u16 frame_span_count = BB_ReadUBits(&br, 16); - BB_ReadSeekBytes(&br, 8); - - for (u16 k = 0; k < frame_span_count; ++k) - { - ASE_Span *span = PushStruct(arena, ASE_Span); - span->next = first_span; - first_span = span; - - span->start = BB_ReadUBits(&br, 16); - span->end = BB_ReadUBits(&br, 16); - BB_ReadSeekBytes(&br, 13); - - u16 str_len = BB_ReadUBits(&br, 16); - span->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) }; - BB_ReadBytes(&br, span->name); - - ++num_spans; - } - - } break; - - //- Decode slice - case ASE_ChunkKind_Slice: - { - ASE_SliceKey *slice_key = PushStruct(arena, ASE_SliceKey); - slice_key->next = first_slice_key; - first_slice_key = slice_key; - - u32 num_slices = BB_ReadUBits(&br, 32); - slice_key->num_slices = num_slices; - - u32 flags = BB_ReadUBits(&br, 32); - BB_ReadSeekBytes(&br, 4); - - u16 str_len = BB_ReadUBits(&br, 16); - slice_key->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) }; - BB_ReadBytes(&br, slice_key->name); - - for (u32 k = 0; k < num_slices; ++k) - { - ASE_Slice *slice = PushStruct(arena, ASE_Slice); - slice->next = slice_key->first_slice; - slice_key->first_slice = slice; - - u32 start = BB_ReadUBits(&br, 32); - i32 x = BB_ReadIBits(&br, 32); - i32 y = BB_ReadIBits(&br, 32); - u32 width = BB_ReadUBits(&br, 32); - u32 height = BB_ReadUBits(&br, 32); - if (flags & 0x01) - { - /* Skip 9-patches info */ - BB_ReadSeekBytes(&br, 128); - } - if (flags & 0x02) - { - /* Skip pivot info */ - BB_ReadSeekBytes(&br, 64); - } - - slice->start = start; - slice->rect.p0 = VEC2I32(x, y); - slice->rect.p1 = VEC2I32(x + width, y + width); - } - - ++num_slice_keys; - } break; - - /* TODO */ - //case ASE_ChunkKind_Userdata + /* Skip 9-patches info */ + BB_ReadSeekBytes(&br, 128); } - } - ++num_frames; + if (flags & 0x02) + { + /* Skip pivot info */ + BB_ReadSeekBytes(&br, 64); + } + + slice->start = start; + slice->rect.p0 = VEC2I32(x, y); + slice->rect.p1 = VEC2I32(x + width, y + width); + } + + ++num_slice_keys; + } break; + + /* TODO */ + //case ASE_ChunkKind_Userdata + } } + ++num_frames; + } - /* Assert all data was read */ - Assert(BB_NumBytesRemaining(&br) == 0); + /* Assert all data was read */ + Assert(BB_NumBytesRemaining(&br) == 0); - result.image_size = VEC2(image_width, image_height); - result.frame_size = VEC2(frame_width, frame_height); - result.num_frames = num_frames; - result.num_spans = num_spans; - result.num_slice_keys = num_slice_keys; - result.first_frame = first_frame; - result.first_span = first_span; - result.first_slice_key = first_slice_key; + result.image_size = VEC2(image_width, image_height); + result.frame_size = VEC2(frame_width, frame_height); + result.num_frames = num_frames; + result.num_spans = num_spans; + result.num_slice_keys = num_slice_keys; + result.first_frame = first_frame; + result.first_span = first_span; + result.first_slice_key = first_slice_key; -abort: + abort: - if (result.errors.count <= 0) - { - result.ok = 1; - } + if (result.errors.count <= 0) + { + result.ok = 1; + } - return result; + return result; } diff --git a/src/ase/ase.h b/src/ase/ase.h index d817401d..4554d9c7 100644 --- a/src/ase/ase.h +++ b/src/ase/ase.h @@ -3,33 +3,33 @@ Struct(ASE_Slice) { - u32 start; - Rng2I32 rect; - ASE_Slice *next; + u32 start; + Rng2I32 rect; + ASE_Slice *next; }; Struct(ASE_Span) { - String name; - u32 start; - u32 end; - ASE_Span *next; + String name; + u32 start; + u32 end; + ASE_Span *next; }; Struct(ASE_Frame) { - u32 index; - Rng2I32 rect; - f64 duration; - ASE_Frame *next; + u32 index; + Rng2I32 rect; + f64 duration; + ASE_Frame *next; }; Struct(ASE_SliceKey) { - String name; - u32 num_slices; - ASE_Slice *first_slice; - ASE_SliceKey *next; + String name; + u32 num_slices; + ASE_Slice *first_slice; + ASE_SliceKey *next; }; //////////////////////////////////////////////////////////// @@ -37,38 +37,38 @@ Struct(ASE_SliceKey) Struct(ASE_Error) { - String msg; - ASE_Error *next; + String msg; + ASE_Error *next; }; Struct(ASE_ErrorList) { - u64 count; - ASE_Error *first; - ASE_Error *last; + u64 count; + ASE_Error *first; + ASE_Error *last; }; Struct(ASE_DecodedImage) { - u32 width; - u32 height; - u32 *pixels; /* Array of [width * height] pixels */ - ASE_ErrorList errors; - b32 ok; + u32 width; + u32 height; + u32 *pixels; /* Array of [width * height] pixels */ + ASE_ErrorList errors; + b32 ok; }; Struct(ASE_DecodedSheet) { - Vec2 image_size; - Vec2 frame_size; - u32 num_frames; - u32 num_spans; - u32 num_slice_keys; - ASE_Frame *first_frame; - ASE_Span *first_span; - ASE_SliceKey *first_slice_key; - ASE_ErrorList errors; - b32 ok; + Vec2 image_size; + Vec2 frame_size; + u32 num_frames; + u32 num_spans; + u32 num_slice_keys; + ASE_Frame *first_frame; + ASE_Span *first_span; + ASE_SliceKey *first_slice_key; + ASE_ErrorList errors; + b32 ok; }; //////////////////////////////////////////////////////////// @@ -78,29 +78,29 @@ Struct(ASE_DecodedSheet) Struct(ASE_Bitbuff) { - u8 *data; - u64 cur_bit; + u8 *data; + u64 cur_bit; }; Enum(ASE_BlockType) { - ASE_BlockType_Uncompressed = 0, - ASE_BlockType_CompressedFixed = 1, - ASE_BlockType_CompressedDynamic = 2, - ASE_BlockType_Reserved = 3 + ASE_BlockType_Uncompressed = 0, + ASE_BlockType_CompressedFixed = 1, + ASE_BlockType_CompressedDynamic = 2, + ASE_BlockType_Reserved = 3 }; Struct(ASE_HuffEntry) { - u16 symbol; - u16 bits_used; + u16 symbol; + u16 bits_used; }; Struct(ASE_HuffDict) { - u32 max_code_bits; - u32 entries_count; - ASE_HuffEntry *entries; + u32 max_code_bits; + u32 entries_count; + ASE_HuffEntry *entries; }; //////////////////////////////////////////////////////////// @@ -108,36 +108,36 @@ Struct(ASE_HuffDict) Packed(Struct(ASE_Header) { - u32 file_size; - u16 magic; - u16 frames; - u16 width; - u16 height; - u16 color_depth; - u32 flags; - u16 speed; - u32 _1; - u32 _2; - u8 palette_entry; - u8 _3[3]; - u16 num_colors; - u8 pixel_width; - u8 pixel_height; - i16 grid_x; - i16 grid_y; - u16 grid_width; - u16 grid_height; - u8 _4[84]; + u32 file_size; + u16 magic; + u16 frames; + u16 width; + u16 height; + u16 color_depth; + u32 flags; + u16 speed; + u32 _1; + u32 _2; + u8 palette_entry; + u8 _3[3]; + u16 num_colors; + u8 pixel_width; + u8 pixel_height; + i16 grid_x; + i16 grid_y; + u16 grid_width; + u16 grid_height; + u8 _4[84]; }); Packed(Struct(ASE_FrameHeader) { - u32 bytes; - u16 magic; - u16 chunks_old; - u16 frame_duration_ms; - u8 _[2]; - u32 chunks_new; + u32 bytes; + u16 magic; + u16 chunks_old; + u16 frame_duration_ms; + u8 _[2]; + u32 chunks_new; }); //////////////////////////////////////////////////////////// @@ -145,63 +145,63 @@ Packed(Struct(ASE_FrameHeader) Enum(ASE_ChunkKind) { - ASE_ChunkKind_OldPalette1 = 0x0004, - ASE_ChunkKind_OldPalette2 = 0x0011, - ASE_ChunkKind_Layer = 0x2004, - ASE_ChunkKind_Cel = 0x2005, - ASE_ChunkKind_CelExtra = 0x2006, - ASE_ChunkKind_ColorProfile = 0x2007, - ASE_ChunkKind_ExternalFiles = 0x2008, - ASE_ChunkKind_Mask = 0x2016, - ASE_ChunkKind_Path = 0x2017, - ASE_ChunkKind_Tags = 0x2018, - ASE_ChunkKind_Palette = 0x2019, - ASE_ChunkKind_Userdata = 0x2020, - ASE_ChunkKind_Slice = 0x2022, - ASE_ChunkKind_Tileset = 0x2023 + ASE_ChunkKind_OldPalette1 = 0x0004, + ASE_ChunkKind_OldPalette2 = 0x0011, + ASE_ChunkKind_Layer = 0x2004, + ASE_ChunkKind_Cel = 0x2005, + ASE_ChunkKind_CelExtra = 0x2006, + ASE_ChunkKind_ColorProfile = 0x2007, + ASE_ChunkKind_ExternalFiles = 0x2008, + ASE_ChunkKind_Mask = 0x2016, + ASE_ChunkKind_Path = 0x2017, + ASE_ChunkKind_Tags = 0x2018, + ASE_ChunkKind_Palette = 0x2019, + ASE_ChunkKind_Userdata = 0x2020, + ASE_ChunkKind_Slice = 0x2022, + ASE_ChunkKind_Tileset = 0x2023 }; Enum(ASE_CelKind) { - ASE_CelKind_RawImage = 0, - ASE_CelKind_Linked = 1, - ASE_CelKind_CompressedImage = 2, - ASE_CelKind_CompressedTilemap = 3 + ASE_CelKind_RawImage = 0, + ASE_CelKind_Linked = 1, + ASE_CelKind_CompressedImage = 2, + ASE_CelKind_CompressedTilemap = 3 }; Struct(ASE_Layer) { - u16 flags; - u16 type; - u16 child_level; - u16 blend_mode; - u8 opacity; - String name; - u32 tileset_index; + u16 flags; + u16 type; + u16 child_level; + u16 blend_mode; + u8 opacity; + String name; + u32 tileset_index; - u32 index; - ASE_Layer *next; + u32 index; + ASE_Layer *next; }; Struct(Ace_Cel) { - u16 layer_index; - i16 x_pos; - i16 y_pos; - u8 opacity; - ASE_CelKind type; - i16 z_index; + u16 layer_index; + i16 x_pos; + i16 y_pos; + u8 opacity; + ASE_CelKind type; + i16 z_index; - /* Linked cel */ - u16 frame_pos; + /* Linked cel */ + u16 frame_pos; - /* Compressed image */ - u32 width; - u32 height; - u32 *pixels; + /* Compressed image */ + u32 width; + u32 height; + u32 *pixels; - u16 frame_index; - Ace_Cel *next; + u16 frame_index; + Ace_Cel *next; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base.cgh b/src/base/base.cgh index f2517554..12afd7e1 100644 --- a/src/base/base.cgh +++ b/src/base/base.cgh @@ -2,39 +2,39 @@ //~ Compiler flag checks #ifndef IsConsoleApp - #error Missing compile time definition for 'IsConsoleApp' + #error Missing compile time definition for 'IsConsoleApp' #endif #ifndef IsRtcEnabled - #error Missing compile time definition for 'IsRtcEnabled' + #error Missing compile time definition for 'IsRtcEnabled' #endif #ifndef IsAsanEnabled - #error Missing compile time definition for 'IsAsanEnabled' + #error Missing compile time definition for 'IsAsanEnabled' #endif #ifndef IsCrtlibEnabled - #error Missing compile time definition for 'IsCrtlibEnabled' + #error Missing compile time definition for 'IsCrtlibEnabled' #endif #ifndef IsDebinfoEnabled - #error Missing compile time definition for 'IsDebinfoEnabled' + #error Missing compile time definition for 'IsDebinfoEnabled' #endif #ifndef IsDeveloperModeEnabled - #error Missing compile time definition for 'IsDeveloperModeEnabled' + #error Missing compile time definition for 'IsDeveloperModeEnabled' #endif #ifndef IsUnoptimized - #error Missing compile time definition for 'IsUnoptimized' + #error Missing compile time definition for 'IsUnoptimized' #endif #ifndef IsTestingEnabled - #error Missing compile time definition for 'IsTestingEnabled' + #error Missing compile time definition for 'IsTestingEnabled' #endif #ifndef IsHotSwappingEnabled - #error Missing compile time definition for 'IsHotSwappingEnabled' + #error Missing compile time definition for 'IsHotSwappingEnabled' #endif //////////////////////////////////////////////////////////// @@ -42,57 +42,57 @@ //- Compiler #if defined(__clang__) - #define IsCompilerClang 1 - #define IsCompilerMsvc 0 + #define IsCompilerClang 1 + #define IsCompilerMsvc 0 #elif defined(_MSC_VER) - #define IsCompilerClang 0 - #define IsCompilerMsvc 1 + #define IsCompilerClang 0 + #define IsCompilerMsvc 1 #else - #error Unknown compiler + #error Unknown compiler #endif //- Language #if defined(__HLSL_VERSION) - #define IsLanguageC 0 - #define IsLanguageG 1 + #define IsLanguageC 0 + #define IsLanguageG 1 #else - #define IsLanguageC 1 - #define IsLanguageG 0 + #define IsLanguageC 1 + #define IsLanguageG 0 #endif //- Platform system #if defined(_WIN32) - #define IsPlatformWindows 1 - #define IsPlatformMac 0 - #define IsPlatformLinux 0 + #define IsPlatformWindows 1 + #define IsPlatformMac 0 + #define IsPlatformLinux 0 #elif defined(__APPLE__) && defined(__MACH__) - #define IsPlatformWindows 0 - #define IsPlatformMac 1 - #define IsPlatformLinux 0 + #define IsPlatformWindows 0 + #define IsPlatformMac 1 + #define IsPlatformLinux 0 #elif defined(__gnu_linux__) - #define IsPlatformWindows 0 - #define IsPlatformMac 0 - #define IsPlatformLinux 1 + #define IsPlatformWindows 0 + #define IsPlatformMac 0 + #define IsPlatformLinux 1 #elif IsLanguageG - #define IsPlatformWindows 0 - #define IsPlatformMac 0 - #define IsPlatformLinux 0 + #define IsPlatformWindows 0 + #define IsPlatformMac 0 + #define IsPlatformLinux 0 #else - #error Unknown platform + #error Unknown platform #endif //- Architecture #if defined(_M_AMD64) || defined(__amd64__) - #define IsArchX64 1 - #define IsArchArm64 0 + #define IsArchX64 1 + #define IsArchArm64 0 #elif defined(_M_ARM64) || defined(__aarch64__) - #define IsArchX64 0 - #define IsArchArm64 1 + #define IsArchX64 0 + #define IsArchArm64 1 #elif IsLanguageG - #define IsArchX64 0 - #define IsArchArm64 0 + #define IsArchX64 0 + #define IsArchArm64 0 #else - #error Unknown architecture + #error Unknown architecture #endif //- Cache line size @@ -102,21 +102,21 @@ //- Windows NTDDI version /* TODO: Remove this */ #if 0 - #if IsCompilerMsvc - #define NTDDI_WIN11_DT 0x0C0A0000 - #define NTDDI_VERSION 0x0A000000 - #if IsRtcEnabled - #define _ALLOW_RTCc_IN_STL 1 - #endif - #endif +#if IsCompilerMsvc + #define NTDDI_WIN11_DT 0x0C0A0000 + #define NTDDI_VERSION 0x0A000000 + #if IsRtcEnabled + #define _ALLOW_RTCc_IN_STL 1 + #endif +#endif #endif //////////////////////////////////////////////////////////// //~ C headers #if IsLanguageC - #include - #include + #include + #include #endif //////////////////////////////////////////////////////////// @@ -129,27 +129,27 @@ //- Debug assert #if IsRtcEnabled - #if IsCompilerMsvc - #define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit(__FILE__ ":" Stringize(__LINE__) ":0: assertion failed: "#cond"")))) - #define DEBUGBREAK __debugbreak() - #else - #define Assert(cond) ((cond) ? 1 : (__builtin_trap(), 0)) - #define DEBUGBREAK __builtin_debugtrap() - #endif - #define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; __DEBUGBREAKABLE_VAR; } (void)0 + #if IsCompilerMsvc + #define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit(__FILE__ ":" Stringize(__LINE__) ":0: assertion failed: "#cond"")))) + #define DEBUGBREAK __debugbreak() + #else + #define Assert(cond) ((cond) ? 1 : (__builtin_trap(), 0)) + #define DEBUGBREAK __builtin_debugtrap() + #endif + #define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; __DEBUGBREAKABLE_VAR; } (void)0 #else - #define Assert(cond) (void)(0) + #define Assert(cond) (void)(0) #endif //- Address sanitization #if IsAsanEnabled - void __asan_poison_memory_region(void const volatile *, size_t); - void __asan_unpoison_memory_region(void const volatile *add, size_t); - #define AsanPoison(addr, size) __asan_poison_memory_region((addr), (size)) - #define AsanUnpoison(addr, size) __asan_unpoison_memory_region((addr), (size)) + void __asan_poison_memory_region(void const volatile *, size_t); + void __asan_unpoison_memory_region(void const volatile *add, size_t); + #define AsanPoison(addr, size) __asan_poison_memory_region((addr), (size)) + #define AsanUnpoison(addr, size) __asan_unpoison_memory_region((addr), (size)) #else - #define AsanPoison(addr, size) - #define AsanUnpoison(addr, size) + #define AsanPoison(addr, size) + #define AsanUnpoison(addr, size) #endif //////////////////////////////////////////////////////////// @@ -157,24 +157,24 @@ //- Zero initialization #if IsLanguageC - #define Zi { 0 } + #define Zi { 0 } #else - #define Zi { } + #define Zi { } #endif //- Inline #define Inline static inline #if IsCompilerMsvc - #define ForceInline Inline __forceinline + #define ForceInline Inline __forceinline #else - #define ForceInline Inline __attribute((always_inline)) + #define ForceInline Inline __attribute((always_inline)) #endif #if IsCompilerMsvc - #define ForceNoInline __declspec(noinline) + #define ForceNoInline __declspec(noinline) #else - #define ForceNoInline __attribute__((noinline)) + #define ForceNoInline __attribute__((noinline)) #endif //- Static @@ -183,35 +183,35 @@ //- Read-only #if IsPlatformWindows - #if IsCompilerMsvc - #pragma section(".rdata$", read) - #define Readonly __declspec(allocate(".rdata$")) - #else - #define Readonly __declspec(allocate(".rdata$")) - #endif + #if IsCompilerMsvc + #pragma section(".rdata$", read) + #define Readonly __declspec(allocate(".rdata$")) + #else + #define Readonly __declspec(allocate(".rdata$")) + #endif #elif IsPlatformMac - #define Readonly __attribute((section("__TEXT,__const"))) + #define Readonly __attribute((section("__TEXT,__const"))) #else - #define Readonly __attribute((section(".rodata"))) + #define Readonly __attribute((section(".rodata"))) #endif //- Thread-local #if IsCompilerMsvc - #define ThreadLocal __declspec(thread) + #define ThreadLocal __declspec(thread) #endif //- Compiler memory barriers #if IsCompilerMsvc - #define CompilerBarrier() _ReadWriteBarrier() + #define CompilerBarrier() _ReadWriteBarrier() #elif IsArchX64 - #define CompilerBarrier() __asm__ volatile("" ::: "memory") + #define CompilerBarrier() __asm__ volatile("" ::: "memory") #endif //- Fallthrough #if IsCompilerClang - #define FALLTHROUGH __attribute((fallthrough)) + #define FALLTHROUGH __attribute((fallthrough)) #else - #define FALLTHROUGH + #define FALLTHROUGH #endif //- Preprocessor concatenation @@ -253,23 +253,23 @@ #define SllQueuePushNZ(nil,f,l,n,next) \ ( \ - CheckNil(nil,f) ? \ - ((f)=(l)=(n),SetNil(nil,(n)->next)) : \ - ((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)) \ + CheckNil(nil,f) ? \ + ((f)=(l)=(n),SetNil(nil,(n)->next)) : \ + ((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)) \ ) #define SllQueuePushFrontNZ(nil,f,l,n,next) \ ( \ - CheckNil(nil,f) ? \ - ((f)=(l)=(n),SetNil(nil,(n)->next)) : \ - ((n)->next=(f),(f)=(n)) \ + CheckNil(nil,f) ? \ + ((f)=(l)=(n),SetNil(nil,(n)->next)) : \ + ((n)->next=(f),(f)=(n)) \ ) #define SllQueuePopNZ(nil,f,l,next) \ ( \ - (f)==(l) ? \ - (SetNil(nil,f),SetNil(nil,l)) : \ - ((f)=(f)->next) \ + (f)==(l) ? \ + (SetNil(nil,f),SetNil(nil,l)) : \ + ((f)=(f)->next) \ ) #define SllQueuePushN(f,l,n,next) SllQueuePushNZ(0,f,l,n,next) @@ -283,28 +283,28 @@ #define DllStackPushNPZ(nil,f,n,next,prev) \ ( \ - SetNil(nil,(n)->prev), \ - ((n)->next = (f)), \ - CheckNil(nil,f) ? (0) : ((f)->prev = (n)), \ - ((f) = (n)) \ + SetNil(nil,(n)->prev), \ + ((n)->next = (f)), \ + CheckNil(nil,f) ? (0) : ((f)->prev = (n)), \ + ((f) = (n)) \ ) #define DllStackInsertNPZ(nil,f,p,n,next,prev) \ ( \ - (CheckNil(nil,f) || CheckNil(nil,p)) ? (DllStackPushNPZ(nil,(f),(n),next,prev)) : \ - ( \ - ((n)->prev = (p)), \ - ((n)->next = (p)->next), \ - ((p)->next = (n)), \ - CheckNil(nil,(p)->next) ? (0) : ((p)->next->prev = (n)) \ - ) \ + (CheckNil(nil,f) || CheckNil(nil,p)) ? (DllStackPushNPZ(nil,(f),(n),next,prev)) : \ + ( \ + ((n)->prev = (p)), \ + ((n)->next = (p)->next), \ + ((p)->next = (n)), \ + CheckNil(nil,(p)->next) ? (0) : ((p)->next->prev = (n)) \ + ) \ ) #define DllStackRemoveNPZ(nil,f,n,next,prev) \ ( \ - ((n) == (f) ? ((f) = (n)->next) : (0)), \ - (CheckNil(nil,(n)->next) ? (0) : ((n)->next->prev = (n)->prev)), \ - (CheckNil(nil,(n)->prev) ? (0) : ((n)->prev->next = (n)->next)) \ + ((n) == (f) ? ((f) = (n)->next) : (0)), \ + (CheckNil(nil,(n)->next) ? (0) : ((n)->next->prev = (n)->prev)), \ + (CheckNil(nil,(n)->prev) ? (0) : ((n)->prev->next = (n)->next)) \ ) #define DllStackPushNP(f,n,next,prev) DllStackPushNPZ(0,f,n,next,prev) @@ -318,29 +318,29 @@ #define DllQueueInsertNPZ(nil,f,l,p,n,next,prev) \ ( \ - CheckNil(nil,f) ? \ - ((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) : \ - CheckNil(nil,p) ? \ - ((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) : \ - ((p)==(l)) ? \ - ((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) : \ - (((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : \ - ( \ - (p)->next->prev = (n))), \ - ((n)->next = (p)->next), \ - ((p)->next = (n)), \ - ((n)->prev = (p)) \ - ) \ + CheckNil(nil,f) ? \ + ((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) : \ + CheckNil(nil,p) ? \ + ((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) : \ + ((p)==(l)) ? \ + ((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) : \ + (((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : \ + ( \ + (p)->next->prev = (n))), \ + ((n)->next = (p)->next), \ + ((p)->next = (n)), \ + ((n)->prev = (p)) \ + ) \ ) #define DllQueueRemoveNPZ(nil,f,l,n,next,prev) \ ( \ - ((n) == (f) ? (f) = (n)->next : (0)), \ - ((n) == (l) ? (l) = (l)->prev : (0)), \ - (CheckNil(nil,(n)->prev) ? (0) : \ - ((n)->prev->next = (n)->next)), \ - (CheckNil(nil,(n)->next) ? (0) : \ - ((n)->next->prev = (n)->prev)) \ + ((n) == (f) ? (f) = (n)->next : (0)), \ + ((n) == (l) ? (l) = (l)->prev : (0)), \ + (CheckNil(nil,(n)->prev) ? (0) : \ + ((n)->prev->next = (n)->next)), \ + (CheckNil(nil,(n)->next) ? (0) : \ + ((n)->next->prev = (n)->prev)) \ ) #define DllQueuePushNPZ(nil,f,l,n,next,prev) DllQueueInsertNPZ(nil,f,l,l,n,next,prev) @@ -384,20 +384,20 @@ //~ Intrinsic headers #if IsLanguageC - /* Intrinsic header info: - * mmintrin.h MMX - * xmmintrin.h SSE - * emmintrin.h SSE2 - * pmmintrin.h SSE3 - * tmmintrin.h SSSE3 - * smmintrin.h SSE4.1 - * nmmintrin.h SSE4.2 - * ammintrin.h SSE4A - * wmmintrin.h AES - * immintrin.h AVX, AVX2, FMA - */ - #include - #include /* SSE4.2 */ + /* Intrinsic header info: + * mmintrin.h MMX + * xmmintrin.h SSE + * emmintrin.h SSE2 + * pmmintrin.h SSE3 + * tmmintrin.h SSSE3 + * smmintrin.h SSE4.1 + * nmmintrin.h SSE4.2 + * ammintrin.h SSE4A + * wmmintrin.h AES + * immintrin.h AVX, AVX2, FMA + */ + #include + #include /* SSE4.2 */ #endif //////////////////////////////////////////////////////////// @@ -410,14 +410,14 @@ //- Enum #if IsLanguageC - #define Enum(name) typedef enum name name; enum name + #define Enum(name) typedef enum name name; enum name #else - #define Enum(name) enum name + #define Enum(name) enum name #endif //- alignof #if IsLanguageC && (IsCompilerMsvc || __STDC_VERSION__ < 202311L) - #define alignof(type) __alignof(type) + #define alignof(type) __alignof(type) #endif //- field sizeof @@ -425,7 +425,7 @@ //- countof #if IsLanguageC - #define countof(a) (sizeof(a) / sizeof((a)[0])) + #define countof(a) (sizeof(a) / sizeof((a)[0])) #endif //- IsFixedArray @@ -434,11 +434,11 @@ //- offsetof #if !IsCompilerMsvc - #ifdef _CRT_USE_BUILTIN_OFFSETOF - #define offsetof(type, field) __builtin_offsetof(type, field) - #else - #define offsetof(type, field) ((u64)&(((type *)0)->field)) - #endif + #ifdef _CRT_USE_BUILTIN_OFFSETOF + #define offsetof(type, field) __builtin_offsetof(type, field) + #else + #define offsetof(type, field) ((u64)&(((type *)0)->field)) + #endif #endif //- struct region @@ -449,44 +449,44 @@ //- Packed #if IsCompilerMsvc - #define Packed(s) __pragma(pack(push, 1)) s __pragma(pack(pop)) + #define Packed(s) __pragma(pack(push, 1)) s __pragma(pack(pop)) #elif IsCompilerClang - #define Packed(s) s __attribute((__packed__)) + #define Packed(s) s __attribute((__packed__)) #elif IsLanguageG - #define Packed(s) s + #define Packed(s) s #endif //- alignas #if (IsCompilerMsvc && IsLanguageC) || (IsLanguageC && __STDC_VERSION__ < 202311L) - #if IsCompilerMsvc - #define alignas(n) __declspec(align(n)) - #else - #define alignas(n) __attribute__((aligned(n))) - #endif + #if IsCompilerMsvc + #define alignas(n) __declspec(align(n)) + #else + #define alignas(n) __attribute__((aligned(n))) + #endif #endif //////////////////////////////////////////////////////////// //~ Scalar types #if IsLanguageC - typedef int8_t i8; - typedef int16_t i16; - typedef int32_t i32; - typedef int64_t i64; - typedef uint8_t u8; - typedef uint16_t u16; - typedef uint32_t u32; - typedef uint64_t u64; - typedef float f32; - typedef double f64; - typedef i8 b8; - typedef u32 b32; - Struct(U128) { u64 hi; u64 lo; }; + typedef int8_t i8; + typedef int16_t i16; + typedef int32_t i32; + typedef int64_t i64; + typedef uint8_t u8; + typedef uint16_t u16; + typedef uint32_t u32; + typedef uint64_t u64; + typedef float f32; + typedef double f64; + typedef i8 b8; + typedef u32 b32; + Struct(U128) { u64 hi; u64 lo; }; #elif IsLanguageG - typedef int i32; - typedef uint u32; - typedef float f32; - typedef uint b32; + typedef int i32; + typedef uint u32; + typedef float f32; + typedef uint b32; #endif //- Min / max constants @@ -507,274 +507,274 @@ //- Float infinity / nan constants #if IsLanguageC - Global const u32 _f32_infinity_u32 = 0x7f800000; - Global const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32; - #define F32Infinity (*_f32_infinity) + Global const u32 _f32_infinity_u32 = 0x7f800000; + Global const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32; + #define F32Infinity (*_f32_infinity) - Global const u64 _f64_infinity_u64 = 0x7ff0000000000000ULL; - Global const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64; - #define F64Infinity (*_f64_infinity) + Global const u64 _f64_infinity_u64 = 0x7ff0000000000000ULL; + Global const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64; + #define F64Infinity (*_f64_infinity) - Global const u32 _f32_nan_u32 = 0x7f800001; - Global const f32 *_f32_nan = (f32 *)&_f32_nan_u32; - #define F32Nan (*_f32_nan) + Global const u32 _f32_nan_u32 = 0x7f800001; + Global const f32 *_f32_nan = (f32 *)&_f32_nan_u32; + #define F32Nan (*_f32_nan) - Global const u64 _f64_nan_u64 = 0x7ff8000000000001; - Global const f64 *_f64_nan = (f64 *)&_f64_nan_u64; - #define F64Nan (*_f64_nan) + Global const u64 _f64_nan_u64 = 0x7ff8000000000001; + Global const f64 *_f64_nan = (f64 *)&_f64_nan_u64; + #define F64Nan (*_f64_nan) - #define IsF32Nan(x) (x != x) - #define IsF64Nan(x) (x != x) + #define IsF32Nan(x) (x != x) + #define IsF64Nan(x) (x != x) #endif //////////////////////////////////////////////////////////// //~ Atomics #if IsLanguageC - //- Atomic types - Struct(Atomic8) { volatile i8 _v; }; - Struct(Atomic16) { volatile i16 _v; }; - Struct(Atomic32) { volatile i32 _v; }; - Struct(Atomic64) { volatile i64 _v; }; + //- Atomic types + Struct(Atomic8) { volatile i8 _v; }; + Struct(Atomic16) { volatile i16 _v; }; + Struct(Atomic32) { volatile i32 _v; }; + Struct(Atomic64) { volatile i64 _v; }; - //- Cache-line isolated aligned atomic types - AlignedStruct(Atomic8Padded, CachelineSize) { Atomic8 v; }; - AlignedStruct(Atomic16Padded, CachelineSize) { Atomic16 v; }; - AlignedStruct(Atomic32Padded, CachelineSize) { Atomic32 v; }; - AlignedStruct(Atomic64Padded, CachelineSize) { Atomic64 v; }; - StaticAssert(alignof(Atomic8Padded) == CachelineSize && sizeof(Atomic8Padded) % CachelineSize == 0); - StaticAssert(alignof(Atomic16Padded) == CachelineSize && sizeof(Atomic16Padded) % CachelineSize == 0); - StaticAssert(alignof(Atomic32Padded) == CachelineSize && sizeof(Atomic32Padded) % CachelineSize == 0); - StaticAssert(alignof(Atomic64Padded) == CachelineSize && sizeof(Atomic64Padded) % CachelineSize == 0); + //- Cache-line isolated aligned atomic types + AlignedStruct(Atomic8Padded, CachelineSize) { Atomic8 v; }; + AlignedStruct(Atomic16Padded, CachelineSize) { Atomic16 v; }; + AlignedStruct(Atomic32Padded, CachelineSize) { Atomic32 v; }; + AlignedStruct(Atomic64Padded, CachelineSize) { Atomic64 v; }; + StaticAssert(alignof(Atomic8Padded) == CachelineSize && sizeof(Atomic8Padded) % CachelineSize == 0); + StaticAssert(alignof(Atomic16Padded) == CachelineSize && sizeof(Atomic16Padded) % CachelineSize == 0); + StaticAssert(alignof(Atomic32Padded) == CachelineSize && sizeof(Atomic32Padded) % CachelineSize == 0); + StaticAssert(alignof(Atomic64Padded) == CachelineSize && sizeof(Atomic64Padded) % CachelineSize == 0); - #if IsPlatformWindows && IsArchX64 - //- 8 bit atomic ops - ForceInline i8 Atomic8Fetch (Atomic8 *x) { CompilerBarrier(); i8 result = x->_v; CompilerBarrier(); return result; } - ForceInline void Atomic8Set (Atomic8 *x, i8 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } - ForceInline i8 Atomic8FetchSet (Atomic8 *x, i8 e) { return (i8)_InterlockedExchange8((volatile char *)&x->_v, e); } - ForceInline i8 Atomic8FetchTestSet (Atomic8 *x, i8 c, i8 e) { return (i8)_InterlockedCompareExchange8((volatile char *)&x->_v, e, c); } - ForceInline i8 Atomic8FetchXor (Atomic8 *x, i8 c) { return (i8)_InterlockedXor8((volatile char *)&x->_v, c); } - ForceInline i8 Atomic8FetchAdd (Atomic8 *x, i8 a) { return (i8)_InterlockedExchangeAdd8((volatile char *)&x->_v, a); } - //- 16 bit atomic ops - ForceInline i16 Atomic16Fetch (Atomic16 *x) { CompilerBarrier(); i16 result = x->_v; CompilerBarrier(); return result; } - ForceInline void Atomic16Set (Atomic16 *x, i16 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } - ForceInline i16 Atomic16FetchSet (Atomic16 *x, i16 e) { return (i16)_InterlockedExchange16(&x->_v, e); } - ForceInline i16 Atomic16FetchTestSet (Atomic16 *x, i16 c, i16 e) { return (i16)_InterlockedCompareExchange16(&x->_v, e, c); } - ForceInline i16 Atomic16FetchXor (Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&x->_v, c); } - ForceInline i16 Atomic16FetchAdd (Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&x->_v, a); } - //- 32 bit atomic ops - ForceInline i32 Atomic32Fetch (Atomic32 *x) { CompilerBarrier(); i32 result = x->_v; CompilerBarrier(); return result; } - ForceInline void Atomic32Set (Atomic32 *x, i32 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } - ForceInline i32 Atomic32FetchSet (Atomic32 *x, i32 e) { return (i32)_InterlockedExchange((volatile long *)&x->_v, e); } - ForceInline i32 Atomic32FetchTestSet (Atomic32 *x, i32 c, i32 e) { return (i32)_InterlockedCompareExchange((volatile long *)&x->_v, e, c); } - ForceInline i32 Atomic32FetchXor (Atomic32 *x, i32 c) { return (i32)_InterlockedXor((volatile long *)&x->_v, c); } - ForceInline i32 Atomic32FetchAdd (Atomic32 *x, i32 a) { return (i32)_InterlockedExchangeAdd((volatile long *)&x->_v, a); } - //- 64 bit atomic ops - ForceInline i64 Atomic64Fetch (Atomic64 *x) { CompilerBarrier(); i64 result = x->_v; CompilerBarrier(); return result; } - ForceInline void Atomic64Set (Atomic64 *x, i64 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } - ForceInline i64 Atomic64FetchSet (Atomic64 *x, i64 e) { return (i64)_InterlockedExchange64(&x->_v, e); } - ForceInline i64 Atomic64FetchTestSet (Atomic64 *x, i64 c, i64 e) { return (i64)_InterlockedCompareExchange64(&x->_v, e, c); } - ForceInline i64 Atomic64FetchXor (Atomic64 *x, i64 c) { return (i64)_InterlockedXor64(&x->_v, c); } - ForceInline i64 Atomic64FetchAdd (Atomic64 *x, i64 a) { return (i64)_InterlockedExchangeAdd64(&x->_v, a); } - #else - #error Atomics not implemented - #endif + #if IsPlatformWindows && IsArchX64 + //- 8 bit atomic ops + ForceInline i8 Atomic8Fetch (Atomic8 *x) { CompilerBarrier(); i8 result = x->_v; CompilerBarrier(); return result; } + ForceInline void Atomic8Set (Atomic8 *x, i8 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } + ForceInline i8 Atomic8FetchSet (Atomic8 *x, i8 e) { return (i8)_InterlockedExchange8((volatile char *)&x->_v, e); } + ForceInline i8 Atomic8FetchTestSet (Atomic8 *x, i8 c, i8 e) { return (i8)_InterlockedCompareExchange8((volatile char *)&x->_v, e, c); } + ForceInline i8 Atomic8FetchXor (Atomic8 *x, i8 c) { return (i8)_InterlockedXor8((volatile char *)&x->_v, c); } + ForceInline i8 Atomic8FetchAdd (Atomic8 *x, i8 a) { return (i8)_InterlockedExchangeAdd8((volatile char *)&x->_v, a); } + //- 16 bit atomic ops + ForceInline i16 Atomic16Fetch (Atomic16 *x) { CompilerBarrier(); i16 result = x->_v; CompilerBarrier(); return result; } + ForceInline void Atomic16Set (Atomic16 *x, i16 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } + ForceInline i16 Atomic16FetchSet (Atomic16 *x, i16 e) { return (i16)_InterlockedExchange16(&x->_v, e); } + ForceInline i16 Atomic16FetchTestSet (Atomic16 *x, i16 c, i16 e) { return (i16)_InterlockedCompareExchange16(&x->_v, e, c); } + ForceInline i16 Atomic16FetchXor (Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&x->_v, c); } + ForceInline i16 Atomic16FetchAdd (Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&x->_v, a); } + //- 32 bit atomic ops + ForceInline i32 Atomic32Fetch (Atomic32 *x) { CompilerBarrier(); i32 result = x->_v; CompilerBarrier(); return result; } + ForceInline void Atomic32Set (Atomic32 *x, i32 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } + ForceInline i32 Atomic32FetchSet (Atomic32 *x, i32 e) { return (i32)_InterlockedExchange((volatile long *)&x->_v, e); } + ForceInline i32 Atomic32FetchTestSet (Atomic32 *x, i32 c, i32 e) { return (i32)_InterlockedCompareExchange((volatile long *)&x->_v, e, c); } + ForceInline i32 Atomic32FetchXor (Atomic32 *x, i32 c) { return (i32)_InterlockedXor((volatile long *)&x->_v, c); } + ForceInline i32 Atomic32FetchAdd (Atomic32 *x, i32 a) { return (i32)_InterlockedExchangeAdd((volatile long *)&x->_v, a); } + //- 64 bit atomic ops + ForceInline i64 Atomic64Fetch (Atomic64 *x) { CompilerBarrier(); i64 result = x->_v; CompilerBarrier(); return result; } + ForceInline void Atomic64Set (Atomic64 *x, i64 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); } + ForceInline i64 Atomic64FetchSet (Atomic64 *x, i64 e) { return (i64)_InterlockedExchange64(&x->_v, e); } + ForceInline i64 Atomic64FetchTestSet (Atomic64 *x, i64 c, i64 e) { return (i64)_InterlockedCompareExchange64(&x->_v, e, c); } + ForceInline i64 Atomic64FetchXor (Atomic64 *x, i64 c) { return (i64)_InterlockedXor64(&x->_v, c); } + ForceInline i64 Atomic64FetchAdd (Atomic64 *x, i64 a) { return (i64)_InterlockedExchangeAdd64(&x->_v, a); } + #else + #error Atomics not implemented + #endif #endif //////////////////////////////////////////////////////////// //~ Ticket mutex #if IsLanguageC - Struct(TicketMutex) - { - Atomic64Padded ticket; - Atomic64Padded serving; - }; + Struct(TicketMutex) + { + Atomic64Padded ticket; + Atomic64Padded serving; + }; - ForceInline void LockTicketMutex(TicketMutex *tm) + ForceInline void LockTicketMutex(TicketMutex *tm) + { + i64 ticket = Atomic64FetchAdd(&tm->ticket.v, 1); + while (Atomic64Fetch(&tm->serving.v) != ticket) { - i64 ticket = Atomic64FetchAdd(&tm->ticket.v, 1); - while (Atomic64Fetch(&tm->serving.v) != ticket) - { - _mm_pause(); - } + _mm_pause(); } + } - ForceInline void UnlockTicketMutex(TicketMutex *tm) - { - /* TODO: Atomic set w/ known ticket + 1 */ - Atomic64FetchAdd(&tm->serving.v, 1); - } + ForceInline void UnlockTicketMutex(TicketMutex *tm) + { + /* TODO: Atomic set w/ known ticket + 1 */ + Atomic64FetchAdd(&tm->serving.v, 1); + } #endif //////////////////////////////////////////////////////////// //~ String types #if IsLanguageC - #define STRING(size, data) ((String) { (size), (data) }) - #define Zstr ((String) { 0, 0}) - #define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } - #define CompLit(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) } - #define StringFromPointers(p0, p1) ((String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 }) - #define StringFromStruct(ptr) ((String) { sizeof(*(ptr)), (u8 *)(ptr) }) - #define StringFromArena(arena) (STRING((arena)->pos, ArenaFirst(arena, u8))) + #define STRING(size, data) ((String) { (size), (data) }) + #define Zstr ((String) { 0, 0}) + #define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } + #define CompLit(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) } + #define StringFromPointers(p0, p1) ((String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 }) + #define StringFromStruct(ptr) ((String) { sizeof(*(ptr)), (u8 *)(ptr) }) + #define StringFromArena(arena) (STRING((arena)->pos, ArenaFirst(arena, u8))) - #define StringFromFixedArray(a) \ - ( \ - Assert(IsFixedArray(a)), \ - ((String) { .len = sizeof(a), .text = (u8 *)(a) }) \ - ) + #define StringFromFixedArray(a) \ + ( \ + Assert(IsFixedArray(a)), \ + ((String) { .len = sizeof(a), .text = (u8 *)(a) }) \ + ) - Struct(String) - { - u64 len; - u8 *text; - }; + Struct(String) + { + u64 len; + u8 *text; + }; - Struct(String16) - { - u64 len; - u16 *text; - }; + Struct(String16) + { + u64 len; + u16 *text; + }; - Struct(String32) - { - u64 len; - u32 *text; - }; + Struct(String32) + { + u64 len; + u32 *text; + }; - Struct(StringArray) - { - u64 count; - String *strings; - }; + Struct(StringArray) + { + u64 count; + String *strings; + }; - Struct(StringListNode) - { - String s; - StringListNode *next; - StringListNode *prev; - }; + Struct(StringListNode) + { + String s; + StringListNode *next; + StringListNode *prev; + }; - Struct(StringList) - { - StringListNode *first; - StringListNode *last; - u64 count; - }; + Struct(StringList) + { + StringListNode *first; + StringListNode *last; + u64 count; + }; #endif //////////////////////////////////////////////////////////// //~ Arena types #if IsLanguageC - Struct(Arena) - { - u64 pos; - u64 committed; - u64 reserved; - }; + Struct(Arena) + { + u64 pos; + u64 committed; + u64 reserved; + }; - Struct(TempArena) - { - Arena *arena; - u64 start_pos; - }; + Struct(TempArena) + { + Arena *arena; + u64 start_pos; + }; #endif //////////////////////////////////////////////////////////// //~ Resource types #if IsLanguageC - #define ResourceEmbeddedMagic 0xfc060937194f4406 + #define ResourceEmbeddedMagic 0xfc060937194f4406 - Struct(ResourceStore) - { - u64 v; - }; + Struct(ResourceStore) + { + u64 v; + }; - Struct(ResourceKey) - { - u64 v; - }; + Struct(ResourceKey) + { + u64 v; + }; #endif //////////////////////////////////////////////////////////// //~ Cpu topology types #if IsLanguageC - Struct(CpuTopologyInfo) - { - i32 num_logical_cores; /* Includes P cores, Non-P cores, SMT siblings */ - i32 num_physical_cores; /* Includes P Cores, Non-P Cores */ - i32 num_physical_performance_cores; /* Includes P Cores */ - i32 num_physical_non_performance_cores; /* Includes Non-P cores */ - }; + Struct(CpuTopologyInfo) + { + i32 num_logical_cores; /* Includes P cores, Non-P cores, SMT siblings */ + i32 num_physical_cores; /* Includes P Cores, Non-P Cores */ + i32 num_physical_performance_cores; /* Includes P Cores */ + i32 num_physical_non_performance_cores; /* Includes Non-P cores */ + }; #endif //////////////////////////////////////////////////////////// //~ Shader linkage types #if IsLanguageC - Struct(VertexShader) { ResourceKey resource; }; - Struct(PixelShader) { ResourceKey resource; }; - Struct(ComputeShader) { ResourceKey resource; }; + Struct(VertexShader) { ResourceKey resource; }; + Struct(PixelShader) { ResourceKey resource; }; + Struct(ComputeShader) { ResourceKey resource; }; #elif IsLanguageG - #define Semantic(t, n) t n : n - #define ComputeShader(name, x) [numthreads(x, 1, 1)] void name(Semantic(u32, SV_DispatchThreadID)) - #define ComputeShader2D(name, x, y) [numthreads(x, y, 1)] void name(Semantic(Vec2U32, SV_DispatchThreadID)) - #define ComputeShader3D(name, x, y, z) [numthreads(x, y, z)] void name(Semantic(Vec3U32, SV_DispatchThreadID)) - #define VertexShader(name, return_type) return_type name(Semantic(u32, SV_InstanceID), Semantic(u32, SV_VertexID)) - #define PixelShader(name, return_type, ...) return_type name(__VA_ARGS__) + #define Semantic(t, n) t n : n + #define ComputeShader(name, x) [numthreads(x, 1, 1)] void name(Semantic(u32, SV_DispatchThreadID)) + #define ComputeShader2D(name, x, y) [numthreads(x, y, 1)] void name(Semantic(Vec2U32, SV_DispatchThreadID)) + #define ComputeShader3D(name, x, y, z) [numthreads(x, y, z)] void name(Semantic(Vec3U32, SV_DispatchThreadID)) + #define VertexShader(name, return_type) return_type name(Semantic(u32, SV_InstanceID), Semantic(u32, SV_VertexID)) + #define PixelShader(name, return_type, ...) return_type name(__VA_ARGS__) #endif //////////////////////////////////////////////////////////// //~ Exit callback types #if IsLanguageC - #define ExitFuncDef(name) void name(void) - typedef ExitFuncDef(ExitFunc); + #define ExitFuncDef(name) void name(void) + typedef ExitFuncDef(ExitFunc); #endif //////////////////////////////////////////////////////////// //~ @hookdecl Core api #if IsLanguageC - StringList GetRawCommandline(void); - void Echo(String msg); - b32 Panic(String msg); - b32 IsRunningInDebugger(void); - i64 TimeNs(void); - void TrueRand(String buffer); - CpuTopologyInfo GetCpuTopologyInfo(void); - void SleepSeconds(f64 seconds); + StringList GetRawCommandline(void); + void Echo(String msg); + b32 Panic(String msg); + b32 IsRunningInDebugger(void); + i64 TimeNs(void); + void TrueRand(String buffer); + CpuTopologyInfo GetCpuTopologyInfo(void); + void SleepSeconds(f64 seconds); #endif //////////////////////////////////////////////////////////// //~ @hookdecl Swap #if IsLanguageC - b32 IsSwappedIn(void); - b32 IsSwappingOut(void); + b32 IsSwappedIn(void); + b32 IsSwappingOut(void); - String SwappedStateFromName(Arena *arena, String name); - void WriteSwappedState(String name, String data); + String SwappedStateFromName(Arena *arena, String name); + void WriteSwappedState(String name, String data); #endif //////////////////////////////////////////////////////////// //~ @hookdecl Exit #if IsLanguageC - void OnExit(ExitFunc *func); - void SignalExit(i32 code); - void ExitNow(i32 code); + void OnExit(ExitFunc *func); + void SignalExit(i32 code); + void ExitNow(i32 code); #endif //////////////////////////////////////////////////////////// //~ @hookdecl Bootstrap layers #if IsLanguageC - void BootstrapLayers(void); + void BootstrapLayers(void); #endif //////////////////////////////////////////////////////////// diff --git a/src/base/base_arena.c b/src/base/base_arena.c index 60f853d4..1f8d9aea 100644 --- a/src/base/base_arena.c +++ b/src/base/base_arena.c @@ -3,86 +3,86 @@ Arena *AcquireArena(u64 reserve) { - reserve += ArenaHeaderSize; + reserve += ArenaHeaderSize; - /* Round up to nearest block size */ - u64 block_remainder = reserve % ArenaBlockSize; - if (block_remainder > 0) - { - reserve += ArenaBlockSize - block_remainder; - } + /* Round up to nearest block size */ + u64 block_remainder = reserve % ArenaBlockSize; + if (block_remainder > 0) + { + reserve += ArenaBlockSize - block_remainder; + } - u8 *base = ReserveMemory(reserve); - if (!base) - { - Panic(Lit("Failed to reserve memory")); - } - u64 reserved = reserve; - AddGstat(ArenaMemoryReserved, reserve); + u8 *base = ReserveMemory(reserve); + if (!base) + { + Panic(Lit("Failed to reserve memory")); + } + u64 reserved = reserve; + AddGstat(ArenaMemoryReserved, reserve); - /* Commit initial block */ - base = CommitMemory(base, ArenaBlockSize); - if (!base) - { - Panic(Lit("Failed to commit initial memory block: System may be out of memory")); - } + /* Commit initial block */ + base = CommitMemory(base, ArenaBlockSize); + if (!base) + { + Panic(Lit("Failed to commit initial memory block: System may be out of memory")); + } - Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */ - StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */ - StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */ + Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */ + StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */ + StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */ - AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena)); - AddGstat(ArenaMemoryCommitted, ArenaBlockSize); - AddGstat(NumArenas, 1); + AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena)); + AddGstat(ArenaMemoryCommitted, ArenaBlockSize); + AddGstat(NumArenas, 1); - /* Create & return arena header at beginning of block */ - Arena *arena = (Arena *)base; - ZeroStruct(arena); - arena->committed = ArenaBlockSize - ArenaHeaderSize; - arena->reserved = reserved; - return arena; + /* Create & return arena header at beginning of block */ + Arena *arena = (Arena *)base; + ZeroStruct(arena); + arena->committed = ArenaBlockSize - ArenaHeaderSize; + arena->reserved = reserved; + return arena; } void ReleaseArena(Arena *arena) { - AsanUnpoison(arena, arena->committed + ArenaHeaderSize); - AddGstat(ArenaMemoryCommitted, -(i64)(arena->committed - ArenaHeaderSize)); - AddGstat(ArenaMemoryReserved, -(i64)(arena->reserved)); - AddGstat(NumArenas, -1); - ReleaseMemory(arena); + AsanUnpoison(arena, arena->committed + ArenaHeaderSize); + AddGstat(ArenaMemoryCommitted, -(i64)(arena->committed - ArenaHeaderSize)); + AddGstat(ArenaMemoryReserved, -(i64)(arena->reserved)); + AddGstat(NumArenas, -1); + ReleaseMemory(arena); } /* Copy the memory from src to dst, replacing old contents. - * Dst will expand if necessary. */ +* Dst will expand if necessary. */ void CopyArena(Arena *dst, Arena *src) { - ResetArena(dst); - u64 data_size = src->pos; - u8 *data_src = ArenaFirst(src, u8); - u8 *data_dst = PushBytesNoZero(dst, data_size, 1); - CopyBytes(data_dst, data_src, data_size); + ResetArena(dst); + u64 data_size = src->pos; + u8 *data_src = ArenaFirst(src, u8); + u8 *data_dst = PushBytesNoZero(dst, data_size, 1); + CopyBytes(data_dst, data_src, data_size); } void ShrinkArena(Arena *arena) { - /* Not implemented */ - Assert(0); + /* Not implemented */ + Assert(0); } void SetArenaReadonly(Arena *arena) { - SetMemoryReadonly(arena, arena->committed + ArenaHeaderSize); + SetMemoryReadonly(arena, arena->committed + ArenaHeaderSize); } void SetArenaReadWrite(Arena *arena) { - SetMemoryReadWrite(arena, arena->committed + ArenaHeaderSize); + SetMemoryReadWrite(arena, arena->committed + ArenaHeaderSize); } void *ResetArena(Arena *arena) { - PopTo(arena, 0); - return ArenaFirst(arena, u8); + PopTo(arena, 0); + return ArenaFirst(arena, u8); } //////////////////////////////////////////////////////////// @@ -90,89 +90,89 @@ void *ResetArena(Arena *arena) void *PushBytesNoZero(Arena *arena, u64 size, u64 align) { - Assert(align > 0); + Assert(align > 0); - u8 *base = ArenaFirst(arena, u8); - u64 start_pos = AlignU64(arena->pos, align); - u64 end_pos = start_pos + size; - void *result = base + start_pos; + u8 *base = ArenaFirst(arena, u8); + u64 start_pos = AlignU64(arena->pos, align); + u64 end_pos = start_pos + size; + void *result = base + start_pos; - /* Commit new block(s) */ - if (size > 0 && end_pos > arena->committed) + /* Commit new block(s) */ + if (size > 0 && end_pos > arena->committed) + { + u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize; + u64 commit_bytes = blocks_needed * ArenaBlockSize; + u64 new_capacity = arena->committed + commit_bytes; + if (new_capacity > arena->reserved) { - u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize; - u64 commit_bytes = blocks_needed * ArenaBlockSize; - u64 new_capacity = arena->committed + commit_bytes; - if (new_capacity > arena->reserved) - { - /* Hard fail if we overflow reserved memory for now */ - Panic(Lit("Failed to commit new memory block: Overflow of reserved memory")); - } - void *commit_address = base + arena->committed; - if (!CommitMemory(commit_address, commit_bytes)) - { - /* Hard fail on memory allocation failure for now */ - Panic(Lit("Failed to commit new memory block: System may be out of memory")); - } - arena->committed += commit_bytes; - AddGstat(ArenaMemoryCommitted, commit_bytes); - AsanPoison(commit_address, commit_bytes); + /* Hard fail if we overflow reserved memory for now */ + Panic(Lit("Failed to commit new memory block: Overflow of reserved memory")); } + void *commit_address = base + arena->committed; + if (!CommitMemory(commit_address, commit_bytes)) + { + /* Hard fail on memory allocation failure for now */ + Panic(Lit("Failed to commit new memory block: System may be out of memory")); + } + arena->committed += commit_bytes; + AddGstat(ArenaMemoryCommitted, commit_bytes); + AsanPoison(commit_address, commit_bytes); + } - AsanUnpoison(result, size); - arena->pos = end_pos; + AsanUnpoison(result, size); + arena->pos = end_pos; - return result; + return result; } void *PushBytes(Arena *arena, u64 size, u64 align) { - void *p = PushBytesNoZero(arena, size, align); - ZeroBytes(p, size); - return p; + void *p = PushBytesNoZero(arena, size, align); + ZeroBytes(p, size); + return p; } void *PushAlign(Arena *arena, u64 align) { - u64 push_count = AlignU64(arena->pos, align) - arena->pos; - return PushStructsNoZero(arena, u8, push_count); + u64 push_count = AlignU64(arena->pos, align) - arena->pos; + return PushStructsNoZero(arena, u8, push_count); } void PopTo(Arena *arena, u64 pos) { - Assert(arena->pos >= pos); - AsanPoison(ArenaFirst(arena, u8) + pos, arena->pos - pos); - arena->pos = pos; + Assert(arena->pos >= pos); + AsanPoison(ArenaFirst(arena, u8) + pos, arena->pos - pos); + arena->pos = pos; } void PopBytesNoCopy(Arena *arena, u64 size) { - Assert(arena->pos >= size); - u64 new_pos = arena->pos - size; - AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos); - arena->pos = new_pos; + Assert(arena->pos >= size); + u64 new_pos = arena->pos - size; + AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos); + arena->pos = new_pos; } void PopBytes(Arena *arena, u64 size, void *copy_dst) { - Assert(arena->pos >= size); - u64 new_pos = arena->pos - size; - void *src = (void *)(ArenaFirst(arena, u8) + new_pos); - CopyBytes(copy_dst, src, size); - AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos); - arena->pos = new_pos; + Assert(arena->pos >= size); + u64 new_pos = arena->pos - size; + void *src = (void *)(ArenaFirst(arena, u8) + new_pos); + CopyBytes(copy_dst, src, size); + AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos); + arena->pos = new_pos; } void *ArenaFirst_(Arena *arena, u64 align) { - void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize, align); - return result; + void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize, align); + return result; } void *ArenaNext_(Arena *arena, u64 align) { - void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize + arena->pos, align); - return result; + void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize + arena->pos, align); + return result; } //////////////////////////////////////////////////////////// @@ -180,15 +180,15 @@ void *ArenaNext_(Arena *arena, u64 align) TempArena BeginTempArena(Arena *arena) { - TempArena t = Zi; - t.arena = arena; - t.start_pos = arena->pos; - return t; + TempArena t = Zi; + t.arena = arena; + t.start_pos = arena->pos; + return t; } void EndTempArena(TempArena temp) { - PopTo(temp.arena, temp.start_pos); + PopTo(temp.arena, temp.start_pos); } //////////////////////////////////////////////////////////// @@ -196,29 +196,29 @@ void EndTempArena(TempArena temp) TempArena BeginScratch(Arena *potential_conflict) { - /* This function is currently hard-coded for 2 thread-local scratch arenas */ - StaticAssert(countof(Base_tl.arenas.scratch) == 2); + /* This function is currently hard-coded for 2 thread-local scratch arenas */ + StaticAssert(countof(Base_tl.arenas.scratch) == 2); - /* Use `BeginScratchNoConflict` if no conflicts are present */ - Assert(potential_conflict != 0); + /* Use `BeginScratchNoConflict` if no conflicts are present */ + Assert(potential_conflict != 0); - Arena *scratch_arena = Base_tl.arenas.scratch[0]; - if (scratch_arena == potential_conflict) - { - scratch_arena = Base_tl.arenas.scratch[1]; - } - TempArena temp = BeginTempArena(scratch_arena); - return temp; + Arena *scratch_arena = Base_tl.arenas.scratch[0]; + if (scratch_arena == potential_conflict) + { + scratch_arena = Base_tl.arenas.scratch[1]; + } + TempArena temp = BeginTempArena(scratch_arena); + return temp; } TempArena BeginScratchNoConflict_(void) { - Arena *scratch_arena = Base_tl.arenas.scratch[0]; - TempArena temp = BeginTempArena(scratch_arena); - return temp; + Arena *scratch_arena = Base_tl.arenas.scratch[0]; + TempArena temp = BeginTempArena(scratch_arena); + return temp; } void EndScratch(TempArena scratch_temp) { - EndTempArena(scratch_temp); + EndTempArena(scratch_temp); } diff --git a/src/base/base_arena.h b/src/base/base_arena.h index 89c8e93b..a0d8fe6f 100644 --- a/src/base/base_arena.h +++ b/src/base/base_arena.h @@ -6,8 +6,8 @@ Struct(ThreadLocalArenaCtx) { - Arena *perm; - Arena *scratch[2]; + Arena *perm; + Arena *scratch[2]; }; //////////////////////////////////////////////////////////// @@ -68,11 +68,11 @@ TempArena BeginScratchNoConflict_(void); void EndScratch(TempArena scratch_temp); /* This macro declares an unused "arena" variable that will produce a shadowing - * warning variable is present (due to shadowing). This is for catching obvious - * cases of `BeginScratchNoConflict` getting called when an `arena` variable - * already exists in the caller's scope. */ +* warning variable is present (due to shadowing). This is for catching obvious +* cases of `BeginScratchNoConflict` getting called when an `arena` variable +* already exists in the caller's scope. */ #define BeginScratchNoConflict() \ - BeginScratchNoConflict_(); \ - do { \ - u8 arena = 0; \ - } while (0) + BeginScratchNoConflict_(); \ + do { \ + u8 arena = 0; \ + } while (0) diff --git a/src/base/base_async.c b/src/base/base_async.c index 6aab47c1..121b752b 100644 --- a/src/base/base_async.c +++ b/src/base/base_async.c @@ -3,8 +3,8 @@ void BootstrapAsync(void) { - /* TODO: Dynamic lane counts */ - DispatchWave(Lit("Async"), 4, AsyncWorkerEntryPoint, 0); + /* TODO: Dynamic lane counts */ + DispatchWave(Lit("Async"), 4, AsyncWorkerEntryPoint, 0); } //////////////////////////////////////////////////////////// @@ -12,23 +12,23 @@ void BootstrapAsync(void) void OnAsyncTick(AsyncTickCallbackFunc *func) { - Arena *perm = PermArena(); + Arena *perm = PermArena(); - AsyncTickCallbackNode *n = PushStruct(perm, AsyncTickCallbackNode); - n->callback.func = func; + AsyncTickCallbackNode *n = PushStruct(perm, AsyncTickCallbackNode); + n->callback.func = func; - Lock lock = LockE(&Base.async.mutex); - { - SllQueuePush(Base.async.first_callback_node, Base.async.last_callback_node, n); - Base.async.callback_nodes_count += 1; - } - Unlock(&lock); + Lock lock = LockE(&Base.async.mutex); + { + SllQueuePush(Base.async.first_callback_node, Base.async.last_callback_node, n); + Base.async.callback_nodes_count += 1; + } + Unlock(&lock); } void SignalAsyncTick(void) { - Atomic64FetchAdd(&Base.async.signal.v, 1); - FutexWakeNeq(&Base.async.signal.v); + Atomic64FetchAdd(&Base.async.signal.v, 1); + FutexWakeNeq(&Base.async.signal.v); } //////////////////////////////////////////////////////////// @@ -36,67 +36,67 @@ void SignalAsyncTick(void) void AsyncWorkerEntryPoint(WaveLaneCtx *lane) { - AsyncTickCtx tick = Zi; - tick.arena = AcquireArena(Gibi(64)); + AsyncTickCtx tick = Zi; + tick.arena = AcquireArena(Gibi(64)); - /* Tick forever */ - for (;;) + /* Tick forever */ + for (;;) + { + AsyncWorkerCtx *w = &Base.async.worker; + + ////////////////////////////// + //- Begin tick + + if (lane->idx == 0) { - AsyncWorkerCtx *w = &Base.async.worker; - - ////////////////////////////// - //- Begin tick - - if (lane->idx == 0) + /* Wait for signal */ + { + i64 cur_signal = Atomic64Fetch(&Base.async.signal.v); + while (cur_signal <= w->last_seen_signal) { - /* Wait for signal */ - { - i64 cur_signal = Atomic64Fetch(&Base.async.signal.v); - while (cur_signal <= w->last_seen_signal) - { - FutexYieldNeq(&Base.async.signal.v, &cur_signal, sizeof(cur_signal)); - cur_signal = Atomic64Fetch(&Base.async.signal.v); - } - w->last_seen_signal = cur_signal; - } - /* Collect callbacks */ - { - Lock lock = LockE(&Base.async.mutex); - { - w->callbacks_count = Base.async.callback_nodes_count; - w->callbacks = PushStructsNoZero(tick.arena, AsyncTickCallback, w->callbacks_count); - u64 callback_idx = 0; - for (AsyncTickCallbackNode *n = Base.async.first_callback_node; n; n = n->next) - { - w->callbacks[callback_idx] = n->callback; - ++callback_idx; - } - } - Unlock(&lock); - } + FutexYieldNeq(&Base.async.signal.v, &cur_signal, sizeof(cur_signal)); + cur_signal = Atomic64Fetch(&Base.async.signal.v); } - - WaveSync(lane); - - ////////////////////////////// - //- Run async callbacks - - for (u64 callback_idx = 0; callback_idx < w->callbacks_count; ++callback_idx) + w->last_seen_signal = cur_signal; + } + /* Collect callbacks */ + { + Lock lock = LockE(&Base.async.mutex); { - AsyncTickCallback *callback = &w->callbacks[callback_idx]; - callback->func(lane, &tick); - } - - ////////////////////////////// - //- End tick - - WaveSync(lane); - - ResetArena(tick.arena); - { - Arena *tick_arena = tick.arena; - ZeroStruct(&tick); - tick.arena = tick_arena; + w->callbacks_count = Base.async.callback_nodes_count; + w->callbacks = PushStructsNoZero(tick.arena, AsyncTickCallback, w->callbacks_count); + u64 callback_idx = 0; + for (AsyncTickCallbackNode *n = Base.async.first_callback_node; n; n = n->next) + { + w->callbacks[callback_idx] = n->callback; + ++callback_idx; + } } + Unlock(&lock); + } } + + WaveSync(lane); + + ////////////////////////////// + //- Run async callbacks + + for (u64 callback_idx = 0; callback_idx < w->callbacks_count; ++callback_idx) + { + AsyncTickCallback *callback = &w->callbacks[callback_idx]; + callback->func(lane, &tick); + } + + ////////////////////////////// + //- End tick + + WaveSync(lane); + + ResetArena(tick.arena); + { + Arena *tick_arena = tick.arena; + ZeroStruct(&tick); + tick.arena = tick_arena; + } + } } diff --git a/src/base/base_async.h b/src/base/base_async.h index 6432f8a1..791b32f6 100644 --- a/src/base/base_async.h +++ b/src/base/base_async.h @@ -6,37 +6,37 @@ typedef void AsyncTickCallbackFunc(WaveLaneCtx *lane, AsyncTickCtx *tick); Struct(AsyncTickCallback) { - AsyncTickCallbackFunc *func; + AsyncTickCallbackFunc *func; }; Struct(AsyncTickCallbackNode) { - AsyncTickCallbackNode *next; - AsyncTickCallback callback; + AsyncTickCallbackNode *next; + AsyncTickCallback callback; }; Struct(AsyncTickCtx) { - Arena *arena; + Arena *arena; }; Struct(AsyncWorkerCtx) { - i64 last_seen_signal; + i64 last_seen_signal; - u64 callbacks_count; - AsyncTickCallback *callbacks; + u64 callbacks_count; + AsyncTickCallback *callbacks; }; Struct(AsyncCtx) { - Mutex mutex; - u64 callback_nodes_count; - AsyncTickCallbackNode *first_callback_node; - AsyncTickCallbackNode *last_callback_node; + Mutex mutex; + u64 callback_nodes_count; + AsyncTickCallbackNode *first_callback_node; + AsyncTickCallbackNode *last_callback_node; - AsyncWorkerCtx worker; - Atomic64Padded signal; + AsyncWorkerCtx worker; + Atomic64Padded signal; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_bitbuff.c b/src/base/base_bitbuff.c index 01775434..1c2ef5bf 100644 --- a/src/base/base_bitbuff.c +++ b/src/base/base_bitbuff.c @@ -5,26 +5,26 @@ BB_Buff BB_AcquireBuff(u64 arena_reserve) { - BB_Buff result = Zi; - result.arena = AcquireArena(arena_reserve); - result.is_backed_by_arena = 1; - return result; + BB_Buff result = Zi; + result.arena = AcquireArena(arena_reserve); + result.is_backed_by_arena = 1; + return result; } void BB_ReleaseBuff(BB_Buff *bb) { - /* Only arena bitbuffs need to be released */ - if (bb->is_backed_by_arena) - { - ReleaseArena(bb->arena); - } + /* Only arena bitbuffs need to be released */ + if (bb->is_backed_by_arena) + { + ReleaseArena(bb->arena); + } } BB_Buff BB_BuffFromString(String s) { - BB_Buff result = Zi; - result.fixed_buffer = s; - return result; + BB_Buff result = Zi; + result.fixed_buffer = s; + return result; } //////////////////////////////////////////////////////////// @@ -32,99 +32,99 @@ BB_Buff BB_BuffFromString(String s) BB_Writer BB_WriterFromBuff(BB_Buff *bb) { - BB_Writer result = Zi; - result.bb = bb; - if (bb->is_backed_by_arena) - { - result.base = ArenaFirst(bb->arena, u8); - } - else - { - result.base = bb->fixed_buffer.text; - } - result.cur_bit = 0; + BB_Writer result = Zi; + result.bb = bb; + if (bb->is_backed_by_arena) + { + result.base = ArenaFirst(bb->arena, u8); + } + else + { + result.base = bb->fixed_buffer.text; + } + result.cur_bit = 0; #if BITBUFF_DEBUG - result.debug_enabled = 1; + result.debug_enabled = 1; #endif - return result; + return result; } /* Use this when writing external formats that will not verify bitbuff debug symbols / magic numbers */ BB_Writer BB_WriterFromBuffNoDebug(BB_Buff *bb) { - BB_Writer result = BB_WriterFromBuff(bb); + BB_Writer result = BB_WriterFromBuff(bb); #if BITBUFF_DEBUG - result.debug_enabled = 0; + result.debug_enabled = 0; #endif - return result; + return result; } /* FIXME: Handle overflowed bw */ u64 BB_GetNumBitsWritten(BB_Writer *bw) { - return bw->cur_bit; + return bw->cur_bit; } /* FIXME: Handle overflowed bw */ u64 BB_GetNumBytesWritten(BB_Writer *bw) { - return (bw->cur_bit + 7) >> 3; + return (bw->cur_bit + 7) >> 3; } /* FIXME: Handle overflowed bw */ String BB_GetWritten(Arena *arena, BB_Writer *bw) { - String result = Zi; - result.len = (bw->cur_bit + 7) >> 3; - result.text = PushStructsNoZero(arena, u8, result.len); - CopyBytes(result.text, bw->base, result.len); - return result; + String result = Zi; + result.len = (bw->cur_bit + 7) >> 3; + result.text = PushStructsNoZero(arena, u8, result.len); + CopyBytes(result.text, bw->base, result.len); + return result; } /* FIXME: Handle overflowed bw */ u8 *BB_GetWrittenRaw(BB_Writer *bw) { - return bw->base; + return bw->base; } /* Returns 1 if num_bits would cause the writer to overflow its fixed buffer size (if writer is not backed by a dynamic arena bitbuff) */ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits) { - b32 result = 0; - BB_Buff *bb = bw->bb; - if (bw->overflowed) + b32 result = 0; + BB_Buff *bb = bw->bb; + if (bw->overflowed) + { + result = 1; + } + else + { + u64 bytes_needed = (bw->cur_bit + num_bits + 7) >> 3; + if (bb->is_backed_by_arena) { - result = 1; + Arena *arena = bb->arena; + if (bytes_needed >= arena->pos) + { + /* Grow arena */ + u64 push_size = (((bytes_needed - arena->pos) / BB_WriterOverflowArenaPushSize) + 1) * BB_WriterOverflowArenaPushSize; + PushStructsNoZero(arena, u8, push_size); + } } else { - u64 bytes_needed = (bw->cur_bit + num_bits + 7) >> 3; - if (bb->is_backed_by_arena) - { - Arena *arena = bb->arena; - if (bytes_needed >= arena->pos) - { - /* Grow arena */ - u64 push_size = (((bytes_needed - arena->pos) / BB_WriterOverflowArenaPushSize) + 1) * BB_WriterOverflowArenaPushSize; - PushStructsNoZero(arena, u8, push_size); - } - } - else - { - u64 max_len = bb->fixed_buffer.len; - if (bytes_needed > max_len) - { - /* Writer overflowed fixed buffer */ + u64 max_len = bb->fixed_buffer.len; + if (bytes_needed > max_len) + { + /* Writer overflowed fixed buffer */ #if BITBUFF_DEBUG - Assert(0); + Assert(0); #endif - result = 1; - bw->cur_bit = max_len << 3; - bw->overflowed = 1; - } - } + result = 1; + bw->cur_bit = max_len << 3; + bw->overflowed = 1; + } } - return result; + } + return result; } //////////////////////////////////////////////////////////// @@ -134,29 +134,29 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits) void BB_WriteAlignToNextByte(BB_Writer *bw) { #if BITBUFF_DEBUG - if ((bw->cur_bit & 7) != 0) - { - BB_WriteDebugMagic(bw, BB_DebugMagicKind_AlignNextByte, 0); - } + if ((bw->cur_bit & 7) != 0) + { + BB_WriteDebugMagic(bw, BB_DebugMagicKind_AlignNextByte, 0); + } #endif - bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7; + bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7; } void BB_WriteAlignBytes(BB_Writer *bw, u64 align) { - BB_WriteAlignToNextByte(bw); - BB_WriteDebugMagic(bw, BB_DebugMagicKind_AlignBytes, align); - if (align > 0) + BB_WriteAlignToNextByte(bw); + BB_WriteDebugMagic(bw, BB_DebugMagicKind_AlignBytes, align); + if (align > 0) + { + u64 new_pos = (bw->cur_bit >> 3); + new_pos += (align - 1); + new_pos -= new_pos % align; + if (BB_CheckWriterOverflowBits(bw, new_pos << 3)) { - u64 new_pos = (bw->cur_bit >> 3); - new_pos += (align - 1); - new_pos -= new_pos % align; - if (BB_CheckWriterOverflowBits(bw, new_pos << 3)) - { - return; - } - bw->cur_bit = new_pos << 3; + return; } + bw->cur_bit = new_pos << 3; + } } //////////////////////////////////////////////////////////// @@ -164,58 +164,58 @@ void BB_WriteAlignBytes(BB_Writer *bw, u64 align) void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits) { - Assert(num_bits > 0 && (num_bits == 64 || value <= ~(U64Max << num_bits))); /* Bit count must be able to hold value */ - if (BB_CheckWriterOverflowBits(bw, num_bits)) - { - return; - } + Assert(num_bits > 0 && (num_bits == 64 || value <= ~(U64Max << num_bits))); /* Bit count must be able to hold value */ + if (BB_CheckWriterOverflowBits(bw, num_bits)) + { + return; + } - u8 offset = bw->cur_bit & 7; - if (offset != 0) - { - /* Write unaligned bits */ - u8 *at = bw->base + (bw->cur_bit >> 3); - u8 num_mix_bits = MinU8((8 - offset), num_bits); - u8 mix_byte = (u8)((value & ((1 << num_mix_bits) - 1)) << offset); - *at |= mix_byte; - value >>= num_mix_bits; - num_bits -= num_mix_bits; - bw->cur_bit += num_mix_bits; - } - - /* cur_bit is now aligned to byte */ + u8 offset = bw->cur_bit & 7; + if (offset != 0) + { + /* Write unaligned bits */ u8 *at = bw->base + (bw->cur_bit >> 3); - u8 num_bytes = (num_bits + 7) >> 3; - CopyBytes(at, &value, num_bytes); - bw->cur_bit += num_bits; + u8 num_mix_bits = MinU8((8 - offset), num_bits); + u8 mix_byte = (u8)((value & ((1 << num_mix_bits) - 1)) << offset); + *at |= mix_byte; + value >>= num_mix_bits; + num_bits -= num_mix_bits; + bw->cur_bit += num_mix_bits; + } + + /* cur_bit is now aligned to byte */ + u8 *at = bw->base + (bw->cur_bit >> 3); + u8 num_bytes = (num_bits + 7) >> 3; + CopyBytes(at, &value, num_bytes); + bw->cur_bit += num_bits; } void BB_WriteUBits(BB_Writer *bw, u64 value, u8 num_bits) { - BB_WriteDebugMagic(bw, BB_DebugMagicKind_UBits, num_bits); - BB_WriteUBitsNoMagic(bw, value, num_bits); + BB_WriteDebugMagic(bw, BB_DebugMagicKind_UBits, num_bits); + BB_WriteUBitsNoMagic(bw, value, num_bits); } void BB_WriteIBits(BB_Writer *bw, i64 value, u8 num_bits) { - BB_WriteDebugMagic(bw, BB_DebugMagicKind_IBits, num_bits); - u64 ubits; - if (value >= 0) - { - ubits = value; - } - else - { - ubits = BB_TwosComplimentFromUint(-value, num_bits); - } - BB_WriteUBits(bw, ubits, num_bits); + BB_WriteDebugMagic(bw, BB_DebugMagicKind_IBits, num_bits); + u64 ubits; + if (value >= 0) + { + ubits = value; + } + else + { + ubits = BB_TwosComplimentFromUint(-value, num_bits); + } + BB_WriteUBits(bw, ubits, num_bits); } /* Returns written bit to make writing delta encoding logic cleaner */ b32 BB_WriteBit(BB_Writer *bw, u8 value) { - BB_WriteUBits(bw, value, 1); - return value; + BB_WriteUBits(bw, value, 1); + return value; } //////////////////////////////////////////////////////////// @@ -225,14 +225,14 @@ b32 BB_WriteBit(BB_Writer *bw, u8 value) * Value is written in chunks of 7 bits w/ 8th bit signaling continuation. */ void BB_WriteUV(BB_Writer *bw, u64 value) { - BB_WriteDebugMagic(bw, BB_DebugMagicKind_UV, 0); - while (value > 0x7F) - { - u8 cont_byte = 0x80 | (value & 0x7F); - BB_WriteUBits(bw, cont_byte, 8); - value >>= 7; - } - BB_WriteUBits(bw, value, 8); + BB_WriteDebugMagic(bw, BB_DebugMagicKind_UV, 0); + while (value > 0x7F) + { + u8 cont_byte = 0x80 | (value & 0x7F); + BB_WriteUBits(bw, cont_byte, 8); + value >>= 7; + } + BB_WriteUBits(bw, value, 8); } /* Writes a variable length signed integer. @@ -240,46 +240,46 @@ void BB_WriteUV(BB_Writer *bw, u64 value) * indicating that the value is stored in twos compliment. */ void BB_WriteIV(BB_Writer *bw, i64 value) { - BB_WriteDebugMagic(bw, BB_DebugMagicKind_IV, 0); - u8 sign_bit; - u64 tc; - if (value >= 0) + BB_WriteDebugMagic(bw, BB_DebugMagicKind_IV, 0); + u8 sign_bit; + u64 tc; + if (value >= 0) + { + sign_bit = 0; + tc = value; + } + else + { + sign_bit = 1; + u64 unsigned_value = -value; + u8 num_bits = 6; + unsigned_value >>= 6; + while (unsigned_value > 0) { - sign_bit = 0; - tc = value; - } - else - { - sign_bit = 1; - u64 unsigned_value = -value; - u8 num_bits = 6; - unsigned_value >>= 6; - while (unsigned_value > 0) - { - num_bits += 7; - unsigned_value >>= 7; - } - num_bits = MinU8(num_bits, 64); - tc = BB_TwosComplimentFromUint(-value, num_bits); + num_bits += 7; + unsigned_value >>= 7; } + num_bits = MinU8(num_bits, 64); + tc = BB_TwosComplimentFromUint(-value, num_bits); + } - /* First byte contains not just cont bit, but sign bit as well. */ - u8 first_byte = (tc & 0x3F); - tc >>= 6; - first_byte |= (tc > 0) << 7; /* Cont bit */ - first_byte |= sign_bit << 6; /* Sign bit */ - BB_WriteUBits(bw, first_byte, 8); + /* First byte contains not just cont bit, but sign bit as well. */ + u8 first_byte = (tc & 0x3F); + tc >>= 6; + first_byte |= (tc > 0) << 7; /* Cont bit */ + first_byte |= sign_bit << 6; /* Sign bit */ + BB_WriteUBits(bw, first_byte, 8); - if (tc > 0) + if (tc > 0) + { + while (tc > 0x7F) { - while (tc > 0x7F) - { - u8 cont_byte = 0x80 | (tc & 0x7F); - BB_WriteUBits(bw, cont_byte, 8); - tc >>= 7; - } - BB_WriteUBits(bw, tc, 8); + u8 cont_byte = 0x80 | (tc & 0x7F); + BB_WriteUBits(bw, cont_byte, 8); + tc >>= 7; } + BB_WriteUBits(bw, tc, 8); + } } //////////////////////////////////////////////////////////// @@ -287,14 +287,14 @@ void BB_WriteIV(BB_Writer *bw, i64 value) void BB_WriteF32(BB_Writer *bw, f32 value) { - BB_WriteDebugMagic(bw, BB_DebugMagicKind_F32, 0); - BB_WriteUBits(bw, *(u32 *)&value, 32); + BB_WriteDebugMagic(bw, BB_DebugMagicKind_F32, 0); + BB_WriteUBits(bw, *(u32 *)&value, 32); } void BB_WriteF64(BB_Writer *bw, f64 value) { - BB_WriteDebugMagic(bw, BB_DebugMagicKind_F64, 0); - BB_WriteUBits(bw, *(u64 *)&value, 64); + BB_WriteDebugMagic(bw, BB_DebugMagicKind_F64, 0); + BB_WriteUBits(bw, *(u64 *)&value, 64); } //////////////////////////////////////////////////////////// @@ -302,9 +302,9 @@ void BB_WriteF64(BB_Writer *bw, f64 value) void BB_WriteUid(BB_Writer *bw, Uid value) { - BB_WriteDebugMagic(bw, BB_DebugMagicKind_Uid, 128); - BB_WriteUBits(bw, value.hi, 64); - BB_WriteUBits(bw, value.lo, 64); + BB_WriteDebugMagic(bw, BB_DebugMagicKind_Uid, 128); + BB_WriteUBits(bw, value.hi, 64); + BB_WriteUBits(bw, value.lo, 64); } //////////////////////////////////////////////////////////// @@ -312,38 +312,38 @@ void BB_WriteUid(BB_Writer *bw, Uid value) void BB_WriteString(BB_Writer *bw, String s) { - BB_WriteDebugMagic(bw, BB_DebugMagicKind_String, 0); - BB_WriteUV(bw, s.len); - BB_WriteBytes(bw, s); + BB_WriteDebugMagic(bw, BB_DebugMagicKind_String, 0); + BB_WriteUV(bw, s.len); + BB_WriteBytes(bw, s); } void BB_WriteBytes(BB_Writer *bw, String bytes) { - /* Align start of bytes */ - BB_WriteAlignToNextByte(bw); + /* Align start of bytes */ + BB_WriteAlignToNextByte(bw); - u64 num_bits = bytes.len << 3; - if (BB_CheckWriterOverflowBits(bw, num_bits)) - { - return; - } + u64 num_bits = bytes.len << 3; + if (BB_CheckWriterOverflowBits(bw, num_bits)) + { + return; + } - u8 *at = bw->base + (bw->cur_bit >> 3); - CopyBytes(at, bytes.text, bytes.len); - bw->cur_bit += num_bits; + u8 *at = bw->base + (bw->cur_bit >> 3); + CopyBytes(at, bytes.text, bytes.len); + bw->cur_bit += num_bits; } void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes) { - BB_WriteAlignToNextByte(bw); + BB_WriteAlignToNextByte(bw); - u64 num_bits = num_bytes << 3; - if (BB_CheckWriterOverflowBits(bw, num_bits)) - { - return; - } + u64 num_bits = num_bytes << 3; + if (BB_CheckWriterOverflowBits(bw, num_bits)) + { + return; + } - bw->cur_bit += num_bits; + bw->cur_bit += num_bits; } //////////////////////////////////////////////////////////// @@ -352,24 +352,24 @@ void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes) #if BITBUFF_DEBUG void BB_WriteDebugMarker(BB_Writer *bw, String name) { - bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7; - for (u64 i = 0; i < name.len; ++i) - { - BB_WriteUBitsNoMagic(bw, name.text[i], 8); - } + bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7; + for (u64 i = 0; i < name.len; ++i) + { + BB_WriteUBitsNoMagic(bw, name.text[i], 8); + } } void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits) { - if (bw->debug_enabled) + if (bw->debug_enabled) + { + if (BB_CheckWriterOverflowBits(bw, 24)) { - if (BB_CheckWriterOverflowBits(bw, 24)) - { - return; - } - u64 magic_ubits = (u64)magic | ((u64)num_bits << 16); - BB_WriteUBitsNoMagic(bw, magic_ubits, 24); + return; } + u64 magic_ubits = (u64)magic | ((u64)num_bits << 16); + BB_WriteUBitsNoMagic(bw, magic_ubits, 24); + } } #endif @@ -378,86 +378,86 @@ void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits) BB_Reader BB_ReaderFromBuff(BB_Buff *bb) { - BB_Reader result = Zi; - if (!bb->is_backed_by_arena) - { - result.base = bb->fixed_buffer.text; - result.base_len = bb->fixed_buffer.len; - } - else - { - Arena *arena = bb->arena; - result.base = ArenaFirst(arena, u8); - result.base_len = arena->pos; - } - result.cur_bit = 0; + BB_Reader result = Zi; + if (!bb->is_backed_by_arena) + { + result.base = bb->fixed_buffer.text; + result.base_len = bb->fixed_buffer.len; + } + else + { + Arena *arena = bb->arena; + result.base = ArenaFirst(arena, u8); + result.base_len = arena->pos; + } + result.cur_bit = 0; #if BITBUFF_DEBUG - result.debug_enabled = 1; + result.debug_enabled = 1; #endif - return result; + return result; } /* Use this when reading from external formats that will not contain bitbuff debug symbols / magic numbers */ BB_Reader BB_ReaderFromBuffNoDebug(BB_Buff *bb) { - BB_Reader result = BB_ReaderFromBuff(bb); + BB_Reader result = BB_ReaderFromBuff(bb); #if BITBUFF_DEBUG - result.debug_enabled = 0; + result.debug_enabled = 0; #endif - return result; + return result; } /* Returns the number of bits read from the bitbuff */ /* FIXME: Handle overflowed br */ u64 BB_GetCurrentReaderBit(BB_Reader *br) { - return br->cur_bit; + return br->cur_bit; } /* Returns the number of *full* bytes read from the bitbuff */ /* FIXME: Handle overflowed br */ u64 BB_GetCurrentReaderByte(BB_Reader *br) { - return br->cur_bit >> 3; + return br->cur_bit >> 3; } /* Returns the number of bits left until the bitbuff overflows */ /* FIXME: Handle overflowed br */ u64 BB_NumBitsRemaining(BB_Reader *br) { - return (br->base_len << 3) - br->cur_bit; + return (br->base_len << 3) - br->cur_bit; } /* Returns the number of *full* bytes left until the bitbuff overflows */ /* FIXME: Handle overflowed br */ u64 BB_NumBytesRemaining(BB_Reader *br) { - return br->base_len - (br->cur_bit >> 3); + return br->base_len - (br->cur_bit >> 3); } b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits) { - b32 result = 0; - if (br->overflowed) + b32 result = 0; + if (br->overflowed) + { + result = 1; + } + else + { + u64 bits_needed = br->cur_bit + num_bits; + u64 base_len_bits = br->base_len << 3; + if (bits_needed > base_len_bits) { - result = 1; - } - else - { - u64 bits_needed = br->cur_bit + num_bits; - u64 base_len_bits = br->base_len << 3; - if (bits_needed > base_len_bits) - { - /* Tried to read past bitbuff memory */ + /* Tried to read past bitbuff memory */ #if BITBUFF_DEBUG - Assert(0); + Assert(0); #endif - result = 1; - br->cur_bit = base_len_bits; - br->overflowed = 1; - } + result = 1; + br->cur_bit = base_len_bits; + br->overflowed = 1; } - return result; + } + return result; } //////////////////////////////////////////////////////////// @@ -467,29 +467,29 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits) void BB_ReadAlignToNextByte(BB_Reader *br) { #if BITBUFF_DEBUG - if ((br->cur_bit & 7) != 0) - { - BB_ReadDebugMagic(br, BB_DebugMagicKind_AlignNextByte, 0); - } + if ((br->cur_bit & 7) != 0) + { + BB_ReadDebugMagic(br, BB_DebugMagicKind_AlignNextByte, 0); + } #endif - br->cur_bit += (8 - (br->cur_bit & 7)) & 7; + br->cur_bit += (8 - (br->cur_bit & 7)) & 7; } void BB_ReadAlignBytes(BB_Reader *br, u64 align) { - BB_ReadAlignToNextByte(br); - BB_ReadDebugMagic(br, BB_DebugMagicKind_AlignBytes, align); - if (align > 0) + BB_ReadAlignToNextByte(br); + BB_ReadDebugMagic(br, BB_DebugMagicKind_AlignBytes, align); + if (align > 0) + { + u64 new_pos = (br->cur_bit >> 3); + new_pos += (align - 1); + new_pos -= new_pos % align; + if (BB_CheckReaderOverflowBits(br, new_pos << 3)) { - u64 new_pos = (br->cur_bit >> 3); - new_pos += (align - 1); - new_pos -= new_pos % align; - if (BB_CheckReaderOverflowBits(br, new_pos << 3)) - { - return; - } - br->cur_bit = new_pos << 3; + return; } + br->cur_bit = new_pos << 3; + } } //////////////////////////////////////////////////////////// @@ -497,60 +497,60 @@ void BB_ReadAlignBytes(BB_Reader *br, u64 align) u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_bits) { - if (BB_CheckReaderOverflowBits(br, num_bits)) - { - return 0; - } + if (BB_CheckReaderOverflowBits(br, num_bits)) + { + return 0; + } - u64 result = 0; + u64 result = 0; - u8 offset = br->cur_bit & 7; - u8 num_trailing_bits = 0; - if (offset) - { - u8 *at = br->base + (br->cur_bit >> 3); - num_trailing_bits = MinU8(8 - offset, num_bits); - u8 mix_byte = *at; - mix_byte >>= offset; - mix_byte &= (1 << num_trailing_bits) - 1; - result = mix_byte; - num_bits -= num_trailing_bits; - br->cur_bit += num_trailing_bits; - } - - /* cur_bit is now aligned to byte */ + u8 offset = br->cur_bit & 7; + u8 num_trailing_bits = 0; + if (offset) + { u8 *at = br->base + (br->cur_bit >> 3); - u8 num_bytes = (num_bits + 7) >> 3; - u64 tmp = 0; - CopyBytes(&tmp, at, num_bytes); - u64 mask = U64Max; - if (num_bits < 64) - { - mask = ~(U64Max << num_bits); - } - tmp &= mask; - result |= tmp << num_trailing_bits; - br->cur_bit += num_bits; - return result; + num_trailing_bits = MinU8(8 - offset, num_bits); + u8 mix_byte = *at; + mix_byte >>= offset; + mix_byte &= (1 << num_trailing_bits) - 1; + result = mix_byte; + num_bits -= num_trailing_bits; + br->cur_bit += num_trailing_bits; + } + + /* cur_bit is now aligned to byte */ + u8 *at = br->base + (br->cur_bit >> 3); + u8 num_bytes = (num_bits + 7) >> 3; + u64 tmp = 0; + CopyBytes(&tmp, at, num_bytes); + u64 mask = U64Max; + if (num_bits < 64) + { + mask = ~(U64Max << num_bits); + } + tmp &= mask; + result |= tmp << num_trailing_bits; + br->cur_bit += num_bits; + return result; } u64 BB_ReadUBits(BB_Reader *br, u8 num_bits) { - BB_ReadDebugMagic(br, BB_DebugMagicKind_UBits, num_bits); - return BB_ReadUBitsNoMagic(br, num_bits); + BB_ReadDebugMagic(br, BB_DebugMagicKind_UBits, num_bits); + return BB_ReadUBitsNoMagic(br, num_bits); } i64 BB_ReadIBits(BB_Reader *br, u8 num_bits) { - Assert(num_bits > 1); - BB_ReadDebugMagic(br, BB_DebugMagicKind_IBits, num_bits); - u64 tc = BB_ReadUBits(br, num_bits); - return BB_IntFromTwosCompliment(tc, num_bits); + Assert(num_bits > 1); + BB_ReadDebugMagic(br, BB_DebugMagicKind_IBits, num_bits); + u64 tc = BB_ReadUBits(br, num_bits); + return BB_IntFromTwosCompliment(tc, num_bits); } u8 BB_ReadBit(BB_Reader *br) { - return BB_ReadUBits(br, 1); + return BB_ReadUBits(br, 1); } //////////////////////////////////////////////////////////// @@ -560,61 +560,61 @@ u8 BB_ReadBit(BB_Reader *br) * See BB_WriteUV for details. */ u64 BB_ReadUV(BB_Reader *br) { - BB_ReadDebugMagic(br, BB_DebugMagicKind_UV, 0); + BB_ReadDebugMagic(br, BB_DebugMagicKind_UV, 0); - u64 result = 0; - for (u64 i = 0; i <= 9; ++i) + u64 result = 0; + for (u64 i = 0; i <= 9; ++i) + { + u64 part = BB_ReadUBits(br, 8); + u8 is_last_part = part <= 0x7F; + result |= (part & 0x7F) << (i * 7); + if (is_last_part) { - u64 part = BB_ReadUBits(br, 8); - u8 is_last_part = part <= 0x7F; - result |= (part & 0x7F) << (i * 7); - if (is_last_part) - { - break; - } + break; } - return result; + } + return result; } /* Read a variable length signed integer. * See BB_WriteIV for details. */ i64 BB_ReadIV(BB_Reader *br) { - BB_ReadDebugMagic(br, BB_DebugMagicKind_IV, 0); - u8 first_byte = BB_ReadUBits(br, 8); - u8 cont_bit = first_byte & 0x80; - u8 sign_bit = first_byte & 0x40; + BB_ReadDebugMagic(br, BB_DebugMagicKind_IV, 0); + u8 first_byte = BB_ReadUBits(br, 8); + u8 cont_bit = first_byte & 0x80; + u8 sign_bit = first_byte & 0x40; - u8 num_bits = 6; - u64 tc = first_byte & 0x3F; - if (cont_bit) + u8 num_bits = 6; + u64 tc = first_byte & 0x3F; + if (cont_bit) + { + for (u64 i = 0; i <= 9; ++i) { - for (u64 i = 0; i <= 9; ++i) - { - u64 part = BB_ReadUBits(br, 8); - u8 is_last_part = part <= 0x7F; - tc |= (part & 0x7F) << num_bits; - num_bits += 7; - if (is_last_part) - { - break; - } - } + u64 part = BB_ReadUBits(br, 8); + u8 is_last_part = part <= 0x7F; + tc |= (part & 0x7F) << num_bits; + num_bits += 7; + if (is_last_part) + { + break; + } } - num_bits = MinU8(num_bits, 64); + } + num_bits = MinU8(num_bits, 64); - i64 result; - if (sign_bit) - { - /* Sign bit is 1, indicating result is stored in twos compliment */ - result = BB_IntFromTwosCompliment(tc, num_bits); - } - else - { - result = (i64)tc; - } + i64 result; + if (sign_bit) + { + /* Sign bit is 1, indicating result is stored in twos compliment */ + result = BB_IntFromTwosCompliment(tc, num_bits); + } + else + { + result = (i64)tc; + } - return result; + return result; } //////////////////////////////////////////////////////////// @@ -622,16 +622,16 @@ i64 BB_ReadIV(BB_Reader *br) f32 BB_ReadF32(BB_Reader *br) { - BB_ReadDebugMagic(br, BB_DebugMagicKind_F32, 0); - u32 ubits = BB_ReadUBits(br, 32); - return *(f32 *)&ubits; + BB_ReadDebugMagic(br, BB_DebugMagicKind_F32, 0); + u32 ubits = BB_ReadUBits(br, 32); + return *(f32 *)&ubits; } f64 BB_ReadF64(BB_Reader *br) { - BB_ReadDebugMagic(br, BB_DebugMagicKind_F64, 0); - u64 ubits = BB_ReadUBits(br, 64); - return *(f64 *)&ubits; + BB_ReadDebugMagic(br, BB_DebugMagicKind_F64, 0); + u64 ubits = BB_ReadUBits(br, 64); + return *(f64 *)&ubits; } //////////////////////////////////////////////////////////// @@ -639,10 +639,10 @@ f64 BB_ReadF64(BB_Reader *br) Uid BB_ReadUid(BB_Reader *br) { - BB_ReadDebugMagic(br, BB_DebugMagicKind_Uid, 128); - u64 hi = BB_ReadUBits(br, 64); - u64 lo = BB_ReadUBits(br, 64); - return UID(hi, lo); + BB_ReadDebugMagic(br, BB_DebugMagicKind_Uid, 128); + u64 hi = BB_ReadUBits(br, 64); + u64 lo = BB_ReadUBits(br, 64); + return UID(hi, lo); } //////////////////////////////////////////////////////////// @@ -650,77 +650,77 @@ Uid BB_ReadUid(BB_Reader *br) String BB_ReadString(Arena *arena, BB_Reader *br) { - BB_ReadDebugMagic(br, BB_DebugMagicKind_String, 0); - String result = Zi; - u64 len = BB_ReadUV(br); - u8 *src = BB_ReadBytesRaw(br, len); - if (src != 0) - { - result.len = len; - result.text = PushStructsNoZero(arena, u8, len); - CopyBytes(result.text, src, len); - } - return result; + BB_ReadDebugMagic(br, BB_DebugMagicKind_String, 0); + String result = Zi; + u64 len = BB_ReadUV(br); + u8 *src = BB_ReadBytesRaw(br, len); + if (src != 0) + { + result.len = len; + result.text = PushStructsNoZero(arena, u8, len); + CopyBytes(result.text, src, len); + } + return result; } /* Will fill dst with zeroes if bitbuff overflows */ void BB_ReadBytes(BB_Reader *br, String out) { - u8 *src = BB_ReadBytesRaw(br, out.len); - if (src) - { - CopyBytes(out.text, src, out.len); - } - else - { - ZeroBytes(out.text, out.len); - } + u8 *src = BB_ReadBytesRaw(br, out.len); + if (src) + { + CopyBytes(out.text, src, out.len); + } + else + { + ZeroBytes(out.text, out.len); + } } /* Will return 0 on bitbuff overflow. Result should be checked. */ u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes) { - BB_ReadAlignToNextByte(br); + BB_ReadAlignToNextByte(br); - u64 num_bits = num_bytes << 3; - if (BB_CheckReaderOverflowBits(br, num_bits)) - { - return 0; - } + u64 num_bits = num_bytes << 3; + if (BB_CheckReaderOverflowBits(br, num_bits)) + { + return 0; + } - u8 *raw = br->base + (br->cur_bit >> 3); - br->cur_bit += num_bits; + u8 *raw = br->base + (br->cur_bit >> 3); + br->cur_bit += num_bits; - return raw; + return raw; } void BB_ReadSeekBytes(BB_Reader *br, u64 num_bytes) { - BB_ReadAlignToNextByte(br); + BB_ReadAlignToNextByte(br); - u64 num_bits = num_bytes << 3; - if (BB_CheckReaderOverflowBits(br, num_bits)) - { - return; - } + u64 num_bits = num_bytes << 3; + if (BB_CheckReaderOverflowBits(br, num_bits)) + { + return; + } - br->cur_bit += num_bits; + br->cur_bit += num_bits; } void BB_ReadSeekToByte(BB_Reader *br, u64 pos) { - u64 cur_byte_pos = br->cur_bit >> 3; - if (pos >= cur_byte_pos) - { - BB_ReadSeekBytes(br, pos - cur_byte_pos); - } - else - { - /* Tried to seek byte backwards in reader */ - Assert(0); - br->overflowed = 1; - br->cur_bit = (br->base_len << 3); - } + u64 cur_byte_pos = br->cur_bit >> 3; + if (pos >= cur_byte_pos) + { + BB_ReadSeekBytes(br, pos - cur_byte_pos); + } + else + { + /* Tried to seek byte backwards in reader */ + Assert(0); + br->overflowed = 1; + br->cur_bit = (br->base_len << 3); + } } //////////////////////////////////////////////////////////// @@ -730,33 +730,33 @@ void BB_ReadSeekToByte(BB_Reader *br, u64 pos) void BB_ReadDebugMagic(BB_Reader *br, BB_DebugMagicKind expected_magic, u8 expected_num_bits) { - if (br->debug_enabled) + if (br->debug_enabled) + { + if (BB_CheckReaderOverflowBits(br, 24)) { - if (BB_CheckReaderOverflowBits(br, 24)) - { - return; - } - u64 stored = BB_ReadUBitsNoMagic(br, 24); - BB_DebugMagicKind stored_magic = stored & 0xFFFF; - u8 stored_num_bits = (stored >> 16) & 0xFF; - - /* Verify stored magic match */ - Assert(expected_magic == stored_magic); - - /* Verify stored bit count match */ - Assert(expected_num_bits == stored_num_bits); + return; } + u64 stored = BB_ReadUBitsNoMagic(br, 24); + BB_DebugMagicKind stored_magic = stored & 0xFFFF; + u8 stored_num_bits = (stored >> 16) & 0xFF; + + /* Verify stored magic match */ + Assert(expected_magic == stored_magic); + + /* Verify stored bit count match */ + Assert(expected_num_bits == stored_num_bits); + } } void BB_ReadDebugMarker(BB_Reader *br, String name) { - br->cur_bit += (8 - (br->cur_bit & 7)) & 7; - for (u64 i = 0; i < name.len; ++i) - { - u8 c_stored = BB_ReadUBitsNoMagic(br, 8); - u8 c_expected = name.text[i]; - Assert(c_expected == c_stored); - } + br->cur_bit += (8 - (br->cur_bit & 7)) & 7; + for (u64 i = 0; i < name.len; ++i) + { + u8 c_stored = BB_ReadUBitsNoMagic(br, 8); + u8 c_expected = name.text[i]; + Assert(c_expected == c_stored); + } } #endif @@ -766,22 +766,22 @@ void BB_ReadDebugMarker(BB_Reader *br, String name) u64 BB_TwosComplimentFromUint(u64 value, u8 num_bits) { - u64 mask = U64Max; - if (num_bits < 64) - { - mask = ~(U64Max << num_bits); - } - u64 tc = (~value & mask) + 1; - tc &= mask; - return tc; + u64 mask = U64Max; + if (num_bits < 64) + { + mask = ~(U64Max << num_bits); + } + u64 tc = (~value & mask) + 1; + tc &= mask; + return tc; } i64 BB_IntFromTwosCompliment(u64 tc, u8 num_bits) { - u64 msb_mask = (u64)1 << (num_bits - 1); - i64 value = -(i64)(tc & msb_mask); - value += tc & ~msb_mask; - return value; + u64 msb_mask = (u64)1 << (num_bits - 1); + i64 value = -(i64)(tc & msb_mask); + value += tc & ~msb_mask; + return value; } //////////////////////////////////////////////////////////// @@ -791,151 +791,151 @@ i64 BB_IntFromTwosCompliment(u64 tc, u8 num_bits) void BB_Test(void) { - TempArena scratch = BeginScratchNoConflict(); + TempArena scratch = BeginScratchNoConflict(); - u8 kind_ubits = 0; - u8 kind_ibits = 1; - u8 kind_uv = 2; - u8 kind_iv = 3; - u8 kind_string = 4; + u8 kind_ubits = 0; + u8 kind_ibits = 1; + u8 kind_uv = 2; + u8 kind_iv = 3; + u8 kind_string = 4; - struct test_case_ubits { u64 v; u64 num_bits; }; - struct test_case_ibits { i64 v; u64 num_bits; }; - struct test_case_uv { u64 v; }; - struct test_case_iv { i64 v; }; - struct test_case_string { String v; }; - struct test_case + struct test_case_ubits { u64 v; u64 num_bits; }; + struct test_case_ibits { i64 v; u64 num_bits; }; + struct test_case_uv { u64 v; }; + struct test_case_iv { i64 v; }; + struct test_case_string { String v; }; + struct test_case + { + u8 kind; + union { - u8 kind; - union - { - struct test_case_ubits ubits; - struct test_case_ibits ibits; - struct test_case_uv uv; - struct test_case_iv iv; - struct test_case_string s; - }; + struct test_case_ubits ubits; + struct test_case_ibits ibits; + struct test_case_uv uv; + struct test_case_iv iv; + struct test_case_string s; }; + }; - struct test_case cases[] = { - { kind_ubits, .ubits = { 40, 8 } }, - { kind_ubits, .ubits = { 32, 8 } }, - { kind_ubits, .ubits = { 100, 7 } }, - { kind_ubits, .ubits = { 4, 3 } }, - { kind_ubits, .ubits = { 13, 8 } }, + struct test_case cases[] = { + { kind_ubits, .ubits = { 40, 8 } }, + { kind_ubits, .ubits = { 32, 8 } }, + { kind_ubits, .ubits = { 100, 7 } }, + { kind_ubits, .ubits = { 4, 3 } }, + { kind_ubits, .ubits = { 13, 8 } }, - { kind_ibits, .ibits = { 0, 8 } }, - { kind_ibits, .ibits = { -1, 8 } }, - { kind_ibits, .ibits = { -2, 8 } }, - { kind_ibits, .ibits = { -3, 8 } }, - { kind_ibits, .ibits = { -100, 8 } }, - { kind_ibits, .ibits = { -50, 7 } }, - { kind_ibits, .ibits = { 50, 7 } }, - { kind_ibits, .ibits = { 4, 7 } }, - { kind_ibits, .ibits = { 1, 7 } }, - { kind_ibits, .ibits = { 3, 3 } }, - { kind_ibits, .ibits = { 1, 2 } }, - { kind_ibits, .ibits = { 0, 2 } }, - { kind_ibits, .ibits = { -1, 2 } }, + { kind_ibits, .ibits = { 0, 8 } }, + { kind_ibits, .ibits = { -1, 8 } }, + { kind_ibits, .ibits = { -2, 8 } }, + { kind_ibits, .ibits = { -3, 8 } }, + { kind_ibits, .ibits = { -100, 8 } }, + { kind_ibits, .ibits = { -50, 7 } }, + { kind_ibits, .ibits = { 50, 7 } }, + { kind_ibits, .ibits = { 4, 7 } }, + { kind_ibits, .ibits = { 1, 7 } }, + { kind_ibits, .ibits = { 3, 3 } }, + { kind_ibits, .ibits = { 1, 2 } }, + { kind_ibits, .ibits = { 0, 2 } }, + { kind_ibits, .ibits = { -1, 2 } }, - { kind_uv, .uv = { 0 } }, - { kind_uv, .uv = { 100 } }, - { kind_uv, .uv = { 10000 } }, - { kind_uv, .uv = { 10000000000000 } }, - { kind_uv, .uv = { U64Max } }, + { kind_uv, .uv = { 0 } }, + { kind_uv, .uv = { 100 } }, + { kind_uv, .uv = { 10000 } }, + { kind_uv, .uv = { 10000000000000 } }, + { kind_uv, .uv = { U64Max } }, - { kind_iv, .iv = { 0 } }, - { kind_iv, .iv = { -1 } }, - { kind_iv, .iv = { 10000000000000 } }, - { kind_iv, .iv = { -10000000000000 } }, - { kind_iv, .iv = { I64Max } }, - { kind_iv, .iv = { I64Min } }, + { kind_iv, .iv = { 0 } }, + { kind_iv, .iv = { -1 } }, + { kind_iv, .iv = { 10000000000000 } }, + { kind_iv, .iv = { -10000000000000 } }, + { kind_iv, .iv = { I64Max } }, + { kind_iv, .iv = { I64Min } }, - { kind_string, .s = { Lit("Hello there! Hope you're doing well.") } }, - { kind_ibits, .ibits = { 3, 3 } }, - { kind_string, .s = { Lit("Alriiiiiiiiiiiiiiiiiiighty then") } }, - { kind_string, .s = { Lit("Alriiiiiiiiiiiiiiiiiiighty then") } }, - }; + { kind_string, .s = { Lit("Hello there! Hope you're doing well.") } }, + { kind_ibits, .ibits = { 3, 3 } }, + { kind_string, .s = { Lit("Alriiiiiiiiiiiiiiiiiiighty then") } }, + { kind_string, .s = { Lit("Alriiiiiiiiiiiiiiiiiiighty then") } }, + }; - String encoded = Zi; + String encoded = Zi; + { + BB_Buff bb = BB_AcquireBuff(Gibi(64)); + BB_Writer bw = BB_WriterFromBuff(&bb); + for (u64 i = 0; i < countof(cases); ++i) { - BB_Buff bb = BB_AcquireBuff(Gibi(64)); - BB_Writer bw = BB_WriterFromBuff(&bb); - for (u64 i = 0; i < countof(cases); ++i) - { - struct test_case c = cases[i]; - if (c.kind == kind_ubits) - { - BB_WriteUBits(&bw, c.ubits.v, c.ubits.num_bits); - } - else if (c.kind == kind_ibits) - { - BB_WriteIBits(&bw, c.ibits.v, c.ibits.num_bits); - } - else if (c.kind == kind_uv) - { - BB_WriteUV(&bw, c.uv.v); - } - else if (c.kind == kind_iv) - { - BB_WriteIV(&bw, c.iv.v); - } - else if (c.kind == kind_string) - { - BB_WriteString(&bw, c.s.v); - } - else - { - Assert(0); - } - } - encoded = BB_GetWritten(scratch.arena, &bw); + struct test_case c = cases[i]; + if (c.kind == kind_ubits) + { + BB_WriteUBits(&bw, c.ubits.v, c.ubits.num_bits); + } + else if (c.kind == kind_ibits) + { + BB_WriteIBits(&bw, c.ibits.v, c.ibits.num_bits); + } + else if (c.kind == kind_uv) + { + BB_WriteUV(&bw, c.uv.v); + } + else if (c.kind == kind_iv) + { + BB_WriteIV(&bw, c.iv.v); + } + else if (c.kind == kind_string) + { + BB_WriteString(&bw, c.s.v); + } + else + { + Assert(0); + } } + encoded = BB_GetWritten(scratch.arena, &bw); + } + { + BB_Buff bb = BB_BuffFromString(encoded); + BB_Reader br = BB_ReaderFromBuff(&bb); + for (u64 i = 0; i < countof(cases); ++i) { - BB_Buff bb = BB_BuffFromString(encoded); - BB_Reader br = BB_ReaderFromBuff(&bb); - for (u64 i = 0; i < countof(cases); ++i) - { - struct test_case c = cases[i]; - if (c.kind == kind_ubits) - { - u64 w = c.ubits.v; - u64 r = BB_ReadUBits(&br, c.ubits.num_bits); - Assert(r == w); - } - else if (c.kind == kind_ibits) - { - i64 w = c.ibits.v; - i64 r = BB_ReadIBits(&br, c.ubits.num_bits); - Assert(r == w); - } - else if (c.kind == kind_uv) - { - u64 w = c.uv.v; - u64 r = BB_ReadUV(&br); - Assert(r == w); - } - else if (c.kind == kind_iv) - { - i64 w = c.iv.v; - i64 r = BB_ReadIV(&br); - Assert(r == w); - } - else if (c.kind == kind_string) - { - String w = c.s.v; - String r = BB_ReadString(scratch.arena, &br); - Assert(MatchString(r, w)); - } - else - { - Assert(0); - } - } + struct test_case c = cases[i]; + if (c.kind == kind_ubits) + { + u64 w = c.ubits.v; + u64 r = BB_ReadUBits(&br, c.ubits.num_bits); + Assert(r == w); + } + else if (c.kind == kind_ibits) + { + i64 w = c.ibits.v; + i64 r = BB_ReadIBits(&br, c.ubits.num_bits); + Assert(r == w); + } + else if (c.kind == kind_uv) + { + u64 w = c.uv.v; + u64 r = BB_ReadUV(&br); + Assert(r == w); + } + else if (c.kind == kind_iv) + { + i64 w = c.iv.v; + i64 r = BB_ReadIV(&br); + Assert(r == w); + } + else if (c.kind == kind_string) + { + String w = c.s.v; + String r = BB_ReadString(scratch.arena, &br); + Assert(MatchString(r, w)); + } + else + { + Assert(0); + } } + } - EndScratch(scratch); + EndScratch(scratch); } #endif diff --git a/src/base/base_bitbuff.h b/src/base/base_bitbuff.h index 0ddb01af..312a5238 100644 --- a/src/base/base_bitbuff.h +++ b/src/base/base_bitbuff.h @@ -4,13 +4,13 @@ //- Buff Struct(BB_Buff) { - b32 is_backed_by_arena; + b32 is_backed_by_arena; - /* If `is_arena_bitbuff` is 1, this dynamically-sized arena will be used for reading & writing (meaning writing cannot overflow) */ - Arena *arena; + /* If `is_arena_bitbuff` is 1, this dynamically-sized arena will be used for reading & writing (meaning writing cannot overflow) */ + Arena *arena; - /* If `is_arena_bitbuff` is 0, this fixed-sized buffer willl be used for reading & writing */ - String fixed_buffer; + /* If `is_arena_bitbuff` is 0, this fixed-sized buffer willl be used for reading & writing */ + String fixed_buffer; }; //- Writer @@ -18,24 +18,24 @@ Struct(BB_Buff) #define BB_WriterOverflowArenaPushSize 4096 Struct(BB_Writer) { - b32 overflowed; - BB_Buff *bb; - u8 *base; - u64 cur_bit; + b32 overflowed; + BB_Buff *bb; + u8 *base; + u64 cur_bit; #if BITBUFF_DEBUG - b32 debug_enabled; + b32 debug_enabled; #endif }; //- Reader Struct(BB_Reader) { - b32 overflowed; - u64 base_len; - u8 *base; - u64 cur_bit; + b32 overflowed; + u64 base_len; + u8 *base; + u64 cur_bit; #if BITBUFF_DEBUG - b32 debug_enabled; + b32 debug_enabled; #endif }; @@ -47,16 +47,16 @@ Struct(BB_Reader) /* Magic numbers inserted to verify read/write type & length */ Enum(BB_DebugMagicKind) { - BB_DebugMagicKind_AlignBytes = 0x20A4, - BB_DebugMagicKind_AlignToNextByte = 0x379A, - BB_DebugMagicKind_UBits = 0xCB4A, - BB_DebugMagicKind_IBits = 0xB30D, - BB_DebugMagicKind_UV = 0xE179, - BB_DebugMagicKind_IV = 0x981f, - BB_DebugMagicKind_F32 = 0x56F9, - BB_DebugMagicKind_F64 = 0x7053, - BB_DebugMagicKind_Uid = 0xA24E, - BB_DebugMagicKind_String = 0x7866 + BB_DebugMagicKind_AlignBytes = 0x20A4, + BB_DebugMagicKind_AlignToNextByte = 0x379A, + BB_DebugMagicKind_UBits = 0xCB4A, + BB_DebugMagicKind_IBits = 0xB30D, + BB_DebugMagicKind_UV = 0xE179, + BB_DebugMagicKind_IV = 0x981f, + BB_DebugMagicKind_F32 = 0x56F9, + BB_DebugMagicKind_F64 = 0x7053, + BB_DebugMagicKind_Uid = 0xA24E, + BB_DebugMagicKind_String = 0x7866 }; #endif @@ -118,11 +118,11 @@ void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes); //~ Writer debug #if BITBUFF_DEBUG -void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits); -void BB_WriteDebugMarker(BB_Writer *bw, String name); + void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits); + void BB_WriteDebugMarker(BB_Writer *bw, String name); #else -#define BB_WriteDebugMagic(bw, magic, num_bits) -#define BB_WriteDebugMarker(bw, name) + #define BB_WriteDebugMagic(bw, magic, num_bits) + #define BB_WriteDebugMarker(bw, name) #endif //////////////////////////////////////////////////////////// diff --git a/src/base/base_buddy.c b/src/base/base_buddy.c index d05f1c08..cda2872e 100644 --- a/src/base/base_buddy.c +++ b/src/base/base_buddy.c @@ -5,29 +5,29 @@ BuddyCtx *AcquireBuddyCtx(u64 reserve) { - /* TODO: Determine meta reserve dynamically */ - Arena *meta_arena = AcquireArena(Gibi(64)); - BuddyCtx *ctx = PushStruct(meta_arena, BuddyCtx); - ctx->meta_arena = meta_arena; - ctx->data_arena = AcquireArena(reserve); + /* TODO: Determine meta reserve dynamically */ + Arena *meta_arena = AcquireArena(Gibi(64)); + BuddyCtx *ctx = PushStruct(meta_arena, BuddyCtx); + ctx->meta_arena = meta_arena; + ctx->data_arena = AcquireArena(reserve); - /* TODO: Minimum block size */ - ctx->levels = PushStructs(ctx->meta_arena, BuddyLevel, 64); - for (u64 i = 0; i < 64; ++i) - { - BuddyLevel *level = &ctx->levels[i]; - level->ctx = ctx; - level->tier = i; - level->size = (u64)1 << i; - } + /* TODO: Minimum block size */ + ctx->levels = PushStructs(ctx->meta_arena, BuddyLevel, 64); + for (u64 i = 0; i < 64; ++i) + { + BuddyLevel *level = &ctx->levels[i]; + level->ctx = ctx; + level->tier = i; + level->size = (u64)1 << i; + } - return ctx; + return ctx; } void ReleaseBuddyCtx(BuddyCtx *ctx) { - ReleaseArena(ctx->data_arena); - ReleaseArena(ctx->meta_arena); + ReleaseArena(ctx->data_arena); + ReleaseArena(ctx->meta_arena); } //////////////////////////////////////////////////////////// @@ -35,172 +35,172 @@ void ReleaseBuddyCtx(BuddyCtx *ctx) BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level) { - BuddyBlock *block = 0; + BuddyBlock *block = 0; - /* TODO: Tier oob check */ + /* TODO: Tier oob check */ + if (level->first_unused_block) + { + block = level->first_unused_block; + level->first_unused_block = block->next; if (level->first_unused_block) { - block = level->first_unused_block; - level->first_unused_block = block->next; - if (level->first_unused_block) - { - level->first_unused_block->prev = 0; - } - block->is_used = 1; - block->next = 0; + level->first_unused_block->prev = 0; + } + block->is_used = 1; + block->next = 0; + } + else + { + if (level->backed) + { + BuddyLevel *parent_level = &ctx->levels[level->tier + 1]; + BuddyBlock *parent_block = GetUnusedBuddyBlock(ctx, parent_level); + + /* Create left (used) block from parent block */ + BuddyBlock *left = PushBuddyBlock(ctx); + left->is_used = 1; + left->level = level; + left->parent = parent_block; + left->memory = parent_block->memory; + + /* Create right LAX block from parent block */ + BuddyBlock *right = PushBuddyBlock(ctx); + right->is_used = 0; + right->level = level; + right->parent = parent_block; + right->memory = left->memory + level->size; + if (level->first_unused_block) + { + right->next = level->first_unused_block; + level->first_unused_block->prev = right; + } + level->first_unused_block = right; + + left->sibling = right; + right->sibling = left; + block = left; } else { - if (level->backed) - { - BuddyLevel *parent_level = &ctx->levels[level->tier + 1]; - BuddyBlock *parent_block = GetUnusedBuddyBlock(ctx, parent_level); + Arena *arena = ctx->data_arena; - /* Create left (used) block from parent block */ - BuddyBlock *left = PushBuddyBlock(ctx); - left->is_used = 1; - left->level = level; - left->parent = parent_block; - left->memory = parent_block->memory; + /* Grow arena */ + i64 level_commit_diff = (level->size * 2) - arena->pos; + if (level_commit_diff > 0) + { + PushStructsNoZero(arena, u8, level_commit_diff); + Assert(arena->pos == (level->size * 2)); + } - /* Create right LAX block from parent block */ - BuddyBlock *right = PushBuddyBlock(ctx); - right->is_used = 0; - right->level = level; - right->parent = parent_block; - right->memory = left->memory + level->size; - if (level->first_unused_block) - { - right->next = level->first_unused_block; - level->first_unused_block->prev = right; - } - level->first_unused_block = right; + /* Create left (used) block from existing child block memory */ + BuddyBlock *left = PushBuddyBlock(ctx); + left->is_used = 1; + left->level = level; + left->memory = ArenaFirst(arena, u8); - left->sibling = right; - right->sibling = left; - block = left; - } - else - { - Arena *arena = ctx->data_arena; + /* Create right LAX block from new arena memory */ + BuddyBlock *right = PushBuddyBlock(ctx); + right->is_used = 0; + right->level = level; + right->memory = left->memory + level->size; - /* Grow arena */ - i64 level_commit_diff = (level->size * 2) - arena->pos; - if (level_commit_diff > 0) - { - PushStructsNoZero(arena, u8, level_commit_diff); - Assert(arena->pos == (level->size * 2)); - } + left->sibling = right; + right->sibling = left; + block = left; - /* Create left (used) block from existing child block memory */ - BuddyBlock *left = PushBuddyBlock(ctx); - left->is_used = 1; - left->level = level; - left->memory = ArenaFirst(arena, u8); - - /* Create right LAX block from new arena memory */ - BuddyBlock *right = PushBuddyBlock(ctx); - right->is_used = 0; - right->level = level; - right->memory = left->memory + level->size; - - left->sibling = right; - right->sibling = left; - block = left; - - level->backed = 1; - } + level->backed = 1; } + } - return block; + return block; } BuddyBlock *PushBuddyBlock(BuddyCtx *ctx) { - BuddyBlock *block; - if (ctx->first_free_block) - { - block = ctx->first_free_block; - ctx->first_free_block = block->next; - } - else - { - block = PushStructNoZero(ctx->meta_arena, BuddyBlock); - } - ZeroStruct(block); - return block; + BuddyBlock *block; + if (ctx->first_free_block) + { + block = ctx->first_free_block; + ctx->first_free_block = block->next; + } + else + { + block = PushStructNoZero(ctx->meta_arena, BuddyBlock); + } + ZeroStruct(block); + return block; } void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block) { - /* Remove from unused list */ + /* Remove from unused list */ + { + BuddyBlock *prev = block->prev; + BuddyBlock *next = block->next; + if (prev) { - BuddyBlock *prev = block->prev; - BuddyBlock *next = block->next; - if (prev) - { - prev->next = next; - } - else - { - level->first_unused_block = next; - } - if (next) - { - next->prev = prev; - } + prev->next = next; } - block->next = ctx->first_free_block; - ctx->first_free_block = block; + else + { + level->first_unused_block = next; + } + if (next) + { + next->prev = prev; + } + } + block->next = ctx->first_free_block; + ctx->first_free_block = block; } BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size) { - if (size > 0x00FFFFFFFFFFFFFFULL) - { - /* TODO: Error */ - Assert(0); - } + if (size > 0x00FFFFFFFFFFFFFFULL) + { + /* TODO: Error */ + Assert(0); + } - /* TODO: Minimum block size */ + /* TODO: Minimum block size */ - /* TODO: Faster MSB calculation */ + /* TODO: Faster MSB calculation */ - u64 desired_block_size = 1; - u64 desired_level_tier = 0; - while (desired_block_size < size && desired_level_tier < 64) - { - desired_block_size <<= 1; - ++desired_level_tier; - } + u64 desired_block_size = 1; + u64 desired_level_tier = 0; + while (desired_block_size < size && desired_level_tier < 64) + { + desired_block_size <<= 1; + ++desired_level_tier; + } - BuddyBlock *block = GetUnusedBuddyBlock(ctx, &ctx->levels[desired_level_tier]); + BuddyBlock *block = GetUnusedBuddyBlock(ctx, &ctx->levels[desired_level_tier]); - return block; + return block; } void ReleaseBuddyBlock(BuddyBlock *block) { - block->is_used = 0; - BuddyLevel *level = block->level; - BuddyBlock *parent = block->parent; - BuddyBlock *sibling = block->sibling; - if (!sibling->is_used && parent != 0) + block->is_used = 0; + BuddyLevel *level = block->level; + BuddyBlock *parent = block->parent; + BuddyBlock *sibling = block->sibling; + if (!sibling->is_used && parent != 0) + { + /* Merge siblings */ + BuddyCtx *ctx = level->ctx; + PopBuddyBlock(ctx, level, block); + PopBuddyBlock(ctx, level, sibling); + /* Release parent */ + ReleaseBuddyBlock(parent); + } + else + { + if (level->first_unused_block) { - /* Merge siblings */ - BuddyCtx *ctx = level->ctx; - PopBuddyBlock(ctx, level, block); - PopBuddyBlock(ctx, level, sibling); - /* Release parent */ - ReleaseBuddyBlock(parent); - } - else - { - if (level->first_unused_block) - { - block->next = level->first_unused_block; - level->first_unused_block->prev = block; - } - level->first_unused_block = block; + block->next = level->first_unused_block; + level->first_unused_block->prev = block; } + level->first_unused_block = block; + } } diff --git a/src/base/base_buddy.h b/src/base/base_buddy.h index 68babbbb..148dc811 100644 --- a/src/base/base_buddy.h +++ b/src/base/base_buddy.h @@ -4,35 +4,35 @@ //- Block Struct(BuddyBlock) { - b32 is_used; - struct BuddyLevel *level; - BuddyBlock *parent; - BuddyBlock *sibling; + b32 is_used; + struct BuddyLevel *level; + BuddyBlock *parent; + BuddyBlock *sibling; - /* Links to block in level's unused list or in ctx's free list */ - BuddyBlock *prev; - BuddyBlock *next; + /* Links to block in level's unused list or in ctx's free list */ + BuddyBlock *prev; + BuddyBlock *next; - u8 *memory; + u8 *memory; }; //- Level Struct(BuddyLevel) { - struct BuddyCtx *ctx; - b32 backed; /* Signals whether this level is backed by memory in the ctx arena */ - u32 tier; - u64 size; - BuddyBlock *first_unused_block; + struct BuddyCtx *ctx; + b32 backed; /* Signals whether this level is backed by memory in the ctx arena */ + u32 tier; + u64 size; + BuddyBlock *first_unused_block; }; //- Ctx Struct(BuddyCtx) { - Arena *meta_arena; - Arena *data_arena; - BuddyLevel *levels; - BuddyBlock *first_free_block; + Arena *meta_arena; + Arena *data_arena; + BuddyLevel *levels; + BuddyBlock *first_free_block; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_cmdline.c b/src/base/base_cmdline.c index 80282011..7f3ee041 100644 --- a/src/base/base_cmdline.c +++ b/src/base/base_cmdline.c @@ -3,70 +3,70 @@ void BootstrapCmdline(void) { - TempArena scratch = BeginScratchNoConflict(); + TempArena scratch = BeginScratchNoConflict(); + { + StringList raw = GetRawCommandline(); + + u64 tmp_args_count = 0; + u64 tmp_positionals_count = 0; + CommandlineArg *tmp_args = PushStructs(scratch.arena, CommandlineArg, raw.count); + String *tmp_positionals = PushStructs(scratch.arena, String, raw.count); { - StringList raw = GetRawCommandline(); - - u64 tmp_args_count = 0; - u64 tmp_positionals_count = 0; - CommandlineArg *tmp_args = PushStructs(scratch.arena, CommandlineArg, raw.count); - String *tmp_positionals = PushStructs(scratch.arena, String, raw.count); + String name = Zi; + for (StringListNode *n = raw.first; n; n = n->next) + { + String s = n->s; + if (StringBeginsWith(s, Lit("--"))) { - String name = Zi; - for (StringListNode *n = raw.first; n; n = n->next) - { - String s = n->s; - if (StringBeginsWith(s, Lit("--"))) - { - if (name.len > 0) - { - CommandlineArg *arg = &tmp_args[tmp_args_count++]; - arg->name = name; - arg->exists = 1; - } - name = TrimLeft(s, Lit("--")); - } - else - { - if (name.len > 0) - { - CommandlineArg *arg = &tmp_args[tmp_args_count++]; - arg->name = name; - arg->value = s; - arg->exists = 1; - name = Zstr; - } - else - { - tmp_positionals[tmp_positionals_count++] = s; - } - } - } - if (name.len > 0) - { - CommandlineArg *arg = &tmp_args[tmp_args_count++]; - arg->name = name; - arg->exists = 1; - } + if (name.len > 0) + { + CommandlineArg *arg = &tmp_args[tmp_args_count++]; + arg->name = name; + arg->exists = 1; + } + name = TrimLeft(s, Lit("--")); } - - Arena *perm = PermArena(); - Base.cmdline.positional_args_count = tmp_positionals_count; - Base.cmdline.positional_args = PushStructsNoZero(perm, String, tmp_positionals_count); - CopyStructs(Base.cmdline.positional_args, tmp_positionals, tmp_positionals_count); - for (u64 i = 0; i < tmp_args_count; ++i) + else { - CommandlineArg arg = tmp_args[i]; - CommandlineArgNode *n = PushStruct(perm, CommandlineArgNode); - u64 hash = HashFnv64(Fnv64Basis, arg.name); - u64 bin_idx = hash % countof(Base.cmdline.arg_bins); - n->arg = arg; - n->hash = hash; - n->next = Base.cmdline.arg_bins[bin_idx]; - Base.cmdline.arg_bins[bin_idx] = n; + if (name.len > 0) + { + CommandlineArg *arg = &tmp_args[tmp_args_count++]; + arg->name = name; + arg->value = s; + arg->exists = 1; + name = Zstr; + } + else + { + tmp_positionals[tmp_positionals_count++] = s; + } } + } + if (name.len > 0) + { + CommandlineArg *arg = &tmp_args[tmp_args_count++]; + arg->name = name; + arg->exists = 1; + } } - EndScratch(scratch); + + Arena *perm = PermArena(); + Base.cmdline.positional_args_count = tmp_positionals_count; + Base.cmdline.positional_args = PushStructsNoZero(perm, String, tmp_positionals_count); + CopyStructs(Base.cmdline.positional_args, tmp_positionals, tmp_positionals_count); + for (u64 i = 0; i < tmp_args_count; ++i) + { + CommandlineArg arg = tmp_args[i]; + CommandlineArgNode *n = PushStruct(perm, CommandlineArgNode); + u64 hash = HashFnv64(Fnv64Basis, arg.name); + u64 bin_idx = hash % countof(Base.cmdline.arg_bins); + n->arg = arg; + n->hash = hash; + n->next = Base.cmdline.arg_bins[bin_idx]; + Base.cmdline.arg_bins[bin_idx] = n; + } + } + EndScratch(scratch); } //////////////////////////////////////////////////////////// @@ -74,25 +74,25 @@ void BootstrapCmdline(void) String StringFromCommandlineIdx(i32 idx) { - String result = Zi; - if (idx < Base.cmdline.positional_args_count) - { - result = Base.cmdline.positional_args[idx]; - } - return result; + String result = Zi; + if (idx < Base.cmdline.positional_args_count) + { + result = Base.cmdline.positional_args[idx]; + } + return result; } CommandlineArg CommandlineArgFromName(String name) { - CommandlineArg result = Zi; - u64 hash = HashFnv64(Fnv64Basis, name); - for (CommandlineArgNode *n = Base.cmdline.arg_bins[hash % countof(Base.cmdline.arg_bins)]; n; n = n->next) + CommandlineArg result = Zi; + u64 hash = HashFnv64(Fnv64Basis, name); + for (CommandlineArgNode *n = Base.cmdline.arg_bins[hash % countof(Base.cmdline.arg_bins)]; n; n = n->next) + { + if (n->hash == hash && MatchString(n->arg.name, name)) { - if (n->hash == hash && MatchString(n->arg.name, name)) - { - result = n->arg; - break; - } + result = n->arg; + break; } - return result; + } + return result; } diff --git a/src/base/base_cmdline.h b/src/base/base_cmdline.h index b8ac6c88..5537cd94 100644 --- a/src/base/base_cmdline.h +++ b/src/base/base_cmdline.h @@ -3,23 +3,23 @@ Struct(CommandlineArg) { - b32 exists; - String name; - String value; + b32 exists; + String name; + String value; }; Struct(CommandlineArgNode) { - CommandlineArgNode *next; - u64 hash; - CommandlineArg arg; + CommandlineArgNode *next; + u64 hash; + CommandlineArg arg; }; Struct(CmdLineCtx) { - String *positional_args; - u64 positional_args_count; - CommandlineArgNode *arg_bins[1024]; + String *positional_args; + u64 positional_args_count; + CommandlineArgNode *arg_bins[1024]; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_controller.c b/src/base/base_controller.c index 0eefc840..9ef0c490 100644 --- a/src/base/base_controller.c +++ b/src/base/base_controller.c @@ -3,107 +3,107 @@ String StringFromButton(Button button) { - PERSIST Readonly String names[Button_Count] = { - [Button_M1] = CompLit("Mouse 1"), - [Button_M2] = CompLit("Mouse 2"), - [Button_M3] = CompLit("Mouse 3"), - [Button_M4] = CompLit("Mouse 4"), - [Button_M5] = CompLit("Mouse 5"), - [Button_MWheelUp] = CompLit("Wheel Up"), - [Button_MWheelDown] = CompLit("Wheel Down"), - [Button_Escape] = CompLit("Escape"), - [Button_F1] = CompLit("F1"), - [Button_F2] = CompLit("F2"), - [Button_F3] = CompLit("F3"), - [Button_F4] = CompLit("F4"), - [Button_F5] = CompLit("F5"), - [Button_F6] = CompLit("F6"), - [Button_F7] = CompLit("F7"), - [Button_F8] = CompLit("F8"), - [Button_F9] = CompLit("F9"), - [Button_F10] = CompLit("F10"), - [Button_F11] = CompLit("F11"), - [Button_F12] = CompLit("F12"), - [Button_F13] = CompLit("F13"), - [Button_F14] = CompLit("F14"), - [Button_F15] = CompLit("F15"), - [Button_F16] = CompLit("F16"), - [Button_F17] = CompLit("F17"), - [Button_F18] = CompLit("F18"), - [Button_F19] = CompLit("F19"), - [Button_F20] = CompLit("F20"), - [Button_F21] = CompLit("F21"), - [Button_F22] = CompLit("F22"), - [Button_F23] = CompLit("F23"), - [Button_F24] = CompLit("F24"), - [Button_GraveAccent] = CompLit("~"), - [Button_0] = CompLit("0"), - [Button_1] = CompLit("1"), - [Button_2] = CompLit("2"), - [Button_3] = CompLit("3"), - [Button_4] = CompLit("4"), - [Button_5] = CompLit("5"), - [Button_6] = CompLit("6"), - [Button_7] = CompLit("7"), - [Button_8] = CompLit("8"), - [Button_9] = CompLit("9"), - [Button_Minus] = CompLit("Minus"), - [Button_Equal] = CompLit("Equal"), - [Button_Backspace] = CompLit("Backspace"), - [Button_Delete] = CompLit("Delete"), - [Button_Tab] = CompLit("Tab"), - [Button_A] = CompLit("A"), - [Button_B] = CompLit("B"), - [Button_C] = CompLit("C"), - [Button_D] = CompLit("D"), - [Button_E] = CompLit("E"), - [Button_F] = CompLit("F"), - [Button_G] = CompLit("G"), - [Button_H] = CompLit("H"), - [Button_I] = CompLit("I"), - [Button_J] = CompLit("J"), - [Button_K] = CompLit("K"), - [Button_L] = CompLit("L"), - [Button_M] = CompLit("M"), - [Button_N] = CompLit("N"), - [Button_O] = CompLit("O"), - [Button_P] = CompLit("P"), - [Button_Q] = CompLit("Q"), - [Button_R] = CompLit("R"), - [Button_S] = CompLit("S"), - [Button_T] = CompLit("T"), - [Button_U] = CompLit("U"), - [Button_V] = CompLit("V"), - [Button_W] = CompLit("W"), - [Button_X] = CompLit("X"), - [Button_Y] = CompLit("Y"), - [Button_Z] = CompLit("Z"), - [Button_Space] = CompLit("Space"), - [Button_Enter] = CompLit("Enter"), - [Button_Ctrl] = CompLit("Ctrl"), - [Button_Shift] = CompLit("Shift"), - [Button_Alt] = CompLit("Alt"), - [Button_Up] = CompLit("Up"), - [Button_Left] = CompLit("Left"), - [Button_Down] = CompLit("Down"), - [Button_Right] = CompLit("Right"), - [Button_PageUp] = CompLit("PageUp"), - [Button_PageDown] = CompLit("PageDown"), - [Button_Home] = CompLit("Home"), - [Button_End] = CompLit("End"), - [Button_ForwardSlash] = CompLit("Slash"), - [Button_Period] = CompLit("Period"), - [Button_Comma] = CompLit("Comma"), - [Button_Quote] = CompLit("Quote"), - [Button_LeftBracket] = CompLit("Left Bracket"), - [Button_RightBracket] = CompLit("Right Bracket"), - [Button_Insert] = CompLit("Insert"), - [Button_Semicolon] = CompLit("Semicolon"), - }; - String name = Lit("None"); - if (button > 0 && button < countof(names)) - { - name = names[button]; - } - return name; + PERSIST Readonly String names[Button_Count] = { + [Button_M1] = CompLit("Mouse 1"), + [Button_M2] = CompLit("Mouse 2"), + [Button_M3] = CompLit("Mouse 3"), + [Button_M4] = CompLit("Mouse 4"), + [Button_M5] = CompLit("Mouse 5"), + [Button_MWheelUp] = CompLit("Wheel Up"), + [Button_MWheelDown] = CompLit("Wheel Down"), + [Button_Escape] = CompLit("Escape"), + [Button_F1] = CompLit("F1"), + [Button_F2] = CompLit("F2"), + [Button_F3] = CompLit("F3"), + [Button_F4] = CompLit("F4"), + [Button_F5] = CompLit("F5"), + [Button_F6] = CompLit("F6"), + [Button_F7] = CompLit("F7"), + [Button_F8] = CompLit("F8"), + [Button_F9] = CompLit("F9"), + [Button_F10] = CompLit("F10"), + [Button_F11] = CompLit("F11"), + [Button_F12] = CompLit("F12"), + [Button_F13] = CompLit("F13"), + [Button_F14] = CompLit("F14"), + [Button_F15] = CompLit("F15"), + [Button_F16] = CompLit("F16"), + [Button_F17] = CompLit("F17"), + [Button_F18] = CompLit("F18"), + [Button_F19] = CompLit("F19"), + [Button_F20] = CompLit("F20"), + [Button_F21] = CompLit("F21"), + [Button_F22] = CompLit("F22"), + [Button_F23] = CompLit("F23"), + [Button_F24] = CompLit("F24"), + [Button_GraveAccent] = CompLit("~"), + [Button_0] = CompLit("0"), + [Button_1] = CompLit("1"), + [Button_2] = CompLit("2"), + [Button_3] = CompLit("3"), + [Button_4] = CompLit("4"), + [Button_5] = CompLit("5"), + [Button_6] = CompLit("6"), + [Button_7] = CompLit("7"), + [Button_8] = CompLit("8"), + [Button_9] = CompLit("9"), + [Button_Minus] = CompLit("Minus"), + [Button_Equal] = CompLit("Equal"), + [Button_Backspace] = CompLit("Backspace"), + [Button_Delete] = CompLit("Delete"), + [Button_Tab] = CompLit("Tab"), + [Button_A] = CompLit("A"), + [Button_B] = CompLit("B"), + [Button_C] = CompLit("C"), + [Button_D] = CompLit("D"), + [Button_E] = CompLit("E"), + [Button_F] = CompLit("F"), + [Button_G] = CompLit("G"), + [Button_H] = CompLit("H"), + [Button_I] = CompLit("I"), + [Button_J] = CompLit("J"), + [Button_K] = CompLit("K"), + [Button_L] = CompLit("L"), + [Button_M] = CompLit("M"), + [Button_N] = CompLit("N"), + [Button_O] = CompLit("O"), + [Button_P] = CompLit("P"), + [Button_Q] = CompLit("Q"), + [Button_R] = CompLit("R"), + [Button_S] = CompLit("S"), + [Button_T] = CompLit("T"), + [Button_U] = CompLit("U"), + [Button_V] = CompLit("V"), + [Button_W] = CompLit("W"), + [Button_X] = CompLit("X"), + [Button_Y] = CompLit("Y"), + [Button_Z] = CompLit("Z"), + [Button_Space] = CompLit("Space"), + [Button_Enter] = CompLit("Enter"), + [Button_Ctrl] = CompLit("Ctrl"), + [Button_Shift] = CompLit("Shift"), + [Button_Alt] = CompLit("Alt"), + [Button_Up] = CompLit("Up"), + [Button_Left] = CompLit("Left"), + [Button_Down] = CompLit("Down"), + [Button_Right] = CompLit("Right"), + [Button_PageUp] = CompLit("PageUp"), + [Button_PageDown] = CompLit("PageDown"), + [Button_Home] = CompLit("Home"), + [Button_End] = CompLit("End"), + [Button_ForwardSlash] = CompLit("Slash"), + [Button_Period] = CompLit("Period"), + [Button_Comma] = CompLit("Comma"), + [Button_Quote] = CompLit("Quote"), + [Button_LeftBracket] = CompLit("Left Bracket"), + [Button_RightBracket] = CompLit("Right Bracket"), + [Button_Insert] = CompLit("Insert"), + [Button_Semicolon] = CompLit("Semicolon"), + }; + String name = Lit("None"); + if (button > 0 && button < countof(names)) + { + name = names[button]; + } + return name; } diff --git a/src/base/base_controller.h b/src/base/base_controller.h index 726f75a3..92b0f16b 100644 --- a/src/base/base_controller.h +++ b/src/base/base_controller.h @@ -3,110 +3,110 @@ Enum(Button) { - Button_None, + Button_None, - //- Mouse buttons - Button_M1, - Button_M2, - Button_M3, - Button_M4, - Button_M5, + //- Mouse buttons + Button_M1, + Button_M2, + Button_M3, + Button_M4, + Button_M5, - //- Mouse wheel - Button_MWheelUp, - Button_MWheelDown, + //- Mouse wheel + Button_MWheelUp, + Button_MWheelDown, - //- Keyboard buttons - Button_Escape, - Button_F1, - Button_F2, - Button_F3, - Button_F4, - Button_F5, - Button_F6, - Button_F7, - Button_F8, - Button_F9, - Button_F10, - Button_F11, - Button_F12, - Button_F13, - Button_F14, - Button_F15, - Button_F16, - Button_F17, - Button_F18, - Button_F19, - Button_F20, - Button_F21, - Button_F22, - Button_F23, - Button_F24, - Button_GraveAccent, - Button_0, - Button_1, - Button_2, - Button_3, - Button_4, - Button_5, - Button_6, - Button_7, - Button_8, - Button_9, - Button_Minus, - Button_Equal, - Button_Backspace, - Button_Delete, - Button_Tab, - Button_A, - Button_B, - Button_C, - Button_D, - Button_E, - Button_F, - Button_G, - Button_H, - Button_I, - Button_J, - Button_K, - Button_L, - Button_M, - Button_N, - Button_O, - Button_P, - Button_Q, - Button_R, - Button_S, - Button_T, - Button_U, - Button_V, - Button_W, - Button_X, - Button_Y, - Button_Z, - Button_Space, - Button_Enter, - Button_Ctrl, - Button_Shift, - Button_Alt, - Button_Up, - Button_Left, - Button_Down, - Button_Right, - Button_PageUp, - Button_PageDown, - Button_Home, - Button_End, - Button_ForwardSlash, - Button_Period, - Button_Comma, - Button_Quote, - Button_LeftBracket, - Button_RightBracket, - Button_Insert, - Button_Semicolon, + //- Keyboard buttons + Button_Escape, + Button_F1, + Button_F2, + Button_F3, + Button_F4, + Button_F5, + Button_F6, + Button_F7, + Button_F8, + Button_F9, + Button_F10, + Button_F11, + Button_F12, + Button_F13, + Button_F14, + Button_F15, + Button_F16, + Button_F17, + Button_F18, + Button_F19, + Button_F20, + Button_F21, + Button_F22, + Button_F23, + Button_F24, + Button_GraveAccent, + Button_0, + Button_1, + Button_2, + Button_3, + Button_4, + Button_5, + Button_6, + Button_7, + Button_8, + Button_9, + Button_Minus, + Button_Equal, + Button_Backspace, + Button_Delete, + Button_Tab, + Button_A, + Button_B, + Button_C, + Button_D, + Button_E, + Button_F, + Button_G, + Button_H, + Button_I, + Button_J, + Button_K, + Button_L, + Button_M, + Button_N, + Button_O, + Button_P, + Button_Q, + Button_R, + Button_S, + Button_T, + Button_U, + Button_V, + Button_W, + Button_X, + Button_Y, + Button_Z, + Button_Space, + Button_Enter, + Button_Ctrl, + Button_Shift, + Button_Alt, + Button_Up, + Button_Left, + Button_Down, + Button_Right, + Button_PageUp, + Button_PageDown, + Button_Home, + Button_End, + Button_ForwardSlash, + Button_Period, + Button_Comma, + Button_Quote, + Button_LeftBracket, + Button_RightBracket, + Button_Insert, + Button_Semicolon, - Button_Count + Button_Count }; //////////////////////////////////////////////////////////// @@ -114,44 +114,44 @@ Enum(Button) Enum(ControllerEventKind) { - ControllerEventKind_None, + ControllerEventKind_None, - ControllerEventKind_ButtonDown, - ControllerEventKind_ButtonUp, + ControllerEventKind_ButtonDown, + ControllerEventKind_ButtonUp, - ControllerEventKind_CursorMove, - ControllerEventKind_MouseMove, + ControllerEventKind_CursorMove, + ControllerEventKind_MouseMove, - ControllerEventKind_Text, + ControllerEventKind_Text, - ControllerEventKind_Quit, + ControllerEventKind_Quit, - ControllerEventKind_Count + ControllerEventKind_Count }; Struct(ControllerEvent) { - ControllerEventKind kind; + ControllerEventKind kind; - /* ControllerEventKind_ButtonDown */ - /* ControllerEventKind_ButtonUp */ - Button button; - b32 is_repeat; + /* ControllerEventKind_ButtonDown */ + /* ControllerEventKind_ButtonUp */ + Button button; + b32 is_repeat; - /* ControllerEventKind_Text */ - u32 text_codepoint; + /* ControllerEventKind_Text */ + u32 text_codepoint; - /* ControllerEventKind_CursorMove */ - Vec2I32 cursor_pos; + /* ControllerEventKind_CursorMove */ + Vec2I32 cursor_pos; - /* ControllerEventKind_MouseMove */ - Vec2I32 mouse_delta; + /* ControllerEventKind_MouseMove */ + Vec2I32 mouse_delta; }; Struct(ControllerEventsArray) { - u64 count; - ControllerEvent *events; + u64 count; + ControllerEvent *events; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_file.h b/src/base/base_file.h index b84dfb06..d26bfe5b 100644 --- a/src/base/base_file.h +++ b/src/base/base_file.h @@ -3,15 +3,15 @@ Enum(OS_FileFlag) { - OS_FileFlag_None = 0, - OS_FileFlag_Read = (1 << 0), - OS_FileFlag_Write = (1 << 1), - OS_FileFlag_Create = (1 << 2), + OS_FileFlag_None = 0, + OS_FileFlag_Read = (1 << 0), + OS_FileFlag_Write = (1 << 1), + OS_FileFlag_Create = (1 << 2), }; Struct(OS_File) { - u64 handle; + u64 handle; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_gstat.h b/src/base/base_gstat.h index 2cbaf12d..8ee5056b 100644 --- a/src/base/base_gstat.h +++ b/src/base/base_gstat.h @@ -5,17 +5,17 @@ Struct(GstatCtx) { - Atomic64Padded SockBytesSent; - Atomic64Padded SockBytesReceived; - Atomic64Padded DebugSteps; + Atomic64Padded SockBytesSent; + Atomic64Padded SockBytesReceived; + Atomic64Padded DebugSteps; - Atomic64Padded NumArenas; - Atomic64Padded ArenaMemoryCommitted; - Atomic64Padded ArenaMemoryReserved; + Atomic64Padded NumArenas; + Atomic64Padded ArenaMemoryCommitted; + Atomic64Padded ArenaMemoryReserved; - Atomic64Padded NumGpuArenas; - Atomic64Padded DedicatedGpuArenaMemoryCommitted; - Atomic64Padded SharedGpuArenaMemoryCommitted; + Atomic64Padded NumGpuArenas; + Atomic64Padded DedicatedGpuArenaMemoryCommitted; + Atomic64Padded SharedGpuArenaMemoryCommitted; }; diff --git a/src/base/base_inc.h b/src/base/base_inc.h index 1c567077..471272ce 100644 --- a/src/base/base_inc.h +++ b/src/base/base_inc.h @@ -5,53 +5,53 @@ //- Api #include "base.cgh" #if IsLanguageC -# include "base_intrinsics.h" -# include "base_memory.h" -# include "base_arena.h" -# include "base_futex.h" -# include "base_sync.h" -# include "base_time.h" -# include "base_uid.h" -# include "base_math.h" -# include "base_wave.h" -# include "base_string.h" -# include "base_cmdline.h" -# include "base_log.h" -# include "base_uni.h" -# include "base_gstat.h" -# include "base_buddy.h" -# include "base_rand.h" -# include "base_util.h" -# include "base_bitbuff.h" -# include "base_resource.h" -# include "base_controller.h" -# include "base_async.h" -# include "base_state.h" + #include "base_intrinsics.h" + #include "base_memory.h" + #include "base_arena.h" + #include "base_futex.h" + #include "base_sync.h" + #include "base_time.h" + #include "base_uid.h" + #include "base_math.h" + #include "base_wave.h" + #include "base_string.h" + #include "base_cmdline.h" + #include "base_log.h" + #include "base_uni.h" + #include "base_gstat.h" + #include "base_buddy.h" + #include "base_rand.h" + #include "base_util.h" + #include "base_bitbuff.h" + #include "base_resource.h" + #include "base_controller.h" + #include "base_async.h" + #include "base_state.h" #elif IsLanguageG -# include "base_shader.gh" + #include "base_shader.gh" #endif //- Impl #if IsLanguageC -# include "base_memory.c" -# include "base_arena.c" -# include "base_sync.c" -# include "base_uid.c" -# include "base_string.c" -# include "base_cmdline.c" -# include "base_uni.c" -# include "base_buddy.c" -# include "base_math.c" -# include "base_wave.c" -# include "base_rand.c" -# include "base_bitbuff.c" -# include "base_resource.c" -# include "base_controller.c" -# include "base_async.c" -# include "base_state.c" + #include "base_memory.c" + #include "base_arena.c" + #include "base_sync.c" + #include "base_uid.c" + #include "base_string.c" + #include "base_cmdline.c" + #include "base_uni.c" + #include "base_buddy.c" + #include "base_math.c" + #include "base_wave.c" + #include "base_rand.c" + #include "base_bitbuff.c" + #include "base_resource.c" + #include "base_controller.c" + #include "base_async.c" + #include "base_state.c" #endif //- Include base_win32 #if IsLanguageC && IsPlatformWindows -# include "base_win32/base_win32_inc.h" + #include "base_win32/base_win32_inc.h" #endif diff --git a/src/base/base_intrinsics.h b/src/base/base_intrinsics.h index 563af523..014beba1 100644 --- a/src/base/base_intrinsics.h +++ b/src/base/base_intrinsics.h @@ -3,23 +3,23 @@ Inline f32 IxSqrtF32(f32 f) { - __m128 n = _mm_set_ss(f); - n = _mm_sqrt_ss(n); - return _mm_cvtss_f32(n); + __m128 n = _mm_set_ss(f); + n = _mm_sqrt_ss(n); + return _mm_cvtss_f32(n); } Inline f64 IxSqrtF64(f64 f) { - __m128d n = _mm_set_sd(f); - n = _mm_sqrt_sd(_mm_setzero_pd(), n); - return _mm_cvtsd_f64(n); + __m128d n = _mm_set_sd(f); + n = _mm_sqrt_sd(_mm_setzero_pd(), n); + return _mm_cvtsd_f64(n); } Inline f32 IxRsqrtF32(f32 f) { - __m128 n = _mm_set_ss(f); - n = _mm_rsqrt_ss(n); - return _mm_cvtss_f32(n); + __m128 n = _mm_set_ss(f); + n = _mm_rsqrt_ss(n); + return _mm_cvtss_f32(n); } //////////////////////////////////////////////////////////// @@ -27,22 +27,22 @@ Inline f32 IxRsqrtF32(f32 f) Inline i32 IxRoundF32ToI32(f32 f) { - return _mm_cvtss_si32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); + return _mm_cvtss_si32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); } Inline f32 IxRoundF32ToF32(f32 f) { - return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); + return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); } Inline i64 IxRoundF64ToI64(f64 f) { - return _mm_cvtsd_si64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); + return _mm_cvtsd_si64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); } Inline f64 IxRoundF64ToF64(f64 f) { - return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); + return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); } //////////////////////////////////////////////////////////// @@ -50,22 +50,22 @@ Inline f64 IxRoundF64ToF64(f64 f) Inline i32 IxFloorF32ToI32(f32 f) { - return _mm_cvtss_si32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f))); + return _mm_cvtss_si32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f))); } Inline f32 IxFloorF32ToF32(f32 f) { - return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f))); + return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f))); } Inline i64 IxFloorF64ToI64(f64 f) { - return _mm_cvtsd_si64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f))); + return _mm_cvtsd_si64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f))); } Inline f64 IxFloorF64ToF64(f64 f) { - return _mm_cvtsd_f64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f))); + return _mm_cvtsd_f64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f))); } //////////////////////////////////////////////////////////// @@ -73,22 +73,22 @@ Inline f64 IxFloorF64ToF64(f64 f) Inline i32 IxCeilF32ToI32(f32 f) { - return _mm_cvtss_si32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f))); + return _mm_cvtss_si32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f))); } Inline f32 IxCeilF32ToF32(f32 f) { - return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f))); + return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f))); } Inline i64 IxCeilF64ToI64(f64 f) { - return _mm_cvtsd_si64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f))); + return _mm_cvtsd_si64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f))); } Inline f64 IxCeilF64ToF64(f64 f) { - return _mm_cvtsd_f64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f))); + return _mm_cvtsd_f64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f))); } //////////////////////////////////////////////////////////// @@ -96,10 +96,10 @@ Inline f64 IxCeilF64ToF64(f64 f) Inline f32 IxTruncF32ToF32(f32 f) { - return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC)); + return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC)); } Inline f64 IxTruncF64ToF64(f64 f) { - return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC)); + return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC)); } diff --git a/src/base/base_log.h b/src/base/base_log.h index f43a1f13..ad017f0e 100644 --- a/src/base/base_log.h +++ b/src/base/base_log.h @@ -3,22 +3,22 @@ Struct(LogEvent) { - u64 id; - u64 level_id; + u64 id; + u64 level_id; - DateTime datetime; - i64 time_ns; + DateTime datetime; + i64 time_ns; - String msg; - i32 level; + String msg; + i32 level; - i32 thread_id; + i32 thread_id; }; Struct(LogEventsArray) { - u64 count; - LogEvent *logs; + u64 count; + LogEvent *logs; }; //////////////////////////////////////////////////////////// @@ -28,11 +28,11 @@ Struct(LogEventsArray) /* Log level configuration */ #ifndef LogLevel_CompTime -# if IsRtcEnabled -# define LogLevel_CompTime LogLevel_Debug -# else -# define LogLevel_CompTime LogLevel_Info -# endif + #if IsRtcEnabled + #define LogLevel_CompTime LogLevel_Debug + #else + #define LogLevel_CompTime LogLevel_Info + #endif #endif #define LogLevel_None -1 @@ -49,84 +49,84 @@ Struct(LogEventsArray) Struct(LogLevelSettings) { - String shorthand; + String shorthand; }; Global Readonly LogLevelSettings log_settings[LogLevel_Count] = { - [LogLevel_Critical] = { - CompLit("CRITICAL"), - }, + [LogLevel_Critical] = { + CompLit("CRITICAL"), + }, - [LogLevel_Error] = { - CompLit("ERROR"), - }, + [LogLevel_Error] = { + CompLit("ERROR"), + }, - [LogLevel_Warning] = { - CompLit("WARNING"), - }, + [LogLevel_Warning] = { + CompLit("WARNING"), + }, - [LogLevel_Success] = { - CompLit("SUCCESS"), - }, + [LogLevel_Success] = { + CompLit("SUCCESS"), + }, - [LogLevel_Info] = { - CompLit("INFO"), - }, + [LogLevel_Info] = { + CompLit("INFO"), + }, - [LogLevel_Debug] = { - CompLit("DEBUG"), - } + [LogLevel_Debug] = { + CompLit("DEBUG"), + } }; //////////////////////////////////////////////////////////// //~ Compile-time logging macros #if LogLevel(LogLevel_Critical) -# define LogCritical(msg) Log_(LogLevel_Critical, msg) -# define LogCriticalF(fmt_lit, ...) LogF_(LogLevel_Critical, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) + #define LogCritical(msg) Log_(LogLevel_Critical, msg) + #define LogCriticalF(fmt_lit, ...) LogF_(LogLevel_Critical, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #else -# define LogCritical(msg) -# define LogCriticalF(...) + #define LogCritical(msg) + #define LogCriticalF(...) #endif #if LogLevel(LogLevel_Error) -# define LogError(msg) Log_(LogLevel_Error, msg) -# define LogErrorF(fmt_lit, ...) LogF_(LogLevel_Error, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) + #define LogError(msg) Log_(LogLevel_Error, msg) + #define LogErrorF(fmt_lit, ...) LogF_(LogLevel_Error, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #else -# define LogError(msg) -# define LogErrorF(...) + #define LogError(msg) + #define LogErrorF(...) #endif #if LogLevel(LogLevel_Warning) -# define LogWarning(msg) Log_(LogLevel_Warning, msg) -# define LogWarningF(fmt_lit, ...) LogF_(LogLevel_Warning, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) + #define LogWarning(msg) Log_(LogLevel_Warning, msg) + #define LogWarningF(fmt_lit, ...) LogF_(LogLevel_Warning, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #else -# define LogWarning(msg) -# define LogWarningF(...) + #define LogWarning(msg) + #define LogWarningF(...) #endif #if LogLevel(LogLevel_Success) -# define LogSuccess(msg) Log_(LogLevel_Success, msg) -# define LogSuccessF(fmt_lit, ...) LogF_(LogLevel_Success, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) + #define LogSuccess(msg) Log_(LogLevel_Success, msg) + #define LogSuccessF(fmt_lit, ...) LogF_(LogLevel_Success, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #else -# define LogSuccess(msg) -# define LogSuccessF(...) + #define LogSuccess(msg) + #define LogSuccessF(...) #endif #if LogLevel(LogLevel_Info) -# define LogInfo(msg) Log_(LogLevel_Info, msg) -# define LogInfoF(fmt_lit, ...) LogF_(LogLevel_Info, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) + #define LogInfo(msg) Log_(LogLevel_Info, msg) + #define LogInfoF(fmt_lit, ...) LogF_(LogLevel_Info, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #else -# define LogInfo(msg) -# define LogInfoF(...) + #define LogInfo(msg) + #define LogInfoF(...) #endif #if LogLevel(LogLevel_Debug) -# define LogDebug(msg) Log_(LogLevel_Debug, msg) -# define LogDebugF(fmt_lit, ...) LogF_(LogLevel_Debug, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) + #define LogDebug(msg) Log_(LogLevel_Debug, msg) + #define LogDebugF(fmt_lit, ...) LogF_(LogLevel_Debug, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd) #else -# define LogDebug(msg) -# define LogDebugF(...) + #define LogDebug(msg) + #define LogDebugF(...) #endif //////////////////////////////////////////////////////////// diff --git a/src/base/base_math.c b/src/base/base_math.c index bacf0e74..512786bd 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -37,75 +37,75 @@ f64 ClampF64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ? max : v //- Round f32 RoundF32(f32 f) { - return IxRoundF32ToF32(f); + return IxRoundF32ToF32(f); } f64 RoundF64(f64 f) { - return IxRoundF64ToF64(f); + return IxRoundF64ToF64(f); } i32 RoundF32ToI32(f32 f) { - return IxRoundF32ToI32(f); + return IxRoundF32ToI32(f); } i64 RoundF64ToI64(f64 f) { - return IxRoundF64ToI64(f); + return IxRoundF64ToI64(f); } //- Floor f32 FloorF32(f32 f) { - return IxFloorF32ToF32(f); + return IxFloorF32ToF32(f); } f64 FloorF64(f64 f) { - return IxFloorF64ToF64(f); + return IxFloorF64ToF64(f); } i32 FloorF32ToI32(f32 f) { - return IxFloorF32ToI32(f); + return IxFloorF32ToI32(f); } i64 FloorF64ToI64(f64 f) { - return IxFloorF64ToI64(f); + return IxFloorF64ToI64(f); } //- Ceil f32 CeilF32(f32 f) { - return IxCeilF32ToF32(f); + return IxCeilF32ToF32(f); } f64 CeilF64(f64 f) { - return IxCeilF64ToF64(f); + return IxCeilF64ToF64(f); } i32 CeilF32ToI32(f32 f) { - return IxCeilF32ToI32(f); + return IxCeilF32ToI32(f); } i64 CeilF64ToI64(f64 f) { - return IxCeilF64ToI64(f); + return IxCeilF64ToI64(f); } //- Trunc f32 TruncF32(f32 f) { - return IxTruncF32ToF32(f); + return IxTruncF32ToF32(f); } f64 TruncF64(f64 f) { - return IxTruncF64ToF64(f); + return IxTruncF64ToF64(f); } //////////////////////////////////////////////////////////// @@ -113,12 +113,12 @@ f64 TruncF64(f64 f) f32 ModF32(f32 x, f32 m) { - return x - m * TruncF32(x / m); + return x - m * TruncF32(x / m); } f64 ModF64(f64 x, f64 m) { - return x - m * TruncF64(x / m); + return x - m * TruncF64(x / m); } //////////////////////////////////////////////////////////// @@ -126,36 +126,36 @@ f64 ModF64(f64 x, f64 m) f32 AbsF32(f32 f) { - u32 truncated = *(u32 *)&f & 0x7FFFFFFF; - return *(f32 *)&truncated; + u32 truncated = *(u32 *)&f & 0x7FFFFFFF; + return *(f32 *)&truncated; } f64 AbsF64(f64 f) { - u64 truncated = *(u64 *)&f & 0x7FFFFFFFFFFFFFFFULL; - return *(f64 *)&truncated; + u64 truncated = *(u64 *)&f & 0x7FFFFFFFFFFFFFFFULL; + return *(f64 *)&truncated; } u32 AbsI32(i32 v) { - return (u32)(v * ((v >= 0) - (v < 0))); + return (u32)(v * ((v >= 0) - (v < 0))); } u64 AbsI64(i64 v) { - return (u64)(v * ((v >= 0) - (v < 0))); + return (u64)(v * ((v >= 0) - (v < 0))); } i32 SignF32(f32 f) { - u32 sign_bit = (*(u32 *)&f >> 31) & 1; - return 1 + -((i32)(sign_bit << 1)); + u32 sign_bit = (*(u32 *)&f >> 31) & 1; + return 1 + -((i32)(sign_bit << 1)); } i64 SignF64(f64 f) { - u64 sign_bit = (*(u64 *)&f >> 63) & 1; - return 1 + -((i64)(sign_bit << 1)); + u64 sign_bit = (*(u64 *)&f >> 63) & 1; + return 1 + -((i64)(sign_bit << 1)); } //////////////////////////////////////////////////////////// @@ -166,94 +166,94 @@ i64 SignF64(f64 f) /* Taken from https://gist.github.com/orlp/3551590 */ u64 PowU64(u64 base, u8 exp) { - PERSIST const u8 highest_bit_set[] = { - 0, 1, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 255, /* Anything past 63 is a guaranteed overflow with base > 1 */ - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - }; + PERSIST const u8 highest_bit_set[] = { + 0, 1, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 255, /* Anything past 63 is a guaranteed overflow with base > 1 */ + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + }; - u64 result = 1; + u64 result = 1; - switch (highest_bit_set[exp]) + switch (highest_bit_set[exp]) + { + case 255: { - case 255: - { - /* 255 = overflow, return 0 */ - if (base == 1) - { - return 1; - } - // if (base == -1) - // { - // return 1 - 2 * (exp & 1); - // } - return 0; - } break; - case 6: - { - if (exp & 1) result *= base; - exp >>= 1; - base *= base; - } FALLTHROUGH; - case 5: - { - if (exp & 1) result *= base; - exp >>= 1; - base *= base; - } FALLTHROUGH; - case 4: - { - if (exp & 1) result *= base; - exp >>= 1; - base *= base; - } FALLTHROUGH; - case 3: - { - if (exp & 1) result *= base; - exp >>= 1; - base *= base; - } FALLTHROUGH; - case 2: - { - if (exp & 1) result *= base; - exp >>= 1; - base *= base; - } FALLTHROUGH; - case 1: - { - if (exp & 1) result *= base; - } FALLTHROUGH; - default: return result; - } + /* 255 = overflow, return 0 */ + if (base == 1) + { + return 1; + } + // if (base == -1) + // { + // return 1 - 2 * (exp & 1); + // } + return 0; + } break; + case 6: + { + if (exp & 1) result *= base; + exp >>= 1; + base *= base; + } FALLTHROUGH; + case 5: + { + if (exp & 1) result *= base; + exp >>= 1; + base *= base; + } FALLTHROUGH; + case 4: + { + if (exp & 1) result *= base; + exp >>= 1; + base *= base; + } FALLTHROUGH; + case 3: + { + if (exp & 1) result *= base; + exp >>= 1; + base *= base; + } FALLTHROUGH; + case 2: + { + if (exp & 1) result *= base; + exp >>= 1; + base *= base; + } FALLTHROUGH; + case 1: + { + if (exp & 1) result *= base; + } FALLTHROUGH; + default: return result; + } } //- Logn @@ -262,92 +262,92 @@ u64 PowU64(u64 base, u8 exp) * https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_logf.c */ f32 LnF32(f32 x) { - PERSIST const f32 ln2_hi = 6.9313812256e-01f; - PERSIST const f32 ln2_lo = 9.0580006145e-06f; + PERSIST const f32 ln2_hi = 6.9313812256e-01f; + PERSIST const f32 ln2_lo = 9.0580006145e-06f; - i32 x_int = *(i32 *)&x; + i32 x_int = *(i32 *)&x; - i32 k = 0; - if (x_int < 0x00800000) + i32 k = 0; + if (x_int < 0x00800000) + { + f32 two_p25 = 3.3554432000e+07; + if ((x_int & 0x7fffffff) == 0) { - f32 two_p25 = 3.3554432000e+07; - if ((x_int & 0x7fffffff) == 0) - { - /* Return -inf if x is 0 */ - return -F32Infinity; - } - else if (x_int < 0) - { - /* Return NaN if x is negative */ - return F32Nan; - } - k -= 25; - x *= two_p25; - x_int = *(i32 *)&x; + /* Return -inf if x is 0 */ + return -F32Infinity; } - else if (x_int >= 0x7f800000) + else if (x_int < 0) { - return x + x; + /* Return NaN if x is negative */ + return F32Nan; } + k -= 25; + x *= two_p25; + x_int = *(i32 *)&x; + } + else if (x_int >= 0x7f800000) + { + return x + x; + } - k += (x_int >> 23) - 127; - x_int &= 0x007fffff; - i32 i = (x_int + (0x95f64 << 3)) & 0x800000; - i32 x_int_normalized = x_int | (i ^ 0x3f800000); - x = *(f32 *)&x_int_normalized - 1.0f; - k += (i >> 23); + k += (x_int >> 23) - 127; + x_int &= 0x007fffff; + i32 i = (x_int + (0x95f64 << 3)) & 0x800000; + i32 x_int_normalized = x_int | (i ^ 0x3f800000); + x = *(f32 *)&x_int_normalized - 1.0f; + k += (i >> 23); - if ((0x007fffff & (0x8000 + x_int)) < 0xc000) + if ((0x007fffff & (0x8000 + x_int)) < 0xc000) + { + if (x == 0) { - if (x == 0) - { - if (k == 0) - { - return 0; - } - else - { - return (f32)k * ln2_hi + (f32)k * ln2_lo; - } - } - f32 r = x * x * (0.5f - 0.33333333333333333f * x); - if (k == 0) - { - return x - r; - } - else - { - return (f32)k * ln2_hi - ((r - (f32)k * ln2_lo) - x); - } + if (k == 0) + { + return 0; + } + else + { + return (f32)k * ln2_hi + (f32)k * ln2_lo; + } } - - f32 s = x / (2.0f + x); - f32 z = s * s; - f32 w = z * z; - f32 r = (z * (0.66666662693f + w * 0.28498786688f)) + (w * (0.40000972152f + w * 0.24279078841f)); - if (((x_int - (0x6147a << 3)) | ((0x6b851 << 3) - x_int)) > 0) + f32 r = x * x * (0.5f - 0.33333333333333333f * x); + if (k == 0) { - f32 hfsq = 0.5f * x * x; - if (k == 0) - { - return x - (hfsq - s * (hfsq + r)); - } - else - { - return (f32)k * ln2_hi - ((hfsq - (s * (hfsq + r) + (f32)k * ln2_lo)) - x); - } + return x - r; } else { - if (k == 0) - { - return x - s * (x - r); - } - else - { - return (f32)k * ln2_hi - ((s * (x - r) - (f32)k * ln2_lo) - x); - } + return (f32)k * ln2_hi - ((r - (f32)k * ln2_lo) - x); } + } + + f32 s = x / (2.0f + x); + f32 z = s * s; + f32 w = z * z; + f32 r = (z * (0.66666662693f + w * 0.28498786688f)) + (w * (0.40000972152f + w * 0.24279078841f)); + if (((x_int - (0x6147a << 3)) | ((0x6b851 << 3) - x_int)) > 0) + { + f32 hfsq = 0.5f * x * x; + if (k == 0) + { + return x - (hfsq - s * (hfsq + r)); + } + else + { + return (f32)k * ln2_hi - ((hfsq - (s * (hfsq + r) + (f32)k * ln2_lo)) - x); + } + } + else + { + if (k == 0) + { + return x - s * (x - r); + } + else + { + return (f32)k * ln2_hi - ((s * (x - r) - (f32)k * ln2_lo) - x); + } + } } //- Exp @@ -356,143 +356,143 @@ f32 LnF32(f32 x) * https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_expf.c */ f32 ExpF32(f32 x) { - PERSIST const f32 half[2] = { 0.5, -0.5 }; - PERSIST const f32 o_threshold = 8.8721679688e+01f; - PERSIST const f32 u_threshold = -1.0397208405e+02f; - PERSIST const f32 ln2_hi[2] = { 6.9314575195e-01f, -6.9314575195e-01f }; - PERSIST const f32 ln2_lo[2] = { 1.4286067653e-06f, -1.4286067653e-06f }; - PERSIST const f32 inv_ln2 = 1.4426950216e+00f; - PERSIST const f32 huge = 1.0e+30f; - PERSIST const f32 two_m100 = 7.8886090522e-31f; + PERSIST const f32 half[2] = { 0.5, -0.5 }; + PERSIST const f32 o_threshold = 8.8721679688e+01f; + PERSIST const f32 u_threshold = -1.0397208405e+02f; + PERSIST const f32 ln2_hi[2] = { 6.9314575195e-01f, -6.9314575195e-01f }; + PERSIST const f32 ln2_lo[2] = { 1.4286067653e-06f, -1.4286067653e-06f }; + PERSIST const f32 inv_ln2 = 1.4426950216e+00f; + PERSIST const f32 huge = 1.0e+30f; + PERSIST const f32 two_m100 = 7.8886090522e-31f; - u32 x_uint = *(u32 *)&x; - i32 x_sign_bit = (i32)((x_uint >> 31) & 1); - x_uint &= 0x7fffffff; + u32 x_uint = *(u32 *)&x; + i32 x_sign_bit = (i32)((x_uint >> 31) & 1); + x_uint &= 0x7fffffff; - /* Filter out non-finite argument */ - if (x_uint >= 0x42b17218) - { /* if |x|>=88.721... */ - if (x_uint > 0x7f800000) - { - return x + x; /* NaN */ - } - else if (x_uint == 0x7f800000) - { - return (x_sign_bit == 0) ? x : 0; - } - if (x > o_threshold) - { - /* Overflow */ - return F32Infinity; - } - else if (x < u_threshold) - { - /* Underflow */ - return two_m100 * two_m100; - } - } - - /* Argument reduction */ - i32 k = 0; - f32 hi = 0; - f32 lo = 0; - if (x_uint > 0x3eb17218) + /* Filter out non-finite argument */ + if (x_uint >= 0x42b17218) + { /* if |x|>=88.721... */ + if (x_uint > 0x7f800000) { - if (x_uint < 0x3F851592) - { - hi = x - ln2_hi[x_sign_bit]; - lo = ln2_lo[x_sign_bit]; - k = 1 - x_sign_bit - x_sign_bit; - } - else - { - k = (i32)(inv_ln2 * x + half[x_sign_bit]); - hi = x - (f32)k * ln2_hi[0]; - lo = (f32)k * ln2_lo[0]; - } - x = hi - lo; + return x + x; /* NaN */ } - else if (x_uint < 0x39000000) + else if (x_uint == 0x7f800000) { - if (huge + x > 1.0f) - { - return 1.0f + x; - } + return (x_sign_bit == 0) ? x : 0; + } + if (x > o_threshold) + { + /* Overflow */ + return F32Infinity; + } + else if (x < u_threshold) + { + /* Underflow */ + return two_m100 * two_m100; + } + } + + /* Argument reduction */ + i32 k = 0; + f32 hi = 0; + f32 lo = 0; + if (x_uint > 0x3eb17218) + { + if (x_uint < 0x3F851592) + { + hi = x - ln2_hi[x_sign_bit]; + lo = ln2_lo[x_sign_bit]; + k = 1 - x_sign_bit - x_sign_bit; } else { - k = 0; + k = (i32)(inv_ln2 * x + half[x_sign_bit]); + hi = x - (f32)k * ln2_hi[0]; + lo = (f32)k * ln2_lo[0]; } + x = hi - lo; + } + else if (x_uint < 0x39000000) + { + if (huge + x > 1.0f) + { + return 1.0f + x; + } + } + else + { + k = 0; + } - f32 two_pk; + f32 two_pk; + if (k >= -125) + { + u32 temp = ((u32)(0x7f + k)) << 23; + two_pk = *(f32 *)&temp; + } + else + { + u32 temp = ((u32)(0x7f + (k + 100))) << 23; + two_pk = *(f32 *)&temp; + } + + f32 t = x * x; + f32 c = x - t * (1.6666625440e-1f + t * -2.7667332906e-3f); + if (k == 0) + { + return 1.0f - ((x * c) / (c - 2.0f) - x); + } + else + { + f32 y = 1.0f - ((lo - (x * c) / (2.0f - c)) - hi); if (k >= -125) { - u32 temp = ((u32)(0x7f + k)) << 23; - two_pk = *(f32 *)&temp; + if (k == 128) + { + u32 temp = 0x7f800000; + return y * 2.0f * (*(f32 *)&temp); + } + return y * two_pk; } else { - u32 temp = ((u32)(0x7f + (k + 100))) << 23; - two_pk = *(f32 *)&temp; - } - - f32 t = x * x; - f32 c = x - t * (1.6666625440e-1f + t * -2.7667332906e-3f); - if (k == 0) - { - return 1.0f - ((x * c) / (c - 2.0f) - x); - } - else - { - f32 y = 1.0f - ((lo - (x * c) / (2.0f - c)) - hi); - if (k >= -125) - { - if (k == 128) - { - u32 temp = 0x7f800000; - return y * 2.0f * (*(f32 *)&temp); - } - return y * two_pk; - } - else - { - return y * two_pk * two_m100; - } + return y * two_pk * two_m100; } + } } //- Pow f32 PowF32(f32 a, f32 b) { - if (a >= 0) - { - /* a is positive */ - return ExpF32(LnF32(a) * b); - } - else - { - /* a is negative */ - i32 res_sign = RoundF32ToI32(b) % 2 == 0 ? 1 : -1; - return ExpF32(LnF32(-a) * b) * res_sign; - } + if (a >= 0) + { + /* a is positive */ + return ExpF32(LnF32(a) * b); + } + else + { + /* a is negative */ + i32 res_sign = RoundF32ToI32(b) % 2 == 0 ? 1 : -1; + return ExpF32(LnF32(-a) * b) * res_sign; + } } //- Sqrt f32 SqrtF32(f32 x) { - return IxSqrtF32(x); + return IxSqrtF32(x); } f64 SqrtF64(f64 x) { - return IxSqrtF64(x); + return IxSqrtF64(x); } f32 RSqrtF32(f32 x) { - return IxRsqrtF32(x); + return IxRsqrtF32(x); } //////////////////////////////////////////////////////////// @@ -500,27 +500,27 @@ f32 RSqrtF32(f32 x) u64 AlignU64(u64 x, u64 align) { - align = MaxU64(align, 1); - u64 result = (x + (align - 1)); - result -= result % align; - return result; + align = MaxU64(align, 1); + u64 result = (x + (align - 1)); + result -= result % align; + return result; } u64 AlignU64ToNextPow2(u64 x) { - u64 result = 0; - if (x > 0) - { - result = x - 1; - result |= result >> 1; - result |= result >> 2; - result |= result >> 4; - result |= result >> 8; - result |= result >> 16; - result |= result >> 32; - ++result; - } - return result; + u64 result = 0; + if (x > 0) + { + result = x - 1; + result |= result >> 1; + result |= result >> 2; + result |= result >> 4; + result |= result >> 8; + result |= result >> 16; + result |= result >> 32; + ++result; + } + return result; } //////////////////////////////////////////////////////////// @@ -539,216 +539,216 @@ u64 AlignU64ToNextPow2(u64 x) * Sets octant_out=-1 on error. */ f32 ReduceToPio4(f32 x, i32 *octant_out) { - i32 octant = -1; + i32 octant = -1; - if (x <= ((1 << 24) - 1)) + if (x <= ((1 << 24) - 1)) + { + octant = (i32)(x * (4 / Pi)); /* Integer part of x/(Pi/4) */ + f32 y = (f32)octant; + if (octant & 1) { - octant = (i32)(x * (4 / Pi)); /* Integer part of x/(Pi/4) */ - f32 y = (f32)octant; - if (octant & 1) - { - octant += 1; - y += 1.0; - } - - /* Modulo 360 degrees */ - octant &= 7; - - if (x > 8192) - { - x = x - y * (Pi / 4); - } - else - { - /* Extended precision modular arithmetic */ - x = ((x - y * 0.78515625) - y * 2.4187564849853515625e-4) - y * 3.77489497744594108e-8; - } + octant += 1; + y += 1.0; } - *octant_out = octant; - return x; + /* Modulo 360 degrees */ + octant &= 7; + + if (x > 8192) + { + x = x - y * (Pi / 4); + } + else + { + /* Extended precision modular arithmetic */ + x = ((x - y * 0.78515625) - y * 2.4187564849853515625e-4) - y * 3.77489497744594108e-8; + } + } + + *octant_out = octant; + return x; } //- Sin approximation /* Approximate sin in range [0, Pi/4] */ f32 SinApproxF32(f32 x) { - f32 x_sq = x * x; - return (((-1.9515295891E-4 * x_sq + 8.3321608736E-3) * x_sq - 1.6666654611E-1) * x_sq * x) + x; + f32 x_sq = x * x; + return (((-1.9515295891E-4 * x_sq + 8.3321608736E-3) * x_sq - 1.6666654611E-1) * x_sq * x) + x; } //- Cos approximation f32 CosApproxF32(f32 x) { - f32 x_sq = x * x; - return (((2.443315711809948E-005 * x_sq - 1.388731625493765E-003) * x_sq + 4.166664568298827E-002) * x_sq * x_sq) - (x_sq * 0.5) + 1; + f32 x_sq = x * x; + return (((2.443315711809948E-005 * x_sq - 1.388731625493765E-003) * x_sq + 4.166664568298827E-002) * x_sq * x_sq) - (x_sq * 0.5) + 1; } //- Sin f32 SinF32(f32 x) { - f32 sign = 1; + f32 sign = 1; - if (IsF32Nan(x)) - { - return 0; - } - else if (x < 0) - { - sign = -1; - x = -x; - } + if (IsF32Nan(x)) + { + return 0; + } + else if (x < 0) + { + sign = -1; + x = -x; + } - i32 octant; - x = ReduceToPio4(x, &octant); + i32 octant; + x = ReduceToPio4(x, &octant); - /* Reflect in x axis */ - if (octant > 3) - { - sign = -sign; - octant -= 4; - } + /* Reflect in x axis */ + if (octant > 3) + { + sign = -sign; + octant -= 4; + } - switch (octant) - { - case -1: return 0; - case 1: case 2: return CosApproxF32(x) * sign; - default: return SinApproxF32(x) * sign; - } + switch (octant) + { + case -1: return 0; + case 1: case 2: return CosApproxF32(x) * sign; + default: return SinApproxF32(x) * sign; + } } //- Cos f32 CosF32(f32 x) { - f32 sign = 1; + f32 sign = 1; - if (IsF32Nan(x)) - { - return 0; - } - else if (x < 0) - { - x = -x; - } + if (IsF32Nan(x)) + { + return 0; + } + else if (x < 0) + { + x = -x; + } - i32 octant; - x = ReduceToPio4(x, &octant); + i32 octant; + x = ReduceToPio4(x, &octant); - /* Reflect in x axis */ - if (octant > 3) - { - sign = -sign; - octant -= 4; - } + /* Reflect in x axis */ + if (octant > 3) + { + sign = -sign; + octant -= 4; + } - if (octant > 1) - { - sign = -sign; - } + if (octant > 1) + { + sign = -sign; + } - switch (octant) - { - case -1: return 0; - case 1: case 2: return SinApproxF32(x) * sign; - default: return CosApproxF32(x) * sign; - } + switch (octant) + { + case -1: return 0; + case 1: case 2: return SinApproxF32(x) * sign; + default: return CosApproxF32(x) * sign; + } } //- ArcTan f32 ArcTanF32(f32 x) { - f32 sign = 1; - if (x < 0) - { - sign = -1; - x = -x; - } + f32 sign = 1; + if (x < 0) + { + sign = -1; + x = -x; + } - /* Reduce range */ - f32 y; - if (x > 2.414213562373095) - { /* tan((Pi / 8) * 3) */ - y = Pi / 2; - x = -(1.f / x); - } - else if (x > 0.4142135623730950) - { /* tan(Pi / 8) */ - y = Pi / 4; - x = (x - 1.f) / (x + 1.f); - } - else - { - y = 0; - } + /* Reduce range */ + f32 y; + if (x > 2.414213562373095) + { /* tan((Pi / 8) * 3) */ + y = Pi / 2; + x = -(1.f / x); + } + else if (x > 0.4142135623730950) + { /* tan(Pi / 8) */ + y = Pi / 4; + x = (x - 1.f) / (x + 1.f); + } + else + { + y = 0; + } - f32 x_sq = x * x; - y += ((((8.05374449538e-2 * x_sq - 1.38776856032E-1) * x_sq + 1.99777106478E-1) * x_sq - 3.33329491539E-1) * x_sq * x + x); + f32 x_sq = x * x; + y += ((((8.05374449538e-2 * x_sq - 1.38776856032E-1) * x_sq + 1.99777106478E-1) * x_sq - 3.33329491539E-1) * x_sq * x + x); - return y * sign; + return y * sign; } //- ArcTan2 f32 ArcTan2F32(f32 y, f32 x) { - f32 result; - if (x == 0) + f32 result; + if (x == 0) + { + if (y < 0) { - if (y < 0) - { - result = 3 * Pi / 2; - } - else if (y == 0) - { - result = 0; - } - else - { - result = Pi / 2; - } + result = 3 * Pi / 2; } else if (y == 0) { - if (x < 0) - { - result = Pi; - } - else - { - result = 0; - } + result = 0; } else { - f32 offset; - if (x < 0) - { - offset = Pi; - } - else if (y < 0) - { - offset = Pi * 2; - } - else - { - offset = 0; - } - result = ArcTanF32(y / x) + offset; + result = Pi / 2; } - return result; + } + else if (y == 0) + { + if (x < 0) + { + result = Pi; + } + else + { + result = 0; + } + } + else + { + f32 offset; + if (x < 0) + { + offset = Pi; + } + else if (y < 0) + { + offset = Pi * 2; + } + else + { + offset = 0; + } + result = ArcTanF32(y / x) + offset; + } + return result; } //- ArcSin f32 ArcSinF32(f32 x) { - /* TODO: Dedicated arcsin approximation */ - return ArcTan2F32(x, SqrtF32(1.0f - (x * x))); + /* TODO: Dedicated arcsin approximation */ + return ArcTan2F32(x, SqrtF32(1.0f - (x * x))); } //- ArcCos f32 ArcCosF32(f32 x) { - /* TODO: Dedicated arccos approximation */ - return (Pi / 2.0f) - ArcTan2F32(x, SqrtF32(1.0f - (x * x))); + /* TODO: Dedicated arccos approximation */ + return (Pi / 2.0f) - ArcTan2F32(x, SqrtF32(1.0f - (x * x))); } //////////////////////////////////////////////////////////// @@ -757,8 +757,8 @@ f32 ArcCosF32(f32 x) /* Returns angle in range [-Pi, Pi] */ f32 UnwindAngleF32(f32 a) { - f32 d = ModF32(a, Tau); - return ModF32(2.0f * d, Tau) - d; + f32 d = ModF32(a, Tau); + return ModF32(2.0f * d, Tau) - d; } //////////////////////////////////////////////////////////// @@ -766,18 +766,18 @@ f32 UnwindAngleF32(f32 a) f32 LerpF32(f32 val0, f32 val1, f32 t) { - return val0 + ((val1 - val0) * t); + return val0 + ((val1 - val0) * t); } f64 LerpF64(f64 val0, f64 val1, f64 t) { - return val0 + ((val1 - val0) * t); + return val0 + ((val1 - val0) * t); } f32 LerpAngleF32(f32 a, f32 b, f32 t) { - f32 diff = UnwindAngleF32(b - a); - return a + diff * t; + f32 diff = UnwindAngleF32(b - a); + return a + diff * t; } //////////////////////////////////////////////////////////// @@ -785,22 +785,22 @@ f32 LerpAngleF32(f32 a, f32 b, f32 t) i32 LerpI32(i32 val0, i32 val1, f32 t) { - return val0 + RoundF32ToI32(((f32)val1 - (f32)val0) * t); + return val0 + RoundF32ToI32(((f32)val1 - (f32)val0) * t); } i64 LerpI64(i64 val0, i64 val1, f64 t) { - return val0 + RoundF64ToI64(((f64)val1 - (f64)val0) * t); + return val0 + RoundF64ToI64(((f64)val1 - (f64)val0) * t); } i32 LerpU32(u32 val0, u32 val1, f32 t) { - return val0 + (u64)RoundF32ToI32(((f32)val1 - (f32)val0) * t); + return val0 + (u64)RoundF32ToI32(((f32)val1 - (f32)val0) * t); } i64 LerpU64(u64 val0, u64 val1, f64 t) { - return val0 + (u64)RoundF64ToI64(((f64)val1 - (f64)val0) * t); + return val0 + (u64)RoundF64ToI64(((f64)val1 - (f64)val0) * t); } //////////////////////////////////////////////////////////// @@ -808,72 +808,72 @@ i64 LerpU64(u64 val0, u64 val1, f64 t) f32 SrgbFromLinearF32(f32 lin) { - f32 result = 0; - if (lin <= 0.0031308f) - { - result = lin * 12.92f; - } - else - { - result = 1.055f * PowF32(lin, 1.0f/2.4f) - 0.055f; - } - return result; + f32 result = 0; + if (lin <= 0.0031308f) + { + result = lin * 12.92f; + } + else + { + result = 1.055f * PowF32(lin, 1.0f/2.4f) - 0.055f; + } + return result; } f32 LinearFromSrgbF32(f32 srgb) { - f32 result = 0; - if (srgb <= 0.04045f) - { - result = srgb / 12.92f; - } - else - { - result = PowF32((srgb + 0.055f) / 1.055f, 2.4f); - } - return result; + f32 result = 0; + if (srgb <= 0.04045f) + { + result = srgb / 12.92f; + } + else + { + result = PowF32((srgb + 0.055f) / 1.055f, 2.4f); + } + return result; } Vec4 LinearFromSrgb(Vec4 srgb) { - Vec4 result = Zi; - result.x = LinearFromSrgbF32(srgb.x); - result.y = LinearFromSrgbF32(srgb.y); - result.z = LinearFromSrgbF32(srgb.z); - result.w = srgb.w; - return result; + Vec4 result = Zi; + result.x = LinearFromSrgbF32(srgb.x); + result.y = LinearFromSrgbF32(srgb.y); + result.z = LinearFromSrgbF32(srgb.z); + result.w = srgb.w; + return result; } Vec4 SrgbFromLinear(Vec4 lin) { - Vec4 result = Zi; - result.x = SrgbFromLinearF32(lin.x); - result.y = SrgbFromLinearF32(lin.y); - result.z = SrgbFromLinearF32(lin.z); - result.w = lin.w; - return result; + Vec4 result = Zi; + result.x = SrgbFromLinearF32(lin.x); + result.y = SrgbFromLinearF32(lin.y); + result.z = SrgbFromLinearF32(lin.z); + result.w = lin.w; + return result; } u32 LinearU32FromSrgb(Vec4 srgb) { - Vec4 lin = LinearFromSrgb(srgb); - u32 result = U32FromVec4(lin); - return result; + Vec4 lin = LinearFromSrgb(srgb); + u32 result = U32FromVec4(lin); + return result; } Vec4 BlendSrgb(Vec4 v0, Vec4 v1, f32 t) { - Vec4 v0_l = LinearFromSrgb(v0); - Vec4 v1_l = LinearFromSrgb(v1); - Vec4 blend_l = Zi; - { - blend_l.x = LerpF32(v0_l.x, v1_l.x, t); - blend_l.y = LerpF32(v0_l.y, v1_l.y, t); - blend_l.z = LerpF32(v0_l.z, v1_l.z, t); - blend_l.w = LerpF32(v0_l.w, v1_l.w, t); - } - Vec4 result = SrgbFromLinear(blend_l); - return result; + Vec4 v0_l = LinearFromSrgb(v0); + Vec4 v1_l = LinearFromSrgb(v1); + Vec4 blend_l = Zi; + { + blend_l.x = LerpF32(v0_l.x, v1_l.x, t); + blend_l.y = LerpF32(v0_l.y, v1_l.y, t); + blend_l.z = LerpF32(v0_l.z, v1_l.z, t); + blend_l.w = LerpF32(v0_l.w, v1_l.w, t); + } + Vec4 result = SrgbFromLinear(blend_l); + return result; } //////////////////////////////////////////////////////////// @@ -881,102 +881,102 @@ Vec4 BlendSrgb(Vec4 v0, Vec4 v1, f32 t) b32 IsVec2Zero(Vec2 a) { - return a.x == 0 && a.y == 0; + return a.x == 0 && a.y == 0; } b32 MatchVec2(Vec2 a, Vec2 b) { - return a.x == b.x && a.y == b.y; + return a.x == b.x && a.y == b.y; } //- Mul Vec2 MulVec2(Vec2 a, f32 s) { - return VEC2(a.x * s, a.y * s); + return VEC2(a.x * s, a.y * s); } Vec2 MulVec2Vec2(Vec2 a, Vec2 b) { - return VEC2(a.x * b.x, a.y * b.y); + return VEC2(a.x * b.x, a.y * b.y); } Vec2 NegVec2(Vec2 a) { - return VEC2(-a.x, -a.y); + return VEC2(-a.x, -a.y); } //- Div Vec2 DivVec2(Vec2 a, f32 s) { - f32 d = 1 / s; - return VEC2(a.x * d, a.y * d); + f32 d = 1 / s; + return VEC2(a.x * d, a.y * d); } Vec2 DivVec2Vec2(Vec2 a, Vec2 b) { - return VEC2(a.x * (1 / b.x), a.y * (1 / b.y)); + return VEC2(a.x * (1 / b.x), a.y * (1 / b.y)); } //- Add Vec2 AddVec2(Vec2 a, Vec2 b) { - return VEC2(a.x + b.x, a.y + b.y); + return VEC2(a.x + b.x, a.y + b.y); } Vec2 SubVec2(Vec2 a, Vec2 b) { - return VEC2(a.x - b.x, a.y - b.y); + return VEC2(a.x - b.x, a.y - b.y); } //- Len f32 Vec2Len(Vec2 a) { - return SqrtF32(a.x * a.x + a.y * a.y); + return SqrtF32(a.x * a.x + a.y * a.y); } f32 Vec2LenSq(Vec2 a) { - return a.x * a.x + a.y * a.y; + return a.x * a.x + a.y * a.y; } Vec2 Vec2WithLen(Vec2 a, f32 len) { - f32 l_sq = a.x * a.x + a.y * a.y; - if (l_sq != 0) - { - f32 denom = len / SqrtF32(l_sq); - a.x *= denom; - a.y *= denom; - } - return a; + f32 l_sq = a.x * a.x + a.y * a.y; + if (l_sq != 0) + { + f32 denom = len / SqrtF32(l_sq); + a.x *= denom; + a.y *= denom; + } + return a; } Vec2 ClampVec2Len(Vec2 a, f32 max) { - f32 l_sq = a.x * a.x + a.y * a.y; - if (l_sq > max * max) - { - f32 denom = max / SqrtF32(l_sq); - a.x *= denom; - a.y *= denom; - } - return a; + f32 l_sq = a.x * a.x + a.y * a.y; + if (l_sq > max * max) + { + f32 denom = max / SqrtF32(l_sq); + a.x *= denom; + a.y *= denom; + } + return a; } f32 Vec2Distance(Vec2 a, Vec2 b) { - f32 dx = b.x - a.x; - f32 dy = b.y - a.y; - return SqrtF32(dx * dx + dy * dy); + f32 dx = b.x - a.x; + f32 dy = b.y - a.y; + return SqrtF32(dx * dx + dy * dy); } Vec2 NormVec2(Vec2 a) { - return Vec2WithLen(a, 1.f); + return Vec2WithLen(a, 1.f); } @@ -984,7 +984,7 @@ Vec2 NormVec2(Vec2 a) f32 DotVec2(Vec2 a, Vec2 b) { - return a.x * b.x + a.y * b.y; + return a.x * b.x + a.y * b.y; } /* Returns signed area between vectors (positive in clockwise direction) @@ -992,57 +992,57 @@ f32 DotVec2(Vec2 a, Vec2 b) * AKA 2d cross-product */ f32 WedgeVec2(Vec2 a, Vec2 b) { - return a.x * b.y - a.y * b.x; + return a.x * b.y - a.y * b.x; } /* Clockwise (right) perpendicular vector */ Vec2 PerpVec2(Vec2 a) { - return VEC2(-a.y, a.x); + return VEC2(-a.y, a.x); } /* Clockwise (right) perpendicular vector scaled by s */ Vec2 MulPerpVec2(Vec2 a, f32 s) { - return VEC2(s * -a.y, s * a.x); + return VEC2(s * -a.y, s * a.x); } Vec2 PerpVec2TowardsDir(Vec2 v, Vec2 dir) { - f32 wedge = WedgeVec2(v, dir); - return MulPerpVec2(v, (wedge >= 0) - (wedge < 0)); + f32 wedge = WedgeVec2(v, dir); + return MulPerpVec2(v, (wedge >= 0) - (wedge < 0)); } //- Round / floor / ceil Vec2 RoundVec2(Vec2 a) { - return VEC2(RoundF32(a.x), RoundF32(a.y)); + return VEC2(RoundF32(a.x), RoundF32(a.y)); } Vec2 FloorVec2(Vec2 a) { - return VEC2(FloorF32(a.x), FloorF32(a.y)); + return VEC2(FloorF32(a.x), FloorF32(a.y)); } Vec2 CeilVec2(Vec2 a) { - return VEC2(CeilF32(a.x), CeilF32(a.y)); + return VEC2(CeilF32(a.x), CeilF32(a.y)); } Vec2I32 RoundVec2ToI32(Vec2 a) { - return VEC2I32(RoundF32ToI32(a.x), RoundF32ToI32(a.y)); + return VEC2I32(RoundF32ToI32(a.x), RoundF32ToI32(a.y)); } Vec2I32 FloorVec2ToI32(Vec2 a) { - return VEC2I32(FloorF32ToI32(a.x), FloorF32ToI32(a.y)); + return VEC2I32(FloorF32ToI32(a.x), FloorF32ToI32(a.y)); } Vec2I32 CeilVec2ToI32(Vec2 a) { - return VEC2I32(CeilF32ToI32(a.x), CeilF32ToI32(a.y)); + return VEC2I32(CeilF32ToI32(a.x), CeilF32ToI32(a.y)); } //- Angle @@ -1050,45 +1050,45 @@ Vec2I32 CeilVec2ToI32(Vec2 a) /* Returns 1 if winding between vectors a & b is clockwise or straight, -1 if counter-clockwise */ i32 WindingFromVec2(Vec2 a, Vec2 b) { - f32 w = WedgeVec2(a, b); - return (w >= 0) - (w < 0); + f32 w = WedgeVec2(a, b); + return (w >= 0) - (w < 0); } Vec2 RotateVec2(Vec2 v, f32 a) { - f32 c = CosF32(a); - f32 s = SinF32(a); - return VEC2(v.x * c - v.y * s, v.x * s + v.y * c); + f32 c = CosF32(a); + f32 s = SinF32(a); + return VEC2(v.x * c - v.y * s, v.x * s + v.y * c); } Vec2 Vec2FromAngle(f32 a) { - return VEC2(CosF32(a), SinF32(a)); + return VEC2(CosF32(a), SinF32(a)); } f32 AngleFromVec2(Vec2 v) { - return ArcTan2F32(v.y, v.x); + return ArcTan2F32(v.y, v.x); } f32 AngleFromVec2Dirs(Vec2 dir1, Vec2 dir2) { - return ArcTan2F32(WedgeVec2(dir1, dir2), DotVec2(dir1, dir2)); + return ArcTan2F32(WedgeVec2(dir1, dir2), DotVec2(dir1, dir2)); } f32 AngleFromVec2Points(Vec2 pt1, Vec2 pt2) { - return AngleFromVec2(SubVec2(pt2, pt1)); + return AngleFromVec2(SubVec2(pt2, pt1)); } //- Closest point Vec2 ClosestPointFromRay(Vec2 ray_pos, Vec2 ray_dir_norm, Vec2 p) { - Vec2 ray_p_dir = SubVec2(p, ray_pos); - f32 dot = DotVec2(ray_dir_norm, ray_p_dir); - Vec2 ray_dir_closest = MulVec2(ray_dir_norm, dot); - return AddVec2(ray_pos, ray_dir_closest); + Vec2 ray_p_dir = SubVec2(p, ray_pos); + f32 dot = DotVec2(ray_dir_norm, ray_p_dir); + Vec2 ray_dir_closest = MulVec2(ray_dir_norm, dot); + return AddVec2(ray_pos, ray_dir_closest); } //- Lerp @@ -1096,20 +1096,20 @@ Vec2 ClosestPointFromRay(Vec2 ray_pos, Vec2 ray_dir_norm, Vec2 p) /* Interpolate position vectors */ Vec2 LerpVec2(Vec2 val0, Vec2 val1, f32 t) { - return VEC2(LerpF32(val0.x, val1.x, t), LerpF32(val0.y, val1.y, t)); + return VEC2(LerpF32(val0.x, val1.x, t), LerpF32(val0.y, val1.y, t)); } Vec2 LerpVec2Vec2(Vec2 val0, Vec2 val1, Vec2 t) { - return VEC2(LerpF32(val0.x, val1.x, t.x), LerpF32(val0.y, val1.y, t.y)); + return VEC2(LerpF32(val0.x, val1.x, t.x), LerpF32(val0.y, val1.y, t.y)); } /* Interpolate direction vectors (spherical lerp) */ Vec2 SlerpVec2(Vec2 val0, Vec2 val1, f32 t) { - f32 rot = LerpAngleF32(AngleFromVec2(val0), AngleFromVec2(val1), t); - f32 len = LerpF32(Vec2Len(val0), Vec2Len(val1), t); - return MulVec2(Vec2FromAngle(rot), len); + f32 rot = LerpAngleF32(AngleFromVec2(val0), AngleFromVec2(val1), t); + f32 len = LerpF32(Vec2Len(val0), Vec2Len(val1), t); + return MulVec2(Vec2FromAngle(rot), len); } //////////////////////////////////////////////////////////// @@ -1117,32 +1117,32 @@ Vec2 SlerpVec2(Vec2 val0, Vec2 val1, f32 t) b32 MatchVec2I32(Vec2I32 a, Vec2I32 b) { - return a.x == b.x && a.y == b.y; + return a.x == b.x && a.y == b.y; } Vec2I32 NegVec2I32(Vec2I32 a) { - return VEC2I32(-a.x, -a.y); + return VEC2I32(-a.x, -a.y); } Vec2I32 AddVec2I32(Vec2I32 a, Vec2I32 b) { - return VEC2I32(a.x + b.x, a.y + b.y); + return VEC2I32(a.x + b.x, a.y + b.y); } Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b) { - return VEC2I32(a.x - b.x, a.y - b.y); + return VEC2I32(a.x - b.x, a.y - b.y); } Vec2I32 MulVec2I32Vec2I32(Vec2I32 a, Vec2I32 b) { - return VEC2I32(a.x * b.x, a.y * b.y); + return VEC2I32(a.x * b.x, a.y * b.y); } Vec2I32 DivVec2I32Vec2I32(Vec2I32 a, Vec2I32 b) { - return VEC2I32(a.x / b.x, a.y / b.y); + return VEC2I32(a.x / b.x, a.y / b.y); } //////////////////////////////////////////////////////////// @@ -1150,22 +1150,22 @@ Vec2I32 DivVec2I32Vec2I32(Vec2I32 a, Vec2I32 b) Vec4 Vec4FromU32(u32 v) { - Vec4 result = Zi; - result.x = ((v >> 0) & 0xFF) / 255.0; - result.y = ((v >> 8) & 0xFF) / 255.0; - result.z = ((v >> 16) & 0xFF) / 255.0; - result.w = ((v >> 24) & 0xFF) / 255.0; - return result; + Vec4 result = Zi; + result.x = ((v >> 0) & 0xFF) / 255.0; + result.y = ((v >> 8) & 0xFF) / 255.0; + result.z = ((v >> 16) & 0xFF) / 255.0; + result.w = ((v >> 24) & 0xFF) / 255.0; + return result; } u32 U32FromVec4(Vec4 v) { - u32 result = 0; - result |= (((u32)(v.x * 255.0)) & 0xFF) << 0; - result |= (((u32)(v.y * 255.0)) & 0xFF) << 8; - result |= (((u32)(v.z * 255.0)) & 0xFF) << 16; - result |= (((u32)(v.w * 255.0)) & 0xFF) << 24; - return result; + u32 result = 0; + result |= (((u32)(v.x * 255.0)) & 0xFF) << 0; + result |= (((u32)(v.y * 255.0)) & 0xFF) << 8; + result |= (((u32)(v.z * 255.0)) & 0xFF) << 16; + result |= (((u32)(v.w * 255.0)) & 0xFF) << 24; + return result; } //////////////////////////////////////////////////////////// @@ -1175,88 +1175,88 @@ u32 U32FromVec4(Vec4 v) Vec2 DimsFromRng2(Rng2 r) { - Vec2 result = Zi; - result.x = r.p1.x - r.p0.x; - result.y = r.p1.y - r.p0.y; - return result; + Vec2 result = Zi; + result.x = r.p1.x - r.p0.x; + result.y = r.p1.y - r.p0.y; + return result; } Rng2 UnionRng2(Rng2 a, Rng2 b) { - Rng2 result = Zi; - result.p0.x = MinF32(a.p0.x, b.p0.x); - result.p0.y = MinF32(a.p0.y, b.p0.y); - result.p1.x = MaxF32(a.p1.x, b.p1.x); - result.p1.y = MaxF32(a.p1.y, b.p1.y); - return result; + Rng2 result = Zi; + result.p0.x = MinF32(a.p0.x, b.p0.x); + result.p0.y = MinF32(a.p0.y, b.p0.y); + result.p1.x = MaxF32(a.p1.x, b.p1.x); + result.p1.y = MaxF32(a.p1.y, b.p1.y); + return result; } Rng2 AddRng2Vec2(Rng2 r, Vec2 v) { - Rng2 result = Zi; - result.p0 = AddVec2(r.p0, v); - result.p1 = AddVec2(r.p1, v); - return result; + Rng2 result = Zi; + result.p0 = AddVec2(r.p0, v); + result.p1 = AddVec2(r.p1, v); + return result; } Rng2 MulRng2Vec2(Rng2 r, Vec2 v) { - Rng2 result = Zi; - result.p0 = MulVec2Vec2(r.p0, v); - result.p1 = MulVec2Vec2(r.p1, v); - return result; + Rng2 result = Zi; + result.p0 = MulVec2Vec2(r.p0, v); + result.p1 = MulVec2Vec2(r.p1, v); + return result; } Rng2 DivRng2Vec2(Rng2 r, Vec2 v) { - Rng2 result = Zi; - result.p0 = DivVec2Vec2(r.p0, v); - result.p1 = DivVec2Vec2(r.p1, v); - return result; + Rng2 result = Zi; + result.p0 = DivVec2Vec2(r.p0, v); + result.p1 = DivVec2Vec2(r.p1, v); + return result; } //- Rng2I32 Vec2I32 DimsFromRng2I32(Rng2I32 r) { - Vec2I32 result = Zi; - result.x = r.p1.x - r.p0.x; - result.y = r.p1.y - r.p0.y; - return result; + Vec2I32 result = Zi; + result.x = r.p1.x - r.p0.x; + result.y = r.p1.y - r.p0.y; + return result; } Rng2I32 UnionRng2I32(Rng2I32 a, Rng2I32 b) { - Rng2I32 result = Zi; - result.p0.x = MinF32(a.p0.x, b.p0.x); - result.p0.y = MinF32(a.p0.y, b.p0.y); - result.p1.x = MaxF32(a.p1.x, b.p1.x); - result.p1.y = MaxF32(a.p1.y, b.p1.y); - return result; + Rng2I32 result = Zi; + result.p0.x = MinF32(a.p0.x, b.p0.x); + result.p0.y = MinF32(a.p0.y, b.p0.y); + result.p1.x = MaxF32(a.p1.x, b.p1.x); + result.p1.y = MaxF32(a.p1.y, b.p1.y); + return result; } Rng2I32 AddRng2I32Vec2I32(Rng2I32 r, Vec2I32 v) { - Rng2I32 result = Zi; - result.p0 = AddVec2I32(r.p0, v); - result.p1 = AddVec2I32(r.p1, v); - return result; + Rng2I32 result = Zi; + result.p0 = AddVec2I32(r.p0, v); + result.p1 = AddVec2I32(r.p1, v); + return result; } Rng2I32 MulRng2I32Vec2I32(Rng2I32 r, Vec2I32 v) { - Rng2I32 result = Zi; - result.p0 = MulVec2I32Vec2I32(r.p0, v); - result.p1 = MulVec2I32Vec2I32(r.p1, v); - return result; + Rng2I32 result = Zi; + result.p0 = MulVec2I32Vec2I32(r.p0, v); + result.p1 = MulVec2I32Vec2I32(r.p1, v); + return result; } Rng2I32 DivRng2I32Vec2I32(Rng2I32 r, Vec2I32 v) { - Rng2I32 result = Zi; - result.p0 = DivVec2I32Vec2I32(r.p0, v); - result.p1 = DivVec2I32Vec2I32(r.p1, v); - return result; + Rng2I32 result = Zi; + result.p0 = DivVec2I32Vec2I32(r.p0, v); + result.p1 = DivVec2I32Vec2I32(r.p1, v); + return result; } //////////////////////////////////////////////////////////// @@ -1264,216 +1264,216 @@ Rng2I32 DivRng2I32Vec2I32(Rng2I32 r, Vec2I32 v) b32 MatchXform(Xform xf1, Xform xf2) { - return MatchVec2(xf1.og, xf2.og) && MatchVec2(xf1.bx, xf2.bx) && MatchVec2(xf1.by, xf2.by); + return MatchVec2(xf1.og, xf2.og) && MatchVec2(xf1.bx, xf2.bx) && MatchVec2(xf1.by, xf2.by); } //- Initialization Xform XformFromPos(Vec2 v) { - Xform xf; - xf.bx = VEC2(1, 0); - xf.by = VEC2(0, 1); - xf.og = v; - return xf; + Xform xf; + xf.bx = VEC2(1, 0); + xf.by = VEC2(0, 1); + xf.og = v; + return xf; } Xform XformFromRot(f32 r) { - Xform result; - f32 c = CosF32(r); - f32 s = SinF32(r); - result.bx = VEC2(c, s); - result.by = VEC2(-s, c); - result.og = VEC2(0, 0); - return result; + Xform result; + f32 c = CosF32(r); + f32 s = SinF32(r); + result.bx = VEC2(c, s); + result.by = VEC2(-s, c); + result.og = VEC2(0, 0); + return result; } Xform XformFromScale(Vec2 scale) { - Xform result; - result.bx = VEC2(scale.x, 0); - result.by = VEC2(0, scale.y); - result.og = VEC2(0, 0); - return result; + Xform result; + result.bx = VEC2(scale.x, 0); + result.by = VEC2(0, scale.y); + result.og = VEC2(0, 0); + return result; } Xform XformFromTrs(Trs trs) { - Xform xf = XformFromPos(trs.t); - xf = RotateXform(xf, trs.r); - xf = ScaleXform(xf, trs.s); - return xf; + Xform xf = XformFromPos(trs.t); + xf = RotateXform(xf, trs.r); + xf = ScaleXform(xf, trs.s); + return xf; } //- Translation Xform TranslateXform(Xform xf, Vec2 v) { - xf.og = VEC2(xf.bx.x * v.x + xf.by.x * v.y + xf.og.x, xf.bx.y * v.x + xf.by.y * v.y + xf.og.y); - return xf; + xf.og = VEC2(xf.bx.x * v.x + xf.by.x * v.y + xf.og.x, xf.bx.y * v.x + xf.by.y * v.y + xf.og.y); + return xf; } Xform WorldTranslateXform(Xform xf, Vec2 v) { - xf.og = AddVec2(xf.og, v); - return xf; + xf.og = AddVec2(xf.og, v); + return xf; } //- Rotation Xform RotateXform(Xform xf, f32 r) { - return MulXform(xf, XformFromRot(r)); + return MulXform(xf, XformFromRot(r)); } Xform WorldRotateXform(Xform xf, f32 r) { - return MulXform(XformFromRot(r), xf); + return MulXform(XformFromRot(r), xf); } Xform WorldRotateXformBasis(Xform xf, f32 r) { - f32 diff = r; - f32 c = CosF32(diff); - f32 s = SinF32(diff); - xf.bx = VEC2(xf.bx.x * c - xf.bx.y * s, xf.bx.x * s + xf.bx.y * c); - xf.by = VEC2(xf.by.x * c - xf.by.y * s, xf.by.x * s + xf.by.y * c); - return xf; + f32 diff = r; + f32 c = CosF32(diff); + f32 s = SinF32(diff); + xf.bx = VEC2(xf.bx.x * c - xf.bx.y * s, xf.bx.x * s + xf.bx.y * c); + xf.by = VEC2(xf.by.x * c - xf.by.y * s, xf.by.x * s + xf.by.y * c); + return xf; } Xform XformWithWorldRotation(Xform xf, f32 r) { - return WorldRotateXformBasis(xf, r - RotationFromXform(xf)); + return WorldRotateXformBasis(xf, r - RotationFromXform(xf)); } //- Scale Xform ScaleXform(Xform xf, Vec2 scale) { - xf.bx = MulVec2(xf.bx, scale.x); - xf.by = MulVec2(xf.by, scale.y); - return xf; + xf.bx = MulVec2(xf.bx, scale.x); + xf.by = MulVec2(xf.by, scale.y); + return xf; } Xform WorldScaleXform(Xform xf, Vec2 scale) { - Xform result; - result.bx = MulVec2Vec2(xf.bx, scale); - result.by = MulVec2Vec2(xf.by, scale); - result.og = MulVec2Vec2(xf.og, scale); - return result; + Xform result; + result.bx = MulVec2Vec2(xf.bx, scale); + result.by = MulVec2Vec2(xf.by, scale); + result.og = MulVec2Vec2(xf.og, scale); + return result; } //- Lerp Xform LerpXform(Xform a, Xform b, f32 t) { - Xform result; - result.bx = SlerpVec2(a.bx, b.bx, t); - result.by = SlerpVec2(a.by, b.by, t); - result.og = LerpVec2(a.og, b.og, t); - return result; + Xform result; + result.bx = SlerpVec2(a.bx, b.bx, t); + result.by = SlerpVec2(a.by, b.by, t); + result.og = LerpVec2(a.og, b.og, t); + return result; } //- Invert Xform InvertXform(Xform xf) { - f32 det = DeterminantFromXform(xf); - f32 inv_det = 1.0f / det; + f32 det = DeterminantFromXform(xf); + f32 inv_det = 1.0f / det; - f32 old_bx_x = xf.bx.x; - xf.bx.x = xf.by.y; - xf.by.y = old_bx_x; + f32 old_bx_x = xf.bx.x; + xf.bx.x = xf.by.y; + xf.by.y = old_bx_x; - xf.bx = MulVec2Vec2(xf.bx, VEC2(inv_det, -inv_det)); - xf.by = MulVec2Vec2(xf.by, VEC2(-inv_det, inv_det)); + xf.bx = MulVec2Vec2(xf.bx, VEC2(inv_det, -inv_det)); + xf.by = MulVec2Vec2(xf.by, VEC2(-inv_det, inv_det)); - xf.og = MulXformBasisV2(xf, NegVec2(xf.og)); + xf.og = MulXformBasisV2(xf, NegVec2(xf.og)); - return xf; + return xf; } //- Mul Xform MulXform(Xform a, Xform b) { - Xform result; - result.bx.x = a.bx.x * b.bx.x + a.by.x * b.bx.y; - result.bx.y = a.bx.y * b.bx.x + a.by.y * b.bx.y; - result.by.x = a.bx.x * b.by.x + a.by.x * b.by.y; - result.by.y = a.bx.y * b.by.x + a.by.y * b.by.y; - result.og = MulXformV2(a, b.og); - return result; + Xform result; + result.bx.x = a.bx.x * b.bx.x + a.by.x * b.bx.y; + result.bx.y = a.bx.y * b.bx.x + a.by.y * b.bx.y; + result.by.x = a.bx.x * b.by.x + a.by.x * b.by.y; + result.by.y = a.bx.y * b.by.x + a.by.y * b.by.y; + result.og = MulXformV2(a, b.og); + return result; } Vec2 MulXformBasisV2(Xform xf, Vec2 v) { - return VEC2( - xf.bx.x * v.x + xf.by.x * v.y, - xf.bx.y * v.x + xf.by.y * v.y - ); + return VEC2( + xf.bx.x * v.x + xf.by.x * v.y, + xf.bx.y * v.x + xf.by.y * v.y + ); } Vec2 MulXformV2(Xform xf, Vec2 v) { - Vec2 result = MulXformBasisV2(xf, v); - result = AddVec2(result, xf.og); - return result; + Vec2 result = MulXformBasisV2(xf, v); + result = AddVec2(result, xf.og); + return result; } Vec2 InvertXformBasisMulV2(Xform xf, Vec2 v) { - Xform inv = InvertXform(xf); - Vec2 result = MulXformBasisV2(inv, v); - return result; + Xform inv = InvertXform(xf); + Vec2 result = MulXformBasisV2(inv, v); + return result; } /* TODO: Get rid of this? Just force caller to use invert manually since it's expensive. */ Vec2 InvertXformMulV2(Xform xf, Vec2 v) { - Xform inv = InvertXform(xf); - return MulXformV2(inv, v); + Xform inv = InvertXform(xf); + return MulXformV2(inv, v); } //- Helpers Xform BasisFromXform(Xform xf) { - Xform result = Zi; - result.bx = xf.bx; - result.by = xf.by; - return result; + Xform result = Zi; + result.bx = xf.bx; + result.by = xf.by; + return result; } f32 DeterminantFromXform(Xform xf) { - return WedgeVec2(xf.bx, xf.by); + return WedgeVec2(xf.bx, xf.by); } Vec2 RightFromXform(Xform xf) { - return xf.bx; + return xf.bx; } Vec2 LeftFromXform(Xform xf) { - return NegVec2(xf.bx); + return NegVec2(xf.bx); } Vec2 UpFromXform(Xform xf) { - return NegVec2(xf.by); + return NegVec2(xf.by); } Vec2 DownFromXform(Xform xf) { - return xf.by; + return xf.by; } f32 RotationFromXform(Xform xf) { - return AngleFromVec2(xf.bx); + return AngleFromVec2(xf.bx); } Vec2 ScaleFromXform(Xform xf) { - f32 det_sign = SignF32(DeterminantFromXform(xf)); - return VEC2(Vec2Len(xf.bx), det_sign * Vec2Len(xf.by)); + f32 det_sign = SignF32(DeterminantFromXform(xf)); + return VEC2(Vec2Len(xf.bx), det_sign * Vec2Len(xf.by)); } //////////////////////////////////////////////////////////// @@ -1482,24 +1482,24 @@ Vec2 ScaleFromXform(Xform xf) /* https://box2d.org/files/ErinCatto_SoftConstraints_GDC2011.pdf */ SoftSpring MakeSpring(f32 hertz, f32 damping_ratio, f32 dt) { - SoftSpring result; - if (hertz == 0.0f) - { - result.bias_rate = 0; - result.mass_scale = 1; - result.impulse_scale = 0; - } - else - { - f32 angular_frequency = Tau * hertz; - f32 a = 2 * damping_ratio + angular_frequency * dt; - f32 b = angular_frequency * a * dt; - f32 c = 1 / (b + 1); - result.bias_rate = angular_frequency / a; - result.mass_scale = b * c; - result.impulse_scale = c; - } - return result; + SoftSpring result; + if (hertz == 0.0f) + { + result.bias_rate = 0; + result.mass_scale = 1; + result.impulse_scale = 0; + } + else + { + f32 angular_frequency = Tau * hertz; + f32 a = 2 * damping_ratio + angular_frequency * dt; + f32 b = angular_frequency * a * dt; + f32 c = 1 / (b + 1); + result.bias_rate = angular_frequency / a; + result.mass_scale = b * c; + result.impulse_scale = c; + } + return result; } //////////////////////////////////////////////////////////// @@ -1507,72 +1507,72 @@ SoftSpring MakeSpring(f32 hertz, f32 damping_ratio, f32 dt) Mat4x4 Mat4x4FromXform(Xform xf) { - return (Mat4x4) - { - .e = { - {xf.bx.x, xf.bx.y, 0, 0}, - {xf.by.x, xf.by.y, 0, 0}, - {0, 0, 1, 0}, - {xf.og.x, xf.og.y, 0, 1}, - } - }; + return (Mat4x4) + { + .e = { + {xf.bx.x, xf.bx.y, 0, 0}, + {xf.by.x, xf.by.y, 0, 0}, + {0, 0, 1, 0}, + {xf.og.x, xf.og.y, 0, 1}, + } + }; } Mat4x4 Mat4x4FromOrtho(f32 left, f32 right, f32 bottom, f32 top, f32 near_z, f32 far_z) { - Mat4x4 m = Zi; + Mat4x4 m = Zi; - f32 rl = 1.0f / (right - left); - f32 tb = 1.0f / (top - bottom); - f32 fn = -1.0f / (far_z - near_z); + f32 rl = 1.0f / (right - left); + f32 tb = 1.0f / (top - bottom); + f32 fn = -1.0f / (far_z - near_z); - m.e[0][0] = 2.0f * rl; - m.e[1][1] = 2.0f * tb; - m.e[2][2] = 2.0f * fn; - m.e[3][0] = -(right + left) * rl; - m.e[3][1] = -(top + bottom) * tb; - m.e[3][2] = (far_z + near_z) * fn; - m.e[3][3] = 1.0f; + m.e[0][0] = 2.0f * rl; + m.e[1][1] = 2.0f * tb; + m.e[2][2] = 2.0f * fn; + m.e[3][0] = -(right + left) * rl; + m.e[3][1] = -(top + bottom) * tb; + m.e[3][2] = (far_z + near_z) * fn; + m.e[3][3] = 1.0f; - return m; + return m; } Mat4x4 MulMat4x4(Mat4x4 m1, Mat4x4 m2) { - f32 a00 = m1.e[0][0], a01 = m1.e[0][1], a02 = m1.e[0][2], a03 = m1.e[0][3], - a10 = m1.e[1][0], a11 = m1.e[1][1], a12 = m1.e[1][2], a13 = m1.e[1][3], - a20 = m1.e[2][0], a21 = m1.e[2][1], a22 = m1.e[2][2], a23 = m1.e[2][3], - a30 = m1.e[3][0], a31 = m1.e[3][1], a32 = m1.e[3][2], a33 = m1.e[3][3], + f32 a00 = m1.e[0][0], a01 = m1.e[0][1], a02 = m1.e[0][2], a03 = m1.e[0][3], + a10 = m1.e[1][0], a11 = m1.e[1][1], a12 = m1.e[1][2], a13 = m1.e[1][3], + a20 = m1.e[2][0], a21 = m1.e[2][1], a22 = m1.e[2][2], a23 = m1.e[2][3], + a30 = m1.e[3][0], a31 = m1.e[3][1], a32 = m1.e[3][2], a33 = m1.e[3][3], - b00 = m2.e[0][0], b01 = m2.e[0][1], b02 = m2.e[0][2], b03 = m2.e[0][3], - b10 = m2.e[1][0], b11 = m2.e[1][1], b12 = m2.e[1][2], b13 = m2.e[1][3], - b20 = m2.e[2][0], b21 = m2.e[2][1], b22 = m2.e[2][2], b23 = m2.e[2][3], - b30 = m2.e[3][0], b31 = m2.e[3][1], b32 = m2.e[3][2], b33 = m2.e[3][3]; + b00 = m2.e[0][0], b01 = m2.e[0][1], b02 = m2.e[0][2], b03 = m2.e[0][3], + b10 = m2.e[1][0], b11 = m2.e[1][1], b12 = m2.e[1][2], b13 = m2.e[1][3], + b20 = m2.e[2][0], b21 = m2.e[2][1], b22 = m2.e[2][2], b23 = m2.e[2][3], + b30 = m2.e[3][0], b31 = m2.e[3][1], b32 = m2.e[3][2], b33 = m2.e[3][3]; - Mat4x4 result; - result.e[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; - result.e[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; - result.e[0][2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03; - result.e[0][3] = a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03; - result.e[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; - result.e[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; - result.e[1][2] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13; - result.e[1][3] = a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13; - result.e[2][0] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23; - result.e[2][1] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23; - result.e[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23; - result.e[2][3] = a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23; - result.e[3][0] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; - result.e[3][1] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; - result.e[3][2] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; - result.e[3][3] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; + Mat4x4 result; + result.e[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; + result.e[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; + result.e[0][2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03; + result.e[0][3] = a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03; + result.e[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; + result.e[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; + result.e[1][2] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13; + result.e[1][3] = a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13; + result.e[2][0] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23; + result.e[2][1] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23; + result.e[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23; + result.e[2][3] = a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23; + result.e[3][0] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; + result.e[3][1] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; + result.e[3][2] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; + result.e[3][3] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; - return result; + return result; } Mat4x4 ProjectMat4x4View(Xform view, f32 viewport_width, f32 viewport_height) { - Mat4x4 projection = Mat4x4FromOrtho(0.0, viewport_width, viewport_height, 0.0, -1.0, 1.0); - Mat4x4 view4x4 = Mat4x4FromXform(view); - return MulMat4x4(projection, view4x4); + Mat4x4 projection = Mat4x4FromOrtho(0.0, viewport_width, viewport_height, 0.0, -1.0, 1.0); + Mat4x4 view4x4 = Mat4x4FromXform(view); + return MulMat4x4(projection, view4x4); } diff --git a/src/base/base_math.h b/src/base/base_math.h index 3cf0500c..bcaccab5 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -9,12 +9,12 @@ Enum(Axis) { - Axis_X = 0, - Axis_Y = 1, - Axis_Z = 2, + Axis_X = 0, + Axis_Y = 1, + Axis_Z = 2, - Axis_CountXY = 2, - Axis_CountXYZ = 3 + Axis_CountXY = 2, + Axis_CountXYZ = 3 }; //////////////////////////////////////////////////////////// @@ -145,17 +145,17 @@ Struct(Rng3U64) { Vec3U64 p0; Vec3U64 p1; }; Struct(Xform) { - Vec2 bx; /* X basis vector (x axis) */ - Vec2 by; /* Y basis vector (y axis)*/ - Vec2 og; /* Translation vector (origin) */ + Vec2 bx; /* X basis vector (x axis) */ + Vec2 by; /* Y basis vector (y axis)*/ + Vec2 og; /* Translation vector (origin) */ }; /* (T)ranslation, (R)otation, (S)cale */ Struct(Trs) { - Vec2 t; - Vec2 s; - f32 r; + Vec2 t; + Vec2 s; + f32 r; }; //////////////////////////////////////////////////////////// @@ -163,9 +163,9 @@ Struct(Trs) Struct(SoftSpring) { - f32 bias_rate; - f32 mass_scale; - f32 impulse_scale; + f32 bias_rate; + f32 mass_scale; + f32 impulse_scale; }; //////////////////////////////////////////////////////////// @@ -173,11 +173,11 @@ Struct(SoftSpring) Struct(Mat4x4) { - union - { - struct { Vec4 bx, by, bz, bw; }; - f32 e[4][4]; - }; + union + { + struct { Vec4 bx, by, bz, bw; }; + f32 e[4][4]; + }; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_memory.c b/src/base/base_memory.c index b9f48aa5..d07b8789 100644 --- a/src/base/base_memory.c +++ b/src/base/base_memory.c @@ -7,43 +7,43 @@ __attribute((section(".text.memcpy"))) void *memcpy(void *__restrict dst, const void *__restrict src, u64 count) { - char *dst_pchar = dst; - char *src_pchar = src; - for (u64 i = 0; i < count; ++i) - { - dst_pchar[i] = src_pchar[i]; - } - return dst; + char *dst_pchar = dst; + char *src_pchar = src; + for (u64 i = 0; i < count; ++i) + { + dst_pchar[i] = src_pchar[i]; + } + return dst; } //- memset __attribute((section(".text.memset"))) void *memset(void *dst, i32 c, u64 count) { - char *dst_pchar = dst; - for (u64 i = 0; i < count; ++i) - { - dst_pchar[i] = (char)c; - } - return dst; + char *dst_pchar = dst; + for (u64 i = 0; i < count; ++i) + { + dst_pchar[i] = (char)c; + } + return dst; } //- memcmp __attribute((section(".text.memcmp"))) i32 memcmp(const void *p1, const void *p2, u64 count) { - i32 result = 0; - char *p1_pchar = p1; - char *p2_pchar = p2; - for (u64 i = 0; i < count; ++i) + i32 result = 0; + char *p1_pchar = p1; + char *p2_pchar = p2; + for (u64 i = 0; i < count; ++i) + { + result = p1_pchar[i] - p2_pchar[i]; + if (result != 0) { - result = p1_pchar[i] - p2_pchar[i]; - if (result != 0) - { - break; - } + break; } - return result; + } + return result; } #endif /* !IsCrtlibEnabled */ diff --git a/src/base/base_memory.h b/src/base/base_memory.h index 5cfabc80..d6ded320 100644 --- a/src/base/base_memory.h +++ b/src/base/base_memory.h @@ -34,9 +34,9 @@ void SetMemoryReadWrite(void *address, u64 size); //~ Crtlib stubs #if IsCrtlibEnabled -# include + #include #else -void *memcpy(void *__restrict dst, const void *__restrict src, u64 n); -void *memset(void *dst, i32 c, u64 n); -i32 memcmp(const void *p1, const void *p2, u64 n); + void *memcpy(void *__restrict dst, const void *__restrict src, u64 n); + void *memset(void *dst, i32 c, u64 n); + i32 memcmp(const void *p1, const void *p2, u64 n); #endif diff --git a/src/base/base_rand.c b/src/base/base_rand.c index a8cb5a4a..007cc07c 100644 --- a/src/base/base_rand.c +++ b/src/base/base_rand.c @@ -1,17 +1,17 @@ u64 RandU64FromState(RandState *state) { - u64 seed = state->seed; - if (seed == 0) - { - TrueRand(StringFromStruct(&seed)); - state->seed = seed; - } - return seed ^ RandU64FromSeed(++state->counter); + u64 seed = state->seed; + if (seed == 0) + { + TrueRand(StringFromStruct(&seed)); + state->seed = seed; + } + return seed ^ RandU64FromSeed(++state->counter); } f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end) { - return range_start + (range_end - range_start) * ((f64)(RandU64FromState(state) % RandMaxF64) / (f64)RandMaxF64); + return range_start + (range_end - range_start) * ((f64)(RandU64FromState(state) % RandMaxF64) / (f64)RandMaxF64); } /* Based on Jon Maiga's "mx3" @@ -19,19 +19,19 @@ f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end) */ u64 RandU64FromSeed(u64 seed) { - seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d; - seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d; - seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d; - seed = (seed ^ (seed >> 29)); - return seed; + seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d; + seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d; + seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d; + seed = (seed ^ (seed >> 29)); + return seed; } u64 RandU64FromSeeds(u64 seed_a, u64 seed_b) { - return RandU64FromSeed((seed_a * 3) + seed_b); + return RandU64FromSeed((seed_a * 3) + seed_b); } f64 RandF64FromSeed(u64 seed, f64 range_start, f64 range_end) { - return range_start + (range_end - range_start) * ((f64)(RandU64FromSeed(seed) % RandMaxF64) / (f64)RandMaxF64); + return range_start + (range_end - range_start) * ((f64)(RandU64FromSeed(seed) % RandMaxF64) / (f64)RandMaxF64); } diff --git a/src/base/base_rand.h b/src/base/base_rand.h index ac228f0e..5169b329 100644 --- a/src/base/base_rand.h +++ b/src/base/base_rand.h @@ -3,8 +3,8 @@ Struct(RandState) { - u64 seed; /* If a state's seed == 0 upon a call to a related function, it will be initialized using platform's true rng source */ - u64 counter; + u64 seed; /* If a state's seed == 0 upon a call to a related function, it will be initialized using platform's true rng source */ + u64 counter; }; /* TODO: Use a value that gives good precision when dividing into range 0 -> 1 */ diff --git a/src/base/base_resource.c b/src/base/base_resource.c index f3e7a599..bc7a5d4c 100644 --- a/src/base/base_resource.c +++ b/src/base/base_resource.c @@ -3,39 +3,39 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings) { - Arena *perm = PermArena(); - for (u64 archive_string_index = 0; archive_string_index < archive_strings_count; ++archive_string_index) + Arena *perm = PermArena(); + for (u64 archive_string_index = 0; archive_string_index < archive_strings_count; ++archive_string_index) + { + String archive = archive_strings[archive_string_index]; + if (archive.len > 0) { - String archive = archive_strings[archive_string_index]; - if (archive.len > 0) - { - BB_Buff bb = BB_BuffFromString(archive); - BB_Reader br = BB_ReaderFromBuff(&bb); + BB_Buff bb = BB_BuffFromString(archive); + BB_Reader br = BB_ReaderFromBuff(&bb); - u64 magic = BB_ReadUBits(&br, 64); - Assert(magic == ResourceEmbeddedMagic); + u64 magic = BB_ReadUBits(&br, 64); + Assert(magic == ResourceEmbeddedMagic); - /* Create & insert entries */ - u64 num_entries = BB_ReadUBits(&br, 64); - for (u64 i = 0; i < num_entries; ++i) - { - u64 name_start = BB_ReadUBits(&br, 64); - u64 name_len = BB_ReadUBits(&br, 64); - u64 data_start = BB_ReadUBits(&br, 64); - u64 data_len = BB_ReadUBits(&br, 64); + /* Create & insert entries */ + u64 num_entries = BB_ReadUBits(&br, 64); + for (u64 i = 0; i < num_entries; ++i) + { + u64 name_start = BB_ReadUBits(&br, 64); + u64 name_len = BB_ReadUBits(&br, 64); + u64 data_start = BB_ReadUBits(&br, 64); + u64 data_len = BB_ReadUBits(&br, 64); - ResourceEntry *entry = PushStruct(perm, ResourceEntry); - entry->name = STRING(name_len, archive.text + name_start); - entry->data = STRING(data_len, archive.text + data_start); - entry->hash = HashFnv64(Fnv64Basis, entry->name); + ResourceEntry *entry = PushStruct(perm, ResourceEntry); + entry->name = STRING(name_len, archive.text + name_start); + entry->data = STRING(data_len, archive.text + data_start); + entry->hash = HashFnv64(Fnv64Basis, entry->name); - ResourceEntryBin *bin = &Base.resource.bins[entry->hash % countof(Base.resource.bins)]; - SllQueuePushN(bin->first, bin->last, entry, next_in_bin); - SllQueuePushN(Base.resource.first_entry, Base.resource.last_entry, entry, next); - } - Base.resource.entries_count += num_entries; - } + ResourceEntryBin *bin = &Base.resource.bins[entry->hash % countof(Base.resource.bins)]; + SllQueuePushN(bin->first, bin->last, entry, next_in_bin); + SllQueuePushN(Base.resource.first_entry, Base.resource.last_entry, entry, next); + } + Base.resource.entries_count += num_entries; } + } } @@ -44,49 +44,49 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings) b32 IsResourceNil(ResourceKey resource) { - return resource.v == 0; + return resource.v == 0; } ResourceKey ResourceKeyFromStore(ResourceStore *store, String name) { - ResourceKey result = Zi; - result.v = HashFnv64(store->v, name); - return result; + ResourceKey result = Zi; + result.v = HashFnv64(store->v, name); + return result; } ResourceEntry *ResourceEntryFromHash(u64 hash) { - ResourceEntry *result = 0; - ResourceEntryBin *bin = &Base.resource.bins[hash % countof(Base.resource.bins)]; - for (ResourceEntry *e = bin->first; e; e = e->next_in_bin) + ResourceEntry *result = 0; + ResourceEntryBin *bin = &Base.resource.bins[hash % countof(Base.resource.bins)]; + for (ResourceEntry *e = bin->first; e; e = e->next_in_bin) + { + if (e->hash == hash) { - if (e->hash == hash) - { - result = e; - break; - } + result = e; + break; } - return result; + } + return result; } String DataFromResource(ResourceKey resource) { - String result = Zi; - ResourceEntry *entry = ResourceEntryFromHash(resource.v); - if (entry) - { - result = entry->data; - } - return result; + String result = Zi; + ResourceEntry *entry = ResourceEntryFromHash(resource.v); + if (entry) + { + result = entry->data; + } + return result; } String NameFromResource(ResourceKey resource) { - String result = Zi; - ResourceEntry *entry = ResourceEntryFromHash(resource.v); - if (entry) - { - result = entry->name; - } - return result; + String result = Zi; + ResourceEntry *entry = ResourceEntryFromHash(resource.v); + if (entry) + { + result = entry->name; + } + return result; } diff --git a/src/base/base_resource.h b/src/base/base_resource.h index d44faeda..22423782 100644 --- a/src/base/base_resource.h +++ b/src/base/base_resource.h @@ -3,26 +3,26 @@ Struct(ResourceEntry) { - ResourceEntry *next; - ResourceEntry *next_in_bin; + ResourceEntry *next; + ResourceEntry *next_in_bin; - u64 hash; - String name; - String data; + u64 hash; + String name; + String data; }; Struct(ResourceEntryBin) { - ResourceEntry *first; - ResourceEntry *last; + ResourceEntry *first; + ResourceEntry *last; }; Struct(ResourceCtx) { - u64 entries_count; - ResourceEntry *first_entry; - ResourceEntry *last_entry; - ResourceEntryBin bins[4096]; + u64 entries_count; + ResourceEntry *first_entry; + ResourceEntry *last_entry; + ResourceEntryBin bins[4096]; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_shader.gh b/src/base/base_shader.gh index 02368f6f..95cd4b46 100644 --- a/src/base/base_shader.gh +++ b/src/base/base_shader.gh @@ -42,7 +42,7 @@ Struct(Rng3U32) { Vec3U32 p0; Vec3U32 p1; }; template u32 countof(T arr[N]) { - return N; + return N; } //////////////////////////////////////////////////////////// @@ -81,46 +81,46 @@ u32 countof(T arr[N]) Vec4 Vec4FromU32(u32 v) { - Vec4 result; - result.x = ((v >> 0) & 0xFF) / 255.0; - result.y = ((v >> 8) & 0xFF) / 255.0; - result.z = ((v >> 16) & 0xFF) / 255.0; - result.w = ((v >> 24) & 0xFF) / 255.0; - return result; + Vec4 result; + result.x = ((v >> 0) & 0xFF) / 255.0; + result.y = ((v >> 8) & 0xFF) / 255.0; + result.z = ((v >> 16) & 0xFF) / 255.0; + result.w = ((v >> 24) & 0xFF) / 255.0; + return result; } u32 U32FromVec4(Vec4 v) { - u32 result; - result |= (((u32)(v.x * 255.0)) & 0xFF) << 0; - result |= (((u32)(v.y * 255.0)) & 0xFF) << 8; - result |= (((u32)(v.z * 255.0)) & 0xFF) << 16; - result |= (((u32)(v.w * 255.0)) & 0xFF) << 24; - return result; + u32 result; + result |= (((u32)(v.x * 255.0)) & 0xFF) << 0; + result |= (((u32)(v.y * 255.0)) & 0xFF) << 8; + result |= (((u32)(v.z * 255.0)) & 0xFF) << 16; + result |= (((u32)(v.w * 255.0)) & 0xFF) << 24; + return result; } f32 LinearFromSrgbF32(f32 srgb) { - f32 result; - if (srgb <= 0.04045f) - { - result = srgb / 12.92f; - } - else - { - result = pow((srgb + 0.055f) / 1.055f, 2.4f); - } - return result; + f32 result; + if (srgb <= 0.04045f) + { + result = srgb / 12.92f; + } + else + { + result = pow((srgb + 0.055f) / 1.055f, 2.4f); + } + return result; } Vec4 LinearFromSrgb(Vec4 srgb) { - Vec4 result; - result.x = LinearFromSrgbF32(srgb.x); - result.y = LinearFromSrgbF32(srgb.y); - result.z = LinearFromSrgbF32(srgb.z); - result.w = srgb.w; - return result; + Vec4 result; + result.x = LinearFromSrgbF32(srgb.x); + result.y = LinearFromSrgbF32(srgb.y); + result.z = LinearFromSrgbF32(srgb.z); + result.w = srgb.w; + return result; } //////////////////////////////////////////////////////////// @@ -128,13 +128,13 @@ Vec4 LinearFromSrgb(Vec4 srgb) Vec2 RectUvFromVertexId(u32 id) { - static const Vec2 uvs[4] = { - Vec2(0, 0), - Vec2(1, 0), - Vec2(1, 1), - Vec2(0, 1) - }; - return uvs[id]; + static const Vec2 uvs[4] = { + Vec2(0, 0), + Vec2(1, 0), + Vec2(1, 1), + Vec2(0, 1) + }; + return uvs[id]; } //////////////////////////////////////////////////////////// @@ -142,20 +142,20 @@ Vec2 RectUvFromVertexId(u32 id) Vec2 NdcFromPos(Vec2 pos, Vec2 size) { - Vec2 result; - result = pos / size; - result *= Vec2(2, -2); - result += Vec2(-1, 1); - return result; + Vec2 result; + result = pos / size; + result *= Vec2(2, -2); + result += Vec2(-1, 1); + return result; } Vec2 NdcFromUv(Vec2 uv) { - Vec2 result; - result = uv; - result *= Vec2(2, -2); - result += Vec2(-1, 1); - return result; + Vec2 result; + result = uv; + result *= Vec2(2, -2); + result += Vec2(-1, 1); + return result; } //////////////////////////////////////////////////////////// @@ -165,195 +165,195 @@ Vec2 NdcFromUv(Vec2 uv) template u32 U32FromChar(in T c) { - if(c == ' ') - return 32; - if(c == '!') - return 33; - if(c == '\"' || c == '\"') - return 34; - if(c == '#') - return 35; - if(c == '$') - return 36; - if(c == '%') - return 37; - if(c == '&') - return 38; - if(c == '\'') - return 39; - if(c == '(') - return 40; - if(c == ')') - return 41; - if(c == '*') - return 42; - if(c == '+') - return 43; - if(c == ',') - return 44; - if(c == '-') - return 45; - if(c == '.') - return 46; - if(c == '/') - return 47; - if(c == '0') - return 48; - if(c == '1') - return 49; - if(c == '2') - return 50; - if(c == '3') - return 51; - if(c == '4') - return 52; - if(c == '5') - return 53; - if(c == '6') - return 54; - if(c == '7') - return 55; - if(c == '8') - return 56; - if(c == '9') - return 57; - if(c == ':') - return 58; - if(c == ';') - return 59; - if(c == '<') - return 60; - if(c == '=') - return 61; - if(c == '>') - return 62; - if(c == '?') - return 63; - if(c == '@') - return 64; - if(c == 'A') - return 65; - if(c == 'B') - return 66; - if(c == 'C') - return 67; - if(c == 'D') - return 68; - if(c == 'E') - return 69; - if(c == 'F') - return 70; - if(c == 'G') - return 71; - if(c == 'H') - return 72; - if(c == 'I') - return 73; - if(c == 'J') - return 74; - if(c == 'K') - return 75; - if(c == 'L') - return 76; - if(c == 'M') - return 77; - if(c == 'N') - return 78; - if(c == 'O') - return 79; - if(c == 'P') - return 80; - if(c == 'Q') - return 81; - if(c == 'R') - return 82; - if(c == 'S') - return 83; - if(c == 'T') - return 84; - if(c == 'U') - return 85; - if(c == 'V') - return 86; - if(c == 'W') - return 87; - if(c == 'X') - return 88; - if(c == 'Y') - return 89; - if(c == 'Z') - return 90; - if(c == '[') - return 91; - if(c == '\\') - return 92; - if(c == ']') - return 93; - if(c == '^') - return 94; - if(c == '_') - return 95; - if(c == '`') - return 96; - if(c == 'a') - return 97; - if(c == 'b') - return 98; - if(c == 'c') - return 99; - if(c == 'd') - return 100; - if(c == 'e') - return 101; - if(c == 'f') - return 102; - if(c == 'g') - return 103; - if(c == 'h') - return 104; - if(c == 'i') - return 105; - if(c == 'j') - return 106; - if(c == 'k') - return 107; - if(c == 'l') - return 108; - if(c == 'm') - return 109; - if(c == 'n') - return 110; - if(c == 'o') - return 111; - if(c == 'p') - return 112; - if(c == 'q') - return 113; - if(c == 'r') - return 114; - if(c == 's') - return 115; - if(c == 't') - return 116; - if(c == 'u') - return 117; - if(c == 'v') - return 118; - if(c == 'w') - return 119; - if(c == 'x') - return 120; - if(c == 'y') - return 121; - if(c == 'z') - return 122; - if(c == '{') - return 123; - if(c == '|') - return 124; - if(c == '}') - return 125; - if(c == '~') - return 126; - return 0; + if(c == ' ') + return 32; + if(c == '!') + return 33; + if(c == '\"' || c == '\"') + return 34; + if(c == '#') + return 35; + if(c == '$') + return 36; + if(c == '%') + return 37; + if(c == '&') + return 38; + if(c == '\'') + return 39; + if(c == '(') + return 40; + if(c == ')') + return 41; + if(c == '*') + return 42; + if(c == '+') + return 43; + if(c == ',') + return 44; + if(c == '-') + return 45; + if(c == '.') + return 46; + if(c == '/') + return 47; + if(c == '0') + return 48; + if(c == '1') + return 49; + if(c == '2') + return 50; + if(c == '3') + return 51; + if(c == '4') + return 52; + if(c == '5') + return 53; + if(c == '6') + return 54; + if(c == '7') + return 55; + if(c == '8') + return 56; + if(c == '9') + return 57; + if(c == ':') + return 58; + if(c == ';') + return 59; + if(c == '<') + return 60; + if(c == '=') + return 61; + if(c == '>') + return 62; + if(c == '?') + return 63; + if(c == '@') + return 64; + if(c == 'A') + return 65; + if(c == 'B') + return 66; + if(c == 'C') + return 67; + if(c == 'D') + return 68; + if(c == 'E') + return 69; + if(c == 'F') + return 70; + if(c == 'G') + return 71; + if(c == 'H') + return 72; + if(c == 'I') + return 73; + if(c == 'J') + return 74; + if(c == 'K') + return 75; + if(c == 'L') + return 76; + if(c == 'M') + return 77; + if(c == 'N') + return 78; + if(c == 'O') + return 79; + if(c == 'P') + return 80; + if(c == 'Q') + return 81; + if(c == 'R') + return 82; + if(c == 'S') + return 83; + if(c == 'T') + return 84; + if(c == 'U') + return 85; + if(c == 'V') + return 86; + if(c == 'W') + return 87; + if(c == 'X') + return 88; + if(c == 'Y') + return 89; + if(c == 'Z') + return 90; + if(c == '[') + return 91; + if(c == '\\') + return 92; + if(c == ']') + return 93; + if(c == '^') + return 94; + if(c == '_') + return 95; + if(c == '`') + return 96; + if(c == 'a') + return 97; + if(c == 'b') + return 98; + if(c == 'c') + return 99; + if(c == 'd') + return 100; + if(c == 'e') + return 101; + if(c == 'f') + return 102; + if(c == 'g') + return 103; + if(c == 'h') + return 104; + if(c == 'i') + return 105; + if(c == 'j') + return 106; + if(c == 'k') + return 107; + if(c == 'l') + return 108; + if(c == 'm') + return 109; + if(c == 'n') + return 110; + if(c == 'o') + return 111; + if(c == 'p') + return 112; + if(c == 'q') + return 113; + if(c == 'r') + return 114; + if(c == 's') + return 115; + if(c == 't') + return 116; + if(c == 'u') + return 117; + if(c == 'v') + return 118; + if(c == 'w') + return 119; + if(c == 'x') + return 120; + if(c == 'y') + return 121; + if(c == 'z') + return 122; + if(c == '{') + return 123; + if(c == '|') + return 124; + if(c == '}') + return 125; + if(c == '~') + return 126; + return 0; } diff --git a/src/base/base_state.h b/src/base/base_state.h index 3c5bd51b..268dc491 100644 --- a/src/base/base_state.h +++ b/src/base/base_state.h @@ -3,10 +3,10 @@ Struct(BaseCtx) { - CmdLineCtx cmdline; - ResourceCtx resource; - GstatCtx gstat; - AsyncCtx async; + CmdLineCtx cmdline; + ResourceCtx resource; + GstatCtx gstat; + AsyncCtx async; }; extern BaseCtx Base; @@ -16,7 +16,7 @@ extern BaseCtx Base; Struct(BaseThreadLocalCtx) { - ThreadLocalArenaCtx arenas; + ThreadLocalArenaCtx arenas; }; extern ThreadLocal BaseThreadLocalCtx Base_tl; diff --git a/src/base/base_string.c b/src/base/base_string.c index aaedb0ad..bf6e77f7 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -5,226 +5,226 @@ String StringFromChar(Arena *arena, char c) { - u8 *dst = PushStructNoZero(arena, u8); - *dst = c; - return (String) - { - .len = 1, - .text = dst - }; + u8 *dst = PushStructNoZero(arena, u8); + *dst = c; + return (String) + { + .len = 1, + .text = dst + }; } //- Unsigned int conversion String StringFromUint(Arena *arena, u64 n, u64 base, u64 zfill) { - /* Base too large */ - Assert(base <= (countof(IntChars) - 1)); - String result = Zi; - TempArena scratch = BeginScratch(arena); + /* Base too large */ + Assert(base <= (countof(IntChars) - 1)); + String result = Zi; + TempArena scratch = BeginScratch(arena); + { + /* Build backwards text starting from least significant digit */ + u8 *backwards_text = ArenaNext(scratch.arena, u8); + do { - /* Build backwards text starting from least significant digit */ - u8 *backwards_text = ArenaNext(scratch.arena, u8); - do - { - StringFromChar(scratch.arena, IntChars[n % base]); - ++result.len; - n /= base; - } while (n > 0); - - while (result.len < zfill) - { - StringFromChar(scratch.arena, '0'); - ++result.len; - } - - /* Reverse text into final string */ - result.text = PushStructsNoZero(arena, u8, result.len); - for (u64 i = 0; i < result.len; ++i) - { - result.text[i] = backwards_text[result.len - i - 1]; - } + StringFromChar(scratch.arena, IntChars[n % base]); + ++result.len; + n /= base; + } while (n > 0); + while (result.len < zfill) + { + StringFromChar(scratch.arena, '0'); + ++result.len; } - EndScratch(scratch); - return result; + + /* Reverse text into final string */ + result.text = PushStructsNoZero(arena, u8, result.len); + for (u64 i = 0; i < result.len; ++i) + { + result.text[i] = backwards_text[result.len - i - 1]; + } + + } + EndScratch(scratch); + return result; } String StringFromUints(Arena *arena, u64 uints_count, u64 *uints, u64 base, u64 zfill) { - String result = Zi; - result.text = ArenaNext(arena, u8); - result.len += StringFromChar(arena, '(').len; - for (u64 uint_idx = 0; uint_idx < uints_count; ++uint_idx) + String result = Zi; + result.text = ArenaNext(arena, u8); + result.len += StringFromChar(arena, '(').len; + for (u64 uint_idx = 0; uint_idx < uints_count; ++uint_idx) + { + result.len += StringFromUint(arena, uints[uint_idx], base, zfill).len; + if (uint_idx + 1 < uints_count) { - result.len += StringFromUint(arena, uints[uint_idx], base, zfill).len; - if (uint_idx + 1 < uints_count) - { - result.len += PushString(arena, Lit(", ")).len; - } + result.len += PushString(arena, Lit(", ")).len; } - result.len += StringFromChar(arena, ')').len; - return result; + } + result.len += StringFromChar(arena, ')').len; + return result; } //- Signed int conversion String StringFromSint(Arena *arena, i64 n, u64 base, u64 zfill) { - String result = Zi; - result.text = ArenaNext(arena, u8); - if (n < 0) - { - result.len += StringFromChar(arena, '-').len; - n = -n; - } - result.len += StringFromUint(arena, (u64)n, base, zfill).len; - return result; + String result = Zi; + result.text = ArenaNext(arena, u8); + if (n < 0) + { + result.len += StringFromChar(arena, '-').len; + n = -n; + } + result.len += StringFromUint(arena, (u64)n, base, zfill).len; + return result; } String StringFromSints(Arena *arena, u64 sints_count, i64 *sints, u64 base, u64 zfill) { - String result = Zi; - result.text = ArenaNext(arena, u8); - result.len += StringFromChar(arena, '(').len; - for (u64 sint_idx = 0; sint_idx < sints_count; ++sint_idx) + String result = Zi; + result.text = ArenaNext(arena, u8); + result.len += StringFromChar(arena, '(').len; + for (u64 sint_idx = 0; sint_idx < sints_count; ++sint_idx) + { + result.len += StringFromSint(arena, sints[sint_idx], base, zfill).len; + if (sint_idx + 1 < sints_count) { - result.len += StringFromSint(arena, sints[sint_idx], base, zfill).len; - if (sint_idx + 1 < sints_count) - { - result.len += PushString(arena, Lit(", ")).len; - } + result.len += PushString(arena, Lit(", ")).len; } - result.len += StringFromChar(arena, ')').len; - return result; + } + result.len += StringFromChar(arena, ')').len; + return result; } //- Floating point conversion String StringFromFloat(Arena *arena, f64 f, u32 precision) { - String result = Zi; - result.text = ArenaNext(arena, u8); - TempArena scratch = BeginScratch(arena); + String result = Zi; + result.text = ArenaNext(arena, u8); + TempArena scratch = BeginScratch(arena); + { + if (IsF32Nan(f)) { - if (IsF32Nan(f)) - { - result.len += PushString(arena, Lit("NaN")).len; - } - else if (f == F64Infinity) - { - result.len += PushString(arena, Lit("inf")).len; - } - else if (f == -F64Infinity) - { - result.len += PushString(arena, Lit("-inf")).len; - } - else - { - if (f < 0) - { - StringFromChar(arena, '-'); - f = -f; - ++result.len; - } - - /* Add one half of next precision level to round up */ - f += 0.5 / (f64)PowU64(10, (u8)precision); - - f64 part_whole = TruncF64(f); - f64 part_decimal = f - part_whole; - - /* Print whole part */ - { - /* Build backwards text starting from least significant digit */ - u8 *backwards_text = ArenaNext(scratch.arena, u8); - u64 backwards_text_len = 0; - do - { - u64 digit = (u64)RoundF64ToI64(ModF64(part_whole, 10.0)); - StringFromChar(scratch.arena, IntChars[digit % 10]); - ++backwards_text_len; - part_whole = TruncF64(part_whole / 10.0); - } while (part_whole > 0); - - /* Reverse text into final string */ - PushStructsNoZero(arena, u8, backwards_text_len); - for (u64 i = backwards_text_len; i-- > 0;) - { - result.text[result.len++] = backwards_text[i]; - } - } - - /* Print decimal part */ - if (precision > 0) - { - StringFromChar(arena, '.'); - for (u64 i = 0; i < precision; ++i) - { - part_decimal *= 10.0; - u64 digit = (u64)part_decimal; - part_decimal -= digit; - StringFromChar(arena, IntChars[digit % 10]); - } - result.len += (u64)precision + 1; - } - } + result.len += PushString(arena, Lit("NaN")).len; } - EndScratch(scratch); - return result; + else if (f == F64Infinity) + { + result.len += PushString(arena, Lit("inf")).len; + } + else if (f == -F64Infinity) + { + result.len += PushString(arena, Lit("-inf")).len; + } + else + { + if (f < 0) + { + StringFromChar(arena, '-'); + f = -f; + ++result.len; + } + + /* Add one half of next precision level to round up */ + f += 0.5 / (f64)PowU64(10, (u8)precision); + + f64 part_whole = TruncF64(f); + f64 part_decimal = f - part_whole; + + /* Print whole part */ + { + /* Build backwards text starting from least significant digit */ + u8 *backwards_text = ArenaNext(scratch.arena, u8); + u64 backwards_text_len = 0; + do + { + u64 digit = (u64)RoundF64ToI64(ModF64(part_whole, 10.0)); + StringFromChar(scratch.arena, IntChars[digit % 10]); + ++backwards_text_len; + part_whole = TruncF64(part_whole / 10.0); + } while (part_whole > 0); + + /* Reverse text into final string */ + PushStructsNoZero(arena, u8, backwards_text_len); + for (u64 i = backwards_text_len; i-- > 0;) + { + result.text[result.len++] = backwards_text[i]; + } + } + + /* Print decimal part */ + if (precision > 0) + { + StringFromChar(arena, '.'); + for (u64 i = 0; i < precision; ++i) + { + part_decimal *= 10.0; + u64 digit = (u64)part_decimal; + part_decimal -= digit; + StringFromChar(arena, IntChars[digit % 10]); + } + result.len += (u64)precision + 1; + } + } + } + EndScratch(scratch); + return result; } String StringFromFloats(Arena *arena, u64 floats_count, f64 *floats, u32 precision) { - String result = Zi; - result.text = ArenaNext(arena, u8); - result.len += StringFromChar(arena, '(').len; - for (u64 float_idx = 0; float_idx < floats_count; ++float_idx) + String result = Zi; + result.text = ArenaNext(arena, u8); + result.len += StringFromChar(arena, '(').len; + for (u64 float_idx = 0; float_idx < floats_count; ++float_idx) + { + result.len += StringFromFloat(arena, floats[float_idx], precision).len; + if (float_idx + 1 < floats_count) { - result.len += StringFromFloat(arena, floats[float_idx], precision).len; - if (float_idx + 1 < floats_count) - { - result.len += PushString(arena, Lit(", ")).len; - } + result.len += PushString(arena, Lit(", ")).len; } - result.len += StringFromChar(arena, ')').len; - return result; + } + result.len += StringFromChar(arena, ')').len; + return result; } //- Pointer conversion String StringFromPtr(Arena *arena, void *ptr) { - String prepend = PushString(arena, Lit("0x")); - String uint_str = StringFromUint(arena, (u64)ptr, 16, sizeof(ptr)); - return (String) - { - .len = prepend.len + uint_str.len, - .text = prepend.text - }; + String prepend = PushString(arena, Lit("0x")); + String uint_str = StringFromUint(arena, (u64)ptr, 16, sizeof(ptr)); + return (String) + { + .len = prepend.len + uint_str.len, + .text = prepend.text + }; } //- Handle conversion String StringFromhandle(Arena *arena, u64 v0, u64 v1) { - String result = Zi; - result.text = ArenaNext(arena, u8); - result.len += PushString(arena, Lit("h")).len; - result.len += StringFromUint(arena, v0, 16, 0).len; - result.len += PushString(arena, Lit("x")).len; - result.len += StringFromUint(arena, v1, 16, 0).len; - return result; + String result = Zi; + result.text = ArenaNext(arena, u8); + result.len += PushString(arena, Lit("h")).len; + result.len += StringFromUint(arena, v0, 16, 0).len; + result.len += PushString(arena, Lit("x")).len; + result.len += StringFromUint(arena, v1, 16, 0).len; + return result; } //- Uid conversion String StringFromUid(Arena *arena, Uid uid) { - String result = Zi; - result.text = ArenaNext(arena, u8); - result.len += StringFromUint(arena, (uid.hi >> 32), 16, 8).len; - return result; + String result = Zi; + result.text = ArenaNext(arena, u8); + result.len += StringFromUint(arena, (uid.hi >> 32), 16, 8).len; + return result; } @@ -235,49 +235,49 @@ String StringFromUid(Arena *arena, Uid uid) String PushString(Arena *arena, String src) { - String result = Zi; - result.len = src.len; - result.text = PushStructsNoZero(arena, u8, src.len); - CopyBytes(result.text, src.text, src.len); - return result; + String result = Zi; + result.len = src.len; + result.text = PushStructsNoZero(arena, u8, src.len); + CopyBytes(result.text, src.text, src.len); + return result; } String CopyString(String dst, String src) { - String result = Zi; - result.len = MinU64(dst.len, src.len); - result.text = dst.text; - CopyBytes(result.text, src.text, result.len); - return result; + String result = Zi; + result.len = MinU64(dst.len, src.len); + result.text = dst.text; + CopyBytes(result.text, src.text, result.len); + return result; } //- Repeat String RepeatString(Arena *arena, String src, u64 count) { - u64 final_len = src.len * count; - u8 *final_text = PushStructsNoZero(arena, u8, final_len); - for (u64 i = 0; i < count; ++i) - { - CopyBytes(final_text + (src.len * i), src.text, src.len); - } - return (String) - { - .text = final_text, - .len = final_len - }; + u64 final_len = src.len * count; + u8 *final_text = PushStructsNoZero(arena, u8, final_len); + for (u64 i = 0; i < count; ++i) + { + CopyBytes(final_text + (src.len * i), src.text, src.len); + } + return (String) + { + .text = final_text, + .len = final_len + }; } //- Concatenate String CatString(Arena *arena, String str1, String str2) { - String new_str = Zi; - new_str.len = str1.len + str2.len; - new_str.text = PushStructsNoZero(arena, u8, new_str.len); - CopyBytes(new_str.text, str1.text, str1.len); - CopyBytes(new_str.text + str1.len, str2.text, str2.len); - return new_str; + String new_str = Zi; + new_str.len = str1.len + str2.len; + new_str.text = PushStructsNoZero(arena, u8, new_str.len); + CopyBytes(new_str.text, str1.text, str1.len); + CopyBytes(new_str.text + str1.len, str2.text, str2.len); + return new_str; } //- Split @@ -286,77 +286,77 @@ String CatString(Arena *arena, String str1, String str2) * into the existing string and do not allocate any new text. */ StringArray SplitString(Arena *arena, String str, String delim) { - StringArray pieces = Zi; - pieces.strings = ArenaNext(arena, String); - i64 piece_start = 0; - for (i64 i = 0; i < (i64)str.len - (i64)delim.len;) - { - String cmp = Zi; - cmp.text = &str.text[i]; - cmp.len = MinI64(str.len - i, delim.len); + StringArray pieces = Zi; + pieces.strings = ArenaNext(arena, String); + i64 piece_start = 0; + for (i64 i = 0; i < (i64)str.len - (i64)delim.len;) + { + String cmp = Zi; + cmp.text = &str.text[i]; + cmp.len = MinI64(str.len - i, delim.len); - if (MatchString(cmp, delim)) - { - String piece = Zi; - piece.text = &str.text[piece_start]; - piece.len = i - piece_start; - *PushStructNoZero(arena, String) = piece; - ++pieces.count; - i += delim.len; - piece_start = i; - } - else - { - i += 1; - } - } - if (piece_start < (i64)str.len) + if (MatchString(cmp, delim)) { - String piece = Zi; - piece.text = &str.text[piece_start]; - piece.len = str.len - piece_start; - *PushStructNoZero(arena, String) = piece; - ++pieces.count; + String piece = Zi; + piece.text = &str.text[piece_start]; + piece.len = i - piece_start; + *PushStructNoZero(arena, String) = piece; + ++pieces.count; + i += delim.len; + piece_start = i; } - return pieces; + else + { + i += 1; + } + } + if (piece_start < (i64)str.len) + { + String piece = Zi; + piece.text = &str.text[piece_start]; + piece.len = str.len - piece_start; + *PushStructNoZero(arena, String) = piece; + ++pieces.count; + } + return pieces; } String ReplaceString(Arena *arena, String str, String old_pattern, String new_pattern) { - String result = Zi; - result.text = ArenaNext(arena, u8); - i64 piece_start = 0; - for (i64 i = 0; i < (i64)str.len - (i64)old_pattern.len;) + String result = Zi; + result.text = ArenaNext(arena, u8); + i64 piece_start = 0; + for (i64 i = 0; i < (i64)str.len - (i64)old_pattern.len;) + { + String cmp = Zi; + cmp.text = &str.text[i]; + cmp.len = MinI64(str.len - i, old_pattern.len); + if (MatchString(cmp, old_pattern)) { - String cmp = Zi; - cmp.text = &str.text[i]; - cmp.len = MinI64(str.len - i, old_pattern.len); - if (MatchString(cmp, old_pattern)) - { - String piece = Zi; - piece.text = &str.text[piece_start]; - piece.len = i - piece_start; - if (piece.len > 0) - { - result.len += PushString(arena, piece).len; - } - result.len += PushString(arena, new_pattern).len; - i += old_pattern.len; - piece_start = i; - } - else - { - i += 1; - } - } - if (piece_start < (i64)str.len) - { - String piece = Zi; - piece.text = &str.text[piece_start]; - piece.len = str.len - piece_start; + String piece = Zi; + piece.text = &str.text[piece_start]; + piece.len = i - piece_start; + if (piece.len > 0) + { result.len += PushString(arena, piece).len; + } + result.len += PushString(arena, new_pattern).len; + i += old_pattern.len; + piece_start = i; } - return result; + else + { + i += 1; + } + } + if (piece_start < (i64)str.len) + { + String piece = Zi; + piece.text = &str.text[piece_start]; + piece.len = str.len - piece_start; + result.len += PushString(arena, piece).len; + } + return result; } //- Indent @@ -364,153 +364,153 @@ String ReplaceString(Arena *arena, String str, String old_pattern, String new_pa /* NOTE: Really slow */ String IndentString(Arena *arena, String str, u32 indent) { - TempArena scratch = BeginScratch(arena); + TempArena scratch = BeginScratch(arena); - u64 final_len = 0; - u8 *final_text = ArenaNext(arena, u8); + u64 final_len = 0; + u8 *final_text = ArenaNext(arena, u8); - StringArray split = SplitString(scratch.arena, str, Lit("\n")); - for (u64 i = 0; i < split.count; ++i) + StringArray split = SplitString(scratch.arena, str, Lit("\n")); + for (u64 i = 0; i < split.count; ++i) + { + String piece = split.strings[i]; + for (u32 j = 0; j < indent; ++j) { - String piece = split.strings[i]; - for (u32 j = 0; j < indent; ++j) - { - StringFromChar(arena, ' '); - ++final_len; - } - PushString(arena, piece); - final_len += piece.len; - if (i < split.count - 1) - { - StringFromChar(arena, '\n'); - ++final_len; - } + StringFromChar(arena, ' '); + ++final_len; } - - EndScratch(scratch); - - return (String) + PushString(arena, piece); + final_len += piece.len; + if (i < split.count - 1) { - .len = final_len, - .text = final_text - }; + StringFromChar(arena, '\n'); + ++final_len; + } + } + + EndScratch(scratch); + + return (String) + { + .len = final_len, + .text = final_text + }; } //- Lower String LowerString(Arena *arena, String str) { - String result = Zi; - result.text = PushStructsNoZero(arena, u8, str.len); - result.len = str.len; + String result = Zi; + result.text = PushStructsNoZero(arena, u8, str.len); + result.len = str.len; - for (u64 i = 0; i < str.len; ++i) + for (u64 i = 0; i < str.len; ++i) + { + u8 c = str.text[i]; + if (65 <= c && c <= 90) { - u8 c = str.text[i]; - if (65 <= c && c <= 90) - { - c += 32; - } - result.text[i] = c; + c += 32; } + result.text[i] = c; + } - return result; + return result; } //- Compare b32 MatchString(String str1, String str2) { - b32 eq = 1; - if (str1.len == str2.len) - { - for (u64 i = 0; i < str1.len; ++i) - { - if (str1.text[i] != str2.text[i]) - { - eq = 0; - break; - } - } - } - else + b32 eq = 1; + if (str1.len == str2.len) + { + for (u64 i = 0; i < str1.len; ++i) { + if (str1.text[i] != str2.text[i]) + { eq = 0; + break; + } } - return eq; + } + else + { + eq = 0; + } + return eq; } //- Match b32 StringContains(String str, String substring) { - if (substring.len > str.len) - { - return 0; - } - - for (u64 i = 0; i <= str.len - substring.len; ++i) - { - b32 match = 1; - for (u64 j = 0; j < substring.len; ++j) - { - if (str.text[i + j] != substring.text[j]) - { - match = 0; - break; - } - } - if (match) - { - return 1; - } - } - + if (substring.len > str.len) + { return 0; + } + + for (u64 i = 0; i <= str.len - substring.len; ++i) + { + b32 match = 1; + for (u64 j = 0; j < substring.len; ++j) + { + if (str.text[i + j] != substring.text[j]) + { + match = 0; + break; + } + } + if (match) + { + return 1; + } + } + + return 0; } b32 StringBeginsWith(String str, String substring) { - if (str.len >= substring.len) + if (str.len >= substring.len) + { + for (u64 i = 0; i < substring.len; ++i) { - for (u64 i = 0; i < substring.len; ++i) - { - if (str.text[i] != substring.text[i]) - { - return 0; - } - } - return 1; + if (str.text[i] != substring.text[i]) + { + return 0; + } } - return 0; + return 1; + } + return 0; } b32 StringEndsWith(String str, String substring) { - if (str.len >= substring.len) + if (str.len >= substring.len) + { + u64 start = str.len - substring.len; + for (u64 i = 0; i < substring.len; ++i) { - u64 start = str.len - substring.len; - for (u64 i = 0; i < substring.len; ++i) - { - if (str.text[start + i] != substring.text[i]) - { - return 0; - } - } - return 1; + if (str.text[start + i] != substring.text[i]) + { + return 0; + } } - return 0; + return 1; + } + return 0; } String StringFromArray(Arena *arena, StringArray a) { - String result = Zi; - result.text = ArenaNext(arena, u8); - for (u64 string_idx = 0; string_idx < a.count; ++string_idx) - { - result.len += PushString(arena, a.strings[string_idx]).len; - } - return result; + String result = Zi; + result.text = ArenaNext(arena, u8); + for (u64 string_idx = 0; string_idx < a.count; ++string_idx) + { + result.len += PushString(arena, a.strings[string_idx]).len; + } + return result; } //////////////////////////////////////////////////////////// @@ -518,38 +518,38 @@ String StringFromArray(Arena *arena, StringArray a) StringListNode *PushStringToList(Arena *arena, StringList *l, String s) { - StringListNode *n = PushStruct(arena, StringListNode); - n->s = s; - n->prev = l->last; - if (l->last) - { - l->last->next = n; - } - else - { - l->first = n; - } - l->last = n; - ++l->count; - return n; + StringListNode *n = PushStruct(arena, StringListNode); + n->s = s; + n->prev = l->last; + if (l->last) + { + l->last->next = n; + } + else + { + l->first = n; + } + l->last = n; + ++l->count; + return n; } String StringFromList(Arena *arena, StringList l, String separator) { - String result = Zi; - result.text = ArenaNext(arena, u8); - for (StringListNode *n = l.first; n; n = n->next) + String result = Zi; + result.text = ArenaNext(arena, u8); + for (StringListNode *n = l.first; n; n = n->next) + { + String s = n->s; + PushString(arena, s); + result.len += s.len; + if (n->next) { - String s = n->s; - PushString(arena, s); - result.len += s.len; - if (n->next) - { - PushString(arena, separator); - result.len += separator.len; - } + PushString(arena, separator); + result.len += separator.len; } - return result; + } + return result; } //////////////////////////////////////////////////////////// @@ -557,50 +557,50 @@ String StringFromList(Arena *arena, StringList l, String separator) String TrimLeft(String s, String pattern) { - String result = s; - while (StringBeginsWith(result, pattern)) - { - result.text += pattern.len; - result.len -= pattern.len; - } - return result; + String result = s; + while (StringBeginsWith(result, pattern)) + { + result.text += pattern.len; + result.len -= pattern.len; + } + return result; } String TrimRight(String s, String pattern) { - String result = s; - while (StringEndsWith(result, pattern)) - { - result.len -= pattern.len; - } - return result; + String result = s; + while (StringEndsWith(result, pattern)) + { + result.len -= pattern.len; + } + return result; } String Trim(String s, String pattern) { - return TrimLeft(TrimRight(s, pattern), pattern); + return TrimLeft(TrimRight(s, pattern), pattern); } String TrimWhitespace(String s) { - b32 stop = 0; - while (!stop) + b32 stop = 0; + while (!stop) + { + if (StringBeginsWith(s, Lit("\n")) || StringBeginsWith(s, Lit("\r")) || StringBeginsWith(s, Lit(" "))) { - if (StringBeginsWith(s, Lit("\n")) || StringBeginsWith(s, Lit("\r")) || StringBeginsWith(s, Lit(" "))) - { - s.text += 1; - s.len -= 1; - } - else if (StringEndsWith(s, Lit("\n")) || StringEndsWith(s, Lit("\r")) || StringEndsWith(s, Lit(" "))) - { - s.len -= 1; - } - else - { - stop = 1; - } + s.text += 1; + s.len -= 1; } - return s; + else if (StringEndsWith(s, Lit("\n")) || StringEndsWith(s, Lit("\r")) || StringEndsWith(s, Lit(" "))) + { + s.len -= 1; + } + else + { + stop = 1; + } + } + return s; } //////////////////////////////////////////////////////////// @@ -627,236 +627,237 @@ String TrimWhitespace(String s) */ String FormatString(Arena *arena, String fmt, FmtArgArray args) { - String result = Zi; - result.text = ArenaNext(arena, u8); + String result = Zi; + result.text = ArenaNext(arena, u8); - u8 *end = fmt.text + fmt.len; - b32 no_more_valid_args = 0; - u64 arg_idx = 0; - for (u8 *c = fmt.text; c < end; ++c) + u8 *end = fmt.text + fmt.len; + b32 no_more_valid_args = 0; + u64 arg_idx = 0; + for (u8 *c = fmt.text; c < end; ++c) + { + u8 *next = ((c + 1) < end) ? (c + 1) : (u8 *)"\0"; + + /* Escape '%%' */ + b32 escape = !no_more_valid_args && *c == '%' && *next == '%'; + if (escape) { - u8 *next = ((c + 1) < end) ? (c + 1) : (u8 *)"\0"; - - /* Escape '%%' */ - b32 escape = !no_more_valid_args && *c == '%' && *next == '%'; - if (escape) - { - /* Skip the escaped '%' char from parsing */ - ++c; - } - - if (!no_more_valid_args && !escape && *c == '%' && *next == 'F') - { - String parsed_arg = Zi; - - FmtArg arg = Zi; - if (arg_idx < args.count) - { - arg = args.args[arg_idx]; - ++arg_idx; - } - else - { - no_more_valid_args = 1; - } - - switch (arg.kind) - { - default: - { - /* Unknown format type */ - Assert(0); - parsed_arg = PushString(arena, Lit("")); - no_more_valid_args = 1; - } break; - - case FmtArgKind_Char: - { - parsed_arg = StringFromChar(arena, arg.value.c); - } break; - - case FmtArgKind_String: - { - parsed_arg = PushString(arena, arg.value.string); - } break; - - case FmtArgKind_Uint: - { - parsed_arg = StringFromUint(arena, arg.value.uints.x, 10, arg.z); - } break; - - case FmtArgKind_Uint2: - { - parsed_arg = StringFromUints(arena, 2, &arg.value.uints.x, 10, arg.z); - } break; - - case FmtArgKind_Uint3: - { - parsed_arg = StringFromUints(arena, 3, &arg.value.uints.x, 10, arg.z); - } break; - - case FmtArgKind_Uint4: - { - parsed_arg = StringFromUints(arena, 4, &arg.value.uints.x, 10, arg.z); - } break; - - case FmtArgKind_Sint: - { - parsed_arg = StringFromSint(arena, arg.value.sints.x, 10, arg.z); - } break; - - case FmtArgKind_Sint2: - { - parsed_arg = StringFromSints(arena, 2, &arg.value.sints.x, 10, arg.z); - } break; - - case FmtArgKind_Sint3: - { - parsed_arg = StringFromSints(arena, 3, &arg.value.sints.x, 10, arg.z); - } break; - - case FmtArgKind_Sint4: - { - parsed_arg = StringFromSints(arena, 4, &arg.value.sints.x, 10, arg.z); - } break; - - case FmtArgKind_Float: - { - parsed_arg = StringFromFloat(arena, arg.value.floats.x, arg.p); - } break; - - case FmtArgKind_Float2: - { - parsed_arg = StringFromFloats(arena, 2, &arg.value.floats.x, arg.p); - } break; - - case FmtArgKind_Float3: - { - parsed_arg = StringFromFloats(arena, 3, &arg.value.floats.x, arg.p); - } break; - - case FmtArgKind_Float4: - { - parsed_arg = StringFromFloats(arena, 4, &arg.value.floats.x, arg.p); - } break; - - case FmtArgKind_Hex: - { - parsed_arg = StringFromUint(arena, arg.value.uints.x, 16, arg.z); - } break; - - case FmtArgKind_Ptr: - { - parsed_arg = StringFromPtr(arena, arg.value.ptr); - } break; - - case FmtArgKind_Handle: - { - parsed_arg = StringFromhandle(arena, arg.value.handle.h64[0], arg.value.handle.h64[1]); - } break; - - case FmtArgKind_Uid: - { - parsed_arg = StringFromUid(arena, arg.value.uid); - } break; - - case FmtArgKind_End: - { - /* Unexpected end. Not enough FMT args passed to function. */ - Assert(0); - parsed_arg = PushString(arena, Lit("")); - no_more_valid_args = 1; - } break; - } - - /* Update final string len / start */ - result.len += parsed_arg.len; - - /* Skip 'F' from parsing */ - ++c; - } - else - { - /* Parse character normally */ - StringFromChar(arena, *c); - ++result.len; - } + /* Skip the escaped '%' char from parsing */ + ++c; } -#if IsRtcEnabled + if (!no_more_valid_args && !escape && *c == '%' && *next == 'F') + { + String parsed_arg = Zi; + + FmtArg arg = Zi; + if (arg_idx < args.count) + { + arg = args.args[arg_idx]; + ++arg_idx; + } + else + { + no_more_valid_args = 1; + } + + switch (arg.kind) + { + default: + { + /* Unknown format type */ + Assert(0); + parsed_arg = PushString(arena, Lit("")); + no_more_valid_args = 1; + } break; + + case FmtArgKind_Char: + { + parsed_arg = StringFromChar(arena, arg.value.c); + } break; + + case FmtArgKind_String: + { + parsed_arg = PushString(arena, arg.value.string); + } break; + + case FmtArgKind_Uint: + { + parsed_arg = StringFromUint(arena, arg.value.uints.x, 10, arg.z); + } break; + + case FmtArgKind_Uint2: + { + parsed_arg = StringFromUints(arena, 2, &arg.value.uints.x, 10, arg.z); + } break; + + case FmtArgKind_Uint3: + { + parsed_arg = StringFromUints(arena, 3, &arg.value.uints.x, 10, arg.z); + } break; + + case FmtArgKind_Uint4: + { + parsed_arg = StringFromUints(arena, 4, &arg.value.uints.x, 10, arg.z); + } break; + + case FmtArgKind_Sint: + { + parsed_arg = StringFromSint(arena, arg.value.sints.x, 10, arg.z); + } break; + + case FmtArgKind_Sint2: + { + parsed_arg = StringFromSints(arena, 2, &arg.value.sints.x, 10, arg.z); + } break; + + case FmtArgKind_Sint3: + { + parsed_arg = StringFromSints(arena, 3, &arg.value.sints.x, 10, arg.z); + } break; + + case FmtArgKind_Sint4: + { + parsed_arg = StringFromSints(arena, 4, &arg.value.sints.x, 10, arg.z); + } break; + + case FmtArgKind_Float: + { + parsed_arg = StringFromFloat(arena, arg.value.floats.x, arg.p); + } break; + + case FmtArgKind_Float2: + { + parsed_arg = StringFromFloats(arena, 2, &arg.value.floats.x, arg.p); + } break; + + case FmtArgKind_Float3: + { + parsed_arg = StringFromFloats(arena, 3, &arg.value.floats.x, arg.p); + } break; + + case FmtArgKind_Float4: + { + parsed_arg = StringFromFloats(arena, 4, &arg.value.floats.x, arg.p); + } break; + + case FmtArgKind_Hex: + { + parsed_arg = StringFromUint(arena, arg.value.uints.x, 16, arg.z); + } break; + + case FmtArgKind_Ptr: + { + parsed_arg = StringFromPtr(arena, arg.value.ptr); + } break; + + case FmtArgKind_Handle: + { + parsed_arg = StringFromhandle(arena, arg.value.handle.h64[0], arg.value.handle.h64[1]); + } break; + + case FmtArgKind_Uid: + { + parsed_arg = StringFromUid(arena, arg.value.uid); + } break; + + case FmtArgKind_End: + { + /* Unexpected end. Not enough FMT args passed to function. */ + Assert(0); + parsed_arg = PushString(arena, Lit("")); + no_more_valid_args = 1; + } break; + } + + /* Update final string len / start */ + result.len += parsed_arg.len; + + /* Skip 'F' from parsing */ + ++c; + } + else + { + /* Parse character normally */ + StringFromChar(arena, *c); + ++result.len; + } + } + + if (IsRtcEnabled) + { if (!no_more_valid_args) { - FmtArg last_arg = Zi; - if (arg_idx < args.count) - { - last_arg = args.args[arg_idx]; - /* End arg not reached. Too many args supplied. */ - Assert(last_arg.kind == FmtArgKind_End); - } + FmtArg last_arg = Zi; + if (arg_idx < args.count) + { + last_arg = args.args[arg_idx]; + /* End arg not reached. Too many args supplied. */ + Assert(last_arg.kind == FmtArgKind_End); + } } -#endif + } - return result; + return result; } String StringF_(Arena *arena, String fmt, ...) { - String result = Zi; - TempArena scratch = BeginScratch(arena); - { - va_list args; - va_start(args, fmt); - result = FormatString(arena, fmt, FmtArgsFromVaList(scratch.arena, args)); - va_end(args); - } - EndScratch(scratch); - return result; + String result = Zi; + TempArena scratch = BeginScratch(arena); + { + va_list args; + va_start(args, fmt); + result = FormatString(arena, fmt, FmtArgsFromVaList(scratch.arena, args)); + va_end(args); + } + EndScratch(scratch); + return result; } FmtArgArray FmtArgsFromVaList(Arena *arena, va_list args) { - FmtArgArray result = Zi; - result.args = ArenaNext(arena, FmtArg); + FmtArgArray result = Zi; + result.args = ArenaNext(arena, FmtArg); + { + b32 done = 0; + while (!done) { - b32 done = 0; - while (!done) + FmtArg arg = va_arg(args, FmtArg); + *PushStructNoZero(arena, FmtArg) = arg; + ++result.count; + switch (arg.kind) + { + default: { - FmtArg arg = va_arg(args, FmtArg); - *PushStructNoZero(arena, FmtArg) = arg; - ++result.count; - switch (arg.kind) - { - default: - { - /* End/Invalid arg reached */ - done = 1; - } break; + /* End/Invalid arg reached */ + done = 1; + } break; - case FmtArgKind_Char: - case FmtArgKind_String: - case FmtArgKind_Uint: - case FmtArgKind_Uint2: - case FmtArgKind_Uint3: - case FmtArgKind_Uint4: - case FmtArgKind_Sint: - case FmtArgKind_Sint2: - case FmtArgKind_Sint3: - case FmtArgKind_Sint4: - case FmtArgKind_Float: - case FmtArgKind_Float2: - case FmtArgKind_Float3: - case FmtArgKind_Float4: - case FmtArgKind_Hex: - case FmtArgKind_Ptr: - case FmtArgKind_Uid: - case FmtArgKind_Handle: - { - /* Continue */ - } break; - } - } + case FmtArgKind_Char: + case FmtArgKind_String: + case FmtArgKind_Uint: + case FmtArgKind_Uint2: + case FmtArgKind_Uint3: + case FmtArgKind_Uint4: + case FmtArgKind_Sint: + case FmtArgKind_Sint2: + case FmtArgKind_Sint3: + case FmtArgKind_Sint4: + case FmtArgKind_Float: + case FmtArgKind_Float2: + case FmtArgKind_Float3: + case FmtArgKind_Float4: + case FmtArgKind_Hex: + case FmtArgKind_Ptr: + case FmtArgKind_Uid: + case FmtArgKind_Handle: + { + /* Continue */ + } break; + } } - return result; + } + return result; } //////////////////////////////////////////////////////////// @@ -866,27 +867,27 @@ FmtArgArray FmtArgsFromVaList(Arena *arena, va_list args) CodepointIter InitCodepointIter(String str) { - return (CodepointIter) - { - .src = str - }; + return (CodepointIter) + { + .src = str + }; } /* Returns 0 if done iterating */ b32 NextCodepoint(CodepointIter *iter) { - if (iter->pos < iter->src.len) - { - String str_remaining = { .len = (iter->src.len - iter->pos), .text = iter->src.text + iter->pos }; - Utf8DecodeResult decoded = DecodeUtf8(str_remaining); - iter->pos += decoded.advance8; - iter->codepoint = decoded.codepoint; - return 1; - } - else - { - return 0; - } + if (iter->pos < iter->src.len) + { + String str_remaining = { .len = (iter->src.len - iter->pos), .text = iter->src.text + iter->pos }; + Utf8DecodeResult decoded = DecodeUtf8(str_remaining); + iter->pos += decoded.advance8; + iter->codepoint = decoded.codepoint; + return 1; + } + else + { + return 0; + } } //- String decode @@ -894,51 +895,51 @@ b32 NextCodepoint(CodepointIter *iter) /* utf8 <- utf16 */ String StringFromString16(Arena *arena, String16 str16) { - String result = { - .len = 0, - .text = ArenaNext(arena, u8) - }; + String result = { + .len = 0, + .text = ArenaNext(arena, u8) + }; - u64 pos16 = 0; - while (pos16 < str16.len) - { - String16 str16_remaining = { .len = (str16.len - pos16), .text = str16.text + pos16 }; - Utf16DecodeResult decoded = DecodeUtf16(str16_remaining); - Utf8EncodeResult encoded = EncodeUtf8(decoded.codepoint); + u64 pos16 = 0; + while (pos16 < str16.len) + { + String16 str16_remaining = { .len = (str16.len - pos16), .text = str16.text + pos16 }; + Utf16DecodeResult decoded = DecodeUtf16(str16_remaining); + Utf8EncodeResult encoded = EncodeUtf8(decoded.codepoint); - u8 *dst = PushStructsNoZero(arena, u8, encoded.count8); - CopyBytes(dst, encoded.chars8, encoded.count8); + u8 *dst = PushStructsNoZero(arena, u8, encoded.count8); + CopyBytes(dst, encoded.chars8, encoded.count8); - pos16 += decoded.advance16; - result.len += encoded.count8; - } + pos16 += decoded.advance16; + result.len += encoded.count8; + } - return result; + return result; } /* utf8 <- utf32 */ String StringFromString32(Arena *arena, String32 str32) { - String result = { - .len = 0, - .text = ArenaNext(arena, u8) - }; + String result = { + .len = 0, + .text = ArenaNext(arena, u8) + }; - u64 pos32 = 0; - while (pos32 < str32.len) - { - String32 str32_remaining = { .len = (str32.len - pos32), .text = str32.text + pos32 }; - Utf32DecodeResult decoded = DecodeUtf32(str32_remaining); - Utf8EncodeResult encoded = EncodeUtf8(decoded.codepoint); + u64 pos32 = 0; + while (pos32 < str32.len) + { + String32 str32_remaining = { .len = (str32.len - pos32), .text = str32.text + pos32 }; + Utf32DecodeResult decoded = DecodeUtf32(str32_remaining); + Utf8EncodeResult encoded = EncodeUtf8(decoded.codepoint); - u8 *dst = PushStructsNoZero(arena, u8, encoded.count8); - CopyBytes(dst, &encoded.chars8, encoded.count8); + u8 *dst = PushStructsNoZero(arena, u8, encoded.count8); + CopyBytes(dst, &encoded.chars8, encoded.count8); - pos32 += 1; - result.len += encoded.count8; - } + pos32 += 1; + result.len += encoded.count8; + } - return result; + return result; } //- String encode @@ -946,51 +947,51 @@ String StringFromString32(Arena *arena, String32 str32) /* utf16 <- utf8 */ String16 String16FromString(Arena *arena, String str8) { - String16 result = { - .len = 0, - .text = ArenaNext(arena, u16) - }; + String16 result = { + .len = 0, + .text = ArenaNext(arena, u16) + }; - u64 pos8 = 0; - while (pos8 < str8.len) - { - String str8_remaining = { .len = (str8.len - pos8), .text = str8.text + pos8 }; - Utf8DecodeResult decoded = DecodeUtf8(str8_remaining); - Utf16EncodeResult encoded = EncodeUtf16(decoded.codepoint); + u64 pos8 = 0; + while (pos8 < str8.len) + { + String str8_remaining = { .len = (str8.len - pos8), .text = str8.text + pos8 }; + Utf8DecodeResult decoded = DecodeUtf8(str8_remaining); + Utf16EncodeResult encoded = EncodeUtf16(decoded.codepoint); - u16 *dst = PushStructsNoZero(arena, u16, encoded.count16); - CopyBytes(dst, encoded.chars16, (encoded.count16 << 1)); + u16 *dst = PushStructsNoZero(arena, u16, encoded.count16); + CopyBytes(dst, encoded.chars16, (encoded.count16 << 1)); - pos8 += decoded.advance8; - result.len += encoded.count16; - } + pos8 += decoded.advance8; + result.len += encoded.count16; + } - return result; + return result; } /* utf32 <- utf8 */ String32 String32FromString(Arena *arena, String str8) { - String32 result = { - .len = 0, - .text = ArenaNext(arena, u32) - }; + String32 result = { + .len = 0, + .text = ArenaNext(arena, u32) + }; - u64 pos8 = 0; - while (pos8 < str8.len) - { - String str8_remaining = { .len = (str8.len - pos8), .text = str8.text + pos8 }; - Utf8DecodeResult decoded = DecodeUtf8(str8_remaining); - Utf32EncodeResult encoded = EncodeUtf32(decoded.codepoint); + u64 pos8 = 0; + while (pos8 < str8.len) + { + String str8_remaining = { .len = (str8.len - pos8), .text = str8.text + pos8 }; + Utf8DecodeResult decoded = DecodeUtf8(str8_remaining); + Utf32EncodeResult encoded = EncodeUtf32(decoded.codepoint); - u32 *dst = PushStructNoZero(arena, u32); - *dst = encoded.chars32; + u32 *dst = PushStructNoZero(arena, u32); + *dst = encoded.chars32; - pos8 += decoded.advance8; - result.len += 1; - } + pos8 += decoded.advance8; + result.len += 1; + } - return result; + return result; } //////////////////////////////////////////////////////////// @@ -1000,153 +1001,153 @@ String32 String32FromString(Arena *arena, String str8) u64 CstrLenNoLimit(char *cstr) { - char *end = cstr; - if (cstr) + char *end = cstr; + if (cstr) + { + while (*end) { - while (*end) - { - ++end; - } + ++end; } - return end - cstr; + } + return end - cstr; } u64 CstrLen(char *cstr, u64 limit) { - char *end = cstr; - if (cstr) + char *end = cstr; + if (cstr) + { + for (u64 i = 0; i < limit; ++i) { - for (u64 i = 0; i < limit; ++i) - { - if (*end) - { - ++end; - } - else - { - break; - } - } + if (*end) + { + ++end; + } + else + { + break; + } } - return end - cstr; + } + return end - cstr; } char *CstrFromString(Arena *arena, String src) { - u8 *text = PushStructsNoZero(arena, u8, src.len + 1); - CopyBytes(text, src.text, src.len); - text[src.len] = 0; - return (char *)text; + u8 *text = PushStructsNoZero(arena, u8, src.len + 1); + CopyBytes(text, src.text, src.len); + text[src.len] = 0; + return (char *)text; } char *CstrFromStringToBuff(String dst_buff, String src) { - if (dst_buff.len > 0) - { - u64 len = MinU64(src.len, dst_buff.len - 1); - CopyBytes(dst_buff.text, src.text, len); - dst_buff.text[len] = 0; - } - return (char *)dst_buff.text; + if (dst_buff.len > 0) + { + u64 len = MinU64(src.len, dst_buff.len - 1); + CopyBytes(dst_buff.text, src.text, len); + dst_buff.text[len] = 0; + } + return (char *)dst_buff.text; } String StringFromCstrNoLimit(char *cstr) { - u64 len = CstrLenNoLimit(cstr); - return (String) - { - .len = len, - .text = (u8 *)cstr - }; + u64 len = CstrLenNoLimit(cstr); + return (String) + { + .len = len, + .text = (u8 *)cstr + }; } String StringFromCstr(char *cstr, u64 limit) { - u64 len = CstrLen(cstr, limit); - return (String) - { - .text = (u8 *)cstr, - .len = len - }; + u64 len = CstrLen(cstr, limit); + return (String) + { + .text = (u8 *)cstr, + .len = len + }; } //- Wide C strings u64 WstrLenNoLimit(wchar_t *wstr) { - wchar_t *end = wstr; - if (end) + wchar_t *end = wstr; + if (end) + { + while (*end) { - while (*end) - { - ++end; - } + ++end; } - return end - wstr; + } + return end - wstr; } u64 WstrLen(wchar_t *wstr, u64 limit) { - wchar_t *end = wstr; - if (wstr) + wchar_t *end = wstr; + if (wstr) + { + for (u64 i = 0; i < limit; ++i) { - for (u64 i = 0; i < limit; ++i) - { - if (*end) - { - ++end; - } - else - { - break; - } - } + if (*end) + { + ++end; + } + else + { + break; + } } - return end - wstr; + } + return end - wstr; } wchar_t *WstrFromString(Arena *arena, String src) { - String16 str16 = String16FromString(arena, src); - *PushStructNoZero(arena, u16) = 0; - return (wchar_t *)str16.text; + String16 str16 = String16FromString(arena, src); + *PushStructNoZero(arena, u16) = 0; + return (wchar_t *)str16.text; } wchar_t *WstrFromString16(Arena *arena, String16 src) { - u16 *text = PushStructsNoZero(arena, u16, src.len + 1); - text[src.len] = 0; - return (wchar_t *)text; + u16 *text = PushStructsNoZero(arena, u16, src.len + 1); + text[src.len] = 0; + return (wchar_t *)text; } String StringFromWstrNoLimit(Arena *arena, wchar_t *wstr) { - String16 str16 = String16FromWstrNoLimit(wstr); - return StringFromString16(arena, str16); + String16 str16 = String16FromWstrNoLimit(wstr); + return StringFromString16(arena, str16); } String StringFromWstr(Arena *arena, wchar_t *wstr, u64 limit) { - String16 str16 = String16FromWstr(wstr, limit); - return StringFromString16(arena, str16); + String16 str16 = String16FromWstr(wstr, limit); + return StringFromString16(arena, str16); } String16 String16FromWstrNoLimit(wchar_t *wstr) { - u64 len = WstrLenNoLimit(wstr); - return (String16) - { - .len = len, - .text = (u16 *)wstr - }; + u64 len = WstrLenNoLimit(wstr); + return (String16) + { + .len = len, + .text = (u16 *)wstr + }; } String16 String16FromWstr(wchar_t *wstr, u64 limit) { - u64 len = WstrLen(wstr, limit); - return (String16) - { - .len = len, - .text = (u16 *)wstr - }; + u64 len = WstrLen(wstr, limit); + return (String16) + { + .len = len, + .text = (u16 *)wstr + }; } diff --git a/src/base/base_string.h b/src/base/base_string.h index a0853bdd..e45a56fd 100644 --- a/src/base/base_string.h +++ b/src/base/base_string.h @@ -6,60 +6,60 @@ Enum(FmtArgKind) { - FmtArgKind_None, + FmtArgKind_None, - /* Arbitrary magic numbers for argument validation */ - FmtArgKind_Char = 0xf5281df, - FmtArgKind_String = 0xa5ffa9a, + /* Arbitrary magic numbers for argument validation */ + FmtArgKind_Char = 0xf5281df, + FmtArgKind_String = 0xa5ffa9a, - FmtArgKind_Uint = 0x746f19b, - FmtArgKind_Uint2 = 0x83429d9, - FmtArgKind_Uint3 = 0x1b4b749, - FmtArgKind_Uint4 = 0xf8eb3cf, + FmtArgKind_Uint = 0x746f19b, + FmtArgKind_Uint2 = 0x83429d9, + FmtArgKind_Uint3 = 0x1b4b749, + FmtArgKind_Uint4 = 0xf8eb3cf, - FmtArgKind_Sint = 0x8603694, - FmtArgKind_Sint2 = 0x335a803, - FmtArgKind_Sint3 = 0xe5e4ab1, - FmtArgKind_Sint4 = 0xe1fd7ad, + FmtArgKind_Sint = 0x8603694, + FmtArgKind_Sint2 = 0x335a803, + FmtArgKind_Sint3 = 0xe5e4ab1, + FmtArgKind_Sint4 = 0xe1fd7ad, - FmtArgKind_Float = 0x4814143, - FmtArgKind_Float2 = 0x4260065, - FmtArgKind_Float3 = 0x0d28ab7, - FmtArgKind_Float4 = 0x76fe314, + FmtArgKind_Float = 0x4814143, + FmtArgKind_Float2 = 0x4260065, + FmtArgKind_Float3 = 0x0d28ab7, + FmtArgKind_Float4 = 0x76fe314, - FmtArgKind_Hex = 0xa3d0792, - FmtArgKind_Ptr = 0xc4519e4, - FmtArgKind_Uid = 0xd1cd407, - FmtArgKind_Handle = 0xead3bec, + FmtArgKind_Hex = 0xa3d0792, + FmtArgKind_Ptr = 0xc4519e4, + FmtArgKind_Uid = 0xd1cd407, + FmtArgKind_Handle = 0xead3bec, - FmtArgKind_End = 0xecbc5ae + FmtArgKind_End = 0xecbc5ae }; Struct(FmtArg) { - FmtArgKind kind; - u32 p; /* Precision */ - u32 z; /* Z-fill */ - union + FmtArgKind kind; + u32 p; /* Precision */ + u32 z; /* Z-fill */ + union + { + u8 c; + String string; + Vec4U64 uints; + Vec4I64 sints; + Vec4F64 floats; + void *ptr; + Uid uid; + struct { - u8 c; - String string; - Vec4U64 uints; - Vec4I64 sints; - Vec4F64 floats; - void *ptr; - Uid uid; - struct - { - u64 h64[2]; - } handle; - } value; + u64 h64[2]; + } handle; + } value; }; Struct(FmtArgArray) { - u64 count; - FmtArg *args; + u64 count; + FmtArg *args; }; //////////////////////////////////////////////////////////// @@ -67,11 +67,11 @@ Struct(FmtArgArray) Struct(CodepointIter) { - u32 codepoint; + u32 codepoint; - /* Internal */ - String src; - u64 pos; + /* Internal */ + String src; + u64 pos; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_sync.c b/src/base/base_sync.c index 772c9290..648f3dba 100644 --- a/src/base/base_sync.c +++ b/src/base/base_sync.c @@ -4,135 +4,135 @@ //- Exclusive mutex lock Lock LockSpinE(Mutex *m, i32 spin) { - b32 locked = 0; - i32 spin_cnt = 0; - while (!locked) + b32 locked = 0; + i32 spin_cnt = 0; + while (!locked) + { + ++spin_cnt; + u32 v = Atomic32FetchTestSet(&m->v, 0, 0x80000000); + if (v == 0) { - ++spin_cnt; - u32 v = Atomic32FetchTestSet(&m->v, 0, 0x80000000); - if (v == 0) - { - locked = 1; - } - else if (v == 0x40000000) - { - /* Lock has pending bit set, try to lock */ - u32 swp = Atomic32FetchTestSet(&m->v, v, 0x80000000); - while (swp != v && swp == 0x40000000) - { - v = swp; - swp = Atomic32FetchTestSet(&m->v, v, 0x80000000); - } - v = swp; - if (v == 0x40000000) - { - locked = 1; - } - } - if (!locked && (v & 0xC0000000) == 0) - { - /* Lock has shared lockers and no pending waiter, set pending bit */ - u32 swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000); - while (swp != v && (swp & 0xC0000000) == 0 && swp != 0) - { - v = swp; - swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000); - } - v = swp; - } - /* Pause or wait */ - if (!locked && v != 0 && v != 0x40000000) - { - if (spin_cnt < spin) - { - _mm_pause(); - } - else - { - FutexYieldNeq(&m->v, &v, 4); - spin_cnt = 0; - } - } + locked = 1; } + else if (v == 0x40000000) + { + /* Lock has pending bit set, try to lock */ + u32 swp = Atomic32FetchTestSet(&m->v, v, 0x80000000); + while (swp != v && swp == 0x40000000) + { + v = swp; + swp = Atomic32FetchTestSet(&m->v, v, 0x80000000); + } + v = swp; + if (v == 0x40000000) + { + locked = 1; + } + } + if (!locked && (v & 0xC0000000) == 0) + { + /* Lock has shared lockers and no pending waiter, set pending bit */ + u32 swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000); + while (swp != v && (swp & 0xC0000000) == 0 && swp != 0) + { + v = swp; + swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000); + } + v = swp; + } + /* Pause or wait */ + if (!locked && v != 0 && v != 0x40000000) + { + if (spin_cnt < spin) + { + _mm_pause(); + } + else + { + FutexYieldNeq(&m->v, &v, 4); + spin_cnt = 0; + } + } + } -#if IsRtcEnabled - Atomic32Set(&m->exclusive_thread_id, ThreadId()); -#endif + #if IsRtcEnabled + Atomic32Set(&m->exclusive_thread_id, ThreadId()); + #endif - Lock lock = Zi; - lock.exclusive = 1; - lock.mutex = m; - return lock; + Lock lock = Zi; + lock.exclusive = 1; + lock.mutex = m; + return lock; } //- Shared mutex lock Lock LockSpinS(Mutex *m, i32 spin) { - b32 locked = 0; - i32 spin_cnt = 0; - while (!locked) + b32 locked = 0; + i32 spin_cnt = 0; + while (!locked) + { + ++spin_cnt; + u32 v = Atomic32Fetch(&m->v); + while (!locked && (v & 0xC0000000) == 0) { - ++spin_cnt; - u32 v = Atomic32Fetch(&m->v); - while (!locked && (v & 0xC0000000) == 0) - { - /* Lock has no exclusive or pending exclusive lock, increment shared count */ - u32 swp = Atomic32FetchTestSet(&m->v, v, v + 1); - if (v == swp) - { - locked = 1; - } - else - { - v = swp; - } - } - /* Pause or wait */ - if (!locked) - { - if (spin_cnt < spin) - { - _mm_pause(); - } - else - { - FutexYieldNeq(&m->v, &v, 4); - spin_cnt = 0; - } - } + /* Lock has no exclusive or pending exclusive lock, increment shared count */ + u32 swp = Atomic32FetchTestSet(&m->v, v, v + 1); + if (v == swp) + { + locked = 1; + } + else + { + v = swp; + } } - Lock lock = Zi; - lock.mutex = m; - return lock; + /* Pause or wait */ + if (!locked) + { + if (spin_cnt < spin) + { + _mm_pause(); + } + else + { + FutexYieldNeq(&m->v, &v, 4); + spin_cnt = 0; + } + } + } + Lock lock = Zi; + lock.mutex = m; + return lock; } //- Mutex lock wrappers Lock LockE(Mutex *m) { - return LockSpinE(m, DefaultMutexSpin); + return LockSpinE(m, DefaultMutexSpin); } Lock LockS(Mutex *m) { - return LockSpinS(m, DefaultMutexSpin); + return LockSpinS(m, DefaultMutexSpin); } void Unlock(Lock *l) { - Mutex *m = l->mutex; - if (l->exclusive) - { -#if IsRtcEnabled - Atomic32Set(&m->exclusive_thread_id, 0); -#endif - Atomic32Set(&m->v, 0); - } - else - { - Atomic32FetchAdd(&m->v, -1); - } - FutexWakeNeq(&m->v); - ZeroStruct(l); + Mutex *m = l->mutex; + if (l->exclusive) + { + #if IsRtcEnabled + Atomic32Set(&m->exclusive_thread_id, 0); + #endif + Atomic32Set(&m->v, 0); + } + else + { + Atomic32FetchAdd(&m->v, -1); + } + FutexWakeNeq(&m->v); + ZeroStruct(l); } //////////////////////////////////////////////////////////// @@ -140,29 +140,29 @@ void Unlock(Lock *l) void YieldOnCv(Cv *cv, Lock *l) { - u64 old_wake_gen = Atomic64Fetch(&cv->wake_gen); - Mutex *mutex = l->mutex; - b32 exclusive = l->exclusive; + u64 old_wake_gen = Atomic64Fetch(&cv->wake_gen); + Mutex *mutex = l->mutex; + b32 exclusive = l->exclusive; + { + Unlock(l); { - Unlock(l); - { - FutexYieldNeq(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen)); - } - if (exclusive) - { - *l = LockE(mutex); - } - else - { - *l = LockS(mutex); - } + FutexYieldNeq(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen)); } + if (exclusive) + { + *l = LockE(mutex); + } + else + { + *l = LockS(mutex); + } + } } void SignalCv(Cv *cv) { - Atomic64FetchAdd(&cv->wake_gen, 1); - FutexWakeNeq(&cv->wake_gen); + Atomic64FetchAdd(&cv->wake_gen, 1); + FutexWakeNeq(&cv->wake_gen); } //////////////////////////////////////////////////////////// @@ -170,36 +170,36 @@ void SignalCv(Cv *cv) i64 FetchFence(Fence *fence) { - return Atomic64Fetch(&fence->v.v); + return Atomic64Fetch(&fence->v.v); } void SetFence(Fence *fence, i64 x) { - Atomic64Set(&fence->v.v, x); - FutexWakeGte(&fence->v.v); + Atomic64Set(&fence->v.v, x); + FutexWakeGte(&fence->v.v); } i64 FetchSetFence(Fence *fence, i64 x) { - i64 fetch = Atomic64FetchSet(&fence->v.v, x); - FutexWakeGte(&fence->v.v); - return fetch; + i64 fetch = Atomic64FetchSet(&fence->v.v, x); + FutexWakeGte(&fence->v.v); + return fetch; } i64 FetchAddFence(Fence *fence, i64 x) { - i64 fetch = Atomic64FetchAdd(&fence->v.v, x); - FutexWakeGte(&fence->v.v); - return fetch; + i64 fetch = Atomic64FetchAdd(&fence->v.v, x); + FutexWakeGte(&fence->v.v); + return fetch; } i64 YieldOnFence(Fence *fence, i64 target) { - i64 v = Atomic64Fetch(&fence->v.v); - while (v < target) - { - FutexYieldGte(&fence->v.v, &v, sizeof(v)); - v = Atomic64Fetch(&fence->v.v); - } - return v; + i64 v = Atomic64Fetch(&fence->v.v); + while (v < target) + { + FutexYieldGte(&fence->v.v, &v, sizeof(v)); + v = Atomic64Fetch(&fence->v.v); + } + return v; } diff --git a/src/base/base_sync.h b/src/base/base_sync.h index 6afe0d19..81ea8676 100644 --- a/src/base/base_sync.h +++ b/src/base/base_sync.h @@ -53,11 +53,11 @@ void Unlock(Lock *lock); //- Lock assertion #if IsRtcEnabled -# define AssertLockedE(l, m) Assert((l)->mutex == (m) && (l)->exclusive == 1) -# define AssertLockedES(l, m) Assert((l)->mutex == (m)) + #define AssertLockedE(l, m) Assert((l)->mutex == (m) && (l)->exclusive == 1) + #define AssertLockedES(l, m) Assert((l)->mutex == (m)) #else -# define AssertLockedE(l, m) -# define AssertLockedES(l, m) + #define AssertLockedE(l, m) + #define AssertLockedES(l, m) #endif //////////////////////////////////////////////////////////// diff --git a/src/base/base_time.h b/src/base/base_time.h index 3f0009ca..697644b7 100644 --- a/src/base/base_time.h +++ b/src/base/base_time.h @@ -3,14 +3,14 @@ Struct(DateTime) { - u32 year; - u32 month; - u32 day_of_week; - u32 day; - u32 hour; - u32 minute; - u32 second; - u32 milliseconds; + u32 year; + u32 month; + u32 day_of_week; + u32 day; + u32 hour; + u32 minute; + u32 second; + u32 milliseconds; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_uid.c b/src/base/base_uid.c index 5eb0b911..ddef8b38 100644 --- a/src/base/base_uid.c +++ b/src/base/base_uid.c @@ -1,22 +1,22 @@ /* Returns a uid generated from the system's random number generator */ Uid UidFromTrueRand(void) { - Uid result = Zi; - TrueRand(StringFromStruct(&result)); - return result; + Uid result = Zi; + TrueRand(StringFromStruct(&result)); + return result; } /* Combines 2 uids into a new uid */ Uid CombineUid(Uid a, Uid b) { - Uid result; - result.hi = (a.hi * 3) + b.hi; - result.lo = (a.lo * 3) + b.lo; - result.hi += result.lo; - result.lo += result.hi; - result.hi = RandU64FromSeed(result.hi); - result.lo = RandU64FromSeed(result.lo); - result.hi += result.lo; - result.lo += result.hi; - return result; + Uid result; + result.hi = (a.hi * 3) + b.hi; + result.lo = (a.lo * 3) + b.lo; + result.hi += result.lo; + result.lo += result.hi; + result.hi = RandU64FromSeed(result.hi); + result.lo = RandU64FromSeed(result.lo); + result.hi += result.lo; + result.lo += result.hi; + return result; } diff --git a/src/base/base_uid.h b/src/base/base_uid.h index b5942963..cb01331e 100644 --- a/src/base/base_uid.h +++ b/src/base/base_uid.h @@ -3,8 +3,8 @@ Struct(Uid) { - u64 hi; - u64 lo; + u64 hi; + u64 lo; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_uni.c b/src/base/base_uni.c index 4ad19533..4c72ae2d 100644 --- a/src/base/base_uni.c +++ b/src/base/base_uni.c @@ -5,126 +5,130 @@ Utf8DecodeResult DecodeUtf8(String str) { - const u8 lengths[32] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5 - }; + const u8 lengths[32] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5 + }; - Utf8DecodeResult result = Zi; - u32 codepoint = U32Max; - u32 advance = 0; - if (str.len > 0) + Utf8DecodeResult result = Zi; + u32 codepoint = U32Max; + u32 advance = 0; + if (str.len > 0) + { + u8 c0 = str.text[0]; + u8 utf8_len = lengths[c0 >> 3]; + + advance = 1; + switch (utf8_len) { - u8 c0 = str.text[0]; - u8 utf8_len = lengths[c0 >> 3]; + default: break; - advance = 1; - switch (utf8_len) + case 1: + { + codepoint = c0; + } break; + + case 2: + { + if (str.len >= 2) { - default: break; - - case 1: - { - codepoint = c0; - } break; - - case 2: - { - if (str.len >= 2) - { - u8 c1 = str.text[1]; - if (lengths[c1 >> 3] == 0) - { - codepoint = (c1 & 0x3F) << 0; - codepoint |= (c0 & 0x1F) << 6; - advance = 2; - } - } - } break; - - case 3: - { - if (str.len >= 3) - { - u8 c1 = str.text[1]; - u8 c2 = str.text[2]; - if (lengths[c1 >> 3] == 0 && - lengths[c2 >> 3] == 0) - { - codepoint = (c2 & 0x3F) << 0; - codepoint |= (c1 & 0x3F) << 6; - codepoint |= (c0 & 0x0F) << 12; - advance = 3; - } - } - } break; - - case 4: - { - if (str.len >= 4) - { - u8 c1 = str.text[1]; - u8 c2 = str.text[2]; - u8 c3 = str.text[3]; - if (lengths[c1 >> 3] == 0 && - lengths[c2 >> 3] == 0 && - lengths[c3 >> 3] == 0) - { - codepoint = (c3 & 0x3F) << 0; - codepoint |= (c2 & 0x3F) << 6; - codepoint |= (c1 & 0x3F) << 12; - codepoint |= (c0 & 0x07) << 16; - advance = 3; - } - } - } break; + u8 c1 = str.text[1]; + if (lengths[c1 >> 3] == 0) + { + codepoint = (c1 & 0x3F) << 0; + codepoint |= (c0 & 0x1F) << 6; + advance = 2; + } } - } + } break; - result.advance8 = advance; - result.codepoint = codepoint; - return result; + case 3: + { + if (str.len >= 3) + { + u8 c1 = str.text[1]; + u8 c2 = str.text[2]; + if ( + lengths[c1 >> 3] == 0 && + lengths[c2 >> 3] == 0 + ) + { + codepoint = (c2 & 0x3F) << 0; + codepoint |= (c1 & 0x3F) << 6; + codepoint |= (c0 & 0x0F) << 12; + advance = 3; + } + } + } break; + + case 4: + { + if (str.len >= 4) + { + u8 c1 = str.text[1]; + u8 c2 = str.text[2]; + u8 c3 = str.text[3]; + if ( + lengths[c1 >> 3] == 0 && + lengths[c2 >> 3] == 0 && + lengths[c3 >> 3] == 0 + ) + { + codepoint = (c3 & 0x3F) << 0; + codepoint |= (c2 & 0x3F) << 6; + codepoint |= (c1 & 0x3F) << 12; + codepoint |= (c0 & 0x07) << 16; + advance = 3; + } + } + } break; + } + } + + result.advance8 = advance; + result.codepoint = codepoint; + return result; } //- Encode Utf8EncodeResult EncodeUtf8(u32 codepoint) { - Utf8EncodeResult result = Zi; + Utf8EncodeResult result = Zi; - if (codepoint <= 0x7F) - { - result.count8 = 1; - result.chars8[0] = codepoint; - } - else if (codepoint <= 0x7FF) - { - result.count8 = 2; - result.chars8[1] = 0x80 | ((codepoint >> 0) & 0x3F); - result.chars8[0] = 0xC0 | ((codepoint >> 6) & 0x1F); - } - else if (codepoint <= 0xFFFF) - { - result.count8 = 3; - result.chars8[2] = 0x80 | ((codepoint >> 0) & 0x3F); - result.chars8[1] = 0x80 | ((codepoint >> 6) & 0x3F); - result.chars8[0] = 0xE0 | ((codepoint >> 12) & 0x0F); - } - else if (codepoint <= 0x10FFFF) - { - result.count8 = 4; - result.chars8[3] = 0x80 | ((codepoint >> 0) & 0x3F); - result.chars8[2] = 0x80 | ((codepoint >> 6) & 0x3F); - result.chars8[1] = 0x80 | ((codepoint >> 12) & 0x3F); - result.chars8[0] = 0xF0 | ((codepoint >> 18) & 0x07); - } - else - { - /* Invalid codepoint */ - result.count8 = 1; - result.chars8[0] = '?'; - } + if (codepoint <= 0x7F) + { + result.count8 = 1; + result.chars8[0] = codepoint; + } + else if (codepoint <= 0x7FF) + { + result.count8 = 2; + result.chars8[1] = 0x80 | ((codepoint >> 0) & 0x3F); + result.chars8[0] = 0xC0 | ((codepoint >> 6) & 0x1F); + } + else if (codepoint <= 0xFFFF) + { + result.count8 = 3; + result.chars8[2] = 0x80 | ((codepoint >> 0) & 0x3F); + result.chars8[1] = 0x80 | ((codepoint >> 6) & 0x3F); + result.chars8[0] = 0xE0 | ((codepoint >> 12) & 0x0F); + } + else if (codepoint <= 0x10FFFF) + { + result.count8 = 4; + result.chars8[3] = 0x80 | ((codepoint >> 0) & 0x3F); + result.chars8[2] = 0x80 | ((codepoint >> 6) & 0x3F); + result.chars8[1] = 0x80 | ((codepoint >> 12) & 0x3F); + result.chars8[0] = 0xF0 | ((codepoint >> 18) & 0x07); + } + else + { + /* Invalid codepoint */ + result.count8 = 1; + result.chars8[0] = '?'; + } - return result; + return result; } //////////////////////////////////////////////////////////// @@ -134,69 +138,69 @@ Utf8EncodeResult EncodeUtf8(u32 codepoint) Utf16DecodeResult DecodeUtf16(String16 str) { - Utf16DecodeResult result = Zi; - u32 codepoint = U32Max; - u32 advance = 0; + Utf16DecodeResult result = Zi; + u32 codepoint = U32Max; + u32 advance = 0; - if (str.len >= 1) + if (str.len >= 1) + { + u16 c0 = str.text[0]; + codepoint = c0; + advance = 1; + if (str.len >= 2) { - u16 c0 = str.text[0]; - codepoint = c0; - advance = 1; - if (str.len >= 2) - { - u16 c1 = str.text[1]; - if ((0xD800 <= c0 && c0 < 0xDC00) && (0xDC00 <= c1 && c1 < 0xE000)) - { - codepoint = (c1 & 0x3FF) << 0; - codepoint |= (c0 & 0x3FF) << 10; - advance = 2; - } - } + u16 c1 = str.text[1]; + if ((0xD800 <= c0 && c0 < 0xDC00) && (0xDC00 <= c1 && c1 < 0xE000)) + { + codepoint = (c1 & 0x3FF) << 0; + codepoint |= (c0 & 0x3FF) << 10; + advance = 2; + } } + } - result.advance16 = advance; - result.codepoint = codepoint; - return result; + result.advance16 = advance; + result.codepoint = codepoint; + return result; } //- Encode Utf16EncodeResult EncodeUtf16(u32 codepoint) { - Utf16EncodeResult result = Zi; + Utf16EncodeResult result = Zi; - if (codepoint <= 0xFFFF) - { - result.count16 = 1; - result.chars16[0] = codepoint; - } - else if (codepoint <= 0x10FFFF) - { - result.count16 = 2; - result.chars16[1] = 0xDC00 | ((codepoint >> 0) & 0x3FF); - result.chars16[0] = 0xD800 | ((codepoint >> 10) & 0x3FF); - } - else - { - /* Invalid codepoint */ - result.count16 = 1; - result.chars16[0] = '?'; - } + if (codepoint <= 0xFFFF) + { + result.count16 = 1; + result.chars16[0] = codepoint; + } + else if (codepoint <= 0x10FFFF) + { + result.count16 = 2; + result.chars16[1] = 0xDC00 | ((codepoint >> 0) & 0x3FF); + result.chars16[0] = 0xD800 | ((codepoint >> 10) & 0x3FF); + } + else + { + /* Invalid codepoint */ + result.count16 = 1; + result.chars16[0] = '?'; + } - return result; + return result; } //- Surrogate check b32 IsUtf16HighSurrogate(u16 c) { - return 0xD800 <= c && c < 0xDC00; + return 0xD800 <= c && c < 0xDC00; } b32 IsUtf16LowSurrogate(u16 c) { - return 0xDC00 <= c && c < 0xE000; + return 0xDC00 <= c && c < 0xE000; } //////////////////////////////////////////////////////////// @@ -206,40 +210,40 @@ b32 IsUtf16LowSurrogate(u16 c) Utf32DecodeResult DecodeUtf32(String32 str) { - Utf32DecodeResult result = Zi; - u32 codepoint = U32Max; - u32 advance = 0; + Utf32DecodeResult result = Zi; + u32 codepoint = U32Max; + u32 advance = 0; - if (str.len >= 1) + if (str.len >= 1) + { + u32 c = str.text[0]; + advance = 1; + if (c <= 0x10FFFF) { - u32 c = str.text[0]; - advance = 1; - if (c <= 0x10FFFF) - { - codepoint = c; - } + codepoint = c; } + } - result.advance32 = advance; - result.codepoint = codepoint; - return result; + result.advance32 = advance; + result.codepoint = codepoint; + return result; } //- Encode Utf32EncodeResult EncodeUtf32(u32 codepoint) { - Utf32EncodeResult result = Zi; + Utf32EncodeResult result = Zi; - if (codepoint <= 0x10FFFF) - { - result.chars32 = codepoint; - } - else - { - /* Invalid codepoint */ - result.chars32 = '?'; - } + if (codepoint <= 0x10FFFF) + { + result.chars32 = codepoint; + } + else + { + /* Invalid codepoint */ + result.chars32 = '?'; + } - return result; + return result; } diff --git a/src/base/base_uni.h b/src/base/base_uni.h index 5a354dae..cf0f62b8 100644 --- a/src/base/base_uni.h +++ b/src/base/base_uni.h @@ -3,14 +3,14 @@ Struct(Utf8DecodeResult) { - u32 advance8; - u32 codepoint; + u32 advance8; + u32 codepoint; }; Struct(Utf8EncodeResult) { - u32 count8; - u8 chars8[4]; + u32 count8; + u8 chars8[4]; }; //////////////////////////////////////////////////////////// @@ -18,14 +18,14 @@ Struct(Utf8EncodeResult) Struct(Utf16DecodeResult) { - u32 advance16; - u32 codepoint; + u32 advance16; + u32 codepoint; }; Struct(Utf16EncodeResult) { - u32 count16; - u16 chars16[2]; + u32 count16; + u16 chars16[2]; }; //////////////////////////////////////////////////////////// @@ -33,13 +33,13 @@ Struct(Utf16EncodeResult) Struct(Utf32DecodeResult) { - u32 advance32; - u32 codepoint; + u32 advance32; + u32 codepoint; }; Struct(Utf32EncodeResult) { - u32 chars32; + u32 chars32; }; //////////////////////////////////////////////////////////// diff --git a/src/base/base_util.h b/src/base/base_util.h index b94ebb74..8e4fa106 100644 --- a/src/base/base_util.h +++ b/src/base/base_util.h @@ -19,27 +19,27 @@ typedef MergesortCompareFuncDef(MergesortCompareFunc, a, b, udata); Struct(DictEntry) { - u64 hash; - u64 value; - DictEntry *prev_in_bin; - DictEntry *next_in_bin; - DictEntry *prev; - DictEntry *next; + u64 hash; + u64 value; + DictEntry *prev_in_bin; + DictEntry *next_in_bin; + DictEntry *prev; + DictEntry *next; }; Struct(DictBin) { - DictEntry *first; - DictEntry *last; + DictEntry *first; + DictEntry *last; }; Struct(Dict) { - u64 bins_count; - DictBin *bins; - DictEntry *first_free; - DictEntry *first; - DictEntry *last; + u64 bins_count; + DictBin *bins; + DictEntry *first_free; + DictEntry *first; + DictEntry *last; }; //////////////////////////////////////////////////////////// @@ -50,31 +50,31 @@ Struct(Dict) */ Inline u64 HashFnv64(u64 seed, String s) { - u64 hash = seed; - for (u64 i = 0; i < s.len; ++i) - { - hash ^= (u8)s.text[i]; - hash *= 0x100000001B3; - } - return hash; + u64 hash = seed; + for (u64 i = 0; i < s.len; ++i) + { + hash ^= (u8)s.text[i]; + hash *= 0x100000001B3; + } + return hash; } #define HashF(fmt_cstr, ...) HashF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd) Inline u64 HashF_(String fmt, ...) { - u64 result = 0; - TempArena scratch = BeginScratchNoConflict(); + u64 result = 0; + TempArena scratch = BeginScratchNoConflict(); + { + va_list args; + va_start(args, fmt); { - va_list args; - va_start(args, fmt); - { - String str = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args)); - result = HashFnv64(Fnv64Basis, str); - } - va_end(args); + String str = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args)); + result = HashFnv64(Fnv64Basis, str); } - EndScratch(scratch); - return result; + va_end(args); + } + EndScratch(scratch); + return result; } //////////////////////////////////////////////////////////// @@ -82,67 +82,67 @@ Inline u64 HashF_(String fmt, ...) Inline void MergesortInternal(u8 *left, u8 *right, u8 *items, u64 left_count, u64 right_count, u64 item_size, MergesortCompareFunc *callback, void *udata) { - /* Sort */ - u64 i = 0; - u64 l = 0; - u64 r = 0; - while (l < left_count && r < right_count) + /* Sort */ + u64 i = 0; + u64 l = 0; + u64 r = 0; + while (l < left_count && r < right_count) + { + u8 *dst = items + (i * item_size); + u8 *left_item = left + (l * item_size); + u8 *right_item = right + (r * item_size); + ++i; + if (callback(left_item, right_item, udata) > 0) { - u8 *dst = items + (i * item_size); - u8 *left_item = left + (l * item_size); - u8 *right_item = right + (r * item_size); - ++i; - if (callback(left_item, right_item, udata) > 0) - { - CopyBytes(dst, left_item, item_size); - ++l; - } - else - { - CopyBytes(dst, right_item, item_size); - ++r; - } + CopyBytes(dst, left_item, item_size); + ++l; } - /* Copy remaining */ - if (l != left_count) + else { - u64 remaining_count = left_count - l; - u64 remaining_bytes = remaining_count * item_size; - u8 *dst = items + (i * item_size); - u8 *src = left + (l * item_size); - CopyBytes(dst, src, remaining_bytes); - } - else if (r != right_count) - { - u64 remaining_count = right_count - r; - u64 remaining_bytes = remaining_count * item_size; - u8 *dst = items + (i * item_size); - u8 *src = right + (r * item_size); - CopyBytes(dst, src, remaining_bytes); + CopyBytes(dst, right_item, item_size); + ++r; } + } + /* Copy remaining */ + if (l != left_count) + { + u64 remaining_count = left_count - l; + u64 remaining_bytes = remaining_count * item_size; + u8 *dst = items + (i * item_size); + u8 *src = left + (l * item_size); + CopyBytes(dst, src, remaining_bytes); + } + else if (r != right_count) + { + u64 remaining_count = right_count - r; + u64 remaining_bytes = remaining_count * item_size; + u8 *dst = items + (i * item_size); + u8 *src = right + (r * item_size); + CopyBytes(dst, src, remaining_bytes); + } } Inline void Mergesort(void *items, u64 item_count, u64 item_size, MergesortCompareFunc *callback, void *udata) { - if (item_count > 1) - { - TempArena scratch = BeginScratchNoConflict(); - u64 left_count = item_count / 2; - u64 right_count = item_count - left_count; + if (item_count > 1) + { + TempArena scratch = BeginScratchNoConflict(); + u64 left_count = item_count / 2; + u64 right_count = item_count - left_count; - u64 left_size = left_count * item_size; - u64 right_size = right_count * item_size; + u64 left_size = left_count * item_size; + u64 right_size = right_count * item_size; - u8 *left = PushStructsNoZero(scratch.arena, u8, left_size); - u8 *right = PushStructsNoZero(scratch.arena, u8, right_size); - CopyBytes(left, items, left_size); - CopyBytes(right, (u8 *)items + left_size, right_size); + u8 *left = PushStructsNoZero(scratch.arena, u8, left_size); + u8 *right = PushStructsNoZero(scratch.arena, u8, right_size); + CopyBytes(left, items, left_size); + CopyBytes(right, (u8 *)items + left_size, right_size); - Mergesort(left, left_count, item_size, callback, udata); - Mergesort(right, right_count, item_size, callback, udata); - MergesortInternal(left, right, (u8 *)items, left_count, right_count, item_size, callback, udata); - EndScratch(scratch); - } + Mergesort(left, left_count, item_size, callback, udata); + Mergesort(right, right_count, item_size, callback, udata); + MergesortInternal(left, right, (u8 *)items, left_count, right_count, item_size, callback, udata); + EndScratch(scratch); + } } //////////////////////////////////////////////////////////// @@ -152,164 +152,164 @@ Inline void Mergesort(void *items, u64 item_count, u64 item_size, MergesortCompa Inline Dict *InitDict(Arena *arena, u64 bins_count) { - Dict *dict = PushStruct(arena, Dict); - dict->bins_count = MaxU64(bins_count, 1); /* Ensure at least 1 bin */ - dict->bins = PushStructs(arena, DictBin, dict->bins_count); - return dict; + Dict *dict = PushStruct(arena, Dict); + dict->bins_count = MaxU64(bins_count, 1); /* Ensure at least 1 bin */ + dict->bins = PushStructs(arena, DictBin, dict->bins_count); + return dict; } Inline void ResetDict(Dict *dict) { - ZeroBytes(dict->bins, sizeof(*dict->bins) * dict->bins_count); - if (dict->first) - { - dict->last->next = dict->first_free; - dict->first_free = dict->first; - } + ZeroBytes(dict->bins, sizeof(*dict->bins) * dict->bins_count); + if (dict->first) + { + dict->last->next = dict->first_free; + dict->first_free = dict->first; + } } //- Dict set Inline DictEntry *EnsureDictEntry(Arena *arena, Dict *dict, u64 hash) { - DictBin *bin = &dict->bins[hash % dict->bins_count]; + DictBin *bin = &dict->bins[hash % dict->bins_count]; - DictEntry *entry = bin->first; - while (entry) + DictEntry *entry = bin->first; + while (entry) + { + if (hash == entry->hash) { - if (hash == entry->hash) - { - /* Existing match found */ - break; - } - entry = entry->next_in_bin; + /* Existing match found */ + break; } + entry = entry->next_in_bin; + } - /* No match found, create new entry */ - if (!entry) + /* No match found, create new entry */ + if (!entry) + { + if (dict->first_free) { - if (dict->first_free) - { - entry = dict->first_free; - dict->first_free = entry->next; - } - else - { - entry = PushStructNoZero(arena, DictEntry); - } - ZeroStruct(entry); - entry->hash = hash; - if (bin->last) - { - bin->last->next_in_bin = entry; - entry->prev_in_bin = bin->last; - } - else - { - bin->first = entry; - } - bin->last = entry; - if (dict->last) - { - dict->last->next = entry; - entry->prev = dict->last; - } - else - { - dict->first = entry; - } - dict->last = entry; + entry = dict->first_free; + dict->first_free = entry->next; } + else + { + entry = PushStructNoZero(arena, DictEntry); + } + ZeroStruct(entry); + entry->hash = hash; + if (bin->last) + { + bin->last->next_in_bin = entry; + entry->prev_in_bin = bin->last; + } + else + { + bin->first = entry; + } + bin->last = entry; + if (dict->last) + { + dict->last->next = entry; + entry->prev = dict->last; + } + else + { + dict->first = entry; + } + dict->last = entry; + } - return entry; + return entry; } Inline void SetDictValue(Arena *arena, Dict *dict, u64 hash, u64 value) { - DictEntry *entry = EnsureDictEntry(arena, dict, hash); - entry->value = value; + DictEntry *entry = EnsureDictEntry(arena, dict, hash); + entry->value = value; } //- Dict remove Inline void RemoveDictEntry(Dict *dict, DictEntry *entry) { - /* Remove from bin */ + /* Remove from bin */ + { + DictBin *bin = &dict->bins[entry->hash % dict->bins_count]; + DictEntry *prev_in_bin = entry->prev_in_bin; + DictEntry *next_in_bin = entry->next_in_bin; + if (prev_in_bin) { - DictBin *bin = &dict->bins[entry->hash % dict->bins_count]; - DictEntry *prev_in_bin = entry->prev_in_bin; - DictEntry *next_in_bin = entry->next_in_bin; - if (prev_in_bin) - { - prev_in_bin->next_in_bin = next_in_bin; - } - else - { - bin->first = next_in_bin; - } - if (next_in_bin) - { - next_in_bin->prev_in_bin = prev_in_bin; - } - else - { - bin->last = prev_in_bin; - } + prev_in_bin->next_in_bin = next_in_bin; } - /* Remove from list */ + else { - DictEntry *prev = entry->prev; - DictEntry *next = entry->next; - if (prev) - { - prev->next = next; - } - else - { - dict->first = next; - } - if (next) - { - next->prev = prev; - } - else - { - dict->last = prev; - } + bin->first = next_in_bin; } - /* Insert into free list */ + if (next_in_bin) { - entry->next = dict->first_free; - dict->first_free = entry; + next_in_bin->prev_in_bin = prev_in_bin; } + else + { + bin->last = prev_in_bin; + } + } + /* Remove from list */ + { + DictEntry *prev = entry->prev; + DictEntry *next = entry->next; + if (prev) + { + prev->next = next; + } + else + { + dict->first = next; + } + if (next) + { + next->prev = prev; + } + else + { + dict->last = prev; + } + } + /* Insert into free list */ + { + entry->next = dict->first_free; + dict->first_free = entry; + } } //- Dict index Inline DictEntry *DictEntryFromHash(Dict *dict, u64 hash) { - DictEntry *result = 0; - DictBin *bin = &dict->bins[hash % dict->bins_count]; - for (DictEntry *entry = bin->first; entry; entry = entry->next_in_bin) + DictEntry *result = 0; + DictBin *bin = &dict->bins[hash % dict->bins_count]; + for (DictEntry *entry = bin->first; entry; entry = entry->next_in_bin) + { + if (hash == entry->hash) { - if (hash == entry->hash) - { - /* Match found */ - result = entry; - break; - } + /* Match found */ + result = entry; + break; } - return result; + } + return result; } Inline u64 DictValueFromHash(Dict *dict, u64 hash) { - DictEntry *entry = DictEntryFromHash(dict, hash); - return entry ? entry->value : 0; + DictEntry *entry = DictEntryFromHash(dict, hash); + return entry ? entry->value : 0; } Inline u64 DictValueOrNilFromHash(Dict *dict, u64 hash, u64 nil) { - DictEntry *entry = DictEntryFromHash(dict, hash); - return entry ? entry->value : nil; + DictEntry *entry = DictEntryFromHash(dict, hash); + return entry ? entry->value : nil; } diff --git a/src/base/base_wave.c b/src/base/base_wave.c index 500b24b0..b9fc02ac 100644 --- a/src/base/base_wave.c +++ b/src/base/base_wave.c @@ -3,108 +3,108 @@ void WaveSyncEx(WaveLaneCtx *lane, u64 spin_count) { - WaveCtx *wave = lane->wave; - i32 lanes_count = wave->lanes_count; - if (lanes_count > 1) + WaveCtx *wave = lane->wave; + i32 lanes_count = wave->lanes_count; + if (lanes_count > 1) + { + i64 sync_gen = Atomic64Fetch(&wave->sync_gen.v); + i32 blocked_count = Atomic32FetchAdd(&wave->sync_count.v, 1) + 1; + if (blocked_count == lanes_count) { - i64 sync_gen = Atomic64Fetch(&wave->sync_gen.v); - i32 blocked_count = Atomic32FetchAdd(&wave->sync_count.v, 1) + 1; - if (blocked_count == lanes_count) + Atomic32Set(&wave->sync_count.v, 0); + Atomic64Set(&wave->sync_gen.v, sync_gen + 1); + FutexWakeNeq(&wave->sync_gen.v); + } + else + { + u64 remaining_spins = spin_count; + while (Atomic64Fetch(&wave->sync_gen.v) == sync_gen) + { + if (remaining_spins > 0) { - Atomic32Set(&wave->sync_count.v, 0); - Atomic64Set(&wave->sync_gen.v, sync_gen + 1); - FutexWakeNeq(&wave->sync_gen.v); + --remaining_spins; + _mm_pause(); } else { - u64 remaining_spins = spin_count; - while (Atomic64Fetch(&wave->sync_gen.v) == sync_gen) - { - if (remaining_spins > 0) - { - --remaining_spins; - _mm_pause(); - } - else - { - FutexYieldNeq(&wave->sync_gen.v, &sync_gen, sizeof(sync_gen)); - } - } + FutexYieldNeq(&wave->sync_gen.v, &sync_gen, sizeof(sync_gen)); } + } } + } } void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broadcast_ptr, u64 broadcast_size, u64 spin_count) { - WaveCtx *wave = lane->wave; - i32 lanes_count = wave->lanes_count; - if (lanes_count > 1) + WaveCtx *wave = lane->wave; + i32 lanes_count = wave->lanes_count; + if (lanes_count > 1) + { + u32 lane_idx = lane->idx; + + if (lane_idx == broadcast_lane_idx) { - u32 lane_idx = lane->idx; + /* Broadcast */ + wave->broadcast_data = broadcast_ptr; + i64 ack_gen = Atomic64Fetch(&wave->ack_gen.v); + lane->seen_broadcast_gen = Atomic64FetchAdd(&wave->broadcast_gen.v, 1) + 1; + FutexWakeNeq(&wave->broadcast_gen.v); - if (lane_idx == broadcast_lane_idx) + /* Wait for ack */ + { + u64 remaining_spins = spin_count; + while (Atomic64Fetch(&wave->ack_gen.v) == ack_gen) { - /* Broadcast */ - wave->broadcast_data = broadcast_ptr; - i64 ack_gen = Atomic64Fetch(&wave->ack_gen.v); - lane->seen_broadcast_gen = Atomic64FetchAdd(&wave->broadcast_gen.v, 1) + 1; - FutexWakeNeq(&wave->broadcast_gen.v); - - /* Wait for ack */ - { - u64 remaining_spins = spin_count; - while (Atomic64Fetch(&wave->ack_gen.v) == ack_gen) - { - if (remaining_spins > 0) - { - --remaining_spins; - _mm_pause(); - } - else - { - FutexYieldNeq(&wave->ack_gen.v, &ack_gen, sizeof(ack_gen)); - } - } - } - } - else - { - /* Wait for broadcast */ - i64 seen_broadcast_gen = lane->seen_broadcast_gen++; - { - u64 remaining_spins = spin_count; - while (Atomic64Fetch(&wave->broadcast_gen.v) == seen_broadcast_gen) - { - if (remaining_spins > 0) - { - --remaining_spins; - _mm_pause(); - } - else - { - FutexYieldNeq(&wave->broadcast_gen.v, &seen_broadcast_gen, sizeof(seen_broadcast_gen)); - } - } - } - - /* Copy broadcast data */ - CopyBytes(broadcast_ptr, wave->broadcast_data, broadcast_size); - - /* Ack */ - i32 ack_count = Atomic32FetchAdd(&wave->ack_count.v, 1) + 1; - if (ack_count == lanes_count - 1) - { - Atomic32Set(&wave->ack_count.v, 0); - Atomic64FetchAdd(&wave->ack_gen.v, 1); - FutexWakeNeq(&wave->ack_gen.v); - } + if (remaining_spins > 0) + { + --remaining_spins; + _mm_pause(); + } + else + { + FutexYieldNeq(&wave->ack_gen.v, &ack_gen, sizeof(ack_gen)); + } } + } } + else + { + /* Wait for broadcast */ + i64 seen_broadcast_gen = lane->seen_broadcast_gen++; + { + u64 remaining_spins = spin_count; + while (Atomic64Fetch(&wave->broadcast_gen.v) == seen_broadcast_gen) + { + if (remaining_spins > 0) + { + --remaining_spins; + _mm_pause(); + } + else + { + FutexYieldNeq(&wave->broadcast_gen.v, &seen_broadcast_gen, sizeof(seen_broadcast_gen)); + } + } + } + + /* Copy broadcast data */ + CopyBytes(broadcast_ptr, wave->broadcast_data, broadcast_size); + + /* Ack */ + i32 ack_count = Atomic32FetchAdd(&wave->ack_count.v, 1) + 1; + if (ack_count == lanes_count - 1) + { + Atomic32Set(&wave->ack_count.v, 0); + Atomic64FetchAdd(&wave->ack_gen.v, 1); + FutexWakeNeq(&wave->ack_gen.v); + } + } + } } void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n) { - lane->default_spin_count = n; + lane->default_spin_count = n; } //////////////////////////////////////////////////////////// @@ -112,30 +112,30 @@ void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n) i32 WaveLaneIdxFromTaskIdx(WaveLaneCtx *lane, u64 task_idx) { - WaveCtx *wave = lane->wave; - return task_idx % wave->lanes_count; + WaveCtx *wave = lane->wave; + return task_idx % wave->lanes_count; } RngU64 WaveIdxRangeFromCount(WaveLaneCtx *lane, u64 tasks_count) { - u64 lanes_count = lane->wave->lanes_count; - u64 lane_idx = lane->idx; + u64 lanes_count = lane->wave->lanes_count; + u64 lane_idx = lane->idx; - u64 tasks_per_lane = tasks_count / lanes_count; - u64 tasks_overflow = tasks_count % lanes_count; + u64 tasks_per_lane = tasks_count / lanes_count; + u64 tasks_overflow = tasks_count % lanes_count; - u64 start = lane_idx * tasks_per_lane; - u64 end = start + tasks_per_lane; - if (lane_idx < tasks_overflow) - { - start += lane_idx; - end += lane_idx + 1; - } - else - { - start += tasks_overflow; - end += tasks_overflow; - } + u64 start = lane_idx * tasks_per_lane; + u64 end = start + tasks_per_lane; + if (lane_idx < tasks_overflow) + { + start += lane_idx; + end += lane_idx + 1; + } + else + { + start += tasks_overflow; + end += tasks_overflow; + } - return RNGU64(start, end); + return RNGU64(start, end); } diff --git a/src/base/base_wave.h b/src/base/base_wave.h index 3b24378c..2fd3adfe 100644 --- a/src/base/base_wave.h +++ b/src/base/base_wave.h @@ -6,26 +6,26 @@ AlignedStruct(WaveCtx, CachelineSize) { - i32 lanes_count; - void *udata; + i32 lanes_count; + void *udata; - /* Sync barrier */ - Atomic32Padded sync_count; - Atomic64Padded sync_gen; + /* Sync barrier */ + Atomic32Padded sync_count; + Atomic64Padded sync_gen; - /* Broadcast barrier */ - void *broadcast_data; - Atomic64Padded broadcast_gen; - Atomic32Padded ack_count; - Atomic64Padded ack_gen; + /* Broadcast barrier */ + void *broadcast_data; + Atomic64Padded broadcast_gen; + Atomic32Padded ack_count; + Atomic64Padded ack_gen; }; AlignedStruct(WaveLaneCtx, CachelineSize) { - i32 idx; - WaveCtx *wave; - u64 default_spin_count; - i64 seen_broadcast_gen; + i32 idx; + WaveCtx *wave; + u64 default_spin_count; + i64 seen_broadcast_gen; }; typedef void WaveLaneEntryFunc(WaveLaneCtx *lane); @@ -34,14 +34,16 @@ typedef void WaveLaneEntryFunc(WaveLaneCtx *lane); //~ Wave sync ops void WaveSyncEx(WaveLaneCtx *lane, u64 spin_count); -#define WaveSync(lane) \ - WaveSyncEx((lane), (lane)->default_spin_count) - void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broadcast_ptr, u64 broadcast_size, u64 spin_count); + +#define WaveSync(lane) \ + WaveSyncEx((lane), (lane)->default_spin_count) + #define WaveSyncBroadcastEx(lane, broadcast_lane_idx, broadcast_ptr, spin_count) \ - WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (spin_count)) + WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (spin_count)) + #define WaveSyncBroadcast(lane, broadcast_lane_idx, broadcast_ptr) \ - WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (lane)->default_spin_count) + WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (lane)->default_spin_count) void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n); diff --git a/src/base/base_win32/base_win32.c b/src/base/base_win32/base_win32.c index 8f0eabc7..03470f07 100644 --- a/src/base/base_win32/base_win32.c +++ b/src/base/base_win32/base_win32.c @@ -5,34 +5,34 @@ W32_Ctx W32 = Zi; BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata) { - W32_FindEmbeddedDataCtx *ctx = (W32_FindEmbeddedDataCtx *)udata; - TempArena scratch = BeginScratchNoConflict(); - String entry_name = StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name); - String embedded_data_prefix = Lit(Stringize(W32_EmbeddedDataPrefix)); - if (StringBeginsWith(entry_name, embedded_data_prefix)) + W32_FindEmbeddedDataCtx *ctx = (W32_FindEmbeddedDataCtx *)udata; + TempArena scratch = BeginScratchNoConflict(); + String entry_name = StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name); + String embedded_data_prefix = Lit(Stringize(W32_EmbeddedDataPrefix)); + if (StringBeginsWith(entry_name, embedded_data_prefix)) + { + HRSRC hres = FindResourceW(module, wstr_entry_name, type); + if (hres) { - HRSRC hres = FindResourceW(module, wstr_entry_name, type); - if (hres) + HGLOBAL hg = LoadResource(module, hres); + if (hg) + { + if (ctx->embedded_strings_count < countof(ctx->embedded_strings)) { - HGLOBAL hg = LoadResource(module, hres); - if (hg) - { - if (ctx->embedded_strings_count < countof(ctx->embedded_strings)) - { - String embedded = Zi; - embedded.len = SizeofResource(module, hres); - embedded.text = LockResource(hg); - ctx->embedded_strings[ctx->embedded_strings_count++] = embedded; - } - else - { - Panic(Lit("Maximum number of embedded resource entries exceeded")); - } - } + String embedded = Zi; + embedded.len = SizeofResource(module, hres); + embedded.text = LockResource(hg); + ctx->embedded_strings[ctx->embedded_strings_count++] = embedded; } + else + { + Panic(Lit("Maximum number of embedded resource entries exceeded")); + } + } } - EndScratch(scratch); - return 1; + } + EndScratch(scratch); + return 1; } //////////////////////////////////////////////////////////// @@ -40,141 +40,141 @@ BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name StringList GetRawCommandline(void) { - return W32.raw_command_line; + return W32.raw_command_line; } void Echo(String msg) { - HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE); - if (console_handle && console_handle != INVALID_HANDLE_VALUE) - { - WriteFile(console_handle, msg.text, msg.len, 0, 0); - } - else if (IsRunningInDebugger()) - { - char msg_cstr[16384]; - u64 len = MinU64(countof(msg_cstr) - 1, msg.len); - CopyBytes(msg_cstr, msg.text, len); - msg_cstr[len] = 0; - OutputDebugStringA(msg_cstr); - } + HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (console_handle && console_handle != INVALID_HANDLE_VALUE) + { + WriteFile(console_handle, msg.text, msg.len, 0, 0); + } + else if (IsRunningInDebugger()) + { + char msg_cstr[16384]; + u64 len = MinU64(countof(msg_cstr) - 1, msg.len); + CopyBytes(msg_cstr, msg.text, len); + msg_cstr[len] = 0; + OutputDebugStringA(msg_cstr); + } } b32 Panic(String msg) { - LogPanic(msg); - char msg_cstr[4096]; - CstrFromStringToBuff(StringFromFixedArray(msg_cstr), msg); - { - u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR; - MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0); - } - HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE); - if (console_handle != INVALID_HANDLE_VALUE) - { - WriteFile(console_handle, msg.text, msg.len, 0, 0); - } - if (IsRunningInDebugger()) - { - Assert(0); - } - else - { - ExitProcess(1); - } - return 0; + LogPanic(msg); + char msg_cstr[4096]; + CstrFromStringToBuff(StringFromFixedArray(msg_cstr), msg); + { + u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR; + MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0); + } + HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE); + if (console_handle != INVALID_HANDLE_VALUE) + { + WriteFile(console_handle, msg.text, msg.len, 0, 0); + } + if (IsRunningInDebugger()) + { + Assert(0); + } + else + { + ExitProcess(1); + } + return 0; } b32 IsRunningInDebugger(void) { - return IsDebuggerPresent(); + return IsDebuggerPresent(); } i64 TimeNs(void) { - LARGE_INTEGER qpc; - QueryPerformanceCounter(&qpc); - i64 result = (qpc.QuadPart - W32.timer_start_qpc) * W32.ns_per_qpc; - return result; + LARGE_INTEGER qpc; + QueryPerformanceCounter(&qpc); + i64 result = (qpc.QuadPart - W32.timer_start_qpc) * W32.ns_per_qpc; + return result; } void TrueRand(String buffer) { - BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0); + BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0); } CpuTopologyInfo GetCpuTopologyInfo(void) { - TempArena scratch = BeginScratchNoConflict(); - CpuTopologyInfo res = Zi; + TempArena scratch = BeginScratchNoConflict(); + CpuTopologyInfo res = Zi; + { + DWORD infos_buff_size = 0; + u8 *infos_buff = 0; + b32 ok = 0; { - DWORD infos_buff_size = 0; - u8 *infos_buff = 0; - b32 ok = 0; - { - GetLogicalProcessorInformationEx(RelationProcessorCore, 0, &infos_buff_size); - infos_buff = PushStructsNoZero(scratch.arena, u8, infos_buff_size); - ok = GetLogicalProcessorInformationEx(RelationProcessorCore, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)infos_buff, &infos_buff_size); - } - if (ok) - { - /* Determine max efficiency class */ - i32 max_efficiency_class = 0; - { - DWORD pos = 0; - while (pos < infos_buff_size) - { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos]; - max_efficiency_class = MaxI32(max_efficiency_class, info->Processor.EfficiencyClass); - pos += info->Size; - } - } - /* Generate physical core info */ - { - DWORD pos = 0; - while (pos < infos_buff_size) - { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos]; - ++res.num_physical_cores; - ++res.num_logical_cores; - if (info->Processor.Flags & LTP_PC_SMT) - { - /* Core has SMT sibling */ - ++res.num_logical_cores; - } - if (info->Processor.EfficiencyClass == max_efficiency_class) - { - /* Core is P-core */ - ++res.num_physical_performance_cores; - } - else - { - /* Core is not a P-core */ - ++res.num_physical_non_performance_cores; - } - pos += info->Size; - } - } - } + GetLogicalProcessorInformationEx(RelationProcessorCore, 0, &infos_buff_size); + infos_buff = PushStructsNoZero(scratch.arena, u8, infos_buff_size); + ok = GetLogicalProcessorInformationEx(RelationProcessorCore, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)infos_buff, &infos_buff_size); } - res.num_logical_cores = MaxI32(res.num_logical_cores, 1); - res.num_physical_cores = MaxI32(res.num_physical_cores, 1); - res.num_physical_performance_cores = MaxI32(res.num_physical_performance_cores, 1); - EndScratch(scratch); - return res; + if (ok) + { + /* Determine max efficiency class */ + i32 max_efficiency_class = 0; + { + DWORD pos = 0; + while (pos < infos_buff_size) + { + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos]; + max_efficiency_class = MaxI32(max_efficiency_class, info->Processor.EfficiencyClass); + pos += info->Size; + } + } + /* Generate physical core info */ + { + DWORD pos = 0; + while (pos < infos_buff_size) + { + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos]; + ++res.num_physical_cores; + ++res.num_logical_cores; + if (info->Processor.Flags & LTP_PC_SMT) + { + /* Core has SMT sibling */ + ++res.num_logical_cores; + } + if (info->Processor.EfficiencyClass == max_efficiency_class) + { + /* Core is P-core */ + ++res.num_physical_performance_cores; + } + else + { + /* Core is not a P-core */ + ++res.num_physical_non_performance_cores; + } + pos += info->Size; + } + } + } + } + res.num_logical_cores = MaxI32(res.num_logical_cores, 1); + res.num_physical_cores = MaxI32(res.num_physical_cores, 1); + res.num_physical_performance_cores = MaxI32(res.num_physical_performance_cores, 1); + EndScratch(scratch); + return res; } void SleepSeconds(f64 seconds) { - f64 ms = seconds * 1000.0; - if (ms > 4000000000) - { - Sleep(INFINITE); - } - else - { - Sleep((u32)ms); - } + f64 ms = seconds * 1000.0; + if (ms > 4000000000) + { + Sleep(INFINITE); + } + else + { + Sleep((u32)ms); + } } //////////////////////////////////////////////////////////// @@ -182,60 +182,60 @@ void SleepSeconds(f64 seconds) b32 IsSwappedIn(void) { - return IsHotSwappingEnabled; + return IsHotSwappingEnabled; } b32 IsSwappingOut(void) { - return IsHotSwappingEnabled; + return IsHotSwappingEnabled; } String SwappedStateFromName(Arena *arena, String name) { - TempArena scratch = BeginScratch(arena); - String result = Zi; - String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name)); - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - HANDLE handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (handle != INVALID_HANDLE_VALUE) + TempArena scratch = BeginScratch(arena); + String result = Zi; + String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name)); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + HANDLE handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (handle != INVALID_HANDLE_VALUE) + { + u32 chunk_size = Kibi(64); + result.text = ArenaNext(arena, u8); + for (;;) { - u32 chunk_size = Kibi(64); - result.text = ArenaNext(arena, u8); - for (;;) - { - u8 *chunk = PushStructsNoZero(arena, u8, chunk_size); - u32 chunk_bytes_read = 0; - ReadFile(handle, chunk, chunk_size, (LPDWORD)&chunk_bytes_read, 0); - result.len += chunk_bytes_read; - if (chunk_bytes_read < chunk_size) - { - PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read); - break; - } - } + u8 *chunk = PushStructsNoZero(arena, u8, chunk_size); + u32 chunk_bytes_read = 0; + ReadFile(handle, chunk, chunk_size, (LPDWORD)&chunk_bytes_read, 0); + result.len += chunk_bytes_read; + if (chunk_bytes_read < chunk_size) + { + PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read); + break; + } } - CloseHandle(handle); - EndScratch(scratch); - return result; + } + CloseHandle(handle); + EndScratch(scratch); + return result; } void WriteSwappedState(String name, String data) { - TempArena scratch = BeginScratchNoConflict(); - /* TODO: Use directory non-relative to executable */ - CreateDirectoryW(L"ppswap", 0); - String result = Zi; - String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name)); - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - HANDLE handle = CreateFileW(path_wstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (handle != INVALID_HANDLE_VALUE) - { - SetFilePointer(handle, 0, 0, FILE_BEGIN); - SetEndOfFile(handle); - WriteFile(handle, data.text, data.len, 0, 0); - } - CloseHandle(handle); - EndScratch(scratch); + TempArena scratch = BeginScratchNoConflict(); + /* TODO: Use directory non-relative to executable */ + CreateDirectoryW(L"ppswap", 0); + String result = Zi; + String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name)); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + HANDLE handle = CreateFileW(path_wstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (handle != INVALID_HANDLE_VALUE) + { + SetFilePointer(handle, 0, 0, FILE_BEGIN); + SetEndOfFile(handle); + WriteFile(handle, data.text, data.len, 0, 0); + } + CloseHandle(handle); + EndScratch(scratch); } //////////////////////////////////////////////////////////// @@ -243,23 +243,23 @@ void WriteSwappedState(String name, String data) void OnExit(ExitFunc *func) { - i32 index = Atomic32FetchAdd(&W32.num_exit_funcs, 1); - if (index >= countof(W32.exit_funcs)) - { - Panic(Lit("Maximum on exit functions registered")); - } - W32.exit_funcs[index] = func; + i32 index = Atomic32FetchAdd(&W32.num_exit_funcs, 1); + if (index >= countof(W32.exit_funcs)) + { + Panic(Lit("Maximum on exit functions registered")); + } + W32.exit_funcs[index] = func; } void SignalExit(i32 code) { - Atomic32Set(&W32.exit_code, code); - SetEvent(W32.exit_event); + Atomic32Set(&W32.exit_code, code); + SetEvent(W32.exit_event); } void ExitNow(i32 code) { - ExitProcess(code); + ExitProcess(code); } //////////////////////////////////////////////////////////// @@ -267,88 +267,88 @@ void ExitNow(i32 code) void W32_BootstrapLogs(String logfile_path) { - W32.logs_arena = AcquireArena(Gibi(64)); - W32.log_msgs_arena = AcquireArena(Gibi(64)); - W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent); - if (logfile_path.len > 0) + W32.logs_arena = AcquireArena(Gibi(64)); + W32.log_msgs_arena = AcquireArena(Gibi(64)); + W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent); + if (logfile_path.len > 0) + { + TempArena scratch = BeginScratchNoConflict(); { - TempArena scratch = BeginScratchNoConflict(); - { - wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path); - W32.logfile = CreateFileW( - path_wstr, - FILE_APPEND_DATA, - FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - 0 - ); - } - EndScratch(scratch); + wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path); + W32.logfile = CreateFileW( + path_wstr, + FILE_APPEND_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + 0 + ); } - Atomic32Set(&W32.logs_initialized, 1); + EndScratch(scratch); + } + Atomic32Set(&W32.logs_initialized, 1); } void W32_Log(i32 level, String msg) { - TempArena scratch = BeginScratchNoConflict(); - if (Atomic32Fetch(&W32.logs_initialized)) + TempArena scratch = BeginScratchNoConflict(); + if (Atomic32Fetch(&W32.logs_initialized)) + { + LogLevelSettings settings = log_settings[level]; + if (level < 0 || level >= LogLevel_Count) { - LogLevelSettings settings = log_settings[level]; - if (level < 0 || level >= LogLevel_Count) - { - Panic(Lit("Invalid log level")); - } - - DateTime datetime = LocalDateTime(); - i64 now_ns = TimeNs(); - i32 thread_id = GetCurrentThreadId(); - - //- Log message to file - /* TODO: Log asynchronously */ - { - String shorthand = settings.shorthand; - String msg_formatted = StringF( - scratch.arena, - "[%F:%F:%F.%F] <%F> [%F] %F\n", - - /* Time */ - FmtUint(datetime.hour, .z = 2), - FmtUint(datetime.minute, .z = 2), - FmtUint(datetime.second, .z = 2), - FmtUint(datetime.milliseconds, .z = 3), - - /* Thread id */ - FmtUint(thread_id, .z = 5), - - /* Level */ - FmtString(shorthand), - - /* Message */ - FmtString(msg) - ); - WriteFile(W32.logfile, msg_formatted.text, msg_formatted.len, 0, 0); - } - - //- Log message to queue - /* TODO: Log asynchronously */ - LockTicketMutex(&W32.logs_tm); - { - /* Get staged data */ - LogEvent *ev = PushStruct(W32.logs_arena, LogEvent); - ev->msg = PushString(W32.log_msgs_arena, msg); - ev->datetime = datetime; - ev->time_ns = now_ns; - ev->level = level; - ev->thread_id = thread_id; - ev->id = W32.logs_count++; - ev->level_id = W32.log_level_counts[level]++; - Atomic64Set(&W32.readable_logs_count, W32.logs_count); - } - UnlockTicketMutex(&W32.logs_tm); + Panic(Lit("Invalid log level")); } - EndScratch(scratch); + + DateTime datetime = LocalDateTime(); + i64 now_ns = TimeNs(); + i32 thread_id = GetCurrentThreadId(); + + //- Log message to file + /* TODO: Log asynchronously */ + { + String shorthand = settings.shorthand; + String msg_formatted = StringF( + scratch.arena, + "[%F:%F:%F.%F] <%F> [%F] %F\n", + + /* Time */ + FmtUint(datetime.hour, .z = 2), + FmtUint(datetime.minute, .z = 2), + FmtUint(datetime.second, .z = 2), + FmtUint(datetime.milliseconds, .z = 3), + + /* Thread id */ + FmtUint(thread_id, .z = 5), + + /* Level */ + FmtString(shorthand), + + /* Message */ + FmtString(msg) + ); + WriteFile(W32.logfile, msg_formatted.text, msg_formatted.len, 0, 0); + } + + //- Log message to queue + /* TODO: Log asynchronously */ + LockTicketMutex(&W32.logs_tm); + { + /* Get staged data */ + LogEvent *ev = PushStruct(W32.logs_arena, LogEvent); + ev->msg = PushString(W32.log_msgs_arena, msg); + ev->datetime = datetime; + ev->time_ns = now_ns; + ev->level = level; + ev->thread_id = thread_id; + ev->id = W32.logs_count++; + ev->level_id = W32.log_level_counts[level]++; + Atomic64Set(&W32.readable_logs_count, W32.logs_count); + } + UnlockTicketMutex(&W32.logs_tm); + } + EndScratch(scratch); } //////////////////////////////////////////////////////////// @@ -358,46 +358,46 @@ void W32_Log(i32 level, String msg) * immediately writing to log file. */ void LogPanic(String msg) { - if (Atomic32Fetch(&W32.logs_initialized)) - { - String beg = Lit("******** PANICKING ********\n"); - String end = Lit("\n***************************\n"); - WriteFile(W32.logfile, beg.text, beg.len, 0, 0); - WriteFile(W32.logfile, msg.text, msg.len, 0, 0); - WriteFile(W32.logfile, end.text, end.len, 0, 0); - } + if (Atomic32Fetch(&W32.logs_initialized)) + { + String beg = Lit("******** PANICKING ********\n"); + String end = Lit("\n***************************\n"); + WriteFile(W32.logfile, beg.text, beg.len, 0, 0); + WriteFile(W32.logfile, msg.text, msg.len, 0, 0); + WriteFile(W32.logfile, end.text, end.len, 0, 0); + } } void Log_(i32 level, String msg) { - W32_Log(level, msg); + W32_Log(level, msg); } void LogF_(i32 level, String fmt, ...) { - if (Atomic32Fetch(&W32.logs_initialized)) + if (Atomic32Fetch(&W32.logs_initialized)) + { + TempArena scratch = BeginScratchNoConflict(); + va_list args; + va_start(args, fmt); { - TempArena scratch = BeginScratchNoConflict(); - va_list args; - va_start(args, fmt); - { - String msg = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args)); - W32_Log(level, msg); - } - va_end(args); - EndScratch(scratch); + String msg = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args)); + W32_Log(level, msg); } + va_end(args); + EndScratch(scratch); + } } LogEventsArray GetLogEvents(void) { - LogEventsArray result = Zi; - result.count = Atomic64Fetch(&W32.readable_logs_count); - if (result.count > 0) - { - result.logs = W32.readable_log_events; - } - return result; + LogEventsArray result = Zi; + result.count = Atomic64Fetch(&W32.readable_logs_count); + if (result.count > 0) + { + result.logs = W32.readable_log_events; + } + return result; } //////////////////////////////////////////////////////////// @@ -405,150 +405,148 @@ LogEventsArray GetLogEvents(void) i32 W32_Main(void) { - /* Init time */ + /* Init time */ + { + LARGE_INTEGER qpf; + QueryPerformanceFrequency(&qpf); + W32.ns_per_qpc = 1000000000 / qpf.QuadPart; + } + { + LARGE_INTEGER qpc; + QueryPerformanceCounter(&qpc); + W32.timer_start_qpc = qpc.QuadPart; + } + + /* Setup events */ + W32.panic_event = CreateEventW(0, 1, 0, 0); + W32.exit_event = CreateEventW(0, 1, 0, 0); + + W32.main_thread_id = GetCurrentThreadId(); + SetThreadDescription(GetCurrentThread(), L"Main thread"); + + /* Query system info */ + GetSystemInfo(&W32.info); + + /* Init main thread */ + W32_InitCurrentThread(Lit("Main")); + + /* Get raw args from command line */ + { + Arena *perm = PermArena(); + StringList args_list = Zi; { - LARGE_INTEGER qpf; - QueryPerformanceFrequency(&qpf); - W32.ns_per_qpc = 1000000000 / qpf.QuadPart; + LPCWSTR cmdline_wstr = GetCommandLineW(); + i32 argc = 0; + LPWSTR *argv = CommandLineToArgvW(cmdline_wstr, &argc); + for (i32 i = 0; i < argc; ++i) + { + wchar_t *arg_wstr = argv[i]; + String arg = StringFromWstrNoLimit(perm, arg_wstr); + PushStringToList(perm, &args_list, arg); + } } + W32.raw_command_line = args_list; + } + + ////////////////////////////// + //- Bootstrap + + /* Bootstrap command line */ + BootstrapCmdline(); + + /* Bootstrap log system */ + /* FIXME: Remove hardcoded log path */ + W32_BootstrapLogs(Lit("log.log")); + LogInfoF("Main thread ID: %F", FmtUint(ThreadId())); + + /* Bootstrap resource system */ + { + W32_FindEmbeddedDataCtx ctx = Zi; + EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&ctx); + BootstrapResources(ctx.embedded_strings_count, ctx.embedded_strings); + } + + /* Bootstrap async */ + BootstrapAsync(); + + /* Bootstrap layers */ + if (!Atomic32Fetch(&W32.panicking)) + { + BootstrapLayers(); + } + + ////////////////////////////// + //- Wait for exit signal + + /* Wait for exit start or panic */ + if (!Atomic32Fetch(&W32.panicking)) + { + HANDLE handles[] = { + W32.exit_event, + W32.panic_event, + }; + DWORD wake = WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); + } + + ////////////////////////////// + //- Shutdown + + /* Run exit callbacks */ + if (!Atomic32Fetch(&W32.panicking)) + { + i32 num_funcs = Atomic32Fetch(&W32.num_exit_funcs); + for (i32 idx = num_funcs - 1; idx >= 0; --idx) { - LARGE_INTEGER qpc; - QueryPerformanceCounter(&qpc); - W32.timer_start_qpc = qpc.QuadPart; + ExitFunc *func = W32.exit_funcs[idx]; + func(); } + } - /* Setup events */ - W32.panic_event = CreateEventW(0, 1, 0, 0); - W32.exit_event = CreateEventW(0, 1, 0, 0); - - W32.main_thread_id = GetCurrentThreadId(); - SetThreadDescription(GetCurrentThread(), L"Main thread"); - - /* Query system info */ - GetSystemInfo(&W32.info); - - /* Init main thread */ - W32_InitCurrentThread(Lit("Main")); - - /* Get raw args from command line */ - { - Arena *perm = PermArena(); - StringList args_list = Zi; - { - LPCWSTR cmdline_wstr = GetCommandLineW(); - i32 argc = 0; - LPWSTR *argv = CommandLineToArgvW(cmdline_wstr, &argc); - for (i32 i = 0; i < argc; ++i) - { - wchar_t *arg_wstr = argv[i]; - String arg = StringFromWstrNoLimit(perm, arg_wstr); - PushStringToList(perm, &args_list, arg); - } - } - W32.raw_command_line = args_list; - } - - ////////////////////////////// - //- Bootstrap - - /* Bootstrap command line */ - BootstrapCmdline(); - - /* Bootstrap log system */ - /* FIXME: Remove hardcoded log path */ - W32_BootstrapLogs(Lit("log.log")); - LogInfoF("Main thread ID: %F", FmtUint(ThreadId())); - - /* Bootstrap resource system */ - { - W32_FindEmbeddedDataCtx ctx = Zi; - EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&ctx); - BootstrapResources(ctx.embedded_strings_count, ctx.embedded_strings); - } - - /* Bootstrap async */ - BootstrapAsync(); - - /* Bootstrap layers */ - if (!Atomic32Fetch(&W32.panicking)) - { - BootstrapLayers(); - } - - ////////////////////////////// - //- Wait for exit signal - - /* Wait for exit start or panic */ - if (!Atomic32Fetch(&W32.panicking)) - { - HANDLE handles[] = { - W32.exit_event, - W32.panic_event, - }; - DWORD wake = WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); - } - - ////////////////////////////// - //- Shutdown - - /* Run exit callbacks */ - if (!Atomic32Fetch(&W32.panicking)) - { - i32 num_funcs = Atomic32Fetch(&W32.num_exit_funcs); - for (i32 idx = num_funcs - 1; idx >= 0; --idx) - { - ExitFunc *func = W32.exit_funcs[idx]; - func(); - } - } - - /* Exit */ - if (Atomic32Fetch(&W32.panicking)) - { - WaitForSingleObject(W32.panic_event, INFINITE); - MessageBoxExW(0, W32.panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); - Atomic32FetchTestSet(&W32.exit_code, 0, 1); - } - return Atomic32Fetch(&W32.exit_code); + /* Exit */ + if (Atomic32Fetch(&W32.panicking)) + { + WaitForSingleObject(W32.panic_event, INFINITE); + MessageBoxExW(0, W32.panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); + Atomic32FetchTestSet(&W32.exit_code, 0, 1); + } + return Atomic32Fetch(&W32.exit_code); } //////////////////////////////////////////////////////////// //~ Crt main #if IsCrtlibEnabled -# if IsConsoleApp -int main(char **argc, int argv) -{ - return W32_Main(); -} -# else -int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code) -{ - return W32_Main(); -} -# endif /* IsConsoleApp */ + #if IsConsoleApp + int main(char **argc, int argv) + { + return W32_Main(); + } + #else + int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code) + { + return W32_Main(); + } + #endif /* IsConsoleApp */ #endif /* IsCrtlibEnabled */ //////////////////////////////////////////////////////////// //~ Crt stub #if !IsCrtlibEnabled + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wmissing-variable-declarations" + #pragma clang diagnostic ignored "-Wmissing-prototypes" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-variable-declarations" -#pragma clang diagnostic ignored "-Wmissing-prototypes" + /* Enable floating point */ + __attribute((used)) + int _fltused; -/* Enable floating point */ -__attribute((used)) -int _fltused; - -__attribute((used)) -void __stdcall wWinMainCRTStartup(void) -{ + __attribute((used)) + void __stdcall wWinMainCRTStartup(void) + { i32 result = W32_Main(); ExitProcess(result); -} - -#pragma clang diagnostic pop + } + #pragma clang diagnostic pop #endif /* !IsCrtlibEnabled */ diff --git a/src/base/base_win32/base_win32.h b/src/base/base_win32/base_win32.h index 4546c361..e920f7a8 100644 --- a/src/base/base_win32/base_win32.h +++ b/src/base/base_win32/base_win32.h @@ -7,28 +7,28 @@ #define WIN32_LEAN_AND_MEAN #define UNICODE #pragma warning(push, 0) - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #pragma warning(pop) #ifndef BCRYPT_RNG_ALG_HANDLE -#define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081) -u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags); + #define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081) + u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags); #endif //- Windows libs @@ -49,8 +49,8 @@ u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags); Struct(W32_FindEmbeddedDataCtx) { - u64 embedded_strings_count; - String embedded_strings[64]; + u64 embedded_strings_count; + String embedded_strings[64]; }; //////////////////////////////////////////////////////////// @@ -58,41 +58,41 @@ Struct(W32_FindEmbeddedDataCtx) Struct(W32_Ctx) { - SYSTEM_INFO info; - u32 main_thread_id; - Atomic32 shutdown; - Atomic32 exit_code; + SYSTEM_INFO info; + u32 main_thread_id; + Atomic32 shutdown; + Atomic32 exit_code; - i64 timer_start_qpc; - i64 ns_per_qpc; + i64 timer_start_qpc; + i64 ns_per_qpc; - StringList raw_command_line; + StringList raw_command_line; - //- Application control flow + //- Application control flow - Atomic32 panicking; - wchar_t panic_wstr[4096]; - HANDLE panic_event; - HANDLE exit_event; + Atomic32 panicking; + wchar_t panic_wstr[4096]; + HANDLE panic_event; + HANDLE exit_event; - //- Exit funcs + //- Exit funcs - Atomic32 num_exit_funcs; - ExitFunc *exit_funcs[4096]; + Atomic32 num_exit_funcs; + ExitFunc *exit_funcs[4096]; - //- Logs + //- Logs - HANDLE logfile; - Atomic32 logs_initialized; + HANDLE logfile; + Atomic32 logs_initialized; - TicketMutex logs_tm; - Arena *log_msgs_arena; - Arena *logs_arena; + TicketMutex logs_tm; + Arena *log_msgs_arena; + Arena *logs_arena; - u64 logs_count; - u64 log_level_counts[LogLevel_Count]; - LogEvent *readable_log_events; - Atomic64 readable_logs_count; + u64 logs_count; + u64 log_level_counts[LogLevel_Count]; + LogEvent *readable_log_events; + Atomic64 readable_logs_count; }; extern W32_Ctx W32; diff --git a/src/base/base_win32/base_win32_futex.c b/src/base/base_win32/base_win32_futex.c index db7ae3fa..477aea0e 100644 --- a/src/base/base_win32/base_win32_futex.c +++ b/src/base/base_win32/base_win32_futex.c @@ -3,12 +3,12 @@ void FutexYieldNeq(volatile void *addr, void *cmp, u8 cmp_size) { - WaitOnAddress(addr, cmp, cmp_size, INFINITE); + WaitOnAddress(addr, cmp, cmp_size, INFINITE); } void FutexWakeNeq(void *addr) { - WakeByAddressAll(addr); + WakeByAddressAll(addr); } //////////////////////////////////////////////////////////// @@ -16,12 +16,12 @@ void FutexWakeNeq(void *addr) void FutexYieldGte(volatile void *addr, void *cmp, u8 cmp_size) { - /* TODO: Actually implement this. Just emulating via neq for now. */ - FutexYieldNeq(addr, cmp, cmp_size); + /* TODO: Actually implement this. Just emulating via neq for now. */ + FutexYieldNeq(addr, cmp, cmp_size); } void FutexWakeGte(void *addr) { - /* TODO: Actually implement this. Just emulating via neq for now. */ - FutexWakeNeq(addr); + /* TODO: Actually implement this. Just emulating via neq for now. */ + FutexWakeNeq(addr); } diff --git a/src/base/base_win32/base_win32_memory.c b/src/base/base_win32/base_win32_memory.c index 1c41bf0a..8657960e 100644 --- a/src/base/base_win32/base_win32_memory.c +++ b/src/base/base_win32/base_win32_memory.c @@ -5,38 +5,38 @@ void *ReserveMemory(u64 size) { - void *ptr = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS); - return ptr; + void *ptr = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS); + return ptr; } void ReleaseMemory(void *address) { - VirtualFree(address, 0, MEM_RELEASE); + VirtualFree(address, 0, MEM_RELEASE); } //- Commit void *CommitMemory(void *address, u64 size) { - void *ptr = VirtualAlloc(address, size, MEM_COMMIT, PAGE_READWRITE); - return ptr; + void *ptr = VirtualAlloc(address, size, MEM_COMMIT, PAGE_READWRITE); + return ptr; } void DecommitMemory(void *address, u64 size) { - VirtualFree(address, size, MEM_DECOMMIT); + VirtualFree(address, size, MEM_DECOMMIT); } //- Protect void SetMemoryReadonly(void *address, u64 size) { - DWORD old; - VirtualProtect(address, size, PAGE_READONLY, &old); + DWORD old; + VirtualProtect(address, size, PAGE_READONLY, &old); } void SetMemoryReadWrite(void *address, u64 size) { - DWORD old; - VirtualProtect(address, size, PAGE_READWRITE, &old); + DWORD old; + VirtualProtect(address, size, PAGE_READWRITE, &old); } diff --git a/src/base/base_win32/base_win32_time.c b/src/base/base_win32/base_win32_time.c index e7e907f1..6dcf519e 100644 --- a/src/base/base_win32/base_win32_time.c +++ b/src/base/base_win32/base_win32_time.c @@ -3,18 +3,18 @@ DateTime LocalDateTime(void) { - DateTime result = Zi; - { - SYSTEMTIME lt; - GetLocalTime(<); - result.year = lt.wYear; - result.month = lt.wMonth; - result.day_of_week = lt.wDayOfWeek; - result.day = lt.wDay; - result.hour = lt.wHour; - result.minute = lt.wMinute; - result.second = lt.wSecond; - result.milliseconds = lt.wMilliseconds; - } - return result; + DateTime result = Zi; + { + SYSTEMTIME lt; + GetLocalTime(<); + result.year = lt.wYear; + result.month = lt.wMonth; + result.day_of_week = lt.wDayOfWeek; + result.day = lt.wDay; + result.hour = lt.wHour; + result.minute = lt.wMinute; + result.second = lt.wSecond; + result.milliseconds = lt.wMilliseconds; + } + return result; } diff --git a/src/base/base_win32/base_win32_wave.c b/src/base/base_win32/base_win32_wave.c index cff0f763..b93f7450 100644 --- a/src/base/base_win32/base_win32_wave.c +++ b/src/base/base_win32/base_win32_wave.c @@ -3,31 +3,31 @@ void W32_InitCurrentThread(String name) { - /* Init thread arenas */ + /* Init thread arenas */ + { + Base_tl.arenas.perm = AcquireArena(Gibi(64)); + for (i32 i = 0; i < (i32)countof(Base_tl.arenas.scratch); ++i) { - Base_tl.arenas.perm = AcquireArena(Gibi(64)); - for (i32 i = 0; i < (i32)countof(Base_tl.arenas.scratch); ++i) - { - Base_tl.arenas.scratch[i] = AcquireArena(Gibi(64)); - } + Base_tl.arenas.scratch[i] = AcquireArena(Gibi(64)); } - Arena *perm = PermArena(); + } + Arena *perm = PermArena(); - /* Set thread name */ - wchar_t *thread_name_wstr = WstrFromString(perm, name); - SetThreadDescription(GetCurrentThread(), thread_name_wstr); + /* Set thread name */ + wchar_t *thread_name_wstr = WstrFromString(perm, name); + SetThreadDescription(GetCurrentThread(), thread_name_wstr); - /* Initialize COM */ - CoInitializeEx(0, COINIT_MULTITHREADED); + /* Initialize COM */ + CoInitializeEx(0, COINIT_MULTITHREADED); } DWORD WINAPI W32_ThreadProc(LPVOID thread_args_vp) { - W32_ThreadArgs *thread_args = (W32_ThreadArgs *)thread_args_vp; - W32_InitCurrentThread(thread_args->name); - LogInfoF("New thread \"%F\" created with ID %F", FmtString(thread_args->name), FmtUint(ThreadId())); - thread_args->entry(thread_args->lane); - return 0; + W32_ThreadArgs *thread_args = (W32_ThreadArgs *)thread_args_vp; + W32_InitCurrentThread(thread_args->name); + LogInfoF("New thread \"%F\" created with ID %F", FmtString(thread_args->name), FmtUint(ThreadId())); + thread_args->entry(thread_args->lane); + return 0; } //////////////////////////////////////////////////////////// @@ -35,58 +35,58 @@ DWORD WINAPI W32_ThreadProc(LPVOID thread_args_vp) void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *udata) { - Arena *perm = PermArena(); - PERSIST Atomic64 num_threads_allocated = Zi; + Arena *perm = PermArena(); + PERSIST Atomic64 num_threads_allocated = Zi; - /* Catch high lane count to prevent OS crash */ - i64 old_num_threads_allocated = Atomic64FetchAdd(&num_threads_allocated, num_lanes); - i64 new_num_threads_allocated = old_num_threads_allocated + num_lanes; - if (new_num_threads_allocated > MaxThreads) + /* Catch high lane count to prevent OS crash */ + i64 old_num_threads_allocated = Atomic64FetchAdd(&num_threads_allocated, num_lanes); + i64 new_num_threads_allocated = old_num_threads_allocated + num_lanes; + if (new_num_threads_allocated > MaxThreads) + { + if (old_num_threads_allocated < MaxThreads) { - if (old_num_threads_allocated < MaxThreads) - { - Panic(StringF(perm, "Maximum number of threads reached (%F)", FmtUint(MaxThreads))); - } - else - { - /* Sleep until panic */ - Sleep(INFINITE); - } + Panic(StringF(perm, "Maximum number of threads reached (%F)", FmtUint(MaxThreads))); + } + else + { + /* Sleep until panic */ + Sleep(INFINITE); + } + } + + WaveCtx *wave_ctx = PushStruct(perm, WaveCtx); + wave_ctx->lanes_count = num_lanes; + wave_ctx->udata = udata; + + for (u32 lane_idx = 0; lane_idx < num_lanes; ++lane_idx) + { + WaveLaneCtx *lane_ctx = PushStruct(perm, WaveLaneCtx); + lane_ctx->idx = lane_idx; + lane_ctx->wave = wave_ctx; + lane_ctx->default_spin_count = DefaultWaveLaneSpinCount; + + String thread_name = Zi; + if (num_lanes > 1) + { + thread_name = StringF(perm, "%F:%F", FmtString(name), FmtUint(lane_idx)); + } + else + { + thread_name = PushString(perm, name); } - WaveCtx *wave_ctx = PushStruct(perm, WaveCtx); - wave_ctx->lanes_count = num_lanes; - wave_ctx->udata = udata; + W32_ThreadArgs *thread_args = PushStruct(perm, W32_ThreadArgs); + thread_args->lane = lane_ctx; + thread_args->udata = udata; + thread_args->entry = entry; + thread_args->name = thread_name; - for (u32 lane_idx = 0; lane_idx < num_lanes; ++lane_idx) + HANDLE handle = CreateThread(0, Mebi(4), W32_ThreadProc, thread_args, 0, 0); + if (!handle) { - WaveLaneCtx *lane_ctx = PushStruct(perm, WaveLaneCtx); - lane_ctx->idx = lane_idx; - lane_ctx->wave = wave_ctx; - lane_ctx->default_spin_count = DefaultWaveLaneSpinCount; - - String thread_name = Zi; - if (num_lanes > 1) - { - thread_name = StringF(perm, "%F:%F", FmtString(name), FmtUint(lane_idx)); - } - else - { - thread_name = PushString(perm, name); - } - - W32_ThreadArgs *thread_args = PushStruct(perm, W32_ThreadArgs); - thread_args->lane = lane_ctx; - thread_args->udata = udata; - thread_args->entry = entry; - thread_args->name = thread_name; - - HANDLE handle = CreateThread(0, Mebi(4), W32_ThreadProc, thread_args, 0, 0); - if (!handle) - { - Panic(Lit("Failed to create thread")); - } + Panic(Lit("Failed to create thread")); } + } } //////////////////////////////////////////////////////////// @@ -94,5 +94,5 @@ void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *ud i32 ThreadId(void) { - return GetCurrentThreadId(); + return GetCurrentThreadId(); } diff --git a/src/base/base_win32/base_win32_wave.h b/src/base/base_win32/base_win32_wave.h index 8fddf80d..ea5a8758 100644 --- a/src/base/base_win32/base_win32_wave.h +++ b/src/base/base_win32/base_win32_wave.h @@ -3,10 +3,10 @@ Struct(W32_ThreadArgs) { - void *udata; - WaveLaneCtx *lane; - WaveLaneEntryFunc *entry; - String name; + void *udata; + WaveLaneCtx *lane; + WaveLaneEntryFunc *entry; + String name; }; //////////////////////////////////////////////////////////// diff --git a/src/collider/collider.c b/src/collider/collider.c index aba9bd5e..4120bab8 100644 --- a/src/collider/collider.c +++ b/src/collider/collider.c @@ -5,7 +5,7 @@ void CLD_DebugBreakable(void) { #if IsRtcEnabled - DEBUGBREAKABLE; + DEBUGBREAKABLE; #endif } #endif @@ -15,14 +15,14 @@ void CLD_DebugBreakable(void) CLD_Shape CLD_ShapeFromQuad(Quad quad) { - CLD_Shape result; - result.points[0] = quad.p0; - result.points[1] = quad.p1; - result.points[2] = quad.p2; - result.points[3] = quad.p3; - result.count = 4; - result.radius = 0; - return result; + CLD_Shape result; + result.points[0] = quad.p0; + result.points[1] = quad.p1; + result.points[2] = quad.p2; + result.points[3] = quad.p3; + result.count = 4; + result.radius = 0; + return result; } //////////////////////////////////////////////////////////// @@ -30,65 +30,65 @@ CLD_Shape CLD_ShapeFromQuad(Quad quad) CLD_SupportPoint CLD_SupportPointFromDirEx(CLD_Shape *shape, Xform xf, Vec2 dir, i32 ignore) { - Vec2 *points = shape->points; - u32 count = shape->count; - f32 radius = shape->radius; + Vec2 *points = shape->points; + u32 count = shape->count; + f32 radius = shape->radius; - dir = RotateVec2(dir, -RotationFromXform(xf)); - dir = MulVec2Vec2(dir, ScaleFromXform(xf)); + dir = RotateVec2(dir, -RotationFromXform(xf)); + dir = MulVec2Vec2(dir, ScaleFromXform(xf)); - if (count == 1) + if (count == 1) + { + /* Skip 'ignore' on single point colliders */ + ignore = -1; + } + + Vec2 furthest = Zi; + u32 furthest_index = 0; + f32 furthest_dot = -F32Infinity; + + for (u32 i = 0; i < count; ++i) + { + if ((i32)i == ignore) { - /* Skip 'ignore' on single point colliders */ - ignore = -1; + continue; } - - Vec2 furthest = Zi; - u32 furthest_index = 0; - f32 furthest_dot = -F32Infinity; - - for (u32 i = 0; i < count; ++i) + Vec2 p = points[i]; + f32 dot = DotVec2(dir, p); + if (dot > furthest_dot) { - if ((i32)i == ignore) - { - continue; - } - Vec2 p = points[i]; - f32 dot = DotVec2(dir, p); - if (dot > furthest_dot) - { - furthest = p; - furthest_dot = dot; - furthest_index = i; - } + furthest = p; + furthest_dot = dot; + furthest_index = i; } + } - if (radius > 0.0) - { - dir = Vec2WithLen(dir, radius); - furthest = AddVec2(furthest, dir); - } + if (radius > 0.0) + { + dir = Vec2WithLen(dir, radius); + furthest = AddVec2(furthest, dir); + } - furthest = MulXformV2(xf, furthest); + furthest = MulXformV2(xf, furthest); - CLD_SupportPoint result; - result.p = furthest; - result.i = furthest_index; - return result; + CLD_SupportPoint result; + result.p = furthest; + result.i = furthest_index; + return result; } CLD_SupportPoint CLD_SupportPointFromDir(CLD_Shape *shape, Xform xf, Vec2 dir) { - return CLD_SupportPointFromDirEx(shape, xf, dir, -1); + return CLD_SupportPointFromDirEx(shape, xf, dir, -1); } CLD_MenkowskiPoint CLD_MenkowskiPointFromDir(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1, Vec2 dir) { - CLD_MenkowskiPoint result; - result.s0 = CLD_SupportPointFromDir(shape0, xf0, dir); - result.s1 = CLD_SupportPointFromDir(shape1, xf1, NegVec2(dir)); - result.p = SubVec2(result.s0.p, result.s1.p); - return result; + CLD_MenkowskiPoint result; + result.s0 = CLD_SupportPointFromDir(shape0, xf0, dir); + result.s1 = CLD_SupportPointFromDir(shape1, xf1, NegVec2(dir)); + result.p = SubVec2(result.s0.p, result.s1.p); + return result; } //////////////////////////////////////////////////////////// @@ -96,36 +96,36 @@ CLD_MenkowskiPoint CLD_MenkowskiPointFromDir(CLD_Shape *shape0, CLD_Shape *shape Aabb CLD_AabbFromShape(CLD_Shape *shape, Xform xf) { - Aabb result; - result.p0.x = CLD_SupportPointFromDir(shape, xf, VEC2(-1, 0)).p.x - CLD_CollisionTolerance; - result.p0.y = CLD_SupportPointFromDir(shape, xf, VEC2(0, -1)).p.y - CLD_CollisionTolerance; - result.p1.x = CLD_SupportPointFromDir(shape, xf, VEC2(1, 0)).p.x + CLD_CollisionTolerance; - result.p1.y = CLD_SupportPointFromDir(shape, xf, VEC2(0, 1)).p.y + CLD_CollisionTolerance; - return result; + Aabb result; + result.p0.x = CLD_SupportPointFromDir(shape, xf, VEC2(-1, 0)).p.x - CLD_CollisionTolerance; + result.p0.y = CLD_SupportPointFromDir(shape, xf, VEC2(0, -1)).p.y - CLD_CollisionTolerance; + result.p1.x = CLD_SupportPointFromDir(shape, xf, VEC2(1, 0)).p.x + CLD_CollisionTolerance; + result.p1.y = CLD_SupportPointFromDir(shape, xf, VEC2(0, 1)).p.y + CLD_CollisionTolerance; + return result; } Aabb CLD_CombineAabb(Aabb b0, Aabb b1) { - Aabb result; - result.p0.x = MinF32(MinF32(b0.p0.x, b0.p1.x), MinF32(b1.p0.x, b1.p1.x)); - result.p0.y = MinF32(MinF32(b0.p0.y, b0.p1.y), MinF32(b1.p0.y, b1.p1.y)); - result.p1.x = MaxF32(MaxF32(b0.p0.x, b0.p1.x), MaxF32(b1.p0.x, b1.p1.x)); - result.p1.y = MaxF32(MaxF32(b0.p0.y, b0.p1.y), MaxF32(b1.p0.y, b1.p1.y)); - return result; + Aabb result; + result.p0.x = MinF32(MinF32(b0.p0.x, b0.p1.x), MinF32(b1.p0.x, b1.p1.x)); + result.p0.y = MinF32(MinF32(b0.p0.y, b0.p1.y), MinF32(b1.p0.y, b1.p1.y)); + result.p1.x = MaxF32(MaxF32(b0.p0.x, b0.p1.x), MaxF32(b1.p0.x, b1.p1.x)); + result.p1.y = MaxF32(MaxF32(b0.p0.y, b0.p1.y), MaxF32(b1.p0.y, b1.p1.y)); + return result; } b32 CLD_TestAabb(Aabb box0, Aabb box1) { - f32 b0_x0 = box0.p0.x; - f32 b0_x1 = box0.p1.x; - f32 b1_x0 = box1.p0.x; - f32 b1_x1 = box1.p1.x; - f32 b0_y0 = box0.p0.y; - f32 b0_y1 = box0.p1.y; - f32 b1_y0 = box1.p0.y; - f32 b1_y1 = box1.p1.y; - return ((b0_x0 >= b1_x0 && b0_x0 <= b1_x1) || (b0_x1 >= b1_x0 && b0_x1 <= b1_x1) || (b1_x0 >= b0_x0 && b1_x0 <= b0_x1) || (b1_x1 >= b0_x0 && b1_x1 <= b0_x1)) && - ((b0_y0 >= b1_y0 && b0_y0 <= b1_y1) || (b0_y1 >= b1_y0 && b0_y1 <= b1_y1) || (b1_y0 >= b0_y0 && b1_y0 <= b0_y1) || (b1_y1 >= b0_y0 && b1_y1 <= b0_y1)); + f32 b0_x0 = box0.p0.x; + f32 b0_x1 = box0.p1.x; + f32 b1_x0 = box1.p0.x; + f32 b1_x1 = box1.p1.x; + f32 b0_y0 = box0.p0.y; + f32 b0_y1 = box0.p1.y; + f32 b1_y0 = box1.p0.y; + f32 b1_y1 = box1.p1.y; + return ((b0_x0 >= b1_x0 && b0_x0 <= b1_x1) || (b0_x1 >= b1_x0 && b0_x1 <= b1_x1) || (b1_x0 >= b0_x0 && b1_x0 <= b0_x1) || (b1_x1 >= b0_x0 && b1_x1 <= b0_x1)) && + ((b0_y0 >= b1_y0 && b0_y0 <= b1_y1) || (b0_y1 >= b1_y0 && b0_y1 <= b1_y1) || (b1_y0 >= b0_y0 && b1_y0 <= b0_y1) || (b1_y1 >= b0_y0 && b1_y1 <= b0_y1)); } //////////////////////////////////////////////////////////// @@ -143,169 +143,171 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1, f32 min_unique_pt_dist_sq) #endif { - b32 overlapping = 0; - CLD_MenkowskiSimplex s = Zi; - Vec2 dir = Zi; - CLD_MenkowskiPoint m = Zi; + b32 overlapping = 0; + CLD_MenkowskiSimplex s = Zi; + Vec2 dir = Zi; + CLD_MenkowskiPoint m = Zi; - /* First point is support point in shape's general directions to eachother */ - dir = SubVec2(xf1.og, xf0.og); - if (IsVec2Zero(dir)) dir = VEC2(1, 0); - s.a = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); - s.len = 1; + /* First point is support point in shape's general directions to eachother */ + dir = SubVec2(xf1.og, xf0.og); + if (IsVec2Zero(dir)) dir = VEC2(1, 0); + s.a = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); + s.len = 1; - Vec2 removed_a = Zi; - Vec2 removed_b = Zi; - u32 num_removed = 0; - for (;;) + Vec2 removed_a = Zi; + Vec2 removed_b = Zi; + u32 num_removed = 0; + for (;;) + { + if (s.len == 1) { - if (s.len == 1) - { - //- Find second point in simplex - /* Second point is support point towards origin */ - dir = NegVec2(s.a.p); + //- Find second point in simplex + /* Second point is support point towards origin */ + dir = NegVec2(s.a.p); - CLD_DBGSTEP; - m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); - /* Check that new point is far enough away from existing point */ - if (Vec2LenSq(SubVec2(m.p, s.a.p)) < min_unique_pt_dist_sq) - { - overlapping = 0; - break; - } - s.b = s.a; - s.a = m; - s.len = 2; + CLD_DBGSTEP; + m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); + /* Check that new point is far enough away from existing point */ + if (Vec2LenSq(SubVec2(m.p, s.a.p)) < min_unique_pt_dist_sq) + { + overlapping = 0; + break; + } + s.b = s.a; + s.a = m; + s.len = 2; - /* Third point is support point in direction of line normal towards origin */ - dir = PerpVec2TowardsDir(SubVec2(s.b.p, s.a.p), NegVec2(s.a.p)); - } - - { - //- Find third point in simplex - CLD_DBGSTEP; - m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); - /* Check that new point is far enough away from existing points */ - if (Vec2LenSq(SubVec2(m.p, s.a.p)) < min_unique_pt_dist_sq || - Vec2LenSq(SubVec2(m.p, s.b.p)) < min_unique_pt_dist_sq || - ( - (num_removed >= 1) && ( - (Vec2LenSq(SubVec2(m.p, removed_a)) < min_unique_pt_dist_sq) || - (num_removed >= 2 && Vec2LenSq(SubVec2(m.p, removed_b)) < min_unique_pt_dist_sq)) - ) || - AbsF32(WedgeVec2(SubVec2(s.b.p, s.a.p), SubVec2(m.p, s.a.p))) < min_unique_pt_dist_sq) - { - overlapping = 0; - break; - } - s.c = s.b; - s.b = s.a; - s.a = m; - s.len = 3; - - if ((AbsF32(WedgeVec2(SubVec2(s.b.p, s.a.p), NegVec2(s.a.p))) <= min_unique_pt_dist_sq) || - (AbsF32(WedgeVec2(SubVec2(s.c.p, s.b.p), NegVec2(s.b.p))) <= min_unique_pt_dist_sq) || - (AbsF32(WedgeVec2(SubVec2(s.c.p, s.a.p), NegVec2(s.a.p))) <= min_unique_pt_dist_sq)) - { - /* Simplex lies on origin */ - overlapping = 1; - break; - } - } - - //- Determine region of the simplex in which the origin lies - CLD_DBGSTEP; - Vec2 vab = SubVec2(s.b.p, s.a.p); - Vec2 vac = SubVec2(s.c.p, s.a.p); - Vec2 vbc = SubVec2(s.c.p, s.b.p); - - Vec2 rab_dir = PerpVec2TowardsDir(vab, NegVec2(vac)); - Vec2 rac_dir = PerpVec2TowardsDir(vac, NegVec2(vab)); - Vec2 rbc_dir = PerpVec2TowardsDir(vbc, vab); - - f32 rab_dot = DotVec2(rab_dir, NegVec2(s.a.p)); - f32 rac_dot = DotVec2(rac_dir, NegVec2(s.a.p)); - f32 rbc_dot = DotVec2(rbc_dir, NegVec2(s.b.p)); - - f32 vab_dot = DotVec2(vab, NegVec2(s.a.p)) / Vec2LenSq(vab); - f32 vac_dot = DotVec2(vac, NegVec2(s.a.p)) / Vec2LenSq(vac); - f32 vbc_dot = DotVec2(vbc, NegVec2(s.b.p)) / Vec2LenSq(vbc); - - if (rab_dot >= 0 && vab_dot >= 0 && vab_dot <= 1) - { - //- Region ab, remove c - num_removed = 1; - removed_a = s.c.p; - s.len = 2; - dir = rab_dir; /* Next third point is in direction of region ab */ - } - else if (rac_dot >= 0 && vac_dot >= 0 && vac_dot <= 1) - { - //- Region ac, remove b - num_removed = 1; - removed_a = s.b.p; - s.len = 2; - s.b = s.c; - dir = rac_dir; /* Next third point is in direction of region ac */ - } - else if (rbc_dot >= 0 && vbc_dot >= 0 && vbc_dot <= 1) - { - //- Region bc, remove a - num_removed = 1; - removed_a = s.a.p; - s.len = 2; - s.a = s.b; - s.b = s.c; - dir = rbc_dir; /* Next third point is in direction of region bc */ - } - else if (vab_dot <= 0 && vac_dot <= 0) - { - //- Region a, remove bc - num_removed = 2; - removed_a = s.b.p; - removed_b = s.c.p; - s.len = 1; - } - else if (vab_dot >= 1 && vbc_dot <= 0) - { - //- Region b, remove ac - num_removed = 2; - removed_a = s.a.p; - removed_b = s.c.p; - s.len = 1; - s.a = s.b; - } - else if (vac_dot >= 1 && vbc_dot >= 1) - { - //- Region c, remove ab - num_removed = 2; - removed_a = s.a.p; - removed_b = s.b.p; - s.len = 1; - s.a = s.c; - } - else - { - /* No region, must be in simplex */ - overlapping = 1; - break; - } + /* Third point is support point in direction of line normal towards origin */ + dir = PerpVec2TowardsDir(SubVec2(s.b.p, s.a.p), NegVec2(s.a.p)); } + { + //- Find third point in simplex + CLD_DBGSTEP; + m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); + /* Check that new point is far enough away from existing points */ + if ( + Vec2LenSq(SubVec2(m.p, s.a.p)) < min_unique_pt_dist_sq || + Vec2LenSq(SubVec2(m.p, s.b.p)) < min_unique_pt_dist_sq || ( + (num_removed >= 1) && ( + (Vec2LenSq(SubVec2(m.p, removed_a)) < min_unique_pt_dist_sq) || + (num_removed >= 2 && Vec2LenSq(SubVec2(m.p, removed_b)) < min_unique_pt_dist_sq) + ) + ) || + AbsF32(WedgeVec2(SubVec2(s.b.p, s.a.p), SubVec2(m.p, s.a.p))) < min_unique_pt_dist_sq + ) + { + overlapping = 0; + break; + } + s.c = s.b; + s.b = s.a; + s.a = m; + s.len = 3; + + if ((AbsF32(WedgeVec2(SubVec2(s.b.p, s.a.p), NegVec2(s.a.p))) <= min_unique_pt_dist_sq) || + (AbsF32(WedgeVec2(SubVec2(s.c.p, s.b.p), NegVec2(s.b.p))) <= min_unique_pt_dist_sq) || + (AbsF32(WedgeVec2(SubVec2(s.c.p, s.a.p), NegVec2(s.a.p))) <= min_unique_pt_dist_sq)) + { + /* Simplex lies on origin */ + overlapping = 1; + break; + } + } + + //- Determine region of the simplex in which the origin lies + CLD_DBGSTEP; + Vec2 vab = SubVec2(s.b.p, s.a.p); + Vec2 vac = SubVec2(s.c.p, s.a.p); + Vec2 vbc = SubVec2(s.c.p, s.b.p); + + Vec2 rab_dir = PerpVec2TowardsDir(vab, NegVec2(vac)); + Vec2 rac_dir = PerpVec2TowardsDir(vac, NegVec2(vab)); + Vec2 rbc_dir = PerpVec2TowardsDir(vbc, vab); + + f32 rab_dot = DotVec2(rab_dir, NegVec2(s.a.p)); + f32 rac_dot = DotVec2(rac_dir, NegVec2(s.a.p)); + f32 rbc_dot = DotVec2(rbc_dir, NegVec2(s.b.p)); + + f32 vab_dot = DotVec2(vab, NegVec2(s.a.p)) / Vec2LenSq(vab); + f32 vac_dot = DotVec2(vac, NegVec2(s.a.p)) / Vec2LenSq(vac); + f32 vbc_dot = DotVec2(vbc, NegVec2(s.b.p)) / Vec2LenSq(vbc); + + if (rab_dot >= 0 && vab_dot >= 0 && vab_dot <= 1) + { + //- Region ab, remove c + num_removed = 1; + removed_a = s.c.p; + s.len = 2; + dir = rab_dir; /* Next third point is in direction of region ab */ + } + else if (rac_dot >= 0 && vac_dot >= 0 && vac_dot <= 1) + { + //- Region ac, remove b + num_removed = 1; + removed_a = s.b.p; + s.len = 2; + s.b = s.c; + dir = rac_dir; /* Next third point is in direction of region ac */ + } + else if (rbc_dot >= 0 && vbc_dot >= 0 && vbc_dot <= 1) + { + //- Region bc, remove a + num_removed = 1; + removed_a = s.a.p; + s.len = 2; + s.a = s.b; + s.b = s.c; + dir = rbc_dir; /* Next third point is in direction of region bc */ + } + else if (vab_dot <= 0 && vac_dot <= 0) + { + //- Region a, remove bc + num_removed = 2; + removed_a = s.b.p; + removed_b = s.c.p; + s.len = 1; + } + else if (vab_dot >= 1 && vbc_dot <= 0) + { + //- Region b, remove ac + num_removed = 2; + removed_a = s.a.p; + removed_b = s.c.p; + s.len = 1; + s.a = s.b; + } + else if (vac_dot >= 1 && vbc_dot >= 1) + { + //- Region c, remove ab + num_removed = 2; + removed_a = s.a.p; + removed_b = s.b.p; + s.len = 1; + s.a = s.c; + } + else + { + /* No region, must be in simplex */ + overlapping = 1; + break; + } + } + #if COLLIDER_DEBUG - abort : + abort: #endif - CLD_GjkData result = { - .simplex = s, - .overlapping = overlapping, - .final_dir = dir, + CLD_GjkData result = { + .simplex = s, + .overlapping = overlapping, + .final_dir = dir, #if COLLIDER_DEBUG - .dbg_step = dbg_step + .dbg_step = dbg_step #endif - }; + }; - return result; + return result; } //////////////////////////////////////////////////////////// @@ -321,160 +323,160 @@ CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1, CLD_GjkData gjk_result, f32 min_unique_pt_dist_sq, u32 max_iterations) #endif { - TempArena scratch = BeginScratchNoConflict(); + TempArena scratch = BeginScratchNoConflict(); - CLD_MenkowskiFeature closest_feature = Zi; - Vec2 normal = Zi; + CLD_MenkowskiFeature closest_feature = Zi; + Vec2 normal = Zi; - CLD_MenkowskiPoint *proto = 0; - u32 proto_count = 0; - if (gjk_result.overlapping) + CLD_MenkowskiPoint *proto = 0; + u32 proto_count = 0; + if (gjk_result.overlapping) + { + CLD_MenkowskiSimplex s = gjk_result.simplex; + proto = ArenaNext(scratch.arena, CLD_MenkowskiPoint); { - CLD_MenkowskiSimplex s = gjk_result.simplex; - proto = ArenaNext(scratch.arena, CLD_MenkowskiPoint); + Assert(s.len == 3); + CLD_MenkowskiPoint *tmp = PushStructsNoZero(scratch.arena, CLD_MenkowskiPoint, 3); + tmp[0] = s.a; + tmp[1] = s.b; + tmp[2] = s.c; + proto_count = 3; + } + + i32 winding = WindingFromVec2(SubVec2(s.c.p, s.a.p), SubVec2(s.b.p, s.a.p)); + + u32 epa_iterations = 0; + for (;;) + { + ++epa_iterations; + + /* Find dir from origin to closest edge */ + /* FIXME: Winding order of ps & pe index */ + f32 closest_len_sq = F32Infinity; + CLD_MenkowskiPoint closest_a = Zi; + CLD_MenkowskiPoint closest_b = Zi; + u32 closest_b_index = 0; + for (u32 i = 0; i < proto_count; ++i) + { + u32 a_index = i; + u32 b_index = (i < proto_count - 1) ? (i + 1) : 0; + CLD_MenkowskiPoint a = proto[a_index]; + CLD_MenkowskiPoint b = proto[b_index]; + + Vec2 vab = SubVec2(b.p, a.p); + Vec2 vao = NegVec2(a.p); + + f32 proj_ratio = ClampF32(DotVec2(vao, vab) / Vec2LenSq(vab), 0, 1); + Vec2 proj = AddVec2(a.p, MulVec2(vab, proj_ratio)); + + f32 proj_len_sq = Vec2LenSq(proj); + if (proj_len_sq < closest_len_sq - min_unique_pt_dist_sq) { - Assert(s.len == 3); - CLD_MenkowskiPoint *tmp = PushStructsNoZero(scratch.arena, CLD_MenkowskiPoint, 3); - tmp[0] = s.a; - tmp[1] = s.b; - tmp[2] = s.c; - proto_count = 3; + closest_a = a; + closest_b = b; + closest_b_index = b_index; + closest_len_sq = proj_len_sq; + } + } + Vec2 vab = SubVec2(closest_b.p, closest_a.p); + + /* Find new point in dir */ + Vec2 dir = MulVec2(PerpVec2(vab), winding); + CLD_MenkowskiPoint m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); + + #if COLLIDER_DEBUG + { + /* If debug step count is reached, we still want to inspect the normal at the step */ + normal = NormVec2(dir); + closest_feature.a = closest_a; + closest_feature.b = closest_b; + closest_feature.len = 2; + } +#endif + + /* Check validity of new point */ + CLD_DBGSTEP; + { + b32 valid = 1; + + { + /* NOTE: Changing this value affects how stable normals are for circular colliders */ + //const f32 validity_epsilon = min_unique_pt_dist_sq; /* Arbitrary */ + //const f32 validity_epsilon = 0.00000000001f; /* Arbitrary */ + const f32 validity_epsilon = min_unique_pt_dist_sq; /* Arbitrary */ + + Vec2 vam = SubVec2(m.p, closest_a.p); + Vec2 vbm = SubVec2(closest_b.p, closest_a.p); + + f32 dot = DotVec2(vab, vam) / Vec2LenSq(vab); + + if (dot >= -validity_epsilon && dot <= 1 - validity_epsilon && (WedgeVec2(vab, vam) * -winding) >= -validity_epsilon) + { + /* New point is not between edge */ + valid = 0; + } + else if (Vec2LenSq(vam) < min_unique_pt_dist_sq || Vec2LenSq(vbm) < min_unique_pt_dist_sq) + { + /* New point is too close to existing */ + valid = 0; + } } - i32 winding = WindingFromVec2(SubVec2(s.c.p, s.a.p), SubVec2(s.b.p, s.a.p)); - - u32 epa_iterations = 0; - for (;;) + if (!valid || epa_iterations >= max_iterations) { - ++epa_iterations; - - /* Find dir from origin to closest edge */ - /* FIXME: Winding order of ps & pe index */ - f32 closest_len_sq = F32Infinity; - CLD_MenkowskiPoint closest_a = Zi; - CLD_MenkowskiPoint closest_b = Zi; - u32 closest_b_index = 0; - for (u32 i = 0; i < proto_count; ++i) - { - u32 a_index = i; - u32 b_index = (i < proto_count - 1) ? (i + 1) : 0; - CLD_MenkowskiPoint a = proto[a_index]; - CLD_MenkowskiPoint b = proto[b_index]; - - Vec2 vab = SubVec2(b.p, a.p); - Vec2 vao = NegVec2(a.p); - - f32 proj_ratio = ClampF32(DotVec2(vao, vab) / Vec2LenSq(vab), 0, 1); - Vec2 proj = AddVec2(a.p, MulVec2(vab, proj_ratio)); - - f32 proj_len_sq = Vec2LenSq(proj); - if (proj_len_sq < closest_len_sq - min_unique_pt_dist_sq) - { - closest_a = a; - closest_b = b; - closest_b_index = b_index; - closest_len_sq = proj_len_sq; - } - } - Vec2 vab = SubVec2(closest_b.p, closest_a.p); - - /* Find new point in dir */ - Vec2 dir = MulVec2(PerpVec2(vab), winding); - CLD_MenkowskiPoint m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); - -#if COLLIDER_DEBUG - { - /* If debug step count is reached, we still want to inspect the normal at the step */ - normal = NormVec2(dir); - closest_feature.a = closest_a; - closest_feature.b = closest_b; - closest_feature.len = 2; - } -#endif - - /* Check validity of new point */ - CLD_DBGSTEP; - { - b32 valid = 1; - - { - /* NOTE: Changing this value affects how stable normals are for circular colliders */ - //const f32 validity_epsilon = min_unique_pt_dist_sq; /* Arbitrary */ - //const f32 validity_epsilon = 0.00000000001f; /* Arbitrary */ - const f32 validity_epsilon = min_unique_pt_dist_sq; /* Arbitrary */ - - Vec2 vam = SubVec2(m.p, closest_a.p); - Vec2 vbm = SubVec2(closest_b.p, closest_a.p); - - f32 dot = DotVec2(vab, vam) / Vec2LenSq(vab); - - if (dot >= -validity_epsilon && dot <= 1 - validity_epsilon && (WedgeVec2(vab, vam) * -winding) >= -validity_epsilon) - { - /* New point is not between edge */ - valid = 0; - } - else if (Vec2LenSq(vam) < min_unique_pt_dist_sq || Vec2LenSq(vbm) < min_unique_pt_dist_sq) - { - /* New point is too close to existing */ - valid = 0; - } - } - - if (!valid || epa_iterations >= max_iterations) - { - normal = NormVec2(dir); - closest_feature.a = closest_a; - closest_feature.b = closest_b; - closest_feature.len = 2; - break; - } - } - - /* Expand prototype */ - PushStructNoZero(scratch.arena, CLD_MenkowskiPoint); - ++proto_count; - - /* Shift points in prototype to make room */ - for (u32 i = proto_count - 1; i > closest_b_index; --i) - { - u32 shift_from = (i > 0) ? i - 1 : proto_count - 1; - u32 shift_to = i; - proto[shift_to] = proto[shift_from]; - } - - /* Insert new point into prototype */ - proto[closest_b_index] = m; + normal = NormVec2(dir); + closest_feature.a = closest_a; + closest_feature.b = closest_b; + closest_feature.len = 2; + break; } + } + + /* Expand prototype */ + PushStructNoZero(scratch.arena, CLD_MenkowskiPoint); + ++proto_count; + + /* Shift points in prototype to make room */ + for (u32 i = proto_count - 1; i > closest_b_index; --i) + { + u32 shift_from = (i > 0) ? i - 1 : proto_count - 1; + u32 shift_to = i; + proto[shift_to] = proto[shift_from]; + } + + /* Insert new point into prototype */ + proto[closest_b_index] = m; } - else - { - normal = NormVec2(gjk_result.final_dir); - closest_feature.len = gjk_result.simplex.len; - closest_feature.a = gjk_result.simplex.a; - closest_feature.b = gjk_result.simplex.b; - } + } + else + { + normal = NormVec2(gjk_result.final_dir); + closest_feature.len = gjk_result.simplex.len; + closest_feature.a = gjk_result.simplex.a; + closest_feature.b = gjk_result.simplex.b; + } #if COLLIDER_DEBUG - abort : + abort: #endif - CLD_EpaData result = { - .normal = normal, - .closest_feature = closest_feature - }; + CLD_EpaData result = { + .normal = normal, + .closest_feature = closest_feature + }; #if COLLIDER_DEBUG - result.dbg_step = dbg_step; - u32 len = MinU32(proto_count, countof(result.prototype.points)); - for (u32 i = 0; i < len; ++i) - { - result.prototype.points[i] = proto[i].p; - } - result.prototype.len = len; + result.dbg_step = dbg_step; + u32 len = MinU32(proto_count, countof(result.prototype.points)); + for (u32 i = 0; i < len; ++i) + { + result.prototype.points[i] = proto[i].p; + } + result.prototype.len = len; #endif - EndScratch(scratch); - return result; + EndScratch(scratch); + return result; } //////////////////////////////////////////////////////////// @@ -482,55 +484,55 @@ CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf CLD_ClippedLine CLD_ClipLineToLine(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1, Vec2 normal) { - Vec2 vab0 = SubVec2(b0, a0); - Vec2 vab1 = SubVec2(b1, a1); - Vec2 va0a1 = SubVec2(a1, a0); - Vec2 vb0b1 = SubVec2(b1, b0); - f32 vab0_w = WedgeVec2(vab0, normal); - f32 vab1_w = WedgeVec2(vab1, normal); - f32 va0a1_w = WedgeVec2(va0a1, normal); - f32 vb0b1_w = WedgeVec2(vb0b1, normal); + Vec2 vab0 = SubVec2(b0, a0); + Vec2 vab1 = SubVec2(b1, a1); + Vec2 va0a1 = SubVec2(a1, a0); + Vec2 vb0b1 = SubVec2(b1, b0); + f32 vab0_w = WedgeVec2(vab0, normal); + f32 vab1_w = WedgeVec2(vab1, normal); + f32 va0a1_w = WedgeVec2(va0a1, normal); + f32 vb0b1_w = WedgeVec2(vb0b1, normal); - /* FIXME: Handle 0 denominator */ - f32 a0t; - f32 b0t; - { - f32 w = 1 / vab0_w; - a0t = ClampF32(va0a1_w * w, 0, 1); - b0t = ClampF32(vb0b1_w * -w, 0, 1); - } - f32 a1t; - f32 b1t; - { - f32 w = 1 / vab1_w; - a1t = ClampF32(-va0a1_w * w, 0, 1); - b1t = ClampF32(-vb0b1_w * -w, 0, 1); - } + /* FIXME: Handle 0 denominator */ + f32 a0t; + f32 b0t; + { + f32 w = 1 / vab0_w; + a0t = ClampF32(va0a1_w * w, 0, 1); + b0t = ClampF32(vb0b1_w * -w, 0, 1); + } + f32 a1t; + f32 b1t; + { + f32 w = 1 / vab1_w; + a1t = ClampF32(-va0a1_w * w, 0, 1); + b1t = ClampF32(-vb0b1_w * -w, 0, 1); + } - CLD_ClippedLine result; - result.a0_clipped = AddVec2(a0, MulVec2(vab0, a0t)); - result.a1_clipped = AddVec2(a1, MulVec2(vab1, a1t)); - result.b0_clipped = AddVec2(b0, MulVec2(vab0, -b0t)); - result.b1_clipped = AddVec2(b1, MulVec2(vab1, -b1t)); - return result; + CLD_ClippedLine result; + result.a0_clipped = AddVec2(a0, MulVec2(vab0, a0t)); + result.a1_clipped = AddVec2(a1, MulVec2(vab1, a1t)); + result.b0_clipped = AddVec2(b0, MulVec2(vab0, -b0t)); + result.b1_clipped = AddVec2(b1, MulVec2(vab1, -b1t)); + return result; } Vec2 CLD_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal) { - Vec2 vab = SubVec2(b, a); - Vec2 vap = SubVec2(p, a); + Vec2 vab = SubVec2(b, a); + Vec2 vap = SubVec2(p, a); - f32 vab_w = WedgeVec2(vab, normal); - f32 vap_w = WedgeVec2(vap, normal); + f32 vab_w = WedgeVec2(vab, normal); + f32 vap_w = WedgeVec2(vap, normal); - f32 t; - { - f32 w = 1 / vab_w; - t = ClampF32(vap_w * w, 0, 1); - } + f32 t; + { + f32 w = 1 / vab_w; + t = ClampF32(vap_w * w, 0, 1); + } - Vec2 result = AddVec2(a, MulVec2(vab, t)); - return result; + Vec2 result = AddVec2(a, MulVec2(vab, t)); + return result; } //////////////////////////////////////////////////////////// @@ -538,280 +540,280 @@ Vec2 CLD_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal) CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1) { - CLD_CollisionData result = Zi; + CLD_CollisionData result = Zi; - const f32 tolerance = CLD_CollisionTolerance; - const f32 min_unique_pt_dist_sq = CLD_MinUniquePtDistSq; - const u32 max_epa_iterations = CLD_MaxEpaIterations; + const f32 tolerance = CLD_CollisionTolerance; + const f32 min_unique_pt_dist_sq = CLD_MinUniquePtDistSq; + const u32 max_epa_iterations = CLD_MaxEpaIterations; - CLD_CollisionPoint points[2] = Zi; - u32 num_points = 0; - b32 colliding = 0; - Vec2 normal = Zi; + CLD_CollisionPoint points[2] = Zi; + u32 num_points = 0; + b32 colliding = 0; + Vec2 normal = Zi; #if COLLIDER_DEBUG - u32 dbg_step = 0; + u32 dbg_step = 0; #endif - CLD_GjkData gjk_result = Zi; - CLD_EpaData epa_result = Zi; + CLD_GjkData gjk_result = Zi; + CLD_EpaData epa_result = Zi; - /* Run GJK */ + /* Run GJK */ #if COLLIDER_DEBUG - gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq, dbg_step); - dbg_step = gjk_result.dbg_step; -#else - gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq); + gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq, dbg_step); + dbg_step = gjk_result.dbg_step; + #else + gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq); #endif - CLD_DBGSTEP; + CLD_DBGSTEP; - /* Run EPA */ + /* Run EPA */ #if COLLIDER_DEBUG - epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations, dbg_step); - dbg_step = epa_result.dbg_step; -#else - epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations); + epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations, dbg_step); + dbg_step = epa_result.dbg_step; + #else + epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations); #endif - normal = epa_result.normal; - CLD_DBGSTEP; + normal = epa_result.normal; + CLD_DBGSTEP; - /* Determine collision */ - if (gjk_result.overlapping) + /* Determine collision */ + if (gjk_result.overlapping) + { + colliding = 1; + } + else + { + CLD_MenkowskiFeature f = epa_result.closest_feature; + /* Shapes not overlapping, determine if distance between shapes within tolerance */ + if (f.len == 1) { + Vec2 p = NegVec2(f.a.p); + if (Vec2LenSq(p) <= (tolerance * tolerance)) + { colliding = 1; + } } else { - CLD_MenkowskiFeature f = epa_result.closest_feature; - /* Shapes not overlapping, determine if distance between shapes within tolerance */ - if (f.len == 1) + /* Project origin to determine if distance is within tolerance. */ + Assert(f.len == 2); + Vec2 vab = SubVec2(f.b.p, f.a.p); + Vec2 vao = NegVec2(f.a.p); + f32 ratio = ClampF32(DotVec2(vab, vao) / DotVec2(vab, vab), 0, 1); + Vec2 p = AddVec2(f.a.p, MulVec2(vab, ratio)); + if (Vec2LenSq(p) <= (tolerance * tolerance)) + { + colliding = 1; + } + } + } + + /* Clip to determine final points */ + if (colliding) + { + /* Max vertices must be < 16 to fit in 4 bit ids */ + StaticAssert(countof(shape0->points) <= 16); + + CLD_MenkowskiFeature f = epa_result.closest_feature; + + { + b32 collapse0 = 0; + b32 collapse1 = 0; + + CLD_SupportPoint a0 = f.a.s0; + CLD_SupportPoint a1 = f.a.s1; + CLD_SupportPoint b0 = f.b.s0; + CLD_SupportPoint b1 = f.b.s1; + /* FIXME: Manually account for shapes w/ 1 & 2 points */ + if (f.len == 2) + { + if (a0.i == b0.i) { - Vec2 p = NegVec2(f.a.p); - if (Vec2LenSq(p) <= (tolerance * tolerance)) - { - colliding = 1; - } + if (shape0->count > 1) + { + b0 = CLD_SupportPointFromDirEx(shape0, xf0, normal, b0.i); + } + else + { + collapse0 = 1; + b0 = a0; + } + } + if (a1.i == b1.i) + { + if (shape1->count > 1) + { + b1 = CLD_SupportPointFromDirEx(shape1, xf1, NegVec2(normal), b1.i); + } + else + { + collapse1 = 1; + b1 = a1; + } + } + } + else + { + collapse0 = 1; + collapse1 = 1; + b0 = a0; + b1 = a1; + } + + Vec2 vab0 = SubVec2(b0.p, a0.p); + Vec2 vab1 = SubVec2(b1.p, a1.p); + Vec2 vab0_norm = NormVec2(vab0); + Vec2 vab1_norm = NormVec2(vab1); + + /* Swap points based on normal direction for consistent clipping */ + if (WedgeVec2(normal, vab0) < 0) + { + CLD_SupportPoint tmp = a0; + a0 = b0; + b0 = tmp; + vab0 = NegVec2(vab0); + } + if (WedgeVec2(normal, vab1) < 0) + { + CLD_SupportPoint tmp = a1; + a1 = b1; + b1 = tmp; + vab1 = NegVec2(vab1); + } + + /* Collapse lines that are too far in the direction of the normal to be accurately clipped */ + f32 collapse_epsilon = 0.05f; + collapse0 = collapse0 || AbsF32(WedgeVec2(normal, vab0_norm)) < collapse_epsilon; + collapse1 = collapse1 || AbsF32(WedgeVec2(normal, vab1_norm)) < collapse_epsilon; + + /* Collapse lines into deepest point */ + if (collapse0) + { + if (DotVec2(normal, vab0) > 0) + { + a0 = b0; } else { - /* Project origin to determine if distance is within tolerance. */ - Assert(f.len == 2); - Vec2 vab = SubVec2(f.b.p, f.a.p); - Vec2 vao = NegVec2(f.a.p); - f32 ratio = ClampF32(DotVec2(vab, vao) / DotVec2(vab, vab), 0, 1); - Vec2 p = AddVec2(f.a.p, MulVec2(vab, ratio)); - if (Vec2LenSq(p) <= (tolerance * tolerance)) - { - colliding = 1; - } + /* TODO: Remove this (debugging) */ + b0 = a0; } - } - - /* Clip to determine final points */ - if (colliding) - { - /* Max vertices must be < 16 to fit in 4 bit ids */ - StaticAssert(countof(shape0->points) <= 16); - - CLD_MenkowskiFeature f = epa_result.closest_feature; - + } + if (collapse1) + { + if (DotVec2(normal, vab1) < 0) { - b32 collapse0 = 0; - b32 collapse1 = 0; - - CLD_SupportPoint a0 = f.a.s0; - CLD_SupportPoint a1 = f.a.s1; - CLD_SupportPoint b0 = f.b.s0; - CLD_SupportPoint b1 = f.b.s1; - /* FIXME: Manually account for shapes w/ 1 & 2 points */ - if (f.len == 2) - { - if (a0.i == b0.i) - { - if (shape0->count > 1) - { - b0 = CLD_SupportPointFromDirEx(shape0, xf0, normal, b0.i); - } - else - { - collapse0 = 1; - b0 = a0; - } - } - if (a1.i == b1.i) - { - if (shape1->count > 1) - { - b1 = CLD_SupportPointFromDirEx(shape1, xf1, NegVec2(normal), b1.i); - } - else - { - collapse1 = 1; - b1 = a1; - } - } - } - else - { - collapse0 = 1; - collapse1 = 1; - b0 = a0; - b1 = a1; - } - - Vec2 vab0 = SubVec2(b0.p, a0.p); - Vec2 vab1 = SubVec2(b1.p, a1.p); - Vec2 vab0_norm = NormVec2(vab0); - Vec2 vab1_norm = NormVec2(vab1); - - /* Swap points based on normal direction for consistent clipping */ - if (WedgeVec2(normal, vab0) < 0) - { - CLD_SupportPoint tmp = a0; - a0 = b0; - b0 = tmp; - vab0 = NegVec2(vab0); - } - if (WedgeVec2(normal, vab1) < 0) - { - CLD_SupportPoint tmp = a1; - a1 = b1; - b1 = tmp; - vab1 = NegVec2(vab1); - } - - /* Collapse lines that are too far in the direction of the normal to be accurately clipped */ - f32 collapse_epsilon = 0.05f; - collapse0 = collapse0 || AbsF32(WedgeVec2(normal, vab0_norm)) < collapse_epsilon; - collapse1 = collapse1 || AbsF32(WedgeVec2(normal, vab1_norm)) < collapse_epsilon; - - /* Collapse lines into deepest point */ - if (collapse0) - { - if (DotVec2(normal, vab0) > 0) - { - a0 = b0; - } - else - { - /* TODO: Remove this (debugging) */ - b0 = a0; - } - } - if (collapse1) - { - if (DotVec2(normal, vab1) < 0) - { - a1 = b1; - } - else - { - /* TODO: Remove this (debugging) */ - b1 = a1; - } - } - - f32 a_sep = F32Infinity; - f32 b_sep = F32Infinity; - Vec2 a_midpoint = Zi; - Vec2 b_midpoint = Zi; - b32 ignore_a = 1; - b32 ignore_b = 1; - if (!collapse0 && !collapse1) - { - /* Clip line to line */ - CLD_ClippedLine clip_result = CLD_ClipLineToLine(a0.p, b0.p, a1.p, b1.p, normal); - Vec2 a0_clipped = clip_result.a0_clipped; - Vec2 a1_clipped = clip_result.a1_clipped; - Vec2 b0_clipped = clip_result.b0_clipped; - Vec2 b1_clipped = clip_result.b1_clipped; - /* Calc midpoint between clipped a & b */ - Vec2 va0a1_clipped = SubVec2(a1_clipped, a0_clipped); - Vec2 vb0b1_clipped = SubVec2(b1_clipped, b0_clipped); - a_sep = DotVec2(va0a1_clipped, normal); - b_sep = DotVec2(vb0b1_clipped, normal); - a_midpoint = AddVec2(a0_clipped, MulVec2(va0a1_clipped, 0.5f)); - b_midpoint = AddVec2(b0_clipped, MulVec2(vb0b1_clipped, 0.5f)); - ignore_a = 0; - ignore_b = 0; - Vec2 vfin = SubVec2(b_midpoint, a_midpoint); - if (Vec2LenSq(vfin) < (0.005 * 0.005)) - { - if (a_sep > b_sep) - { - ignore_a = 1; - } - else - { - ignore_b = 1; - } - } - result.a0_clipped = a0_clipped; - result.a1_clipped = a1_clipped; - result.b0_clipped = b0_clipped; - result.b1_clipped = b1_clipped; - } - else - { - Vec2 p0 = a0.p; - Vec2 p1 = a1.p; - /* TODO: Choose ID based on closest clipped point */ - if (collapse1 && !collapse0) - { - /* Project a1 onto vab0 */ - p0 = CLD_ClipPointToLine(a0.p, b0.p, a1.p, normal); - } - if (collapse0 && !collapse1) - { - /* Project a0 onto vab1 */ - p1 = CLD_ClipPointToLine(a1.p, b1.p, a0.p, normal); - } - /* Calc midpoint */ - Vec2 vsep = SubVec2(p1, p0); - a_midpoint = AddVec2(p0, MulVec2(vsep, 0.5f)); - a_sep = DotVec2(normal, p1) - DotVec2(normal, p0); - ignore_a = 0; - result.a0_clipped = p0; - result.a1_clipped = p1; - result.b0_clipped = p0; - result.b1_clipped = p1; - } - - /* Insert points */ - if (!ignore_a && a_sep < tolerance) - { - CLD_CollisionPoint *point = &points[num_points++]; - point->id = a0.i | (a1.i << 4); - point->separation = a_sep; - point->point = a_midpoint; - } - if (!ignore_b && b_sep < tolerance) - { - CLD_CollisionPoint *point = &points[num_points++]; - point->id = b0.i | (b1.i << 4); - point->separation = b_sep; - point->point = b_midpoint; - } - - result.a0 = a0.p; - result.a1 = a1.p; - result.b0 = b0.p; - result.b1 = b1.p; + a1 = b1; } + else + { + /* TODO: Remove this (debugging) */ + b1 = a1; + } + } + + f32 a_sep = F32Infinity; + f32 b_sep = F32Infinity; + Vec2 a_midpoint = Zi; + Vec2 b_midpoint = Zi; + b32 ignore_a = 1; + b32 ignore_b = 1; + if (!collapse0 && !collapse1) + { + /* Clip line to line */ + CLD_ClippedLine clip_result = CLD_ClipLineToLine(a0.p, b0.p, a1.p, b1.p, normal); + Vec2 a0_clipped = clip_result.a0_clipped; + Vec2 a1_clipped = clip_result.a1_clipped; + Vec2 b0_clipped = clip_result.b0_clipped; + Vec2 b1_clipped = clip_result.b1_clipped; + /* Calc midpoint between clipped a & b */ + Vec2 va0a1_clipped = SubVec2(a1_clipped, a0_clipped); + Vec2 vb0b1_clipped = SubVec2(b1_clipped, b0_clipped); + a_sep = DotVec2(va0a1_clipped, normal); + b_sep = DotVec2(vb0b1_clipped, normal); + a_midpoint = AddVec2(a0_clipped, MulVec2(va0a1_clipped, 0.5f)); + b_midpoint = AddVec2(b0_clipped, MulVec2(vb0b1_clipped, 0.5f)); + ignore_a = 0; + ignore_b = 0; + Vec2 vfin = SubVec2(b_midpoint, a_midpoint); + if (Vec2LenSq(vfin) < (0.005 * 0.005)) + { + if (a_sep > b_sep) + { + ignore_a = 1; + } + else + { + ignore_b = 1; + } + } + result.a0_clipped = a0_clipped; + result.a1_clipped = a1_clipped; + result.b0_clipped = b0_clipped; + result.b1_clipped = b1_clipped; + } + else + { + Vec2 p0 = a0.p; + Vec2 p1 = a1.p; + /* TODO: Choose ID based on closest clipped point */ + if (collapse1 && !collapse0) + { + /* Project a1 onto vab0 */ + p0 = CLD_ClipPointToLine(a0.p, b0.p, a1.p, normal); + } + if (collapse0 && !collapse1) + { + /* Project a0 onto vab1 */ + p1 = CLD_ClipPointToLine(a1.p, b1.p, a0.p, normal); + } + /* Calc midpoint */ + Vec2 vsep = SubVec2(p1, p0); + a_midpoint = AddVec2(p0, MulVec2(vsep, 0.5f)); + a_sep = DotVec2(normal, p1) - DotVec2(normal, p0); + ignore_a = 0; + result.a0_clipped = p0; + result.a1_clipped = p1; + result.b0_clipped = p0; + result.b1_clipped = p1; + } + + /* Insert points */ + if (!ignore_a && a_sep < tolerance) + { + CLD_CollisionPoint *point = &points[num_points++]; + point->id = a0.i | (a1.i << 4); + point->separation = a_sep; + point->point = a_midpoint; + } + if (!ignore_b && b_sep < tolerance) + { + CLD_CollisionPoint *point = &points[num_points++]; + point->id = b0.i | (b1.i << 4); + point->separation = b_sep; + point->point = b_midpoint; + } + + result.a0 = a0.p; + result.a1 = a1.p; + result.b0 = b0.p; + result.b1 = b1.p; } + } #if COLLIDER_DEBUG - result.solved = 1; -abort: - result.simplex = gjk_result.simplex; - result.prototype.len = epa_result.prototype.len; - CopyBytes(result.prototype.points, epa_result.prototype.points, sizeof(result.prototype.points[0]) * result.prototype.len); + result.solved = 1; + abort: + result.simplex = gjk_result.simplex; + result.prototype.len = epa_result.prototype.len; + CopyBytes(result.prototype.points, epa_result.prototype.points, sizeof(result.prototype.points[0]) * result.prototype.len); #endif - result.normal = normal; - result.points[0] = points[0]; - result.points[1] = points[1]; - result.num_points = num_points; - return result; + result.normal = normal; + result.points[0] = points[0]; + result.points[1] = points[1]; + result.num_points = num_points; + return result; } //////////////////////////////////////////////////////////// @@ -821,84 +823,84 @@ abort: CLD_ClosestPointData CLD_ClosestPointDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1) { - CLD_ClosestPointData result = Zi; + CLD_ClosestPointData result = Zi; - const f32 tolerance = CLD_CollisionTolerance; - const f32 min_unique_pt_dist_sq = CLD_MinUniquePtDistSq; - const u32 max_epa_iterations = CLD_MaxEpaIterations; + const f32 tolerance = CLD_CollisionTolerance; + const f32 min_unique_pt_dist_sq = CLD_MinUniquePtDistSq; + const u32 max_epa_iterations = CLD_MaxEpaIterations; - Vec2 p0 = Zi; - Vec2 p1 = Zi; - b32 colliding = 0; + Vec2 p0 = Zi; + Vec2 p1 = Zi; + b32 colliding = 0; #if COLLIDER_DEBUG - u32 dbg_step = 0; + u32 dbg_step = 0; #endif - CLD_GjkData gjk_result = Zi; - CLD_EpaData epa_result = Zi; + CLD_GjkData gjk_result = Zi; + CLD_EpaData epa_result = Zi; - //- Run GJK + //- Run GJK #if COLLIDER_DEBUG - gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq, dbg_step); - dbg_step = gjk_result.dbg_step; -#else - gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq); + gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq, dbg_step); + dbg_step = gjk_result.dbg_step; + #else + gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq); #endif - CLD_DBGSTEP; + CLD_DBGSTEP; - //- Run EPA + //- Run EPA #if COLLIDER_DEBUG - epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations, dbg_step); - dbg_step = epa_result.dbg_step; -#else - epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations); + epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations, dbg_step); + dbg_step = epa_result.dbg_step; + #else + epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations); #endif - CLD_DBGSTEP; + CLD_DBGSTEP; - //- Resolve points - colliding = gjk_result.overlapping; - CLD_MenkowskiFeature f = epa_result.closest_feature; - if (f.len == 1) + //- Resolve points + colliding = gjk_result.overlapping; + CLD_MenkowskiFeature f = epa_result.closest_feature; + if (f.len == 1) + { + p0 = f.a.s0.p; + p1 = f.a.s1.p; + colliding = gjk_result.overlapping || Vec2LenSq(NegVec2(f.a.p)) <= (tolerance * tolerance); + } + else + { + Assert(f.len == 2); + /* FIXME: Winding order dependent? */ + f32 ratio; { - p0 = f.a.s0.p; - p1 = f.a.s1.p; - colliding = gjk_result.overlapping || Vec2LenSq(NegVec2(f.a.p)) <= (tolerance * tolerance); - } - else - { - Assert(f.len == 2); - /* FIXME: Winding order dependent? */ - f32 ratio; - { - /* Determine ratio between edge a & b that projected origin lies */ - Vec2 vab = SubVec2(f.b.p, f.a.p); - Vec2 vao = NegVec2(f.a.p); - ratio = ClampF32(DotVec2(vab, vao) / DotVec2(vab, vab), 0, 1); - } - /* Shape 0 */ - p0 = SubVec2(f.b.s0.p, f.a.s0.p); - p0 = MulVec2(p0, ratio); - p0 = AddVec2(p0, f.a.s0.p); - /* Shape 1 */ - p1 = SubVec2(f.b.s1.p, f.a.s1.p); - p1 = MulVec2(p1, ratio); - p1 = AddVec2(p1, f.a.s1.p); - colliding = gjk_result.overlapping || Vec2LenSq(SubVec2(p1, p0)) <= (tolerance * tolerance); + /* Determine ratio between edge a & b that projected origin lies */ + Vec2 vab = SubVec2(f.b.p, f.a.p); + Vec2 vao = NegVec2(f.a.p); + ratio = ClampF32(DotVec2(vab, vao) / DotVec2(vab, vab), 0, 1); } + /* Shape 0 */ + p0 = SubVec2(f.b.s0.p, f.a.s0.p); + p0 = MulVec2(p0, ratio); + p0 = AddVec2(p0, f.a.s0.p); + /* Shape 1 */ + p1 = SubVec2(f.b.s1.p, f.a.s1.p); + p1 = MulVec2(p1, ratio); + p1 = AddVec2(p1, f.a.s1.p); + colliding = gjk_result.overlapping || Vec2LenSq(SubVec2(p1, p0)) <= (tolerance * tolerance); + } #if COLLIDER_DEBUG - result.solved = 1; -abort: - result.simplex = gjk_result.simplex; - result.prototype.len = epa_result.prototype.len; - CopyBytes(result.prototype.points, epa_result.prototype.points, sizeof(result.prototype.points[0]) * result.prototype.len); - result.simplex = gjk_result.simplex; + result.solved = 1; + abort: + result.simplex = gjk_result.simplex; + result.prototype.len = epa_result.prototype.len; + CopyBytes(result.prototype.points, epa_result.prototype.points, sizeof(result.prototype.points[0]) * result.prototype.len); + result.simplex = gjk_result.simplex; #endif - result.p0 = p0; - result.p1 = p1; - result.colliding = colliding; - return result; + result.p0 = p0; + result.p1 = p1; + result.colliding = colliding; + return result; } //////////////////////////////////////////////////////////// @@ -908,80 +910,80 @@ abort: * Returns time of impact in range [0, 1]. */ f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Xform xf0_t0, Xform xf1_t0, Xform xf0_t1, Xform xf1_t1, f32 tolerance, u32 max_iterations) { - f32 t0 = 0; - f32 t1 = 1; - f32 t0_sep = 0; - f32 t1_sep = 0; - f32 t = 0; - f32 t_sep = F32Infinity; + f32 t0 = 0; + f32 t1 = 1; + f32 t0_sep = 0; + f32 t1_sep = 0; + f32 t = 0; + f32 t_sep = F32Infinity; - /* Find direction p0 -> p1 at t=0 */ - Vec2 dir; - Vec2 dir_neg; + /* Find direction p0 -> p1 at t=0 */ + Vec2 dir; + Vec2 dir_neg; + { + CLD_ClosestPointData closest_points = CLD_ClosestPointDataFromShapes(c0, c1, xf0_t0, xf1_t0); + if (closest_points.colliding) { - CLD_ClosestPointData closest_points = CLD_ClosestPointDataFromShapes(c0, c1, xf0_t0, xf1_t0); - if (closest_points.colliding) - { - /* Shapes are penetrating at t=0 */ - return 0; - } - dir = SubVec2(closest_points.p1, closest_points.p0); - t0_sep = Vec2Len(dir); - dir = DivVec2(dir, t0_sep); /* Normalize */ - dir_neg = NegVec2(dir); + /* Shapes are penetrating at t=0 */ + return 0; + } + dir = SubVec2(closest_points.p1, closest_points.p0); + t0_sep = Vec2Len(dir); + dir = DivVec2(dir, t0_sep); /* Normalize */ + dir_neg = NegVec2(dir); + } + + { + Vec2 p0 = CLD_SupportPointFromDir(c0, xf0_t1, dir).p; + Vec2 p1 = CLD_SupportPointFromDir(c1, xf1_t1, dir_neg).p; + t1_sep = DotVec2(dir, SubVec2(p1, p0)); + if (t1_sep > 0) + { + /* Shapes are not penetrating at t=1 */ + return 1; + } + } + + u32 iteration = 0; + while (AbsF32(t_sep) > tolerance && iteration < max_iterations) + { + /* Use mix of bisection & 0 position method to find root + * (as described in https://box2d.org/files/ErinCatto_ContinuousCollision_GDC2013.pdf) */ + if (iteration & 1) + { + /* Bisect */ + t = (t1 + t0) / 2.0; + } + else + { + /* False position (fastest for linear case) */ + f32 m = (t1_sep - t0_sep) / (t1 - t0); + t = (-t1_sep / m) + t1; } + Xform xf0 = LerpXform(xf0_t0, xf0_t1, t); + Xform xf1 = LerpXform(xf1_t0, xf1_t1, t); + + Vec2 p0 = CLD_SupportPointFromDir(c0, xf0, dir).p; + Vec2 p1 = CLD_SupportPointFromDir(c1, xf1, dir_neg).p; + t_sep = DotVec2(dir, SubVec2(p1, p0)); + + /* Update bracket */ + if (t_sep > 0) { - Vec2 p0 = CLD_SupportPointFromDir(c0, xf0_t1, dir).p; - Vec2 p1 = CLD_SupportPointFromDir(c1, xf1_t1, dir_neg).p; - t1_sep = DotVec2(dir, SubVec2(p1, p0)); - if (t1_sep > 0) - { - /* Shapes are not penetrating at t=1 */ - return 1; - } + t0 = t; + t0_sep = t_sep; + } + else + { + t1 = t; + t1_sep = t_sep; } - u32 iteration = 0; - while (AbsF32(t_sep) > tolerance && iteration < max_iterations) - { - /* Use mix of bisection & 0 position method to find root - * (as described in https://box2d.org/files/ErinCatto_ContinuousCollision_GDC2013.pdf) */ - if (iteration & 1) - { - /* Bisect */ - t = (t1 + t0) / 2.0; - } - else - { - /* False position (fastest for linear case) */ - f32 m = (t1_sep - t0_sep) / (t1 - t0); - t = (-t1_sep / m) + t1; - } + ++iteration; + } - Xform xf0 = LerpXform(xf0_t0, xf0_t1, t); - Xform xf1 = LerpXform(xf1_t0, xf1_t1, t); - - Vec2 p0 = CLD_SupportPointFromDir(c0, xf0, dir).p; - Vec2 p1 = CLD_SupportPointFromDir(c1, xf1, dir_neg).p; - t_sep = DotVec2(dir, SubVec2(p1, p0)); - - /* Update bracket */ - if (t_sep > 0) - { - t0 = t; - t0_sep = t_sep; - } - else - { - t1 = t; - t1_sep = t_sep; - } - - ++iteration; - } - - return t; + return t; } //////////////////////////////////////////////////////////// @@ -990,41 +992,41 @@ f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Xform xf0_t0, Xform xf1_t0, X /* TODO: Remove this (debugging) */ Vec2Array CLD_Menkowski(Arena *arena, CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1, u32 detail) { - Vec2Array result = { .points = ArenaNext(arena, Vec2) }; - for (u64 i = 0; i < detail; ++i) + Vec2Array result = { .points = ArenaNext(arena, Vec2) }; + for (u64 i = 0; i < detail; ++i) + { + f32 angle = ((f32)i / detail) * (2 * Pi); + Vec2 dir = Vec2FromAngle(angle); + CLD_MenkowskiPoint m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); + if (result.count == 0 || !MatchVec2(m.p, result.points[result.count - 1])) { - f32 angle = ((f32)i / detail) * (2 * Pi); - Vec2 dir = Vec2FromAngle(angle); - CLD_MenkowskiPoint m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); - if (result.count == 0 || !MatchVec2(m.p, result.points[result.count - 1])) - { - *PushStructNoZero(arena, Vec2) = m.p; - ++result.count; - } + *PushStructNoZero(arena, Vec2) = m.p; + ++result.count; } - return result; + } + return result; } /* TODO: Remove this (debugging) */ Vec2Array CLD_PointCloud(Arena *arena, CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1) { - /* FIXME: Account for radius */ - Vec2Array result = { .points = ArenaNext(arena, Vec2) }; - Vec2 *points0 = shape0->points; - Vec2 *points1 = shape1->points; - u32 count0 = shape0->count; - u32 count1 = shape1->count; - for (u64 i = 0; i < count0; ++i) + /* FIXME: Account for radius */ + Vec2Array result = { .points = ArenaNext(arena, Vec2) }; + Vec2 *points0 = shape0->points; + Vec2 *points1 = shape1->points; + u32 count0 = shape0->count; + u32 count1 = shape1->count; + for (u64 i = 0; i < count0; ++i) + { + Vec2 p0 = MulXformV2(xf0, points0[i]); + for (u64 j = 0; j < count1; ++j) { - Vec2 p0 = MulXformV2(xf0, points0[i]); - for (u64 j = 0; j < count1; ++j) - { - Vec2 p1 = MulXformV2(xf1, points1[j]); - *PushStructNoZero(arena, Vec2) = SubVec2(p0, p1); - ++result.count; - } + Vec2 p1 = MulXformV2(xf1, points1[j]); + *PushStructNoZero(arena, Vec2) = SubVec2(p0, p1); + ++result.count; } - return result; + } + return result; } //////////////////////////////////////////////////////////// @@ -1033,65 +1035,65 @@ Vec2Array CLD_PointCloud(Arena *arena, CLD_Shape *shape0, CLD_Shape *shape1, Xfo #if 0 b32 CLD_GjkBoolean(CLD_Shape *shape0, CLD_Shape *shape1) { - struct { Vec2 a, b, c; } s = Zi; + struct { Vec2 a, b, c; } s = Zi; - /* FIXME: Infinite loop when shapes exactly overlap same space? */ - Vec2 dir, p; + /* FIXME: Infinite loop when shapes exactly overlap same space? */ + Vec2 dir, p; - /* First point is support point in shape's general directions to eachother */ - dir = SubVec2(starting_point(shape1), starting_point(shape0)); - if (IsVec2Zero(dir)) dir = VEC2(1, 0); - s.a = CLD_MenkowskiPointFromDir(shape0, shape1, dir); + /* First point is support point in shape's general directions to eachother */ + dir = SubVec2(starting_point(shape1), starting_point(shape0)); + if (IsVec2Zero(dir)) dir = VEC2(1, 0); + s.a = CLD_MenkowskiPointFromDir(shape0, shape1, dir); - /* Second point is support point towards origin */ - dir = NegVec2(s.a); - p = CLD_MenkowskiPointFromDir(shape0, shape1, dir); - if (DotVec2(dir, p) >= 0) + /* Second point is support point towards origin */ + dir = NegVec2(s.a); + p = CLD_MenkowskiPointFromDir(shape0, shape1, dir); + if (DotVec2(dir, p) >= 0) + { + s.b = s.a; + s.a = p; + for (;;) { - s.b = s.a; - s.a = p; - for (;;) + /* Third point is support point in direction of line normal towards origin */ + dir = PerpVec2TowardsDir(SubVec2(s.b, s.a), NegVec2(s.a)); + p = CLD_MenkowskiPointFromDir(shape0, shape1, dir); + if (DotVec2(dir, p) < 0) + { + /* New point did not cross origin, collision impossible */ + break; + } + + s.c = s.b; + s.b = s.a; + s.a = p; + + Vec2 vab = SubVec2(s.b, s.a); + Vec2 vac = SubVec2(s.c, s.a); + Vec2 a_to_origin = NegVec2(s.a); + + dir = PerpVec2TowardsDir(vab, NegVec2(vac)); /* Normal of ab pointing away from c */ + if (DotVec2(dir, a_to_origin) >= 0) + { + /* Point is in region ab, remove c from simplex (will happen automatically next iteration) */ + } + else + { + /* Point is not in region ab */ + dir = PerpVec2TowardsDir(vac, NegVec2(vab)); /* Normal of ac pointing away from b */ + if (DotVec2(dir, a_to_origin) >= 0) { - /* Third point is support point in direction of line normal towards origin */ - dir = PerpVec2TowardsDir(SubVec2(s.b, s.a), NegVec2(s.a)); - p = CLD_MenkowskiPointFromDir(shape0, shape1, dir); - if (DotVec2(dir, p) < 0) - { - /* New point did not cross origin, collision impossible */ - break; - } - - s.c = s.b; - s.b = s.a; - s.a = p; - - Vec2 vab = SubVec2(s.b, s.a); - Vec2 vac = SubVec2(s.c, s.a); - Vec2 a_to_origin = NegVec2(s.a); - - dir = PerpVec2TowardsDir(vab, NegVec2(vac)); /* Normal of ab pointing away from c */ - if (DotVec2(dir, a_to_origin) >= 0) - { - /* Point is in region ab, remove c from simplex (will happen automatically next iteration) */ - } - else - { - /* Point is not in region ab */ - dir = PerpVec2TowardsDir(vac, NegVec2(vab)); /* Normal of ac pointing away from b */ - if (DotVec2(dir, a_to_origin) >= 0) - { - /* Point is in region ac, remove b from simplex */ - s.b = s.c; - } - else - { - /* Point is in simplex */ - return 1; - } - } + /* Point is in region ac, remove b from simplex */ + s.b = s.c; } + else + { + /* Point is in simplex */ + return 1; + } + } } + } - return 0; + return 0; } #endif diff --git a/src/collider/collider.h b/src/collider/collider.h index 3b9fb395..10be7e9a 100644 --- a/src/collider/collider.h +++ b/src/collider/collider.h @@ -15,9 +15,9 @@ Struct(CLD_Shape) { - Vec2 points[8]; - u32 count; - f32 radius; + Vec2 points[8]; + u32 count; + f32 radius; }; //////////////////////////////////////////////////////////// @@ -25,27 +25,27 @@ Struct(CLD_Shape) Struct(CLD_SupportPoint) { - Vec2 p; - u32 i; /* Index of original point in shape */ + Vec2 p; + u32 i; /* Index of original point in shape */ }; Struct(CLD_MenkowskiPoint) { - Vec2 p; /* Menkowski difference point */ - CLD_SupportPoint s0; /* Support point of first shape in dir */ - CLD_SupportPoint s1; /* Support point of second shape in -dir */ + Vec2 p; /* Menkowski difference point */ + CLD_SupportPoint s0; /* Support point of first shape in dir */ + CLD_SupportPoint s1; /* Support point of second shape in -dir */ }; Struct(CLD_MenkowskiSimplex) { - u32 len; - CLD_MenkowskiPoint a, b, c; + u32 len; + CLD_MenkowskiPoint a, b, c; }; Struct(CLD_MenkowskiFeature) { - u32 len; - CLD_MenkowskiPoint a, b; + u32 len; + CLD_MenkowskiPoint a, b; }; //////////////////////////////////////////////////////////// @@ -53,42 +53,42 @@ Struct(CLD_MenkowskiFeature) Struct(CLD_CollisionPoint) { - Vec2 point; - f32 separation; - u32 id; /* Based on polygon edge-to-edge */ + Vec2 point; + f32 separation; + u32 id; /* Based on polygon edge-to-edge */ }; Struct(CLD_Prototype) { - Vec2 points[64]; - u32 len; + Vec2 points[64]; + u32 len; }; Struct(CLD_CollisionData) { - Vec2 normal; - CLD_CollisionPoint points[2]; - u32 num_points; + Vec2 normal; + CLD_CollisionPoint points[2]; + u32 num_points; - /* For debugging */ - b32 solved; - CLD_MenkowskiSimplex simplex; - CLD_Prototype prototype; + /* For debugging */ + b32 solved; + CLD_MenkowskiSimplex simplex; + CLD_Prototype prototype; - /* For debugging */ - Vec2 a0, b0, a1, b1; - Vec2 a0_clipped, b0_clipped, a1_clipped, b1_clipped; + /* For debugging */ + Vec2 a0, b0, a1, b1; + Vec2 a0_clipped, b0_clipped, a1_clipped, b1_clipped; }; Struct(CLD_ClosestPointData) { - Vec2 p0, p1; - b32 colliding; + Vec2 p0, p1; + b32 colliding; - /* For debugging */ - b32 solved; - CLD_MenkowskiSimplex simplex; - CLD_Prototype prototype; + /* For debugging */ + b32 solved; + CLD_MenkowskiSimplex simplex; + CLD_Prototype prototype; }; //////////////////////////////////////////////////////////// @@ -96,8 +96,8 @@ Struct(CLD_ClosestPointData) Struct(CLD_ClippedLine) { - Vec2 a0_clipped, b0_clipped; - Vec2 a1_clipped, b1_clipped; + Vec2 a0_clipped, b0_clipped; + Vec2 a1_clipped, b1_clipped; }; //////////////////////////////////////////////////////////// @@ -105,16 +105,16 @@ Struct(CLD_ClippedLine) Struct(CLD_GjkData) { - CLD_MenkowskiSimplex simplex; - Vec2 final_dir; + CLD_MenkowskiSimplex simplex; + Vec2 final_dir; - /* If 1, simplex represents triangle inside of CLD_Menkowski difference - * encapsulating the origin. If 0, simplex represents the closest - * feature on CLD_Menkowski difference to the origin. */ - b32 overlapping; + /* If 1, simplex represents triangle inside of CLD_Menkowski difference + * encapsulating the origin. If 0, simplex represents the closest + * feature on CLD_Menkowski difference to the origin. */ + b32 overlapping; #if COLLIDER_DEBUG - u32 dbg_step; + u32 dbg_step; #endif }; @@ -123,12 +123,12 @@ Struct(CLD_GjkData) Struct(CLD_EpaData) { - Vec2 normal; - CLD_MenkowskiFeature closest_feature; /* Represents closest feature (edge or point) to origin on CLD_Menkowski difference */ + Vec2 normal; + CLD_MenkowskiFeature closest_feature; /* Represents closest feature (edge or point) to origin on CLD_Menkowski difference */ #if COLLIDER_DEBUG - CLD_Prototype prototype; - u32 dbg_step; + CLD_Prototype prototype; + u32 dbg_step; #endif }; @@ -139,17 +139,17 @@ Struct(CLD_EpaData) void CLD_DebugBreakable(void); #define CLD_DBGSTEP \ - dbg_step++; \ - if (dbg_step >= GetGstat(DebugSteps)) \ - { \ - goto abort; \ - } \ - else if (dbg_step >= GetGstat(DebugSteps) - 1) \ - { \ - CLD_DebugBreakable(); \ - } (void)0 + dbg_step++; \ + if (dbg_step >= GetGstat(DebugSteps)) \ + { \ + goto abort; \ + } \ + else if (dbg_step >= GetGstat(DebugSteps) - 1) \ + { \ + CLD_DebugBreakable(); \ + } (void)0 #else -#define CLD_DBGSTEP + #define CLD_DBGSTEP #endif //////////////////////////////////////////////////////////// diff --git a/src/config.h b/src/config.h index 6329442a..65e613bd 100644 --- a/src/config.h +++ b/src/config.h @@ -4,17 +4,17 @@ /* Window title */ #if IsRtcEnabled -# if IsDeveloperModeEnabled -# define WINDOW_TITLE "Debug (Developer Build)" -# else -# define WINDOW_TITLE "Debug" -# endif + #if IsDeveloperModeEnabled + #define WINDOW_TITLE "Debug (Developer Build)" + #else + #define WINDOW_TITLE "Debug" + #endif #else -# if IsDeveloperModeEnabled -# define WINDOW_TITLE "Power Play (Developer Build)" -# else -# define WINDOW_TITLE "Power Play" -# endif + #if IsDeveloperModeEnabled + #define WINDOW_TITLE "Power Play (Developer Build)" + #else + #define WINDOW_TITLE "Power Play" + #endif #endif #define DEFAULT_CAMERA_WIDTH (16) @@ -33,7 +33,7 @@ #define USER_INTERP_RATIO 1.2 #define USER_INTERP_ENABLED 1 - /* 64^2 = 4096 bins */ +/* 64^2 = 4096 bins */ #define SPACE_CELL_BINS_SQRT (64) #define SPACE_CELL_SIZE (1) @@ -56,11 +56,11 @@ #define SIM_PLAYER_AIM 1 #if 0 -# define SIM_MAX_LINEAR_VELOCITY 500 -# define SIM_MAX_ANGULAR_VELOCITY (Tau * 20) + #define SIM_MAX_LINEAR_VELOCITY 500 + #define SIM_MAX_ANGULAR_VELOCITY (Tau * 20) #else -# define SIM_MAX_LINEAR_VELOCITY F32Infinity -# define SIM_MAX_ANGULAR_VELOCITY F32Infinity + #define SIM_MAX_LINEAR_VELOCITY F32Infinity + #define SIM_MAX_ANGULAR_VELOCITY F32Infinity #endif #define COLLIDER_DEBUG 0 diff --git a/src/draw/draw.c b/src/draw/draw.c index 72b0b8cc..ae3bd294 100644 --- a/src/draw/draw.c +++ b/src/draw/draw.c @@ -5,9 +5,9 @@ D_SharedState D_shared_state = ZI; void D_Bootstrap(void) { - D_SharedState *g = &D_shared_state; - u32 pixel_white = 0xFFFFFFFF; - g->solid_white_texture = GPU_AcquireTexture(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, VEC2I32(1, 1), &pixel_white); + D_SharedState *g = &D_shared_state; + u32 pixel_white = 0xFFFFFFFF; + g->solid_white_texture = GPU_AcquireTexture(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, VEC2I32(1, 1), &pixel_white); } //////////////////////////////////////////////////////////// @@ -15,15 +15,15 @@ void D_Bootstrap(void) void D_DrawMaterial(GPU_RenderSig *sig, D_MaterialParams params) { - GPU_RenderCmdDesc cmd = ZI; - cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL; - cmd.material.xf = params.xf; - cmd.material.texture = params.texture; - cmd.material.clip = params.clip; - cmd.material.tint = params.tint; - cmd.material.is_light = params.is_light; - cmd.material.light_emittance = params.light_emittance; - GPU_PushRenderCmd(sig, &cmd); + GPU_RenderCmdDesc cmd = ZI; + cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL; + cmd.material.xf = params.xf; + cmd.material.texture = params.texture; + cmd.material.clip = params.clip; + cmd.material.tint = params.tint; + cmd.material.is_light = params.is_light; + cmd.material.light_emittance = params.light_emittance; + GPU_PushRenderCmd(sig, &cmd); } //////////////////////////////////////////////////////////// @@ -31,75 +31,75 @@ void D_DrawMaterial(GPU_RenderSig *sig, D_MaterialParams params) void D_DrawPolyEx(GPU_RenderSig *sig, Vec2Array vertices, GPU_Indices indices, u32 color) { - GPU_RenderCmdDesc cmd = ZI; - cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_SHAPE; - cmd.ui_shape.vertices = vertices; - cmd.ui_shape.indices = indices; - cmd.ui_shape.color = color; - GPU_PushRenderCmd(sig, &cmd); + GPU_RenderCmdDesc cmd = ZI; + cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_SHAPE; + cmd.ui_shape.vertices = vertices; + cmd.ui_shape.indices = indices; + cmd.ui_shape.color = color; + GPU_PushRenderCmd(sig, &cmd); } /* Draws a filled polygon using triangles in a fan pattern */ void D_DrawPoly(GPU_RenderSig *sig, Vec2Array vertices, u32 color) { - if (vertices.count >= 3) + if (vertices.count >= 3) + { + TempArena scratch = BeginScratchNoConflict(); + + u32 num_tris = vertices.count - 2; + u32 num_indices = num_tris * 3; + + /* Generate indices in a fan pattern */ + GPU_Indices indices = ZI; + indices.count = num_indices; + indices.indices = PushStructsNoZero(scratch.arena, u32, num_indices); + for (u32 i = 0; i < num_tris; ++i) { - TempArena scratch = BeginScratchNoConflict(); - - u32 num_tris = vertices.count - 2; - u32 num_indices = num_tris * 3; - - /* Generate indices in a fan pattern */ - GPU_Indices indices = ZI; - indices.count = num_indices; - indices.indices = PushStructsNoZero(scratch.arena, u32, num_indices); - for (u32 i = 0; i < num_tris; ++i) - { - u32 tri_offset = i * 3; - indices.indices[tri_offset + 0] = 0; - indices.indices[tri_offset + 1] = (i + 1); - indices.indices[tri_offset + 2] = (i + 2); - } - - D_DrawPolyEx(sig, vertices, indices, color); - - EndScratch(scratch); + u32 tri_offset = i * 3; + indices.indices[tri_offset + 0] = 0; + indices.indices[tri_offset + 1] = (i + 1); + indices.indices[tri_offset + 2] = (i + 2); } + + D_DrawPolyEx(sig, vertices, indices, color); + + EndScratch(scratch); + } } void D_DrawCircle(GPU_RenderSig *sig, Vec2 pos, f32 radius, u32 color, u32 detail) { - TempArena scratch = BeginScratchNoConflict(); + TempArena scratch = BeginScratchNoConflict(); - Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail); - for (u32 i = 0; i < detail; ++i) - { - f32 angle = ((f32)i / (f32)detail) * Tau; - Vec2 p = VEC2( - radius * CosF32(angle), - radius * SinF32(angle) - ); - points[i] = AddVec2(pos, p); - } + Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail); + for (u32 i = 0; i < detail; ++i) + { + f32 angle = ((f32)i / (f32)detail) * Tau; + Vec2 p = VEC2( + radius * CosF32(angle), + radius * SinF32(angle) + ); + points[i] = AddVec2(pos, p); + } - Vec2Array vertices = { - .points = points, - .count = detail - }; - D_DrawPoly(sig, vertices, color); + Vec2Array vertices = { + .points = points, + .count = detail + }; + D_DrawPoly(sig, vertices, color); - EndScratch(scratch); + EndScratch(scratch); } void D_DrawQuad(GPU_RenderSig *sig, Quad quad, u32 color) { - PERSIST const u32 indices_array[6] = { - 0, 1, 2, - 0, 2, 3 - }; - Vec2Array vertices = { .count = 4, .points = quad.e }; - GPU_Indices indices = { .count = 6, .indices = indices_array }; - D_DrawPolyEx(sig, vertices, indices, color); + PERSIST const u32 indices_array[6] = { + 0, 1, 2, + 0, 2, 3 + }; + Vec2Array vertices = { .count = 4, .points = quad.e }; + GPU_Indices indices = { .count = 6, .indices = indices_array }; + D_DrawPolyEx(sig, vertices, indices, color); } //////////////////////////////////////////////////////////// @@ -108,144 +108,144 @@ void D_DrawQuad(GPU_RenderSig *sig, Quad quad, u32 color) void D_DrawLineGradient(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, u32 start_color, u32 end_color) { #if 0 - D_SharedState *g = &D_shared_state; - Quad quad = QuadFromLine(start, end, thickness); - D_DrawMaterial(sig, D_MATERIALPARAMS(.texture = g->solid_white_texture, .tint0 = start_color, .tint1 = end_color, .quad = quad)); + D_SharedState *g = &D_shared_state; + Quad quad = QuadFromLine(start, end, thickness); + D_DrawMaterial(sig, D_MATERIALPARAMS(.texture = g->solid_white_texture, .tint0 = start_color, .tint1 = end_color, .quad = quad)); #else - /* Placeholder */ - Quad quad = QuadFromLine(start, end, thickness); - D_DrawQuad(sig, quad, start_color); + /* Placeholder */ + Quad quad = QuadFromLine(start, end, thickness); + D_DrawQuad(sig, quad, start_color); #endif } void D_DrawLine(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, u32 color) { - Quad quad = QuadFromLine(start, end, thickness); - D_DrawQuad(sig, quad, color); + Quad quad = QuadFromLine(start, end, thickness); + D_DrawQuad(sig, quad, color); } void D_DrawRay(GPU_RenderSig *sig, Vec2 pos, Vec2 rel, f32 thickness, u32 color) { - Quad quad = QuadFromRay(pos, rel, thickness); - D_DrawQuad(sig, quad, color); + Quad quad = QuadFromRay(pos, rel, thickness); + D_DrawQuad(sig, quad, color); } void D_DrawPolyLine(GPU_RenderSig *sig, Vec2Array points, b32 loop, f32 thickness, u32 color) { - if (points.count >= 2) + if (points.count >= 2) + { + for (u64 i = 1; i < points.count; ++i) { - for (u64 i = 1; i < points.count; ++i) - { - Vec2 p1 = points.points[i - 1]; - Vec2 p2 = points.points[i]; - Quad q = QuadFromLine(p1, p2, thickness); - D_DrawQuad(sig, q, color); - } - if (loop && points.count > 2) - { - Vec2 p1 = points.points[points.count - 1]; - Vec2 p2 = points.points[0]; - Quad q = QuadFromLine(p1, p2, thickness); - D_DrawQuad(sig, q, color); - } + Vec2 p1 = points.points[i - 1]; + Vec2 p2 = points.points[i]; + Quad q = QuadFromLine(p1, p2, thickness); + D_DrawQuad(sig, q, color); } + if (loop && points.count > 2) + { + Vec2 p1 = points.points[points.count - 1]; + Vec2 p2 = points.points[0]; + Quad q = QuadFromLine(p1, p2, thickness); + D_DrawQuad(sig, q, color); + } + } } void D_DrawCircleLine(GPU_RenderSig *sig, Vec2 pos, f32 radius, f32 thickness, u32 color, u32 detail) { - TempArena scratch = BeginScratchNoConflict(); + TempArena scratch = BeginScratchNoConflict(); - Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail); - for (u32 i = 0; i < detail; ++i) - { - f32 angle = ((f32)i / (f32)detail) * Tau; - Vec2 p = VEC2( - radius * CosF32(angle), - radius * SinF32(angle) - ); - points[i] = AddVec2(pos, p); - } + Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail); + for (u32 i = 0; i < detail; ++i) + { + f32 angle = ((f32)i / (f32)detail) * Tau; + Vec2 p = VEC2( + radius * CosF32(angle), + radius * SinF32(angle) + ); + points[i] = AddVec2(pos, p); + } - Vec2Array a = { - .points = points, - .count = detail - }; - D_DrawPolyLine(sig, a, 1, thickness, color); + Vec2Array a = { + .points = points, + .count = detail + }; + D_DrawPolyLine(sig, a, 1, thickness, color); - EndScratch(scratch); + EndScratch(scratch); } void D_DrawQuadLine(GPU_RenderSig *sig, Quad quad, f32 thickness, u32 color) { - Vec2 points[] = { quad.p0, quad.p1, quad.p2, quad.p3 }; - Vec2Array a = { .points = points, .count = countof(points) }; - D_DrawPolyLine(sig, a, 1, thickness, color); + Vec2 points[] = { quad.p0, quad.p1, quad.p2, quad.p3 }; + Vec2Array a = { .points = points, .count = countof(points) }; + D_DrawPolyLine(sig, a, 1, thickness, color); } void D_DrawArrowLine(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, f32 arrowhead_height, u32 color) { - const f32 head_width_ratio = 0.5f; /* Width of arrowhead relative to its length */ + const f32 head_width_ratio = 0.5f; /* Width of arrowhead relative to its length */ - const f32 max_height_to_line_ratio = 0.9f; /* Maximum length of arrowhead relative to total line length */ - arrowhead_height = MinF32(arrowhead_height, Vec2Len(SubVec2(end, start)) * max_height_to_line_ratio); + const f32 max_height_to_line_ratio = 0.9f; /* Maximum length of arrowhead relative to total line length */ + arrowhead_height = MinF32(arrowhead_height, Vec2Len(SubVec2(end, start)) * max_height_to_line_ratio); - Vec2 head_start_dir = SubVec2(start, end); - head_start_dir = NormVec2(head_start_dir); - head_start_dir = MulVec2(head_start_dir, arrowhead_height); + Vec2 head_start_dir = SubVec2(start, end); + head_start_dir = NormVec2(head_start_dir); + head_start_dir = MulVec2(head_start_dir, arrowhead_height); - Vec2 head_start = AddVec2(end, head_start_dir); + Vec2 head_start = AddVec2(end, head_start_dir); - Vec2 head_p1_dir = MulPerpVec2(head_start_dir, head_width_ratio); - Vec2 head_p2_dir = NegVec2(head_p1_dir); + Vec2 head_p1_dir = MulPerpVec2(head_start_dir, head_width_ratio); + Vec2 head_p2_dir = NegVec2(head_p1_dir); - Vec2 head_p1 = AddVec2(head_start, head_p1_dir); - Vec2 head_p2 = AddVec2(head_start, head_p2_dir); + Vec2 head_p1 = AddVec2(head_start, head_p1_dir); + Vec2 head_p2 = AddVec2(head_start, head_p2_dir); - Vec2 head_points[] = { end, head_p1, head_p2 }; - Vec2Array head_points_v2_array = { - .points = head_points, - .count = countof(head_points) - }; - D_DrawPoly(sig, head_points_v2_array, color); + Vec2 head_points[] = { end, head_p1, head_p2 }; + Vec2Array head_points_v2_array = { + .points = head_points, + .count = countof(head_points) + }; + D_DrawPoly(sig, head_points_v2_array, color); - Quad line_quad = QuadFromLine(start, head_start, thickness); - D_DrawQuad(sig, line_quad, color); + Quad line_quad = QuadFromLine(start, head_start, thickness); + D_DrawQuad(sig, line_quad, color); } void D_DrawArrowRay(GPU_RenderSig *sig, Vec2 pos, Vec2 rel, f32 thickness, f32 arrowhead_height, u32 color) { - Vec2 end = AddVec2(pos, rel); - D_DrawArrowLine(sig, pos, end, thickness, arrowhead_height, color); + Vec2 end = AddVec2(pos, rel); + D_DrawArrowLine(sig, pos, end, thickness, arrowhead_height, color); } void D_DrawColliderLine(GPU_RenderSig *sig, CLD_Shape shape, Xform shape_xf, f32 thickness, u32 color, u32 detail) { - TempArena scratch = BeginScratchNoConflict(); - Vec2Array poly = ZI; - if (shape.radius == 0) + TempArena scratch = BeginScratchNoConflict(); + Vec2Array poly = ZI; + if (shape.radius == 0) + { + poly.count = shape.count; + poly.points = PushStructsNoZero(scratch.arena, Vec2, shape.count); + for (u32 i = 0; i < shape.count; ++i) { - poly.count = shape.count; - poly.points = PushStructsNoZero(scratch.arena, Vec2, shape.count); - for (u32 i = 0; i < shape.count; ++i) - { - Vec2 p = MulXformV2(shape_xf, shape.points[i]); - poly.points[i] = p; - } + Vec2 p = MulXformV2(shape_xf, shape.points[i]); + poly.points[i] = p; } - else + } + else + { + poly.count = detail; + poly.points = PushStructsNoZero(scratch.arena, Vec2, detail); + for (u32 i = 0; i < detail; ++i) { - poly.count = detail; - poly.points = PushStructsNoZero(scratch.arena, Vec2, detail); - for (u32 i = 0; i < detail; ++i) - { - f32 angle = ((f32)i / (f32)detail) * Tau; - Vec2 dir = VEC2(CosF32(angle), SinF32(angle)); - Vec2 p = CLD_SupportPointFromDir(&shape, shape_xf, dir).p; - poly.points[i] = p; - } + f32 angle = ((f32)i / (f32)detail) * Tau; + Vec2 dir = VEC2(CosF32(angle), SinF32(angle)); + Vec2 p = CLD_SupportPointFromDir(&shape, shape_xf, dir).p; + poly.points[i] = p; } - D_DrawPolyLine(sig, poly, 1, thickness, color); - EndScratch(scratch); + } + D_DrawPolyLine(sig, poly, 1, thickness, color); + EndScratch(scratch); } //////////////////////////////////////////////////////////// @@ -253,27 +253,27 @@ void D_DrawColliderLine(GPU_RenderSig *sig, CLD_Shape shape, Xform shape_xf, f32 void D_DrawGrid(GPU_RenderSig *sig, Xform xf, u32 bg0_color, u32 bg1_color, u32 line_color, u32 x_color, u32 y_color, f32 thickness, f32 spacing, Vec2 offset) { - i32 grid_id = 0; - { - GPU_RenderCmdDesc cmd = ZI; - cmd.kind = GP_RENDER_CMD_KIND_PUSH_GRID; - cmd.grid.bg0_color = bg0_color; - cmd.grid.bg1_color = bg1_color; - cmd.grid.line_color = line_color; - cmd.grid.x_color = x_color; - cmd.grid.y_color = y_color; - cmd.grid.line_thickness = thickness; - cmd.grid.line_spacing = spacing; - cmd.grid.offset = offset; - grid_id = GPU_PushRenderCmd(sig, &cmd); - } - + i32 grid_id = 0; + { GPU_RenderCmdDesc cmd = ZI; - cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL; - cmd.material.xf = xf; - cmd.material.tint = Color_White; - cmd.material.grid_cmd_id = grid_id; - GPU_PushRenderCmd(sig, &cmd); + cmd.kind = GP_RENDER_CMD_KIND_PUSH_GRID; + cmd.grid.bg0_color = bg0_color; + cmd.grid.bg1_color = bg1_color; + cmd.grid.line_color = line_color; + cmd.grid.x_color = x_color; + cmd.grid.y_color = y_color; + cmd.grid.line_thickness = thickness; + cmd.grid.line_spacing = spacing; + cmd.grid.offset = offset; + grid_id = GPU_PushRenderCmd(sig, &cmd); + } + + GPU_RenderCmdDesc cmd = ZI; + cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL; + cmd.material.xf = xf; + cmd.material.tint = Color_White; + cmd.material.grid_cmd_id = grid_id; + GPU_PushRenderCmd(sig, &cmd); } //////////////////////////////////////////////////////////// @@ -281,190 +281,190 @@ void D_DrawGrid(GPU_RenderSig *sig, Xform xf, u32 bg0_color, u32 bg1_color, u32 void D_DrawUiRect(GPU_RenderSig *sig, D_UiRectParams params) { - GPU_RenderCmdDesc cmd = ZI; - cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_RECT; - cmd.ui_rect.xf = params.xf; - cmd.ui_rect.texture = params.texture; - cmd.ui_rect.clip = params.clip; - cmd.ui_rect.tint = params.tint; - GPU_PushRenderCmd(sig, &cmd); + GPU_RenderCmdDesc cmd = ZI; + cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_RECT; + cmd.ui_rect.xf = params.xf; + cmd.ui_rect.texture = params.texture; + cmd.ui_rect.clip = params.clip; + cmd.ui_rect.tint = params.tint; + GPU_PushRenderCmd(sig, &cmd); } //////////////////////////////////////////////////////////// //~ Text - /* Returns the rect of the text area */ +/* Returns the rect of the text area */ Rect draw_text(GPU_RenderSig *sig, D_TextParams params) { - TempArena scratch = BeginScratchNoConflict(); + TempArena scratch = BeginScratchNoConflict(); - f32 inv_font_image_width = 1.0 / (f32)params.font->image_width; - f32 inv_font_image_height = 1.0 / (f32)params.font->image_height; - f32 line_spacing = params.font->point_size * 1.5f * params.scale; + f32 inv_font_image_width = 1.0 / (f32)params.font->image_width; + f32 inv_font_image_height = 1.0 / (f32)params.font->image_height; + f32 line_spacing = params.font->point_size * 1.5f * params.scale; - //- Build line glyphs + //- Build line glyphs - u64 num_lines = 0; - f32 widest_line = 0; + u64 num_lines = 0; + f32 widest_line = 0; - D_TextLine *first_line = 0; - D_TextLine *last_line = 0; - f32 first_line_top_offset = 0; - f32 last_line_bottom_offset = 0; + D_TextLine *first_line = 0; + D_TextLine *last_line = 0; + f32 first_line_top_offset = 0; + f32 last_line_bottom_offset = 0; - if (params.str.len > 0) + if (params.str.len > 0) + { + b32 string_done = 0; + CodepointIter iter = BeginCodepointIter(params.str); + while (!string_done) { - b32 string_done = 0; - CodepointIter iter = BeginCodepointIter(params.str); - while (!string_done) + f32 line_width = 0; + f32 top_offset = 0; + f32 bottom_offset = 0; + u64 num_line_glyphs = 0; + D_TextGlyph *line_glyphs = PushDry(scratch.arena, D_TextGlyph); + + b32 line_done = 0; + while (!line_done) + { + string_done = !AdvanceCodepointIter(&iter); + if (string_done) { - f32 line_width = 0; - f32 top_offset = 0; - f32 bottom_offset = 0; - u64 num_line_glyphs = 0; - D_TextGlyph *line_glyphs = PushDry(scratch.arena, D_TextGlyph); - - b32 line_done = 0; - while (!line_done) - { - string_done = !AdvanceCodepointIter(&iter); - if (string_done) - { - line_done = 1; - } - else - { - u32 codepoint = iter.codepoint; - if (codepoint == '\n') - { - line_done = 1; - } - else - { - D_TextGlyph *tg = PushStruct(scratch.arena, D_TextGlyph); - ++num_line_glyphs; - F_Glyph *glyph = F_GetGlyph(params.font, codepoint); - tg->off_x = glyph->off_x * params.scale; - tg->off_y = glyph->off_y * params.scale; - tg->width = glyph->width * params.scale; - tg->height = glyph->height * params.scale; - tg->advance = glyph->advance * params.scale; - Rect glyph_atlas_rect = glyph->atlas_rect; - tg->clip = (ClipRect) { - { - glyph_atlas_rect.x * inv_font_image_width, - glyph_atlas_rect.y * inv_font_image_height - }, - { - (glyph_atlas_rect.x + glyph_atlas_rect.width) * inv_font_image_width, - (glyph_atlas_rect.y + glyph_atlas_rect.height) * inv_font_image_height - } - }; - line_width += tg->advance; - top_offset = MinF32(top_offset, tg->off_y); - bottom_offset = MaxF32(bottom_offset, tg->off_y + tg->height); - } - } - } - - /* Line ended */ - /* TODO: Only create nodes for non-empty lines. Embed line number in the node. */ - D_TextLine *node = PushStruct(scratch.arena, D_TextLine); - node->line_width = line_width; - node->num_glyphs = num_line_glyphs; - node->glyphs = line_glyphs; - if (last_line) - { - last_line->next = node; - } - else - { - first_line = node; - first_line_top_offset = top_offset; - } - last_line = node; - last_line_bottom_offset = bottom_offset; - widest_line = MaxF32(widest_line, line_width); - ++num_lines; + line_done = 1; } - EndCodepointIter(&iter); - } - - //- Determine text bounds - - Rect bounds = ZI; - bounds.x = params.pos.x; - bounds.y = params.pos.y; - bounds.width = widest_line; - bounds.height = num_lines * line_spacing + first_line_top_offset + last_line_bottom_offset; - - /* Offset bounds X */ - switch (params.offset_x) - { - case DRAW_TEXT_OFFSET_X_LEFT: break; - case DRAW_TEXT_OFFSET_X_CENTER: + else { - bounds.x -= bounds.width / 2.f; - } break; - case DRAW_TEXT_OFFSET_X_RIGHT: - { - bounds.x -= bounds.width; - } break; - } - - /* Offset bounds Y */ - switch (params.offset_y) - { - case DRAW_TEXT_OFFSET_Y_TOP: break; - case DRAW_TEXT_OFFSET_Y_CENTER: - { - bounds.y -= bounds.height / 2.f; - } break; - case DRAW_TEXT_OFFSET_Y_BOTTOM: - { - if (last_line) - { - bounds.y -= bounds.height + last_line_bottom_offset; - } - } break; - } - - //- Draw lines - - u64 line_number = 0; - for (D_TextLine *line = first_line; line; line = line->next) - { - Vec2 draw_pos = bounds.pos; - draw_pos.y += line_number * line_spacing - first_line_top_offset; - - /* Alignment */ - switch (params.alignment) - { - case DRAW_TEXT_ALIGNMENT_LEFT: break; - case DRAW_TEXT_ALIGNMENT_CENTER: - { - draw_pos.x += (bounds.width - line->line_width) / 2.f; - } break; - case DRAW_TEXT_ALIGNMENT_RIGHT: - { - draw_pos.x += bounds.width - line->line_width; - } break; + u32 codepoint = iter.codepoint; + if (codepoint == '\n') + { + line_done = 1; + } + else + { + D_TextGlyph *tg = PushStruct(scratch.arena, D_TextGlyph); + ++num_line_glyphs; + F_Glyph *glyph = F_GetGlyph(params.font, codepoint); + tg->off_x = glyph->off_x * params.scale; + tg->off_y = glyph->off_y * params.scale; + tg->width = glyph->width * params.scale; + tg->height = glyph->height * params.scale; + tg->advance = glyph->advance * params.scale; + Rect glyph_atlas_rect = glyph->atlas_rect; + tg->clip = (ClipRect) { + { + glyph_atlas_rect.x * inv_font_image_width, + glyph_atlas_rect.y * inv_font_image_height + }, + { + (glyph_atlas_rect.x + glyph_atlas_rect.width) * inv_font_image_width, + (glyph_atlas_rect.y + glyph_atlas_rect.height) * inv_font_image_height + } + }; + line_width += tg->advance; + top_offset = MinF32(top_offset, tg->off_y); + bottom_offset = MaxF32(bottom_offset, tg->off_y + tg->height); + } } + } - /* Draw glyphs in line */ - for (u64 i = 0; i < line->num_glyphs; ++i) - { - D_TextGlyph *tg = &line->glyphs[i]; - Vec2 pos = VEC2(draw_pos.x + tg->off_x, draw_pos.y + tg->off_y); - Vec2 size = VEC2(tg->width, tg->height); - Xform xf = XformFromRect(RectFromVec2(pos, size)); - D_DrawUiRect(sig, D_UIRECTPARAMS(.xf = xf, .texture = params.font->texture, .tint = params.color, .clip = tg->clip)); - draw_pos.x += tg->advance; + /* Line ended */ + /* TODO: Only create nodes for non-empty lines. Embed line number in the node. */ + D_TextLine *node = PushStruct(scratch.arena, D_TextLine); + node->line_width = line_width; + node->num_glyphs = num_line_glyphs; + node->glyphs = line_glyphs; + if (last_line) + { + last_line->next = node; + } + else + { + first_line = node; + first_line_top_offset = top_offset; + } + last_line = node; + last_line_bottom_offset = bottom_offset; + widest_line = MaxF32(widest_line, line_width); + ++num_lines; + } + EndCodepointIter(&iter); + } - } - ++line_number; + //- Determine text bounds + + Rect bounds = ZI; + bounds.x = params.pos.x; + bounds.y = params.pos.y; + bounds.width = widest_line; + bounds.height = num_lines * line_spacing + first_line_top_offset + last_line_bottom_offset; + + /* Offset bounds X */ + switch (params.offset_x) + { + case DRAW_TEXT_OFFSET_X_LEFT: break; + case DRAW_TEXT_OFFSET_X_CENTER: + { + bounds.x -= bounds.width / 2.f; + } break; + case DRAW_TEXT_OFFSET_X_RIGHT: + { + bounds.x -= bounds.width; + } break; + } + + /* Offset bounds Y */ + switch (params.offset_y) + { + case DRAW_TEXT_OFFSET_Y_TOP: break; + case DRAW_TEXT_OFFSET_Y_CENTER: + { + bounds.y -= bounds.height / 2.f; + } break; + case DRAW_TEXT_OFFSET_Y_BOTTOM: + { + if (last_line) + { + bounds.y -= bounds.height + last_line_bottom_offset; + } + } break; + } + + //- Draw lines + + u64 line_number = 0; + for (D_TextLine *line = first_line; line; line = line->next) + { + Vec2 draw_pos = bounds.pos; + draw_pos.y += line_number * line_spacing - first_line_top_offset; + + /* Alignment */ + switch (params.alignment) + { + case DRAW_TEXT_ALIGNMENT_LEFT: break; + case DRAW_TEXT_ALIGNMENT_CENTER: + { + draw_pos.x += (bounds.width - line->line_width) / 2.f; + } break; + case DRAW_TEXT_ALIGNMENT_RIGHT: + { + draw_pos.x += bounds.width - line->line_width; + } break; } - EndScratch(scratch); - return bounds; + /* Draw glyphs in line */ + for (u64 i = 0; i < line->num_glyphs; ++i) + { + D_TextGlyph *tg = &line->glyphs[i]; + Vec2 pos = VEC2(draw_pos.x + tg->off_x, draw_pos.y + tg->off_y); + Vec2 size = VEC2(tg->width, tg->height); + Xform xf = XformFromRect(RectFromVec2(pos, size)); + D_DrawUiRect(sig, D_UIRECTPARAMS(.xf = xf, .texture = params.font->texture, .tint = params.color, .clip = tg->clip)); + draw_pos.x += tg->advance; + + } + ++line_number; + } + + EndScratch(scratch); + return bounds; } diff --git a/src/draw/draw.h b/src/draw/draw.h index 6a60eadd..66d5be6e 100644 --- a/src/draw/draw.h +++ b/src/draw/draw.h @@ -3,17 +3,17 @@ Struct(D_MaterialParams) { - Xform xf; - GPU_Resource *texture; - ClipRect clip; - u32 tint; - b32 is_light; - Vec3 light_emittance; + Xform xf; + GPU_Resource *texture; + ClipRect clip; + u32 tint; + b32 is_light; + Vec3 light_emittance; }; #define D_MATERIALPARAMS(...) ((D_MaterialParams) { \ - .tint = Color_White, \ - .clip = AllClipped, \ - __VA_ARGS__ \ + .tint = Color_White, \ + .clip = AllClipped, \ + __VA_ARGS__ \ }) //////////////////////////////////////////////////////////// @@ -21,15 +21,15 @@ Struct(D_MaterialParams) Struct(D_UiRectParams) { - Xform xf; - GPU_Resource *texture; - ClipRect clip; - u32 tint; + Xform xf; + GPU_Resource *texture; + ClipRect clip; + u32 tint; }; #define D_UIRECTPARAMS(...) ((D_UiRectParams) { \ - .tint = Color_White, \ - .clip = AllClipped, \ - __VA_ARGS__ \ + .tint = Color_White, \ + .clip = AllClipped, \ + __VA_ARGS__ \ }) //////////////////////////////////////////////////////////// @@ -38,9 +38,9 @@ Struct(D_UiRectParams) /* How is text aligned within its area */ Enum(D_TextAlignment) { - DRAW_TEXT_ALIGNMENT_LEFT, /* Default */ - DRAW_TEXT_ALIGNMENT_CENTER, - DRAW_TEXT_ALIGNMENT_RIGHT + DRAW_TEXT_ALIGNMENT_LEFT, /* Default */ + DRAW_TEXT_ALIGNMENT_CENTER, + DRAW_TEXT_ALIGNMENT_RIGHT }; /* How does the specified text position relate to the text area. @@ -48,54 +48,54 @@ Enum(D_TextAlignment) * the specified position. */ Enum(D_TextOffsetX) { - DRAW_TEXT_OFFSET_X_LEFT, /* Default */ - DRAW_TEXT_OFFSET_X_CENTER, - DRAW_TEXT_OFFSET_X_RIGHT + DRAW_TEXT_OFFSET_X_LEFT, /* Default */ + DRAW_TEXT_OFFSET_X_CENTER, + DRAW_TEXT_OFFSET_X_RIGHT }; Enum(D_TextOffsetY) { - DRAW_TEXT_OFFSET_Y_TOP, /* Default */ - DRAW_TEXT_OFFSET_Y_CENTER, - DRAW_TEXT_OFFSET_Y_BOTTOM + DRAW_TEXT_OFFSET_Y_TOP, /* Default */ + DRAW_TEXT_OFFSET_Y_CENTER, + DRAW_TEXT_OFFSET_Y_BOTTOM }; Struct(D_TextGlyph) { - f32 off_x; - f32 off_y; - f32 width; - f32 height; - f32 advance; - ClipRect clip; + f32 off_x; + f32 off_y; + f32 width; + f32 height; + f32 advance; + ClipRect clip; }; Struct(D_TextLine) { - f32 line_width; - u32 num_glyphs; - D_TextGlyph *glyphs; - D_TextLine *next; + f32 line_width; + u32 num_glyphs; + D_TextGlyph *glyphs; + D_TextLine *next; }; Struct(D_TextParams) { - F_Font *font; - Vec2 pos; - f32 scale; - u32 color; - D_TextAlignment alignment; - D_TextOffsetX offset_x; - D_TextOffsetY offset_y; - String str; + F_Font *font; + Vec2 pos; + f32 scale; + u32 color; + D_TextAlignment alignment; + D_TextOffsetX offset_x; + D_TextOffsetY offset_y; + String str; }; #define D_TEXTPARAMS(...) ((D_TextParams) { \ - .scale = 1.0, \ - .alignment = DRAW_TEXT_ALIGNMENT_LEFT, \ - .offset_x = DRAW_TEXT_OFFSET_X_LEFT, \ - .offset_y = DRAW_TEXT_OFFSET_Y_TOP, \ - .color = Color_White, \ - __VA_ARGS__ \ + .scale = 1.0, \ + .alignment = DRAW_TEXT_ALIGNMENT_LEFT, \ + .offset_x = DRAW_TEXT_OFFSET_X_LEFT, \ + .offset_y = DRAW_TEXT_OFFSET_Y_TOP, \ + .color = Color_White, \ + __VA_ARGS__ \ }) //////////////////////////////////////////////////////////// @@ -103,7 +103,7 @@ Struct(D_TextParams) Struct(D_SharedState) { - GPU_Resource *solid_white_texture; + GPU_Resource *solid_white_texture; } extern D_shared_state; //////////////////////////////////////////////////////////// diff --git a/src/glyph_cache/glyph_cache.c b/src/glyph_cache/glyph_cache.c index f6bd6fb3..497c49f8 100644 --- a/src/glyph_cache/glyph_cache.c +++ b/src/glyph_cache/glyph_cache.c @@ -5,7 +5,7 @@ GC_Ctx GC = Zi; void GC_Bootstrap(void) { - OnAsyncTick(GC_TickAsync); + OnAsyncTick(GC_TickAsync); } //////////////////////////////////////////////////////////// @@ -13,15 +13,15 @@ void GC_Bootstrap(void) GC_FontKey GC_FontKeyFromResource(ResourceKey resource) { - GC_FontKey result = Zi; - result.r = resource; - return result; + GC_FontKey result = Zi; + result.r = resource; + return result; } u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc) { - /* TODO: Lower font-size precision to prevent unique hashes for slightly-different font sizes */ - return RandU64FromSeeds(desc.font.r.v, ((u64)desc.codepoint << 32) | *(u32 *)&desc.font_size); + /* TODO: Lower font-size precision to prevent unique hashes for slightly-different font sizes */ + return RandU64FromSeeds(desc.font.r.v, ((u64)desc.codepoint << 32) | *(u32 *)&desc.font_size); } //////////////////////////////////////////////////////////// @@ -30,189 +30,189 @@ u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc) /* TODO: Thread-local cache */ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size) { - GC_Run result = Zi; - TempArena scratch = BeginScratch(arena); - Arena *perm = PermArena(); + GC_Run result = Zi; + TempArena scratch = BeginScratch(arena); + Arena *perm = PermArena(); - u64 codepoints_count = 0; - u32 *codepoints = 0; + u64 codepoints_count = 0; + u32 *codepoints = 0; + { + String32 str32 = String32FromString(scratch.arena, str); + codepoints_count = str32.len; + codepoints = str32.text; + } + + ////////////////////////////// + //- Grab glyphs from cache + + u64 ready_glyphs_count = 0; + GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, codepoints_count); + + u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count); + u64 uncached_codepoints_count = 0; + + /* TODO: Include advances for glyphs in run that have rasterized but not finished uploading to atlas */ + u64 pending_glyphs_count = 0; + { + if (codepoints_count > 0) { - String32 str32 = String32FromString(scratch.arena, str); - codepoints_count = str32.len; - codepoints = str32.text; - } - - ////////////////////////////// - //- Grab glyphs from cache - - u64 ready_glyphs_count = 0; - GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, codepoints_count); - - u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count); - u64 uncached_codepoints_count = 0; - - /* TODO: Include advances for glyphs in run that have rasterized but not finished uploading to atlas */ - u64 pending_glyphs_count = 0; - { - if (codepoints_count > 0) + Lock lock = LockS(&GC.glyphs_mutex); + { + i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy); + for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx) { - Lock lock = LockS(&GC.glyphs_mutex); - { - i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy); - for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx) - { - u32 codepoint = codepoints[codepoint_idx]; + u32 codepoint = codepoints[codepoint_idx]; - GC_GlyphDesc desc = Zi; - desc.font = font; - desc.font_size = font_size; - desc.codepoint = codepoint; + GC_GlyphDesc desc = Zi; + desc.font = font; + desc.font_size = font_size; + desc.codepoint = codepoint; - u64 hash = GC_HashFromGlyphDesc(desc); - GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)]; - GC_Glyph *glyph = bin->first; - for (; glyph; glyph = glyph->next) - { - if (glyph->hash == hash) break; - } + u64 hash = GC_HashFromGlyphDesc(desc); + GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)]; + GC_Glyph *glyph = bin->first; + for (; glyph; glyph = glyph->next) + { + if (glyph->hash == hash) break; + } - if (glyph == 0) - { - uncached_codepoints[uncached_codepoints_count] = codepoint; - uncached_codepoints_count += 1; - } - else if (completion < Atomic64Fetch(&glyph->async_copy_completion_target)) - { - pending_glyphs_count += 1; - } - else - { - ready_glyphs[ready_glyphs_count] = glyph; - ready_glyphs_count += 1; - } - } - } - Unlock(&lock); + if (glyph == 0) + { + uncached_codepoints[uncached_codepoints_count] = codepoint; + uncached_codepoints_count += 1; + } + else if (completion < Atomic64Fetch(&glyph->async_copy_completion_target)) + { + pending_glyphs_count += 1; + } + else + { + ready_glyphs[ready_glyphs_count] = glyph; + ready_glyphs_count += 1; + } } + } + Unlock(&lock); } + } - ////////////////////////////// - //- Create cache entries + ////////////////////////////// + //- Create cache entries - u64 submit_cmds_count = 0; - GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count); - if (uncached_codepoints_count > 0) + u64 submit_cmds_count = 0; + GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count); + if (uncached_codepoints_count > 0) + { + Lock lock = LockE(&GC.glyphs_mutex); { - Lock lock = LockE(&GC.glyphs_mutex); + for (u64 uncached_codepoint_idx = 0; uncached_codepoint_idx < uncached_codepoints_count; ++uncached_codepoint_idx) + { + GC_GlyphDesc desc = Zi; + desc.font = font; + desc.font_size = font_size; + desc.codepoint = uncached_codepoints[uncached_codepoint_idx]; + + u64 hash = GC_HashFromGlyphDesc(desc); + GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)]; + GC_Glyph *glyph = bin->first; + for (; glyph; glyph = glyph->next) { - for (u64 uncached_codepoint_idx = 0; uncached_codepoint_idx < uncached_codepoints_count; ++uncached_codepoint_idx) - { - GC_GlyphDesc desc = Zi; - desc.font = font; - desc.font_size = font_size; - desc.codepoint = uncached_codepoints[uncached_codepoint_idx]; - - u64 hash = GC_HashFromGlyphDesc(desc); - GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)]; - GC_Glyph *glyph = bin->first; - for (; glyph; glyph = glyph->next) - { - if (glyph->hash == hash) break; - } - - if (glyph == 0) - { - glyph = PushStruct(perm, GC_Glyph); - glyph->desc = desc; - glyph->hash = hash; - Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max); - SllStackPush(bin->first, glyph); - /* Create cmd */ - { - GC_Cmd *cmd = &submit_cmds[submit_cmds_count]; - cmd->glyph = glyph; - ++submit_cmds_count; - } - } - } - } - Unlock(&lock); - } - - ////////////////////////////// - //- Submit cmds - - if (submit_cmds_count > 0) - { - Lock lock = LockE(&GC.submit.mutex); - for (u64 cmd_idx = 0; cmd_idx < submit_cmds_count; ++cmd_idx) - { - GC_Cmd *src = &submit_cmds[cmd_idx]; - GC_CmdNode *n = GC.submit.first_free; - if (n) - { - SllStackPop(GC.submit.first_free); - ZeroStruct(n); - } - else - { - n = PushStruct(perm, GC_CmdNode); - } - n->cmd = *src; - GC.submit.count += 1; - SllQueuePush(GC.submit.first, GC.submit.last, n); - } - Unlock(&lock); - SignalAsyncTick(); - } - - ////////////////////////////// - //- Create run from glyphs - - f32 baseline_pos = 0; - result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count); - result.rects_count = ready_glyphs_count; - for (u64 glyph_idx = 0; glyph_idx < ready_glyphs_count; ++glyph_idx) - { - GC_Glyph *glyph = ready_glyphs[glyph_idx]; - GC_RunRect *rect = &result.rects[glyph_idx]; - - rect->tex = glyph->atlas->tex_ref; - rect->tex_slice = glyph->tex_slice; - rect->tex_slice_uv = glyph->tex_slice_uv; - - rect->baseline_pos = baseline_pos; - rect->advance = glyph->advance; - - rect->bounds = glyph->bounds; - - if (glyph_idx == 0) - { - result.bounds = rect->bounds; - } - else - { - result.bounds = UnionRng2(result.bounds, rect->bounds); + if (glyph->hash == hash) break; } - baseline_pos += rect->advance; - result.baseline_length = MaxF32(result.baseline_length, baseline_pos); + if (glyph == 0) + { + glyph = PushStruct(perm, GC_Glyph); + glyph->desc = desc; + glyph->hash = hash; + Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max); + SllStackPush(bin->first, glyph); + /* Create cmd */ + { + GC_Cmd *cmd = &submit_cmds[submit_cmds_count]; + cmd->glyph = glyph; + ++submit_cmds_count; + } + } + } } + Unlock(&lock); + } - if (ready_glyphs_count > 0) + ////////////////////////////// + //- Submit cmds + + if (submit_cmds_count > 0) + { + Lock lock = LockE(&GC.submit.mutex); + for (u64 cmd_idx = 0; cmd_idx < submit_cmds_count; ++cmd_idx) { - GC_Glyph *glyph = ready_glyphs[0]; - result.font_size = glyph->font_size; - result.font_ascent = glyph->font_ascent; - result.font_descent = glyph->font_descent; - result.font_cap = glyph->font_cap; + GC_Cmd *src = &submit_cmds[cmd_idx]; + GC_CmdNode *n = GC.submit.first_free; + if (n) + { + SllStackPop(GC.submit.first_free); + ZeroStruct(n); + } + else + { + n = PushStruct(perm, GC_CmdNode); + } + n->cmd = *src; + GC.submit.count += 1; + SllQueuePush(GC.submit.first, GC.submit.last, n); + } + Unlock(&lock); + SignalAsyncTick(); + } + + ////////////////////////////// + //- Create run from glyphs + + f32 baseline_pos = 0; + result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count); + result.rects_count = ready_glyphs_count; + for (u64 glyph_idx = 0; glyph_idx < ready_glyphs_count; ++glyph_idx) + { + GC_Glyph *glyph = ready_glyphs[glyph_idx]; + GC_RunRect *rect = &result.rects[glyph_idx]; + + rect->tex = glyph->atlas->tex_ref; + rect->tex_slice = glyph->tex_slice; + rect->tex_slice_uv = glyph->tex_slice_uv; + + rect->baseline_pos = baseline_pos; + rect->advance = glyph->advance; + + rect->bounds = glyph->bounds; + + if (glyph_idx == 0) + { + result.bounds = rect->bounds; + } + else + { + result.bounds = UnionRng2(result.bounds, rect->bounds); } - // result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0; - result.ready = 1; + baseline_pos += rect->advance; + result.baseline_length = MaxF32(result.baseline_length, baseline_pos); + } - EndScratch(scratch); - return result; + if (ready_glyphs_count > 0) + { + GC_Glyph *glyph = ready_glyphs[0]; + result.font_size = glyph->font_size; + result.font_ascent = glyph->font_ascent; + result.font_descent = glyph->font_descent; + result.font_cap = glyph->font_cap; + } + + // result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0; + result.ready = 1; + + EndScratch(scratch); + return result; } //////////////////////////////////////////////////////////// @@ -220,162 +220,162 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick) { - GC_AsyncCtx *async = &GC.async_ctx; + GC_AsyncCtx *async = &GC.async_ctx; - ////////////////////////////// - //- Begin tick + ////////////////////////////// + //- Begin tick - /* TODO: Limit cmds processed per-tick */ + /* TODO: Limit cmds processed per-tick */ - if (lane->idx == 0) + if (lane->idx == 0) + { + ZeroStruct(&async->cmds); + + Lock lock = LockE(&GC.submit.mutex); { - ZeroStruct(&async->cmds); - - Lock lock = LockE(&GC.submit.mutex); - { - /* Pop cmds from submission queue */ - async->cmds.count = GC.submit.count; - async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count); - u64 cmd_idx = 0; - for (GC_CmdNode *n = GC.submit.first; n; n = n->next) - { - async->cmds.v[cmd_idx] = n->cmd; - ++cmd_idx; - } - /* Reset submission queue */ - GC.submit.first_free = GC.submit.first; - GC.submit.count = 0; - GC.submit.first = 0; - GC.submit.last = 0; - } - Unlock(&lock); + /* Pop cmds from submission queue */ + async->cmds.count = GC.submit.count; + async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count); + u64 cmd_idx = 0; + for (GC_CmdNode *n = GC.submit.first; n; n = n->next) + { + async->cmds.v[cmd_idx] = n->cmd; + ++cmd_idx; + } + /* Reset submission queue */ + GC.submit.first_free = GC.submit.first; + GC.submit.count = 0; + GC.submit.first = 0; + GC.submit.last = 0; } + Unlock(&lock); + } + + WaveSync(lane); + + if (async->cmds.count > 0) + { + ////////////////////////////// + //- Rasterize glyphs + + /* TODO: Process cmds unevenly to account for varying work size */ + + { + RngU64 cmd_idxs = WaveIdxRangeFromCount(lane, async->cmds.count); + for (u64 cmd_idx = cmd_idxs.min; cmd_idx < cmd_idxs.max; ++cmd_idx) + { + GC_Cmd *cmd = &async->cmds.v[cmd_idx]; + GC_Glyph *glyph = cmd->glyph; + ResourceKey resource = glyph->desc.font.r; + GC_GlyphDesc desc = glyph->desc; + TTF_GlyphResult ttf_result = TTF_RasterizeGlyphFromCodepoint(tick->arena, desc.codepoint, resource, desc.font_size);; + glyph->font_size = desc.font_size; + glyph->font_ascent = ttf_result.font_ascent; + glyph->font_descent = ttf_result.font_descent; + glyph->font_cap = ttf_result.font_cap; + glyph->advance = ttf_result.advance; + glyph->bounds = ttf_result.bounds; + cmd->rasterized = ttf_result; + } + } + + /* TODO: Only sync first lane? */ WaveSync(lane); - if (async->cmds.count > 0) + //////////////////////////// + //- Allocate atlas slices + + if (lane->idx == 0) { - ////////////////////////////// - //- Rasterize glyphs + G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy); + for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx) + { + GC_Cmd *cmd = &async->cmds.v[cmd_idx]; + GC_Glyph *glyph = cmd->glyph; + GC_GlyphDesc desc = glyph->desc; + TTF_GlyphResult ttf_result = cmd->rasterized; - /* TODO: Process cmds unevenly to account for varying work size */ + Vec2I32 image_dims = ttf_result.image_dims; + /* TODO: Use a more efficient atlas packing algorithm for less wasted space `*/ + GC_Atlas *atlas = GC.first_atlas; + b32 can_use_atlas = 0; + Vec2I32 pos_in_atlas = Zi; + while (can_use_atlas == 0) { - RngU64 cmd_idxs = WaveIdxRangeFromCount(lane, async->cmds.count); - for (u64 cmd_idx = cmd_idxs.min; cmd_idx < cmd_idxs.max; ++cmd_idx) + /* Create atlas */ + if (!atlas) + { + Arena *perm = PermArena(); + atlas = PushStruct(perm, GC_Atlas); + atlas->dims = VEC2I32(1024, 1024); { - GC_Cmd *cmd = &async->cmds.v[cmd_idx]; - GC_Glyph *glyph = cmd->glyph; - ResourceKey resource = glyph->desc.font.r; - GC_GlyphDesc desc = glyph->desc; - TTF_GlyphResult ttf_result = TTF_RasterizeGlyphFromCodepoint(tick->arena, desc.codepoint, resource, desc.font_size);; - glyph->font_size = desc.font_size; - glyph->font_ascent = ttf_result.font_ascent; - glyph->font_descent = ttf_result.font_descent; - glyph->font_cap = ttf_result.font_cap; - glyph->advance = ttf_result.advance; - glyph->bounds = ttf_result.bounds; - cmd->rasterized = ttf_result; + G_ArenaHandle gpu_perm = G_PermArena(); + atlas->tex = G_PushTexture2D( + gpu_perm, cl, + G_Format_R8G8B8A8_Unorm_Srgb, + atlas->dims, + G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present, + ); + atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex); } + SllStackPush(GC.first_atlas, atlas); + ++GC.atlases_count; + } + + /* Determine pos in atlas */ + pos_in_atlas = atlas->cur_pos; + atlas->cur_row_height = MaxI32(atlas->cur_row_height, image_dims.y); + if (pos_in_atlas.x + image_dims.x > atlas->dims.x); + { + atlas->cur_pos.x = 0; + atlas->cur_pos.y += atlas->cur_row_height; + atlas->cur_row_height = image_dims.y; + } + atlas->cur_pos.x += image_dims.x; + if (atlas->cur_pos.x < atlas->dims.x && atlas->cur_pos.y < atlas->dims.y) + { + can_use_atlas = 1; + } + else + { + atlas = 0; + } } - /* TODO: Only sync first lane? */ + /* Atlas info */ + glyph->atlas = atlas; + glyph->tex_slice = RNG2I32(pos_in_atlas, AddVec2I32(pos_in_atlas, image_dims)); + glyph->tex_slice_uv.p0.x = (f32)glyph->tex_slice.p0.x / (f32)atlas->dims.x; + glyph->tex_slice_uv.p0.y = (f32)glyph->tex_slice.p0.y / (f32)atlas->dims.x; + glyph->tex_slice_uv.p1.x = (f32)glyph->tex_slice.p1.x / (f32)atlas->dims.x; + glyph->tex_slice_uv.p1.y = (f32)glyph->tex_slice.p1.y / (f32)atlas->dims.x; - WaveSync(lane); - - //////////////////////////// - //- Allocate atlas slices - - if (lane->idx == 0) + /* Copy to atlas */ + u32 *image_pixels = ttf_result.image_pixels; + if (image_dims.x > 0 && image_dims.y > 0) { - G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy); - for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx) - { - GC_Cmd *cmd = &async->cmds.v[cmd_idx]; - GC_Glyph *glyph = cmd->glyph; - GC_GlyphDesc desc = glyph->desc; - TTF_GlyphResult ttf_result = cmd->rasterized; - - Vec2I32 image_dims = ttf_result.image_dims; - - /* TODO: Use a more efficient atlas packing algorithm for less wasted space `*/ - GC_Atlas *atlas = GC.first_atlas; - b32 can_use_atlas = 0; - Vec2I32 pos_in_atlas = Zi; - while (can_use_atlas == 0) - { - /* Create atlas */ - if (!atlas) - { - Arena *perm = PermArena(); - atlas = PushStruct(perm, GC_Atlas); - atlas->dims = VEC2I32(1024, 1024); - { - G_ArenaHandle gpu_perm = G_PermArena(); - atlas->tex = G_PushTexture2D( - gpu_perm, cl, - G_Format_R8G8B8A8_Unorm_Srgb, - atlas->dims, - G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present, - ); - atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex); - } - SllStackPush(GC.first_atlas, atlas); - ++GC.atlases_count; - } - - /* Determine pos in atlas */ - pos_in_atlas = atlas->cur_pos; - atlas->cur_row_height = MaxI32(atlas->cur_row_height, image_dims.y); - if (pos_in_atlas.x + image_dims.x > atlas->dims.x); - { - atlas->cur_pos.x = 0; - atlas->cur_pos.y += atlas->cur_row_height; - atlas->cur_row_height = image_dims.y; - } - atlas->cur_pos.x += image_dims.x; - if (atlas->cur_pos.x < atlas->dims.x && atlas->cur_pos.y < atlas->dims.y) - { - can_use_atlas = 1; - } - else - { - atlas = 0; - } - } - - /* Atlas info */ - glyph->atlas = atlas; - glyph->tex_slice = RNG2I32(pos_in_atlas, AddVec2I32(pos_in_atlas, image_dims)); - glyph->tex_slice_uv.p0.x = (f32)glyph->tex_slice.p0.x / (f32)atlas->dims.x; - glyph->tex_slice_uv.p0.y = (f32)glyph->tex_slice.p0.y / (f32)atlas->dims.x; - glyph->tex_slice_uv.p1.x = (f32)glyph->tex_slice.p1.x / (f32)atlas->dims.x; - glyph->tex_slice_uv.p1.y = (f32)glyph->tex_slice.p1.y / (f32)atlas->dims.x; - - /* Copy to atlas */ - u32 *image_pixels = ttf_result.image_pixels; - if (image_dims.x > 0 && image_dims.y > 0) - { - G_CopyCpuToTexture( - cl, - glyph->atlas->tex, VEC3I32(glyph->tex_slice.p0.x, glyph->tex_slice.p0.y, 0), - image_pixels, VEC3I32(image_dims.x, image_dims.y, 1), - RNG3I32( - VEC3I32(0, 0, 0), - VEC3I32(image_dims.x, image_dims.y, 1) - ) - ); - } - } - i64 completion_target = G_CommitCommandList(cl); - - /* Update completion targets */ - for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx) - { - GC_Cmd *cmd = &async->cmds.v[cmd_idx]; - GC_Glyph *glyph = cmd->glyph; - Atomic64Set(&glyph->async_copy_completion_target, completion_target); - } + G_CopyCpuToTexture( + cl, + glyph->atlas->tex, VEC3I32(glyph->tex_slice.p0.x, glyph->tex_slice.p0.y, 0), + image_pixels, VEC3I32(image_dims.x, image_dims.y, 1), + RNG3I32( + VEC3I32(0, 0, 0), + VEC3I32(image_dims.x, image_dims.y, 1) + ) + ); } + } + i64 completion_target = G_CommitCommandList(cl); + + /* Update completion targets */ + for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx) + { + GC_Cmd *cmd = &async->cmds.v[cmd_idx]; + GC_Glyph *glyph = cmd->glyph; + Atomic64Set(&glyph->async_copy_completion_target, completion_target); + } } + } } diff --git a/src/glyph_cache/glyph_cache.h b/src/glyph_cache/glyph_cache.h index e8ccafc7..3406747b 100644 --- a/src/glyph_cache/glyph_cache.h +++ b/src/glyph_cache/glyph_cache.h @@ -3,7 +3,7 @@ Struct(GC_FontKey) { - ResourceKey r; + ResourceKey r; }; //////////////////////////////////////////////////////////// @@ -11,13 +11,13 @@ Struct(GC_FontKey) Struct(GC_Atlas) { - GC_Atlas *next; + GC_Atlas *next; - Vec2I32 dims; - G_ResourceHandle tex; - G_Texture2DRef tex_ref; - Vec2I32 cur_pos; - i32 cur_row_height; + Vec2I32 dims; + G_ResourceHandle tex; + G_Texture2DRef tex_ref; + Vec2I32 cur_pos; + i32 cur_row_height; }; //////////////////////////////////////////////////////////// @@ -25,38 +25,38 @@ Struct(GC_Atlas) Struct(GC_GlyphDesc) { - GC_FontKey font; - f32 font_size; - u32 codepoint; + GC_FontKey font; + f32 font_size; + u32 codepoint; }; Struct(GC_Glyph) { - GC_Glyph *next; + GC_Glyph *next; - GC_GlyphDesc desc; - u64 hash; - Atomic64 async_copy_completion_target; + GC_GlyphDesc desc; + u64 hash; + Atomic64 async_copy_completion_target; - /* Font info */ - f32 font_size; - f32 font_ascent; - f32 font_descent; - f32 font_cap; + /* Font info */ + f32 font_size; + f32 font_ascent; + f32 font_descent; + f32 font_cap; - /* Layout info */ - f32 advance; - Rng2 bounds; + /* Layout info */ + f32 advance; + Rng2 bounds; - /* Atlas info */ - GC_Atlas *atlas; - Rng2I32 tex_slice; - Rng2 tex_slice_uv; + /* Atlas info */ + GC_Atlas *atlas; + Rng2I32 tex_slice; + Rng2 tex_slice_uv; }; Struct(GC_GlyphBin) { - GC_Glyph *first; + GC_Glyph *first; }; //////////////////////////////////////////////////////////// @@ -64,30 +64,30 @@ Struct(GC_GlyphBin) Struct(GC_RunRect) { - Rng2 bounds; /* Visual bounds in relation to the baseline */ - f32 baseline_pos; /* Horizontal distance from start of baseline */ - f32 advance; + Rng2 bounds; /* Visual bounds in relation to the baseline */ + f32 baseline_pos; /* Horizontal distance from start of baseline */ + f32 advance; - G_Texture2DRef tex; - Rng2I32 tex_slice; - Rng2 tex_slice_uv; + G_Texture2DRef tex; + Rng2I32 tex_slice; + Rng2 tex_slice_uv; }; Struct(GC_Run) { - /* Run data */ - Rng2 bounds; /* Visual bounds of the run in relation to the baseline */ - f32 baseline_length; - u64 rects_count; - GC_RunRect *rects; + /* Run data */ + Rng2 bounds; /* Visual bounds of the run in relation to the baseline */ + f32 baseline_length; + u64 rects_count; + GC_RunRect *rects; - /* Font info */ - f32 font_size; - f32 font_ascent; - f32 font_descent; - f32 font_cap; + /* Font info */ + f32 font_size; + f32 font_ascent; + f32 font_descent; + f32 font_cap; - b32 ready; + b32 ready; }; //////////////////////////////////////////////////////////// @@ -95,16 +95,16 @@ Struct(GC_Run) Struct(GC_Cmd) { - GC_Glyph *glyph; + GC_Glyph *glyph; - /* Async temporary data */ - TTF_GlyphResult rasterized; + /* Async temporary data */ + TTF_GlyphResult rasterized; }; Struct(GC_CmdNode) { - GC_CmdNode *next; - GC_Cmd cmd; + GC_CmdNode *next; + GC_Cmd cmd; }; //////////////////////////////////////////////////////////// @@ -112,31 +112,31 @@ Struct(GC_CmdNode) Struct(GC_AsyncCtx) { - struct - { - u64 count; - GC_Cmd *v; - } cmds; + struct + { + u64 count; + GC_Cmd *v; + } cmds; }; Struct(GC_Ctx) { - Mutex glyphs_mutex; - GC_GlyphBin glyph_bins[16384]; + Mutex glyphs_mutex; + GC_GlyphBin glyph_bins[16384]; - u64 atlases_count; - GC_Atlas *first_atlas; + u64 atlases_count; + GC_Atlas *first_atlas; - struct - { - Mutex mutex; - u64 count; - GC_CmdNode *first; - GC_CmdNode *last; - GC_CmdNode *first_free; - } submit; + struct + { + Mutex mutex; + u64 count; + GC_CmdNode *first; + GC_CmdNode *last; + GC_CmdNode *first_free; + } submit; - GC_AsyncCtx async_ctx; + GC_AsyncCtx async_ctx; }; extern GC_Ctx GC; diff --git a/src/gpu/gpu_common.c b/src/gpu/gpu_common.c index 33981d45..8350e60e 100644 --- a/src/gpu/gpu_common.c +++ b/src/gpu/gpu_common.c @@ -6,57 +6,57 @@ ThreadLocal G_ArenaHandle G_t_perm_arena = Zi; void G_BootstrapCommon(void) { - G_SharedUtilState *g = &G_shared_util_state; + G_SharedUtilState *g = &G_shared_util_state; - G_ArenaHandle gpu_perm = G_PermArena(); + G_ArenaHandle gpu_perm = G_PermArena(); - G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct); + G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct); + { + /* Init quad index buffer */ { - /* Init quad index buffer */ - { - G_ResourceHandle quad_indices = Zi; - u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 }; - quad_indices = G_PushBuffer(gpu_perm, cl, u16, countof(quad_data)); - G_CopyCpuToBuffer(cl, quad_indices, 0, quad_data, RNGU64(0, sizeof(quad_data))); - g->quad_indices = G_IdxBuff16(quad_indices); - } - - /* Init point sampler */ - { - G_ResourceHandle pt_sampler = G_PushSampler(gpu_perm, cl, .filter = G_Filter_MinMagMipPoint); - g->basic_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler); - } - - /* Init noise texture */ - { - G_ResourceHandle noise_tex = Zi; - String noise_data = DataFromResource(ResourceKeyFromStore(&G_Resources, Lit("noise_128x128x64_16.dat"))); - Vec3I32 noise_dims = VEC3I32(128, 128, 64); - if (noise_data.len != noise_dims.x * noise_dims.y * noise_dims.z * 2) - { - Panic(Lit("Unexpected noise texture size")); - } - noise_tex = G_PushTexture3D( - gpu_perm, cl, - G_Format_R16_Uint, - noise_dims, - G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present - ); - G_CopyCpuToTexture( - cl, - noise_tex, VEC3I32(0, 0, 0), - noise_data.text, noise_dims, - RNG3I32(VEC3I32(0, 0, 0), noise_dims) - ); - - g->basic_noise = G_PushTexture3DRef(gpu_perm, noise_tex); - } - + G_ResourceHandle quad_indices = Zi; + u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 }; + quad_indices = G_PushBuffer(gpu_perm, cl, u16, countof(quad_data)); + G_CopyCpuToBuffer(cl, quad_indices, 0, quad_data, RNGU64(0, sizeof(quad_data))); + g->quad_indices = G_IdxBuff16(quad_indices); } - G_CommitCommandList(cl); - /* Barrier all queues until direct queue finishes initializing resources */ - G_Sync(G_QueueMask_Direct, G_QueueMask_All); + /* Init point sampler */ + { + G_ResourceHandle pt_sampler = G_PushSampler(gpu_perm, cl, .filter = G_Filter_MinMagMipPoint); + g->basic_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler); + } + + /* Init noise texture */ + { + G_ResourceHandle noise_tex = Zi; + String noise_data = DataFromResource(ResourceKeyFromStore(&G_Resources, Lit("noise_128x128x64_16.dat"))); + Vec3I32 noise_dims = VEC3I32(128, 128, 64); + if (noise_data.len != noise_dims.x * noise_dims.y * noise_dims.z * 2) + { + Panic(Lit("Unexpected noise texture size")); + } + noise_tex = G_PushTexture3D( + gpu_perm, cl, + G_Format_R16_Uint, + noise_dims, + G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present + ); + G_CopyCpuToTexture( + cl, + noise_tex, VEC3I32(0, 0, 0), + noise_data.text, noise_dims, + RNG3I32(VEC3I32(0, 0, 0), noise_dims) + ); + + g->basic_noise = G_PushTexture3DRef(gpu_perm, noise_tex); + } + + } + G_CommitCommandList(cl); + + /* Barrier all queues until direct queue finishes initializing resources */ + G_Sync(G_QueueMask_Direct, G_QueueMask_All); } //////////////////////////////////////////////////////////// @@ -66,56 +66,56 @@ void G_BootstrapCommon(void) G_ArenaHandle G_PermArena(void) { - G_ArenaHandle perm = G_t_perm_arena; - if (G_IsArenaNil(perm)) - { - G_t_perm_arena = G_AcquireArena(); - perm = G_t_perm_arena; - } - return perm; + G_ArenaHandle perm = G_t_perm_arena; + if (G_IsArenaNil(perm)) + { + G_t_perm_arena = G_AcquireArena(); + perm = G_t_perm_arena; + } + return perm; } //- Cpu -> Gpu upload G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc) { - G_ResourceHandle buffer = G_PushResource(gpu_arena, cl, (G_ResourceDesc) { .kind = G_ResourceKind_Buffer, .buffer = desc }); - G_CopyCpuToBuffer(cl, buffer, 0, src.text, RNGU64(0, src.len)); - G_MemorySync( - cl, buffer, - G_Stage_Copy, G_Access_CopyWrite, - G_Stage_All, G_Access_All - ); - return buffer; + G_ResourceHandle buffer = G_PushResource(gpu_arena, cl, (G_ResourceDesc) { .kind = G_ResourceKind_Buffer, .buffer = desc }); + G_CopyCpuToBuffer(cl, buffer, 0, src.text, RNGU64(0, src.len)); + G_MemorySync( + cl, buffer, + G_Stage_Copy, G_Access_CopyWrite, + G_Stage_All, G_Access_All + ); + return buffer; } //- Viewport / scissor Rng3 G_ViewportFromTexture(G_ResourceHandle texture) { - Vec2I32 dims = G_Count2D(texture); - return RNG3(VEC3(0, 0, 0), VEC3(dims.x, dims.y, 1)); + Vec2I32 dims = G_Count2D(texture); + return RNG3(VEC3(0, 0, 0), VEC3(dims.x, dims.y, 1)); } Rng2 G_ScissorFromTexture(G_ResourceHandle texture) { - Vec2I32 dims = G_Count2D(texture); - return RNG2(VEC2(0, 0), VEC2(dims.x, dims.y)); + Vec2I32 dims = G_Count2D(texture); + return RNG2(VEC2(0, 0), VEC2(dims.x, dims.y)); } //- Shared resources G_IndexBufferDesc G_QuadIndices(void) { - return G_shared_util_state.quad_indices; + return G_shared_util_state.quad_indices; } G_SamplerStateRef G_BasicSampler(void) { - return G_shared_util_state.basic_sampler; + return G_shared_util_state.basic_sampler; } G_Texture3DRef G_BasicNoiseTexture(void) { - return G_shared_util_state.basic_noise; + return G_shared_util_state.basic_noise; } diff --git a/src/gpu/gpu_common.h b/src/gpu/gpu_common.h index 2f5173b9..a070fcbc 100644 --- a/src/gpu/gpu_common.h +++ b/src/gpu/gpu_common.h @@ -3,10 +3,10 @@ Struct(G_SharedUtilState) { - /* Common shared resources */ - G_IndexBufferDesc quad_indices; - G_SamplerStateRef basic_sampler; - G_Texture3DRef basic_noise; + /* Common shared resources */ + G_IndexBufferDesc quad_indices; + G_SamplerStateRef basic_sampler; + G_Texture3DRef basic_noise; } extern G_shared_util_state; extern ThreadLocal G_ArenaHandle G_t_perm_arena; @@ -27,7 +27,7 @@ G_ArenaHandle G_PermArena(void); G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc); #define G_PushBufferFromString(_arena, _cl, _src, ...) \ - G_PushBufferFromString_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ }) + G_PushBufferFromString_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ }) //- Viewport / scissor diff --git a/src/gpu/gpu_core.h b/src/gpu/gpu_core.h index 6ab4be1d..89c4a5b6 100644 --- a/src/gpu/gpu_core.h +++ b/src/gpu/gpu_core.h @@ -18,43 +18,43 @@ Struct(G_SwapchainHandle) { u64 v; }; Enum(G_QueueKind) { - G_QueueKind_Direct = 0, + G_QueueKind_Direct = 0, #if G_IsMultiQueueEnabled - G_QueueKind_AsyncCompute = 1, - G_QueueKind_AsyncCopy = 2, + G_QueueKind_AsyncCompute = 1, + G_QueueKind_AsyncCopy = 2, #else - G_QueueKind_AsyncCompute = G_QueueKind_Direct, - G_QueueKind_AsyncCopy = G_QueueKind_Direct, + G_QueueKind_AsyncCompute = G_QueueKind_Direct, + G_QueueKind_AsyncCopy = G_QueueKind_Direct, #endif - G_NumQueues + G_NumQueues }; Enum(G_QueueMask) { - G_QueueMask_None = 0, - G_QueueMask_Direct = (1 << 0), + G_QueueMask_None = 0, + G_QueueMask_Direct = (1 << 0), #if G_IsMultiQueueEnabled - G_QueueMask_AsyncCompute = (1 << 1), - G_QueueMask_AsyncCopy = (1 << 2), + G_QueueMask_AsyncCompute = (1 << 1), + G_QueueMask_AsyncCopy = (1 << 2), #else - G_QueueMask_AsyncCompute = G_QueueMask_Direct, - G_QueueMask_AsyncCopy = G_QueueMask_Direct, + G_QueueMask_AsyncCompute = G_QueueMask_Direct, + G_QueueMask_AsyncCopy = G_QueueMask_Direct, #endif - G_QueueMask_All = (0xFFFFFFFF >> (32 - G_NumQueues)) + G_QueueMask_All = (0xFFFFFFFF >> (32 - G_NumQueues)) }; #define G_MaskFromQueue(queue_kind) (1 << queue_kind) Struct(G_QueueCompletions) { - i64 v[G_NumQueues]; /* Array of completions indexed by queue kind */ + i64 v[G_NumQueues]; /* Array of completions indexed by queue kind */ }; /* All waiters will wait until specified queues reach their value in the `completions` array */ Struct(G_QueueBarrierDesc) { - G_QueueCompletions completions; /* Completions that waiters should wait for */ - G_QueueMask wait_queues; /* Mask of queues that will wait for completions */ - b32 wait_cpu; /* Will the cpu wait for completion */ + G_QueueCompletions completions; /* Completions that waiters should wait for */ + G_QueueMask wait_queues; /* Mask of queues that will wait for completions */ + b32 wait_cpu; /* Will the cpu wait for completion */ }; //////////////////////////////////////////////////////////// @@ -63,129 +63,129 @@ Struct(G_QueueBarrierDesc) /* NOTE: Matches DirectX DXGI_FORMAT */ Enum(G_Format) { - G_Format_Unknown = 0, - G_Format_R32G32B32A32_Typeless = 1, - G_Format_R32G32B32A32_Float = 2, - G_Format_R32G32B32A32_Uint = 3, - G_Format_R32G32B32A32_Sint = 4, - G_Format_R32G32B32_Typeless = 5, - G_Format_R32G32B32_Float = 6, - G_Format_R32G32B32_Uint = 7, - G_Format_R32G32B32_Sint = 8, - G_Format_R16G16B16A16_Typeless = 9, - G_Format_R16G16B16A16_Float = 10, - G_Format_R16G16B16A16_Unorm = 11, - G_Format_R16G16B16A16_Uint = 12, - G_Format_R16G16B16A16_Snorm = 13, - G_Format_R16G16B16A16_Sint = 14, - G_Format_R32G32_Typeless = 15, - G_Format_R32G32_Float = 16, - G_Format_R32G32_Uint = 17, - G_Format_R32G32_Sint = 18, - G_Format_R32G8X24_Typeless = 19, - G_Format_D32_Float_S8X24_Uint = 20, - G_Format_R32_Float_X8X24_Typeless = 21, - G_Format_X32_Typeless_G8X24_Uint = 22, - G_Format_R10G10B10A2_Typeless = 23, - G_Format_R10G10B10A2_Unorm = 24, - G_Format_R10G10B10A2_Uint = 25, - G_Format_R11G11B10_Float = 26, - G_Format_R8G8B8A8_Typeless = 27, - G_Format_R8G8B8A8_Unorm = 28, - G_Format_R8G8B8A8_Unorm_Srgb = 29, - G_Format_R8G8B8A8_Uint = 30, - G_Format_R8G8B8A8_Snorm = 31, - G_Format_R8G8B8A8_Sint = 32, - G_Format_R16G16_Typeless = 33, - G_Format_R16G16_Float = 34, - G_Format_R16G16_Unorm = 35, - G_Format_R16G16_Uint = 36, - G_Format_R16G16_Snorm = 37, - G_Format_R16G16_Sint = 38, - G_Format_R32_Typeless = 39, - G_Format_D32_Float = 40, - G_Format_R32_Float = 41, - G_Format_R32_Uint = 42, - G_Format_R32_Sint = 43, - G_Format_R24G8_Typeless = 44, - G_Format_D24_Unorm_S8_Uint = 45, - G_Format_R24_Unorm_X8_Typeless = 46, - G_Format_X24_Typeless_G8_Uint = 47, - G_Format_R8G8_Typeless = 48, - G_Format_R8G8_Unorm = 49, - G_Format_R8G8_Uint = 50, - G_Format_R8G8_Snorm = 51, - G_Format_R8G8_Sint = 52, - G_Format_R16_Typeless = 53, - G_Format_R16_Float = 54, - G_Format_D16_Unorm = 55, - G_Format_R16_Unorm = 56, - G_Format_R16_Uint = 57, - G_Format_R16_Snorm = 58, - G_Format_R16_Sint = 59, - G_Format_R8_Typeless = 60, - G_Format_R8_Unorm = 61, - G_Format_R8_Uint = 62, - G_Format_R8_Snorm = 63, - G_Format_R8_Sint = 64, - G_Format_A8_Unorm = 65, - G_Format_R1_Unorm = 66, - G_Format_R9G9B9E5_SharedXP = 67, - G_Format_R8G8_B8G8_Unorm = 68, - G_Format_G8R8_G8B8_Unorm = 69, - G_Format_BC1_Typeless = 70, - G_Format_BC1_Unorm = 71, - G_Format_BC1_Unorm_Srgb = 72, - G_Format_BC2_Typeless = 73, - G_Format_BC2_Unorm = 74, - G_Format_BC2_Unorm_Srgb = 75, - G_Format_BC3_Typeless = 76, - G_Format_BC3_Unorm = 77, - G_Format_BC3_Unorm_Srgb = 78, - G_Format_BC4_Typeless = 79, - G_Format_BC4_Unorm = 80, - G_Format_BC4_Snorm = 81, - G_Format_BC5_Typeless = 82, - G_Format_BC5_Unorm = 83, - G_Format_BC5_Snorm = 84, - G_Format_B5G6R5_Unorm = 85, - G_Format_B5G5R5A1_Unorm = 86, - G_Format_B8G8R8A8_Unorm = 87, - G_Format_B8G8R8X8_Unorm = 88, - G_Format_R10G10B10_XR_BIAS_A2_Unorm = 89, - G_Format_B8G8R8A8_Typeless = 90, - G_Format_B8G8R8A8_Unorm_Srgb = 91, - G_Format_B8G8R8X8_Typeless = 92, - G_Format_B8G8R8X8_Unorm_Srgb = 93, - G_Format_BC6H_Typeless = 94, - G_Format_BC6H_UF16 = 95, - G_Format_BC6H_SF16 = 96, - G_Format_BC7_Typeless = 97, - G_Format_BC7_Unorm = 98, - G_Format_BC7_Unorm_Srgb = 99, - G_Format_AYUV = 100, - G_Format_Y410 = 101, - G_Format_Y416 = 102, - G_Format_NV12 = 103, - G_Format_P010 = 104, - G_Format_P016 = 105, - G_Format_420_Opaque = 106, - G_Format_YUY2 = 107, - G_Format_Y210 = 108, - G_Format_Y216 = 109, - G_Format_NV11 = 110, - G_Format_AI44 = 111, - G_Format_IA44 = 112, - G_Format_P8 = 113, - G_Format_A8P8 = 114, - G_Format_B4G4R4A4_Unorm = 115, - G_Format_P208 = 130, - G_Format_V208 = 131, - G_Format_V408 = 132, - G_Format_SamplerFeedbackMinMipOpaque = 189, - G_Format_SamplerFeedbackMipRegionUsedOpaque = 190, - G_Format_A4B4G4R4_Unorm = 191, - G_Format_Count = 192 + G_Format_Unknown = 0, + G_Format_R32G32B32A32_Typeless = 1, + G_Format_R32G32B32A32_Float = 2, + G_Format_R32G32B32A32_Uint = 3, + G_Format_R32G32B32A32_Sint = 4, + G_Format_R32G32B32_Typeless = 5, + G_Format_R32G32B32_Float = 6, + G_Format_R32G32B32_Uint = 7, + G_Format_R32G32B32_Sint = 8, + G_Format_R16G16B16A16_Typeless = 9, + G_Format_R16G16B16A16_Float = 10, + G_Format_R16G16B16A16_Unorm = 11, + G_Format_R16G16B16A16_Uint = 12, + G_Format_R16G16B16A16_Snorm = 13, + G_Format_R16G16B16A16_Sint = 14, + G_Format_R32G32_Typeless = 15, + G_Format_R32G32_Float = 16, + G_Format_R32G32_Uint = 17, + G_Format_R32G32_Sint = 18, + G_Format_R32G8X24_Typeless = 19, + G_Format_D32_Float_S8X24_Uint = 20, + G_Format_R32_Float_X8X24_Typeless = 21, + G_Format_X32_Typeless_G8X24_Uint = 22, + G_Format_R10G10B10A2_Typeless = 23, + G_Format_R10G10B10A2_Unorm = 24, + G_Format_R10G10B10A2_Uint = 25, + G_Format_R11G11B10_Float = 26, + G_Format_R8G8B8A8_Typeless = 27, + G_Format_R8G8B8A8_Unorm = 28, + G_Format_R8G8B8A8_Unorm_Srgb = 29, + G_Format_R8G8B8A8_Uint = 30, + G_Format_R8G8B8A8_Snorm = 31, + G_Format_R8G8B8A8_Sint = 32, + G_Format_R16G16_Typeless = 33, + G_Format_R16G16_Float = 34, + G_Format_R16G16_Unorm = 35, + G_Format_R16G16_Uint = 36, + G_Format_R16G16_Snorm = 37, + G_Format_R16G16_Sint = 38, + G_Format_R32_Typeless = 39, + G_Format_D32_Float = 40, + G_Format_R32_Float = 41, + G_Format_R32_Uint = 42, + G_Format_R32_Sint = 43, + G_Format_R24G8_Typeless = 44, + G_Format_D24_Unorm_S8_Uint = 45, + G_Format_R24_Unorm_X8_Typeless = 46, + G_Format_X24_Typeless_G8_Uint = 47, + G_Format_R8G8_Typeless = 48, + G_Format_R8G8_Unorm = 49, + G_Format_R8G8_Uint = 50, + G_Format_R8G8_Snorm = 51, + G_Format_R8G8_Sint = 52, + G_Format_R16_Typeless = 53, + G_Format_R16_Float = 54, + G_Format_D16_Unorm = 55, + G_Format_R16_Unorm = 56, + G_Format_R16_Uint = 57, + G_Format_R16_Snorm = 58, + G_Format_R16_Sint = 59, + G_Format_R8_Typeless = 60, + G_Format_R8_Unorm = 61, + G_Format_R8_Uint = 62, + G_Format_R8_Snorm = 63, + G_Format_R8_Sint = 64, + G_Format_A8_Unorm = 65, + G_Format_R1_Unorm = 66, + G_Format_R9G9B9E5_SharedXP = 67, + G_Format_R8G8_B8G8_Unorm = 68, + G_Format_G8R8_G8B8_Unorm = 69, + G_Format_BC1_Typeless = 70, + G_Format_BC1_Unorm = 71, + G_Format_BC1_Unorm_Srgb = 72, + G_Format_BC2_Typeless = 73, + G_Format_BC2_Unorm = 74, + G_Format_BC2_Unorm_Srgb = 75, + G_Format_BC3_Typeless = 76, + G_Format_BC3_Unorm = 77, + G_Format_BC3_Unorm_Srgb = 78, + G_Format_BC4_Typeless = 79, + G_Format_BC4_Unorm = 80, + G_Format_BC4_Snorm = 81, + G_Format_BC5_Typeless = 82, + G_Format_BC5_Unorm = 83, + G_Format_BC5_Snorm = 84, + G_Format_B5G6R5_Unorm = 85, + G_Format_B5G5R5A1_Unorm = 86, + G_Format_B8G8R8A8_Unorm = 87, + G_Format_B8G8R8X8_Unorm = 88, + G_Format_R10G10B10_XR_BIAS_A2_Unorm = 89, + G_Format_B8G8R8A8_Typeless = 90, + G_Format_B8G8R8A8_Unorm_Srgb = 91, + G_Format_B8G8R8X8_Typeless = 92, + G_Format_B8G8R8X8_Unorm_Srgb = 93, + G_Format_BC6H_Typeless = 94, + G_Format_BC6H_UF16 = 95, + G_Format_BC6H_SF16 = 96, + G_Format_BC7_Typeless = 97, + G_Format_BC7_Unorm = 98, + G_Format_BC7_Unorm_Srgb = 99, + G_Format_AYUV = 100, + G_Format_Y410 = 101, + G_Format_Y416 = 102, + G_Format_NV12 = 103, + G_Format_P010 = 104, + G_Format_P016 = 105, + G_Format_420_Opaque = 106, + G_Format_YUY2 = 107, + G_Format_Y210 = 108, + G_Format_Y216 = 109, + G_Format_NV11 = 110, + G_Format_AI44 = 111, + G_Format_IA44 = 112, + G_Format_P8 = 113, + G_Format_A8P8 = 114, + G_Format_B4G4R4A4_Unorm = 115, + G_Format_P208 = 130, + G_Format_V208 = 131, + G_Format_V408 = 132, + G_Format_SamplerFeedbackMinMipOpaque = 189, + G_Format_SamplerFeedbackMipRegionUsedOpaque = 190, + G_Format_A4B4G4R4_Unorm = 191, + G_Format_Count = 192 }; //////////////////////////////////////////////////////////// @@ -193,110 +193,110 @@ Enum(G_Format) Enum(G_Stage) { - G_Stage_None = 0, + G_Stage_None = 0, - /* Compute stages */ - G_Stage_ComputeShading = (1 << 1), + /* Compute stages */ + G_Stage_ComputeShading = (1 << 1), - /* Draw stages */ - G_Stage_IndexAssembly = (1 << 2), - G_Stage_VertexShading = (1 << 3), - G_Stage_PixelShading = (1 << 4), - G_Stage_DepthStencil = (1 << 5), - G_Stage_RenderTarget = (1 << 6), + /* Draw stages */ + G_Stage_IndexAssembly = (1 << 2), + G_Stage_VertexShading = (1 << 3), + G_Stage_PixelShading = (1 << 4), + G_Stage_DepthStencil = (1 << 5), + G_Stage_RenderTarget = (1 << 6), - /* Copy stages */ - G_Stage_Copy = (1 << 7), + /* Copy stages */ + G_Stage_Copy = (1 << 7), - /* Indirect stages */ - G_Stage_Indirect = (1 << 8), + /* Indirect stages */ + G_Stage_Indirect = (1 << 8), - /* Aggregate stages */ - G_Stage_AllDraw = G_Stage_IndexAssembly | - G_Stage_VertexShading | - G_Stage_PixelShading | - G_Stage_DepthStencil | - G_Stage_RenderTarget, + /* Aggregate stages */ + G_Stage_AllDraw = G_Stage_IndexAssembly | + G_Stage_VertexShading | + G_Stage_PixelShading | + G_Stage_DepthStencil | + G_Stage_RenderTarget, - G_Stage_AllShading = G_Stage_ComputeShading | - G_Stage_VertexShading | - G_Stage_PixelShading, + G_Stage_AllShading = G_Stage_ComputeShading | + G_Stage_VertexShading | + G_Stage_PixelShading, - G_Stage_All = 0xFFFFFFFF + G_Stage_All = 0xFFFFFFFF }; Enum(G_Access) { - G_Access_None = 0, + G_Access_None = 0, - G_Access_ShaderReadWrite = (1 << 1), - G_Access_ShaderRead = (1 << 2), + G_Access_ShaderReadWrite = (1 << 1), + G_Access_ShaderRead = (1 << 2), - G_Access_CopyWrite = (1 << 3), - G_Access_CopyRead = (1 << 4), + G_Access_CopyWrite = (1 << 3), + G_Access_CopyRead = (1 << 4), - G_Access_DepthStencilRead = (1 << 5), - G_Access_DepthStencilWrite = (1 << 6), - G_Access_RenderTargetWrite = (1 << 7), + G_Access_DepthStencilRead = (1 << 5), + G_Access_DepthStencilWrite = (1 << 6), + G_Access_RenderTargetWrite = (1 << 7), - G_Access_IndexBuffer = (1 << 8), - G_Access_IndirectArgument = (1 << 9), + G_Access_IndexBuffer = (1 << 8), + G_Access_IndirectArgument = (1 << 9), - G_Access_All = 0xFFFFFFFF + G_Access_All = 0xFFFFFFFF }; Enum(G_Layout) { - G_Layout_NoChange, + G_Layout_NoChange, - /* Allows a resource to be used on any queue with any access type, as long - * as there is only one writer at a time, and the writer is not writing to - * any texels currently being read. - * - * Resources cannot transition to/from this layout. They must be created - * with it and are locked to it. - */ - G_Layout_Simultaneous, /* D3D12_BARRIER_LAYOUT_COMMON + D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS */ + /* Allows a resource to be used on any queue with any access type, as long + * as there is only one writer at a time, and the writer is not writing to + * any texels currently being read. + * + * Resources cannot transition to/from this layout. They must be created + * with it and are locked to it. + */ + G_Layout_Simultaneous, /* D3D12_BARRIER_LAYOUT_COMMON + D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS */ - G_Layout_Undefined, /* D3D12_BARRIER_LAYOUT_UNDEFINED */ + G_Layout_Undefined, /* D3D12_BARRIER_LAYOUT_UNDEFINED */ - ////////////////////////////// - //- Queue-agnostic + ////////////////////////////// + //- Queue-agnostic - G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present, /* D3D12_BARRIER_LAYOUT_COMMON */ + G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present, /* D3D12_BARRIER_LAYOUT_COMMON */ - ////////////////////////////// - //- Direct & Compute queue + ////////////////////////////// + //- Direct & Compute queue - G_Layout_DirectComputeQueue_ShaderRead_CopyRead, /* D3D12_BARRIER_LAYOUT_GENERIC_READ */ + G_Layout_DirectComputeQueue_ShaderRead_CopyRead, /* D3D12_BARRIER_LAYOUT_GENERIC_READ */ - G_Layout_DirectComputeQueue_ShaderReadWrite, /* D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS */ - G_Layout_DirectComputeQueue_ShaderRead, /* D3D12_BARRIER_LAYOUT_SHADER_RESOURCE */ - G_Layout_DirectComputeQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_COPY_SOURCE */ + G_Layout_DirectComputeQueue_ShaderReadWrite, /* D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS */ + G_Layout_DirectComputeQueue_ShaderRead, /* D3D12_BARRIER_LAYOUT_SHADER_RESOURCE */ + G_Layout_DirectComputeQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_COPY_SOURCE */ - ////////////////////////////// - //- Direct queue + ////////////////////////////// + //- Direct queue - G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON */ - G_Layout_DirectQueue_ShaderRead_CopyRead_DepthStencilRead, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ */ + G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON */ + G_Layout_DirectQueue_ShaderRead_CopyRead_DepthStencilRead, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ */ - G_Layout_DirectQueue_ShaderReadWrite, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS */ - G_Layout_DirectQueue_ShaderRead, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE */ - G_Layout_DirectQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE */ + G_Layout_DirectQueue_ShaderReadWrite, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS */ + G_Layout_DirectQueue_ShaderRead, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE */ + G_Layout_DirectQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE */ - G_Layout_DirectQueue_DepthStencilRead_DepthStencilWrite, /* D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE */ - G_Layout_DirectQueue_DepthStencilRead, /* D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ */ - G_Layout_DirectQueue_RenderTargetWrite, /* D3D12_BARRIER_LAYOUT_RENDER_TARGET */ + G_Layout_DirectQueue_DepthStencilRead_DepthStencilWrite, /* D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE */ + G_Layout_DirectQueue_DepthStencilRead, /* D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ */ + G_Layout_DirectQueue_RenderTargetWrite, /* D3D12_BARRIER_LAYOUT_RENDER_TARGET */ - ////////////////////////////// - //- Compute queue + ////////////////////////////// + //- Compute queue - G_Layout_ComputeQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COMMON */ - G_Layout_ComputeQueue_ShaderRead_CopyRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_GENERIC_READ */ + G_Layout_ComputeQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COMMON */ + G_Layout_ComputeQueue_ShaderRead_CopyRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_GENERIC_READ */ - G_Layout_ComputeQueue_ShaderReadWrite, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS */ - G_Layout_ComputeQueue_ShaderRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE */ - G_Layout_ComputeQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_SOURCE */ + G_Layout_ComputeQueue_ShaderReadWrite, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS */ + G_Layout_ComputeQueue_ShaderRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE */ + G_Layout_ComputeQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_SOURCE */ }; /* Barrier will execute after previous stages specified by `stage_prev`, and before next stages specified by `stage_next`. @@ -306,13 +306,13 @@ Enum(G_Layout) */ Struct(G_MemoryBarrierDesc) { - G_ResourceHandle resource; - b32 is_global; - G_Stage stage_prev; - G_Stage stage_next; - G_Access access_prev; - G_Access access_next; - G_Layout layout; + G_ResourceHandle resource; + b32 is_global; + G_Stage stage_prev; + G_Stage stage_next; + G_Access access_prev; + G_Access access_next; + G_Layout layout; }; //////////////////////////////////////////////////////////// @@ -321,77 +321,77 @@ Struct(G_MemoryBarrierDesc) /* NOTE: Matches DirectX D3D12_FILTER */ Enum(G_Filter) { - /* Standard filter */ - G_Filter_MinMagMipPoint = 0, - G_Filter_MinMagPointMipLinear = 0x1, - G_Filter_MinPointMagLinearMipPoint = 0x4, - G_Filter_MinPointMagMipLinear = 0x5, - G_Filter_MinLinearMagMipPoint = 0x10, - G_Filter_MinLinearMagPointMipLinear = 0x11, - G_Filter_MinMagLinearMipPoint = 0x14, - G_Filter_MinMagMipLinear = 0x15, - G_Filter_MinMagAnisotropicMipPoint = 0x54, - G_Filter_Anisotropic = 0x55, + /* Standard filter */ + G_Filter_MinMagMipPoint = 0, + G_Filter_MinMagPointMipLinear = 0x1, + G_Filter_MinPointMagLinearMipPoint = 0x4, + G_Filter_MinPointMagMipLinear = 0x5, + G_Filter_MinLinearMagMipPoint = 0x10, + G_Filter_MinLinearMagPointMipLinear = 0x11, + G_Filter_MinMagLinearMipPoint = 0x14, + G_Filter_MinMagMipLinear = 0x15, + G_Filter_MinMagAnisotropicMipPoint = 0x54, + G_Filter_Anisotropic = 0x55, - /* Comparison filter */ - G_Filter_Comparison_MinMagMipPoint = 0x80, - G_Filter_Comparison_MinMagPointMipLinear = 0x81, - G_Filter_Comparison_MinPointMagLinearMipPoint = 0x84, - G_Filter_Comparison_MinPointMagMipLinear = 0x85, - G_Filter_Comparison_MinLinearMagMipPoint = 0x90, - G_Filter_Comparison_MinLinearMagPointMipLinear = 0x91, - G_Filter_Comparison_MinMagLinearMipPoint = 0x94, - G_Filter_Comparison_MinMagMipLinear = 0x95, - G_Filter_Comparison_MinMagAnisotropicMipPoint = 0xd4, - G_Filter_Comparison_Anisotropic = 0xd5, + /* Comparison filter */ + G_Filter_Comparison_MinMagMipPoint = 0x80, + G_Filter_Comparison_MinMagPointMipLinear = 0x81, + G_Filter_Comparison_MinPointMagLinearMipPoint = 0x84, + G_Filter_Comparison_MinPointMagMipLinear = 0x85, + G_Filter_Comparison_MinLinearMagMipPoint = 0x90, + G_Filter_Comparison_MinLinearMagPointMipLinear = 0x91, + G_Filter_Comparison_MinMagLinearMipPoint = 0x94, + G_Filter_Comparison_MinMagMipLinear = 0x95, + G_Filter_Comparison_MinMagAnisotropicMipPoint = 0xd4, + G_Filter_Comparison_Anisotropic = 0xd5, - /* Minimum filter */ - G_Filter_Minimum_MinMagMipPoint = 0x100, - G_Filter_Minimum_MinMagPointMipLinear = 0x101, - G_Filter_Minimum_MinPointMagLinearMipPoint = 0x104, - G_Filter_Minimum_MinPointMagMipLinear = 0x105, - G_Filter_Minimum_MinLinearMagMipPoint = 0x110, - G_Filter_Minimum_MinLinearMagPointMipLinear = 0x111, - G_Filter_Minimum_MinMagLinearMipPoint = 0x114, - G_Filter_Minimum_MinMagMipLinear = 0x115, - G_Filter_Minimum_MinMagAnisotropicMipPoint = 0x155, - G_Filter_Minimum_Anisotropic = 0x155, + /* Minimum filter */ + G_Filter_Minimum_MinMagMipPoint = 0x100, + G_Filter_Minimum_MinMagPointMipLinear = 0x101, + G_Filter_Minimum_MinPointMagLinearMipPoint = 0x104, + G_Filter_Minimum_MinPointMagMipLinear = 0x105, + G_Filter_Minimum_MinLinearMagMipPoint = 0x110, + G_Filter_Minimum_MinLinearMagPointMipLinear = 0x111, + G_Filter_Minimum_MinMagLinearMipPoint = 0x114, + G_Filter_Minimum_MinMagMipLinear = 0x115, + G_Filter_Minimum_MinMagAnisotropicMipPoint = 0x155, + G_Filter_Minimum_Anisotropic = 0x155, - /* Maximum filter */ - G_Filter_Maximum_MinMagMipPoint = 0x180, - G_Filter_Maximum_MinMagPointMipLinear = 0x181, - G_Filter_Maximum_MinPointMagLinearMipPoint = 0x184, - G_Filter_Maximum_MinPointMagMipLinear = 0x185, - G_Filter_Maximum_MinLinearMagMipPoint = 0x190, - G_Filter_Maximum_MinLinearMagPointMipLinear = 0x191, - G_Filter_Maximum_MinMagLinearMipPoint = 0x194, - G_Filter_Maximum_MinMagMipLinear = 0x195, - G_Filter_Maximum_MinMagAnisotropicMipPoint = 0x1d4, - G_Filter_Maximum_Anisotropic = 0x1d5 + /* Maximum filter */ + G_Filter_Maximum_MinMagMipPoint = 0x180, + G_Filter_Maximum_MinMagPointMipLinear = 0x181, + G_Filter_Maximum_MinPointMagLinearMipPoint = 0x184, + G_Filter_Maximum_MinPointMagMipLinear = 0x185, + G_Filter_Maximum_MinLinearMagMipPoint = 0x190, + G_Filter_Maximum_MinLinearMagPointMipLinear = 0x191, + G_Filter_Maximum_MinMagLinearMipPoint = 0x194, + G_Filter_Maximum_MinMagMipLinear = 0x195, + G_Filter_Maximum_MinMagAnisotropicMipPoint = 0x1d4, + G_Filter_Maximum_Anisotropic = 0x1d5 }; /* NOTE: Matches DirectX D3D12_TEXTURE_ADDRESS_MODE */ Enum(G_AddressMode) { - G_AddressMode_Wrap = 1, - G_AddressMode_Mirror = 2, - G_AddressMode_Clamp = 3, /* Default */ - G_AddressMode_Border = 4, - G_AddressMode_MirrorOnce = 5 + G_AddressMode_Wrap = 1, + G_AddressMode_Mirror = 2, + G_AddressMode_Clamp = 3, /* Default */ + G_AddressMode_Border = 4, + G_AddressMode_MirrorOnce = 5 }; /* NOTE: Matches DirectX D3D12_COMPARISON_FUNC */ Enum(G_ComparisonFunc) { - G_ComparisonFunc_None = 0, - G_ComparisonFunc_Never = 1, - G_ComparisonFunc_Less = 2, - G_ComparisonFunc_Equal = 3, - G_ComparisonFunc_LessEqual = 4, - G_ComparisonFunc_Greater = 5, - G_ComparisonFunc_NotEqual = 6, - G_ComparisonFunc_GreaterEqual = 7, - G_ComparisonFunc_Always = 8 + G_ComparisonFunc_None = 0, + G_ComparisonFunc_Never = 1, + G_ComparisonFunc_Less = 2, + G_ComparisonFunc_Equal = 3, + G_ComparisonFunc_LessEqual = 4, + G_ComparisonFunc_Greater = 5, + G_ComparisonFunc_NotEqual = 6, + G_ComparisonFunc_GreaterEqual = 7, + G_ComparisonFunc_Always = 8 }; //////////////////////////////////////////////////////////// @@ -399,60 +399,60 @@ Enum(G_ComparisonFunc) Enum(G_ResourceKind) { - G_ResourceKind_Buffer, - G_ResourceKind_Texture1D, - G_ResourceKind_Texture2D, - G_ResourceKind_Texture3D, - G_ResourceKind_Sampler, + G_ResourceKind_Buffer, + G_ResourceKind_Texture1D, + G_ResourceKind_Texture2D, + G_ResourceKind_Texture3D, + G_ResourceKind_Sampler, }; Enum(G_ResourceFlag) { - G_ResourceFlag_None = 0, - G_ResourceFlag_AllowShaderReadWrite = (1 << 0), - G_ResourceFlag_AllowRenderTarget = (1 << 1), - G_ResourceFlag_AllowDepthStencil = (1 << 2), - G_ResourceFlag_HostMemory = (1 << 3), /* Resource will be mapped into the cpu's address space */ - G_ResourceFlag_Uncached = (1 << 4), /* Cpu writes will be combined & reads will be uncached */ + G_ResourceFlag_None = 0, + G_ResourceFlag_AllowShaderReadWrite = (1 << 0), + G_ResourceFlag_AllowRenderTarget = (1 << 1), + G_ResourceFlag_AllowDepthStencil = (1 << 2), + G_ResourceFlag_HostMemory = (1 << 3), /* Resource will be mapped into the cpu's address space */ + G_ResourceFlag_Uncached = (1 << 4), /* Cpu writes will be combined & reads will be uncached */ }; Struct(G_BufferDesc) { - G_ResourceFlag flags; - u64 size; + G_ResourceFlag flags; + u64 size; }; Struct(G_TextureDesc) { - G_ResourceFlag flags; - G_Format format; - Vec3I32 dims; - G_Layout initial_layout; - i32 mip_levels; /* Will be clamped to range [1, inf) */ - Vec4 clear_color; + G_ResourceFlag flags; + G_Format format; + Vec3I32 dims; + G_Layout initial_layout; + i32 mip_levels; /* Will be clamped to range [1, inf) */ + Vec4 clear_color; }; Struct(G_SamplerDesc) { - G_ResourceFlag flags; - G_Filter filter; - G_AddressMode x; - G_AddressMode y; - G_AddressMode z; - f32 mip_lod_bias; - u32 max_anisotropy; - G_ComparisonFunc comparison; - Vec4 border_color; - f32 min_lod; - f32 max_lod; + G_ResourceFlag flags; + G_Filter filter; + G_AddressMode x; + G_AddressMode y; + G_AddressMode z; + f32 mip_lod_bias; + u32 max_anisotropy; + G_ComparisonFunc comparison; + Vec4 border_color; + f32 min_lod; + f32 max_lod; }; Struct(G_ResourceDesc) { - G_ResourceKind kind; - G_BufferDesc buffer; - G_TextureDesc texture; - G_SamplerDesc sampler; + G_ResourceKind kind; + G_BufferDesc buffer; + G_TextureDesc texture; + G_SamplerDesc sampler; }; //////////////////////////////////////////////////////////// @@ -460,9 +460,9 @@ Struct(G_ResourceDesc) Struct(G_RefDesc) { - G_RefKind kind; - u64 element_size; - u64 element_offset; + G_RefKind kind; + u64 element_size; + u64 element_offset; }; //////////////////////////////////////////////////////////// @@ -472,21 +472,21 @@ Struct(G_RefDesc) Enum(G_RasterMode) { - G_RasterMode_None, - G_RasterMode_PointList, - G_RasterMode_LineList, - G_RasterMode_LineStrip, - G_RasterMode_TriangleList, - G_RasterMode_TriangleStrip, - G_RasterMode_WireTriangleList, - G_RasterMode_WireTriangleStrip, + G_RasterMode_None, + G_RasterMode_PointList, + G_RasterMode_LineList, + G_RasterMode_LineStrip, + G_RasterMode_TriangleList, + G_RasterMode_TriangleStrip, + G_RasterMode_WireTriangleList, + G_RasterMode_WireTriangleStrip, }; Struct(G_IndexBufferDesc) { - G_ResourceHandle resource; - u32 index_size; /* Either 2 for u16 indices, or 4 for u32 indices */ - u32 index_count; + G_ResourceHandle resource; + u32 index_size; /* Either 2 for u16 indices, or 4 for u32 indices */ + u32 index_count; }; //////////////////////////////////////////////////////////// @@ -494,17 +494,17 @@ Struct(G_IndexBufferDesc) Struct(G_Stats) { - /* Memory usage */ - u64 local_committed; - u64 local_budget; - u64 non_local_committed; - u64 non_local_budget; + /* Memory usage */ + u64 local_committed; + u64 local_budget; + u64 non_local_committed; + u64 non_local_budget; - /* Resources */ - u64 driver_resources_allocated; - u64 driver_descriptors_allocated; + /* Resources */ + u64 driver_resources_allocated; + u64 driver_descriptors_allocated; - /* TODO: Arena stats (committed, reserved, etc) */ + /* TODO: Arena stats (committed, reserved, etc) */ }; //////////////////////////////////////////////////////////// @@ -527,59 +527,59 @@ void G_ResetArena(G_CommandListHandle cl_handle, G_ArenaHandle arena_handle); G_ResourceHandle G_PushResource(G_ArenaHandle arena, G_CommandListHandle cl, G_ResourceDesc desc); #define G_PushBuffer(arena, cl, _type, _count, ...) G_PushResource((arena), (cl), \ - (G_ResourceDesc) { \ - .kind = G_ResourceKind_Buffer, \ - .buffer = { \ - .size = sizeof(_type) * (_count), \ - __VA_ARGS__ \ - } \ + (G_ResourceDesc) { \ + .kind = G_ResourceKind_Buffer, \ + .buffer = { \ + .size = sizeof(_type) * (_count), \ + __VA_ARGS__ \ } \ + } \ ) #define G_PushTexture1D(arena, cl, _format, _size, _initial_layout, ...) G_PushResource((arena), (cl), \ - (G_ResourceDesc) { \ - .kind = G_ResourceKind_Texture1D, \ - .texture = { \ - .format = (_format), \ - .dims = VEC3I32((_size), 1, 1), \ - .initial_layout = (_initial_layout), \ - __VA_ARGS__ \ - } \ + (G_ResourceDesc) { \ + .kind = G_ResourceKind_Texture1D, \ + .texture = { \ + .format = (_format), \ + .dims = VEC3I32((_size), 1, 1), \ + .initial_layout = (_initial_layout), \ + __VA_ARGS__ \ } \ + } \ ) #define G_PushTexture2D(arena, cl, _format, _size, _initial_layout, ...) G_PushResource((arena), (cl), \ - (G_ResourceDesc) { \ - .kind = G_ResourceKind_Texture2D, \ - .texture = { \ - .format = (_format), \ - .dims = VEC3I32((_size).x, (_size).y, 1), \ - .initial_layout = (_initial_layout), \ - __VA_ARGS__ \ - } \ + (G_ResourceDesc) { \ + .kind = G_ResourceKind_Texture2D, \ + .texture = { \ + .format = (_format), \ + .dims = VEC3I32((_size).x, (_size).y, 1), \ + .initial_layout = (_initial_layout), \ + __VA_ARGS__ \ } \ + } \ ) #define G_PushTexture3D(arena, cl, _format, _size, _initial_layout, ...) G_PushResource((arena), (cl), \ - (G_ResourceDesc) { \ - .kind = G_ResourceKind_Texture3D, \ - .texture = { \ - .format = (_format), \ - .dims = (_size), \ - .initial_layout = (_initial_layout), \ - __VA_ARGS__ \ - } \ + (G_ResourceDesc) { \ + .kind = G_ResourceKind_Texture3D, \ + .texture = { \ + .format = (_format), \ + .dims = (_size), \ + .initial_layout = (_initial_layout), \ + __VA_ARGS__ \ } \ + } \ ) #define G_PushSampler(arena, cl, ...) G_PushResource((arena), (cl), \ - (G_ResourceDesc) { \ - .kind = G_ResourceKind_Sampler, \ - .sampler = { \ - .filter = G_Filter_MinMagMipPoint, \ - __VA_ARGS__ \ - } \ + (G_ResourceDesc) { \ + .kind = G_ResourceKind_Sampler, \ + .sampler = { \ + .filter = G_Filter_MinMagMipPoint, \ + __VA_ARGS__ \ } \ + } \ ) @@ -610,60 +610,82 @@ void *G_HostPointerFromResource(G_ResourceHandle resource); u32 G_PushRef(G_ArenaHandle arena, G_ResourceHandle resource, G_RefDesc desc); -#define G_PushStructuredBufferRef(arena, resource, type, ...) (G_StructuredBufferRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_StructuredBuffer, .element_size = sizeof(type), __VA_ARGS__ }) \ - } +#define G_PushStructuredBufferRef(arena, resource, type, ...)(G_StructuredBufferRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_StructuredBuffer, .element_size = sizeof(type), __VA_ARGS__ } \ + ) \ +} -#define G_PushRWStructuredBufferRef(arena, resource, type, ...) (G_RWStructuredBufferRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_RWStructuredBuffer, .element_size = sizeof(type), __VA_ARGS__ }) \ - } +#define G_PushRWStructuredBufferRef(arena, resource, type, ...)(G_RWStructuredBufferRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_RWStructuredBuffer, .element_size = sizeof(type), __VA_ARGS__ } \ + ) \ +} -#define G_PushByteAddressBufferRef(arena, resource, ...) (G_ByteAddressBufferRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_ByteAddressBuffer, __VA_ARGS__ }) \ - } +#define G_PushByteAddressBufferRef(arena, resource, ...)(G_ByteAddressBufferRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_ByteAddressBuffer, __VA_ARGS__ } \ + ) \ +} -#define G_PushRWByteAddressBufferRef(arena, resource, ...) (G_RWByteAddressBufferRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_RWByteAddressBuffer, __VA_ARGS__ }) \ - } +#define G_PushRWByteAddressBufferRef(arena, resource, ...)(G_RWByteAddressBufferRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_RWByteAddressBuffer, __VA_ARGS__ } \ + ) \ +} -#define G_PushTexture1DRef(arena, resource, ...) (G_Texture1DRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_Texture1D, __VA_ARGS__ }) \ - } +#define G_PushTexture1DRef(arena, resource, ...)(G_Texture1DRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_Texture1D, __VA_ARGS__ } \ + ) \ +} -#define G_PushRWTexture1DRef(arena, resource, ...) (G_RWTexture1DRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_RWTexture1D, __VA_ARGS__ }) \ - } +#define G_PushRWTexture1DRef(arena, resource, ...)(G_RWTexture1DRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_RWTexture1D, __VA_ARGS__ } \ + ) \ +} -#define G_PushTexture2DRef(arena, resource, ...) (G_Texture2DRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_Texture2D, __VA_ARGS__ }) \ - } +#define G_PushTexture2DRef(arena, resource, ...)(G_Texture2DRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_Texture2D, __VA_ARGS__ } \ + ) \ +} -#define G_PushRWTexture2DRef(arena, resource, ...) (G_RWTexture2DRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_RWTexture2D, __VA_ARGS__ }) \ - } +#define G_PushRWTexture2DRef(arena, resource, ...)(G_RWTexture2DRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_RWTexture2D, __VA_ARGS__ } \ + ) \ +} -#define G_PushTexture3DRef(arena, resource, ...) (G_Texture3DRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_Texture3D, __VA_ARGS__ }) \ - } +#define G_PushTexture3DRef(arena, resource, ...)(G_Texture3DRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_Texture3D, __VA_ARGS__ } \ + ) \ +} -#define G_PushRWTexture3DRef(arena, resource, ...) (G_RWTexture3DRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_RWTexture3D, __VA_ARGS__ }) \ - } +#define G_PushRWTexture3DRef(arena, resource, ...)(G_RWTexture3DRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_RWTexture3D, __VA_ARGS__ } \ + ) \ +} -#define G_PushSamplerStateRef(arena, resource, ...) (G_SamplerStateRef) { \ - .v = G_PushRef((arena), (resource), \ - (G_RefDesc) { .kind = G_RefKind_SamplerState, __VA_ARGS__ }) \ - } +#define G_PushSamplerStateRef(arena, resource, ...)(G_SamplerStateRef) { \ + .v = G_PushRef( \ + (arena), (resource), \ + (G_RefDesc) { .kind = G_RefKind_SamplerState, __VA_ARGS__ } \ + ) \ +} //////////////////////////////////////////////////////////// //~ @hookdecl Command @@ -690,51 +712,51 @@ void G_CopyTextureToBuffer(G_CommandListHandle cl, G_ResourceHandle dst, Vec3I32 void G_SetConstant_(G_CommandListHandle cl, i32 slot, void *src_32bit, u32 size); #define G_SetConstant(cl, name, value) do { \ - name##__shaderconstanttype __src; \ - __src.v = value; \ - G_SetConstant_((cl), (name), &__src, sizeof(__src)); \ + name##__shaderconstanttype __src; \ + __src.v = value; \ + G_SetConstant_((cl), (name), &__src, sizeof(__src)); \ } while (0) //- Memory sync void G_MemorySyncEx(G_CommandListHandle cl, G_MemoryBarrierDesc desc); -#define G_MemorySync(_cl, _resource, _stage_prev, _access_prev, _stage_next, _access_next) \ - G_MemorySyncEx((_cl), (G_MemoryBarrierDesc) { \ - .resource = (_resource), \ - .stage_prev = _stage_prev, \ - .access_prev = _access_prev, \ - .stage_next = _stage_next, \ - .access_next = _access_next, \ - }) +#define G_MemorySync(_cl, _resource, _stage_prev, _access_prev, _stage_next, _access_next) \ + G_MemorySyncEx((_cl), (G_MemoryBarrierDesc) { \ + .resource = (_resource), \ + .stage_prev = _stage_prev, \ + .access_prev = _access_prev, \ + .stage_next = _stage_next, \ + .access_next = _access_next, \ + }) -#define G_MemoryLayoutSync(_cl, _resource, _stage_prev, _access_prev, _stage_next, _access_next, _layout) \ - G_MemorySyncEx((_cl), (G_MemoryBarrierDesc) { \ - .resource = (_resource), \ - .stage_prev = _stage_prev, \ - .access_prev = _access_prev, \ - .stage_next = _stage_next, \ - .access_next = _access_next, \ - .layout = _layout, \ - }) +#define G_MemoryLayoutSync(_cl, _resource, _stage_prev, _access_prev, _stage_next, _access_next, _layout) \ + G_MemorySyncEx((_cl), (G_MemoryBarrierDesc) { \ + .resource = (_resource), \ + .stage_prev = _stage_prev, \ + .access_prev = _access_prev, \ + .stage_next = _stage_next, \ + .access_next = _access_next, \ + .layout = _layout, \ + }) -#define G_GlobalMemorySync(_cl, _stage_prev, _access_prev, _stage_next, _access_next) \ - G_MemorySyncEx((_cl), (G_MemoryBarrierDesc) { \ - .is_global = 1, \ - .stage_prev = _stage_prev, \ - .access_prev = _access_prev, \ - .stage_next = _stage_next, \ - .access_next = _access_next, \ - }) +#define G_GlobalMemorySync(_cl, _stage_prev, _access_prev, _stage_next, _access_next) \ + G_MemorySyncEx((_cl), (G_MemoryBarrierDesc) { \ + .is_global = 1, \ + .stage_prev = _stage_prev, \ + .access_prev = _access_prev, \ + .stage_next = _stage_next, \ + .access_next = _access_next, \ + }) #define G_DumbMemorySync(cl, resource) \ - G_MemorySync((cl), (resource), G_Stage_All, G_Access_All, G_Stage_All, G_Access_All) + G_MemorySync((cl), (resource), G_Stage_All, G_Access_All, G_Stage_All, G_Access_All) #define G_DumbMemoryLayoutSync(cl, resource, layout) \ - G_MemoryLayoutSync((cl), (resource), G_Stage_All, G_Access_All, G_Stage_All, G_Access_All, (layout)) + G_MemoryLayoutSync((cl), (resource), G_Stage_All, G_Access_All, G_Stage_All, G_Access_All, (layout)) #define G_DumbGlobalMemorySync(cl) \ - G_GlobalMemorySync((cl), G_Stage_All, G_Access_All, G_Stage_All, G_Access_All) + G_GlobalMemorySync((cl), G_Stage_All, G_Access_All, G_Stage_All, G_Access_All) //- Compute @@ -743,12 +765,12 @@ void G_Compute(G_CommandListHandle cl, ComputeShader cs, Vec3I32 groups); //- Rasterize void G_Rasterize( - G_CommandListHandle cl, - VertexShader vs, PixelShader ps, - u32 instances_count, G_IndexBufferDesc index_buffer, - u32 render_targets_count, G_ResourceHandle *render_targets, - Rng3 viewport, Rng2 scissor, - G_RasterMode mode + G_CommandListHandle cl, + VertexShader vs, PixelShader ps, + u32 instances_count, G_IndexBufferDesc index_buffer, + u32 render_targets_count, G_ResourceHandle *render_targets, + Rng3 viewport, Rng2 scissor, + G_RasterMode mode ); //- Clear @@ -769,11 +791,11 @@ G_QueueCompletions G_CompletionTargetsFromQueues(G_QueueMask queue_mask); void G_SyncEx(G_QueueBarrierDesc desc); -#define G_Sync(completion_mask, ...) \ - G_SyncEx((G_QueueBarrierDesc) { \ - .completions = G_CompletionTargetsFromQueues(completion_mask), \ - __VA_ARGS__ \ - }) +#define G_Sync(completion_mask, ...) \ + G_SyncEx((G_QueueBarrierDesc) { \ + .completions = G_CompletionTargetsFromQueues(completion_mask), \ + __VA_ARGS__ \ + }) #define G_SyncGpu(completion_mask, wait_mask) G_Sync((completion_mask), .wait_queues = (wait_mask)) #define G_SyncCpu(completion_mask) G_Sync((completion_mask), .wait_cpu = 1); diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.c b/src/gpu/gpu_dx12/gpu_dx12_core.c index dcb4351c..99e689f7 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.c +++ b/src/gpu/gpu_dx12/gpu_dx12_core.c @@ -6,342 +6,339 @@ ThreadLocal G_D12_ThreadLocalState G_D12_tl = Zi; void G_Bootstrap(void) { - G_D12_SharedState *g = &G_D12_shared_state; - TempArena scratch = BeginScratchNoConflict(); - Arena *perm = PermArena(); + G_D12_SharedState *g = &G_D12_shared_state; + TempArena scratch = BeginScratchNoConflict(); + Arena *perm = PermArena(); - ////////////////////////////// - //- Initialize device + ////////////////////////////// + //- Initialize device + { + HRESULT hr = 0; + + /* Enable debug layer */ + u32 dxgi_factory_flags = 0; + if (GPU_DEBUG) { - HRESULT hr = 0; - - /* Enable debug layer */ - u32 dxgi_factory_flags = 0; -#if GPU_DEBUG - { - ID3D12Debug *debug_controller0 = 0; - { - hr = D3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug_controller0); - if (FAILED(hr)) - { - Panic(Lit("Failed to create ID3D12Debug0")); - } - ID3D12Debug_EnableDebugLayer(debug_controller0); -#if GPU_DEBUG_VALIDATION - { - ID3D12Debug1 *debug_controller1 = 0; - { - hr = ID3D12Debug_QueryInterface(debug_controller0, &IID_ID3D12Debug1, (void **)&debug_controller1); - if (FAILED(hr)) - { - Panic(Lit("Failed to create ID3D12Debug1")); - } - ID3D12Debug1_SetEnableGPUBasedValidation(debug_controller1, 1); - } - ID3D12Debug_Release(debug_controller1); - } -#endif - } - ID3D12Debug_Release(debug_controller0); - dxgi_factory_flags |= DXGI_CREATE_FACTORY_DEBUG; - } -#endif - - /* Create factory */ - { - hr = CreateDXGIFactory2(dxgi_factory_flags, &IID_IDXGIFactory6, (void **)&g->factory); - if (FAILED(hr)) - { - Panic(Lit("Failed to initialize DXGI factory")); - } - } - - /* Create device */ - { - IDXGIAdapter3 *adapter = 0; - ID3D12Device10 *device = 0; - String error = Lit("Could not initialize GPU device."); - String first_gpu_name = Zi; - u32 adapter_index = 0; - b32 skip = 0; /* For iGPU testing */ - for (;;) - { - { - hr = IDXGIFactory6_EnumAdapterByGpuPreference(g->factory, adapter_index, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, &IID_IDXGIAdapter3, (void **)&adapter); - } - if (SUCCEEDED(hr)) - { - DXGI_ADAPTER_DESC1 desc; - IDXGIAdapter3_GetDesc1(adapter, &desc); - if (first_gpu_name.len == 0) - { - first_gpu_name = StringFromWstrNoLimit(scratch.arena, desc.Description); - } - { - /* TODO: Verify feature support: - * - HighestShaderModel >= D3D_SHADER_MODEL_6_6 - * - ResourceBindingTier >= D3D12_RESOURCE_BINDING_TIER_3 - * - EnhancedBarriersSupported == 1 - */ - hr = D3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_12_0, &IID_ID3D12Device10, (void **)&device); - } - if (SUCCEEDED(hr) && !skip) - { - break; - } - skip = 0; - ID3D12Device_Release(device); - IDXGIAdapter3_Release(adapter); - adapter = 0; - device = 0; - ++adapter_index; - } - else - { - break; - } - } - if (!device) - { - if (first_gpu_name.len > 0) - { - error = StringF( - scratch.arena, - "Could not initialize device '%F' with D3D_FEATURE_LEVEL_12_0. Ensure that the device is capable and drivers are up to date.", - FmtString(first_gpu_name) - ); - } - Panic(error); - } - g->adapter = adapter; - g->device = device; - } - - /* Enable debug layer breaks */ - { -#if GPU_DEBUG - /* Enable D3D12 Debug break */ - { - ID3D12InfoQueue *info = 0; - hr = ID3D12Device_QueryInterface(g->device, &IID_ID3D12InfoQueue, (void **)&info); - if (FAILED(hr)) - { - Panic(Lit("Failed to query ID3D12Device interface")); - } - ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_CORRUPTION, 1); - ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_ERROR, 1); - ID3D12InfoQueue_Release(info); - } - /* Enable DXGI Debug break */ - { - IDXGIInfoQueue *dxgi_info = 0; - hr = DXGIGetDebugInterface1(0, &IID_IDXGIInfoQueue, (void **)&dxgi_info); - if (FAILED(hr)) - { - Panic(Lit("Failed to retrieve DXGI debug interface")); - } - IDXGIInfoQueue_SetBreakOnSeverity(dxgi_info, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, 1); - IDXGIInfoQueue_SetBreakOnSeverity(dxgi_info, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, 1); - IDXGIInfoQueue_Release(dxgi_info); - } -#endif - } - } - - ////////////////////////////// - //- Initialize command queues - - { - G_D12_CommandQueueDesc descs[] = { - { .type = D3D12_COMMAND_LIST_TYPE_DIRECT, .priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH }, - { .type = D3D12_COMMAND_LIST_TYPE_COMPUTE, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL }, - { .type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL }, - }; - for (u32 i = 0; i < MinU32(countof(descs), countof(g->queues)); ++i) - { - G_D12_CommandQueueDesc desc = descs[i]; - D3D12_COMMAND_QUEUE_DESC d3d_desc = { .Type = desc.type, .Priority = desc.priority }; - G_D12_Queue *queue = &g->queues[i]; - queue->desc = desc; - HRESULT hr = ID3D12Device_CreateCommandQueue(g->device, &d3d_desc, &IID_ID3D12CommandQueue, (void **)&queue->d3d_queue); - if (SUCCEEDED(hr)) - { - hr = ID3D12Device_CreateFence(g->device, 0, 0, &IID_ID3D12Fence, (void **)&queue->commit_fence); - } - if (FAILED(hr)) - { - Panic(Lit("Failed to create GPU Command Queue")); - } - } - } - - ////////////////////////////// - //- Initialize descriptor heaps - - { - Struct(Dx12HeapDesc) { D3D12_DESCRIPTOR_HEAP_TYPE type; D3D12_DESCRIPTOR_HEAP_FLAGS flags; u64 max; }; - Dx12HeapDesc descs[G_D12_DescriptorHeapKind_Count] = { - [G_D12_DescriptorHeapKind_CbvSrvUav] = { - .type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - .flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, - .max = G_D12_MaxCbvSrvUavDescriptors, - }, - [G_D12_DescriptorHeapKind_Rtv] = { - .type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV, - .flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE, - .max = G_D12_MaxRtvDescriptors, - }, - [G_D12_DescriptorHeapKind_Sampler] = { - .type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, - .flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, - .max = G_D12_MaxSamplerDescriptors, - }, - }; - for (G_D12_DescriptorHeapKind kind = 0; kind < countof(descs); ++kind) - { - Dx12HeapDesc desc = descs[kind]; - G_D12_DescriptorHeap *heap = &g->descriptor_heaps[kind]; - heap->descriptors_arena = AcquireArena(Gibi(1)); - - heap->kind = kind; - heap->type = desc.type; - heap->max_count = desc.max; - heap->descriptor_size = ID3D12Device_GetDescriptorHandleIncrementSize(g->device, desc.type); - - D3D12_DESCRIPTOR_HEAP_DESC d3d_desc = Zi; - d3d_desc.Type = desc.type; - d3d_desc.Flags = desc.flags; - d3d_desc.NumDescriptors = desc.max; - - HRESULT hr = 0; - - if (SUCCEEDED(hr)) - { - hr = ID3D12Device_CreateDescriptorHeap(g->device, &d3d_desc, &IID_ID3D12DescriptorHeap, (void **)&heap->d3d_heap); - } - - if (SUCCEEDED(hr)) - { - ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(heap->d3d_heap, &heap->start_handle); - } - - if (SUCCEEDED(hr)) - { - /* Push an empty descriptor at index 0, so that a handle with a value of 0 always represents nil */ - G_D12_Arena *gpu_perm = G_D12_ArenaFromHandle(G_PermArena()); - G_D12_Descriptor *nil_descriptor = G_D12_PushDescriptor(gpu_perm, kind); - Assert(nil_descriptor->index == 0); - } - - if (FAILED(hr)) - { - Panic(Lit("Failed to create descriptor heap")); - } - } - } - - ////////////////////////////// - //- Initialize bindless root signature - - { - HRESULT hr = 0; - - /* Serialize root signature */ - ID3D10Blob *blob = 0; - if (SUCCEEDED(hr)) - { - D3D12_ROOT_PARAMETER params[G_NumConstants] = Zi; - for (i32 slot = 0; slot < G_NumConstants; ++slot) - { - D3D12_ROOT_PARAMETER *param = ¶ms[slot]; - param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; - param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - param->Constants.ShaderRegister = slot; - param->Constants.RegisterSpace = 0; - param->Constants.Num32BitValues = 1; - } - - D3D12_ROOT_SIGNATURE_DESC desc = Zi; - desc.NumParameters = countof(params); - desc.pParameters = params; - desc.NumStaticSamplers = 0; - desc.pStaticSamplers = 0; - desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED | D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED; - - hr = D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, 0); - } - - /* Create root signature */ - ID3D12RootSignature *rootsig = 0; - if (SUCCEEDED(hr)) - { - hr = ID3D12Device_CreateRootSignature(g->device, 0, ID3D10Blob_GetBufferPointer(blob), ID3D10Blob_GetBufferSize(blob), &IID_ID3D12RootSignature, (void **)&rootsig); - } - g->bindless_rootsig = rootsig; - - if (blob) - { - ID3D10Blob_Release(blob); - } + ID3D12Debug *debug_controller0 = 0; + { + hr = D3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug_controller0); if (FAILED(hr)) { - Panic(Lit("Failed to create root signature")); + Panic(Lit("Failed to create ID3D12Debug0")); } - } - - ////////////////////////////// - //- Create global resources - - { - /* Create debug print buffers */ - if (GPU_SHADER_PRINT) + ID3D12Debug_EnableDebugLayer(debug_controller0); + if (GPU_DEBUG_VALIDATION) { - for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) + ID3D12Debug1 *debug_controller1 = 0; + { + hr = ID3D12Debug_QueryInterface(debug_controller0, &IID_ID3D12Debug1, (void **)&debug_controller1); + if (FAILED(hr)) { - G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); - if (queue_kind != G_QueueKind_AsyncCopy) - { - G_CommandListHandle cl = G_PrepareCommandList(queue_kind); - { - G_ArenaHandle gpu_perm = G_PermArena(); - queue->print_buffer_size = GPU_SHADER_PRINT_BUFFER_SIZE; - queue->print_buffer = G_PushBuffer( - gpu_perm, cl, - u8, - queue->print_buffer_size, - .flags = G_ResourceFlag_AllowShaderReadWrite - ); - queue->print_readback_buffer = G_PushBuffer( - gpu_perm, cl, - u8, - queue->print_buffer_size, - .flags = G_ResourceFlag_HostMemory - ); - queue->print_buffer_ref = G_PushRWByteAddressBufferRef(gpu_perm, queue->print_buffer); - } - G_CommitCommandList(cl); - } + Panic(Lit("Failed to create ID3D12Debug1")); } + ID3D12Debug1_SetEnableGPUBasedValidation(debug_controller1, 1); + } + ID3D12Debug_Release(debug_controller1); } - + } + ID3D12Debug_Release(debug_controller0); + dxgi_factory_flags |= DXGI_CREATE_FACTORY_DEBUG; } - ////////////////////////////// - //- Start workers + /* Create factory */ + { + hr = CreateDXGIFactory2(dxgi_factory_flags, &IID_IDXGIFactory6, (void **)&g->factory); + if (FAILED(hr)) + { + Panic(Lit("Failed to initialize DXGI factory")); + } + } - // for (G_QueueKind kind = 0; kind < G_NumQueues; ++kind) - // { - // String name = Zi; - // if (kind == G_QueueKind_Direct) name = Lit("Gpu direct queue worker"); - // if (kind == G_QueueKind_AsyncCompute) name = Lit("Gpu compute queue worker"); - // if (kind == G_QueueKind_AsyncCopy) name = Lit("Gpu copy queue worker"); - // DispatchWave(name, 1, G_D12_WorkerEntry, (void *)(u64)kind); - // } + /* Create device */ + { + IDXGIAdapter3 *adapter = 0; + ID3D12Device10 *device = 0; + String error = Lit("Could not initialize GPU device."); + String first_gpu_name = Zi; + u32 adapter_index = 0; + b32 skip = 0; /* For iGPU testing */ + for (;;) + { + { + hr = IDXGIFactory6_EnumAdapterByGpuPreference(g->factory, adapter_index, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, &IID_IDXGIAdapter3, (void **)&adapter); + } + if (SUCCEEDED(hr)) + { + DXGI_ADAPTER_DESC1 desc; + IDXGIAdapter3_GetDesc1(adapter, &desc); + if (first_gpu_name.len == 0) + { + first_gpu_name = StringFromWstrNoLimit(scratch.arena, desc.Description); + } + { + /* TODO: Verify feature support: + * - HighestShaderModel >= D3D_SHADER_MODEL_6_6 + * - ResourceBindingTier >= D3D12_RESOURCE_BINDING_TIER_3 + * - EnhancedBarriersSupported == 1 + */ + hr = D3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_12_0, &IID_ID3D12Device10, (void **)&device); + } + if (SUCCEEDED(hr) && !skip) + { + break; + } + skip = 0; + ID3D12Device_Release(device); + IDXGIAdapter3_Release(adapter); + adapter = 0; + device = 0; + ++adapter_index; + } + else + { + break; + } + } + if (!device) + { + if (first_gpu_name.len > 0) + { + error = StringF( + scratch.arena, + "Could not initialize device '%F' with D3D_FEATURE_LEVEL_12_0. Ensure that the device is capable and drivers are up to date.", + FmtString(first_gpu_name) + ); + } + Panic(error); + } + g->adapter = adapter; + g->device = device; + } - DispatchWave(Lit("Gpu collection worker"), 1, G_D12_CollectionWorkerEntryPoint, 0); + /* Enable debug layer breaks */ + if (GPU_DEBUG) + { + /* Enable D3D12 Debug break */ + { + ID3D12InfoQueue *info = 0; + hr = ID3D12Device_QueryInterface(g->device, &IID_ID3D12InfoQueue, (void **)&info); + if (FAILED(hr)) + { + Panic(Lit("Failed to query ID3D12Device interface")); + } + ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_CORRUPTION, 1); + ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_ERROR, 1); + ID3D12InfoQueue_Release(info); + } + /* Enable DXGI Debug break */ + { + IDXGIInfoQueue *dxgi_info = 0; + hr = DXGIGetDebugInterface1(0, &IID_IDXGIInfoQueue, (void **)&dxgi_info); + if (FAILED(hr)) + { + Panic(Lit("Failed to retrieve DXGI debug interface")); + } + IDXGIInfoQueue_SetBreakOnSeverity(dxgi_info, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, 1); + IDXGIInfoQueue_SetBreakOnSeverity(dxgi_info, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, 1); + IDXGIInfoQueue_Release(dxgi_info); + } + } + } - EndScratch(scratch); + ////////////////////////////// + //- Initialize command queues + + { + G_D12_CommandQueueDesc descs[] = { + { .type = D3D12_COMMAND_LIST_TYPE_DIRECT, .priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH }, + { .type = D3D12_COMMAND_LIST_TYPE_COMPUTE, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL }, + { .type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL }, + }; + for (u32 i = 0; i < MinU32(countof(descs), countof(g->queues)); ++i) + { + G_D12_CommandQueueDesc desc = descs[i]; + D3D12_COMMAND_QUEUE_DESC d3d_desc = { .Type = desc.type, .Priority = desc.priority }; + G_D12_Queue *queue = &g->queues[i]; + queue->desc = desc; + HRESULT hr = ID3D12Device_CreateCommandQueue(g->device, &d3d_desc, &IID_ID3D12CommandQueue, (void **)&queue->d3d_queue); + if (SUCCEEDED(hr)) + { + hr = ID3D12Device_CreateFence(g->device, 0, 0, &IID_ID3D12Fence, (void **)&queue->commit_fence); + } + if (FAILED(hr)) + { + Panic(Lit("Failed to create GPU Command Queue")); + } + } + } + + ////////////////////////////// + //- Initialize descriptor heaps + + { + Struct(Dx12HeapDesc) { D3D12_DESCRIPTOR_HEAP_TYPE type; D3D12_DESCRIPTOR_HEAP_FLAGS flags; u64 max; }; + Dx12HeapDesc descs[G_D12_DescriptorHeapKind_Count] = { + [G_D12_DescriptorHeapKind_CbvSrvUav] = { + .type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, + .flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, + .max = G_D12_MaxCbvSrvUavDescriptors, + }, + [G_D12_DescriptorHeapKind_Rtv] = { + .type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV, + .flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE, + .max = G_D12_MaxRtvDescriptors, + }, + [G_D12_DescriptorHeapKind_Sampler] = { + .type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, + .flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, + .max = G_D12_MaxSamplerDescriptors, + }, + }; + for (G_D12_DescriptorHeapKind kind = 0; kind < countof(descs); ++kind) + { + Dx12HeapDesc desc = descs[kind]; + G_D12_DescriptorHeap *heap = &g->descriptor_heaps[kind]; + heap->descriptors_arena = AcquireArena(Gibi(1)); + + heap->kind = kind; + heap->type = desc.type; + heap->max_count = desc.max; + heap->descriptor_size = ID3D12Device_GetDescriptorHandleIncrementSize(g->device, desc.type); + + D3D12_DESCRIPTOR_HEAP_DESC d3d_desc = Zi; + d3d_desc.Type = desc.type; + d3d_desc.Flags = desc.flags; + d3d_desc.NumDescriptors = desc.max; + + HRESULT hr = 0; + + if (SUCCEEDED(hr)) + { + hr = ID3D12Device_CreateDescriptorHeap(g->device, &d3d_desc, &IID_ID3D12DescriptorHeap, (void **)&heap->d3d_heap); + } + + if (SUCCEEDED(hr)) + { + ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(heap->d3d_heap, &heap->start_handle); + } + + if (SUCCEEDED(hr)) + { + /* Push an empty descriptor at index 0, so that a handle with a value of 0 always represents nil */ + G_D12_Arena *gpu_perm = G_D12_ArenaFromHandle(G_PermArena()); + G_D12_Descriptor *nil_descriptor = G_D12_PushDescriptor(gpu_perm, kind); + Assert(nil_descriptor->index == 0); + } + + if (FAILED(hr)) + { + Panic(Lit("Failed to create descriptor heap")); + } + } + } + + ////////////////////////////// + //- Initialize bindless root signature + + { + HRESULT hr = 0; + + /* Serialize root signature */ + ID3D10Blob *blob = 0; + if (SUCCEEDED(hr)) + { + D3D12_ROOT_PARAMETER params[G_NumConstants] = Zi; + for (i32 slot = 0; slot < G_NumConstants; ++slot) + { + D3D12_ROOT_PARAMETER *param = ¶ms[slot]; + param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + param->Constants.ShaderRegister = slot; + param->Constants.RegisterSpace = 0; + param->Constants.Num32BitValues = 1; + } + + D3D12_ROOT_SIGNATURE_DESC desc = Zi; + desc.NumParameters = countof(params); + desc.pParameters = params; + desc.NumStaticSamplers = 0; + desc.pStaticSamplers = 0; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED | D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED; + + hr = D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, 0); + } + + /* Create root signature */ + ID3D12RootSignature *rootsig = 0; + if (SUCCEEDED(hr)) + { + hr = ID3D12Device_CreateRootSignature(g->device, 0, ID3D10Blob_GetBufferPointer(blob), ID3D10Blob_GetBufferSize(blob), &IID_ID3D12RootSignature, (void **)&rootsig); + } + g->bindless_rootsig = rootsig; + + if (blob) + { + ID3D10Blob_Release(blob); + } + if (FAILED(hr)) + { + Panic(Lit("Failed to create root signature")); + } + } + + ////////////////////////////// + //- Create global resources + + { + /* Create debug print buffers */ + if (GPU_SHADER_PRINT) + { + for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) + { + G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); + if (queue_kind != G_QueueKind_AsyncCopy) + { + G_CommandListHandle cl = G_PrepareCommandList(queue_kind); + { + G_ArenaHandle gpu_perm = G_PermArena(); + queue->print_buffer_size = GPU_SHADER_PRINT_BUFFER_SIZE; + queue->print_buffer = G_PushBuffer( + gpu_perm, cl, + u8, + queue->print_buffer_size, + .flags = G_ResourceFlag_AllowShaderReadWrite + ); + queue->print_readback_buffer = G_PushBuffer( + gpu_perm, cl, + u8, + queue->print_buffer_size, + .flags = G_ResourceFlag_HostMemory + ); + queue->print_buffer_ref = G_PushRWByteAddressBufferRef(gpu_perm, queue->print_buffer); + } + G_CommitCommandList(cl); + } + } + } + + } + + ////////////////////////////// + //- Start workers + + // for (G_QueueKind kind = 0; kind < G_NumQueues; ++kind) + // { + // String name = Zi; + // if (kind == G_QueueKind_Direct) name = Lit("Gpu direct queue worker"); + // if (kind == G_QueueKind_AsyncCompute) name = Lit("Gpu compute queue worker"); + // if (kind == G_QueueKind_AsyncCopy) name = Lit("Gpu copy queue worker"); + // DispatchWave(name, 1, G_D12_WorkerEntry, (void *)(u64)kind); + // } + + DispatchWave(Lit("Gpu collection worker"), 1, G_D12_CollectionWorkerEntryPoint, 0); + + EndScratch(scratch); } //////////////////////////////////////////////////////////// @@ -349,101 +346,101 @@ void G_Bootstrap(void) G_D12_Arena *G_D12_ArenaFromHandle(G_ArenaHandle handle) { - return (G_D12_Arena *)handle.v; + return (G_D12_Arena *)handle.v; } G_D12_CmdList *G_D12_CmdListFromHandle(G_CommandListHandle handle) { - return (G_D12_CmdList *)handle.v; + return (G_D12_CmdList *)handle.v; } G_D12_Resource *G_D12_ResourceFromHandle(G_ResourceHandle handle) { - return (G_D12_Resource *)handle.v; + return (G_D12_Resource *)handle.v; } G_D12_Swapchain *G_D12_SwapchainFromHandle(G_SwapchainHandle handle) { - return (G_D12_Swapchain *)handle.v; + return (G_D12_Swapchain *)handle.v; } DXGI_FORMAT G_D12_DxgiFormatFromGpuFormat(G_Format format) { - return (DXGI_FORMAT)format; + return (DXGI_FORMAT)format; } D3D12_BARRIER_SYNC G_D12_BarrierSyncFromStages(G_Stage stages) { - D3D12_BARRIER_SYNC result = 0; - if (stages == G_Stage_All) - { - result = D3D12_BARRIER_SYNC_ALL; - } - else - { - result |= D3D12_BARRIER_SYNC_COMPUTE_SHADING * AnyBit(stages, G_Stage_ComputeShading); - result |= D3D12_BARRIER_SYNC_INDEX_INPUT * AnyBit(stages, G_Stage_IndexAssembly); - result |= D3D12_BARRIER_SYNC_VERTEX_SHADING * AnyBit(stages, G_Stage_VertexShading); - result |= D3D12_BARRIER_SYNC_PIXEL_SHADING * AnyBit(stages, G_Stage_PixelShading); - result |= D3D12_BARRIER_SYNC_DEPTH_STENCIL * AnyBit(stages, G_Stage_DepthStencil); - result |= D3D12_BARRIER_SYNC_RENDER_TARGET * AnyBit(stages, G_Stage_RenderTarget); - result |= D3D12_BARRIER_SYNC_COPY * AnyBit(stages, G_Stage_Copy); - result |= D3D12_BARRIER_SYNC_EXECUTE_INDIRECT * AnyBit(stages, G_Stage_Indirect); - } - return result; + D3D12_BARRIER_SYNC result = 0; + if (stages == G_Stage_All) + { + result = D3D12_BARRIER_SYNC_ALL; + } + else + { + result |= D3D12_BARRIER_SYNC_COMPUTE_SHADING * AnyBit(stages, G_Stage_ComputeShading); + result |= D3D12_BARRIER_SYNC_INDEX_INPUT * AnyBit(stages, G_Stage_IndexAssembly); + result |= D3D12_BARRIER_SYNC_VERTEX_SHADING * AnyBit(stages, G_Stage_VertexShading); + result |= D3D12_BARRIER_SYNC_PIXEL_SHADING * AnyBit(stages, G_Stage_PixelShading); + result |= D3D12_BARRIER_SYNC_DEPTH_STENCIL * AnyBit(stages, G_Stage_DepthStencil); + result |= D3D12_BARRIER_SYNC_RENDER_TARGET * AnyBit(stages, G_Stage_RenderTarget); + result |= D3D12_BARRIER_SYNC_COPY * AnyBit(stages, G_Stage_Copy); + result |= D3D12_BARRIER_SYNC_EXECUTE_INDIRECT * AnyBit(stages, G_Stage_Indirect); + } + return result; } D3D12_BARRIER_ACCESS G_D12_BarrierAccessFromAccesses(G_Access accesses) { - D3D12_BARRIER_ACCESS result = 0; - if (accesses == 0) - { - result = D3D12_BARRIER_ACCESS_NO_ACCESS; - } - else if (accesses == G_Access_All) - { - result = D3D12_BARRIER_ACCESS_COMMON; - } - else - { - result |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS * AnyBit(accesses, G_Access_ShaderReadWrite); - result |= D3D12_BARRIER_ACCESS_SHADER_RESOURCE * AnyBit(accesses, G_Access_ShaderRead); - result |= D3D12_BARRIER_ACCESS_COPY_DEST * AnyBit(accesses, G_Access_CopyWrite); - result |= D3D12_BARRIER_ACCESS_COPY_SOURCE * AnyBit(accesses, G_Access_CopyRead); - result |= D3D12_BARRIER_ACCESS_INDEX_BUFFER * AnyBit(accesses, G_Access_IndexBuffer); - result |= D3D12_BARRIER_ACCESS_INDIRECT_ARGUMENT * AnyBit(accesses, G_Access_IndirectArgument); - result |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ * AnyBit(accesses, G_Access_DepthStencilRead); - result |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE * AnyBit(accesses, G_Access_DepthStencilWrite); - result |= D3D12_BARRIER_ACCESS_RENDER_TARGET * AnyBit(accesses, G_Access_RenderTargetWrite); - } - return result; + D3D12_BARRIER_ACCESS result = 0; + if (accesses == 0) + { + result = D3D12_BARRIER_ACCESS_NO_ACCESS; + } + else if (accesses == G_Access_All) + { + result = D3D12_BARRIER_ACCESS_COMMON; + } + else + { + result |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS * AnyBit(accesses, G_Access_ShaderReadWrite); + result |= D3D12_BARRIER_ACCESS_SHADER_RESOURCE * AnyBit(accesses, G_Access_ShaderRead); + result |= D3D12_BARRIER_ACCESS_COPY_DEST * AnyBit(accesses, G_Access_CopyWrite); + result |= D3D12_BARRIER_ACCESS_COPY_SOURCE * AnyBit(accesses, G_Access_CopyRead); + result |= D3D12_BARRIER_ACCESS_INDEX_BUFFER * AnyBit(accesses, G_Access_IndexBuffer); + result |= D3D12_BARRIER_ACCESS_INDIRECT_ARGUMENT * AnyBit(accesses, G_Access_IndirectArgument); + result |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ * AnyBit(accesses, G_Access_DepthStencilRead); + result |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE * AnyBit(accesses, G_Access_DepthStencilWrite); + result |= D3D12_BARRIER_ACCESS_RENDER_TARGET * AnyBit(accesses, G_Access_RenderTargetWrite); + } + return result; } D3D12_BARRIER_LAYOUT G_D12_BarrierLayoutFromLayout(G_Layout layout) { - PERSIST Readonly D3D12_BARRIER_LAYOUT translate[] = { - [G_Layout_Undefined] = D3D12_BARRIER_LAYOUT_UNDEFINED, - [G_Layout_Simultaneous] = D3D12_BARRIER_LAYOUT_COMMON, - [G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present] = D3D12_BARRIER_LAYOUT_COMMON, - [G_Layout_DirectComputeQueue_ShaderReadWrite] = D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS, - [G_Layout_DirectComputeQueue_ShaderRead_CopyRead] = D3D12_BARRIER_LAYOUT_GENERIC_READ, - [G_Layout_DirectComputeQueue_ShaderRead] = D3D12_BARRIER_LAYOUT_SHADER_RESOURCE, - [G_Layout_DirectComputeQueue_CopyRead] = D3D12_BARRIER_LAYOUT_COPY_SOURCE, - [G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON, - [G_Layout_DirectQueue_ShaderReadWrite] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS, - [G_Layout_DirectQueue_ShaderRead_CopyRead_DepthStencilRead] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ, - [G_Layout_DirectQueue_ShaderRead] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE, - [G_Layout_DirectQueue_CopyRead] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE, - [G_Layout_DirectQueue_DepthStencilRead_DepthStencilWrite] = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE, - [G_Layout_DirectQueue_DepthStencilRead] = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ, - [G_Layout_DirectQueue_RenderTargetWrite] = D3D12_BARRIER_LAYOUT_RENDER_TARGET, - [G_Layout_ComputeQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COMMON, - [G_Layout_ComputeQueue_ShaderReadWrite] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS, - [G_Layout_ComputeQueue_ShaderRead_CopyRead] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_GENERIC_READ, - [G_Layout_ComputeQueue_ShaderRead] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE, - [G_Layout_ComputeQueue_CopyRead] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_SOURCE, - }; - return translate[layout]; + PERSIST Readonly D3D12_BARRIER_LAYOUT translate[] = { + [G_Layout_Undefined] = D3D12_BARRIER_LAYOUT_UNDEFINED, + [G_Layout_Simultaneous] = D3D12_BARRIER_LAYOUT_COMMON, + [G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present] = D3D12_BARRIER_LAYOUT_COMMON, + [G_Layout_DirectComputeQueue_ShaderReadWrite] = D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS, + [G_Layout_DirectComputeQueue_ShaderRead_CopyRead] = D3D12_BARRIER_LAYOUT_GENERIC_READ, + [G_Layout_DirectComputeQueue_ShaderRead] = D3D12_BARRIER_LAYOUT_SHADER_RESOURCE, + [G_Layout_DirectComputeQueue_CopyRead] = D3D12_BARRIER_LAYOUT_COPY_SOURCE, + [G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON, + [G_Layout_DirectQueue_ShaderReadWrite] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS, + [G_Layout_DirectQueue_ShaderRead_CopyRead_DepthStencilRead] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ, + [G_Layout_DirectQueue_ShaderRead] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE, + [G_Layout_DirectQueue_CopyRead] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE, + [G_Layout_DirectQueue_DepthStencilRead_DepthStencilWrite] = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE, + [G_Layout_DirectQueue_DepthStencilRead] = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ, + [G_Layout_DirectQueue_RenderTargetWrite] = D3D12_BARRIER_LAYOUT_RENDER_TARGET, + [G_Layout_ComputeQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COMMON, + [G_Layout_ComputeQueue_ShaderReadWrite] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS, + [G_Layout_ComputeQueue_ShaderRead_CopyRead] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_GENERIC_READ, + [G_Layout_ComputeQueue_ShaderRead] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE, + [G_Layout_ComputeQueue_CopyRead] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_SOURCE, + }; + return translate[layout]; }; //////////////////////////////////////////////////////////// @@ -451,163 +448,163 @@ D3D12_BARRIER_LAYOUT G_D12_BarrierLayoutFromLayout(G_Layout layout) G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc) { - G_D12_SharedState *g = &G_D12_shared_state; - u64 hash = RandU64FromSeed(HashFnv64(Fnv64Basis, StringFromStruct(&desc))); + G_D12_SharedState *g = &G_D12_shared_state; + u64 hash = RandU64FromSeed(HashFnv64(Fnv64Basis, StringFromStruct(&desc))); - /* Fetch pipeline from cache */ - G_D12_Pipeline *pipeline = 0; - b32 is_pipeline_new = 0; - G_D12_PipelineBin *bin = &g->pipeline_bins[hash % countof(g->pipeline_bins)]; + /* Fetch pipeline from cache */ + G_D12_Pipeline *pipeline = 0; + b32 is_pipeline_new = 0; + G_D12_PipelineBin *bin = &g->pipeline_bins[hash % countof(g->pipeline_bins)]; + { { + Lock lock = LockS(&bin->mutex); + for (pipeline = bin->first; pipeline; pipeline = pipeline->next_in_bin) + { + if (pipeline->hash == hash) break; + } + Unlock(&lock); + } + if (!pipeline) + { + Lock lock = LockE(&bin->mutex); + for (pipeline = bin->first; pipeline; pipeline = pipeline->next_in_bin) + { + if (pipeline->hash == hash) break; + } + if (!pipeline) + { + Arena *perm = PermArena(); + PushAlign(perm, CachelineSize); + pipeline = PushStruct(perm, G_D12_Pipeline); + pipeline->desc = desc; + pipeline->hash = hash; + is_pipeline_new = 1; + PushAlign(perm, CachelineSize); + SllStackPushN(bin->first, pipeline, next_in_bin); + } + Unlock(&lock); + } + } + + /* Create pipeline */ + if (is_pipeline_new) + { + HRESULT hr = 0; + b32 ok = 1; + String error_str = Zi; + + /* Create PSO */ + ID3D12PipelineState *pso = 0; + if (ok && (!IsResourceNil(desc.vs.resource) || !IsResourceNil(desc.ps.resource))) + { + D3D12_RASTERIZER_DESC raster_desc = Zi; + { + if (desc.is_wireframe) { - Lock lock = LockS(&bin->mutex); - for (pipeline = bin->first; pipeline; pipeline = pipeline->next_in_bin) - { - if (pipeline->hash == hash) break; - } - Unlock(&lock); + raster_desc.FillMode = D3D12_FILL_MODE_WIREFRAME; } - if (!pipeline) + else { - Lock lock = LockE(&bin->mutex); - for (pipeline = bin->first; pipeline; pipeline = pipeline->next_in_bin) - { - if (pipeline->hash == hash) break; - } - if (!pipeline) - { - Arena *perm = PermArena(); - PushAlign(perm, CachelineSize); - pipeline = PushStruct(perm, G_D12_Pipeline); - pipeline->desc = desc; - pipeline->hash = hash; - is_pipeline_new = 1; - PushAlign(perm, CachelineSize); - SllStackPushN(bin->first, pipeline, next_in_bin); - } - Unlock(&lock); + raster_desc.FillMode = D3D12_FILL_MODE_SOLID; } + raster_desc.CullMode = D3D12_CULL_MODE_NONE; + raster_desc.FrontCounterClockwise = 0; + raster_desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; + raster_desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; + raster_desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; + raster_desc.DepthClipEnable = 1; + raster_desc.MultisampleEnable = 0; + raster_desc.AntialiasedLineEnable = 0; + raster_desc.ForcedSampleCount = 0; + raster_desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; + } + + D3D12_BLEND_DESC blend_desc = Zi; + { + blend_desc.AlphaToCoverageEnable = 0; + blend_desc.IndependentBlendEnable = 0; + blend_desc.RenderTarget[0].BlendEnable = 1; + blend_desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; + blend_desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; + blend_desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + blend_desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; + blend_desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; + blend_desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + } + + D3D12_DEPTH_STENCIL_DESC ds_desc = Zi; + { + ds_desc.DepthEnable = 0; + ds_desc.StencilEnable = 0; + } + + String vs = DataFromResource(desc.vs.resource); + String ps = DataFromResource(desc.ps.resource); + D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = Zi; + { + pso_desc.pRootSignature = g->bindless_rootsig; + pso_desc.VS.pShaderBytecode = vs.text; + pso_desc.VS.BytecodeLength = vs.len; + pso_desc.PS.pShaderBytecode = ps.text; + pso_desc.PS.BytecodeLength = ps.len; + pso_desc.RasterizerState = raster_desc; + pso_desc.BlendState = blend_desc; + pso_desc.DepthStencilState = ds_desc; + pso_desc.PrimitiveTopologyType = desc.topology_type; + pso_desc.SampleMask = UINT_MAX; + pso_desc.SampleDesc.Count = 1; + pso_desc.SampleDesc.Quality = 0; + for (i32 i = 0; i < (i32)countof(desc.render_target_formats); ++i) + { + StaticAssert(countof(pso_desc.RTVFormats) <= countof(desc.render_target_formats)); + DXGI_FORMAT format = G_D12_DxgiFormatFromGpuFormat(desc.render_target_formats[i]); + if (format != DXGI_FORMAT_UNKNOWN) + { + pso_desc.RTVFormats[pso_desc.NumRenderTargets++] = format; + } + else + { + break; + } + } + } + hr = ID3D12Device_CreateGraphicsPipelineState(g->device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso); + if (FAILED(hr)) + { + error_str = Lit("Failed to create graphics pipeline"); + ok = 0; + } + } + else if (ok) + { + String cs = DataFromResource(desc.cs.resource); + D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc = Zi; + { + pso_desc.pRootSignature = g->bindless_rootsig; + pso_desc.CS.pShaderBytecode = cs.text; + pso_desc.CS.BytecodeLength = cs.len; + } + hr = ID3D12Device_CreateComputePipelineState(g->device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso); + if (FAILED(hr)) + { + error_str = Lit("Failed to create compute pipeline"); + ok = 0; + } } - /* Create pipeline */ - if (is_pipeline_new) + if (!ok) { - HRESULT hr = 0; - b32 ok = 1; - String error_str = Zi; - - /* Create PSO */ - ID3D12PipelineState *pso = 0; - if (ok && (!IsResourceNil(desc.vs.resource) || !IsResourceNil(desc.ps.resource))) - { - D3D12_RASTERIZER_DESC raster_desc = Zi; - { - if (desc.is_wireframe) - { - raster_desc.FillMode = D3D12_FILL_MODE_WIREFRAME; - } - else - { - raster_desc.FillMode = D3D12_FILL_MODE_SOLID; - } - raster_desc.CullMode = D3D12_CULL_MODE_NONE; - raster_desc.FrontCounterClockwise = 0; - raster_desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; - raster_desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; - raster_desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; - raster_desc.DepthClipEnable = 1; - raster_desc.MultisampleEnable = 0; - raster_desc.AntialiasedLineEnable = 0; - raster_desc.ForcedSampleCount = 0; - raster_desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; - } - - D3D12_BLEND_DESC blend_desc = Zi; - { - blend_desc.AlphaToCoverageEnable = 0; - blend_desc.IndependentBlendEnable = 0; - blend_desc.RenderTarget[0].BlendEnable = 1; - blend_desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; - blend_desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; - blend_desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; - blend_desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; - blend_desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; - blend_desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; - blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; - } - - D3D12_DEPTH_STENCIL_DESC ds_desc = Zi; - { - ds_desc.DepthEnable = 0; - ds_desc.StencilEnable = 0; - } - - String vs = DataFromResource(desc.vs.resource); - String ps = DataFromResource(desc.ps.resource); - D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = Zi; - { - pso_desc.pRootSignature = g->bindless_rootsig; - pso_desc.VS.pShaderBytecode = vs.text; - pso_desc.VS.BytecodeLength = vs.len; - pso_desc.PS.pShaderBytecode = ps.text; - pso_desc.PS.BytecodeLength = ps.len; - pso_desc.RasterizerState = raster_desc; - pso_desc.BlendState = blend_desc; - pso_desc.DepthStencilState = ds_desc; - pso_desc.PrimitiveTopologyType = desc.topology_type; - pso_desc.SampleMask = UINT_MAX; - pso_desc.SampleDesc.Count = 1; - pso_desc.SampleDesc.Quality = 0; - for (i32 i = 0; i < (i32)countof(desc.render_target_formats); ++i) - { - StaticAssert(countof(pso_desc.RTVFormats) <= countof(desc.render_target_formats)); - DXGI_FORMAT format = G_D12_DxgiFormatFromGpuFormat(desc.render_target_formats[i]); - if (format != DXGI_FORMAT_UNKNOWN) - { - pso_desc.RTVFormats[pso_desc.NumRenderTargets++] = format; - } - else - { - break; - } - } - } - hr = ID3D12Device_CreateGraphicsPipelineState(g->device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso); - if (FAILED(hr)) - { - error_str = Lit("Failed to create graphics pipeline"); - ok = 0; - } - } - else if (ok) - { - String cs = DataFromResource(desc.cs.resource); - D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc = Zi; - { - pso_desc.pRootSignature = g->bindless_rootsig; - pso_desc.CS.pShaderBytecode = cs.text; - pso_desc.CS.BytecodeLength = cs.len; - } - hr = ID3D12Device_CreateComputePipelineState(g->device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso); - if (FAILED(hr)) - { - error_str = Lit("Failed to create compute pipeline"); - ok = 0; - } - } - - if (!ok) - { - /* TOOD: Don't panic */ - Panic(error_str); - } - - pipeline->pso = pso; - pipeline->error = error_str; - pipeline->ok = ok; + /* TOOD: Don't panic */ + Panic(error_str); } - return pipeline; + pipeline->pso = pso; + pipeline->error = error_str; + pipeline->ok = ok; + } + + return pipeline; } //////////////////////////////////////////////////////////// @@ -615,8 +612,8 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc) G_D12_Queue *G_D12_QueueFromKind(G_QueueKind kind) { - G_D12_SharedState *g = &G_D12_shared_state; - return &g->queues[kind]; + G_D12_SharedState *g = &G_D12_shared_state; + return &g->queues[kind]; } //////////////////////////////////////////////////////////// @@ -624,131 +621,131 @@ G_D12_Queue *G_D12_QueueFromKind(G_QueueKind kind) G_D12_RawCommandList *G_D12_PrepareRawCommandList(G_QueueKind queue_kind) { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); - /* Try to pull first completed command list from queue */ - G_D12_RawCommandList *cl = Zi; + /* Try to pull first completed command list from queue */ + G_D12_RawCommandList *cl = Zi; + { + Lock lock = LockE(&queue->commit_mutex); { - Lock lock = LockE(&queue->commit_mutex); + u64 completed = ID3D12Fence_GetCompletedValue(queue->commit_fence); + cl = queue->first_committed_cl; + if (cl && cl->commit_fence_target <= completed) + { + SllQueuePop(queue->first_committed_cl, queue->last_committed_cl); + } + else + { + cl = 0; + } + } + Unlock(&lock); + } + + /* Allocate new command list if none are available */ + if (!cl) + { + Arena *perm = PermArena(); + { + PushAlign(perm, CachelineSize); + cl = PushStruct(perm, G_D12_RawCommandList); + PushAlign(perm, CachelineSize); + } + cl->queue = queue; + + HRESULT hr = 0; + { + if (SUCCEEDED(hr)) + { + hr = ID3D12Device_CreateCommandAllocator(g->device, queue->desc.type, &IID_ID3D12CommandAllocator, (void **)&cl->d3d_ca); + } + + if (SUCCEEDED(hr)) + { + hr = ID3D12Device_CreateCommandList(g->device, 0, queue->desc.type, cl->d3d_ca, 0, &IID_ID3D12GraphicsCommandList7, (void **)&cl->d3d_cl); + } + + if (SUCCEEDED(hr)) + { + hr = ID3D12GraphicsCommandList_Close(cl->d3d_cl); + } + + /* Initialize Direct queue CPU-only descriptors */ + if (SUCCEEDED(hr) && queue_kind == G_QueueKind_Direct) + { + G_D12_Arena *gpu_perm = G_D12_ArenaFromHandle(G_PermArena()); + for (u32 i = 0; i < countof(cl->rtv_descriptors); ++i) { - u64 completed = ID3D12Fence_GetCompletedValue(queue->commit_fence); - cl = queue->first_committed_cl; - if (cl && cl->commit_fence_target <= completed) - { - SllQueuePop(queue->first_committed_cl, queue->last_committed_cl); - } - else - { - cl = 0; - } + cl->rtv_descriptors[i] = G_D12_PushDescriptor(gpu_perm, G_D12_DescriptorHeapKind_Rtv); } - Unlock(&lock); + cl->rtv_clear_descriptor = G_D12_PushDescriptor(gpu_perm, G_D12_DescriptorHeapKind_Rtv); + } } - /* Allocate new command list if none are available */ - if (!cl) + if (FAILED(hr)) { - Arena *perm = PermArena(); - { - PushAlign(perm, CachelineSize); - cl = PushStruct(perm, G_D12_RawCommandList); - PushAlign(perm, CachelineSize); - } - cl->queue = queue; + Panic(Lit("Failed to create command list")); + } + } - HRESULT hr = 0; - { - if (SUCCEEDED(hr)) - { - hr = ID3D12Device_CreateCommandAllocator(g->device, queue->desc.type, &IID_ID3D12CommandAllocator, (void **)&cl->d3d_ca); - } + /* Reset command list */ + { + HRESULT hr = 0; + { + if (SUCCEEDED(hr)) + { + hr = ID3D12CommandAllocator_Reset(cl->d3d_ca); + } - if (SUCCEEDED(hr)) - { - hr = ID3D12Device_CreateCommandList(g->device, 0, queue->desc.type, cl->d3d_ca, 0, &IID_ID3D12GraphicsCommandList7, (void **)&cl->d3d_cl); - } - - if (SUCCEEDED(hr)) - { - hr = ID3D12GraphicsCommandList_Close(cl->d3d_cl); - } - - /* Initialize Direct queue CPU-only descriptors */ - if (SUCCEEDED(hr) && queue_kind == G_QueueKind_Direct) - { - G_D12_Arena *gpu_perm = G_D12_ArenaFromHandle(G_PermArena()); - for (u32 i = 0; i < countof(cl->rtv_descriptors); ++i) - { - cl->rtv_descriptors[i] = G_D12_PushDescriptor(gpu_perm, G_D12_DescriptorHeapKind_Rtv); - } - cl->rtv_clear_descriptor = G_D12_PushDescriptor(gpu_perm, G_D12_DescriptorHeapKind_Rtv); - } - } - - if (FAILED(hr)) - { - Panic(Lit("Failed to create command list")); - } + if (SUCCEEDED(hr)) + { + hr = ID3D12GraphicsCommandList_Reset(cl->d3d_cl, cl->d3d_ca, 0); + } } - /* Reset command list */ + if (FAILED(hr)) { - HRESULT hr = 0; - { - if (SUCCEEDED(hr)) - { - hr = ID3D12CommandAllocator_Reset(cl->d3d_ca); - } - - if (SUCCEEDED(hr)) - { - hr = ID3D12GraphicsCommandList_Reset(cl->d3d_cl, cl->d3d_ca, 0); - } - } - - if (FAILED(hr)) - { - Panic(Lit("Failed to reset command list")); - } + Panic(Lit("Failed to reset command list")); } + } - return cl; + return cl; } i64 G_D12_CommitRawCommandList(G_D12_RawCommandList *cl) { - G_D12_Queue *queue = cl->queue; + G_D12_Queue *queue = cl->queue; - /* Close */ + /* Close */ + { + HRESULT hr = ID3D12GraphicsCommandList_Close(cl->d3d_cl); + if (FAILED(hr)) { - HRESULT hr = ID3D12GraphicsCommandList_Close(cl->d3d_cl); - if (FAILED(hr)) - { - /* TODO: Don't panic */ - Panic(Lit("Failed to close command list before execution")); - } + /* TODO: Don't panic */ + Panic(Lit("Failed to close command list before execution")); } + } - /* Commit */ - i64 completion_target = 0; + /* Commit */ + i64 completion_target = 0; + { + /* Execute */ + ID3D12CommandQueue_ExecuteCommandLists(queue->d3d_queue, 1, (ID3D12CommandList **)&cl->d3d_cl); + Lock lock = LockE(&queue->commit_mutex); { - /* Execute */ - ID3D12CommandQueue_ExecuteCommandLists(queue->d3d_queue, 1, (ID3D12CommandList **)&cl->d3d_cl); - Lock lock = LockE(&queue->commit_mutex); - { - completion_target = ++queue->commit_fence_target; - cl->commit_fence_target = completion_target; + completion_target = ++queue->commit_fence_target; + cl->commit_fence_target = completion_target; - ID3D12CommandQueue_Signal(queue->d3d_queue, queue->commit_fence, completion_target); + ID3D12CommandQueue_Signal(queue->d3d_queue, queue->commit_fence, completion_target); - /* Append */ - SllQueuePush(queue->first_committed_cl, queue->last_committed_cl, cl); - } - Unlock(&lock); + /* Append */ + SllQueuePush(queue->first_committed_cl, queue->last_committed_cl, cl); } + Unlock(&lock); + } - return completion_target; + return completion_target; } //////////////////////////////////////////////////////////// @@ -756,39 +753,39 @@ i64 G_D12_CommitRawCommandList(G_D12_RawCommandList *cl) G_ArenaHandle G_AcquireArena(void) { - G_D12_Arena *gpu_arena = 0; - { - Arena *perm = PermArena(); - PushAlign(perm, CachelineSize); - gpu_arena = PushStruct(perm, G_D12_Arena); - PushAlign(perm, CachelineSize); - } - gpu_arena->arena = AcquireArena(Gibi(1)); + G_D12_Arena *gpu_arena = 0; + { + Arena *perm = PermArena(); + PushAlign(perm, CachelineSize); + gpu_arena = PushStruct(perm, G_D12_Arena); + PushAlign(perm, CachelineSize); + } + gpu_arena->arena = AcquireArena(Gibi(1)); - for (u64 heap_idx = 0; heap_idx < countof(gpu_arena->resource_heaps); ++heap_idx) - { - gpu_arena->resource_heaps[heap_idx].kind = (G_D12_ResourceHeapKind)heap_idx; - } + for (u64 heap_idx = 0; heap_idx < countof(gpu_arena->resource_heaps); ++heap_idx) + { + gpu_arena->resource_heaps[heap_idx].kind = (G_D12_ResourceHeapKind)heap_idx; + } - AddGstat(NumGpuArenas, 1); + AddGstat(NumGpuArenas, 1); - return G_D12_MakeHandle(G_ArenaHandle, gpu_arena); + return G_D12_MakeHandle(G_ArenaHandle, gpu_arena); } void G_ReleaseArena(G_ArenaHandle arena) { - /* TODO */ + /* TODO */ - /* TODO: Unmap heaps */ + /* TODO: Unmap heaps */ - /* TODO: Update gstats */ + /* TODO: Update gstats */ } void G_ResetArena(G_CommandListHandle cl_handle, G_ArenaHandle arena_handle) { - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Arena *gpu_arena = G_D12_ArenaFromHandle(arena_handle); - G_D12_ResetArena(cl, gpu_arena); + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Arena *gpu_arena = G_D12_ArenaFromHandle(arena_handle); + G_D12_ResetArena(cl, gpu_arena); } //////////////////////////////////////////////////////////// @@ -796,54 +793,54 @@ void G_ResetArena(G_CommandListHandle cl_handle, G_ArenaHandle arena_handle) void G_D12_ResetArena(G_D12_CmdList *cl, G_D12_Arena *gpu_arena) { - /* TODO */ + /* TODO */ - for (u64 heap_idx = 0; heap_idx < countof(gpu_arena->resource_heaps); ++heap_idx) + for (u64 heap_idx = 0; heap_idx < countof(gpu_arena->resource_heaps); ++heap_idx) + { + G_D12_ResourceHeap *heap = &gpu_arena->resource_heaps[heap_idx]; + heap->pos = 0; + + if (heap->resources.first) { - G_D12_ResourceHeap *heap = &gpu_arena->resource_heaps[heap_idx]; - heap->pos = 0; - - if (heap->resources.first) - { - for (G_D12_Resource *resource = heap->resources.first; resource; resource = resource->next) - { - ID3D12Resource_Release(resource->d3d_resource); - } - if (gpu_arena->free_resources.last) - { - gpu_arena->free_resources.last->next = heap->resources.first; - } - else - { - gpu_arena->free_resources.first = heap->resources.first; - } - gpu_arena->free_resources.last = heap->resources.last; - gpu_arena->free_resources.count += heap->resources.count; - heap->resources.count = 0; - heap->resources.first = 0; - heap->resources.last = 0; - } + for (G_D12_Resource *resource = heap->resources.first; resource; resource = resource->next) + { + ID3D12Resource_Release(resource->d3d_resource); + } + if (gpu_arena->free_resources.last) + { + gpu_arena->free_resources.last->next = heap->resources.first; + } + else + { + gpu_arena->free_resources.first = heap->resources.first; + } + gpu_arena->free_resources.last = heap->resources.last; + gpu_arena->free_resources.count += heap->resources.count; + heap->resources.count = 0; + heap->resources.first = 0; + heap->resources.last = 0; } + } - /* Push descriptors to cl reset list */ - if (gpu_arena->descriptors.first) + /* Push descriptors to cl reset list */ + if (gpu_arena->descriptors.first) + { + if (cl->reset_descriptors.last) { - if (cl->reset_descriptors.last) - { - cl->reset_descriptors.last->next = gpu_arena->descriptors.first; - } - else - { - cl->reset_descriptors.first = gpu_arena->descriptors.first; - } - cl->reset_descriptors.last = gpu_arena->descriptors.last; - cl->reset_descriptors.count += gpu_arena->descriptors.count; - gpu_arena->descriptors.count = 0; - gpu_arena->descriptors.first = 0; - gpu_arena->descriptors.last = 0; + cl->reset_descriptors.last->next = gpu_arena->descriptors.first; } + else + { + cl->reset_descriptors.first = gpu_arena->descriptors.first; + } + cl->reset_descriptors.last = gpu_arena->descriptors.last; + cl->reset_descriptors.count += gpu_arena->descriptors.count; + gpu_arena->descriptors.count = 0; + gpu_arena->descriptors.first = 0; + gpu_arena->descriptors.last = 0; + } } @@ -852,311 +849,311 @@ void G_D12_ResetArena(G_D12_CmdList *cl, G_D12_Arena *gpu_arena) G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle cl_handle, G_ResourceDesc desc) { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_Arena *gpu_arena = G_D12_ArenaFromHandle(arena_handle); - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Resource *resource = 0; - HRESULT hr = 0; + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_Arena *gpu_arena = G_D12_ArenaFromHandle(arena_handle); + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Resource *resource = 0; + HRESULT hr = 0; - b32 is_buffer = desc.kind == G_ResourceKind_Buffer; - b32 is_texture = desc.kind == G_ResourceKind_Texture1D || - desc.kind == G_ResourceKind_Texture2D || - desc.kind == G_ResourceKind_Texture3D; - b32 is_sampler = desc.kind == G_ResourceKind_Sampler; - G_ResourceFlag flags = is_buffer ? desc.buffer.flags : - is_texture ? desc.texture.flags : - desc.sampler.flags; + b32 is_buffer = desc.kind == G_ResourceKind_Buffer; + b32 is_texture = desc.kind == G_ResourceKind_Texture1D || + desc.kind == G_ResourceKind_Texture2D || + desc.kind == G_ResourceKind_Texture3D; + b32 is_sampler = desc.kind == G_ResourceKind_Sampler; + G_ResourceFlag flags = is_buffer ? desc.buffer.flags : + is_texture ? desc.texture.flags : + desc.sampler.flags; + if (is_buffer || is_texture) + { + ////////////////////////////// + //- Initialize heap + + G_D12_ResourceHeap *heap = 0; if (is_buffer || is_texture) { - ////////////////////////////// - //- Initialize heap - - G_D12_ResourceHeap *heap = 0; - if (is_buffer || is_texture) + G_D12_ResourceHeapKind heap_kind = G_D12_ResourceHeapKind_Gpu; + if (flags & G_ResourceFlag_HostMemory) + { + heap_kind = G_D12_ResourceHeapKind_Cpu; + if (flags & G_ResourceFlag_Uncached) { - G_D12_ResourceHeapKind heap_kind = G_D12_ResourceHeapKind_Gpu; - if (flags & G_ResourceFlag_HostMemory) - { - heap_kind = G_D12_ResourceHeapKind_Cpu; - if (flags & G_ResourceFlag_Uncached) - { - heap_kind = G_D12_ResourceHeapKind_CpuWriteCombined; - } - } - heap = &gpu_arena->resource_heaps[heap_kind]; - if (heap->d3d_heap == 0) - { - b32 is_mappable = 0; - - /* Initialize heap */ - /* FIXME: Dynamic size */ - if (heap->d3d_heap == 0) - { - /* Create d3d heap */ - { - D3D12_HEAP_DESC d3d_desc = Zi; - d3d_desc.SizeInBytes = Mebi(256); - if (heap_kind == G_D12_ResourceHeapKind_Cpu) - { - d3d_desc.Properties.Type = D3D12_HEAP_TYPE_CUSTOM; - d3d_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK; - d3d_desc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0; - is_mappable = 1; - } - else if (heap_kind == G_D12_ResourceHeapKind_CpuWriteCombined) - { - d3d_desc.Properties.Type = D3D12_HEAP_TYPE_CUSTOM; - d3d_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE; - d3d_desc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0; - is_mappable = 1; - } - else - { - d3d_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; - } - d3d_desc.Flags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED; - d3d_desc.Flags |= D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES; /* TODO: Remove this and support tier 1 resource heaps */ - hr = ID3D12Device_CreateHeap(g->device, &d3d_desc, &IID_ID3D12Heap, (void **)&heap->d3d_heap); - heap->size = d3d_desc.SizeInBytes; - if (d3d_desc.Properties.Type == D3D12_HEAP_TYPE_DEFAULT) - { - AddGstat(DedicatedGpuArenaMemoryCommitted, heap->size); - } - else - { - AddGstat(SharedGpuArenaMemoryCommitted, heap->size); - } - } - - /* Map heap resource */ - if (is_mappable) - { - if (SUCCEEDED(hr)) - { - D3D12_RESOURCE_DESC1 d3d_desc = Zi; - d3d_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - d3d_desc.Format = DXGI_FORMAT_UNKNOWN; - d3d_desc.Width = heap->size; - d3d_desc.Height = 1; - d3d_desc.DepthOrArraySize = 1; - d3d_desc.MipLevels = 1; - d3d_desc.SampleDesc.Count = 1; - d3d_desc.SampleDesc.Quality = 0; - d3d_desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; - - u64 alloc_size = 0; - u64 alloc_align = 0; - { - D3D12_RESOURCE_ALLOCATION_INFO alloc_info = Zi; - ID3D12Device_GetResourceAllocationInfo(g->device, &alloc_info, 0, 1, (D3D12_RESOURCE_DESC *)&d3d_desc); - alloc_size = alloc_info.SizeInBytes; - alloc_align = alloc_info.Alignment; - } - - if (alloc_size > heap->size) - { - Panic(Lit("Gpu heap overflow")); - } - - hr = ID3D12Device10_CreatePlacedResource2( - g->device, - heap->d3d_heap, - 0, - &d3d_desc, - D3D12_BARRIER_LAYOUT_UNDEFINED, - 0, - 0, - 0, - &IID_ID3D12Resource, - (void **)&heap->d3d_mapped_resource - ); - } - if (SUCCEEDED(hr)) - { - D3D12_RANGE read_range = Zi; - hr = ID3D12Resource_Map(heap->d3d_mapped_resource, 0, &read_range, &heap->mapped); - } - } - - if (!SUCCEEDED(hr)) - { - /* TODO: Don't panic */ - Panic(Lit("Failed to create D3D12 resource heap")); - } - } - } + heap_kind = G_D12_ResourceHeapKind_CpuWriteCombined; } + } + heap = &gpu_arena->resource_heaps[heap_kind]; + if (heap->d3d_heap == 0) + { + b32 is_mappable = 0; - ////////////////////////////// - //- Initialize d3d resource desc - - D3D12_BARRIER_LAYOUT initial_layout = D3D12_BARRIER_LAYOUT_UNDEFINED; - D3D12_CLEAR_VALUE clear_value = Zi; - D3D12_RESOURCE_DESC1 d3d_desc = Zi; + /* Initialize heap */ + /* FIXME: Dynamic size */ + if (heap->d3d_heap == 0) { - if (is_buffer) + /* Create d3d heap */ + { + D3D12_HEAP_DESC d3d_desc = Zi; + d3d_desc.SizeInBytes = Mebi(256); + if (heap_kind == G_D12_ResourceHeapKind_Cpu) { - d3d_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - d3d_desc.Format = DXGI_FORMAT_UNKNOWN; - d3d_desc.Width = AlignU64(MaxU64(desc.buffer.size, 1), 4); - d3d_desc.Height = 1; - d3d_desc.DepthOrArraySize = 1; - d3d_desc.MipLevels = 1; - d3d_desc.SampleDesc.Count = 1; - d3d_desc.SampleDesc.Quality = 0; - d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS * AnyBit(flags, G_ResourceFlag_AllowShaderReadWrite); + d3d_desc.Properties.Type = D3D12_HEAP_TYPE_CUSTOM; + d3d_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK; + d3d_desc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0; + is_mappable = 1; } - if (is_texture) + else if (heap_kind == G_D12_ResourceHeapKind_CpuWriteCombined) { - initial_layout = G_D12_BarrierLayoutFromLayout(desc.texture.initial_layout); - d3d_desc.Dimension = desc.kind == G_ResourceKind_Texture1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D : - desc.kind == G_ResourceKind_Texture2D ? D3D12_RESOURCE_DIMENSION_TEXTURE2D : - D3D12_RESOURCE_DIMENSION_TEXTURE3D; - d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - d3d_desc.Format = G_D12_DxgiFormatFromGpuFormat(desc.texture.format); - d3d_desc.Width = MaxI32(desc.texture.dims.x, 1); - d3d_desc.Height = MaxI32(desc.texture.dims.y, 1); - d3d_desc.DepthOrArraySize = MaxI32(desc.texture.dims.z, 1); - d3d_desc.MipLevels = MaxI32(desc.texture.mip_levels, 1); - d3d_desc.SampleDesc.Count = 1; - d3d_desc.SampleDesc.Quality = 0; - d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS * AnyBit(flags, G_ResourceFlag_AllowShaderReadWrite); - d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET * AnyBit(flags, G_ResourceFlag_AllowRenderTarget); - d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL * AnyBit(flags, G_ResourceFlag_AllowDepthStencil); - d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS * (desc.texture.initial_layout == G_Layout_Simultaneous); - clear_value.Color[0] = desc.texture.clear_color.x, - clear_value.Color[1] = desc.texture.clear_color.y, - clear_value.Color[2] = desc.texture.clear_color.z, - clear_value.Color[3] = desc.texture.clear_color.w, - clear_value.Format = d3d_desc.Format; + d3d_desc.Properties.Type = D3D12_HEAP_TYPE_CUSTOM; + d3d_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE; + d3d_desc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0; + is_mappable = 1; } - } - - u64 align_in_heap = 0; - u64 size_in_heap = 0; - { - D3D12_RESOURCE_ALLOCATION_INFO alloc_info = Zi; - ID3D12Device_GetResourceAllocationInfo(g->device, &alloc_info, 0, 1, (D3D12_RESOURCE_DESC *)&d3d_desc); - align_in_heap = alloc_info.Alignment; - size_in_heap = alloc_info.SizeInBytes; - } - - ////////////////////////////// - //- Re-use existing resource - - // u64 pos_in_heap = 0; - // ID3D12Resource *d3d_resource = 0; - // { - // resource = heap->first_reset_resource; - // if (resource) - // { - // SllQueuePop(heap->first_reset_resource, heap->last_reset_resource); - // --heap->reset_resources_count; - // b32 can_use = 1; - // can_use = can_use && resource->is_texture == is_texture; - // can_use = can_use && resource->size_in_heap >= size_in_heap; - // can_use = can_use && resource->pos_in_heap % align_in_heap == 0; - // if (can_use) - // { - // d3d_resource = resource->d3d_resource; - // pos_in_heap = resource->pos_in_heap; - // size_in_heap = resource->size_in_heap; - // heap->pos = resource->pos_in_heap + resource->size_in_heap; - // } - // else - // { - // /* FIXME: Free d3d resource here? */ - // ZeroStruct(resource); - // } - // } - // if (!resource) - // { - // resource = PushStruct(gpu_arena->arena, G_D12_Resource); - // } - // } - u64 pos_in_heap = 0; - ID3D12Resource *d3d_resource = 0; - resource = gpu_arena->free_resources.first; - if (resource) - { - SllQueuePop(gpu_arena->free_resources.first, gpu_arena->free_resources.last); - --gpu_arena->free_resources.count; - ZeroStruct(resource); - } - else - { - resource = PushStruct(gpu_arena->arena, G_D12_Resource); - } - - ////////////////////////////// - //- Create new d3d resource - - if (!resource->d3d_resource) - { - pos_in_heap = heap->pos; - pos_in_heap = AlignU64(pos_in_heap, align_in_heap); - heap->pos = pos_in_heap + size_in_heap; - if (pos_in_heap + size_in_heap > heap->size) + else { - Panic(Lit("Gpu arena overflow")); + d3d_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; } - hr = ID3D12Device10_CreatePlacedResource2( + d3d_desc.Flags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED; + d3d_desc.Flags |= D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES; /* TODO: Remove this and support tier 1 resource heaps */ + hr = ID3D12Device_CreateHeap(g->device, &d3d_desc, &IID_ID3D12Heap, (void **)&heap->d3d_heap); + heap->size = d3d_desc.SizeInBytes; + if (d3d_desc.Properties.Type == D3D12_HEAP_TYPE_DEFAULT) + { + AddGstat(DedicatedGpuArenaMemoryCommitted, heap->size); + } + else + { + AddGstat(SharedGpuArenaMemoryCommitted, heap->size); + } + } + + /* Map heap resource */ + if (is_mappable) + { + if (SUCCEEDED(hr)) + { + D3D12_RESOURCE_DESC1 d3d_desc = Zi; + d3d_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + d3d_desc.Format = DXGI_FORMAT_UNKNOWN; + d3d_desc.Width = heap->size; + d3d_desc.Height = 1; + d3d_desc.DepthOrArraySize = 1; + d3d_desc.MipLevels = 1; + d3d_desc.SampleDesc.Count = 1; + d3d_desc.SampleDesc.Quality = 0; + d3d_desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; + + u64 alloc_size = 0; + u64 alloc_align = 0; + { + D3D12_RESOURCE_ALLOCATION_INFO alloc_info = Zi; + ID3D12Device_GetResourceAllocationInfo(g->device, &alloc_info, 0, 1, (D3D12_RESOURCE_DESC *)&d3d_desc); + alloc_size = alloc_info.SizeInBytes; + alloc_align = alloc_info.Alignment; + } + + if (alloc_size > heap->size) + { + Panic(Lit("Gpu heap overflow")); + } + + hr = ID3D12Device10_CreatePlacedResource2( g->device, heap->d3d_heap, - pos_in_heap, + 0, &d3d_desc, - initial_layout, - (d3d_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? &clear_value : 0, + D3D12_BARRIER_LAYOUT_UNDEFINED, + 0, 0, 0, &IID_ID3D12Resource, - (void **)&d3d_resource - ); - } + (void **)&heap->d3d_mapped_resource + ); + } + if (SUCCEEDED(hr)) + { + D3D12_RANGE read_range = Zi; + hr = ID3D12Resource_Map(heap->d3d_mapped_resource, 0, &read_range, &heap->mapped); + } + } - ////////////////////////////// - //- Insert resource - - resource->heap = heap; - resource->pos_in_heap = pos_in_heap; - resource->size_in_heap = size_in_heap; - resource->d3d_resource = d3d_resource; - resource->uid = Atomic64FetchAdd(&g->resource_creation_gen.v, 1) + 1; - resource->flags = flags; - if (is_buffer) - { - resource->buffer_size = desc.buffer.size; - resource->buffer_size_actual = d3d_desc.Width; - /* TODO: Cache this */ - resource->buffer_gpu_address = ID3D12Resource_GetGPUVirtualAddress(d3d_resource); + if (!SUCCEEDED(hr)) + { + /* TODO: Don't panic */ + Panic(Lit("Failed to create D3D12 resource heap")); + } } - if (is_texture) - { - resource->is_texture = 1; - resource->texture_format = desc.texture.format; - resource->texture_dims = desc.texture.dims; - resource->texture_mip_levels = d3d_desc.MipLevels; - resource->texture_layout = initial_layout; - } - - SllQueuePush(heap->resources.first, heap->resources.last, resource); - ++heap->resources.count; + } } ////////////////////////////// - //- Create sampler + //- Initialize d3d resource desc - if (is_sampler) + D3D12_BARRIER_LAYOUT initial_layout = D3D12_BARRIER_LAYOUT_UNDEFINED; + D3D12_CLEAR_VALUE clear_value = Zi; + D3D12_RESOURCE_DESC1 d3d_desc = Zi; { - resource = PushStruct(gpu_arena->arena, G_D12_Resource); - resource->uid = Atomic64FetchAdd(&g->resource_creation_gen.v, 1) + 1; - resource->sampler_desc = desc.sampler; + if (is_buffer) + { + d3d_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + d3d_desc.Format = DXGI_FORMAT_UNKNOWN; + d3d_desc.Width = AlignU64(MaxU64(desc.buffer.size, 1), 4); + d3d_desc.Height = 1; + d3d_desc.DepthOrArraySize = 1; + d3d_desc.MipLevels = 1; + d3d_desc.SampleDesc.Count = 1; + d3d_desc.SampleDesc.Quality = 0; + d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS * AnyBit(flags, G_ResourceFlag_AllowShaderReadWrite); + } + if (is_texture) + { + initial_layout = G_D12_BarrierLayoutFromLayout(desc.texture.initial_layout); + d3d_desc.Dimension = desc.kind == G_ResourceKind_Texture1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D : + desc.kind == G_ResourceKind_Texture2D ? D3D12_RESOURCE_DIMENSION_TEXTURE2D : + D3D12_RESOURCE_DIMENSION_TEXTURE3D; + d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + d3d_desc.Format = G_D12_DxgiFormatFromGpuFormat(desc.texture.format); + d3d_desc.Width = MaxI32(desc.texture.dims.x, 1); + d3d_desc.Height = MaxI32(desc.texture.dims.y, 1); + d3d_desc.DepthOrArraySize = MaxI32(desc.texture.dims.z, 1); + d3d_desc.MipLevels = MaxI32(desc.texture.mip_levels, 1); + d3d_desc.SampleDesc.Count = 1; + d3d_desc.SampleDesc.Quality = 0; + d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS * AnyBit(flags, G_ResourceFlag_AllowShaderReadWrite); + d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET * AnyBit(flags, G_ResourceFlag_AllowRenderTarget); + d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL * AnyBit(flags, G_ResourceFlag_AllowDepthStencil); + d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS * (desc.texture.initial_layout == G_Layout_Simultaneous); + clear_value.Color[0] = desc.texture.clear_color.x, + clear_value.Color[1] = desc.texture.clear_color.y, + clear_value.Color[2] = desc.texture.clear_color.z, + clear_value.Color[3] = desc.texture.clear_color.w, + clear_value.Format = d3d_desc.Format; + } } - return G_D12_MakeHandle(G_ResourceHandle, resource); + u64 align_in_heap = 0; + u64 size_in_heap = 0; + { + D3D12_RESOURCE_ALLOCATION_INFO alloc_info = Zi; + ID3D12Device_GetResourceAllocationInfo(g->device, &alloc_info, 0, 1, (D3D12_RESOURCE_DESC *)&d3d_desc); + align_in_heap = alloc_info.Alignment; + size_in_heap = alloc_info.SizeInBytes; + } + + ////////////////////////////// + //- Re-use existing resource + + // u64 pos_in_heap = 0; + // ID3D12Resource *d3d_resource = 0; + // { + // resource = heap->first_reset_resource; + // if (resource) + // { + // SllQueuePop(heap->first_reset_resource, heap->last_reset_resource); + // --heap->reset_resources_count; + // b32 can_use = 1; + // can_use = can_use && resource->is_texture == is_texture; + // can_use = can_use && resource->size_in_heap >= size_in_heap; + // can_use = can_use && resource->pos_in_heap % align_in_heap == 0; + // if (can_use) + // { + // d3d_resource = resource->d3d_resource; + // pos_in_heap = resource->pos_in_heap; + // size_in_heap = resource->size_in_heap; + // heap->pos = resource->pos_in_heap + resource->size_in_heap; + // } + // else + // { + // /* FIXME: Free d3d resource here? */ + // ZeroStruct(resource); + // } + // } + // if (!resource) + // { + // resource = PushStruct(gpu_arena->arena, G_D12_Resource); + // } + // } + u64 pos_in_heap = 0; + ID3D12Resource *d3d_resource = 0; + resource = gpu_arena->free_resources.first; + if (resource) + { + SllQueuePop(gpu_arena->free_resources.first, gpu_arena->free_resources.last); + --gpu_arena->free_resources.count; + ZeroStruct(resource); + } + else + { + resource = PushStruct(gpu_arena->arena, G_D12_Resource); + } + + ////////////////////////////// + //- Create new d3d resource + + if (!resource->d3d_resource) + { + pos_in_heap = heap->pos; + pos_in_heap = AlignU64(pos_in_heap, align_in_heap); + heap->pos = pos_in_heap + size_in_heap; + if (pos_in_heap + size_in_heap > heap->size) + { + Panic(Lit("Gpu arena overflow")); + } + hr = ID3D12Device10_CreatePlacedResource2( + g->device, + heap->d3d_heap, + pos_in_heap, + &d3d_desc, + initial_layout, + (d3d_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? &clear_value : 0, + 0, + 0, + &IID_ID3D12Resource, + (void **)&d3d_resource + ); + } + + ////////////////////////////// + //- Insert resource + + resource->heap = heap; + resource->pos_in_heap = pos_in_heap; + resource->size_in_heap = size_in_heap; + resource->d3d_resource = d3d_resource; + resource->uid = Atomic64FetchAdd(&g->resource_creation_gen.v, 1) + 1; + resource->flags = flags; + if (is_buffer) + { + resource->buffer_size = desc.buffer.size; + resource->buffer_size_actual = d3d_desc.Width; + /* TODO: Cache this */ + resource->buffer_gpu_address = ID3D12Resource_GetGPUVirtualAddress(d3d_resource); + } + if (is_texture) + { + resource->is_texture = 1; + resource->texture_format = desc.texture.format; + resource->texture_dims = desc.texture.dims; + resource->texture_mip_levels = d3d_desc.MipLevels; + resource->texture_layout = initial_layout; + } + + SllQueuePush(heap->resources.first, heap->resources.last, resource); + ++heap->resources.count; + } + + ////////////////////////////// + //- Create sampler + + if (is_sampler) + { + resource = PushStruct(gpu_arena->arena, G_D12_Resource); + resource->uid = Atomic64FetchAdd(&g->resource_creation_gen.v, 1) + 1; + resource->sampler_desc = desc.sampler; + } + + return G_D12_MakeHandle(G_ResourceHandle, resource); } //////////////////////////////////////////////////////////// @@ -1164,77 +1161,77 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle G_D12_Descriptor *G_D12_DescriptorFromIndex(G_D12_DescriptorHeapKind heap_kind, u32 index) { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_DescriptorHeap *heap = &g->descriptor_heaps[heap_kind]; - G_D12_Descriptor *descriptors = ArenaFirst(heap->descriptors_arena, G_D12_Descriptor); - return &descriptors[index]; + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_DescriptorHeap *heap = &g->descriptor_heaps[heap_kind]; + G_D12_Descriptor *descriptors = ArenaFirst(heap->descriptors_arena, G_D12_Descriptor); + return &descriptors[index]; } G_D12_Descriptor *G_D12_PushDescriptor(G_D12_Arena *gpu_arena, G_D12_DescriptorHeapKind heap_kind) { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_DescriptorHeap *heap = &g->descriptor_heaps[heap_kind]; + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_DescriptorHeap *heap = &g->descriptor_heaps[heap_kind]; - G_D12_Descriptor *descriptor = 0; - u32 index = 0; + G_D12_Descriptor *descriptor = 0; + u32 index = 0; - /* Grab completed descriptor from arena */ - G_D12_DescriptorList *descriptors = &gpu_arena->reset_descriptors_by_heap[heap_kind]; - descriptor = descriptors->first; - if (descriptor) + /* Grab completed descriptor from arena */ + G_D12_DescriptorList *descriptors = &gpu_arena->reset_descriptors_by_heap[heap_kind]; + descriptor = descriptors->first; + if (descriptor) + { + G_D12_Queue *queue = G_D12_QueueFromKind(descriptor->completion_queue_kind); + i64 queue_commit_completion = ID3D12Fence_GetCompletedValue(queue->commit_fence); + if (queue_commit_completion >= descriptor->completion_queue_target) { - G_D12_Queue *queue = G_D12_QueueFromKind(descriptor->completion_queue_kind); - i64 queue_commit_completion = ID3D12Fence_GetCompletedValue(queue->commit_fence); - if (queue_commit_completion >= descriptor->completion_queue_target) - { - /* Descriptor no longer in use by gpu, reuse it */ - SllQueuePop(descriptors->first, descriptors->last); - --descriptors->count; - index = descriptor->index; - } - else - { - /* Descriptor may still be in use by gpu */ - descriptor = 0; - } + /* Descriptor no longer in use by gpu, reuse it */ + SllQueuePop(descriptors->first, descriptors->last); + --descriptors->count; + index = descriptor->index; } - - /* Allocate new descriptor from heap */ - if (!descriptor) + else { - Lock lock = LockE(&heap->mutex); - { - if (heap->first_free) - { - descriptor = heap->first_free; - SllStackPop(heap->first_free); - index = descriptor->index; - } - else - { - u32 descriptors_count = ArenaCount(heap->descriptors_arena, G_D12_Descriptor); - if (descriptors_count >= heap->max_count) - { - Panic(Lit("Max descriptors reached in heap")); - } - descriptor = PushStruct(heap->descriptors_arena, G_D12_Descriptor); - index = descriptors_count; - } - } - Unlock(&lock); + /* Descriptor may still be in use by gpu */ + descriptor = 0; } + } - /* Initialize descriptor handle */ - ZeroStruct(descriptor); - descriptor->gpu_arena = gpu_arena; - descriptor->index = index; - descriptor->handle.ptr = heap->start_handle.ptr + (index * heap->descriptor_size); - descriptor->heap = heap; + /* Allocate new descriptor from heap */ + if (!descriptor) + { + Lock lock = LockE(&heap->mutex); + { + if (heap->first_free) + { + descriptor = heap->first_free; + SllStackPop(heap->first_free); + index = descriptor->index; + } + else + { + u32 descriptors_count = ArenaCount(heap->descriptors_arena, G_D12_Descriptor); + if (descriptors_count >= heap->max_count) + { + Panic(Lit("Max descriptors reached in heap")); + } + descriptor = PushStruct(heap->descriptors_arena, G_D12_Descriptor); + index = descriptors_count; + } + } + Unlock(&lock); + } - SllQueuePush(gpu_arena->descriptors.first, gpu_arena->descriptors.last, descriptor); - ++gpu_arena->descriptors.count; + /* Initialize descriptor handle */ + ZeroStruct(descriptor); + descriptor->gpu_arena = gpu_arena; + descriptor->index = index; + descriptor->handle.ptr = heap->start_handle.ptr + (index * heap->descriptor_size); + descriptor->heap = heap; - return descriptor; + SllQueuePush(gpu_arena->descriptors.first, gpu_arena->descriptors.last, descriptor); + ++gpu_arena->descriptors.count; + + return descriptor; } //////////////////////////////////////////////////////////// @@ -1242,190 +1239,190 @@ G_D12_Descriptor *G_D12_PushDescriptor(G_D12_Arena *gpu_arena, G_D12_DescriptorH u32 G_PushRef(G_ArenaHandle arena_handle, G_ResourceHandle resource_handle, G_RefDesc ref_desc) { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_Arena *gpu_arena = G_D12_ArenaFromHandle(arena_handle); - G_D12_Resource *resource = G_D12_ResourceFromHandle(resource_handle); - u32 result = 0; + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_Arena *gpu_arena = G_D12_ArenaFromHandle(arena_handle); + G_D12_Resource *resource = G_D12_ResourceFromHandle(resource_handle); + u32 result = 0; - G_RefKind kind = ref_desc.kind; + G_RefKind kind = ref_desc.kind; - b32 is_buffer = kind == G_RefKind_StructuredBuffer || - kind == G_RefKind_RWStructuredBuffer || - kind == G_RefKind_ByteAddressBuffer || - kind == G_RefKind_RWByteAddressBuffer; + b32 is_buffer = kind == G_RefKind_StructuredBuffer || + kind == G_RefKind_RWStructuredBuffer || + kind == G_RefKind_ByteAddressBuffer || + kind == G_RefKind_RWByteAddressBuffer; - b32 is_sampler = kind == G_RefKind_SamplerState; + b32 is_sampler = kind == G_RefKind_SamplerState; - b32 is_texture = !is_buffer && !is_sampler; + b32 is_texture = !is_buffer && !is_sampler; - b32 is_raw = kind == G_RefKind_ByteAddressBuffer || - kind == G_RefKind_RWByteAddressBuffer; + b32 is_raw = kind == G_RefKind_ByteAddressBuffer || + kind == G_RefKind_RWByteAddressBuffer; - b32 is_uav = kind == G_RefKind_RWStructuredBuffer || - kind == G_RefKind_RWByteAddressBuffer || - kind == G_RefKind_RWTexture1D || - kind == G_RefKind_RWTexture2D || - kind == G_RefKind_RWTexture3D; + b32 is_uav = kind == G_RefKind_RWStructuredBuffer || + kind == G_RefKind_RWByteAddressBuffer || + kind == G_RefKind_RWTexture1D || + kind == G_RefKind_RWTexture2D || + kind == G_RefKind_RWTexture3D; - if (is_uav) + if (is_uav) + { + /* RW refs must be allowed on this resource */ + Assert(resource->flags & G_ResourceFlag_AllowShaderReadWrite); + } + + G_D12_Descriptor *descriptor = 0; + if (is_buffer) + { + if (is_raw) { - /* RW refs must be allowed on this resource */ - Assert(resource->flags & G_ResourceFlag_AllowShaderReadWrite); + ref_desc.element_size = 4; + ref_desc.element_offset /= 4; } - G_D12_Descriptor *descriptor = 0; - if (is_buffer) + descriptor = G_D12_PushDescriptor(gpu_arena, G_D12_DescriptorHeapKind_CbvSrvUav); + u64 buffer_size_actual = resource->buffer_size_actual; + u64 num_elements_in_buffer = buffer_size_actual / ref_desc.element_size; + u64 num_elements_after_offset = num_elements_in_buffer > ref_desc.element_offset ? num_elements_in_buffer - ref_desc.element_offset : 0; + + if (num_elements_after_offset > 0) { + if (is_uav) + { + D3D12_UNORDERED_ACCESS_VIEW_DESC desc = Zi; + { + desc.Format = DXGI_FORMAT_UNKNOWN; + desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + desc.Buffer.FirstElement = ref_desc.element_offset; + desc.Buffer.NumElements = num_elements_after_offset; + desc.Buffer.StructureByteStride = ref_desc.element_size; + desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; + } if (is_raw) { - ref_desc.element_size = 4; - ref_desc.element_offset /= 4; + desc.Format = DXGI_FORMAT_R32_TYPELESS; + desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; + desc.Buffer.StructureByteStride = 0; } - - descriptor = G_D12_PushDescriptor(gpu_arena, G_D12_DescriptorHeapKind_CbvSrvUav); - u64 buffer_size_actual = resource->buffer_size_actual; - u64 num_elements_in_buffer = buffer_size_actual / ref_desc.element_size; - u64 num_elements_after_offset = num_elements_in_buffer > ref_desc.element_offset ? num_elements_in_buffer - ref_desc.element_offset : 0; - - if (num_elements_after_offset > 0) + ID3D12Device_CreateUnorderedAccessView(g->device, resource->d3d_resource, 0, &desc, descriptor->handle); + } + else + { + D3D12_SHADER_RESOURCE_VIEW_DESC desc = Zi; { - if (is_uav) - { - D3D12_UNORDERED_ACCESS_VIEW_DESC desc = Zi; - { - desc.Format = DXGI_FORMAT_UNKNOWN; - desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - desc.Buffer.FirstElement = ref_desc.element_offset; - desc.Buffer.NumElements = num_elements_after_offset; - desc.Buffer.StructureByteStride = ref_desc.element_size; - desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; - } - if (is_raw) - { - desc.Format = DXGI_FORMAT_R32_TYPELESS; - desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; - desc.Buffer.StructureByteStride = 0; - } - ID3D12Device_CreateUnorderedAccessView(g->device, resource->d3d_resource, 0, &desc, descriptor->handle); - } - else - { - D3D12_SHADER_RESOURCE_VIEW_DESC desc = Zi; - { - desc.Format = DXGI_FORMAT_UNKNOWN; - desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - desc.Buffer.FirstElement = ref_desc.element_offset; - desc.Buffer.NumElements = num_elements_after_offset; - desc.Buffer.StructureByteStride = ref_desc.element_size; - desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; - } - if (is_raw) - { - desc.Format = DXGI_FORMAT_R32_TYPELESS; - desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; - desc.Buffer.StructureByteStride = 0; - } - ID3D12Device_CreateShaderResourceView(g->device, resource->d3d_resource, &desc, descriptor->handle); - } + desc.Format = DXGI_FORMAT_UNKNOWN; + desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + desc.Buffer.FirstElement = ref_desc.element_offset; + desc.Buffer.NumElements = num_elements_after_offset; + desc.Buffer.StructureByteStride = ref_desc.element_size; + desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; } + if (is_raw) + { + desc.Format = DXGI_FORMAT_R32_TYPELESS; + desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; + desc.Buffer.StructureByteStride = 0; + } + ID3D12Device_CreateShaderResourceView(g->device, resource->d3d_resource, &desc, descriptor->handle); + } } - else if (is_texture) + } + else if (is_texture) + { + descriptor = G_D12_PushDescriptor(gpu_arena, G_D12_DescriptorHeapKind_CbvSrvUav); + if (is_uav) { - descriptor = G_D12_PushDescriptor(gpu_arena, G_D12_DescriptorHeapKind_CbvSrvUav); - if (is_uav) - { - ID3D12Device_CreateUnorderedAccessView(g->device, resource->d3d_resource, 0, 0, descriptor->handle); - } - else - { - ID3D12Device_CreateShaderResourceView(g->device, resource->d3d_resource, 0, descriptor->handle); - } + ID3D12Device_CreateUnorderedAccessView(g->device, resource->d3d_resource, 0, 0, descriptor->handle); } - else if (is_sampler) + else { - descriptor = G_D12_PushDescriptor(gpu_arena, G_D12_DescriptorHeapKind_Sampler); - G_SamplerDesc sampler_desc = resource->sampler_desc; - D3D12_SAMPLER_DESC d3d_desc = Zi; - { - d3d_desc.Filter = (D3D12_FILTER)sampler_desc.filter; - d3d_desc.AddressU = (D3D12_TEXTURE_ADDRESS_MODE)sampler_desc.x; - d3d_desc.AddressV = (D3D12_TEXTURE_ADDRESS_MODE)sampler_desc.y; - d3d_desc.AddressW = (D3D12_TEXTURE_ADDRESS_MODE)sampler_desc.z; - d3d_desc.MipLODBias = sampler_desc.mip_lod_bias; - d3d_desc.MaxAnisotropy = MaxU32(sampler_desc.max_anisotropy, 1); - d3d_desc.ComparisonFunc = (D3D12_COMPARISON_FUNC)sampler_desc.comparison; - d3d_desc.BorderColor[0] = sampler_desc.border_color.x; - d3d_desc.BorderColor[1] = sampler_desc.border_color.y; - d3d_desc.BorderColor[2] = sampler_desc.border_color.z; - d3d_desc.BorderColor[3] = sampler_desc.border_color.w; - d3d_desc.MinLOD = sampler_desc.min_lod; - d3d_desc.MaxLOD = sampler_desc.max_lod; - } - if (d3d_desc.AddressU == 0) d3d_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - if (d3d_desc.AddressV == 0) d3d_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - if (d3d_desc.AddressW == 0) d3d_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - if (d3d_desc.MaxLOD >= F32Infinity) - { - d3d_desc.MaxLOD = D3D12_FLOAT32_MAX; - } - ID3D12Device_CreateSampler(g->device, &d3d_desc, descriptor->handle); + ID3D12Device_CreateShaderResourceView(g->device, resource->d3d_resource, 0, descriptor->handle); } + } + else if (is_sampler) + { + descriptor = G_D12_PushDescriptor(gpu_arena, G_D12_DescriptorHeapKind_Sampler); + G_SamplerDesc sampler_desc = resource->sampler_desc; + D3D12_SAMPLER_DESC d3d_desc = Zi; + { + d3d_desc.Filter = (D3D12_FILTER)sampler_desc.filter; + d3d_desc.AddressU = (D3D12_TEXTURE_ADDRESS_MODE)sampler_desc.x; + d3d_desc.AddressV = (D3D12_TEXTURE_ADDRESS_MODE)sampler_desc.y; + d3d_desc.AddressW = (D3D12_TEXTURE_ADDRESS_MODE)sampler_desc.z; + d3d_desc.MipLODBias = sampler_desc.mip_lod_bias; + d3d_desc.MaxAnisotropy = MaxU32(sampler_desc.max_anisotropy, 1); + d3d_desc.ComparisonFunc = (D3D12_COMPARISON_FUNC)sampler_desc.comparison; + d3d_desc.BorderColor[0] = sampler_desc.border_color.x; + d3d_desc.BorderColor[1] = sampler_desc.border_color.y; + d3d_desc.BorderColor[2] = sampler_desc.border_color.z; + d3d_desc.BorderColor[3] = sampler_desc.border_color.w; + d3d_desc.MinLOD = sampler_desc.min_lod; + d3d_desc.MaxLOD = sampler_desc.max_lod; + } + if (d3d_desc.AddressU == 0) d3d_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + if (d3d_desc.AddressV == 0) d3d_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + if (d3d_desc.AddressW == 0) d3d_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + if (d3d_desc.MaxLOD >= F32Infinity) + { + d3d_desc.MaxLOD = D3D12_FLOAT32_MAX; + } + ID3D12Device_CreateSampler(g->device, &d3d_desc, descriptor->handle); + } - return descriptor->index; + return descriptor->index; } //- Count u64 G_CountBufferBytes(G_ResourceHandle buffer) { - G_D12_Resource *resource = G_D12_ResourceFromHandle(buffer); - return resource->buffer_size; + G_D12_Resource *resource = G_D12_ResourceFromHandle(buffer); + return resource->buffer_size; } i32 G_Count1D(G_ResourceHandle texture) { - G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); - return resource->texture_dims.x; + G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); + return resource->texture_dims.x; } Vec2I32 G_Count2D(G_ResourceHandle texture) { - G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); - return VEC2I32(resource->texture_dims.x, resource->texture_dims.y); + G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); + return VEC2I32(resource->texture_dims.x, resource->texture_dims.y); } Vec3I32 G_Count3D(G_ResourceHandle texture) { - G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); - return resource->texture_dims; + G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); + return resource->texture_dims; } i32 G_CountWidth(G_ResourceHandle texture) { - G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); - return resource->texture_dims.x; + G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); + return resource->texture_dims.x; } i32 G_CountHeight(G_ResourceHandle texture) { - G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); - return resource->texture_dims.y; + G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); + return resource->texture_dims.y; } i32 G_CountDepth(G_ResourceHandle texture) { - G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); - return resource->texture_dims.z; + G_D12_Resource *resource = G_D12_ResourceFromHandle(texture); + return resource->texture_dims.z; } //- Map void *G_HostPointerFromResource(G_ResourceHandle resource_handle) { - G_D12_Resource *resource = G_D12_ResourceFromHandle(resource_handle); - G_D12_ResourceHeap *heap = resource->heap; - return ((u8 *)heap->mapped) + resource->pos_in_heap; + G_D12_Resource *resource = G_D12_ResourceFromHandle(resource_handle); + G_D12_ResourceHeap *heap = resource->heap; + return ((u8 *)heap->mapped) + resource->pos_in_heap; } //////////////////////////////////////////////////////////// @@ -1433,258 +1430,258 @@ void *G_HostPointerFromResource(G_ResourceHandle resource_handle) G_D12_Cmd *G_D12_PushCmd(G_D12_CmdList *cl) { - G_D12_SharedState *g = &G_D12_shared_state; + G_D12_SharedState *g = &G_D12_shared_state; - /* Grab chunk */ - G_D12_CmdChunk *chunk = cl->last_cmd_chunk; + /* Grab chunk */ + G_D12_CmdChunk *chunk = cl->last_cmd_chunk; + { + if (chunk && chunk->cmds_count >= G_D12_CmdsPerChunk) { - if (chunk && chunk->cmds_count >= G_D12_CmdsPerChunk) - { - chunk = 0; - } - if (!chunk) - { - Lock lock = LockE(&g->free_cmd_chunks_mutex); - { - chunk = g->first_free_cmd_chunk; - if (chunk) - { - g->first_free_cmd_chunk = chunk->next; - } - } - Unlock(&lock); - if (chunk) - { - G_D12_Cmd *cmds = chunk->cmds; - ZeroStruct(chunk); - chunk->cmds = cmds; - } - } - if (!chunk) - { - Arena *perm = PermArena(); - chunk = PushStruct(perm, G_D12_CmdChunk); - chunk->cmds = PushStructsNoZero(perm, G_D12_Cmd, G_D12_CmdsPerChunk); - } - if (chunk != cl->last_cmd_chunk) - { - SllQueuePush(cl->first_cmd_chunk, cl->last_cmd_chunk, chunk); - } + chunk = 0; } + if (!chunk) + { + Lock lock = LockE(&g->free_cmd_chunks_mutex); + { + chunk = g->first_free_cmd_chunk; + if (chunk) + { + g->first_free_cmd_chunk = chunk->next; + } + } + Unlock(&lock); + if (chunk) + { + G_D12_Cmd *cmds = chunk->cmds; + ZeroStruct(chunk); + chunk->cmds = cmds; + } + } + if (!chunk) + { + Arena *perm = PermArena(); + chunk = PushStruct(perm, G_D12_CmdChunk); + chunk->cmds = PushStructsNoZero(perm, G_D12_Cmd, G_D12_CmdsPerChunk); + } + if (chunk != cl->last_cmd_chunk) + { + SllQueuePush(cl->first_cmd_chunk, cl->last_cmd_chunk, chunk); + } + } - /* Push cmd to chunk */ - G_D12_Cmd *cmd = &chunk->cmds[chunk->cmds_count++]; - ZeroStruct(cmd); - ++cl->cmds_count; - return cmd; + /* Push cmd to chunk */ + G_D12_Cmd *cmd = &chunk->cmds[chunk->cmds_count++]; + ZeroStruct(cmd); + ++cl->cmds_count; + return cmd; } G_D12_Cmd *G_D12_PushConstCmd(G_D12_CmdList *cl, i32 slot, void *v) { - G_D12_Cmd *cmd = G_D12_PushCmd(cl); - cmd->kind = G_D12_CmdKind_Constant; - cmd->constant.slot = slot; - CopyBytes(&cmd->constant.value, v, 4); - return cmd; + G_D12_Cmd *cmd = G_D12_PushCmd(cl); + cmd->kind = G_D12_CmdKind_Constant; + cmd->constant.slot = slot; + CopyBytes(&cmd->constant.value, v, 4); + return cmd; } G_D12_StagingRegionNode *G_D12_PushStagingRegion(G_D12_CmdList *cl, u64 size) { - size = AlignU64(size, MaxU64(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT, 512)); + size = AlignU64(size, MaxU64(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT, 512)); - G_D12_SharedState *g = &G_D12_shared_state; - G_QueueKind queue_kind = cl->queue_kind; - G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); - G_D12_StagingRegionNode *result = 0; + G_D12_SharedState *g = &G_D12_shared_state; + G_QueueKind queue_kind = cl->queue_kind; + G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); + G_D12_StagingRegionNode *result = 0; - Lock lock = LockE(&queue->staging_mutex); + Lock lock = LockE(&queue->staging_mutex); + { + G_D12_StagingRing *old_ring = 0; + G_D12_StagingRing *ring = queue->staging_ring; + i64 completion = ID3D12Fence_GetCompletedValue(queue->commit_fence); + + /* Find first completed region with matching size. + * For each region in ring: + * - If region size > size, split off a smaller region & use it + * + * - If region size < size, try to merge with next completed region + * + * - If no available completed region with eligible size, queue the + * current ring for deletion & create a new ring + * with larger size + */ + + + + + /* Find region with large enough size */ + G_D12_StagingRegionNode *match = 0; + if (ring && ring->size >= size) { - G_D12_StagingRing *old_ring = 0; - G_D12_StagingRing *ring = queue->staging_ring; - i64 completion = ID3D12Fence_GetCompletedValue(queue->commit_fence); - - /* Find first completed region with matching size. - * For each region in ring: - * - If region size > size, split off a smaller region & use it - * - * - If region size < size, try to merge with next completed region - * - * - If no available completed region with eligible size, queue the - * current ring for deletion & create a new ring - * with larger size - */ - - - - - /* Find region with large enough size */ - G_D12_StagingRegionNode *match = 0; - if (ring && ring->size >= size) + G_D12_StagingRegionNode *r = ring->head_region_node; + for (;;) + { + G_D12_StagingRegionNode *next = r->next; + b32 is_completed = completion >= Atomic64Fetch(&r->completion_target); + if (is_completed) { - G_D12_StagingRegionNode *r = ring->head_region_node; - for (;;) + u64 region_size = 0; + if (next->pos > r->pos) + { + region_size = next->pos - r->pos; + } + else + { + region_size = ring->size - r->pos; + } + + if (region_size < size) + { + b32 next_is_completed = completion >= Atomic64Fetch(&next->completion_target); + if (next_is_completed) { - G_D12_StagingRegionNode *next = r->next; - b32 is_completed = completion >= Atomic64Fetch(&r->completion_target); - if (is_completed) + if (next->pos > r->pos) + { + /* Merge with next region & retry */ + if (next == ring->head_region_node) { - u64 region_size = 0; - if (next->pos > r->pos) - { - region_size = next->pos - r->pos; - } - else - { - region_size = ring->size - r->pos; - } - - if (region_size < size) - { - b32 next_is_completed = completion >= Atomic64Fetch(&next->completion_target); - if (next_is_completed) - { - if (next->pos > r->pos) - { - /* Merge with next region & retry */ - if (next == ring->head_region_node) - { - ring->head_region_node = r; - } - r->next = next->next; - r->next->prev = r; - SllStackPush(ring->first_free_region_node, next); - } - else - { - /* Wrap to beginning */ - r = next; - if (r == ring->head_region_node) - { - /* No large-enough completed region found */ - break; - } - } - } - else - { - /* No large-enough completed region found */ - break; - } - } - else - { - /* Found matching region */ - match = r; - break; - } + ring->head_region_node = r; } - else + r->next = next->next; + r->next->prev = r; + SllStackPush(ring->first_free_region_node, next); + } + else + { + /* Wrap to beginning */ + r = next; + if (r == ring->head_region_node) { - /* Continue to next region */ - r = next; - if (r == ring->head_region_node) - { - /* No large-enough completed region found */ - break; - } + /* No large-enough completed region found */ + break; } - } - } - - /* Create new ring if no match found */ - if (!match) - { - /* Queue old ring for deletion */ - old_ring = ring; - ring = 0; - u64 new_ring_size = MaxU64(AlignU64ToNextPow2(size), Mebi(8)); - if (old_ring) - { - new_ring_size = MaxU64(new_ring_size, old_ring->size * 2); - } - - /* Create new ring */ - { - Arena *arena = AcquireArena(Gibi(1)); - ring = PushStruct(arena, G_D12_StagingRing); - ring->arena = arena; - ring->size = new_ring_size; - - G_ArenaHandle gpu_arena_handle = G_AcquireArena(); - ring->gpu_arena = G_D12_ArenaFromHandle(gpu_arena_handle); - - G_ResourceHandle resource_handle = G_PushBuffer( - gpu_arena_handle, G_D12_MakeHandle(G_CommandListHandle, cl), - u8, - new_ring_size, - .flags = G_ResourceFlag_HostMemory | G_ResourceFlag_Uncached - ); - ring->resource = G_D12_ResourceFromHandle(resource_handle); - ring->base = G_StructFromResource(resource_handle, u8); - } - - /* Create initial region */ - match = PushStruct(ring->arena, G_D12_StagingRegionNode); - match->ring = ring; - match->next = match; - match->prev = match; - - /* FIXME: Remove this */ - queue->staging_ring = ring; - } - - /* Split extra region space */ - { - G_D12_StagingRegionNode *next = match->next; - u64 region_size = 0; - if (next->pos > match->pos) - { - region_size = next->pos - match->pos; + } } else { - region_size = ring->size - match->pos; - } - - if (region_size > size) - { - G_D12_StagingRegionNode *new_next = ring->first_free_region_node; - if (new_next) - { - SllStackPop(ring->first_free_region_node); - ZeroStruct(new_next); - } - else - { - new_next = PushStruct(ring->arena, G_D12_StagingRegionNode); - } - new_next->next = next; - new_next->prev = match; - next->prev = new_next; - match->next = new_next; - - new_next->ring = ring; - new_next->pos = match->pos + size; + /* No large-enough completed region found */ + break; } + } + else + { + /* Found matching region */ + match = r; + break; + } } - - ring->head_region_node = match->next; - - Atomic64Set(&match->completion_target, I64Max); - result = match; - - if (old_ring) + else { - /* FIXME: Queue old ring for deletion with command list */ - DEBUGBREAKABLE; + /* Continue to next region */ + r = next; + if (r == ring->head_region_node) + { + /* No large-enough completed region found */ + break; + } } + } } - Unlock(&lock); - /* Add to command list */ - SllQueuePushN(cl->first_staging_region, cl->last_staging_region, result, next_in_command_list); + /* Create new ring if no match found */ + if (!match) + { + /* Queue old ring for deletion */ + old_ring = ring; + ring = 0; + u64 new_ring_size = MaxU64(AlignU64ToNextPow2(size), Mebi(8)); + if (old_ring) + { + new_ring_size = MaxU64(new_ring_size, old_ring->size * 2); + } - return result; + /* Create new ring */ + { + Arena *arena = AcquireArena(Gibi(1)); + ring = PushStruct(arena, G_D12_StagingRing); + ring->arena = arena; + ring->size = new_ring_size; + + G_ArenaHandle gpu_arena_handle = G_AcquireArena(); + ring->gpu_arena = G_D12_ArenaFromHandle(gpu_arena_handle); + + G_ResourceHandle resource_handle = G_PushBuffer( + gpu_arena_handle, G_D12_MakeHandle(G_CommandListHandle, cl), + u8, + new_ring_size, + .flags = G_ResourceFlag_HostMemory | G_ResourceFlag_Uncached + ); + ring->resource = G_D12_ResourceFromHandle(resource_handle); + ring->base = G_StructFromResource(resource_handle, u8); + } + + /* Create initial region */ + match = PushStruct(ring->arena, G_D12_StagingRegionNode); + match->ring = ring; + match->next = match; + match->prev = match; + + /* FIXME: Remove this */ + queue->staging_ring = ring; + } + + /* Split extra region space */ + { + G_D12_StagingRegionNode *next = match->next; + u64 region_size = 0; + if (next->pos > match->pos) + { + region_size = next->pos - match->pos; + } + else + { + region_size = ring->size - match->pos; + } + + if (region_size > size) + { + G_D12_StagingRegionNode *new_next = ring->first_free_region_node; + if (new_next) + { + SllStackPop(ring->first_free_region_node); + ZeroStruct(new_next); + } + else + { + new_next = PushStruct(ring->arena, G_D12_StagingRegionNode); + } + new_next->next = next; + new_next->prev = match; + next->prev = new_next; + match->next = new_next; + + new_next->ring = ring; + new_next->pos = match->pos + size; + } + } + + ring->head_region_node = match->next; + + Atomic64Set(&match->completion_target, I64Max); + result = match; + + if (old_ring) + { + /* FIXME: Queue old ring for deletion with command list */ + DEBUGBREAKABLE; + } + } + Unlock(&lock); + + /* Add to command list */ + SllQueuePushN(cl->first_staging_region, cl->last_staging_region, result, next_in_command_list); + + return result; } //////////////////////////////////////////////////////////// @@ -1694,998 +1691,998 @@ G_D12_StagingRegionNode *G_D12_PushStagingRegion(G_D12_CmdList *cl, u64 size) G_CommandListHandle G_PrepareCommandList(G_QueueKind queue) { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_CmdList *cl = 0; - Lock lock = LockE(&g->free_cmd_lists_mutex); + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_CmdList *cl = 0; + Lock lock = LockE(&g->free_cmd_lists_mutex); + { + cl = g->first_free_cmd_list; + if (cl) { - cl = g->first_free_cmd_list; - if (cl) - { - g->first_free_cmd_list = cl->next; - ZeroStruct(cl); - } - else - { - Arena *perm = PermArena(); - cl = PushStruct(perm, G_D12_CmdList); - } + g->first_free_cmd_list = cl->next; + ZeroStruct(cl); } - Unlock(&lock); - cl->queue_kind = queue; + else + { + Arena *perm = PermArena(); + cl = PushStruct(perm, G_D12_CmdList); + } + } + Unlock(&lock); + cl->queue_kind = queue; - return G_D12_MakeHandle(G_CommandListHandle, cl); + return G_D12_MakeHandle(G_CommandListHandle, cl); } i64 G_CommitCommandList(G_CommandListHandle cl_handle) { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_QueueKind queue_kind = cl->queue_kind; - G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); - TempArena scratch = BeginScratchNoConflict(); + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_QueueKind queue_kind = cl->queue_kind; + G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); + TempArena scratch = BeginScratchNoConflict(); - /* Begin dx12 command list */ - G_D12_RawCommandList *rcl = G_D12_PrepareRawCommandList(queue_kind); - ID3D12GraphicsCommandList7 *d3d_cl = rcl->d3d_cl; + /* Begin dx12 command list */ + G_D12_RawCommandList *rcl = G_D12_PrepareRawCommandList(queue_kind); + ID3D12GraphicsCommandList7 *d3d_cl = rcl->d3d_cl; - /* Pipeline state */ - b32 graphics_rootsig_set = 0; - b32 compute_rootsig_set = 0; - b32 descriptor_heaps_set = 0; - G_D12_Pipeline *bound_pipeline = 0; + /* Pipeline state */ + b32 graphics_rootsig_set = 0; + b32 compute_rootsig_set = 0; + b32 descriptor_heaps_set = 0; + G_D12_Pipeline *bound_pipeline = 0; - /* Constants state */ - u64 slotted_constants[G_NumConstants]; - u64 bound_compute_constants[G_NumConstants]; - u64 bound_graphics_constants[G_NumConstants]; - for (i32 i = 0; i < countof(slotted_constants); ++i) { slotted_constants[i] = 0; } /* Zero-initialize all slots */ - for (i32 i = 0; i < countof(bound_compute_constants); ++i) { bound_compute_constants[i] = U64Max; } - for (i32 i = 0; i < countof(bound_graphics_constants); ++i) { bound_graphics_constants[i] = U64Max; } + /* Constants state */ + u64 slotted_constants[G_NumConstants]; + u64 bound_compute_constants[G_NumConstants]; + u64 bound_graphics_constants[G_NumConstants]; + for (i32 i = 0; i < countof(slotted_constants); ++i) { slotted_constants[i] = 0; } /* Zero-initialize all slots */ + for (i32 i = 0; i < countof(bound_compute_constants); ++i) { bound_compute_constants[i] = U64Max; } + for (i32 i = 0; i < countof(bound_graphics_constants); ++i) { bound_graphics_constants[i] = U64Max; } - if (!G_IsRefNil(queue->print_buffer_ref)) - { - slotted_constants[G_ShaderConst_PrintBufferRef] = queue->print_buffer_ref.v; - } + if (!G_IsRefNil(queue->print_buffer_ref)) + { + slotted_constants[G_ShaderConst_PrintBufferRef] = queue->print_buffer_ref.v; + } - /* Rasterizer state */ - D3D12_VIEWPORT bound_viewport = Zi; - D3D12_RECT bound_scissor = Zi; - D3D_PRIMITIVE_TOPOLOGY bound_primitive_topology = -1; - D3D12_INDEX_BUFFER_VIEW bound_ibv = Zi; - u64 bound_render_target_uids[G_MaxRenderTargets] = Zi; - u64 bound_render_clear_target_uid = 0; + /* Rasterizer state */ + D3D12_VIEWPORT bound_viewport = Zi; + D3D12_RECT bound_scissor = Zi; + D3D_PRIMITIVE_TOPOLOGY bound_primitive_topology = -1; + D3D12_INDEX_BUFFER_VIEW bound_ibv = Zi; + u64 bound_render_target_uids[G_MaxRenderTargets] = Zi; + u64 bound_render_clear_target_uid = 0; + /* Flatten command chunks */ + u64 cmds_count = 0; + G_D12_Cmd *cmds = PushStructsNoZero(scratch.arena, G_D12_Cmd, cl->cmds_count); + { /* Flatten command chunks */ - u64 cmds_count = 0; - G_D12_Cmd *cmds = PushStructsNoZero(scratch.arena, G_D12_Cmd, cl->cmds_count); { - /* Flatten command chunks */ + for (G_D12_CmdChunk *chunk = cl->first_cmd_chunk; chunk; chunk = chunk->next) + { + for (u64 cmd_chunk_idx = 0; cmd_chunk_idx < chunk->cmds_count; ++cmd_chunk_idx) { - for (G_D12_CmdChunk *chunk = cl->first_cmd_chunk; chunk; chunk = chunk->next) + cmds[cmds_count++] = chunk->cmds[cmd_chunk_idx]; + } + } + } + /* Free command chunks */ + { + Lock lock = LockE(&g->free_cmd_chunks_mutex); + { + G_D12_CmdChunk *chunk = cl->first_cmd_chunk; + while (chunk) + { + G_D12_CmdChunk *next = chunk->next; + g->first_free_cmd_chunk = chunk; + chunk = next; + } + } + Unlock(&lock); + } + } + + /* Batch barrier cmds */ + { + u64 cmd_idx = 0; + u64 batch_gen = 0; + G_D12_Cmd *prev_barrier_cmd = 0; + while (cmd_idx < cmds_count) + { + G_D12_Cmd *cmd = &cmds[cmd_idx]; + switch (cmd->kind) + { + /* Batch-interrupting cmds */ + default: + { + cmd_idx += 1; + batch_gen += 1; + } break; + + /* Non-batch-interrupting cmds */ + case G_D12_CmdKind_Constant: + { + cmd_idx += 1; + } break; + + case G_D12_CmdKind_Barrier: + { + /* Determine 'before' state from lookup */ + if (prev_barrier_cmd) + { + if (prev_barrier_cmd->barrier.batch_gen != batch_gen) { - for (u64 cmd_chunk_idx = 0; cmd_chunk_idx < chunk->cmds_count; ++cmd_chunk_idx) + /* This barrier is part of new batch */ + prev_barrier_cmd->barrier.is_end_of_batch = 1; + } + } + cmd->barrier.batch_gen = batch_gen; + prev_barrier_cmd = cmd; + cmd_idx += 1; + } break; + } + } + + if (prev_barrier_cmd) + { + prev_barrier_cmd->barrier.is_end_of_batch = 1; + } + } + + /* Process gpu commands into dx12 commands */ + { + u64 batch_barrier_idx_start = 0; + u64 batch_barrier_idx_opl = 0; /* One past last */ + + u64 cmd_idx = 0; + while (cmd_idx < cmds_count) + { + G_D12_Cmd *cmd = &cmds[cmd_idx]; + switch (cmd->kind) + { + default: + { + cmd_idx += 1; + } break; + + //- Constant + + case G_D12_CmdKind_Constant: + { + i32 slot = cmd->constant.slot; + u32 value = cmd->constant.value; + if (slot >= 0 && slot < countof(slotted_constants)) + { + slotted_constants[slot] = value; + } + cmd_idx += 1; + } break; + + //- Barrier + + case G_D12_CmdKind_Barrier: + { + batch_barrier_idx_opl = cmd_idx + 1; + + /* Submit batched barriers */ + if (cmd->barrier.is_end_of_batch) + { + /* Build barriers */ + u64 buffer_barriers_count = 0; + u64 texture_barriers_count = 0; + u64 global_barriers_count = 0; + D3D12_BUFFER_BARRIER *buffer_barriers = PushStructs(scratch.arena, D3D12_BUFFER_BARRIER, (batch_barrier_idx_opl - batch_barrier_idx_start)); + D3D12_TEXTURE_BARRIER *texture_barriers = PushStructs(scratch.arena, D3D12_TEXTURE_BARRIER, (batch_barrier_idx_opl - batch_barrier_idx_start)); + D3D12_GLOBAL_BARRIER *global_barriers = PushStructs(scratch.arena, D3D12_GLOBAL_BARRIER, (batch_barrier_idx_opl - batch_barrier_idx_start)); + for (u64 barrier_cmd_idx = batch_barrier_idx_start; barrier_cmd_idx < batch_barrier_idx_opl; ++barrier_cmd_idx) + { + G_D12_Cmd *barrier_cmd = &cmds[barrier_cmd_idx]; + if (barrier_cmd->kind == G_D12_CmdKind_Barrier) + { + G_MemoryBarrierDesc desc = barrier_cmd->barrier.desc; + /* Translate gpu barrier kind -> d3d barrier fields */ + D3D12_BARRIER_SYNC sync_before = G_D12_BarrierSyncFromStages(desc.stage_prev); + D3D12_BARRIER_SYNC sync_after = G_D12_BarrierSyncFromStages(desc.stage_next); + D3D12_BARRIER_ACCESS access_before = G_D12_BarrierAccessFromAccesses(desc.access_prev); + D3D12_BARRIER_ACCESS access_after = G_D12_BarrierAccessFromAccesses(desc.access_next); + D3D12_BARRIER_LAYOUT layout_before = D3D12_BARRIER_LAYOUT_UNDEFINED; + D3D12_BARRIER_LAYOUT layout_after = D3D12_BARRIER_LAYOUT_UNDEFINED; + D3D12_BARRIER_TYPE barrier_type = D3D12_BARRIER_TYPE_GLOBAL; + if (!desc.is_global) { - cmds[cmds_count++] = chunk->cmds[cmd_chunk_idx]; + G_D12_Resource *resource = G_D12_ResourceFromHandle(desc.resource); + barrier_type = resource->is_texture ? D3D12_BARRIER_TYPE_TEXTURE : D3D12_BARRIER_TYPE_BUFFER; + layout_before = resource->texture_layout; + layout_after = resource->texture_layout; + if (desc.layout != G_Layout_NoChange) + { + layout_after = G_D12_BarrierLayoutFromLayout(desc.layout); + resource->texture_layout = layout_after; + } } - } - } - /* Free command chunks */ - { - Lock lock = LockE(&g->free_cmd_chunks_mutex); - { - G_D12_CmdChunk *chunk = cl->first_cmd_chunk; - while (chunk) + + /* Build barrier */ + switch (barrier_type) { - G_D12_CmdChunk *next = chunk->next; - g->first_free_cmd_chunk = chunk; - chunk = next; + case D3D12_BARRIER_TYPE_BUFFER: + { + G_D12_Resource *resource = G_D12_ResourceFromHandle(desc.resource); + D3D12_BUFFER_BARRIER *barrier = &buffer_barriers[buffer_barriers_count++]; + barrier->SyncBefore = sync_before; + barrier->SyncAfter = sync_after; + barrier->AccessBefore = access_before; + barrier->AccessAfter = access_after; + barrier->pResource = resource->d3d_resource; + barrier->Offset = 0; + barrier->Size = U64Max; + } break; + + case D3D12_BARRIER_TYPE_TEXTURE: + { + G_D12_Resource *resource = G_D12_ResourceFromHandle(desc.resource); + D3D12_TEXTURE_BARRIER *barrier = &texture_barriers[texture_barriers_count++]; + barrier->SyncBefore = sync_before; + barrier->SyncAfter = sync_after; + barrier->AccessBefore = access_before; + barrier->AccessAfter = access_after; + barrier->LayoutBefore = layout_before; + barrier->LayoutAfter = layout_after; + barrier->pResource = resource->d3d_resource; + barrier->Subresources.IndexOrFirstMipLevel = 0xffffffff; + } break; + + case D3D12_BARRIER_TYPE_GLOBAL: + { + D3D12_GLOBAL_BARRIER *barrier = &global_barriers[global_barriers_count++]; + barrier->SyncBefore = sync_before; + barrier->SyncAfter = sync_after; + barrier->AccessBefore = access_before; + barrier->AccessAfter = access_after; + } break; } + } } - Unlock(&lock); - } - } - /* Batch barrier cmds */ - { - u64 cmd_idx = 0; - u64 batch_gen = 0; - G_D12_Cmd *prev_barrier_cmd = 0; - while (cmd_idx < cmds_count) - { - G_D12_Cmd *cmd = &cmds[cmd_idx]; - switch (cmd->kind) + /* Dispatch barriers */ { - /* Batch-interrupting cmds */ - default: - { - cmd_idx += 1; - batch_gen += 1; - } break; - - /* Non-batch-interrupting cmds */ - case G_D12_CmdKind_Constant: - { - cmd_idx += 1; - } break; - - case G_D12_CmdKind_Barrier: - { - /* Determine 'before' state from lookup */ - if (prev_barrier_cmd) - { - if (prev_barrier_cmd->barrier.batch_gen != batch_gen) - { - /* This barrier is part of new batch */ - prev_barrier_cmd->barrier.is_end_of_batch = 1; - } - } - cmd->barrier.batch_gen = batch_gen; - prev_barrier_cmd = cmd; - cmd_idx += 1; - } break; + u32 barrier_groups_count = 0; + D3D12_BARRIER_GROUP barrier_groups[3] = Zi; + if (buffer_barriers_count > 0) + { + D3D12_BARRIER_GROUP *group = &barrier_groups[barrier_groups_count++]; + group->Type = D3D12_BARRIER_TYPE_BUFFER; + group->NumBarriers = buffer_barriers_count; + group->pBufferBarriers = buffer_barriers; + } + if (texture_barriers_count > 0) + { + D3D12_BARRIER_GROUP *group = &barrier_groups[barrier_groups_count++]; + group->Type = D3D12_BARRIER_TYPE_TEXTURE; + group->NumBarriers = texture_barriers_count; + group->pTextureBarriers = texture_barriers; + } + if (global_barriers_count > 0) + { + D3D12_BARRIER_GROUP *group = &barrier_groups[barrier_groups_count++]; + group->Type = D3D12_BARRIER_TYPE_GLOBAL; + group->NumBarriers = global_barriers_count; + group->pGlobalBarriers = global_barriers; + } + if (barrier_groups_count > 0) + { + ID3D12GraphicsCommandList7_Barrier(d3d_cl, barrier_groups_count, barrier_groups); + } } - } - if (prev_barrier_cmd) + batch_barrier_idx_start = cmd_idx + 1; + } + + cmd_idx += 1; + } break; + + //- Copy bytes + + case G_D12_CmdKind_CopyBytes: { - prev_barrier_cmd->barrier.is_end_of_batch = 1; - } - } + u64 src_offset = cmd->copy_bytes.src_range.min; + u64 copy_size = cmd->copy_bytes.src_range.max - cmd->copy_bytes.src_range.min; + ID3D12GraphicsCommandList_CopyBufferRegion( + d3d_cl, + cmd->copy_bytes.dst->d3d_resource, + cmd->copy_bytes.dst_offset, + cmd->copy_bytes.src->d3d_resource, + src_offset, + copy_size + ); + cmd_idx += 1; + } break; - /* Process gpu commands into dx12 commands */ - { - u64 batch_barrier_idx_start = 0; - u64 batch_barrier_idx_opl = 0; /* One past last */ + //- Copy texels - u64 cmd_idx = 0; - while (cmd_idx < cmds_count) + case G_D12_CmdKind_CopyTexels: { - G_D12_Cmd *cmd = &cmds[cmd_idx]; - switch (cmd->kind) + G_D12_Resource *dst = cmd->copy_texels.dst; + G_D12_Resource *src = cmd->copy_texels.src; + D3D12_TEXTURE_COPY_LOCATION dst_loc = cmd->copy_texels.dst_loc; + D3D12_TEXTURE_COPY_LOCATION src_loc = cmd->copy_texels.src_loc; + Vec3I32 dst_offset = cmd->copy_texels.dst_texture_offset; + Rng3I32 src_range = cmd->copy_texels.src_texture_range; + + D3D12_BOX src_box = Zi; + D3D12_BOX *src_box_ptr = 0; + { + src_box.left = src_range.p0.x; + src_box.top = src_range.p0.y; + src_box.front = src_range.p0.z; + src_box.right = src_range.p1.x; + src_box.bottom = src_range.p1.y; + src_box.back = src_range.p1.z; + if (src->is_texture) { - default: - { - cmd_idx += 1; - } break; - - //- Constant - - case G_D12_CmdKind_Constant: - { - i32 slot = cmd->constant.slot; - u32 value = cmd->constant.value; - if (slot >= 0 && slot < countof(slotted_constants)) - { - slotted_constants[slot] = value; - } - cmd_idx += 1; - } break; - - //- Barrier - - case G_D12_CmdKind_Barrier: - { - batch_barrier_idx_opl = cmd_idx + 1; - - /* Submit batched barriers */ - if (cmd->barrier.is_end_of_batch) - { - /* Build barriers */ - u64 buffer_barriers_count = 0; - u64 texture_barriers_count = 0; - u64 global_barriers_count = 0; - D3D12_BUFFER_BARRIER *buffer_barriers = PushStructs(scratch.arena, D3D12_BUFFER_BARRIER, (batch_barrier_idx_opl - batch_barrier_idx_start)); - D3D12_TEXTURE_BARRIER *texture_barriers = PushStructs(scratch.arena, D3D12_TEXTURE_BARRIER, (batch_barrier_idx_opl - batch_barrier_idx_start)); - D3D12_GLOBAL_BARRIER *global_barriers = PushStructs(scratch.arena, D3D12_GLOBAL_BARRIER, (batch_barrier_idx_opl - batch_barrier_idx_start)); - for (u64 barrier_cmd_idx = batch_barrier_idx_start; barrier_cmd_idx < batch_barrier_idx_opl; ++barrier_cmd_idx) - { - G_D12_Cmd *barrier_cmd = &cmds[barrier_cmd_idx]; - if (barrier_cmd->kind == G_D12_CmdKind_Barrier) - { - G_MemoryBarrierDesc desc = barrier_cmd->barrier.desc; - /* Translate gpu barrier kind -> d3d barrier fields */ - D3D12_BARRIER_SYNC sync_before = G_D12_BarrierSyncFromStages(desc.stage_prev); - D3D12_BARRIER_SYNC sync_after = G_D12_BarrierSyncFromStages(desc.stage_next); - D3D12_BARRIER_ACCESS access_before = G_D12_BarrierAccessFromAccesses(desc.access_prev); - D3D12_BARRIER_ACCESS access_after = G_D12_BarrierAccessFromAccesses(desc.access_next); - D3D12_BARRIER_LAYOUT layout_before = D3D12_BARRIER_LAYOUT_UNDEFINED; - D3D12_BARRIER_LAYOUT layout_after = D3D12_BARRIER_LAYOUT_UNDEFINED; - D3D12_BARRIER_TYPE barrier_type = D3D12_BARRIER_TYPE_GLOBAL; - if (!desc.is_global) - { - G_D12_Resource *resource = G_D12_ResourceFromHandle(desc.resource); - barrier_type = resource->is_texture ? D3D12_BARRIER_TYPE_TEXTURE : D3D12_BARRIER_TYPE_BUFFER; - layout_before = resource->texture_layout; - layout_after = resource->texture_layout; - if (desc.layout != G_Layout_NoChange) - { - layout_after = G_D12_BarrierLayoutFromLayout(desc.layout); - resource->texture_layout = layout_after; - } - } - - /* Build barrier */ - switch (barrier_type) - { - case D3D12_BARRIER_TYPE_BUFFER: - { - G_D12_Resource *resource = G_D12_ResourceFromHandle(desc.resource); - D3D12_BUFFER_BARRIER *barrier = &buffer_barriers[buffer_barriers_count++]; - barrier->SyncBefore = sync_before; - barrier->SyncAfter = sync_after; - barrier->AccessBefore = access_before; - barrier->AccessAfter = access_after; - barrier->pResource = resource->d3d_resource; - barrier->Offset = 0; - barrier->Size = U64Max; - } break; - - case D3D12_BARRIER_TYPE_TEXTURE: - { - G_D12_Resource *resource = G_D12_ResourceFromHandle(desc.resource); - D3D12_TEXTURE_BARRIER *barrier = &texture_barriers[texture_barriers_count++]; - barrier->SyncBefore = sync_before; - barrier->SyncAfter = sync_after; - barrier->AccessBefore = access_before; - barrier->AccessAfter = access_after; - barrier->LayoutBefore = layout_before; - barrier->LayoutAfter = layout_after; - barrier->pResource = resource->d3d_resource; - barrier->Subresources.IndexOrFirstMipLevel = 0xffffffff; - } break; - - case D3D12_BARRIER_TYPE_GLOBAL: - { - D3D12_GLOBAL_BARRIER *barrier = &global_barriers[global_barriers_count++]; - barrier->SyncBefore = sync_before; - barrier->SyncAfter = sync_after; - barrier->AccessBefore = access_before; - barrier->AccessAfter = access_after; - } break; - } - } - } - - /* Dispatch barriers */ - { - u32 barrier_groups_count = 0; - D3D12_BARRIER_GROUP barrier_groups[3] = Zi; - if (buffer_barriers_count > 0) - { - D3D12_BARRIER_GROUP *group = &barrier_groups[barrier_groups_count++]; - group->Type = D3D12_BARRIER_TYPE_BUFFER; - group->NumBarriers = buffer_barriers_count; - group->pBufferBarriers = buffer_barriers; - } - if (texture_barriers_count > 0) - { - D3D12_BARRIER_GROUP *group = &barrier_groups[barrier_groups_count++]; - group->Type = D3D12_BARRIER_TYPE_TEXTURE; - group->NumBarriers = texture_barriers_count; - group->pTextureBarriers = texture_barriers; - } - if (global_barriers_count > 0) - { - D3D12_BARRIER_GROUP *group = &barrier_groups[barrier_groups_count++]; - group->Type = D3D12_BARRIER_TYPE_GLOBAL; - group->NumBarriers = global_barriers_count; - group->pGlobalBarriers = global_barriers; - } - if (barrier_groups_count > 0) - { - ID3D12GraphicsCommandList7_Barrier(d3d_cl, barrier_groups_count, barrier_groups); - } - } - - batch_barrier_idx_start = cmd_idx + 1; - } - - cmd_idx += 1; - } break; - - //- Copy bytes - - case G_D12_CmdKind_CopyBytes: - { - u64 src_offset = cmd->copy_bytes.src_range.min; - u64 copy_size = cmd->copy_bytes.src_range.max - cmd->copy_bytes.src_range.min; - ID3D12GraphicsCommandList_CopyBufferRegion( - d3d_cl, - cmd->copy_bytes.dst->d3d_resource, - cmd->copy_bytes.dst_offset, - cmd->copy_bytes.src->d3d_resource, - src_offset, - copy_size - ); - cmd_idx += 1; - } break; - - //- Copy texels - - case G_D12_CmdKind_CopyTexels: - { - G_D12_Resource *dst = cmd->copy_texels.dst; - G_D12_Resource *src = cmd->copy_texels.src; - D3D12_TEXTURE_COPY_LOCATION dst_loc = cmd->copy_texels.dst_loc; - D3D12_TEXTURE_COPY_LOCATION src_loc = cmd->copy_texels.src_loc; - Vec3I32 dst_offset = cmd->copy_texels.dst_texture_offset; - Rng3I32 src_range = cmd->copy_texels.src_texture_range; - - D3D12_BOX src_box = Zi; - D3D12_BOX *src_box_ptr = 0; - { - src_box.left = src_range.p0.x; - src_box.top = src_range.p0.y; - src_box.front = src_range.p0.z; - src_box.right = src_range.p1.x; - src_box.bottom = src_range.p1.y; - src_box.back = src_range.p1.z; - if (src->is_texture) - { - src_box_ptr = &src_box; - } - } - - if (dst->flags & G_ResourceFlag_AllowDepthStencil) - { - /* Depth-stencil textures must have src box & dst offset set to 0 - * https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12graphicscommandlist-copytextureregion - */ - ID3D12GraphicsCommandList_CopyTextureRegion(d3d_cl, &dst_loc, 0, 0, 0, &src_loc, 0); - } - else - { - ID3D12GraphicsCommandList_CopyTextureRegion(d3d_cl, &dst_loc, dst_offset.x, dst_offset.y, dst_offset.z, &src_loc, src_box_ptr); - } - - cmd_idx += 1; - } break; - - //- Compute - - case G_D12_CmdKind_Compute: - { - G_D12_Pipeline *pipeline = 0; - { - G_D12_PipelineDesc pipeline_desc = Zi; - pipeline_desc.cs = cmd->compute.cs; - pipeline = G_D12_PipelineFromDesc(pipeline_desc); - } - - if (pipeline) - { - /* Set descriptor heaps */ - if (!descriptor_heaps_set) - { - ID3D12DescriptorHeap *heaps[] = { - g->descriptor_heaps[G_D12_DescriptorHeapKind_CbvSrvUav].d3d_heap, - g->descriptor_heaps[G_D12_DescriptorHeapKind_Sampler].d3d_heap, - }; - ID3D12GraphicsCommandList_SetDescriptorHeaps(d3d_cl, countof(heaps), heaps); - descriptor_heaps_set = 1; - } - - /* Bind rootsig */ - if (!compute_rootsig_set) - { - ID3D12GraphicsCommandList_SetComputeRootSignature(d3d_cl, g->bindless_rootsig); - compute_rootsig_set = 1; - } - - /* Bind pipeline */ - if (pipeline != bound_pipeline) - { - ID3D12GraphicsCommandList_SetPipelineState(d3d_cl, pipeline->pso); - bound_pipeline = pipeline; - } - - /* Update root constants */ - for (i32 slot = 0; slot < countof(slotted_constants); ++slot) - { - if (bound_compute_constants[slot] != slotted_constants[slot]) - { - ID3D12GraphicsCommandList_SetComputeRoot32BitConstant(d3d_cl, slot, slotted_constants[slot], 0); - bound_compute_constants[slot] = slotted_constants[slot]; - } - } - - /* Dispatch */ - ID3D12GraphicsCommandList_Dispatch(d3d_cl, cmd->compute.groups.x, cmd->compute.groups.y, cmd->compute.groups.z); - } - - cmd_idx += 1; - } break; - - //- Rasterize - - case G_D12_CmdKind_Rasterize: - { - G_D12_Pipeline *pipeline = 0; - { - G_D12_PipelineDesc pipeline_desc = Zi; - pipeline_desc.vs = cmd->rasterize.vs; - pipeline_desc.ps = cmd->rasterize.ps; - { - pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED; - switch (cmd->rasterize.mode) - { - default: Assert(0); break; - case G_RasterMode_PointList: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; break; - case G_RasterMode_LineList: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; break; - case G_RasterMode_LineStrip: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; break; - case G_RasterMode_TriangleList: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; - case G_RasterMode_TriangleStrip: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; - case G_RasterMode_WireTriangleList: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; - case G_RasterMode_WireTriangleStrip: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; - } - } - if (cmd->rasterize.mode == G_RasterMode_WireTriangleList || cmd->rasterize.mode == G_RasterMode_WireTriangleStrip) - { - pipeline_desc.is_wireframe = 1; - } - for (u32 i = 0; i < countof(cmd->rasterize.render_targets); ++i) - { - G_D12_Resource *rt = cmd->rasterize.render_targets[i]; - if (rt) - { - pipeline_desc.render_target_formats[i] = rt->texture_format; - } - else - { - pipeline_desc.render_target_formats[i] = G_Format_Unknown; - } - } - pipeline = G_D12_PipelineFromDesc(pipeline_desc); - } - - /* Create ibv */ - u32 indices_count = 0; - D3D12_INDEX_BUFFER_VIEW ibv = Zi; - { - G_IndexBufferDesc desc = cmd->rasterize.index_buffer_desc; - if (desc.index_count > 0) - { - G_D12_Resource *index_buffer_resource = G_D12_ResourceFromHandle(desc.resource); - ibv.BufferLocation = index_buffer_resource->buffer_gpu_address; - ibv.SizeInBytes = desc.index_size * desc.index_count; - if (desc.index_size == 2) - { - ibv.Format = DXGI_FORMAT_R16_UINT; - indices_count = ibv.SizeInBytes / 2; - } - else if (desc.index_size == 4) - { - ibv.Format = DXGI_FORMAT_R32_UINT; - indices_count = ibv.SizeInBytes / 4; - } - else - { - Assert(0); /* Invalid index size */ - } - } - } - - /* Prepare & dispatch */ - if (pipeline && indices_count > 0) - { - /* Set descriptor heaps */ - if (!descriptor_heaps_set) - { - ID3D12DescriptorHeap *heaps[] = { - g->descriptor_heaps[G_D12_DescriptorHeapKind_CbvSrvUav].d3d_heap, - g->descriptor_heaps[G_D12_DescriptorHeapKind_Sampler].d3d_heap, - }; - ID3D12GraphicsCommandList_SetDescriptorHeaps(d3d_cl, countof(heaps), heaps); - descriptor_heaps_set = 1; - } - - /* Bind rootsig */ - if (!graphics_rootsig_set) - { - ID3D12GraphicsCommandList_SetGraphicsRootSignature(d3d_cl, g->bindless_rootsig); - graphics_rootsig_set = 1; - } - - /* Bind pipeline */ - if (pipeline != bound_pipeline) - { - ID3D12GraphicsCommandList_SetPipelineState(d3d_cl, pipeline->pso); - bound_pipeline = pipeline; - } - - /* Update root constants */ - for (i32 slot = 0; slot < countof(slotted_constants); ++slot) - { - if (bound_graphics_constants[slot] != slotted_constants[slot]) - { - ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstant(d3d_cl, slot, slotted_constants[slot], 0); - bound_graphics_constants[slot] = slotted_constants[slot]; - } - } - - /* Set viewport */ - { - D3D12_VIEWPORT viewport = Zi; - { - Rng3 range = cmd->rasterize.viewport; - viewport.TopLeftX = range.p0.x; - viewport.TopLeftY = range.p0.y; - viewport.Width = range.p1.x - range.p0.x; - viewport.Height = range.p1.y - range.p0.y; - viewport.MinDepth = range.p0.z; - viewport.MaxDepth = range.p1.z; - } - if (!MatchStruct(&viewport, &bound_viewport)) - { - bound_viewport = viewport; - ID3D12GraphicsCommandList_RSSetViewports(d3d_cl, 1, &viewport); - } - } - - /* Set scissor */ - { - D3D12_RECT scissor = Zi; - { - Rng2 range = cmd->rasterize.scissor; - scissor.left = range.p0.x; - scissor.top = range.p0.y; - scissor.right = range.p1.x; - scissor.bottom = range.p1.y; - } - if (!MatchStruct(&scissor, &bound_scissor)) - { - bound_scissor = scissor; - ID3D12GraphicsCommandList_RSSetScissorRects(d3d_cl, 1, &scissor); - } - } - - /* Set topology */ - { - D3D_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - switch (cmd->rasterize.mode) - { - default: Assert(0); break; - case G_RasterMode_PointList: topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; break; - case G_RasterMode_LineList: topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; break; - case G_RasterMode_LineStrip: topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; break; - case G_RasterMode_TriangleList: topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break; - case G_RasterMode_TriangleStrip: topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; break; - case G_RasterMode_WireTriangleList: topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break; - case G_RasterMode_WireTriangleStrip: topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; break; - } - if (topology != bound_primitive_topology) - { - ID3D12GraphicsCommandList_IASetPrimitiveTopology(d3d_cl, topology); - } - } - - /* Set index buffer */ - if (!MatchStruct(&ibv, &bound_ibv)) - { - ID3D12GraphicsCommandList_IASetIndexBuffer(d3d_cl, &ibv); - bound_ibv = ibv; - } - - /* Bind render targets */ - { - b32 om_dirty = 0; - u32 rtvs_count = 0; - for (u32 i = 0; i < countof(cmd->rasterize.render_targets); ++i) - { - G_D12_Resource *rt = cmd->rasterize.render_targets[i]; - if (rt) - { - if (bound_render_target_uids[i] != rt->uid) - { - G_D12_Descriptor *rtv_descriptor = rcl->rtv_descriptors[i]; - ID3D12Device_CreateRenderTargetView(g->device, rt->d3d_resource, 0, rtv_descriptor->handle); - bound_render_target_uids[i] = rt->uid; - om_dirty = 1; - } - ++rtvs_count; - } - else - { - break; - } - } - if (om_dirty) - { - D3D12_CPU_DESCRIPTOR_HANDLE rtv_handles[G_MaxRenderTargets] = Zi; - for (u32 i = 0; i < rtvs_count; ++i) - { - rtv_handles[i] = rcl->rtv_descriptors[i]->handle; - } - ID3D12GraphicsCommandList_OMSetRenderTargets(d3d_cl, rtvs_count, rtv_handles, 0, 0); - } - } - - /* Dispatch */ - ID3D12GraphicsCommandList_DrawIndexedInstanced(d3d_cl, indices_count, cmd->rasterize.instances_count, 0, 0, 0); - } - - cmd_idx += 1; - } break; - - //- Clear rtv - - case G_D12_CmdKind_ClearRtv: - { - G_D12_Resource *rt = cmd->clear_rtv.render_target; - f32 clear_color[4] = Zi; - { - clear_color[0] = cmd->clear_rtv.color.x; - clear_color[1] = cmd->clear_rtv.color.y; - clear_color[2] = cmd->clear_rtv.color.z; - clear_color[3] = cmd->clear_rtv.color.w; - } - D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = rcl->rtv_clear_descriptor->handle; - if (bound_render_clear_target_uid != rt->uid) - { - ID3D12Device_CreateRenderTargetView(g->device, rt->d3d_resource, 0, rtv_handle); - bound_render_clear_target_uid = rt->uid; - } - ID3D12GraphicsCommandList_ClearRenderTargetView(d3d_cl, rtv_handle, clear_color, 0, 0); - cmd_idx += 1; - } break; - - //- Discard rtv - - case G_D12_CmdKind_DiscardRtv: - { - G_D12_Resource *resource = cmd->discard_rtv.render_target; - ID3D12GraphicsCommandList_DiscardResource(d3d_cl, resource->d3d_resource, 0); - cmd_idx += 1; - } break; + src_box_ptr = &src_box; } - } - } + } - /* End dx12 command list */ - i64 completion_target = G_D12_CommitRawCommandList(rcl); + if (dst->flags & G_ResourceFlag_AllowDepthStencil) + { + /* Depth-stencil textures must have src box & dst offset set to 0 + * https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12graphicscommandlist-copytextureregion + */ + ID3D12GraphicsCommandList_CopyTextureRegion(d3d_cl, &dst_loc, 0, 0, 0, &src_loc, 0); + } + else + { + ID3D12GraphicsCommandList_CopyTextureRegion(d3d_cl, &dst_loc, dst_offset.x, dst_offset.y, dst_offset.z, &src_loc, src_box_ptr); + } - /* Attach completion info to staging regions */ - for (G_D12_StagingRegionNode *n = cl->first_staging_region; n;) - { - G_D12_StagingRegionNode *next = n->next_in_command_list; + cmd_idx += 1; + } break; + + //- Compute + + case G_D12_CmdKind_Compute: { - Atomic64Set(&n->completion_target, completion_target); - n->next_in_command_list = 0; - } - n = next; - } + G_D12_Pipeline *pipeline = 0; + { + G_D12_PipelineDesc pipeline_desc = Zi; + pipeline_desc.cs = cmd->compute.cs; + pipeline = G_D12_PipelineFromDesc(pipeline_desc); + } - /* Attach completion info to descriptors */ - for (G_D12_Descriptor *d = cl->reset_descriptors.first; d;) - { - G_D12_Descriptor *next = d->next; + if (pipeline) + { + /* Set descriptor heaps */ + if (!descriptor_heaps_set) + { + ID3D12DescriptorHeap *heaps[] = { + g->descriptor_heaps[G_D12_DescriptorHeapKind_CbvSrvUav].d3d_heap, + g->descriptor_heaps[G_D12_DescriptorHeapKind_Sampler].d3d_heap, + }; + ID3D12GraphicsCommandList_SetDescriptorHeaps(d3d_cl, countof(heaps), heaps); + descriptor_heaps_set = 1; + } + + /* Bind rootsig */ + if (!compute_rootsig_set) + { + ID3D12GraphicsCommandList_SetComputeRootSignature(d3d_cl, g->bindless_rootsig); + compute_rootsig_set = 1; + } + + /* Bind pipeline */ + if (pipeline != bound_pipeline) + { + ID3D12GraphicsCommandList_SetPipelineState(d3d_cl, pipeline->pso); + bound_pipeline = pipeline; + } + + /* Update root constants */ + for (i32 slot = 0; slot < countof(slotted_constants); ++slot) + { + if (bound_compute_constants[slot] != slotted_constants[slot]) + { + ID3D12GraphicsCommandList_SetComputeRoot32BitConstant(d3d_cl, slot, slotted_constants[slot], 0); + bound_compute_constants[slot] = slotted_constants[slot]; + } + } + + /* Dispatch */ + ID3D12GraphicsCommandList_Dispatch(d3d_cl, cmd->compute.groups.x, cmd->compute.groups.y, cmd->compute.groups.z); + } + + cmd_idx += 1; + } break; + + //- Rasterize + + case G_D12_CmdKind_Rasterize: { - G_D12_Arena *gpu_arena = d->gpu_arena; - d->completion_queue_kind = queue_kind; - d->completion_queue_target = completion_target; - G_D12_DescriptorList *gpu_arena_reset_descriptors_list = &gpu_arena->reset_descriptors_by_heap[d->heap->kind]; - SllQueuePush(gpu_arena_reset_descriptors_list->first, gpu_arena_reset_descriptors_list->last, d); - ++gpu_arena_reset_descriptors_list->count; - } - d = next; - } + G_D12_Pipeline *pipeline = 0; + { + G_D12_PipelineDesc pipeline_desc = Zi; + pipeline_desc.vs = cmd->rasterize.vs; + pipeline_desc.ps = cmd->rasterize.ps; + { + pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED; + switch (cmd->rasterize.mode) + { + default: Assert(0); break; + case G_RasterMode_PointList: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; break; + case G_RasterMode_LineList: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; break; + case G_RasterMode_LineStrip: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; break; + case G_RasterMode_TriangleList: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; + case G_RasterMode_TriangleStrip: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; + case G_RasterMode_WireTriangleList: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; + case G_RasterMode_WireTriangleStrip: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; + } + } + if (cmd->rasterize.mode == G_RasterMode_WireTriangleList || cmd->rasterize.mode == G_RasterMode_WireTriangleStrip) + { + pipeline_desc.is_wireframe = 1; + } + for (u32 i = 0; i < countof(cmd->rasterize.render_targets); ++i) + { + G_D12_Resource *rt = cmd->rasterize.render_targets[i]; + if (rt) + { + pipeline_desc.render_target_formats[i] = rt->texture_format; + } + else + { + pipeline_desc.render_target_formats[i] = G_Format_Unknown; + } + } + pipeline = G_D12_PipelineFromDesc(pipeline_desc); + } - // /* Attach completion info to resources */ - // for (G_D12_Resource *r = cl->reset_resources.first; r;) - // { - // G_D12_Resource *next = r->next; - // { - // G_D12_ResourceHeap *heap = r->heap; - // G_D12_Arena *gpu_arena = >heap->gpu_arena; - // r->completion_queue_kind = queue->kind; - // r->completion_queue_target = completion_target; - // G_D12_ResourceList *heap_reset_resources_list = &heap->reset_resources; - // SllQueuePush(heap_reset_resources_list->first, heap_reset_resourecs_list->last, r); - // ++heap_reset_resources_list->count; - // } - // r = next; - // } + /* Create ibv */ + u32 indices_count = 0; + D3D12_INDEX_BUFFER_VIEW ibv = Zi; + { + G_IndexBufferDesc desc = cmd->rasterize.index_buffer_desc; + if (desc.index_count > 0) + { + G_D12_Resource *index_buffer_resource = G_D12_ResourceFromHandle(desc.resource); + ibv.BufferLocation = index_buffer_resource->buffer_gpu_address; + ibv.SizeInBytes = desc.index_size * desc.index_count; + if (desc.index_size == 2) + { + ibv.Format = DXGI_FORMAT_R16_UINT; + indices_count = ibv.SizeInBytes / 2; + } + else if (desc.index_size == 4) + { + ibv.Format = DXGI_FORMAT_R32_UINT; + indices_count = ibv.SizeInBytes / 4; + } + else + { + Assert(0); /* Invalid index size */ + } + } + } - /* Free command list */ - { - Lock lock = LockE(&g->free_cmd_lists_mutex); + /* Prepare & dispatch */ + if (pipeline && indices_count > 0) + { + /* Set descriptor heaps */ + if (!descriptor_heaps_set) + { + ID3D12DescriptorHeap *heaps[] = { + g->descriptor_heaps[G_D12_DescriptorHeapKind_CbvSrvUav].d3d_heap, + g->descriptor_heaps[G_D12_DescriptorHeapKind_Sampler].d3d_heap, + }; + ID3D12GraphicsCommandList_SetDescriptorHeaps(d3d_cl, countof(heaps), heaps); + descriptor_heaps_set = 1; + } + + /* Bind rootsig */ + if (!graphics_rootsig_set) + { + ID3D12GraphicsCommandList_SetGraphicsRootSignature(d3d_cl, g->bindless_rootsig); + graphics_rootsig_set = 1; + } + + /* Bind pipeline */ + if (pipeline != bound_pipeline) + { + ID3D12GraphicsCommandList_SetPipelineState(d3d_cl, pipeline->pso); + bound_pipeline = pipeline; + } + + /* Update root constants */ + for (i32 slot = 0; slot < countof(slotted_constants); ++slot) + { + if (bound_graphics_constants[slot] != slotted_constants[slot]) + { + ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstant(d3d_cl, slot, slotted_constants[slot], 0); + bound_graphics_constants[slot] = slotted_constants[slot]; + } + } + + /* Set viewport */ + { + D3D12_VIEWPORT viewport = Zi; + { + Rng3 range = cmd->rasterize.viewport; + viewport.TopLeftX = range.p0.x; + viewport.TopLeftY = range.p0.y; + viewport.Width = range.p1.x - range.p0.x; + viewport.Height = range.p1.y - range.p0.y; + viewport.MinDepth = range.p0.z; + viewport.MaxDepth = range.p1.z; + } + if (!MatchStruct(&viewport, &bound_viewport)) + { + bound_viewport = viewport; + ID3D12GraphicsCommandList_RSSetViewports(d3d_cl, 1, &viewport); + } + } + + /* Set scissor */ + { + D3D12_RECT scissor = Zi; + { + Rng2 range = cmd->rasterize.scissor; + scissor.left = range.p0.x; + scissor.top = range.p0.y; + scissor.right = range.p1.x; + scissor.bottom = range.p1.y; + } + if (!MatchStruct(&scissor, &bound_scissor)) + { + bound_scissor = scissor; + ID3D12GraphicsCommandList_RSSetScissorRects(d3d_cl, 1, &scissor); + } + } + + /* Set topology */ + { + D3D_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + switch (cmd->rasterize.mode) + { + default: Assert(0); break; + case G_RasterMode_PointList: topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; break; + case G_RasterMode_LineList: topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; break; + case G_RasterMode_LineStrip: topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; break; + case G_RasterMode_TriangleList: topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break; + case G_RasterMode_TriangleStrip: topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; break; + case G_RasterMode_WireTriangleList: topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break; + case G_RasterMode_WireTriangleStrip: topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; break; + } + if (topology != bound_primitive_topology) + { + ID3D12GraphicsCommandList_IASetPrimitiveTopology(d3d_cl, topology); + } + } + + /* Set index buffer */ + if (!MatchStruct(&ibv, &bound_ibv)) + { + ID3D12GraphicsCommandList_IASetIndexBuffer(d3d_cl, &ibv); + bound_ibv = ibv; + } + + /* Bind render targets */ + { + b32 om_dirty = 0; + u32 rtvs_count = 0; + for (u32 i = 0; i < countof(cmd->rasterize.render_targets); ++i) + { + G_D12_Resource *rt = cmd->rasterize.render_targets[i]; + if (rt) + { + if (bound_render_target_uids[i] != rt->uid) + { + G_D12_Descriptor *rtv_descriptor = rcl->rtv_descriptors[i]; + ID3D12Device_CreateRenderTargetView(g->device, rt->d3d_resource, 0, rtv_descriptor->handle); + bound_render_target_uids[i] = rt->uid; + om_dirty = 1; + } + ++rtvs_count; + } + else + { + break; + } + } + if (om_dirty) + { + D3D12_CPU_DESCRIPTOR_HANDLE rtv_handles[G_MaxRenderTargets] = Zi; + for (u32 i = 0; i < rtvs_count; ++i) + { + rtv_handles[i] = rcl->rtv_descriptors[i]->handle; + } + ID3D12GraphicsCommandList_OMSetRenderTargets(d3d_cl, rtvs_count, rtv_handles, 0, 0); + } + } + + /* Dispatch */ + ID3D12GraphicsCommandList_DrawIndexedInstanced(d3d_cl, indices_count, cmd->rasterize.instances_count, 0, 0, 0); + } + + cmd_idx += 1; + } break; + + //- Clear rtv + + case G_D12_CmdKind_ClearRtv: { - cl->next = g->first_free_cmd_list; - g->first_free_cmd_list = cl; - } - Unlock(&lock); - } + G_D12_Resource *rt = cmd->clear_rtv.render_target; + f32 clear_color[4] = Zi; + { + clear_color[0] = cmd->clear_rtv.color.x; + clear_color[1] = cmd->clear_rtv.color.y; + clear_color[2] = cmd->clear_rtv.color.z; + clear_color[3] = cmd->clear_rtv.color.w; + } + D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = rcl->rtv_clear_descriptor->handle; + if (bound_render_clear_target_uid != rt->uid) + { + ID3D12Device_CreateRenderTargetView(g->device, rt->d3d_resource, 0, rtv_handle); + bound_render_clear_target_uid = rt->uid; + } + ID3D12GraphicsCommandList_ClearRenderTargetView(d3d_cl, rtv_handle, clear_color, 0, 0); + cmd_idx += 1; + } break; - EndScratch(scratch); - return completion_target; + //- Discard rtv + + case G_D12_CmdKind_DiscardRtv: + { + G_D12_Resource *resource = cmd->discard_rtv.render_target; + ID3D12GraphicsCommandList_DiscardResource(d3d_cl, resource->d3d_resource, 0); + cmd_idx += 1; + } break; + } + } + } + + /* End dx12 command list */ + i64 completion_target = G_D12_CommitRawCommandList(rcl); + + /* Attach completion info to staging regions */ + for (G_D12_StagingRegionNode *n = cl->first_staging_region; n;) + { + G_D12_StagingRegionNode *next = n->next_in_command_list; + { + Atomic64Set(&n->completion_target, completion_target); + n->next_in_command_list = 0; + } + n = next; + } + + /* Attach completion info to descriptors */ + for (G_D12_Descriptor *d = cl->reset_descriptors.first; d;) + { + G_D12_Descriptor *next = d->next; + { + G_D12_Arena *gpu_arena = d->gpu_arena; + d->completion_queue_kind = queue_kind; + d->completion_queue_target = completion_target; + G_D12_DescriptorList *gpu_arena_reset_descriptors_list = &gpu_arena->reset_descriptors_by_heap[d->heap->kind]; + SllQueuePush(gpu_arena_reset_descriptors_list->first, gpu_arena_reset_descriptors_list->last, d); + ++gpu_arena_reset_descriptors_list->count; + } + d = next; + } + + // /* Attach completion info to resources */ + // for (G_D12_Resource *r = cl->reset_resources.first; r;) + // { + // G_D12_Resource *next = r->next; + // { + // G_D12_ResourceHeap *heap = r->heap; + // G_D12_Arena *gpu_arena = >heap->gpu_arena; + // r->completion_queue_kind = queue->kind; + // r->completion_queue_target = completion_target; + // G_D12_ResourceList *heap_reset_resources_list = &heap->reset_resources; + // SllQueuePush(heap_reset_resources_list->first, heap_reset_resourecs_list->last, r); + // ++heap_reset_resources_list->count; + // } + // r = next; + // } + + /* Free command list */ + { + Lock lock = LockE(&g->free_cmd_lists_mutex); + { + cl->next = g->first_free_cmd_list; + g->first_free_cmd_list = cl; + } + Unlock(&lock); + } + + EndScratch(scratch); + return completion_target; } //- Cpu -> Gpu copy void G_CopyCpuToBuffer(G_CommandListHandle cl_handle, G_ResourceHandle dst_handle, u64 dst_offset, void *src, RngU64 src_copy_range) { - if (src_copy_range.max > src_copy_range.min) - { - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - u64 copy_size = src_copy_range.max - src_copy_range.min; - G_D12_StagingRegionNode *region = G_D12_PushStagingRegion(cl, copy_size); - CopyBytes((u8 *)region->ring->base + region->pos, (u8 *)src + src_copy_range.min, copy_size); - G_CopyBufferToBuffer( - cl_handle, - dst_handle, - dst_offset, - G_D12_MakeHandle(G_ResourceHandle, region->ring->resource), - RNGU64(region->pos, region->pos + copy_size) - ); - } + if (src_copy_range.max > src_copy_range.min) + { + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + u64 copy_size = src_copy_range.max - src_copy_range.min; + G_D12_StagingRegionNode *region = G_D12_PushStagingRegion(cl, copy_size); + CopyBytes((u8 *)region->ring->base + region->pos, (u8 *)src + src_copy_range.min, copy_size); + G_CopyBufferToBuffer( + cl_handle, + dst_handle, + dst_offset, + G_D12_MakeHandle(G_ResourceHandle, region->ring->resource), + RNGU64(region->pos, region->pos + copy_size) + ); + } } void G_CopyCpuToTexture(G_CommandListHandle cl_handle, G_ResourceHandle dst_handle, Vec3I32 dst_offset, void *src, Vec3I32 src_dims, Rng3I32 src_copy_range) { - Vec3I32 staged_dims = Zi; + Vec3I32 staged_dims = Zi; + { + staged_dims.x = src_copy_range.p1.x - src_copy_range.p0.x; + staged_dims.y = src_copy_range.p1.y - src_copy_range.p0.y; + staged_dims.z = src_copy_range.p1.z - src_copy_range.p0.z; + } + if (staged_dims.x > 0 && staged_dims.y > 0 && staged_dims.z > 0) + { + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Resource *dst = G_D12_ResourceFromHandle(dst_handle); + Assert(dst->is_texture); + + /* Grab footprint info */ + u64 staging_footprint_rows_count = 0; + u64 staging_footprint_row_size = 0; + u64 staging_footprint_row_pitch = 0; + u64 staging_footprint_size = 0; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT staging_footprint = Zi; { - staged_dims.x = src_copy_range.p1.x - src_copy_range.p0.x; - staged_dims.y = src_copy_range.p1.y - src_copy_range.p0.y; - staged_dims.z = src_copy_range.p1.z - src_copy_range.p0.z; + D3D12_RESOURCE_DESC src_desc = Zi; + { + ID3D12Resource_GetDesc(dst->d3d_resource, &src_desc); + src_desc.Width = staged_dims.x; + src_desc.Height = staged_dims.y; + src_desc.DepthOrArraySize = staged_dims.z; + } + ID3D12Device_GetCopyableFootprints(g->device, &src_desc, 0, 1, 0, &staging_footprint, (u32 *)&staging_footprint_rows_count, &staging_footprint_row_size, &staging_footprint_size); + staging_footprint_row_pitch = staging_footprint.Footprint.RowPitch; } - if (staged_dims.x > 0 && staged_dims.y > 0 && staged_dims.z > 0) + + i32 bytes_per_texel = staging_footprint_row_size / staged_dims.x; + u64 src_row_pitch = src_dims.x * bytes_per_texel; + + G_D12_StagingRegionNode *staging_region = G_D12_PushStagingRegion(cl, staging_footprint_size); + G_D12_Resource *staging_resource = staging_region->ring->resource; + G_ResourceHandle staging_resource_handle = G_D12_MakeHandle(G_ResourceHandle, staging_resource); + staging_footprint.Offset = staging_region->pos; + + /* Fill staging buffer */ { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Resource *dst = G_D12_ResourceFromHandle(dst_handle); - Assert(dst->is_texture); - - /* Grab footprint info */ - u64 staging_footprint_rows_count = 0; - u64 staging_footprint_row_size = 0; - u64 staging_footprint_row_pitch = 0; - u64 staging_footprint_size = 0; - D3D12_PLACED_SUBRESOURCE_FOOTPRINT staging_footprint = Zi; + u8 *src_base = (u8 *)src + (src_copy_range.p0.y * src_row_pitch) + (src_copy_range.p0.x * bytes_per_texel); + u8 *staged_base = (u8 *)staging_region->ring->base + staging_footprint.Offset; + u64 src_z_pitch = src_row_pitch * src_dims.y; + u64 staged_z_pitch = staging_footprint_row_size * staging_footprint_rows_count; + for (i32 z = 0; z < src_dims.z; ++z) + { + u64 src_z_offset = z * src_z_pitch; + u64 staged_z_offset = z * staged_z_pitch; + for (i32 y = 0; y < staging_footprint_rows_count; ++y) { - D3D12_RESOURCE_DESC src_desc = Zi; - { - ID3D12Resource_GetDesc(dst->d3d_resource, &src_desc); - src_desc.Width = staged_dims.x; - src_desc.Height = staged_dims.y; - src_desc.DepthOrArraySize = staged_dims.z; - } - ID3D12Device_GetCopyableFootprints(g->device, &src_desc, 0, 1, 0, &staging_footprint, (u32 *)&staging_footprint_rows_count, &staging_footprint_row_size, &staging_footprint_size); - staging_footprint_row_pitch = staging_footprint.Footprint.RowPitch; + u8 *src_row = src_base + y * src_row_pitch + src_z_offset; + u8 *staged_row = staged_base + y * staging_footprint_row_pitch + staged_z_offset; + CopyBytes(staged_row, src_row, staging_footprint_row_size); } - - i32 bytes_per_texel = staging_footprint_row_size / staged_dims.x; - u64 src_row_pitch = src_dims.x * bytes_per_texel; - - G_D12_StagingRegionNode *staging_region = G_D12_PushStagingRegion(cl, staging_footprint_size); - G_D12_Resource *staging_resource = staging_region->ring->resource; - G_ResourceHandle staging_resource_handle = G_D12_MakeHandle(G_ResourceHandle, staging_resource); - staging_footprint.Offset = staging_region->pos; - - /* Fill staging buffer */ - { - u8 *src_base = (u8 *)src + (src_copy_range.p0.y * src_row_pitch) + (src_copy_range.p0.x * bytes_per_texel); - u8 *staged_base = (u8 *)staging_region->ring->base + staging_footprint.Offset; - u64 src_z_pitch = src_row_pitch * src_dims.y; - u64 staged_z_pitch = staging_footprint_row_size * staging_footprint_rows_count; - for (i32 z = 0; z < src_dims.z; ++z) - { - u64 src_z_offset = z * src_z_pitch; - u64 staged_z_offset = z * staged_z_pitch; - for (i32 y = 0; y < staging_footprint_rows_count; ++y) - { - u8 *src_row = src_base + y * src_row_pitch + src_z_offset; - u8 *staged_row = staged_base + y * staging_footprint_row_pitch + staged_z_offset; - CopyBytes(staged_row, src_row, staging_footprint_row_size); - } - } - } - - Rng3I32 dst_copy_range = Zi; - dst_copy_range.p0 = dst_offset; - dst_copy_range.p1.x = dst_copy_range.p0.x + staged_dims.x; - dst_copy_range.p1.y = dst_copy_range.p0.y + staged_dims.y; - dst_copy_range.p1.z = dst_copy_range.p0.z + staged_dims.z; - G_CopyBufferToTexture( - cl_handle, - dst_handle, dst_copy_range, - staging_resource_handle, staging_footprint.Offset - ); + } } + + Rng3I32 dst_copy_range = Zi; + dst_copy_range.p0 = dst_offset; + dst_copy_range.p1.x = dst_copy_range.p0.x + staged_dims.x; + dst_copy_range.p1.y = dst_copy_range.p0.y + staged_dims.y; + dst_copy_range.p1.z = dst_copy_range.p0.z + staged_dims.z; + G_CopyBufferToTexture( + cl_handle, + dst_handle, dst_copy_range, + staging_resource_handle, staging_footprint.Offset + ); + } } //- Gpu <-> Gpu copy void G_CopyBufferToBuffer(G_CommandListHandle cl_handle, G_ResourceHandle dst_handle, u64 dst_offset, G_ResourceHandle src_handle, RngU64 src_copy_range) { - if (src_copy_range.max > src_copy_range.min) - { - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Cmd *cmd = G_D12_PushCmd(cl); - cmd->kind = G_D12_CmdKind_CopyBytes; - cmd->copy_bytes.src = G_D12_ResourceFromHandle(src_handle); - cmd->copy_bytes.dst = G_D12_ResourceFromHandle(dst_handle); - cmd->copy_bytes.dst_offset = dst_offset; - cmd->copy_bytes.src_range = src_copy_range; - } + if (src_copy_range.max > src_copy_range.min) + { + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Cmd *cmd = G_D12_PushCmd(cl); + cmd->kind = G_D12_CmdKind_CopyBytes; + cmd->copy_bytes.src = G_D12_ResourceFromHandle(src_handle); + cmd->copy_bytes.dst = G_D12_ResourceFromHandle(dst_handle); + cmd->copy_bytes.dst_offset = dst_offset; + cmd->copy_bytes.src_range = src_copy_range; + } } void G_CopyBufferToTexture(G_CommandListHandle cl_handle, G_ResourceHandle dst_handle, Rng3I32 dst_copy_range, G_ResourceHandle src_handle, u64 src_offset) { - Vec3I32 src_dims = Zi; + Vec3I32 src_dims = Zi; + { + src_dims.x = dst_copy_range.p1.x - dst_copy_range.p0.x; + src_dims.y = dst_copy_range.p1.y - dst_copy_range.p0.y; + src_dims.z = dst_copy_range.p1.z - dst_copy_range.p0.z; + } + if (src_dims.x > 0 && src_dims.y > 0 && src_dims.z > 0) + { + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Resource *src = G_D12_ResourceFromHandle(src_handle); + G_D12_Resource *dst = G_D12_ResourceFromHandle(dst_handle); + Assert(!src->is_texture); + Assert(dst->is_texture); + + /* Grab footprint info */ + D3D12_PLACED_SUBRESOURCE_FOOTPRINT src_footprint = Zi; { - src_dims.x = dst_copy_range.p1.x - dst_copy_range.p0.x; - src_dims.y = dst_copy_range.p1.y - dst_copy_range.p0.y; - src_dims.z = dst_copy_range.p1.z - dst_copy_range.p0.z; + D3D12_RESOURCE_DESC src_desc = Zi; + { + ID3D12Resource_GetDesc(dst->d3d_resource, &src_desc); + src_desc.Width = src_dims.x; + src_desc.Height = src_dims.y; + src_desc.DepthOrArraySize = src_dims.z; + } + ID3D12Device_GetCopyableFootprints(g->device, &src_desc, 0, 1, 0, &src_footprint, 0, 0, 0); + src_footprint.Offset = src_offset; } - if (src_dims.x > 0 && src_dims.y > 0 && src_dims.z > 0) + + D3D12_TEXTURE_COPY_LOCATION src_loc = Zi; + D3D12_TEXTURE_COPY_LOCATION dst_loc = Zi; { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Resource *src = G_D12_ResourceFromHandle(src_handle); - G_D12_Resource *dst = G_D12_ResourceFromHandle(dst_handle); - Assert(!src->is_texture); - Assert(dst->is_texture); - - /* Grab footprint info */ - D3D12_PLACED_SUBRESOURCE_FOOTPRINT src_footprint = Zi; - { - D3D12_RESOURCE_DESC src_desc = Zi; - { - ID3D12Resource_GetDesc(dst->d3d_resource, &src_desc); - src_desc.Width = src_dims.x; - src_desc.Height = src_dims.y; - src_desc.DepthOrArraySize = src_dims.z; - } - ID3D12Device_GetCopyableFootprints(g->device, &src_desc, 0, 1, 0, &src_footprint, 0, 0, 0); - src_footprint.Offset = src_offset; - } - - D3D12_TEXTURE_COPY_LOCATION src_loc = Zi; - D3D12_TEXTURE_COPY_LOCATION dst_loc = Zi; - { - src_loc.pResource = src->d3d_resource; - src_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src_loc.PlacedFootprint = src_footprint; - } - { - dst_loc.pResource = dst->d3d_resource; - dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dst_loc.SubresourceIndex = 0; - } - - G_D12_Cmd *cmd = G_D12_PushCmd(cl); - cmd->kind = G_D12_CmdKind_CopyTexels; - cmd->copy_texels.dst = dst; - cmd->copy_texels.src = src; - cmd->copy_texels.dst_loc = dst_loc; - cmd->copy_texels.src_loc = src_loc; - cmd->copy_texels.dst_texture_offset = dst_copy_range.p0; + src_loc.pResource = src->d3d_resource; + src_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src_loc.PlacedFootprint = src_footprint; } + { + dst_loc.pResource = dst->d3d_resource; + dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst_loc.SubresourceIndex = 0; + } + + G_D12_Cmd *cmd = G_D12_PushCmd(cl); + cmd->kind = G_D12_CmdKind_CopyTexels; + cmd->copy_texels.dst = dst; + cmd->copy_texels.src = src; + cmd->copy_texels.dst_loc = dst_loc; + cmd->copy_texels.src_loc = src_loc; + cmd->copy_texels.dst_texture_offset = dst_copy_range.p0; + } } void G_CopyTextureToTexture(G_CommandListHandle cl_handle, G_ResourceHandle dst_handle, Vec3I32 dst_offset, G_ResourceHandle src_handle, Rng3I32 src_copy_range) { - if ( - src_copy_range.p1.x > src_copy_range.p0.x && - src_copy_range.p1.y > src_copy_range.p0.y && - src_copy_range.p1.z > src_copy_range.p0.z - ) + if ( + src_copy_range.p1.x > src_copy_range.p0.x && + src_copy_range.p1.y > src_copy_range.p0.y && + src_copy_range.p1.z > src_copy_range.p0.z + ) + { + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Resource *src = G_D12_ResourceFromHandle(src_handle); + G_D12_Resource *dst = G_D12_ResourceFromHandle(dst_handle); + Assert(src->is_texture); + Assert(dst->is_texture); + + D3D12_TEXTURE_COPY_LOCATION src_loc = Zi; + D3D12_TEXTURE_COPY_LOCATION dst_loc = Zi; { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Resource *src = G_D12_ResourceFromHandle(src_handle); - G_D12_Resource *dst = G_D12_ResourceFromHandle(dst_handle); - Assert(src->is_texture); - Assert(dst->is_texture); - - D3D12_TEXTURE_COPY_LOCATION src_loc = Zi; - D3D12_TEXTURE_COPY_LOCATION dst_loc = Zi; - { - src_loc.pResource = dst->d3d_resource; - src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - src_loc.SubresourceIndex = 0; - } - { - dst_loc.pResource = dst->d3d_resource; - dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dst_loc.SubresourceIndex = 0; - } - - G_D12_Cmd *cmd = G_D12_PushCmd(cl); - cmd->kind = G_D12_CmdKind_CopyTexels; - cmd->copy_texels.dst = dst; - cmd->copy_texels.src = src; - cmd->copy_texels.dst_loc = dst_loc; - cmd->copy_texels.src_loc = src_loc; - cmd->copy_texels.dst_texture_offset = dst_offset; - cmd->copy_texels.src_texture_range = src_copy_range; + src_loc.pResource = dst->d3d_resource; + src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src_loc.SubresourceIndex = 0; } + { + dst_loc.pResource = dst->d3d_resource; + dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst_loc.SubresourceIndex = 0; + } + + G_D12_Cmd *cmd = G_D12_PushCmd(cl); + cmd->kind = G_D12_CmdKind_CopyTexels; + cmd->copy_texels.dst = dst; + cmd->copy_texels.src = src; + cmd->copy_texels.dst_loc = dst_loc; + cmd->copy_texels.src_loc = src_loc; + cmd->copy_texels.dst_texture_offset = dst_offset; + cmd->copy_texels.src_texture_range = src_copy_range; + } } void G_CopyTextureToBuffer(G_CommandListHandle cl_handle, G_ResourceHandle dst_handle, Vec3I32 dst_offset, G_ResourceHandle src_handle, Rng3I32 src_copy_range) { - /* TODO */ - Assert(0); + /* TODO */ + Assert(0); } //- Constant void G_SetConstant_(G_CommandListHandle cl_handle, i32 slot, void *src_32bit, u32 size) { - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Cmd *cmd = G_D12_PushCmd(cl); - cmd->kind = G_D12_CmdKind_Constant; - cmd->constant.slot = slot; - CopyBytes(&cmd->constant.value, src_32bit, MinU32(size, 4)); + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Cmd *cmd = G_D12_PushCmd(cl); + cmd->kind = G_D12_CmdKind_Constant; + cmd->constant.slot = slot; + CopyBytes(&cmd->constant.value, src_32bit, MinU32(size, 4)); } //- Memory sync void G_MemorySyncEx(G_CommandListHandle cl_handle, G_MemoryBarrierDesc desc) { - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Cmd *cmd = G_D12_PushCmd(cl); - cmd->kind = G_D12_CmdKind_Barrier; - cmd->barrier.desc = desc; + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Cmd *cmd = G_D12_PushCmd(cl); + cmd->kind = G_D12_CmdKind_Barrier; + cmd->barrier.desc = desc; } //- Compute void G_Compute(G_CommandListHandle cl_handle, ComputeShader cs, Vec3I32 groups) { - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Cmd *cmd = G_D12_PushCmd(cl); - cmd->kind = G_D12_CmdKind_Compute; - cmd->compute.cs = cs; - cmd->compute.groups = groups; + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Cmd *cmd = G_D12_PushCmd(cl); + cmd->kind = G_D12_CmdKind_Compute; + cmd->compute.cs = cs; + cmd->compute.groups = groups; } //- Rasterize void G_Rasterize( - G_CommandListHandle cl_handle, - VertexShader vs, PixelShader ps, - u32 instances_count, G_IndexBufferDesc index_buffer, - u32 render_targets_count, G_ResourceHandle *render_targets, - Rng3 viewport, Rng2 scissor, - G_RasterMode mode + G_CommandListHandle cl_handle, + VertexShader vs, PixelShader ps, + u32 instances_count, G_IndexBufferDesc index_buffer, + u32 render_targets_count, G_ResourceHandle *render_targets, + Rng3 viewport, Rng2 scissor, + G_RasterMode mode ) { - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Cmd *cmd = G_D12_PushCmd(cl); - cmd->kind = G_D12_CmdKind_Rasterize; - cmd->rasterize.vs = vs; - cmd->rasterize.ps = ps; - cmd->rasterize.instances_count = instances_count; - cmd->rasterize.index_buffer_desc = index_buffer; - for (u32 i = 0; i < MinU32(render_targets_count, G_MaxRenderTargets); ++i) - { - cmd->rasterize.render_targets[i] = G_D12_ResourceFromHandle(render_targets[i]); - } - cmd->rasterize.viewport = viewport; - cmd->rasterize.scissor = scissor; - cmd->rasterize.mode = mode; + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Cmd *cmd = G_D12_PushCmd(cl); + cmd->kind = G_D12_CmdKind_Rasterize; + cmd->rasterize.vs = vs; + cmd->rasterize.ps = ps; + cmd->rasterize.instances_count = instances_count; + cmd->rasterize.index_buffer_desc = index_buffer; + for (u32 i = 0; i < MinU32(render_targets_count, G_MaxRenderTargets); ++i) + { + cmd->rasterize.render_targets[i] = G_D12_ResourceFromHandle(render_targets[i]); + } + cmd->rasterize.viewport = viewport; + cmd->rasterize.scissor = scissor; + cmd->rasterize.mode = mode; } //- Clear void G_ClearRenderTarget(G_CommandListHandle cl_handle, G_ResourceHandle resource_handle, Vec4 color) { - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Cmd *cmd = G_D12_PushCmd(cl); - cmd->kind = G_D12_CmdKind_ClearRtv; - cmd->clear_rtv.render_target = G_D12_ResourceFromHandle(resource_handle); - cmd->clear_rtv.color = color; + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Cmd *cmd = G_D12_PushCmd(cl); + cmd->kind = G_D12_CmdKind_ClearRtv; + cmd->clear_rtv.render_target = G_D12_ResourceFromHandle(resource_handle); + cmd->clear_rtv.color = color; } //- Discard void G_DiscardRenderTarget(G_CommandListHandle cl_handle, G_ResourceHandle resource_handle) { - G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); - G_D12_Cmd *cmd = G_D12_PushCmd(cl); - cmd->kind = G_D12_CmdKind_DiscardRtv; - cmd->discard_rtv.render_target = G_D12_ResourceFromHandle(resource_handle); + G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); + G_D12_Cmd *cmd = G_D12_PushCmd(cl); + cmd->kind = G_D12_CmdKind_DiscardRtv; + cmd->discard_rtv.render_target = G_D12_ResourceFromHandle(resource_handle); } //////////////////////////////////////////////////////////// @@ -2693,108 +2690,108 @@ void G_DiscardRenderTarget(G_CommandListHandle cl_handle, G_ResourceHandle resou i64 G_CompletionValueFromQueue(G_QueueKind queue_kind) { - G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); - return ID3D12Fence_GetCompletedValue(queue->commit_fence); + G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); + return ID3D12Fence_GetCompletedValue(queue->commit_fence); } i64 G_CompletionTargetFromQueue(G_QueueKind queue_kind) { - G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); - i64 target = 0; - { - Lock lock = LockS(&queue->commit_mutex); - target = queue->commit_fence_target; - Unlock(&lock); - } - return target; + G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); + i64 target = 0; + { + Lock lock = LockS(&queue->commit_mutex); + target = queue->commit_fence_target; + Unlock(&lock); + } + return target; } G_QueueCompletions G_CompletionValuesFromQueues(G_QueueMask queue_mask) { - G_QueueCompletions completions = Zi; - for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) + G_QueueCompletions completions = Zi; + for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) + { + if (queue_mask & (1 << queue_kind)) { - if (queue_mask & (1 << queue_kind)) - { - completions.v[queue_kind] = G_CompletionTargetFromQueue(queue_kind); - } + completions.v[queue_kind] = G_CompletionTargetFromQueue(queue_kind); } - return completions; + } + return completions; } G_QueueCompletions G_CompletionTargetsFromQueues(G_QueueMask queue_mask) { - G_QueueCompletions completions = Zi; - for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) + G_QueueCompletions completions = Zi; + for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) + { + if (queue_mask & (1 << queue_kind)) { - if (queue_mask & (1 << queue_kind)) - { - completions.v[queue_kind] = G_CompletionTargetFromQueue(queue_kind); - } + completions.v[queue_kind] = G_CompletionTargetFromQueue(queue_kind); } - return completions; + } + return completions; } void G_SyncEx(G_QueueBarrierDesc desc) { - G_D12_SharedState *g = &G_D12_shared_state; + G_D12_SharedState *g = &G_D12_shared_state; - u64 fences_count = 0; - ID3D12Fence *fences[G_NumQueues] = Zi; - i64 fence_targets[G_NumQueues] = Zi; + u64 fences_count = 0; + ID3D12Fence *fences[G_NumQueues] = Zi; + i64 fence_targets[G_NumQueues] = Zi; - /* Grab fences */ - for (G_QueueKind completion_queue_kind = 0; completion_queue_kind < G_NumQueues; ++ completion_queue_kind) + /* Grab fences */ + for (G_QueueKind completion_queue_kind = 0; completion_queue_kind < G_NumQueues; ++ completion_queue_kind) + { + G_D12_Queue *completion_queue = G_D12_QueueFromKind(completion_queue_kind); + i64 target = desc.completions.v[completion_queue_kind]; + if (target > 0) { - G_D12_Queue *completion_queue = G_D12_QueueFromKind(completion_queue_kind); - i64 target = desc.completions.v[completion_queue_kind]; - if (target > 0) - { - i64 fence_value = ID3D12Fence_GetCompletedValue(completion_queue->commit_fence); - if (fence_value < target) - { - fences[fences_count] = completion_queue->commit_fence; - fence_targets[fences_count] = target; - fences_count += 1; - } - } + i64 fence_value = ID3D12Fence_GetCompletedValue(completion_queue->commit_fence); + if (fence_value < target) + { + fences[fences_count] = completion_queue->commit_fence; + fence_targets[fences_count] = target; + fences_count += 1; + } } + } - /* Sync Queues */ - for (G_QueueKind waiter_queue_kind = 0; waiter_queue_kind < G_NumQueues; ++ waiter_queue_kind) + /* Sync Queues */ + for (G_QueueKind waiter_queue_kind = 0; waiter_queue_kind < G_NumQueues; ++ waiter_queue_kind) + { + if (desc.wait_queues & (1 << waiter_queue_kind)) { - if (desc.wait_queues & (1 << waiter_queue_kind)) + G_D12_Queue *waiter_queue = G_D12_QueueFromKind(waiter_queue_kind); + for (u64 fence_idx = 0; fence_idx < fences_count; ++fence_idx) + { + ID3D12Fence *fence = fences[fence_idx]; + if (waiter_queue->commit_fence != fence) { - G_D12_Queue *waiter_queue = G_D12_QueueFromKind(waiter_queue_kind); - for (u64 fence_idx = 0; fence_idx < fences_count; ++fence_idx) - { - ID3D12Fence *fence = fences[fence_idx]; - if (waiter_queue->commit_fence != fence) - { - i64 target = fence_targets[fence_idx]; - ID3D12CommandQueue_Wait(waiter_queue->d3d_queue, fence, target); - } - } + i64 target = fence_targets[fence_idx]; + ID3D12CommandQueue_Wait(waiter_queue->d3d_queue, fence, target); } + } } + } - /* Sync Cpu */ - if (desc.wait_cpu && fences_count > 0) + /* Sync Cpu */ + if (desc.wait_cpu && fences_count > 0) + { + if (G_D12_tl.sync_event == 0) { - if (G_D12_tl.sync_event == 0) - { - G_D12_tl.sync_event = CreateEvent(0, 0, 0, 0); - } - ID3D12Device1_SetEventOnMultipleFenceCompletion( - g->device, - fences, - (u64 *)fence_targets, - fences_count, - D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL, - G_D12_tl.sync_event - ); - WaitForSingleObject(G_D12_tl.sync_event, INFINITE); + G_D12_tl.sync_event = CreateEvent(0, 0, 0, 0); } + ID3D12Device1_SetEventOnMultipleFenceCompletion( + g->device, + fences, + (u64 *)fence_targets, + fences_count, + D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL, + G_D12_tl.sync_event + ); + WaitForSingleObject(G_D12_tl.sync_event, INFINITE); + } } //////////////////////////////////////////////////////////// @@ -2802,23 +2799,23 @@ void G_SyncEx(G_QueueBarrierDesc desc) G_Stats G_QueryStats(void) { - G_D12_SharedState *g = &G_D12_shared_state; - G_Stats result = Zi; - { - DXGI_QUERY_VIDEO_MEMORY_INFO info = Zi; - IDXGIAdapter3_QueryVideoMemoryInfo(g->adapter, 0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info); - result.local_committed = info.CurrentUsage; - result.local_budget = info.Budget; - } - { - DXGI_QUERY_VIDEO_MEMORY_INFO info = Zi; - IDXGIAdapter3_QueryVideoMemoryInfo(g->adapter, 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &info); - result.non_local_budget = info.Budget; - result.non_local_committed = info.CurrentUsage; - } - result.driver_resources_allocated = Atomic64Fetch(&g->driver_resources_allocated); - result.driver_descriptors_allocated = Atomic64Fetch(&g->driver_descriptors_allocated); - return result; + G_D12_SharedState *g = &G_D12_shared_state; + G_Stats result = Zi; + { + DXGI_QUERY_VIDEO_MEMORY_INFO info = Zi; + IDXGIAdapter3_QueryVideoMemoryInfo(g->adapter, 0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info); + result.local_committed = info.CurrentUsage; + result.local_budget = info.Budget; + } + { + DXGI_QUERY_VIDEO_MEMORY_INFO info = Zi; + IDXGIAdapter3_QueryVideoMemoryInfo(g->adapter, 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &info); + result.non_local_budget = info.Budget; + result.non_local_committed = info.CurrentUsage; + } + result.driver_resources_allocated = Atomic64Fetch(&g->driver_resources_allocated); + result.driver_descriptors_allocated = Atomic64Fetch(&g->driver_descriptors_allocated); + return result; } //////////////////////////////////////////////////////////// @@ -2826,217 +2823,217 @@ G_Stats G_QueryStats(void) G_SwapchainHandle G_AcquireSwapchain(u64 os_window_handle) { - G_D12_Swapchain *swapchain = 0; - { - Arena *perm = PermArena(); - swapchain = PushStruct(perm, G_D12_Swapchain); - } - swapchain->window_hwnd = (HWND)os_window_handle; - return G_D12_MakeHandle(G_SwapchainHandle, swapchain); + G_D12_Swapchain *swapchain = 0; + { + Arena *perm = PermArena(); + swapchain = PushStruct(perm, G_D12_Swapchain); + } + swapchain->window_hwnd = (HWND)os_window_handle; + return G_D12_MakeHandle(G_SwapchainHandle, swapchain); } void G_ReleaseSwapchain(G_SwapchainHandle swapchain_handle) { - /* TODO */ + /* TODO */ } G_ResourceHandle G_PrepareBackbuffer(G_SwapchainHandle swapchain_handle, G_Format format, Vec2I32 size) { - G_D12_SharedState *g = &G_D12_shared_state; - G_D12_Swapchain *swapchain = G_D12_SwapchainFromHandle(swapchain_handle); - size = VEC2I32(MaxI32(size.x, 1), MaxI32(size.y, 1)); - G_D12_Queue *direct_queue = G_D12_QueueFromKind(G_QueueKind_Direct); + G_D12_SharedState *g = &G_D12_shared_state; + G_D12_Swapchain *swapchain = G_D12_SwapchainFromHandle(swapchain_handle); + size = VEC2I32(MaxI32(size.x, 1), MaxI32(size.y, 1)); + G_D12_Queue *direct_queue = G_D12_QueueFromKind(G_QueueKind_Direct); - /* Initialize swapchain */ - if (!swapchain->d3d_swapchain) + /* Initialize swapchain */ + if (!swapchain->d3d_swapchain) + { + HRESULT hr = 0; + + /* Create d3d swapchain */ { - HRESULT hr = 0; - - /* Create d3d swapchain */ + IDXGISwapChain3 *swapchain3 = 0; + { + /* Create swapchain1 */ + IDXGISwapChain1 *swapchain1 = 0; + if (SUCCEEDED(hr)) { - IDXGISwapChain3 *swapchain3 = 0; - { - /* Create swapchain1 */ - IDXGISwapChain1 *swapchain1 = 0; - if (SUCCEEDED(hr)) - { - DXGI_SWAP_CHAIN_DESC1 desc = Zi; - desc.Format = G_D12_DxgiFormatFromGpuFormat(format); - desc.Width = size.x; - desc.Height = size.y; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.BufferCount = G_D12_SwapchainBufferCount; - desc.Scaling = DXGI_SCALING_NONE; - desc.Flags = G_D12_SwapchainFlags; - desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; - desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - hr = IDXGIFactory2_CreateSwapChainForHwnd(g->factory, (IUnknown *)direct_queue->d3d_queue, swapchain->window_hwnd, &desc, 0, 0, &swapchain1); - } - - /* Upgrade to swapchain3 */ - if (SUCCEEDED(hr)) - { - hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain3); - IDXGISwapChain1_Release(swapchain1); - } - - - } - swapchain->d3d_swapchain = swapchain3; - swapchain->backbuffers_format = format; - swapchain->backbuffers_resolution = size; + DXGI_SWAP_CHAIN_DESC1 desc = Zi; + desc.Format = G_D12_DxgiFormatFromGpuFormat(format); + desc.Width = size.x; + desc.Height = size.y; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = G_D12_SwapchainBufferCount; + desc.Scaling = DXGI_SCALING_NONE; + desc.Flags = G_D12_SwapchainFlags; + desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + hr = IDXGIFactory2_CreateSwapChainForHwnd(g->factory, (IUnknown *)direct_queue->d3d_queue, swapchain->window_hwnd, &desc, 0, 0, &swapchain1); } - /* Create waitable object */ + /* Upgrade to swapchain3 */ + if (SUCCEEDED(hr)) { - HANDLE waitable = 0; - if (SUCCEEDED(hr) && G_D12_FrameLatency > 0) - { - hr = IDXGISwapChain3_SetMaximumFrameLatency(swapchain->d3d_swapchain, G_D12_FrameLatency); - waitable = IDXGISwapChain2_GetFrameLatencyWaitableObject(swapchain->d3d_swapchain); - } - swapchain->waitable = waitable; + hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain3); + IDXGISwapChain1_Release(swapchain1); } - /* Create present fence */ - { - HANDLE present_event = 0; - ID3D12Fence *present_fence = 0; - if (SUCCEEDED(hr)) - { - present_event = CreateEvent(0, 0, 0, 0); - hr = ID3D12Device_CreateFence(g->device, 0, 0, &IID_ID3D12Fence, (void **)&present_fence); - } - swapchain->present_fence = present_fence; - swapchain->present_event = present_event; - } - /* Disable Alt+Enter */ - IDXGIFactory_MakeWindowAssociation(g->factory, swapchain->window_hwnd, DXGI_MWA_NO_ALT_ENTER); + } + swapchain->d3d_swapchain = swapchain3; + swapchain->backbuffers_format = format; + swapchain->backbuffers_resolution = size; + } + /* Create waitable object */ + { + HANDLE waitable = 0; + if (SUCCEEDED(hr) && G_D12_FrameLatency > 0) + { + hr = IDXGISwapChain3_SetMaximumFrameLatency(swapchain->d3d_swapchain, G_D12_FrameLatency); + waitable = IDXGISwapChain2_GetFrameLatencyWaitableObject(swapchain->d3d_swapchain); + } + swapchain->waitable = waitable; + } + + /* Create present fence */ + { + HANDLE present_event = 0; + ID3D12Fence *present_fence = 0; + if (SUCCEEDED(hr)) + { + present_event = CreateEvent(0, 0, 0, 0); + hr = ID3D12Device_CreateFence(g->device, 0, 0, &IID_ID3D12Fence, (void **)&present_fence); + } + swapchain->present_fence = present_fence; + swapchain->present_event = present_event; + } + + /* Disable Alt+Enter */ + IDXGIFactory_MakeWindowAssociation(g->factory, swapchain->window_hwnd, DXGI_MWA_NO_ALT_ENTER); + + if (FAILED(hr)) + { + Panic(Lit("Failed to create swapchain")); + } + } + + /* Resize backbuffers */ + if (!MatchVec2I32(swapchain->backbuffers_resolution, size) || swapchain->backbuffers_format != format) + { + HRESULT hr = 0; + + /* Wait for any previous backbuffer commands to finish */ + { + ID3D12Fence_SetEventOnCompletion(swapchain->present_fence, swapchain->present_fence_target, swapchain->present_event); + WaitForSingleObject(swapchain->present_event, INFINITE); + } + + /* Release backbuffers */ + for (u32 i = 0; i < countof(swapchain->backbuffers); ++i) + { + G_D12_Resource *backbuffer = &swapchain->backbuffers[i]; + if (backbuffer->d3d_resource) + { + ID3D12Resource_Release(backbuffer->d3d_resource); + backbuffer->d3d_resource = 0; + } + } + + /* Resize buffers */ + hr = IDXGISwapChain_ResizeBuffers(swapchain->d3d_swapchain, 0, size.x, size.y, DXGI_FORMAT_UNKNOWN, G_D12_SwapchainFlags); + if (FAILED(hr)) + { + /* TODO: Don't panic */ + Panic(Lit("Failed to resize swapchain")); + } + } + + /* Initialize backbuffers */ + { + for (u32 i = 0; i < countof(swapchain->backbuffers); ++i) + { + G_D12_Resource *backbuffer = &swapchain->backbuffers[i]; + if (!backbuffer->d3d_resource) + { + ID3D12Resource *d3d_resource = 0; + HRESULT hr = IDXGISwapChain3_GetBuffer(swapchain->d3d_swapchain, i, &IID_ID3D12Resource, (void **)&d3d_resource); if (FAILED(hr)) { - Panic(Lit("Failed to create swapchain")); + /* TODO: Don't panic */ + Panic(Lit("Failed to retrieve swapchain buffer")); } - } + ZeroStruct(backbuffer); + backbuffer->d3d_resource = d3d_resource; + backbuffer->uid = Atomic64FetchAdd(&g->resource_creation_gen.v, 1) + 1; + backbuffer->flags = G_ResourceFlag_AllowRenderTarget; - /* Resize backbuffers */ - if (!MatchVec2I32(swapchain->backbuffers_resolution, size) || swapchain->backbuffers_format != format) + backbuffer->is_texture = 1; + backbuffer->texture_format = format; + backbuffer->texture_dims = VEC3I32(size.x, size.y, 1); + backbuffer->texture_mip_levels = 1; + backbuffer->texture_layout = D3D12_BARRIER_LAYOUT_PRESENT; + backbuffer->swapchain = swapchain; + } + } + swapchain->backbuffers_format = format; + swapchain->backbuffers_resolution = size; + } + + /* Wait for available backbuffer */ + if (swapchain->waitable) + { + DWORD wait_result = WaitForSingleObject(swapchain->waitable, 500); + if (wait_result == WAIT_TIMEOUT) { - HRESULT hr = 0; - - /* Wait for any previous backbuffer commands to finish */ - { - ID3D12Fence_SetEventOnCompletion(swapchain->present_fence, swapchain->present_fence_target, swapchain->present_event); - WaitForSingleObject(swapchain->present_event, INFINITE); - } - - /* Release backbuffers */ - for (u32 i = 0; i < countof(swapchain->backbuffers); ++i) - { - G_D12_Resource *backbuffer = &swapchain->backbuffers[i]; - if (backbuffer->d3d_resource) - { - ID3D12Resource_Release(backbuffer->d3d_resource); - backbuffer->d3d_resource = 0; - } - } - - /* Resize buffers */ - hr = IDXGISwapChain_ResizeBuffers(swapchain->d3d_swapchain, 0, size.x, size.y, DXGI_FORMAT_UNKNOWN, G_D12_SwapchainFlags); - if (FAILED(hr)) - { - /* TODO: Don't panic */ - Panic(Lit("Failed to resize swapchain")); - } + ID3D12Fence_SetEventOnCompletion(swapchain->present_fence, swapchain->present_fence_target, swapchain->present_event); + WaitForSingleObject(swapchain->present_event, INFINITE); } + } - /* Initialize backbuffers */ - { - for (u32 i = 0; i < countof(swapchain->backbuffers); ++i) - { - G_D12_Resource *backbuffer = &swapchain->backbuffers[i]; - if (!backbuffer->d3d_resource) - { - ID3D12Resource *d3d_resource = 0; - HRESULT hr = IDXGISwapChain3_GetBuffer(swapchain->d3d_swapchain, i, &IID_ID3D12Resource, (void **)&d3d_resource); - if (FAILED(hr)) - { - /* TODO: Don't panic */ - Panic(Lit("Failed to retrieve swapchain buffer")); - } - ZeroStruct(backbuffer); - backbuffer->d3d_resource = d3d_resource; - backbuffer->uid = Atomic64FetchAdd(&g->resource_creation_gen.v, 1) + 1; - backbuffer->flags = G_ResourceFlag_AllowRenderTarget; + /* Grab current backbuffer */ + G_D12_Resource *cur_backbuffer = 0; + { + u32 backbuffer_idx = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain->d3d_swapchain); + cur_backbuffer = &swapchain->backbuffers[backbuffer_idx]; + } - backbuffer->is_texture = 1; - backbuffer->texture_format = format; - backbuffer->texture_dims = VEC3I32(size.x, size.y, 1); - backbuffer->texture_mip_levels = 1; - backbuffer->texture_layout = D3D12_BARRIER_LAYOUT_PRESENT; - backbuffer->swapchain = swapchain; - } - } - swapchain->backbuffers_format = format; - swapchain->backbuffers_resolution = size; - } - - /* Wait for available backbuffer */ - if (swapchain->waitable) - { - DWORD wait_result = WaitForSingleObject(swapchain->waitable, 500); - if (wait_result == WAIT_TIMEOUT) - { - ID3D12Fence_SetEventOnCompletion(swapchain->present_fence, swapchain->present_fence_target, swapchain->present_event); - WaitForSingleObject(swapchain->present_event, INFINITE); - } - } - - /* Grab current backbuffer */ - G_D12_Resource *cur_backbuffer = 0; - { - u32 backbuffer_idx = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain->d3d_swapchain); - cur_backbuffer = &swapchain->backbuffers[backbuffer_idx]; - } - - return G_D12_MakeHandle(G_ResourceHandle, cur_backbuffer); + return G_D12_MakeHandle(G_ResourceHandle, cur_backbuffer); } void G_CommitBackbuffer(G_ResourceHandle backbuffer_handle, i32 vsync) { - G_D12_Resource *backbuffer = G_D12_ResourceFromHandle(backbuffer_handle); - G_D12_Swapchain *swapchain = backbuffer->swapchain; - G_D12_Queue *direct_queue = G_D12_QueueFromKind(G_QueueKind_Direct); + G_D12_Resource *backbuffer = G_D12_ResourceFromHandle(backbuffer_handle); + G_D12_Swapchain *swapchain = backbuffer->swapchain; + G_D12_Queue *direct_queue = G_D12_QueueFromKind(G_QueueKind_Direct); - u32 present_flags = 0; - if (G_D12_TearingIsAllowed && vsync == 0) - { - present_flags |= DXGI_PRESENT_ALLOW_TEARING; - } + u32 present_flags = 0; + if (G_D12_TearingIsAllowed && vsync == 0) + { + present_flags |= DXGI_PRESENT_ALLOW_TEARING; + } - /* Present */ + /* Present */ + { + HRESULT hr = IDXGISwapChain3_Present(swapchain->d3d_swapchain, vsync, present_flags); + if (!SUCCEEDED(hr)) { - HRESULT hr = IDXGISwapChain3_Present(swapchain->d3d_swapchain, vsync, present_flags); - if (!SUCCEEDED(hr)) - { - Assert(0); - } + Assert(0); } + } - if (vsync != 0 && !(present_flags & DXGI_PRESENT_ALLOW_TEARING)) - { - /* FIXME: Flush in windowed mode? */ - // DwmFlush(); - } + if (vsync != 0 && !(present_flags & DXGI_PRESENT_ALLOW_TEARING)) + { + /* FIXME: Flush in windowed mode? */ + // DwmFlush(); + } - /* Increment swapchain fence */ - { - u64 target = ++swapchain->present_fence_target; - ID3D12CommandQueue_Signal(direct_queue->d3d_queue, swapchain->present_fence, target); - } + /* Increment swapchain fence */ + { + u64 target = ++swapchain->present_fence_target; + ID3D12CommandQueue_Signal(direct_queue->d3d_queue, swapchain->present_fence, target); + } } //////////////////////////////////////////////////////////// @@ -3046,201 +3043,201 @@ void G_CommitBackbuffer(G_ResourceHandle backbuffer_handle, i32 vsync) void G_D12_CollectionWorkerEntryPoint(WaveLaneCtx *lane) { - for (;;) + for (;;) + { + /* FIXME: Remove this */ + SleepSeconds(0.100); + + + + + /* Copy print-buffers to readback */ + for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) { - /* FIXME: Remove this */ - SleepSeconds(0.100); - - - - - /* Copy print-buffers to readback */ - for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) + G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); + if (!G_IsResourceNil(queue->print_buffer)) + { + G_CommandListHandle cl = G_PrepareCommandList(queue_kind); { - G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); - if (!G_IsResourceNil(queue->print_buffer)) - { - G_CommandListHandle cl = G_PrepareCommandList(queue_kind); - { - /* Copy print buffer to readback buffer */ - G_CopyBufferToBuffer(cl, queue->print_readback_buffer, 0, queue->print_buffer, RNGU64(0, queue->print_buffer_size)); - /* Reset counters to 0 */ - G_MemorySync( - cl, queue->print_buffer, - G_Stage_Copy, G_Access_CopyRead, - G_Stage_Copy, G_Access_CopyWrite - ); - u8 zero[12] = Zi; - G_CopyCpuToBuffer(cl, queue->print_buffer, 0, zero, RNGU64(0, sizeof(zero))); - } - G_CommitCommandList(cl); - } - } - - /* TODO: Collect asynchronously */ - G_SyncCpu(G_QueueMask_Direct | G_QueueMask_AsyncCompute); - - for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) - { - G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); - if (!G_IsResourceNil(queue->print_buffer)) - { - u32 attempted_print_bytes_count = *(G_StructFromResource(queue->print_readback_buffer, u32) + 0); /* The number of bytes shaders attempted to write */ - u32 prints_count = *(G_StructFromResource(queue->print_readback_buffer, u32) + 1); /* The number of shader prints that are in the buffer */ - u32 overflows_count = *(G_StructFromResource(queue->print_readback_buffer, u32) + 2); /* The number of shader prints that could not fit in the buffer */ - u8 *start = G_StructFromResource(queue->print_readback_buffer, u8) + 12; - - /* Deserialize */ - if (GPU_SHADER_PRINT_LOG) - { - if (prints_count > 0) - { - LogDebugF( - "Forwarding logs collected from GPU - Resident prints: %F, Total attempted prints: %F, Total attempted bytes: %F", - FmtUint(prints_count), - FmtUint(prints_count + overflows_count), - FmtUint(attempted_print_bytes_count) - ); - } - - /* FIXME: Remove this */ - TempArena scratch = BeginScratchNoConflict(); - u8 *at = start; - { - for (u32 print_idx = 0; print_idx < prints_count; ++print_idx) - { - u32 chars_count = 0; - u32 args_count = 0; - b32 internal_overflow = 0; - { - u32 header = *(u32 *)at; - chars_count = (header & 0x0000FFFF) >> 0; - args_count = (header & 0x7FFF0000) >> 16; - internal_overflow = (header & 0xF0000000) >> 31; - at += 4; - } - - String fmt = Zi; - { - fmt.len = chars_count; - fmt.text = at; - at += chars_count; - } - - FmtArgArray args = Zi; - args.count = args_count; - { - if (args_count > 0) - { - args.args = PushStructs(scratch.arena, FmtArg, args_count); - for (u32 arg_idx = 0; arg_idx < args_count; ++arg_idx) - { - G_FmtArgKind gpu_kind = (G_FmtArgKind)(*at); - at += 1; - - FmtArg *dst = &args.args[arg_idx]; - switch (gpu_kind) - { - - /* Translate unsigned integer args */ - case G_FmtArgKind_Uint: - { - u32 gpu_value = *(u32 *)at; - *dst = FmtUint(gpu_value); - at += 4; - } break; - case G_FmtArgKind_Uint2: - { - Vec2U32 gpu_value = *(Vec2U32 *)at; - *dst = FmtUint2(gpu_value); - at += 8; - } break; - case G_FmtArgKind_Uint3: - { - Vec3U32 gpu_value = *(Vec3U32 *)at; - *dst = FmtUint3(gpu_value); - at += 12; - } break; - case G_FmtArgKind_Uint4: - { - Vec4U32 gpu_value = *(Vec4U32 *)at; - *dst = FmtUint4(gpu_value); - at += 16; - } break; - - /* Translate signed integer args */ - case G_FmtArgKind_Sint: - { - i32 gpu_value = *(i32 *)at; - *dst = FmtSint(gpu_value); - at += 4; - } break; - case G_FmtArgKind_Sint2: - { - Vec2I32 gpu_value = *(Vec2I32 *)at; - *dst = FmtSint2(gpu_value); - at += 8; - } break; - case G_FmtArgKind_Sint3: - { - Vec3I32 gpu_value = *(Vec3I32 *)at; - *dst = FmtSint3(gpu_value); - at += 12; - } break; - case G_FmtArgKind_Sint4: - { - Vec4I32 gpu_value = *(Vec4I32 *)at; - *dst = FmtSint4(gpu_value); - at += 16; - } break; - - /* Translate float args */ - case G_FmtArgKind_Float: - { - f32 gpu_value = *(f32 *)at; - *dst = FmtFloat(gpu_value); - at += 4; - } break; - case G_FmtArgKind_Float2: - { - Vec2 gpu_value = *(Vec2 *)at; - *dst = FmtFloat2(gpu_value); - at += 8; - } break; - case G_FmtArgKind_Float3: - { - Vec3 gpu_value = *(Vec3 *)at; - *dst = FmtFloat3(gpu_value); - at += 12; - } break; - case G_FmtArgKind_Float4: - { - Vec4 gpu_value = *(Vec4 *)at; - *dst = FmtFloat4(gpu_value); - at += 16; - } break; - } - } - } - } - - String final_str = Zi; - if (internal_overflow) - { - final_str = Lit("[Shader PrintF is too large]"); - } - else - { - final_str = FormatString(scratch.arena, fmt, args); - } - LogDebug(final_str); - - at = (u8 *)AlignU64((u64)at, 4); - } - } - EndScratch(scratch); - } - } + /* Copy print buffer to readback buffer */ + G_CopyBufferToBuffer(cl, queue->print_readback_buffer, 0, queue->print_buffer, RNGU64(0, queue->print_buffer_size)); + /* Reset counters to 0 */ + G_MemorySync( + cl, queue->print_buffer, + G_Stage_Copy, G_Access_CopyRead, + G_Stage_Copy, G_Access_CopyWrite + ); + u8 zero[12] = Zi; + G_CopyCpuToBuffer(cl, queue->print_buffer, 0, zero, RNGU64(0, sizeof(zero))); } + G_CommitCommandList(cl); + } } + + /* TODO: Collect asynchronously */ + G_SyncCpu(G_QueueMask_Direct | G_QueueMask_AsyncCompute); + + for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) + { + G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); + if (!G_IsResourceNil(queue->print_buffer)) + { + u32 attempted_print_bytes_count = *(G_StructFromResource(queue->print_readback_buffer, u32) + 0); /* The number of bytes shaders attempted to write */ + u32 prints_count = *(G_StructFromResource(queue->print_readback_buffer, u32) + 1); /* The number of shader prints that are in the buffer */ + u32 overflows_count = *(G_StructFromResource(queue->print_readback_buffer, u32) + 2); /* The number of shader prints that could not fit in the buffer */ + u8 *start = G_StructFromResource(queue->print_readback_buffer, u8) + 12; + + /* Deserialize */ + if (GPU_SHADER_PRINT_LOG) + { + if (prints_count > 0) + { + LogDebugF( + "Forwarding logs collected from GPU - Resident prints: %F, Total attempted prints: %F, Total attempted bytes: %F", + FmtUint(prints_count), + FmtUint(prints_count + overflows_count), + FmtUint(attempted_print_bytes_count) + ); + } + + /* FIXME: Remove this */ + TempArena scratch = BeginScratchNoConflict(); + u8 *at = start; + { + for (u32 print_idx = 0; print_idx < prints_count; ++print_idx) + { + u32 chars_count = 0; + u32 args_count = 0; + b32 internal_overflow = 0; + { + u32 header = *(u32 *)at; + chars_count = (header & 0x0000FFFF) >> 0; + args_count = (header & 0x7FFF0000) >> 16; + internal_overflow = (header & 0xF0000000) >> 31; + at += 4; + } + + String fmt = Zi; + { + fmt.len = chars_count; + fmt.text = at; + at += chars_count; + } + + FmtArgArray args = Zi; + args.count = args_count; + { + if (args_count > 0) + { + args.args = PushStructs(scratch.arena, FmtArg, args_count); + for (u32 arg_idx = 0; arg_idx < args_count; ++arg_idx) + { + G_FmtArgKind gpu_kind = (G_FmtArgKind)(*at); + at += 1; + + FmtArg *dst = &args.args[arg_idx]; + switch (gpu_kind) + { + + /* Translate unsigned integer args */ + case G_FmtArgKind_Uint: + { + u32 gpu_value = *(u32 *)at; + *dst = FmtUint(gpu_value); + at += 4; + } break; + case G_FmtArgKind_Uint2: + { + Vec2U32 gpu_value = *(Vec2U32 *)at; + *dst = FmtUint2(gpu_value); + at += 8; + } break; + case G_FmtArgKind_Uint3: + { + Vec3U32 gpu_value = *(Vec3U32 *)at; + *dst = FmtUint3(gpu_value); + at += 12; + } break; + case G_FmtArgKind_Uint4: + { + Vec4U32 gpu_value = *(Vec4U32 *)at; + *dst = FmtUint4(gpu_value); + at += 16; + } break; + + /* Translate signed integer args */ + case G_FmtArgKind_Sint: + { + i32 gpu_value = *(i32 *)at; + *dst = FmtSint(gpu_value); + at += 4; + } break; + case G_FmtArgKind_Sint2: + { + Vec2I32 gpu_value = *(Vec2I32 *)at; + *dst = FmtSint2(gpu_value); + at += 8; + } break; + case G_FmtArgKind_Sint3: + { + Vec3I32 gpu_value = *(Vec3I32 *)at; + *dst = FmtSint3(gpu_value); + at += 12; + } break; + case G_FmtArgKind_Sint4: + { + Vec4I32 gpu_value = *(Vec4I32 *)at; + *dst = FmtSint4(gpu_value); + at += 16; + } break; + + /* Translate float args */ + case G_FmtArgKind_Float: + { + f32 gpu_value = *(f32 *)at; + *dst = FmtFloat(gpu_value); + at += 4; + } break; + case G_FmtArgKind_Float2: + { + Vec2 gpu_value = *(Vec2 *)at; + *dst = FmtFloat2(gpu_value); + at += 8; + } break; + case G_FmtArgKind_Float3: + { + Vec3 gpu_value = *(Vec3 *)at; + *dst = FmtFloat3(gpu_value); + at += 12; + } break; + case G_FmtArgKind_Float4: + { + Vec4 gpu_value = *(Vec4 *)at; + *dst = FmtFloat4(gpu_value); + at += 16; + } break; + } + } + } + } + + String final_str = Zi; + if (internal_overflow) + { + final_str = Lit("[Shader PrintF is too large]"); + } + else + { + final_str = FormatString(scratch.arena, fmt, args); + } + LogDebug(final_str); + + at = (u8 *)AlignU64((u64)at, 4); + } + } + EndScratch(scratch); + } + } + } + } } diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.h b/src/gpu/gpu_dx12/gpu_dx12_core.h index 9ea5fc9d..05db1c37 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.h +++ b/src/gpu/gpu_dx12/gpu_dx12_core.h @@ -2,9 +2,9 @@ //~ DirectX12 libs #pragma warning(push, 0) -# include -# include -# include + #include + #include + #include #pragma warning(pop) #pragma comment(lib, "d3d12") @@ -16,9 +16,10 @@ #define G_D12_TearingIsAllowed 1 #define G_D12_FrameLatency 1 #define G_D12_SwapchainBufferCount 3 -#define G_D12_SwapchainFlags (((G_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) \ - | ((G_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)) - +#define G_D12_SwapchainFlags (0 \ + | ((G_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) \ + | ((G_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) \ + ) #define G_D12_MaxCbvSrvUavDescriptors (1024 * 128) #define G_D12_MaxSamplerDescriptors (1024 * 1) @@ -29,30 +30,30 @@ Struct(G_D12_PipelineDesc) { - VertexShader vs; - PixelShader ps; - ComputeShader cs; - b32 is_wireframe; - D3D12_PRIMITIVE_TOPOLOGY_TYPE topology_type; - G_Format render_target_formats[G_MaxRenderTargets]; + VertexShader vs; + PixelShader ps; + ComputeShader cs; + b32 is_wireframe; + D3D12_PRIMITIVE_TOPOLOGY_TYPE topology_type; + G_Format render_target_formats[G_MaxRenderTargets]; }; Struct(G_D12_Pipeline) { - G_D12_Pipeline *next_in_bin; - u64 hash; + G_D12_Pipeline *next_in_bin; + u64 hash; - G_D12_PipelineDesc desc; - ID3D12PipelineState *pso; + G_D12_PipelineDesc desc; + ID3D12PipelineState *pso; - b32 ok; - String error; + b32 ok; + String error; }; Struct(G_D12_PipelineBin) { - Mutex mutex; - G_D12_Pipeline *first; + Mutex mutex; + G_D12_Pipeline *first; }; //////////////////////////////////////////////////////////// @@ -60,40 +61,40 @@ Struct(G_D12_PipelineBin) Struct(G_D12_Resource) { - G_D12_Resource *next; + G_D12_Resource *next; - struct G_D12_ResourceHeap *heap; - u64 pos_in_heap; - u64 size_in_heap; + struct G_D12_ResourceHeap *heap; + u64 pos_in_heap; + u64 size_in_heap; - ID3D12Resource *d3d_resource; - u64 uid; - G_ResourceFlag flags; + ID3D12Resource *d3d_resource; + u64 uid; + G_ResourceFlag flags; - /* Buffer info */ - u64 buffer_size; - u64 buffer_size_actual; - D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address; + /* Buffer info */ + u64 buffer_size; + u64 buffer_size_actual; + D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address; - /* Texture info */ - b32 is_texture; - G_Format texture_format; - Vec3I32 texture_dims; - i32 texture_mip_levels; - D3D12_BARRIER_LAYOUT texture_layout; + /* Texture info */ + b32 is_texture; + G_Format texture_format; + Vec3I32 texture_dims; + i32 texture_mip_levels; + D3D12_BARRIER_LAYOUT texture_layout; - /* Sampler info */ - G_SamplerDesc sampler_desc; + /* Sampler info */ + G_SamplerDesc sampler_desc; - /* Backbuffer info */ - struct G_D12_Swapchain *swapchain; + /* Backbuffer info */ + struct G_D12_Swapchain *swapchain; }; Struct(G_D12_ResourceList) { - u64 count; - G_D12_Resource *first; - G_D12_Resource *last; + u64 count; + G_D12_Resource *first; + G_D12_Resource *last; }; //////////////////////////////////////////////////////////// @@ -101,46 +102,46 @@ Struct(G_D12_ResourceList) Enum(G_D12_DescriptorHeapKind) { - G_D12_DescriptorHeapKind_CbvSrvUav, - G_D12_DescriptorHeapKind_Rtv, - G_D12_DescriptorHeapKind_Sampler, + G_D12_DescriptorHeapKind_CbvSrvUav, + G_D12_DescriptorHeapKind_Rtv, + G_D12_DescriptorHeapKind_Sampler, - G_D12_DescriptorHeapKind_Count + G_D12_DescriptorHeapKind_Count }; Struct(G_D12_DescriptorHeap) { - Arena *descriptors_arena; - G_D12_DescriptorHeapKind kind; + Arena *descriptors_arena; + G_D12_DescriptorHeapKind kind; - D3D12_DESCRIPTOR_HEAP_TYPE type; - u32 descriptor_size; - ID3D12DescriptorHeap *d3d_heap; - D3D12_CPU_DESCRIPTOR_HANDLE start_handle; + D3D12_DESCRIPTOR_HEAP_TYPE type; + u32 descriptor_size; + ID3D12DescriptorHeap *d3d_heap; + D3D12_CPU_DESCRIPTOR_HANDLE start_handle; - Mutex mutex; - struct G_D12_Descriptor *first_free; - u32 max_count; + Mutex mutex; + struct G_D12_Descriptor *first_free; + u32 max_count; }; Struct(G_D12_Descriptor) { - G_D12_Descriptor *next; + G_D12_Descriptor *next; - struct G_D12_Arena *gpu_arena; - G_QueueKind completion_queue_kind; - i64 completion_queue_target; + struct G_D12_Arena *gpu_arena; + G_QueueKind completion_queue_kind; + i64 completion_queue_target; - G_D12_DescriptorHeap *heap; - D3D12_CPU_DESCRIPTOR_HANDLE handle; - u32 index; + G_D12_DescriptorHeap *heap; + D3D12_CPU_DESCRIPTOR_HANDLE handle; + u32 index; }; Struct(G_D12_DescriptorList) { - u64 count; - G_D12_Descriptor *first; - G_D12_Descriptor *last; + u64 count; + G_D12_Descriptor *first; + G_D12_Descriptor *last; }; //////////////////////////////////////////////////////////// @@ -154,40 +155,40 @@ Struct(G_D12_DescriptorList) */ Enum(G_D12_ResourceHeapKind) { - G_D12_ResourceHeapKind_Gpu, - G_D12_ResourceHeapKind_Cpu, - G_D12_ResourceHeapKind_CpuWriteCombined, + G_D12_ResourceHeapKind_Gpu, + G_D12_ResourceHeapKind_Cpu, + G_D12_ResourceHeapKind_CpuWriteCombined, - G_D12_ResourceHeapKind_Count, + G_D12_ResourceHeapKind_Count, }; Struct(G_D12_ResourceHeap) { - G_D12_ResourceHeapKind kind; + G_D12_ResourceHeapKind kind; - struct GPU_D12_Arena *gpu_arena; + struct GPU_D12_Arena *gpu_arena; - ID3D12Heap *d3d_heap; - ID3D12Resource *d3d_mapped_resource; - void *mapped; + ID3D12Heap *d3d_heap; + ID3D12Resource *d3d_mapped_resource; + void *mapped; - G_D12_ResourceList resources; - G_D12_ResourceList reset_resources; + G_D12_ResourceList resources; + G_D12_ResourceList reset_resources; - u64 pos; - u64 size; + u64 pos; + u64 size; }; Struct(G_D12_Arena) { - Arena *arena; + Arena *arena; - G_D12_DescriptorList descriptors; - G_D12_DescriptorList reset_descriptors_by_heap[G_D12_DescriptorHeapKind_Count]; + G_D12_DescriptorList descriptors; + G_D12_DescriptorList reset_descriptors_by_heap[G_D12_DescriptorHeapKind_Count]; - G_D12_ResourceList free_resources; + G_D12_ResourceList free_resources; - G_D12_ResourceHeap resource_heaps[G_D12_ResourceHeapKind_Count]; + G_D12_ResourceHeap resource_heaps[G_D12_ResourceHeapKind_Count]; }; //////////////////////////////////////////////////////////// @@ -195,32 +196,32 @@ Struct(G_D12_Arena) Struct(G_D12_StagingRing) { - Arena *arena; - G_D12_Arena *gpu_arena; - u64 size; + Arena *arena; + G_D12_Arena *gpu_arena; + u64 size; - G_D12_Resource *resource; - u8 *base; + G_D12_Resource *resource; + u8 *base; - struct G_D12_StagingRegionNode *head_region_node; - struct G_D12_StagingRegionNode *first_free_region_node; + struct G_D12_StagingRegionNode *head_region_node; + struct G_D12_StagingRegionNode *first_free_region_node; }; Struct(G_D12_StagingRegionNode) { - G_D12_StagingRing *ring; + G_D12_StagingRing *ring; - /* Ring links (requires ring lock to read) */ - G_D12_StagingRegionNode *prev; - G_D12_StagingRegionNode *next; + /* Ring links (requires ring lock to read) */ + G_D12_StagingRegionNode *prev; + G_D12_StagingRegionNode *next; - /* Command list links */ - G_D12_StagingRegionNode *next_in_command_list; + /* Command list links */ + G_D12_StagingRegionNode *next_in_command_list; - /* Region info */ - Atomic64 completion_target; - u64 pos; + /* Region info */ + Atomic64 completion_target; + u64 pos; }; //////////////////////////////////////////////////////////// @@ -228,34 +229,34 @@ Struct(G_D12_StagingRegionNode) Struct(G_D12_CommandQueueDesc) { - D3D12_COMMAND_LIST_TYPE type; - D3D12_COMMAND_QUEUE_PRIORITY priority; + D3D12_COMMAND_LIST_TYPE type; + D3D12_COMMAND_QUEUE_PRIORITY priority; }; Struct(G_D12_Queue) { - ID3D12CommandQueue *d3d_queue; - G_D12_CommandQueueDesc desc; + ID3D12CommandQueue *d3d_queue; + G_D12_CommandQueueDesc desc; - Mutex commit_mutex; - ID3D12Fence *commit_fence; - u64 commit_fence_target; + Mutex commit_mutex; + ID3D12Fence *commit_fence; + u64 commit_fence_target; - /* Global resources */ - u64 print_buffer_size; - G_ResourceHandle print_buffer; - G_ResourceHandle print_readback_buffer; - G_RWByteAddressBufferRef print_buffer_ref; + /* Global resources */ + u64 print_buffer_size; + G_ResourceHandle print_buffer; + G_ResourceHandle print_readback_buffer; + G_RWByteAddressBufferRef print_buffer_ref; - /* Raw command lists */ - struct G_D12_RawCommandList *first_committed_cl; - struct G_D12_RawCommandList *last_committed_cl; + /* Raw command lists */ + struct G_D12_RawCommandList *first_committed_cl; + struct G_D12_RawCommandList *last_committed_cl; - /* Staging heap */ - Mutex staging_mutex; - G_D12_StagingRing *staging_ring; + /* Staging heap */ + Mutex staging_mutex; + G_D12_StagingRing *staging_ring; - Fence sync_fence; + Fence sync_fence; }; //////////////////////////////////////////////////////////// @@ -263,17 +264,17 @@ Struct(G_D12_Queue) Struct(G_D12_RawCommandList) { - G_D12_Queue *queue; - G_D12_RawCommandList *next; + G_D12_Queue *queue; + G_D12_RawCommandList *next; - u64 commit_fence_target; + u64 commit_fence_target; - ID3D12CommandAllocator *d3d_ca; - ID3D12GraphicsCommandList7 *d3d_cl; + ID3D12CommandAllocator *d3d_ca; + ID3D12GraphicsCommandList7 *d3d_cl; - /* Direct queue command lists keep a constant list of CPU-only descriptors */ - G_D12_Descriptor *rtv_descriptors[G_MaxRenderTargets]; - G_D12_Descriptor *rtv_clear_descriptor; + /* Direct queue command lists keep a constant list of CPU-only descriptors */ + G_D12_Descriptor *rtv_descriptors[G_MaxRenderTargets]; + G_D12_Descriptor *rtv_clear_descriptor; }; //////////////////////////////////////////////////////////// @@ -283,108 +284,108 @@ Struct(G_D12_RawCommandList) Enum(G_D12_CmdKind) { - G_D12_CmdKind_None, - G_D12_CmdKind_Barrier, - G_D12_CmdKind_Constant, - G_D12_CmdKind_CopyBytes, - G_D12_CmdKind_CopyTexels, - G_D12_CmdKind_Compute, - G_D12_CmdKind_Rasterize, - G_D12_CmdKind_ClearRtv, - G_D12_CmdKind_DiscardRtv, + G_D12_CmdKind_None, + G_D12_CmdKind_Barrier, + G_D12_CmdKind_Constant, + G_D12_CmdKind_CopyBytes, + G_D12_CmdKind_CopyTexels, + G_D12_CmdKind_Compute, + G_D12_CmdKind_Rasterize, + G_D12_CmdKind_ClearRtv, + G_D12_CmdKind_DiscardRtv, }; Struct(G_D12_Cmd) { - G_D12_CmdKind kind; - b32 skip; - union + G_D12_CmdKind kind; + b32 skip; + union + { + struct { - struct - { - i32 slot; - u32 value; - } constant; + i32 slot; + u32 value; + } constant; - struct - { - G_MemoryBarrierDesc desc; + struct + { + G_MemoryBarrierDesc desc; - /* Post-batch data */ - b32 is_end_of_batch; - u64 batch_gen; - } barrier; + /* Post-batch data */ + b32 is_end_of_batch; + u64 batch_gen; + } barrier; - struct - { - G_D12_Resource *dst; - G_D12_Resource *src; - u64 dst_offset; - RngU64 src_range; - } copy_bytes; + struct + { + G_D12_Resource *dst; + G_D12_Resource *src; + u64 dst_offset; + RngU64 src_range; + } copy_bytes; - struct - { - G_D12_Resource *dst; - G_D12_Resource *src; - D3D12_TEXTURE_COPY_LOCATION dst_loc; - D3D12_TEXTURE_COPY_LOCATION src_loc; - Vec3I32 dst_texture_offset; - Rng3I32 src_texture_range; - } copy_texels; + struct + { + G_D12_Resource *dst; + G_D12_Resource *src; + D3D12_TEXTURE_COPY_LOCATION dst_loc; + D3D12_TEXTURE_COPY_LOCATION src_loc; + Vec3I32 dst_texture_offset; + Rng3I32 src_texture_range; + } copy_texels; - struct - { - ComputeShader cs; - Vec3I32 groups; - } compute; + struct + { + ComputeShader cs; + Vec3I32 groups; + } compute; - struct - { - VertexShader vs; - PixelShader ps; - u32 instances_count; - G_IndexBufferDesc index_buffer_desc; - G_D12_Resource *render_targets[G_MaxRenderTargets]; - Rng3 viewport; - Rng2 scissor; - G_RasterMode mode; - } rasterize; + struct + { + VertexShader vs; + PixelShader ps; + u32 instances_count; + G_IndexBufferDesc index_buffer_desc; + G_D12_Resource *render_targets[G_MaxRenderTargets]; + Rng3 viewport; + Rng2 scissor; + G_RasterMode mode; + } rasterize; - struct - { - G_D12_Resource *render_target; - Vec4 color; - } clear_rtv; + struct + { + G_D12_Resource *render_target; + Vec4 color; + } clear_rtv; - struct - { - G_D12_Resource *render_target; - } discard_rtv; - }; + struct + { + G_D12_Resource *render_target; + } discard_rtv; + }; }; Struct(G_D12_CmdChunk) { - G_D12_CmdChunk *next; - struct G_D12_CmdList *cl; - G_D12_Cmd *cmds; - u64 cmds_count; + G_D12_CmdChunk *next; + struct G_D12_CmdList *cl; + G_D12_Cmd *cmds; + u64 cmds_count; }; Struct(G_D12_CmdList) { - G_D12_CmdList *next; - G_QueueKind queue_kind; + G_D12_CmdList *next; + G_QueueKind queue_kind; - G_D12_DescriptorList reset_descriptors; - G_D12_StagingRegionNode *first_staging_region; - G_D12_StagingRegionNode *last_staging_region; + G_D12_DescriptorList reset_descriptors; + G_D12_StagingRegionNode *first_staging_region; + G_D12_StagingRegionNode *last_staging_region; - G_D12_CmdChunk *first_cmd_chunk; - G_D12_CmdChunk *last_cmd_chunk; - u64 chunks_count; - u64 cmds_count; + G_D12_CmdChunk *first_cmd_chunk; + G_D12_CmdChunk *last_cmd_chunk; + u64 chunks_count; + u64 cmds_count; }; //////////////////////////////////////////////////////////// @@ -393,17 +394,17 @@ Struct(G_D12_CmdList) Struct(G_D12_Swapchain) { - IDXGISwapChain3 *d3d_swapchain; - HWND window_hwnd; - HANDLE waitable; + IDXGISwapChain3 *d3d_swapchain; + HWND window_hwnd; + HANDLE waitable; - HANDLE present_event; - ID3D12Fence *present_fence; - u64 present_fence_target; + HANDLE present_event; + ID3D12Fence *present_fence; + u64 present_fence_target; - G_Format backbuffers_format; - Vec2I32 backbuffers_resolution; - G_D12_Resource backbuffers[G_D12_SwapchainBufferCount]; + G_Format backbuffers_format; + Vec2I32 backbuffers_resolution; + G_D12_Resource backbuffers[G_D12_SwapchainBufferCount]; }; //////////////////////////////////////////////////////////// @@ -411,45 +412,45 @@ Struct(G_D12_Swapchain) Struct(G_D12_SharedState) { - Atomic64Padded resource_creation_gen; + Atomic64Padded resource_creation_gen; - /* Stats */ - Atomic64 driver_resources_allocated; - Atomic64 driver_descriptors_allocated; + /* Stats */ + Atomic64 driver_resources_allocated; + Atomic64 driver_descriptors_allocated; - /* Queues */ - G_D12_Queue queues[G_NumQueues]; + /* Queues */ + G_D12_Queue queues[G_NumQueues]; - /* Descriptor heaps */ - G_D12_DescriptorHeap descriptor_heaps[G_D12_DescriptorHeapKind_Count]; + /* Descriptor heaps */ + G_D12_DescriptorHeap descriptor_heaps[G_D12_DescriptorHeapKind_Count]; - /* Rootsig */ - ID3D12RootSignature *bindless_rootsig; + /* Rootsig */ + ID3D12RootSignature *bindless_rootsig; - /* Pipelines */ - G_D12_PipelineBin pipeline_bins[1024]; + /* Pipelines */ + G_D12_PipelineBin pipeline_bins[1024]; - /* Command lists */ - Mutex free_cmd_lists_mutex; - G_D12_CmdList *first_free_cmd_list; + /* Command lists */ + Mutex free_cmd_lists_mutex; + G_D12_CmdList *first_free_cmd_list; - /* Command chunks */ - Mutex free_cmd_chunks_mutex; - G_D12_CmdChunk *first_free_cmd_chunk; + /* Command chunks */ + Mutex free_cmd_chunks_mutex; + G_D12_CmdChunk *first_free_cmd_chunk; - /* Swapchains */ - Mutex free_swapchains_mutex; - G_D12_Swapchain *first_free_swapchain; + /* Swapchains */ + Mutex free_swapchains_mutex; + G_D12_Swapchain *first_free_swapchain; - /* Device */ - IDXGIFactory6 *factory; - IDXGIAdapter3 *adapter; - ID3D12Device10 *device; + /* Device */ + IDXGIFactory6 *factory; + IDXGIAdapter3 *adapter; + ID3D12Device10 *device; } extern G_D12_shared_state; Struct(G_D12_ThreadLocalState) { - HANDLE sync_event; + HANDLE sync_event; } extern ThreadLocal G_D12_tl; //////////////////////////////////////////////////////////// diff --git a/src/gpu/gpu_shader_core.cgh b/src/gpu/gpu_shader_core.cgh index 42c38264..d9195491 100644 --- a/src/gpu/gpu_shader_core.cgh +++ b/src/gpu/gpu_shader_core.cgh @@ -3,17 +3,17 @@ Enum(G_RefKind) { - G_RefKind_StructuredBuffer, - G_RefKind_RWStructuredBuffer, - G_RefKind_ByteAddressBuffer, - G_RefKind_RWByteAddressBuffer, - G_RefKind_Texture1D, - G_RefKind_RWTexture1D, - G_RefKind_Texture2D, - G_RefKind_RWTexture2D, - G_RefKind_Texture3D, - G_RefKind_RWTexture3D, - G_RefKind_SamplerState, + G_RefKind_StructuredBuffer, + G_RefKind_RWStructuredBuffer, + G_RefKind_ByteAddressBuffer, + G_RefKind_RWByteAddressBuffer, + G_RefKind_Texture1D, + G_RefKind_RWTexture1D, + G_RefKind_Texture2D, + G_RefKind_RWTexture2D, + G_RefKind_Texture3D, + G_RefKind_RWTexture3D, + G_RefKind_SamplerState, }; Struct(G_StructuredBufferRef) { u32 v; }; @@ -43,56 +43,56 @@ Struct(G_SamplerStateRef) { u32 v; }; #define G_NumConstants (G_NumGeneralPurposeConstants + G_NumReservedConstants) #if IsLanguageC - #define G_ForceDeclConstant(type, name, slot) \ - Enum(name##__shaderconstantenum) { name = slot }; \ - Struct(name##__shaderconstanttype) { type v; } - #define G_DeclConstant(type, name, slot) \ - StaticAssert(sizeof(type) <= 4); \ - StaticAssert(slot < G_NumGeneralPurposeConstants); \ - G_ForceDeclConstant(type, name, slot) + #define G_ForceDeclConstant(type, name, slot) \ + Enum(name##__shaderconstantenum) { name = slot }; \ + Struct(name##__shaderconstanttype) { type v; } + #define G_DeclConstant(type, name, slot) \ + StaticAssert(sizeof(type) <= 4); \ + StaticAssert(slot < G_NumGeneralPurposeConstants); \ + G_ForceDeclConstant(type, name, slot) #elif IsLanguageG - #define G_ForceDeclConstant(type, name, slot) cbuffer name : register(b##slot) { type name; } - #define G_DeclConstant(type, name, slot) G_ForceDeclConstant(type, name, slot) + #define G_ForceDeclConstant(type, name, slot) cbuffer name : register(b##slot) { type name; } + #define G_DeclConstant(type, name, slot) G_ForceDeclConstant(type, name, slot) #endif //////////////////////////////////////////////////////////// //~ Resource dereference #if IsLanguageG - /* TODO: Non-uniform resource access currently is assumed as the default - * behavior. We may want to add explicit "uniform" variants for - * optimization on amd in the future. */ + /* TODO: Non-uniform resource access currently is assumed as the default + * behavior. We may want to add explicit "uniform" variants for + * optimization on amd in the future. */ - template StructuredBuffer G_Dereference(G_StructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } - template RWStructuredBuffer G_Dereference(G_RWStructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } + template StructuredBuffer G_Dereference(G_StructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } + template RWStructuredBuffer G_Dereference(G_RWStructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } - ByteAddressBuffer G_Dereference(G_ByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } - RWByteAddressBuffer G_Dereference(G_RWByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } + ByteAddressBuffer G_Dereference(G_ByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } + RWByteAddressBuffer G_Dereference(G_RWByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } - template Texture1D G_Dereference(G_Texture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } - template Texture2D G_Dereference(G_Texture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } - template Texture3D G_Dereference(G_Texture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } - template RWTexture1D G_Dereference(G_RWTexture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } - template RWTexture2D G_Dereference(G_RWTexture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } - template RWTexture3D G_Dereference(G_RWTexture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } + template Texture1D G_Dereference(G_Texture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } + template Texture2D G_Dereference(G_Texture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } + template Texture3D G_Dereference(G_Texture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } + template RWTexture1D G_Dereference(G_RWTexture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } + template RWTexture2D G_Dereference(G_RWTexture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } + template RWTexture3D G_Dereference(G_RWTexture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } - SamplerState G_Dereference(G_SamplerStateRef r) { return SamplerDescriptorHeap[NonUniformResourceIndex(r.v)]; } + SamplerState G_Dereference(G_SamplerStateRef r) { return SamplerDescriptorHeap[NonUniformResourceIndex(r.v)]; } #endif //////////////////////////////////////////////////////////// //~ Size helpers #if IsLanguageG - template u32 countof(StructuredBuffer buff) { u32 result; buff.GetDimensions(result); return result; } - template u32 countof(RWStructuredBuffer buff) { u32 result; buff.GetDimensions(result); return result; } - u32 countof(ByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; } - u32 countof(RWByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; } - u32 countof(Texture1D tex) { u32 result; tex.GetDimensions(result); return result; } - template u32 countof(RWTexture1D tex) { u32 result; tex.GetDimensions(result); return result; } - Vec2U32 countof(Texture2D tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; } - template Vec2U32 countof(RWTexture2D tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; } - Vec3U32 countof(Texture3D tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; } - template Vec3U32 countof(RWTexture3D tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; } + template u32 countof(StructuredBuffer buff) { u32 result; buff.GetDimensions(result); return result; } + template u32 countof(RWStructuredBuffer buff) { u32 result; buff.GetDimensions(result); return result; } + u32 countof(ByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; } + u32 countof(RWByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; } + u32 countof(Texture1D tex) { u32 result; tex.GetDimensions(result); return result; } + template u32 countof(RWTexture1D tex) { u32 result; tex.GetDimensions(result); return result; } + Vec2U32 countof(Texture2D tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; } + template Vec2U32 countof(RWTexture2D tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; } + Vec3U32 countof(Texture3D tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; } + template Vec3U32 countof(RWTexture3D tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; } #endif //////////////////////////////////////////////////////////// @@ -111,196 +111,196 @@ G_ForceDeclConstant(G_RWByteAddressBufferRef, G_ShaderConst_PrintBufferRef, 8) Enum(G_FmtArgKind) { - G_FmtArgKind_None, - G_FmtArgKind_End, + G_FmtArgKind_None, + G_FmtArgKind_End, - G_FmtArgKind_BEGINSIZE1, + G_FmtArgKind_BEGINSIZE1, - G_FmtArgKind_Uint, - G_FmtArgKind_Sint, - G_FmtArgKind_Float, + G_FmtArgKind_Uint, + G_FmtArgKind_Sint, + G_FmtArgKind_Float, - G_FmtArgKind_BEGINSIZE2, + G_FmtArgKind_BEGINSIZE2, - G_FmtArgKind_Uint2, - G_FmtArgKind_Sint2, - G_FmtArgKind_Float2, + G_FmtArgKind_Uint2, + G_FmtArgKind_Sint2, + G_FmtArgKind_Float2, - G_FmtArgKind_BEGINSIZE3, + G_FmtArgKind_BEGINSIZE3, - G_FmtArgKind_Uint3, - G_FmtArgKind_Sint3, - G_FmtArgKind_Float3, + G_FmtArgKind_Uint3, + G_FmtArgKind_Sint3, + G_FmtArgKind_Float3, - G_FmtArgKind_BEGINSIZE4, + G_FmtArgKind_BEGINSIZE4, - G_FmtArgKind_Uint4, - G_FmtArgKind_Sint4, - G_FmtArgKind_Float4, + G_FmtArgKind_Uint4, + G_FmtArgKind_Sint4, + G_FmtArgKind_Float4, }; Struct(G_FmtArg) { - G_FmtArgKind kind; - Vec4U32 v; + G_FmtArgKind kind; + Vec4U32 v; }; #if IsLanguageG && GPU_SHADER_PRINT - G_FmtArg G_Fmt(u32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint; result.v.x = v; return result; } - G_FmtArg G_Fmt(Vec2U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint2; result.v.xy = v.xy; return result; } - G_FmtArg G_Fmt(Vec3U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint3; result.v.xyz = v.xyz; return result; } - G_FmtArg G_Fmt(Vec4U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint4; result.v.xyzw = v.xyzw; return result; } + G_FmtArg G_Fmt(u32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint; result.v.x = v; return result; } + G_FmtArg G_Fmt(Vec2U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint2; result.v.xy = v.xy; return result; } + G_FmtArg G_Fmt(Vec3U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint3; result.v.xyz = v.xyz; return result; } + G_FmtArg G_Fmt(Vec4U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint4; result.v.xyzw = v.xyzw; return result; } - G_FmtArg G_Fmt(i32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint; result.v.x = v; return result; } - G_FmtArg G_Fmt(Vec2I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint2; result.v.xy = v.xy; return result; } - G_FmtArg G_Fmt(Vec3I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint3; result.v.xyz = v.xyz; return result; } - G_FmtArg G_Fmt(Vec4I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint4; result.v.xyzw = v.xyzw; return result; } + G_FmtArg G_Fmt(i32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint; result.v.x = v; return result; } + G_FmtArg G_Fmt(Vec2I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint2; result.v.xy = v.xy; return result; } + G_FmtArg G_Fmt(Vec3I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint3; result.v.xyz = v.xyz; return result; } + G_FmtArg G_Fmt(Vec4I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint4; result.v.xyzw = v.xyzw; return result; } - G_FmtArg G_Fmt(f32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float; result.v.x = asuint(v); return result; } - G_FmtArg G_Fmt(Vec2 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float2; result.v.xy = asuint(v.xy); return result; } - G_FmtArg G_Fmt(Vec3 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float3; result.v.xyz = asuint(v.xyz); return result; } - G_FmtArg G_Fmt(Vec4 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float4; result.v.xyzw = asuint(v.xyzw); return result; } + G_FmtArg G_Fmt(f32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float; result.v.x = asuint(v); return result; } + G_FmtArg G_Fmt(Vec2 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float2; result.v.xy = asuint(v.xy); return result; } + G_FmtArg G_Fmt(Vec3 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float3; result.v.xyz = asuint(v.xyz); return result; } + G_FmtArg G_Fmt(Vec4 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float4; result.v.xyzw = asuint(v.xyzw); return result; } - G_FmtArg G_FmtEnd(void) { G_FmtArg result; result.kind = G_FmtArgKind_End; return result; } + G_FmtArg G_FmtEnd(void) { G_FmtArg result; result.kind = G_FmtArgKind_End; return result; } - Struct(G_TempPrintBuffer) + Struct(G_TempPrintBuffer) + { + /* NOTE: The larger the array size, the longer the compilation time */ + u32 byte_chunks[64]; + u32 bytes_count; + u32 chars_count; + u32 args_count; + b32 overflowed; + }; + + void G_PushPrintByte(inout G_TempPrintBuffer buff, u32 v) + { + u32 chunk_idx = buff.bytes_count / 4; + if (chunk_idx < countof(buff.byte_chunks)) { - /* NOTE: The larger the array size, the longer the compilation time */ - u32 byte_chunks[64]; - u32 bytes_count; - u32 chars_count; - u32 args_count; - b32 overflowed; - }; - - void G_PushPrintByte(inout G_TempPrintBuffer buff, u32 v) + u32 byte_idx_in_chunk = buff.bytes_count & 0x03; + if (byte_idx_in_chunk == 0) + { + /* Since buff is not zero initialized, we set the chunk on first write here */ + buff.byte_chunks[chunk_idx] = v & 0xFF; + } + else + { + buff.byte_chunks[chunk_idx] |= (v & 0xFF) << (byte_idx_in_chunk * 8); + } + buff.bytes_count += 1; + } + else { - u32 chunk_idx = buff.bytes_count / 4; - if (chunk_idx < countof(buff.byte_chunks)) - { - u32 byte_idx_in_chunk = buff.bytes_count & 0x03; - if (byte_idx_in_chunk == 0) - { - /* Since buff is not zero initialized, we set the chunk on first write here */ - buff.byte_chunks[chunk_idx] = v & 0xFF; - } - else - { - buff.byte_chunks[chunk_idx] |= (v & 0xFF) << (byte_idx_in_chunk * 8); - } - buff.bytes_count += 1; - } - else - { - buff.overflowed = 1; - } + buff.overflowed = 1; + } + } + + void G_CommitPrint(G_TempPrintBuffer buff) + { + RWByteAddressBuffer rw = G_Dereference(G_ShaderConst_PrintBufferRef); + + if (buff.overflowed) + { + buff.bytes_count = 0; + buff.chars_count = 0; + buff.args_count = 0; } - void G_CommitPrint(G_TempPrintBuffer buff) + u32 chunks_count = (buff.bytes_count + 3) / 4; + u32 alloc_size = 0; + alloc_size += 4; /* Header */ + alloc_size += chunks_count * 4; /* Chunks */ + + /* Atomic fetch + add to base counter */ + u32 base; + rw.InterlockedAdd(0, alloc_size, base); + base += 4; /* Offset for allocation counter */ + base += 4; /* Offset for success counter */ + base += 4; /* Offset for overflow counter */ + + if ((base + alloc_size) < countof(rw)) { - RWByteAddressBuffer rw = G_Dereference(G_ShaderConst_PrintBufferRef); + /* Increment success counter */ + rw.InterlockedAdd(4, 1); + u32 pos = 0; - if (buff.overflowed) - { - buff.bytes_count = 0; - buff.chars_count = 0; - buff.args_count = 0; - } + /* Write header */ + { + u32 header = 0; + header |= (buff.chars_count << 0) & 0x0000FFFF; + header |= (buff.args_count << 16) & 0x7FFF0000; + header |= (buff.overflowed << 31) & 0xF0000000; + rw.Store(base + pos, header); + pos += 4; + } - u32 chunks_count = (buff.bytes_count + 3) / 4; - u32 alloc_size = 0; - alloc_size += 4; /* Header */ - alloc_size += chunks_count * 4; /* Chunks */ - - /* Atomic fetch + add to base counter */ - u32 base; - rw.InterlockedAdd(0, alloc_size, base); - base += 4; /* Offset for allocation counter */ - base += 4; /* Offset for success counter */ - base += 4; /* Offset for overflow counter */ - - if ((base + alloc_size) < countof(rw)) - { - /* Increment success counter */ - rw.InterlockedAdd(4, 1); - u32 pos = 0; - - /* Write header */ - { - u32 header = 0; - header |= (buff.chars_count << 0) & 0x0000FFFF; - header |= (buff.args_count << 16) & 0x7FFF0000; - header |= (buff.overflowed << 31) & 0xF0000000; - rw.Store(base + pos, header); - pos += 4; - } - - /* Write chunks */ - for (u32 chunk_idx = 0; chunk_idx < chunks_count; ++chunk_idx) - { - u32 chunk = buff.byte_chunks[chunk_idx]; - rw.Store(base + pos, chunk); - pos += 4; - } - } - else - { - /* Increment overflow counter */ - rw.InterlockedAdd(8, 1); - } + /* Write chunks */ + for (u32 chunk_idx = 0; chunk_idx < chunks_count; ++chunk_idx) + { + u32 chunk = buff.byte_chunks[chunk_idx]; + rw.Store(base + pos, chunk); + pos += 4; + } } + else + { + /* Increment overflow counter */ + rw.InterlockedAdd(8, 1); + } + } - #define G_PrintF_(fmt, ...) do { \ - G_TempPrintBuffer __tmp; \ - __tmp.bytes_count = 0; \ - __tmp.overflowed = 0; \ - u32 __char_idx = 0; \ - while (U32FromChar(fmt[__char_idx]) != 0) \ - { \ - G_PushPrintByte(__tmp, U32FromChar(fmt[__char_idx])); \ - ++__char_idx; \ - } \ - G_FmtArg __args[] = { __VA_ARGS__ }; \ - __tmp.chars_count = __char_idx; \ - __tmp.args_count = (countof(__args) - 1); \ - for (u32 __arg_idx = 0; __arg_idx < __tmp.args_count; ++__arg_idx) \ - { \ - G_FmtArg __arg = __args[__arg_idx]; \ - G_PushPrintByte(__tmp, __arg.kind); \ - if (__arg.kind > G_FmtArgKind_BEGINSIZE1) \ - { \ - G_PushPrintByte(__tmp, __arg.v.x >> 0); \ - G_PushPrintByte(__tmp, __arg.v.x >> 8); \ - G_PushPrintByte(__tmp, __arg.v.x >> 16); \ - G_PushPrintByte(__tmp, __arg.v.x >> 24); \ - } \ - if (__arg.kind > G_FmtArgKind_BEGINSIZE2) \ - { \ - G_PushPrintByte(__tmp, __arg.v.y >> 0); \ - G_PushPrintByte(__tmp, __arg.v.y >> 8); \ - G_PushPrintByte(__tmp, __arg.v.y >> 16); \ - G_PushPrintByte(__tmp, __arg.v.y >> 24); \ - } \ - if (__arg.kind > G_FmtArgKind_BEGINSIZE3) \ - { \ - G_PushPrintByte(__tmp, __arg.v.z >> 0); \ - G_PushPrintByte(__tmp, __arg.v.z >> 8); \ - G_PushPrintByte(__tmp, __arg.v.z >> 16); \ - G_PushPrintByte(__tmp, __arg.v.z >> 24); \ - } \ - if (__arg.kind > G_FmtArgKind_BEGINSIZE4) \ - { \ - G_PushPrintByte(__tmp, __arg.v.w >> 0); \ - G_PushPrintByte(__tmp, __arg.v.w >> 8); \ - G_PushPrintByte(__tmp, __arg.v.w >> 16); \ - G_PushPrintByte(__tmp, __arg.v.w >> 24); \ - } \ - } \ - G_CommitPrint(__tmp); \ - } while (0) + #define G_PrintF_(fmt, ...) do { \ + G_TempPrintBuffer __tmp; \ + __tmp.bytes_count = 0; \ + __tmp.overflowed = 0; \ + u32 __char_idx = 0; \ + while (U32FromChar(fmt[__char_idx]) != 0) \ + { \ + G_PushPrintByte(__tmp, U32FromChar(fmt[__char_idx])); \ + ++__char_idx; \ + } \ + G_FmtArg __args[] = { __VA_ARGS__ }; \ + __tmp.chars_count = __char_idx; \ + __tmp.args_count = (countof(__args) - 1); \ + for (u32 __arg_idx = 0; __arg_idx < __tmp.args_count; ++__arg_idx) \ + { \ + G_FmtArg __arg = __args[__arg_idx]; \ + G_PushPrintByte(__tmp, __arg.kind); \ + if (__arg.kind > G_FmtArgKind_BEGINSIZE1) \ + { \ + G_PushPrintByte(__tmp, __arg.v.x >> 0); \ + G_PushPrintByte(__tmp, __arg.v.x >> 8); \ + G_PushPrintByte(__tmp, __arg.v.x >> 16); \ + G_PushPrintByte(__tmp, __arg.v.x >> 24); \ + } \ + if (__arg.kind > G_FmtArgKind_BEGINSIZE2) \ + { \ + G_PushPrintByte(__tmp, __arg.v.y >> 0); \ + G_PushPrintByte(__tmp, __arg.v.y >> 8); \ + G_PushPrintByte(__tmp, __arg.v.y >> 16); \ + G_PushPrintByte(__tmp, __arg.v.y >> 24); \ + } \ + if (__arg.kind > G_FmtArgKind_BEGINSIZE3) \ + { \ + G_PushPrintByte(__tmp, __arg.v.z >> 0); \ + G_PushPrintByte(__tmp, __arg.v.z >> 8); \ + G_PushPrintByte(__tmp, __arg.v.z >> 16); \ + G_PushPrintByte(__tmp, __arg.v.z >> 24); \ + } \ + if (__arg.kind > G_FmtArgKind_BEGINSIZE4) \ + { \ + G_PushPrintByte(__tmp, __arg.v.w >> 0); \ + G_PushPrintByte(__tmp, __arg.v.w >> 8); \ + G_PushPrintByte(__tmp, __arg.v.w >> 16); \ + G_PushPrintByte(__tmp, __arg.v.w >> 24); \ + } \ + } \ + G_CommitPrint(__tmp); \ + } while (0) - #define G_PrintF(fmt, ...) G_PrintF_(fmt, ##__VA_ARGS__, G_FmtEnd()) + #define G_PrintF(fmt, ...) G_PrintF_(fmt, ##__VA_ARGS__, G_FmtEnd()) #else - #define G_PrintF(fmt) + #define G_PrintF(fmt) #endif diff --git a/src/json/json.c b/src/json/json.c index b4f38386..7a4a5406 100644 --- a/src/json/json.c +++ b/src/json/json.c @@ -8,347 +8,347 @@ JSON_Token *JSON_PushToken(Arena *arena, JSON_TokenList *list) { - JSON_Token *t = PushStruct(arena, JSON_Token); - if (!list->token_first) - { - list->token_first = t; - } - else - { - list->token_last->next = t; - } - list->token_last = t; - return t; + JSON_Token *t = PushStruct(arena, JSON_Token); + if (!list->token_first) + { + list->token_first = t; + } + else + { + list->token_last->next = t; + } + list->token_last = t; + return t; } JSON_TokenList JSON_TokensFromString(Arena *arena, String src) { - JSON_TokenList result = ZI; + JSON_TokenList result = ZI; - JSON_Token *bof = JSON_PushToken(arena, &result); - bof->kind = JSON_TokenKind_Bof; + JSON_Token *bof = JSON_PushToken(arena, &result); + bof->kind = JSON_TokenKind_Bof; - u64 pos = 0; - b32 lexing_done = 0; - while (!lexing_done) + u64 pos = 0; + b32 lexing_done = 0; + while (!lexing_done) + { + /* Skip whitespace */ + b32 whitespace_done = 0; + while (!whitespace_done && pos < src.len) { - /* Skip whitespace */ - b32 whitespace_done = 0; - while (!whitespace_done && pos < src.len) + switch (src.text[pos]) + { + default: { - switch (src.text[pos]) - { - default: - { - whitespace_done = 1; - } break; + whitespace_done = 1; + } break; - case JSON_Case_Newline: - case JSON_Case_Space: - { - ++pos; - } break; - } - } - - /* Create token */ - JSON_Token *t = JSON_PushToken(arena, &result); - t->start = pos; - - if (pos >= src.len) + case JSON_Case_Newline: + case JSON_Case_Space: { - t->kind = JSON_TokenKind_Eof; - t->next = t; /* Self reference */ - lexing_done = 1; - } - else - { - /* Lex known token kinds */ - switch (src.text[pos]) - { - default: break; - - /* Symbols */ - case ',': - { - t->kind = JSON_TokenKind_Comma; - ++pos; - } break; - - case ':': - { - t->kind = JSON_TokenKind_Colon; - ++pos; - } break; - - case '[': - { - t->kind = JSON_TokenKind_SquareBraceOpen; - ++pos; - } break; - - case ']': - { - t->kind = JSON_TokenKind_SquareBraceClose; - ++pos; - } break; - - case '{': - { - t->kind = JSON_TokenKind_CurlyBraceOpen; - ++pos; - } break; - - case '}': - { - t->kind = JSON_TokenKind_CurlyBraceClose; - ++pos; - } break; - - /* Number */ - case '-': - { - /* Verify '-' precedes digit */ - b32 next_is_digit = 0; - if ((pos + 1) < src.len) - { - switch (src.text[pos + 1]) - { - case JSON_Case_Digit0Through9: - { - next_is_digit = 1; - } break; - } - } - ++pos; - if (!next_is_digit) - { - break; - } - } FALLTHROUGH; - case JSON_Case_Digit0Through9: - { - t->kind = JSON_TokenKind_Number; - JSON_LexNumberState state = JSON_LexNumberState_Whole; - b32 number_done = 0; - while (!number_done && pos < src.len) - { - switch (src.text[pos]) - { - default: - { - number_done = 1; - } break; - - case JSON_Case_Digit0Through9: - { - ++pos; - } break; - - case '.': - { - u64 consume = 0; - if (state == JSON_LexNumberState_Whole && (pos + 1) < src.len) - { - u8 c1 = src.text[pos + 1]; - switch (c1) - { - default: break; - - case JSON_Case_Digit0Through9: - { - /* Consume '.' */ - ++consume; - } break; - } - } - if (consume) - { - state = JSON_LexNumberState_Fraction; - pos += consume; - } - else - { - number_done = 1; - } - } break; - - case 'e': - case 'E': - { - u64 consume = 0; - if ((state == JSON_LexNumberState_Whole || state == JSON_LexNumberState_Fraction) && (pos + 1) < src.len) - { - u8 c1 = src.text[pos + 1]; - switch (c1) - { - case JSON_Case_Digit0Through9: - { - /* Consume 'E'/'e' */ - ++consume; - } break; - - case '-': - case '+': - { - if ((pos + 2) < src.len) - { - u8 c2 = src.text[pos + 2]; - switch (c2) - { - default: break; - - case JSON_Case_Digit0Through9: - { - /* Consume 'E'/'e' & '+'/'-' */ - consume += 2; - } break; - } - } - } break; - - default: break; - } - } - if (consume) - { - state = JSON_LexNumberState_Exponent; - pos += consume; - } - else - { - number_done = 1; - } - } break; - } - } - } break; - - /* String */ - case '"': - { - ++pos; - - b32 string_done = 0; - b32 next_escaped = 0; - while (!string_done && pos < src.len) - { - b32 escaped = next_escaped; - next_escaped = 0; - switch (src.text[pos]) - { - default: - { - ++pos; - } break; - - case JSON_Case_Newline: - { - ++pos; - string_done = 1; - } break; - - case '"': - { - ++pos; - if (!escaped) - { - t->kind = JSON_TokenKind_String; - string_done = 1; - } - } break; - - case '\\': - { - ++pos; - if (!escaped) - { - next_escaped = 1; - } - } break; - } - } - } break; - - /* Keywords */ - case 't': - case 'f': - case 'n': - { - String keyword = JSON_keyword_strings[src.text[pos]]; - - b32 match = 1; - if ((pos + keyword.len - 1) < src.len) - { - if ((pos + keyword.len) < src.len) - { - /* Don't match if word continues past keyword */ - switch (src.text[pos + keyword.len]) - { - default: - { - match = 0; - } break; - - case JSON_Case_Symbol: - case JSON_Case_Space: - case JSON_Case_Newline: - { - } break; - } - } - if (match) - { - String cmp_str = { - .len = keyword.len, - .text = &src.text[pos] - }; - match = MatchString(cmp_str, keyword); - } - } - - if (match) - { - t->kind = JSON_keyword_types[src.text[pos]]; - pos += keyword.len; - } - } break; - } - } - - /* Lex unknown token */ - if (t->kind == JSON_TokenKind_Unknown) - { - b32 unknown_done = 0; - while (!unknown_done && pos < src.len) - { - switch (src.text[pos]) - { - default: - { - ++pos; - } break; - - case JSON_Case_Symbol: - case JSON_Case_Space: - case JSON_Case_Newline: - { - unknown_done = 1; - } break; - } - } - t->end = pos; - - /* Exit early if unknown token encountered */ - return result; - } - else - { - t->end = pos; - } + ++pos; + } break; + } } - return result; + /* Create token */ + JSON_Token *t = JSON_PushToken(arena, &result); + t->start = pos; + + if (pos >= src.len) + { + t->kind = JSON_TokenKind_Eof; + t->next = t; /* Self reference */ + lexing_done = 1; + } + else + { + /* Lex known token kinds */ + switch (src.text[pos]) + { + default: break; + + /* Symbols */ + case ',': + { + t->kind = JSON_TokenKind_Comma; + ++pos; + } break; + + case ':': + { + t->kind = JSON_TokenKind_Colon; + ++pos; + } break; + + case '[': + { + t->kind = JSON_TokenKind_SquareBraceOpen; + ++pos; + } break; + + case ']': + { + t->kind = JSON_TokenKind_SquareBraceClose; + ++pos; + } break; + + case '{': + { + t->kind = JSON_TokenKind_CurlyBraceOpen; + ++pos; + } break; + + case '}': + { + t->kind = JSON_TokenKind_CurlyBraceClose; + ++pos; + } break; + + /* Number */ + case '-': + { + /* Verify '-' precedes digit */ + b32 next_is_digit = 0; + if ((pos + 1) < src.len) + { + switch (src.text[pos + 1]) + { + case JSON_Case_Digit0Through9: + { + next_is_digit = 1; + } break; + } + } + ++pos; + if (!next_is_digit) + { + break; + } + } FALLTHROUGH; + case JSON_Case_Digit0Through9: + { + t->kind = JSON_TokenKind_Number; + JSON_LexNumberState state = JSON_LexNumberState_Whole; + b32 number_done = 0; + while (!number_done && pos < src.len) + { + switch (src.text[pos]) + { + default: + { + number_done = 1; + } break; + + case JSON_Case_Digit0Through9: + { + ++pos; + } break; + + case '.': + { + u64 consume = 0; + if (state == JSON_LexNumberState_Whole && (pos + 1) < src.len) + { + u8 c1 = src.text[pos + 1]; + switch (c1) + { + default: break; + + case JSON_Case_Digit0Through9: + { + /* Consume '.' */ + ++consume; + } break; + } + } + if (consume) + { + state = JSON_LexNumberState_Fraction; + pos += consume; + } + else + { + number_done = 1; + } + } break; + + case 'e': + case 'E': + { + u64 consume = 0; + if ((state == JSON_LexNumberState_Whole || state == JSON_LexNumberState_Fraction) && (pos + 1) < src.len) + { + u8 c1 = src.text[pos + 1]; + switch (c1) + { + case JSON_Case_Digit0Through9: + { + /* Consume 'E'/'e' */ + ++consume; + } break; + + case '-': + case '+': + { + if ((pos + 2) < src.len) + { + u8 c2 = src.text[pos + 2]; + switch (c2) + { + default: break; + + case JSON_Case_Digit0Through9: + { + /* Consume 'E'/'e' & '+'/'-' */ + consume += 2; + } break; + } + } + } break; + + default: break; + } + } + if (consume) + { + state = JSON_LexNumberState_Exponent; + pos += consume; + } + else + { + number_done = 1; + } + } break; + } + } + } break; + + /* String */ + case '"': + { + ++pos; + + b32 string_done = 0; + b32 next_escaped = 0; + while (!string_done && pos < src.len) + { + b32 escaped = next_escaped; + next_escaped = 0; + switch (src.text[pos]) + { + default: + { + ++pos; + } break; + + case JSON_Case_Newline: + { + ++pos; + string_done = 1; + } break; + + case '"': + { + ++pos; + if (!escaped) + { + t->kind = JSON_TokenKind_String; + string_done = 1; + } + } break; + + case '\\': + { + ++pos; + if (!escaped) + { + next_escaped = 1; + } + } break; + } + } + } break; + + /* Keywords */ + case 't': + case 'f': + case 'n': + { + String keyword = JSON_keyword_strings[src.text[pos]]; + + b32 match = 1; + if ((pos + keyword.len - 1) < src.len) + { + if ((pos + keyword.len) < src.len) + { + /* Don't match if word continues past keyword */ + switch (src.text[pos + keyword.len]) + { + default: + { + match = 0; + } break; + + case JSON_Case_Symbol: + case JSON_Case_Space: + case JSON_Case_Newline: + { + } break; + } + } + if (match) + { + String cmp_str = { + .len = keyword.len, + .text = &src.text[pos] + }; + match = MatchString(cmp_str, keyword); + } + } + + if (match) + { + t->kind = JSON_keyword_types[src.text[pos]]; + pos += keyword.len; + } + } break; + } + } + + /* Lex unknown token */ + if (t->kind == JSON_TokenKind_Unknown) + { + b32 unknown_done = 0; + while (!unknown_done && pos < src.len) + { + switch (src.text[pos]) + { + default: + { + ++pos; + } break; + + case JSON_Case_Symbol: + case JSON_Case_Space: + case JSON_Case_Newline: + { + unknown_done = 1; + } break; + } + } + t->end = pos; + + /* Exit early if unknown token encountered */ + return result; + } + else + { + t->end = pos; + } + } + + return result; } //////////////////////////////////////////////////////////// @@ -356,331 +356,329 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src) f64 interpret_number(String src) { - b32 whole_present = 0; - u64 whole_left = 0; - u64 whole_right = 0; - i32 whole_sign = 1; + b32 whole_present = 0; + u64 whole_left = 0; + u64 whole_right = 0; + i32 whole_sign = 1; - b32 fraction_present = 0; - u64 fraction_left = 0; - u64 fraction_right = 0; + b32 fraction_present = 0; + u64 fraction_left = 0; + u64 fraction_right = 0; - b32 exponent_present = 0; - u64 exponent_left = 0; - u64 exponent_right = 0; - i32 exponent_sign = 1; + b32 exponent_present = 0; + u64 exponent_left = 0; + u64 exponent_right = 0; + i32 exponent_sign = 1; - /* Lex number parts */ + /* Lex number parts */ + { + u64 pos = 0; + if (src.len > 0 && src.text[0] == '-') { - u64 pos = 0; - if (src.len > 0 && src.text[0] == '-') - { - whole_sign = -1; - ++pos; - } + whole_sign = -1; + ++pos; + } - JSON_LexNumberState state = JSON_LexNumberState_Whole; - while (pos < src.len) + JSON_LexNumberState state = JSON_LexNumberState_Whole; + while (pos < src.len) + { + switch (src.text[pos]) + { + default: { - switch (src.text[pos]) + /* Unreachable */ + Assert(0); + ++pos; + } break; + + case JSON_Case_Digit0Through9: + { + switch (state) + { + case JSON_LexNumberState_Whole: { - default: - { - /* Unreachable */ - Assert(0); - ++pos; - } break; + if (!whole_present) + { + whole_present = 1; + whole_left = pos; + } + whole_right = pos; + ++pos; + } break; - case JSON_Case_Digit0Through9: - { - switch (state) - { - case JSON_LexNumberState_Whole: - { - if (!whole_present) - { - whole_present = 1; - whole_left = pos; - } - whole_right = pos; - ++pos; - } break; + case JSON_LexNumberState_Fraction: + { + if (!fraction_present) + { + fraction_present = 1; + fraction_left = pos; + } + fraction_right = pos; + ++pos; + } break; - case JSON_LexNumberState_Fraction: - { - if (!fraction_present) - { - fraction_present = 1; - fraction_left = pos; - } - fraction_right = pos; - ++pos; - } break; + case JSON_LexNumberState_Exponent: + { + if (!exponent_present) + { + exponent_present = 1; + exponent_left = pos; + } + exponent_right = pos; + ++pos; + } break; + } + } break; - case JSON_LexNumberState_Exponent: - { - if (!exponent_present) - { - exponent_present = 1; - exponent_left = pos; - } - exponent_right = pos; - ++pos; - } break; - } - } break; + case '.': + { + state = JSON_LexNumberState_Fraction; + ++pos; + } break; - case '.': - { - state = JSON_LexNumberState_Fraction; - ++pos; - } break; + case 'e': + case 'E': + { + state = JSON_LexNumberState_Exponent; + ++pos; + } break; - case 'e': - case 'E': - { - state = JSON_LexNumberState_Exponent; - ++pos; - } break; + case '-': + { + switch (state) + { + default: + { + /* Unreachable */ + Assert(0); + ++pos; + } break; - case '-': - { - switch (state) - { - default: - { - /* Unreachable */ - Assert(0); - ++pos; - } break; + case JSON_LexNumberState_Whole: + { + whole_sign = -1; + ++pos; + } break; - case JSON_LexNumberState_Whole: - { - whole_sign = -1; - ++pos; - } break; + case JSON_LexNumberState_Exponent: + { + exponent_sign = -1; + ++pos; + } break; + } + } break; - case JSON_LexNumberState_Exponent: - { - exponent_sign = -1; - ++pos; - } break; - } - } break; + case '+': + { + switch (state) + { + default: + { + /* Unreachable */ + Assert(0); + ++pos; + } break; - case '+': - { - switch (state) - { - default: - { - /* Unreachable */ - Assert(0); - ++pos; - } break; - - case JSON_LexNumberState_Exponent: - { - exponent_sign = 1; - ++pos; - } break; - } - } break; - } - } + case JSON_LexNumberState_Exponent: + { + exponent_sign = 1; + ++pos; + } break; + } + } break; + } } + } - f64 result = 0; + f64 result = 0; - /* Process whole part */ - if (whole_present) + /* Process whole part */ + if (whole_present) + { + u64 pos = whole_left; + while (pos <= whole_right) { - u64 pos = whole_left; - while (pos <= whole_right) - { - u8 digit = MinU8(src.text[pos] - 48, 9); - u64 exp = whole_right - pos; - result += digit * PowU64(10, exp); - ++pos; - } - result *= whole_sign; + u8 digit = MinU8(src.text[pos] - 48, 9); + u64 exp = whole_right - pos; + result += digit * PowU64(10, exp); + ++pos; } + result *= whole_sign; + } - /* Process fraction part */ - if (fraction_present) + /* Process fraction part */ + if (fraction_present) + { + u64 frac_whole = 0; + u64 pos = fraction_left; + while (pos <= fraction_right) { - u64 frac_whole = 0; - u64 pos = fraction_left; - while (pos <= fraction_right) - { - u8 digit = MinU8(src.text[pos] - 48, 9); - u64 exp = fraction_right - pos; - frac_whole += digit * PowU64(10, exp); - ++pos; - } - - result += (f64)frac_whole / PowU64(10, (fraction_right - fraction_left + 1)); + u8 digit = MinU8(src.text[pos] - 48, 9); + u64 exp = fraction_right - pos; + frac_whole += digit * PowU64(10, exp); + ++pos; } - /* Process exponent part */ - if (exponent_present) + result += (f64)frac_whole / PowU64(10, (fraction_right - fraction_left + 1)); + } + + /* Process exponent part */ + if (exponent_present) + { + u64 exponent_whole = 0; + u64 pos = exponent_left; + while (pos <= exponent_right) { - u64 exponent_whole = 0; - u64 pos = exponent_left; - while (pos <= exponent_right) - { - u8 digit = MinU8(src.text[pos] - 48, 9); - u64 exp = exponent_right - pos; - exponent_whole += digit * PowU64(10, exp); - ++pos; - } - - if (exponent_sign >= 0) - { - result *= PowU64(10, exponent_whole); - } - else - { - result /= PowU64(10, exponent_whole); - } + u8 digit = MinU8(src.text[pos] - 48, 9); + u64 exp = exponent_right - pos; + exponent_whole += digit * PowU64(10, exp); + ++pos; } - return result; + if (exponent_sign >= 0) + { + result *= PowU64(10, exponent_whole); + } + else + { + result /= PowU64(10, exponent_whole); + } + } + + return result; } String interpret_string(Arena *arena, String src, String *error) { - String result = { - .len = 0, - .text = PushDry(arena, u8) - }; + String result = { + .len = 0, + .text = PushDry(arena, u8) + }; - if (src.len < 2) + if (src.len < 2) + { + if (error) { - if (error) - { - *error = Lit("Malformed string."); - } - return result; + *error = Lit("Malformed string."); } - /* Ignore beginning quote */ - u64 pos = 1; - - b32 valid_close = 0; - b32 string_done = 0; - b32 next_escaped = 0; - while (!string_done && pos < src.len) - { - b32 escaped = next_escaped; - next_escaped = 0; - - if (escaped) - { - switch (src.text[pos]) - { - default: - { - if (error) - { - *error = Lit("Invalid escape character in string."); - return result; - } - } break; - - case '"': - case '\\': - case '/': - { - *PushStructNoZero(arena, u8) = src.text[pos]; - ++result.len; - ++pos; - } break; - - /* Backspace */ - case 'b': - { - *PushStructNoZero(arena, u8) = '\b'; - ++result.len; - ++pos; - } break; - - /* Formfeed */ - case 'f': - { - *PushStructNoZero(arena, u8) = '\f'; - ++result.len; - ++pos; - } break; - - /* Linefeed */ - case 'n': - { - *PushStructNoZero(arena, u8) = '\n'; - ++result.len; - ++pos; - } break; - - /* Carriage return */ - case 'r': - { - *PushStructNoZero(arena, u8) = '\r'; - ++result.len; - ++pos; - } break; - - /* Horizontal tab */ - case 't': - { - *PushStructNoZero(arena, u8) = '\t'; - ++result.len; - ++pos; - } break; - - /* TODO: Unicode escape support */ -#if 0 - case 'u': - { - /* TODO */ - } break; -#endif - } - } - else - { - switch (src.text[pos]) - { - default: - { - *PushStructNoZero(arena, u8) = src.text[pos]; - ++result.len; - ++pos; - } break; - - case '\\': - { - escaped = 1; - ++pos; - } break; - - case '"': - { - string_done = 1; - valid_close = 1; - ++pos; - } break; - } - } - } - - if (!valid_close) - { - if (error) - { - *error = Lit("Expected end of string."); - } - } - return result; + } + /* Ignore beginning quote */ + u64 pos = 1; + + b32 valid_close = 0; + b32 string_done = 0; + b32 next_escaped = 0; + while (!string_done && pos < src.len) + { + b32 escaped = next_escaped; + next_escaped = 0; + + if (escaped) + { + switch (src.text[pos]) + { + default: + { + if (error) + { + *error = Lit("Invalid escape character in string."); + return result; + } + } break; + + case '"': + case '\\': + case '/': + { + *PushStructNoZero(arena, u8) = src.text[pos]; + ++result.len; + ++pos; + } break; + + /* Backspace */ + case 'b': + { + *PushStructNoZero(arena, u8) = '\b'; + ++result.len; + ++pos; + } break; + + /* Formfeed */ + case 'f': + { + *PushStructNoZero(arena, u8) = '\f'; + ++result.len; + ++pos; + } break; + + /* Linefeed */ + case 'n': + { + *PushStructNoZero(arena, u8) = '\n'; + ++result.len; + ++pos; + } break; + + /* Carriage return */ + case 'r': + { + *PushStructNoZero(arena, u8) = '\r'; + ++result.len; + ++pos; + } break; + + /* Horizontal tab */ + case 't': + { + *PushStructNoZero(arena, u8) = '\t'; + ++result.len; + ++pos; + } break; + + /* TODO: Unicode escape support */ + // case 'u': + // { + // /* TODO */ + // } break; + } + } + else + { + switch (src.text[pos]) + { + default: + { + *PushStructNoZero(arena, u8) = src.text[pos]; + ++result.len; + ++pos; + } break; + + case '\\': + { + escaped = 1; + ++pos; + } break; + + case '"': + { + string_done = 1; + valid_close = 1; + ++pos; + } break; + } + } + } + + if (!valid_close) + { + if (error) + { + *error = Lit("Expected end of string."); + } + } + + return result; } //////////////////////////////////////////////////////////// @@ -688,246 +686,246 @@ String interpret_string(Arena *arena, String src, String *error) void JSON_PushError(Arena *arena, JSON_Parser *p, JSON_Token *t, String msg) { - JSON_Error *error = PushStruct(arena, JSON_Error); - error->msg = msg; - error->start = t->start; - error->end = t->end; + JSON_Error *error = PushStruct(arena, JSON_Error); + error->msg = msg; + error->start = t->start; + error->end = t->end; - JSON_ErrorList *list = &p->errors; - if (!list->first) - { - list->first = error; - } - else - { - list->last->next = error; - } - list->last = error; - ++list->count; + JSON_ErrorList *list = &p->errors; + if (!list->first) + { + list->first = error; + } + else + { + list->last->next = error; + } + list->last = error; + ++list->count; } void JSON_Parse(Arena *arena, JSON_Parser *p) { - TempArena scratch = BeginScratch(arena); + TempArena scratch = BeginScratch(arena); - JSON_Blob *root = PushStruct(arena, JSON_Blob); - JSON_Token *at = p->at; - String src = p->src; + JSON_Blob *root = PushStruct(arena, JSON_Blob); + JSON_Token *at = p->at; + String src = p->src; - if (at->kind == JSON_TokenKind_Bof) + if (at->kind == JSON_TokenKind_Bof) + { + at = at->next; + } + + /* Depth first stack */ + *PushStructNoZero(scratch.arena, JSON_Blob *) = root; + u64 stack_count = 1; + + while (stack_count > 0) + { + JSON_Blob *json = 0; + PopStruct(scratch.arena, JSON_Blob *, &json); + --stack_count; + + JSON_Blob *parent_json = json->parent; + b32 is_new_parent = 0; + if (json->type == JSON_Type_Object || json->type == JSON_Type_Array) { + /* No more children to parse for object/array, check for closing brace. */ + JSON_TokenKind tok_close_kind = json->type == JSON_Type_Object ? JSON_TokenKind_CurlyBraceClose : JSON_TokenKind_SquareBraceClose; + if (at->kind == tok_close_kind) + { at = at->next; + } + else + { + JSON_PushError(arena, p, at, Lit("Expected comma.")); + at = at->next; + goto abort; + } } - - /* Depth first stack */ - *PushStructNoZero(scratch.arena, JSON_Blob *) = root; - u64 stack_count = 1; - - while (stack_count > 0) + else { - JSON_Blob *json = 0; - PopStruct(scratch.arena, JSON_Blob *, &json); - --stack_count; - - JSON_Blob *parent_json = json->parent; - b32 is_new_parent = 0; - if (json->type == JSON_Type_Object || json->type == JSON_Type_Array) + if (parent_json) + { + if (parent_json->type == JSON_Type_Object) { - /* No more children to parse for object/array, check for closing brace. */ - JSON_TokenKind tok_close_kind = json->type == JSON_Type_Object ? JSON_TokenKind_CurlyBraceClose : JSON_TokenKind_SquareBraceClose; - if (at->kind == tok_close_kind) + /* Parse key */ + if (at->kind == JSON_TokenKind_String) + { + String t_text = (String) { .len = at->end - at->start, .text = &src.text[at->start] }; + String error = ZI; + String key = interpret_string(arena, t_text, &error); + if (error.len > 0) { - at = at->next; + JSON_PushError(arena, p, at, error); + goto abort; } else { - JSON_PushError(arena, p, at, Lit("Expected comma.")); - at = at->next; - goto abort; + json->key = key; + at = at->next; } + } + else + { + JSON_PushError(arena, p, at, Lit("Key expected.")); + goto abort; + } + + /* Parse colon */ + if (at->kind == JSON_TokenKind_Colon) + { + at = at->next; + } + else + { + JSON_PushError(arena, p, at, Lit("Colon expected.")); + goto abort; + } + } + + if (parent_json->child_last) + { + parent_json->child_last->next = json; } else { - if (parent_json) - { - if (parent_json->type == JSON_Type_Object) - { - /* Parse key */ - if (at->kind == JSON_TokenKind_String) - { - String t_text = (String) { .len = at->end - at->start, .text = &src.text[at->start] }; - String error = ZI; - String key = interpret_string(arena, t_text, &error); - if (error.len > 0) - { - JSON_PushError(arena, p, at, error); - goto abort; - } - else - { - json->key = key; - at = at->next; - } - } - else - { - JSON_PushError(arena, p, at, Lit("Key expected.")); - goto abort; - } - - /* Parse colon */ - if (at->kind == JSON_TokenKind_Colon) - { - at = at->next; - } - else - { - JSON_PushError(arena, p, at, Lit("Colon expected.")); - goto abort; - } - } - - if (parent_json->child_last) - { - parent_json->child_last->next = json; - } - else - { - parent_json->child_first = json; - } - parent_json->child_last = json; - } - - /* Parse value */ - switch (at->kind) - { - default: - { - JSON_PushError(arena, p, at, Lit("Value expected.")); - at = at->next; - goto abort; - } break; - - case JSON_TokenKind_Number: - { - String t_text = STRING(at->end - at->start, &src.text[at->start]); - f64 value = interpret_number(t_text); - json->type = JSON_Type_Number; - json->value.number = value; - at = at->next; - } break; - - case JSON_TokenKind_String: - { - String t_text = STRING(at->end - at->start, &src.text[at->start]); - String error = ZI; - String value = interpret_string(arena, t_text, &error); - if (error.len > 0) - { - JSON_PushError(arena, p, at, error); - goto abort; - } - else - { - json->type = JSON_Type_String; - json->value.string = value; - at = at->next; - } - } break; - - case JSON_TokenKind_KeywordTrue: - { - json->type = JSON_Type_Bool; - json->value.boolean = 1; - at = at->next; - } break; - - case JSON_TokenKind_KeywordFalse: - { - json->type = JSON_Type_Bool; - json->value.boolean = 0; - at = at->next; - } break; - - case JSON_TokenKind_KeywordNull: - { - json->type = JSON_Type_Null; - at = at->next; - } break; - - case JSON_TokenKind_CurlyBraceOpen: - { - json->type = JSON_Type_Object; - at = at->next; - is_new_parent = 1; - } break; - - case JSON_TokenKind_SquareBraceOpen: - { - json->type = JSON_Type_Array; - at = at->next; - is_new_parent = 1; - } break; - } + parent_json->child_first = json; } + parent_json->child_last = json; + } - if (is_new_parent) + /* Parse value */ + switch (at->kind) + { + default: { - /* Push self back to stack to re-check for closing brace later */ - *PushStructNoZero(scratch.arena, JSON_Blob *) = json; - ++stack_count; + JSON_PushError(arena, p, at, Lit("Value expected.")); + at = at->next; + goto abort; + } break; - /* Create child & push to stack */ - JSON_Blob *child = PushStruct(arena, JSON_Blob); - child->parent = json; - *PushStructNoZero(scratch.arena, JSON_Blob *) = child; - ++stack_count; - } - else if (parent_json) + case JSON_TokenKind_Number: { - /* Check for comma */ - if (at->kind == JSON_TokenKind_Comma) - { - /* Create sibling & push to stack */ - JSON_Blob *sibling = PushStruct(arena, JSON_Blob); - sibling->parent = parent_json; - *PushStructNoZero(scratch.arena, JSON_Blob *) = sibling; - ++stack_count; - at = at->next; - } - } + String t_text = STRING(at->end - at->start, &src.text[at->start]); + f64 value = interpret_number(t_text); + json->type = JSON_Type_Number; + json->value.number = value; + at = at->next; + } break; + + case JSON_TokenKind_String: + { + String t_text = STRING(at->end - at->start, &src.text[at->start]); + String error = ZI; + String value = interpret_string(arena, t_text, &error); + if (error.len > 0) + { + JSON_PushError(arena, p, at, error); + goto abort; + } + else + { + json->type = JSON_Type_String; + json->value.string = value; + at = at->next; + } + } break; + + case JSON_TokenKind_KeywordTrue: + { + json->type = JSON_Type_Bool; + json->value.boolean = 1; + at = at->next; + } break; + + case JSON_TokenKind_KeywordFalse: + { + json->type = JSON_Type_Bool; + json->value.boolean = 0; + at = at->next; + } break; + + case JSON_TokenKind_KeywordNull: + { + json->type = JSON_Type_Null; + at = at->next; + } break; + + case JSON_TokenKind_CurlyBraceOpen: + { + json->type = JSON_Type_Object; + at = at->next; + is_new_parent = 1; + } break; + + case JSON_TokenKind_SquareBraceOpen: + { + json->type = JSON_Type_Array; + at = at->next; + is_new_parent = 1; + } break; + } } -abort: + if (is_new_parent) + { + /* Push self back to stack to re-check for closing brace later */ + *PushStructNoZero(scratch.arena, JSON_Blob *) = json; + ++stack_count; - p->at = at; - p->root = root; + /* Create child & push to stack */ + JSON_Blob *child = PushStruct(arena, JSON_Blob); + child->parent = json; + *PushStructNoZero(scratch.arena, JSON_Blob *) = child; + ++stack_count; + } + else if (parent_json) + { + /* Check for comma */ + if (at->kind == JSON_TokenKind_Comma) + { + /* Create sibling & push to stack */ + JSON_Blob *sibling = PushStruct(arena, JSON_Blob); + sibling->parent = parent_json; + *PushStructNoZero(scratch.arena, JSON_Blob *) = sibling; + ++stack_count; + at = at->next; + } + } + } - EndScratch(scratch); + abort: + + p->at = at; + p->root = root; + + EndScratch(scratch); } JSON_Result JSON_BlobFromString(Arena *arena, String src) { - TempArena scratch = BeginScratch(arena); + TempArena scratch = BeginScratch(arena); - JSON_TokenList tl = JSON_TokensFromString(scratch.arena, src); + JSON_TokenList tl = JSON_TokensFromString(scratch.arena, src); - /* Parse root */ - JSON_Parser p = ZI; - p.src = src; - p.at = tl.token_first; - JSON_Parse(arena, &p); + /* Parse root */ + JSON_Parser p = ZI; + p.src = src; + p.at = tl.token_first; + JSON_Parse(arena, &p); - /* Verify end of file */ - if (p.errors.count == 0 && p.at->kind != JSON_TokenKind_Eof) - { - JSON_PushError(arena, &p, p.at, Lit("Expected end of file.")); - } + /* Verify end of file */ + if (p.errors.count == 0 && p.at->kind != JSON_TokenKind_Eof) + { + JSON_PushError(arena, &p, p.at, Lit("Expected end of file.")); + } - EndScratch(scratch); + EndScratch(scratch); - JSON_Result result = ZI; - result.root = p.root; - result.errors = p.errors; - return result; + JSON_Result result = ZI; + result.root = p.root; + result.errors = p.errors; + return result; } diff --git a/src/json/json.h b/src/json/json.h index 4f413d4a..b1389ca7 100644 --- a/src/json/json.h +++ b/src/json/json.h @@ -3,126 +3,126 @@ Enum(JSON_Type) { - JSON_Type_Null, - JSON_Type_Bool, - JSON_Type_Number, - JSON_Type_String, - JSON_Type_Array, - JSON_Type_Object + JSON_Type_Null, + JSON_Type_Bool, + JSON_Type_Number, + JSON_Type_String, + JSON_Type_Array, + JSON_Type_Object }; Struct(JSON_Blob) { - JSON_Type type; - String key; + JSON_Type type; + String key; - JSON_Blob *parent; - JSON_Blob *next; - JSON_Blob *child_first; - JSON_Blob *child_last; + JSON_Blob *parent; + JSON_Blob *next; + JSON_Blob *child_first; + JSON_Blob *child_last; - union - { - String string; - f64 number; - b32 boolean; - } value; + union + { + String string; + f64 number; + b32 boolean; + } value; }; Struct(JSON_Error) { - String msg; - u64 start; - u64 end; - JSON_Error *next; + String msg; + u64 start; + u64 end; + JSON_Error *next; }; Struct(JSON_ErrorList) { - u64 count; - JSON_Error *first; - JSON_Error *last; + u64 count; + JSON_Error *first; + JSON_Error *last; }; Struct(JSON_Result) { - JSON_Blob *root; - JSON_ErrorList errors; + JSON_Blob *root; + JSON_ErrorList errors; }; //////////////////////////////////////////////////////////// //~ Lexer types #define JSON_Case_Newline \ - 0x0A: /* Line feed or New line */ \ - case 0x0D /* Carriage return */ + 0x0A: /* Line feed or New line */ \ + case 0x0D /* Carriage return */ #define JSON_Case_Space \ - 0x20: /* Space */ \ - case 0x09 /* Horizontal tab */ + 0x20: /* Space */ \ + case 0x09 /* Horizontal tab */ #define JSON_Case_Digit0Through9 \ - '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' + '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' #define JSON_Case_Digit1Through9 \ - '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' + '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' #define JSON_Case_Symbol \ - ',': case ':': case '[': case ']': case '{': case '}' + ',': case ':': case '[': case ']': case '{': case '}' Enum(JSON_TokenKind) { - JSON_TokenKind_Unknown, + JSON_TokenKind_Unknown, - JSON_TokenKind_Number, - JSON_TokenKind_String, + JSON_TokenKind_Number, + JSON_TokenKind_String, - JSON_TokenKind_KeywordTrue, - JSON_TokenKind_KeywordFalse, - JSON_TokenKind_KeywordNull, + JSON_TokenKind_KeywordTrue, + JSON_TokenKind_KeywordFalse, + JSON_TokenKind_KeywordNull, - JSON_TokenKind_Comma, - JSON_TokenKind_Colon, - JSON_TokenKind_SquareBraceOpen, - JSON_TokenKind_SquareBraceClose, - JSON_TokenKind_CurlyBraceOpen, - JSON_TokenKind_CurlyBraceClose, + JSON_TokenKind_Comma, + JSON_TokenKind_Colon, + JSON_TokenKind_SquareBraceOpen, + JSON_TokenKind_SquareBraceClose, + JSON_TokenKind_CurlyBraceOpen, + JSON_TokenKind_CurlyBraceClose, - JSON_TokenKind_Bof, - JSON_TokenKind_Eof + JSON_TokenKind_Bof, + JSON_TokenKind_Eof }; Struct(JSON_Token) { - JSON_TokenKind kind; - u64 start; - u64 end; - JSON_Token *next; + JSON_TokenKind kind; + u64 start; + u64 end; + JSON_Token *next; }; Struct(JSON_TokenList) { - JSON_Token *token_first; - JSON_Token *token_last; + JSON_Token *token_first; + JSON_Token *token_last; }; Enum(JSON_LexNumberState) { - JSON_LexNumberState_Whole, - JSON_LexNumberState_Fraction, - JSON_LexNumberState_Exponent + JSON_LexNumberState_Whole, + JSON_LexNumberState_Fraction, + JSON_LexNumberState_Exponent }; Global Readonly String JSON_keyword_strings[] = { - ['t'] = CompLit("true"), - ['f'] = CompLit("false"), - ['n'] = CompLit("null") + ['t'] = CompLit("true"), + ['f'] = CompLit("false"), + ['n'] = CompLit("null") }; Global Readonly JSON_TokenKind JSON_keyword_types[] = { - ['t'] = JSON_TokenKind_KeywordTrue, - ['f'] = JSON_TokenKind_KeywordFalse, - ['n'] = JSON_TokenKind_KeywordNull + ['t'] = JSON_TokenKind_KeywordTrue, + ['f'] = JSON_TokenKind_KeywordFalse, + ['n'] = JSON_TokenKind_KeywordNull }; //////////////////////////////////////////////////////////// @@ -130,13 +130,13 @@ Global Readonly JSON_TokenKind JSON_keyword_types[] = { Struct(JSON_Parser) { - /* Input */ - String src; - JSON_Token *at; + /* Input */ + String src; + JSON_Token *at; - /* Output */ - JSON_Blob *root; - JSON_ErrorList errors; + /* Output */ + JSON_Blob *root; + JSON_ErrorList errors; }; //////////////////////////////////////////////////////////// diff --git a/src/meta/meta.c b/src/meta/meta.c index 727b6bcb..f20b9922 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -7,241 +7,243 @@ BuildCtx Build = Zi; i32 GetBuildStatus(void) { - return Atomic32Fetch(&Build.status); + return Atomic32Fetch(&Build.status); } void SetBuildStatus(i32 code) { - Atomic32FetchTestSet(&Build.status, 0, code); + Atomic32FetchTestSet(&Build.status, 0, code); } void EchoLine(String msg) { - TempArena scratch = BeginScratchNoConflict(); - { - String msg_w_newline = StringF(scratch.arena, "%F\n", FmtString(msg)); - Echo(msg_w_newline); - } - EndScratch(scratch); + TempArena scratch = BeginScratchNoConflict(); + { + String msg_w_newline = StringF(scratch.arena, "%F\n", FmtString(msg)); + Echo(msg_w_newline); + } + EndScratch(scratch); } void EchoLineOrNothing(String msg) { - String trimmed_msg = TrimWhitespace(msg); - if (trimmed_msg.len > 0) - { - EchoLine(trimmed_msg); - } + String trimmed_msg = TrimWhitespace(msg); + if (trimmed_msg.len > 0) + { + EchoLine(trimmed_msg); + } } LineCol LineColFromPos(String data, i64 pos) { - TempArena scratch = BeginScratchNoConflict(); - LineCol result = Zi; - for (u64 cur = 0; cur < data.len && cur <= (u64)pos; ++cur) + TempArena scratch = BeginScratchNoConflict(); + LineCol result = Zi; + for (u64 cur = 0; cur < data.len && cur <= (u64)pos; ++cur) + { + u8 c = data.text[cur]; + if (c == '\n') { - u8 c = data.text[cur]; - if (c == '\n') - { - ++result.line; - result.col = 0; - } - else if (c != '\r') - { - ++result.col; - } + ++result.line; + result.col = 0; } - result.line += 1; - EndScratch(scratch); - return result; + else if (c != '\r') + { + ++result.col; + } + } + result.line += 1; + EndScratch(scratch); + return result; } String StringFromMetaErrors(Arena *arena, M_ErrorList errors) { - TempArena scratch = BeginScratch(arena); + TempArena scratch = BeginScratch(arena); - StringList error_strings = Zi; - for (M_Error *e = errors.first; e; e = e->next) + StringList error_strings = Zi; + for (M_Error *e = errors.first; e; e = e->next) + { + M_Token *token = e->token; + String token_file = token->file->name; + String token_file_data = token->file->data; + if (token_file.len > 0) { - M_Token *token = e->token; - String token_file = token->file->name; - String token_file_data = token->file->data; - if (token_file.len > 0) - { - i64 token_pos = -1; - if (token->s.len > 0 - && token_file_data.len > 0 - && token->s.text > token_file_data.text - && token->s.text < (token_file_data.text + token_file_data.len)) - { - token_pos = token->s.text - token_file_data.text; - } - LineCol line_col = Zi; - if (token_pos >= 0) - { - line_col = LineColFromPos(token_file_data, token_pos); - } - String formatted = StringF( - scratch.arena, - "%F:%F:%F: error: %F", - FmtString(token_file), - FmtSint(line_col.line), - FmtSint(line_col.col), - FmtString(e->msg) - ); - PushStringToList(scratch.arena, &error_strings, formatted); - } - else - { - PushStringToList(scratch.arena, &error_strings, StringF(scratch.arena, "error: %F", FmtString(e->msg))); - } + i64 token_pos = -1; + if ( + token->s.len > 0 + && token_file_data.len > 0 + && token->s.text > token_file_data.text + && token->s.text < (token_file_data.text + token_file_data.len) + ) + { + token_pos = token->s.text - token_file_data.text; + } + LineCol line_col = Zi; + if (token_pos >= 0) + { + line_col = LineColFromPos(token_file_data, token_pos); + } + String formatted = StringF( + scratch.arena, + "%F:%F:%F: error: %F", + FmtString(token_file), + FmtSint(line_col.line), + FmtSint(line_col.col), + FmtString(e->msg) + ); + PushStringToList(scratch.arena, &error_strings, formatted); } + else + { + PushStringToList(scratch.arena, &error_strings, StringF(scratch.arena, "error: %F", FmtString(e->msg))); + } + } - String result = StringFromList(arena, error_strings, Lit("\n")); + String result = StringFromList(arena, error_strings, Lit("\n")); - EndScratch(scratch); - return result; + EndScratch(scratch); + return result; } EmbedObj Embed(String store_name, String dir_path) { - Arena *perm = PermArena(); - EmbedObj result = Zi; + Arena *perm = PermArena(); + EmbedObj result = Zi; - /* Generate resource archive contents */ - String arc_contents = Zi; + /* Generate resource archive contents */ + String arc_contents = Zi; + { + StringList files = Zi; + F_FilesFromDir(perm, &files, dir_path, F_IterFlag_Recurse); + + Struct(EntryNode) { - StringList files = Zi; - F_FilesFromDir(perm, &files, dir_path, F_IterFlag_Recurse); - - Struct(EntryNode) + EntryNode *next; + String entry_name; + String file_name; + }; + EntryNode *first_entry = 0; + EntryNode *last_entry = 0; + u64 entries_count = 0; + for (StringListNode *file_node = files.first; file_node; file_node = file_node->next) + { + String file_name = file_node->s; + if (F_IsFile(file_name)) + { + String entry_name = file_name; + if (entry_name.len > (dir_path.len + 1)) { - EntryNode *next; - String entry_name; - String file_name; - }; - EntryNode *first_entry = 0; - EntryNode *last_entry = 0; - u64 entries_count = 0; - for (StringListNode *file_node = files.first; file_node; file_node = file_node->next) + entry_name.len -= dir_path.len + 1; + entry_name.text += dir_path.len + 1; + } + entry_name = StringF(perm, "%F/%F", FmtString(store_name), FmtString(entry_name)); + for (u64 i = 0; i < entry_name.len; ++i) { - String file_name = file_node->s; - if (F_IsFile(file_name)) - { - String entry_name = file_name; - if (entry_name.len > (dir_path.len + 1)) - { - entry_name.len -= dir_path.len + 1; - entry_name.text += dir_path.len + 1; - } - entry_name = StringF(perm, "%F/%F", FmtString(store_name), FmtString(entry_name)); - for (u64 i = 0; i < entry_name.len; ++i) - { - if (entry_name.text[i] == '\\') - { - entry_name.text[i] = '/'; - } - } - - EntryNode *en = PushStruct(perm, EntryNode); - en->entry_name = entry_name; - en->file_name = file_name; - SllQueuePush(first_entry, last_entry, en); - ++entries_count; - } + if (entry_name.text[i] == '\\') + { + entry_name.text[i] = '/'; + } } - BB_Buff bb = BB_AcquireBuff(Gibi(2)); - BB_Writer bw = BB_WriterFromBuff(&bb); - - /* Write magic */ - BB_WriteUBits(&bw, ResourceEmbeddedMagic, 64); - - /* Write header */ - BB_WriteUBits(&bw, entries_count, 64); - - /* Reserve entries space */ - u64 entry_size = 8 /* Name start */ - + 8 /* Name end */ - + 8 /* Data start */ - + 8; /* Data end */ - u8 *entries_start = BB_GetWrittenRaw(&bw) + BB_GetNumBytesWritten(&bw); - u64 entries_size = entry_size * entries_count; - String entries_str = STRING(entries_size, entries_start); - BB_WriteSeekBytes(&bw, entries_size); - BB_Buff entries_bb = BB_BuffFromString(entries_str); - BB_Writer entries_bw = BB_WriterFromBuff(&entries_bb); - - /* Write entries */ - for (EntryNode *en = first_entry; en; en = en->next) - { - /* TODO: Copy file data directly into archive file */ - String file_data = F_DataFromFile(perm, en->file_name); - - /* Write name */ - BB_WriteAlignBytes(&bw, 64); - u64 name_start = BB_GetNumBytesWritten(&bw) + 1; - BB_WriteString(&bw, en->entry_name); - u64 name_len = BB_GetNumBytesWritten(&bw) - name_start; - - /* Write data */ - BB_WriteAlignBytes(&bw, 64); - /* FIXME: Why no +1 here? */ - u64 data_start = BB_GetNumBytesWritten(&bw); - BB_WriteBytes(&bw, file_data); - u64 data_len = BB_GetNumBytesWritten(&bw) - data_start; - - /* Write entry */ - BB_WriteUBits(&entries_bw, name_start, 64); - BB_WriteUBits(&entries_bw, name_len, 64); - BB_WriteUBits(&entries_bw, data_start, 64); - BB_WriteUBits(&entries_bw, data_len, 64); - } - - arc_contents.len = BB_GetNumBytesWritten(&bw); - arc_contents.text = BB_GetWrittenRaw(&bw); + EntryNode *en = PushStruct(perm, EntryNode); + en->entry_name = entry_name; + en->file_name = file_name; + SllQueuePush(first_entry, last_entry, en); + ++entries_count; + } } - /* Write archive to file */ - String arc_path = StringF(perm, "%F.arc", FmtString(store_name)); - F_ClearWrite(arc_path, arc_contents); + BB_Buff bb = BB_AcquireBuff(Gibi(2)); + BB_Writer bw = BB_WriterFromBuff(&bb); - /* Generate object file */ - if (IsPlatformWindows) + /* Write magic */ + BB_WriteUBits(&bw, ResourceEmbeddedMagic, 64); + + /* Write header */ + BB_WriteUBits(&bw, entries_count, 64); + + /* Reserve entries space */ + u64 entry_size = 8 /* Name start */ + + 8 /* Name end */ + + 8 /* Data start */ + + 8; /* Data end */ + u8 *entries_start = BB_GetWrittenRaw(&bw) + BB_GetNumBytesWritten(&bw); + u64 entries_size = entry_size * entries_count; + String entries_str = STRING(entries_size, entries_start); + BB_WriteSeekBytes(&bw, entries_size); + BB_Buff entries_bb = BB_BuffFromString(entries_str); + BB_Writer entries_bw = BB_WriterFromBuff(&entries_bb); + + /* Write entries */ + for (EntryNode *en = first_entry; en; en = en->next) { - /* Generate RC file */ - String rc_out_file = StringF(perm, "%F.rc", FmtString(store_name)); - { - RandState rs = Zi; - StringList rc_out_lines = Zi; - String arc_file_cp = F_GetFullCrossPlatform(perm, arc_path); - String line = StringF(perm, "%F_%F RCDATA \"%F\"", FmtString(Lit(Stringize(W32_EmbeddedDataPrefix))), FmtHex(RandU64FromState(&rs)), FmtString(arc_file_cp)); - PushStringToList(perm, &rc_out_lines, line); - /* Write to file */ - String rc_out = StringFromList(perm, rc_out_lines, Lit("\n")); - F_ClearWrite(rc_out_file, rc_out); - } + /* TODO: Copy file data directly into archive file */ + String file_data = F_DataFromFile(perm, en->file_name); - /* Compile RC file */ - result.obj_file = StringF(perm, "%F.res", FmtString(store_name)); - { - result.obj_file, FmtString(F_GetFull(perm, rc_out_file)); - String cmd = StringF(perm, "rc.exe -nologo -fo %F %F", FmtString(result.obj_file), FmtString(F_GetFull(perm, rc_out_file))); - OS_CommandResult cmd_result = OS_RunCommand(perm, cmd); - String cmd_output = TrimWhitespace(cmd_result.output); - result.output = cmd_output; - result.return_code = cmd_result.code; - } + /* Write name */ + BB_WriteAlignBytes(&bw, 64); + u64 name_start = BB_GetNumBytesWritten(&bw) + 1; + BB_WriteString(&bw, en->entry_name); + u64 name_len = BB_GetNumBytesWritten(&bw) - name_start; - SetBuildStatus(result.return_code); - } - else - { - /* TODO: Generate object files using .incbin on non-windows platforms */ - Panic(Lit("Resource embedding not implemented for this platform")); + /* Write data */ + BB_WriteAlignBytes(&bw, 64); + /* FIXME: Why no +1 here? */ + u64 data_start = BB_GetNumBytesWritten(&bw); + BB_WriteBytes(&bw, file_data); + u64 data_len = BB_GetNumBytesWritten(&bw) - data_start; + + /* Write entry */ + BB_WriteUBits(&entries_bw, name_start, 64); + BB_WriteUBits(&entries_bw, name_len, 64); + BB_WriteUBits(&entries_bw, data_start, 64); + BB_WriteUBits(&entries_bw, data_len, 64); } - return result; + arc_contents.len = BB_GetNumBytesWritten(&bw); + arc_contents.text = BB_GetWrittenRaw(&bw); + } + + /* Write archive to file */ + String arc_path = StringF(perm, "%F.arc", FmtString(store_name)); + F_ClearWrite(arc_path, arc_contents); + + /* Generate object file */ + if (IsPlatformWindows) + { + /* Generate RC file */ + String rc_out_file = StringF(perm, "%F.rc", FmtString(store_name)); + { + RandState rs = Zi; + StringList rc_out_lines = Zi; + String arc_file_cp = F_GetFullCrossPlatform(perm, arc_path); + String line = StringF(perm, "%F_%F RCDATA \"%F\"", FmtString(Lit(Stringize(W32_EmbeddedDataPrefix))), FmtHex(RandU64FromState(&rs)), FmtString(arc_file_cp)); + PushStringToList(perm, &rc_out_lines, line); + /* Write to file */ + String rc_out = StringFromList(perm, rc_out_lines, Lit("\n")); + F_ClearWrite(rc_out_file, rc_out); + } + + /* Compile RC file */ + result.obj_file = StringF(perm, "%F.res", FmtString(store_name)); + { + result.obj_file, FmtString(F_GetFull(perm, rc_out_file)); + String cmd = StringF(perm, "rc.exe -nologo -fo %F %F", FmtString(result.obj_file), FmtString(F_GetFull(perm, rc_out_file))); + OS_CommandResult cmd_result = OS_RunCommand(perm, cmd); + String cmd_output = TrimWhitespace(cmd_result.output); + result.output = cmd_output; + result.return_code = cmd_result.code; + } + + SetBuildStatus(result.return_code); + } + else + { + /* TODO: Generate object files using .incbin on non-windows platforms */ + Panic(Lit("Resource embedding not implemented for this platform")); + } + + return result; } //////////////////////////////////////////////////////////// @@ -249,767 +251,767 @@ EmbedObj Embed(String store_name, String dir_path) void BuildEntryPoint(WaveLaneCtx *lane) { - Arena *perm = PermArena(); + Arena *perm = PermArena(); - ////////////////////////////// - //- Dirty check + ////////////////////////////// + //- Dirty check - /* Return rebuild code if metaprogram is dirty */ - if (lane->idx == 0) + /* Return rebuild code if metaprogram is dirty */ + if (lane->idx == 0) + { + /* Read old metahash */ + u64 old_metahash = 0; + if (F_IsFile(Lit("metahash.dat"))) { - /* Read old metahash */ - u64 old_metahash = 0; - if (F_IsFile(Lit("metahash.dat"))) - { - String hashes_str = F_DataFromFile(perm, Lit("metahash.dat")); - if (hashes_str.len == sizeof(old_metahash)) - { - CopyBytes(&old_metahash, hashes_str.text, sizeof(old_metahash)); - } - OS_Rm(Lit("metahash.dat")); - } - - /* Compute new metahash */ - u64 new_metahash = 0; - { - StringList check_files = Zi; - F_FilesFromDir(perm, &check_files, Lit("../src/base"), F_IterFlag_Recurse); - F_FilesFromDir(perm, &check_files, Lit("../src/meta"), F_IterFlag_Recurse); - PushStringToList(perm, &check_files, Lit("../src/config.h")); - for (StringListNode *n = check_files.first; n; n = n->next) - { - String file = n->s; - new_metahash = RandU64FromSeeds(HashFnv64(new_metahash, file), OS_LastWriteTimestampFromPath(file)); - } - } - - /* Exit if metaprogram needs recompilation */ - if (old_metahash == 0 || old_metahash == new_metahash) - { - F_ClearWrite(Lit("metahash.dat"), StringFromStruct(&new_metahash)); - } - else - { - EchoLine(Lit("Metaprogram is dirty")); - ExitNow(MetaRebuildCode); - } + String hashes_str = F_DataFromFile(perm, Lit("metahash.dat")); + if (hashes_str.len == sizeof(old_metahash)) + { + CopyBytes(&old_metahash, hashes_str.text, sizeof(old_metahash)); + } + OS_Rm(Lit("metahash.dat")); } - ////////////////////////////// - //- Command line - - Struct(CmdLineArgs) + /* Compute new metahash */ + u64 new_metahash = 0; { - String leaf_layer_name; - }; - CmdLineArgs cmdline = Zi; - { - CommandlineArg layer_arg = CommandlineArgFromName(Lit("layer")); - String layer_name = Zi; - if (layer_arg.name.len != 0) - { - layer_name = layer_arg.value; - } - else - { - layer_name = StringFromCommandlineIdx(1); - } - if (layer_name.len == 0) - { - layer_name = Lit("pp"); - if (lane->idx == 0) - { - EchoLine(Lit("No layer supplied, assuming \"pp\" build")); - } - } - cmdline.leaf_layer_name = layer_name; + StringList check_files = Zi; + F_FilesFromDir(perm, &check_files, Lit("../src/base"), F_IterFlag_Recurse); + F_FilesFromDir(perm, &check_files, Lit("../src/meta"), F_IterFlag_Recurse); + PushStringToList(perm, &check_files, Lit("../src/config.h")); + for (StringListNode *n = check_files.first; n; n = n->next) + { + String file = n->s; + new_metahash = RandU64FromSeeds(HashFnv64(new_metahash, file), OS_LastWriteTimestampFromPath(file)); + } } - if (lane->idx == 0) + /* Exit if metaprogram needs recompilation */ + if (old_metahash == 0 || old_metahash == new_metahash) { - EchoLine(StringF(perm, "Building layer \"%F\"", FmtString(cmdline.leaf_layer_name))); + F_ClearWrite(Lit("metahash.dat"), StringFromStruct(&new_metahash)); + } + else + { + EchoLine(Lit("Metaprogram is dirty")); + ExitNow(MetaRebuildCode); + } + } + + ////////////////////////////// + //- Command line + + Struct(CmdLineArgs) + { + String leaf_layer_name; + }; + CmdLineArgs cmdline = Zi; + { + CommandlineArg layer_arg = CommandlineArgFromName(Lit("layer")); + String layer_name = Zi; + if (layer_arg.name.len != 0) + { + layer_name = layer_arg.value; + } + else + { + layer_name = StringFromCommandlineIdx(1); + } + if (layer_name.len == 0) + { + layer_name = Lit("pp"); + if (lane->idx == 0) + { + EchoLine(Lit("No layer supplied, assuming \"pp\" build")); + } + } + cmdline.leaf_layer_name = layer_name; + } + + if (lane->idx == 0) + { + EchoLine(StringF(perm, "Building layer \"%F\"", FmtString(cmdline.leaf_layer_name))); + } + + ////////////////////////////// + //- Generate compiler params + + CompilerParams cp = Zi; + { + //- Common + { + PushStringToList(perm, &cp.defs, Lit("-DIsConsoleApp=0")); + PushStringToList(perm, &cp.defs, Lit("-DIsRtcEnabled=1")); + PushStringToList(perm, &cp.defs, Lit("-DIsAsanEnabled=0")); + PushStringToList(perm, &cp.defs, Lit("-DIsCrtlibEnabled=1")); + PushStringToList(perm, &cp.defs, Lit("-DIsDebinfoEnabled=1")); + PushStringToList(perm, &cp.defs, Lit("-DIsDeveloperModeEnabled=1")); + PushStringToList(perm, &cp.defs, Lit("-DIsUnoptimized=1")); + PushStringToList(perm, &cp.defs, Lit("-DIsTestingEnabled=0")); + PushStringToList(perm, &cp.defs, Lit("-DIsHotSwappingEnabled=1")); } - ////////////////////////////// - //- Generate compiler params - - CompilerParams cp = Zi; + //- Msvc { - //- Common - { - PushStringToList(perm, &cp.defs, Lit("-DIsConsoleApp=0")); - PushStringToList(perm, &cp.defs, Lit("-DIsRtcEnabled=1")); - PushStringToList(perm, &cp.defs, Lit("-DIsAsanEnabled=0")); - PushStringToList(perm, &cp.defs, Lit("-DIsCrtlibEnabled=1")); - PushStringToList(perm, &cp.defs, Lit("-DIsDebinfoEnabled=1")); - PushStringToList(perm, &cp.defs, Lit("-DIsDeveloperModeEnabled=1")); - PushStringToList(perm, &cp.defs, Lit("-DIsUnoptimized=1")); - PushStringToList(perm, &cp.defs, Lit("-DIsTestingEnabled=0")); - PushStringToList(perm, &cp.defs, Lit("-DIsHotSwappingEnabled=1")); - } + PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-diagnostics:column")); + PushStringToList(perm, &cp.flags_msvc, Lit("-INCREMENTAL:NO")); + PushStringToList(perm, &cp.flags_msvc, Lit("-nologo")); - //- Msvc - { - PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-diagnostics:column")); - PushStringToList(perm, &cp.flags_msvc, Lit("-INCREMENTAL:NO")); - PushStringToList(perm, &cp.flags_msvc, Lit("-nologo")); + /* Optimization */ + PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Od")); - /* Optimization */ - PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Od")); + /* Debug info */ + PushStringToList(perm, &cp.flags_msvc, Lit("-DEBUG:FULL")); + PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Z7")); - /* Debug info */ - PushStringToList(perm, &cp.flags_msvc, Lit("-DEBUG:FULL")); - PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Z7")); + /* Enable warnings */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-W4")); + PushStringToList(perm, &cp.warnings_msvc, Lit("-WX")); + // PushStringToList(perm, &cp.warnings_msvc, Lit("-we4013")); /* function undefined; assuming extern returning int */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-we4668")); /* 'X' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ - /* Enable warnings */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-W4")); - PushStringToList(perm, &cp.warnings_msvc, Lit("-WX")); - // PushStringToList(perm, &cp.warnings_msvc, Lit("-we4013")); /* function undefined; assuming extern returning int */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-we4668")); /* 'X' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ + /* Disable warnings */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4244")); /* 'function': conversion from 'int' to 'f32', possible loss of data */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4201")); /* nonstandard extension used: nameless struct/union */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4324")); /* structure was padded due to alignment specifier */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4100")); /* unreferenced parameter */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4101")); /* unreferenced local variable */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4189")); /* local variable is initialized but not referenced */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4200")); /* nonstandard extension used: zero-sized array in struct/union */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4702")); /* unreachable code */ + PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4305")); /* 'initializing': truncation from 'double' to 'f32' */ - /* Disable warnings */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4244")); /* 'function': conversion from 'int' to 'f32', possible loss of data */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4201")); /* nonstandard extension used: nameless struct/union */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4324")); /* structure was padded due to alignment specifier */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4100")); /* unreferenced parameter */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4101")); /* unreferenced local variable */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4189")); /* local variable is initialized but not referenced */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4200")); /* nonstandard extension used: zero-sized array in struct/union */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4702")); /* unreachable code */ - PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4305")); /* 'initializing': truncation from 'double' to 'f32' */ - - // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4127")); /* conditional expression is constant */ - // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4820")); /* bytes padding added after data member */ - // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4464")); /* relative include path contains '..' */ - // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4061")); /* enumerator is not explicitly handled by a case label */ - // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4242")); /* conversion from X to Y, possible loss of data */ - // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4388")); /* signed/unsigned mismatch */ - // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd5045")); /* Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified */ - } - - //- Clang - { - PushStringToList(perm, &cp.flags_clang, Lit("-std=c99")); - PushStringToList(perm, &cp.flags_clang, Lit("-fno-finite-loops")); - PushStringToList(perm, &cp.flags_clang, Lit("-fno-strict-aliasing")); - PushStringToList(perm, &cp.flags_clang, Lit("-g -gcodeview")); - PushStringToList(perm, &cp.flags_clang, Lit("-O0")); - PushStringToList(perm, &cp.flags_clang, Lit("-msse4.2")); - - /* Enable warnings */ - PushStringToList(perm, &cp.warnings_clang, Lit("-Wall")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Werror")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wframe-larger-than=65536")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wmissing-prototypes")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wmissing-declarations")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wunused-variable")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wunused-but-set-variable")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wunused-parameter")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wimplicit-fallthrough")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wswitch")); - - /* Disable warnings */ - PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-initializer-overrides")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-microsoft-enum-forward-reference")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-unused-variable")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-unused-parameter")); - PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-incompatible-function-pointer-types")); - } - - //- Dxc - { - // PushStringToList(perm, &cp.flags_dxc, Lit("-Od")); - PushStringToList(perm, &cp.flags_dxc, Lit("-O3")); - PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug")); - } + // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4127")); /* conditional expression is constant */ + // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4820")); /* bytes padding added after data member */ + // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4464")); /* relative include path contains '..' */ + // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4061")); /* enumerator is not explicitly handled by a case label */ + // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4242")); /* conversion from X to Y, possible loss of data */ + // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4388")); /* signed/unsigned mismatch */ + // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd5045")); /* Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified */ } - ////////////////////////////// - //- Phase 1/3: Prep - - /* - * Phase 1/3: Prep (narrow) - * - Parse layers - * - Generate final C file - * - Generate final HLSL file - * - Generate resource dirs info - * - * Phase 2/3: Compile (wide) - * - Compile C - * - Compile & embed shaders - * - Embed resource dirs - * - * Phase 3/3: Link (narrow) - * - Link - */ - - /* TODO: Dispatch OS commands asynchronously */ - - String shader_store_name = Lit("ShadersStore"); - String c_out_file = F_GetFull(perm, StringF(perm, "%F_gen.c", FmtString(cmdline.leaf_layer_name))); - String gpu_out_file = F_GetFull(perm, StringF(perm, "%F_gen.g", FmtString(cmdline.leaf_layer_name))); - - if (lane->idx == 0 && GetBuildStatus() == 0) + //- Clang { - //- Parse layers - { - /* Lex */ - StringList src_dirs = Zi; - PushStringToList(perm, &src_dirs, Lit("../src")); - M_TokenFileList lexed = M_TokensFromSrcDirs(perm, src_dirs); + PushStringToList(perm, &cp.flags_clang, Lit("-std=c99")); + PushStringToList(perm, &cp.flags_clang, Lit("-fno-finite-loops")); + PushStringToList(perm, &cp.flags_clang, Lit("-fno-strict-aliasing")); + PushStringToList(perm, &cp.flags_clang, Lit("-g -gcodeview")); + PushStringToList(perm, &cp.flags_clang, Lit("-O0")); + PushStringToList(perm, &cp.flags_clang, Lit("-msse4.2")); - /* Parse */ - M_LayerList parsed = M_LayersFromTokenFiles(perm, lexed);; + /* Enable warnings */ + PushStringToList(perm, &cp.warnings_clang, Lit("-Wall")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Werror")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wframe-larger-than=65536")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wmissing-prototypes")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wmissing-declarations")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wunused-variable")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wunused-but-set-variable")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wunused-parameter")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wimplicit-fallthrough")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wswitch")); - /* Flatten */ - StringList starting_layer_names = Zi; - PushStringToList(perm, &starting_layer_names, cmdline.leaf_layer_name); - Build.layers_parse = M_FlattenEntries(perm, parsed, starting_layer_names); - - SetBuildStatus(Build.layers_parse.errors.count > 0); - } - - //- Generate C file - { - StringList c_store_lines = Zi; - StringList c_shader_lines = Zi; - StringList c_include_lines = Zi; - StringList c_bootstrap_lines = Zi; - { - for (M_Entry *entry = Build.layers_parse.first; entry->valid; entry = entry->next) - { - M_EntryKind kind = entry->kind; - M_Token *entry_tok = entry->name_token; - M_Token *arg0_tok = entry->arg_tokens[0]; - M_Token *arg1_tok = entry->arg_tokens[1]; - switch (kind) - { - default: break; - case M_EntryKind_EmbedDir: - { - if (arg0_tok->valid && arg1_tok->valid) - { - String store_name = arg0_tok->s; - String token_file = arg1_tok->file->name; - String token_parent_dir = F_GetParentDir(token_file); - String arg_dir = arg1_tok->s; - String full = F_GetFullCrossPlatform(perm, StringF(perm, "%F/%F", FmtString(token_parent_dir), FmtString(arg_dir))); - if (F_IsDir(full)) - { - u64 hash = HashFnv64(Fnv64Basis, StringF(perm, "%F/", FmtString(store_name))); - String line = StringF(perm, "ResourceStore %F = { 0x%F };", FmtString(store_name), FmtHex(hash)); - PushStringToList(perm, &c_store_lines, line); - } - else - { - String err = StringF(perm, "Directory '%F' not found", FmtString(full)); - M_PushError(perm, &Build.c_parse.errors, arg1_tok, err); - } - } - else - { - M_PushError(perm, &Build.c_parse.errors, entry_tok, Lit("Expected resource store & directory name")); - } - } break; - case M_EntryKind_VertexShader: - case M_EntryKind_PixelShader: - case M_EntryKind_ComputeShader: - { - if (arg0_tok->valid) - { - String shader_type = kind == M_EntryKind_VertexShader ? Lit("VertexShader") - : kind == M_EntryKind_PixelShader ? Lit("PixelShader") - : kind == M_EntryKind_ComputeShader ? Lit("ComputeShader") - : Lit(""); - String shader_name = arg0_tok->s; - u64 hash = HashFnv64(Fnv64Basis, StringF(perm, "%F/%F", FmtString(shader_store_name), FmtString(shader_name))); - String line = StringF(perm, "%F %F = { 0x%F };", FmtString(shader_type), FmtString(shader_name), FmtHex(hash)); - PushStringToList(perm, &c_shader_lines, line); - } - else - { - M_PushError(perm, &Build.c_parse.errors, entry_tok, Lit("Expected shader name")); - } - } break; - case M_EntryKind_IncludeC: - { - if (arg0_tok->valid) - { - String token_file = arg0_tok->file->name; - String token_parent_dir = F_GetParentDir(token_file); - String arg_file = arg0_tok->s; - String full = F_GetFull(perm, StringF(perm, "%F/%F", FmtString(token_parent_dir), FmtString(arg_file))); - if (F_IsFile(full)) - { - String line = StringF(perm, "#include \"%F\"", FmtString(full)); - PushStringToList(perm, &c_include_lines, line); - } - else - { - String err = StringF(perm, "File '%F' not found", FmtString(full)); - M_PushError(perm, &Build.c_parse.errors, arg0_tok, err); - } - } - else - { - M_PushError(perm, &Build.c_parse.errors, entry_tok, Lit("Expected file name")); - } - } break; - case M_EntryKind_Bootstrap: - { - if (arg0_tok->valid) - { - String bootstrap = arg0_tok->s; - String line = StringF(perm, " %F();", FmtString(bootstrap)); - PushStringToList(perm, &c_bootstrap_lines, line); - } - else - { - M_PushError(perm, &Build.c_parse.errors, entry_tok, Lit("Expected bootstrap function name")); - } - } break; - } - } - } - if (Build.c_parse.errors.count == 0) - { - StringList c_out_lines = Zi; - PushStringToList(perm, &c_out_lines, Lit("// Auto generated file")); - /* Include base layer */ - { - String base_inc_path = F_GetFull(perm, Lit("../src/base/base_inc.h")); - PushStringToList(perm, &c_out_lines, Lit("")); - PushStringToList(perm, &c_out_lines, Lit("//- Base layer includes")); - PushStringToList(perm, &c_out_lines, StringF(perm, "#include \"%F\"", FmtString(base_inc_path))); - } - /* Define resource stores */ - if (c_store_lines.count > 0) - { - PushStringToList(perm, &c_out_lines, Lit("")); - PushStringToList(perm, &c_out_lines, Lit("//- Resource stores")); - for (StringListNode *n = c_store_lines.first; n; n = n->next) - { - PushStringToList(perm, &c_out_lines, n->s); - } - } - /* Define shaders */ - if (c_shader_lines.count > 0) - { - PushStringToList(perm, &c_out_lines, Lit("")); - PushStringToList(perm, &c_out_lines, Lit("//- Shaders")); - for (StringListNode *n = c_shader_lines.first; n; n = n->next) - { - PushStringToList(perm, &c_out_lines, n->s); - } - } - /* Include dependency layers */ - if (c_include_lines.count > 0) - { - PushStringToList(perm, &c_out_lines, Lit("")); - PushStringToList(perm, &c_out_lines, Lit("//- Dependency graph includes")); - for (StringListNode *n = c_include_lines.first; n; n = n->next) - { - PushStringToList(perm, &c_out_lines, n->s); - } - } - /* Define BootstrapLayers */ - { - PushStringToList(perm, &c_out_lines, Lit("")); - PushStringToList(perm, &c_out_lines, Lit("//- Bootstrap")); - PushStringToList(perm, &c_out_lines, Lit("void BootstrapLayers(void)")); - PushStringToList(perm, &c_out_lines, Lit("{")); - for (StringListNode *n = c_bootstrap_lines.first; n; n = n->next) - { - PushStringToList(perm, &c_out_lines, n->s); - } - PushStringToList(perm, &c_out_lines, Lit("}")); - } - /* Write to file */ - PushStringToList(perm, &c_out_lines, Lit("")); - String c_out = StringFromList(perm, c_out_lines, Lit("\n")); - F_ClearWrite(c_out_file, c_out); - } - - SetBuildStatus(Build.c_parse.errors.count > 0); - } - - //- Generate HLSL file - { - /* Clear shader store */ - /* TODO: Move to separate artifacts dir that gets cleared, including archive files */ - OS_Mkdir(shader_store_name); - { - /* Remove all old shaders */ - StringList files = Zi; - F_FilesFromDir(perm, &files, shader_store_name, F_IterFlag_None); - for (StringListNode *n = files.first; n; n = n->next) - { - String file = n->s; - /* Safety check to prevent non-shader files from being removed */ - if (StringEndsWith(file, Lit("VS")) || StringEndsWith(file, Lit("CS")) || StringEndsWith(file, Lit("PS"))) - { - OS_Rm(n->s); - } - else - { - /* Unexpected file in shader store */ - Assert(0); - } - } - } - - /* Generate GPU file & shader entries */ - { - StringList gpu_include_lines = Zi; - { - for (M_Entry *entry = Build.layers_parse.first; entry->valid; entry = entry->next) - { - M_EntryKind kind = entry->kind; - M_Token *entry_tok = entry->name_token; - M_Token *arg0_tok = entry->arg_tokens[0]; - M_Token *arg1_tok = entry->arg_tokens[1]; - switch (kind) - { - default: break; - case M_EntryKind_IncludeG: - { - if (arg0_tok->valid) - { - String token_file = arg0_tok->file->name; - String token_parent_dir = F_GetParentDir(token_file); - String arg_file = arg0_tok->s; - String full = F_GetFull(perm, StringF(perm, "%F/%F", FmtString(token_parent_dir), FmtString(arg_file))); - if (F_IsFile(full)) - { - String line = StringF(perm, "#include \"%F\"", FmtString(full)); - PushStringToList(perm, &gpu_include_lines, line); - } - else - { - String err = StringF(perm, "File '%F' not found", FmtString(full)); - M_PushError(perm, &Build.gpu_parse.errors, arg0_tok, err); - } - } - else - { - M_PushError(perm, &Build.gpu_parse.errors, entry_tok, Lit("Expected file name")); - } - } break; - case M_EntryKind_VertexShader: - case M_EntryKind_PixelShader: - case M_EntryKind_ComputeShader: - { - if (arg0_tok->valid) - { - ShaderEntryKind shader_kind = kind == M_EntryKind_VertexShader ? ShaderEntryKind_VS - : kind == M_EntryKind_PixelShader ? ShaderEntryKind_PS - : kind == M_EntryKind_ComputeShader ? ShaderEntryKind_CS - : ShaderEntryKind_VS; - String shader_name = arg0_tok->s; - ShaderEntry *e = PushStruct(perm, ShaderEntry); - e->kind = shader_kind; - e->name = shader_name; - SllQueuePush(Build.gpu_parse.first_shader_entry, Build.gpu_parse.last_shader_entry, e); - ++Build.gpu_parse.shader_entries_count; - } - else - { - M_PushError(perm, &Build.gpu_parse.errors, entry_tok, Lit("Expected shader name")); - } - } break; - } - } - } - if (Build.gpu_parse.errors.count == 0) - { - StringList gpu_out_lines = Zi; - PushStringToList(perm, &gpu_out_lines, Lit("// Auto generated file")); - /* Include base layer */ - { - String base_inc_path = F_GetFull(perm, Lit("../src/base/base_inc.h")); - PushStringToList(perm, &gpu_out_lines, Lit("")); - PushStringToList(perm, &gpu_out_lines, Lit("//- Base layer includes")); - PushStringToList(perm, &gpu_out_lines, StringF(perm, "#include \"%F\"", FmtString(base_inc_path))); - } - /* Include dependency layers */ - if (gpu_out_lines.count > 0) - { - PushStringToList(perm, &gpu_out_lines, Lit("")); - PushStringToList(perm, &gpu_out_lines, Lit("//- Dependency graph includes")); - for (StringListNode *n = gpu_include_lines.first; n; n = n->next) - { - PushStringToList(perm, &gpu_out_lines, n->s); - } - } - /* Write to file */ - PushStringToList(perm, &gpu_out_lines, Lit("")); - String c_out = StringFromList(perm, gpu_out_lines, Lit("\n")); - F_ClearWrite(gpu_out_file, c_out); - } - } - - SetBuildStatus(Build.gpu_parse.errors.count > 0); - } - - //- Generate archive info - { - /* Push embedded archive dirs */ - for (M_Entry *entry = Build.layers_parse.first; entry->valid; entry = entry->next) - { - M_EntryKind kind = entry->kind; - M_Token *entry_tok = entry->name_token; - M_Token *arg0_tok = entry->arg_tokens[0]; - M_Token *arg1_tok = entry->arg_tokens[1]; - switch (kind) - { - default: break; - case M_EntryKind_EmbedDir: - { - if (arg0_tok->valid && arg1_tok->valid) - { - String store_name = arg0_tok->s; - String token_file = arg1_tok->file->name; - String token_parent_dir = F_GetParentDir(token_file); - String arg_dir = arg1_tok->s; - String full = F_GetFullCrossPlatform(perm, StringF(perm, "%F/%F", FmtString(token_parent_dir), FmtString(arg_dir))); - if (F_IsDir(full)) - { - ResDir *rd = PushStruct(perm, ResDir); - rd->store_name = store_name; - rd->dir_path = full; - SllQueuePush(Build.res_dir_parse.first_res_dir, Build.res_dir_parse.last_res_dir, rd); - ++Build.res_dir_parse.res_dirs_count; - } - else - { - String err = StringF(perm, "Directory '%F' not found", FmtString(full)); - M_PushError(perm, &Build.res_dir_parse.errors, arg1_tok, err); - } - } - else - { - M_PushError(perm, &Build.res_dir_parse.errors, entry_tok, Lit("Expected resource store & directory name")); - } - } break; - } - } - SetBuildStatus(Build.res_dir_parse.errors.count > 0); - } - - //- Prep obj arrays - { - /* Gpu objs */ - Build.gpu_objs.count = Build.gpu_parse.shader_entries_count; - Build.gpu_objs.array = PushStructs(perm, GpuObj, Build.gpu_objs.count); - - /* Embed objs */ - Build.embed_objs.count += Build.res_dir_parse.res_dirs_count; - if (Build.gpu_parse.shader_entries_count > 0) - { - Build.embed_objs.count += 1; - } - Build.embed_objs.array = PushStructs(perm, EmbedObj, Build.embed_objs.count); - } + /* Disable warnings */ + PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-initializer-overrides")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-microsoft-enum-forward-reference")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-unused-variable")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-unused-parameter")); + PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-incompatible-function-pointer-types")); } - WaveSync(lane); - - ////////////////////////////// - //- Phase 2/3: Compile - + //- Dxc { - u64 task_idx = 0; - u32 embed_idx = 0; + // PushStringToList(perm, &cp.flags_dxc, Lit("-Od")); + PushStringToList(perm, &cp.flags_dxc, Lit("-O3")); + PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug")); + } + } - //- Compile C - { - if (lane->idx == WaveLaneIdxFromTaskIdx(lane, task_idx++) && GetBuildStatus() == 0) - { - Build.c_obj.obj_file = StringF(perm, "%F_gen_c.obj", FmtString(cmdline.leaf_layer_name)); - String cmd = StringF( - perm, - "cl.exe /c %F -Fo:%F %F %F %F %F", - FmtString(c_out_file), - FmtString(Build.c_obj.obj_file), - FmtString(StringFromList(perm, cp.flags_msvc, Lit(" "))), - FmtString(StringFromList(perm, cp.compiler_only_flags_msvc, Lit(" "))), - FmtString(StringFromList(perm, cp.warnings_msvc, Lit(" "))), - FmtString(StringFromList(perm, cp.defs, Lit(" "))) - ); - OS_CommandResult cmd_result = OS_RunCommand(perm, cmd); - String cmd_output = TrimWhitespace(cmd_result.output); - Build.c_obj.output = cmd_output; - Build.c_obj.return_code = cmd_result.code; + ////////////////////////////// + //- Phase 1/3: Prep - /* Ignore MSVC file-name echo */ - if (MatchString(TrimWhitespace(Build.c_obj.output), F_GetFileName(c_out_file))) - { - Build.c_obj.output = Zstr; - } + /* + * Phase 1/3: Prep (narrow) + * - Parse layers + * - Generate final C file + * - Generate final HLSL file + * - Generate resource dirs info + * + * Phase 2/3: Compile (wide) + * - Compile C + * - Compile & embed shaders + * - Embed resource dirs + * + * Phase 3/3: Link (narrow) + * - Link + */ - SetBuildStatus(Build.c_obj.return_code); - } - } + /* TODO: Dispatch OS commands asynchronously */ - //- Compile shaders - { - u32 gpu_obj_idx = 0; - for (ShaderEntry *e = Build.gpu_parse.first_shader_entry; e; e = e->next) - { - if (lane->idx == WaveLaneIdxFromTaskIdx(lane, task_idx++) && GetBuildStatus() == 0) - { - String shader_name = e->name; - GpuObj *gpu_obj = &Build.gpu_objs.array[gpu_obj_idx]; - String out_file = StringF(perm, "%F/%F", FmtString(shader_store_name), FmtString(e->name)); - String target = e->kind == ShaderEntryKind_VS ? Lit("vs_6_6") - : e->kind == ShaderEntryKind_PS ? Lit("ps_6_6") - : e->kind == ShaderEntryKind_CS ? Lit("cs_6_6") - : Lit("vs_6_6"); - String compile_cmd = StringF( - perm, - "dxc.exe -T %F -E %F -Fo %F %F %F %F", - FmtString(target), - FmtString(e->name), - FmtString(out_file), - FmtString(gpu_out_file), - FmtString(StringFromList(perm, cp.defs, Lit(" "))), - FmtString(StringFromList(perm, cp.flags_dxc, Lit(" "))) - ); + String shader_store_name = Lit("ShadersStore"); + String c_out_file = F_GetFull(perm, StringF(perm, "%F_gen.c", FmtString(cmdline.leaf_layer_name))); + String gpu_out_file = F_GetFull(perm, StringF(perm, "%F_gen.g", FmtString(cmdline.leaf_layer_name))); - OS_CommandResult cmd_result = OS_RunCommand(perm, compile_cmd); - gpu_obj->output = cmd_result.output; - gpu_obj->return_code = cmd_result.code; + if (lane->idx == 0 && GetBuildStatus() == 0) + { + //- Parse layers + { + /* Lex */ + StringList src_dirs = Zi; + PushStringToList(perm, &src_dirs, Lit("../src")); + M_TokenFileList lexed = M_TokensFromSrcDirs(perm, src_dirs); - SetBuildStatus(gpu_obj->return_code); + /* Parse */ + M_LayerList parsed = M_LayersFromTokenFiles(perm, lexed);; - /* Final shader compilation lane embeds shader archive */ - u32 finished_count = Atomic32FetchAdd(&Build.gpu_objs.finished_count, 1) + 1; - if (finished_count == Build.gpu_objs.count && GetBuildStatus() == 0) - { - EmbedObj *embed = &Build.embed_objs.array[embed_idx]; - *embed = Embed(shader_store_name, shader_store_name); - } - } - ++gpu_obj_idx; - } - if (Build.gpu_parse.shader_entries_count > 0) - { - ++embed_idx; - } - } + /* Flatten */ + StringList starting_layer_names = Zi; + PushStringToList(perm, &starting_layer_names, cmdline.leaf_layer_name); + Build.layers_parse = M_FlattenEntries(perm, parsed, starting_layer_names); - //- Embed resource dirs - { - for (ResDir *rd = Build.res_dir_parse.first_res_dir; rd; rd = rd->next) - { - if (lane->idx == WaveLaneIdxFromTaskIdx(lane, task_idx++) && GetBuildStatus() == 0) - { - String dir_path = rd->dir_path; - String store_name = rd->store_name; - EmbedObj *embed = &Build.embed_objs.array[embed_idx]; - *embed = Embed(store_name, dir_path); - } - ++embed_idx; - } - } + SetBuildStatus(Build.layers_parse.errors.count > 0); } - WaveSync(lane); - - ////////////////////////////// - //- Phase 3/3: Link - - if (lane->idx == 0 && GetBuildStatus() == 0) + //- Generate C file { - String exe_file = StringF(perm, "%F.exe", FmtString(cmdline.leaf_layer_name)); + StringList c_store_lines = Zi; + StringList c_shader_lines = Zi; + StringList c_include_lines = Zi; + StringList c_bootstrap_lines = Zi; + { + for (M_Entry *entry = Build.layers_parse.first; entry->valid; entry = entry->next) { - /* Wait for exe to become writable (wait for program to close) */ - f32 timeout = 1.0; - OS_File file = OS_OpenFile(exe_file, OS_FileFlag_Write, NsFromSeconds(timeout)); - OS_CloseFile(file); - } - - i64 start_ns = TimeNs(); - - String obj_files_str = Zi; - { - StringList obj_files = Zi; - PushStringToList(perm, &obj_files, Build.c_obj.obj_file); - for (u64 embed_obj_idx = 0; embed_obj_idx < Build.embed_objs.count; ++embed_obj_idx) + M_EntryKind kind = entry->kind; + M_Token *entry_tok = entry->name_token; + M_Token *arg0_tok = entry->arg_tokens[0]; + M_Token *arg1_tok = entry->arg_tokens[1]; + switch (kind) + { + default: break; + case M_EntryKind_EmbedDir: { - EmbedObj *embed_obj = &Build.embed_objs.array[embed_obj_idx]; - PushStringToList(perm, &obj_files, embed_obj->obj_file); - } - obj_files_str = StringFromList(perm, obj_files, Lit(" ")); + if (arg0_tok->valid && arg1_tok->valid) + { + String store_name = arg0_tok->s; + String token_file = arg1_tok->file->name; + String token_parent_dir = F_GetParentDir(token_file); + String arg_dir = arg1_tok->s; + String full = F_GetFullCrossPlatform(perm, StringF(perm, "%F/%F", FmtString(token_parent_dir), FmtString(arg_dir))); + if (F_IsDir(full)) + { + u64 hash = HashFnv64(Fnv64Basis, StringF(perm, "%F/", FmtString(store_name))); + String line = StringF(perm, "ResourceStore %F = { 0x%F };", FmtString(store_name), FmtHex(hash)); + PushStringToList(perm, &c_store_lines, line); + } + else + { + String err = StringF(perm, "Directory '%F' not found", FmtString(full)); + M_PushError(perm, &Build.c_parse.errors, arg1_tok, err); + } + } + else + { + M_PushError(perm, &Build.c_parse.errors, entry_tok, Lit("Expected resource store & directory name")); + } + } break; + case M_EntryKind_VertexShader: + case M_EntryKind_PixelShader: + case M_EntryKind_ComputeShader: + { + if (arg0_tok->valid) + { + String shader_type = kind == M_EntryKind_VertexShader ? Lit("VertexShader") + : kind == M_EntryKind_PixelShader ? Lit("PixelShader") + : kind == M_EntryKind_ComputeShader ? Lit("ComputeShader") + : Lit(""); + String shader_name = arg0_tok->s; + u64 hash = HashFnv64(Fnv64Basis, StringF(perm, "%F/%F", FmtString(shader_store_name), FmtString(shader_name))); + String line = StringF(perm, "%F %F = { 0x%F };", FmtString(shader_type), FmtString(shader_name), FmtHex(hash)); + PushStringToList(perm, &c_shader_lines, line); + } + else + { + M_PushError(perm, &Build.c_parse.errors, entry_tok, Lit("Expected shader name")); + } + } break; + case M_EntryKind_IncludeC: + { + if (arg0_tok->valid) + { + String token_file = arg0_tok->file->name; + String token_parent_dir = F_GetParentDir(token_file); + String arg_file = arg0_tok->s; + String full = F_GetFull(perm, StringF(perm, "%F/%F", FmtString(token_parent_dir), FmtString(arg_file))); + if (F_IsFile(full)) + { + String line = StringF(perm, "#include \"%F\"", FmtString(full)); + PushStringToList(perm, &c_include_lines, line); + } + else + { + String err = StringF(perm, "File '%F' not found", FmtString(full)); + M_PushError(perm, &Build.c_parse.errors, arg0_tok, err); + } + } + else + { + M_PushError(perm, &Build.c_parse.errors, entry_tok, Lit("Expected file name")); + } + } break; + case M_EntryKind_Bootstrap: + { + if (arg0_tok->valid) + { + String bootstrap = arg0_tok->s; + String line = StringF(perm, " %F();", FmtString(bootstrap)); + PushStringToList(perm, &c_bootstrap_lines, line); + } + else + { + M_PushError(perm, &Build.c_parse.errors, entry_tok, Lit("Expected bootstrap function name")); + } + } break; + } } + } + if (Build.c_parse.errors.count == 0) + { + StringList c_out_lines = Zi; + PushStringToList(perm, &c_out_lines, Lit("// Auto generated file")); + /* Include base layer */ + { + String base_inc_path = F_GetFull(perm, Lit("../src/base/base_inc.h")); + PushStringToList(perm, &c_out_lines, Lit("")); + PushStringToList(perm, &c_out_lines, Lit("//- Base layer includes")); + PushStringToList(perm, &c_out_lines, StringF(perm, "#include \"%F\"", FmtString(base_inc_path))); + } + /* Define resource stores */ + if (c_store_lines.count > 0) + { + PushStringToList(perm, &c_out_lines, Lit("")); + PushStringToList(perm, &c_out_lines, Lit("//- Resource stores")); + for (StringListNode *n = c_store_lines.first; n; n = n->next) + { + PushStringToList(perm, &c_out_lines, n->s); + } + } + /* Define shaders */ + if (c_shader_lines.count > 0) + { + PushStringToList(perm, &c_out_lines, Lit("")); + PushStringToList(perm, &c_out_lines, Lit("//- Shaders")); + for (StringListNode *n = c_shader_lines.first; n; n = n->next) + { + PushStringToList(perm, &c_out_lines, n->s); + } + } + /* Include dependency layers */ + if (c_include_lines.count > 0) + { + PushStringToList(perm, &c_out_lines, Lit("")); + PushStringToList(perm, &c_out_lines, Lit("//- Dependency graph includes")); + for (StringListNode *n = c_include_lines.first; n; n = n->next) + { + PushStringToList(perm, &c_out_lines, n->s); + } + } + /* Define BootstrapLayers */ + { + PushStringToList(perm, &c_out_lines, Lit("")); + PushStringToList(perm, &c_out_lines, Lit("//- Bootstrap")); + PushStringToList(perm, &c_out_lines, Lit("void BootstrapLayers(void)")); + PushStringToList(perm, &c_out_lines, Lit("{")); + for (StringListNode *n = c_bootstrap_lines.first; n; n = n->next) + { + PushStringToList(perm, &c_out_lines, n->s); + } + PushStringToList(perm, &c_out_lines, Lit("}")); + } + /* Write to file */ + PushStringToList(perm, &c_out_lines, Lit("")); + String c_out = StringFromList(perm, c_out_lines, Lit("\n")); + F_ClearWrite(c_out_file, c_out); + } + SetBuildStatus(Build.c_parse.errors.count > 0); + } + + //- Generate HLSL file + { + /* Clear shader store */ + /* TODO: Move to separate artifacts dir that gets cleared, including archive files */ + OS_Mkdir(shader_store_name); + { + /* Remove all old shaders */ + StringList files = Zi; + F_FilesFromDir(perm, &files, shader_store_name, F_IterFlag_None); + for (StringListNode *n = files.first; n; n = n->next) + { + String file = n->s; + /* Safety check to prevent non-shader files from being removed */ + if (StringEndsWith(file, Lit("VS")) || StringEndsWith(file, Lit("CS")) || StringEndsWith(file, Lit("PS"))) + { + OS_Rm(n->s); + } + else + { + /* Unexpected file in shader store */ + Assert(0); + } + } + } + + /* Generate GPU file & shader entries */ + { + StringList gpu_include_lines = Zi; + { + for (M_Entry *entry = Build.layers_parse.first; entry->valid; entry = entry->next) + { + M_EntryKind kind = entry->kind; + M_Token *entry_tok = entry->name_token; + M_Token *arg0_tok = entry->arg_tokens[0]; + M_Token *arg1_tok = entry->arg_tokens[1]; + switch (kind) + { + default: break; + case M_EntryKind_IncludeG: + { + if (arg0_tok->valid) + { + String token_file = arg0_tok->file->name; + String token_parent_dir = F_GetParentDir(token_file); + String arg_file = arg0_tok->s; + String full = F_GetFull(perm, StringF(perm, "%F/%F", FmtString(token_parent_dir), FmtString(arg_file))); + if (F_IsFile(full)) + { + String line = StringF(perm, "#include \"%F\"", FmtString(full)); + PushStringToList(perm, &gpu_include_lines, line); + } + else + { + String err = StringF(perm, "File '%F' not found", FmtString(full)); + M_PushError(perm, &Build.gpu_parse.errors, arg0_tok, err); + } + } + else + { + M_PushError(perm, &Build.gpu_parse.errors, entry_tok, Lit("Expected file name")); + } + } break; + case M_EntryKind_VertexShader: + case M_EntryKind_PixelShader: + case M_EntryKind_ComputeShader: + { + if (arg0_tok->valid) + { + ShaderEntryKind shader_kind = kind == M_EntryKind_VertexShader ? ShaderEntryKind_VS + : kind == M_EntryKind_PixelShader ? ShaderEntryKind_PS + : kind == M_EntryKind_ComputeShader ? ShaderEntryKind_CS + : ShaderEntryKind_VS; + String shader_name = arg0_tok->s; + ShaderEntry *e = PushStruct(perm, ShaderEntry); + e->kind = shader_kind; + e->name = shader_name; + SllQueuePush(Build.gpu_parse.first_shader_entry, Build.gpu_parse.last_shader_entry, e); + ++Build.gpu_parse.shader_entries_count; + } + else + { + M_PushError(perm, &Build.gpu_parse.errors, entry_tok, Lit("Expected shader name")); + } + } break; + } + } + } + if (Build.gpu_parse.errors.count == 0) + { + StringList gpu_out_lines = Zi; + PushStringToList(perm, &gpu_out_lines, Lit("// Auto generated file")); + /* Include base layer */ + { + String base_inc_path = F_GetFull(perm, Lit("../src/base/base_inc.h")); + PushStringToList(perm, &gpu_out_lines, Lit("")); + PushStringToList(perm, &gpu_out_lines, Lit("//- Base layer includes")); + PushStringToList(perm, &gpu_out_lines, StringF(perm, "#include \"%F\"", FmtString(base_inc_path))); + } + /* Include dependency layers */ + if (gpu_out_lines.count > 0) + { + PushStringToList(perm, &gpu_out_lines, Lit("")); + PushStringToList(perm, &gpu_out_lines, Lit("//- Dependency graph includes")); + for (StringListNode *n = gpu_include_lines.first; n; n = n->next) + { + PushStringToList(perm, &gpu_out_lines, n->s); + } + } + /* Write to file */ + PushStringToList(perm, &gpu_out_lines, Lit("")); + String c_out = StringFromList(perm, gpu_out_lines, Lit("\n")); + F_ClearWrite(gpu_out_file, c_out); + } + } + + SetBuildStatus(Build.gpu_parse.errors.count > 0); + } + + //- Generate archive info + { + /* Push embedded archive dirs */ + for (M_Entry *entry = Build.layers_parse.first; entry->valid; entry = entry->next) + { + M_EntryKind kind = entry->kind; + M_Token *entry_tok = entry->name_token; + M_Token *arg0_tok = entry->arg_tokens[0]; + M_Token *arg1_tok = entry->arg_tokens[1]; + switch (kind) + { + default: break; + case M_EntryKind_EmbedDir: + { + if (arg0_tok->valid && arg1_tok->valid) + { + String store_name = arg0_tok->s; + String token_file = arg1_tok->file->name; + String token_parent_dir = F_GetParentDir(token_file); + String arg_dir = arg1_tok->s; + String full = F_GetFullCrossPlatform(perm, StringF(perm, "%F/%F", FmtString(token_parent_dir), FmtString(arg_dir))); + if (F_IsDir(full)) + { + ResDir *rd = PushStruct(perm, ResDir); + rd->store_name = store_name; + rd->dir_path = full; + SllQueuePush(Build.res_dir_parse.first_res_dir, Build.res_dir_parse.last_res_dir, rd); + ++Build.res_dir_parse.res_dirs_count; + } + else + { + String err = StringF(perm, "Directory '%F' not found", FmtString(full)); + M_PushError(perm, &Build.res_dir_parse.errors, arg1_tok, err); + } + } + else + { + M_PushError(perm, &Build.res_dir_parse.errors, entry_tok, Lit("Expected resource store & directory name")); + } + } break; + } + } + SetBuildStatus(Build.res_dir_parse.errors.count > 0); + } + + //- Prep obj arrays + { + /* Gpu objs */ + Build.gpu_objs.count = Build.gpu_parse.shader_entries_count; + Build.gpu_objs.array = PushStructs(perm, GpuObj, Build.gpu_objs.count); + + /* Embed objs */ + Build.embed_objs.count += Build.res_dir_parse.res_dirs_count; + if (Build.gpu_parse.shader_entries_count > 0) + { + Build.embed_objs.count += 1; + } + Build.embed_objs.array = PushStructs(perm, EmbedObj, Build.embed_objs.count); + } + } + + WaveSync(lane); + + ////////////////////////////// + //- Phase 2/3: Compile + + { + u64 task_idx = 0; + u32 embed_idx = 0; + + //- Compile C + { + if (lane->idx == WaveLaneIdxFromTaskIdx(lane, task_idx++) && GetBuildStatus() == 0) + { + Build.c_obj.obj_file = StringF(perm, "%F_gen_c.obj", FmtString(cmdline.leaf_layer_name)); String cmd = StringF( - perm, - "link.exe %F /OUT:%F %F %F", - FmtString(obj_files_str), - FmtString(exe_file), - FmtString(StringFromList(perm, cp.flags_msvc, Lit(" "))), - FmtString(StringFromList(perm, cp.linker_only_flags_msvc, Lit(" "))) + perm, + "cl.exe /c %F -Fo:%F %F %F %F %F", + FmtString(c_out_file), + FmtString(Build.c_obj.obj_file), + FmtString(StringFromList(perm, cp.flags_msvc, Lit(" "))), + FmtString(StringFromList(perm, cp.compiler_only_flags_msvc, Lit(" "))), + FmtString(StringFromList(perm, cp.warnings_msvc, Lit(" "))), + FmtString(StringFromList(perm, cp.defs, Lit(" "))) ); - OS_CommandResult result = OS_RunCommand(perm, cmd); - Build.link.output = TrimWhitespace(result.output); - Build.link.return_code = result.code; - i64 link_elapsed_ns = TimeNs() - start_ns; - // EchoLine(StringF(perm, ">>>>> Linked in %Fs", FmtFloat(SecondsFromNs(link_elapsed_ns)))); + OS_CommandResult cmd_result = OS_RunCommand(perm, cmd); + String cmd_output = TrimWhitespace(cmd_result.output); + Build.c_obj.output = cmd_output; + Build.c_obj.return_code = cmd_result.code; - SetBuildStatus(Build.link.return_code); - } - - ////////////////////////////// - //- Display build results - - if (lane->idx == 0) - { - String gpu_obj_output = Zi; + /* Ignore MSVC file-name echo */ + if (MatchString(TrimWhitespace(Build.c_obj.output), F_GetFileName(c_out_file))) { - GpuObj *disp_obj = 0; - for (u32 gpu_obj_idx = 0; gpu_obj_idx < Build.gpu_objs.count; ++gpu_obj_idx) - { - GpuObj *gpu_obj = &Build.gpu_objs.array[gpu_obj_idx]; - if (!disp_obj || TrimWhitespace(disp_obj->output).len == 0 || gpu_obj->return_code != 0) - { - disp_obj = gpu_obj; - } - } - if (disp_obj) - { - gpu_obj_output = TrimWhitespace(disp_obj->output); - } - } - String embed_obj_output = Zi; - { - StringList embed_obj_outputs = Zi; - for (u32 embed_obj_idx = 0; embed_obj_idx < Build.embed_objs.count; ++embed_obj_idx) - { - EmbedObj *embed_obj = &Build.embed_objs.array[embed_obj_idx]; - PushStringToList(perm, &embed_obj_outputs, embed_obj->output); - } - embed_obj_output = StringFromList(perm, embed_obj_outputs, Lit("\n")); + Build.c_obj.output = Zstr; } - EchoLineOrNothing(StringFromMetaErrors(perm, Build.layers_parse.errors)); - EchoLineOrNothing(StringFromMetaErrors(perm, Build.c_parse.errors)); - EchoLineOrNothing(StringFromMetaErrors(perm, Build.gpu_parse.errors)); - EchoLineOrNothing(Build.c_obj.output); - EchoLineOrNothing(gpu_obj_output); - EchoLineOrNothing(StringFromMetaErrors(perm, Build.res_dir_parse.errors)); - EchoLineOrNothing(embed_obj_output); - EchoLineOrNothing(Build.link.output); + SetBuildStatus(Build.c_obj.return_code); + } } - ////////////////////////////// - //- Exit - - if (lane->idx == 0) + //- Compile shaders { - EchoLine(StringF(perm, "Runtime: %Fs", FmtFloat(SecondsFromNs(TimeNs())))); - ExitNow(GetBuildStatus()); + u32 gpu_obj_idx = 0; + for (ShaderEntry *e = Build.gpu_parse.first_shader_entry; e; e = e->next) + { + if (lane->idx == WaveLaneIdxFromTaskIdx(lane, task_idx++) && GetBuildStatus() == 0) + { + String shader_name = e->name; + GpuObj *gpu_obj = &Build.gpu_objs.array[gpu_obj_idx]; + String out_file = StringF(perm, "%F/%F", FmtString(shader_store_name), FmtString(e->name)); + String target = e->kind == ShaderEntryKind_VS ? Lit("vs_6_6") + : e->kind == ShaderEntryKind_PS ? Lit("ps_6_6") + : e->kind == ShaderEntryKind_CS ? Lit("cs_6_6") + : Lit("vs_6_6"); + String compile_cmd = StringF( + perm, + "dxc.exe -T %F -E %F -Fo %F %F %F %F", + FmtString(target), + FmtString(e->name), + FmtString(out_file), + FmtString(gpu_out_file), + FmtString(StringFromList(perm, cp.defs, Lit(" "))), + FmtString(StringFromList(perm, cp.flags_dxc, Lit(" "))) + ); + + OS_CommandResult cmd_result = OS_RunCommand(perm, compile_cmd); + gpu_obj->output = cmd_result.output; + gpu_obj->return_code = cmd_result.code; + + SetBuildStatus(gpu_obj->return_code); + + /* Final shader compilation lane embeds shader archive */ + u32 finished_count = Atomic32FetchAdd(&Build.gpu_objs.finished_count, 1) + 1; + if (finished_count == Build.gpu_objs.count && GetBuildStatus() == 0) + { + EmbedObj *embed = &Build.embed_objs.array[embed_idx]; + *embed = Embed(shader_store_name, shader_store_name); + } + } + ++gpu_obj_idx; + } + if (Build.gpu_parse.shader_entries_count > 0) + { + ++embed_idx; + } } + + //- Embed resource dirs + { + for (ResDir *rd = Build.res_dir_parse.first_res_dir; rd; rd = rd->next) + { + if (lane->idx == WaveLaneIdxFromTaskIdx(lane, task_idx++) && GetBuildStatus() == 0) + { + String dir_path = rd->dir_path; + String store_name = rd->store_name; + EmbedObj *embed = &Build.embed_objs.array[embed_idx]; + *embed = Embed(store_name, dir_path); + } + ++embed_idx; + } + } + } + + WaveSync(lane); + + ////////////////////////////// + //- Phase 3/3: Link + + if (lane->idx == 0 && GetBuildStatus() == 0) + { + String exe_file = StringF(perm, "%F.exe", FmtString(cmdline.leaf_layer_name)); + { + /* Wait for exe to become writable (wait for program to close) */ + f32 timeout = 1.0; + OS_File file = OS_OpenFile(exe_file, OS_FileFlag_Write, NsFromSeconds(timeout)); + OS_CloseFile(file); + } + + i64 start_ns = TimeNs(); + + String obj_files_str = Zi; + { + StringList obj_files = Zi; + PushStringToList(perm, &obj_files, Build.c_obj.obj_file); + for (u64 embed_obj_idx = 0; embed_obj_idx < Build.embed_objs.count; ++embed_obj_idx) + { + EmbedObj *embed_obj = &Build.embed_objs.array[embed_obj_idx]; + PushStringToList(perm, &obj_files, embed_obj->obj_file); + } + obj_files_str = StringFromList(perm, obj_files, Lit(" ")); + } + + String cmd = StringF( + perm, + "link.exe %F /OUT:%F %F %F", + FmtString(obj_files_str), + FmtString(exe_file), + FmtString(StringFromList(perm, cp.flags_msvc, Lit(" "))), + FmtString(StringFromList(perm, cp.linker_only_flags_msvc, Lit(" "))) + ); + OS_CommandResult result = OS_RunCommand(perm, cmd); + Build.link.output = TrimWhitespace(result.output); + Build.link.return_code = result.code; + i64 link_elapsed_ns = TimeNs() - start_ns; + // EchoLine(StringF(perm, ">>>>> Linked in %Fs", FmtFloat(SecondsFromNs(link_elapsed_ns)))); + + SetBuildStatus(Build.link.return_code); + } + + ////////////////////////////// + //- Display build results + + if (lane->idx == 0) + { + String gpu_obj_output = Zi; + { + GpuObj *disp_obj = 0; + for (u32 gpu_obj_idx = 0; gpu_obj_idx < Build.gpu_objs.count; ++gpu_obj_idx) + { + GpuObj *gpu_obj = &Build.gpu_objs.array[gpu_obj_idx]; + if (!disp_obj || TrimWhitespace(disp_obj->output).len == 0 || gpu_obj->return_code != 0) + { + disp_obj = gpu_obj; + } + } + if (disp_obj) + { + gpu_obj_output = TrimWhitespace(disp_obj->output); + } + } + String embed_obj_output = Zi; + { + StringList embed_obj_outputs = Zi; + for (u32 embed_obj_idx = 0; embed_obj_idx < Build.embed_objs.count; ++embed_obj_idx) + { + EmbedObj *embed_obj = &Build.embed_objs.array[embed_obj_idx]; + PushStringToList(perm, &embed_obj_outputs, embed_obj->output); + } + embed_obj_output = StringFromList(perm, embed_obj_outputs, Lit("\n")); + } + + EchoLineOrNothing(StringFromMetaErrors(perm, Build.layers_parse.errors)); + EchoLineOrNothing(StringFromMetaErrors(perm, Build.c_parse.errors)); + EchoLineOrNothing(StringFromMetaErrors(perm, Build.gpu_parse.errors)); + EchoLineOrNothing(Build.c_obj.output); + EchoLineOrNothing(gpu_obj_output); + EchoLineOrNothing(StringFromMetaErrors(perm, Build.res_dir_parse.errors)); + EchoLineOrNothing(embed_obj_output); + EchoLineOrNothing(Build.link.output); + } + + ////////////////////////////// + //- Exit + + if (lane->idx == 0) + { + EchoLine(StringF(perm, "Runtime: %Fs", FmtFloat(SecondsFromNs(TimeNs())))); + ExitNow(GetBuildStatus()); + } } //////////////////////////////////////////////////////////// @@ -1017,8 +1019,8 @@ void BuildEntryPoint(WaveLaneCtx *lane) void BootstrapLayers(void) { - OS_Bootstrap(); - CpuTopologyInfo cpu_info = GetCpuTopologyInfo(); - i32 meta_lanes_count = cpu_info.num_logical_cores - 1; - DispatchWave(Lit("Meta"), MaxI32(meta_lanes_count, 1), BuildEntryPoint, 0); + OS_Bootstrap(); + CpuTopologyInfo cpu_info = GetCpuTopologyInfo(); + i32 meta_lanes_count = cpu_info.num_logical_cores - 1; + DispatchWave(Lit("Meta"), MaxI32(meta_lanes_count, 1), BuildEntryPoint, 0); } diff --git a/src/meta/meta.h b/src/meta/meta.h index ed6eac4c..1899092f 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -4,43 +4,43 @@ //~ Base layer definitions #ifndef IsConsoleApp -# define IsConsoleApp 1 + #define IsConsoleApp 1 #endif #ifndef IsRtcEnabled -# define IsRtcEnabled 1 + #define IsRtcEnabled 1 #endif #ifndef IsUnoptimized -# define IsUnoptimized 1 + #define IsUnoptimized 1 #endif #ifndef IsAsanEnabled -# define IsAsanEnabled 0 + #define IsAsanEnabled 0 #endif #ifndef IsCrtlibEnabled -# define IsCrtlibEnabled 1 + #define IsCrtlibEnabled 1 #endif #ifndef IsDebinfoEnabled -# define IsDebinfoEnabled 1 + #define IsDebinfoEnabled 1 #endif #ifndef IsDeveloperModeEnabled -# define IsDeveloperModeEnabled 1 + #define IsDeveloperModeEnabled 1 #endif #ifndef IsUnoptimized -# define IsUnoptimized 1 + #define IsUnoptimized 1 #endif #ifndef IsTestingEnabled -# define IsTestingEnabled 0 + #define IsTestingEnabled 0 #endif #ifndef IsHotSwappingEnabled -# define IsHotSwappingEnabled 0 + #define IsHotSwappingEnabled 0 #endif //////////////////////////////////////////////////////////// @@ -60,8 +60,8 @@ Struct(LineCol) { - i64 line; - i64 col; + i64 line; + i64 col; }; //////////////////////////////////////////////////////////// @@ -69,109 +69,109 @@ Struct(LineCol) Struct(CompilerParams) { - StringList defs; + StringList defs; - StringList warnings_msvc; - StringList warnings_clang; - StringList warnings_dxc; + StringList warnings_msvc; + StringList warnings_clang; + StringList warnings_dxc; - StringList flags_msvc; - StringList flags_clang; - StringList flags_dxc; + StringList flags_msvc; + StringList flags_clang; + StringList flags_dxc; - StringList compiler_only_flags_msvc; - StringList compiler_only_flags_clang; + StringList compiler_only_flags_msvc; + StringList compiler_only_flags_clang; - StringList linker_only_flags_msvc; - StringList linker_only_flags_clang; + StringList linker_only_flags_msvc; + StringList linker_only_flags_clang; }; Enum(ShaderEntryKind) { - ShaderEntryKind_VS, - ShaderEntryKind_PS, - ShaderEntryKind_CS, + ShaderEntryKind_VS, + ShaderEntryKind_PS, + ShaderEntryKind_CS, }; Struct(ShaderEntry) { - ShaderEntry *next; - ShaderEntryKind kind; - String name; + ShaderEntry *next; + ShaderEntryKind kind; + String name; }; Struct(ResDir) { - ResDir *next; - String dir_path; - String store_name; + ResDir *next; + String dir_path; + String store_name; }; Struct(GpuObj) { - String output; - i32 return_code; + String output; + i32 return_code; }; Struct(EmbedObj) { - String obj_file; - String output; - i32 return_code; + String obj_file; + String output; + i32 return_code; }; Struct(BuildCtx) { - Atomic32 status; + Atomic32 status; - M_Layer layers_parse; + M_Layer layers_parse; - struct - { - M_ErrorList errors; - } c_parse; + struct + { + M_ErrorList errors; + } c_parse; - struct - { - M_ErrorList errors; - ShaderEntry *first_shader_entry; - ShaderEntry *last_shader_entry; - u64 shader_entries_count; - } gpu_parse; + struct + { + M_ErrorList errors; + ShaderEntry *first_shader_entry; + ShaderEntry *last_shader_entry; + u64 shader_entries_count; + } gpu_parse; - struct - { - M_ErrorList errors; - ResDir *first_res_dir; - ResDir *last_res_dir; - u64 res_dirs_count; - } res_dir_parse; + struct + { + M_ErrorList errors; + ResDir *first_res_dir; + ResDir *last_res_dir; + u64 res_dirs_count; + } res_dir_parse; - struct - { - String obj_file; - String output; - i32 return_code; - } c_obj; + struct + { + String obj_file; + String output; + i32 return_code; + } c_obj; - struct - { - GpuObj *array; - u32 count; - Atomic32 finished_count; - } gpu_objs; + struct + { + GpuObj *array; + u32 count; + Atomic32 finished_count; + } gpu_objs; - struct - { - EmbedObj *array; - u32 count; - } embed_objs; + struct + { + EmbedObj *array; + u32 count; + } embed_objs; - struct - { - String output; - i32 return_code; - } link; + struct + { + String output; + i32 return_code; + } link; }; extern BuildCtx Build; diff --git a/src/meta/meta_file/meta_file.c b/src/meta/meta_file/meta_file.c index 1c26c75d..7ea2ef6d 100644 --- a/src/meta/meta_file/meta_file.c +++ b/src/meta/meta_file/meta_file.c @@ -3,82 +3,82 @@ String F_GetFull(Arena *arena, String path) { - return OS_GetFullPath(arena, path); + return OS_GetFullPath(arena, path); } String F_GetFullCrossPlatform(Arena *arena, String path) { - String result = OS_GetFullPath(arena, path); - for (u64 i = 0; i < result.len; ++i) + String result = OS_GetFullPath(arena, path); + for (u64 i = 0; i < result.len; ++i) + { + if (result.text[i] == '\\') { - if (result.text[i] == '\\') - { - result.text[i] = '/'; - } + result.text[i] = '/'; } - return result; + } + return result; } String F_GetFileName(String path) { - String result = path; - u64 start = path.len; - for (u64 i = path.len; i-- > 0;) + String result = path; + u64 start = path.len; + for (u64 i = path.len; i-- > 0;) + { + if (path.text[i] == '\\' || path.text[i] == '/') { - if (path.text[i] == '\\' || path.text[i] == '/') - { - start = i + 1; - break; - } + start = i + 1; + break; } - if (start < path.len) - { - result.text = &path.text[start]; - result.len = path.len - start; + } + if (start < path.len) + { + result.text = &path.text[start]; + result.len = path.len - start; - } - return result; + } + return result; } String F_GetParentDir(String path) { - String result = Zi; - result.text = path.text; - u64 end = path.len; - for (u64 i = path.len; i-- > 0;) + String result = Zi; + result.text = path.text; + u64 end = path.len; + for (u64 i = path.len; i-- > 0;) + { + if (path.text[i] == '\\' || path.text[i] == '/') { - if (path.text[i] == '\\' || path.text[i] == '/') - { - end = i + 1; - break; - } + end = i + 1; + break; } - if (end < path.len) - { - result.len = end; - } - return result; + } + if (end < path.len) + { + result.len = end; + } + return result; } String F_ExtensionFromFile(String path) { - String result = Zi; - u64 start = path.len; - for (u64 i = path.len; i-- > 0;) + String result = Zi; + u64 start = path.len; + for (u64 i = path.len; i-- > 0;) + { + if (path.text[i] == '.') { - if (path.text[i] == '.') - { - start = i + 1; - break; - } + start = i + 1; + break; } - if (start < path.len) - { - result.text = &path.text[start]; - result.len = path.len - start; + } + if (start < path.len) + { + result.text = &path.text[start]; + result.len = path.len - start; - } - return result; + } + return result; } //////////////////////////////////////////////////////////// @@ -86,11 +86,11 @@ String F_ExtensionFromFile(String path) String F_DataFromFile(Arena *arena, String path) { - String result = Zi; - OS_File file = OS_OpenFile(path, OS_FileFlag_Read, I64Max); - result = OS_ReadEntireFile(arena, file); - OS_CloseFile(file); - return result; + String result = Zi; + OS_File file = OS_OpenFile(path, OS_FileFlag_Read, I64Max); + result = OS_ReadEntireFile(arena, file); + OS_CloseFile(file); + return result; } //////////////////////////////////////////////////////////// @@ -98,9 +98,9 @@ String F_DataFromFile(Arena *arena, String path) void F_ClearWrite(String path, String data) { - OS_File file = OS_OpenFile(path, OS_FileFlag_Write | OS_FileFlag_Create, I64Max); - OS_ClearWriteFile(file, data); - OS_CloseFile(file); + OS_File file = OS_OpenFile(path, OS_FileFlag_Write | OS_FileFlag_Create, I64Max); + OS_ClearWriteFile(file, data); + OS_CloseFile(file); } //////////////////////////////////////////////////////////// @@ -108,12 +108,12 @@ void F_ClearWrite(String path, String data) b32 F_IsFile(String path) { - return OS_FileExists(path); + return OS_FileExists(path); } b32 F_IsDir(String path) { - return OS_DirExists(path); + return OS_DirExists(path); } //////////////////////////////////////////////////////////// @@ -121,18 +121,18 @@ b32 F_IsDir(String path) void F_FilesFromDir(Arena *arena, StringList *list, String dir, F_IterFlag flags) { - TempArena scratch = BeginScratch(arena); - StringList tmp = Zi; - String dir_full_path = F_GetFull(scratch.arena, dir); - OS_DirContentsFromFullPath(scratch.arena, &tmp, dir_full_path); - for (StringListNode *n = tmp.first; n; n = n->next) + TempArena scratch = BeginScratch(arena); + StringList tmp = Zi; + String dir_full_path = F_GetFull(scratch.arena, dir); + OS_DirContentsFromFullPath(scratch.arena, &tmp, dir_full_path); + for (StringListNode *n = tmp.first; n; n = n->next) + { + String file_joined_path = StringF(arena, "%F/%F", FmtString(dir), FmtString(n->s)); + PushStringToList(arena, list, file_joined_path); + if (flags & F_IterFlag_Recurse && F_IsDir(file_joined_path)) { - String file_joined_path = StringF(arena, "%F/%F", FmtString(dir), FmtString(n->s)); - PushStringToList(arena, list, file_joined_path); - if (flags & F_IterFlag_Recurse && F_IsDir(file_joined_path)) - { - F_FilesFromDir(arena, list, file_joined_path, flags); - } + F_FilesFromDir(arena, list, file_joined_path, flags); } - EndScratch(scratch); + } + EndScratch(scratch); } diff --git a/src/meta/meta_file/meta_file.h b/src/meta/meta_file/meta_file.h index a631b4e8..a35a8df5 100644 --- a/src/meta/meta_file/meta_file.h +++ b/src/meta/meta_file/meta_file.h @@ -3,8 +3,8 @@ Enum(F_IterFlag) { - F_IterFlag_None = 0, - F_IterFlag_Recurse = (1 << 0) + F_IterFlag_None = 0, + F_IterFlag_Recurse = (1 << 0) }; //////////////////////////////////////////////////////////// diff --git a/src/meta/meta_lay.c b/src/meta/meta_lay.c index 65cc22f4..1ea8bfad 100644 --- a/src/meta/meta_lay.c +++ b/src/meta/meta_lay.c @@ -1,27 +1,27 @@ Readonly M_Token M_NilToken = { - .next = &M_NilToken, - .file = &M_NilTokenFile, + .next = &M_NilToken, + .file = &M_NilTokenFile, }; Readonly M_TokenFile M_NilTokenFile = { - .next = &M_NilTokenFile, - .first_token = &M_NilToken, - .last_token = &M_NilToken, + .next = &M_NilTokenFile, + .first_token = &M_NilToken, + .last_token = &M_NilToken, }; Readonly M_Entry M_NilEntry = { - .next = &M_NilEntry, - .name_token = &M_NilToken, - .arg_tokens[0] = &M_NilToken, - .arg_tokens[1] = &M_NilToken, + .next = &M_NilEntry, + .name_token = &M_NilToken, + .arg_tokens[0] = &M_NilToken, + .arg_tokens[1] = &M_NilToken, }; StaticAssert(countof(M_NilEntry.arg_tokens) == 2); /* NilEntry must define point args to nil tokens */ Readonly M_Layer M_NilLayer = { - .next = &M_NilLayer, - .file = &M_NilTokenFile, - .first = &M_NilEntry, - .last = &M_NilEntry, + .next = &M_NilLayer, + .file = &M_NilTokenFile, + .first = &M_NilEntry, + .last = &M_NilEntry, }; //////////////////////////////////////////////////////////// @@ -29,20 +29,20 @@ Readonly M_Layer M_NilLayer = { M_Error *M_PushError(Arena *arena, M_ErrorList *l, M_Token *token, String msg) { - M_Error *e = PushStruct(arena, M_Error); - e->msg = msg; - e->token = token ? token : &M_NilToken; - SllQueuePush(l->first, l->last, e); - ++l->count; - return e; + M_Error *e = PushStruct(arena, M_Error); + e->msg = msg; + e->token = token ? token : &M_NilToken; + SllQueuePush(l->first, l->last, e); + ++l->count; + return e; } void M_AppendErrors(Arena *arena, M_ErrorList *dst, M_ErrorList src) { - for (M_Error *e = src.first; e; e = e->next) - { - M_PushError(arena, dst, e->token, e->msg); - } + for (M_Error *e = src.first; e; e = e->next) + { + M_PushError(arena, dst, e->token, e->msg); + } } //////////////////////////////////////////////////////////// @@ -50,153 +50,153 @@ void M_AppendErrors(Arena *arena, M_ErrorList *dst, M_ErrorList src) M_TokenFile *M_PushTokenFile(Arena *arena, M_TokenFileList *l, String name, String data) { - M_TokenFile *tf = PushStruct(arena, M_TokenFile); - *tf = M_NilTokenFile; - tf->valid = 1; - tf->name = name; - tf->data = data; - M_PushToken(arena, tf, Lit(""), M_TokenKind_Eol); - SllQueuePushNZ(&M_NilTokenFile, l->first, l->last, tf, next); - ++l->count; - return tf; + M_TokenFile *tf = PushStruct(arena, M_TokenFile); + *tf = M_NilTokenFile; + tf->valid = 1; + tf->name = name; + tf->data = data; + M_PushToken(arena, tf, Lit(""), M_TokenKind_Eol); + SllQueuePushNZ(&M_NilTokenFile, l->first, l->last, tf, next); + ++l->count; + return tf; } M_Token *M_PushToken(Arena *arena, M_TokenFile *file, String s, M_TokenKind kind) { - M_Token *t = PushStruct(arena, M_Token); - *t = M_NilToken; - t->valid = 1; - t->s = s; - t->kind = kind; - if (file) - { - t->file = file; - } - SllQueuePushNZ(&M_NilToken, file->first_token, file->last_token, t, next); - ++file->tokens_count; - return t; + M_Token *t = PushStruct(arena, M_Token); + *t = M_NilToken; + t->valid = 1; + t->s = s; + t->kind = kind; + if (file) + { + t->file = file; + } + SllQueuePushNZ(&M_NilToken, file->first_token, file->last_token, t, next); + ++file->tokens_count; + return t; } M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs) { - M_TokenFileList result = Zi; - TempArena scratch = BeginScratch(arena); - result.first = &M_NilTokenFile; - result.last = &M_NilTokenFile; + M_TokenFileList result = Zi; + TempArena scratch = BeginScratch(arena); + result.first = &M_NilTokenFile; + result.last = &M_NilTokenFile; - /* Build token file list from src dirs */ - Dict *dedup_dict = InitDict(scratch.arena, 1021); - for (StringListNode *dir_name_node = src_dirs.first; dir_name_node; dir_name_node = dir_name_node->next) + /* Build token file list from src dirs */ + Dict *dedup_dict = InitDict(scratch.arena, 1021); + for (StringListNode *dir_name_node = src_dirs.first; dir_name_node; dir_name_node = dir_name_node->next) + { + String dir_name = dir_name_node->s; + StringList files = Zi; + F_FilesFromDir(arena, &files, dir_name, F_IterFlag_Recurse); + for (StringListNode *file_name_node = files.first; file_name_node; file_name_node = file_name_node->next) { - String dir_name = dir_name_node->s; - StringList files = Zi; - F_FilesFromDir(arena, &files, dir_name, F_IterFlag_Recurse); - for (StringListNode *file_name_node = files.first; file_name_node; file_name_node = file_name_node->next) + String file_name = file_name_node->s; + if (StringEndsWith(file_name, Lit(".lay"))) + { + String tmp_full = F_GetFull(scratch.arena, file_name); + u64 hash = HashFnv64(Fnv64Basis, tmp_full); + if (DictValueFromHash(dedup_dict, hash) == 0) { - String file_name = file_name_node->s; - if (StringEndsWith(file_name, Lit(".lay"))) - { - String tmp_full = F_GetFull(scratch.arena, file_name); - u64 hash = HashFnv64(Fnv64Basis, tmp_full); - if (DictValueFromHash(dedup_dict, hash) == 0) - { - SetDictValue(scratch.arena, dedup_dict, hash, 1); - String full = PushString(arena, tmp_full); - String data = F_DataFromFile(arena, full); - M_PushTokenFile(arena, &result, full, data); - } - } + SetDictValue(scratch.arena, dedup_dict, hash, 1); + String full = PushString(arena, tmp_full); + String data = F_DataFromFile(arena, full); + M_PushTokenFile(arena, &result, full, data); } + } } + } - for (M_TokenFile *tf = result.first; tf->valid; tf = tf->next) + for (M_TokenFile *tf = result.first; tf->valid; tf = tf->next) + { + Enum(TokenizerMode) { - Enum(TokenizerMode) - { - TokenizerMode_None, - TokenizerMode_SingleLineComment, - TokenizerMode_MultiLineComment, - }; - TokenizerMode mode = TokenizerMode_None; + TokenizerMode_None, + TokenizerMode_SingleLineComment, + TokenizerMode_MultiLineComment, + }; + TokenizerMode mode = TokenizerMode_None; - u8 *t = tf->data.text; - u64 l = tf->data.len; - u64 p = 0; - String cur_ident = STRING(0, t); - while (p < l) + u8 *t = tf->data.text; + u64 l = tf->data.len; + u64 p = 0; + String cur_ident = STRING(0, t); + while (p < l) + { + switch (mode) + { + case TokenizerMode_None: { - switch (mode) + u8 c = t[p]; + b32 is_eol = c == '\r' || c == '\n' || c == 0 || (p + 1) >= l; + b32 is_whitespace = is_eol || c == ' '; + if (is_whitespace) + { /* Whitespace */ + if (cur_ident.len > 0) { - case TokenizerMode_None: - { - u8 c = t[p]; - b32 is_eol = c == '\r' || c == '\n' || c == 0 || (p + 1) >= l; - b32 is_whitespace = is_eol || c == ' '; - if (is_whitespace) - { /* Whitespace */ - if (cur_ident.len > 0) - { - M_PushToken(arena, tf, cur_ident, M_TokenKind_Ident); - cur_ident.len = 0; - } - if (is_eol) - { - M_PushToken(arena, tf, STRING(1, &t[p]), M_TokenKind_Eol); - } - p += 1; - } - else if (c == '/' && (p + 1) < l && t[p + 1] == '/') - { /* Start single line comment */ - mode = TokenizerMode_SingleLineComment; - p += 2; - } - else if (c == '/' && (p + 1) < l && t[p + 1] == '*') - { /* Start multi line comment */ - mode = TokenizerMode_MultiLineComment; - p += 2; - } - else - { - if (cur_ident.len == 0) - { - cur_ident.text = &t[p]; - } - ++cur_ident.len; - p += 1; - } - } break; - - case TokenizerMode_SingleLineComment: - { - if (t[p] == '\n') - { /* End single line comment */ - mode = TokenizerMode_None; - p += 1; - } - else - { - p += 1; - } - } break; - - case TokenizerMode_MultiLineComment: - { - if (t[p] == '*' && (p + 1) < l && t[p + 1] == '/') - { /* End multi line comment */ - mode = TokenizerMode_None; - p += 2; - } - else - { - p += 1; - } - } break; + M_PushToken(arena, tf, cur_ident, M_TokenKind_Ident); + cur_ident.len = 0; } - } - } + if (is_eol) + { + M_PushToken(arena, tf, STRING(1, &t[p]), M_TokenKind_Eol); + } + p += 1; + } + else if (c == '/' && (p + 1) < l && t[p + 1] == '/') + { /* Start single line comment */ + mode = TokenizerMode_SingleLineComment; + p += 2; + } + else if (c == '/' && (p + 1) < l && t[p + 1] == '*') + { /* Start multi line comment */ + mode = TokenizerMode_MultiLineComment; + p += 2; + } + else + { + if (cur_ident.len == 0) + { + cur_ident.text = &t[p]; + } + ++cur_ident.len; + p += 1; + } + } break; - EndScratch(scratch); - return result; + case TokenizerMode_SingleLineComment: + { + if (t[p] == '\n') + { /* End single line comment */ + mode = TokenizerMode_None; + p += 1; + } + else + { + p += 1; + } + } break; + + case TokenizerMode_MultiLineComment: + { + if (t[p] == '*' && (p + 1) < l && t[p + 1] == '/') + { /* End multi line comment */ + mode = TokenizerMode_None; + p += 2; + } + else + { + p += 1; + } + } break; + } + } + } + + EndScratch(scratch); + return result; } //////////////////////////////////////////////////////////// @@ -204,124 +204,124 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs) M_Layer *M_PushLayer(Arena *arena, M_LayerList *list, M_TokenFile *file) { - M_Layer *layer = PushStruct(arena, M_Layer); - *layer = M_NilLayer; - layer->valid = 1; - layer->file = file; - SllQueuePushNZ(&M_NilLayer, list->first, list->last, layer, next); - ++list->count; - return layer; + M_Layer *layer = PushStruct(arena, M_Layer); + *layer = M_NilLayer; + layer->valid = 1; + layer->file = file; + SllQueuePushNZ(&M_NilLayer, list->first, list->last, layer, next); + ++list->count; + return layer; } M_Entry *M_PushEntry(Arena *arena, M_Layer *l, M_EntryKind kind, M_Token *entry_token, u64 args_count, M_Token **args) { - M_Entry *e = PushStruct(arena, M_Entry); - *e = M_NilEntry; - e->valid = 1; - e->kind = kind; - if (entry_token) e->name_token = entry_token; - for (u64 i = 0; i < MinU64(args_count, countof(e->arg_tokens)); ++i) - { - e->arg_tokens[i] = args[i]; - } - e->args_count = args_count; - SllQueuePushNZ(&M_NilEntry, l->first, l->last, e, next); - ++l->count; - return e; + M_Entry *e = PushStruct(arena, M_Entry); + *e = M_NilEntry; + e->valid = 1; + e->kind = kind; + if (entry_token) e->name_token = entry_token; + for (u64 i = 0; i < MinU64(args_count, countof(e->arg_tokens)); ++i) + { + e->arg_tokens[i] = args[i]; + } + e->args_count = args_count; + SllQueuePushNZ(&M_NilEntry, l->first, l->last, e, next); + ++l->count; + return e; } M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed) { - TempArena scratch = BeginScratch(arena); - M_LayerList result = Zi; - result.first = &M_NilLayer; - result.last = &M_NilLayer; + TempArena scratch = BeginScratch(arena); + M_LayerList result = Zi; + result.first = &M_NilLayer; + result.last = &M_NilLayer; + + /* Copy errors */ + b32 lexer_errors_present = 0; + for (M_TokenFile *lf = lexed.first; lf->valid; lf = lf->next) + { + if (lf->errors.count > 0) + { + M_Layer *layer = M_PushLayer(arena, &result, lf); + M_AppendErrors(arena, &layer->errors, lf->errors); + lexer_errors_present = 1; + } + } + + if (!lexer_errors_present) + { + Dict *rules_dict = InitDict(scratch.arena, 1024); + for (u64 i = 0; i < countof(M_entry_kind_rules); ++i) + { + char *rule_cstr = M_entry_kind_rules[i]; + u64 rule_hash = HashFnv64(Fnv64Basis, StringFromCstrNoLimit(rule_cstr)); + SetDictValue(scratch.arena, rules_dict, rule_hash, i + 1); + } - /* Copy errors */ - b32 lexer_errors_present = 0; for (M_TokenFile *lf = lexed.first; lf->valid; lf = lf->next) { - if (lf->errors.count > 0) - { - M_Layer *layer = M_PushLayer(arena, &result, lf); - M_AppendErrors(arena, &layer->errors, lf->errors); - lexer_errors_present = 1; - } - } + M_Layer *layer = M_PushLayer(arena, &result, lf); - if (!lexer_errors_present) - { - Dict *rules_dict = InitDict(scratch.arena, 1024); - for (u64 i = 0; i < countof(M_entry_kind_rules); ++i) - { - char *rule_cstr = M_entry_kind_rules[i]; - u64 rule_hash = HashFnv64(Fnv64Basis, StringFromCstrNoLimit(rule_cstr)); - SetDictValue(scratch.arena, rules_dict, rule_hash, i + 1); - } + M_Token *entry_token = &M_NilToken; + M_Token *arg_tokens[countof(M_NilEntry.arg_tokens) + 1]; + u64 args_count = 0; + for (u64 i = 0; i < countof(arg_tokens); ++i) + { + arg_tokens[i] = &M_NilToken; + } - for (M_TokenFile *lf = lexed.first; lf->valid; lf = lf->next) + M_Token *token = lf->first_token; + while (token->valid) + { + if (token->kind == M_TokenKind_Eol) { - M_Layer *layer = M_PushLayer(arena, &result, lf); - - M_Token *entry_token = &M_NilToken; - M_Token *arg_tokens[countof(M_NilEntry.arg_tokens) + 1]; - u64 args_count = 0; - for (u64 i = 0; i < countof(arg_tokens); ++i) + if (entry_token->valid) + { + M_Entry *entry = M_PushEntry(arena, layer, M_EntryKind_Unknown, entry_token, args_count, arg_tokens); { - arg_tokens[i] = &M_NilToken; - } - - M_Token *token = lf->first_token; - while (token->valid) - { - if (token->kind == M_TokenKind_Eol) - { - if (entry_token->valid) - { - M_Entry *entry = M_PushEntry(arena, layer, M_EntryKind_Unknown, entry_token, args_count, arg_tokens); - { - u64 entry_hash = HashFnv64(Fnv64Basis, entry_token->s); - u64 kind_plus_1 = DictValueFromHash(rules_dict, entry_hash); - if (kind_plus_1 > 0) - { - entry->kind = kind_plus_1 - 1; - } - else - { - String err = StringF(arena, "Unexpected token \"%F\"", FmtString(entry_token->s)); - M_PushError(arena, &layer->errors, entry->name_token, err); - } - } - } - token = token->next; - entry_token = &M_NilToken; - args_count = 0; - for (u64 i = 0; i < countof(arg_tokens); ++i) - { - arg_tokens[i] = &M_NilToken; - } - } - else - { - /* Parse entry */ - entry_token = token; - token = token->next; - /* Parse args */ - while (token->kind != M_TokenKind_Eol) - { - if (args_count < countof(arg_tokens)) - { - arg_tokens[args_count++] = token; - } - token = token->next; - } - } + u64 entry_hash = HashFnv64(Fnv64Basis, entry_token->s); + u64 kind_plus_1 = DictValueFromHash(rules_dict, entry_hash); + if (kind_plus_1 > 0) + { + entry->kind = kind_plus_1 - 1; + } + else + { + String err = StringF(arena, "Unexpected token \"%F\"", FmtString(entry_token->s)); + M_PushError(arena, &layer->errors, entry->name_token, err); + } } + } + token = token->next; + entry_token = &M_NilToken; + args_count = 0; + for (u64 i = 0; i < countof(arg_tokens); ++i) + { + arg_tokens[i] = &M_NilToken; + } } + else + { + /* Parse entry */ + entry_token = token; + token = token->next; + /* Parse args */ + while (token->kind != M_TokenKind_Eol) + { + if (args_count < countof(arg_tokens)) + { + arg_tokens[args_count++] = token; + } + token = token->next; + } + } + } } + } - EndScratch(scratch); - return result; + EndScratch(scratch); + return result; } //////////////////////////////////////////////////////////// @@ -329,244 +329,244 @@ M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed) M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList starting_layer_names) { - TempArena scratch = BeginScratch(arena); - M_Layer result = M_NilLayer; + TempArena scratch = BeginScratch(arena); + M_Layer result = M_NilLayer; - /* Copy errors */ - b32 unflattened_errors_present = 0; + /* Copy errors */ + b32 unflattened_errors_present = 0; + for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next) + { + if (layer->errors.count > 0) + { + M_AppendErrors(arena, &result.errors, layer->errors); + unflattened_errors_present = 1; + } + } + + if (!unflattened_errors_present) + { + Enum(IterStateMode) + { + IterStateMode_None, + IterStateMode_Entered, + IterStateMode_Exited + }; + Struct(IterState) + { + M_Layer *layer; + b32 is_entered; + b32 is_exited; + } NilIterState = { + .layer = &M_NilLayer + }; + + /* Construct state lookups */ + Dict *layer_ptr_to_state = InitDict(scratch.arena, 1021); + Dict *layer_name_to_state = InitDict(scratch.arena, 1021); for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next) { - if (layer->errors.count > 0) + M_Entry *name_entry = &M_NilEntry; + u64 num_name_entries = 0; + for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) + { + if (entry->kind == M_EntryKind_Layer) { - M_AppendErrors(arena, &result.errors, layer->errors); - unflattened_errors_present = 1; + if (num_name_entries == 0) + { + name_entry = entry; + } + else + { + String err = StringF(arena, "Layer already has name \"%F\"", FmtString(name_entry->arg_tokens[0]->s)); + M_PushError(arena, &result.errors, entry->name_token, err); + } + ++num_name_entries; } + } + if (num_name_entries == 1 && name_entry->arg_tokens[0]->s.len > 0) + { + IterState *state = PushStruct(scratch.arena, IterState); + state->layer = layer; + + String name = name_entry->arg_tokens[0]->s; + + u64 name_hash = HashFnv64(Fnv64Basis, name); + DictEntry *ptr_dict_entry = EnsureDictEntry(scratch.arena, layer_ptr_to_state, (u64)layer); + DictEntry *name_dict_entry = EnsureDictEntry(scratch.arena, layer_name_to_state, name_hash); + + ptr_dict_entry->value = (u64)state; + if (name_dict_entry->value == 0) + { + name_dict_entry->value = (u64)state; + } + else + { + String err = StringF(arena, "Layer with name \"%F\" already exists", FmtString(name)); + M_PushError(arena, &result.errors, name_entry->arg_tokens[0], err); + } + } + else if (num_name_entries == 0) + { + M_PushError(arena, &result.errors, layer->file->first_token, Lit("Layer is missing a name")); + } } - if (!unflattened_errors_present) + Struct(StackNode) { StackNode *next; IterState *state; b32 exit; }; + StackNode *stack = 0; + + /* Init stack with starting layers */ + for (StringListNode *sln = starting_layer_names.first; sln; sln = sln->next) { - Enum(IterStateMode) - { - IterStateMode_None, - IterStateMode_Entered, - IterStateMode_Exited - }; - Struct(IterState) - { - M_Layer *layer; - b32 is_entered; - b32 is_exited; - } NilIterState = { - .layer = &M_NilLayer - }; + String name = sln->s; + u64 name_hash = HashFnv64(Fnv64Basis, name); + IterState *state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, name_hash, (u64)&NilIterState); + M_Layer *layer = state->layer; + if (layer->valid) + { + StackNode *n = PushStruct(scratch.arena, StackNode); + n->state = state; + SllStackPush(stack, n); + } + else + { + String err = StringF(arena, "Starting layer \"%F\" not found", FmtString(name)); + M_PushError(arena, &result.errors, 0, err); + } + } - /* Construct state lookups */ - Dict *layer_ptr_to_state = InitDict(scratch.arena, 1021); - Dict *layer_name_to_state = InitDict(scratch.arena, 1021); - for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next) + /* Flatten via post-order DFS */ + while (stack) + { + StackNode *stack_node = stack; + SllStackPop(stack); + IterState *state = stack_node->state; + M_Layer *layer = state->layer; + + if (stack_node->exit) + { + /* Push items to sorted root */ + state->is_entered = 0; + state->is_exited = 1; + for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) { - M_Entry *name_entry = &M_NilEntry; - u64 num_name_entries = 0; - for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) + M_PushEntry(arena, &result, entry->kind, entry->name_token, entry->args_count, entry->arg_tokens); + } + } + else + { + if (state->is_entered) + { + /* Cyclic dependency */ + /* FIXME: Handle cyclic dependency error */ + Assert(0); + } + else if (!state->is_exited) + { + state->is_entered = 1; + + /* Push downstream impl entries to stack */ + for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) + { + if (entry->kind == M_EntryKind_DefaultDownstream) { - if (entry->kind == M_EntryKind_Layer) + M_Token *platform_token = entry->arg_tokens[0]; + M_Token *downstream_layer_token = entry->arg_tokens[1]; + + if (platform_token->valid && downstream_layer_token->valid) + { + /* Determine platform match */ + b32 should_include = 0; { - if (num_name_entries == 0) - { - name_entry = entry; - } - else - { - String err = StringF(arena, "Layer already has name \"%F\"", FmtString(name_entry->arg_tokens[0]->s)); - M_PushError(arena, &result.errors, entry->name_token, err); - } - ++num_name_entries; + String platform_name = platform_token->s; + if (MatchString(platform_name, Lit("Any"))) + { + should_include = 1; + } + else if (MatchString(platform_name, Lit("Win32"))) + { + should_include = IsPlatformWindows; + } + else + { + String err = StringF(arena, "Unknown platform \"%F\"", FmtString(platform_name)); + M_PushError(arena, &result.errors, platform_token, err); + } } - } - if (num_name_entries == 1 && name_entry->arg_tokens[0]->s.len > 0) - { - IterState *state = PushStruct(scratch.arena, IterState); - state->layer = layer; - String name = name_entry->arg_tokens[0]->s; - - u64 name_hash = HashFnv64(Fnv64Basis, name); - DictEntry *ptr_dict_entry = EnsureDictEntry(scratch.arena, layer_ptr_to_state, (u64)layer); - DictEntry *name_dict_entry = EnsureDictEntry(scratch.arena, layer_name_to_state, name_hash); - - ptr_dict_entry->value = (u64)state; - if (name_dict_entry->value == 0) + /* Include layer downstream */ + if (should_include) { - name_dict_entry->value = (u64)state; + String downstream_layer_name = downstream_layer_token->s; + u64 hash = HashFnv64(Fnv64Basis, downstream_layer_name); + IterState *downstream_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState); + M_Layer *downstream_layer = downstream_layer_state->layer; + if (downstream_layer->valid) + { + if (!downstream_layer_state->is_exited) + { + StackNode *n = PushStruct(scratch.arena, StackNode); + n->state = downstream_layer_state; + SllStackPush(stack, n); + } + } + else + { + String err = StringF(arena, "Layer \"%F\" not found", FmtString(downstream_layer_name)); + M_PushError(arena, &result.errors, downstream_layer_token, err); + } + } + } + else + { + M_PushError(arena, &result.errors, entry->name_token, Lit("Expected platform and layer arguments")); + } + } + } + + /* Push node exit to stack */ + { + stack_node->exit = 1; + SllStackPush(stack, stack_node); + } + + /* Push upstream dep entries to stack */ + for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) + { + if (entry->kind == M_EntryKind_Dep) + { + M_Token *dep_token = entry->arg_tokens[0]; + if (dep_token->valid) + { + String dep_name = dep_token->s; + u64 hash = HashFnv64(Fnv64Basis, dep_name); + IterState *dep_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState); + M_Layer *dep_layer = dep_layer_state->layer; + if (dep_layer->valid) + { + if (!dep_layer_state->is_exited) + { + StackNode *n = PushStruct(scratch.arena, StackNode); + n->state = dep_layer_state; + SllStackPush(stack, n); + } } else { - String err = StringF(arena, "Layer with name \"%F\" already exists", FmtString(name)); - M_PushError(arena, &result.errors, name_entry->arg_tokens[0], err); - } - } - else if (num_name_entries == 0) - { - M_PushError(arena, &result.errors, layer->file->first_token, Lit("Layer is missing a name")); - } - } - - Struct(StackNode) { StackNode *next; IterState *state; b32 exit; }; - StackNode *stack = 0; - - /* Init stack with starting layers */ - for (StringListNode *sln = starting_layer_names.first; sln; sln = sln->next) - { - String name = sln->s; - u64 name_hash = HashFnv64(Fnv64Basis, name); - IterState *state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, name_hash, (u64)&NilIterState); - M_Layer *layer = state->layer; - if (layer->valid) - { - StackNode *n = PushStruct(scratch.arena, StackNode); - n->state = state; - SllStackPush(stack, n); - } - else - { - String err = StringF(arena, "Starting layer \"%F\" not found", FmtString(name)); - M_PushError(arena, &result.errors, 0, err); - } - } - - /* Flatten via post-order DFS */ - while (stack) - { - StackNode *stack_node = stack; - SllStackPop(stack); - IterState *state = stack_node->state; - M_Layer *layer = state->layer; - - if (stack_node->exit) - { - /* Push items to sorted root */ - state->is_entered = 0; - state->is_exited = 1; - for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) - { - M_PushEntry(arena, &result, entry->kind, entry->name_token, entry->args_count, entry->arg_tokens); - } - } - else - { - if (state->is_entered) - { - /* Cyclic dependency */ - /* FIXME: Handle cyclic dependency error */ - Assert(0); - } - else if (!state->is_exited) - { - state->is_entered = 1; - - /* Push downstream impl entries to stack */ - for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) - { - if (entry->kind == M_EntryKind_DefaultDownstream) - { - M_Token *platform_token = entry->arg_tokens[0]; - M_Token *downstream_layer_token = entry->arg_tokens[1]; - - if (platform_token->valid && downstream_layer_token->valid) - { - /* Determine platform match */ - b32 should_include = 0; - { - String platform_name = platform_token->s; - if (MatchString(platform_name, Lit("Any"))) - { - should_include = 1; - } - else if (MatchString(platform_name, Lit("Win32"))) - { - should_include = IsPlatformWindows; - } - else - { - String err = StringF(arena, "Unknown platform \"%F\"", FmtString(platform_name)); - M_PushError(arena, &result.errors, platform_token, err); - } - } - - /* Include layer downstream */ - if (should_include) - { - String downstream_layer_name = downstream_layer_token->s; - u64 hash = HashFnv64(Fnv64Basis, downstream_layer_name); - IterState *downstream_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState); - M_Layer *downstream_layer = downstream_layer_state->layer; - if (downstream_layer->valid) - { - if (!downstream_layer_state->is_exited) - { - StackNode *n = PushStruct(scratch.arena, StackNode); - n->state = downstream_layer_state; - SllStackPush(stack, n); - } - } - else - { - String err = StringF(arena, "Layer \"%F\" not found", FmtString(downstream_layer_name)); - M_PushError(arena, &result.errors, downstream_layer_token, err); - } - } - } - else - { - M_PushError(arena, &result.errors, entry->name_token, Lit("Expected platform and layer arguments")); - } - } - } - - /* Push node exit to stack */ - { - stack_node->exit = 1; - SllStackPush(stack, stack_node); - } - - /* Push upstream dep entries to stack */ - for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) - { - if (entry->kind == M_EntryKind_Dep) - { - M_Token *dep_token = entry->arg_tokens[0]; - if (dep_token->valid) - { - String dep_name = dep_token->s; - u64 hash = HashFnv64(Fnv64Basis, dep_name); - IterState *dep_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState); - M_Layer *dep_layer = dep_layer_state->layer; - if (dep_layer->valid) - { - if (!dep_layer_state->is_exited) - { - StackNode *n = PushStruct(scratch.arena, StackNode); - n->state = dep_layer_state; - SllStackPush(stack, n); - } - } - else - { - String err = StringF(arena, "Layer \"%F\" not found", FmtString(dep_name)); - M_PushError(arena, &result.errors, dep_token, err); - } - } - else - { - M_PushError(arena, &result.errors, entry->name_token, Lit("Expected layer argument")); - } - } - } + String err = StringF(arena, "Layer \"%F\" not found", FmtString(dep_name)); + M_PushError(arena, &result.errors, dep_token, err); } + } + else + { + M_PushError(arena, &result.errors, entry->name_token, Lit("Expected layer argument")); + } } + } } + } } + } - EndScratch(scratch); - return result; + EndScratch(scratch); + return result; } diff --git a/src/meta/meta_lay.h b/src/meta/meta_lay.h index f6416e86..bd96a2ba 100644 --- a/src/meta/meta_lay.h +++ b/src/meta/meta_lay.h @@ -3,16 +3,16 @@ Struct(M_Error) { - M_Error *next; - String msg; - struct M_Token *token; + M_Error *next; + String msg; + struct M_Token *token; }; Struct(M_ErrorList) { - M_Error *first; - M_Error *last; - u64 count; + M_Error *first; + M_Error *last; + u64 count; }; //////////////////////////////////////////////////////////// @@ -20,8 +20,8 @@ Struct(M_ErrorList) Struct(M_File) { - String name; - String data; + String name; + String data; }; //////////////////////////////////////////////////////////// @@ -29,41 +29,41 @@ Struct(M_File) Enum(M_TokenKind) { - M_TokenKind_Ident, - M_TokenKind_Eol, /* End of line */ + M_TokenKind_Ident, + M_TokenKind_Eol, /* End of line */ }; Struct(M_Token) { - b32 valid; - M_Token *next; + b32 valid; + M_Token *next; - M_TokenKind kind; - struct M_TokenFile *file; + M_TokenKind kind; + struct M_TokenFile *file; - String s; + String s; } extern Readonly M_NilToken; Struct(M_TokenFile) { - b32 valid; - M_TokenFile *next; + b32 valid; + M_TokenFile *next; - String name; - String data; + String name; + String data; - M_Token *first_token; - M_Token *last_token; - u64 tokens_count; + M_Token *first_token; + M_Token *last_token; + u64 tokens_count; - M_ErrorList errors; + M_ErrorList errors; } extern Readonly M_NilTokenFile; Struct(M_TokenFileList) { - M_TokenFile *first; - M_TokenFile *last; - u64 count; + M_TokenFile *first; + M_TokenFile *last; + u64 count; }; //////////////////////////////////////////////////////////// @@ -71,68 +71,68 @@ Struct(M_TokenFileList) Enum(M_EntryKind) { - M_EntryKind_Unknown, - M_EntryKind_Layer, - M_EntryKind_Dep, - M_EntryKind_IncludeC, - M_EntryKind_IncludeG, - M_EntryKind_DefaultDownstream, - M_EntryKind_Bootstrap, - M_EntryKind_VertexShader, - M_EntryKind_PixelShader, - M_EntryKind_ComputeShader, - M_EntryKind_EmbedDir, + M_EntryKind_Unknown, + M_EntryKind_Layer, + M_EntryKind_Dep, + M_EntryKind_IncludeC, + M_EntryKind_IncludeG, + M_EntryKind_DefaultDownstream, + M_EntryKind_Bootstrap, + M_EntryKind_VertexShader, + M_EntryKind_PixelShader, + M_EntryKind_ComputeShader, + M_EntryKind_EmbedDir, }; Enum(M_PlatformKind) { - M_PlatformKind_Any, - M_PlatformKind_Win32, + M_PlatformKind_Any, + M_PlatformKind_Win32, }; Global Readonly char *M_entry_kind_rules[] = { - [M_EntryKind_Layer] = "@Layer", - [M_EntryKind_Dep] = "@Dep", - [M_EntryKind_IncludeC] = "@IncludeC", - [M_EntryKind_IncludeG] = "@IncludeG", - [M_EntryKind_DefaultDownstream] = "@DefaultDownstream", - [M_EntryKind_Bootstrap] = "@Bootstrap", - [M_EntryKind_VertexShader] = "@VertexShader", - [M_EntryKind_PixelShader] = "@PixelShader", - [M_EntryKind_ComputeShader] = "@ComputeShader", - [M_EntryKind_EmbedDir] = "@EmbedDir", + [M_EntryKind_Layer] = "@Layer", + [M_EntryKind_Dep] = "@Dep", + [M_EntryKind_IncludeC] = "@IncludeC", + [M_EntryKind_IncludeG] = "@IncludeG", + [M_EntryKind_DefaultDownstream] = "@DefaultDownstream", + [M_EntryKind_Bootstrap] = "@Bootstrap", + [M_EntryKind_VertexShader] = "@VertexShader", + [M_EntryKind_PixelShader] = "@PixelShader", + [M_EntryKind_ComputeShader] = "@ComputeShader", + [M_EntryKind_EmbedDir] = "@EmbedDir", }; Struct(M_Entry) { - b32 valid; - M_Entry *next; + b32 valid; + M_Entry *next; - M_EntryKind kind; - M_Token *name_token; + M_EntryKind kind; + M_Token *name_token; - M_Token *arg_tokens[2]; - u64 args_count; + M_Token *arg_tokens[2]; + u64 args_count; } extern Readonly M_NilEntry; Struct(M_Layer) { - b32 valid; - M_Layer *next; + b32 valid; + M_Layer *next; - M_TokenFile *file; + M_TokenFile *file; - M_Entry *first; - M_Entry *last; - u64 count; - M_ErrorList errors; + M_Entry *first; + M_Entry *last; + u64 count; + M_ErrorList errors; } extern Readonly M_NilLayer; Struct(M_LayerList) { - M_Layer *first; - M_Layer *last; - u64 count; + M_Layer *first; + M_Layer *last; + u64 count; }; //////////////////////////////////////////////////////////// diff --git a/src/meta/meta_os/meta_os.h b/src/meta/meta_os/meta_os.h index ae22db8d..1c0704d8 100644 --- a/src/meta/meta_os/meta_os.h +++ b/src/meta/meta_os/meta_os.h @@ -3,15 +3,15 @@ Enum(OS_FileFlag) { - OS_FileFlag_None = 0, - OS_FileFlag_Read = (1 << 0), - OS_FileFlag_Write = (1 << 1), - OS_FileFlag_Create = (1 << 2), + OS_FileFlag_None = 0, + OS_FileFlag_Read = (1 << 0), + OS_FileFlag_Write = (1 << 1), + OS_FileFlag_Create = (1 << 2), }; Struct(OS_File) { - u64 handle; + u64 handle; }; //////////////////////////////////////////////////////////// @@ -19,8 +19,8 @@ Struct(OS_File) Struct(OS_CommandResult) { - i32 code; - String output; + i32 code; + String output; }; //////////////////////////////////////////////////////////// diff --git a/src/meta/meta_os/meta_os_inc.h b/src/meta/meta_os/meta_os_inc.h index 84f72c30..17b2c388 100644 --- a/src/meta/meta_os/meta_os_inc.h +++ b/src/meta/meta_os/meta_os_inc.h @@ -1,5 +1,5 @@ #include "meta_os.h" #if IsPlatformWindows -# include "meta_os_win32/meta_os_win32_inc.h" + #include "meta_os_win32/meta_os_win32_inc.h" #endif diff --git a/src/meta/meta_os/meta_os_win32/meta_os_win32.c b/src/meta/meta_os/meta_os_win32/meta_os_win32.c index 1f9b8d5f..7c811fb4 100644 --- a/src/meta/meta_os/meta_os_win32/meta_os_win32.c +++ b/src/meta/meta_os/meta_os_win32/meta_os_win32.c @@ -3,27 +3,27 @@ String W32_StringFromError(Arena *arena, DWORD err) { - String result = Zi; - char *msg_cstr = 0; - i64 len = FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - 0, - err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&msg_cstr, - 0, - 0 - ); - if (len > 0) - { - result = PushString(arena, TrimWhitespace(StringFromCstr(msg_cstr, len))); - LocalFree(msg_cstr); - } - else - { - result = StringF(arena, "Unknown win32 error - %F", FmtHex(err)); - } - return result; + String result = Zi; + char *msg_cstr = 0; + i64 len = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + 0, + err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&msg_cstr, + 0, + 0 + ); + if (len > 0) + { + result = PushString(arena, TrimWhitespace(StringFromCstr(msg_cstr, len))); + LocalFree(msg_cstr); + } + else + { + result = StringF(arena, "Unknown win32 error - %F", FmtHex(err)); + } + return result; } //////////////////////////////////////////////////////////// @@ -38,117 +38,117 @@ void OS_Bootstrap(void) OS_File OS_OpenFile(String path, OS_FileFlag flags, i64 timeout_ns) { - TempArena scratch = BeginScratchNoConflict(); - OS_File result = Zi; - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - u32 share_mode = FILE_SHARE_READ; - u32 create_mode = OPEN_EXISTING; - u32 access_flags = 0; - if (flags & OS_FileFlag_Read) access_flags |= GENERIC_READ; - if (flags & OS_FileFlag_Write) access_flags |= GENERIC_WRITE; - if (flags & OS_FileFlag_Create) create_mode = OPEN_ALWAYS; - i32 timeout_ms = timeout_ns / 1000000; - i32 elapsed_ms = 0; - i32 delay_ms = 1; - HANDLE handle = INVALID_HANDLE_VALUE; - for (;;) + TempArena scratch = BeginScratchNoConflict(); + OS_File result = Zi; + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + u32 share_mode = FILE_SHARE_READ; + u32 create_mode = OPEN_EXISTING; + u32 access_flags = 0; + if (flags & OS_FileFlag_Read) access_flags |= GENERIC_READ; + if (flags & OS_FileFlag_Write) access_flags |= GENERIC_WRITE; + if (flags & OS_FileFlag_Create) create_mode = OPEN_ALWAYS; + i32 timeout_ms = timeout_ns / 1000000; + i32 elapsed_ms = 0; + i32 delay_ms = 1; + HANDLE handle = INVALID_HANDLE_VALUE; + for (;;) + { + handle = CreateFileW(path_wstr, access_flags, share_mode, 0, create_mode, FILE_ATTRIBUTE_NORMAL, 0); + if (handle == INVALID_HANDLE_VALUE && elapsed_ms < timeout_ms && GetLastError() == ERROR_SHARING_VIOLATION) { - handle = CreateFileW(path_wstr, access_flags, share_mode, 0, create_mode, FILE_ATTRIBUTE_NORMAL, 0); - if (handle == INVALID_HANDLE_VALUE && elapsed_ms < timeout_ms && GetLastError() == ERROR_SHARING_VIOLATION) - { - Sleep(delay_ms); - elapsed_ms += delay_ms; - delay_ms = MinI32(delay_ms * 2, 1024); - } - else - { - break; - } + Sleep(delay_ms); + elapsed_ms += delay_ms; + delay_ms = MinI32(delay_ms * 2, 1024); } - EndScratch(scratch); - result.handle = (u64)handle; - return result; + else + { + break; + } + } + EndScratch(scratch); + result.handle = (u64)handle; + return result; } void OS_CloseFile(OS_File file) { - HANDLE handle = (HANDLE)file.handle; - CloseHandle(handle); + HANDLE handle = (HANDLE)file.handle; + CloseHandle(handle); } String OS_ReadEntireFile(Arena *arena, OS_File file) { - String result = Zi; - HANDLE handle = (HANDLE)file.handle; - u32 chunk_size = Kibi(64); - result.text = ArenaNext(arena, u8); - for (;;) + String result = Zi; + HANDLE handle = (HANDLE)file.handle; + u32 chunk_size = Kibi(64); + result.text = ArenaNext(arena, u8); + for (;;) + { + u8 *chunk = PushStructsNoZero(arena, u8, chunk_size); + DWORD chunk_bytes_read = 0; + ReadFile(handle, chunk, chunk_size, &chunk_bytes_read, 0); + result.len += chunk_bytes_read; + if (chunk_bytes_read < chunk_size) { - u8 *chunk = PushStructsNoZero(arena, u8, chunk_size); - DWORD chunk_bytes_read = 0; - ReadFile(handle, chunk, chunk_size, &chunk_bytes_read, 0); - result.len += chunk_bytes_read; - if (chunk_bytes_read < chunk_size) - { - PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read); - break; - } + PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read); + break; } - return result; + } + return result; } void OS_ClearWriteFile(OS_File file, String data) { - HANDLE handle = (HANDLE)file.handle; - SetFilePointer(handle, 0, 0, FILE_BEGIN); - SetEndOfFile(handle); - WriteFile(handle, data.text, data.len, 0, 0); + HANDLE handle = (HANDLE)file.handle; + SetFilePointer(handle, 0, 0, FILE_BEGIN); + SetEndOfFile(handle); + WriteFile(handle, data.text, data.len, 0, 0); } void OS_DirContentsFromFullPath(Arena *arena, StringList *list, String path) { - TempArena scratch = BeginScratch(arena); - WIN32_FIND_DATAW find_data = Zi; - String filter = StringF(scratch.arena, "%F\\*", FmtString(path)); - wchar_t *filter_wstr = WstrFromString(scratch.arena, filter); - HANDLE find_handle = FindFirstFileExW(filter_wstr, FindExInfoStandard, &find_data, FindExSearchNameMatch, 0, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH); - b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE; - while (found) + TempArena scratch = BeginScratch(arena); + WIN32_FIND_DATAW find_data = Zi; + String filter = StringF(scratch.arena, "%F\\*", FmtString(path)); + wchar_t *filter_wstr = WstrFromString(scratch.arena, filter); + HANDLE find_handle = FindFirstFileExW(filter_wstr, FindExInfoStandard, &find_data, FindExSearchNameMatch, 0, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH); + b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE; + while (found) + { + String file_name = StringFromWstrNoLimit(arena, find_data.cFileName); + if (!MatchString(file_name, Lit(".")) && !MatchString(file_name, Lit(".."))) { - String file_name = StringFromWstrNoLimit(arena, find_data.cFileName); - if (!MatchString(file_name, Lit(".")) && !MatchString(file_name, Lit(".."))) - { - PushStringToList(arena, list, file_name); - } - found = FindNextFileW(find_handle, &find_data); + PushStringToList(arena, list, file_name); } - EndScratch(scratch); + found = FindNextFileW(find_handle, &find_data); + } + EndScratch(scratch); } String OS_GetFullPath(Arena *arena, String path) { - TempArena scratch = BeginScratch(arena); - wchar_t *rel_path_wstr = WstrFromString(scratch.arena, path); - wchar_t full_path_wstr_buff[4096]; - GetFullPathNameW(rel_path_wstr, countof(full_path_wstr_buff), full_path_wstr_buff, 0); - String res = StringFromWstr(arena, full_path_wstr_buff, countof(full_path_wstr_buff)); - EndScratch(scratch); - return res; + TempArena scratch = BeginScratch(arena); + wchar_t *rel_path_wstr = WstrFromString(scratch.arena, path); + wchar_t full_path_wstr_buff[4096]; + GetFullPathNameW(rel_path_wstr, countof(full_path_wstr_buff), full_path_wstr_buff, 0); + String res = StringFromWstr(arena, full_path_wstr_buff, countof(full_path_wstr_buff)); + EndScratch(scratch); + return res; } u64 OS_LastWriteTimestampFromPath(String path) { - TempArena scratch = BeginScratchNoConflict(); - u64 result = 0; - WIN32_FILE_ATTRIBUTE_DATA a = Zi; - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - if (GetFileAttributesExW(path_wstr, GetFileExInfoStandard, &a)) - { - result = ((ULONGLONG)a.ftLastWriteTime.dwHighDateTime << 32) | - (ULONGLONG)a.ftLastWriteTime.dwLowDateTime; - } - EndScratch(scratch); - return result; + TempArena scratch = BeginScratchNoConflict(); + u64 result = 0; + WIN32_FILE_ATTRIBUTE_DATA a = Zi; + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + if (GetFileAttributesExW(path_wstr, GetFileExInfoStandard, &a)) + { + result = ((ULONGLONG)a.ftLastWriteTime.dwHighDateTime << 32) | + (ULONGLONG)a.ftLastWriteTime.dwLowDateTime; + } + EndScratch(scratch); + return result; } //////////////////////////////////////////////////////////// @@ -156,45 +156,45 @@ u64 OS_LastWriteTimestampFromPath(String path) b32 OS_FileOrDirExists(String path) { - TempArena scratch = BeginScratchNoConflict(); - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - DWORD attributes = GetFileAttributesW(path_wstr); - EndScratch(scratch); - return attributes != INVALID_FILE_ATTRIBUTES; + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + DWORD attributes = GetFileAttributesW(path_wstr); + EndScratch(scratch); + return attributes != INVALID_FILE_ATTRIBUTES; } b32 OS_FileExists(String path) { - TempArena scratch = BeginScratchNoConflict(); - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - DWORD attributes = GetFileAttributesW(path_wstr); - EndScratch(scratch); - return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY); + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + DWORD attributes = GetFileAttributesW(path_wstr); + EndScratch(scratch); + return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY); } b32 OS_DirExists(String path) { - TempArena scratch = BeginScratchNoConflict(); - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - DWORD attributes = GetFileAttributesW(path_wstr); - EndScratch(scratch); - return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY); + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + DWORD attributes = GetFileAttributesW(path_wstr); + EndScratch(scratch); + return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY); } void OS_Mkdir(String path) { - TempArena scratch = BeginScratchNoConflict(); - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - CreateDirectoryW(path_wstr, 0); - EndScratch(scratch); + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + CreateDirectoryW(path_wstr, 0); + EndScratch(scratch); } void OS_Rm(String path) { - TempArena scratch = BeginScratchNoConflict(); - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - DeleteFile(path_wstr); - EndScratch(scratch); + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + DeleteFile(path_wstr); + EndScratch(scratch); } //////////////////////////////////////////////////////////// @@ -202,150 +202,150 @@ void OS_Rm(String path) OS_CommandResult OS_RunCommand(Arena *arena, String cmd) { - TempArena scratch = BeginScratch(arena); - OS_CommandResult result = Zi; - b32 ok = 1; + TempArena scratch = BeginScratch(arena); + OS_CommandResult result = Zi; + b32 ok = 1; - wchar_t *cmd_wstr = WstrFromString(scratch.arena, cmd); + wchar_t *cmd_wstr = WstrFromString(scratch.arena, cmd); - SECURITY_ATTRIBUTES sa = Zi; - sa.nLength = sizeof(sa); - sa.bInheritHandle = 0; + SECURITY_ATTRIBUTES sa = Zi; + sa.nLength = sizeof(sa); + sa.bInheritHandle = 0; - /* Create pipe */ - HANDLE pipe_read = 0; - HANDLE pipe_write = 0; + /* Create pipe */ + HANDLE pipe_read = 0; + HANDLE pipe_write = 0; + if (ok) + { + ok = CreatePipe(&pipe_read, &pipe_write, &sa, 0) != 0; + if (!ok) + { + result.output = Lit("Failed to create pipe"); + pipe_read = 0; + pipe_write = 0; + } + } + + /* Duplicate pipe for child process */ + HANDLE child_pipe_write = 0; + if (ok) + { + ok = DuplicateHandle(GetCurrentProcess(), pipe_write, GetCurrentProcess(), &child_pipe_write, 0, 1, DUPLICATE_SAME_ACCESS) != 0; + if (!ok) + { + result.output = Lit("Failed to create child pipe"); + child_pipe_write = 0; + } + } + + /* Initialize attrs list */ + LPPROC_THREAD_ATTRIBUTE_LIST attrs = Zi; + if (ok) + { + u64 attrs_size = 0; + InitializeProcThreadAttributeList(0, 1, 0, &attrs_size); + ok = attrs_size > 0; if (ok) { - ok = CreatePipe(&pipe_read, &pipe_write, &sa, 0) != 0; - if (!ok) - { - result.output = Lit("Failed to create pipe"); - pipe_read = 0; - pipe_write = 0; - } + attrs = PushBytes(scratch.arena, attrs_size, 64); + ok = InitializeProcThreadAttributeList(attrs, 1, 0, &attrs_size) != 0; } + if (!ok) + { + result.output = Lit("Failed to initialize attrs list"); + } + } - /* Duplicate pipe for child process */ - HANDLE child_pipe_write = 0; + /* Build the handle inheritance whitelist */ + if (ok) { + HANDLE inherit_list[] = { child_pipe_write }; + ok = UpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherit_list, sizeof(inherit_list), 0, 0) != 0; + if (!ok) + { + result.output = Lit("Failed to update attributes"); + } + } + + /* Create process */ + /* TODO: Allow caller to set child process's thread affinity by job pool */ + HANDLE process = 0; + HANDLE process_thread = 0; + if (ok) + { + PROCESS_INFORMATION pi = Zi; + STARTUPINFOEXW si = Zi; + si.StartupInfo.cb = sizeof(si); + si.StartupInfo.dwFlags = STARTF_USESTDHANDLES; + si.StartupInfo.hStdOutput = child_pipe_write; + si.StartupInfo.hStdError = child_pipe_write; + si.lpAttributeList = attrs; + ok = CreateProcessW(0, cmd_wstr, 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi) != 0; if (ok) { - ok = DuplicateHandle(GetCurrentProcess(), pipe_write, GetCurrentProcess(), &child_pipe_write, 0, 1, DUPLICATE_SAME_ACCESS) != 0; - if (!ok) - { - result.output = Lit("Failed to create child pipe"); - child_pipe_write = 0; - } + process = pi.hProcess; + process_thread = pi.hThread; } - - /* Initialize attrs list */ - LPPROC_THREAD_ATTRIBUTE_LIST attrs = Zi; - if (ok) + else { - u64 attrs_size = 0; - InitializeProcThreadAttributeList(0, 1, 0, &attrs_size); - ok = attrs_size > 0; - if (ok) - { - attrs = PushBytes(scratch.arena, attrs_size, 64); - ok = InitializeProcThreadAttributeList(attrs, 1, 0, &attrs_size) != 0; - } - if (!ok) - { - result.output = Lit("Failed to initialize attrs list"); - } + result.output = W32_StringFromError(arena, GetLastError()); } - - /* Build the handle inheritance whitelist */ - if (ok) { - HANDLE inherit_list[] = { child_pipe_write }; - ok = UpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherit_list, sizeof(inherit_list), 0, 0) != 0; - if (!ok) - { - result.output = Lit("Failed to update attributes"); - } - } - - /* Create process */ - /* TODO: Allow caller to set child process's thread affinity by job pool */ - HANDLE process = 0; - HANDLE process_thread = 0; - if (ok) + /* Close write pipe handles */ { - PROCESS_INFORMATION pi = Zi; - STARTUPINFOEXW si = Zi; - si.StartupInfo.cb = sizeof(si); - si.StartupInfo.dwFlags = STARTF_USESTDHANDLES; - si.StartupInfo.hStdOutput = child_pipe_write; - si.StartupInfo.hStdError = child_pipe_write; - si.lpAttributeList = attrs; - ok = CreateProcessW(0, cmd_wstr, 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi) != 0; - if (ok) + CloseHandle(child_pipe_write); + CloseHandle(pipe_write); + child_pipe_write = 0; + pipe_write = 0; + } + } + + /* Read process output */ + if (ok) + { + result.output.text = ArenaNext(arena, u8); + b32 exit_code_valid = 0; + DWORD exit_code = 0; + b32 stdout_finished = 0; + while (!stdout_finished) + { + u8 buff[4096] = Zi; + DWORD bytes_read = 0; + if (!ReadFile(pipe_read, buff, countof(buff), &bytes_read, 0)) + { + DWORD err = GetLastError(); + if (err == ERROR_BROKEN_PIPE) { - process = pi.hProcess; - process_thread = pi.hThread; + GetExitCodeProcess(process, &exit_code); + exit_code_valid = 1; } else { - result.output = W32_StringFromError(arena, GetLastError()); - } - /* Close write pipe handles */ - { - CloseHandle(child_pipe_write); - CloseHandle(pipe_write); - child_pipe_write = 0; - pipe_write = 0; + result.output.len += W32_StringFromError(arena, err).len; } + stdout_finished = 1; + } + PushStructsNoZero(arena, u8, bytes_read); + CopyBytes(result.output.text + result.output.len, buff, bytes_read); + result.output.len += bytes_read; } - - /* Read process output */ - if (ok) + if (exit_code_valid) { - result.output.text = ArenaNext(arena, u8); - b32 exit_code_valid = 0; - DWORD exit_code = 0; - b32 stdout_finished = 0; - while (!stdout_finished) - { - u8 buff[4096] = Zi; - DWORD bytes_read = 0; - if (!ReadFile(pipe_read, buff, countof(buff), &bytes_read, 0)) - { - DWORD err = GetLastError(); - if (err == ERROR_BROKEN_PIPE) - { - GetExitCodeProcess(process, &exit_code); - exit_code_valid = 1; - } - else - { - result.output.len += W32_StringFromError(arena, err).len; - } - stdout_finished = 1; - } - PushStructsNoZero(arena, u8, bytes_read); - CopyBytes(result.output.text + result.output.len, buff, bytes_read); - result.output.len += bytes_read; - } - if (exit_code_valid) - { - result.code = exit_code; - } + result.code = exit_code; } + } - /* Close handles */ - if (attrs) DeleteProcThreadAttributeList(attrs); - if (process_thread) CloseHandle(process_thread); - if (process) CloseHandle(process); - if (child_pipe_write) CloseHandle(child_pipe_write); - if (pipe_read) CloseHandle(pipe_read); - if (pipe_write) CloseHandle(pipe_write); + /* Close handles */ + if (attrs) DeleteProcThreadAttributeList(attrs); + if (process_thread) CloseHandle(process_thread); + if (process) CloseHandle(process); + if (child_pipe_write) CloseHandle(child_pipe_write); + if (pipe_read) CloseHandle(pipe_read); + if (pipe_write) CloseHandle(pipe_write); - if (!ok && result.code == 0) - { - result.code = -1; - } + if (!ok && result.code == 0) + { + result.code = -1; + } - EndScratch(scratch); - return result; + EndScratch(scratch); + return result; } diff --git a/src/mixer/mixer.c b/src/mixer/mixer.c index 203b2c12..9a1aef4b 100644 --- a/src/mixer/mixer.c +++ b/src/mixer/mixer.c @@ -21,10 +21,10 @@ MIX_SharedState M_shared_state = ZI; void MIX_Bootstrap(void) { - MIX_SharedState *g = &M_shared_state; - g->track_arena = AcquireArena(Gibi(64)); - g->listener_pos = VEC2(0, 0); - g->listener_dir = VEC2(0, -1); + MIX_SharedState *g = &M_shared_state; + g->track_arena = AcquireArena(Gibi(64)); + g->listener_pos = VEC2(0, 0); + g->listener_dir = VEC2(0, -1); } //////////////////////////////////////////////////////////// @@ -32,187 +32,187 @@ void MIX_Bootstrap(void) MIX_Handle MIX_HandleFromTrack(MIX_Track *track) { - MIX_Handle result = ZI; - result.gen = track->gen; - result.data = track; - return result; + MIX_Handle result = ZI; + result.gen = track->gen; + result.data = track; + return result; } MIX_Track *MIX_TrackFromHandle(MIX_Handle handle) { - MIX_Track *track = (MIX_Track *)handle.data; - if (track && track->gen == handle.gen) - { - return track; - } - else - { - return 0; - } + MIX_Track *track = (MIX_Track *)handle.data; + if (track && track->gen == handle.gen) + { + return track; + } + else + { + return 0; + } } MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound) { - MIX_SharedState *g = &M_shared_state; - AssertLockedE(lock, &g->mutex); + MIX_SharedState *g = &M_shared_state; + AssertLockedE(lock, &g->mutex); - MIX_Track *track = 0; - if (g->track_first_free) + MIX_Track *track = 0; + if (g->track_first_free) + { + /* Take from free list */ + track = g->track_first_free; + MIX_Track *next_free = track->next; + g->track_first_free = next_free; + if (next_free) { - /* Take from free list */ - track = g->track_first_free; - MIX_Track *next_free = track->next; - g->track_first_free = next_free; - if (next_free) - { - next_free->prev = 0; - } - *track = (MIX_Track) { .gen = track->gen + 1 }; - } - else - { - /* Acquire new */ - track = PushStruct(g->track_arena, MIX_Track); - track->gen = 1; + next_free->prev = 0; } + *track = (MIX_Track) { .gen = track->gen + 1 }; + } + else + { + /* Acquire new */ + track = PushStruct(g->track_arena, MIX_Track); + track->gen = 1; + } - track->sound = sound; - track->mix.source = sound; - track->mix.track_handle = MIX_HandleFromTrack(track); + track->sound = sound; + track->mix.source = sound; + track->mix.track_handle = MIX_HandleFromTrack(track); - /* Append to playing list */ - MIX_Track *prev = g->track_last_playing; - if (prev) - { - prev->next = track; - } - else - { - g->track_first_playing = track; - } - g->track_last_playing = track; - track->prev = prev; - ++g->track_playing_count; + /* Append to playing list */ + MIX_Track *prev = g->track_last_playing; + if (prev) + { + prev->next = track; + } + else + { + g->track_first_playing = track; + } + g->track_last_playing = track; + track->prev = prev; + ++g->track_playing_count; - return track; + return track; } void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track) { - MIX_SharedState *g = &M_shared_state; - AssertLockedE(lock, &g->mutex); + MIX_SharedState *g = &M_shared_state; + AssertLockedE(lock, &g->mutex); - /* Remove from playing list */ - MIX_Track *prev = track->prev; - MIX_Track *next = track->next; - if (prev) - { - prev->next = next; - } - else - { - /* Track was first in list */ - g->track_first_playing = next; - } - if (next) - { - next->prev = prev; - } - else - { - /* Track was last in list */ - g->track_last_playing = prev; - } - --g->track_playing_count; - ++track->gen; + /* Remove from playing list */ + MIX_Track *prev = track->prev; + MIX_Track *next = track->next; + if (prev) + { + prev->next = next; + } + else + { + /* Track was first in list */ + g->track_first_playing = next; + } + if (next) + { + next->prev = prev; + } + else + { + /* Track was last in list */ + g->track_last_playing = prev; + } + --g->track_playing_count; + ++track->gen; - /* Add to free list */ - track->prev = 0; - track->next = g->track_first_free; - if (g->track_first_free) - { - g->track_first_free->prev = track; - } - g->track_first_free = track; + /* Add to free list */ + track->prev = 0; + track->next = g->track_first_free; + if (g->track_first_free) + { + g->track_first_free->prev = track; + } + g->track_first_free = track; } /* TODO: Rework interface to be command based instead of directly modifying tracks. */ MIX_Handle MIX_PlaySound(SND_Sound *sound) { - return MIX_PlaySoundEx(sound, M_TRACKDESC()); + return MIX_PlaySoundEx(sound, M_TRACKDESC()); } MIX_Handle MIX_PlaySoundEx(SND_Sound *sound, MIX_TrackDesc desc) { - MIX_SharedState *g = &M_shared_state; - MIX_Track *track; + MIX_SharedState *g = &M_shared_state; + MIX_Track *track; + { + Lock lock = LockE(&g->mutex); { - Lock lock = LockE(&g->mutex); - { - track = MIX_AcquireTrackLocked(&lock, sound); - track->desc = desc; - } - Unlock(&lock); + track = MIX_AcquireTrackLocked(&lock, sound); + track->desc = desc; } - return MIX_HandleFromTrack(track); + Unlock(&lock); + } + return MIX_HandleFromTrack(track); } /* NOTE: This is quite inefficient. */ MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle) { - MIX_SharedState *g = &M_shared_state; - MIX_TrackDesc result = ZI; + MIX_SharedState *g = &M_shared_state; + MIX_TrackDesc result = ZI; - MIX_Track *track = MIX_TrackFromHandle(handle); - if (track) + MIX_Track *track = MIX_TrackFromHandle(handle); + if (track) + { + /* TODO: Only lock mutex on track itself or something */ + Lock lock = LockE(&g->mutex); { - /* TODO: Only lock mutex on track itself or something */ - Lock lock = LockE(&g->mutex); - { - /* Confirm handle is still valid now that we're locked */ - track = MIX_TrackFromHandle(handle); - if (track) - { - result = track->desc; - } - } - Unlock(&lock); + /* Confirm handle is still valid now that we're locked */ + track = MIX_TrackFromHandle(handle); + if (track) + { + result = track->desc; + } } + Unlock(&lock); + } - return result; + return result; } /* NOTE: This is quite inefficient. */ void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc) { - MIX_SharedState *g = &M_shared_state; - MIX_Track *track = MIX_TrackFromHandle(handle); - if (track) + MIX_SharedState *g = &M_shared_state; + MIX_Track *track = MIX_TrackFromHandle(handle); + if (track) + { + /* TODO: Only lock mutex on track itself or something */ + Lock lock = LockE(&g->mutex); { - /* TODO: Only lock mutex on track itself or something */ - Lock lock = LockE(&g->mutex); - { - /* Confirm handle is still valid now that we're locked */ - track = MIX_TrackFromHandle(handle); - if (track) - { - track->desc = desc; - } - } - Unlock(&lock); + /* Confirm handle is still valid now that we're locked */ + track = MIX_TrackFromHandle(handle); + if (track) + { + track->desc = desc; + } } + Unlock(&lock); + } } void MIX_UpdateListener(Vec2 pos, Vec2 dir) { - MIX_SharedState *g = &M_shared_state; - Lock lock = LockE(&g->mutex); - { - g->listener_pos = pos; - g->listener_dir = NormVec2(dir); - } - Unlock(&lock); + MIX_SharedState *g = &M_shared_state; + Lock lock = LockE(&g->mutex); + { + g->listener_pos = pos; + g->listener_dir = NormVec2(dir); + } + Unlock(&lock); } //////////////////////////////////////////////////////////// @@ -220,250 +220,250 @@ void MIX_UpdateListener(Vec2 pos, Vec2 dir) i16 MIX_SampleSound(SND_Sound *sound, u64 sample_pos, b32 wrap) { - if (wrap) - { - return sound->samples[sample_pos % sound->samples_count]; - } - else if (sample_pos < sound->samples_count) - { - return sound->samples[sample_pos]; - } - else - { - return 0; - } + if (wrap) + { + return sound->samples[sample_pos % sound->samples_count]; + } + else if (sample_pos < sound->samples_count) + { + return sound->samples[sample_pos]; + } + else + { + return 0; + } } /* To be called once per audio playback interval */ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count) { - TempArena scratch = BeginScratch(arena); - MIX_SharedState *g = &M_shared_state; + TempArena scratch = BeginScratch(arena); + MIX_SharedState *g = &M_shared_state; - MIX_PcmF32 result = ZI; - result.count = frame_count * 2; - result.samples = PushStructs(arena, f32, result.count); + MIX_PcmF32 result = ZI; + result.count = frame_count * 2; + result.samples = PushStructs(arena, f32, result.count); - Vec2 listener_pos = VEC2(0, 0); - Vec2 listener_dir = VEC2(0, 0); + Vec2 listener_pos = VEC2(0, 0); + Vec2 listener_dir = VEC2(0, 0); - //- Create temp mix array + //- Create temp mix array - MIX_MixData **mixes = 0; - u64 mixes_count = 0; + MIX_MixData **mixes = 0; + u64 mixes_count = 0; + { + Lock lock = LockE(&g->mutex); + + /* Read listener info */ + listener_pos = g->listener_pos; + listener_dir = g->listener_dir; + + /* Update & read mixes */ + mixes = PushStructsNoZero(scratch.arena, MIX_MixData *, g->track_playing_count); + for (MIX_Track *track = g->track_first_playing; track; track = track->next) { - Lock lock = LockE(&g->mutex); - - /* Read listener info */ - listener_pos = g->listener_pos; - listener_dir = g->listener_dir; - - /* Update & read mixes */ - mixes = PushStructsNoZero(scratch.arena, MIX_MixData *, g->track_playing_count); - for (MIX_Track *track = g->track_first_playing; track; track = track->next) - { - MIX_MixData *mix = &track->mix; - mix->desc = track->desc; - mixes[mixes_count++] = mix; - } - - Unlock(&lock); + MIX_MixData *mix = &track->mix; + mix->desc = track->desc; + mixes[mixes_count++] = mix; } - //- Process mix data + Unlock(&lock); + } - for (u64 mix_index = 0; mix_index < mixes_count; ++mix_index) + //- Process mix data + + for (u64 mix_index = 0; mix_index < mixes_count; ++mix_index) + { + MIX_MixData *mix = mixes[mix_index]; + + if (mix->source->samples_count <= 0) { - MIX_MixData *mix = mixes[mix_index]; - - if (mix->source->samples_count <= 0) - { - /* Skip empty sounds */ - continue; - } - - SND_Sound *source = mix->source; - MIX_TrackDesc desc = mix->desc; - MIX_EffectData *effect_data = &mix->effect_data; - b32 source_is_stereo = source->flags & SND_SoundFlag_Stereo; - f32 speed = MaxF32(0, desc.speed); - - //- Determine sample range - u64 source_samples_count = 0; - if (source_is_stereo) - { - source_samples_count = frame_count * 2; - /* Round to nearest frame boundary (nearest multiple of 2) */ - source_samples_count = (u64)CeilF32ToI32((f32)source_samples_count * speed); - source_samples_count &= ~1; - } - else - { - source_samples_count = frame_count; - /* Round to nearest sample */ - source_samples_count = (u64)RoundF32ToI32((f32)source_samples_count * speed); - } - - u64 source_sample_pos_start = mix->source_pos; - u64 source_sample_pos_end = source_sample_pos_start + source_samples_count; - if (source_sample_pos_end >= source->samples_count) - { - if (desc.looping) - { - source_sample_pos_end = source_sample_pos_end % source->samples_count; - } - else - { - source_sample_pos_end = source->samples_count; - mix->track_finished = 1; - } - } - u64 source_frames_count = source_is_stereo ? source_samples_count / 2 : source_samples_count; - u64 source_frame_pos_start = source_is_stereo ? source_sample_pos_start / 2 : source_sample_pos_start; - - mix->source_pos = source_sample_pos_end; - - MIX_PcmF32 mix_pcm = { - .count = result.count, - .samples = PushStructs(scratch.arena, f32, result.count) - }; - - //- Resample - /* Transform 16 bit source -> 32 bit stereo at output duration */ - { - f32 *out_samples = mix_pcm.samples; - - u64 out_frames_count = mix_pcm.count / 2; - - /* TODO: Fast path for 1:1 copy when speed = 1.0? */ - /* TODO: Optimize */ - if (source_is_stereo) - { - /* 16 bit Stereo -> 32 bit Stereo */ - for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos) - { - f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count); - u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact); - u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact); - - /* Sample source */ - f32 sample1_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 0, desc.looping) * (1.f / 32768.f); - f32 sample1_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 0, desc.looping) * (1.f / 32768.f); - f32 sample2_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 1, desc.looping) * (1.f / 32768.f); - f32 sample2_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 1, desc.looping) * (1.f / 32768.f); - - /* Lerp */ - f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev; - f32 sample1 = LerpF32(sample1_prev, sample1_next, t); - f32 sample2 = LerpF32(sample2_prev, sample2_next, t); - - out_samples[(out_frame_pos * 2) + 0] += sample1; - out_samples[(out_frame_pos * 2) + 1] += sample2; - } - } - else - { - /* 16 bit Mono -> 32 bit Stereo */ - for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos) - { - f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count); - u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact); - u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact); - - /* Sample source */ - f32 sample_prev = MIX_SampleSound(source, in_frame_pos_prev, desc.looping) * (1.f / 32768.f); - f32 sample_next = MIX_SampleSound(source, in_frame_pos_next, desc.looping) * (1.f / 32768.f); - - /* Lerp */ - f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev; - f32 sample = LerpF32(sample_prev, sample_next, t); - - out_samples[(out_frame_pos * 2) + 0] += sample; - out_samples[(out_frame_pos * 2) + 1] += sample; - } - } - } - - //- Spatialize - if (desc.flags & MIX_TrackFlag_Spatialize) - { - /* Algorithm constants */ - const f32 rolloff_height = 1.2f; - const f32 rolloff_scale = 6.0f; - const f32 pan_scale = 0.75; - - Vec2 pos = desc.pos; - - /* If sound pos = listener pos, pretend sound is close in front of listener. */ - if (MatchVec2(listener_pos, pos)) - { - pos = AddVec2(listener_pos, MulVec2(listener_dir, 0.001f)); - } - Vec2 sound_rel = SubVec2(pos, listener_pos); - Vec2 sound_rel_dir = NormVec2(sound_rel); - - /* Compute volume */ - f32 volume_start = effect_data->spatial_volume; - f32 volume_end; - { - /* https://www.desmos.com/calculator/c2h941hobz - * h = `rolloff_height` - * s = `rolloff_scale` - */ - f32 dist = Vec2Len(sound_rel); - f32 v = (dist / rolloff_scale) + 1.0f; - volume_end = rolloff_height * (1.0f / (v * v)); - } - effect_data->spatial_volume = volume_end; - - /* Compute pan */ - f32 pan_start = effect_data->spatial_pan; - f32 pan_end = WedgeVec2(listener_dir, sound_rel_dir) * pan_scale; - effect_data->spatial_pan = pan_end; - - /* Spatialize samples */ - for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos) - { - f32 t = (f32)frame_pos / (f32)(frame_count - 1); - f32 volume = LerpF32(volume_start, volume_end, t); - f32 pan = LerpF32(pan_start, pan_end, t); - - u64 sample1_index = frame_pos * 2; - u64 sample2_index = sample1_index + 1; - - f32 sample_mono = ((mix_pcm.samples[sample1_index + 0] / 2.0f) + (mix_pcm.samples[sample2_index] / 2.0f)) * volume; - - mix_pcm.samples[sample1_index] = sample_mono * (1.0f - pan); - mix_pcm.samples[sample2_index] = sample_mono * (1.0f + pan); - } - } - - //- Mix into result - for (u64 i = 0; i < mix_pcm.count; ++i) - { - result.samples[i] += mix_pcm.samples[i] * desc.volume; - } + /* Skip empty sounds */ + continue; } - //- Update track effect data + SND_Sound *source = mix->source; + MIX_TrackDesc desc = mix->desc; + MIX_EffectData *effect_data = &mix->effect_data; + b32 source_is_stereo = source->flags & SND_SoundFlag_Stereo; + f32 speed = MaxF32(0, desc.speed); + + //- Determine sample range + u64 source_samples_count = 0; + if (source_is_stereo) { - Lock lock = LockE(&g->mutex); - for (u64 i = 0; i < mixes_count; ++i) - { - MIX_MixData *mix = mixes[i]; - MIX_Track *track = MIX_TrackFromHandle(mix->track_handle); - if (track) - { - if (mix->track_finished) - { - /* Release finished tracks */ - MIX_ReleaseTrackLocked(&lock, track); - } - } - } - Unlock(&lock); + source_samples_count = frame_count * 2; + /* Round to nearest frame boundary (nearest multiple of 2) */ + source_samples_count = (u64)CeilF32ToI32((f32)source_samples_count * speed); + source_samples_count &= ~1; + } + else + { + source_samples_count = frame_count; + /* Round to nearest sample */ + source_samples_count = (u64)RoundF32ToI32((f32)source_samples_count * speed); } - EndScratch(scratch); - return result; + u64 source_sample_pos_start = mix->source_pos; + u64 source_sample_pos_end = source_sample_pos_start + source_samples_count; + if (source_sample_pos_end >= source->samples_count) + { + if (desc.looping) + { + source_sample_pos_end = source_sample_pos_end % source->samples_count; + } + else + { + source_sample_pos_end = source->samples_count; + mix->track_finished = 1; + } + } + u64 source_frames_count = source_is_stereo ? source_samples_count / 2 : source_samples_count; + u64 source_frame_pos_start = source_is_stereo ? source_sample_pos_start / 2 : source_sample_pos_start; + + mix->source_pos = source_sample_pos_end; + + MIX_PcmF32 mix_pcm = { + .count = result.count, + .samples = PushStructs(scratch.arena, f32, result.count) + }; + + //- Resample + /* Transform 16 bit source -> 32 bit stereo at output duration */ + { + f32 *out_samples = mix_pcm.samples; + + u64 out_frames_count = mix_pcm.count / 2; + + /* TODO: Fast path for 1:1 copy when speed = 1.0? */ + /* TODO: Optimize */ + if (source_is_stereo) + { + /* 16 bit Stereo -> 32 bit Stereo */ + for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos) + { + f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count); + u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact); + u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact); + + /* Sample source */ + f32 sample1_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 0, desc.looping) * (1.f / 32768.f); + f32 sample1_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 0, desc.looping) * (1.f / 32768.f); + f32 sample2_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 1, desc.looping) * (1.f / 32768.f); + f32 sample2_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 1, desc.looping) * (1.f / 32768.f); + + /* Lerp */ + f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev; + f32 sample1 = LerpF32(sample1_prev, sample1_next, t); + f32 sample2 = LerpF32(sample2_prev, sample2_next, t); + + out_samples[(out_frame_pos * 2) + 0] += sample1; + out_samples[(out_frame_pos * 2) + 1] += sample2; + } + } + else + { + /* 16 bit Mono -> 32 bit Stereo */ + for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos) + { + f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count); + u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact); + u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact); + + /* Sample source */ + f32 sample_prev = MIX_SampleSound(source, in_frame_pos_prev, desc.looping) * (1.f / 32768.f); + f32 sample_next = MIX_SampleSound(source, in_frame_pos_next, desc.looping) * (1.f / 32768.f); + + /* Lerp */ + f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev; + f32 sample = LerpF32(sample_prev, sample_next, t); + + out_samples[(out_frame_pos * 2) + 0] += sample; + out_samples[(out_frame_pos * 2) + 1] += sample; + } + } + } + + //- Spatialize + if (desc.flags & MIX_TrackFlag_Spatialize) + { + /* Algorithm constants */ + const f32 rolloff_height = 1.2f; + const f32 rolloff_scale = 6.0f; + const f32 pan_scale = 0.75; + + Vec2 pos = desc.pos; + + /* If sound pos = listener pos, pretend sound is close in front of listener. */ + if (MatchVec2(listener_pos, pos)) + { + pos = AddVec2(listener_pos, MulVec2(listener_dir, 0.001f)); + } + Vec2 sound_rel = SubVec2(pos, listener_pos); + Vec2 sound_rel_dir = NormVec2(sound_rel); + + /* Compute volume */ + f32 volume_start = effect_data->spatial_volume; + f32 volume_end; + { + /* https://www.desmos.com/calculator/c2h941hobz + * h = `rolloff_height` + * s = `rolloff_scale` + */ + f32 dist = Vec2Len(sound_rel); + f32 v = (dist / rolloff_scale) + 1.0f; + volume_end = rolloff_height * (1.0f / (v * v)); + } + effect_data->spatial_volume = volume_end; + + /* Compute pan */ + f32 pan_start = effect_data->spatial_pan; + f32 pan_end = WedgeVec2(listener_dir, sound_rel_dir) * pan_scale; + effect_data->spatial_pan = pan_end; + + /* Spatialize samples */ + for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos) + { + f32 t = (f32)frame_pos / (f32)(frame_count - 1); + f32 volume = LerpF32(volume_start, volume_end, t); + f32 pan = LerpF32(pan_start, pan_end, t); + + u64 sample1_index = frame_pos * 2; + u64 sample2_index = sample1_index + 1; + + f32 sample_mono = ((mix_pcm.samples[sample1_index + 0] / 2.0f) + (mix_pcm.samples[sample2_index] / 2.0f)) * volume; + + mix_pcm.samples[sample1_index] = sample_mono * (1.0f - pan); + mix_pcm.samples[sample2_index] = sample_mono * (1.0f + pan); + } + } + + //- Mix into result + for (u64 i = 0; i < mix_pcm.count; ++i) + { + result.samples[i] += mix_pcm.samples[i] * desc.volume; + } + } + + //- Update track effect data + { + Lock lock = LockE(&g->mutex); + for (u64 i = 0; i < mixes_count; ++i) + { + MIX_MixData *mix = mixes[i]; + MIX_Track *track = MIX_TrackFromHandle(mix->track_handle); + if (track) + { + if (mix->track_finished) + { + /* Release finished tracks */ + MIX_ReleaseTrackLocked(&lock, track); + } + } + } + Unlock(&lock); + } + + EndScratch(scratch); + return result; } diff --git a/src/mixer/mixer.h b/src/mixer/mixer.h index f88f28c7..543381e4 100644 --- a/src/mixer/mixer.h +++ b/src/mixer/mixer.h @@ -3,33 +3,33 @@ Enum(MIX_TrackFlag) { - MIX_TrackFlag_None = 0, - MIX_TrackFlag_Spatialize = (1 << 0) + MIX_TrackFlag_None = 0, + MIX_TrackFlag_Spatialize = (1 << 0) }; Struct(MIX_Handle) { - u64 gen; - void *data; + u64 gen; + void *data; }; Struct(MIX_TrackDesc) { - MIX_TrackFlag flags; - f32 volume; /* 0 -> 1.0+ */ - f32 speed; /* 0 -> 1.0+ */ - b32 looping; + MIX_TrackFlag flags; + f32 volume; /* 0 -> 1.0+ */ + f32 speed; /* 0 -> 1.0+ */ + b32 looping; - /* MIX_TrackFlag_Spatialize */ - Vec2 pos; + /* MIX_TrackFlag_Spatialize */ + Vec2 pos; }; #define M_TRACKDESC(...) ((MIX_TrackDesc) { \ - .flags = 0, \ - .volume = 1.0, \ - .speed = 1.0, \ - .looping = 0, \ - .pos = VEC2(0, 0), \ - __VA_ARGS__ \ + .flags = 0, \ + .volume = 1.0, \ + .speed = 1.0, \ + .looping = 0, \ + .pos = VEC2(0, 0), \ + __VA_ARGS__ \ }) //////////////////////////////////////////////////////////// @@ -38,40 +38,40 @@ Struct(MIX_TrackDesc) /* Stereo mix of 32 bit float samples */ Struct(MIX_PcmF32) { - u64 count; - f32 *samples; + u64 count; + f32 *samples; }; Struct(MIX_EffectData) { - /* Spatialization */ - f32 spatial_volume; - f32 spatial_pan; + /* Spatialization */ + f32 spatial_volume; + f32 spatial_pan; }; Struct(MIX_MixData) { - MIX_Handle track_handle; - b32 track_finished; + MIX_Handle track_handle; + b32 track_finished; - MIX_TrackDesc desc; - MIX_EffectData effect_data; - SND_Sound *source; - u64 source_pos; + MIX_TrackDesc desc; + MIX_EffectData effect_data; + SND_Sound *source; + u64 source_pos; }; Struct(MIX_Track){ - u64 gen; + u64 gen; - /* Controlled via interface */ - SND_Sound *sound; - MIX_TrackDesc desc; + /* Controlled via interface */ + SND_Sound *sound; + MIX_TrackDesc desc; - /* Internal */ - MIX_MixData mix; + /* Internal */ + MIX_MixData mix; - MIX_Track *next; - MIX_Track *prev; + MIX_Track *next; + MIX_Track *prev; }; //////////////////////////////////////////////////////////// @@ -79,18 +79,18 @@ Struct(MIX_Track){ Struct(MIX_SharedState) { - Mutex mutex; + Mutex mutex; - /* Listener */ - Vec2 listener_pos; - Vec2 listener_dir; + /* Listener */ + Vec2 listener_pos; + Vec2 listener_dir; - /* Track list */ - Arena *track_arena; - MIX_Track *track_first_playing; - MIX_Track *track_last_playing; - u64 track_playing_count; - MIX_Track *track_first_free; + /* Track list */ + Arena *track_arena; + MIX_Track *track_first_playing; + MIX_Track *track_last_playing; + u64 track_playing_count; + MIX_Track *track_first_free; } extern M_shared_state; //////////////////////////////////////////////////////////// diff --git a/src/mp3/mp3.h b/src/mp3/mp3.h index cac40d39..3c92ee95 100644 --- a/src/mp3/mp3.h +++ b/src/mp3/mp3.h @@ -3,15 +3,15 @@ Enum(MP3_DecodeFlag) { - MP3_DecodeFlag_None = 0, - MP3_DecodeFlag_Stereo = (1 << 0), + MP3_DecodeFlag_None = 0, + MP3_DecodeFlag_Stereo = (1 << 0), }; Struct(MP3_Result) { - u64 samples_count; - i16 *samples; - b32 ok; + u64 samples_count; + i16 *samples; + b32 ok; }; //////////////////////////////////////////////////////////// diff --git a/src/mp3/mp3_mmf/mp3_mmf.c b/src/mp3/mp3_mmf/mp3_mmf.c index 9efc95f0..f6d98755 100644 --- a/src/mp3/mp3_mmf/mp3_mmf.c +++ b/src/mp3/mp3_mmf/mp3_mmf.c @@ -3,114 +3,114 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeFlag flags) { - MP3_Result result = ZI; - u64 bytes_per_sample = 2; + MP3_Result result = ZI; + u64 bytes_per_sample = 2; - u64 channel_count; - u32 channel_mask; - if (flags & MP3_DecodeFlag_Stereo) + u64 channel_count; + u32 channel_mask; + if (flags & MP3_DecodeFlag_Stereo) + { + channel_count = 2; + channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + } + else + { + channel_count = 1; + channel_mask = SPEAKER_FRONT_CENTER; + } + + //- Startup + + MFStartup(MF_VERSION, MFSTARTUP_LITE); + + /* Create IStream from encoded string */ + IStream *i_stream = SHCreateMemStream(encoded.text, encoded.len); + + /* Create IMFByteStream from IStream */ + IMFByteStream *byte_stream = 0; + MFCreateMFByteStreamOnStream(i_stream, &byte_stream); + + /* Create reader from IMFByteStream */ + IMFSourceReader *reader; + MFCreateSourceReaderFromByteStream(byte_stream, 0, &reader); + + //- Get media type + + /* Read only first audio stream */ + IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_ALL_STREAMS, 0); + IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 1); + + WAVEFORMATEXTENSIBLE format = { + .Format = { + .wFormatTag = WAVE_FORMAT_EXTENSIBLE, + .nChannels = (WORD)channel_count, + .nSamplesPerSec = (WORD)sample_rate, + .nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * bytes_per_sample), + .nBlockAlign = (WORD)(channel_count * bytes_per_sample), + .wBitsPerSample = (WORD)(8 * bytes_per_sample), + .cbSize = sizeof(format) - sizeof(format.Format) + }, + .Samples.wValidBitsPerSample = 8 * bytes_per_sample, + .dwChannelMask = channel_mask, + .SubFormat = MEDIASUBTYPE_PCM + }; + + /* Media Foundation in Windows 8+ allows reader to convert output to different format than native */ + IMFMediaType *type; + MFCreateMediaType(&type); + MFInitMediaTypeFromWaveFormatEx(type, &format.Format, sizeof(format)); + IMFSourceReader_SetCurrentMediaType(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, type); + IMFMediaType_Release(type); + + //- Read + + result.samples = ArenaNext(arena, i16); + u64 sample_bytes_read = 0; + for (;;) + { + IMFSample *sample; + DWORD sample_flags = 0; + HRESULT hr = IMFSourceReader_ReadSample(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, 0, &sample_flags, 0, &sample); + if (FAILED(hr)) { - channel_count = 2; - channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; - } - else - { - channel_count = 1; - channel_mask = SPEAKER_FRONT_CENTER; + break; } - //- Startup - - MFStartup(MF_VERSION, MFSTARTUP_LITE); - - /* Create IStream from encoded string */ - IStream *i_stream = SHCreateMemStream(encoded.text, encoded.len); - - /* Create IMFByteStream from IStream */ - IMFByteStream *byte_stream = 0; - MFCreateMFByteStreamOnStream(i_stream, &byte_stream); - - /* Create reader from IMFByteStream */ - IMFSourceReader *reader; - MFCreateSourceReaderFromByteStream(byte_stream, 0, &reader); - - //- Get media type - - /* Read only first audio stream */ - IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_ALL_STREAMS, 0); - IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 1); - - WAVEFORMATEXTENSIBLE format = { - .Format = { - .wFormatTag = WAVE_FORMAT_EXTENSIBLE, - .nChannels = (WORD)channel_count, - .nSamplesPerSec = (WORD)sample_rate, - .nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * bytes_per_sample), - .nBlockAlign = (WORD)(channel_count * bytes_per_sample), - .wBitsPerSample = (WORD)(8 * bytes_per_sample), - .cbSize = sizeof(format) - sizeof(format.Format) - }, - .Samples.wValidBitsPerSample = 8 * bytes_per_sample, - .dwChannelMask = channel_mask, - .SubFormat = MEDIASUBTYPE_PCM - }; - - /* Media Foundation in Windows 8+ allows reader to convert output to different format than native */ - IMFMediaType *type; - MFCreateMediaType(&type); - MFInitMediaTypeFromWaveFormatEx(type, &format.Format, sizeof(format)); - IMFSourceReader_SetCurrentMediaType(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, type); - IMFMediaType_Release(type); - - //- Read - - result.samples = ArenaNext(arena, i16); - u64 sample_bytes_read = 0; - for (;;) + /* Check if done */ + if (sample_flags & MF_SOURCE_READERF_ENDOFSTREAM) { - IMFSample *sample; - DWORD sample_flags = 0; - HRESULT hr = IMFSourceReader_ReadSample(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, 0, &sample_flags, 0, &sample); - if (FAILED(hr)) - { - break; - } - - /* Check if done */ - if (sample_flags & MF_SOURCE_READERF_ENDOFSTREAM) - { - result.ok = 1; - break; - } - Assert(sample_flags == 0); - - /* Read samples */ - IMFMediaBuffer *buffer; - IMFSample_ConvertToContiguousBuffer(sample, &buffer); - - BYTE *src; - DWORD size_bytes; - IMFMediaBuffer_Lock(buffer, &src, 0, &size_bytes); - { - i16 *dst = PushStructsNoZero(arena, i16, (size_bytes + 1) >> 1); - CopyBytes(dst, src, size_bytes); - sample_bytes_read += size_bytes; - } - IMFMediaBuffer_Unlock(buffer); - - IMediaBuffer_Release(buffer); - IMFSample_Release(sample); + result.ok = 1; + break; } + Assert(sample_flags == 0); - result.samples_count = sample_bytes_read / bytes_per_sample; + /* Read samples */ + IMFMediaBuffer *buffer; + IMFSample_ConvertToContiguousBuffer(sample, &buffer); - //- Cleanup + BYTE *src; + DWORD size_bytes; + IMFMediaBuffer_Lock(buffer, &src, 0, &size_bytes); + { + i16 *dst = PushStructsNoZero(arena, i16, (size_bytes + 1) >> 1); + CopyBytes(dst, src, size_bytes); + sample_bytes_read += size_bytes; + } + IMFMediaBuffer_Unlock(buffer); - IMFSourceReader_Release(reader); - IMFByteStream_Close(byte_stream); - /* FIXME: Enable this */ - //IStream_Release(i_stream); - MFShutdown(); + IMediaBuffer_Release(buffer); + IMFSample_Release(sample); + } - return result; + result.samples_count = sample_bytes_read / bytes_per_sample; + + //- Cleanup + + IMFSourceReader_Release(reader); + IMFByteStream_Close(byte_stream); + /* FIXME: Enable this */ + //IStream_Release(i_stream); + MFShutdown(); + + return result; } diff --git a/src/mp3/mp3_mmf/mp3_mmf.h b/src/mp3/mp3_mmf/mp3_mmf.h index a3a00f37..145eaec8 100644 --- a/src/mp3/mp3_mmf/mp3_mmf.h +++ b/src/mp3/mp3_mmf/mp3_mmf.h @@ -2,11 +2,11 @@ //~ Windows headers #pragma warning(push, 0) -# include -# include -# include -# include -# include + #include + #include + #include + #include + #include #pragma warning(pop) #pragma comment(lib, "mfplat") diff --git a/src/net/net.c b/src/net/net.c index bd2a63c6..db33bf05 100644 --- a/src/net/net.c +++ b/src/net/net.c @@ -17,41 +17,41 @@ N_Host *N_AcquireHost(u16 listen_port) { - Arena *arena = AcquireArena(Gibi(64)); - N_Host *host = PushStruct(arena, N_Host); + Arena *arena = AcquireArena(Gibi(64)); + N_Host *host = PushStruct(arena, N_Host); - host->arena = arena; - host->cmd_arena = AcquireArena(Gibi(64)); - host->channel_arena = AcquireArena(Gibi(64)); - host->rcv_buffer_read = PushStruct(host->arena, N_RcvBuffer); - host->rcv_buffer_write = PushStruct(host->arena, N_RcvBuffer); - host->rcv_buffer_read->arena = AcquireArena(Gibi(64)); - host->rcv_buffer_write->arena = AcquireArena(Gibi(64)); - host->buddy = AcquireBuddyCtx(Gibi(64)); + host->arena = arena; + host->cmd_arena = AcquireArena(Gibi(64)); + host->channel_arena = AcquireArena(Gibi(64)); + host->rcv_buffer_read = PushStruct(host->arena, N_RcvBuffer); + host->rcv_buffer_write = PushStruct(host->arena, N_RcvBuffer); + host->rcv_buffer_read->arena = AcquireArena(Gibi(64)); + host->rcv_buffer_write->arena = AcquireArena(Gibi(64)); + host->buddy = AcquireBuddyCtx(Gibi(64)); - host->channels = ArenaNext(host->channel_arena, N_Channel); + host->channels = ArenaNext(host->channel_arena, N_Channel); - host->num_channel_lookup_bins = N_NumChannelLookupBins; - host->channel_lookup_bins = PushStructs(host->arena, N_ChannelLookupBin, host->num_channel_lookup_bins); + host->num_channel_lookup_bins = N_NumChannelLookupBins; + host->channel_lookup_bins = PushStructs(host->arena, N_ChannelLookupBin, host->num_channel_lookup_bins); - host->num_msg_assembler_lookup_bins = N_NumMsgAssemblerLookupBins; - host->msg_assembler_lookup_bins = PushStructs(host->arena, N_MsgAssemblerLookupBin, host->num_msg_assembler_lookup_bins); + host->num_msg_assembler_lookup_bins = N_NumMsgAssemblerLookupBins; + host->msg_assembler_lookup_bins = PushStructs(host->arena, N_MsgAssemblerLookupBin, host->num_msg_assembler_lookup_bins); - host->sock = P_AcquireSock(listen_port, Mebi(2), Mebi(2)); + host->sock = P_AcquireSock(listen_port, Mebi(2), Mebi(2)); - return host; + return host; } void N_ReleaseHost(N_Host *host) { - P_ReleaseSock(host->sock); + P_ReleaseSock(host->sock); - ReleaseBuddyCtx(host->buddy); - ReleaseArena(host->rcv_buffer_write->arena); - ReleaseArena(host->rcv_buffer_read->arena); - ReleaseArena(host->channel_arena); - ReleaseArena(host->cmd_arena); - ReleaseArena(host->arena); + ReleaseBuddyCtx(host->buddy); + ReleaseArena(host->rcv_buffer_write->arena); + ReleaseArena(host->rcv_buffer_read->arena); + ReleaseArena(host->channel_arena); + ReleaseArena(host->cmd_arena); + ReleaseArena(host->arena); } //////////////////////////////////////////////////////////// @@ -59,168 +59,168 @@ void N_ReleaseHost(N_Host *host) u64 N_HashFromAddress(P_Address address) { - return HashFnv64(Fnv64Basis, StringFromStruct(&address)); + return HashFnv64(Fnv64Basis, StringFromStruct(&address)); } N_Channel *N_ChannelFromAddress(N_Host *host, P_Address address) { - u64 hash = N_HashFromAddress(address); - N_ChannelLookupBin *bin = &host->channel_lookup_bins[hash % host->num_channel_lookup_bins]; - for (N_Channel *channel = bin->first; channel; channel = channel->next_address_hash) + u64 hash = N_HashFromAddress(address); + N_ChannelLookupBin *bin = &host->channel_lookup_bins[hash % host->num_channel_lookup_bins]; + for (N_Channel *channel = bin->first; channel; channel = channel->next_address_hash) + { + if (channel->address_hash == hash && P_MatchAddress(channel->address, address)) { - if (channel->address_hash == hash && P_MatchAddress(channel->address, address)) - { - return channel; - } + return channel; } - return &N_nil_channel; + } + return &N_nil_channel; } /* Returns nil channel if id = N_AllChannelsId */ N_Channel *N_ChannelFromId(N_Host *host, N_ChannelId channel_id) { - if (channel_id.gen > 0 && channel_id.idx < host->num_channels_reserved) + if (channel_id.gen > 0 && channel_id.idx < host->num_channels_reserved) + { + N_Channel *channel = &host->channels[channel_id.idx]; + if (channel->id.gen == channel_id.gen) { - N_Channel *channel = &host->channels[channel_id.idx]; - if (channel->id.gen == channel_id.gen) - { - return channel; - } + return channel; } - return &N_nil_channel; + } + return &N_nil_channel; } N_ChannelList N_ChannelsFromId(Arena *arena, N_Host *host, N_ChannelId channel_id) { - N_ChannelList result = ZI; - if (N_MatchChannelId(channel_id, N_AllChannelsId)) + N_ChannelList result = ZI; + if (N_MatchChannelId(channel_id, N_AllChannelsId)) + { + for (u64 i = 0; i < host->num_channels_reserved; ++i) { - for (u64 i = 0; i < host->num_channels_reserved; ++i) + N_Channel *channel = &host->channels[i]; + if (channel->valid) + { + N_ChannelNode *n = PushStruct(arena, N_ChannelNode); + n->channel = channel; + if (result.last) { - N_Channel *channel = &host->channels[i]; - if (channel->valid) - { - N_ChannelNode *n = PushStruct(arena, N_ChannelNode); - n->channel = channel; - if (result.last) - { - result.last->next = n; - } - else - { - result.first = n; - } - result.last = n; - } + result.last->next = n; } + else + { + result.first = n; + } + result.last = n; + } } - else + } + else + { + N_Channel *channel = N_ChannelFromId(host, channel_id); + if (channel->valid) { - N_Channel *channel = N_ChannelFromId(host, channel_id); - if (channel->valid) - { - N_ChannelNode *n = PushStruct(arena, N_ChannelNode); - n->channel = channel; - result.first = n; - result.last = n; - } + N_ChannelNode *n = PushStruct(arena, N_ChannelNode); + n->channel = channel; + result.first = n; + result.last = n; } - return result; + } + return result; } N_Channel *N_AcquireChannel(N_Host *host, P_Address address) { - N_ChannelId id = ZI; - N_Channel *channel; - if (host->first_free_channel) - { - channel = host->first_free_channel; - host->first_free_channel = channel->next_free; - id = channel->id; - ++id.gen; - } - else - { - channel = PushStructNoZero(host->channel_arena, N_Channel); - id.gen = 1; - id.idx = host->num_channels_reserved; - ++host->num_channels_reserved; - } - ZeroStruct(channel); - channel->valid = 1; - channel->id = id; - channel->host = host; - channel->address = address; - u64 address_hash = N_HashFromAddress(address); - channel->address_hash = address_hash; + N_ChannelId id = ZI; + N_Channel *channel; + if (host->first_free_channel) + { + channel = host->first_free_channel; + host->first_free_channel = channel->next_free; + id = channel->id; + ++id.gen; + } + else + { + channel = PushStructNoZero(host->channel_arena, N_Channel); + id.gen = 1; + id.idx = host->num_channels_reserved; + ++host->num_channels_reserved; + } + ZeroStruct(channel); + channel->valid = 1; + channel->id = id; + channel->host = host; + channel->address = address; + u64 address_hash = N_HashFromAddress(address); + channel->address_hash = address_hash; - u64 bin_index = address_hash % host->num_channel_lookup_bins; - N_ChannelLookupBin *bin = &host->channel_lookup_bins[bin_index]; - if (bin->last) - { - channel->prev_address_hash = bin->last; - bin->last->next_address_hash = channel; - } - else - { - bin->first = channel; - } - bin->last = channel; + u64 bin_index = address_hash % host->num_channel_lookup_bins; + N_ChannelLookupBin *bin = &host->channel_lookup_bins[bin_index]; + if (bin->last) + { + channel->prev_address_hash = bin->last; + bin->last->next_address_hash = channel; + } + else + { + bin->first = channel; + } + bin->last = channel; - return channel; + return channel; } void N_ReleaseChannel(N_Channel *channel) { - N_Host *host = channel->host; + N_Host *host = channel->host; - /* Release from lookup table */ + /* Release from lookup table */ + { + N_ChannelLookupBin *bin = &host->channel_lookup_bins[channel->address_hash % host->num_channel_lookup_bins]; + N_Channel *prev = channel->prev_address_hash; + N_Channel *next = channel->next_address_hash; + if (prev) { - N_ChannelLookupBin *bin = &host->channel_lookup_bins[channel->address_hash % host->num_channel_lookup_bins]; - N_Channel *prev = channel->prev_address_hash; - N_Channel *next = channel->next_address_hash; - if (prev) - { - prev->next_address_hash = next; - } - else - { - bin->first = next; - } - if (next) - { - next->prev_address_hash = prev; - } - else - { - bin->last = prev; - } + prev->next_address_hash = next; } - - /* Release packets */ + else { - if (channel->first_unreliable_packet) - { - host->first_free_packet = channel->first_unreliable_packet; - channel->last_unreliable_packet->next = host->first_free_packet; - } - if (channel->first_reliable_packet) - { - host->first_free_packet = channel->first_reliable_packet; - channel->last_reliable_packet->next = host->first_free_packet; - } + bin->first = next; } - - /* Release msg assemblers */ - for (N_MsgAssembler *ma = channel->least_recent_msg_assembler; ma; ma = ma->more_recent) + if (next) { - N_ReleaseMessageAssembler(ma); + next->prev_address_hash = prev; } + else + { + bin->last = prev; + } + } - ++channel->id.gen; - channel->valid = 0; - channel->next_free = host->first_free_channel; - host->first_free_channel = channel; + /* Release packets */ + { + if (channel->first_unreliable_packet) + { + host->first_free_packet = channel->first_unreliable_packet; + channel->last_unreliable_packet->next = host->first_free_packet; + } + if (channel->first_reliable_packet) + { + host->first_free_packet = channel->first_reliable_packet; + channel->last_reliable_packet->next = host->first_free_packet; + } + } + + /* Release msg assemblers */ + for (N_MsgAssembler *ma = channel->least_recent_msg_assembler; ma; ma = ma->more_recent) + { + N_ReleaseMessageAssembler(ma); + } + + ++channel->id.gen; + channel->valid = 0; + channel->next_free = host->first_free_channel; + host->first_free_channel = channel; } //////////////////////////////////////////////////////////// @@ -228,209 +228,209 @@ void N_ReleaseChannel(N_Channel *channel) u64 N_HashFromMsg(N_ChannelId channel_id, u64 msg_id) { - u64 result = Fnv64Basis; - result = HashFnv64(result, StringFromStruct(&channel_id)); - result = HashFnv64(result, StringFromStruct(&msg_id)); - return result; + u64 result = Fnv64Basis; + result = HashFnv64(result, StringFromStruct(&channel_id)); + result = HashFnv64(result, StringFromStruct(&msg_id)); + return result; } N_MsgAssembler *N_MsgAssemblerFromMsg(N_Host *host, N_ChannelId channel_id, u64 msg_id) { - u64 hash = N_HashFromMsg(channel_id, msg_id); - N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins]; - for (N_MsgAssembler *ma = bin->first; ma; ma = ma->next_hash) + u64 hash = N_HashFromMsg(channel_id, msg_id); + N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins]; + for (N_MsgAssembler *ma = bin->first; ma; ma = ma->next_hash) + { + if (ma->hash == hash && N_MatchChannelId(ma->channel->id, channel_id) && ma->msg_id == msg_id) { - if (ma->hash == hash && N_MatchChannelId(ma->channel->id, channel_id) && ma->msg_id == msg_id) - { - return ma; - } + return ma; } - return 0; + } + return 0; } N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_count, u64 now_ns, b32 is_reliable) { - N_Host *host = channel->host; - N_MsgAssembler *ma; - if (host->first_free_msg_assembler) - { - ma = host->first_free_msg_assembler; - host->first_free_msg_assembler = ma->next_free; - } - else - { - ma = PushStructNoZero(host->arena, N_MsgAssembler); - } - ZeroStruct(ma); - ma->channel = channel; - ma->msg_id = msg_id; + N_Host *host = channel->host; + N_MsgAssembler *ma; + if (host->first_free_msg_assembler) + { + ma = host->first_free_msg_assembler; + host->first_free_msg_assembler = ma->next_free; + } + else + { + ma = PushStructNoZero(host->arena, N_MsgAssembler); + } + ZeroStruct(ma); + ma->channel = channel; + ma->msg_id = msg_id; - ma->num_chunks_total = chunk_count; + ma->num_chunks_total = chunk_count; - u64 chunk_bitmap_size = (chunk_count + 7) >> 3; - if ((chunk_bitmap_size % 16) != 0) - { - /* Align chunk bitmap to 16 so msg data is aligned */ - chunk_bitmap_size += 16 - (chunk_bitmap_size % 16); - } - u64 chunk_data_size = chunk_count * N_MaxPacketChunkLen; + u64 chunk_bitmap_size = (chunk_count + 7) >> 3; + if ((chunk_bitmap_size % 16) != 0) + { + /* Align chunk bitmap to 16 so msg data is aligned */ + chunk_bitmap_size += 16 - (chunk_bitmap_size % 16); + } + u64 chunk_data_size = chunk_count * N_MaxPacketChunkLen; - /* Acquire msg data using buddy allocator since the assembler has - * arbitrary lifetime and data needs to stay contiguous for random - * access as packets are received */ - ma->buddy_block = AcquireBuddyBlock(host->buddy, chunk_bitmap_size + chunk_data_size); - ma->chunk_bitmap = ma->buddy_block->memory; - ZeroBytes(ma->chunk_bitmap, chunk_bitmap_size); - ma->chunk_data = ma->chunk_bitmap + chunk_bitmap_size; + /* Acquire msg data using buddy allocator since the assembler has + * arbitrary lifetime and data needs to stay contiguous for random + * access as packets are received */ + ma->buddy_block = AcquireBuddyBlock(host->buddy, chunk_bitmap_size + chunk_data_size); + ma->chunk_bitmap = ma->buddy_block->memory; + ZeroBytes(ma->chunk_bitmap, chunk_bitmap_size); + ma->chunk_data = ma->chunk_bitmap + chunk_bitmap_size; - /* FIXME: Ensure chunk_count > 0 */ - ma->is_reliable = is_reliable; + /* FIXME: Ensure chunk_count > 0 */ + ma->is_reliable = is_reliable; - /* Insert into channel list */ - ma->touched_ns = now_ns; - if (channel->most_recent_msg_assembler) - { - channel->most_recent_msg_assembler->more_recent = ma; - ma->less_recent = channel->most_recent_msg_assembler; - } - else - { - channel->least_recent_msg_assembler = ma; - } - channel->most_recent_msg_assembler = ma; + /* Insert into channel list */ + ma->touched_ns = now_ns; + if (channel->most_recent_msg_assembler) + { + channel->most_recent_msg_assembler->more_recent = ma; + ma->less_recent = channel->most_recent_msg_assembler; + } + else + { + channel->least_recent_msg_assembler = ma; + } + channel->most_recent_msg_assembler = ma; - /* Insert into lookup table */ - u64 hash = N_HashFromMsg(channel->id, msg_id); - ma->hash = hash; - N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins]; - if (bin->last) - { - bin->last->next_hash = ma; - ma->prev_hash = bin->last; - } - else - { - bin->first = ma; - } - bin->last = ma; + /* Insert into lookup table */ + u64 hash = N_HashFromMsg(channel->id, msg_id); + ma->hash = hash; + N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins]; + if (bin->last) + { + bin->last->next_hash = ma; + ma->prev_hash = bin->last; + } + else + { + bin->first = ma; + } + bin->last = ma; - return ma; + return ma; } void N_ReleaseMessageAssembler(N_MsgAssembler *ma) { - N_Channel *channel = ma->channel; - N_Host *host = channel->host; - ReleaseBuddyBlock(ma->buddy_block); + N_Channel *channel = ma->channel; + N_Host *host = channel->host; + ReleaseBuddyBlock(ma->buddy_block); - /* Release from channel list */ + /* Release from channel list */ + { + N_MsgAssembler *prev = ma->less_recent; + N_MsgAssembler *next = ma->more_recent; + if (prev) { - N_MsgAssembler *prev = ma->less_recent; - N_MsgAssembler *next = ma->more_recent; - if (prev) - { - prev->more_recent = next; - } - else - { - channel->least_recent_msg_assembler = next; - } - if (next) - { - next->less_recent = prev; - } - else - { - channel->most_recent_msg_assembler = prev; - } + prev->more_recent = next; } - - /* Release from lookup table */ - N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[ma->hash % host->num_msg_assembler_lookup_bins]; + else { - N_MsgAssembler *prev = ma->prev_hash; - N_MsgAssembler *next = ma->next_hash; - if (prev) - { - prev->next_hash = next; - } - else - { - bin->first = next; - } - if (next) - { - next->prev_hash = prev; - } - else - { - bin->last = prev; - } + channel->least_recent_msg_assembler = next; } + if (next) + { + next->less_recent = prev; + } + else + { + channel->most_recent_msg_assembler = prev; + } + } - ma->next_free = host->first_free_msg_assembler; - host->first_free_msg_assembler = ma; + /* Release from lookup table */ + N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[ma->hash % host->num_msg_assembler_lookup_bins]; + { + N_MsgAssembler *prev = ma->prev_hash; + N_MsgAssembler *next = ma->next_hash; + if (prev) + { + prev->next_hash = next; + } + else + { + bin->first = next; + } + if (next) + { + next->prev_hash = prev; + } + else + { + bin->last = prev; + } + } + + ma->next_free = host->first_free_msg_assembler; + host->first_free_msg_assembler = ma; } void N_TouchMessageAssembler(N_MsgAssembler *ma, i64 now_ns) { - N_Channel *channel = ma->channel; - if (ma != channel->most_recent_msg_assembler) + N_Channel *channel = ma->channel; + if (ma != channel->most_recent_msg_assembler) + { + /* Remove from channel list */ { - /* Remove from channel list */ - { - N_MsgAssembler *prev = ma->less_recent; - N_MsgAssembler *next = ma->more_recent; - if (prev) - { - prev->more_recent = next; - } - else - { - channel->least_recent_msg_assembler = next; - } - if (next) - { - next->less_recent = prev; - } - else - { - channel->most_recent_msg_assembler = prev; - } - } - - /* Insert at end of channel list */ - { - if (channel->most_recent_msg_assembler) - { - channel->most_recent_msg_assembler->more_recent = ma; - ma->less_recent = channel->most_recent_msg_assembler; - } - else - { - channel->least_recent_msg_assembler = ma; - } - channel->most_recent_msg_assembler = ma; - } + N_MsgAssembler *prev = ma->less_recent; + N_MsgAssembler *next = ma->more_recent; + if (prev) + { + prev->more_recent = next; + } + else + { + channel->least_recent_msg_assembler = next; + } + if (next) + { + next->less_recent = prev; + } + else + { + channel->most_recent_msg_assembler = prev; + } } - ma->touched_ns = now_ns; + + /* Insert at end of channel list */ + { + if (channel->most_recent_msg_assembler) + { + channel->most_recent_msg_assembler->more_recent = ma; + ma->less_recent = channel->most_recent_msg_assembler; + } + else + { + channel->least_recent_msg_assembler = ma; + } + channel->most_recent_msg_assembler = ma; + } + } + ma->touched_ns = now_ns; } b32 N_IsChunkFilled(N_MsgAssembler *ma, u64 chunk_id) { - if (chunk_id < ma->num_chunks_total) - { - return (ma->chunk_bitmap[chunk_id / 8] & (1 << (chunk_id % 8))) != 0; - } - return 0; + if (chunk_id < ma->num_chunks_total) + { + return (ma->chunk_bitmap[chunk_id / 8] & (1 << (chunk_id % 8))) != 0; + } + return 0; } void N_MarkChunkReceived(N_MsgAssembler *ma, u64 chunk_id) { - if (chunk_id < ma->num_chunks_total) - { - ma->chunk_bitmap[chunk_id / 8] |= (1 << (chunk_id % 8)); - } + if (chunk_id < ma->num_chunks_total) + { + ma->chunk_bitmap[chunk_id / 8] |= (1 << (chunk_id % 8)); + } } //////////////////////////////////////////////////////////// @@ -438,47 +438,47 @@ void N_MarkChunkReceived(N_MsgAssembler *ma, u64 chunk_id) N_SndPacket *N_PushSndPacket(N_Channel *channel, b32 is_reliable) { - N_Host *host = channel->host; - N_SndPacket *packet = 0; - if (host->first_free_packet) - { - packet = host->first_free_packet; - host->first_free_packet = packet->next; - } - else - { - packet = PushStructNoZero(host->arena, N_SndPacket); - } - ZeroStruct(packet); + N_Host *host = channel->host; + N_SndPacket *packet = 0; + if (host->first_free_packet) + { + packet = host->first_free_packet; + host->first_free_packet = packet->next; + } + else + { + packet = PushStructNoZero(host->arena, N_SndPacket); + } + ZeroStruct(packet); - if (is_reliable) + if (is_reliable) + { + if (channel->last_reliable_packet) { - if (channel->last_reliable_packet) - { - channel->last_reliable_packet->next = packet; - } - else - { - channel->first_reliable_packet = packet; - } - channel->last_reliable_packet = packet; - ++channel->num_reliable_packets; - packet->seq = ++channel->last_sent_seq; + channel->last_reliable_packet->next = packet; } else { - if (channel->last_unreliable_packet) - { - channel->last_unreliable_packet->next = packet; - } - else - { - channel->first_unreliable_packet = packet; - } - channel->last_unreliable_packet = packet; - ++channel->num_unreliable_packets; + channel->first_reliable_packet = packet; } - return packet; + channel->last_reliable_packet = packet; + ++channel->num_reliable_packets; + packet->seq = ++channel->last_sent_seq; + } + else + { + if (channel->last_unreliable_packet) + { + channel->last_unreliable_packet->next = packet; + } + else + { + channel->first_unreliable_packet = packet; + } + channel->last_unreliable_packet = packet; + ++channel->num_unreliable_packets; + } + return packet; } //////////////////////////////////////////////////////////// @@ -486,42 +486,42 @@ N_SndPacket *N_PushSndPacket(N_Channel *channel, b32 is_reliable) N_Cmd *N_PushCmd(N_Host *host) { - N_Cmd *cmd = PushStruct(host->cmd_arena, N_Cmd); - if (host->last_cmd) - { - host->last_cmd->next = cmd; - } - else - { - host->first_cmd = cmd; - } - host->last_cmd = cmd; - return cmd; + N_Cmd *cmd = PushStruct(host->cmd_arena, N_Cmd); + if (host->last_cmd) + { + host->last_cmd->next = cmd; + } + else + { + host->first_cmd = cmd; + } + host->last_cmd = cmd; + return cmd; } void N_Connect(N_Host *host, P_Address connect_address) { - N_Channel *channel = N_ChannelFromAddress(host, connect_address); - if (!channel->valid) - { - channel = N_AcquireChannel(host, connect_address); - } + N_Channel *channel = N_ChannelFromAddress(host, connect_address); + if (!channel->valid) + { + channel = N_AcquireChannel(host, connect_address); + } } void N_Disconnect(N_Host *host, N_ChannelId channel_id) { - N_Cmd *cmd = N_PushCmd(host); - cmd->kind = N_CmdKind_Disconnect; - cmd->channel_id = channel_id; + N_Cmd *cmd = N_PushCmd(host); + cmd->kind = N_CmdKind_Disconnect; + cmd->channel_id = channel_id; } void N_Write(N_Host *host, N_ChannelId channel_id, String msg, N_WriteFlag flags) { - N_Cmd *cmd = N_PushCmd(host); - cmd->kind = N_CmdKind_Write; - cmd->channel_id = channel_id; - cmd->write_msg = PushString(host->cmd_arena, msg); - cmd->write_reliable = flags & N_WriteFlag_Reliable; + N_Cmd *cmd = N_PushCmd(host); + cmd->kind = N_CmdKind_Write; + cmd->channel_id = channel_id; + cmd->write_msg = PushString(host->cmd_arena, msg); + cmd->write_reliable = flags & N_WriteFlag_Reliable; } //////////////////////////////////////////////////////////// @@ -529,8 +529,8 @@ void N_Write(N_Host *host, N_ChannelId channel_id, String msg, N_WriteFlag flags i64 N_GetChannelLastRttNs(N_Host *host, N_ChannelId channel_id) { - N_Channel *channel = N_ChannelFromId(host, channel_id); - return channel->last_heartbeat_rtt_ns; + N_Channel *channel = N_ChannelFromId(host, channel_id); + return channel->last_heartbeat_rtt_ns; } //////////////////////////////////////////////////////////// @@ -539,304 +539,304 @@ i64 N_GetChannelLastRttNs(N_Host *host, N_ChannelId channel_id) /* Read incoming packets, update channels, and return events */ N_EventList N_BeginUpdate(Arena *arena, N_Host *host) { - TempArena scratch = BeginScratch(arena); + TempArena scratch = BeginScratch(arena); - N_EventList events = ZI; - i64 now_ns = TimeNs(); + N_EventList events = ZI; + i64 now_ns = TimeNs(); + { + //- Read socket + N_RcvPacket *first_packet = 0; + N_RcvPacket *last_packet = 0; { - //- Read socket - N_RcvPacket *first_packet = 0; - N_RcvPacket *last_packet = 0; + P_Sock *sock = host->sock; + P_SockReadResult result = ZI; + while ((result = P_ReadSock(scratch.arena, sock)).valid) + { + P_Address address = result.address; + String data = result.data; + if (data.len > 0) { - P_Sock *sock = host->sock; - P_SockReadResult result = ZI; - while ((result = P_ReadSock(scratch.arena, sock)).valid) - { - P_Address address = result.address; - String data = result.data; - if (data.len > 0) - { - N_RcvPacket *packet = PushStruct(scratch.arena, N_RcvPacket); - packet->address = address; - packet->data = PushString(scratch.arena, data); - if (last_packet) - { - last_packet->next = packet; - } - else - { - first_packet = packet; - } - last_packet = packet; - } - } - } - - //- Read incoming packets - { - for (N_RcvPacket *packet = first_packet; packet; packet = packet->next) - { - //struct sock *sock = packet->sock; - P_Address address = packet->address; - BB_Buff bb = BB_BuffFromString(packet->data); - BB_Reader br = BB_ReaderFromBuff(&bb); - u32 magic = BB_ReadUBits(&br, 32); /* TODO: implicitly encode magic into crc32 */ - if (magic == N_PacketMagic) - { - /* TODO: Combine kind byte with flags byte */ - N_Channel *channel = N_ChannelFromAddress(host, address); - N_PacketKind packet_kind = BB_ReadIBits(&br, 8); - u8 packet_flags = BB_ReadUBits(&br, 8); - - u64 their_acked_seq = BB_ReadUV(&br); - if (channel->valid) - { - channel->last_packet_received_ns = now_ns; - if (their_acked_seq > channel->their_acked_seq) - { - channel->their_acked_seq = their_acked_seq; - } - } - - b32 skip_packet = 0; - b32 is_reliable = packet_flags & N_PacketFlag_Reliable; - if (channel->valid) - { - if (is_reliable) - { - u64 packet_seq = BB_ReadUV(&br); - if (packet_seq == channel->our_acked_seq + 1) - { - channel->our_acked_seq = packet_seq; - } - else - { - skip_packet = 1; - } - } - } - - if (!skip_packet) - { - switch (packet_kind) - { - default: break; - - //- Read packet kind: TryConnect - case N_PacketKind_TryConnect: - { - /* A foreign host is trying to connect to us */ - if (!channel->valid) - { - LogInfoF("Host received conection attempt from %F", FmtString(P_StringFromAddress(scratch.arena, address))); - /* TODO: Verify that some per-host uuid isn't present in a rolling window to prevent reconnects right after a disconnect? */ - channel = N_AcquireChannel(host, address); - } - N_Cmd *cmd = N_PushCmd(host); - cmd->kind = N_CmdKind_ConnectSuccess; - cmd->channel_id = channel->id; - } break; - //- Read packet kind: ConnectSuccess - case N_PacketKind_ConnectSuccess: - { - /* We successfully connected to a foreign host and they are ready to receive messages */ - if (channel->valid && !channel->connected) - { - LogInfoF("Host received connection from %F", FmtString(P_StringFromAddress(scratch.arena, address))); - N_Event *event = N_PushEvent(arena, &events); - event->kind = N_EventKind_ChannelOpened; - event->channel_id = channel->id; - channel->connected = 1; - } - } break; - //- Read packet kind: Disconnect - case N_PacketKind_Disconnect: - { - /* A foreign host disconnected from us */ - if (channel->valid) - { - LogInfoF("Host received disconnection from %F", FmtString(P_StringFromAddress(scratch.arena, address))); - N_Event *event = N_PushEvent(arena, &events); - event->kind = N_EventKind_ChannelClosed; - event->channel_id = channel->id; - N_ReleaseChannel(channel); - } - - } break; - //- Read packet kind: Heartbeat - case N_PacketKind_Heartbeat: - { - if (channel->valid) - { - u16 heartbeat_id = BB_ReadUBits(&br, 16); - u16 acked_heartbeat_id = BB_ReadUBits(&br, 16); - if (heartbeat_id > channel->last_heartbeat_received_id) - { - channel->last_heartbeat_received_id = heartbeat_id; - } - if (acked_heartbeat_id == channel->last_heartbeat_acked_id + 1) - { - channel->last_heartbeat_acked_id = acked_heartbeat_id; - if (channel->last_heartbeat_acked_ns > 0) - { - channel->last_heartbeat_rtt_ns = now_ns - channel->last_heartbeat_acked_ns; - } - channel->last_heartbeat_acked_ns = now_ns; - } - } - } break; - //- Read packet kind: MsgChunk - case N_PacketKind_MsgChunk: - { - if (channel->valid && channel->connected) - { - /* Packet is chunk out of belonging to message */ - u64 msg_id = BB_ReadUV(&br); - u64 chunk_id = BB_ReadUV(&br); - u64 chunk_count = BB_ReadUV(&br); - b32 is_last_chunk = (chunk_id + 1) == chunk_count; - u64 chunk_len = is_last_chunk ? BB_ReadUV(&br) : N_MaxPacketChunkLen; - - N_MsgAssembler *ma = N_MsgAssemblerFromMsg(host, channel->id, msg_id); - if (!ma) - { - ma = N_AcquireMsgAssembler(channel, msg_id, chunk_count, now_ns, is_reliable); - } - - if (chunk_count == ma->num_chunks_total && chunk_id < chunk_count) - { - if (!N_IsChunkFilled(ma, chunk_id)) - { - u8 *src = BB_ReadBytesRaw(&br, chunk_len); - if (src) - { - u8 *dst = &ma->chunk_data[chunk_id * N_MaxPacketChunkLen]; - CopyBytes(dst, src, chunk_len); - if (is_last_chunk) - { - ma->last_chunk_len = chunk_len; - } - N_MarkChunkReceived(ma, chunk_id); - ++ma->num_chunks_received; - N_TouchMessageAssembler(ma, now_ns); - if (ma->num_chunks_received == chunk_count) - { - /* All chunks filled, message has finished assembling */ - /* TODO: Message ordering */ - N_Event *event = N_PushEvent(arena, &events); - String data = ZI; - data.len = ((chunk_count - 1) * N_MaxPacketChunkLen) + ma->last_chunk_len; - data.text = PushStructsNoZero(arena, u8, data.len); - CopyBytes(data.text, ma->chunk_data, data.len); - event->kind = N_EventKind_Msg; - event->msg = data; - event->channel_id = channel->id; - if (is_reliable) - { - /* Release assembler if reliable */ - N_ReleaseMessageAssembler(ma); - } - } - } - else - { - /* Overflow reading chunk */ - Assert(0); - } - } - } - else - { - /* Chunk id/count mismatch */ - Assert(0); - } - } - } break; - } - } - host->bytes_received += packet->data.len; - } - } + N_RcvPacket *packet = PushStruct(scratch.arena, N_RcvPacket); + packet->address = address; + packet->data = PushString(scratch.arena, data); + if (last_packet) + { + last_packet->next = packet; + } + else + { + first_packet = packet; + } + last_packet = packet; } + } } - //- Update channels + //- Read incoming packets { - for (u64 i = 0; i < host->num_channels_reserved; ++i) + for (N_RcvPacket *packet = first_packet; packet; packet = packet->next) + { + //struct sock *sock = packet->sock; + P_Address address = packet->address; + BB_Buff bb = BB_BuffFromString(packet->data); + BB_Reader br = BB_ReaderFromBuff(&bb); + u32 magic = BB_ReadUBits(&br, 32); /* TODO: implicitly encode magic into crc32 */ + if (magic == N_PacketMagic) { - N_Channel *channel = &host->channels[i]; - if (channel->valid) - { - /* Send / resend handshake if not connected */ - if (!channel->connected) - { - N_Cmd *cmd = N_PushCmd(host); - cmd->kind = N_CmdKind_TryConnect; - cmd->channel_id = channel->id; - } - /* Send heartbeat */ - /* TODO: Send this less frequently (once per second or half of timeout or something) */ - { - N_Cmd *cmd = N_PushCmd(host); - cmd->kind = N_CmdKind_Heartbeat; - cmd->heartbeat_id = channel->last_heartbeat_acked_id + 1; - cmd->heartbeat_ack_id = channel->last_heartbeat_received_id; - cmd->channel_id = channel->id; - } - /* Release acked reliable packets */ - { - u64 acked_seq = channel->their_acked_seq; - N_SndPacket *packet = channel->first_reliable_packet; - while (packet) - { - N_SndPacket *next = packet->next; - u64 seq = packet->seq; - if (seq < acked_seq) - { - packet->next = host->first_free_packet; - host->first_free_packet = packet; - channel->first_reliable_packet = next; - --channel->num_reliable_packets; - } - else - { - break; - } - packet = next; - } - if (channel->first_reliable_packet == 0) - { - channel->last_reliable_packet = 0; - } - } - /* Release timed out unreliable msg buffers */ - { - /* TODO: Configurable timeout */ - i64 unreliable_msg_timeout_ns = NsFromSeconds(0.1); - N_MsgAssembler *ma = channel->least_recent_msg_assembler; - while (ma) - { - N_MsgAssembler *next = ma->more_recent; - if ((now_ns - ma->touched_ns) > unreliable_msg_timeout_ns) - { - if (!ma->is_reliable) - { - N_ReleaseMessageAssembler(ma); - } - } - else - { - break; - } - ma = next; - } - } - } - } - } + /* TODO: Combine kind byte with flags byte */ + N_Channel *channel = N_ChannelFromAddress(host, address); + N_PacketKind packet_kind = BB_ReadIBits(&br, 8); + u8 packet_flags = BB_ReadUBits(&br, 8); - EndScratch(scratch); - return events; + u64 their_acked_seq = BB_ReadUV(&br); + if (channel->valid) + { + channel->last_packet_received_ns = now_ns; + if (their_acked_seq > channel->their_acked_seq) + { + channel->their_acked_seq = their_acked_seq; + } + } + + b32 skip_packet = 0; + b32 is_reliable = packet_flags & N_PacketFlag_Reliable; + if (channel->valid) + { + if (is_reliable) + { + u64 packet_seq = BB_ReadUV(&br); + if (packet_seq == channel->our_acked_seq + 1) + { + channel->our_acked_seq = packet_seq; + } + else + { + skip_packet = 1; + } + } + } + + if (!skip_packet) + { + switch (packet_kind) + { + default: break; + + //- Read packet kind: TryConnect + case N_PacketKind_TryConnect: + { + /* A foreign host is trying to connect to us */ + if (!channel->valid) + { + LogInfoF("Host received conection attempt from %F", FmtString(P_StringFromAddress(scratch.arena, address))); + /* TODO: Verify that some per-host uuid isn't present in a rolling window to prevent reconnects right after a disconnect? */ + channel = N_AcquireChannel(host, address); + } + N_Cmd *cmd = N_PushCmd(host); + cmd->kind = N_CmdKind_ConnectSuccess; + cmd->channel_id = channel->id; + } break; + //- Read packet kind: ConnectSuccess + case N_PacketKind_ConnectSuccess: + { + /* We successfully connected to a foreign host and they are ready to receive messages */ + if (channel->valid && !channel->connected) + { + LogInfoF("Host received connection from %F", FmtString(P_StringFromAddress(scratch.arena, address))); + N_Event *event = N_PushEvent(arena, &events); + event->kind = N_EventKind_ChannelOpened; + event->channel_id = channel->id; + channel->connected = 1; + } + } break; + //- Read packet kind: Disconnect + case N_PacketKind_Disconnect: + { + /* A foreign host disconnected from us */ + if (channel->valid) + { + LogInfoF("Host received disconnection from %F", FmtString(P_StringFromAddress(scratch.arena, address))); + N_Event *event = N_PushEvent(arena, &events); + event->kind = N_EventKind_ChannelClosed; + event->channel_id = channel->id; + N_ReleaseChannel(channel); + } + + } break; + //- Read packet kind: Heartbeat + case N_PacketKind_Heartbeat: + { + if (channel->valid) + { + u16 heartbeat_id = BB_ReadUBits(&br, 16); + u16 acked_heartbeat_id = BB_ReadUBits(&br, 16); + if (heartbeat_id > channel->last_heartbeat_received_id) + { + channel->last_heartbeat_received_id = heartbeat_id; + } + if (acked_heartbeat_id == channel->last_heartbeat_acked_id + 1) + { + channel->last_heartbeat_acked_id = acked_heartbeat_id; + if (channel->last_heartbeat_acked_ns > 0) + { + channel->last_heartbeat_rtt_ns = now_ns - channel->last_heartbeat_acked_ns; + } + channel->last_heartbeat_acked_ns = now_ns; + } + } + } break; + //- Read packet kind: MsgChunk + case N_PacketKind_MsgChunk: + { + if (channel->valid && channel->connected) + { + /* Packet is chunk out of belonging to message */ + u64 msg_id = BB_ReadUV(&br); + u64 chunk_id = BB_ReadUV(&br); + u64 chunk_count = BB_ReadUV(&br); + b32 is_last_chunk = (chunk_id + 1) == chunk_count; + u64 chunk_len = is_last_chunk ? BB_ReadUV(&br) : N_MaxPacketChunkLen; + + N_MsgAssembler *ma = N_MsgAssemblerFromMsg(host, channel->id, msg_id); + if (!ma) + { + ma = N_AcquireMsgAssembler(channel, msg_id, chunk_count, now_ns, is_reliable); + } + + if (chunk_count == ma->num_chunks_total && chunk_id < chunk_count) + { + if (!N_IsChunkFilled(ma, chunk_id)) + { + u8 *src = BB_ReadBytesRaw(&br, chunk_len); + if (src) + { + u8 *dst = &ma->chunk_data[chunk_id * N_MaxPacketChunkLen]; + CopyBytes(dst, src, chunk_len); + if (is_last_chunk) + { + ma->last_chunk_len = chunk_len; + } + N_MarkChunkReceived(ma, chunk_id); + ++ma->num_chunks_received; + N_TouchMessageAssembler(ma, now_ns); + if (ma->num_chunks_received == chunk_count) + { + /* All chunks filled, message has finished assembling */ + /* TODO: Message ordering */ + N_Event *event = N_PushEvent(arena, &events); + String data = ZI; + data.len = ((chunk_count - 1) * N_MaxPacketChunkLen) + ma->last_chunk_len; + data.text = PushStructsNoZero(arena, u8, data.len); + CopyBytes(data.text, ma->chunk_data, data.len); + event->kind = N_EventKind_Msg; + event->msg = data; + event->channel_id = channel->id; + if (is_reliable) + { + /* Release assembler if reliable */ + N_ReleaseMessageAssembler(ma); + } + } + } + else + { + /* Overflow reading chunk */ + Assert(0); + } + } + } + else + { + /* Chunk id/count mismatch */ + Assert(0); + } + } + } break; + } + } + host->bytes_received += packet->data.len; + } + } + } + } + + //- Update channels + { + for (u64 i = 0; i < host->num_channels_reserved; ++i) + { + N_Channel *channel = &host->channels[i]; + if (channel->valid) + { + /* Send / resend handshake if not connected */ + if (!channel->connected) + { + N_Cmd *cmd = N_PushCmd(host); + cmd->kind = N_CmdKind_TryConnect; + cmd->channel_id = channel->id; + } + /* Send heartbeat */ + /* TODO: Send this less frequently (once per second or half of timeout or something) */ + { + N_Cmd *cmd = N_PushCmd(host); + cmd->kind = N_CmdKind_Heartbeat; + cmd->heartbeat_id = channel->last_heartbeat_acked_id + 1; + cmd->heartbeat_ack_id = channel->last_heartbeat_received_id; + cmd->channel_id = channel->id; + } + /* Release acked reliable packets */ + { + u64 acked_seq = channel->their_acked_seq; + N_SndPacket *packet = channel->first_reliable_packet; + while (packet) + { + N_SndPacket *next = packet->next; + u64 seq = packet->seq; + if (seq < acked_seq) + { + packet->next = host->first_free_packet; + host->first_free_packet = packet; + channel->first_reliable_packet = next; + --channel->num_reliable_packets; + } + else + { + break; + } + packet = next; + } + if (channel->first_reliable_packet == 0) + { + channel->last_reliable_packet = 0; + } + } + /* Release timed out unreliable msg buffers */ + { + /* TODO: Configurable timeout */ + i64 unreliable_msg_timeout_ns = NsFromSeconds(0.1); + N_MsgAssembler *ma = channel->least_recent_msg_assembler; + while (ma) + { + N_MsgAssembler *next = ma->more_recent; + if ((now_ns - ma->touched_ns) > unreliable_msg_timeout_ns) + { + if (!ma->is_reliable) + { + N_ReleaseMessageAssembler(ma); + } + } + else + { + break; + } + ma = next; + } + } + } + } + } + + EndScratch(scratch); + return events; } //////////////////////////////////////////////////////////// @@ -845,176 +845,176 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host) /* Process host cmds & send outgoing packets */ void N_EndUpdate(N_Host *host) { - TempArena scratch = BeginScratchNoConflict(); + TempArena scratch = BeginScratchNoConflict(); - /* Process cmds into sendable packets */ - /* TODO: Unreliable packets don't need to be allocated into unreliable packet queue, should just send them and forget */ + /* Process cmds into sendable packets */ + /* TODO: Unreliable packets don't need to be allocated into unreliable packet queue, should just send them and forget */ + { + for (N_Cmd *cmd = host->first_cmd; cmd; cmd = cmd->next) { - for (N_Cmd *cmd = host->first_cmd; cmd; cmd = cmd->next) + N_CmdKind kind = cmd->kind; + N_ChannelId channel_id = cmd->channel_id; + N_ChannelList channels = N_ChannelsFromId(scratch.arena, host, channel_id); + for (N_ChannelNode *node = channels.first; node; node = node->next) + { + N_Channel *channel = node->channel; + switch (kind) { - N_CmdKind kind = cmd->kind; - N_ChannelId channel_id = cmd->channel_id; - N_ChannelList channels = N_ChannelsFromId(scratch.arena, host, channel_id); - for (N_ChannelNode *node = channels.first; node; node = node->next) + default: break; + + //- Process command: TryConnect + case N_CmdKind_TryConnect: + { + u8 packet_flags = 0; + N_SndPacket *packet = N_PushSndPacket(channel, 0); + BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); + BB_Writer bw = BB_WriterFromBuff(&bb); + BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ + BB_WriteIBits(&bw, N_PacketKind_TryConnect, 8); + BB_WriteUBits(&bw, packet_flags, 8); + BB_WriteUV(&bw, channel->our_acked_seq); + packet->data_len = BB_GetNumBytesWritten(&bw); + } break; + //- Process command: ConnectSuccess + case N_CmdKind_ConnectSuccess: + { + u8 packet_flags = 0; + N_SndPacket *packet = N_PushSndPacket(channel, 0); + BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); + BB_Writer bw = BB_WriterFromBuff(&bb); + BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ + BB_WriteIBits(&bw, N_PacketKind_ConnectSuccess, 8); + BB_WriteUBits(&bw, packet_flags, 8); + BB_WriteUV(&bw, channel->our_acked_seq); + packet->data_len = BB_GetNumBytesWritten(&bw); + } break; + //- Process command: Disconnect + case N_CmdKind_Disconnect: + { + u8 packet_flags = 0; + N_SndPacket *packet = N_PushSndPacket(channel, 0); + BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); + BB_Writer bw = BB_WriterFromBuff(&bb); + BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ + BB_WriteIBits(&bw, N_PacketKind_Disconnect, 8); + BB_WriteUBits(&bw, packet_flags, 8); + BB_WriteUV(&bw, channel->our_acked_seq); + packet->data_len = BB_GetNumBytesWritten(&bw); + } break; + //- Process command: Heartbeat + case N_CmdKind_Heartbeat: + { + u8 packet_flags = 0; + N_SndPacket *packet = N_PushSndPacket(channel, 0); + BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); + BB_Writer bw = BB_WriterFromBuff(&bb); + BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ + BB_WriteIBits(&bw, N_PacketKind_Heartbeat, 8); + BB_WriteUBits(&bw, packet_flags, 8); + BB_WriteUV(&bw, channel->our_acked_seq); + BB_WriteUBits(&bw, cmd->heartbeat_id, 16); + BB_WriteUBits(&bw, cmd->heartbeat_ack_id, 16); + packet->data_len = BB_GetNumBytesWritten(&bw); + } break; + //- Process command: Write + case N_CmdKind_Write: + { + b32 is_reliable = cmd->write_reliable; + u8 packet_flags = (is_reliable * N_PacketFlag_Reliable); + String msg = cmd->write_msg; + + u64 chunk_count = 0; + if (msg.len > 0) { - N_Channel *channel = node->channel; - switch (kind) - { - default: break; - - //- Process command: TryConnect - case N_CmdKind_TryConnect: - { - u8 packet_flags = 0; - N_SndPacket *packet = N_PushSndPacket(channel, 0); - BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); - BB_Writer bw = BB_WriterFromBuff(&bb); - BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ - BB_WriteIBits(&bw, N_PacketKind_TryConnect, 8); - BB_WriteUBits(&bw, packet_flags, 8); - BB_WriteUV(&bw, channel->our_acked_seq); - packet->data_len = BB_GetNumBytesWritten(&bw); - } break; - //- Process command: ConnectSuccess - case N_CmdKind_ConnectSuccess: - { - u8 packet_flags = 0; - N_SndPacket *packet = N_PushSndPacket(channel, 0); - BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); - BB_Writer bw = BB_WriterFromBuff(&bb); - BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ - BB_WriteIBits(&bw, N_PacketKind_ConnectSuccess, 8); - BB_WriteUBits(&bw, packet_flags, 8); - BB_WriteUV(&bw, channel->our_acked_seq); - packet->data_len = BB_GetNumBytesWritten(&bw); - } break; - //- Process command: Disconnect - case N_CmdKind_Disconnect: - { - u8 packet_flags = 0; - N_SndPacket *packet = N_PushSndPacket(channel, 0); - BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); - BB_Writer bw = BB_WriterFromBuff(&bb); - BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ - BB_WriteIBits(&bw, N_PacketKind_Disconnect, 8); - BB_WriteUBits(&bw, packet_flags, 8); - BB_WriteUV(&bw, channel->our_acked_seq); - packet->data_len = BB_GetNumBytesWritten(&bw); - } break; - //- Process command: Heartbeat - case N_CmdKind_Heartbeat: - { - u8 packet_flags = 0; - N_SndPacket *packet = N_PushSndPacket(channel, 0); - BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); - BB_Writer bw = BB_WriterFromBuff(&bb); - BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ - BB_WriteIBits(&bw, N_PacketKind_Heartbeat, 8); - BB_WriteUBits(&bw, packet_flags, 8); - BB_WriteUV(&bw, channel->our_acked_seq); - BB_WriteUBits(&bw, cmd->heartbeat_id, 16); - BB_WriteUBits(&bw, cmd->heartbeat_ack_id, 16); - packet->data_len = BB_GetNumBytesWritten(&bw); - } break; - //- Process command: Write - case N_CmdKind_Write: - { - b32 is_reliable = cmd->write_reliable; - u8 packet_flags = (is_reliable * N_PacketFlag_Reliable); - String msg = cmd->write_msg; - - u64 chunk_count = 0; - if (msg.len > 0) - { - chunk_count = (msg.len - 1) / N_MaxPacketChunkLen; - } - chunk_count += 1; - - u64 msg_id = ++channel->last_sent_msg_id; - for (u64 i = 0; i < chunk_count; ++i) - { - u64 chunk_len = N_MaxPacketChunkLen; - b32 is_last_chunk = i + 1 == chunk_count; - if (is_last_chunk) - { - chunk_len = msg.len % N_MaxPacketChunkLen; - if (chunk_len == 0) - { - chunk_len = N_MaxPacketChunkLen; - } - } - N_SndPacket *packet = N_PushSndPacket(channel, is_reliable); - BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); - BB_Writer bw = BB_WriterFromBuff(&bb); - BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ - BB_WriteIBits(&bw, N_PacketKind_MsgChunk, 8); - BB_WriteUBits(&bw, packet_flags, 8); - BB_WriteUV(&bw, channel->our_acked_seq); - if (is_reliable) - { - BB_WriteUV(&bw, packet->seq); - } - BB_WriteUV(&bw, msg_id); - BB_WriteUV(&bw, i); - BB_WriteUV(&bw, chunk_count); - if (is_last_chunk) - { - BB_WriteUV(&bw, chunk_len); - } - u8 *chunk_data = msg.text + (i * N_MaxPacketChunkLen); - BB_WriteBytes(&bw, STRING(chunk_len, chunk_data)); - packet->data_len = BB_GetNumBytesWritten(&bw); - } - } break; - } + chunk_count = (msg.len - 1) / N_MaxPacketChunkLen; } - } - } + chunk_count += 1; - //- Send packets - /* TODO: Aggregate small packets */ + u64 msg_id = ++channel->last_sent_msg_id; + for (u64 i = 0; i < chunk_count; ++i) + { + u64 chunk_len = N_MaxPacketChunkLen; + b32 is_last_chunk = i + 1 == chunk_count; + if (is_last_chunk) + { + chunk_len = msg.len % N_MaxPacketChunkLen; + if (chunk_len == 0) + { + chunk_len = N_MaxPacketChunkLen; + } + } + N_SndPacket *packet = N_PushSndPacket(channel, is_reliable); + BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); + BB_Writer bw = BB_WriterFromBuff(&bb); + BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ + BB_WriteIBits(&bw, N_PacketKind_MsgChunk, 8); + BB_WriteUBits(&bw, packet_flags, 8); + BB_WriteUV(&bw, channel->our_acked_seq); + if (is_reliable) + { + BB_WriteUV(&bw, packet->seq); + } + BB_WriteUV(&bw, msg_id); + BB_WriteUV(&bw, i); + BB_WriteUV(&bw, chunk_count); + if (is_last_chunk) + { + BB_WriteUV(&bw, chunk_len); + } + u8 *chunk_data = msg.text + (i * N_MaxPacketChunkLen); + BB_WriteBytes(&bw, STRING(chunk_len, chunk_data)); + packet->data_len = BB_GetNumBytesWritten(&bw); + } + } break; + } + } + } + } + + //- Send packets + /* TODO: Aggregate small packets */ + { + for (u64 i = 0; i < host->num_channels_reserved; ++i) { - for (u64 i = 0; i < host->num_channels_reserved; ++i) + P_Sock *sock = host->sock; + N_Channel *channel = &host->channels[i]; + u64 total_sent = 0; + if (channel->valid) + { + P_Address address = channel->address; + /* Send reliable packets to channel */ + for (N_SndPacket *packet = channel->first_reliable_packet; packet; packet = packet->next) { - P_Sock *sock = host->sock; - N_Channel *channel = &host->channels[i]; - u64 total_sent = 0; - if (channel->valid) - { - P_Address address = channel->address; - /* Send reliable packets to channel */ - for (N_SndPacket *packet = channel->first_reliable_packet; packet; packet = packet->next) - { - P_WriteSock(sock, address, STRING(packet->data_len, packet->data)); - total_sent += packet->data_len; - } - /* Send unreliable packets to channel */ - for (N_SndPacket *packet = channel->first_unreliable_packet; packet; packet = packet->next) - { - P_WriteSock(sock, address, STRING(packet->data_len, packet->data)); - total_sent += packet->data_len; - } - /* Release unreliable packets */ - if (channel->first_unreliable_packet) - { - channel->last_unreliable_packet->next = host->first_free_packet; - host->first_free_packet = channel->first_unreliable_packet; - channel->first_unreliable_packet = 0; - channel->last_unreliable_packet = 0; - channel->num_unreliable_packets = 0; - } - host->bytes_sent += total_sent; - } + P_WriteSock(sock, address, STRING(packet->data_len, packet->data)); + total_sent += packet->data_len; } + /* Send unreliable packets to channel */ + for (N_SndPacket *packet = channel->first_unreliable_packet; packet; packet = packet->next) + { + P_WriteSock(sock, address, STRING(packet->data_len, packet->data)); + total_sent += packet->data_len; + } + /* Release unreliable packets */ + if (channel->first_unreliable_packet) + { + channel->last_unreliable_packet->next = host->first_free_packet; + host->first_free_packet = channel->first_unreliable_packet; + channel->first_unreliable_packet = 0; + channel->last_unreliable_packet = 0; + channel->num_unreliable_packets = 0; + } + host->bytes_sent += total_sent; + } } + } - //- Reset commands list - host->first_cmd = 0; - host->last_cmd = 0; - ResetArena(host->cmd_arena); + //- Reset commands list + host->first_cmd = 0; + host->last_cmd = 0; + ResetArena(host->cmd_arena); - EndScratch(scratch); + EndScratch(scratch); } //////////////////////////////////////////////////////////// @@ -1022,15 +1022,15 @@ void N_EndUpdate(N_Host *host) N_Event *N_PushEvent(Arena *arena, N_EventList *list) { - N_Event *event = PushStruct(arena, N_Event); - if (list->last) - { - list->last->next = event; - } - else - { - list->first = event; - } - list->last = event; - return event; + N_Event *event = PushStruct(arena, N_Event); + if (list->last) + { + list->last->next = event; + } + else + { + list->first = event; + } + list->last = event; + return event; } diff --git a/src/net/net.h b/src/net/net.h index 31373044..8a436680 100644 --- a/src/net/net.h +++ b/src/net/net.h @@ -3,8 +3,8 @@ Struct(N_ChannelId) { - u32 gen; - u32 idx; + u32 gen; + u32 idx; }; //////////////////////////////////////////////////////////// @@ -12,32 +12,32 @@ Struct(N_ChannelId) Enum(N_CmdKind) { - N_CmdKind_None, - N_CmdKind_TryConnect, - N_CmdKind_ConnectSuccess, - N_CmdKind_Disconnect, - N_CmdKind_Heartbeat, - N_CmdKind_Write + N_CmdKind_None, + N_CmdKind_TryConnect, + N_CmdKind_ConnectSuccess, + N_CmdKind_Disconnect, + N_CmdKind_Heartbeat, + N_CmdKind_Write }; Enum(N_WriteFlag) { - N_WriteFlag_None = 0, - N_WriteFlag_Reliable = (1 << 0) + N_WriteFlag_None = 0, + N_WriteFlag_Reliable = (1 << 0) }; Struct(N_Cmd) { - N_CmdKind kind; - N_ChannelId channel_id; + N_CmdKind kind; + N_ChannelId channel_id; - u16 heartbeat_id; - u16 heartbeat_ack_id; + u16 heartbeat_id; + u16 heartbeat_ack_id; - b32 write_reliable; - String write_msg; + b32 write_reliable; + String write_msg; - N_Cmd *next; + N_Cmd *next; }; //////////////////////////////////////////////////////////// @@ -45,31 +45,31 @@ Struct(N_Cmd) Enum(N_EventKind) { - N_EventKind_None, - N_EventKind_ChannelOpened, - N_EventKind_ChannelClosed, - N_EventKind_Msg + N_EventKind_None, + N_EventKind_ChannelOpened, + N_EventKind_ChannelClosed, + N_EventKind_Msg }; Struct(N_Event) { - N_EventKind kind; - N_ChannelId channel_id; - String msg; + N_EventKind kind; + N_ChannelId channel_id; + String msg; - N_Event *next; + N_Event *next; }; Struct(N_EventList) { - N_Event *first; - N_Event *last; + N_Event *first; + N_Event *last; }; Struct(N_ChannelLookupBin) { - struct N_Channel *first; - struct N_Channel *last; + struct N_Channel *first; + struct N_Channel *last; }; //////////////////////////////////////////////////////////// @@ -81,42 +81,42 @@ Struct(N_ChannelLookupBin) Enum(N_PacketKind) { - N_PacketKind_None, - N_PacketKind_TryConnect, - N_PacketKind_ConnectSuccess, - N_PacketKind_Disconnect, - N_PacketKind_Heartbeat, - N_PacketKind_MsgChunk + N_PacketKind_None, + N_PacketKind_TryConnect, + N_PacketKind_ConnectSuccess, + N_PacketKind_Disconnect, + N_PacketKind_Heartbeat, + N_PacketKind_MsgChunk }; Enum(N_PacketFlag) { - N_PacketFlag_None = 0, - N_PacketFlag_Reliable = (1 << 0) + N_PacketFlag_None = 0, + N_PacketFlag_Reliable = (1 << 0) }; Struct(N_SndPacket) { - N_SndPacket *next; - u64 seq; + N_SndPacket *next; + u64 seq; - u64 data_len; - u8 data[N_MaxPacketLen]; + u64 data_len; + u8 data[N_MaxPacketLen]; }; Struct(N_RcvPacket) { - P_Sock *sock; - P_Address address; - String data; - N_RcvPacket *next; + P_Sock *sock; + P_Address address; + String data; + N_RcvPacket *next; }; Struct(N_RcvBuffer) { - Arena *arena; - N_RcvPacket *first_packet; - N_RcvPacket *last_packet; + Arena *arena; + N_RcvPacket *first_packet; + N_RcvPacket *last_packet; }; //////////////////////////////////////////////////////////// @@ -124,53 +124,53 @@ Struct(N_RcvBuffer) Struct(N_Channel) { - N_ChannelId id; - b32 valid; - b32 connected; - struct N_Host *host; + N_ChannelId id; + b32 valid; + b32 connected; + struct N_Host *host; - N_Channel *next_free; + N_Channel *next_free; - P_Address address; - u64 address_hash; - N_Channel *next_address_hash; - N_Channel *prev_address_hash; + P_Address address; + u64 address_hash; + N_Channel *next_address_hash; + N_Channel *prev_address_hash; - /* NOTE: Packets are allocated in host's `arena` */ - N_SndPacket *first_reliable_packet; - N_SndPacket *last_reliable_packet; - N_SndPacket *first_unreliable_packet; - N_SndPacket *last_unreliable_packet; - u64 num_reliable_packets; - u64 num_unreliable_packets; + /* NOTE: Packets are allocated in host's `arena` */ + N_SndPacket *first_reliable_packet; + N_SndPacket *last_reliable_packet; + N_SndPacket *first_unreliable_packet; + N_SndPacket *last_unreliable_packet; + u64 num_reliable_packets; + u64 num_unreliable_packets; - /* NOTE: Msg assemblers are allocated in host's `arena` */ - struct N_MsgAssembler *least_recent_msg_assembler; - struct N_MsgAssembler *most_recent_msg_assembler; + /* NOTE: Msg assemblers are allocated in host's `arena` */ + struct N_MsgAssembler *least_recent_msg_assembler; + struct N_MsgAssembler *most_recent_msg_assembler; - u16 last_heartbeat_received_id; - u16 last_heartbeat_acked_id; - i64 last_heartbeat_acked_ns; - i64 last_heartbeat_rtt_ns; + u16 last_heartbeat_received_id; + u16 last_heartbeat_acked_id; + i64 last_heartbeat_acked_ns; + i64 last_heartbeat_rtt_ns; - u64 last_sent_msg_id; - u64 their_acked_seq; - u64 our_acked_seq; - u64 last_sent_seq; + u64 last_sent_msg_id; + u64 their_acked_seq; + u64 our_acked_seq; + u64 last_sent_seq; - i64 last_packet_received_ns; + i64 last_packet_received_ns; }; Struct(N_ChannelNode) { - N_Channel *channel; - N_ChannelNode *next; + N_Channel *channel; + N_ChannelNode *next; }; Struct(N_ChannelList) { - N_ChannelNode *first; - N_ChannelNode *last; + N_ChannelNode *first; + N_ChannelNode *last; }; //////////////////////////////////////////////////////////// @@ -178,38 +178,38 @@ Struct(N_ChannelList) Struct(N_MsgAssembler) { - N_Channel *channel; - b32 is_reliable; + N_Channel *channel; + b32 is_reliable; - /* Free list */ - N_MsgAssembler *next_free; + /* Free list */ + N_MsgAssembler *next_free; - /* Bucket list */ - N_MsgAssembler *next_hash; - N_MsgAssembler *prev_hash; + /* Bucket list */ + N_MsgAssembler *next_hash; + N_MsgAssembler *prev_hash; - /* Channel list */ - N_MsgAssembler *less_recent; - N_MsgAssembler *more_recent; + /* Channel list */ + N_MsgAssembler *less_recent; + N_MsgAssembler *more_recent; - u64 msg_id; - u64 hash; + u64 msg_id; + u64 hash; - u64 last_chunk_len; - u64 num_chunks_total; - u64 num_chunks_received; + u64 last_chunk_len; + u64 num_chunks_total; + u64 num_chunks_received; - i64 touched_ns; + i64 touched_ns; - BuddyBlock *buddy_block; - u8 *chunk_bitmap; - u8 *chunk_data; + BuddyBlock *buddy_block; + u8 *chunk_bitmap; + u8 *chunk_data; }; Struct(N_MsgAssemblerLookupBin) { - N_MsgAssembler *first; - N_MsgAssembler *last; + N_MsgAssembler *first; + N_MsgAssembler *last; }; //////////////////////////////////////////////////////////// @@ -220,38 +220,38 @@ Struct(N_MsgAssemblerLookupBin) Struct(N_Host) { - Arena *arena; + Arena *arena; - P_Sock *sock; + P_Sock *sock; - BuddyCtx *buddy; /* For storing msg assembler data */ + BuddyCtx *buddy; /* For storing msg assembler data */ - Arena *cmd_arena; - N_Cmd *first_cmd; - N_Cmd *last_cmd; - N_Cmd *first_free_cmd; + Arena *cmd_arena; + N_Cmd *first_cmd; + N_Cmd *last_cmd; + N_Cmd *first_free_cmd; - Arena *channel_arena; - N_Channel *channels; - N_Channel *first_free_channel; - u64 num_channels_reserved; + Arena *channel_arena; + N_Channel *channels; + N_Channel *first_free_channel; + u64 num_channels_reserved; - N_SndPacket *first_free_packet; /* Acquired in `arena` */ - N_MsgAssembler *first_free_msg_assembler; /* Acquired in `arena` */ + N_SndPacket *first_free_packet; /* Acquired in `arena` */ + N_MsgAssembler *first_free_msg_assembler; /* Acquired in `arena` */ - N_ChannelLookupBin *channel_lookup_bins; /* Acquired in `arena` */ - u64 num_channel_lookup_bins; + N_ChannelLookupBin *channel_lookup_bins; /* Acquired in `arena` */ + u64 num_channel_lookup_bins; - N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; /* Acquired in `arena` */ - u64 num_msg_assembler_lookup_bins; + N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; /* Acquired in `arena` */ + u64 num_msg_assembler_lookup_bins; - /* Double buffer for incoming data */ - Mutex rcv_buffer_write_mutex; - N_RcvBuffer *rcv_buffer_read; - N_RcvBuffer *rcv_buffer_write; + /* Double buffer for incoming data */ + Mutex rcv_buffer_write_mutex; + N_RcvBuffer *rcv_buffer_read; + N_RcvBuffer *rcv_buffer_write; - u64 bytes_received; - u64 bytes_sent; + u64 bytes_received; + u64 bytes_sent; }; //////////////////////////////////////////////////////////// diff --git a/src/platform/platform.h b/src/platform/platform.h index 380f791f..1558bb30 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -9,22 +9,22 @@ Struct(P_Sock); Struct(P_File) { - u64 handle; - b32 valid; + u64 handle; + b32 valid; }; Struct(P_FileTime) { - DateTime created; - DateTime accessed; - DateTime modified; + DateTime created; + DateTime accessed; + DateTime modified; }; Struct(P_FileMap) { - String mapped_memory; - u64 handle; - b32 valid; + String mapped_memory; + u64 handle; + b32 valid; }; //////////////////////////////////////////////////////////// @@ -32,17 +32,17 @@ Struct(P_FileMap) Enum(P_AddressFamily) { - P_AddressFamily_Ipv4, - P_AddressFamily_Ipv6 + P_AddressFamily_Ipv4, + P_AddressFamily_Ipv6 }; Struct(P_Address) { - b32 valid; - P_AddressFamily family; - /* NOTE: ipnb & portnb are stored in network byte order */ - u8 ipnb[16]; - u16 portnb; + b32 valid; + P_AddressFamily family; + /* NOTE: ipnb & portnb are stored in network byte order */ + u8 ipnb[16]; + u16 portnb; }; //////////////////////////////////////////////////////////// @@ -50,9 +50,9 @@ Struct(P_Address) Struct(P_SockReadResult) { - b32 valid; /* Since data.len = 0 can be valid */ - P_Address address; - String data; + b32 valid; /* Since data.len = 0 can be valid */ + P_Address address; + String data; }; //////////////////////////////////////////////////////////// @@ -60,10 +60,10 @@ Struct(P_SockReadResult) Enum(P_MessageBoxKind) { - P_MessageBoxKind_Ok, - P_MessageBoxKind_Warning, - P_MessageBoxKind_Error, - P_MessageBoxKind_Fatal + P_MessageBoxKind_Ok, + P_MessageBoxKind_Warning, + P_MessageBoxKind_Error, + P_MessageBoxKind_Fatal }; //////////////////////////////////////////////////////////// diff --git a/src/platform/platform_win32/platform_win32.c b/src/platform/platform_win32/platform_win32.c index ce6fdd8c..3863bafc 100644 --- a/src/platform/platform_win32/platform_win32.c +++ b/src/platform/platform_win32/platform_win32.c @@ -5,17 +5,17 @@ P_W32_SharedState P_W32_shared_state = Zi; void P_Bootstrap(void) { - P_W32_SharedState *g = &P_W32_shared_state; + P_W32_SharedState *g = &P_W32_shared_state; - //- Init watches pool - g->watches_arena = AcquireArena(Gibi(64)); + //- Init watches pool + g->watches_arena = AcquireArena(Gibi(64)); - //- Init winsock - WSAStartup(MAKEWORD(2, 2), &g->wsa_data); - g->socks_arena = AcquireArena(Gibi(64)); + //- Init winsock + WSAStartup(MAKEWORD(2, 2), &g->wsa_data); + g->socks_arena = AcquireArena(Gibi(64)); - //- Init timer - DispatchWave(Lit("Win32 timer sync"), 1, P_W32_SyncTimerForever, 0); + //- Init timer + DispatchWave(Lit("Win32 timer sync"), 1, P_W32_SyncTimerForever, 0); } //////////////////////////////////////////////////////////// @@ -23,17 +23,17 @@ void P_Bootstrap(void) DateTime P_W32_DateTimeFromWin32SystemTime(SYSTEMTIME st) { - return (DateTime) - { - .year = st.wYear, - .month = st.wMonth, - .day_of_week = st.wDayOfWeek, - .day = st.wDay, - .hour = st.wHour, - .minute = st.wMinute, - .second = st.wSecond, - .milliseconds = st.wMilliseconds - }; + return (DateTime) + { + .year = st.wYear, + .month = st.wMonth, + .day_of_week = st.wDayOfWeek, + .day = st.wDay, + .hour = st.wHour, + .minute = st.wMinute, + .second = st.wSecond, + .milliseconds = st.wMilliseconds + }; } //////////////////////////////////////////////////////////// @@ -41,31 +41,31 @@ DateTime P_W32_DateTimeFromWin32SystemTime(SYSTEMTIME st) String P_W32_StringFromWin32Path(Arena *arena, wchar_t *src) { - String result = { - .len = 0, - .text = ArenaNext(arena, u8) - }; + String result = { + .len = 0, + .text = ArenaNext(arena, u8) + }; - while (*src) + while (*src) + { + String16 decode_str = { .len = *(src + 1) ? 2 : 1, .text = src }; + Utf16DecodeResult decoded = DecodeUtf16(decode_str); + Utf8EncodeResult encoded = EncodeUtf8(decoded.codepoint); + u8 *dest = PushStructsNoZero(arena, u8, encoded.count8); + for (u32 i = 0; i < encoded.count8; ++i) { - String16 decode_str = { .len = *(src + 1) ? 2 : 1, .text = src }; - Utf16DecodeResult decoded = DecodeUtf16(decode_str); - Utf8EncodeResult encoded = EncodeUtf8(decoded.codepoint); - u8 *dest = PushStructsNoZero(arena, u8, encoded.count8); - for (u32 i = 0; i < encoded.count8; ++i) - { - u8 byte = encoded.chars8[i]; - if (byte == '\\') - { - byte = '/'; - } - dest[i] = byte; - } - result.len += encoded.count8; - src += decoded.advance16; + u8 byte = encoded.chars8[i]; + if (byte == '\\') + { + byte = '/'; + } + dest[i] = byte; } + result.len += encoded.count8; + src += decoded.advance16; + } - return result; + return result; } //////////////////////////////////////////////////////////// @@ -73,85 +73,85 @@ String P_W32_StringFromWin32Path(Arena *arena, wchar_t *src) P_W32_Address P_W32_Win32AddressFromPlatformAddress(P_Address addr) { - P_W32_Address result = Zi; - if (addr.family == P_AddressFamily_Ipv4) - { - result.family = AF_INET; - result.size = sizeof(struct sockaddr_in); - result.sin.sin_port = addr.portnb; - result.sin.sin_family = result.family; - CopyBytes(&result.sin.sin_addr, addr.ipnb, 4); - } - else - { - result.family = AF_INET6; - result.sin6.sin6_port = addr.portnb; - result.sin6.sin6_family = result.family; - result.size = sizeof(struct sockaddr_in6); - CopyBytes(&result.sin6.sin6_addr.s6_addr, addr.ipnb, 16); - } - return result; + P_W32_Address result = Zi; + if (addr.family == P_AddressFamily_Ipv4) + { + result.family = AF_INET; + result.size = sizeof(struct sockaddr_in); + result.sin.sin_port = addr.portnb; + result.sin.sin_family = result.family; + CopyBytes(&result.sin.sin_addr, addr.ipnb, 4); + } + else + { + result.family = AF_INET6; + result.sin6.sin6_port = addr.portnb; + result.sin6.sin6_family = result.family; + result.size = sizeof(struct sockaddr_in6); + CopyBytes(&result.sin6.sin6_addr.s6_addr, addr.ipnb, 16); + } + return result; } /* If supplied address has ip INADDR_ANY (0), convert ip to localhost */ P_W32_Address P_W32_ConvertAnyaddrToLocalhost(P_W32_Address addr) { - if (addr.family == AF_INET) + if (addr.family == AF_INET) + { + u8 *bytes = (u8 *)&addr.sin.sin_addr; + b32 is_any = 1; + for (u64 i = 0; i < 4; ++i) { - u8 *bytes = (u8 *)&addr.sin.sin_addr; - b32 is_any = 1; - for (u64 i = 0; i < 4; ++i) - { - if (bytes[i] != 0) - { - is_any = 0; - break; - } - } - if (is_any) - { - bytes[0] = 127; - bytes[3] = 1; - } + if (bytes[i] != 0) + { + is_any = 0; + break; + } } - else if (addr.family == AF_INET6) + if (is_any) { - u8 *bytes = (u8 *)&addr.sin.sin_addr; - b32 is_any = 1; - for (u64 i = 0; i < 16; ++i) - { - if (bytes[i] != 0) - { - is_any = 0; - break; - } - } - if (is_any) - { - bytes[15] = 1; - } + bytes[0] = 127; + bytes[3] = 1; } - return addr; + } + else if (addr.family == AF_INET6) + { + u8 *bytes = (u8 *)&addr.sin.sin_addr; + b32 is_any = 1; + for (u64 i = 0; i < 16; ++i) + { + if (bytes[i] != 0) + { + is_any = 0; + break; + } + } + if (is_any) + { + bytes[15] = 1; + } + } + return addr; } P_Address P_W32_PlatformAddressFromWin32Address(P_W32_Address ws_addr) { - P_Address result = Zi; - if (ws_addr.family == AF_INET) - { - result.family = P_AddressFamily_Ipv4; - result.portnb = ws_addr.sin.sin_port; - CopyBytes(result.ipnb, &ws_addr.sin.sin_addr, 4); - result.valid = 1; - } - else if (ws_addr.family == AF_INET6) - { - result.family = P_AddressFamily_Ipv6; - result.portnb = ws_addr.sin6.sin6_port; - CopyBytes(result.ipnb, &ws_addr.sin6.sin6_addr.s6_addr, 16); - result.valid = 1; - } - return result; + P_Address result = Zi; + if (ws_addr.family == AF_INET) + { + result.family = P_AddressFamily_Ipv4; + result.portnb = ws_addr.sin.sin_port; + CopyBytes(result.ipnb, &ws_addr.sin.sin_addr, 4); + result.valid = 1; + } + else if (ws_addr.family == AF_INET6) + { + result.family = P_AddressFamily_Ipv6; + result.portnb = ws_addr.sin6.sin6_port; + CopyBytes(result.ipnb, &ws_addr.sin6.sin6_addr.s6_addr, 16); + result.valid = 1; + } + return result; } //////////////////////////////////////////////////////////// @@ -159,61 +159,61 @@ P_Address P_W32_PlatformAddressFromWin32Address(P_W32_Address ws_addr) void P_W32_SyncTimerForever(WaveLaneCtx *lane) { - P_W32_SharedState *g = &P_W32_shared_state; - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + P_W32_SharedState *g = &P_W32_shared_state; + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - /* Create high resolution timer */ - HANDLE timer = CreateWaitableTimerExW(0, 0, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); - if (!timer) + /* Create high resolution timer */ + HANDLE timer = CreateWaitableTimerExW(0, 0, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); + if (!timer) + { + Panic(Lit("Failed to create high resolution timer")); + } + + i32 periods_index = 0; + i64 periods[P_W32_NumRollingTimerPeriods] = Zi; + for (i32 i = 0; i < (i32)countof(periods); ++i) + { + periods[i] = P_W32_DefaultTimerPeriodNs; + } + + i64 last_cycle_ns = 0; + /* FIXME: shutdown */ + for (;;) + { { - Panic(Lit("Failed to create high resolution timer")); + /* TODO: Minimum timer frequency in case timers ever become ultra precise in the future */ + LARGE_INTEGER due = Zi; + due.QuadPart = -1; + //due.QuadPart = -10000; + //due.QuadPart = -32000; + //due.QuadPart = -12000; + //due.QuadPart = -8000; + SetWaitableTimerEx(timer, &due, 0, 0, 0, 0, 0); + WaitForSingleObject(timer, INFINITE); + } + i64 now_ns = TimeNs(); + i64 period_ns = last_cycle_ns == 0 ? P_W32_DefaultTimerPeriodNs : now_ns - last_cycle_ns; + last_cycle_ns = now_ns; + + /* Compute mean period */ + { + periods[periods_index++] = period_ns; + if (periods_index == countof(periods)) + { + periods_index = 0; + } + f64 periods_sum_ns = 0; + for (i32 i = 0; i < (i32)countof(periods); ++i) + { + periods_sum_ns += (f64)periods[i]; + } + f64 mean_ns = periods_sum_ns / (f64)countof(periods); + Atomic64Set(&g->average_timer_period_ns.v, RoundF64ToI64(mean_ns)); } - i32 periods_index = 0; - i64 periods[P_W32_NumRollingTimerPeriods] = Zi; - for (i32 i = 0; i < (i32)countof(periods); ++i) - { - periods[i] = P_W32_DefaultTimerPeriodNs; - } - - i64 last_cycle_ns = 0; - /* FIXME: shutdown */ - for (;;) - { - { - /* TODO: Minimum timer frequency in case timers ever become ultra precise in the future */ - LARGE_INTEGER due = Zi; - due.QuadPart = -1; - //due.QuadPart = -10000; - //due.QuadPart = -32000; - //due.QuadPart = -12000; - //due.QuadPart = -8000; - SetWaitableTimerEx(timer, &due, 0, 0, 0, 0, 0); - WaitForSingleObject(timer, INFINITE); - } - i64 now_ns = TimeNs(); - i64 period_ns = last_cycle_ns == 0 ? P_W32_DefaultTimerPeriodNs : now_ns - last_cycle_ns; - last_cycle_ns = now_ns; - - /* Compute mean period */ - { - periods[periods_index++] = period_ns; - if (periods_index == countof(periods)) - { - periods_index = 0; - } - f64 periods_sum_ns = 0; - for (i32 i = 0; i < (i32)countof(periods); ++i) - { - periods_sum_ns += (f64)periods[i]; - } - f64 mean_ns = periods_sum_ns / (f64)countof(periods); - Atomic64Set(&g->average_timer_period_ns.v, RoundF64ToI64(mean_ns)); - } - - /* Update fence */ - SetFence(&g->timer_fence, now_ns); - } + /* Update fence */ + SetFence(&g->timer_fence, now_ns); + } } //////////////////////////////////////////////////////////// @@ -222,282 +222,284 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane) //- File system helpers String P_GetWritePath(Arena *arena) { - u16 *p = 0; - /* TODO: cache this? */ - HRESULT result = SHGetKnownFolderPath( - &FOLDERID_LocalAppData, - 0, - 0, - &p - ); - String path = Zi; - if (result == S_OK) - { - path = P_W32_StringFromWin32Path(arena, p); - } - CoTaskMemFree(p); - return path; + u16 *p = 0; + /* TODO: cache this? */ + HRESULT result = SHGetKnownFolderPath( + &FOLDERID_LocalAppData, + 0, + 0, + &p + ); + String path = Zi; + if (result == S_OK) + { + path = P_W32_StringFromWin32Path(arena, p); + } + CoTaskMemFree(p); + return path; } b32 P_IsFile(String path) { - TempArena scratch = BeginScratchNoConflict(); - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - DWORD attributes = GetFileAttributesW(path_wstr); - EndScratch(scratch); - return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY); + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + DWORD attributes = GetFileAttributesW(path_wstr); + EndScratch(scratch); + return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY); } b32 P_IsDir(String path) { - TempArena scratch = BeginScratchNoConflict(); - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - DWORD attributes = GetFileAttributesW(path_wstr); - EndScratch(scratch); - return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY); + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + DWORD attributes = GetFileAttributesW(path_wstr); + EndScratch(scratch); + return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY); } void P_MkDir(String path) { - TempArena scratch = BeginScratchNoConflict(); - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - int err_code = SHCreateDirectory(0, path_wstr); - String err = Zi; - switch (err_code) + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + int err_code = SHCreateDirectory(0, path_wstr); + String err = Zi; + switch (err_code) + { + default: break; + + case ERROR_BAD_PATHNAME: { - default: break; + err = Lit("Bad path name"); + } break; - case ERROR_BAD_PATHNAME: - { - err = Lit("Bad path name"); - } break; - - case ERROR_FILENAME_EXCED_RANGE: - { - err = Lit("Path name too long"); - } break; - - case ERROR_FILE_EXISTS: - { - err = Lit("A file already exists at this location"); - } break; - - case ERROR_CANCELLED: - { - err = Lit("User canceled the operation"); - } break; - } - if (err.len > 0) + case ERROR_FILENAME_EXCED_RANGE: { - String msg = StringF( - scratch.arena, - "Failed to create directory \"%F\": %F", - FmtString(path), - FmtString(err) - ); - Panic(msg); - } - EndScratch(scratch); + err = Lit("Path name too long"); + } break; + + case ERROR_FILE_EXISTS: + { + err = Lit("A file already exists at this location"); + } break; + + case ERROR_CANCELLED: + { + err = Lit("User canceled the operation"); + } break; + } + if (err.len > 0) + { + String msg = StringF( + scratch.arena, + "Failed to create directory \"%F\": %F", + FmtString(path), + FmtString(err) + ); + Panic(msg); + } + EndScratch(scratch); } //- File creation P_File P_OpenFileRead(String path) { - TempArena scratch = BeginScratchNoConflict(); - P_File file = Zi; + TempArena scratch = BeginScratchNoConflict(); + P_File file = Zi; - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - HANDLE handle = CreateFileW( - path_wstr, - GENERIC_READ, - FILE_SHARE_READ, - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0 - ); - file.handle = (u64)handle; - file.valid = handle != INVALID_HANDLE_VALUE; + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + HANDLE handle = CreateFileW( + path_wstr, + GENERIC_READ, + FILE_SHARE_READ, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0 + ); + file.handle = (u64)handle; + file.valid = handle != INVALID_HANDLE_VALUE; - EndScratch(scratch); - return file; + EndScratch(scratch); + return file; } P_File P_OpenFileReadWait(String path) { - TempArena scratch = BeginScratchNoConflict(); - P_File file = Zi; + TempArena scratch = BeginScratchNoConflict(); + P_File file = Zi; - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - i32 delay_ms = 1; - HANDLE handle; - while ((handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + i32 delay_ms = 1; + HANDLE handle; + while ((handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) + { + if (GetLastError() == ERROR_SHARING_VIOLATION) { - if (GetLastError() == ERROR_SHARING_VIOLATION) - { - Sleep(delay_ms); - if (delay_ms < 1024) - { - delay_ms *= 2; - } - } - else - { - break; - } + Sleep(delay_ms); + if (delay_ms < 1024) + { + delay_ms *= 2; + } } - file.handle = (u64)handle; - file.valid = handle != INVALID_HANDLE_VALUE; + else + { + break; + } + } + file.handle = (u64)handle; + file.valid = handle != INVALID_HANDLE_VALUE; - EndScratch(scratch); - return file; + EndScratch(scratch); + return file; } P_File P_OpenFileWrite(String path) { - TempArena scratch = BeginScratchNoConflict(); - P_File file = Zi; + TempArena scratch = BeginScratchNoConflict(); + P_File file = Zi; - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - HANDLE handle = CreateFileW( - path_wstr, - GENERIC_WRITE, - 0, - 0, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - 0 - ); - file.handle = (u64)handle; - file.valid = handle != INVALID_HANDLE_VALUE; + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + HANDLE handle = CreateFileW( + path_wstr, + GENERIC_WRITE, + 0, + 0, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + 0 + ); + file.handle = (u64)handle; + file.valid = handle != INVALID_HANDLE_VALUE; - EndScratch(scratch); - return file; + EndScratch(scratch); + return file; } P_File P_OpenFileAppend(String path) { - TempArena scratch = BeginScratchNoConflict(); - P_File file = Zi; + TempArena scratch = BeginScratchNoConflict(); + P_File file = Zi; - wchar_t *path_wstr = WstrFromString(scratch.arena, path); - HANDLE handle = CreateFileW( - path_wstr, - FILE_APPEND_DATA, - FILE_SHARE_READ, - 0, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - 0 - ); - file.handle = (u64)handle; - file.valid = handle != INVALID_HANDLE_VALUE; + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + HANDLE handle = CreateFileW( + path_wstr, + FILE_APPEND_DATA, + FILE_SHARE_READ, + 0, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + 0 + ); + file.handle = (u64)handle; + file.valid = handle != INVALID_HANDLE_VALUE; - EndScratch(scratch); - return file; + EndScratch(scratch); + return file; } void P_CloseFile(P_File file) { - if (file.handle) - { - CloseHandle((HANDLE)file.handle); - } + if (file.handle) + { + CloseHandle((HANDLE)file.handle); + } } //- File data manipulation String P_ReadFile(Arena *arena, P_File file) { - i64 size = 0; - GetFileSizeEx((HANDLE)file.handle, (PLARGE_INTEGER)&size); + i64 size = 0; + GetFileSizeEx((HANDLE)file.handle, (PLARGE_INTEGER)&size); - String s = { - .len = size, - .text = 0 - }; + String s = { + .len = size, + .text = 0 + }; - if (size > 0) - { - /* ReadFile returns non-zero on success */ - /* TODO: error checking */ - PushAlign(arena, CachelineSize); - s.text = PushStructsNoZero(arena, u8, size); - ReadFile( - (HANDLE)file.handle, - s.text, - (DWORD)s.len, - 0, /* lpNumberOfBytesRead */ - 0 - ); - } + if (size > 0) + { + /* ReadFile returns non-zero on success */ + /* TODO: error checking */ + PushAlign(arena, CachelineSize); + s.text = PushStructsNoZero(arena, u8, size); + ReadFile( + (HANDLE)file.handle, + s.text, + (DWORD)s.len, + 0, /* lpNumberOfBytesRead */ + 0 + ); + } - return s; + return s; } void P_WriteFile(P_File file, String data) { - /* TODO: Check what the real data limit is and chunk sequentially based on - * that (rather than failing) */ - if (data.len >= 0x7FFF) - { - TempArena scratch = BeginScratchNoConflict(); - Panic(StringF(scratch.arena, - "Tried to write too many bytes to disk (%F)", - FmtUint(data.len))); - EndScratch(scratch); - } + /* TODO: Check what the real data limit is and chunk sequentially based on + * that (rather than failing) */ + if (data.len >= 0x7FFF) + { + TempArena scratch = BeginScratchNoConflict(); + Panic(StringF( + scratch.arena, + "Tried to write too many bytes to disk (%F)", + FmtUint(data.len) + )); + EndScratch(scratch); + } - /* WriteFile returns TRUE on success */ - WriteFile( - (HANDLE)file.handle, - data.text, - (DWORD)data.len, - 0, /* lpNumberOfBytesWritten */ - 0 - ); + /* WriteFile returns TRUE on success */ + WriteFile( + (HANDLE)file.handle, + data.text, + (DWORD)data.len, + 0, /* lpNumberOfBytesWritten */ + 0 + ); } //- File info u64 P_GetFileSize(P_File file) { - LARGE_INTEGER li_file_size; - GetFileSizeEx((HANDLE)file.handle, &li_file_size); - return (u64)(li_file_size.QuadPart > 0 ? li_file_size.QuadPart : 0); + LARGE_INTEGER li_file_size; + GetFileSizeEx((HANDLE)file.handle, &li_file_size); + return (u64)(li_file_size.QuadPart > 0 ? li_file_size.QuadPart : 0); } P_FileTime P_GetFileTime(P_File file) { - /* Get file times */ - FILETIME ft_created; - FILETIME ft_accessed; - FILETIME ft_modified; - b32 ok = !!GetFileTime((HANDLE)file.handle, &ft_created, &ft_accessed, &ft_modified); - if (ok) - { - /* Convert file times to local file time */ - FileTimeToLocalFileTime(&ft_created, &ft_created); - FileTimeToLocalFileTime(&ft_accessed, &ft_accessed); - FileTimeToLocalFileTime(&ft_modified, &ft_modified); + /* Get file times */ + FILETIME ft_created; + FILETIME ft_accessed; + FILETIME ft_modified; + b32 ok = !!GetFileTime((HANDLE)file.handle, &ft_created, &ft_accessed, &ft_modified); + if (ok) + { + /* Convert file times to local file time */ + FileTimeToLocalFileTime(&ft_created, &ft_created); + FileTimeToLocalFileTime(&ft_accessed, &ft_accessed); + FileTimeToLocalFileTime(&ft_modified, &ft_modified); - /* Convert local file times to system times */ - SYSTEMTIME st_created; - SYSTEMTIME st_accessed; - SYSTEMTIME st_modified; - FileTimeToSystemTime(&ft_created, &st_created); - FileTimeToSystemTime(&ft_accessed, &st_accessed); - FileTimeToSystemTime(&ft_modified, &st_modified); + /* Convert local file times to system times */ + SYSTEMTIME st_created; + SYSTEMTIME st_accessed; + SYSTEMTIME st_modified; + FileTimeToSystemTime(&ft_created, &st_created); + FileTimeToSystemTime(&ft_accessed, &st_accessed); + FileTimeToSystemTime(&ft_modified, &st_modified); - return (P_FileTime) - { - .created = P_W32_DateTimeFromWin32SystemTime(st_created), - .accessed = P_W32_DateTimeFromWin32SystemTime(st_accessed), - .modified = P_W32_DateTimeFromWin32SystemTime(st_modified) - }; - } - else + return (P_FileTime) { - return (P_FileTime) { 0 }; - } + .created = P_W32_DateTimeFromWin32SystemTime(st_created), + .accessed = P_W32_DateTimeFromWin32SystemTime(st_accessed), + .modified = P_W32_DateTimeFromWin32SystemTime(st_modified) + }; + } + else + { + return (P_FileTime) { 0 }; + } } //////////////////////////////////////////////////////////// @@ -505,66 +507,66 @@ P_FileTime P_GetFileTime(P_File file) P_FileMap P_OpenFileMap(P_File file) { - P_FileMap map = Zi; + P_FileMap map = Zi; - u64 size = P_GetFileSize(file); - u8 *base_ptr = 0; - HANDLE map_handle = 0; + u64 size = P_GetFileSize(file); + u8 *base_ptr = 0; + HANDLE map_handle = 0; - if (size > 0) + if (size > 0) + { + map_handle = CreateFileMappingW( + (HANDLE)file.handle, + 0, + PAGE_READONLY, + 0, + 0, + 0 + ); + if (map_handle != INVALID_HANDLE_VALUE) { - map_handle = CreateFileMappingW( - (HANDLE)file.handle, - 0, - PAGE_READONLY, - 0, - 0, - 0 - ); - if (map_handle != INVALID_HANDLE_VALUE) - { - base_ptr = MapViewOfFile( - map_handle, - FILE_MAP_READ, - 0, - 0, - 0 - ); - if (base_ptr == 0) - { - /* Failed to create view */ - CloseHandle(map_handle); - map_handle = INVALID_HANDLE_VALUE; - } - } + base_ptr = MapViewOfFile( + map_handle, + FILE_MAP_READ, + 0, + 0, + 0 + ); + if (base_ptr == 0) + { + /* Failed to create view */ + CloseHandle(map_handle); + map_handle = INVALID_HANDLE_VALUE; + } } - if (map_handle == INVALID_HANDLE_VALUE) - { - size = 0; - } - map.handle = (u64)map_handle; - map.mapped_memory = STRING(size, base_ptr); - map.valid = map_handle != INVALID_HANDLE_VALUE && base_ptr != 0; + } + if (map_handle == INVALID_HANDLE_VALUE) + { + size = 0; + } + map.handle = (u64)map_handle; + map.mapped_memory = STRING(size, base_ptr); + map.valid = map_handle != INVALID_HANDLE_VALUE && base_ptr != 0; - return map; + return map; } void P_CloseFileMap(P_FileMap map) { - if (map.mapped_memory.text) - { - UnmapViewOfFile(map.mapped_memory.text); - } - if (map.handle) - { - CloseHandle((HANDLE)map.handle); - } + if (map.mapped_memory.text) + { + UnmapViewOfFile(map.mapped_memory.text); + } + if (map.handle) + { + CloseHandle((HANDLE)map.handle); + } } String P_GetFileMapData(P_FileMap map) { - return map.mapped_memory; + return map.mapped_memory; } //////////////////////////////////////////////////////////// @@ -572,201 +574,199 @@ String P_GetFileMapData(P_FileMap map) P_Address P_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr) { - P_Address result = Zi; + P_Address result = Zi; - struct addrinfo hints = Zi; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE; + struct addrinfo hints = Zi; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; - struct addrinfo *ai_result = 0; - i32 status = getaddrinfo(ip_cstr, port_cstr, &hints, &ai_result); - if (status == 0) + struct addrinfo *ai_result = 0; + i32 status = getaddrinfo(ip_cstr, port_cstr, &hints, &ai_result); + if (status == 0) + { + while (ai_result) { - while (ai_result) - { - if (ai_result->ai_family == AF_INET) - { - struct sockaddr_in *sockaddr = (struct sockaddr_in *)ai_result->ai_addr; - result.valid = 1; - result.family = P_AddressFamily_Ipv4; - result.portnb = sockaddr->sin_port; - StaticAssert(sizeof(sockaddr->sin_addr) == 4); - CopyBytes(result.ipnb, (void *)&sockaddr->sin_addr, 4); - break; - } - else if (ai_result->ai_family == AF_INET6) - { - /* TODO: Enable ipv6 */ -#if 0 - struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_result->ai_addr; - result.valid = 1; - result.family = P_AddressFamily_Ipv6; - result.portnb = sockaddr->sin6_port; - StaticAssert(sizeof(sockaddr->sin6_addr) == 16); - CopyBytes(result.ipnb, (void *)&sockaddr->sin6_addr, 16); - break; -#endif - } - ai_result = ai_result->ai_next; - } - freeaddrinfo(ai_result); + if (ai_result->ai_family == AF_INET) + { + struct sockaddr_in *sockaddr = (struct sockaddr_in *)ai_result->ai_addr; + result.valid = 1; + result.family = P_AddressFamily_Ipv4; + result.portnb = sockaddr->sin_port; + StaticAssert(sizeof(sockaddr->sin_addr) == 4); + CopyBytes(result.ipnb, (void *)&sockaddr->sin_addr, 4); + break; + } + else if (ai_result->ai_family == AF_INET6) + { + /* TODO: Enable ipv6 */ + // struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_result->ai_addr; + // result.valid = 1; + // result.family = P_AddressFamily_Ipv6; + // result.portnb = sockaddr->sin6_port; + // StaticAssert(sizeof(sockaddr->sin6_addr) == 16); + // CopyBytes(result.ipnb, (void *)&sockaddr->sin6_addr, 16); + // break; + } + ai_result = ai_result->ai_next; } + freeaddrinfo(ai_result); + } - return result; + return result; } P_Address P_AddressFromString(String str) { - /* Parse string into ip & port */ - u8 ip_buff[1024]; - u8 port_buff[countof(ip_buff)]; - char *ip_cstr = 0; - char *port_cstr = 0; + /* Parse string into ip & port */ + u8 ip_buff[1024]; + u8 port_buff[countof(ip_buff)]; + char *ip_cstr = 0; + char *port_cstr = 0; + { + u64 colon_count = 0; + for (u64 i = 0; i < str.len; ++i) { - u64 colon_count = 0; - for (u64 i = 0; i < str.len; ++i) + u8 c = str.text[i]; + if (c == ':') + { + ++colon_count; + } + } + u64 ip_len = 0; + u64 port_len = 0; + u64 parse_len = MinU64(MinU64(str.len, countof(ip_buff) - 1), countof(port_buff) - 1); + if (colon_count > 1 && str.text[0] == '[') + { + /* Parse ipv6 with port */ + b32 parse_addr = 1; + for (u64 i = 1; i < parse_len; ++i) + { + u8 c = str.text[i]; + if (parse_addr) { - u8 c = str.text[i]; - if (c == ':') - { - ++colon_count; - } + if (c == ']') + { + parse_addr = 0; + } + else + { + ip_buff[ip_len] = c; + ++ip_len; + } } - u64 ip_len = 0; - u64 port_len = 0; - u64 parse_len = MinU64(MinU64(str.len, countof(ip_buff) - 1), countof(port_buff) - 1); - if (colon_count > 1 && str.text[0] == '[') + else if (c != ':') { - /* Parse ipv6 with port */ - b32 parse_addr = 1; - for (u64 i = 1; i < parse_len; ++i) - { - u8 c = str.text[i]; - if (parse_addr) - { - if (c == ']') - { - parse_addr = 0; - } - else - { - ip_buff[ip_len] = c; - ++ip_len; - } - } - else if (c != ':') - { - port_buff[port_len] = c; - ++port_len; - } - } + port_buff[port_len] = c; + ++port_len; } - else if (colon_count == 1) + } + } + else if (colon_count == 1) + { + /* Parse address with port */ + b32 parse_addr = 1; + for (u64 i = 0; i < parse_len; ++i) + { + u8 c = str.text[i]; + if (parse_addr) { - /* Parse address with port */ - b32 parse_addr = 1; - for (u64 i = 0; i < parse_len; ++i) - { - u8 c = str.text[i]; - if (parse_addr) - { - if (c == ':') - { - parse_addr = 0; - } - else - { - ip_buff[ip_len] = c; - ++ip_len; - } - } - else - { - port_buff[port_len] = c; - ++port_len; - } - } + if (c == ':') + { + parse_addr = 0; + } + else + { + ip_buff[ip_len] = c; + ++ip_len; + } } else { - /* Copy address without port */ - ip_len = MinU64(str.len, countof(ip_buff) - 1); - CopyBytes(ip_buff, str.text, ip_len); - } - if (ip_len > 0) - { - ip_buff[ip_len] = 0; - ip_cstr = (char *)ip_buff; - } - if (port_len > 0) - { - port_buff[port_len] = 0; - port_cstr = (char *)port_buff; - + port_buff[port_len] = c; + ++port_len; } + } } + else + { + /* Copy address without port */ + ip_len = MinU64(str.len, countof(ip_buff) - 1); + CopyBytes(ip_buff, str.text, ip_len); + } + if (ip_len > 0) + { + ip_buff[ip_len] = 0; + ip_cstr = (char *)ip_buff; + } + if (port_len > 0) + { + port_buff[port_len] = 0; + port_cstr = (char *)port_buff; - P_Address result = P_AddressFromIpPortCstr(ip_cstr, port_cstr); - return result; + } + } + + P_Address result = P_AddressFromIpPortCstr(ip_cstr, port_cstr); + return result; } P_Address P_AddressFromPort(u16 port) { - u8 port_buff[128]; - char *port_cstr = 0; + u8 port_buff[128]; + char *port_cstr = 0; + { + u8 port_buff_reverse[countof(port_buff)]; + u64 port_len = 0; + while (port > 0 && port_len < (countof(port_buff) - 1)) { - u8 port_buff_reverse[countof(port_buff)]; - u64 port_len = 0; - while (port > 0 && port_len < (countof(port_buff) - 1)) - { - u8 digit = port % 10; - port /= 10; - port_buff_reverse[port_len] = '0' + digit; - ++port_len; - } - for (u64 i = 0; i < port_len; ++i) - { - u64 j = port_len - 1 - i; - port_buff[i] = port_buff_reverse[j]; - } - if (port_len > 0) - { - port_buff[port_len] = 0; - port_cstr = (char *)port_buff; - } + u8 digit = port % 10; + port /= 10; + port_buff_reverse[port_len] = '0' + digit; + ++port_len; } + for (u64 i = 0; i < port_len; ++i) + { + u64 j = port_len - 1 - i; + port_buff[i] = port_buff_reverse[j]; + } + if (port_len > 0) + { + port_buff[port_len] = 0; + port_cstr = (char *)port_buff; + } + } - P_Address result = P_AddressFromIpPortCstr(0, port_cstr); + P_Address result = P_AddressFromIpPortCstr(0, port_cstr); - return result; + return result; } String P_StringFromAddress(Arena *arena, P_Address address) { - String result = Zi; + String result = Zi; - if (address.family == P_AddressFamily_Ipv6) + if (address.family == P_AddressFamily_Ipv6) + { + /* TODO */ + } + else + { + u8 ip[4]; + for (u32 i = 0; i < 4; ++i) { - /* TODO */ - } - else - { - u8 ip[4]; - for (u32 i = 0; i < 4; ++i) - { - ip[i] = ntohs(address.ipnb[i]); - } - u16 port = ntohs(address.portnb); - result = StringF(arena, "%F.%F.%F.%F:%F", FmtUint(ip[0]), FmtUint(ip[1]), FmtUint(ip[2]), FmtUint(ip[3]), FmtUint(port)); + ip[i] = ntohs(address.ipnb[i]); } + u16 port = ntohs(address.portnb); + result = StringF(arena, "%F.%F.%F.%F:%F", FmtUint(ip[0]), FmtUint(ip[1]), FmtUint(ip[2]), FmtUint(ip[3]), FmtUint(port)); + } - return result; + return result; } b32 P_MatchAddress(P_Address a, P_Address b) { - return MatchStruct(&a, &b); + return MatchStruct(&a, &b); } //////////////////////////////////////////////////////////// @@ -774,110 +774,112 @@ b32 P_MatchAddress(P_Address a, P_Address b) P_Sock *P_AcquireSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size) { - P_W32_SharedState *g = &P_W32_shared_state; - P_W32_Sock *ws = 0; + P_W32_SharedState *g = &P_W32_shared_state; + P_W32_Sock *ws = 0; + { + Lock lock = LockE(&g->socks_mutex); + if (g->first_free_sock) { - Lock lock = LockE(&g->socks_mutex); - if (g->first_free_sock) - { - ws = g->first_free_sock; - g->first_free_sock = ws->next_free; - } - else - { - ws = PushStructNoZero(g->socks_arena, P_W32_Sock); - } - Unlock(&lock); + ws = g->first_free_sock; + g->first_free_sock = ws->next_free; } - ZeroStruct(ws); - - P_Address addr = P_AddressFromPort(listen_port); - P_W32_Address bind_address = P_W32_Win32AddressFromPlatformAddress(addr); - ws->sock = socket(bind_address.family, SOCK_DGRAM, IPPROTO_UDP); + else { - i32 sb = sndbuf_size; - i32 rb = rcvbuf_size; - u32 imode = 1; - setsockopt(ws->sock, SOL_SOCKET, SO_SNDBUF, (char *)&sb, sizeof(sb)); - setsockopt(ws->sock, SOL_SOCKET, SO_RCVBUF, (char *)&rb, sizeof(rb)); - ioctlsocket(ws->sock, FIONBIO, (unsigned long *)&imode); + ws = PushStructNoZero(g->socks_arena, P_W32_Sock); } - bind(ws->sock, &bind_address.sa, bind_address.size); + Unlock(&lock); + } + ZeroStruct(ws); - return (P_Sock *)ws; + P_Address addr = P_AddressFromPort(listen_port); + P_W32_Address bind_address = P_W32_Win32AddressFromPlatformAddress(addr); + ws->sock = socket(bind_address.family, SOCK_DGRAM, IPPROTO_UDP); + { + i32 sb = sndbuf_size; + i32 rb = rcvbuf_size; + u32 imode = 1; + setsockopt(ws->sock, SOL_SOCKET, SO_SNDBUF, (char *)&sb, sizeof(sb)); + setsockopt(ws->sock, SOL_SOCKET, SO_RCVBUF, (char *)&rb, sizeof(rb)); + ioctlsocket(ws->sock, FIONBIO, (unsigned long *)&imode); + } + bind(ws->sock, &bind_address.sa, bind_address.size); + + return (P_Sock *)ws; } void P_ReleaseSock(P_Sock *sock) { - P_W32_SharedState *g = &P_W32_shared_state; - P_W32_Sock *ws = (P_W32_Sock *)sock; - closesocket(ws->sock); - Lock lock = LockE(&g->socks_mutex); - { - ws->next_free = g->first_free_sock; - g->first_free_sock = ws; - } - Unlock(&lock); + P_W32_SharedState *g = &P_W32_shared_state; + P_W32_Sock *ws = (P_W32_Sock *)sock; + closesocket(ws->sock); + Lock lock = LockE(&g->socks_mutex); + { + ws->next_free = g->first_free_sock; + g->first_free_sock = ws; + } + Unlock(&lock); } P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock) { - P_W32_Sock *ws = (P_W32_Sock *)sock; + P_W32_Sock *ws = (P_W32_Sock *)sock; - u64 read_buff_size = Kibi(64); - String read_buff = Zi; - read_buff.len = read_buff_size; - read_buff.text = PushStructsNoZero(arena, u8, read_buff_size); + u64 read_buff_size = Kibi(64); + String read_buff = Zi; + read_buff.len = read_buff_size; + read_buff.text = PushStructsNoZero(arena, u8, read_buff_size); - P_SockReadResult result = Zi; + P_SockReadResult result = Zi; - P_W32_Address ws_addr = Zi; - ws_addr.size = sizeof(ws_addr.sas); + P_W32_Address ws_addr = Zi; + ws_addr.size = sizeof(ws_addr.sas); - i32 size = recvfrom(ws->sock, (char *)read_buff.text, read_buff.len, 0, &ws_addr.sa, &ws_addr.size); - ws_addr.family = ws_addr.sin.sin_family; + i32 size = recvfrom(ws->sock, (char *)read_buff.text, read_buff.len, 0, &ws_addr.sa, &ws_addr.size); + ws_addr.family = ws_addr.sin.sin_family; - result.address = P_W32_PlatformAddressFromWin32Address(ws_addr); - if (size >= 0) + result.address = P_W32_PlatformAddressFromWin32Address(ws_addr); + if (size >= 0) + { + AddGstat(SockBytesReceived, size); + result.data.text = read_buff.text; + result.data.len = size; + result.valid = 1; + + /* PopStruct arena back to end of msg */ + PopTo(arena, arena->pos - read_buff_size + size); + } + else + { + if (IsRtcEnabled) { - AddGstat(SockBytesReceived, size); - result.data.text = read_buff.text; - result.data.len = size; - result.valid = 1; - - /* PopStruct arena back to end of msg */ - PopTo(arena, arena->pos - read_buff_size + size); - } - else - { -#if IsRtcEnabled - i32 err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK && err != WSAETIMEDOUT && err != WSAECONNRESET) - { - Assert(0); - } -#endif + i32 err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAETIMEDOUT && err != WSAECONNRESET) + { + Assert(0); + } } + } - return result; + return result; } void P_WriteSock(P_Sock *sock, P_Address address, String data) { - P_W32_Sock *ws = (P_W32_Sock *)sock; - P_W32_Address ws_addr = P_W32_Win32AddressFromPlatformAddress(address); - i32 size = sendto(ws->sock, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size); - if (size > 0) - { - AddGstat(SockBytesSent, size); - } -#if IsRtcEnabled + P_W32_Sock *ws = (P_W32_Sock *)sock; + P_W32_Address ws_addr = P_W32_Win32AddressFromPlatformAddress(address); + i32 size = sendto(ws->sock, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size); + if (size > 0) + { + AddGstat(SockBytesSent, size); + } + if (IsRtcEnabled) + { if (size != (i32)data.len) { - i32 err = WSAGetLastError(); - Assert(0); + i32 err = WSAGetLastError(); + Assert(0); } -#endif + } } //////////////////////////////////////////////////////////// @@ -885,81 +887,81 @@ void P_WriteSock(P_Sock *sock, P_Address address, String data) void P_MessageBox(P_MessageBoxKind kind, String message) { - TempArena scratch = BeginScratchNoConflict(); + TempArena scratch = BeginScratchNoConflict(); - wchar_t *message_wstr = WstrFromString(scratch.arena, message); - const wchar_t *title = L""; - UINT mbox_type = MB_SETFOREGROUND; + wchar_t *message_wstr = WstrFromString(scratch.arena, message); + const wchar_t *title = L""; + UINT mbox_type = MB_SETFOREGROUND; - switch (kind) + switch (kind) + { + case P_MessageBoxKind_Ok: { - case P_MessageBoxKind_Ok: - { - mbox_type |= MB_ICONINFORMATION; - } break; + mbox_type |= MB_ICONINFORMATION; + } break; - case P_MessageBoxKind_Warning: - { - title = L"Warning"; - mbox_type |= MB_ICONWARNING; - } break; + case P_MessageBoxKind_Warning: + { + title = L"Warning"; + mbox_type |= MB_ICONWARNING; + } break; - case P_MessageBoxKind_Error: - { - title = L"Error"; - mbox_type |= MB_ICONERROR; - } break; + case P_MessageBoxKind_Error: + { + title = L"Error"; + mbox_type |= MB_ICONERROR; + } break; - case P_MessageBoxKind_Fatal: - { - title = L"Fatal error"; - mbox_type |= MB_ICONSTOP; - } break; - } + case P_MessageBoxKind_Fatal: + { + title = L"Fatal error"; + mbox_type |= MB_ICONSTOP; + } break; + } - LogDebugF("Showing message box kind %F with text \"%F\"", FmtSint(kind), FmtString(message)); - MessageBoxExW(0, message_wstr, title, mbox_type, 0); + LogDebugF("Showing message box kind %F with text \"%F\"", FmtSint(kind), FmtString(message)); + MessageBoxExW(0, message_wstr, title, mbox_type, 0); - EndScratch(scratch); + EndScratch(scratch); } void P_SetClipboardText(String str) { - if (OpenClipboard(0)) + if (OpenClipboard(0)) + { + TempArena scratch = BeginScratchNoConflict(); + String16 str16 = String16FromString(scratch.arena, str); + u64 str16_size_bytes = str16.len * 2; + EmptyClipboard(); + HANDLE handle = GlobalAlloc(GMEM_MOVEABLE, str16_size_bytes + 1); + if (handle) { - TempArena scratch = BeginScratchNoConflict(); - String16 str16 = String16FromString(scratch.arena, str); - u64 str16_size_bytes = str16.len * 2; - EmptyClipboard(); - HANDLE handle = GlobalAlloc(GMEM_MOVEABLE, str16_size_bytes + 1); - if (handle) - { - u16 *dest_wstr = (u16 *)GlobalLock(handle); - CopyBytes(dest_wstr, str16.text, str16_size_bytes); - dest_wstr[str16.len] = 0; - GlobalUnlock(handle); - SetClipboardData(CF_UNICODETEXT, handle); - } - CloseClipboard(); - EndScratch(scratch); + u16 *dest_wstr = (u16 *)GlobalLock(handle); + CopyBytes(dest_wstr, str16.text, str16_size_bytes); + dest_wstr[str16.len] = 0; + GlobalUnlock(handle); + SetClipboardData(CF_UNICODETEXT, handle); } + CloseClipboard(); + EndScratch(scratch); + } } String P_GetClipboardText(Arena *arena) { - String result = Zi; - if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(0)) + String result = Zi; + if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(0)) + { + HANDLE handle = GetClipboardData(CF_UNICODETEXT); + if (handle) { - HANDLE handle = GetClipboardData(CF_UNICODETEXT); - if (handle) - { - u16 *src_wstr = (u16 *)GlobalLock(handle); - result = StringFromString16(arena, String16FromWstrNoLimit(src_wstr)); - GlobalUnlock(handle); - } - CloseClipboard(); + u16 *src_wstr = (u16 *)GlobalLock(handle); + result = StringFromString16(arena, String16FromWstrNoLimit(src_wstr)); + GlobalUnlock(handle); } - return result; + CloseClipboard(); + } + return result; } //////////////////////////////////////////////////////////// @@ -967,14 +969,14 @@ String P_GetClipboardText(Arena *arena) Fence *P_GetTimerFence(void) { - P_W32_SharedState *g = &P_W32_shared_state; - return &g->timer_fence; + P_W32_SharedState *g = &P_W32_shared_state; + return &g->timer_fence; } i64 P_GetCurrentTimerPeriodNs(void) { - P_W32_SharedState *g = &P_W32_shared_state; - return Atomic64Fetch(&g->average_timer_period_ns.v); + P_W32_SharedState *g = &P_W32_shared_state; + return Atomic64Fetch(&g->average_timer_period_ns.v); } //////////////////////////////////////////////////////////// @@ -982,37 +984,37 @@ i64 P_GetCurrentTimerPeriodNs(void) void P_SleepPrecise(i64 sleep_time_ns) { - i64 now_ns = TimeNs(); - i64 target_ns = now_ns + sleep_time_ns; + i64 now_ns = TimeNs(); + i64 target_ns = now_ns + sleep_time_ns; - /* Sleep on timer to conserve power */ - { - Fence *timer_fence = P_GetTimerFence(); - i64 timer_period_ns = P_GetCurrentTimerPeriodNs(); - i64 timer_tolerance_ns = timer_period_ns * 0.5; - i64 target_timer_sleep_ns = target_ns - timer_period_ns - timer_tolerance_ns; - YieldOnFence(timer_fence, target_timer_sleep_ns); - } + /* Sleep on timer to conserve power */ + { + Fence *timer_fence = P_GetTimerFence(); + i64 timer_period_ns = P_GetCurrentTimerPeriodNs(); + i64 timer_tolerance_ns = timer_period_ns * 0.5; + i64 target_timer_sleep_ns = target_ns - timer_period_ns - timer_tolerance_ns; + YieldOnFence(timer_fence, target_timer_sleep_ns); + } - /* Spin */ + /* Spin */ + now_ns = TimeNs(); + while (now_ns < target_ns) + { + _mm_pause(); now_ns = TimeNs(); - while (now_ns < target_ns) - { - _mm_pause(); - now_ns = TimeNs(); - } + } } void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns) { - if (last_frame_time_ns != 0 && target_dt_ns > 0) + if (last_frame_time_ns != 0 && target_dt_ns > 0) + { + i64 now_ns = TimeNs(); + i64 last_frame_dt_ns = now_ns - last_frame_time_ns; + i64 sleep_time_ns = target_dt_ns - last_frame_dt_ns; + if (sleep_time_ns > 0) { - i64 now_ns = TimeNs(); - i64 last_frame_dt_ns = now_ns - last_frame_time_ns; - i64 sleep_time_ns = target_dt_ns - last_frame_dt_ns; - if (sleep_time_ns > 0) - { - P_SleepPrecise(sleep_time_ns); - } + P_SleepPrecise(sleep_time_ns); } + } } diff --git a/src/platform/platform_win32/platform_win32.h b/src/platform/platform_win32/platform_win32.h index a56b3569..279cf519 100644 --- a/src/platform/platform_win32/platform_win32.h +++ b/src/platform/platform_win32/platform_win32.h @@ -2,15 +2,15 @@ //~ Win32 libs #pragma warning(push, 0) -# include -# include -# include -# include -# include -# include -# include -# include -# include + #include + #include + #include + #include + #include + #include + #include + #include + #include #pragma warning(pop) #pragma comment(lib, "kernel32") @@ -28,10 +28,10 @@ Struct(P_W32_Watch) { - HANDLE dir_handle; - HANDLE wake_handle; - P_W32_Watch *next_free; - u8 results_buff[Kibi(64)]; + HANDLE dir_handle; + HANDLE wake_handle; + P_W32_Watch *next_free; + u8 results_buff[Kibi(64)]; }; //////////////////////////////////////////////////////////// @@ -39,15 +39,15 @@ Struct(P_W32_Watch) Struct(P_W32_Address) { - i32 size; - i32 family; - union - { - struct sockaddr_storage sas; - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - }; + i32 size; + i32 family; + union + { + struct sockaddr_storage sas; + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + }; }; //////////////////////////////////////////////////////////// @@ -55,8 +55,8 @@ Struct(P_W32_Address) Struct(P_W32_Sock) { - SOCKET sock; - P_W32_Sock *next_free; + SOCKET sock; + P_W32_Sock *next_free; }; //////////////////////////////////////////////////////////// @@ -67,20 +67,20 @@ Struct(P_W32_Sock) Struct(P_W32_SharedState) { - //- Watches pool - Mutex watches_mutex; - Arena *watches_arena; - P_W32_Watch *watches_first_free; + //- Watches pool + Mutex watches_mutex; + Arena *watches_arena; + P_W32_Watch *watches_first_free; - //- Socket pool - WSADATA wsa_data; - Arena *socks_arena; - Mutex socks_mutex; - P_W32_Sock *first_free_sock; + //- Socket pool + WSADATA wsa_data; + Arena *socks_arena; + Mutex socks_mutex; + P_W32_Sock *first_free_sock; - //- Timer - Fence timer_fence; - Atomic64Padded average_timer_period_ns; + //- Timer + Fence timer_fence; + Atomic64Padded average_timer_period_ns; } extern P_W32_shared_state; //////////////////////////////////////////////////////////// diff --git a/src/playback/playback_wasapi/playback_wasapi.c b/src/playback/playback_wasapi/playback_wasapi.c index 595c6c71..ce8b69b8 100644 --- a/src/playback/playback_wasapi/playback_wasapi.c +++ b/src/playback/playback_wasapi/playback_wasapi.c @@ -11,12 +11,12 @@ PB_WSP_SharedState PB_WSP_shared_state = ZI; void PB_Bootstrap(void) { - PB_WSP_SharedState *g = &PB_WSP_shared_state; - PB_WSP_InitializeWasapi(); - /* Start playback job */ - JobPoolId playback_pool = InitJobPool(1, Lit("Playback"), JobPoolPriority_Audio); - g->shutdown_jobs_count += RunJob(PB_WSP_Playback, .pool = playback_pool, .fence = &g->shutdown_jobs_fence); - OnExit(&PB_WSP_Shutdown); + PB_WSP_SharedState *g = &PB_WSP_shared_state; + PB_WSP_InitializeWasapi(); + /* Start playback job */ + JobPoolId playback_pool = InitJobPool(1, Lit("Playback"), JobPoolPriority_Audio); + g->shutdown_jobs_count += RunJob(PB_WSP_Playback, .pool = playback_pool, .fence = &g->shutdown_jobs_fence); + OnExit(&PB_WSP_Shutdown); } //////////////////////////////////////////////////////////// @@ -24,102 +24,102 @@ void PB_Bootstrap(void) ExitFuncDef(PB_WSP_Shutdown) { - PB_WSP_SharedState *g = &PB_WSP_shared_state; - Atomic32Set(&g->shutdown, 1); - YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count); + PB_WSP_SharedState *g = &PB_WSP_shared_state; + Atomic32Set(&g->shutdown, 1); + YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count); } void PB_WSP_InitializeWasapi(void) { - PB_WSP_SharedState *g = &PB_WSP_shared_state; - u64 sample_rate = PB_SampleRate; - u64 channel_count = 2; - u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + PB_WSP_SharedState *g = &PB_WSP_shared_state; + u64 sample_rate = PB_SampleRate; + u64 channel_count = 2; + u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; - /* Create enumerator to get audio device */ - IMMDeviceEnumerator *enumerator; - CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator); + /* Create enumerator to get audio device */ + IMMDeviceEnumerator *enumerator; + CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator); - /* Get default playback device */ - IMMDevice *device; - IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device); - IMMDeviceEnumerator_Release(enumerator); + /* Get default playback device */ + IMMDevice *device; + IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device); + IMMDeviceEnumerator_Release(enumerator); - /* Create audio client for device */ - IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client); - IMMDevice_Release(device); + /* Create audio client for device */ + IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client); + IMMDevice_Release(device); - WAVEFORMATEXTENSIBLE format_ex = { - .Format = { - .wFormatTag = WAVE_FORMAT_EXTENSIBLE, - .nChannels = (WORD)channel_count, - .nSamplesPerSec = (WORD)sample_rate, - .nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * sizeof(f32)), - .nBlockAlign = (WORD)(channel_count * sizeof(f32)), - .wBitsPerSample = (WORD)(8 * sizeof(f32)), - .cbSize = sizeof(format_ex) - sizeof(format_ex.Format), - }, - .Samples.wValidBitsPerSample = 8 * sizeof(f32), - .dwChannelMask = channel_mask, - .SubFormat = MEDIASUBTYPE_IEEE_FLOAT, - }; - WAVEFORMATEX *wfx = &format_ex.Format; + WAVEFORMATEXTENSIBLE format_ex = { + .Format = { + .wFormatTag = WAVE_FORMAT_EXTENSIBLE, + .nChannels = (WORD)channel_count, + .nSamplesPerSec = (WORD)sample_rate, + .nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * sizeof(f32)), + .nBlockAlign = (WORD)(channel_count * sizeof(f32)), + .wBitsPerSample = (WORD)(8 * sizeof(f32)), + .cbSize = sizeof(format_ex) - sizeof(format_ex.Format), + }, + .Samples.wValidBitsPerSample = 8 * sizeof(f32), + .dwChannelMask = channel_mask, + .SubFormat = MEDIASUBTYPE_IEEE_FLOAT, + }; + WAVEFORMATEX *wfx = &format_ex.Format; -#if 0 - b32 client_initialized = 0; - IAudioClient3 *client3; - if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3))) + #if 0 + b32 client_initialized = 0; + IAudioClient3 *client3; + if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3))) + { + /* From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz) + * but it can be 128 samples (2.66 msec @ 48khz) if driver is properly installed + * see bullet-point instructions here: https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio#measurement-tools + */ + UINT32 default_period_samples, fundamental_period_samples, min_period_samples, max_period_samples; + IAudioClient3_GetSharedModeEnginePeriod(client3, wfx, &default_period_samples, &fundamental_period_samples, &min_period_samples, &max_period_samples); + + const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK; + if (SUCCEEDED(IAudioClient3_InitializeSharedAudioStream(client3, flags, min_period_samples, wfx, 0))) { - /* From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz) - * but it can be 128 samples (2.66 msec @ 48khz) if driver is properly installed - * see bullet-point instructions here: https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio#measurement-tools - */ - UINT32 default_period_samples, fundamental_period_samples, min_period_samples, max_period_samples; - IAudioClient3_GetSharedModeEnginePeriod(client3, wfx, &default_period_samples, &fundamental_period_samples, &min_period_samples, &max_period_samples); - - const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK; - if (SUCCEEDED(IAudioClient3_InitializeSharedAudioStream(client3, flags, min_period_samples, wfx, 0))) - { - client_initialized = 1; - } - - IAudioClient3_Release(client3); - } -#else - b32 client_initialized = 0; -#endif - - if (!client_initialized) - { - /* Get duration for shared-mode streams, this will typically be 480 samples (10msec @ 48khz) */ - REFERENCE_TIME duration; - IAudioClient_GetDevicePeriod(g->client, &duration, 0); - - /* Initialize audio playback - * - * NOTE: - * Passing AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM will tell WASAPI to - * always convert to native mixing format. This may introduce latency - * but allows for any input format. - */ - const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; - IAudioClient_Initialize(g->client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0); + client_initialized = 1; } - IAudioClient_GetMixFormat(g->client, &g->buffer_format); + IAudioClient3_Release(client3); + } + #else + b32 client_initialized = 0; + #endif - /* Set up event handler to wait on */ - g->event = CreateEventW(0, 0, 0, 0); - IAudioClient_SetEventHandle(g->client, g->event); + if (!client_initialized) + { + /* Get duration for shared-mode streams, this will typically be 480 samples (10msec @ 48khz) */ + REFERENCE_TIME duration; + IAudioClient_GetDevicePeriod(g->client, &duration, 0); - /* Get playback client */ - IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback); + /* Initialize audio playback + * + * NOTE: + * Passing AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM will tell WASAPI to + * always convert to native mixing format. This may introduce latency + * but allows for any input format. + */ + const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; + IAudioClient_Initialize(g->client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0); + } - /* Start the playback */ - IAudioClient_Start(g->client); + IAudioClient_GetMixFormat(g->client, &g->buffer_format); - /* Get audio buffer size in samples */ - IAudioClient_GetBufferSize(g->client, &g->buffer_frames); + /* Set up event handler to wait on */ + g->event = CreateEventW(0, 0, 0, 0); + IAudioClient_SetEventHandle(g->client, g->event); + + /* Get playback client */ + IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback); + + /* Start the playback */ + IAudioClient_Start(g->client); + + /* Get audio buffer size in samples */ + IAudioClient_GetBufferSize(g->client, &g->buffer_frames); } //////////////////////////////////////////////////////////// @@ -127,54 +127,55 @@ void PB_WSP_InitializeWasapi(void) PB_WSP_Buff PB_WSP_BeginUpdate(void) { - PB_WSP_SharedState *g = &PB_WSP_shared_state; - PB_WSP_Buff wspbuf = ZI; + PB_WSP_SharedState *g = &PB_WSP_shared_state; + PB_WSP_Buff wspbuf = ZI; - /* Get padding frames */ - u32 padding_frames; - IAudioClient_GetCurrentPadding(g->client, &padding_frames); + /* Get padding frames */ + u32 padding_frames; + IAudioClient_GetCurrentPadding(g->client, &padding_frames); - /* Get output buffer from WASAPI */ - wspbuf.frames_count = 0; - if (padding_frames <= g->buffer_frames) - { - wspbuf.frames_count = g->buffer_frames - padding_frames; - } - IAudioRenderClient_GetBuffer(g->playback, wspbuf.frames_count, &wspbuf.frames); + /* Get output buffer from WASAPI */ + wspbuf.frames_count = 0; + if (padding_frames <= g->buffer_frames) + { + wspbuf.frames_count = g->buffer_frames - padding_frames; + } + IAudioRenderClient_GetBuffer(g->playback, wspbuf.frames_count, &wspbuf.frames); - return wspbuf; + return wspbuf; } void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src) { - PB_WSP_SharedState *g = &PB_WSP_shared_state; - u32 frames_in_source = src.count / 2; - u32 frames_in_output = wspbuf->frames_count; + PB_WSP_SharedState *g = &PB_WSP_shared_state; + u32 frames_in_source = src.count / 2; + u32 frames_in_output = wspbuf->frames_count; - u32 flags = 0; - if (frames_in_source == frames_in_output) - { - /* Copy bytes to output */ - u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels; - u32 write_size = frames_in_source * 2 * bytes_per_sample; - CopyBytes(wspbuf->frames, src.samples, write_size); - } - else - { - /* Submit silence if not enough samples */ - flags = AUDCLNT_BUFFERFLAGS_SILENT; + u32 flags = 0; + if (frames_in_source == frames_in_output) + { + /* Copy bytes to output */ + u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels; + u32 write_size = frames_in_source * 2 * bytes_per_sample; + CopyBytes(wspbuf->frames, src.samples, write_size); + } + else + { + /* Submit silence if not enough samples */ + flags |= AUDCLNT_BUFFERFLAGS_SILENT; - /* This shouldn't occur, mixer should be generating samples equivilent - * to value returned from `PB_WSP_BeginUpdate`. */ - Assert(0); - } + /* This shouldn't occur, mixer should be generating samples equivilent + * to value returned from `PB_WSP_BeginUpdate`. */ + Assert(0); + } -#if !AUDIO_ENABLED - flags = AUDCLNT_BUFFERFLAGS_SILENT; -#endif + if (!AUDIO_ENABLED) + { + flags |= AUDCLNT_BUFFERFLAGS_SILENT; + } - /* Submit output buffer to WASAPI */ - IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags); + /* Submit output buffer to WASAPI */ + IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags); } //////////////////////////////////////////////////////////// @@ -182,22 +183,22 @@ void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src) JobImpl(PB_WSP_Playback, sig, id) { - PB_WSP_SharedState *g = &PB_WSP_shared_state; + PB_WSP_SharedState *g = &PB_WSP_shared_state; - /* FIXME: If playback fails at any point and mixer stops advancing, we - * need to halt mixer to prevent memory leak when sounds are played. */ - /* TODO: Signal counter that running job wiats on, rather than scheduling job manually */ - while (!Atomic32Fetch(&g->shutdown)) + /* FIXME: If playback fails at any point and mixer stops advancing, we + * need to halt mixer to prevent memory leak when sounds are played. */ + /* TODO: Signal counter that running job wiats on, rather than scheduling job manually */ + while (!Atomic32Fetch(&g->shutdown)) + { + TempArena scratch = BeginScratchNoConflict(); { - TempArena scratch = BeginScratchNoConflict(); - { - WaitForSingleObject(g->event, INFINITE); - } - { - PB_WSP_Buff wspbuf = PB_WSP_BeginUpdate(); - MIX_PcmF32 pcm = MIX_MixAllTracks(scratch.arena, wspbuf.frames_count); - PB_WSP_EndUpdate(&wspbuf, pcm); - } - EndScratch(scratch); + WaitForSingleObject(g->event, INFINITE); } + { + PB_WSP_Buff wspbuf = PB_WSP_BeginUpdate(); + MIX_PcmF32 pcm = MIX_MixAllTracks(scratch.arena, wspbuf.frames_count); + PB_WSP_EndUpdate(&wspbuf, pcm); + } + EndScratch(scratch); + } } diff --git a/src/playback/playback_wasapi/playback_wasapi.h b/src/playback/playback_wasapi/playback_wasapi.h index 75ceb450..0cedd794 100644 --- a/src/playback/playback_wasapi/playback_wasapi.h +++ b/src/playback/playback_wasapi/playback_wasapi.h @@ -2,8 +2,8 @@ //~ Win32 libs #pragma warning(push, 0) -# include -# include + #include + #include #pragma warning(pop) DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e); @@ -17,8 +17,8 @@ DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7, 0xbf, 0x Struct(PB_WSP_Buff) { - u32 frames_count; - u8 *frames; + u32 frames_count; + u8 *frames; }; //////////////////////////////////////////////////////////// @@ -26,14 +26,14 @@ Struct(PB_WSP_Buff) Struct(PB_WSP_SharedState) { - Atomic32 shutdown; - IAudioClient *client; - HANDLE event; - IAudioRenderClient *playback; - WAVEFORMATEX *buffer_format; - u32 buffer_frames; - Fence shutdown_jobs_fence; - u32 shutdown_jobs_count; + Atomic32 shutdown; + IAudioClient *client; + HANDLE event; + IAudioRenderClient *playback; + WAVEFORMATEX *buffer_format; + u32 buffer_frames; + Fence shutdown_jobs_fence; + u32 shutdown_jobs_count; } extern PB_WSP_shared_state; //////////////////////////////////////////////////////////// diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index 1ac75db1..0b2ac391 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -1,9 +1,9 @@ S_Ctx S = Zi; Readonly S_ReadonlyCtx S_ro = { - .nil_ent = { - .xf = CompXformIdentity - } + .nil_ent = { + .xf = CompXformIdentity + } }; //////////////////////////////////////////////////////////// @@ -11,26 +11,26 @@ Readonly S_ReadonlyCtx S_ro = { void S_Bootstrap(void) { - /* Initialize shared state */ - for (u64 i = 0; i < countof(S.input_states); ++i) - { - S_InputState *input = &S.input_states[i]; - input->arena = AcquireArena(Gibi(64)); - } - for (u64 i = 0; i < countof(S.output_states); ++i) - { - S_OutputState *output = &S.output_states[i]; - output->arena = AcquireArena(Gibi(64)); - } + /* Initialize shared state */ + for (u64 i = 0; i < countof(S.input_states); ++i) + { + S_InputState *input = &S.input_states[i]; + input->arena = AcquireArena(Gibi(64)); + } + for (u64 i = 0; i < countof(S.output_states); ++i) + { + S_OutputState *output = &S.output_states[i]; + output->arena = AcquireArena(Gibi(64)); + } - /* Dispatch sim wave */ - DispatchWave(Lit("Sim"), 1, S_TickForever, 0); + /* Dispatch sim wave */ + DispatchWave(Lit("Sim"), 1, S_TickForever, 0); } void S_Shutdown(void) { - Atomic32Set(&S.shutdown, 1); - YieldOnFence(&S.worker_completion_fence, S.workers_count); + Atomic32Set(&S.shutdown, 1); + YieldOnFence(&S.worker_completion_fence, S.workers_count); } //////////////////////////////////////////////////////////// @@ -38,17 +38,17 @@ void S_Shutdown(void) b32 S_IsKeyNil(S_Key key) { - return key.v.hi == 0 && key.v.lo == 0; + return key.v.hi == 0 && key.v.lo == 0; } b32 S_IsEntNil(S_Ent *ent) { - return ent == 0 || ent == &S_ro.nil_ent; + return ent == 0 || ent == &S_ro.nil_ent; } b32 S_MatchKey(S_Key a, S_Key b) { - return a.v.hi == b.v.hi && a.v.lo == b.v.lo; + return a.v.hi == b.v.hi && a.v.lo == b.v.lo; } //////////////////////////////////////////////////////////// @@ -56,10 +56,10 @@ b32 S_MatchKey(S_Key a, S_Key b) S_Key S_RandKey(void) { - /* TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. */ - S_Key result = Zi; - TrueRand(StringFromStruct(&result)); - return result; + /* TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. */ + S_Key result = Zi; + TrueRand(StringFromStruct(&result)); + return result; } //////////////////////////////////////////////////////////// @@ -67,26 +67,26 @@ S_Key S_RandKey(void) Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement) { - Rng2I32 dirty_rect = Zi; - switch (placement.placement_kind) + Rng2I32 dirty_rect = Zi; + switch (placement.placement_kind) + { + case S_TilePlacementKind_Range: { - case S_TilePlacementKind_Range: + S_TileKind tile = placement.tile_kind; + Rng2I32 range = placement.range; + for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y) + { + for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x) { - S_TileKind tile = placement.tile_kind; - Rng2I32 range = placement.range; - for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y) - { - for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x) - { - Vec2I32 tile_pos = VEC2I32(tile_x, tile_y); - i32 tile_idx = S_TileIdxFromTilePos(tile_pos); - tiles[tile_idx] = (u8)tile; - } - } - dirty_rect = range; - } break; - } - return dirty_rect; + Vec2I32 tile_pos = VEC2I32(tile_x, tile_y); + i32 tile_idx = S_TileIdxFromTilePos(tile_pos); + tiles[tile_idx] = (u8)tile; + } + } + dirty_rect = range; + } break; + } + return dirty_rect; } //////////////////////////////////////////////////////////// @@ -94,52 +94,52 @@ Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement) S_Shape S_ShapeFromDescEx(S_ShapeDesc desc) { - desc.count = MaxI32(desc.count, 1); - S_Shape result = Zi; + desc.count = MaxI32(desc.count, 1); + S_Shape result = Zi; + { + result.points_count = desc.count; + CopyStructs(result.points, desc.points, result.points_count); + Vec2 accum = Zi; + for (i32 p_idx = 0; p_idx < result.points_count; ++p_idx) { - result.points_count = desc.count; - CopyStructs(result.points, desc.points, result.points_count); - Vec2 accum = Zi; - for (i32 p_idx = 0; p_idx < result.points_count; ++p_idx) - { - accum = AddVec2(accum, result.points[p_idx]); - } - result.centroid = DivVec2(accum, result.points_count); - result.center_of_mass = result.centroid; - result.radius = desc.radius; - result.mass = desc.mass; + accum = AddVec2(accum, result.points[p_idx]); } - return result; + result.centroid = DivVec2(accum, result.points_count); + result.center_of_mass = result.centroid; + result.radius = desc.radius; + result.mass = desc.mass; + } + return result; } S_Shape S_MulXformShape(Xform xf, S_Shape shape) { - S_Shape result = shape; - for (i32 i = 0; i < shape.points_count; ++i) - { - result.points[i] = MulXformV2(xf, shape.points[i]); - } - Vec2 scale = ScaleFromXform(xf); - result.radius *= MaxF32(scale.x, scale.y); - return result; + S_Shape result = shape; + for (i32 i = 0; i < shape.points_count; ++i) + { + result.points[i] = MulXformV2(xf, shape.points[i]); + } + Vec2 scale = ScaleFromXform(xf); + result.radius *= MaxF32(scale.x, scale.y); + return result; } Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir) { - Vec2 result = Zi; - f32 max_dot = -F32Infinity; - for (i32 i = 0; i < shape.points_count; ++i) + Vec2 result = Zi; + f32 max_dot = -F32Infinity; + for (i32 i = 0; i < shape.points_count; ++i) + { + Vec2 p = shape.points[i]; + f32 dot = DotVec2(p, dir); + if (dot > max_dot) { - Vec2 p = shape.points[i]; - f32 dot = DotVec2(p, dir); - if (dot > max_dot) - { - max_dot = dot; - result = p; - } + max_dot = dot; + result = p; } - result = AddVec2(result, MulVec2(dir, shape.radius)); - return result; + } + result = AddVec2(result, MulVec2(dir, shape.radius)); + return result; } //////////////////////////////////////////////////////////// @@ -147,46 +147,46 @@ Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir) S_Lookup S_LookupFromWorld(Arena *arena, S_World *world) { - S_Lookup lookup = Zi; + S_Lookup lookup = Zi; - lookup.bins_count = 4096; - lookup.bins = PushStructs(arena, S_LookupEntNode *, lookup.bins_count); - for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx) + lookup.bins_count = 4096; + lookup.bins = PushStructs(arena, S_LookupEntNode *, lookup.bins_count); + for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx) + { + S_Ent *ent = &world->ents[ent_idx]; + if (ent->active) { - S_Ent *ent = &world->ents[ent_idx]; - if (ent->active) - { - S_Key key = ent->key; - S_LookupEntNode *n = PushStruct(arena, S_LookupEntNode); - n->ent = ent; - S_LookupEntNode **bin = &lookup.bins[ent->key.v.lo % lookup.bins_count]; - SllStackPush(*bin, n); - } + S_Key key = ent->key; + S_LookupEntNode *n = PushStruct(arena, S_LookupEntNode); + n->ent = ent; + S_LookupEntNode **bin = &lookup.bins[ent->key.v.lo % lookup.bins_count]; + SllStackPush(*bin, n); } + } - return lookup; + return lookup; } S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key) { - S_Ent *result = &S_ro.nil_ent; - if (!S_IsKeyNil(key)) + S_Ent *result = &S_ro.nil_ent; + if (!S_IsKeyNil(key)) + { + i64 bins_count = lookup->bins_count; + if (bins_count > 0) { - i64 bins_count = lookup->bins_count; - if (bins_count > 0) + S_LookupEntNode *n = lookup->bins[key.v.lo % bins_count]; + for (; n; n = n->next) + { + if (S_MatchKey(n->ent->key, key)) { - S_LookupEntNode *n = lookup->bins[key.v.lo % bins_count]; - for (; n; n = n->next) - { - if (S_MatchKey(n->ent->key, key)) - { - result = n->ent; - break; - } - } + result = n->ent; + break; } + } } - return result; + } + return result; } //////////////////////////////////////////////////////////// @@ -194,29 +194,29 @@ S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key) S_Ent *S_FirstEnt(S_Iter *iter, S_World *world) { - ZeroStruct(iter); - iter->world = world; - return S_NextEnt(iter); + ZeroStruct(iter); + iter->world = world; + return S_NextEnt(iter); } S_Ent *S_NextEnt(S_Iter *iter) { - S_World *world = iter->world; - S_Ent *result = &S_ro.nil_ent; + S_World *world = iter->world; + S_Ent *result = &S_ro.nil_ent; - i64 ent_idx = iter->cur_idx; - for (; ent_idx < world->ents_count; ++ent_idx) + i64 ent_idx = iter->cur_idx; + for (; ent_idx < world->ents_count; ++ent_idx) + { + S_Ent *ent = &world->ents[ent_idx]; + if (ent->active) { - S_Ent *ent = &world->ents[ent_idx]; - if (ent->active) - { - result = ent; - break; - } + result = ent; + break; } - iter->cur_idx = ent_idx + 1; + } + iter->cur_idx = ent_idx + 1; - return result; + return result; } //////////////////////////////////////////////////////////// @@ -224,15 +224,15 @@ S_Ent *S_NextEnt(S_Iter *iter) S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot) { - S_World *world = PushStruct(arena, S_World); + S_World *world = PushStruct(arena, S_World); - /* Copy ents */ - world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count); - CopyStructs(world->ents, snapshot->ents, snapshot->ents_count); - world->ents_count = snapshot->ents_count; - world->tick = snapshot->tick; + /* Copy ents */ + world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count); + CopyStructs(world->ents, snapshot->ents, snapshot->ents_count); + world->ents_count = snapshot->ents_count; + world->tick = snapshot->tick; - return world; + return world; } //////////////////////////////////////////////////////////// @@ -240,20 +240,20 @@ S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot) MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _) { - S_Ent *a = *(S_Ent **)arg_a; - S_Ent *b = *(S_Ent **)arg_b; - S_Key a_key = a->key; - S_Key b_key = b->key; - i32 result = 0; - if (result == 0) - { - result = ((a_key.v.lo < b_key.v.lo) - (a_key.v.lo > b_key.v.lo)); - } - if (result == 0) - { - result = ((a_key.v.hi < b_key.v.hi) - (a_key.v.hi > b_key.v.hi)); - } - return result; + S_Ent *a = *(S_Ent **)arg_a; + S_Ent *b = *(S_Ent **)arg_b; + S_Key a_key = a->key; + S_Key b_key = b->key; + i32 result = 0; + if (result == 0) + { + result = ((a_key.v.lo < b_key.v.lo) - (a_key.v.lo > b_key.v.lo)); + } + if (result == 0) + { + result = ((a_key.v.hi < b_key.v.hi) - (a_key.v.hi > b_key.v.hi)); + } + return result; } //////////////////////////////////////////////////////////// @@ -261,204 +261,204 @@ MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _) void S_TickForever(WaveLaneCtx *lane) { - Arena *frame_arena = AcquireArena(Gibi(64)); - Arena *perm = PermArena(); + Arena *frame_arena = AcquireArena(Gibi(64)); + Arena *perm = PermArena(); - const i32 world_size = S_WorldSize; + const i32 world_size = S_WorldSize; - //- World data - Arena *ents_arena = AcquireArena(Gibi(64)); - S_World *world = PushStruct(perm, S_World); - world->ents = ArenaFirst(ents_arena, S_Ent); - i64 first_free_ent_num = 0; - i64 sim_time_ns = 0; + //- World data + Arena *ents_arena = AcquireArena(Gibi(64)); + S_World *world = PushStruct(perm, S_World); + world->ents = ArenaFirst(ents_arena, S_Ent); + i64 first_free_ent_num = 0; + i64 sim_time_ns = 0; - u8 *tiles = PushBytes(perm, world_size * world_size * 4, alignof(S_TileKind)); + u8 *tiles = PushBytes(perm, world_size * world_size * 4, alignof(S_TileKind)); + + ////////////////////////////// + //- Sim loop + + b32 shutdown = 0; + while (!shutdown) + { + ResetArena(frame_arena); + S_Iter iter = Zi; + S_Lookup lookup = Zi; ////////////////////////////// - //- Sim loop + //- Begin sim frame - b32 shutdown = 0; - while (!shutdown) + i64 frame_begin_ns = TimeNs(); + i64 sim_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; + f64 sim_dt = SecondsFromNs(sim_dt_ns); + world->tick += 1; + + lookup = S_LookupFromWorld(frame_arena, world); + + ////////////////////////////// + //- Pop sim commands + + S_InputState *input = 0; + LockTicketMutex(&S.input_back_tm); { - ResetArena(frame_arena); - S_Iter iter = Zi; - S_Lookup lookup = Zi; - - ////////////////////////////// - //- Begin sim frame - - i64 frame_begin_ns = TimeNs(); - i64 sim_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; - f64 sim_dt = SecondsFromNs(sim_dt_ns); - world->tick += 1; - - lookup = S_LookupFromWorld(frame_arena, world); - - ////////////////////////////// - //- Pop sim commands - - S_InputState *input = 0; - LockTicketMutex(&S.input_back_tm); - { - input = &S.input_states[S.input_back_idx]; - ++S.input_back_idx; - if (S.input_back_idx >= countof(S.input_states)) - { - S.input_back_idx = 0; - } - } - UnlockTicketMutex(&S.input_back_tm); - - ////////////////////////////// - //- Process world edit commands - - u64 tile_placements_count = 0; - for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next) - { - S_Cmd *cmd = &cmd_node->cmd; - - /* Spawn entity */ - if (cmd->kind == S_CmdKind_Spawn) - { - S_Ent *src = &cmd->ent; - S_Key key = src->key; - if (!S_IsKeyNil(key)) - { - S_Ent *dst = S_EntFromKey(&lookup, key); - if (S_IsEntNil(dst)) - { - if (first_free_ent_num > 0) - { - dst = &world->ents[first_free_ent_num - 1]; - first_free_ent_num = dst->next_free_ent_num; - } - else - { - dst = PushStructNoZero(ents_arena, S_Ent); - } - *dst = S_ro.nil_ent; - dst->key = key; - ++world->ents_count; - } - *dst = *src; - dst->local_shape.points_count = MaxI32(dst->local_shape.points_count, 1); - - dst->active = 1; - } - } - - /* Place tiles */ - if (cmd->kind == S_CmdKind_Tile) - { - tile_placements_count += 1; - S_TilePlacement placement = cmd->tile_placement; - S_UpdateTilesInPlaceFromPlacement(tiles, placement); - } - } - lookup = S_LookupFromWorld(frame_arena, world); - - ////////////////////////////// - //- Update ent controls - - for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next) - { - S_Cmd cmd = cmd_node->cmd; - if (cmd.kind == S_CmdKind_Control) - { - S_Ent *target = S_EntFromKey(&lookup, cmd.target); - if (target->active) - { - target->move = ClampVec2Len(cmd.move, 1); - target->look = cmd.look; - } - } - } - - ////////////////////////////// - //- Apply control forces - - for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter)) - { - if (!IsVec2Zero(ent->move)) - { - DEBUGBREAKABLE; - } - - Xform xf = ent->xf; - if (!IsVec2Zero(ent->look)) - { - xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look)); - } - xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed)); - ent->xf = xf; - } - - ////////////////////////////// - //- Publish sim state - - /* TODO: Only copy active entities */ - LockTicketMutex(&S.output_back_tm); - { - S_OutputState *output = &S.output_states[S.output_back_idx]; - ResetArena(output->arena); - S_SnapshotNode *snapshot_node = PushStruct(output->arena, S_SnapshotNode); - S_Snapshot *snapshot = &snapshot_node->snapshot; - SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node); - ++output->snapshots_count; - snapshot->ents_count = world->ents_count; - snapshot->tick = world->tick; - snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count); - for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx) - { - S_Ent *src = &world->ents[ent_idx]; - S_Ent *dst = &snapshot->ents[ent_idx]; - *dst = *src; - } - - /* Forward tile placements */ - snapshot->tile_placements_count = tile_placements_count; - snapshot->tile_placements = PushStructs(output->arena, S_TilePlacement, tile_placements_count); - { - u64 tile_placement_idx = 0; - for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node && tile_placement_idx < tile_placements_count; cmd_node = cmd_node->next) - { - S_Cmd *cmd = &cmd_node->cmd; - if (cmd->kind == S_CmdKind_Tile) - { - S_TilePlacement *dst_placement = &snapshot->tile_placements[tile_placement_idx]; - *dst_placement = cmd->tile_placement; - tile_placement_idx += 1; - } - } - } - - } - UnlockTicketMutex(&S.output_back_tm); - - ////////////////////////////// - //- End sim frame - - /* Reset front input state */ - { - Arena *arena = input->arena; - ResetArena(arena); - ZeroStruct(input); - input->arena = arena; - } - - - i64 frame_end_ns = TimeNs(); - sim_time_ns += sim_dt_ns; - - ////////////////////////////// - //- Sleep - - if (!Atomic32Fetch(&S.shutdown)) - { - i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; - P_SleepFrame(frame_begin_ns, step_dt_ns); - } - shutdown = Atomic32Fetch(&S.shutdown); + input = &S.input_states[S.input_back_idx]; + ++S.input_back_idx; + if (S.input_back_idx >= countof(S.input_states)) + { + S.input_back_idx = 0; + } } + UnlockTicketMutex(&S.input_back_tm); + + ////////////////////////////// + //- Process world edit commands + + u64 tile_placements_count = 0; + for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next) + { + S_Cmd *cmd = &cmd_node->cmd; + + /* Spawn entity */ + if (cmd->kind == S_CmdKind_Spawn) + { + S_Ent *src = &cmd->ent; + S_Key key = src->key; + if (!S_IsKeyNil(key)) + { + S_Ent *dst = S_EntFromKey(&lookup, key); + if (S_IsEntNil(dst)) + { + if (first_free_ent_num > 0) + { + dst = &world->ents[first_free_ent_num - 1]; + first_free_ent_num = dst->next_free_ent_num; + } + else + { + dst = PushStructNoZero(ents_arena, S_Ent); + } + *dst = S_ro.nil_ent; + dst->key = key; + ++world->ents_count; + } + *dst = *src; + dst->local_shape.points_count = MaxI32(dst->local_shape.points_count, 1); + + dst->active = 1; + } + } + + /* Place tiles */ + if (cmd->kind == S_CmdKind_Tile) + { + tile_placements_count += 1; + S_TilePlacement placement = cmd->tile_placement; + S_UpdateTilesInPlaceFromPlacement(tiles, placement); + } + } + lookup = S_LookupFromWorld(frame_arena, world); + + ////////////////////////////// + //- Update ent controls + + for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next) + { + S_Cmd cmd = cmd_node->cmd; + if (cmd.kind == S_CmdKind_Control) + { + S_Ent *target = S_EntFromKey(&lookup, cmd.target); + if (target->active) + { + target->move = ClampVec2Len(cmd.move, 1); + target->look = cmd.look; + } + } + } + + ////////////////////////////// + //- Apply control forces + + for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter)) + { + if (!IsVec2Zero(ent->move)) + { + DEBUGBREAKABLE; + } + + Xform xf = ent->xf; + if (!IsVec2Zero(ent->look)) + { + xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look)); + } + xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed)); + ent->xf = xf; + } + + ////////////////////////////// + //- Publish sim state + + /* TODO: Only copy active entities */ + LockTicketMutex(&S.output_back_tm); + { + S_OutputState *output = &S.output_states[S.output_back_idx]; + ResetArena(output->arena); + S_SnapshotNode *snapshot_node = PushStruct(output->arena, S_SnapshotNode); + S_Snapshot *snapshot = &snapshot_node->snapshot; + SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node); + ++output->snapshots_count; + snapshot->ents_count = world->ents_count; + snapshot->tick = world->tick; + snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count); + for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx) + { + S_Ent *src = &world->ents[ent_idx]; + S_Ent *dst = &snapshot->ents[ent_idx]; + *dst = *src; + } + + /* Forward tile placements */ + snapshot->tile_placements_count = tile_placements_count; + snapshot->tile_placements = PushStructs(output->arena, S_TilePlacement, tile_placements_count); + { + u64 tile_placement_idx = 0; + for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node && tile_placement_idx < tile_placements_count; cmd_node = cmd_node->next) + { + S_Cmd *cmd = &cmd_node->cmd; + if (cmd->kind == S_CmdKind_Tile) + { + S_TilePlacement *dst_placement = &snapshot->tile_placements[tile_placement_idx]; + *dst_placement = cmd->tile_placement; + tile_placement_idx += 1; + } + } + } + + } + UnlockTicketMutex(&S.output_back_tm); + + ////////////////////////////// + //- End sim frame + + /* Reset front input state */ + { + Arena *arena = input->arena; + ResetArena(arena); + ZeroStruct(input); + input->arena = arena; + } + + + i64 frame_end_ns = TimeNs(); + sim_time_ns += sim_dt_ns; + + ////////////////////////////// + //- Sleep + + if (!Atomic32Fetch(&S.shutdown)) + { + i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; + P_SleepFrame(frame_begin_ns, step_dt_ns); + } + shutdown = Atomic32Fetch(&S.shutdown); + } } diff --git a/src/pp/pp_sim/pp_sim_core.h b/src/pp/pp_sim/pp_sim_core.h index c3a6ea55..b7d35ecc 100644 --- a/src/pp/pp_sim/pp_sim_core.h +++ b/src/pp/pp_sim/pp_sim_core.h @@ -5,7 +5,7 @@ Struct(S_Key) { - U128 v; + U128 v; }; //////////////////////////////////////////////////////////// @@ -13,21 +13,21 @@ Struct(S_Key) Struct(S_ShapeDesc) { - f32 radius; - f32 mass; - i32 count; - Vec2 points[8]; + f32 radius; + f32 mass; + i32 count; + Vec2 points[8]; }; Struct(S_Shape) { - f32 mass; - Vec2 centroid; - Vec2 center_of_mass; + f32 mass; + Vec2 centroid; + Vec2 center_of_mass; - f32 radius; - i32 points_count; - Vec2 points[8]; + f32 radius; + i32 points_count; + Vec2 points[8]; }; //////////////////////////////////////////////////////////// @@ -37,28 +37,28 @@ Struct(S_Shape) Struct(S_Ent) { - ////////////////////////////// - //- Persistent data + ////////////////////////////// + //- Persistent data - b32 active; - S_Key key; + b32 active; + S_Key key; - ////////////////////////////// - //- Build data + ////////////////////////////// + //- Build data - Xform xf; - S_Shape local_shape; + Xform xf; + S_Shape local_shape; - f32 move_speed; - Vec2 move; - Vec2 look; + f32 move_speed; + Vec2 move; + Vec2 look; - b32 has_weapon; + b32 has_weapon; - ////////////////////////////// - //- Internal sim data + ////////////////////////////// + //- Internal sim data - i64 next_free_ent_num; + i64 next_free_ent_num; }; @@ -67,21 +67,21 @@ Struct(S_Ent) Struct(S_EntArray) { - u64 count; - S_Ent *ents; + u64 count; + S_Ent *ents; }; Struct(S_EntListNode) { - S_EntListNode *next; - S_Ent ent; + S_EntListNode *next; + S_Ent ent; }; Struct(S_EntList) { - S_EntListNode *first; - S_EntListNode *last; - u64 count; + S_EntListNode *first; + S_EntListNode *last; + u64 count; }; //////////////////////////////////////////////////////////// @@ -89,14 +89,14 @@ Struct(S_EntList) Struct(S_LookupEntNode) { - S_LookupEntNode *next; - S_Ent *ent; + S_LookupEntNode *next; + S_Ent *ent; }; Struct(S_Lookup) { - S_LookupEntNode **bins; - i64 bins_count; + S_LookupEntNode **bins; + i64 bins_count; }; //////////////////////////////////////////////////////////// @@ -104,27 +104,27 @@ Struct(S_Lookup) Struct(S_World) { - i64 tick; + i64 tick; - S_Ent *ents; - i64 ents_count; + S_Ent *ents; + i64 ents_count; }; Struct(S_Snapshot) { - i64 tick; + i64 tick; - S_Ent *ents; - i64 ents_count; + S_Ent *ents; + i64 ents_count; - S_TilePlacement *tile_placements; - u64 tile_placements_count; + S_TilePlacement *tile_placements; + u64 tile_placements_count; }; Struct(S_SnapshotNode) { - S_SnapshotNode *next; - S_Snapshot snapshot; + S_SnapshotNode *next; + S_Snapshot snapshot; }; //////////////////////////////////////////////////////////// @@ -132,8 +132,8 @@ Struct(S_SnapshotNode) Struct(S_Iter) { - S_World *world; - i64 cur_idx; + S_World *world; + i64 cur_idx; }; //////////////////////////////////////////////////////////// @@ -141,32 +141,32 @@ Struct(S_Iter) Enum(S_CmdKind) { - S_CmdKind_Nop, - S_CmdKind_Tile, - S_CmdKind_Spawn, - S_CmdKind_Control, + S_CmdKind_Nop, + S_CmdKind_Tile, + S_CmdKind_Spawn, + S_CmdKind_Control, }; Struct(S_Cmd) { - S_CmdKind kind; + S_CmdKind kind; - /* Tiles */ - S_TilePlacement tile_placement; + /* Tiles */ + S_TilePlacement tile_placement; - /* Spawn */ - S_Ent ent; + /* Spawn */ + S_Ent ent; - /* Control */ - S_Key target; - Vec2 move; - Vec2 look; + /* Control */ + S_Key target; + Vec2 move; + Vec2 look; }; Struct(S_CmdNode) { - S_CmdNode *next; - S_Cmd cmd; + S_CmdNode *next; + S_Cmd cmd; }; //////////////////////////////////////////////////////////// @@ -177,41 +177,41 @@ Struct(S_CmdNode) Struct(S_InputState) { - Arena *arena; - S_CmdNode *first_cmd_node; - S_CmdNode *last_cmd_node; - u64 cmds_count; + Arena *arena; + S_CmdNode *first_cmd_node; + S_CmdNode *last_cmd_node; + u64 cmds_count; }; Struct(S_OutputState) { - Arena *arena; - S_SnapshotNode *first_snapshot_node; - S_SnapshotNode *last_snapshot_node; - u64 snapshots_count; + Arena *arena; + S_SnapshotNode *first_snapshot_node; + S_SnapshotNode *last_snapshot_node; + u64 snapshots_count; }; Struct(S_Ctx) { - Atomic32 shutdown; - Fence worker_completion_fence; - i64 workers_count; + Atomic32 shutdown; + Fence worker_completion_fence; + i64 workers_count; - //- Sim input - TicketMutex input_back_tm; - i32 input_back_idx; - S_InputState input_states[S_InputStatesCount]; + //- Sim input + TicketMutex input_back_tm; + i32 input_back_idx; + S_InputState input_states[S_InputStatesCount]; - //- Sim output - TicketMutex output_back_tm; - i32 output_back_idx; - S_OutputState output_states[S_OutputStatesCount]; + //- Sim output + TicketMutex output_back_tm; + i32 output_back_idx; + S_OutputState output_states[S_OutputStatesCount]; }; Struct(S_ReadonlyCtx) { - S_Ent nil_ent; + S_Ent nil_ent; }; extern S_Ctx S; diff --git a/src/pp/pp_sim/pp_sim_tiles.cg b/src/pp/pp_sim/pp_sim_tiles.cg index f4693235..83b0c90a 100644 --- a/src/pp/pp_sim/pp_sim_tiles.cg +++ b/src/pp/pp_sim/pp_sim_tiles.cg @@ -3,14 +3,14 @@ Vec2I32 S_TilePosFromWorldPos(Vec2 p) { - Vec2I32 result; - result.x = ClampI32((p.x + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1); - result.y = ClampI32((p.y + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1); - return result; + Vec2I32 result; + result.x = ClampI32((p.x + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1); + result.y = ClampI32((p.y + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1); + return result; } i32 S_TileIdxFromTilePos(Vec2I32 p) { - i32 result = ClampI32(p.x + (p.y * S_WorldSize * 2), 0, S_WorldSize * S_WorldSize * 4); - return result; + i32 result = ClampI32(p.x + (p.y * S_WorldSize * 2), 0, S_WorldSize * S_WorldSize * 4); + return result; } diff --git a/src/pp/pp_sim/pp_sim_tiles.cgh b/src/pp/pp_sim/pp_sim_tiles.cgh index ad4a72d5..6e84a218 100644 --- a/src/pp/pp_sim/pp_sim_tiles.cgh +++ b/src/pp/pp_sim/pp_sim_tiles.cgh @@ -5,21 +5,21 @@ Enum(S_TileKind) { - S_TileKind_None, - S_TileKind_Floor, - S_TileKind_Wall, + S_TileKind_None, + S_TileKind_Floor, + S_TileKind_Wall, }; Enum(S_TilePlacementKind) { - S_TilePlacementKind_Range + S_TilePlacementKind_Range }; Struct(S_TilePlacement) { - S_TilePlacementKind placement_kind; - S_TileKind tile_kind; - Rng2I32 range; + S_TilePlacementKind placement_kind; + S_TileKind tile_kind; + Rng2I32 range; }; //////////////////////////////////////////////////////////// diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 717b2553..e88886dc 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -5,13 +5,13 @@ V_Ctx V = Zi; void V_Bootstrap(void) { - DispatchWave(Lit("Vis"), 1, V_TickForever, 0); + DispatchWave(Lit("Vis"), 1, V_TickForever, 0); } void V_Shutdown(void) { - Atomic32Set(&V.shutdown, 1); - YieldOnFence(&V.shutdown_complete, 1); + Atomic32Set(&V.shutdown, 1); + YieldOnFence(&V.shutdown_complete, 1); } //////////////////////////////////////////////////////////// @@ -19,38 +19,38 @@ void V_Shutdown(void) V_Frame *V_CurrentFrame(void) { - return &V.frames[V.current_frame_idx]; + return &V.frames[V.current_frame_idx]; } S_Cmd *V_PushSimCmd(S_CmdKind kind) { - V_Frame *frame = V_CurrentFrame(); - S_CmdNode *n = PushStruct(frame->arena, S_CmdNode); - n->cmd.kind = kind; - SllQueuePush(frame->first_sim_cmd_node, frame->last_sim_cmd_node, n); - ++frame->sim_cmds_count; - return &n->cmd; + V_Frame *frame = V_CurrentFrame(); + S_CmdNode *n = PushStruct(frame->arena, S_CmdNode); + n->cmd.kind = kind; + SllQueuePush(frame->first_sim_cmd_node, frame->last_sim_cmd_node, n); + ++frame->sim_cmds_count; + return &n->cmd; } String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey) { - TempArena scratch = BeginScratch(arena); - StringList parts = Zi; - if (hotkey.ctrl) - { - PushStringToList(scratch.arena, &parts, Lit("Ctrl")); - } - if (hotkey.alt) - { - PushStringToList(scratch.arena, &parts, Lit("Alt")); - } - if (hotkey.shift) - { - PushStringToList(scratch.arena, &parts, Lit("Shift")); - } - PushStringToList(scratch.arena, &parts, StringFromButton(hotkey.button)); - EndScratch(scratch); - return StringFromList(arena, parts, Lit(" + ")); + TempArena scratch = BeginScratch(arena); + StringList parts = Zi; + if (hotkey.ctrl) + { + PushStringToList(scratch.arena, &parts, Lit("Ctrl")); + } + if (hotkey.alt) + { + PushStringToList(scratch.arena, &parts, Lit("Alt")); + } + if (hotkey.shift) + { + PushStringToList(scratch.arena, &parts, Lit("Shift")); + } + PushStringToList(scratch.arena, &parts, StringFromButton(hotkey.button)); + EndScratch(scratch); + return StringFromList(arena, parts, Lit(" + ")); } //////////////////////////////////////////////////////////// @@ -58,35 +58,35 @@ String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey) V_WidgetTheme V_GetWidgetTheme(void) { - V_WidgetTheme theme = Zi; + V_WidgetTheme theme = Zi; - theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/fixedsys.ttf"))); - theme.font_size = 16; + theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/fixedsys.ttf"))); + theme.font_size = 16; - // theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/fixedsys.ttf"))); - // theme.font_size = 64; + // theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/fixedsys.ttf"))); + // theme.font_size = 64; - // theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/roboto-med.ttf"))); - // theme.font_size = 100; + // theme.font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/roboto-med.ttf"))); + // theme.font_size = 100; - theme.window_background_color = Rgb32(0xff1a1d1e); - theme.window_border_color = Rgb32(0xff343a3b); - theme.window_border = 1; - theme.window_width = 500; - theme.window_padding = theme.window_border - 1; - theme.divider_color = theme.window_border_color; + theme.window_background_color = Rgb32(0xff1a1d1e); + theme.window_border_color = Rgb32(0xff343a3b); + theme.window_border = 1; + theme.window_width = 500; + theme.window_padding = theme.window_border - 1; + theme.divider_color = theme.window_border_color; - theme.window_title_font_size = 16; - theme.text_padding_x = 3; - theme.text_padding_y = 3; + theme.window_title_font_size = 16; + theme.text_padding_x = 3; + theme.text_padding_y = 3; - return theme; + return theme; } void V_PushWidgetThemeStyles(V_WidgetTheme theme) { - UI_Push(Font, theme.font); - UI_Push(FontSize, theme.font_size); + UI_Push(Font, theme.font); + UI_Push(FontSize, theme.font_size); } //////////////////////////////////////////////////////////// @@ -94,223 +94,222 @@ void V_PushWidgetThemeStyles(V_WidgetTheme theme) void V_BeginCommandsWidget(V_CommandsWidget *widget) { - ZeroStruct(&widget->build); - widget->build.cp = UI_PushCP(UI_NilKey); - UI_Push(Tag, HashF("commands widget")); + ZeroStruct(&widget->build); + widget->build.cp = UI_PushCP(UI_NilKey); + UI_Push(Tag, HashF("commands widget")); } V_CommandsWidgetItemReport V_PushCommandsWidgetItem(V_CommandsWidget *widget, V_CommandsWidgetItemDesc desc) { - Arena *frame_arena = UI_FrameArena(); + Arena *frame_arena = UI_FrameArena(); - UI_Key key = UI_KeyF("btn%F", FmtSint(widget->build.num_items)); - { - V_CommandsWidgetItem *item = PushStruct(frame_arena, V_CommandsWidgetItem); - item->key = key; - item->desc = desc; - SllQueuePush(widget->build.first_item, widget->build.last_item, item); - ++widget->build.num_items; - } + UI_Key key = UI_KeyF("btn%F", FmtSint(widget->build.num_items)); + { + V_CommandsWidgetItem *item = PushStruct(frame_arena, V_CommandsWidgetItem); + item->key = key; + item->desc = desc; + SllQueuePush(widget->build.first_item, widget->build.last_item, item); + ++widget->build.num_items; + } - V_CommandsWidgetItemReport result = Zi; - UI_Report rep = UI_ReportFromKey(key); - result.ui_report = rep; - result.pressed = rep.m1_presses > 0; - CopyStructs(result.new_hotkeys, desc.hotkeys, MinU32(countof(result.new_hotkeys), countof(desc.hotkeys))); - return result; + V_CommandsWidgetItemReport result = Zi; + UI_Report rep = UI_ReportFromKey(key); + result.ui_report = rep; + result.pressed = rep.m1_presses > 0; + CopyStructs(result.new_hotkeys, desc.hotkeys, MinU32(countof(result.new_hotkeys), countof(desc.hotkeys))); + return result; } void V_EndCommandsWidget(V_CommandsWidget *widget) { - V_WidgetTheme theme = V_GetWidgetTheme(); - Vec2 cursor_pos = UI_CursorPos(); + V_WidgetTheme theme = V_GetWidgetTheme(); + Vec2 cursor_pos = UI_CursorPos(); - UI_Push(Tag, HashF("commands widget")); + UI_Push(Tag, HashF("commands widget")); - UI_Key titlebar_key = UI_KeyF("title bar"); + UI_Key titlebar_key = UI_KeyF("title bar"); - Vec4 window_background_color = theme.window_background_color; - Vec4 window_border_color = theme.window_border_color; - Vec4 titlebar_color = Zi; - Vec4 titlebar_border_color = Zi; - Vec4 divider_color = theme.divider_color; + Vec4 window_background_color = theme.window_background_color; + Vec4 window_border_color = theme.window_border_color; + Vec4 titlebar_color = Zi; + Vec4 titlebar_border_color = Zi; + Vec4 divider_color = theme.divider_color; + { + UI_Report rep = UI_ReportFromKey(titlebar_key); + if (rep.m1_held) { - UI_Report rep = UI_ReportFromKey(titlebar_key); - if (rep.m1_held) - { - widget->pos = SubVec2(cursor_pos, rep.last_m1_offset); - } - // window_border_color = BlendSrgb(window_border_color, Rgb(0.5, 0.5, 0.5), rep.hot); - window_border_color = BlendSrgb(window_border_color, Rgb32(0x0078a6), rep.hot); + widget->pos = SubVec2(cursor_pos, rep.last_m1_offset); } + // window_border_color = BlendSrgb(window_border_color, Rgb(0.5, 0.5, 0.5), rep.hot); + window_border_color = BlendSrgb(window_border_color, Rgb32(0x0078a6), rep.hot); + } - UI_Push(BackgroundColor, window_background_color); - UI_Push(BorderColor, window_border_color); - UI_Push(Border, theme.window_border); - // UI_Push(Rounding, UI_RPIX(15)); - UI_Push(Rounding, UI_RPIX(15)); - UI_Push(Width, UI_PIX(theme.window_width, 0)); - UI_Push(Height, UI_SHRINK(0, 0)); - UI_Push(ChildLayoutAxis, Axis_Y); - UI_Push(FloatingPos, widget->pos); - UI_SetNext(Flags, UI_BoxFlag_Floating); - UI_PushCP(UI_BuildBoxEx(UI_KeyF("titlebar"))); + UI_Push(BackgroundColor, window_background_color); + UI_Push(BorderColor, window_border_color); + UI_Push(Border, theme.window_border); + // UI_Push(Rounding, UI_RPIX(15)); + UI_Push(Rounding, UI_RPIX(15)); + UI_Push(Width, UI_PIX(theme.window_width, 0)); + UI_Push(Height, UI_SHRINK(0, 0)); + UI_Push(ChildLayoutAxis, Axis_Y); + UI_Push(FloatingPos, widget->pos); + UI_SetNext(Flags, UI_BoxFlag_Floating); + UI_PushCP(UI_BuildBoxEx(UI_KeyF("titlebar"))); + { + /* Title bar */ + UI_PushCP(UI_NilKey); { - /* Title bar */ - UI_PushCP(UI_NilKey); - { - UI_Push(BackgroundColor, titlebar_color); - UI_Push(BorderColor, titlebar_border_color); - UI_Push(Rounding, UI_RPIX(0)); - UI_Push(ChildLayoutAxis, Axis_X); - UI_Push(Width, UI_GROW(1, 0)); - UI_Push(Height, UI_FNT(2, 1)); - UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); - UI_PushCP(UI_BuildBoxEx(titlebar_key)); - { - UI_Push(Width, UI_GROW(1, 0)); - UI_Push(BorderColor, 0); + UI_Push(BackgroundColor, titlebar_color); + UI_Push(BorderColor, titlebar_border_color); + UI_Push(Rounding, UI_RPIX(0)); + UI_Push(ChildLayoutAxis, Axis_X); + UI_Push(Width, UI_GROW(1, 0)); + UI_Push(Height, UI_FNT(2, 1)); + UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); + UI_PushCP(UI_BuildBoxEx(titlebar_key)); + { + UI_Push(Width, UI_GROW(1, 0)); + UI_Push(BorderColor, 0); - /* Left title box */ - UI_BuildRow(); + /* Left title box */ + UI_BuildRow(); - /* Title box */ - UI_SetNext(FontSize, theme.window_title_font_size); - UI_SetNext(ChildAlignment, UI_Alignment_Center); - UI_SetNext(Width, UI_SHRINK(0, 1)); - UI_SetNext(Text, Lit("Commands")); - UI_SetNext(Flags, UI_BoxFlag_DrawText); - UI_BuildBox(); + /* Title box */ + UI_SetNext(FontSize, theme.window_title_font_size); + UI_SetNext(ChildAlignment, UI_Alignment_Center); + UI_SetNext(Width, UI_SHRINK(0, 1)); + UI_SetNext(Text, Lit("Commands")); + UI_SetNext(Flags, UI_BoxFlag_DrawText); + UI_BuildBox(); - /* Right title box */ - UI_BuildRow(); - } - UI_PopCP(UI_TopCP()); - } - UI_PopCP(UI_TopCP()); - } - - f32 padding = theme.window_border; - UI_SetNext(Tint, 0); - UI_SetNext(Rounding, 0); - UI_PushCP(UI_BuildRow()); - { - UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); - { - UI_SetNext(Tint, 0); - UI_SetNext(Rounding, 0); - UI_SetNext(Width, UI_GROW(1, 0)); - UI_PushCP(UI_BuildColumn()); - { - for (V_CommandsWidgetItem *item = widget->build.first_item; item; item = item->next) - { - UI_BuildDivider(UI_PIX(1, 1), theme.divider_color, Axis_Y); - - UI_Key btn_key = item->key; - UI_Report btn_rep = UI_ReportFromKey(btn_key); - - Vec4 btn_color = theme.window_background_color; - Vec4 btn_border_color = Zi; - { - Vec4 hovered_color = Rgb32(0x103c4c); - Vec4 pressed_color = hovered_color; - pressed_color.w = 0.2; - f32 btn_hot = btn_rep.hot; - f32 btn_active = btn_rep.active; - f32 btn_hovered = btn_rep.hovered; - btn_color = BlendSrgb(btn_color, hovered_color, btn_hot); - btn_color = BlendSrgb(btn_color, pressed_color, btn_active * btn_hovered); - btn_border_color = BlendSrgb(btn_border_color, Rgb32(0x0078a6), btn_hot); - } - - UI_SetNext(Rounding, 0); - UI_SetNext(Tint, 0); - UI_PushCP(UI_BuildRow()); - { - UI_SetNext(BorderColor, btn_border_color); - UI_SetNext(BackgroundColor, btn_color); - UI_SetNext(Rounding, UI_RPIX(5)); - UI_SetNext(Width, UI_GROW(1, 0)); - UI_SetNext(Height, UI_FNT(1.5, 1)); - UI_SetNext(ChildAlignment, UI_Alignment_Left); - UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); - UI_PushCP(UI_BuildRowEx(btn_key)); - { - UI_Push(Tag, btn_key.hash); - - /* Begin spacer */ - UI_BuildSpacer(UI_PIX(20, 1), Axis_X); - - /* Command label */ - UI_SetNext(ChildAlignment, UI_Alignment_Center); - UI_BuildLabel(item->desc.display_name); - - /* Middle spacer */ - UI_BuildSpacer(UI_GROW(1, 0), Axis_X); - - /* Command hotkey buttons */ - for (u64 i = 0; i < countof(item->desc.hotkeys); ++i) - { - UI_Key hotkey_key = UI_KeyF("hotkey%F", FmtUint(i)); - UI_Report hotkey_rep = UI_ReportFromKey(hotkey_key); - - Vec4 hotkey_color = Zi; - Vec4 hotkey_border_color = Zi; - { - Vec4 hovered_color = Rgb32(0x103c4c); - Vec4 pressed_color = hovered_color; - pressed_color.w = 0.2; - f32 hotkey_hot = hotkey_rep.hot; - f32 hotkey_active = hotkey_rep.active; - f32 hotkey_hovered = hotkey_rep.hovered; - hotkey_color = BlendSrgb(hotkey_color, hovered_color, hotkey_hot); - hotkey_color = BlendSrgb(hotkey_color, pressed_color, hotkey_active * hotkey_hovered); - hotkey_border_color = BlendSrgb(hotkey_border_color, Rgb32(0x0078a6), hotkey_hot); - } - - V_Hotkey hotkey = item->desc.hotkeys[i]; - if (hotkey.button == Button_None) - { - break; - } - else - { - UI_BuildSpacer(UI_PIX(10, 1), Axis_X); - - String hotkey_name = V_StringFromHotkey(UI_FrameArena(), hotkey); - UI_SetNext(BackgroundColor, hotkey_color); - UI_SetNext(BorderColor, hotkey_border_color); - UI_SetNext(Text, hotkey_name); - UI_SetNext(Width, UI_SHRINK(theme.text_padding_x, 1)); - UI_SetNext(Height, UI_GROW(1, 0)); - UI_SetNext(Rounding, UI_RPIX(5)); - UI_SetNext(Border, 1); - UI_SetNext(ChildAlignment, UI_Alignment_Center); - UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); - UI_PushCP(UI_BuildRowEx(hotkey_key)); - { - - } - UI_PopCP(UI_TopCP()); - } - } - - /* End spacer */ - UI_BuildSpacer(UI_PIX(20, 1), Axis_X); - } - UI_PopCP(UI_TopCP()); - } - UI_PopCP(UI_TopCP()); - } - } - UI_PopCP(UI_TopCP()); - } - UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); + /* Right title box */ + UI_BuildRow(); + } + UI_PopCP(UI_TopCP()); } UI_PopCP(UI_TopCP()); + } - UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); - UI_PopCP(widget->build.cp); + f32 padding = theme.window_border; + UI_SetNext(Tint, 0); + UI_SetNext(Rounding, 0); + UI_PushCP(UI_BuildRow()); + { + UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); + { + UI_SetNext(Tint, 0); + UI_SetNext(Rounding, 0); + UI_SetNext(Width, UI_GROW(1, 0)); + UI_PushCP(UI_BuildColumn()); + { + for (V_CommandsWidgetItem *item = widget->build.first_item; item; item = item->next) + { + UI_BuildDivider(UI_PIX(1, 1), theme.divider_color, Axis_Y); + + UI_Key btn_key = item->key; + UI_Report btn_rep = UI_ReportFromKey(btn_key); + + Vec4 btn_color = theme.window_background_color; + Vec4 btn_border_color = Zi; + { + Vec4 hovered_color = Rgb32(0x103c4c); + Vec4 pressed_color = hovered_color; + pressed_color.w = 0.2; + f32 btn_hot = btn_rep.hot; + f32 btn_active = btn_rep.active; + f32 btn_hovered = btn_rep.hovered; + btn_color = BlendSrgb(btn_color, hovered_color, btn_hot); + btn_color = BlendSrgb(btn_color, pressed_color, btn_active * btn_hovered); + btn_border_color = BlendSrgb(btn_border_color, Rgb32(0x0078a6), btn_hot); + } + + UI_SetNext(Rounding, 0); + UI_SetNext(Tint, 0); + UI_PushCP(UI_BuildRow()); + { + UI_SetNext(BorderColor, btn_border_color); + UI_SetNext(BackgroundColor, btn_color); + UI_SetNext(Rounding, UI_RPIX(5)); + UI_SetNext(Width, UI_GROW(1, 0)); + UI_SetNext(Height, UI_FNT(1.5, 1)); + UI_SetNext(ChildAlignment, UI_Alignment_Left); + UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); + UI_PushCP(UI_BuildRowEx(btn_key)); + { + UI_Push(Tag, btn_key.hash); + + /* Begin spacer */ + UI_BuildSpacer(UI_PIX(20, 1), Axis_X); + + /* Command label */ + UI_SetNext(ChildAlignment, UI_Alignment_Center); + UI_BuildLabel(item->desc.display_name); + + /* Middle spacer */ + UI_BuildSpacer(UI_GROW(1, 0), Axis_X); + + /* Command hotkey buttons */ + for (u64 i = 0; i < countof(item->desc.hotkeys); ++i) + { + UI_Key hotkey_key = UI_KeyF("hotkey%F", FmtUint(i)); + UI_Report hotkey_rep = UI_ReportFromKey(hotkey_key); + + Vec4 hotkey_color = Zi; + Vec4 hotkey_border_color = Zi; + { + Vec4 hovered_color = Rgb32(0x103c4c); + Vec4 pressed_color = hovered_color; + pressed_color.w = 0.2; + f32 hotkey_hot = hotkey_rep.hot; + f32 hotkey_active = hotkey_rep.active; + f32 hotkey_hovered = hotkey_rep.hovered; + hotkey_color = BlendSrgb(hotkey_color, hovered_color, hotkey_hot); + hotkey_color = BlendSrgb(hotkey_color, pressed_color, hotkey_active * hotkey_hovered); + hotkey_border_color = BlendSrgb(hotkey_border_color, Rgb32(0x0078a6), hotkey_hot); + } + + V_Hotkey hotkey = item->desc.hotkeys[i]; + if (hotkey.button == Button_None) + { + break; + } + else + { + UI_BuildSpacer(UI_PIX(10, 1), Axis_X); + + String hotkey_name = V_StringFromHotkey(UI_FrameArena(), hotkey); + UI_SetNext(BackgroundColor, hotkey_color); + UI_SetNext(BorderColor, hotkey_border_color); + UI_SetNext(Text, hotkey_name); + UI_SetNext(Width, UI_SHRINK(theme.text_padding_x, 1)); + UI_SetNext(Height, UI_GROW(1, 0)); + UI_SetNext(Rounding, UI_RPIX(5)); + UI_SetNext(Border, 1); + UI_SetNext(ChildAlignment, UI_Alignment_Center); + UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); + UI_PushCP(UI_BuildRowEx(hotkey_key)); + { + } + UI_PopCP(UI_TopCP()); + } + } + + /* End spacer */ + UI_BuildSpacer(UI_PIX(20, 1), Axis_X); + } + UI_PopCP(UI_TopCP()); + } + UI_PopCP(UI_TopCP()); + } + } + UI_PopCP(UI_TopCP()); + } + UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); + } + UI_PopCP(UI_TopCP()); + + UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); + UI_PopCP(widget->build.cp); } //////////////////////////////////////////////////////////// @@ -318,1207 +317,1207 @@ void V_EndCommandsWidget(V_CommandsWidget *widget) void V_TickForever(WaveLaneCtx *lane) { - Arena *perm = PermArena(); - G_ArenaHandle gpu_perm = G_PermArena(); + Arena *perm = PermArena(); + G_ArenaHandle gpu_perm = G_PermArena(); - const i32 world_size = S_WorldSize; - const f32 zoom_rate = 1.50; - const f32 min_zoom = 0.03; - const f32 max_zoom = 15.0; - const f32 meters_per_draw_width = 18; + const i32 world_size = S_WorldSize; + const f32 zoom_rate = 1.50; + const f32 min_zoom = 0.03; + const f32 max_zoom = 15.0; + const f32 meters_per_draw_width = 18; + + ////////////////////////////// + //- Init vis state + + V.world_arena = AcquireArena(Gibi(64)); + V.world = PushStruct(V.world_arena, S_World); + V.player_key = S_RandKey(); + + Vec2I32 tiles_dims = VEC2I32(world_size * 2, world_size * 2); + u8 *tiles = PushBytes(perm, tiles_dims.x * tiles_dims.y, alignof(S_TileKind)); + G_ResourceHandle gpu_tiles = Zi; + G_Texture2DRef gpu_tiles_ref = Zi; + { + G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct); + { + gpu_tiles = G_PushTexture2D( + gpu_perm, cl, + G_Format_R8_Uint, + tiles_dims, + G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite + ); + gpu_tiles_ref = G_PushTexture2DRef(gpu_perm, gpu_tiles); + /* TODO: Clear tiles from GPU (instead of copy from cpu) */ + G_CopyCpuToTexture( + cl, + gpu_tiles, VEC3I32(0, 0, 0), + tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1), + RNG3I32(VEC3I32(0, 0, 0), VEC3I32(tiles_dims.x, tiles_dims.y, 1)) + ); + } + G_CommitCommandList(cl); + } + + for (u32 i = 0; i < countof(V.frames); ++i) + { + V_Frame *frame = &V.frames[i]; + frame->arena = AcquireArena(Gibi(64)); + frame->dverts_arena = AcquireArena(Gibi(64)); + frame->dvert_idxs_arena = AcquireArena(Gibi(64)); + frame->gpu_arena = G_AcquireArena(); + } + + ////////////////////////////// + //- State + + /* Init shortcuts */ + u64 shortcut_bins_count = 1024; + V_ShortcutBin *shortcut_bins = PushStructs(perm, V_ShortcutBin, shortcut_bins_count); + { + for (u64 desc_idx = 1; desc_idx < countof(V_cmd_descs); ++desc_idx) + { + V_CmdDesc desc = V_cmd_descs[desc_idx]; + for (u64 hotkey_idx = 0; hotkey_idx < countof(desc.default_hotkeys); ++hotkey_idx) + { + V_Hotkey hotkey = desc.default_hotkeys[hotkey_idx]; + if (hotkey.button == Button_None) + { + break; + } + else + { + u64 hotkey_hash = HashFnv64(Fnv64Basis, StringFromStruct(&hotkey)); + V_ShortcutBin *bin = &shortcut_bins[hotkey_hash % shortcut_bins_count]; + V_Shortcut *shortcut = PushStruct(perm, V_Shortcut); + shortcut->hotkey_hash = hotkey_hash; + shortcut->hotkey = hotkey; + shortcut->cmd_name = desc.name; + DllQueuePushNP(bin->first, bin->last, shortcut, next_in_bin, prev_in_bin); + } + } + } + } + + ////////////////////////////// + //- Swap in + + // if (IsSwappedIn()) + // { + // TempArena scratch = BeginScratchNoConflict(); + // { + // String swap_encoded = SwappedStateFromName(scratch.arena, Lit("pp_vis")); + // BB_Buff bb = BB_BuffFromString(swap_encoded); + // BB_Reader br = BB_ReaderFromBuff(&bb); + // String swap_str = BB_ReadString(scratch.arena, &br); + // if (swap_str.len == sizeof(Persist)) + // { + // CopyBytes(&persist, swap_str.text, swap_str.len); + // } + // window_restore = BB_ReadString(perm, &br); + // } + // EndScratch(scratch); + // } + + ////////////////////////////// + //- Begin vis loop + + b32 shutdown = 0; + while (!shutdown) + { + u64 last_frame_idx = V.current_frame_idx; + u64 frame_idx = last_frame_idx + 1; + if (frame_idx >= countof(V.frames)) + { + frame_idx = 0; + } + V.current_frame_idx = frame_idx; + V_Frame *last_frame = &V.frames[last_frame_idx]; + V_Frame *frame = &V.frames[frame_idx]; ////////////////////////////// - //- Init vis state + //- Begin frame - V.world_arena = AcquireArena(Gibi(64)); - V.world = PushStruct(V.world_arena, S_World); - V.player_key = S_RandKey(); - - Vec2I32 tiles_dims = VEC2I32(world_size * 2, world_size * 2); - u8 *tiles = PushBytes(perm, tiles_dims.x * tiles_dims.y, alignof(S_TileKind)); - G_ResourceHandle gpu_tiles = Zi; - G_Texture2DRef gpu_tiles_ref = Zi; { - G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct); + Arena *old_arena = frame->arena; + Arena *old_dverts_arena = frame->dverts_arena; + Arena *old_dvert_idxs_arena = frame->dvert_idxs_arena; + G_ArenaHandle old_gpu_arena = frame->gpu_arena; + ZeroStruct(frame); + frame->arena = old_arena; + frame->dverts_arena = old_dverts_arena; + frame->dvert_idxs_arena = old_dvert_idxs_arena; + frame->gpu_arena = old_gpu_arena; + } + frame->cl = G_PrepareCommandList(G_QueueKind_Direct); + ResetArena(frame->arena); + ResetArena(frame->dverts_arena); + ResetArena(frame->dvert_idxs_arena); + G_ResetArena(frame->cl, frame->gpu_arena); + + /* Persist state */ + CopyBytes(frame->held_buttons, last_frame->held_buttons, sizeof(frame->held_buttons)); + frame->commands_widget = last_frame->commands_widget; + frame->is_editing = last_frame->is_editing; + frame->ui_debug = last_frame->ui_debug; + frame->show_command_palette = last_frame->show_command_palette; + frame->show_console = last_frame->show_console; + frame->edit_camera_pos = last_frame->edit_camera_pos; + frame->edit_camera_zoom = last_frame->edit_camera_zoom; + frame->look = last_frame->look; + + frame->time_ns = TimeNs(); + frame->tick = last_frame->tick + 1; + frame->dt_ns = frame->time_ns - last_frame->time_ns; + frame->dt = SecondsFromNs(frame->dt_ns); + + S_Iter iter = Zi; + + ////////////////////////////// + //- Spawn test ents + + if (frame->tick == 1) + { + S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Spawn); + S_Ent *ent = &cmd->ent; + ent->key = V.player_key; + ent->move_speed = 0.1; + { + ent->local_shape = S_ShapeFromDesc( + .mass = 10, + .count = 1, + .radius = 0.3, + ); + } + // ent->local_xf = XformFromPos(VEC2(200, 200)); + ent->xf = XformFromPos(VEC2(0, 0)); + ent->has_weapon = 1; + } + + ////////////////////////////// + //- Begin UI frame + + UI_FrameFlag ui_frame_flags = 0; + Vec4 swapchain_color = V_GetWidgetTheme().window_background_color; + ui_frame_flags |= UI_FrameFlag_Debug * !!frame->ui_debug; + ui_frame_flags |= UI_FrameFlag_Vsync * !!VSYNC; + UI_Frame *ui_frame = UI_BeginFrame(ui_frame_flags, swapchain_color); + WND_Frame window_frame = ui_frame->window_frame; + + /* Restore window */ + { + if (frame->window_restore.len > 0) + { + WND_PushCmd(window_frame, .kind = WND_CmdKind_Restore, .restore = frame->window_restore); + } + frame->window_restore = PushString(frame->arena, window_frame.restore); + } + + /* Set widget theme */ + V_WidgetTheme theme = V_GetWidgetTheme(); + V_PushWidgetThemeStyles(theme); + + UI_Push(ChildLayoutAxis, Axis_Y); + UI_Push(Width, UI_GROW(1, 0)); + UI_Push(Height, UI_GROW(1, 0)); + UI_Key vis_box = UI_KeyF("vis box"); + UI_Push(Parent, UI_BuildColumnEx(vis_box)); + + { + /* TODO: Don't rely on ui report for draw size since it introduces one frame of delay when resizing */ + UI_Report vis_rep = UI_ReportFromKey(vis_box); + frame->ui_dims = RoundVec2ToI32(DimsFromRng2(vis_rep.screen_rect)); + } + frame->ui_dims.x = MaxI32(frame->ui_dims.x, 64); + frame->ui_dims.y = MaxI32(frame->ui_dims.y, 64); + frame->draw_dims = frame->ui_dims; + + ////////////////////////////// + //- Pop sim output + + S_OutputState *sim_output = 0; + LockTicketMutex(&S.output_back_tm); + { + sim_output = &S.output_states[S.output_back_idx]; + ++S.output_back_idx; + if (S.output_back_idx >= countof(S.output_states)) + { + S.output_back_idx = 0; + } + } + UnlockTicketMutex(&S.output_back_tm); + + ////////////////////////////// + //- Update tiles from sim + + { + for (S_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next) + { + S_Snapshot *snapshot = &n->snapshot; + if (snapshot->tick > V.world->tick) { - gpu_tiles = G_PushTexture2D( - gpu_perm, cl, - G_Format_R8_Uint, - tiles_dims, - G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite - ); - gpu_tiles_ref = G_PushTexture2DRef(gpu_perm, gpu_tiles); - /* TODO: Clear tiles from GPU (instead of copy from cpu) */ + for (u64 placement_idx = 0; placement_idx < snapshot->tile_placements_count; ++placement_idx) + { + S_TilePlacement placement = snapshot->tile_placements[placement_idx]; + Rng2I32 dirty_rect = S_UpdateTilesInPlaceFromPlacement(tiles, placement); G_CopyCpuToTexture( - cl, - gpu_tiles, VEC3I32(0, 0, 0), - tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1), - RNG3I32(VEC3I32(0, 0, 0), VEC3I32(tiles_dims.x, tiles_dims.y, 1)) + frame->cl, + gpu_tiles, VEC3I32(dirty_rect.p0.x, dirty_rect.p0.y, 0), + tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1), + RNG3I32(VEC3I32(dirty_rect.p0.x, dirty_rect.p0.y, 0), VEC3I32(dirty_rect.p1.x, dirty_rect.p1.y, 1)) ); + } } - G_CommitCommandList(cl); - } - - for (u32 i = 0; i < countof(V.frames); ++i) - { - V_Frame *frame = &V.frames[i]; - frame->arena = AcquireArena(Gibi(64)); - frame->dverts_arena = AcquireArena(Gibi(64)); - frame->dvert_idxs_arena = AcquireArena(Gibi(64)); - frame->gpu_arena = G_AcquireArena(); + } } ////////////////////////////// - //- State + //- Update world from sim - /* Init shortcuts */ - u64 shortcut_bins_count = 1024; - V_ShortcutBin *shortcut_bins = PushStructs(perm, V_ShortcutBin, shortcut_bins_count); + if (sim_output->last_snapshot_node && sim_output->last_snapshot_node->snapshot.tick > V.world->tick) { - for (u64 desc_idx = 1; desc_idx < countof(V_cmd_descs); ++desc_idx) - { - V_CmdDesc desc = V_cmd_descs[desc_idx]; - for (u64 hotkey_idx = 0; hotkey_idx < countof(desc.default_hotkeys); ++hotkey_idx) - { - V_Hotkey hotkey = desc.default_hotkeys[hotkey_idx]; - if (hotkey.button == Button_None) - { - break; - } - else - { - u64 hotkey_hash = HashFnv64(Fnv64Basis, StringFromStruct(&hotkey)); - V_ShortcutBin *bin = &shortcut_bins[hotkey_hash % shortcut_bins_count]; - V_Shortcut *shortcut = PushStruct(perm, V_Shortcut); - shortcut->hotkey_hash = hotkey_hash; - shortcut->hotkey = hotkey; - shortcut->cmd_name = desc.name; - DllQueuePushNP(bin->first, bin->last, shortcut, next_in_bin, prev_in_bin); - } - } - } + ResetArena(V.world_arena); + V.world = S_WorldFromSnapshot(V.world_arena, &sim_output->last_snapshot_node->snapshot); + V.lookup = S_LookupFromWorld(V.world_arena, V.world); } ////////////////////////////// - //- Swap in + //- Process controller events into vis cmds - // if (IsSwappedIn()) - // { - // TempArena scratch = BeginScratchNoConflict(); - // { - // String swap_encoded = SwappedStateFromName(scratch.arena, Lit("pp_vis")); - // BB_Buff bb = BB_BuffFromString(swap_encoded); - // BB_Reader br = BB_ReaderFromBuff(&bb); - // String swap_str = BB_ReadString(scratch.arena, &br); - // if (swap_str.len == sizeof(Persist)) - // { - // CopyBytes(&persist, swap_str.text, swap_str.len); - // } - // window_restore = BB_ReadString(perm, &br); - // } - // EndScratch(scratch); - // } + u64 cmds_count = 0; + V_CmdNode *first_cmd_node = 0; + V_CmdNode *last_cmd_node = 0; + + if (!window_frame.has_focus) + { + ZeroStructs(frame->held_buttons, countof(frame->held_buttons)); + } + for (u64 i = 0; i < window_frame.controller_events.count; ++i) + { + ControllerEvent cev = window_frame.controller_events.events[i]; + b32 down = cev.kind == ControllerEventKind_ButtonDown; + b32 up = cev.kind == ControllerEventKind_ButtonUp; + if (down || up) + { + V_Hotkey hotkey = Zi; + hotkey.button = cev.button; + hotkey.ctrl = frame->held_buttons[Button_Ctrl]; + hotkey.shift = frame->held_buttons[Button_Shift]; + hotkey.alt = frame->held_buttons[Button_Alt]; + { + u64 hotkey_hash = HashFnv64(Fnv64Basis, StringFromStruct(&hotkey)); + V_ShortcutBin *bin = &shortcut_bins[hotkey_hash % shortcut_bins_count]; + V_Shortcut *shortcut = bin->first; + for (; shortcut; shortcut = shortcut->next_in_bin) + { + if (shortcut->hotkey_hash == hotkey_hash && MatchStruct(&shortcut->hotkey, &hotkey)) + { + break; + } + } + if (shortcut != 0 && down) + { + V_CmdNode *cmd_node = PushStruct(frame->arena, V_CmdNode); + cmd_node->cmd.name = shortcut->cmd_name; + SllQueuePush(first_cmd_node, last_cmd_node, cmd_node); + ++cmds_count; + } + } + frame->held_buttons[hotkey.button] = down; + } + } ////////////////////////////// - //- Begin vis loop + //- Initialize world <-> draw <-> ui transforms - b32 shutdown = 0; - while (!shutdown) + /* World <-> ui */ + frame->world_to_ui_xf = XformIdentity; + frame->ui_to_world_xf = XformIdentity; { - u64 last_frame_idx = V.current_frame_idx; - u64 frame_idx = last_frame_idx + 1; - if (frame_idx >= countof(V.frames)) + /* Determine target camera pos */ + Vec2 target_camera_pos = Zi; + f32 target_camera_zoom = 0; + if (frame->is_editing) + { + b32 pan_button = Button_M3; + frame->is_panning = frame->held_buttons[pan_button] != 0; + frame->edit_camera_zoom *= PowF32(zoom_rate, -last_frame->zooms); + if (frame->edit_camera_zoom <= 0) { - frame_idx = 0; + frame->edit_camera_pos = S_EntFromKey(&V.lookup, V.player_key)->xf.og; + frame->edit_camera_zoom = 3; } - V.current_frame_idx = frame_idx; - V_Frame *last_frame = &V.frames[last_frame_idx]; - V_Frame *frame = &V.frames[frame_idx]; - - ////////////////////////////// - //- Begin frame - + frame->edit_camera_zoom = ClampF32(frame->edit_camera_zoom, min_zoom, max_zoom); + /* Offset edit camera based on cursor if panning / zooming */ + b32 is_zooming = last_frame->zooms != 0 && (frame->edit_camera_zoom != last_frame->edit_camera_zoom); + if (last_frame->is_editing && (is_zooming || (frame->is_panning && last_frame->is_panning))) { - Arena *old_arena = frame->arena; - Arena *old_dverts_arena = frame->dverts_arena; - Arena *old_dvert_idxs_arena = frame->dvert_idxs_arena; - G_ArenaHandle old_gpu_arena = frame->gpu_arena; - ZeroStruct(frame); - frame->arena = old_arena; - frame->dverts_arena = old_dverts_arena; - frame->dvert_idxs_arena = old_dvert_idxs_arena; - frame->gpu_arena = old_gpu_arena; + Xform last_frame_edit_to_ui_xf = Zi; + Xform edit_to_ui_xf = Zi; + { + f32 last_edit_camera_scale = (f32)last_frame->draw_dims.x / (meters_per_draw_width * last_frame->edit_camera_zoom); + f32 edit_camera_scale = (f32)frame->draw_dims.x / (meters_per_draw_width * frame->edit_camera_zoom); + last_frame_edit_to_ui_xf = XformFromScale(VEC2(last_edit_camera_scale, last_edit_camera_scale)); + last_frame_edit_to_ui_xf = TranslateXform(last_frame_edit_to_ui_xf, NegVec2(last_frame->edit_camera_pos)); + last_frame_edit_to_ui_xf = WorldTranslateXform(last_frame_edit_to_ui_xf, MulVec2(Vec2FromVec(frame->draw_dims), 0.5)); + edit_to_ui_xf = XformFromScale(VEC2(edit_camera_scale, edit_camera_scale)); + edit_to_ui_xf = TranslateXform(edit_to_ui_xf, NegVec2(frame->edit_camera_pos)); + edit_to_ui_xf = WorldTranslateXform(edit_to_ui_xf, MulVec2(Vec2FromVec(frame->draw_dims), 0.5)); + } + Vec2 last_target_cursor = MulXformV2(InvertXform(last_frame_edit_to_ui_xf), last_frame->ui_cursor); + Vec2 target_cursor = MulXformV2(InvertXform(edit_to_ui_xf), ui_frame->cursor_pos); + Vec2 diff = SubVec2(last_target_cursor, target_cursor); + frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, diff); } - frame->cl = G_PrepareCommandList(G_QueueKind_Direct); - ResetArena(frame->arena); - ResetArena(frame->dverts_arena); - ResetArena(frame->dvert_idxs_arena); - G_ResetArena(frame->cl, frame->gpu_arena); + frame->edit_camera_pos.x = ClampF32(frame->edit_camera_pos.x, -world_size / 2, world_size / 2); + frame->edit_camera_pos.y = ClampF32(frame->edit_camera_pos.y, -world_size / 2, world_size / 2); + target_camera_pos = frame->edit_camera_pos; + target_camera_zoom = frame->edit_camera_zoom; + } + else + { + Vec2 look_ratio = Zi; + look_ratio.y = 0.25; + look_ratio.x = look_ratio.y / (16.0 / 9.0); + S_Ent *player = S_EntFromKey(&V.lookup, V.player_key); + target_camera_pos = MulXformV2(player->xf, player->local_shape.centroid); + target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(player->look, look_ratio)); + target_camera_zoom = 1; + } + target_camera_pos.x = ClampF32(target_camera_pos.x, -world_size / 2, world_size / 2); + target_camera_pos.y = ClampF32(target_camera_pos.y, -world_size / 2, world_size / 2); + target_camera_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom); - /* Persist state */ - CopyBytes(frame->held_buttons, last_frame->held_buttons, sizeof(frame->held_buttons)); - frame->commands_widget = last_frame->commands_widget; - frame->is_editing = last_frame->is_editing; - frame->ui_debug = last_frame->ui_debug; - frame->show_command_palette = last_frame->show_command_palette; - frame->show_console = last_frame->show_console; - frame->edit_camera_pos = last_frame->edit_camera_pos; - frame->edit_camera_zoom = last_frame->edit_camera_zoom; - frame->look = last_frame->look; - - frame->time_ns = TimeNs(); - frame->tick = last_frame->tick + 1; - frame->dt_ns = frame->time_ns - last_frame->time_ns; - frame->dt = SecondsFromNs(frame->dt_ns); - - S_Iter iter = Zi; - - ////////////////////////////// - //- Spawn test ents - - if (frame->tick == 1) + /* Create world <-> ui xforms */ + { + f32 lerp_ratio = 15.0 * frame->dt; + if (last_frame->tick == 0) { - S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Spawn); - S_Ent *ent = &cmd->ent; - ent->key = V.player_key; - ent->move_speed = 0.1; + lerp_ratio = 1; + } + else if (frame->is_editing) + { + lerp_ratio = 30.0 * frame->dt; + } + frame->camera_pos = LerpVec2(last_frame->camera_pos, target_camera_pos, lerp_ratio); + frame->camera_zoom = LerpF32(last_frame->camera_zoom, target_camera_zoom, lerp_ratio); + { + f32 camera_scale = (f32)frame->draw_dims.x / (meters_per_draw_width * frame->camera_zoom); + frame->world_to_ui_xf = XformFromScale(VEC2(camera_scale, camera_scale)); + frame->world_to_ui_xf = TranslateXform(frame->world_to_ui_xf, NegVec2(frame->camera_pos)); + frame->world_to_ui_xf = WorldTranslateXform(frame->world_to_ui_xf, MulVec2(Vec2FromVec(frame->draw_dims), 0.5)); + frame->ui_to_world_xf = InvertXform(frame->world_to_ui_xf); + } + } + } + + /* Draw <-> ui */ + frame->draw_to_ui_xf = XformIdentity; + frame->ui_to_draw_xf = XformIdentity; + { + frame->ui_to_draw_xf = InvertXform(frame->draw_to_ui_xf); + } + + /* World <-> draw */ + frame->world_to_draw_xf = XformIdentity; + frame->draw_to_world_xf = XformIdentity; + { + frame->world_to_draw_xf = MulXform(frame->world_to_ui_xf, frame->ui_to_draw_xf); + frame->draw_to_world_xf = InvertXform(frame->world_to_draw_xf); + } + + ////////////////////////////// + //- Update cursors / selection + + frame->ui_cursor = ui_frame->cursor_pos; + frame->draw_cursor = MulXformV2(frame->ui_to_draw_xf, frame->ui_cursor); + frame->world_cursor = MulXformV2(frame->ui_to_world_xf, frame->ui_cursor); + + frame->world_selection_start = frame->world_cursor; + if (frame->is_editing) + { + b32 m1_held = frame->held_buttons[Button_M1]; + b32 m2_held = frame->held_buttons[Button_M2]; + frame->selection_mode = V_SelectionMode_Tile; + if (m1_held) + { + frame->is_selecting = 1; + frame->equipped_tile = S_TileKind_Floor; + } + else if (m2_held) + { + frame->is_selecting = 1; + frame->equipped_tile = S_TileKind_None; + } + + if (frame->is_selecting && last_frame->is_selecting) + { + frame->world_selection_start = last_frame->world_selection_start; + } + } + + frame->world_selection.p0.x = MinF32(frame->world_cursor.x, frame->world_selection_start.x); + frame->world_selection.p0.y = MinF32(frame->world_cursor.y, frame->world_selection_start.y); + frame->world_selection.p1.x = MaxF32(frame->world_cursor.x, frame->world_selection_start.x); + frame->world_selection.p1.y = MaxF32(frame->world_cursor.y, frame->world_selection_start.y); + + frame->ui_selection.p0 = MulXformV2(frame->world_to_ui_xf, frame->world_selection.p0); + frame->ui_selection.p1 = MulXformV2(frame->world_to_ui_xf, frame->world_selection.p1); + + frame->draw_selection.p0 = MulXformV2(frame->world_to_draw_xf, frame->world_selection.p0); + frame->draw_selection.p1 = MulXformV2(frame->world_to_draw_xf, frame->world_selection.p1); + + ////////////////////////////// + //- Place tiles + + /* TODO: Push vis cmd */ + + if (frame->is_editing && last_frame->is_selecting && !frame->is_selecting) + { + if (last_frame->selection_mode == V_SelectionMode_Tile) + { + /* TODO: Fix clamp when both start & end are outside of world */ + Rng2I32 tile_range = Zi; + tile_range.p0 = S_TilePosFromWorldPos(last_frame->world_selection.p0); + tile_range.p1 = S_TilePosFromWorldPos(last_frame->world_selection.p1); + tile_range.p1 = AddVec2I32(tile_range.p1, VEC2I32(1, 1)); + + S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Tile); + cmd->tile_placement.placement_kind = S_TilePlacementKind_Range; + cmd->tile_placement.tile_kind = last_frame->equipped_tile; + cmd->tile_placement.range = tile_range; + } + } + + ////////////////////////////// + //- Build editor UI + + /* TODO: Remove this (testing) */ + if (!V.root_space); + { + V_Space *space = PushStruct(perm, V_Space); + space->axis = Axis_Y; + V.root_space = space; + + { + V_Panel *panel = PushStruct(perm, V_Panel); + panel->space = space; + DllQueuePushNP(space->first_panel, space->last_panel, panel, next_in_space, prev_in_space); + ++space->panels_count; + + { + V_Window *window = PushStruct(perm, V_Window); + window->panel = panel; + // window->is_tile_window = 1; + DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); + ++panel->windows_count; + } + { + V_Window *window = PushStruct(perm, V_Window); + window->panel = panel; + window->is_tile_window = 1; + DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); + ++panel->windows_count; + } + } + + { + V_Panel *panel = PushStruct(perm, V_Panel); + panel->space = space; + DllQueuePushNP(space->first_panel, space->last_panel, panel, next_in_space, prev_in_space); + ++space->panels_count; + + { + V_Window *window = PushStruct(perm, V_Window); + window->panel = panel; + window->is_tile_window = 1; + DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); + ++panel->windows_count; + } + } + } + + if (frame->is_editing) + { + Struct(SpaceDfsNode) { SpaceDfsNode *next; b32 visited; V_Space *space; UI_Checkpoint cp; }; + SpaceDfsNode *first_space_dfs = PushStruct(frame->arena, SpaceDfsNode); + first_space_dfs->space = V.root_space; + + while (first_space_dfs) + { + SpaceDfsNode *space_dfs = first_space_dfs; + V_Space *space = space_dfs->space; + if (!space_dfs->visited) + { + space_dfs->visited = 1; + for (V_Space *child = space->last; child; child = child->prev) + { + SpaceDfsNode *n = PushStruct(frame->arena, SpaceDfsNode); + n->space = child; + SllStackPush(first_space_dfs, n); + } + + UI_Key space_key = UI_TransKey(); + if (space->axis == Axis_X) + { + UI_BuildRowEx(space_key); + } + else + { + UI_BuildColumnEx(space_key); + } + space_dfs->cp = UI_PushCP(space_key); + + for (V_Panel *panel = space->first_panel; panel; panel = panel->next_in_space) + { + i64 active_window_idx = ClampI64(panel->active_window_idx, 0, MaxI64(panel->windows_count - 1, 0)); + /* Build tabs */ + V_Window *window = 0; { - ent->local_shape = S_ShapeFromDesc( - .mass = 10, - .count = 1, - .radius = 0.3, - ); - } - // ent->local_xf = XformFromPos(VEC2(200, 200)); - ent->xf = XformFromPos(VEC2(0, 0)); - ent->has_weapon = 1; - } - - ////////////////////////////// - //- Begin UI frame - - UI_FrameFlag ui_frame_flags = 0; - Vec4 swapchain_color = V_GetWidgetTheme().window_background_color; - ui_frame_flags |= UI_FrameFlag_Debug * !!frame->ui_debug; - ui_frame_flags |= UI_FrameFlag_Vsync * !!VSYNC; - UI_Frame *ui_frame = UI_BeginFrame(ui_frame_flags, swapchain_color); - WND_Frame window_frame = ui_frame->window_frame; - - /* Restore window */ - { - if (frame->window_restore.len > 0) - { - WND_PushCmd(window_frame, .kind = WND_CmdKind_Restore, .restore = frame->window_restore); - } - frame->window_restore = PushString(frame->arena, window_frame.restore); - } - - /* Set widget theme */ - V_WidgetTheme theme = V_GetWidgetTheme(); - V_PushWidgetThemeStyles(theme); - - UI_Push(ChildLayoutAxis, Axis_Y); - UI_Push(Width, UI_GROW(1, 0)); - UI_Push(Height, UI_GROW(1, 0)); - UI_Key vis_box = UI_KeyF("vis box"); - UI_Push(Parent, UI_BuildColumnEx(vis_box)); - - { - /* TODO: Don't rely on ui report for draw size since it introduces one frame of delay when resizing */ - UI_Report vis_rep = UI_ReportFromKey(vis_box); - frame->ui_dims = RoundVec2ToI32(DimsFromRng2(vis_rep.screen_rect)); - } - frame->ui_dims.x = MaxI32(frame->ui_dims.x, 64); - frame->ui_dims.y = MaxI32(frame->ui_dims.y, 64); - frame->draw_dims = frame->ui_dims; - - ////////////////////////////// - //- Pop sim output - - S_OutputState *sim_output = 0; - LockTicketMutex(&S.output_back_tm); - { - sim_output = &S.output_states[S.output_back_idx]; - ++S.output_back_idx; - if (S.output_back_idx >= countof(S.output_states)) - { - S.output_back_idx = 0; - } - } - UnlockTicketMutex(&S.output_back_tm); - - ////////////////////////////// - //- Update tiles from sim - - { - for (S_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next) - { - S_Snapshot *snapshot = &n->snapshot; - if (snapshot->tick > V.world->tick) + UI_SetNext(Width, UI_SHRINK(0, 1)); + UI_SetNext(Height, UI_SHRINK(0, 1)); + UI_PushCP(UI_BuildRow()); + i64 window_idx = 0; + for (V_Window *tab_window = panel->first_window; tab_window; tab_window = tab_window->next_in_panel) + { + if (window_idx == active_window_idx) { - for (u64 placement_idx = 0; placement_idx < snapshot->tile_placements_count; ++placement_idx) - { - S_TilePlacement placement = snapshot->tile_placements[placement_idx]; - Rng2I32 dirty_rect = S_UpdateTilesInPlaceFromPlacement(tiles, placement); - G_CopyCpuToTexture( - frame->cl, - gpu_tiles, VEC3I32(dirty_rect.p0.x, dirty_rect.p0.y, 0), - tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1), - RNG3I32(VEC3I32(dirty_rect.p0.x, dirty_rect.p0.y, 0), VEC3I32(dirty_rect.p1.x, dirty_rect.p1.y, 1)) - ); - } - } - } - } - - ////////////////////////////// - //- Update world from sim - - if (sim_output->last_snapshot_node && sim_output->last_snapshot_node->snapshot.tick > V.world->tick) - { - ResetArena(V.world_arena); - V.world = S_WorldFromSnapshot(V.world_arena, &sim_output->last_snapshot_node->snapshot); - V.lookup = S_LookupFromWorld(V.world_arena, V.world); - } - - ////////////////////////////// - //- Process controller events into vis cmds - - u64 cmds_count = 0; - V_CmdNode *first_cmd_node = 0; - V_CmdNode *last_cmd_node = 0; - - if (!window_frame.has_focus) - { - ZeroStructs(frame->held_buttons, countof(frame->held_buttons)); - } - for (u64 i = 0; i < window_frame.controller_events.count; ++i) - { - ControllerEvent cev = window_frame.controller_events.events[i]; - b32 down = cev.kind == ControllerEventKind_ButtonDown; - b32 up = cev.kind == ControllerEventKind_ButtonUp; - if (down || up) - { - V_Hotkey hotkey = Zi; - hotkey.button = cev.button; - hotkey.ctrl = frame->held_buttons[Button_Ctrl]; - hotkey.shift = frame->held_buttons[Button_Shift]; - hotkey.alt = frame->held_buttons[Button_Alt]; - { - u64 hotkey_hash = HashFnv64(Fnv64Basis, StringFromStruct(&hotkey)); - V_ShortcutBin *bin = &shortcut_bins[hotkey_hash % shortcut_bins_count]; - V_Shortcut *shortcut = bin->first; - for (; shortcut; shortcut = shortcut->next_in_bin) - { - if (shortcut->hotkey_hash == hotkey_hash && MatchStruct(&shortcut->hotkey, &hotkey)) - { - break; - } - } - if (shortcut != 0 && down) - { - V_CmdNode *cmd_node = PushStruct(frame->arena, V_CmdNode); - cmd_node->cmd.name = shortcut->cmd_name; - SllQueuePush(first_cmd_node, last_cmd_node, cmd_node); - ++cmds_count; - } - } - frame->held_buttons[hotkey.button] = down; - } - } - - ////////////////////////////// - //- Initialize world <-> draw <-> ui transforms - - /* World <-> ui */ - frame->world_to_ui_xf = XformIdentity; - frame->ui_to_world_xf = XformIdentity; - { - /* Determine target camera pos */ - Vec2 target_camera_pos = Zi; - f32 target_camera_zoom = 0; - if (frame->is_editing) - { - b32 pan_button = Button_M3; - frame->is_panning = frame->held_buttons[pan_button] != 0; - frame->edit_camera_zoom *= PowF32(zoom_rate, -last_frame->zooms); - if (frame->edit_camera_zoom <= 0) - { - frame->edit_camera_pos = S_EntFromKey(&V.lookup, V.player_key)->xf.og; - frame->edit_camera_zoom = 3; - } - frame->edit_camera_zoom = ClampF32(frame->edit_camera_zoom, min_zoom, max_zoom); - /* Offset edit camera based on cursor if panning / zooming */ - b32 is_zooming = last_frame->zooms != 0 && (frame->edit_camera_zoom != last_frame->edit_camera_zoom); - if (last_frame->is_editing && (is_zooming || (frame->is_panning && last_frame->is_panning))) - { - Xform last_frame_edit_to_ui_xf = Zi; - Xform edit_to_ui_xf = Zi; - { - f32 last_edit_camera_scale = (f32)last_frame->draw_dims.x / (meters_per_draw_width * last_frame->edit_camera_zoom); - f32 edit_camera_scale = (f32)frame->draw_dims.x / (meters_per_draw_width * frame->edit_camera_zoom); - last_frame_edit_to_ui_xf = XformFromScale(VEC2(last_edit_camera_scale, last_edit_camera_scale)); - last_frame_edit_to_ui_xf = TranslateXform(last_frame_edit_to_ui_xf, NegVec2(last_frame->edit_camera_pos)); - last_frame_edit_to_ui_xf = WorldTranslateXform(last_frame_edit_to_ui_xf, MulVec2(Vec2FromVec(frame->draw_dims), 0.5)); - edit_to_ui_xf = XformFromScale(VEC2(edit_camera_scale, edit_camera_scale)); - edit_to_ui_xf = TranslateXform(edit_to_ui_xf, NegVec2(frame->edit_camera_pos)); - edit_to_ui_xf = WorldTranslateXform(edit_to_ui_xf, MulVec2(Vec2FromVec(frame->draw_dims), 0.5)); - } - Vec2 last_target_cursor = MulXformV2(InvertXform(last_frame_edit_to_ui_xf), last_frame->ui_cursor); - Vec2 target_cursor = MulXformV2(InvertXform(edit_to_ui_xf), ui_frame->cursor_pos); - Vec2 diff = SubVec2(last_target_cursor, target_cursor); - frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, diff); - } - frame->edit_camera_pos.x = ClampF32(frame->edit_camera_pos.x, -world_size / 2, world_size / 2); - frame->edit_camera_pos.y = ClampF32(frame->edit_camera_pos.y, -world_size / 2, world_size / 2); - target_camera_pos = frame->edit_camera_pos; - target_camera_zoom = frame->edit_camera_zoom; - } - else - { - Vec2 look_ratio = Zi; - look_ratio.y = 0.25; - look_ratio.x = look_ratio.y / (16.0 / 9.0); - S_Ent *player = S_EntFromKey(&V.lookup, V.player_key); - target_camera_pos = MulXformV2(player->xf, player->local_shape.centroid); - target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(player->look, look_ratio)); - target_camera_zoom = 1; - } - target_camera_pos.x = ClampF32(target_camera_pos.x, -world_size / 2, world_size / 2); - target_camera_pos.y = ClampF32(target_camera_pos.y, -world_size / 2, world_size / 2); - target_camera_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom); - - /* Create world <-> ui xforms */ - { - f32 lerp_ratio = 15.0 * frame->dt; - if (last_frame->tick == 0) - { - lerp_ratio = 1; - } - else if (frame->is_editing) - { - lerp_ratio = 30.0 * frame->dt; - } - frame->camera_pos = LerpVec2(last_frame->camera_pos, target_camera_pos, lerp_ratio); - frame->camera_zoom = LerpF32(last_frame->camera_zoom, target_camera_zoom, lerp_ratio); - { - f32 camera_scale = (f32)frame->draw_dims.x / (meters_per_draw_width * frame->camera_zoom); - frame->world_to_ui_xf = XformFromScale(VEC2(camera_scale, camera_scale)); - frame->world_to_ui_xf = TranslateXform(frame->world_to_ui_xf, NegVec2(frame->camera_pos)); - frame->world_to_ui_xf = WorldTranslateXform(frame->world_to_ui_xf, MulVec2(Vec2FromVec(frame->draw_dims), 0.5)); - frame->ui_to_world_xf = InvertXform(frame->world_to_ui_xf); - } - } - } - - /* Draw <-> ui */ - frame->draw_to_ui_xf = XformIdentity; - frame->ui_to_draw_xf = XformIdentity; - { - frame->ui_to_draw_xf = InvertXform(frame->draw_to_ui_xf); - } - - /* World <-> draw */ - frame->world_to_draw_xf = XformIdentity; - frame->draw_to_world_xf = XformIdentity; - { - frame->world_to_draw_xf = MulXform(frame->world_to_ui_xf, frame->ui_to_draw_xf); - frame->draw_to_world_xf = InvertXform(frame->world_to_draw_xf); - } - - ////////////////////////////// - //- Update cursors / selection - - frame->ui_cursor = ui_frame->cursor_pos; - frame->draw_cursor = MulXformV2(frame->ui_to_draw_xf, frame->ui_cursor); - frame->world_cursor = MulXformV2(frame->ui_to_world_xf, frame->ui_cursor); - - frame->world_selection_start = frame->world_cursor; - if (frame->is_editing) - { - b32 m1_held = frame->held_buttons[Button_M1]; - b32 m2_held = frame->held_buttons[Button_M2]; - frame->selection_mode = V_SelectionMode_Tile; - if (m1_held) - { - frame->is_selecting = 1; - frame->equipped_tile = S_TileKind_Floor; - } - else if (m2_held) - { - frame->is_selecting = 1; - frame->equipped_tile = S_TileKind_None; - } - - if (frame->is_selecting && last_frame->is_selecting) - { - frame->world_selection_start = last_frame->world_selection_start; - } - } - - frame->world_selection.p0.x = MinF32(frame->world_cursor.x, frame->world_selection_start.x); - frame->world_selection.p0.y = MinF32(frame->world_cursor.y, frame->world_selection_start.y); - frame->world_selection.p1.x = MaxF32(frame->world_cursor.x, frame->world_selection_start.x); - frame->world_selection.p1.y = MaxF32(frame->world_cursor.y, frame->world_selection_start.y); - - frame->ui_selection.p0 = MulXformV2(frame->world_to_ui_xf, frame->world_selection.p0); - frame->ui_selection.p1 = MulXformV2(frame->world_to_ui_xf, frame->world_selection.p1); - - frame->draw_selection.p0 = MulXformV2(frame->world_to_draw_xf, frame->world_selection.p0); - frame->draw_selection.p1 = MulXformV2(frame->world_to_draw_xf, frame->world_selection.p1); - - ////////////////////////////// - //- Place tiles - - /* TODO: Push vis cmd */ - - if (frame->is_editing && last_frame->is_selecting && !frame->is_selecting) - { - if (last_frame->selection_mode == V_SelectionMode_Tile) - { - /* TODO: Fix clamp when both start & end are outside of world */ - Rng2I32 tile_range = Zi; - tile_range.p0 = S_TilePosFromWorldPos(last_frame->world_selection.p0); - tile_range.p1 = S_TilePosFromWorldPos(last_frame->world_selection.p1); - tile_range.p1 = AddVec2I32(tile_range.p1, VEC2I32(1, 1)); - - S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Tile); - cmd->tile_placement.placement_kind = S_TilePlacementKind_Range; - cmd->tile_placement.tile_kind = last_frame->equipped_tile; - cmd->tile_placement.range = tile_range; - } - } - - ////////////////////////////// - //- Build editor UI - - /* TODO: Remove this (testing) */ - if (!V.root_space); - { - V_Space *space = PushStruct(perm, V_Space); - space->axis = Axis_Y; - V.root_space = space; - - { - V_Panel *panel = PushStruct(perm, V_Panel); - panel->space = space; - DllQueuePushNP(space->first_panel, space->last_panel, panel, next_in_space, prev_in_space); - ++space->panels_count; - - { - V_Window *window = PushStruct(perm, V_Window); - window->panel = panel; - // window->is_tile_window = 1; - DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); - ++panel->windows_count; - } - { - V_Window *window = PushStruct(perm, V_Window); - window->panel = panel; - window->is_tile_window = 1; - DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); - ++panel->windows_count; - } - } - - { - V_Panel *panel = PushStruct(perm, V_Panel); - panel->space = space; - DllQueuePushNP(space->first_panel, space->last_panel, panel, next_in_space, prev_in_space); - ++space->panels_count; - - { - V_Window *window = PushStruct(perm, V_Window); - window->panel = panel; - window->is_tile_window = 1; - DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); - ++panel->windows_count; - } - } - } - - if (frame->is_editing) - { - Struct(DfsNode) { DfsNode *next; b32 visited; V_Space *space; UI_Checkpoint cp; }; - DfsNode *first_dfs = PushStruct(frame->arena, DfsNode); - first_dfs->space = V.root_space; - - while (first_dfs) - { - DfsNode *dfs = first_dfs; - V_Space *space = dfs->space; - if (!dfs->visited) - { - dfs->visited = 1; - for (V_Space *child = space->last; child; child = child->prev) - { - DfsNode *n = PushStruct(frame->arena, DfsNode); - n->space = child; - SllStackPush(first_dfs, n); - } - - UI_Key space_key = UI_TransKey(); - if (space->axis == Axis_X) - { - UI_BuildRowEx(space_key); - } - else - { - UI_BuildColumnEx(space_key); - } - dfs->cp = UI_PushCP(space_key); - - for (V_Panel *panel = space->first_panel; panel; panel = panel->next_in_space) - { - i64 active_window_idx = ClampI64(panel->active_window_idx, 0, MaxI64(panel->windows_count - 1, 0)); - /* Build tabs */ - V_Window *window = 0; - { - UI_SetNext(Width, UI_SHRINK(0, 1)); - UI_SetNext(Height, UI_SHRINK(0, 1)); - UI_PushCP(UI_BuildRow()); - i64 window_idx = 0; - for (V_Window *tab_window = panel->first_window; tab_window; tab_window = tab_window->next_in_panel) - { - if (window_idx == active_window_idx) - { - window = tab_window; - UI_SetNext(BorderColor, VEC4(0.9, 0.5, 0.5, 1)); - } - else - { - UI_SetNext(BorderColor, VEC4(0.5, 0.5, 0.5, 1)); - } - UI_SetNext(BackgroundColor, VEC4(0.2, 0.2, 0.2, 1)); - UI_SetNext(Border, 1); - UI_SetNext(Width, UI_SHRINK(0, 1)); - UI_SetNext(Height, UI_SHRINK(0, 1)); - UI_PushCP(UI_BuildRow()); - { - if (tab_window->is_tile_window) - { - UI_BuildLabelF("Tiles"); - } - else - { - UI_BuildLabelF("Unknown"); - } - } - UI_PopCP(UI_TopCP()); - window_idx += 1; - } - UI_PopCP(UI_TopCP()); - } - /* Build active window */ - if (window) - { - if (window->is_tile_window) - { - UI_SetNext(BackgroundColor, VEC4(0, 0, 0, 1)); - UI_SetNext(BorderColor, VEC4(0.5, 0.5, 0.5, 1)); - UI_SetNext(Border, 1); - UI_SetNext(Width, UI_PIX(100, 1)); - UI_SetNext(Height, UI_PIX(100, 1)); - // UI_SetNext(Width, UI_SHRINK(0, 1)); - // UI_SetNext(Height, UI_SHRINK(0, 1)); - UI_PushCP(UI_BuildRow()); - { - // UI_BuildLabelF("Tiles"); - } - UI_PopCP(UI_TopCP()); - } - } - } + window = tab_window; + UI_SetNext(BorderColor, VEC4(0.9, 0.5, 0.5, 1)); } else { - UI_PopCP(dfs->cp); - SllStackPop(first_dfs); + UI_SetNext(BorderColor, VEC4(0.5, 0.5, 0.5, 1)); } - } - } - - ////////////////////////////// - //- Build command palette - - if (frame->show_command_palette) - { - V_BeginCommandsWidget(&frame->commands_widget); - { - for (u64 i = 0; i < countof(V_cmd_descs); ++i) - { - V_CmdDesc desc = V_cmd_descs[i]; - if (!desc.flags & V_CmdDescFlag_HideFromPalette) - { - V_CommandsWidgetItemDesc item_desc = Zi; - item_desc.display_name = desc.display_name; - /* FIXME: Attach active shortcuts instead of default hotkeys */ - CopyStructs(item_desc.hotkeys, desc.default_hotkeys, MinU32(countof(item_desc.hotkeys), countof(desc.default_hotkeys))); - if (V_PushCommandsWidgetItem(&frame->commands_widget, item_desc).pressed > 0) - { - V_CmdNode *cmd_node = PushStruct(frame->arena, V_CmdNode); - cmd_node->cmd.name = desc.name; - SllQueuePush(first_cmd_node, last_cmd_node, cmd_node); - ++cmds_count; - } - } - } - } - V_EndCommandsWidget(&frame->commands_widget); - } - - ////////////////////////////// - //- Build console UI - - /* TODO: Remove this whole thing */ - if (frame->show_console) - { - b32 minimized = 0; - - // i32 console_level = minimized ? LogLevel_Success : LogLevel_Debug; - i32 console_level = LogLevel_Debug; - - Vec4 colors[LogLevel_Count][2] = Zi; - SetBytes(colors, 0xFF, sizeof(colors)); - /* Debug colors */ - colors[LogLevel_Debug][0] = Rgb(0.4, 0.1, 0.4); - colors[LogLevel_Debug][1] = Rgb(0.5, 0.2, 0.5); - /* Info colors */ - colors[LogLevel_Info][0] = Rgb(0.4, 0.4, 0.4); - colors[LogLevel_Info][1] = Rgb(0.5, 0.5, 0.5); - /* Success colors */ - colors[LogLevel_Success][0] = Rgb(0.1, 0.3, 0.1); - colors[LogLevel_Success][1] = Rgb(0.2, 0.4, 0.2); - /* Warning colors */ - colors[LogLevel_Warning][0] = Rgb(0.4, 0.4, 0.1); - colors[LogLevel_Warning][1] = Rgb(0.5, 0.5, 0.2); - /* Error colors */ - colors[LogLevel_Error][0] = Rgb(0.4, 0.1, 0.1); - colors[LogLevel_Error][1] = Rgb(0.5, 0.2, 0.2); - - i64 max_time_ns = I64Max; - i64 fade_time_ns = max_time_ns; - if (minimized) - { - max_time_ns = NsFromSeconds(10); - fade_time_ns = max_time_ns; - } - f32 fade_curve = 0.5; - - i64 now_ns = TimeNs(); - UI_Key console_box = Zi; - { - UI_Push(FloatingPos, VEC2(0, 0)); - UI_SetNext(Flags, UI_BoxFlag_Floating); - UI_SetNext(Border, 0); - if (minimized) - { - UI_SetNext(BackgroundColor, 0); - UI_SetNext(Width, UI_PIX(500, 0)); - UI_SetNext(Height, UI_SHRINK(0, 1)); - } - else - { - UI_SetNext(BackgroundColor, Rgba(1, 1, 1, 0.02)); - UI_SetNext(Width, UI_GROW(1, 0)); - UI_SetNext(Height, UI_SHRINK(0, 1)); - } - console_box = UI_BuildColumnEx(UI_KeyF("Console box")); - UI_PushCP(console_box); - { - /* Gather display logs */ - u64 max = 20; - u64 display_count = 0; - LogEvent *display_logs = PushStructs(frame->arena, LogEvent, max); - { - b32 done = 0; - if (minimized) - { - max = 5; - } - LogEventsArray logs = GetLogEvents(); - for (u64 i = logs.count; i-- > 0 && display_count < max && !done;) - { - LogEvent ev = logs.logs[i]; - if (ev.time_ns > (now_ns - max_time_ns)) - { - if (ev.level <= console_level) - { - display_logs[display_count] = ev; - ++display_count; - } - } - else - { - done = 1; - } - } - } - /* Display logs in reverse */ - for (u64 i = display_count; i-- > 0;) - { - LogEvent log = display_logs[i]; - f32 opacity = 0.75; - f32 lin = 1.0 - ClampF64((f64)(now_ns - log.time_ns) / (f64)fade_time_ns, 0, 1); - opacity *= PowF32(lin, fade_curve); - String text = log.msg; - if (!minimized) - { - DateTime datetime = log.datetime; - text = StringF( - frame->arena, - "[%F:%F:%F.%F] %F", - FmtUint(datetime.hour, .z = 2), - FmtUint(datetime.minute, .z = 2), - FmtUint(datetime.second, .z = 2), - FmtUint(datetime.milliseconds, .z = 3), - FmtString(text) - ); - } - UI_PushCP(UI_NilKey); - { - Vec4 tint = VEC4(1, 1, 1, opacity); - UI_Push(Tint, tint); - { - Vec4 color = colors[log.level][log.level_id % 2]; - UI_Push(BackgroundColor, color); - UI_Push(Width, UI_GROW(1, 0)); - UI_Push(Height, UI_FNT(1.5, 1)); - UI_Push(BorderColor, Rgb(0.25, 0.25, 0.25)); - UI_Push(Rounding, UI_RPIX(0)); - UI_Push(Border, 1); - UI_Push(ChildAlignment, UI_Alignment_Left); - UI_PushCP(UI_BuildRow()); - { - // UI_SetNext(Height, UI_PIX(100, 0)); - UI_BuildSpacer(UI_PIX(10, 0), Axis_X); - UI_Push(BackgroundColor, 0); - UI_Push(Border, 0); - UI_Push(Text, text); - UI_Push(Width, UI_GROW(1, 0)); - UI_Push(Height, UI_SHRINK(0, 1)); - UI_Push(Flags, UI_BoxFlag_DrawText); - UI_BuildBox(); - } - UI_PopCP(UI_TopCP()); - } - } - UI_PopCP(UI_TopCP()); - } - } - UI_PopCP(UI_TopCP()); - } - } - - ////////////////////////////// - //- Build debug info UI - - if (frame->show_console) - { - f32 padding = 20; - f32 rounding = 0; - Vec4 color = VEC4(0, 0, 0, 0.75); - UI_BuildSpacer(UI_GROW(1, 0), Axis_Y); - // UI_SetNext(Width, UI_SHRINK(0, 1)); - // UI_SetNext(Height, UI_SHRINK(0, 1)); - UI_SetNext(Width, UI_SHRINK(0, 1)); - UI_SetNext(Height, UI_SHRINK(0, 1)); - UI_SetNext(BackgroundColor, color); - UI_SetNext(Rounding, UI_RPIX(rounding)); - UI_PushCP(UI_BuildColumn()); - { - // UI_BuildSpacer(UI_PIX(10, 1), Axis_X); - // UI_Push(ChildAlignment, UI_Alignment_Center); - // UI_SetNext(Width, UI_SHRINK(0, 1)); - // UI_SetNext(Height, UI_SHRINK(0, 1)); + UI_SetNext(BackgroundColor, VEC4(0.2, 0.2, 0.2, 1)); + UI_SetNext(Border, 1); UI_SetNext(Width, UI_SHRINK(0, 1)); UI_SetNext(Height, UI_SHRINK(0, 1)); UI_PushCP(UI_BuildRow()); { - UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); - UI_SetNext(Width, UI_SHRINK(0, 1)); - UI_SetNext(Height, UI_SHRINK(0, 1)); - UI_PushCP(UI_BuildColumn()); - { - UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); - Vec2I32 tile_pos = S_TilePosFromWorldPos(frame->world_cursor); - i32 tile_idx = S_TileIdxFromTilePos(tile_pos); - { - UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor)); - UI_BuildLabelF("Cursor tile pos: %F", FmtSint2(tile_pos)); - UI_BuildLabelF("Cursor tile idx: %F", FmtSint(tile_idx)); - } - UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); - { - { - UI_Push(FontSize, 32); - UI_BuildLabelF("CPU:"); - UI_Pop(FontSize); - } - UI_BuildLabelF(" Arenas: %F", FmtSint(GetGstat(NumArenas))); - UI_BuildLabelF(" Arena memory committed: %F MiB", FmtFloat((f64)GetGstat(ArenaMemoryCommitted) / 1024 / 1024)); - UI_BuildLabelF(" Arena memory reserved: %F TiB", FmtFloat((f64)GetGstat(ArenaMemoryReserved) / 1024 / 1024 / 1024 / 1024)); - } - UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); - { - { - UI_Push(FontSize, 32); - UI_BuildLabelF("GPU:"); - UI_Pop(FontSize); - } - UI_BuildLabelF(" Arenas: %F", FmtSint(GetGstat(NumGpuArenas))); - UI_BuildLabelF(" Dedicated arena memory committed: %F MiB", FmtFloat((f64)GetGstat(DedicatedGpuArenaMemoryCommitted) / 1024 / 1024)); - UI_BuildLabelF(" Shared arena memory committed: %F MiB", FmtFloat((f64)GetGstat(SharedGpuArenaMemoryCommitted) / 1024 / 1024)); - } - UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); - } - UI_PopCP(UI_TopCP()); - UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); + if (tab_window->is_tile_window) + { + UI_BuildLabelF("Tiles"); + } + else + { + UI_BuildLabelF("Unknown"); + } } UI_PopCP(UI_TopCP()); + window_idx += 1; + } + UI_PopCP(UI_TopCP()); } - UI_PopCP(UI_TopCP()); - } - - ////////////////////////////// - //- Process vis commands - - for (V_CmdNode *cmd_node = first_cmd_node; cmd_node; cmd_node = cmd_node->next) - { - String cmd_name = cmd_node->cmd.name; - V_CmdKind kind = V_CmdKind_nop; - for (V_CmdKind tmp_kind = V_CmdKind_nop; tmp_kind < V_CmdKind_Count; ++tmp_kind) + /* Build active window */ + if (window) { - V_CmdDesc desc = V_cmd_descs[tmp_kind]; - if (MatchString(desc.name, cmd_name)) + if (window->is_tile_window) + { + UI_SetNext(BackgroundColor, VEC4(0, 0, 0, 1)); + UI_SetNext(BorderColor, VEC4(0.5, 0.5, 0.5, 1)); + UI_SetNext(Border, 1); + UI_SetNext(Width, UI_PIX(100, 1)); + UI_SetNext(Height, UI_PIX(100, 1)); + // UI_SetNext(Width, UI_SHRINK(0, 1)); + // UI_SetNext(Height, UI_SHRINK(0, 1)); + UI_PushCP(UI_BuildRow()); { - kind = tmp_kind; - break; + // UI_BuildLabelF("Tiles"); } + UI_PopCP(UI_TopCP()); + } } - - switch (kind) - { - case V_CmdKind_exit_program: - { - SignalExit(0); - } break; - - case V_CmdKind_toggle_command_palette: - { - frame->show_command_palette = !frame->show_command_palette; - } break; - - case V_CmdKind_zoom_in: - { - if (frame->is_editing) - { - frame->zooms += 1; - } - } break; - - case V_CmdKind_zoom_out: - { - if (frame->is_editing) - { - frame->zooms -= 1; - } - } break; - - case V_CmdKind_toggle_editor: - { - b32 new = !frame->is_editing; - if (new) - { - LogInfoF("Enabled editor"); - } - else - { - LogInfoF("Disabled editor"); - } - frame->is_editing = new; - } break; - - case V_CmdKind_toggle_ui_debug: - { - frame->ui_debug = !frame->ui_debug; - } break; - - case V_CmdKind_toggle_console: - { - b32 new = !frame->show_console; - frame->show_console = new; - } break; - - case V_CmdKind_toggle_fullscreen: - { - b32 new = !window_frame.fullscreen; - WND_PushCmd(window_frame, .kind = WND_CmdKind_SetFullscreen, .v = new); - LogInfoF("Toggled fullscreen: %F", FmtSint(new)); - } break; - - case V_CmdKind_toggle_window_topmost: - { - b32 new = !window_frame.forced_top; - WND_PushCmd(window_frame, .kind = WND_CmdKind_SetForcedTop, .v = new); - LogInfoF("Toggled topmost: %F", FmtSint(new)); - } break; - - case V_CmdKind_spawn: - { - // S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Tile); - // cmd->tile_placement.placement_kind = S_TilePlacementKind_Range; - // cmd->tile_placement.tile_kind = S_TileKind_Wall; - // cmd->tile_placement.range.p0 = VEC2I32(100, 100); - // cmd->tile_placement.range.p1 = VEC2I32(110, 110); - // cmd->tile_placement.range.p0 = VEC2I32(2, 2); - // cmd->tile_placement.range.p1 = VEC2I32(5, 5); - } break; - } + } } - - ////////////////////////////// - //- Compute movement & look - + else { - Vec2 move = Zi; - { - if (frame->held_buttons[Button_A]) move.x -= 1; - if (frame->held_buttons[Button_D]) move.x += 1; - if (frame->held_buttons[Button_W]) move.y -= 1; - if (frame->held_buttons[Button_S]) move.y += 1; - } - Vec2 look = Zi; - { - S_Ent *player = S_EntFromKey(&V.lookup, V.player_key); - Vec2 center = MulXformV2(player->xf, player->local_shape.centroid); - look = SubVec2(frame->world_cursor, center); - } - if (frame->is_editing) - { - if (!frame->is_panning) - { - f32 edit_move_speed = 15.0 * MaxF32(frame->edit_camera_zoom, min_zoom); - frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, MulVec2(move, edit_move_speed * frame->dt)); - } - } - else - { - frame->move = move; - frame->look = look; - } + UI_PopCP(space_dfs->cp); + SllStackPop(first_space_dfs); } - - /* Push control cmd */ - { - S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Control); - cmd->target = V.player_key; - cmd->move = frame->move; - cmd->look = frame->look; - } - - ////////////////////////////// - //- Submit sim commands - - LockTicketMutex(&S.input_back_tm); - { - S_InputState *v2s = &S.input_states[S.input_back_idx]; - for (S_CmdNode *src = frame->first_sim_cmd_node; src; src = src->next) - { - S_CmdNode *cmd_node = PushStruct(v2s->arena, S_CmdNode); - cmd_node->cmd = src->cmd; - SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node); - ++v2s->cmds_count; - } - } - UnlockTicketMutex(&S.input_back_tm); - - ////////////////////////////// - //- Render - - { - ////////////////////////////// - //- Build render data - - /* Build shape buffers */ - for (S_Ent *ent = S_FirstEnt(&iter, V.world); ent->active; ent = S_NextEnt(&iter)) - { - Xform ent_to_world_xf = ent->xf; - Xform ent_to_draw_xf = MulXform(frame->world_to_draw_xf, ent_to_world_xf); - - b32 is_visible = 1; - if (is_visible) - { - /* Draw shape */ - { - Vec4 color = Color_Purple; - i32 detail = 32; - S_Shape shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape); - V_DrawShape(frame->dverts_arena, frame->dvert_idxs_arena, shape, LinearFromSrgb(color), detail, V_DrawFlag_Line); - } - /* Draw weapon */ - if (ent->has_weapon) - { - Vec4 color = Color_Cyan; - f32 width = 0.1; - f32 height = 0.75; - S_Shape local_shape = S_ShapeFromDesc( - .count = 4, - .points = { - VEC2(-width / 2, -height), VEC2(width / 2, -height), - VEC2(width / 2, 0), VEC2(-width / 2, 0), - } - ); - Xform local_xf = XformFromTrs(TRS(.t = { 0, 0 }, .r = Tau / 4)); - Xform xf = MulXform(ent_to_draw_xf, local_xf); - S_Shape shape = S_MulXformShape(xf, local_shape); - V_DrawShape(frame->dverts_arena, frame->dvert_idxs_arena, shape, LinearFromSrgb(color), 10, V_DrawFlag_Line); - } - } - } - - ////////////////////////////// - //- Push data to GPU - - /* Target */ - G_ResourceHandle draw_target = G_PushTexture2D( - frame->gpu_arena, frame->cl, - G_Format_R16G16B16A16_Float, - frame->draw_dims, - G_Layout_DirectQueue_RenderTargetWrite, - .flags = G_ResourceFlag_AllowShaderReadWrite | G_ResourceFlag_AllowRenderTarget - ); - G_Texture2DRef draw_target_ro = G_PushTexture2DRef(frame->gpu_arena, draw_target); - G_RWTexture2DRef draw_target_rw = G_PushRWTexture2DRef(frame->gpu_arena, draw_target); - Rng3 viewport = RNG3(VEC3(0, 0, 0), VEC3(frame->draw_dims.x, frame->draw_dims.y, 1)); - Rng2 scissor = RNG2(VEC2(viewport.p0.x, viewport.p0.y), VEC2(viewport.p1.x, viewport.p1.y)); - - /* Verts */ - G_ResourceHandle dverts_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dverts_arena)); - G_ResourceHandle dvert_idxs_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dvert_idxs_arena)); - G_StructuredBufferRef dverts_ro = G_PushStructuredBufferRef(frame->gpu_arena, dverts_buff, V_DVert); - G_IndexBufferDesc dvert_idxs_ib = G_IdxBuff32(dvert_idxs_buff); - - /* Params */ - V_DParams params = Zi; - { - params.target_size = frame->draw_dims; - params.target_ro = draw_target_ro; - params.target_rw = draw_target_rw; - - params.world_to_draw_xf = frame->world_to_draw_xf; - params.draw_to_world_xf = frame->draw_to_world_xf; - - params.selection_mode = frame->selection_mode; - params.equipped_tile = frame->equipped_tile; - - params.ui_cursor = frame->ui_cursor; - params.draw_cursor = frame->draw_cursor; - params.world_cursor = frame->world_cursor; - params.ui_selection = frame->ui_selection; - params.draw_selection = frame->draw_selection; - params.world_selection = frame->world_selection; - - params.camera_pos = frame->camera_pos; - params.camera_zoom = frame->camera_zoom; - - params.world_size = world_size; - params.tiles = gpu_tiles_ref; - params.shape_verts = dverts_ro; - } - G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(¶ms)); - G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, V_DParams); - - /* Constants */ - G_SetConstant(frame->cl, V_ShaderConst_Params, params_ro); - - /* Sync */ - G_DumbGlobalMemorySync(frame->cl); - - ////////////////////////////// - //- Discard pass - - G_DiscardRenderTarget(frame->cl, draw_target); - - ////////////////////////////// - //- Backdrop pass - - G_DumbMemoryLayoutSync(frame->cl, draw_target, G_Layout_DirectQueue_ShaderReadWrite); - - { - G_Compute(frame->cl, V_BackdropCS, V_BackdropCSThreadSizeFromTexSize(frame->draw_dims)); - } - - ////////////////////////////// - //- Shapes pass - - G_DumbMemoryLayoutSync(frame->cl, draw_target, G_Layout_DirectQueue_RenderTargetWrite); - - { - G_Rasterize( - frame->cl, - V_DVertVS, V_DVertPS, - 1, dvert_idxs_ib, - 1, &draw_target, - viewport, scissor, - G_RasterMode_TriangleList - ); - } - - ////////////////////////////// - //- Overlay pass - - { - G_Rasterize( - frame->cl, - V_OverlayVS, V_OverlayPS, - 1, G_QuadIndices(), - 1, &draw_target, - viewport, scissor, - G_RasterMode_TriangleList - ); - } - - ////////////////////////////// - //- Finalize draw target - - G_DumbMemoryLayoutSync(frame->cl, draw_target, G_Layout_DirectQueue_ShaderRead); - { - Rng2 uv = Zi; - uv.p0 = Vec2FromVec(viewport.p0); - uv.p1 = Vec2FromVec(viewport.p1); - uv = DivRng2Vec2(uv, Vec2FromVec(frame->draw_dims)); - UI_SetRawTexture(vis_box, draw_target_ro, uv); - } - } - - ////////////////////////////// - //- End frame - - G_CommitCommandList(frame->cl); - - UI_EndFrame(ui_frame); - - shutdown = Atomic32Fetch(&V.shutdown); + } } ////////////////////////////// - //- Swap out + //- Build command palette - // if (IsSwappingOut()) - // { - // TempArena scratch = BeginScratchNoConflict(); - // u64 max_size = Mebi(64); - // u8 *bytes = PushStructsNoZero(scratch.arena, u8, max_size); - // BB_Buff bb = BB_BuffFromString(STRING(max_size, bytes)); - // { - // BB_Writer bw = BB_WriterFromBuff(&bb); - // BB_WriteString(&bw, StringFromStruct(&persist)); - // BB_WriteString(&bw, window_restore); - // WriteSwappedState(Lit("pp_vis"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw))); - // } - // EndScratch(scratch); - // } + if (frame->show_command_palette) + { + V_BeginCommandsWidget(&frame->commands_widget); + { + for (u64 i = 0; i < countof(V_cmd_descs); ++i) + { + V_CmdDesc desc = V_cmd_descs[i]; + if (!desc.flags & V_CmdDescFlag_HideFromPalette) + { + V_CommandsWidgetItemDesc item_desc = Zi; + item_desc.display_name = desc.display_name; + /* FIXME: Attach active shortcuts instead of default hotkeys */ + CopyStructs(item_desc.hotkeys, desc.default_hotkeys, MinU32(countof(item_desc.hotkeys), countof(desc.default_hotkeys))); + if (V_PushCommandsWidgetItem(&frame->commands_widget, item_desc).pressed > 0) + { + V_CmdNode *cmd_node = PushStruct(frame->arena, V_CmdNode); + cmd_node->cmd.name = desc.name; + SllQueuePush(first_cmd_node, last_cmd_node, cmd_node); + ++cmds_count; + } + } + } + } + V_EndCommandsWidget(&frame->commands_widget); + } - FetchAddFence(&V.shutdown_complete, 1); + ////////////////////////////// + //- Build console UI + + /* TODO: Remove this whole thing */ + if (frame->show_console) + { + b32 minimized = 0; + + // i32 console_level = minimized ? LogLevel_Success : LogLevel_Debug; + i32 console_level = LogLevel_Debug; + + Vec4 colors[LogLevel_Count][2] = Zi; + SetBytes(colors, 0xFF, sizeof(colors)); + /* Debug colors */ + colors[LogLevel_Debug][0] = Rgb(0.4, 0.1, 0.4); + colors[LogLevel_Debug][1] = Rgb(0.5, 0.2, 0.5); + /* Info colors */ + colors[LogLevel_Info][0] = Rgb(0.4, 0.4, 0.4); + colors[LogLevel_Info][1] = Rgb(0.5, 0.5, 0.5); + /* Success colors */ + colors[LogLevel_Success][0] = Rgb(0.1, 0.3, 0.1); + colors[LogLevel_Success][1] = Rgb(0.2, 0.4, 0.2); + /* Warning colors */ + colors[LogLevel_Warning][0] = Rgb(0.4, 0.4, 0.1); + colors[LogLevel_Warning][1] = Rgb(0.5, 0.5, 0.2); + /* Error colors */ + colors[LogLevel_Error][0] = Rgb(0.4, 0.1, 0.1); + colors[LogLevel_Error][1] = Rgb(0.5, 0.2, 0.2); + + i64 max_time_ns = I64Max; + i64 fade_time_ns = max_time_ns; + if (minimized) + { + max_time_ns = NsFromSeconds(10); + fade_time_ns = max_time_ns; + } + f32 fade_curve = 0.5; + + i64 now_ns = TimeNs(); + UI_Key console_box = Zi; + { + UI_Push(FloatingPos, VEC2(0, 0)); + UI_SetNext(Flags, UI_BoxFlag_Floating); + UI_SetNext(Border, 0); + if (minimized) + { + UI_SetNext(BackgroundColor, 0); + UI_SetNext(Width, UI_PIX(500, 0)); + UI_SetNext(Height, UI_SHRINK(0, 1)); + } + else + { + UI_SetNext(BackgroundColor, Rgba(1, 1, 1, 0.02)); + UI_SetNext(Width, UI_GROW(1, 0)); + UI_SetNext(Height, UI_SHRINK(0, 1)); + } + console_box = UI_BuildColumnEx(UI_KeyF("Console box")); + UI_PushCP(console_box); + { + /* Gather display logs */ + u64 max = 20; + u64 display_count = 0; + LogEvent *display_logs = PushStructs(frame->arena, LogEvent, max); + { + b32 done = 0; + if (minimized) + { + max = 5; + } + LogEventsArray logs = GetLogEvents(); + for (u64 i = logs.count; i-- > 0 && display_count < max && !done;) + { + LogEvent ev = logs.logs[i]; + if (ev.time_ns > (now_ns - max_time_ns)) + { + if (ev.level <= console_level) + { + display_logs[display_count] = ev; + ++display_count; + } + } + else + { + done = 1; + } + } + } + /* Display logs in reverse */ + for (u64 i = display_count; i-- > 0;) + { + LogEvent log = display_logs[i]; + f32 opacity = 0.75; + f32 lin = 1.0 - ClampF64((f64)(now_ns - log.time_ns) / (f64)fade_time_ns, 0, 1); + opacity *= PowF32(lin, fade_curve); + String text = log.msg; + if (!minimized) + { + DateTime datetime = log.datetime; + text = StringF( + frame->arena, + "[%F:%F:%F.%F] %F", + FmtUint(datetime.hour, .z = 2), + FmtUint(datetime.minute, .z = 2), + FmtUint(datetime.second, .z = 2), + FmtUint(datetime.milliseconds, .z = 3), + FmtString(text) + ); + } + UI_PushCP(UI_NilKey); + { + Vec4 tint = VEC4(1, 1, 1, opacity); + UI_Push(Tint, tint); + { + Vec4 color = colors[log.level][log.level_id % 2]; + UI_Push(BackgroundColor, color); + UI_Push(Width, UI_GROW(1, 0)); + UI_Push(Height, UI_FNT(1.5, 1)); + UI_Push(BorderColor, Rgb(0.25, 0.25, 0.25)); + UI_Push(Rounding, UI_RPIX(0)); + UI_Push(Border, 1); + UI_Push(ChildAlignment, UI_Alignment_Left); + UI_PushCP(UI_BuildRow()); + { + // UI_SetNext(Height, UI_PIX(100, 0)); + UI_BuildSpacer(UI_PIX(10, 0), Axis_X); + UI_Push(BackgroundColor, 0); + UI_Push(Border, 0); + UI_Push(Text, text); + UI_Push(Width, UI_GROW(1, 0)); + UI_Push(Height, UI_SHRINK(0, 1)); + UI_Push(Flags, UI_BoxFlag_DrawText); + UI_BuildBox(); + } + UI_PopCP(UI_TopCP()); + } + } + UI_PopCP(UI_TopCP()); + } + } + UI_PopCP(UI_TopCP()); + } + } + + ////////////////////////////// + //- Build debug info UI + + if (frame->show_console) + { + f32 padding = 20; + f32 rounding = 0; + Vec4 color = VEC4(0, 0, 0, 0.75); + UI_BuildSpacer(UI_GROW(1, 0), Axis_Y); + // UI_SetNext(Width, UI_SHRINK(0, 1)); + // UI_SetNext(Height, UI_SHRINK(0, 1)); + UI_SetNext(Width, UI_SHRINK(0, 1)); + UI_SetNext(Height, UI_SHRINK(0, 1)); + UI_SetNext(BackgroundColor, color); + UI_SetNext(Rounding, UI_RPIX(rounding)); + UI_PushCP(UI_BuildColumn()); + { + // UI_BuildSpacer(UI_PIX(10, 1), Axis_X); + // UI_Push(ChildAlignment, UI_Alignment_Center); + // UI_SetNext(Width, UI_SHRINK(0, 1)); + // UI_SetNext(Height, UI_SHRINK(0, 1)); + UI_SetNext(Width, UI_SHRINK(0, 1)); + UI_SetNext(Height, UI_SHRINK(0, 1)); + UI_PushCP(UI_BuildRow()); + { + UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); + UI_SetNext(Width, UI_SHRINK(0, 1)); + UI_SetNext(Height, UI_SHRINK(0, 1)); + UI_PushCP(UI_BuildColumn()); + { + UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); + Vec2I32 tile_pos = S_TilePosFromWorldPos(frame->world_cursor); + i32 tile_idx = S_TileIdxFromTilePos(tile_pos); + { + UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor)); + UI_BuildLabelF("Cursor tile pos: %F", FmtSint2(tile_pos)); + UI_BuildLabelF("Cursor tile idx: %F", FmtSint(tile_idx)); + } + UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); + { + { + UI_Push(FontSize, 32); + UI_BuildLabelF("CPU:"); + UI_Pop(FontSize); + } + UI_BuildLabelF(" Arenas: %F", FmtSint(GetGstat(NumArenas))); + UI_BuildLabelF(" Arena memory committed: %F MiB", FmtFloat((f64)GetGstat(ArenaMemoryCommitted) / 1024 / 1024)); + UI_BuildLabelF(" Arena memory reserved: %F TiB", FmtFloat((f64)GetGstat(ArenaMemoryReserved) / 1024 / 1024 / 1024 / 1024)); + } + UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); + { + { + UI_Push(FontSize, 32); + UI_BuildLabelF("GPU:"); + UI_Pop(FontSize); + } + UI_BuildLabelF(" Arenas: %F", FmtSint(GetGstat(NumGpuArenas))); + UI_BuildLabelF(" Dedicated arena memory committed: %F MiB", FmtFloat((f64)GetGstat(DedicatedGpuArenaMemoryCommitted) / 1024 / 1024)); + UI_BuildLabelF(" Shared arena memory committed: %F MiB", FmtFloat((f64)GetGstat(SharedGpuArenaMemoryCommitted) / 1024 / 1024)); + } + UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); + } + UI_PopCP(UI_TopCP()); + UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); + } + UI_PopCP(UI_TopCP()); + } + UI_PopCP(UI_TopCP()); + } + + ////////////////////////////// + //- Process vis commands + + for (V_CmdNode *cmd_node = first_cmd_node; cmd_node; cmd_node = cmd_node->next) + { + String cmd_name = cmd_node->cmd.name; + V_CmdKind kind = V_CmdKind_nop; + for (V_CmdKind tmp_kind = V_CmdKind_nop; tmp_kind < V_CmdKind_Count; ++tmp_kind) + { + V_CmdDesc desc = V_cmd_descs[tmp_kind]; + if (MatchString(desc.name, cmd_name)) + { + kind = tmp_kind; + break; + } + } + + switch (kind) + { + case V_CmdKind_exit_program: + { + SignalExit(0); + } break; + + case V_CmdKind_toggle_command_palette: + { + frame->show_command_palette = !frame->show_command_palette; + } break; + + case V_CmdKind_zoom_in: + { + if (frame->is_editing) + { + frame->zooms += 1; + } + } break; + + case V_CmdKind_zoom_out: + { + if (frame->is_editing) + { + frame->zooms -= 1; + } + } break; + + case V_CmdKind_toggle_editor: + { + b32 new = !frame->is_editing; + if (new) + { + LogInfoF("Enabled editor"); + } + else + { + LogInfoF("Disabled editor"); + } + frame->is_editing = new; + } break; + + case V_CmdKind_toggle_ui_debug: + { + frame->ui_debug = !frame->ui_debug; + } break; + + case V_CmdKind_toggle_console: + { + b32 new = !frame->show_console; + frame->show_console = new; + } break; + + case V_CmdKind_toggle_fullscreen: + { + b32 new = !window_frame.fullscreen; + WND_PushCmd(window_frame, .kind = WND_CmdKind_SetFullscreen, .v = new); + LogInfoF("Toggled fullscreen: %F", FmtSint(new)); + } break; + + case V_CmdKind_toggle_window_topmost: + { + b32 new = !window_frame.forced_top; + WND_PushCmd(window_frame, .kind = WND_CmdKind_SetForcedTop, .v = new); + LogInfoF("Toggled topmost: %F", FmtSint(new)); + } break; + + case V_CmdKind_spawn: + { + // S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Tile); + // cmd->tile_placement.placement_kind = S_TilePlacementKind_Range; + // cmd->tile_placement.tile_kind = S_TileKind_Wall; + // cmd->tile_placement.range.p0 = VEC2I32(100, 100); + // cmd->tile_placement.range.p1 = VEC2I32(110, 110); + // cmd->tile_placement.range.p0 = VEC2I32(2, 2); + // cmd->tile_placement.range.p1 = VEC2I32(5, 5); + } break; + } + } + + ////////////////////////////// + //- Compute movement & look + + { + Vec2 move = Zi; + { + if (frame->held_buttons[Button_A]) move.x -= 1; + if (frame->held_buttons[Button_D]) move.x += 1; + if (frame->held_buttons[Button_W]) move.y -= 1; + if (frame->held_buttons[Button_S]) move.y += 1; + } + Vec2 look = Zi; + { + S_Ent *player = S_EntFromKey(&V.lookup, V.player_key); + Vec2 center = MulXformV2(player->xf, player->local_shape.centroid); + look = SubVec2(frame->world_cursor, center); + } + if (frame->is_editing) + { + if (!frame->is_panning) + { + f32 edit_move_speed = 15.0 * MaxF32(frame->edit_camera_zoom, min_zoom); + frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, MulVec2(move, edit_move_speed * frame->dt)); + } + } + else + { + frame->move = move; + frame->look = look; + } + } + + /* Push control cmd */ + { + S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Control); + cmd->target = V.player_key; + cmd->move = frame->move; + cmd->look = frame->look; + } + + ////////////////////////////// + //- Submit sim commands + + LockTicketMutex(&S.input_back_tm); + { + S_InputState *v2s = &S.input_states[S.input_back_idx]; + for (S_CmdNode *src = frame->first_sim_cmd_node; src; src = src->next) + { + S_CmdNode *cmd_node = PushStruct(v2s->arena, S_CmdNode); + cmd_node->cmd = src->cmd; + SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node); + ++v2s->cmds_count; + } + } + UnlockTicketMutex(&S.input_back_tm); + + ////////////////////////////// + //- Render + + { + ////////////////////////////// + //- Build render data + + /* Build shape buffers */ + for (S_Ent *ent = S_FirstEnt(&iter, V.world); ent->active; ent = S_NextEnt(&iter)) + { + Xform ent_to_world_xf = ent->xf; + Xform ent_to_draw_xf = MulXform(frame->world_to_draw_xf, ent_to_world_xf); + + b32 is_visible = 1; + if (is_visible) + { + /* Draw shape */ + { + Vec4 color = Color_Purple; + i32 detail = 32; + S_Shape shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape); + V_DrawShape(frame->dverts_arena, frame->dvert_idxs_arena, shape, LinearFromSrgb(color), detail, V_DrawFlag_Line); + } + /* Draw weapon */ + if (ent->has_weapon) + { + Vec4 color = Color_Cyan; + f32 width = 0.1; + f32 height = 0.75; + S_Shape local_shape = S_ShapeFromDesc( + .count = 4, + .points = { + VEC2(-width / 2, -height), VEC2(width / 2, -height), + VEC2(width / 2, 0), VEC2(-width / 2, 0), + } + ); + Xform local_xf = XformFromTrs(TRS(.t = { 0, 0 }, .r = Tau / 4)); + Xform xf = MulXform(ent_to_draw_xf, local_xf); + S_Shape shape = S_MulXformShape(xf, local_shape); + V_DrawShape(frame->dverts_arena, frame->dvert_idxs_arena, shape, LinearFromSrgb(color), 10, V_DrawFlag_Line); + } + } + } + + ////////////////////////////// + //- Push data to GPU + + /* Target */ + G_ResourceHandle draw_target = G_PushTexture2D( + frame->gpu_arena, frame->cl, + G_Format_R16G16B16A16_Float, + frame->draw_dims, + G_Layout_DirectQueue_RenderTargetWrite, + .flags = G_ResourceFlag_AllowShaderReadWrite | G_ResourceFlag_AllowRenderTarget + ); + G_Texture2DRef draw_target_ro = G_PushTexture2DRef(frame->gpu_arena, draw_target); + G_RWTexture2DRef draw_target_rw = G_PushRWTexture2DRef(frame->gpu_arena, draw_target); + Rng3 viewport = RNG3(VEC3(0, 0, 0), VEC3(frame->draw_dims.x, frame->draw_dims.y, 1)); + Rng2 scissor = RNG2(VEC2(viewport.p0.x, viewport.p0.y), VEC2(viewport.p1.x, viewport.p1.y)); + + /* Verts */ + G_ResourceHandle dverts_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dverts_arena)); + G_ResourceHandle dvert_idxs_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dvert_idxs_arena)); + G_StructuredBufferRef dverts_ro = G_PushStructuredBufferRef(frame->gpu_arena, dverts_buff, V_DVert); + G_IndexBufferDesc dvert_idxs_ib = G_IdxBuff32(dvert_idxs_buff); + + /* Params */ + V_DParams params = Zi; + { + params.target_size = frame->draw_dims; + params.target_ro = draw_target_ro; + params.target_rw = draw_target_rw; + + params.world_to_draw_xf = frame->world_to_draw_xf; + params.draw_to_world_xf = frame->draw_to_world_xf; + + params.selection_mode = frame->selection_mode; + params.equipped_tile = frame->equipped_tile; + + params.ui_cursor = frame->ui_cursor; + params.draw_cursor = frame->draw_cursor; + params.world_cursor = frame->world_cursor; + params.ui_selection = frame->ui_selection; + params.draw_selection = frame->draw_selection; + params.world_selection = frame->world_selection; + + params.camera_pos = frame->camera_pos; + params.camera_zoom = frame->camera_zoom; + + params.world_size = world_size; + params.tiles = gpu_tiles_ref; + params.shape_verts = dverts_ro; + } + G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(¶ms)); + G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, V_DParams); + + /* Constants */ + G_SetConstant(frame->cl, V_ShaderConst_Params, params_ro); + + /* Sync */ + G_DumbGlobalMemorySync(frame->cl); + + ////////////////////////////// + //- Discard pass + + G_DiscardRenderTarget(frame->cl, draw_target); + + ////////////////////////////// + //- Backdrop pass + + G_DumbMemoryLayoutSync(frame->cl, draw_target, G_Layout_DirectQueue_ShaderReadWrite); + + { + G_Compute(frame->cl, V_BackdropCS, V_BackdropCSThreadSizeFromTexSize(frame->draw_dims)); + } + + ////////////////////////////// + //- Shapes pass + + G_DumbMemoryLayoutSync(frame->cl, draw_target, G_Layout_DirectQueue_RenderTargetWrite); + + { + G_Rasterize( + frame->cl, + V_DVertVS, V_DVertPS, + 1, dvert_idxs_ib, + 1, &draw_target, + viewport, scissor, + G_RasterMode_TriangleList + ); + } + + ////////////////////////////// + //- Overlay pass + + { + G_Rasterize( + frame->cl, + V_OverlayVS, V_OverlayPS, + 1, G_QuadIndices(), + 1, &draw_target, + viewport, scissor, + G_RasterMode_TriangleList + ); + } + + ////////////////////////////// + //- Finalize draw target + + G_DumbMemoryLayoutSync(frame->cl, draw_target, G_Layout_DirectQueue_ShaderRead); + { + Rng2 uv = Zi; + uv.p0 = Vec2FromVec(viewport.p0); + uv.p1 = Vec2FromVec(viewport.p1); + uv = DivRng2Vec2(uv, Vec2FromVec(frame->draw_dims)); + UI_SetRawTexture(vis_box, draw_target_ro, uv); + } + } + + ////////////////////////////// + //- End frame + + G_CommitCommandList(frame->cl); + + UI_EndFrame(ui_frame); + + shutdown = Atomic32Fetch(&V.shutdown); + } + + ////////////////////////////// + //- Swap out + + // if (IsSwappingOut()) + // { + // TempArena scratch = BeginScratchNoConflict(); + // u64 max_size = Mebi(64); + // u8 *bytes = PushStructsNoZero(scratch.arena, u8, max_size); + // BB_Buff bb = BB_BuffFromString(STRING(max_size, bytes)); + // { + // BB_Writer bw = BB_WriterFromBuff(&bb); + // BB_WriteString(&bw, StringFromStruct(&persist)); + // BB_WriteString(&bw, window_restore); + // WriteSwappedState(Lit("pp_vis"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw))); + // } + // EndScratch(scratch); + // } + + FetchAddFence(&V.shutdown_complete, 1); } diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 75b30e28..51b10c47 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -1,38 +1,38 @@ //////////////////////////////////////////////////////////// //~ Command table -#define V_CmdsTableXMacro(X) \ - X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \ - X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \ - X(toggle_command_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \ - X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \ - X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \ - X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \ - X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \ - X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \ - X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \ - X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \ - X(spawn, Spawn, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \ - /* -------------------------------------------------------------------------------------------------------------------- */ +#define V_CmdsTableXMacro(X) \ + X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \ + X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \ + X(toggle_command_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \ + X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \ + X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \ + X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \ + X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \ + X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \ + X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \ + X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \ + X(spawn, Spawn, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \ +/* -------------------------------------------------------------------------------------------------------------------- */ //////////////////////////////////////////////////////////// //~ Theme types Struct(V_WidgetTheme) { - GC_FontKey font; - f32 font_size; - f32 window_title_font_size; + GC_FontKey font; + f32 font_size; + f32 window_title_font_size; - Vec4 window_background_color; - Vec4 window_border_color; - Vec4 divider_color; - f32 window_border; - f32 window_padding; - f32 window_width; + Vec4 window_background_color; + Vec4 window_border_color; + Vec4 divider_color; + f32 window_border; + f32 window_padding; + f32 window_width; - f32 text_padding_x; - f32 text_padding_y; + f32 text_padding_x; + f32 text_padding_y; }; //////////////////////////////////////////////////////////// @@ -41,10 +41,10 @@ Struct(V_WidgetTheme) #define V_HOTKEY(_button, ...) { .button = _button, __VA_ARGS__ } Struct(V_Hotkey) { - Button button; - b32 ctrl; - b32 alt; - b32 shift; + Button button; + b32 ctrl; + b32 alt; + b32 shift; }; //////////////////////////////////////////////////////////// @@ -52,57 +52,57 @@ Struct(V_Hotkey) Enum(V_CmdKind) { - #define X(name, ...) V_CmdKind_##name, - V_CmdsTableXMacro(X) - #undef X + #define X(name, ...) V_CmdKind_##name, + V_CmdsTableXMacro(X) + #undef X - V_CmdKind_Count, + V_CmdKind_Count, }; Struct(V_Shortcut) { - V_Shortcut *next_in_bin; - V_Shortcut *prev_in_bin; - u64 hotkey_hash; - V_Hotkey hotkey; - String cmd_name; + V_Shortcut *next_in_bin; + V_Shortcut *prev_in_bin; + u64 hotkey_hash; + V_Hotkey hotkey; + String cmd_name; }; Struct(V_ShortcutBin) { - V_Shortcut *first; - V_Shortcut *last; + V_Shortcut *first; + V_Shortcut *last; }; Enum(V_CmdDescFlag) { - V_CmdDescFlag_None = 0, - V_CmdDescFlag_HideFromPalette = (1 << 0), + V_CmdDescFlag_None = 0, + V_CmdDescFlag_HideFromPalette = (1 << 0), }; Struct(V_CmdDesc) { - String name; - String display_name; - V_CmdDescFlag flags; - V_Hotkey default_hotkeys[8]; + String name; + String display_name; + V_CmdDescFlag flags; + V_Hotkey default_hotkeys[8]; }; Struct(V_Cmd) { - String name; + String name; }; Struct(V_CmdNode) { - V_CmdNode *next; - V_Cmd cmd; + V_CmdNode *next; + V_Cmd cmd; }; Global Readonly V_CmdDesc V_cmd_descs[V_CmdKind_Count] = { - #define X(_name, _display_name, _flags, ...) { .name = CompLit(#_name), .display_name = CompLit(#_display_name), .flags = _flags, .default_hotkeys = { __VA_ARGS__ } }, - V_CmdsTableXMacro(X) - #undef X + #define X(_name, _display_name, _flags, ...) { .name = CompLit(#_name), .display_name = CompLit(#_display_name), .flags = _flags, .default_hotkeys = { __VA_ARGS__ } }, + V_CmdsTableXMacro(X) + #undef X }; //////////////////////////////////////////////////////////// @@ -110,38 +110,38 @@ Global Readonly V_CmdDesc V_cmd_descs[V_CmdKind_Count] = { Struct(V_CommandsWidgetItemReport) { - b32 pressed; - b32 hotkey_changed; - UI_Report ui_report; - V_Hotkey new_hotkeys[8]; + b32 pressed; + b32 hotkey_changed; + UI_Report ui_report; + V_Hotkey new_hotkeys[8]; }; Struct(V_CommandsWidgetItemDesc) { - String display_name; - V_Hotkey hotkeys[8]; + String display_name; + V_Hotkey hotkeys[8]; }; Struct(V_CommandsWidgetItem) { - V_CommandsWidgetItem *next; - UI_Key key; - V_CommandsWidgetItemDesc desc; + V_CommandsWidgetItem *next; + UI_Key key; + V_CommandsWidgetItemDesc desc; }; Struct(V_CommandsWidget) { - /* Persistent state */ - Vec2 pos; + /* Persistent state */ + Vec2 pos; - /* Per-build state */ - struct - { - UI_Checkpoint cp; - V_CommandsWidgetItem *first_item; - V_CommandsWidgetItem *last_item; - u64 num_items; - } build; + /* Per-build state */ + struct + { + UI_Checkpoint cp; + V_CommandsWidgetItem *first_item; + V_CommandsWidgetItem *last_item; + u64 num_items; + } build; }; //////////////////////////////////////////////////////////// @@ -151,38 +151,38 @@ Struct(V_CommandsWidget) Struct(V_Space) { - V_Space *parent; - V_Space *next; - V_Space *prev; - V_Space *first; - V_Space *last; + V_Space *parent; + V_Space *next; + V_Space *prev; + V_Space *first; + V_Space *last; - i64 panels_count; - struct V_Panel *first_panel; - struct V_Panel *last_panel; + i64 panels_count; + struct V_Panel *first_panel; + struct V_Panel *last_panel; - Axis axis; + Axis axis; }; Struct(V_Panel) { - V_Space *space; - V_Panel *next_in_space; - V_Panel *prev_in_space; + V_Space *space; + V_Panel *next_in_space; + V_Panel *prev_in_space; - i64 active_window_idx; - i64 windows_count; - struct V_Window *first_window; - struct V_Window *last_window; + i64 active_window_idx; + i64 windows_count; + struct V_Window *first_window; + struct V_Window *last_window; }; Struct(V_Window) { - V_Panel *panel; - V_Window *next_in_panel; - V_Window *prev_in_panel; + V_Panel *panel; + V_Window *next_in_panel; + V_Window *prev_in_panel; - b32 is_tile_window; + b32 is_tile_window; }; //////////////////////////////////////////////////////////// @@ -190,97 +190,97 @@ Struct(V_Window) Enum(V_EditMode) { - V_EditMode_Tile, + V_EditMode_Tile, }; Struct(V_Frame) { - Arena *arena; - Arena *dverts_arena; - Arena *dvert_idxs_arena; - G_ArenaHandle gpu_arena; - G_CommandListHandle cl; + Arena *arena; + Arena *dverts_arena; + Arena *dvert_idxs_arena; + G_ArenaHandle gpu_arena; + G_CommandListHandle cl; - i64 tick; - i64 time_ns; - i64 dt_ns; - f64 dt; + i64 tick; + i64 time_ns; + i64 dt_ns; + f64 dt; - Button held_buttons[Button_Count]; - V_CommandsWidget commands_widget; + Button held_buttons[Button_Count]; + V_CommandsWidget commands_widget; - String window_restore; - i32 zooms; + String window_restore; + i32 zooms; - Vec2I32 ui_dims; - Vec2I32 draw_dims; + Vec2I32 ui_dims; + Vec2I32 draw_dims; - /* Modes */ - b32 is_editing; - b32 ui_debug; - b32 show_command_palette; - b32 show_console; + /* Modes */ + b32 is_editing; + b32 ui_debug; + b32 show_command_palette; + b32 show_console; - /* Editor state */ - V_EditMode edit_mode; - S_TileKind equipped_tile; + /* Editor state */ + V_EditMode edit_mode; + S_TileKind equipped_tile; - /* Editor */ - b32 is_selecting; - b32 is_panning; - V_SelectionMode selection_mode; - Vec2 world_selection_start; - Vec2 edit_camera_pos; - f32 edit_camera_zoom; + /* Editor */ + b32 is_selecting; + b32 is_panning; + V_SelectionMode selection_mode; + Vec2 world_selection_start; + Vec2 edit_camera_pos; + f32 edit_camera_zoom; - /* Camera */ - Vec2 camera_pos; - f32 camera_zoom; + /* Camera */ + Vec2 camera_pos; + f32 camera_zoom; - /* World <-> ui */ - Xform world_to_ui_xf; - Xform ui_to_world_xf; + /* World <-> ui */ + Xform world_to_ui_xf; + Xform ui_to_world_xf; - /* Draw <-> ui */ - Xform draw_to_ui_xf; - Xform ui_to_draw_xf; + /* Draw <-> ui */ + Xform draw_to_ui_xf; + Xform ui_to_draw_xf; - /* World <-> draw */ - Xform world_to_draw_xf; - Xform draw_to_world_xf; + /* World <-> draw */ + Xform world_to_draw_xf; + Xform draw_to_world_xf; - /* Cursors */ - Vec2 ui_cursor; - Vec2 draw_cursor; - Vec2 world_cursor; - Rng2 ui_selection; - Rng2 draw_selection; - Rng2 world_selection; + /* Cursors */ + Vec2 ui_cursor; + Vec2 draw_cursor; + Vec2 world_cursor; + Rng2 ui_selection; + Rng2 draw_selection; + Rng2 world_selection; - /* Control */ - Vec2 move; - Vec2 look; + /* Control */ + Vec2 move; + Vec2 look; - /* Sim cmds */ - u64 sim_cmds_count; - S_CmdNode *first_sim_cmd_node; - S_CmdNode *last_sim_cmd_node; + /* Sim cmds */ + u64 sim_cmds_count; + S_CmdNode *first_sim_cmd_node; + S_CmdNode *last_sim_cmd_node; }; Struct(V_Ctx) { - Arena *world_arena; - S_World *world; - S_Lookup lookup; - S_Key player_key; + Arena *world_arena; + S_World *world; + S_Lookup lookup; + S_Key player_key; - V_Space *root_space; + V_Space *root_space; - Atomic32 shutdown; - Fence shutdown_complete; + Atomic32 shutdown; + Fence shutdown_complete; - u64 current_frame_idx; - V_Frame frames[2]; + u64 current_frame_idx; + V_Frame frames[2]; }; extern V_Ctx V; diff --git a/src/pp/pp_vis/pp_vis_draw.c b/src/pp/pp_vis/pp_vis_draw.c index 5f38dc04..01faf80b 100644 --- a/src/pp/pp_vis/pp_vis_draw.c +++ b/src/pp/pp_vis/pp_vis_draw.c @@ -3,121 +3,121 @@ void V_DrawPoly(Arena *verts_arena, Arena *idxs_arena, Vec2Array points, Vec4 color_lin, V_DrawFlag flags) { - if (flags & V_DrawFlag_Line) + if (flags & V_DrawFlag_Line) + { + i32 verts_count = points.count; + if (verts_count >= 2) { - i32 verts_count = points.count; - if (verts_count >= 2) + TempArena scratch = BeginScratchNoConflict(); + { + f32 half_thickness = 1; + i32 lines_count = verts_count == 2 ? 1 : verts_count; + i32 line_verts_count = lines_count * 4; + i32 idx_count = lines_count * 6; + i32 idx_offset = ArenaCount(verts_arena, V_DVert); + + /* Push dverts */ + V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count); + for (i32 line_idx = 0; line_idx < lines_count; ++line_idx) { - TempArena scratch = BeginScratchNoConflict(); - { - f32 half_thickness = 1; - i32 lines_count = verts_count == 2 ? 1 : verts_count; - i32 line_verts_count = lines_count * 4; - i32 idx_count = lines_count * 6; - i32 idx_offset = ArenaCount(verts_arena, V_DVert); + i32 a_idx = line_idx; + i32 b_idx = line_idx + 1; + if (b_idx >= lines_count) + { + b_idx = 0; + } - /* Push dverts */ - V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count); - for (i32 line_idx = 0; line_idx < lines_count; ++line_idx) - { - i32 a_idx = line_idx; - i32 b_idx = line_idx + 1; - if (b_idx >= lines_count) - { - b_idx = 0; - } + Vec2 a = points.points[a_idx]; + Vec2 b = points.points[b_idx]; - Vec2 a = points.points[a_idx]; - Vec2 b = points.points[b_idx]; + Vec2 a_to_b = SubVec2(b, a); + Vec2 perp = Vec2WithLen(PerpVec2(a_to_b), half_thickness); - Vec2 a_to_b = SubVec2(b, a); - Vec2 perp = Vec2WithLen(PerpVec2(a_to_b), half_thickness); + Vec2 p0 = AddVec2(a, perp); + Vec2 p1 = SubVec2(a, perp); + Vec2 p2 = SubVec2(b, perp); + Vec2 p3 = AddVec2(b, perp); - Vec2 p0 = AddVec2(a, perp); - Vec2 p1 = SubVec2(a, perp); - Vec2 p2 = SubVec2(b, perp); - Vec2 p3 = AddVec2(b, perp); - - i32 offset = line_idx * 4; - dverts[offset + 0] = (V_DVert) { .pos = p0, .color_lin = color_lin }; - dverts[offset + 1] = (V_DVert) { .pos = p1, .color_lin = color_lin }; - dverts[offset + 2] = (V_DVert) { .pos = p2, .color_lin = color_lin }; - dverts[offset + 3] = (V_DVert) { .pos = p3, .color_lin = color_lin }; - } - - /* Generate indices */ - i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count); - for (i32 line_idx = 0; line_idx < lines_count; ++line_idx) - { - i32 indices_offset = line_idx * 6; - i32 vert_idx_offset = idx_offset + (line_idx * 4); - indices[indices_offset + 0] = vert_idx_offset + 0; - indices[indices_offset + 1] = vert_idx_offset + 1; - indices[indices_offset + 2] = vert_idx_offset + 2; - indices[indices_offset + 3] = vert_idx_offset + 0; - indices[indices_offset + 4] = vert_idx_offset + 2; - indices[indices_offset + 5] = vert_idx_offset + 3; - } - } - EndScratch(scratch); + i32 offset = line_idx * 4; + dverts[offset + 0] = (V_DVert) { .pos = p0, .color_lin = color_lin }; + dverts[offset + 1] = (V_DVert) { .pos = p1, .color_lin = color_lin }; + dverts[offset + 2] = (V_DVert) { .pos = p2, .color_lin = color_lin }; + dverts[offset + 3] = (V_DVert) { .pos = p3, .color_lin = color_lin }; } + + /* Generate indices */ + i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count); + for (i32 line_idx = 0; line_idx < lines_count; ++line_idx) + { + i32 indices_offset = line_idx * 6; + i32 vert_idx_offset = idx_offset + (line_idx * 4); + indices[indices_offset + 0] = vert_idx_offset + 0; + indices[indices_offset + 1] = vert_idx_offset + 1; + indices[indices_offset + 2] = vert_idx_offset + 2; + indices[indices_offset + 3] = vert_idx_offset + 0; + indices[indices_offset + 4] = vert_idx_offset + 2; + indices[indices_offset + 5] = vert_idx_offset + 3; + } + } + EndScratch(scratch); } - else + } + else + { + i32 verts_count = points.count; + if (verts_count >= 3) { - i32 verts_count = points.count; - if (verts_count >= 3) - { - i32 idx_offset = ArenaCount(verts_arena, V_DVert); - i32 tris_count = verts_count - 2; - i32 idx_count = tris_count * 3; + i32 idx_offset = ArenaCount(verts_arena, V_DVert); + i32 tris_count = verts_count - 2; + i32 idx_count = tris_count * 3; - /* Push dverts */ - V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count); - for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx) - { - V_DVert *dvert = &dverts[point_idx]; - dvert->pos = points.points[point_idx]; - dvert->color_lin = color_lin; - } + /* Push dverts */ + V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count); + for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx) + { + V_DVert *dvert = &dverts[point_idx]; + dvert->pos = points.points[point_idx]; + dvert->color_lin = color_lin; + } - /* Generate indices in a fan pattern */ - i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count); - for (i32 i = 0; i < tris_count; ++i) - { - i32 tri_offset = i * 3; - indices[tri_offset + 0] = idx_offset; - indices[tri_offset + 1] = idx_offset + i + 1; - indices[tri_offset + 2] = idx_offset + i + 2; - } - } + /* Generate indices in a fan pattern */ + i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count); + for (i32 i = 0; i < tris_count; ++i) + { + i32 tri_offset = i * 3; + indices[tri_offset + 0] = idx_offset; + indices[tri_offset + 1] = idx_offset + i + 1; + indices[tri_offset + 2] = idx_offset + i + 2; + } } + } } void V_DrawShape(Arena *verts_arena, Arena *idxs_arena, S_Shape shape, Vec4 color_lin, i32 detail, V_DrawFlag flags) { - if (shape.radius == 0) + if (shape.radius == 0) + { + Vec2Array draw_points = Zi; + draw_points.points = shape.points; + draw_points.count = shape.points_count; + V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags); + } + else + { + TempArena scratch = BeginScratchNoConflict(); { - Vec2Array draw_points = Zi; - draw_points.points = shape.points; - draw_points.count = shape.points_count; - V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags); - } - else - { - TempArena scratch = BeginScratchNoConflict(); - { - Vec2Array draw_points = Zi; - draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail); - draw_points.count = detail; - for (i32 i = 0; i < detail; ++i) - { - f32 rad = ((f32)i / (f32)detail) * Tau; - Vec2 dir = Vec2FromAngle(rad); - Vec2 sp = S_SupportPointFromShape(shape, dir); - draw_points.points[i] = sp; - } - V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags); - } - EndScratch(scratch); + Vec2Array draw_points = Zi; + draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail); + draw_points.count = detail; + for (i32 i = 0; i < detail; ++i) + { + f32 rad = ((f32)i / (f32)detail) * Tau; + Vec2 dir = Vec2FromAngle(rad); + Vec2 sp = S_SupportPointFromShape(shape, dir); + draw_points.points[i] = sp; + } + V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags); } + EndScratch(scratch); + } } diff --git a/src/pp/pp_vis/pp_vis_draw.h b/src/pp/pp_vis/pp_vis_draw.h index 7541468e..c4566663 100644 --- a/src/pp/pp_vis/pp_vis_draw.h +++ b/src/pp/pp_vis/pp_vis_draw.h @@ -3,8 +3,8 @@ Enum(V_DrawFlag) { - V_DrawFlag_None = 0, - V_DrawFlag_Line = (1 << 0), + V_DrawFlag_None = 0, + V_DrawFlag_Line = (1 << 0), }; //////////////////////////////////////////////////////////// diff --git a/src/pp/pp_vis/pp_vis_shaders.cgh b/src/pp/pp_vis/pp_vis_shaders.cgh index ccd0d074..08becb9e 100644 --- a/src/pp/pp_vis/pp_vis_shaders.cgh +++ b/src/pp/pp_vis/pp_vis_shaders.cgh @@ -5,36 +5,36 @@ G_DeclConstant(G_StructuredBufferRef, V_ShaderConst_Params, 0); Enum(V_SelectionMode) { - V_SelectionMode_None, - V_SelectionMode_Tile, + V_SelectionMode_None, + V_SelectionMode_Tile, }; Struct(V_DParams) { - Vec2I32 target_size; - G_Texture2DRef target_ro; - G_RWTexture2DRef target_rw; + Vec2I32 target_size; + G_Texture2DRef target_ro; + G_RWTexture2DRef target_rw; - Xform world_to_draw_xf; - Xform draw_to_world_xf; + Xform world_to_draw_xf; + Xform draw_to_world_xf; - V_SelectionMode selection_mode; - S_TileKind equipped_tile; + V_SelectionMode selection_mode; + S_TileKind equipped_tile; - Vec2 ui_cursor; - Vec2 draw_cursor; - Vec2 world_cursor; - Rng2 ui_selection; - Rng2 draw_selection; - Rng2 world_selection; + Vec2 ui_cursor; + Vec2 draw_cursor; + Vec2 world_cursor; + Rng2 ui_selection; + Rng2 draw_selection; + Rng2 world_selection; - Vec2 camera_pos; - f32 camera_zoom; + Vec2 camera_pos; + f32 camera_zoom; - f32 world_size; - G_Texture2DRef tiles; - G_StructuredBufferRef quads; - G_StructuredBufferRef shape_verts; + f32 world_size; + G_Texture2DRef tiles; + G_StructuredBufferRef quads; + G_StructuredBufferRef shape_verts; }; //////////////////////////////////////////////////////////// @@ -47,13 +47,13 @@ Struct(V_DParams) Enum(V_DQuadFlag) { - V_DQuadFlag_None = 0, - V_DQuadFlag_DrawGrid = (1 << 0), + V_DQuadFlag_None = 0, + V_DQuadFlag_DrawGrid = (1 << 0), }; Struct(V_DQuad) { - V_DQuadFlag flags; + V_DQuadFlag flags; }; //////////////////////////////////////////////////////////// @@ -61,6 +61,6 @@ Struct(V_DQuad) Struct(V_DVert) { - Vec2 pos; - Vec4 color_lin; + Vec2 pos; + Vec4 color_lin; }; diff --git a/src/pp/pp_vis/pp_vis_shaders.g b/src/pp/pp_vis/pp_vis_shaders.g index 64de1852..e39b91e2 100644 --- a/src/pp/pp_vis/pp_vis_shaders.g +++ b/src/pp/pp_vis/pp_vis_shaders.g @@ -3,124 +3,124 @@ ComputeShader2D(V_BackdropCS, 8, 8) { - V_DParams params = G_Dereference(V_ShaderConst_Params)[0]; - RWTexture2D target = G_Dereference(params.target_rw); - Texture2D tiles = G_Dereference(params.tiles); + V_DParams params = G_Dereference(V_ShaderConst_Params)[0]; + RWTexture2D target = G_Dereference(params.target_rw); + Texture2D tiles = G_Dereference(params.tiles); - const Vec4 background_color_a = LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1)); - const Vec4 background_color_b = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1)); - const Vec4 grid_color = LinearFromSrgb(Vec4(0, 0, 0, 1)); - const Vec4 x_axis_color = LinearFromSrgb(Vec4(0.75, 0, 0, 1)); - const Vec4 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1)); - const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1)); + const Vec4 background_color_a = LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1)); + const Vec4 background_color_b = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1)); + const Vec4 grid_color = LinearFromSrgb(Vec4(0, 0, 0, 1)); + const Vec4 x_axis_color = LinearFromSrgb(Vec4(0.75, 0, 0, 1)); + const Vec4 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1)); + const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1)); - Vec2 screen_pos = Vec2(SV_DispatchThreadID) + Vec2(0.5, 0.5); - if (screen_pos.x < params.target_size.x && screen_pos.y < params.target_size.y) + Vec2 screen_pos = Vec2(SV_DispatchThreadID) + Vec2(0.5, 0.5); + if (screen_pos.x < params.target_size.x && screen_pos.y < params.target_size.y) + { + Vec4 result = Vec4(0.025, 0.025, 0.025, 1); + Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1)); + Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos); + + f32 half_thickness = 1; + f32 half_bounds_size = params.world_size * 0.5; + Vec2 bounds_screen_p0 = mul(params.world_to_draw_xf, Vec3(-half_bounds_size, -half_bounds_size, 1)); + Vec2 bounds_screen_p1 = mul(params.world_to_draw_xf, Vec3(half_bounds_size, half_bounds_size, 1)); + b32 is_in_bounds = screen_pos.x > (bounds_screen_p0.x - half_thickness) && + screen_pos.y > (bounds_screen_p0.y - half_thickness) && + screen_pos.x < (bounds_screen_p1.x + half_thickness) && + screen_pos.y < (bounds_screen_p1.y + half_thickness); + if (is_in_bounds) { - Vec4 result = Vec4(0.025, 0.025, 0.025, 1); - Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1)); - Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos); - - f32 half_thickness = 1; - f32 half_bounds_size = params.world_size * 0.5; - Vec2 bounds_screen_p0 = mul(params.world_to_draw_xf, Vec3(-half_bounds_size, -half_bounds_size, 1)); - Vec2 bounds_screen_p1 = mul(params.world_to_draw_xf, Vec3(half_bounds_size, half_bounds_size, 1)); - b32 is_in_bounds = screen_pos.x > (bounds_screen_p0.x - half_thickness) && - screen_pos.y > (bounds_screen_p0.y - half_thickness) && - screen_pos.x < (bounds_screen_p1.x + half_thickness) && - screen_pos.y < (bounds_screen_p1.y + half_thickness); - if (is_in_bounds) + /* Grid checker */ + { + i32 color_idx = 0; + Vec4 colors[2] = { + background_color_a, + background_color_b + }; + const f32 checker_size = 0.5; + Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(checker_size * 2, checker_size * 2)); + if (world_pos_modded.x < checker_size) { - /* Grid checker */ - { - i32 color_idx = 0; - Vec4 colors[2] = { - background_color_a, - background_color_b - }; - const f32 checker_size = 0.5; - Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(checker_size * 2, checker_size * 2)); - if (world_pos_modded.x < checker_size) - { - color_idx = !color_idx; - } - if (world_pos_modded.y < checker_size) - { - color_idx = !color_idx; - } - if (world_pos.x < 0) - { - color_idx = !color_idx; - } - if (world_pos.y < 0) - { - color_idx = !color_idx; - } - result = colors[color_idx]; - } - /* Grid outline */ - { - Vec2 grid_screen_p0 = mul(params.world_to_draw_xf, Vec3(floor(world_pos), 1)); - Vec2 grid_screen_p1 = mul(params.world_to_draw_xf, Vec3(ceil(world_pos), 1)); - f32 grid_dist = 100000; - grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p0.x)); - grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p1.x)); - grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p0.y)); - grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p1.y)); - if (grid_dist <= half_thickness) - { - result = grid_color; - } - } - /* Tile */ - { - S_TileKind tile = (S_TileKind)tiles.Load(Vec3I32(tile_pos, 0)); - switch (tile) - { - default: break; - - case S_TileKind_Floor: - { - result = Color_Blue; - } break; - - case S_TileKind_Wall: - { - result = Color_Red; - } break; - } - } - /* Axis */ - { - Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1)); - f32 x_dist = abs(screen_pos.x - zero_screen.x); - f32 y_dist = abs(screen_pos.y - zero_screen.y); - if (y_dist <= half_thickness) - { - result = x_axis_color; - } - else if (x_dist <= half_thickness) - { - result = y_axis_color; - } - } - /* World bounds */ - { - f32 bounds_dist = 100000; - bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p0.x)); - bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p1.x)); - bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p0.y)); - bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p1.y)); - if (bounds_dist <= half_thickness) - { - result = bounds_color; - } - } + color_idx = !color_idx; } + if (world_pos_modded.y < checker_size) + { + color_idx = !color_idx; + } + if (world_pos.x < 0) + { + color_idx = !color_idx; + } + if (world_pos.y < 0) + { + color_idx = !color_idx; + } + result = colors[color_idx]; + } + /* Grid outline */ + { + Vec2 grid_screen_p0 = mul(params.world_to_draw_xf, Vec3(floor(world_pos), 1)); + Vec2 grid_screen_p1 = mul(params.world_to_draw_xf, Vec3(ceil(world_pos), 1)); + f32 grid_dist = 100000; + grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p0.x)); + grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p1.x)); + grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p0.y)); + grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p1.y)); + if (grid_dist <= half_thickness) + { + result = grid_color; + } + } + /* Tile */ + { + S_TileKind tile = (S_TileKind)tiles.Load(Vec3I32(tile_pos, 0)); + switch (tile) + { + default: break; + case S_TileKind_Floor: + { + result = Color_Blue; + } break; - target[trunc(screen_pos)] = result; + case S_TileKind_Wall: + { + result = Color_Red; + } break; + } + } + /* Axis */ + { + Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1)); + f32 x_dist = abs(screen_pos.x - zero_screen.x); + f32 y_dist = abs(screen_pos.y - zero_screen.y); + if (y_dist <= half_thickness) + { + result = x_axis_color; + } + else if (x_dist <= half_thickness) + { + result = y_axis_color; + } + } + /* World bounds */ + { + f32 bounds_dist = 100000; + bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p0.x)); + bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p1.x)); + bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p0.y)); + bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p1.y)); + if (bounds_dist <= half_thickness) + { + result = bounds_color; + } + } } + + + target[trunc(screen_pos)] = result; + } } //////////////////////////////////////////////////////////// @@ -131,21 +131,21 @@ ComputeShader2D(V_BackdropCS, 8, 8) VertexShader(V_DQuadVS, V_DQuadPSInput) { - V_DParams params = G_Dereference(V_ShaderConst_Params)[0]; - StructuredBuffer quads = G_Dereference(params.quads); - RWTexture2D target = G_Dereference(params.target_rw); + V_DParams params = G_Dereference(V_ShaderConst_Params)[0]; + StructuredBuffer quads = G_Dereference(params.quads); + RWTexture2D target = G_Dereference(params.target_rw); - V_DQuad quad = quads[SV_InstanceID]; + V_DQuad quad = quads[SV_InstanceID]; - Vec2 rect_uv = RectUvFromVertexId(SV_VertexID); - // Vec2 tex_uv = lerp(quad.tex_uv0, quad.tex_uv1, rect_uv); - // Vec2 target_pos = lerp(quad.p0, quad.p1, rect_uv); - Vec2 target_pos = 0; + Vec2 rect_uv = RectUvFromVertexId(SV_VertexID); + // Vec2 tex_uv = lerp(quad.tex_uv0, quad.tex_uv1, rect_uv); + // Vec2 target_pos = lerp(quad.p0, quad.p1, rect_uv); + Vec2 target_pos = 0; - V_DQuadPSInput result; - result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1); - result.quad_idx = SV_InstanceID; - return result; + V_DQuadPSInput result; + result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1); + result.quad_idx = SV_InstanceID; + return result; } ////////////////////////////// @@ -153,15 +153,15 @@ VertexShader(V_DQuadVS, V_DQuadPSInput) PixelShader(V_DQuadPS, V_DQuadPSOutput, V_DQuadPSInput input) { - V_DParams params = G_Dereference(V_ShaderConst_Params)[0]; - StructuredBuffer quads = G_Dereference(params.quads); - V_DQuad quad = quads[input.quad_idx]; + V_DParams params = G_Dereference(V_ShaderConst_Params)[0]; + StructuredBuffer quads = G_Dereference(params.quads); + V_DQuad quad = quads[input.quad_idx]; - Vec4 final_color = 0; + Vec4 final_color = 0; - V_DQuadPSOutput output; - output.sv_target0 = final_color; - return output; + V_DQuadPSOutput output; + output.sv_target0 = final_color; + return output; } //////////////////////////////////////////////////////////// @@ -172,18 +172,18 @@ PixelShader(V_DQuadPS, V_DQuadPSOutput, V_DQuadPSInput input) VertexShader(V_DVertVS, V_DVertPSInput) { - V_DParams params = G_Dereference(V_ShaderConst_Params)[0]; - StructuredBuffer verts = G_Dereference(params.shape_verts); - RWTexture2D target = G_Dereference(params.target_rw); + V_DParams params = G_Dereference(V_ShaderConst_Params)[0]; + StructuredBuffer verts = G_Dereference(params.shape_verts); + RWTexture2D target = G_Dereference(params.target_rw); - V_DVert vert = verts[SV_VertexID]; + V_DVert vert = verts[SV_VertexID]; - Vec2 target_pos = vert.pos; + Vec2 target_pos = vert.pos; - V_DVertPSInput result; - result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1); - result.color_lin = vert.color_lin; - return result; + V_DVertPSInput result; + result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1); + result.color_lin = vert.color_lin; + return result; } ////////////////////////////// @@ -191,9 +191,9 @@ VertexShader(V_DVertVS, V_DVertPSInput) PixelShader(V_DVertPS, V_DVertPSOutput, V_DVertPSInput input) { - V_DVertPSOutput output; - output.sv_target0 = input.color_lin; - return output; + V_DVertPSOutput output; + output.sv_target0 = input.color_lin; + return output; } //////////////////////////////////////////////////////////// @@ -204,10 +204,10 @@ PixelShader(V_DVertPS, V_DVertPSOutput, V_DVertPSInput input) VertexShader(V_OverlayVS, V_OverlayPSInput) { - Vec2 uv = RectUvFromVertexId(SV_VertexID); - V_OverlayPSInput result; - result.sv_position = Vec4(NdcFromUv(uv).xy, 0, 1); - return result; + Vec2 uv = RectUvFromVertexId(SV_VertexID); + V_OverlayPSInput result; + result.sv_position = Vec4(NdcFromUv(uv).xy, 0, 1); + return result; } ////////////////////////////// @@ -215,59 +215,59 @@ VertexShader(V_OverlayVS, V_OverlayPSInput) PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input) { - V_DParams params = G_Dereference(V_ShaderConst_Params)[0]; - Texture2D tiles = G_Dereference(params.tiles); - Vec2 screen_pos = input.sv_position.xy; - Vec4 result = 0; + V_DParams params = G_Dereference(V_ShaderConst_Params)[0]; + Texture2D tiles = G_Dereference(params.tiles); + Vec2 screen_pos = input.sv_position.xy; + Vec4 result = 0; - Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1)); - Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos); - S_TileKind equipped_tile = params.equipped_tile; + Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1)); + Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos); + S_TileKind equipped_tile = params.equipped_tile; - f32 half_thickness = 1; - Vec4 border_color = LinearFromSrgb(Vec4(1, 1, 1, 1)); - // Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.4, 0.4, 0.25)); + f32 half_thickness = 1; + Vec4 border_color = LinearFromSrgb(Vec4(1, 1, 1, 1)); + // Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.4, 0.4, 0.25)); - Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.8, 0.4, 0.6)); + Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.8, 0.4, 0.6)); - Rng2 screen_selection = params.draw_selection; - Rng2 world_selection = params.world_selection; + Rng2 screen_selection = params.draw_selection; + Rng2 world_selection = params.world_selection; - Rng2I32 tile_selection; - tile_selection.p0 = S_TilePosFromWorldPos(world_selection.p0); - tile_selection.p1 = S_TilePosFromWorldPos(world_selection.p1); + Rng2I32 tile_selection; + tile_selection.p0 = S_TilePosFromWorldPos(world_selection.p0); + tile_selection.p1 = S_TilePosFromWorldPos(world_selection.p1); - if (params.selection_mode == V_SelectionMode_Tile) + if (params.selection_mode == V_SelectionMode_Tile) + { + f32 dist = 100000000; + dist = min(dist, screen_pos.x - screen_selection.p0.x); + dist = min(dist, screen_pos.y - screen_selection.p0.y); + dist = min(dist, screen_selection.p1.x - screen_pos.x); + dist = min(dist, screen_selection.p1.y - screen_pos.y); + dist = -dist; + + // if (dist >= -half_thickness && dist <= half_thickness) + // { + // result = border_color; + // } + // else { - f32 dist = 100000000; - dist = min(dist, screen_pos.x - screen_selection.p0.x); - dist = min(dist, screen_pos.y - screen_selection.p0.y); - dist = min(dist, screen_selection.p1.x - screen_pos.x); - dist = min(dist, screen_selection.p1.y - screen_pos.y); - dist = -dist; - - // if (dist >= -half_thickness && dist <= half_thickness) - // { - // result = border_color; - // } - // else - { - if (world_pos.x > -(S_WorldSize / 2) && - world_pos.y > -(S_WorldSize / 2) && - world_pos.x < (S_WorldSize / 2) && - world_pos.y < (S_WorldSize / 2) && - tile_pos.x >= tile_selection.p0.x && - tile_pos.x <= tile_selection.p1.x && - tile_pos.y >= tile_selection.p0.y && - tile_pos.y <= tile_selection.p1.y) - { - result = inner_color; - } - } + if (world_pos.x > -(S_WorldSize / 2) && + world_pos.y > -(S_WorldSize / 2) && + world_pos.x < (S_WorldSize / 2) && + world_pos.y < (S_WorldSize / 2) && + tile_pos.x >= tile_selection.p0.x && + tile_pos.x <= tile_selection.p1.x && + tile_pos.y >= tile_selection.p0.y && + tile_pos.y <= tile_selection.p1.y) + { + result = inner_color; + } } + } - V_OverlayPSOutput output; - output.sv_target0 = result; - return output; + V_OverlayPSOutput output; + output.sv_target0 = result; + return output; } diff --git a/src/pp/pp_vis/pp_vis_shaders.gh b/src/pp/pp_vis/pp_vis_shaders.gh index d311e6e1..b29865ec 100644 --- a/src/pp/pp_vis/pp_vis_shaders.gh +++ b/src/pp/pp_vis/pp_vis_shaders.gh @@ -3,13 +3,13 @@ Struct(V_DQuadPSInput) { - Semantic(Vec4, sv_position); - Semantic(nointerpolation u32, quad_idx); + Semantic(Vec4, sv_position); + Semantic(nointerpolation u32, quad_idx); }; Struct(V_DQuadPSOutput) { - Semantic(Vec4, sv_target0); + Semantic(Vec4, sv_target0); }; //////////////////////////////////////////////////////////// @@ -18,13 +18,13 @@ Struct(V_DQuadPSOutput) Struct(V_DVertPSInput) { - Semantic(Vec4, sv_position); - Semantic(Vec4, color_lin); + Semantic(Vec4, sv_position); + Semantic(Vec4, color_lin); }; Struct(V_DVertPSOutput) { - Semantic(Vec4, sv_target0); + Semantic(Vec4, sv_target0); }; //////////////////////////////////////////////////////////// @@ -33,12 +33,12 @@ Struct(V_DVertPSOutput) Struct(V_OverlayPSInput) { - Semantic(Vec4, sv_position); + Semantic(Vec4, sv_position); }; Struct(V_OverlayPSOutput) { - Semantic(Vec4, sv_target0); + Semantic(Vec4, sv_target0); }; //////////////////////////////////////////////////////////// diff --git a/src/pp_old/pp.c b/src/pp_old/pp.c index 3c00c7d4..d75998ea 100644 --- a/src/pp_old/pp.c +++ b/src/pp_old/pp.c @@ -5,62 +5,62 @@ PP_SharedUserState PP_shared_user_state = ZI; void PP_StartupUser(void) { - __prof; - PP_SharedUserState *g = &PP_shared_user_state; + __prof; + PP_SharedUserState *g = &PP_shared_user_state; - SetGstat(GSTAT_DEBUG_STEPS, U64Max); + SetGstat(GSTAT_DEBUG_STEPS, U64Max); - Arena *perm = PermArena(); - g->real_time_ns = TimeNs(); + Arena *perm = PermArena(); + g->real_time_ns = TimeNs(); - /* TODO: Remove this */ - String connect_address_str = Lit(""); - g->connect_address_str = PushString(perm, connect_address_str); + /* TODO: Remove this */ + String connect_address_str = Lit(""); + g->connect_address_str = PushString(perm, connect_address_str); - /* Initialize average dt to a reasonable value */ - g->average_local_to_user_snapshot_publish_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; + /* Initialize average dt to a reasonable value */ + g->average_local_to_user_snapshot_publish_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; - /* User blend clients */ - g->user_client_store = PP_AcquireClientStore(); - g->user_unblended_client = PP_AcquireClient(g->user_client_store); - g->user_blended_client = PP_AcquireClient(g->user_client_store); - g->ss_blended = PP_NilSnapshot(); + /* User blend clients */ + g->user_client_store = PP_AcquireClientStore(); + g->user_unblended_client = PP_AcquireClient(g->user_client_store); + g->user_blended_client = PP_AcquireClient(g->user_client_store); + g->ss_blended = PP_NilSnapshot(); - /* Local to user client */ - g->local_to_user_client_store = PP_AcquireClientStore(); - g->local_to_user_client = PP_AcquireClient(g->local_to_user_client_store); + /* Local to user client */ + g->local_to_user_client_store = PP_AcquireClientStore(); + g->local_to_user_client = PP_AcquireClient(g->local_to_user_client_store); - /* Init from swap */ - if (IsSwappedIn()); + /* Init from swap */ + if (IsSwappedIn()); + { + TempArena scratch = BeginScratchNoConflict(); + String swap_encoded = SwappedStateFromName(scratch.arena, Lit("pp_user")); + + BB_Buff bb = BB_BuffFromString(swap_encoded); + BB_Reader br = BB_ReaderFromBuff(&bb); + + String swap_str = BB_ReadString(scratch.arena, &br); + g->window_restore = BB_ReadString(perm, &br); + + if (swap_str.len == sizeof(PP_SwappedUserState)) { - TempArena scratch = BeginScratchNoConflict(); - String swap_encoded = SwappedStateFromName(scratch.arena, Lit("pp_user")); - - BB_Buff bb = BB_BuffFromString(swap_encoded); - BB_Reader br = BB_ReaderFromBuff(&bb); - - String swap_str = BB_ReadString(scratch.arena, &br); - g->window_restore = BB_ReadString(perm, &br); - - if (swap_str.len == sizeof(PP_SwappedUserState)) - { - PP_SwappedUserState *swap = PushStructNoZero(scratch.arena, PP_SwappedUserState); - CopyBytes(swap, swap_str.text, swap_str.len); - PP_SharedUserState *old = &swap->s; - CopyStructRegion(g, old, AUTO_PERSIST_START, AUTO_PERSIST_END); - } - - EndScratch(scratch); + PP_SwappedUserState *swap = PushStructNoZero(scratch.arena, PP_SwappedUserState); + CopyBytes(swap, swap_str.text, swap_str.len); + PP_SharedUserState *old = &swap->s; + CopyStructRegion(g, old, AUTO_PERSIST_START, AUTO_PERSIST_END); } - /* Create job pools */ - JobPoolId user_pool = InitJobPool(1, Lit("User"), JobPoolPriority_Graphics); - JobPoolId sim_pool = InitJobPool(1, Lit("Simulation"), JobPoolPriority_Simulation); + EndScratch(scratch); + } - /* Start jobs */ - g->shutdown_jobs_count += RunJob(PP_UpdateUserOrSleep, .pool = user_pool, .fence = &g->shutdown_jobs_fence); - g->shutdown_jobs_count += RunJob(PP_UpdateSim, .pool = sim_pool, .fence = &g->shutdown_jobs_fence); - OnExit(&PP_ShutdownUser); + /* Create job pools */ + JobPoolId user_pool = InitJobPool(1, Lit("User"), JobPoolPriority_Graphics); + JobPoolId sim_pool = InitJobPool(1, Lit("Simulation"), JobPoolPriority_Simulation); + + /* Start jobs */ + g->shutdown_jobs_count += RunJob(PP_UpdateUserOrSleep, .pool = user_pool, .fence = &g->shutdown_jobs_fence); + g->shutdown_jobs_count += RunJob(PP_UpdateSim, .pool = sim_pool, .fence = &g->shutdown_jobs_fence); + OnExit(&PP_ShutdownUser); } //////////////////////////////////////////////////////////// @@ -68,28 +68,28 @@ void PP_StartupUser(void) ExitFuncDef(PP_ShutdownUser) { - __prof; - PP_SharedUserState *g = &PP_shared_user_state; - Atomic32Set(&g->shutdown, 1); - YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count); + __prof; + PP_SharedUserState *g = &PP_shared_user_state; + Atomic32Set(&g->shutdown, 1); + YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count); - /* Swap out */ - if (IsSwappingOut()) + /* Swap out */ + if (IsSwappingOut()) + { + TempArena scratch = BeginScratchNoConflict(); + u64 max_size = Mebi(16); + u8 *bytes = PushStructsNoZero(scratch.arena, u8, max_size); + BB_Buff bb = BB_BuffFromString(STRING(max_size, bytes)); { - TempArena scratch = BeginScratchNoConflict(); - u64 max_size = Mebi(16); - u8 *bytes = PushStructsNoZero(scratch.arena, u8, max_size); - BB_Buff bb = BB_BuffFromString(STRING(max_size, bytes)); - { - BB_Writer bw = BB_WriterFromBuff(&bb); - PP_SwappedUserState *swap = PushStruct(scratch.arena, PP_SwappedUserState); - swap->s = *g; - BB_WriteString(&bw, StringFromStruct(swap)); - BB_WriteString(&bw, g->window_restore); - WriteSwappedState(Lit("pp_user"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw))); - } - EndScratch(scratch); + BB_Writer bw = BB_WriterFromBuff(&bb); + PP_SwappedUserState *swap = PushStruct(scratch.arena, PP_SwappedUserState); + swap->s = *g; + BB_WriteString(&bw, StringFromStruct(swap)); + BB_WriteString(&bw, g->window_restore); + WriteSwappedState(Lit("pp_user"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw))); } + EndScratch(scratch); + } } //////////////////////////////////////////////////////////// @@ -98,196 +98,178 @@ ExitFuncDef(PP_ShutdownUser) //- Ui style void PP_PushGameUiStyle(void) { - // UI_Push(FontSize, 48); - // UI_Push(FontSize, 32); + // UI_Push(FontSize, 48); + // UI_Push(FontSize, 32); - // UI_Push(Font, ResourceKeyFromStore(&PP_Resources, Lit("font/roboto-med.ttf"))); - UI_Push(Font, ResourceKeyFromStore(&PP_Resources, Lit("font/fixedsys.ttf"))); - UI_Push(FontSize, 16); + // UI_Push(Font, ResourceKeyFromStore(&PP_Resources, Lit("font/roboto-med.ttf"))); + UI_Push(Font, ResourceKeyFromStore(&PP_Resources, Lit("font/fixedsys.ttf"))); + UI_Push(FontSize, 16); - UI_Push(Rounding, UI_RPIX(0)); + UI_Push(Rounding, UI_RPIX(0)); - UI_Push(Border, 1); - // UI_Push(BackgroundColor, Rgba32F(0.3, 0.5, 0.3, 0.3)); - UI_Push(BackgroundColor, Rgba32F(0.3, 0.3, 0.3, 1)); + UI_Push(Border, 1); + // UI_Push(BackgroundColor, Rgba32F(0.3, 0.5, 0.3, 0.3)); + UI_Push(BackgroundColor, Rgba32F(0.3, 0.3, 0.3, 1)); - UI_Push(BorderColor, Rgba32F(0.6, 0.6, 0.6, 1)); + UI_Push(BorderColor, Rgba32F(0.6, 0.6, 0.6, 1)); - UI_Push(Width, UI_FILL(1, 0)); - UI_Push(Height, UI_FILL(1, 0)); + UI_Push(Width, UI_FILL(1, 0)); + UI_Push(Height, UI_FILL(1, 0)); - UI_Push(ChildLayoutAxis, Axis_Y); + UI_Push(ChildLayoutAxis, Axis_Y); } //- Draw xform void PP_DrawDebugXform(Xform xf, u32 color_x, u32 color_y) { - PP_SharedUserState *g = &PP_shared_user_state; - f32 thickness = 2.f; - f32 arrowhead_len = 15.f; + PP_SharedUserState *g = &PP_shared_user_state; + f32 thickness = 2.f; + f32 arrowhead_len = 15.f; - Vec2 pos = MulXformV2(g->world_to_ui_xf, xf.og); - Vec2 x_ray = MulXformBasisV2(g->world_to_ui_xf, RightFromXform(xf)); - Vec2 y_ray = MulXformBasisV2(g->world_to_ui_xf, UpFromXform(xf)); + Vec2 pos = MulXformV2(g->world_to_ui_xf, xf.og); + Vec2 x_ray = MulXformBasisV2(g->world_to_ui_xf, RightFromXform(xf)); + Vec2 y_ray = MulXformBasisV2(g->world_to_ui_xf, UpFromXform(xf)); - f32 ray_scale = 1; - x_ray = MulVec2(x_ray, ray_scale); - y_ray = MulVec2(y_ray, ray_scale); + f32 ray_scale = 1; + x_ray = MulVec2(x_ray, ray_scale); + y_ray = MulVec2(y_ray, ray_scale); - /* FIXME: Enable this */ + /* FIXME: Enable this */ #if 0 - D_DrawArrowRay(g->render_sig, pos, x_ray, thickness, arrowhead_len, color_x); - D_DrawArrowRay(g->render_sig, pos, y_ray, thickness, arrowhead_len, color_y); -#else - LAX x_ray; - LAX y_ray; - LAX thickness; - LAX arrowhead_len; - LAX pos; - LAX color_x; - LAX color_y; + D_DrawArrowRay(g->render_sig, pos, x_ray, thickness, arrowhead_len, color_x); + D_DrawArrowRay(g->render_sig, pos, y_ray, thickness, arrowhead_len, color_y); #endif - //u32 color_quad = Rgba32F(0, 1, 1, 0.3); - //Quad quad = QuadFromRect(RectFromScalar(0, 0, 1, -1)); - //quad = MulXformQuad(xf, ScaleQuad(quad, 0.075f)); - //D_DrawQuad(g->render_sig, quad, color); + //u32 color_quad = Rgba32F(0, 1, 1, 0.3); + //Quad quad = QuadFromRect(RectFromScalar(0, 0, 1, -1)); + //quad = MulXformQuad(xf, ScaleQuad(quad, 0.075f)); + //D_DrawQuad(g->render_sig, quad, color); } //- Draw movement void PP_DrawDebugMovement(PP_Ent *ent) { - PP_SharedUserState *g = &PP_shared_user_state; - f32 thickness = 2.f; - f32 arrow_len = 15.f; + PP_SharedUserState *g = &PP_shared_user_state; + f32 thickness = 2.f; + f32 arrow_len = 15.f; - u32 color_vel = Color_Orange; + u32 color_vel = Color_Orange; - Xform xf = PP_XformFromEnt(ent); - Vec2 velocity = ent->linear_velocity; + Xform xf = PP_XformFromEnt(ent); + Vec2 velocity = ent->linear_velocity; - Vec2 pos = MulXformV2(g->world_to_ui_xf, xf.og); - Vec2 vel_ray = MulXformBasisV2(g->world_to_ui_xf, velocity); + Vec2 pos = MulXformV2(g->world_to_ui_xf, xf.og); + Vec2 vel_ray = MulXformBasisV2(g->world_to_ui_xf, velocity); - if (Vec2Len(vel_ray) > 0.00001) - { - /* FIXME: Enable this */ -#if 0 - D_DrawArrowRay(g->render_sig, pos, vel_ray, thickness, arrow_len, color_vel); -#else - LAX thickness; - LAX arrow_len; - LAX color_vel; - LAX xf; - LAX velocity; - LAX pos; - LAX vel_ray; -#endif - } + if (Vec2Len(vel_ray) > 0.00001) + { + /* FIXME: Enable this */ + D_DrawArrowRay(g->render_sig, pos, vel_ray, thickness, arrow_len, color_vel); + } } //- Ent debug string String PP_DebugStringFromEnt(Arena *arena, PP_Ent *ent) { - TempArena scratch = BeginScratch(arena); - PP_Snapshot *ss = ent->ss; + TempArena scratch = BeginScratch(arena); + PP_Snapshot *ss = ent->ss; - const u8 hex[] = "0123456789abcdef"; + const u8 hex[] = "0123456789abcdef"; - String result = ZI; - result.text = PushDry(arena, u8); + String result = ZI; + result.text = PushDry(arena, u8); - //result.len += StringF(arena, "[%F]", FmtUid(ent->key.uid)).len; + //result.len += StringF(arena, "[%F]", FmtUid(ent->key.uid)).len; + { + b32 transmitting = PP_HasProp(ent, PP_Prop_SyncSrc); + b32 receiving = PP_HasProp(ent, PP_Prop_SyncDst); + if (transmitting & receiving) { - b32 transmitting = PP_HasProp(ent, PP_Prop_SyncSrc); - b32 receiving = PP_HasProp(ent, PP_Prop_SyncDst); - if (transmitting & receiving) + result.len += StringF(arena, " networked (sending & receiving)").len; + } + else if (transmitting) + { + result.len += StringF(arena, " networked (sending)").len; + } + else if (receiving) + { + result.len += StringF(arena, " networked (receiving)").len; + } + else + { + result.len += StringF(arena, " local").len; + } + } + result.len += StringF(arena, "\n").len; + + result.len += StringF(arena, "owner: [%F]\n", FmtUid(ent->owner.uid)).len; + + result.len += StringF(arena, "\n").len; + + { + result.len += StringF(arena, "props: 0x").len; + for (u64 chunk_index = countof(ent->props); chunk_index-- > 0;) + { + u64 chunk = ent->props[chunk_index]; + for (u64 part_index = 8; part_index-- > 0;) + { + if ((chunk_index != (countof(ent->props) - 1)) || ((chunk_index * 64) + (part_index * 8)) <= PP_Prop_Count) { - result.len += StringF(arena, " networked (sending & receiving)").len; - } - else if (transmitting) - { - result.len += StringF(arena, " networked (sending)").len; - } - else if (receiving) - { - result.len += StringF(arena, " networked (receiving)").len; - } - else - { - result.len += StringF(arena, " local").len; + u8 part = (chunk >> (part_index * 8)) & 0xFF; + StringFromChar(arena, hex[(part >> 4) & 0x0F]); + StringFromChar(arena, hex[(part >> 0) & 0x0F]); + result.len += 2; } + } } result.len += StringF(arena, "\n").len; + } - result.len += StringF(arena, "owner: [%F]\n", FmtUid(ent->owner.uid)).len; + if (!PP_EqEntKey(ent->parent, PP_RootEntKey)) + { + result.len += StringF(arena, "parent: [%F]\n", FmtUid(ent->parent.uid)).len; + } - result.len += StringF(arena, "\n").len; + if (!PP_IsNilEntKey(ent->next) || !PP_IsNilEntKey(ent->prev)) + { + result.len += StringF(arena, "prev: [%F]\n", FmtUid(ent->prev.uid)).len; + result.len += StringF(arena, "next: [%F]\n", FmtUid(ent->next.uid)).len; + } + result.len += StringF(arena, "\n").len; + + /* Pos */ + Xform xf = PP_XformFromEnt(ent); + Vec2 linear_velocity = ent->linear_velocity; + f32 angular_velocity = ent->angular_velocity; + result.len += StringF(arena, "pos: (%F, %F)\n", FmtFloat(xf.og.x), FmtFloat(xf.og.y)).len; + result.len += StringF(arena, "linear velocity: (%F, %F)\n", FmtFloat(linear_velocity.x), FmtFloat(linear_velocity.y)).len; + result.len += StringF(arena, "angular velocity: %F\n", FmtFloat(angular_velocity)).len; + + /* Test */ + result.len += StringF(arena, "collision dir: (%F, %F)\n", FmtFloat(ent->collision_dir.x), FmtFloat(ent->collision_dir.y)).len; + + /* Children */ + if (!PP_IsNilEntKey(ent->first) || !PP_IsNilEntKey(ent->last)) + { + PP_Ent *child = PP_EntFromKey(ss, ent->first); + if (!PP_EqEntKey(ent->first, ent->last) || !child->valid) { - result.len += StringF(arena, "props: 0x").len; - for (u64 chunk_index = countof(ent->props); chunk_index-- > 0;) - { - u64 chunk = ent->props[chunk_index]; - for (u64 part_index = 8; part_index-- > 0;) - { - if ((chunk_index != (countof(ent->props) - 1)) || ((chunk_index * 64) + (part_index * 8)) <= PP_Prop_Count) - { - u8 part = (chunk >> (part_index * 8)) & 0xFF; - StringFromChar(arena, hex[(part >> 4) & 0x0F]); - StringFromChar(arena, hex[(part >> 0) & 0x0F]); - result.len += 2; - } - } - } - result.len += StringF(arena, "\n").len; + result.len += StringF(arena, "first child: [%F]\n", FmtUid(ent->first.uid)).len; + result.len += StringF(arena, "last child: [%F]\n", FmtUid(ent->last.uid)).len; } - - if (!PP_EqEntKey(ent->parent, PP_RootEntKey)) + while (child->valid) { - result.len += StringF(arena, "parent: [%F]\n", FmtUid(ent->parent.uid)).len; + result.len += StringF(arena, "\n---------------------------------\n").len; + result.len += StringF(arena, "CHILD\n").len; + String child_text = PP_DebugStringFromEnt(scratch.arena, child); + result.len += IndentString(arena, child_text, 4).len; + child = PP_EntFromKey(ss, child->next); } + } - if (!PP_IsNilEntKey(ent->next) || !PP_IsNilEntKey(ent->prev)) - { - result.len += StringF(arena, "prev: [%F]\n", FmtUid(ent->prev.uid)).len; - result.len += StringF(arena, "next: [%F]\n", FmtUid(ent->next.uid)).len; - } - - result.len += StringF(arena, "\n").len; - - /* Pos */ - Xform xf = PP_XformFromEnt(ent); - Vec2 linear_velocity = ent->linear_velocity; - f32 angular_velocity = ent->angular_velocity; - result.len += StringF(arena, "pos: (%F, %F)\n", FmtFloat(xf.og.x), FmtFloat(xf.og.y)).len; - result.len += StringF(arena, "linear velocity: (%F, %F)\n", FmtFloat(linear_velocity.x), FmtFloat(linear_velocity.y)).len; - result.len += StringF(arena, "angular velocity: %F\n", FmtFloat(angular_velocity)).len; - - /* Test */ - result.len += StringF(arena, "collision dir: (%F, %F)\n", FmtFloat(ent->collision_dir.x), FmtFloat(ent->collision_dir.y)).len; - - /* Children */ - if (!PP_IsNilEntKey(ent->first) || !PP_IsNilEntKey(ent->last)) - { - PP_Ent *child = PP_EntFromKey(ss, ent->first); - if (!PP_EqEntKey(ent->first, ent->last) || !child->valid) - { - result.len += StringF(arena, "first child: [%F]\n", FmtUid(ent->first.uid)).len; - result.len += StringF(arena, "last child: [%F]\n", FmtUid(ent->last.uid)).len; - } - while (child->valid) - { - result.len += StringF(arena, "\n---------------------------------\n").len; - result.len += StringF(arena, "CHILD\n").len; - String child_text = PP_DebugStringFromEnt(scratch.arena, child); - result.len += IndentString(arena, child_text, 4).len; - child = PP_EntFromKey(ss, child->next); - } - } - - EndScratch(scratch); - return result; + EndScratch(scratch); + return result; } //////////////////////////////////////////////////////////// @@ -297,13 +279,13 @@ String PP_DebugStringFromEnt(Arena *arena, PP_Ent *ent) GPU_Resource *PP_AcquireGbuffer(GPU_Format format, Vec2I32 size) { - __prof; - GPU_ResourceDesc desc = ZI; - desc.kind = GPU_ResourceKind_Texture2D; - desc.flags = GPU_ResourceFlag_Writable | GPU_ResourceFlag_Renderable; - desc.texture.format = format; - desc.texture.size = VEC3I32(size.x, size.y, 1); - return GPU_AcquireResource(desc); + __prof; + GPU_ResourceDesc desc = ZI; + desc.kind = GPU_ResourceKind_Texture2D; + desc.flags = GPU_ResourceFlag_Writable | GPU_ResourceFlag_Renderable; + desc.texture.format = format; + desc.texture.size = VEC3I32(size.x, size.y, 1); + return GPU_AcquireResource(desc); } //////////////////////////////////////////////////////////// @@ -311,41 +293,41 @@ GPU_Resource *PP_AcquireGbuffer(GPU_Format format, Vec2I32 size) MergesortCompareFuncDef(PP_EntSortCmp, arg_a, arg_b, _) { - PP_Ent *a = *(PP_Ent **)arg_a; - PP_Ent *b = *(PP_Ent **)arg_b; + PP_Ent *a = *(PP_Ent **)arg_a; + PP_Ent *b = *(PP_Ent **)arg_b; - i32 result = 0; + i32 result = 0; - if (result == 0) - { - /* Sort by light */ - b32 a_cmp = PP_HasProp(a, PP_Prop_LightTest); - b32 b_cmp = PP_HasProp(b, PP_Prop_LightTest); - result = (a_cmp > b_cmp) - (a_cmp < b_cmp); - } - if (result == 0) - { - /* Sort by layer */ - i32 a_cmp = a->layer; - i32 b_cmp = b->layer; - result = (a_cmp < b_cmp) - (a_cmp > b_cmp); - } - if (result == 0) - { - /* Sort by sprite */ - u64 a_cmp = a->sprite.hash; - u64 b_cmp = b->sprite.hash; - result = (a_cmp < b_cmp) - (a_cmp > b_cmp); - } - if (result == 0) - { - /* Sort by activation */ - u64 a_cmp = a->activation_tick; - u64 b_cmp = b->activation_tick; - result = (a_cmp < b_cmp) - (a_cmp > b_cmp); - } + if (result == 0) + { + /* Sort by light */ + b32 a_cmp = PP_HasProp(a, PP_Prop_LightTest); + b32 b_cmp = PP_HasProp(b, PP_Prop_LightTest); + result = (a_cmp > b_cmp) - (a_cmp < b_cmp); + } + if (result == 0) + { + /* Sort by layer */ + i32 a_cmp = a->layer; + i32 b_cmp = b->layer; + result = (a_cmp < b_cmp) - (a_cmp > b_cmp); + } + if (result == 0) + { + /* Sort by sprite */ + u64 a_cmp = a->sprite.hash; + u64 b_cmp = b->sprite.hash; + result = (a_cmp < b_cmp) - (a_cmp > b_cmp); + } + if (result == 0) + { + /* Sort by activation */ + u64 a_cmp = a->activation_tick; + u64 b_cmp = b->activation_tick; + result = (a_cmp < b_cmp) - (a_cmp > b_cmp); + } - return result; + return result; } //////////////////////////////////////////////////////////// @@ -353,2066 +335,1959 @@ MergesortCompareFuncDef(PP_EntSortCmp, arg_a, arg_b, _) void PP_UpdateUser(void) { - __prof; - PP_SharedUserState *g = &PP_shared_user_state; - TempArena scratch = BeginScratchNoConflict(); + __prof; + PP_SharedUserState *g = &PP_shared_user_state; + TempArena scratch = BeginScratchNoConflict(); - //- Begin UI frame - UI_FrameFlag ui_frame_flags = 0; - ui_frame_flags |= UI_FrameFlag_Debug * !!g->ui_debug; - ui_frame_flags |= UI_FrameFlag_Vsync * !!VSYNC; - UI_Frame ui_frame = UI_BeginFrame(ui_frame_flags); - WND_Frame window_frame = ui_frame.window_frame; - ControllerEventsArray controller_events = window_frame.controller_events; + //- Begin UI frame + UI_FrameFlag ui_frame_flags = 0; + ui_frame_flags |= UI_FrameFlag_Debug * !!g->ui_debug; + ui_frame_flags |= UI_FrameFlag_Vsync * !!VSYNC; + UI_Frame ui_frame = UI_BeginFrame(ui_frame_flags); + WND_Frame window_frame = ui_frame.window_frame; + ControllerEventsArray controller_events = window_frame.controller_events; - g->real_dt_ns = TimeNs() - g->real_time_ns; - g->real_time_ns += g->real_dt_ns; + g->real_dt_ns = TimeNs() - g->real_time_ns; + g->real_time_ns += g->real_dt_ns; - //- Restore window - if (g->user_tick == 0) + //- Restore window + if (g->user_tick == 0) + { + String restore = g->window_restore; + if (restore.len > 0) { - String restore = g->window_restore; - if (restore.len > 0) - { - WND_PushCmd(window_frame, .kind = WND_CmdKind_Restore, .restore = restore); - } + WND_PushCmd(window_frame, .kind = WND_CmdKind_Restore, .restore = restore); + } + } + else + { + String src = window_frame.restore; + if (src.len > g->window_restore.len) + { + Arena *perm = PermArena(); + g->window_restore = PushString(perm, src); + } + CopyBytes(g->window_restore.text, src.text, src.len); + g->window_restore.len = src.len; + } + + + g->screen_size = window_frame.draw_size; + g->screen_size.x = MaxI32(g->screen_size.x, 1); + g->screen_size.y = MaxI32(g->screen_size.y, 1); + + //- Init render data buffers + if (!g->material_instances_arena) + { + g->material_instances_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(PP_MaterialInstance)); + g->grids_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(PP_MaterialGrid)); + g->material_instances_arena = AcquireArena(Gibi(64)); + g->grids_arena = AcquireArena(Gibi(64)); + } + + //- Pull latest local sim snapshot + { + __profn("Pull snapshot"); + Lock lock = LockE(&g->local_to_user_client_mutex); + u64 old_last_tick = g->user_unblended_client->last_tick; + u64 last_tick = g->local_to_user_client->last_tick; + if (last_tick > old_last_tick) + { + PP_Snapshot *src = PP_SnapshotFromTick(g->local_to_user_client, last_tick); + PP_AcquireSnapshot(g->user_unblended_client, src, src->tick); + g->last_local_to_user_snapshot_published_at_ns = g->local_to_user_client_publish_time_ns; + g->average_local_to_user_snapshot_publish_dt_ns -= g->average_local_to_user_snapshot_publish_dt_ns / 50; + g->average_local_to_user_snapshot_publish_dt_ns += g->local_to_user_client_publish_dt_ns / 50; + } + Unlock(&lock); + } + + //- Create user world from blended snapshots + { + __profn("Blend snapshots"); + /* Determine how far along are we between sim ticks (0 = start of tick, 1 = end of tick) */ + f64 tick_progress = 0; + i64 next_tick_expected_ns = g->last_local_to_user_snapshot_published_at_ns + g->average_local_to_user_snapshot_publish_dt_ns; + if (next_tick_expected_ns > g->last_local_to_user_snapshot_published_at_ns) + { + tick_progress = (f64)(g->real_time_ns - g->last_local_to_user_snapshot_published_at_ns) / (f64)(next_tick_expected_ns - g->last_local_to_user_snapshot_published_at_ns); + } + + /* Predict local sim time based on average snapshot publish dt. */ + PP_Snapshot *newest_snapshot = PP_SnapshotFromTick(g->user_unblended_client, g->user_unblended_client->last_tick); + g->local_sim_last_known_time_ns = newest_snapshot->sim_time_ns; + g->local_sim_last_known_tick = newest_snapshot->tick; + if (Atomic32Fetch(&g->user_paused)) + { + g->local_sim_predicted_time_ns = g->local_sim_last_known_tick; } else { - String src = window_frame.restore; - if (src.len > g->window_restore.len) - { - Arena *perm = PermArena(); - g->window_restore = PushString(perm, src); - } - CopyBytes(g->window_restore.text, src.text, src.len); - g->window_restore.len = src.len; + g->local_sim_predicted_time_ns = newest_snapshot->sim_time_ns + (newest_snapshot->sim_dt_ns * tick_progress); } - - g->screen_size = window_frame.draw_size; - g->screen_size.x = MaxI32(g->screen_size.x, 1); - g->screen_size.y = MaxI32(g->screen_size.y, 1); - - //- Init render data buffers - if (!g->material_instances_arena) + if (USER_INTERP_ENABLED && !Atomic32Fetch(&g->user_paused)) { - g->material_instances_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(PP_MaterialInstance)); - g->grids_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(PP_MaterialGrid)); - g->material_instances_arena = AcquireArena(Gibi(64)); - g->grids_arena = AcquireArena(Gibi(64)); + /* Determine render time */ + g->render_time_target_ns = g->local_sim_predicted_time_ns - (USER_INTERP_RATIO * g->average_local_to_user_snapshot_publish_dt_ns); + if (g->average_local_to_user_snapshot_publish_dt_ns > 0) + { + /* Increment render time based on average publish dt */ + f64 sim_publish_timescale = (f64)newest_snapshot->sim_dt_ns / (f64)g->average_local_to_user_snapshot_publish_dt_ns; + g->render_time_ns += g->real_dt_ns * sim_publish_timescale; + } + i64 render_time_target_diff_ns = g->render_time_target_ns - g->render_time_ns; + if (render_time_target_diff_ns > NsFromSeconds(0.010) || render_time_target_diff_ns < NsFromSeconds(-0.005)) + { + /* Snap render time if it gets too out of sync with target render time */ + g->render_time_ns = g->render_time_target_ns; + } + + /* Get two snapshots nearest to render time */ + PP_Snapshot *left_snapshot = PP_NilSnapshot(); + PP_Snapshot *right_snapshot = newest_snapshot; + { + PP_Snapshot *ss = PP_SnapshotFromTick(g->user_unblended_client, g->user_unblended_client->first_tick); + while (ss->valid) + { + u64 next_tick = ss->next_tick; + i64 ss_time_ns = ss->sim_time_ns; + if (ss_time_ns < g->render_time_ns && ss_time_ns > left_snapshot->sim_time_ns) + { + left_snapshot = ss; + } + if (ss_time_ns > g->render_time_ns && ss_time_ns < right_snapshot->sim_time_ns) + { + right_snapshot = ss; + } + ss = PP_SnapshotFromTick(g->user_unblended_client, next_tick); + } + } + + /* Create world from blended snapshots */ + if (left_snapshot->valid && right_snapshot->valid) + { + f64 blend = (f64)(g->render_time_ns - left_snapshot->sim_time_ns) / (f64)(right_snapshot->sim_time_ns - left_snapshot->sim_time_ns); + g->ss_blended = PP_AcquireSnapshotFromLerp(g->user_blended_client, left_snapshot, right_snapshot, blend); + } + else if (left_snapshot->valid) + { + g->ss_blended = PP_AcquireSnapshot(g->user_blended_client, left_snapshot, left_snapshot->tick); + } + else if (right_snapshot->valid) + { + g->ss_blended = PP_AcquireSnapshot(g->user_blended_client, right_snapshot, right_snapshot->tick); + } + + /* Release unneeded unblended snapshots */ + if (left_snapshot->tick > 0) + { + PP_ReleaseSnapshotsInRange(g->user_unblended_client, 0, left_snapshot->tick - 1); + } + } + else + { + /* Interp disabled, just copy latest snapshot */ + g->render_time_target_ns = newest_snapshot->sim_time_ns; + g->render_time_ns = newest_snapshot->sim_time_ns; + g->ss_blended = PP_AcquireSnapshot(g->user_blended_client, newest_snapshot, newest_snapshot->tick); + + /* Release unneeded unblended snapshots */ + if (newest_snapshot->tick > 0) + { + PP_ReleaseSnapshotsInRange(g->user_unblended_client, 0, newest_snapshot->tick - 1); + } } - //- Pull latest local sim snapshot + /* Release unneeded blended snapshots */ + if (g->ss_blended->tick > 0) { - __profn("Pull snapshot"); - Lock lock = LockE(&g->local_to_user_client_mutex); - u64 old_last_tick = g->user_unblended_client->last_tick; - u64 last_tick = g->local_to_user_client->last_tick; - if (last_tick > old_last_tick) - { - PP_Snapshot *src = PP_SnapshotFromTick(g->local_to_user_client, last_tick); - PP_AcquireSnapshot(g->user_unblended_client, src, src->tick); - g->last_local_to_user_snapshot_published_at_ns = g->local_to_user_client_publish_time_ns; - g->average_local_to_user_snapshot_publish_dt_ns -= g->average_local_to_user_snapshot_publish_dt_ns / 50; - g->average_local_to_user_snapshot_publish_dt_ns += g->local_to_user_client_publish_dt_ns / 50; - } - Unlock(&lock); + PP_ReleaseSnapshotsInRange(g->user_blended_client, 0, g->ss_blended->tick - 1); + PP_ReleaseSnapshotsInRange(g->user_blended_client, g->ss_blended->tick + 1, U64Max); + } + } + + //- Process controller events into user bind state + { + __profn("Process controller events"); + + /* Reset bind pressed / released states */ + for (u32 i = 0; i < countof(g->bind_states); ++i) + { + g->bind_states[i] = (PP_BindState) { + .is_held = g->bind_states[i].is_held + }; } - //- Create user world from blended snapshots + for (u64 idx = 0; idx < controller_events.count; ++idx) { - __profn("Blend snapshots"); - /* Determine how far along are we between sim ticks (0 = start of tick, 1 = end of tick) */ - f64 tick_progress = 0; - i64 next_tick_expected_ns = g->last_local_to_user_snapshot_published_at_ns + g->average_local_to_user_snapshot_publish_dt_ns; - if (next_tick_expected_ns > g->last_local_to_user_snapshot_published_at_ns) + ControllerEvent *event = &controller_events.events[idx]; + if (event->kind == ControllerEventKind_Quit) + { + SignalExit(0); + } + + if (event->kind == ControllerEventKind_ButtonUp) + { + /* Escape quit */ + if (event->button == Btn_Esc) { - tick_progress = (f64)(g->real_time_ns - g->last_local_to_user_snapshot_published_at_ns) / (f64)(next_tick_expected_ns - g->last_local_to_user_snapshot_published_at_ns); + SignalExit(0); } + } - /* Predict local sim time based on average snapshot publish dt. */ - PP_Snapshot *newest_snapshot = PP_SnapshotFromTick(g->user_unblended_client, g->user_unblended_client->last_tick); - g->local_sim_last_known_time_ns = newest_snapshot->sim_time_ns; - g->local_sim_last_known_tick = newest_snapshot->tick; - if (Atomic32Fetch(&g->user_paused)) + /* Update mouse pos */ + if (event->kind == ControllerEventKind_CursorMove) + { + g->screen_cursor = Vec2FromFields(event->cursor_pos); + } + + /* Update bind states */ + if ((event->kind == ControllerEventKind_ButtonDown || event->kind == ControllerEventKind_ButtonUp)) + { + Btn button = event->button; + button = button >= Btn_Count ? Btn_None : button; + PP_BindKind bind = g_binds[button]; + if (bind) { - g->local_sim_predicted_time_ns = g->local_sim_last_known_tick; - } - else - { - g->local_sim_predicted_time_ns = newest_snapshot->sim_time_ns + (newest_snapshot->sim_dt_ns * tick_progress); - } - - if (USER_INTERP_ENABLED && !Atomic32Fetch(&g->user_paused)) - { - /* Determine render time */ - g->render_time_target_ns = g->local_sim_predicted_time_ns - (USER_INTERP_RATIO * g->average_local_to_user_snapshot_publish_dt_ns); - if (g->average_local_to_user_snapshot_publish_dt_ns > 0) - { - /* Increment render time based on average publish dt */ - f64 sim_publish_timescale = (f64)newest_snapshot->sim_dt_ns / (f64)g->average_local_to_user_snapshot_publish_dt_ns; - g->render_time_ns += g->real_dt_ns * sim_publish_timescale; - } - i64 render_time_target_diff_ns = g->render_time_target_ns - g->render_time_ns; - if (render_time_target_diff_ns > NsFromSeconds(0.010) || render_time_target_diff_ns < NsFromSeconds(-0.005)) - { - /* Snap render time if it gets too out of sync with target render time */ - g->render_time_ns = g->render_time_target_ns; - } - - /* Get two snapshots nearest to render time */ - PP_Snapshot *left_snapshot = PP_NilSnapshot(); - PP_Snapshot *right_snapshot = newest_snapshot; - { - PP_Snapshot *ss = PP_SnapshotFromTick(g->user_unblended_client, g->user_unblended_client->first_tick); - while (ss->valid) - { - u64 next_tick = ss->next_tick; - i64 ss_time_ns = ss->sim_time_ns; - if (ss_time_ns < g->render_time_ns && ss_time_ns > left_snapshot->sim_time_ns) - { - left_snapshot = ss; - } - if (ss_time_ns > g->render_time_ns && ss_time_ns < right_snapshot->sim_time_ns) - { - right_snapshot = ss; - } - ss = PP_SnapshotFromTick(g->user_unblended_client, next_tick); - } - } - - /* Create world from blended snapshots */ - if (left_snapshot->valid && right_snapshot->valid) - { - f64 blend = (f64)(g->render_time_ns - left_snapshot->sim_time_ns) / (f64)(right_snapshot->sim_time_ns - left_snapshot->sim_time_ns); - g->ss_blended = PP_AcquireSnapshotFromLerp(g->user_blended_client, left_snapshot, right_snapshot, blend); - } - else if (left_snapshot->valid) - { - g->ss_blended = PP_AcquireSnapshot(g->user_blended_client, left_snapshot, left_snapshot->tick); - } - else if (right_snapshot->valid) - { - g->ss_blended = PP_AcquireSnapshot(g->user_blended_client, right_snapshot, right_snapshot->tick); - } - - /* Release unneeded unblended snapshots */ - if (left_snapshot->tick > 0) - { - PP_ReleaseSnapshotsInRange(g->user_unblended_client, 0, left_snapshot->tick - 1); - } - } - else - { - /* Interp disabled, just copy latest snapshot */ - g->render_time_target_ns = newest_snapshot->sim_time_ns; - g->render_time_ns = newest_snapshot->sim_time_ns; - g->ss_blended = PP_AcquireSnapshot(g->user_blended_client, newest_snapshot, newest_snapshot->tick); - - /* Release unneeded unblended snapshots */ - if (newest_snapshot->tick > 0) - { - PP_ReleaseSnapshotsInRange(g->user_unblended_client, 0, newest_snapshot->tick - 1); - } - } - - /* Release unneeded blended snapshots */ - if (g->ss_blended->tick > 0) - { - PP_ReleaseSnapshotsInRange(g->user_blended_client, 0, g->ss_blended->tick - 1); - PP_ReleaseSnapshotsInRange(g->user_blended_client, g->ss_blended->tick + 1, U64Max); - } - } - - //- Process controller events into user bind state - { - __profn("Process controller events"); - - /* Reset bind pressed / released states */ - for (u32 i = 0; i < countof(g->bind_states); ++i) - { - g->bind_states[i] = (PP_BindState) { - .is_held = g->bind_states[i].is_held - }; - } - - for (u64 idx = 0; idx < controller_events.count; ++idx) - { - ControllerEvent *event = &controller_events.events[idx]; - if (event->kind == ControllerEventKind_Quit) - { - SignalExit(0); - } - - if (event->kind == ControllerEventKind_ButtonUp) - { - /* Escape quit */ - if (event->button == Btn_Esc) - { - SignalExit(0); - } - } - - /* Update mouse pos */ - if (event->kind == ControllerEventKind_CursorMove) - { - g->screen_cursor = Vec2FromFields(event->cursor_pos); - } - - /* Update bind states */ - if ((event->kind == ControllerEventKind_ButtonDown || event->kind == ControllerEventKind_ButtonUp)) - { - Btn button = event->button; - button = button >= Btn_Count ? Btn_None : button; - PP_BindKind bind = g_binds[button]; - if (bind) - { - b32 pressed = event->kind == ControllerEventKind_ButtonDown; + b32 pressed = event->kind == ControllerEventKind_ButtonDown; #if 0 - b32 out_of_bounds = button >= Btn_M1 && button <= Btn_M5 && - (g->ui_cursor.x < 0 || - g->ui_cursor.y < 0 || - g->ui_cursor.x > g->ui_size.x || - g->ui_cursor.y > g->ui_size.y); + b32 out_of_bounds = button >= Btn_M1 && button <= Btn_M5 && + (g->ui_cursor.x < 0 || + g->ui_cursor.y < 0 || + g->ui_cursor.x > g->ui_size.x || + g->ui_cursor.y > g->ui_size.y); #else - b32 out_of_bounds = 0; + b32 out_of_bounds = 0; #endif - g->bind_states[bind].is_held = pressed && !out_of_bounds; - if (pressed) - { - if (!out_of_bounds) - { - ++g->bind_states[bind].num_presses_and_repeats; - if (event->is_repeat) - { - ++g->bind_states[bind].num_repeats; - } - else - { - ++g->bind_states[bind].num_presses; - } - } - } - else - { - ++g->bind_states[bind].num_releases; - } - } + g->bind_states[bind].is_held = pressed && !out_of_bounds; + if (pressed) + { + if (!out_of_bounds) + { + ++g->bind_states[bind].num_presses_and_repeats; + if (event->is_repeat) + { + ++g->bind_states[bind].num_repeats; + } + else + { + ++g->bind_states[bind].num_presses; + } } + } + else + { + ++g->bind_states[bind].num_releases; + } } + } } + } - //- Find local entities - PP_Ent *local_player = PP_EntFromKey(g->ss_blended, g->ss_blended->local_player); - PP_Ent *local_control = PP_EntFromKey(g->ss_blended, local_player->player_control_ent); - PP_Ent *local_camera = PP_EntFromKey(g->ss_blended, local_player->player_camera_ent); + //- Find local entities + PP_Ent *local_player = PP_EntFromKey(g->ss_blended, g->ss_blended->local_player); + PP_Ent *local_control = PP_EntFromKey(g->ss_blended, local_player->player_control_ent); + PP_Ent *local_camera = PP_EntFromKey(g->ss_blended, local_player->player_camera_ent); - //- Find hovered entity - PP_Ent *hovered_ent = PP_NilEnt(); - { - Xform mouse_xf = XformFromPos(g->world_cursor); - CLD_Shape mouse_shape = ZI; - mouse_shape.points[0] = VEC2(0, 0); - mouse_shape.count = 1; - mouse_shape.radius = 0.01f; - for (u64 ent_index = 0; ent_index < g->ss_blended->num_ents_reserved; ++ent_index) - { - PP_Ent *ent = &g->ss_blended->ents[ent_index]; - if (!PP_IsValidAndActive(ent)) continue; - - CLD_Shape ent_collider = ent->local_collider; - if (ent_collider.count > 0) - { - /* TODO: Can just use boolean GJK */ - Xform ent_xf = PP_XformFromEnt(ent); - CLD_CollisionData collision_result = CLD_CollisionDataFromShapes(&ent_collider, &mouse_shape, ent_xf, mouse_xf); - if (collision_result.num_points > 0) - { - hovered_ent = PP_EntFromKey(g->ss_blended, ent->top); - break; - } - } - } - } - - //- Update user state from binds - { - if (g->bind_states[PP_BindKind_Fullscreen].num_presses && g->bind_states[PP_BindKind_FullscreenMod].is_held) - { - WND_PushCmd(window_frame, .kind = WND_CmdKind_SetFullscreen, .v = !window_frame.fullscreen); - } - } - - if (g->bind_states[PP_BindKind_DebugDraw].num_presses > 0) - { - g->debug_draw = !g->debug_draw; - } - - if (g->bind_states[PP_BindKind_DebugToggleTopmost].num_presses > 0) - { - WND_PushCmd(window_frame, .kind = WND_CmdKind_SetForcedTop, .v = !window_frame.forced_top); - LogSuccessF("Toggle topmost"); - } - - if (g->bind_states[PP_BindKind_DebugConsole].num_presses > 0) - { - g->debug_console = !g->debug_console; - } - - if (g->bind_states[PP_BindKind_DebugCamera].num_presses > 0) - { - g->debug_camera = !g->debug_camera; - } - - if (g->bind_states[PP_BindKind_DebugUi].num_presses > 0) - { - g->ui_debug = !g->ui_debug; - } - - if (g->bind_states[PP_BindKind_DebugLister].num_presses > 0) - { - g->lister_active = !g->lister_active; - } - - { - if (g->bind_states[PP_BindKind_DebugFollow].num_presses > 0) - { - if (PP_IsNilEntKey(g->debug_following)) - { - g->debug_following = hovered_ent->key; - } - else - { - g->debug_following = PP_NilEntKey; - } - } - if (!PP_IsNilEntKey(g->debug_following)) - { - PP_Ent *follow_ent = PP_EntFromKey(g->ss_blended, g->debug_following); - PP_Ent *follow_camera = PP_NilEnt(); - for (u64 i = 0; i < g->ss_blended->num_ents_reserved; ++i) - { - PP_Ent *ent = &g->ss_blended->ents[i]; - PP_Ent *ent_camera_follow = PP_EntFromKey(g->ss_blended, ent->camera_follow); - if (ent_camera_follow->valid && ent_camera_follow == follow_ent) - { - follow_camera = ent; - break; - } - } - if (follow_camera->valid) - { - local_camera = follow_camera; - } - else - { - g->debug_following = PP_NilEntKey; - } - } - } - - //- Apply shake + //- Find hovered entity + PP_Ent *hovered_ent = PP_NilEnt(); + { + Xform mouse_xf = XformFromPos(g->world_cursor); + CLD_Shape mouse_shape = ZI; + mouse_shape.points[0] = VEC2(0, 0); + mouse_shape.count = 1; + mouse_shape.radius = 0.01f; for (u64 ent_index = 0; ent_index < g->ss_blended->num_ents_reserved; ++ent_index) { - PP_Ent *ent = &g->ss_blended->ents[ent_index]; - if (!PP_IsValidAndActive(ent)) continue; + PP_Ent *ent = &g->ss_blended->ents[ent_index]; + if (!PP_IsValidAndActive(ent)) continue; - /* How much time between camera shakes */ - i64 frequency_ns = NsFromSeconds(0.01f); - f32 shake = ent->shake; - if (shake > 0) + CLD_Shape ent_collider = ent->local_collider; + if (ent_collider.count > 0) + { + /* TODO: Can just use boolean GJK */ + Xform ent_xf = PP_XformFromEnt(ent); + CLD_CollisionData collision_result = CLD_CollisionDataFromShapes(&ent_collider, &mouse_shape, ent_xf, mouse_xf); + if (collision_result.num_points > 0) { - u64 angle_seed0 = ent->key.uid.lo + (u64)(g->ss_blended->sim_time_ns / frequency_ns); - u64 angle_seed1 = angle_seed0 + 1; - f32 angle0 = RandF64FromSeed(angle_seed0, 0, Tau); - f32 angle1 = RandF64FromSeed(angle_seed1, 0, Tau); - - Vec2 vec0 = Vec2WithLen(Vec2FromAngle(angle0), shake); - /* NOTE: vec1 not completely accurate since shake can change between frames, it's just a prediction */ - Vec2 vec1 = Vec2WithLen(Vec2FromAngle(angle1), shake); - - /* TODO: Cubic interp? */ - f32 blend = (f32)(g->ss_blended->sim_time_ns % frequency_ns) / (f32)frequency_ns; - Vec2 vec = LerpVec2(vec0, vec1, blend); - - Xform xf = PP_XformFromEnt(ent); - xf.og = AddVec2(xf.og, MulVec2(vec, shake)); - PP_SetXform(ent, xf); + hovered_ent = PP_EntFromKey(g->ss_blended, ent->top); + break; } + } } + } - //- Update ui to screen xform from screen size - if (g->debug_camera) + //- Update user state from binds + { + if (g->bind_states[PP_BindKind_Fullscreen].num_presses && g->bind_states[PP_BindKind_FullscreenMod].is_held) { - g->ui_size = g->screen_size; - g->ui_to_screen_xf = XformIdentity; - g->ui_to_screen_xf.og = RoundVec2(g->ui_to_screen_xf.og); + WND_PushCmd(window_frame, .kind = WND_CmdKind_SetFullscreen, .v = !window_frame.fullscreen); + } + } + + if (g->bind_states[PP_BindKind_DebugDraw].num_presses > 0) + { + g->debug_draw = !g->debug_draw; + } + + if (g->bind_states[PP_BindKind_DebugToggleTopmost].num_presses > 0) + { + WND_PushCmd(window_frame, .kind = WND_CmdKind_SetForcedTop, .v = !window_frame.forced_top); + LogSuccessF("Toggle topmost"); + } + + if (g->bind_states[PP_BindKind_DebugConsole].num_presses > 0) + { + g->debug_console = !g->debug_console; + } + + if (g->bind_states[PP_BindKind_DebugCamera].num_presses > 0) + { + g->debug_camera = !g->debug_camera; + } + + if (g->bind_states[PP_BindKind_DebugUi].num_presses > 0) + { + g->ui_debug = !g->ui_debug; + } + + if (g->bind_states[PP_BindKind_DebugLister].num_presses > 0) + { + g->lister_active = !g->lister_active; + } + + { + if (g->bind_states[PP_BindKind_DebugFollow].num_presses > 0) + { + if (PP_IsNilEntKey(g->debug_following)) + { + g->debug_following = hovered_ent->key; + } + else + { + g->debug_following = PP_NilEntKey; + } + } + if (!PP_IsNilEntKey(g->debug_following)) + { + PP_Ent *follow_ent = PP_EntFromKey(g->ss_blended, g->debug_following); + PP_Ent *follow_camera = PP_NilEnt(); + for (u64 i = 0; i < g->ss_blended->num_ents_reserved; ++i) + { + PP_Ent *ent = &g->ss_blended->ents[i]; + PP_Ent *ent_camera_follow = PP_EntFromKey(g->ss_blended, ent->camera_follow); + if (ent_camera_follow->valid && ent_camera_follow == follow_ent) + { + follow_camera = ent; + break; + } + } + if (follow_camera->valid) + { + local_camera = follow_camera; + } + else + { + g->debug_following = PP_NilEntKey; + } + } + } + + //- Apply shake + for (u64 ent_index = 0; ent_index < g->ss_blended->num_ents_reserved; ++ent_index) + { + PP_Ent *ent = &g->ss_blended->ents[ent_index]; + if (!PP_IsValidAndActive(ent)) continue; + + /* How much time between camera shakes */ + i64 frequency_ns = NsFromSeconds(0.01f); + f32 shake = ent->shake; + if (shake > 0) + { + u64 angle_seed0 = ent->key.uid.lo + (u64)(g->ss_blended->sim_time_ns / frequency_ns); + u64 angle_seed1 = angle_seed0 + 1; + f32 angle0 = RandF64FromSeed(angle_seed0, 0, Tau); + f32 angle1 = RandF64FromSeed(angle_seed1, 0, Tau); + + Vec2 vec0 = Vec2WithLen(Vec2FromAngle(angle0), shake); + /* NOTE: vec1 not completely accurate since shake can change between frames, it's just a prediction */ + Vec2 vec1 = Vec2WithLen(Vec2FromAngle(angle1), shake); + + /* TODO: Cubic interp? */ + f32 blend = (f32)(g->ss_blended->sim_time_ns % frequency_ns) / (f32)frequency_ns; + Vec2 vec = LerpVec2(vec0, vec1, blend); + + Xform xf = PP_XformFromEnt(ent); + xf.og = AddVec2(xf.og, MulVec2(vec, shake)); + PP_SetXform(ent, xf); + } + } + + //- Update ui to screen xform from screen size + if (g->debug_camera) + { + g->ui_size = g->screen_size; + g->ui_to_screen_xf = XformIdentity; + g->ui_to_screen_xf.og = RoundVec2(g->ui_to_screen_xf.og); + } + else + { + /* Determine ui size by camera & window dimensions */ + f32 aspect_ratio = (f32)(DEFAULT_CAMERA_WIDTH / DEFAULT_CAMERA_HEIGHT); + if (local_camera->valid) + { + Xform quad_xf = MulXform(PP_XformFromEnt(local_camera), local_camera->camera_quad_xform); + Vec2 camera_size = ScaleFromXform(quad_xf); + if (!IsVec2Zero(camera_size)) + { + aspect_ratio = camera_size.x / camera_size.y; + } + } + f32 width = g->screen_size.x; + f32 height = g->screen_size.y; + if (width / height > aspect_ratio) + { + width = height * aspect_ratio; } else { - /* Determine ui size by camera & window dimensions */ - f32 aspect_ratio = (f32)(DEFAULT_CAMERA_WIDTH / DEFAULT_CAMERA_HEIGHT); - if (local_camera->valid) - { - Xform quad_xf = MulXform(PP_XformFromEnt(local_camera), local_camera->camera_quad_xform); - Vec2 camera_size = ScaleFromXform(quad_xf); - if (!IsVec2Zero(camera_size)) - { - aspect_ratio = camera_size.x / camera_size.y; - } - } - f32 width = g->screen_size.x; - f32 height = g->screen_size.y; - if (width / height > aspect_ratio) - { - width = height * aspect_ratio; - } - else - { - height = CeilF32(width / aspect_ratio); - } - g->ui_size = VEC2I32(width, height); - - /* Center ui in window */ - f32 x = RoundF32(g->screen_size.x / 2 - width / 2); - f32 y = RoundF32(g->screen_size.y / 2 - height / 2); - g->ui_to_screen_xf = XformFromTrs(TRS(.t = VEC2(x, y))); - g->ui_to_screen_xf.og = RoundVec2(g->ui_to_screen_xf.og); + height = CeilF32(width / aspect_ratio); } + g->ui_size = VEC2I32(width, height); - g->ui_cursor = MulXformV2(InvertXform(g->ui_to_screen_xf), g->screen_cursor); + /* Center ui in window */ + f32 x = RoundF32(g->screen_size.x / 2 - width / 2); + f32 y = RoundF32(g->screen_size.y / 2 - height / 2); + g->ui_to_screen_xf = XformFromTrs(TRS(.t = VEC2(x, y))); + g->ui_to_screen_xf.og = RoundVec2(g->ui_to_screen_xf.og); + } - UI_Box *pp_root_box = 0; + g->ui_cursor = MulXformV2(InvertXform(g->ui_to_screen_xf), g->screen_cursor); + + UI_Box *pp_root_box = 0; + { + UI_PushCP(UI_BuildRow(UI_NilKey)); { - UI_PushCP(UI_BuildRow(UI_NilKey)); + UI_BuildSpacer(UI_FILL(1, 0)); + { + UI_SetNext(Width, UI_PIX(g->ui_size.x, 1)); + UI_PushCP(UI_BuildColumn(UI_NilKey)); { - UI_BuildSpacer(UI_FILL(1, 0)); + UI_BuildSpacer(UI_FILL(1, 0)); + { + if (window_frame.forced_top) { - UI_SetNext(Width, UI_PIX(g->ui_size.x, 1)); - UI_PushCP(UI_BuildColumn(UI_NilKey)); - { - UI_BuildSpacer(UI_FILL(1, 0)); - { - if (window_frame.forced_top) - { - UI_SetNext(Border, 10); - UI_SetNext(BorderColor, Rgba32F(1, 0, 0, 0.5)); - } - UI_SetNext(ChildLayoutAxis, Axis_Y); - UI_SetNext(Height, UI_PIX(g->ui_size.y, 1)); - pp_root_box = UI_BuildBox(UI_KeyF("pp root")); - } - UI_BuildSpacer(UI_FILL(1, 0)); - } - UI_PopCP(); + UI_SetNext(Border, 10); + UI_SetNext(BorderColor, Rgba32F(1, 0, 0, 0.5)); } - UI_BuildSpacer(UI_FILL(1, 0)); + UI_SetNext(ChildLayoutAxis, Axis_Y); + UI_SetNext(Height, UI_PIX(g->ui_size.y, 1)); + pp_root_box = UI_BuildBox(UI_KeyF("pp root")); + } + UI_BuildSpacer(UI_FILL(1, 0)); } UI_PopCP(); + } + UI_BuildSpacer(UI_FILL(1, 0)); } - PP_PushGameUiStyle(); - UI_Push(Parent, pp_root_box); + UI_PopCP(); + } + PP_PushGameUiStyle(); + UI_Push(Parent, pp_root_box); - //- Update world to ui xform from camera - if (g->debug_camera) + //- Update world to ui xform from camera + if (g->debug_camera) + { + g->world_to_ui_xf = XformWithWorldRotation(g->world_to_ui_xf, 0); + + Vec2 world_cursor = InvertXformMulV2(g->world_to_ui_xf, g->ui_cursor); + + /* Pan view */ + if (g->bind_states[PP_BindKind_Pan].is_held) { - g->world_to_ui_xf = XformWithWorldRotation(g->world_to_ui_xf, 0); - - Vec2 world_cursor = InvertXformMulV2(g->world_to_ui_xf, g->ui_cursor); - - /* Pan view */ - if (g->bind_states[PP_BindKind_Pan].is_held) - { - if (!g->debug_camera_panning) - { - g->debug_camera_pan_start = world_cursor; - g->debug_camera_panning = 1; - } - Vec2 offset = NegVec2(SubVec2(g->debug_camera_pan_start, world_cursor)); - g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, offset); - world_cursor = InvertXformMulV2(g->world_to_ui_xf, g->ui_cursor); - g->debug_camera_pan_start = world_cursor; - } - else - { - g->debug_camera_panning = 0; - } - - /* Zoom view */ - i32 input_zooms = g->bind_states[PP_BindKind_ZoomIn].num_presses - g->bind_states[PP_BindKind_ZoomOut].num_presses; - if (input_zooms != 0) - { - /* Zoom to cursor */ - f32 zoom_rate = 2; - f32 zoom = PowF32(zoom_rate, input_zooms); - g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, world_cursor); - g->world_to_ui_xf = ScaleXform(g->world_to_ui_xf, VEC2(zoom, zoom)); - g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, NegVec2(world_cursor)); - } - g->world_to_ui_xf.og = RoundVec2(g->world_to_ui_xf.og); + if (!g->debug_camera_panning) + { + g->debug_camera_pan_start = world_cursor; + g->debug_camera_panning = 1; + } + Vec2 offset = NegVec2(SubVec2(g->debug_camera_pan_start, world_cursor)); + g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, offset); + world_cursor = InvertXformMulV2(g->world_to_ui_xf, g->ui_cursor); + g->debug_camera_pan_start = world_cursor; } else { - Xform xf = PP_XformFromEnt(local_camera); + g->debug_camera_panning = 0; + } - Vec2 world_center = xf.og; - f32 rot = RotationFromXform(xf); + /* Zoom view */ + i32 input_zooms = g->bind_states[PP_BindKind_ZoomIn].num_presses - g->bind_states[PP_BindKind_ZoomOut].num_presses; + if (input_zooms != 0) + { + /* Zoom to cursor */ + f32 zoom_rate = 2; + f32 zoom = PowF32(zoom_rate, input_zooms); + g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, world_cursor); + g->world_to_ui_xf = ScaleXform(g->world_to_ui_xf, VEC2(zoom, zoom)); + g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, NegVec2(world_cursor)); + } + g->world_to_ui_xf.og = RoundVec2(g->world_to_ui_xf.og); + } + else + { + Xform xf = PP_XformFromEnt(local_camera); - /* Scale view into viewport based on camera size */ - Vec2 scale = VEC2(g->ui_size.x, g->ui_size.y); + Vec2 world_center = xf.og; + f32 rot = RotationFromXform(xf); + + /* Scale view into viewport based on camera size */ + Vec2 scale = VEC2(g->ui_size.x, g->ui_size.y); + { + Xform quad_xf = MulXform(xf, local_camera->camera_quad_xform); + Vec2 camera_size = ScaleFromXform(quad_xf); + if (!IsVec2Zero(camera_size)) + { + scale = DivVec2Vec2(scale, camera_size); + } + } + scale.x = MinF32(scale.x, scale.y); + scale.y = scale.x; + + Vec2 ui_center = MulVec2(VEC2(g->ui_size.x, g->ui_size.y), 0.5); + Trs trs = TRS(.t = SubVec2(ui_center, world_center), .r = rot, .s = scale); + Vec2 pivot = world_center; + g->world_to_ui_xf = XformIdentity; + g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, pivot); + g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, trs.t); + g->world_to_ui_xf = RotateXform(g->world_to_ui_xf, trs.r); + g->world_to_ui_xf = ScaleXform(g->world_to_ui_xf, trs.s); + g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, NegVec2(pivot)); + g->world_to_ui_xf.og = RoundVec2(g->world_to_ui_xf.og); + } + + g->world_cursor = InvertXformMulV2(g->world_to_ui_xf, g->ui_cursor); + + //- Update world to render xform from world to ui xform + + b32 effects_disabled = 0; + // b32 effects_disabled = 1; + g->render_size = RoundVec2ToVec2I32(VEC2(RENDER_WIDTH, RENDER_HEIGHT)); + + if (g->debug_camera) + { + g->render_size = g->ui_size; + effects_disabled = 1; + g->world_to_render_xf = g->world_to_ui_xf; + } + else + { + Xform ui_to_world_xf = InvertXform(g->world_to_ui_xf); + Vec2 world_center = MulXformV2(ui_to_world_xf, MulVec2(VEC2(g->ui_size.x, g->ui_size.y), 0.5)); + + Vec2 scale = VEC2(PIXELS_PER_UNIT, PIXELS_PER_UNIT); + + Xform xf = XformIdentity; + + xf = TranslateXform(xf, MulVec2(VEC2(g->render_size.x, g->render_size.y), 0.5)); + + xf = ScaleXform(xf, scale); + xf = TranslateXform(xf, MulVec2(world_center, -1)); + xf.og = RoundVec2(xf.og); + + g->world_to_render_xf = xf; + } + + //- Update render to ui xform + { + Xform world_to_ui_xf = g->world_to_ui_xf; + Xform world_to_render_xf = g->world_to_render_xf; + Xform render_to_world_xf = InvertXform(world_to_render_xf); + Xform render_to_ui_xf = MulXform(world_to_ui_xf, render_to_world_xf); + g->render_to_ui_xf = render_to_ui_xf; + } + + //- Update listener from view + { + Vec2 up = VEC2(0, -1); + Vec2 ui_center = MulVec2(VEC2(g->ui_size.x, g->ui_size.y), 0.5f); + Vec2 listener_pos = InvertXformMulV2(g->world_to_ui_xf, ui_center); + Vec2 listener_dir = NormVec2(InvertXformBasisMulV2(g->world_to_ui_xf, up)); + MIX_UpdateListener(listener_pos, listener_dir); + } + + //- Draw grid + { + f32 thickness = 2; + + Vec2 offset = NegVec2(MulXformV2(g->world_to_render_xf, VEC2(0, 0))); + f32 spacing = ScaleFromXform(g->world_to_render_xf).x; + + Vec2 pos = InvertXformMulV2(g->world_to_render_xf, VEC2(0, 0)); + Vec2 size = InvertXformBasisMulV2(g->world_to_render_xf, VEC2(g->render_size.x, g->render_size.y)); + u32 color0 = Rgb32F(0.17f, 0.17f, 0.17f); + u32 color1 = Rgb32F(0.15f, 0.15f, 0.15f); + + PP_MaterialGrid *grid = PushStruct(g->grids_arena, PP_MaterialGrid); + *grid = PP_DefaultMaterialGrid; + grid->line_thickness = thickness; + grid->line_spacing = spacing; + grid->offset = offset; + grid->bg0_srgb = color0; + grid->bg1_srgb = color1; + grid->line_srgb = Rgb32(0x3f, 0x3f, 0x3f); + grid->x_srgb = Color_Red; + grid->y_srgb = Color_Green; + + PP_MaterialInstance *mat = PushStruct(g->material_instances_arena, PP_MaterialInstance); + *mat = PP_DefaultMaterialInstance; + mat->grid_id = grid - (PP_MaterialGrid *)ArenaBase(g->grids_arena); + mat->xf = XformFromRect(RectFromVec2(pos, size)); + } + + //- Sort drawable entities + PP_Ent **sorted = PushDry(scratch.arena, PP_Ent *); + u64 sorted_count = 0; + { + /* Copy valid entities */ + { + __profn("Build ents list for sorting"); + for (u64 ent_index = 0; ent_index < g->ss_blended->num_ents_reserved; ++ent_index) + { + PP_Ent *ent = &g->ss_blended->ents[ent_index]; + if (PP_IsValidAndActive(ent)) { - Xform quad_xf = MulXform(xf, local_camera->camera_quad_xform); - Vec2 camera_size = ScaleFromXform(quad_xf); - if (!IsVec2Zero(camera_size)) - { - scale = DivVec2Vec2(scale, camera_size); - } + *PushStructNoZero(scratch.arena, PP_Ent *) = ent; + ++sorted_count; } - scale.x = MinF32(scale.x, scale.y); - scale.y = scale.x; - - Vec2 ui_center = MulVec2(VEC2(g->ui_size.x, g->ui_size.y), 0.5); - Trs trs = TRS(.t = SubVec2(ui_center, world_center), .r = rot, .s = scale); - Vec2 pivot = world_center; - g->world_to_ui_xf = XformIdentity; - g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, pivot); - g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, trs.t); - g->world_to_ui_xf = RotateXform(g->world_to_ui_xf, trs.r); - g->world_to_ui_xf = ScaleXform(g->world_to_ui_xf, trs.s); - g->world_to_ui_xf = TranslateXform(g->world_to_ui_xf, NegVec2(pivot)); - g->world_to_ui_xf.og = RoundVec2(g->world_to_ui_xf.og); + } } - - g->world_cursor = InvertXformMulV2(g->world_to_ui_xf, g->ui_cursor); - - //- Update world to render xform from world to ui xform - - b32 effects_disabled = 0; - // b32 effects_disabled = 1; - g->render_size = RoundVec2ToVec2I32(VEC2(RENDER_WIDTH, RENDER_HEIGHT)); - - if (g->debug_camera) + /* Sort */ { - g->render_size = g->ui_size; - effects_disabled = 1; - g->world_to_render_xf = g->world_to_ui_xf; + __profn("Sort ents"); + Mergesort(sorted, sorted_count, sizeof(*sorted), PP_EntSortCmp, 0); } - else + } + + //- Draw entities + { + __profn("Draw entities"); + for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index) { - Xform ui_to_world_xf = InvertXform(g->world_to_ui_xf); - Vec2 world_center = MulXformV2(ui_to_world_xf, MulVec2(VEC2(g->ui_size.x, g->ui_size.y), 0.5)); + PP_Ent *ent = sorted[sorted_index]; + if (!PP_IsValidAndActive(ent)) continue; + //if (SPR_IsNil(ent->sprite)) continue; - Vec2 scale = VEC2(PIXELS_PER_UNIT, PIXELS_PER_UNIT); + ResourceKey sprite = ent->sprite; - Xform xf = XformIdentity; + PP_Ent *parent = PP_EntFromKey(g->ss_blended, ent->parent); - xf = TranslateXform(xf, MulVec2(VEC2(g->render_size.x, g->render_size.y), 0.5)); + Xform xf = PP_XformFromEnt(ent); + UNUSED Xform parent_xf = PP_XformFromEnt(parent); - xf = ScaleXform(xf, scale); - xf = TranslateXform(xf, MulVec2(world_center, -1)); - xf.og = RoundVec2(xf.og); + b32 skip_debug_draw = !g->debug_camera && ent == local_camera; + skip_debug_draw = skip_debug_draw || PP_HasProp(ent, PP_Prop_MotorJoint); - g->world_to_render_xf = xf; - } + b32 skip_debug_draw_transform = PP_HasProp(ent, PP_Prop_Camera); + skip_debug_draw_transform = 1; - //- Update render to ui xform - { - Xform world_to_ui_xf = g->world_to_ui_xf; - Xform world_to_render_xf = g->world_to_render_xf; - Xform render_to_world_xf = InvertXform(world_to_render_xf); - Xform render_to_ui_xf = MulXform(world_to_ui_xf, render_to_world_xf); - g->render_to_ui_xf = render_to_ui_xf; - } - - //- Update listener from view - { - Vec2 up = VEC2(0, -1); - Vec2 ui_center = MulVec2(VEC2(g->ui_size.x, g->ui_size.y), 0.5f); - Vec2 listener_pos = InvertXformMulV2(g->world_to_ui_xf, ui_center); - Vec2 listener_dir = NormVec2(InvertXformBasisMulV2(g->world_to_ui_xf, up)); - MIX_UpdateListener(listener_pos, listener_dir); - } - - //- Draw grid - { - f32 thickness = 2; - - Vec2 offset = NegVec2(MulXformV2(g->world_to_render_xf, VEC2(0, 0))); - f32 spacing = ScaleFromXform(g->world_to_render_xf).x; - - Vec2 pos = InvertXformMulV2(g->world_to_render_xf, VEC2(0, 0)); - Vec2 size = InvertXformBasisMulV2(g->world_to_render_xf, VEC2(g->render_size.x, g->render_size.y)); - u32 color0 = Rgb32F(0.17f, 0.17f, 0.17f); - u32 color1 = Rgb32F(0.15f, 0.15f, 0.15f); - - PP_MaterialGrid *grid = PushStruct(g->grids_arena, PP_MaterialGrid); - *grid = PP_DefaultMaterialGrid; - grid->line_thickness = thickness; - grid->line_spacing = spacing; - grid->offset = offset; - grid->bg0_srgb = color0; - grid->bg1_srgb = color1; - grid->line_srgb = Rgb32(0x3f, 0x3f, 0x3f); - grid->x_srgb = Color_Red; - grid->y_srgb = Color_Green; - - PP_MaterialInstance *mat = PushStruct(g->material_instances_arena, PP_MaterialInstance); - *mat = PP_DefaultMaterialInstance; - mat->grid_id = grid - (PP_MaterialGrid *)ArenaBase(g->grids_arena); - mat->xf = XformFromRect(RectFromVec2(pos, size)); - } + UNUSED Xform sprite_xform = MulXform(xf, ent->sprite_local_xform); + /* Draw tracer */ + /* TODO: Enable this */ #if 0 - //- Acquire / release tile cache entries + if (PP_HasProp(ent, PP_Prop_Tracer)) + { + Vec2 velocity = ent->tracer_start_velocity; - /* Acquire entries from new sim chunks */ + Vec2 a = ent->tracer_start; + Vec2 b = xf.og; + Vec2 c = ent->tracer_gradient_start; + Vec2 d = ent->tracer_gradient_end; - for (u64 ent_index = 0; ent_index < g->ss_blended->num_ents_reserved; ++ent_index) - { - PP_Ent *chunk_ent = &g->ss_blended->ents[ent_index]; - if (PP_IsValidAndActive(chunk_ent) && PP_HasProp(chunk_ent, PP_Prop_TileChunk)) + Vec2 vcd = SubVec2(d, c); + Vec2 vca = SubVec2(a, c); + Vec2 vdb = SubVec2(b, d); + Vec2 vdc = NegVec2(vcd); + + f32 opacity_a = 1; + f32 opacity_b = 1; + if (Vec2LenSq(vcd) != 0) { - struct user_tile_cache_entry *entry = user_tile_cache_entry_from_chunk_pos(chunk_ent->tile_chunk_pos); - if (!entry->valid) - { - entry = user_tile_cache_entry_acquire(chunk_ent->tile_chunk_pos); - } + if (DotVec2(velocity, vca) <= 0) + { + a = c; + opacity_a = 0; + } + else + { + opacity_a = DotVec2(vcd, vca) / Vec2LenSq(vcd); + } + opacity_a = ClampF32(opacity_a, 0, 1); + opacity_b = ClampF32(1.f - (DotVec2(vdc, vdb) / Vec2LenSq(vdc)), 0, 1); } - } - /* Release entries with invalid sim chunks */ + f32 thickness = 0.01f; + u32 color_start = Rgba32F(1, 0.5, 0, opacity_a); + u32 color_end = Rgba32F(1, 0.8, 0.4, opacity_b); - for (u64 entry_index = 0; entry_index < g->tile_cache.num_reserved_entries; ++entry_index) - { - struct tile_cache_entry *entry = &g->tile_cache.entries[entry_index]; - if (entry->valid) + if (opacity_b > 0.99f) { - PP_Ent *chunk_ent = sim_ent_from_chunk_pos(entry->pos); - if (!chunk_ent->valid) - { - user_tile_cache_entry_release(entry); - } + D_DrawCircle(g->render_sig, b, thickness / 2, color_end, 20); } - } + D_DrawLineGradient(g->render_sig, a, b, thickness, color_start, color_end); + } +#endif - //- Draw dirty tile cache entries - - for (u64 entry_index = 0; entry_index < g->tile_cache.num_reserved_entries; ++entry_index) - { - struct tile_cache_entry *entry = &g->tile_cache.entries[entry_index]; - if (entry->valid) + /* Draw sprite */ + if (!IsResourceNil(sprite)) + { + SPR_Sheet *sheet = SPR_SheetFromResourceAsync(sprite); + SPR_Texture *texture = SPR_TextureFromResourceAsync(sprite); + /* TODO: Fade in placeholder if texture isn't loaded */ + if (sheet->loaded && texture->loaded) { - Vec2I32 chunk_pos = entry->pos; - PP_Ent *chunk_ent = sim_ent_from_chunk_pos(chunk_pos); - if (entry->applied_dirty_gen != chunk_ent->dirty_gen) - { - entry->applied_dirty_gen = chunk_ent->dirty_gen; - /* TODO: Autotiling */ - - String data = sim_ent_get_chunk_tile_data(chunk_ent); - u64 tile_count = data.len; - if (tile_count == SIM_TILES_PER_CHUNK_SQRT * SIM_TILES_PER_CHUNK_SQRT) - { - for (u64 y_in_chunk = 0; y_in_chunk < SIM_TILES_PER_CHUNK_SQRT; ++y_in_chunk) - { - for (u64 x_in_chunk = 0; x_in_chunk < SIM_TILES_PER_CHUNK_SQRT; ++x_in_chunk) - { - } - } - } - else - { - /* TODO: Clear gpu buffer if it exists */ - } - } + b32 is_light = PP_HasProp(ent, PP_Prop_LightTest); + Vec3 emittance = ent->sprite_emittance; + u32 tint = ent->sprite_tint; + SPR_Frame frame = SPR_FrameFromIndex(sheet, ent->animation_frame); + PP_MaterialInstance *mat = PushStruct(g->material_instances_arena, PP_MaterialInstance); + *mat = PP_DefaultMaterialInstance; + mat->xf = sprite_xform; + mat->tex = GPU_Texture2DRidFromResource(texture->gpu_texture); + mat->tint_srgb = tint; + mat->tex_uv0 = frame.clip.p0; + mat->tex_uv1 = frame.clip.p1; + mat->is_light = is_light; + mat->light_emittance_srgb = emittance; } - } + } -#if 0 - for (u64 entry_index = 0; entry_index < g->tile_cache.num_reserved_entries; ++entry_index) - { - struct tile_cache_entry *entry = &g->tile_cache.entries[entry_index]; - if (entry->valid) + /* Draw tiles */ + /* TODO: Something better */ + if (PP_HasProp(ent, PP_Prop_TileChunk)) + { + Vec2I32 chunk_index = ent->tile_chunk_index; + ResourceKey tile_sprite = ResourceKeyFromStore(&PP_Resources, Lit("sprite/tile.ase")); + SPR_Texture *tile_texture = SPR_TextureFromResourceAsync(tile_sprite); + if (tile_texture->loaded) { - Vec2I32 chunk_pos = entry->pos; - PP_Ent *chunk_ent = sim_ent_from_chunk_pos(chunk_pos); - if (entry->applied_dirty_gen != chunk_ent->dirty_gen) + f32 tile_size = 1.f / SIM_TILES_PER_UNIT_SQRT; + for (i32 tile_y = 0; tile_y < SIM_TILES_PER_CHUNK_SQRT; ++tile_y) + { + for (i32 tile_x = 0; tile_x < SIM_TILES_PER_CHUNK_SQRT; ++tile_x) { - entry->applied_dirty_gen = chunk_ent->dirty_gen; - - /* Retreive surrounding chunk info since we're auto-tiling - * [TL] [T] [TR] - * [L ] X [R ] - * [BL] [B] [BR] - */ - Vec2I32 chunk_pos_tl = VEC2I32(chunk_pos.x - 1, chunk_pos.y - 1); - Vec2I32 chunk_pos_t = VEC2I32(chunk_pos.x, chunk_pos.y - 1); - Vec2I32 chunk_pos_tr = VEC2I32(chunk_pos.x + 1, chunk_pos.y - 1); - Vec2I32 chunk_pos_l = VEC2I32(chunk_pos.x - 1, chunk_pos.y); - Vec2I32 chunk_pos_r = VEC2I32(chunk_pos.x + 1, chunk_pos.y); - Vec2I32 chunk_pos_bl = VEC2I32(chunk_pos.x - 1, chunk_pos.y + 1); - Vec2I32 chunk_pos_b = VEC2I32(chunk_pos.x, chunk_pos.y + 1); - Vec2I32 chunk_pos_br = VEC2I32(chunk_pos.x + 1, chunk_pos.y + 1); - PP_Ent *chunk_ent_tl = sim_ent_from_chunk_pos(chunk_pos_tl); - PP_Ent *chunk_ent_t = sim_ent_from_chunk_pos(chunk_pos_t); - PP_Ent *chunk_ent_tr = sim_ent_from_chunk_pos(chunk_pos_tr); - PP_Ent *chunk_ent_l = sim_ent_from_chunk_pos(chunk_pos_l); - PP_Ent *chunk_ent_r = sim_ent_from_chunk_pos(chunk_pos_r); - PP_Ent *chunk_ent_bl = sim_ent_from_chunk_pos(chunk_pos_bl); - PP_Ent *chunk_ent_b = sim_ent_from_chunk_pos(chunk_pos_b); - PP_Ent *chunk_ent_br = sim_ent_from_chunk_pos(chunk_pos_br); - - String data = sim_ent_get_chunk_tile_data(chunk_ent); + Vec2I32 local_tile_index = VEC2I32(tile_x, tile_y); + PP_TileKind tile = ent->tile_chunk_tiles[local_tile_index.x + (local_tile_index.y * SIM_TILES_PER_CHUNK_SQRT)]; + /* FIXME: Enable this */ + //if (tile > -1) + if (tile == PP_TileKind_Wall) + { + Vec2I32 world_tile_index = PP_WorldTileIndexFromLocalTileIndex(chunk_index, local_tile_index); + Vec2 pos = PP_PosFromWorldTileIndex(world_tile_index); + Xform tile_xf = XformFromRect(RectFromVec2(pos, VEC2(tile_size, tile_size))); + PP_MaterialInstance *mat = PushStruct(g->material_instances_arena, PP_MaterialInstance); + *mat = PP_DefaultMaterialInstance; + mat->xf = tile_xf; + mat->tex = GPU_Texture2DRidFromResource(tile_texture->gpu_texture); + mat->is_light = 1; + mat->light_emittance_srgb = VEC3(0, 0, 0); + } } + } } - } -#endif -#endif + } - //- Sort drawable entities - PP_Ent **sorted = PushDry(scratch.arena, PP_Ent *); - u64 sorted_count = 0; - { - /* Copy valid entities */ + /* Debug draw entity info */ + if (g->debug_draw && !skip_debug_draw) + { + TempArena temp = BeginTempArena(scratch.arena); + + if (PP_HasProp(ent, PP_Prop_Kinematic) || PP_HasProp(ent, PP_Prop_Dynamic)) { - __profn("Build ents list for sorting"); - for (u64 ent_index = 0; ent_index < g->ss_blended->num_ents_reserved; ++ent_index) - { - PP_Ent *ent = &g->ss_blended->ents[ent_index]; - if (PP_IsValidAndActive(ent)) - { - *PushStructNoZero(scratch.arena, PP_Ent *) = ent; - ++sorted_count; - } - } + PP_DrawDebugMovement(ent); } - /* Sort */ + + /* Draw xform */ + if (!skip_debug_draw_transform) { - __profn("Sort ents"); - Mergesort(sorted, sorted_count, sizeof(*sorted), PP_EntSortCmp, 0); + u32 color_x = Rgba32F(1, 0, 0, 0.5); + u32 color_y = Rgba32F(0, 1, 0, 0.5); + PP_DrawDebugXform(xf, color_x, color_y); } - } - //- Draw entities - { - __profn("Draw entities"); - for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index) + /* Draw AABB */ + /* FIXME: Enable this */ +#if 0 + if (ent->local_collider.count > 0) { - PP_Ent *ent = sorted[sorted_index]; - if (!PP_IsValidAndActive(ent)) continue; - //if (SPR_IsNil(ent->sprite)) continue; + Aabb aabb = CLD_AabbFromShape(&ent->local_collider, xf); + f32 thickness = 1; + u32 color = Rgba32F(1, 0, 1, 0.5); + Quad quad = QuadFromAabb(aabb); + quad = MulXformQuad(g->world_to_ui_xf, quad); + D_DrawQuadLine(g->render_sig, quad, thickness, color); + } - ResourceKey sprite = ent->sprite; + /* Draw focus arrow */ + if (ent == local_control || PP_EqEntKey(ent->key, g->debug_following)) + { + SPR_Sheet *sheet = SPR_SheetFromResourceAsync(ent->sprite); + SPR_Slice slice = SPR_SliceFromNameIndex(sheet, Lit("attach.wep"), ent->animation_frame); + Vec2 start = MulXformV2(sprite_xform, slice.center); + start = MulXformV2(g->world_to_ui_xf, start); + Vec2 end = AddVec2(xf.og, ent->control.focus); + end = MulXformV2(g->world_to_ui_xf, end); + D_DrawArrowLine(g->render_sig, start, end, 3, 10, Rgba32F(1, 1, 1, 0.5)); + } +#endif - PP_Ent *parent = PP_EntFromKey(g->ss_blended, ent->parent); - - Xform xf = PP_XformFromEnt(ent); - UNUSED Xform parent_xf = PP_XformFromEnt(parent); - - b32 skip_debug_draw = !g->debug_camera && ent == local_camera; - skip_debug_draw = skip_debug_draw || PP_HasProp(ent, PP_Prop_MotorJoint); - - b32 skip_debug_draw_transform = PP_HasProp(ent, PP_Prop_Camera); - skip_debug_draw_transform = 1; - - UNUSED Xform sprite_xform = MulXform(xf, ent->sprite_local_xform); - - /* Draw tracer */ - /* TODO: Enable this */ #if 0 - if (PP_HasProp(ent, PP_Prop_Tracer)) + /* Draw slices */ + if (!SPR_IsNil(ent->sprite)) + { + SPR_Sheet *sheet = SPR_SheetFromResourceAsync(sprite); + + u32 quad_color = Rgba32F(1, 0, 0.5, 1); + u32 point_color = Rgba32F(1, 0, 0, 1); + u32 ray_color = Rgba32F(1, 0, 0.5, 1); + + for (u64 i = 0; i < sheet->slice_groups_count; ++i) + { + SPR_SheetSliceGroup *group = &sheet->slice_groups[i]; + if (StringEndsWith(group->name, Lit(".ray"))) continue; + + for (u32 j = 0; j < group->per_frame_count; ++j) { - Vec2 velocity = ent->tracer_start_velocity; + SPR_Slice slice = group->frame_slices[(ent->animation_frame * group->per_frame_count) + j]; - Vec2 a = ent->tracer_start; - Vec2 b = xf.og; - Vec2 c = ent->tracer_gradient_start; - Vec2 d = ent->tracer_gradient_end; + Vec2 center = MulXformV2(sprite_xform, slice.center); + center = MulXformV2(g->world_to_ui_xf, center); - Vec2 vcd = SubVec2(d, c); - Vec2 vca = SubVec2(a, c); - Vec2 vdb = SubVec2(b, d); - Vec2 vdc = NegVec2(vcd); + if (!slice.has_ray) + { + Quad quad = QuadFromRect(slice.rect); + quad = MulXformQuad(sprite_xform, quad); + quad = MulXformQuad(g->world_to_ui_xf, quad); + D_DrawQuadLine(g->render_sig, quad, 2, quad_color); + } - f32 opacity_a = 1; - f32 opacity_b = 1; - if (Vec2LenSq(vcd) != 0) - { - if (DotVec2(velocity, vca) <= 0) - { - a = c; - opacity_a = 0; - } - else - { - opacity_a = DotVec2(vcd, vca) / Vec2LenSq(vcd); - } - opacity_a = ClampF32(opacity_a, 0, 1); - opacity_b = ClampF32(1.f - (DotVec2(vdc, vdb) / Vec2LenSq(vdc)), 0, 1); - } + D_DrawCircle(g->render_sig, center, 3, point_color, 20); - f32 thickness = 0.01f; - u32 color_start = Rgba32F(1, 0.5, 0, opacity_a); - u32 color_end = Rgba32F(1, 0.8, 0.4, opacity_b); - - if (opacity_b > 0.99f) - { - D_DrawCircle(g->render_sig, b, thickness / 2, color_end, 20); - } - D_DrawLineGradient(g->render_sig, a, b, thickness, color_start, color_end); + if (slice.has_ray) + { + Vec2 ray = MulXformBasisV2(sprite_xform, slice.dir); + ray = MulXformBasisV2(g->world_to_ui_xf, ray); + ray = Vec2WithLen(ray, 25); + D_DrawArrowRay(g->render_sig, center, ray, 2, 10, ray_color); + } } + } + } #endif - /* Draw sprite */ - if (!IsResourceNil(sprite)) + /* Draw weld joint */ +#if 0 + if (PP_HasProp(ent, PP_Prop_WeldJoint)) + { + PP_Ent *e1 = PP_EntFromKey(g->ss_blended, ent->weld_joint_data.e1); + Xform e1_xf = PP_XformFromEnt(e1); + + u32 color = Color_Yellow; + f32 radius = 3; + Vec2 point = MulXformV2(e1_xf, ent->weld_joint_data.point_local_e1); + point = MulXformV2(g->world_to_ui_xf, point); + D_DrawCircle(g->render_sig, point, radius, color, 10); + + DEBUGBREAKABLE; + } +#endif + + /* Draw mouse joint */ + /* FIXME: Enable this */ +#if 0 + if (PP_HasProp(ent, PP_Prop_MouseJoint)) + { + PP_Ent *target = PP_EntFromKey(g->ss_blended, ent->mouse_joint_data.target); + Xform target_xf = PP_XformFromEnt(target); + u32 color = Color_White; + Vec2 point_start = MulXformV2(target_xf, ent->mouse_joint_data.point_local_start); + Vec2 point_end = g->world_cursor; + point_start = MulXformV2(g->world_to_ui_xf, point_start); + point_end = MulXformV2(g->world_to_ui_xf, point_end); + D_DrawArrowLine(g->render_sig, point_start, point_end, 3, 10, color); + D_DrawCircle(g->render_sig, point_start, 4, color, 10); + } +#endif + + /* Draw collider */ + /* FIXME: Enable this */ +#if 0 + if (ent->local_collider.count > 0) + { + CLD_Shape collider = ent->local_collider; + u32 color = Rgba32F(1, 1, 0, 0.5); + f32 thickness = 2; + { + /* Draw collider using support points */ + u32 detail = 32; + Xform collider_draw_xf = MulXform(g->world_to_ui_xf, xf); + D_DrawColliderLine(g->render_sig, collider, collider_draw_xf, thickness, color, detail); + } + { + /* Draw collider shape points */ + for (u32 i = 0; i < collider.count; ++i) { - SPR_Sheet *sheet = SPR_SheetFromResourceAsync(sprite); - SPR_Texture *texture = SPR_TextureFromResourceAsync(sprite); - /* TODO: Fade in placeholder if texture isn't loaded */ - if (sheet->loaded && texture->loaded) - { - b32 is_light = PP_HasProp(ent, PP_Prop_LightTest); - Vec3 emittance = ent->sprite_emittance; - u32 tint = ent->sprite_tint; - SPR_Frame frame = SPR_FrameFromIndex(sheet, ent->animation_frame); - PP_MaterialInstance *mat = PushStruct(g->material_instances_arena, PP_MaterialInstance); - *mat = PP_DefaultMaterialInstance; - mat->xf = sprite_xform; - mat->tex = GPU_Texture2DRidFromResource(texture->gpu_texture); - mat->tint_srgb = tint; - mat->tex_uv0 = frame.clip.p0; - mat->tex_uv1 = frame.clip.p1; - mat->is_light = is_light; - mat->light_emittance_srgb = emittance; - } + Vec2 p = MulXformV2(MulXform(g->world_to_ui_xf, xf), collider.points[i]); + D_DrawCircle(g->render_sig, p, 3, Color_Blue, 10); } - - /* Draw tiles */ - /* TODO: Something better */ - if (PP_HasProp(ent, PP_Prop_TileChunk)) - { - Vec2I32 chunk_index = ent->tile_chunk_index; - ResourceKey tile_sprite = ResourceKeyFromStore(&PP_Resources, Lit("sprite/tile.ase")); - SPR_Texture *tile_texture = SPR_TextureFromResourceAsync(tile_sprite); - if (tile_texture->loaded) - { - f32 tile_size = 1.f / SIM_TILES_PER_UNIT_SQRT; - for (i32 tile_y = 0; tile_y < SIM_TILES_PER_CHUNK_SQRT; ++tile_y) - { - for (i32 tile_x = 0; tile_x < SIM_TILES_PER_CHUNK_SQRT; ++tile_x) - { - Vec2I32 local_tile_index = VEC2I32(tile_x, tile_y); - PP_TileKind tile = ent->tile_chunk_tiles[local_tile_index.x + (local_tile_index.y * SIM_TILES_PER_CHUNK_SQRT)]; - /* FIXME: Enable this */ - //if (tile > -1) - if (tile == PP_TileKind_Wall) - { - Vec2I32 world_tile_index = PP_WorldTileIndexFromLocalTileIndex(chunk_index, local_tile_index); - Vec2 pos = PP_PosFromWorldTileIndex(world_tile_index); - Xform tile_xf = XformFromRect(RectFromVec2(pos, VEC2(tile_size, tile_size))); - PP_MaterialInstance *mat = PushStruct(g->material_instances_arena, PP_MaterialInstance); - *mat = PP_DefaultMaterialInstance; - mat->xf = tile_xf; - mat->tex = GPU_Texture2DRidFromResource(tile_texture->gpu_texture); - mat->is_light = 1; - mat->light_emittance_srgb = VEC3(0, 0, 0); - } - } - } - } - } - - /* Debug draw entity info */ - if (g->debug_draw && !skip_debug_draw) - { - TempArena temp = BeginTempArena(scratch.arena); - - if (PP_HasProp(ent, PP_Prop_Kinematic) || PP_HasProp(ent, PP_Prop_Dynamic)) - { - PP_DrawDebugMovement(ent); - } - - /* Draw xform */ - if (!skip_debug_draw_transform) - { - u32 color_x = Rgba32F(1, 0, 0, 0.5); - u32 color_y = Rgba32F(0, 1, 0, 0.5); - PP_DrawDebugXform(xf, color_x, color_y); - } - - /* Draw AABB */ - /* FIXME: Enable this */ + } + if (collider.count == 1 && collider.radius > 0) + { + /* Draw upwards line for circle */ + Vec2 start = xf.og; + Vec2 end = CLD_SupportPointFromDir(&collider, xf, NegVec2(xf.by)).p; + start = MulXformV2(g->world_to_ui_xf, start); + end = MulXformV2(g->world_to_ui_xf, end); + D_DrawLine(g->render_sig, start, end, thickness, color); + } #if 0 - if (ent->local_collider.count > 0) - { - Aabb aabb = CLD_AabbFromShape(&ent->local_collider, xf); - f32 thickness = 1; - u32 color = Rgba32F(1, 0, 1, 0.5); - Quad quad = QuadFromAabb(aabb); - quad = MulXformQuad(g->world_to_ui_xf, quad); - D_DrawQuadLine(g->render_sig, quad, thickness, color); - } - - /* Draw focus arrow */ - if (ent == local_control || PP_EqEntKey(ent->key, g->debug_following)) - { - SPR_Sheet *sheet = SPR_SheetFromResourceAsync(ent->sprite); - SPR_Slice slice = SPR_SliceFromNameIndex(sheet, Lit("attach.wep"), ent->animation_frame); - Vec2 start = MulXformV2(sprite_xform, slice.center); - start = MulXformV2(g->world_to_ui_xf, start); - Vec2 end = AddVec2(xf.og, ent->control.focus); - end = MulXformV2(g->world_to_ui_xf, end); - D_DrawArrowLine(g->render_sig, start, end, 3, 10, Rgba32F(1, 1, 1, 0.5)); - } + /* Draw support point at focus dir */ + { + Vec2 p = collider_support_point(&collider, xf, ent->control.focus); + p = MulXformV2(g->world_to_ui_xf, p); + D_DrawCircle(g->render_sig, p, 3, Color_Red, 10); + } +#endif + } #endif + /* Draw contact constraint */ + /* FIXME: Enable this */ #if 0 - /* Draw slices */ - if (!SPR_IsNil(ent->sprite)) - { - SPR_Sheet *sheet = SPR_SheetFromResourceAsync(sprite); - - u32 quad_color = Rgba32F(1, 0, 0.5, 1); - u32 point_color = Rgba32F(1, 0, 0, 1); - u32 ray_color = Rgba32F(1, 0, 0.5, 1); - - for (u64 i = 0; i < sheet->slice_groups_count; ++i) - { - SPR_SheetSliceGroup *group = &sheet->slice_groups[i]; - if (StringEndsWith(group->name, Lit(".ray"))) continue; - - for (u32 j = 0; j < group->per_frame_count; ++j) - { - SPR_Slice slice = group->frame_slices[(ent->animation_frame * group->per_frame_count) + j]; - - Vec2 center = MulXformV2(sprite_xform, slice.center); - center = MulXformV2(g->world_to_ui_xf, center); - - if (!slice.has_ray) - { - Quad quad = QuadFromRect(slice.rect); - quad = MulXformQuad(sprite_xform, quad); - quad = MulXformQuad(g->world_to_ui_xf, quad); - D_DrawQuadLine(g->render_sig, quad, 2, quad_color); - } - - D_DrawCircle(g->render_sig, center, 3, point_color, 20); - - if (slice.has_ray) - { - Vec2 ray = MulXformBasisV2(sprite_xform, slice.dir); - ray = MulXformBasisV2(g->world_to_ui_xf, ray); - ray = Vec2WithLen(ray, 25); - D_DrawArrowRay(g->render_sig, center, ray, 2, 10, ray_color); - } - } - } - } -#endif - - /* Draw weld joint */ -#if 0 - if (PP_HasProp(ent, PP_Prop_WeldJoint)) - { - PP_Ent *e1 = PP_EntFromKey(g->ss_blended, ent->weld_joint_data.e1); - Xform e1_xf = PP_XformFromEnt(e1); - - u32 color = Color_Yellow; - f32 radius = 3; - Vec2 point = MulXformV2(e1_xf, ent->weld_joint_data.point_local_e1); - point = MulXformV2(g->world_to_ui_xf, point); - D_DrawCircle(g->render_sig, point, radius, color, 10); - - DEBUGBREAKABLE; - } -#endif - - /* Draw mouse joint */ - /* FIXME: Enable this */ -#if 0 - if (PP_HasProp(ent, PP_Prop_MouseJoint)) - { - PP_Ent *target = PP_EntFromKey(g->ss_blended, ent->mouse_joint_data.target); - Xform target_xf = PP_XformFromEnt(target); - u32 color = Color_White; - Vec2 point_start = MulXformV2(target_xf, ent->mouse_joint_data.point_local_start); - Vec2 point_end = g->world_cursor; - point_start = MulXformV2(g->world_to_ui_xf, point_start); - point_end = MulXformV2(g->world_to_ui_xf, point_end); - D_DrawArrowLine(g->render_sig, point_start, point_end, 3, 10, color); - D_DrawCircle(g->render_sig, point_start, 4, color, 10); - } -#endif - - /* Draw collider */ - /* FIXME: Enable this */ -#if 0 - if (ent->local_collider.count > 0) - { - CLD_Shape collider = ent->local_collider; - u32 color = Rgba32F(1, 1, 0, 0.5); - f32 thickness = 2; - { - /* Draw collider using support points */ - u32 detail = 32; - Xform collider_draw_xf = MulXform(g->world_to_ui_xf, xf); - D_DrawColliderLine(g->render_sig, collider, collider_draw_xf, thickness, color, detail); - } - { - /* Draw collider shape points */ - for (u32 i = 0; i < collider.count; ++i) - { - Vec2 p = MulXformV2(MulXform(g->world_to_ui_xf, xf), collider.points[i]); - D_DrawCircle(g->render_sig, p, 3, Color_Blue, 10); - } - } - if (collider.count == 1 && collider.radius > 0) - { - /* Draw upwards line for circle */ - Vec2 start = xf.og; - Vec2 end = CLD_SupportPointFromDir(&collider, xf, NegVec2(xf.by)).p; - start = MulXformV2(g->world_to_ui_xf, start); - end = MulXformV2(g->world_to_ui_xf, end); - D_DrawLine(g->render_sig, start, end, thickness, color); - } -#if 0 - /* Draw support point at focus dir */ - { - Vec2 p = collider_support_point(&collider, xf, ent->control.focus); - p = MulXformV2(g->world_to_ui_xf, p); - D_DrawCircle(g->render_sig, p, 3, Color_Red, 10); - } -#endif - } -#endif - - /* Draw contact constraint */ - /* FIXME: Enable this */ -#if 0 - if (PP_HasProp(ent, PP_Prop_ContactConstraint)) - { - ContactConstraint *data = &ent->contact_constraint_data; - PP_Ent *e0 = PP_EntFromKey(g->ss_blended, data->e0); - PP_Ent *e1 = PP_EntFromKey(g->ss_blended, data->e1); - LAX e0; - LAX e1; + if (PP_HasProp(ent, PP_Prop_ContactConstraint)) + { + ContactConstraint *data = &ent->contact_constraint_data; + PP_Ent *e0 = PP_EntFromKey(g->ss_blended, data->e0); + PP_Ent *e1 = PP_EntFromKey(g->ss_blended, data->e1); + LAX e0; + LAX e1; #if IsDeveloperModeEnabled - /* Draw contact points */ - { - f32 radius = 5; - for (u32 i = 0; i < data->num_points; ++i) - { - u32 color = (data->skip_solve || data->wrong_dir) ? Alpha32F(Color_Yellow, 0.3) : Rgba32F(0.8, 0.2, 0.2, 1); - ContactPoint point = data->points[i]; - Vec2 dbg_pt = point.dbg_pt; + /* Draw contact points */ + { + f32 radius = 5; + for (u32 i = 0; i < data->num_points; ++i) + { + u32 color = (data->skip_solve || data->wrong_dir) ? Alpha32F(Color_Yellow, 0.3) : Rgba32F(0.8, 0.2, 0.2, 1); + ContactPoint point = data->points[i]; + Vec2 dbg_pt = point.dbg_pt; - /* Draw point */ - { - D_DrawCircle(g->render_sig, MulXformV2(g->world_to_ui_xf, dbg_pt), radius, color, 10); - } + /* Draw point */ + { + D_DrawCircle(g->render_sig, MulXformV2(g->world_to_ui_xf, dbg_pt), radius, color, 10); + } - /* Draw normal */ - { - f32 len = 0.1f; - f32 arrow_thickness = 2; - f32 arrow_height = 5; - Vec2 start = MulXformV2(g->world_to_ui_xf, dbg_pt); - Vec2 end = MulXformV2(g->world_to_ui_xf, AddVec2(dbg_pt, MulVec2(NormVec2(data->normal), len))); - D_DrawArrowLine(g->render_sig, start, end, arrow_thickness, arrow_height, color); - } + /* Draw normal */ + { + f32 len = 0.1f; + f32 arrow_thickness = 2; + f32 arrow_height = 5; + Vec2 start = MulXformV2(g->world_to_ui_xf, dbg_pt); + Vec2 end = MulXformV2(g->world_to_ui_xf, AddVec2(dbg_pt, MulVec2(NormVec2(data->normal), len))); + D_DrawArrowLine(g->render_sig, start, end, arrow_thickness, arrow_height, color); + } #if 0 - /* Draw contact info */ - { - F_Font *disp_font = F_LoadFontAsync(ResourceKeyFromStore(&PP_Resources, Lit("font/fixedsys.ttf")), 12.0f); - if (disp_font) - { - f32 offset_px = 10; - - String fmt = Lit( - "e0 index: %F\n" - "e1 index: %F\n" - "key: 0x%F\n" - "impulse (n): %F\n" - "impulse (t): %F\n" - "separation: %F\n" - "normal: (%F, %F)\n" - "num contacts: %F" - ); - String text = StringF( - temp.arena, fmt, - FmtUint(e0->key.idx), - FmtUint(e1->key.idx), - FmtHex(point.key), - FmtFloat(point.normal_impulse), - FmtFloat(point.tangent_impulse), - FmtFloatP(point.starting_separation, 6), - FmtFloatP(data->normal.x, 6), FmtFloatP(data->normal.y, 6), - FmtUint(data->num_points) - ); - - draw_text(g->render_sig, disp_font, AddVec2(RoundVec2(MulXformV2(g->world_to_ui_xf, dbg_pt)), VEC2(0, offset_px)), text); - } - } -#endif - } - } -#endif - } -#endif - - /* Draw collision debug */ -#if COLLIDER_DEBUG - if (PP_HasProp(ent, PP_Prop_CollisionDebug)) + /* Draw contact info */ + { + F_Font *disp_font = F_LoadFontAsync(ResourceKeyFromStore(&PP_Resources, Lit("font/fixedsys.ttf")), 12.0f); + if (disp_font) { - ContactDebugData *data = &ent->collision_debug_data; - CLD_CollisionData collision_reuslt = data->collision_result; - PP_Ent *e0 = PP_EntFromKey(g->ss_blended, data->e0); - PP_Ent *e1 = PP_EntFromKey(g->ss_blended, data->e1); - CLD_Shape e0_collider = e0->local_collider; - CLD_Shape e1_collider = e1->local_collider; - LAX e0_collider; - LAX e1_collider; + f32 offset_px = 10; - /* Draw closest points */ -#if 0 - { - f32 radius = 4; - u32 color = Rgba32F(1, 1, 0, 0.5); - Vec2 a = MulXformV2(g->world_to_ui_xf, data->closest0); - Vec2 b = MulXformV2(g->world_to_ui_xf, data->closest1); - D_DrawCircle(g->render_sig, a, radius, color, 10); - D_DrawCircle(g->render_sig, b, radius, color, 10); - } + String fmt = Lit( + "e0 index: %F\n" + "e1 index: %F\n" + "key: 0x%F\n" + "impulse (n): %F\n" + "impulse (t): %F\n" + "separation: %F\n" + "normal: (%F, %F)\n" + "num contacts: %F" + ); + String text = StringF( + temp.arena, fmt, + FmtUint(e0->key.idx), + FmtUint(e1->key.idx), + FmtHex(point.key), + FmtFloat(point.normal_impulse), + FmtFloat(point.tangent_impulse), + FmtFloatP(point.starting_separation, 6), + FmtFloatP(data->normal.x, 6), FmtFloatP(data->normal.y, 6), + FmtUint(data->num_points) + ); + + draw_text(g->render_sig, disp_font, AddVec2(RoundVec2(MulXformV2(g->world_to_ui_xf, dbg_pt)), VEC2(0, offset_px)), text); + } + } +#endif + } + } +#endif + } #endif - /* Draw clipping */ - { - f32 thickness = 4; - f32 radius = 4; - u32 color_line = Rgba32F(1, 0, 1, 0.75); - u32 color_a = Rgba32F(1, 0, 0, 0.25); - u32 color_b = Rgba32F(0, 1, 0, 0.25); - u32 color_line_clipped = Rgba32F(1, 0, 1, 1); - u32 color_a_clipped = Rgba32F(1, 0, 0, 1); - u32 color_b_clipped = Rgba32F(0, 1, 0, 1); - { - Vec2 a = MulXformV2(g->world_to_ui_xf, collision_reuslt.a0); - Vec2 b = MulXformV2(g->world_to_ui_xf, collision_reuslt.b0); - D_DrawLine(g->render_sig, a, b, thickness, color_line); - D_DrawCircle(g->render_sig, a, radius, color_a, 10); - D_DrawCircle(g->render_sig, b, radius, color_b, 10); + /* Draw collision debug */ +#if COLLIDER_DEBUG + if (PP_HasProp(ent, PP_Prop_CollisionDebug)) + { + ContactDebugData *data = &ent->collision_debug_data; + CLD_CollisionData collision_reuslt = data->collision_result; + PP_Ent *e0 = PP_EntFromKey(g->ss_blended, data->e0); + PP_Ent *e1 = PP_EntFromKey(g->ss_blended, data->e1); + CLD_Shape e0_collider = e0->local_collider; + CLD_Shape e1_collider = e1->local_collider; + LAX e0_collider; + LAX e1_collider; - Vec2 a_clipped = MulXformV2(g->world_to_ui_xf, collision_reuslt.a0_clipped); - Vec2 b_clipped = MulXformV2(g->world_to_ui_xf, collision_reuslt.b0_clipped); - D_DrawLine(g->render_sig, a_clipped, b_clipped, thickness, color_line_clipped); - D_DrawCircle(g->render_sig, a_clipped, radius, color_a_clipped, 10); - D_DrawCircle(g->render_sig, b_clipped, radius, color_b_clipped, 10); - } - { - Vec2 a = MulXformV2(g->world_to_ui_xf, collision_reuslt.a1); - Vec2 b = MulXformV2(g->world_to_ui_xf, collision_reuslt.b1); - D_DrawLine(g->render_sig, a, b, thickness, color_line); - D_DrawCircle(g->render_sig, a, radius, color_a, 10); - D_DrawCircle(g->render_sig, b, radius, color_b, 10); + /* Draw closest points */ +#if 0 + { + f32 radius = 4; + u32 color = Rgba32F(1, 1, 0, 0.5); + Vec2 a = MulXformV2(g->world_to_ui_xf, data->closest0); + Vec2 b = MulXformV2(g->world_to_ui_xf, data->closest1); + D_DrawCircle(g->render_sig, a, radius, color, 10); + D_DrawCircle(g->render_sig, b, radius, color, 10); + } +#endif - Vec2 a_clipped = MulXformV2(g->world_to_ui_xf, collision_reuslt.a1_clipped); - Vec2 b_clipped = MulXformV2(g->world_to_ui_xf, collision_reuslt.b1_clipped); - D_DrawLine(g->render_sig, a_clipped, b_clipped, thickness, color_line_clipped); - D_DrawCircle(g->render_sig, a_clipped, radius, color_a_clipped, 10); - D_DrawCircle(g->render_sig, b_clipped, radius, color_b_clipped, 10); - } - } + /* Draw clipping */ + { + f32 thickness = 4; + f32 radius = 4; + u32 color_line = Rgba32F(1, 0, 1, 0.75); + u32 color_a = Rgba32F(1, 0, 0, 0.25); + u32 color_b = Rgba32F(0, 1, 0, 0.25); + u32 color_line_clipped = Rgba32F(1, 0, 1, 1); + u32 color_a_clipped = Rgba32F(1, 0, 0, 1); + u32 color_b_clipped = Rgba32F(0, 1, 0, 1); + { + Vec2 a = MulXformV2(g->world_to_ui_xf, collision_reuslt.a0); + Vec2 b = MulXformV2(g->world_to_ui_xf, collision_reuslt.b0); + D_DrawLine(g->render_sig, a, b, thickness, color_line); + D_DrawCircle(g->render_sig, a, radius, color_a, 10); + D_DrawCircle(g->render_sig, b, radius, color_b, 10); + + Vec2 a_clipped = MulXformV2(g->world_to_ui_xf, collision_reuslt.a0_clipped); + Vec2 b_clipped = MulXformV2(g->world_to_ui_xf, collision_reuslt.b0_clipped); + D_DrawLine(g->render_sig, a_clipped, b_clipped, thickness, color_line_clipped); + D_DrawCircle(g->render_sig, a_clipped, radius, color_a_clipped, 10); + D_DrawCircle(g->render_sig, b_clipped, radius, color_b_clipped, 10); + } + { + Vec2 a = MulXformV2(g->world_to_ui_xf, collision_reuslt.a1); + Vec2 b = MulXformV2(g->world_to_ui_xf, collision_reuslt.b1); + D_DrawLine(g->render_sig, a, b, thickness, color_line); + D_DrawCircle(g->render_sig, a, radius, color_a, 10); + D_DrawCircle(g->render_sig, b, radius, color_b, 10); + + Vec2 a_clipped = MulXformV2(g->world_to_ui_xf, collision_reuslt.a1_clipped); + Vec2 b_clipped = MulXformV2(g->world_to_ui_xf, collision_reuslt.b1_clipped); + D_DrawLine(g->render_sig, a_clipped, b_clipped, thickness, color_line_clipped); + D_DrawCircle(g->render_sig, a_clipped, radius, color_a_clipped, 10); + D_DrawCircle(g->render_sig, b_clipped, radius, color_b_clipped, 10); + } + } #if COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI - Xform e0_xf = data->xf0; - Xform e1_xf = data->xf1; + Xform e0_xf = data->xf0; + Xform e1_xf = data->xf1; #if 0 - /* Only draw points with large separation */ - b32 should_draw = 0; - for (u32 i = 0; i < data->num_points; ++i) - { - if (data->points[i].starting_separation < -0.1) - { - should_draw = 1; - break; - } - } -#else - b32 should_draw = 1; -#endif - - if (should_draw) - { -#if 0 - /* Test info */ - { - F_Font *disp_font = F_LoadFontAsync(ResourceKeyFromStore(&PP_Resources, Lit("font/fixedsys.ttf")), 12.0f); - if (disp_font) - { - f32 offset_px = 10; - String fmt = Lit( - "e0 pos: (%F, %F)\n" - "e0 rot: %F\n" - "e1 pos: (%F, %F)\n" - "e1 rot: %F\n" - ); - String text = StringF( - temp.arena, fmt, - FmtFloatP(e0_xf.og.x, 24), FmtFloatP(e0_xf.og.y, 24), - FmtFloatP(RotationFromXform(e0_xf), 24), - FmtFloatP(e1_xf.og.x, 24), FmtFloatP(e1_xf.og.y, 24), - FmtFloatP(RotationFromXform(e1_xf), 24) - ); - - draw_text(g->render_sig, disp_font, AddVec2(RoundVec2(MulXformV2(g->world_to_ui_xf, VEC2(0, 0))), VEC2(0, offset_px)), text); - } - } -#endif - - /* Draw CLD_Menkowski */ - { - - u32 color = collision_reuslt.solved ? Rgba32F(0, 0, 0.25, 1) : Rgba32F(0, 0.25, 0.25, 1); - f32 thickness = 2; - u32 detail = 512; - LAX thickness; - - Vec2Array m = CLD_Menkowski(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf, detail); - - for (u64 i = 0; i < m.count; ++i) m.points[i] = MulXformV2(g->world_to_ui_xf, m.points[i]); - D_DrawPolyLine(g->render_sig, m, 1, thickness, color); - //D_DrawPoly(g->render_sig, m, color); - } - - /* Draw CLD_PointCloud */ - { - u32 color = Rgba32F(1, 1, 1, 1); - f32 radius = 2; - - Vec2Array m = CLD_PointCloud(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf); - - for (u64 i = 0; i < m.count; ++i) - { - Vec2 p = MulXformV2(g->world_to_ui_xf, m.points[i]); - D_DrawCircle(g->render_sig, p, radius, color, 10); - } - } - - /* Draw prototype */ - { - f32 thickness = 2; - u32 color = Rgba32F(1, 1, 1, 0.25); - - Vec2Array m = { - .points = collision_reuslt.prototype.points, - .count = collision_reuslt.prototype.len - }; - for (u64 i = 0; i < m.count; ++i) m.points[i] = MulXformV2(g->world_to_ui_xf, m.points[i]); - D_DrawPolyLine(g->render_sig, m, 1, thickness, color); - for (u64 i = 0; i < m.count; ++i) D_DrawCircle(g->render_sig, m.points[i], 10, color, 10); - } - - /* Draw simplex */ - { - f32 thickness = 2; - u32 line_color = Color_Yellow; - u32 color_first = Rgba32F(1, 0, 0, 0.75); - u32 color_second = Rgba32F(0, 1, 0, 0.75); - u32 color_third = Rgba32F(0, 0, 1, 0.75); - - CLD_MenkowskiSimplex simplex = collision_reuslt.simplex; - Vec2 simplex_points[] = { simplex.a.p, simplex.b.p, simplex.c.p }; - for (u64 i = 0; i < countof(simplex_points); ++i) simplex_points[i] = MulXformV2(g->world_to_ui_xf, simplex_points[i]); - Vec2Array simplex_array = { .count = simplex.len, .points = simplex_points }; - - if (simplex.len >= 1) - { - u32 color = simplex.len == 1 ? color_first : (simplex.len == 2 ? color_second : color_third); - D_DrawCircle(g->render_sig, simplex_array.points[0], thickness * 3, color, 10); - } - if (simplex.len >= 2) - { - u32 color = simplex.len == 2 ? color_first : color_second; - D_DrawCircle(g->render_sig, simplex_array.points[1], thickness * 3, color, 10); - } - if (simplex.len >= 3) - { - u32 color = color_first; - D_DrawCircle(g->render_sig, simplex_array.points[2], thickness * 3, color, 10); - } - if (simplex.len >= 2) - { - D_DrawPolyLine(g->render_sig, simplex_array, simplex.len > 2, thickness, line_color); - } - } - - /* Draw normal */ - { - u32 color = Color_White; - f32 len = 0.1f; - f32 arrow_thickness = 4; - f32 arrowhead_height = 10; - Vec2 start = MulXformV2(g->world_to_ui_xf, VEC2(0, 0)); - Vec2 end = MulXformV2(g->world_to_ui_xf, MulVec2(NormVec2(collision_reuslt.normal), len)); - D_DrawArrowLine(g->render_sig, start, end, arrow_thickness, arrowhead_height, color); - } - } -#endif - } -#endif - - /* Draw hierarchy */ - /* FIXME: Enable this */ -#if 0 - if (PP_HasProp(parent, PP_Prop_Active) && !parent->is_root) - { - u32 color = Rgba32F(0.6, 0.6, 1, 0.75); - f32 thickness = 2; - f32 arrow_height = 15; - - Vec2 start = MulXformV2(g->world_to_ui_xf, xf.og); - Vec2 end = MulXformV2(g->world_to_ui_xf, parent_xf.og); - D_DrawArrowLine(g->render_sig, start, end, thickness, arrow_height, color); - } - - /* Draw camera rect */ - if (PP_HasProp(ent, PP_Prop_Camera)) - { - u32 color = ent == local_camera ? Rgba32F(1, 1, 1, 0.5) : Rgba32F(0, 0.75, 0, 0.5); - f32 thickness = 3; - - Xform quad_xf = MulXform(xf, ent->camera_quad_xform); - Quad quad = MulXformQuad(quad_xf, CenteredUnitSquareQuad); - quad = MulXformQuad(g->world_to_ui_xf, quad); - - D_DrawQuadLine(g->render_sig, quad, thickness, color); - } -#endif - - EndTempArena(temp); + /* Only draw points with large separation */ + b32 should_draw = 0; + for (u32 i = 0; i < data->num_points; ++i) + { + if (data->points[i].starting_separation < -0.1) + { + should_draw = 1; + break; } + } +#else + b32 should_draw = 1; +#endif + + if (should_draw) + { +#if 0 + /* Test info */ + { + F_Font *disp_font = F_LoadFontAsync(ResourceKeyFromStore(&PP_Resources, Lit("font/fixedsys.ttf")), 12.0f); + if (disp_font) + { + f32 offset_px = 10; + String fmt = Lit( + "e0 pos: (%F, %F)\n" + "e0 rot: %F\n" + "e1 pos: (%F, %F)\n" + "e1 rot: %F\n" + ); + String text = StringF( + temp.arena, fmt, + FmtFloatP(e0_xf.og.x, 24), FmtFloatP(e0_xf.og.y, 24), + FmtFloatP(RotationFromXform(e0_xf), 24), + FmtFloatP(e1_xf.og.x, 24), FmtFloatP(e1_xf.og.y, 24), + FmtFloatP(RotationFromXform(e1_xf), 24) + ); + + draw_text(g->render_sig, disp_font, AddVec2(RoundVec2(MulXformV2(g->world_to_ui_xf, VEC2(0, 0))), VEC2(0, offset_px)), text); + } + } +#endif + + /* Draw CLD_Menkowski */ + { + + u32 color = collision_reuslt.solved ? Rgba32F(0, 0, 0.25, 1) : Rgba32F(0, 0.25, 0.25, 1); + f32 thickness = 2; + u32 detail = 512; + LAX thickness; + + Vec2Array m = CLD_Menkowski(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf, detail); + + for (u64 i = 0; i < m.count; ++i) m.points[i] = MulXformV2(g->world_to_ui_xf, m.points[i]); + D_DrawPolyLine(g->render_sig, m, 1, thickness, color); + //D_DrawPoly(g->render_sig, m, color); + } + + /* Draw CLD_PointCloud */ + { + u32 color = Rgba32F(1, 1, 1, 1); + f32 radius = 2; + + Vec2Array m = CLD_PointCloud(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf); + + for (u64 i = 0; i < m.count; ++i) + { + Vec2 p = MulXformV2(g->world_to_ui_xf, m.points[i]); + D_DrawCircle(g->render_sig, p, radius, color, 10); + } + } + + /* Draw prototype */ + { + f32 thickness = 2; + u32 color = Rgba32F(1, 1, 1, 0.25); + + Vec2Array m = { + .points = collision_reuslt.prototype.points, + .count = collision_reuslt.prototype.len + }; + for (u64 i = 0; i < m.count; ++i) m.points[i] = MulXformV2(g->world_to_ui_xf, m.points[i]); + D_DrawPolyLine(g->render_sig, m, 1, thickness, color); + for (u64 i = 0; i < m.count; ++i) D_DrawCircle(g->render_sig, m.points[i], 10, color, 10); + } + + /* Draw simplex */ + { + f32 thickness = 2; + u32 line_color = Color_Yellow; + u32 color_first = Rgba32F(1, 0, 0, 0.75); + u32 color_second = Rgba32F(0, 1, 0, 0.75); + u32 color_third = Rgba32F(0, 0, 1, 0.75); + + CLD_MenkowskiSimplex simplex = collision_reuslt.simplex; + Vec2 simplex_points[] = { simplex.a.p, simplex.b.p, simplex.c.p }; + for (u64 i = 0; i < countof(simplex_points); ++i) simplex_points[i] = MulXformV2(g->world_to_ui_xf, simplex_points[i]); + Vec2Array simplex_array = { .count = simplex.len, .points = simplex_points }; + + if (simplex.len >= 1) + { + u32 color = simplex.len == 1 ? color_first : (simplex.len == 2 ? color_second : color_third); + D_DrawCircle(g->render_sig, simplex_array.points[0], thickness * 3, color, 10); + } + if (simplex.len >= 2) + { + u32 color = simplex.len == 2 ? color_first : color_second; + D_DrawCircle(g->render_sig, simplex_array.points[1], thickness * 3, color, 10); + } + if (simplex.len >= 3) + { + u32 color = color_first; + D_DrawCircle(g->render_sig, simplex_array.points[2], thickness * 3, color, 10); + } + if (simplex.len >= 2) + { + D_DrawPolyLine(g->render_sig, simplex_array, simplex.len > 2, thickness, line_color); + } + } + + /* Draw normal */ + { + u32 color = Color_White; + f32 len = 0.1f; + f32 arrow_thickness = 4; + f32 arrowhead_height = 10; + Vec2 start = MulXformV2(g->world_to_ui_xf, VEC2(0, 0)); + Vec2 end = MulXformV2(g->world_to_ui_xf, MulVec2(NormVec2(collision_reuslt.normal), len)); + D_DrawArrowLine(g->render_sig, start, end, arrow_thickness, arrowhead_height, color); + } + } + #endif } + #endif + + /* Draw hierarchy */ + /* FIXME: Enable this */ +#if 0 + if (PP_HasProp(parent, PP_Prop_Active) && !parent->is_root) + { + u32 color = Rgba32F(0.6, 0.6, 1, 0.75); + f32 thickness = 2; + f32 arrow_height = 15; + + Vec2 start = MulXformV2(g->world_to_ui_xf, xf.og); + Vec2 end = MulXformV2(g->world_to_ui_xf, parent_xf.og); + D_DrawArrowLine(g->render_sig, start, end, thickness, arrow_height, color); + } + + /* Draw camera rect */ + if (PP_HasProp(ent, PP_Prop_Camera)) + { + u32 color = ent == local_camera ? Rgba32F(1, 1, 1, 0.5) : Rgba32F(0, 0.75, 0, 0.5); + f32 thickness = 3; + + Xform quad_xf = MulXform(xf, ent->camera_quad_xform); + Quad quad = MulXformQuad(quad_xf, CenteredUnitSquareQuad); + quad = MulXformQuad(g->world_to_ui_xf, quad); + + D_DrawQuadLine(g->render_sig, quad, thickness, color); + } +#endif + + EndTempArena(temp); + } + } + } + + /* Draw crosshair or show cursor */ + /* FIXME: Enable this */ + #if 0 + if (!g->debug_camera) + { + __profn("Draw crosshair"); + Vec2 crosshair_pos = g->ui_cursor; + ResourceKey crosshair = ResourceKeyFromStore(PP_Resources, Lit("sprite/crosshair.ase")); + SPR_Texture *t = SPR_TextureFromResourceAsync(crosshair); + Vec2 size = VEC2(t->width, t->height); + Xform xf = XformFromTrs(TRS(.t = crosshair_pos, .s = size)); + D_DrawUiRect(g->render_sig, D_UIRECTPARAMS(.xf = xf, .texture = t->gpu_resource)); + } + #endif + + /* FIXME: Enable this */ + #if 0 + { + __profn("Update window cursor"); + if (g->debug_camera) + { + P_DisableWindoweCursorClip(g->window); + P_ShowWindowCursor(g->window); + } + else + { + SPR_Texture *t = SPR_TextureFromResourceAsync(ResourceKeyFromStore(PP_Resources, Lit("sprite/crosshair.ase"))); + Vec2 size = VEC2(t->width, t->height); + Rect cursor_clip = RectFromVec2(g->ui_screen_offset, g->ui_size); + cursor_clip.pos = AddVec2(cursor_clip.pos, MulVec2(size, 0.5f)); + cursor_clip.pos = AddVec2(cursor_clip.pos, VEC2(1, 1)); + cursor_clip.size = SubVec2(cursor_clip.size, size); + P_HideWindowCursor(g->window); + P_EnableWindoweCursorClip(g->window, cursor_clip); + } + } + #endif + + //- Create user sim cmd + + { + /* Queue player move cmd */ + f32 move_speed = 1.0f; + //if (g->bind_states[PP_BindKind_Walk].is_held) + if (g->bind_states[PP_BindKind_FullscreenMod].is_held) + { + //const f32 walk_ratio = 0.25f; + const f32 walk_ratio = 0.05f; + move_speed *= walk_ratio; + } + + Vec2 input_move_dir = ZI; + { + for (PP_BindKind bind = 0; bind < (i32)countof(g->bind_states); ++bind) + { + PP_BindState state = g->bind_states[bind]; + + if (!state.is_held && state.num_presses <= 0) + { + continue; + } + + switch (bind) + { + default: break; + + /* Movement */ + case PP_BindKind_MoveUp: + { + input_move_dir.y -= 1; + } break; + + case PP_BindKind_MoveDown: + { + input_move_dir.y += 1; + } break; + + case PP_BindKind_MoveLeft: + { + input_move_dir.x -= 1; + } break; + + case PP_BindKind_MoveRight: + { + input_move_dir.x += 1; + } break; + } + } + + input_move_dir = InvertXformBasisMulV2(g->world_to_ui_xf, input_move_dir); /* Make move dir relative to world view */ + input_move_dir = MulVec2(NormVec2(input_move_dir), move_speed); } - /* Draw crosshair or show cursor */ - /* FIXME: Enable this */ -#if 0 if (!g->debug_camera) { - __profn("Draw crosshair"); - Vec2 crosshair_pos = g->ui_cursor; - ResourceKey crosshair = ResourceKeyFromStore(PP_Resources, Lit("sprite/crosshair.ase")); - SPR_Texture *t = SPR_TextureFromResourceAsync(crosshair); - Vec2 size = VEC2(t->width, t->height); - Xform xf = XformFromTrs(TRS(.t = crosshair_pos, .s = size)); - D_DrawUiRect(g->render_sig, D_UIRECTPARAMS(.xf = xf, .texture = t->gpu_resource)); + g->focus_send = SubVec2(g->world_cursor, PP_XformFromEnt(local_control).og); } -#endif + Vec2 input_aim_dir = g->focus_send; - /* FIXME: Enable this */ -#if 0 + /* Queue player control cmd */ { - __profn("Update window cursor"); - if (g->debug_camera) + PP_ControlData control = ZI; + control.move = input_move_dir; + control.focus = input_aim_dir; + control.dbg_cursor = g->world_cursor; + + PP_BindState fire_state = g->bind_states[PP_BindKind_Fire]; + PP_BindState fire_alt_state = g->bind_states[PP_BindKind_AltFire]; + PP_BindState drag_state = g->bind_states[PP_BindKind_DebugDrag]; + PP_BindState delete_state = g->bind_states[PP_BindKind_DebugDelete]; + PP_BindState clear_state = g->bind_states[PP_BindKind_DebugClear]; + PP_BindState spawn1_state = g->bind_states[PP_BindKind_DebugSpawn1]; + PP_BindState spawn2_state = g->bind_states[PP_BindKind_DebugSpawn2]; + PP_BindState spawn3_state = g->bind_states[PP_BindKind_DebugSpawn3]; + PP_BindState spawn4_state = g->bind_states[PP_BindKind_DebugSpawn4]; + PP_BindState walls_state = g->bind_states[PP_BindKind_DebugWalls]; + PP_BindState pause_state = g->bind_states[PP_BindKind_DebugPause]; + PP_BindState step_state = g->bind_states[PP_BindKind_DebugStep]; + PP_BindState tile_state = g->bind_states[PP_BindKind_TestTile]; + PP_BindState explode_state = g->bind_states[PP_BindKind_DebugExplode]; + PP_BindState teleport_state = g->bind_states[PP_BindKind_DebugTeleport]; + + if (fire_state.num_presses || fire_state.is_held) + { + control.flags |= PP_ControlFlag_Fire; + } + if (fire_alt_state.num_presses || fire_alt_state.is_held) + { + control.flags |= PP_ControlFlag_AltFire; + } + if (drag_state.num_presses || drag_state.is_held) + { + control.flags |= PP_ControlFlag_Drag; + } + if (delete_state.num_presses || delete_state.is_held) + { + control.flags |= PP_ControlFlag_Delete; + } + if (clear_state.num_presses_and_repeats) + { + control.flags |= PP_ControlFlag_ClearAll; + } + if (spawn1_state.num_presses_and_repeats) + { + control.flags |= PP_ControlFlag_SpawnTest1; + } + if (spawn2_state.num_presses_and_repeats) + { + control.flags |= PP_ControlFlag_SpawnTest2; + } + if (spawn3_state.num_presses_and_repeats) + { + control.flags |= PP_ControlFlag_SpawnTest3; + } + if (spawn4_state.num_presses_and_repeats) + { + control.flags |= PP_ControlFlag_SpawnTest4; + } + if (walls_state.num_presses_and_repeats) + { + control.flags |= PP_ControlFlag_TestWalls; + } + if (tile_state.num_presses || tile_state.is_held) + { + control.flags |= PP_ControlFlag_TestTiles; + } + if (explode_state.num_presses_and_repeats) + { + control.flags |= PP_ControlFlag_TestExplode; + } + if (teleport_state.num_presses_and_repeats || (g->debug_camera && teleport_state.is_held)) + { + control.flags |= PP_ControlFlag_TestTeleport; + } + + if (pause_state.num_presses) + { + Atomic32FetchXor(&g->user_paused, 1); + } + Atomic32FetchAdd(&g->user_paused_steps, step_state.num_presses_and_repeats); + + /* Set user sim control */ + { + Lock lock = LockE(&g->user_sim_cmd_mutex); + + /* Reset flags */ + if (g->user_sim_cmd_gen != g->last_user_sim_cmd_gen) { - P_DisableWindoweCursorClip(g->window); - P_ShowWindowCursor(g->window); - } - else - { - SPR_Texture *t = SPR_TextureFromResourceAsync(ResourceKeyFromStore(PP_Resources, Lit("sprite/crosshair.ase"))); - Vec2 size = VEC2(t->width, t->height); - Rect cursor_clip = RectFromVec2(g->ui_screen_offset, g->ui_size); - cursor_clip.pos = AddVec2(cursor_clip.pos, MulVec2(size, 0.5f)); - cursor_clip.pos = AddVec2(cursor_clip.pos, VEC2(1, 1)); - cursor_clip.size = SubVec2(cursor_clip.size, size); - P_HideWindowCursor(g->window); - P_EnableWindoweCursorClip(g->window, cursor_clip); + g->user_sim_cmd_control.flags = 0; + g->last_user_sim_cmd_gen = g->user_sim_cmd_gen; } + + u32 old_flags = g->user_sim_cmd_control.flags; + g->user_sim_cmd_control = control; + g->user_sim_cmd_control.flags |= old_flags; + g->user_hovered_ent = hovered_ent->key; + Unlock(&lock); + } } -#endif - - //- Create user sim cmd - - { - /* Queue player move cmd */ - f32 move_speed = 1.0f; - //if (g->bind_states[PP_BindKind_Walk].is_held) - if (g->bind_states[PP_BindKind_FullscreenMod].is_held) - { - //const f32 walk_ratio = 0.25f; - const f32 walk_ratio = 0.05f; - move_speed *= walk_ratio; - } - - Vec2 input_move_dir = ZI; - { - for (PP_BindKind bind = 0; bind < (i32)countof(g->bind_states); ++bind) - { - PP_BindState state = g->bind_states[bind]; - - if (!state.is_held && state.num_presses <= 0) - { - continue; - } - - switch (bind) - { - default: break; - - /* Movement */ - case PP_BindKind_MoveUp: - { - input_move_dir.y -= 1; - } break; - - case PP_BindKind_MoveDown: - { - input_move_dir.y += 1; - } break; - - case PP_BindKind_MoveLeft: - { - input_move_dir.x -= 1; - } break; - - case PP_BindKind_MoveRight: - { - input_move_dir.x += 1; - } break; - } - } - - input_move_dir = InvertXformBasisMulV2(g->world_to_ui_xf, input_move_dir); /* Make move dir relative to world view */ - input_move_dir = MulVec2(NormVec2(input_move_dir), move_speed); - } - - if (!g->debug_camera) - { - g->focus_send = SubVec2(g->world_cursor, PP_XformFromEnt(local_control).og); - } - Vec2 input_aim_dir = g->focus_send; - - /* Queue player control cmd */ - { - PP_ControlData control = ZI; - control.move = input_move_dir; - control.focus = input_aim_dir; - control.dbg_cursor = g->world_cursor; - - PP_BindState fire_state = g->bind_states[PP_BindKind_Fire]; - PP_BindState fire_alt_state = g->bind_states[PP_BindKind_AltFire]; - PP_BindState drag_state = g->bind_states[PP_BindKind_DebugDrag]; - PP_BindState delete_state = g->bind_states[PP_BindKind_DebugDelete]; - PP_BindState clear_state = g->bind_states[PP_BindKind_DebugClear]; - PP_BindState spawn1_state = g->bind_states[PP_BindKind_DebugSpawn1]; - PP_BindState spawn2_state = g->bind_states[PP_BindKind_DebugSpawn2]; - PP_BindState spawn3_state = g->bind_states[PP_BindKind_DebugSpawn3]; - PP_BindState spawn4_state = g->bind_states[PP_BindKind_DebugSpawn4]; - PP_BindState walls_state = g->bind_states[PP_BindKind_DebugWalls]; - PP_BindState pause_state = g->bind_states[PP_BindKind_DebugPause]; - PP_BindState step_state = g->bind_states[PP_BindKind_DebugStep]; - PP_BindState tile_state = g->bind_states[PP_BindKind_TestTile]; - PP_BindState explode_state = g->bind_states[PP_BindKind_DebugExplode]; - PP_BindState teleport_state = g->bind_states[PP_BindKind_DebugTeleport]; - - if (fire_state.num_presses || fire_state.is_held) - { - control.flags |= PP_ControlFlag_Fire; - } - if (fire_alt_state.num_presses || fire_alt_state.is_held) - { - control.flags |= PP_ControlFlag_AltFire; - } - if (drag_state.num_presses || drag_state.is_held) - { - control.flags |= PP_ControlFlag_Drag; - } - if (delete_state.num_presses || delete_state.is_held) - { - control.flags |= PP_ControlFlag_Delete; - } - if (clear_state.num_presses_and_repeats) - { - control.flags |= PP_ControlFlag_ClearAll; - } - if (spawn1_state.num_presses_and_repeats) - { - control.flags |= PP_ControlFlag_SpawnTest1; - } - if (spawn2_state.num_presses_and_repeats) - { - control.flags |= PP_ControlFlag_SpawnTest2; - } - if (spawn3_state.num_presses_and_repeats) - { - control.flags |= PP_ControlFlag_SpawnTest3; - } - if (spawn4_state.num_presses_and_repeats) - { - control.flags |= PP_ControlFlag_SpawnTest4; - } - if (walls_state.num_presses_and_repeats) - { - control.flags |= PP_ControlFlag_TestWalls; - } - if (tile_state.num_presses || tile_state.is_held) - { - control.flags |= PP_ControlFlag_TestTiles; - } - if (explode_state.num_presses_and_repeats) - { - control.flags |= PP_ControlFlag_TestExplode; - } - if (teleport_state.num_presses_and_repeats || (g->debug_camera && teleport_state.is_held)) - { - control.flags |= PP_ControlFlag_TestTeleport; - } - - if (pause_state.num_presses) - { - Atomic32FetchXor(&g->user_paused, 1); - } - Atomic32FetchAdd(&g->user_paused_steps, step_state.num_presses_and_repeats); - - /* Set user sim control */ - { - Lock lock = LockE(&g->user_sim_cmd_mutex); - - /* Reset flags */ - if (g->user_sim_cmd_gen != g->last_user_sim_cmd_gen) - { - g->user_sim_cmd_control.flags = 0; - g->last_user_sim_cmd_gen = g->user_sim_cmd_gen; - } - - u32 old_flags = g->user_sim_cmd_control.flags; - g->user_sim_cmd_control = control; - g->user_sim_cmd_control.flags |= old_flags; - g->user_hovered_ent = hovered_ent->key; - Unlock(&lock); - } - } #if IsRtcEnabled - /* Gjk steps */ - { - if (g->bind_states[PP_BindKind_ResetDebugSteps].num_presses_and_repeats > 0) - { - SetGstat(GSTAT_DEBUG_STEPS, 0); - } - i32 add_steps = 0; - add_steps += g->bind_states[PP_BindKind_IncrementDebugSteps].num_presses_and_repeats; - add_steps -= g->bind_states[PP_BindKind_DecrementDebugSteps].num_presses_and_repeats; - if (add_steps != 0) - { - AddGstat(GSTAT_DEBUG_STEPS, add_steps); - } - } -#endif - } - + /* Gjk steps */ { - /* Update network usage stats */ - i64 stat_now_ns = TimeNs(); - g->net_bytes_read.last_second_end = GetGstat(GSTAT_SOCK_BYTES_RECEIVED); - g->net_bytes_sent.last_second_end = GetGstat(GSTAT_SOCK_BYTES_SENT); - if (stat_now_ns - g->last_second_reset_ns > NsFromSeconds(1)) - { - g->last_second_reset_ns = stat_now_ns; - g->net_bytes_read.last_second = g->net_bytes_read.last_second_end - g->net_bytes_read.last_second_start; - g->net_bytes_sent.last_second = g->net_bytes_sent.last_second_end - g->net_bytes_sent.last_second_start; - g->net_bytes_read.last_second_start = g->net_bytes_read.last_second_end; - g->net_bytes_sent.last_second_start = g->net_bytes_sent.last_second_end; - } + if (g->bind_states[PP_BindKind_ResetDebugSteps].num_presses_and_repeats > 0) + { + SetGstat(GSTAT_DEBUG_STEPS, 0); + } + i32 add_steps = 0; + add_steps += g->bind_states[PP_BindKind_IncrementDebugSteps].num_presses_and_repeats; + add_steps -= g->bind_states[PP_BindKind_DecrementDebugSteps].num_presses_and_repeats; + if (add_steps != 0) + { + AddGstat(GSTAT_DEBUG_STEPS, add_steps); + } } +#endif + } - //- Draw ent debug info - /* FIXME: Enable this */ + { + /* Update network usage stats */ + i64 stat_now_ns = TimeNs(); + g->net_bytes_read.last_second_end = GetGstat(GSTAT_SOCK_BYTES_RECEIVED); + g->net_bytes_sent.last_second_end = GetGstat(GSTAT_SOCK_BYTES_SENT); + if (stat_now_ns - g->last_second_reset_ns > NsFromSeconds(1)) + { + g->last_second_reset_ns = stat_now_ns; + g->net_bytes_read.last_second = g->net_bytes_read.last_second_end - g->net_bytes_read.last_second_start; + g->net_bytes_sent.last_second = g->net_bytes_sent.last_second_end - g->net_bytes_sent.last_second_start; + g->net_bytes_read.last_second_start = g->net_bytes_read.last_second_end; + g->net_bytes_sent.last_second_start = g->net_bytes_sent.last_second_end; + } + } + + //- Draw ent debug info + /* FIXME: Enable this */ #if 0 - if (g->debug_draw && hovered_ent->valid) + if (g->debug_draw && hovered_ent->valid) + { + PP_Ent *ent = hovered_ent; + + Vec2 pos = AddVec2(g->ui_cursor, VEC2(15, 15)); + F_Font *font = F_LoadFontAsync(ResourceKeyFromStore(&PP_Resources, Lit("font/fixedsys.ttf")), 12.0f); + if (font) { - PP_Ent *ent = hovered_ent; + TempArena temp = BeginTempArena(scratch.arena); - Vec2 pos = AddVec2(g->ui_cursor, VEC2(15, 15)); - F_Font *font = F_LoadFontAsync(ResourceKeyFromStore(&PP_Resources, Lit("font/fixedsys.ttf")), 12.0f); - if (font) - { - TempArena temp = BeginTempArena(scratch.arena); + String dbg_text = ZI; + dbg_text.text = PushDry(temp.arena, u8); + dbg_text.len += PP_DebugStringFromEnt(temp.arena, ent).len; + draw_text(g->render_sig, D_TEXTPARAMS(.font = font, .pos = pos, .str = dbg_text)); - String dbg_text = ZI; - dbg_text.text = PushDry(temp.arena, u8); - dbg_text.len += PP_DebugStringFromEnt(temp.arena, ent).len; - draw_text(g->render_sig, D_TEXTPARAMS(.font = font, .pos = pos, .str = dbg_text)); - - EndTempArena(temp); - } + EndTempArena(temp); } + } #endif - ////////////////////////////// - //- Debug draw + ////////////////////////////// + //- Debug draw - GPU_Stats gpu_stats = GPU_QueryStats(); + GPU_Stats gpu_stats = GPU_QueryStats(); - /* Draw console */ - UI_Box *console_box = 0; + /* Draw console */ + UI_Box *console_box = 0; + { + b32 console_minimized = !g->debug_console; + console_box = PP_BuildDebugConsole(console_minimized); + } + + /* Draw lister */ + if (g->lister_active) + { + UI_PushCP(pp_root_box); { - b32 console_minimized = !g->debug_console; - console_box = PP_BuildDebugConsole(console_minimized); - } + UI_Push(Tag, HashF("lister")); + UI_Key titlebar_key = UI_KeyF("lister title bar"); - /* Draw lister */ - if (g->lister_active) - { - UI_PushCP(pp_root_box); + u32 base_background_color = 0xff1a1d1e; + u32 base_border_color = 0xff343a3b; + + f32 window_border = 1; + f32 window_width = 300; + u32 window_background_color = base_background_color; + u32 window_border_color = base_border_color; + u32 titlebar_color = 0; + u32 titlebar_border_color = 0; + u32 divider_color = base_border_color; + { + UI_Report rep = UI_ReportFromKey(titlebar_key); + if (rep.m1_held) { - UI_Push(Tag, HashF("lister")); - UI_Key titlebar_key = UI_KeyF("lister title bar"); - - u32 base_background_color = 0xff1a1d1e; - u32 base_border_color = 0xff343a3b; - - f32 window_border = 1; - f32 window_width = 300; - u32 window_background_color = base_background_color; - u32 window_border_color = base_border_color; - u32 titlebar_color = 0; - u32 titlebar_border_color = 0; - u32 divider_color = base_border_color; - { - UI_Report rep = UI_ReportFromKey(titlebar_key); - if (rep.m1_held) - { - g->lister_pos = SubVec2(g->ui_cursor, rep.last_m1_offset); - } - { - window_border_color = BlendSrgbU32(window_border_color, Rgb32F(0.5, 0.5, 0.5), rep.hot); - } - } - - UI_Push(BackgroundColor, window_background_color); - UI_Push(BorderColor, window_border_color); - UI_Push(Border, window_border); - // UI_Push(Rounding, UI_RPIX(15)); - UI_Push(Rounding, UI_RPIX(15)); - UI_Push(Width, UI_PIX(window_width, 0)); - UI_Push(Height, UI_FIT(0)); - UI_Push(ChildLayoutAxis, Axis_Y); - UI_Push(FloatingPos, g->lister_pos); - UI_SetNext(Flags, UI_BoxFlag_Floating); - UI_PushCP(UI_BuildBox(UI_KeyF("lister"))); - { - /* Title bar */ - UI_PushCP(0); - { - UI_Push(BackgroundColor, titlebar_color); - UI_Push(BorderColor, titlebar_border_color); - UI_Push(Rounding, UI_RPIX(0)); - UI_Push(ChildLayoutAxis, Axis_X); - UI_Push(Width, UI_FILL(1, 0)); - UI_Push(Height, UI_FNT(2, 1)); - UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); - UI_PushCP(UI_BuildBox(titlebar_key)); - { - UI_Push(Width, UI_FILL(1, 0)); - UI_Push(BorderColor, 0); - - /* Left title box */ - UI_BuildRow(UI_NilKey); - - /* Title box */ - UI_SetNext(ChildAlignment, UI_Alignment_Center); - UI_SetNext(Width, UI_FIT(1)); - UI_SetNext(Text, Lit("Titleeeeeeeeeeeeeee")); - UI_SetNext(Flags, UI_BoxFlag_DrawText); - UI_BuildBox(UI_NilKey); - - /* Right title box */ - UI_BuildRow(UI_NilKey); - } - UI_PopCP(); - } - UI_PopCP(); - } - - UI_SetNext(Tint, 0); - UI_SetNext(Rounding, 0); - UI_PushCP(UI_BuildRow(UI_NilKey)); - { - f32 padding = window_border; - UI_BuildSpacer(UI_PIX(padding, 1)); - { - UI_SetNext(Tint, 0); - UI_SetNext(Rounding, 0); - UI_SetNext(Width, UI_FILL(1, 0)); - UI_PushCP(UI_BuildColumn(UI_NilKey)); - { - u32 count = 10; - for (u32 i = 0; i < count; ++i) - { - UI_BuildDivider(UI_PIX(1, 1), divider_color); - - UI_Key btn_key = UI_KeyF("btn%F", FmtSint(i)); - UI_Report rep = UI_ReportFromKey(btn_key); - - u32 hovered_color = Rgb32(0x10, 0x3c, 0x4c); - u32 pressed_color = Alpha32F(hovered_color, 0.25); - - f32 hot = rep.hot; - f32 active = rep.active; - f32 hovered = rep.hovered; - - u32 color = 0; - u32 border_color = 0; - color = BlendSrgbU32(color, hovered_color, hot); - color = BlendSrgbU32(color, pressed_color, active * hovered); - border_color = BlendSrgbU32(border_color, Rgb32(0x00, 0x79, 0xa6), hot); - - String button_text = UI_StringF("Button %F", FmtSint(i)); - - UI_SetNext(BorderColor, border_color); - UI_SetNext(BackgroundColor, color); - UI_SetNext(Rounding, UI_RPIX(5)); - UI_SetNext(Width, UI_FILL(1, 0)); - UI_SetNext(Height, UI_FNT(1.5, 1)); - UI_SetNext(Text, button_text); - UI_SetNext(ChildAlignment, UI_Alignment_Center); - UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); - UI_BuildBox(btn_key); - - if (rep.m1_presses) - { - LogInfoF("%F pressed", FmtString(button_text)); - } - } - UI_BuildSpacer(UI_PIX(padding, 1)); - } - UI_PopCP(); - } - UI_BuildSpacer(UI_PIX(padding, 1)); - } - UI_PopCP(); - - - - UI_PopCP(); + g->lister_pos = SubVec2(g->ui_cursor, rep.last_m1_offset); } - UI_PopCP(); - } - - /* Draw debug info */ - if (g->debug_draw) - { - __profn("Draw debug info"); - - UI_BuildSpacer(UI_FILL(1, 0)); - - UI_SetNext(ChildLayoutAxis, Axis_Y); - UI_SetNext(BackgroundColor, 0); - UI_SetNext(BorderColor, 0); - UI_SetNext(Width, UI_FIT(1)); - UI_SetNext(Height, UI_FIT(1)); - UI_SetNext(Tint, 0); - UI_PushCP(UI_BuildBox(UI_KeyF("dbg"))); { - UI_Push(BackgroundColor, 0); + window_border_color = BlendSrgbU32(window_border_color, Rgb32F(0.5, 0.5, 0.5), rep.hot); + } + } + + UI_Push(BackgroundColor, window_background_color); + UI_Push(BorderColor, window_border_color); + UI_Push(Border, window_border); + // UI_Push(Rounding, UI_RPIX(15)); + UI_Push(Rounding, UI_RPIX(15)); + UI_Push(Width, UI_PIX(window_width, 0)); + UI_Push(Height, UI_FIT(0)); + UI_Push(ChildLayoutAxis, Axis_Y); + UI_Push(FloatingPos, g->lister_pos); + UI_SetNext(Flags, UI_BoxFlag_Floating); + UI_PushCP(UI_BuildBox(UI_KeyF("lister"))); + { + /* Title bar */ + UI_PushCP(0); + { + UI_Push(BackgroundColor, titlebar_color); + UI_Push(BorderColor, titlebar_border_color); + UI_Push(Rounding, UI_RPIX(0)); + UI_Push(ChildLayoutAxis, Axis_X); + UI_Push(Width, UI_FILL(1, 0)); + UI_Push(Height, UI_FNT(2, 1)); + UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); + UI_PushCP(UI_BuildBox(titlebar_key)); + { + UI_Push(Width, UI_FILL(1, 0)); UI_Push(BorderColor, 0); - UI_BuildLabelF("Blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved)); - UI_BuildLabelF("Blended world tick: %F", FmtUint(g->ss_blended->tick)); + /* Left title box */ + UI_BuildRow(UI_NilKey); - UI_BuildLabelF("Blended world time: %F", FmtFloat(SecondsFromNs(g->ss_blended->sim_time_ns))); - UI_BuildSpacer(UI_FNT(1, 0)); + /* Title box */ + UI_SetNext(ChildAlignment, UI_Alignment_Center); + UI_SetNext(Width, UI_FIT(1)); + UI_SetNext(Text, Lit("Titleeeeeeeeeeeeeee")); + UI_SetNext(Flags, UI_BoxFlag_DrawText); + UI_BuildBox(UI_NilKey); - UI_BuildLabelF("Average local sim publish dt: %F", FmtFloat(SecondsFromNs(g->average_local_to_user_snapshot_publish_dt_ns))); - UI_BuildLabelF("Local sim last known tick: %F", FmtUint(g->local_sim_last_known_tick)); - UI_BuildLabelF("Local sim last known time: %F", FmtFloat(SecondsFromNs(g->local_sim_last_known_time_ns))); - UI_BuildLabelF("Local sim predicted time: %F", FmtFloat(SecondsFromNs(g->local_sim_predicted_time_ns))); - UI_BuildLabelF("Render time target: %F", FmtFloat(SecondsFromNs(g->render_time_target_ns))); - - UI_BuildLabelF("Render time: %F", FmtFloat(SecondsFromNs(g->render_time_ns))); - - UI_BuildLabelF("Local player: [%F]", FmtUid(local_player->key.uid)); - UI_BuildSpacer(UI_FNT(1, 0)); - - Vec2 world_cursor = g->world_cursor; - UI_BuildLabelF("Cursor world: %F, %F", FmtFloat(world_cursor.x), FmtFloat(world_cursor.y)); - - Vec2I32 world_tile_cursor = PP_WorldTileIndexFromPos(world_cursor); - UI_BuildLabelF("Cursor world tile: %F, %F", FmtSint(world_tile_cursor.x), FmtSint(world_tile_cursor.y)); - - Vec2I32 local_tile_cursor = PP_LocalTileIndexFromWorldTileIndex(world_tile_cursor); - UI_BuildLabelF("Cursor local tile: %F, %F", FmtSint(local_tile_cursor.x), FmtSint(local_tile_cursor.y)); - - Vec2I32 tile_chunk_cursor = PP_TileChunkIndexFromWorldTileIndex(world_tile_cursor); - UI_BuildLabelF("Cursor tile chunk: %F, %F", FmtSint(tile_chunk_cursor.x), FmtSint(tile_chunk_cursor.y)); - UI_BuildSpacer(UI_FNT(1, 0)); - - UI_BuildLabelF("Network read: %F mbit/s", FmtFloat((f64)g->net_bytes_read.last_second * 8 / 1000 / 1000)); - - UI_BuildLabelF("Network write: %F mbit/s", FmtFloat((f64)g->net_bytes_sent.last_second * 8 / 1000 / 1000)); - - UI_BuildLabelF("Ping (real): %F ms", FmtFloat(SecondsFromNs(local_player->player_last_rtt_ns) * 1000)); - - UI_BuildLabelF("Ping (average): %F ms", FmtFloat(local_player->player_average_rtt_seconds * 1000)); - UI_BuildSpacer(UI_FNT(1, 0)); - - UI_BuildLabelF("Memory committed: %F MiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_COMMITTED) / 1024 / 1024)); - - UI_BuildLabelF("Virtual memory reserved: %F TiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_RESERVED) / 1024 / 1024 / 1024 / 1024)); - - UI_BuildLabelF("Arenas allocated: %F", FmtUint(GetGstat(GSTAT_NUM_ARENAS))); - UI_BuildSpacer(UI_FNT(1, 0)); - - UI_BuildLabelF("GPU dedicated memory usage: %F MiB", FmtFloat((f64)gpu_stats.local_committed / 1024 / 1024)); - UI_BuildLabelF("GPU shared memory usage: %F MiB", FmtFloat((f64)gpu_stats.non_local_committed / 1024 / 1024)); - UI_BuildSpacer(UI_FNT(1, 0)); - - UI_BuildLabelF("GPU resources: %F", FmtUint(gpu_stats.driver_resources_allocated)); - UI_BuildLabelF("GPU descriptors: %F", FmtUint(gpu_stats.driver_descriptors_allocated)); - //UI_BuildLabelF(\n")); - //UI_BuildLabelF(\n")); - -#if IsRtcEnabled - UI_BuildSpacer(UI_FNT(1, 0)); - UI_BuildLabelF("Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS))); - //UI_BuildLabelF(\n")); -#endif + /* Right title box */ + UI_BuildRow(UI_NilKey); + } + UI_PopCP(); } UI_PopCP(); + } + + UI_SetNext(Tint, 0); + UI_SetNext(Rounding, 0); + UI_PushCP(UI_BuildRow(UI_NilKey)); + { + f32 padding = window_border; + UI_BuildSpacer(UI_PIX(padding, 1)); + { + UI_SetNext(Tint, 0); + UI_SetNext(Rounding, 0); + UI_SetNext(Width, UI_FILL(1, 0)); + UI_PushCP(UI_BuildColumn(UI_NilKey)); + { + u32 count = 10; + for (u32 i = 0; i < count; ++i) + { + UI_BuildDivider(UI_PIX(1, 1), divider_color); + + UI_Key btn_key = UI_KeyF("btn%F", FmtSint(i)); + UI_Report rep = UI_ReportFromKey(btn_key); + + u32 hovered_color = Rgb32(0x10, 0x3c, 0x4c); + u32 pressed_color = Alpha32F(hovered_color, 0.25); + + f32 hot = rep.hot; + f32 active = rep.active; + f32 hovered = rep.hovered; + + u32 color = 0; + u32 border_color = 0; + color = BlendSrgbU32(color, hovered_color, hot); + color = BlendSrgbU32(color, pressed_color, active * hovered); + border_color = BlendSrgbU32(border_color, Rgb32(0x00, 0x79, 0xa6), hot); + + String button_text = UI_StringF("Button %F", FmtSint(i)); + + UI_SetNext(BorderColor, border_color); + UI_SetNext(BackgroundColor, color); + UI_SetNext(Rounding, UI_RPIX(5)); + UI_SetNext(Width, UI_FILL(1, 0)); + UI_SetNext(Height, UI_FNT(1.5, 1)); + UI_SetNext(Text, button_text); + UI_SetNext(ChildAlignment, UI_Alignment_Center); + UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); + UI_BuildBox(btn_key); + + if (rep.m1_presses) + { + LogInfoF("%F pressed", FmtString(button_text)); + } + } + UI_BuildSpacer(UI_PIX(padding, 1)); + } + UI_PopCP(); + } + UI_BuildSpacer(UI_PIX(padding, 1)); + } + UI_PopCP(); + + + + UI_PopCP(); } + UI_PopCP(); + } - ////////////////////////////// - //- Render + /* Draw debug info */ + if (g->debug_draw) + { + __profn("Draw debug info"); - Rect ui_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->ui_size.x, g->ui_size.y)); - Rect render_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->render_size.x, g->render_size.y)); - GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct; - Fence *submit_fence = GPU_FenceFromQueue(gpu_render_queue); + UI_BuildSpacer(UI_FILL(1, 0)); + + UI_SetNext(ChildLayoutAxis, Axis_Y); + UI_SetNext(BackgroundColor, 0); + UI_SetNext(BorderColor, 0); + UI_SetNext(Width, UI_FIT(1)); + UI_SetNext(Height, UI_FIT(1)); + UI_SetNext(Tint, 0); + UI_PushCP(UI_BuildBox(UI_KeyF("dbg"))); { - __profn("Render"); + UI_Push(BackgroundColor, 0); + UI_Push(BorderColor, 0); + UI_BuildLabelF("Blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved)); + UI_BuildLabelF("Blended world tick: %F", FmtUint(g->ss_blended->tick)); - /* Acquire gbuffers */ - if (g->shade_target && !EqVec2I32(g->render_size, GPU_GetTextureSize2D(g->shade_target))) - { - __profn("Release render resources"); - YieldOnFence(submit_fence, g->gpu_submit_fence_target); - GPU_ReleaseResource(g->albedo, GPU_ReleaseFlag_None); - GPU_ReleaseResource(g->emittance, GPU_ReleaseFlag_None); - GPU_ReleaseResource(g->emittance_flood_read, GPU_ReleaseFlag_None); - GPU_ReleaseResource(g->emittance_flood_target, GPU_ReleaseFlag_None); - GPU_ReleaseResource(g->shade_read, GPU_ReleaseFlag_None); - GPU_ReleaseResource(g->shade_target, GPU_ReleaseFlag_None); - g->shade_target = 0; - } - if (!g->shade_target) - { - __profn("Acquire sig resources"); - g->albedo = PP_AcquireGbuffer(GPU_Format_R8G8B8A8_Unorm, g->render_size); - g->emittance = PP_AcquireGbuffer(GPU_Format_R16G16B16A16_Float, g->render_size); - g->emittance_flood_read = PP_AcquireGbuffer(GPU_Format_R16G16_Uint, g->render_size); - g->emittance_flood_target = PP_AcquireGbuffer(GPU_Format_R16G16_Uint, g->render_size); - g->shade_read = PP_AcquireGbuffer(GPU_Format_R16G16B16A16_Float, g->render_size); - g->shade_target = PP_AcquireGbuffer(GPU_Format_R16G16B16A16_Float, g->render_size); - } + UI_BuildLabelF("Blended world time: %F", FmtFloat(SecondsFromNs(g->ss_blended->sim_time_ns))); + UI_BuildSpacer(UI_FNT(1, 0)); - /* Upload transient buffers */ - GPU_Resource *material_instances_buffer = GPU_UploadTransientBufferFromArena(&g->material_instances_tbuff, g->material_instances_arena); - GPU_Resource *grids_buffer = GPU_UploadTransientBufferFromArena(&g->grids_tbuff, g->grids_arena); - u64 material_instances_count = GPU_GetBufferCount(material_instances_buffer); - u64 grids_count = GPU_GetBufferCount(grids_buffer); + UI_BuildLabelF("Average local sim publish dt: %F", FmtFloat(SecondsFromNs(g->average_local_to_user_snapshot_publish_dt_ns))); + UI_BuildLabelF("Local sim last known tick: %F", FmtUint(g->local_sim_last_known_tick)); + UI_BuildLabelF("Local sim last known time: %F", FmtFloat(SecondsFromNs(g->local_sim_last_known_time_ns))); + UI_BuildLabelF("Local sim predicted time: %F", FmtFloat(SecondsFromNs(g->local_sim_predicted_time_ns))); + UI_BuildLabelF("Render time target: %F", FmtFloat(SecondsFromNs(g->render_time_target_ns))); - GPU_CommandList *cl = GPU_BeginCommandList(gpu_render_queue); - { - __profn("Run render"); - GPU_ProfN(cl, Lit("Run render")); - Mat4x4 world_to_render_vp_matrix = ProjectMat4x4View(g->world_to_render_xf, render_viewport.width, render_viewport.height); - Mat4x4 ui_vp_matrix = ProjectMat4x4View(XformIdentity, ui_viewport.width, ui_viewport.height); - Mat4x4 blit_vp_matrix = ZI; - { - Xform xf = g->render_to_ui_xf; - xf = ScaleXform(xf, VEC2(g->render_size.x, g->render_size.y)); - xf = TranslateXform(xf, VEC2(0.5, 0.5)); - blit_vp_matrix = ProjectMat4x4View(xf, ui_viewport.width, ui_viewport.height); - } + UI_BuildLabelF("Render time: %F", FmtFloat(SecondsFromNs(g->render_time_ns))); - //- Prep material pass - { - __profn("Clear gbuffers"); - GPU_ProfN(cl, Lit("Clear gbuffers")); - GPU_TransitionToRenderable(cl, g->albedo, 0); - GPU_TransitionToRenderable(cl, g->emittance, 1); - GPU_ClearRenderable(cl, g->albedo); - GPU_ClearRenderable(cl, g->emittance); - } + UI_BuildLabelF("Local player: [%F]", FmtUid(local_player->key.uid)); + UI_BuildSpacer(UI_FNT(1, 0)); - //- Material pass - if (material_instances_count > 0) - { - __profn("Material pass"); - GPU_ProfN(cl, Lit("Material pass")); + Vec2 world_cursor = g->world_cursor; + UI_BuildLabelF("Cursor world: %F, %F", FmtFloat(world_cursor.x), FmtFloat(world_cursor.y)); - GPU_Viewport viewport = GPU_ViewportFromRect(render_viewport); - GPU_Scissor scissor = GPU_ScissorFromRect(render_viewport); + Vec2I32 world_tile_cursor = PP_WorldTileIndexFromPos(world_cursor); + UI_BuildLabelF("Cursor world tile: %F, %F", FmtSint(world_tile_cursor.x), FmtSint(world_tile_cursor.y)); - PP_MaterialSig sig = ZI; - sig.projection = world_to_render_vp_matrix; - sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler()); - sig.instances = GPU_StructuredBufferRidFromResource(material_instances_buffer); - sig.grids = GPU_StructuredBufferRidFromResource(grids_buffer); - GPU_Rasterize( - cl, - &sig, - PP_MaterialVS, PP_MaterialPS, - 2, - viewport, - scissor, - material_instances_count, - GPU_GetCommonQuadIndices(), - GPU_RasterizeMode_TriangleList - ); - } + Vec2I32 local_tile_cursor = PP_LocalTileIndexFromWorldTileIndex(world_tile_cursor); + UI_BuildLabelF("Cursor local tile: %F, %F", FmtSint(local_tile_cursor.x), FmtSint(local_tile_cursor.y)); - //- Prep flood pass - { - GPU_TransitionToReadable(cl, g->emittance); - GPU_TransitionToWritable(cl, g->emittance_flood_read); - GPU_TransitionToWritable(cl, g->emittance_flood_target); - } + Vec2I32 tile_chunk_cursor = PP_TileChunkIndexFromWorldTileIndex(world_tile_cursor); + UI_BuildLabelF("Cursor tile chunk: %F, %F", FmtSint(tile_chunk_cursor.x), FmtSint(tile_chunk_cursor.y)); + UI_BuildSpacer(UI_FNT(1, 0)); - //- Flood pass - if (!effects_disabled) - { - __profn("Flood pass"); - GPU_ProfN(cl, Lit("Flood pass")); + UI_BuildLabelF("Network read: %F mbit/s", FmtFloat((f64)g->net_bytes_read.last_second * 8 / 1000 / 1000)); - i32 step_length = -1; + UI_BuildLabelF("Network write: %F mbit/s", FmtFloat((f64)g->net_bytes_sent.last_second * 8 / 1000 / 1000)); - /* TODO: Remove this */ - u64 max_steps = GetGstat(GSTAT_DEBUG_STEPS); - u64 step = 0; - while (step_length != 0 && step < max_steps) - { - __profn("Flood step"); - GPU_ProfN(cl, Lit("Flood step")); + UI_BuildLabelF("Ping (real): %F ms", FmtFloat(SecondsFromNs(local_player->player_last_rtt_ns) * 1000)); - GPU_FlushWritable(cl, g->emittance_flood_read); + UI_BuildLabelF("Ping (average): %F ms", FmtFloat(local_player->player_average_rtt_seconds * 1000)); + UI_BuildSpacer(UI_FNT(1, 0)); - PP_FloodSig sig = ZI; - sig.step_len = step_length; - sig.emittance = GPU_Texture2DRidFromResource(g->emittance); - sig.read = GPU_RWTexture2DRidFromResource(g->emittance_flood_read); - sig.target = GPU_RWTexture2DRidFromResource(g->emittance_flood_target); - sig.tex_width = g->render_size.x; - sig.tex_height = g->render_size.y; - GPU_Compute(cl, &sig, PP_FloodCS, (g->render_size.x + 7) / 8, (g->render_size.y + 7) / 8, 1); + UI_BuildLabelF("Memory committed: %F MiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_COMMITTED) / 1024 / 1024)); - /* Swap buffers */ - GPU_Resource *swp = g->emittance_flood_read; - g->emittance_flood_read = g->emittance_flood_target; - g->emittance_flood_target = swp; + UI_BuildLabelF("Virtual memory reserved: %F TiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_RESERVED) / 1024 / 1024 / 1024 / 1024)); - /* Update step */ - if (step_length == -1) - { - step_length = MaxI32(g->render_size.x, g->render_size.y) / 2; - } - else - { - step_length /= 2; - } - ++step; - } - } + UI_BuildLabelF("Arenas allocated: %F", FmtUint(GetGstat(GSTAT_NUM_ARENAS))); + UI_BuildSpacer(UI_FNT(1, 0)); - //- Prep shade pass - { - __profn("Clear shade target"); - GPU_ProfN(cl, Lit("Clear shade target")); - GPU_TransitionToReadable(cl, g->albedo); - GPU_TransitionToReadable(cl, g->emittance); - GPU_TransitionToWritable(cl, g->shade_target); - GPU_FlushWritable(cl, g->emittance_flood_read); - GPU_FlushWritable(cl, g->shade_read); - } + UI_BuildLabelF("GPU dedicated memory usage: %F MiB", FmtFloat((f64)gpu_stats.local_committed / 1024 / 1024)); + UI_BuildLabelF("GPU shared memory usage: %F MiB", FmtFloat((f64)gpu_stats.non_local_committed / 1024 / 1024)); + UI_BuildSpacer(UI_FNT(1, 0)); - //- Shade pass - { - __profn("Shade pass"); - GPU_ProfN(cl, Lit("Shade pass")); - Vec3I32 noise_size = GPU_GetTextureSize3D(GPU_GetCommonNoise()); + UI_BuildLabelF("GPU resources: %F", FmtUint(gpu_stats.driver_resources_allocated)); + UI_BuildLabelF("GPU descriptors: %F", FmtUint(gpu_stats.driver_descriptors_allocated)); + //UI_BuildLabelF(\n")); + //UI_BuildLabelF(\n")); - u32 shade_flags = PP_ShadeFlag_None | PP_ShadeFlag_ToneMap; - if (effects_disabled) - { - shade_flags |= PP_ShadeFlag_DisableEffects; - } - - PP_ShadeSig sig = ZI; - sig.flags = shade_flags; - sig.tex_width = g->render_size.x; - sig.tex_height = g->render_size.y; - sig.exposure = 2.0; - sig.frame_seed = VEC4U32( - (u32)(RandU64FromState(&g->frame_rand) & 0xFFFFFFFF), - (u32)(RandU64FromState(&g->frame_rand) & 0xFFFFFFFF), - (u32)(RandU64FromState(&g->frame_rand) & 0xFFFFFFFF), - (u32)(RandU64FromState(&g->frame_rand) & 0xFFFFFFFF) - ); - sig.frame_index = g->frame_index; - sig.camera_offset = g->world_to_render_xf.og; - sig.noise = GPU_Texture3DRidFromResource(GPU_GetCommonNoise()); - sig.albedo = GPU_Texture2DRidFromResource(g->albedo); - sig.emittance = GPU_Texture2DRidFromResource(g->emittance); - sig.emittance_flood = GPU_Texture2DRidFromResource(g->emittance_flood_read); - sig.read = GPU_Texture2DRidFromResource(g->shade_read); - sig.target = GPU_RWTexture2DRidFromResource(g->shade_target); - sig.noise_tex_width = noise_size.x; - sig.noise_tex_height = noise_size.y; - sig.noise_tex_depth = noise_size.z; - GPU_Compute(cl, &sig, PP_ShadeCS, (g->render_size.x + 7) / 8, (g->render_size.y + 7) / 8, 1); - - /* Swap */ - GPU_Resource *swp = g->shade_read; - g->shade_read = g->shade_target; - g->shade_target = swp; - } - - //- Transition target to readable before UI pass - GPU_TransitionToReadable(cl, g->shade_read); - GPU_TransitionToReadable(cl, g->shade_target); - } - g->gpu_submit_fence_target = GPU_EndCommandList(cl); - - /* Reset render data */ - GPU_ResetTransientBuffer(&g->material_instances_tbuff, g->gpu_submit_fence_target); - GPU_ResetTransientBuffer(&g->grids_tbuff, g->gpu_submit_fence_target); - ResetArena(g->material_instances_arena); - ResetArena(g->grids_arena); +#if IsRtcEnabled + UI_BuildSpacer(UI_FNT(1, 0)); + UI_BuildLabelF("Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS))); + //UI_BuildLabelF(\n")); +#endif } + UI_PopCP(); + } - /* Set root background texture to game texture */ + ////////////////////////////// + //- Render + + Rect ui_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->ui_size.x, g->ui_size.y)); + Rect render_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->render_size.x, g->render_size.y)); + GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct; + Fence *submit_fence = GPU_FenceFromQueue(gpu_render_queue); + { + __profn("Render"); + + + /* Acquire gbuffers */ + if (g->shade_target && !EqVec2I32(g->render_size, GPU_GetTextureSize2D(g->shade_target))) { - Xform ui_to_render_xf = InvertXform(g->render_to_ui_xf); - Vec2 p0 = MulXformV2(ui_to_render_xf, VEC2(0, 0)); - Vec2 p1 = MulXformV2(ui_to_render_xf, Vec2FromFields(g->ui_size)); - Vec2 uv0 = DivVec2Vec2(p0, Vec2FromFields(g->render_size)); - Vec2 uv1 = DivVec2Vec2(p1, Vec2FromFields(g->render_size)); - UI_SetBackgroundTexture(pp_root_box, g->shade_read, uv0, uv1); + __profn("Release render resources"); + YieldOnFence(submit_fence, g->gpu_submit_fence_target); + GPU_ReleaseResource(g->albedo, GPU_ReleaseFlag_None); + GPU_ReleaseResource(g->emittance, GPU_ReleaseFlag_None); + GPU_ReleaseResource(g->emittance_flood_read, GPU_ReleaseFlag_None); + GPU_ReleaseResource(g->emittance_flood_target, GPU_ReleaseFlag_None); + GPU_ReleaseResource(g->shade_read, GPU_ReleaseFlag_None); + GPU_ReleaseResource(g->shade_target, GPU_ReleaseFlag_None); + g->shade_target = 0; + } + if (!g->shade_target) + { + __profn("Acquire sig resources"); + g->albedo = PP_AcquireGbuffer(GPU_Format_R8G8B8A8_Unorm, g->render_size); + g->emittance = PP_AcquireGbuffer(GPU_Format_R16G16B16A16_Float, g->render_size); + g->emittance_flood_read = PP_AcquireGbuffer(GPU_Format_R16G16_Uint, g->render_size); + g->emittance_flood_target = PP_AcquireGbuffer(GPU_Format_R16G16_Uint, g->render_size); + g->shade_read = PP_AcquireGbuffer(GPU_Format_R16G16B16A16_Float, g->render_size); + g->shade_target = PP_AcquireGbuffer(GPU_Format_R16G16B16A16_Float, g->render_size); } - ////////////////////////////// - //- End frame + /* Upload transient buffers */ + GPU_Resource *material_instances_buffer = GPU_UploadTransientBufferFromArena(&g->material_instances_tbuff, g->material_instances_arena); + GPU_Resource *grids_buffer = GPU_UploadTransientBufferFromArena(&g->grids_tbuff, g->grids_arena); + u64 material_instances_count = GPU_GetBufferCount(material_instances_buffer); + u64 grids_count = GPU_GetBufferCount(grids_buffer); - g->gpu_submit_fence_target = UI_EndFrame(ui_frame); + GPU_CommandList *cl = GPU_BeginCommandList(gpu_render_queue); + { + __profn("Run render"); + GPU_ProfN(cl, Lit("Run render")); + Mat4x4 world_to_render_vp_matrix = ProjectMat4x4View(g->world_to_render_xf, render_viewport.width, render_viewport.height); + Mat4x4 ui_vp_matrix = ProjectMat4x4View(XformIdentity, ui_viewport.width, ui_viewport.height); + Mat4x4 blit_vp_matrix = ZI; + { + Xform xf = g->render_to_ui_xf; + xf = ScaleXform(xf, VEC2(g->render_size.x, g->render_size.y)); + xf = TranslateXform(xf, VEC2(0.5, 0.5)); + blit_vp_matrix = ProjectMat4x4View(xf, ui_viewport.width, ui_viewport.height); + } - ++g->user_tick; - EndScratch(scratch); + //- Prep material pass + { + __profn("Clear gbuffers"); + GPU_ProfN(cl, Lit("Clear gbuffers")); + GPU_TransitionToRenderable(cl, g->albedo, 0); + GPU_TransitionToRenderable(cl, g->emittance, 1); + GPU_ClearRenderable(cl, g->albedo); + GPU_ClearRenderable(cl, g->emittance); + } + + //- Material pass + if (material_instances_count > 0) + { + __profn("Material pass"); + GPU_ProfN(cl, Lit("Material pass")); + + GPU_Viewport viewport = GPU_ViewportFromRect(render_viewport); + GPU_Scissor scissor = GPU_ScissorFromRect(render_viewport); + + PP_MaterialSig sig = ZI; + sig.projection = world_to_render_vp_matrix; + sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler()); + sig.instances = GPU_StructuredBufferRidFromResource(material_instances_buffer); + sig.grids = GPU_StructuredBufferRidFromResource(grids_buffer); + GPU_Rasterize( + cl, + &sig, + PP_MaterialVS, PP_MaterialPS, + 2, + viewport, + scissor, + material_instances_count, + GPU_GetCommonQuadIndices(), + GPU_RasterizeMode_TriangleList + ); + } + + //- Prep flood pass + { + GPU_TransitionToReadable(cl, g->emittance); + GPU_TransitionToWritable(cl, g->emittance_flood_read); + GPU_TransitionToWritable(cl, g->emittance_flood_target); + } + + //- Flood pass + if (!effects_disabled) + { + __profn("Flood pass"); + GPU_ProfN(cl, Lit("Flood pass")); + + i32 step_length = -1; + + /* TODO: Remove this */ + u64 max_steps = GetGstat(GSTAT_DEBUG_STEPS); + u64 step = 0; + while (step_length != 0 && step < max_steps) + { + __profn("Flood step"); + GPU_ProfN(cl, Lit("Flood step")); + + GPU_FlushWritable(cl, g->emittance_flood_read); + + PP_FloodSig sig = ZI; + sig.step_len = step_length; + sig.emittance = GPU_Texture2DRidFromResource(g->emittance); + sig.read = GPU_RWTexture2DRidFromResource(g->emittance_flood_read); + sig.target = GPU_RWTexture2DRidFromResource(g->emittance_flood_target); + sig.tex_width = g->render_size.x; + sig.tex_height = g->render_size.y; + GPU_Compute(cl, &sig, PP_FloodCS, (g->render_size.x + 7) / 8, (g->render_size.y + 7) / 8, 1); + + /* Swap buffers */ + GPU_Resource *swp = g->emittance_flood_read; + g->emittance_flood_read = g->emittance_flood_target; + g->emittance_flood_target = swp; + + /* Update step */ + if (step_length == -1) + { + step_length = MaxI32(g->render_size.x, g->render_size.y) / 2; + } + else + { + step_length /= 2; + } + ++step; + } + } + + //- Prep shade pass + { + __profn("Clear shade target"); + GPU_ProfN(cl, Lit("Clear shade target")); + GPU_TransitionToReadable(cl, g->albedo); + GPU_TransitionToReadable(cl, g->emittance); + GPU_TransitionToWritable(cl, g->shade_target); + GPU_FlushWritable(cl, g->emittance_flood_read); + GPU_FlushWritable(cl, g->shade_read); + } + + //- Shade pass + { + __profn("Shade pass"); + GPU_ProfN(cl, Lit("Shade pass")); + Vec3I32 noise_size = GPU_GetTextureSize3D(GPU_GetCommonNoise()); + + u32 shade_flags = PP_ShadeFlag_None | PP_ShadeFlag_ToneMap; + if (effects_disabled) + { + shade_flags |= PP_ShadeFlag_DisableEffects; + } + + PP_ShadeSig sig = ZI; + sig.flags = shade_flags; + sig.tex_width = g->render_size.x; + sig.tex_height = g->render_size.y; + sig.exposure = 2.0; + sig.frame_seed = VEC4U32( + (u32)(RandU64FromState(&g->frame_rand) & 0xFFFFFFFF), + (u32)(RandU64FromState(&g->frame_rand) & 0xFFFFFFFF), + (u32)(RandU64FromState(&g->frame_rand) & 0xFFFFFFFF), + (u32)(RandU64FromState(&g->frame_rand) & 0xFFFFFFFF) + ); + sig.frame_index = g->frame_index; + sig.camera_offset = g->world_to_render_xf.og; + sig.noise = GPU_Texture3DRidFromResource(GPU_GetCommonNoise()); + sig.albedo = GPU_Texture2DRidFromResource(g->albedo); + sig.emittance = GPU_Texture2DRidFromResource(g->emittance); + sig.emittance_flood = GPU_Texture2DRidFromResource(g->emittance_flood_read); + sig.read = GPU_Texture2DRidFromResource(g->shade_read); + sig.target = GPU_RWTexture2DRidFromResource(g->shade_target); + sig.noise_tex_width = noise_size.x; + sig.noise_tex_height = noise_size.y; + sig.noise_tex_depth = noise_size.z; + GPU_Compute(cl, &sig, PP_ShadeCS, (g->render_size.x + 7) / 8, (g->render_size.y + 7) / 8, 1); + + /* Swap */ + GPU_Resource *swp = g->shade_read; + g->shade_read = g->shade_target; + g->shade_target = swp; + } + + //- Transition target to readable before UI pass + GPU_TransitionToReadable(cl, g->shade_read); + GPU_TransitionToReadable(cl, g->shade_target); + } + g->gpu_submit_fence_target = GPU_EndCommandList(cl); + + /* Reset render data */ + GPU_ResetTransientBuffer(&g->material_instances_tbuff, g->gpu_submit_fence_target); + GPU_ResetTransientBuffer(&g->grids_tbuff, g->gpu_submit_fence_target); + ResetArena(g->material_instances_arena); + ResetArena(g->grids_arena); + } + + /* Set root background texture to game texture */ + { + Xform ui_to_render_xf = InvertXform(g->render_to_ui_xf); + Vec2 p0 = MulXformV2(ui_to_render_xf, VEC2(0, 0)); + Vec2 p1 = MulXformV2(ui_to_render_xf, Vec2FromFields(g->ui_size)); + Vec2 uv0 = DivVec2Vec2(p0, Vec2FromFields(g->render_size)); + Vec2 uv1 = DivVec2Vec2(p1, Vec2FromFields(g->render_size)); + UI_SetBackgroundTexture(pp_root_box, g->shade_read, uv0, uv1); + } + + ////////////////////////////// + //- End frame + + g->gpu_submit_fence_target = UI_EndFrame(ui_frame); + + ++g->user_tick; + EndScratch(scratch); } //////////////////////////////////////////////////////////// @@ -2420,19 +2295,19 @@ void PP_UpdateUser(void) JobImpl(PP_UpdateUserOrSleep, UNUSED sig, UNUSED key) { - PP_SharedUserState *g = &PP_shared_user_state; - i64 time_ns = TimeNs(); - while (!Atomic32Fetch(&g->shutdown)) + PP_SharedUserState *g = &PP_shared_user_state; + i64 time_ns = TimeNs(); + while (!Atomic32Fetch(&g->shutdown)) + { + u32 fps_limit = FPS_LIMIT; + if (fps_limit > 0) { - u32 fps_limit = FPS_LIMIT; - if (fps_limit > 0) - { - __profn("User frame limit"); - P_SleepFrame(time_ns, 1000000000 / fps_limit); - time_ns = TimeNs(); - } - PP_UpdateUser(); + __profn("User frame limit"); + P_SleepFrame(time_ns, 1000000000 / fps_limit); + time_ns = TimeNs(); } + PP_UpdateUser(); + } } //////////////////////////////////////////////////////////// @@ -2440,39 +2315,39 @@ JobImpl(PP_UpdateUserOrSleep, UNUSED sig, UNUSED key) void PP_GenerateuserInputCmds(PP_Client *user_input_client, u64 tick) { - PP_SharedUserState *g = &PP_shared_user_state; - PP_Snapshot *prev_user_input_ss = PP_SnapshotFromTick(user_input_client, user_input_client->last_tick); - PP_Snapshot *user_input_ss = PP_AcquireSnapshot(user_input_client, prev_user_input_ss, tick); - PP_Ent *user_input_root = PP_EntFromKey(user_input_ss, PP_RootEntKey); - /* Find / create local control cmd ent */ - PP_Ent *control_cmd = PP_FirstWithProp(user_input_ss, PP_Prop_Cmd); - if (!control_cmd->valid) + PP_SharedUserState *g = &PP_shared_user_state; + PP_Snapshot *prev_user_input_ss = PP_SnapshotFromTick(user_input_client, user_input_client->last_tick); + PP_Snapshot *user_input_ss = PP_AcquireSnapshot(user_input_client, prev_user_input_ss, tick); + PP_Ent *user_input_root = PP_EntFromKey(user_input_ss, PP_RootEntKey); + /* Find / create local control cmd ent */ + PP_Ent *control_cmd = PP_FirstWithProp(user_input_ss, PP_Prop_Cmd); + if (!control_cmd->valid) + { + control_cmd = PP_AcquireSyncSrcEnt(user_input_root); + control_cmd->cmd_kind = PP_CmdKind_Control; + control_cmd->predictor = user_input_client->player_id; + PP_EnableProp(control_cmd, PP_Prop_Cmd); + PP_ActivateEnt(control_cmd, user_input_ss->tick); + } + { + Lock lock = LockE(&g->user_sim_cmd_mutex); + /* Update control cmd */ { - control_cmd = PP_AcquireSyncSrcEnt(user_input_root); - control_cmd->cmd_kind = PP_CmdKind_Control; - control_cmd->predictor = user_input_client->player_id; - PP_EnableProp(control_cmd, PP_Prop_Cmd); - PP_ActivateEnt(control_cmd, user_input_ss->tick); + control_cmd->cmd_control = g->user_sim_cmd_control; + control_cmd->cmd_control_hovered_ent = g->user_hovered_ent; } - { - Lock lock = LockE(&g->user_sim_cmd_mutex); - /* Update control cmd */ - { - control_cmd->cmd_control = g->user_sim_cmd_control; - control_cmd->cmd_control_hovered_ent = g->user_hovered_ent; - } #if 0 - /* Create chat cmd */ - if (g->user_sim_cmd_chat.len > 0) - { - PP_Ent *chat_cmd = PP_AcquireSyncSrcEnt(user_input_root); - chat_cmd->cmd_kind = PP_CmdKind_Chat; - //chat_cmd->chat_msg = ZI - } -#endif - ++g->user_sim_cmd_gen; - Unlock(&lock); + /* Create chat cmd */ + if (g->user_sim_cmd_chat.len > 0) + { + PP_Ent *chat_cmd = PP_AcquireSyncSrcEnt(user_input_root); + chat_cmd->cmd_kind = PP_CmdKind_Chat; + //chat_cmd->chat_msg = ZI } +#endif + ++g->user_sim_cmd_gen; + Unlock(&lock); + } } //////////////////////////////////////////////////////////// @@ -2480,739 +2355,739 @@ void PP_GenerateuserInputCmds(PP_Client *user_input_client, u64 tick) JobImpl(PP_UpdateSim, UNUSED sig, UNUSED key) { - PP_SharedUserState *g = &PP_shared_user_state; -#if 0 - struct host_listen_address local_listen_addr = host_listen_address_from_local_name(Lit("LOCAL_SIM")); - struct host_listen_address net_listen_addr = host_listen_address_from_net_port(12345); - //N_Host *host = N_AcquireHost(); - /* TODO: Host system should allocate & copy string stored in local_listen_addr */ - //host_listen(host, local_listen_addr); - //host_listen(host, net_listen_addr); -#endif + PP_SharedUserState *g = &PP_shared_user_state; + #if 0 + struct host_listen_address local_listen_addr = host_listen_address_from_local_name(Lit("LOCAL_SIM")); + struct host_listen_address net_listen_addr = host_listen_address_from_net_port(12345); + //N_Host *host = N_AcquireHost(); + /* TODO: Host system should allocate & copy string stored in local_listen_addr */ + //host_listen(host, local_listen_addr); + //host_listen(host, net_listen_addr); + #endif - b32 is_master = 0; - N_Host *host; - if (g->connect_address_str.len > 0) + b32 is_master = 0; + N_Host *host; + if (g->connect_address_str.len > 0) + { + host = N_AcquireHost(0); + P_Address addr = P_AddressFromString(g->connect_address_str); + N_Connect(host, addr); + } + else + { + host = N_AcquireHost(12345); + is_master = 1; + } + + BB_Buff msg_writer_bb = BB_AcquireBuff(Gibi(64)); + BB_Buff snapshot_writer_bb = BB_AcquireBuff(Gibi(64)); + PP_Accel accel = PP_AcquireAccel(); + + PP_ClientStore *store = PP_AcquireClientStore(); + PP_Client *user_input_client = PP_AcquireClient(store); /* Stores snapshots containing commands to be published to local client */ + PP_Client *local_client = PP_AcquireClient(store); /* Stores snapshots produced locally */ + PP_Client *publish_client = PP_AcquireClient(store); /* Stores versions of local snapshots that will be published to remote sims */ + + PP_Client *master_client = PP_NilClient(); /* Stores snapshots received from master */ + PP_Client *master_blended_client = PP_NilClient(); /* Stores interpolated master snapshots */ + b32 initialized_from_master = 0; + + + + + + #if 0 + if (IsSwappedIn()) + { + TempArena scratch = BeginScratchNoConflict(); + String encoded = SwappedStateFromName(scratch.arena, Lit("pp_snapshot")); + + BB_Buff bb = BB_BuffFromString(encoded); + BB_Reader br = BB_ReaderFromBuff(&bb); + + u64 tick = BB_ReadIBits(&br, 64); + if (tick > 0) { - host = N_AcquireHost(0); - P_Address addr = P_AddressFromString(g->connect_address_str); - N_Connect(host, addr); - } - else - { - host = N_AcquireHost(12345); - is_master = 1; + PP_EntKey player_id = { .uid = BB_ReadUid(&br) }; + local_client->player_id = player_id; + user_input_client->player_id = player_id; + PP_Snapshot *ss = PP_AcquireSnapshot(local_client, PP_NilSnapshot(), tick); + PP_DecodeSnapshot(&br, ss); } - BB_Buff msg_writer_bb = BB_AcquireBuff(Gibi(64)); - BB_Buff snapshot_writer_bb = BB_AcquireBuff(Gibi(64)); - PP_Accel accel = PP_AcquireAccel(); - - PP_ClientStore *store = PP_AcquireClientStore(); - PP_Client *user_input_client = PP_AcquireClient(store); /* Stores snapshots containing commands to be published to local client */ - PP_Client *local_client = PP_AcquireClient(store); /* Stores snapshots produced locally */ - PP_Client *publish_client = PP_AcquireClient(store); /* Stores versions of local snapshots that will be published to remote sims */ - - PP_Client *master_client = PP_NilClient(); /* Stores snapshots received from master */ - PP_Client *master_blended_client = PP_NilClient(); /* Stores interpolated master snapshots */ - b32 initialized_from_master = 0; + EndScratch(scratch); + } + #endif -#if 0 - if (IsSwappedIn()) + + + + + + i64 master_blend_time_ns = 0; + i64 average_master_receive_dt_ns = 0; + i64 last_tick_from_master_received_at_ns = 0; + + + + + + + + + + + + + + + + i64 last_publish_to_user_ns = 0; + i64 real_time_ns = 0; + i64 real_dt_ns = 0; + i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; + f64 compute_timescale = 1.0; + while (!Atomic32Fetch(&g->shutdown)) + { + TempArena scratch = BeginScratchNoConflict(); { - TempArena scratch = BeginScratchNoConflict(); - String encoded = SwappedStateFromName(scratch.arena, Lit("pp_snapshot")); - - BB_Buff bb = BB_BuffFromString(encoded); - BB_Reader br = BB_ReaderFromBuff(&bb); - - u64 tick = BB_ReadIBits(&br, 64); - if (tick > 0) - { - PP_EntKey player_id = { .uid = BB_ReadUid(&br) }; - local_client->player_id = player_id; - user_input_client->player_id = player_id; - PP_Snapshot *ss = PP_AcquireSnapshot(local_client, PP_NilSnapshot(), tick); - PP_DecodeSnapshot(&br, ss); - } - - EndScratch(scratch); + __profn("Sim sleep"); + P_SleepFrame(real_time_ns, step_dt_ns * compute_timescale); } -#endif - - - - - - - - - - - i64 master_blend_time_ns = 0; - i64 average_master_receive_dt_ns = 0; - i64 last_tick_from_master_received_at_ns = 0; - - - - - - - - - - - - - - - - i64 last_publish_to_user_ns = 0; - i64 real_time_ns = 0; - i64 real_dt_ns = 0; - i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; - f64 compute_timescale = 1.0; - while (!Atomic32Fetch(&g->shutdown)) { - TempArena scratch = BeginScratchNoConflict(); + __profn("Sim update"); + + real_dt_ns = TimeNs() - real_time_ns; + real_time_ns += real_dt_ns; + + N_EventList host_events = N_BeginUpdate(scratch.arena, host); + + /* Read net messages */ + PP_DecodeQueue queue = ZI; + { + for (N_Event *event = host_events.first; event; event = event->next) { - __profn("Sim sleep"); - P_SleepFrame(real_time_ns, step_dt_ns * compute_timescale); - } - { - __profn("Sim update"); - - real_dt_ns = TimeNs() - real_time_ns; - real_time_ns += real_dt_ns; - - N_EventList host_events = N_BeginUpdate(scratch.arena, host); - - /* Read net messages */ - PP_DecodeQueue queue = ZI; + N_ChannelId channel_id = event->channel_id; + PP_Client *client = PP_ClientFromChannelId(store, channel_id); + switch (event->kind) + { + case N_EventKind_ChannelOpened: { - for (N_Event *event = host_events.first; event; event = event->next) + if (!client->valid) + { + if (is_master) { - N_ChannelId channel_id = event->channel_id; - PP_Client *client = PP_ClientFromChannelId(store, channel_id); - switch (event->kind) - { - case N_EventKind_ChannelOpened: - { - if (!client->valid) - { - if (is_master) - { - /* Create remote client */ - client = PP_AcquireClient(store); - PP_SetClientChannelId(client, channel_id); - } - else - { - /* Create master client */ - if (!master_client->valid) - { - client = PP_AcquireClient(store); - PP_SetClientChannelId(client, channel_id); - master_client = client; - master_blended_client = PP_AcquireClient(store); - } - else - { - /* We already have a master client */ - Assert(0); - } - } - } - } break; - - case N_EventKind_Msg: - { - if (client->valid) - { - BB_Buff msg_bb = BB_BuffFromString(event->msg); - BB_Reader msg_br = BB_ReaderFromBuff(&msg_bb); - - u64 ack = BB_ReadUV(&msg_br); - u64 double_ack = BB_ReadUV(&msg_br); - if (ack > client->ack) - { - client->ack = ack; - } - if (double_ack > client->double_ack) - { - client->double_ack = double_ack; - } - - /* Read & queue incoming snapshots for decoding */ - u64 tmp_encoded_len = BB_ReadUV(&msg_br); - while (tmp_encoded_len > 0) - { - u8 *tmp_encoded_bytes = BB_ReadBytesRaw(&msg_br, tmp_encoded_len); - if (!tmp_encoded_bytes) break; - - BB_Buff decoder_bb = BB_BuffFromString(STRING(tmp_encoded_len, tmp_encoded_bytes)); - BB_Reader decoder_br = BB_ReaderFromBuff(&decoder_bb); - u64 base_tick = BB_ReadUV(&decoder_br); - u64 tick = BB_ReadUV(&decoder_br); - - String tmp_encoded = ZI; - tmp_encoded.len = BB_NumBytesRemaining(&decoder_br); - tmp_encoded.text = BB_ReadBytesRaw(&decoder_br, tmp_encoded.len); - if (!tmp_encoded.text) tmp_encoded.len = 0; - - PP_Snapshot *base_ss = PP_SnapshotFromTick(client, base_tick); - if (base_ss->tick == base_tick) - { - if (is_master) - { - /* Queue incoming slave client snapshot for decoding */ - //b32 should_decode = tick == client->highest_received_tick + 1 || client->highest_received_tick == 0; - b32 should_decode = tick > client->highest_received_tick; - if (should_decode) - { - PP_DecodeQueueNode *node = PushStruct(scratch.arena, PP_DecodeQueueNode); - node->client = client; - node->tick = tick; - node->base_tick = base_tick; - node->tmp_encoded = tmp_encoded; - if (queue.last) - { - queue.last->next = node; - } - else - { - queue.first = node; - } - queue.last = node; - if (tick > client->highest_received_tick) - { - client->highest_received_tick = tick; - } - } - } - else - { - /* Decode incoming master client snapshots for decoding (only the newest one) */ - b32 should_decode = client == master_client && tick > client->highest_received_tick; - if (should_decode) - { - PP_DecodeQueueNode *node = queue.first ? queue.first : PushStruct(scratch.arena, PP_DecodeQueueNode); - node->client = client; - node->tick = tick; - node->base_tick = base_tick; - node->tmp_encoded = tmp_encoded; - queue.first = node; - queue.last = node; - if (tick > client->highest_received_tick) - { - client->highest_received_tick = tick; - if (average_master_receive_dt_ns == 0) - { - average_master_receive_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; - } - else - { - average_master_receive_dt_ns -= average_master_receive_dt_ns / 50; - average_master_receive_dt_ns += (real_time_ns - last_tick_from_master_received_at_ns) / 50; - } - last_tick_from_master_received_at_ns = real_time_ns; - } - } - } - } - else - { - /* We do not have the tick that the incoming delta is based from */ - Assert(0); - } - - tmp_encoded_len = BB_ReadUV(&msg_br); - } - } - } break; - - default: break; - } - } - } - - /* Decode incoming snapshots */ - for (PP_DecodeQueueNode *n = queue.first; n; n = n->next) - { - PP_Client *client = n->client; - u64 base_tick = n->base_tick; - u64 tick = n->tick; - PP_Snapshot *base_ss = PP_SnapshotFromTick(client, base_tick); - if (base_ss->tick == base_tick) - { - BB_Buff bb = BB_BuffFromString(n->tmp_encoded); - BB_Reader br = BB_ReaderFromBuff(&bb); - - /* Acquire & decode snapshot */ - PP_Snapshot *ss = PP_AcquireSnapshot(client, base_ss, tick); - PP_DecodeSnapshot(&br, ss); - - /* Assume all incoming ents want to be sync srcs */ - for (u64 i = 0; i < ss->num_ents_reserved; ++i) - { - PP_Ent *ent = &ss->ents[i]; - if (ent->valid && PP_HasProp(ent, PP_Prop_SyncDst)) - { - PP_DisableProp(ent, PP_Prop_SyncDst); - PP_EnableProp(ent, PP_Prop_SyncSrc); - } - } + /* Create remote client */ + client = PP_AcquireClient(store); + PP_SetClientChannelId(client, channel_id); } else { - /* We do not have the tick that the incoming delta is based from. - * This decode should never have been queued in the first place. */ + /* Create master client */ + if (!master_client->valid) + { + client = PP_AcquireClient(store); + PP_SetClientChannelId(client, channel_id); + master_client = client; + master_blended_client = PP_AcquireClient(store); + } + else + { + /* We already have a master client */ Assert(0); + } } - } + } + } break; - if (!is_master && !initialized_from_master) + case N_EventKind_Msg: { - if (master_client->valid && master_client->last_tick > 0) + if (client->valid) + { + BB_Buff msg_bb = BB_BuffFromString(event->msg); + BB_Reader msg_br = BB_ReaderFromBuff(&msg_bb); + + u64 ack = BB_ReadUV(&msg_br); + u64 double_ack = BB_ReadUV(&msg_br); + if (ack > client->ack) { - initialized_from_master = 1; + client->ack = ack; } - else + if (double_ack > client->double_ack) { - goto skip_step; + client->double_ack = double_ack; } - } - b32 should_step = !Atomic32Fetch(&g->user_paused); - if (Atomic32Fetch(&g->user_paused_steps) > 0) - { - should_step = 1; - Atomic32FetchAdd(&g->user_paused_steps, -1); - } - - if (!should_step) - { - goto skip_step; - } - - /* Update networked clients */ - u64 oldest_client_ack = 0; - for (u64 i = 0; i < store->num_clients_reserved; ++i) - { - PP_Client *client = &store->clients[i]; - if (client->valid && client != local_client && client != publish_client && client != user_input_client && client != master_client) + /* Read & queue incoming snapshots for decoding */ + u64 tmp_encoded_len = BB_ReadUV(&msg_br); + while (tmp_encoded_len > 0) { - client->last_rtt_ns = N_GetChannelLastRttNs(host, client->channel_id); - /* Release unneeded received snapshots */ - /* TDOO: Cap how many client snapshots we're willing to retain */ - if (client->double_ack > 0) + u8 *tmp_encoded_bytes = BB_ReadBytesRaw(&msg_br, tmp_encoded_len); + if (!tmp_encoded_bytes) break; + + BB_Buff decoder_bb = BB_BuffFromString(STRING(tmp_encoded_len, tmp_encoded_bytes)); + BB_Reader decoder_br = BB_ReaderFromBuff(&decoder_bb); + u64 base_tick = BB_ReadUV(&decoder_br); + u64 tick = BB_ReadUV(&decoder_br); + + String tmp_encoded = ZI; + tmp_encoded.len = BB_NumBytesRemaining(&decoder_br); + tmp_encoded.text = BB_ReadBytesRaw(&decoder_br, tmp_encoded.len); + if (!tmp_encoded.text) tmp_encoded.len = 0; + + PP_Snapshot *base_ss = PP_SnapshotFromTick(client, base_tick); + if (base_ss->tick == base_tick) + { + if (is_master) { - u64 keep_tick = MinU64(client->double_ack, local_client->last_tick); - if (keep_tick > 0) + /* Queue incoming slave client snapshot for decoding */ + //b32 should_decode = tick == client->highest_received_tick + 1 || client->highest_received_tick == 0; + b32 should_decode = tick > client->highest_received_tick; + if (should_decode) + { + PP_DecodeQueueNode *node = PushStruct(scratch.arena, PP_DecodeQueueNode); + node->client = client; + node->tick = tick; + node->base_tick = base_tick; + node->tmp_encoded = tmp_encoded; + if (queue.last) { - PP_ReleaseSnapshotsInRange(client, 0, keep_tick - 1); - } - } - if (client->ack < oldest_client_ack || oldest_client_ack == 0) - { - oldest_client_ack = client->ack; - } - } - } - - /* Release unneeded published snapshots */ - { - u64 keep_tick = oldest_client_ack; - if (keep_tick == 0 && publish_client->last_tick > 0) - { - keep_tick = publish_client->last_tick - 1; - } - if (keep_tick > 0) - { - --keep_tick; - } - PP_ReleaseSnapshotsInRange(publish_client, 0, keep_tick); - } - - /* Release old local snapshots */ - { - u64 keep_range = 50; - if (local_client->last_tick > keep_range) - { - u64 keep_tick = local_client->last_tick - keep_range; - PP_ReleaseSnapshotsInRange(local_client, 0, keep_tick); - } - } - - /* Release unneeded user input snapshots */ - PP_ReleaseSnapshotsInRange(user_input_client, 0, local_client->first_tick - 1); - - - - - - - - - - if (is_master) - { - /* Step master */ - u64 prev_tick = local_client->last_tick; - u64 next_tick = prev_tick + 1; - PP_SimStepCtx ctx = ZI; - ctx.is_master = is_master; - ctx.sim_dt_ns = step_dt_ns; - ctx.accel = &accel; - ctx.user_input_client = user_input_client; - ctx.master_client = master_client; - ctx.publish_client = publish_client; - PP_Snapshot *prev_world = PP_SnapshotFromTick(local_client, prev_tick); - ctx.world = PP_AcquireSnapshot(local_client, prev_world, next_tick); - PP_GenerateuserInputCmds(user_input_client, next_tick); - PP_StepSim(&ctx); - } - else if (master_client->valid) - { - /* Step client */ - - /* TODO: Eventually determine master tick based on a delay to allow for jitter and also interpolation so we can lower snapshot publish frequency */ - - - b32 master_ss_is_blended = 0; - PP_Snapshot *master_ss = PP_NilSnapshot(); - { - /* How along are we between master sim ticks (0 = start of tick, 1 = end of tick) */ - f64 tick_progress = 0; - i64 next_tick_expected_ns = last_tick_from_master_received_at_ns + average_master_receive_dt_ns; - if (next_tick_expected_ns > last_tick_from_master_received_at_ns) - { - tick_progress = (f64)(real_time_ns - last_tick_from_master_received_at_ns) / (f64)(next_tick_expected_ns - last_tick_from_master_received_at_ns); - } - - /* Predict master sim time based on average snapshot publish dt. */ - PP_Snapshot *newest_snapshot = PP_SnapshotFromTick(master_client, master_client->last_tick); - i64 master_sim_predicted_time_ns = newest_snapshot->sim_time_ns + (newest_snapshot->sim_dt_ns * tick_progress); - - /* Determine blend time */ - i64 master_blend_time_target_ns = master_sim_predicted_time_ns - (SIM_CLIENT_INTERP_RATIO * average_master_receive_dt_ns); - if (average_master_receive_dt_ns > 0) - { - master_blend_time_ns += real_dt_ns; - } - - i64 blend_time_target_diff_ns = master_blend_time_target_ns - master_blend_time_ns; - if (blend_time_target_diff_ns > NsFromSeconds(0.100) || blend_time_target_diff_ns < NsFromSeconds(-0.100)) - { - /* Snap blend time if it gets too far from target blend time */ - master_blend_time_ns = master_blend_time_target_ns; - } - u64 master_blend_tick = master_blend_time_ns / newest_snapshot->sim_dt_ns; - - /* Get snapshot nearest to master blend time */ - /* TODO: Blend */ - PP_Snapshot *left_snapshot = PP_NilSnapshot(); - PP_Snapshot *right_snapshot = newest_snapshot; - { - PP_Snapshot *ss = PP_SnapshotFromTick(master_client, master_client->first_tick); - while (ss->valid) - { - u64 next_tick = ss->next_tick; - i64 ss_time_ns = ss->sim_time_ns; - if (ss_time_ns < master_blend_time_ns && ss_time_ns > left_snapshot->sim_time_ns) - { - left_snapshot = ss; - } - if (ss_time_ns > master_blend_time_ns && ss_time_ns < right_snapshot->sim_time_ns) - { - right_snapshot = ss; - } - ss = PP_SnapshotFromTick(master_client, next_tick); - } - } - - /* Create world from blended master snapshots */ - f64 blend = 0; - if (left_snapshot->valid && right_snapshot->valid && right_snapshot->tick > left_snapshot->tick) - { - blend = (f64)(master_blend_tick - left_snapshot->tick) / (f64)(right_snapshot->tick - left_snapshot->tick); - f64 epsilon = 0.001; - if (blend < epsilon) - { - master_ss_is_blended = 0; - master_ss = left_snapshot; - } - else if (blend > 1 - epsilon) - { - master_ss_is_blended = 0; - master_ss = right_snapshot; + queue.last->next = node; } else { - master_ss_is_blended = 1; - master_ss = PP_AcquireSnapshotFromLerp(master_blended_client, left_snapshot, right_snapshot, blend); - - /* Release unneeded blended master snapshots */ - if (master_ss->tick > 0) - { - PP_ReleaseSnapshotsInRange(master_blended_client, 0, master_ss->tick - 1); - PP_ReleaseSnapshotsInRange(master_blended_client, master_ss->tick + 1, U64Max); - } + queue.first = node; } + queue.last = node; + if (tick > client->highest_received_tick) + { + client->highest_received_tick = tick; + } + } } else { - master_ss_is_blended = 0; - master_ss = left_snapshot->valid ? left_snapshot : right_snapshot; + /* Decode incoming master client snapshots for decoding (only the newest one) */ + b32 should_decode = client == master_client && tick > client->highest_received_tick; + if (should_decode) + { + PP_DecodeQueueNode *node = queue.first ? queue.first : PushStruct(scratch.arena, PP_DecodeQueueNode); + node->client = client; + node->tick = tick; + node->base_tick = base_tick; + node->tmp_encoded = tmp_encoded; + queue.first = node; + queue.last = node; + if (tick > client->highest_received_tick) + { + client->highest_received_tick = tick; + if (average_master_receive_dt_ns == 0) + { + average_master_receive_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; + } + else + { + average_master_receive_dt_ns -= average_master_receive_dt_ns / 50; + average_master_receive_dt_ns += (real_time_ns - last_tick_from_master_received_at_ns) / 50; + } + last_tick_from_master_received_at_ns = real_time_ns; + } + } } + } + else + { + /* We do not have the tick that the incoming delta is based from */ + Assert(0); + } - /* Release unneeded master snapshots */ - u64 keep_master_tick = MinU64(left_snapshot->tick, master_client->double_ack); - if (keep_master_tick > 0) - { - PP_ReleaseSnapshotsInRange(master_client, 0, keep_master_tick - 1); - } - -#if 0 - DEBUGBREAKABLE; - LogDebugF("*************************************************"); - LogDebugF("local_client->last_tick: %F", FmtUint(local_client->last_tick)); - LogDebugF("master_sim_predicted_time_ns: %F", FmtSint(master_sim_predicted_time_ns)); - LogDebugF("tick_progress: %F", FmtFloat(tick_progress)); - LogDebugF("sim_publish_timescale: %F", FmtFloat(sim_publish_timescale)); - LogDebugF("last_tick_from_master_received_at_ns: %F", FmtSint(last_tick_from_master_received_at_ns)); - LogDebugF("average_master_receive_dt_ns: %F", FmtSint(average_master_receive_dt_ns)); - LogDebugF("next_tick_expected_ns: %F", FmtSint(next_tick_expected_ns)); - LogDebugF("master_blend_time_target_ns: %F", FmtSint(master_blend_time_target_ns)); - LogDebugF("blend_time_target_diff_ns: %F", FmtSint(blend_time_target_diff_ns)); - LogDebugF("master_blend_time_ns: %F", FmtSint(master_blend_time_ns)); - LogDebugF("left_snapshot->tick: %F", FmtUint(left_snapshot->tick)); - LogDebugF("right_snapshot->tick: %F", FmtUint(right_snapshot->tick)); - LogDebugF("master_ss->tick: %F", FmtUint(master_ss->tick)); -#endif + tmp_encoded_len = BB_ReadUV(&msg_br); } + } + } break; - if (master_ss->valid) - { - PP_Ent *master_player = PP_FirstWithProp(master_ss, PP_Prop_IsMaster); - - /* Update ent key from master */ - { - user_input_client->player_id = master_ss->local_player; - local_client->player_id = master_ss->local_player; - } - - /* Check for misprediction */ - u64 mispredicted_tick = 0; - if (!master_ss_is_blended) - { - /* TODO: Actually check for misprediction rather than triggering mispredict any time a new master snapshot is received */ - mispredicted_tick = master_ss->tick; - } - - u64 step_base_tick = local_client->last_tick; - u64 step_end_tick = step_base_tick + 1; - if (mispredicted_tick > 0) - { - step_base_tick = mispredicted_tick; - if (step_end_tick <= step_base_tick) - { - step_end_tick = step_base_tick + 1; - } - } - - /* We want to simulate the ahead of the server to predict client input. - * How many ticks ahead we want to simulate is a balance between added latency and the server not receiving our inputs on time. - * We can take the server's ack minus the server's tick to determine how many cmds of ours the server has buffered. - * - * If this buffer gets too low (because we are lagging behind or the connection is unstable), meaning the server is not getting our input on time: - * - Shorten local compute rate to increase the rate at which we predict ahead & produce cmds, until the server's ack indicates a buffer size within desired range. - * - * If this buffer gets too large (because the client predicts too far ahead), meaning unneeded latency is being introduced: - * - Dilate local compute rate to decrease the rate at which we predict ahead & produce cmds until the server's ack indicates a buffer size within desired range. - */ - { - i64 cmds_ahead_on_master = (i64)master_client->ack - (i64)master_client->last_tick; - if (cmds_ahead_on_master < -3 || cmds_ahead_on_master > 10) - { - /* Cmds are too far from master time, snap step end tick */ - i64 rtt_ns = master_client->last_rtt_ns; - f64 rtt_tick_ratio = (f64)(rtt_ns + (step_dt_ns - 1)) / (f64)step_dt_ns; - i64 num_predict_ticks = RoundF64ToI64(rtt_tick_ratio) + 5; - step_end_tick = master_client->last_tick + num_predict_ticks; - compute_timescale = 1.1; - } - else if (cmds_ahead_on_master > 2) - { - /* Slow down simulation to dial back how far ahead we are predicting and bring local sim time closer to master sim time */ - compute_timescale = 1.1; - } - else if (cmds_ahead_on_master < 1) - { - /* Speed up simulation rate predict more ticks and give master more inputs to work with */ - compute_timescale = 0.9; - } - else - { - /* Server's cmd buffer is in a healthy range */ - compute_timescale = 1; - } - } - - /* Sync master with local base tick */ - PP_Snapshot *base_ss = PP_SnapshotFromTick(local_client, step_base_tick); - if (mispredicted_tick) - { - if (base_ss->valid) - { - PP_SyncSnapshotEnts(base_ss, master_ss, master_player->key, 0); - } - else - { - base_ss = PP_AcquireSnapshot(local_client, master_ss, step_base_tick); - } - } - - /* Release any existing ticks that are about to be simulated */ - PP_ReleaseSnapshotsInRange(local_client, step_base_tick + 1, U64Max); - - /* Step */ - PP_GenerateuserInputCmds(user_input_client, step_end_tick); - { - PP_SimStepCtx ctx = ZI; - ctx.is_master = is_master; - ctx.sim_dt_ns = step_dt_ns; - ctx.accel = &accel; - ctx.user_input_client = user_input_client; - ctx.master_client = master_client; - ctx.publish_client = publish_client; - - u64 step_tick = step_base_tick + 1; - PP_Snapshot *prev_ss = base_ss; - while (step_tick <= step_end_tick) - { - ctx.world = PP_AcquireSnapshot(local_client, prev_ss, step_tick); - if (!mispredicted_tick && step_tick == step_end_tick) - { - PP_SyncSnapshotEnts(ctx.world, master_ss, master_player->key, PP_SyncFlag_NoSyncPredictables); - } - PP_StepSim(&ctx); - prev_ss = ctx.world; - ++step_tick; - } - } - } - } - - /* Publish snapshot to remote clients */ - for (u64 i = 0; i < store->num_clients_reserved; ++i) - { - PP_Client *client = &store->clients[i]; - if (client->valid && client != user_input_client && client != local_client && client != publish_client) - { - BB_Writer msg_bw = BB_WriterFromBuff(&msg_writer_bb); - - BB_WriteUV(&msg_bw, client->highest_received_tick); /* ack */ - BB_WriteUV(&msg_bw, client->ack); /* double ack */ - - PP_Snapshot *base_ss = PP_SnapshotFromTick(publish_client, client->ack); - PP_Snapshot *publish_ss; - if (client == master_client) - { - /* If sending to master, start sending all snapshots since last ack */ - publish_ss = PP_SnapshotFromClosestTickGte(publish_client, base_ss->tick + 1); - } - else - { - /* If sending to slave, only send latest snapshot */ - publish_ss = PP_SnapshotFromTick(publish_client, publish_client->last_tick); - } - - while (publish_ss->valid) - { - BB_Writer snapshot_bw = BB_WriterFromBuff(&snapshot_writer_bb); - String tmp_snapshot_encoded = ZI; - { - BB_WriteUV(&snapshot_bw, base_ss->tick); - BB_WriteUV(&snapshot_bw, publish_ss->tick); - PP_EncodeSnapshot(&snapshot_bw, client, base_ss, publish_ss); - tmp_snapshot_encoded.len = BB_GetNumBytesWritten(&snapshot_bw); - tmp_snapshot_encoded.text = BB_GetWrittenRaw(&snapshot_bw); - } - BB_WriteUV(&msg_bw, tmp_snapshot_encoded.len); - BB_WriteBytes(&msg_bw, tmp_snapshot_encoded); - publish_ss = PP_SnapshotFromTick(publish_client, publish_ss->tick + 1); - } - BB_WriteUV(&msg_bw, 0); - - String encoded = ZI; - encoded.len = BB_GetNumBytesWritten(&msg_bw); - encoded.text = BB_GetWrittenRaw(&msg_bw); - N_Write(host, client->channel_id, encoded, 0); - } - } - - /* Copy local snapshot to user client */ - { - PP_Snapshot *local_ss = PP_SnapshotFromTick(local_client, local_client->last_tick); - if (local_ss->valid) - { - /* TODO: Double buffer */ - Lock lock = LockE(&g->local_to_user_client_mutex); - PP_AcquireSnapshot(g->local_to_user_client, local_ss, local_ss->tick); - i64 publish_ns = TimeNs(); - if (last_publish_to_user_ns == 0) - { - last_publish_to_user_ns = publish_ns - g->average_local_to_user_snapshot_publish_dt_ns; - } - g->local_to_user_client_publish_dt_ns = publish_ns - last_publish_to_user_ns; - g->local_to_user_client_publish_time_ns = publish_ns; - last_publish_to_user_ns = publish_ns; - PP_ReleaseSnapshotsInRange(g->local_to_user_client, 0, local_ss->tick - 1); - Unlock(&lock); - } - } - - skip_step: - - /* Send host messages */ - N_EndUpdate(host); - __profframe("Local sim"); - - EndScratch(scratch); + default: break; + } } - } + } -#if 0 - if (IsSwappingOut()) - { - TempArena scratch = BeginScratchNoConflict(); - u64 max_size = Mebi(64); - u8 *bytes = PushStructsNoZero(scratch.arena, u8, max_size); - BB_Buff bb = BB_BuffFromString(STRING(max_size, bytes)); + /* Decode incoming snapshots */ + for (PP_DecodeQueueNode *n = queue.first; n; n = n->next) + { + PP_Client *client = n->client; + u64 base_tick = n->base_tick; + u64 tick = n->tick; + PP_Snapshot *base_ss = PP_SnapshotFromTick(client, base_tick); + if (base_ss->tick == base_tick) { - BB_Writer bw = BB_WriterFromBuff(&bb); + BB_Buff bb = BB_BuffFromString(n->tmp_encoded); + BB_Reader br = BB_ReaderFromBuff(&bb); - u64 tick = local_client->last_tick; - PP_Snapshot *ss = PP_SnapshotFromTick(local_client, tick); - BB_WriteUBits(&bw, tick, 64); - BB_WriteUid(&bw, local_client->player_id.uid); - PP_EncodeSnapshot(&bw, local_client, PP_NilSnapshot(), ss); - WriteSwappedState(Lit("pp_snapshot"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw))); + /* Acquire & decode snapshot */ + PP_Snapshot *ss = PP_AcquireSnapshot(client, base_ss, tick); + PP_DecodeSnapshot(&br, ss); + + /* Assume all incoming ents want to be sync srcs */ + for (u64 i = 0; i < ss->num_ents_reserved; ++i) + { + PP_Ent *ent = &ss->ents[i]; + if (ent->valid && PP_HasProp(ent, PP_Prop_SyncDst)) + { + PP_DisableProp(ent, PP_Prop_SyncDst); + PP_EnableProp(ent, PP_Prop_SyncSrc); + } + } } - EndScratch(scratch); + else + { + /* We do not have the tick that the incoming delta is based from. + * This decode should never have been queued in the first place. */ + Assert(0); + } + } + + if (!is_master && !initialized_from_master) + { + if (master_client->valid && master_client->last_tick > 0) + { + initialized_from_master = 1; + } + else + { + goto skip_step; + } + } + + b32 should_step = !Atomic32Fetch(&g->user_paused); + if (Atomic32Fetch(&g->user_paused_steps) > 0) + { + should_step = 1; + Atomic32FetchAdd(&g->user_paused_steps, -1); + } + + if (!should_step) + { + goto skip_step; + } + + /* Update networked clients */ + u64 oldest_client_ack = 0; + for (u64 i = 0; i < store->num_clients_reserved; ++i) + { + PP_Client *client = &store->clients[i]; + if (client->valid && client != local_client && client != publish_client && client != user_input_client && client != master_client) + { + client->last_rtt_ns = N_GetChannelLastRttNs(host, client->channel_id); + /* Release unneeded received snapshots */ + /* TDOO: Cap how many client snapshots we're willing to retain */ + if (client->double_ack > 0) + { + u64 keep_tick = MinU64(client->double_ack, local_client->last_tick); + if (keep_tick > 0) + { + PP_ReleaseSnapshotsInRange(client, 0, keep_tick - 1); + } + } + if (client->ack < oldest_client_ack || oldest_client_ack == 0) + { + oldest_client_ack = client->ack; + } + } + } + + /* Release unneeded published snapshots */ + { + u64 keep_tick = oldest_client_ack; + if (keep_tick == 0 && publish_client->last_tick > 0) + { + keep_tick = publish_client->last_tick - 1; + } + if (keep_tick > 0) + { + --keep_tick; + } + PP_ReleaseSnapshotsInRange(publish_client, 0, keep_tick); + } + + /* Release old local snapshots */ + { + u64 keep_range = 50; + if (local_client->last_tick > keep_range) + { + u64 keep_tick = local_client->last_tick - keep_range; + PP_ReleaseSnapshotsInRange(local_client, 0, keep_tick); + } + } + + /* Release unneeded user input snapshots */ + PP_ReleaseSnapshotsInRange(user_input_client, 0, local_client->first_tick - 1); + + + + + + + + + + if (is_master) + { + /* Step master */ + u64 prev_tick = local_client->last_tick; + u64 next_tick = prev_tick + 1; + PP_SimStepCtx ctx = ZI; + ctx.is_master = is_master; + ctx.sim_dt_ns = step_dt_ns; + ctx.accel = &accel; + ctx.user_input_client = user_input_client; + ctx.master_client = master_client; + ctx.publish_client = publish_client; + PP_Snapshot *prev_world = PP_SnapshotFromTick(local_client, prev_tick); + ctx.world = PP_AcquireSnapshot(local_client, prev_world, next_tick); + PP_GenerateuserInputCmds(user_input_client, next_tick); + PP_StepSim(&ctx); + } + else if (master_client->valid) + { + /* Step client */ + + /* TODO: Eventually determine master tick based on a delay to allow for jitter and also interpolation so we can lower snapshot publish frequency */ + + + b32 master_ss_is_blended = 0; + PP_Snapshot *master_ss = PP_NilSnapshot(); + { + /* How along are we between master sim ticks (0 = start of tick, 1 = end of tick) */ + f64 tick_progress = 0; + i64 next_tick_expected_ns = last_tick_from_master_received_at_ns + average_master_receive_dt_ns; + if (next_tick_expected_ns > last_tick_from_master_received_at_ns) + { + tick_progress = (f64)(real_time_ns - last_tick_from_master_received_at_ns) / (f64)(next_tick_expected_ns - last_tick_from_master_received_at_ns); + } + + /* Predict master sim time based on average snapshot publish dt. */ + PP_Snapshot *newest_snapshot = PP_SnapshotFromTick(master_client, master_client->last_tick); + i64 master_sim_predicted_time_ns = newest_snapshot->sim_time_ns + (newest_snapshot->sim_dt_ns * tick_progress); + + /* Determine blend time */ + i64 master_blend_time_target_ns = master_sim_predicted_time_ns - (SIM_CLIENT_INTERP_RATIO * average_master_receive_dt_ns); + if (average_master_receive_dt_ns > 0) + { + master_blend_time_ns += real_dt_ns; + } + + i64 blend_time_target_diff_ns = master_blend_time_target_ns - master_blend_time_ns; + if (blend_time_target_diff_ns > NsFromSeconds(0.100) || blend_time_target_diff_ns < NsFromSeconds(-0.100)) + { + /* Snap blend time if it gets too far from target blend time */ + master_blend_time_ns = master_blend_time_target_ns; + } + u64 master_blend_tick = master_blend_time_ns / newest_snapshot->sim_dt_ns; + + /* Get snapshot nearest to master blend time */ + /* TODO: Blend */ + PP_Snapshot *left_snapshot = PP_NilSnapshot(); + PP_Snapshot *right_snapshot = newest_snapshot; + { + PP_Snapshot *ss = PP_SnapshotFromTick(master_client, master_client->first_tick); + while (ss->valid) + { + u64 next_tick = ss->next_tick; + i64 ss_time_ns = ss->sim_time_ns; + if (ss_time_ns < master_blend_time_ns && ss_time_ns > left_snapshot->sim_time_ns) + { + left_snapshot = ss; + } + if (ss_time_ns > master_blend_time_ns && ss_time_ns < right_snapshot->sim_time_ns) + { + right_snapshot = ss; + } + ss = PP_SnapshotFromTick(master_client, next_tick); + } + } + + /* Create world from blended master snapshots */ + f64 blend = 0; + if (left_snapshot->valid && right_snapshot->valid && right_snapshot->tick > left_snapshot->tick) + { + blend = (f64)(master_blend_tick - left_snapshot->tick) / (f64)(right_snapshot->tick - left_snapshot->tick); + f64 epsilon = 0.001; + if (blend < epsilon) + { + master_ss_is_blended = 0; + master_ss = left_snapshot; + } + else if (blend > 1 - epsilon) + { + master_ss_is_blended = 0; + master_ss = right_snapshot; + } + else + { + master_ss_is_blended = 1; + master_ss = PP_AcquireSnapshotFromLerp(master_blended_client, left_snapshot, right_snapshot, blend); + + /* Release unneeded blended master snapshots */ + if (master_ss->tick > 0) + { + PP_ReleaseSnapshotsInRange(master_blended_client, 0, master_ss->tick - 1); + PP_ReleaseSnapshotsInRange(master_blended_client, master_ss->tick + 1, U64Max); + } + } + } + else + { + master_ss_is_blended = 0; + master_ss = left_snapshot->valid ? left_snapshot : right_snapshot; + } + + /* Release unneeded master snapshots */ + u64 keep_master_tick = MinU64(left_snapshot->tick, master_client->double_ack); + if (keep_master_tick > 0) + { + PP_ReleaseSnapshotsInRange(master_client, 0, keep_master_tick - 1); + } + +#if 0 + DEBUGBREAKABLE; + LogDebugF("*************************************************"); + LogDebugF("local_client->last_tick: %F", FmtUint(local_client->last_tick)); + LogDebugF("master_sim_predicted_time_ns: %F", FmtSint(master_sim_predicted_time_ns)); + LogDebugF("tick_progress: %F", FmtFloat(tick_progress)); + LogDebugF("sim_publish_timescale: %F", FmtFloat(sim_publish_timescale)); + LogDebugF("last_tick_from_master_received_at_ns: %F", FmtSint(last_tick_from_master_received_at_ns)); + LogDebugF("average_master_receive_dt_ns: %F", FmtSint(average_master_receive_dt_ns)); + LogDebugF("next_tick_expected_ns: %F", FmtSint(next_tick_expected_ns)); + LogDebugF("master_blend_time_target_ns: %F", FmtSint(master_blend_time_target_ns)); + LogDebugF("blend_time_target_diff_ns: %F", FmtSint(blend_time_target_diff_ns)); + LogDebugF("master_blend_time_ns: %F", FmtSint(master_blend_time_ns)); + LogDebugF("left_snapshot->tick: %F", FmtUint(left_snapshot->tick)); + LogDebugF("right_snapshot->tick: %F", FmtUint(right_snapshot->tick)); + LogDebugF("master_ss->tick: %F", FmtUint(master_ss->tick)); +#endif + } + + if (master_ss->valid) + { + PP_Ent *master_player = PP_FirstWithProp(master_ss, PP_Prop_IsMaster); + + /* Update ent key from master */ + { + user_input_client->player_id = master_ss->local_player; + local_client->player_id = master_ss->local_player; + } + + /* Check for misprediction */ + u64 mispredicted_tick = 0; + if (!master_ss_is_blended) + { + /* TODO: Actually check for misprediction rather than triggering mispredict any time a new master snapshot is received */ + mispredicted_tick = master_ss->tick; + } + + u64 step_base_tick = local_client->last_tick; + u64 step_end_tick = step_base_tick + 1; + if (mispredicted_tick > 0) + { + step_base_tick = mispredicted_tick; + if (step_end_tick <= step_base_tick) + { + step_end_tick = step_base_tick + 1; + } + } + + /* We want to simulate the ahead of the server to predict client input. + * How many ticks ahead we want to simulate is a balance between added latency and the server not receiving our inputs on time. + * We can take the server's ack minus the server's tick to determine how many cmds of ours the server has buffered. + * + * If this buffer gets too low (because we are lagging behind or the connection is unstable), meaning the server is not getting our input on time: + * - Shorten local compute rate to increase the rate at which we predict ahead & produce cmds, until the server's ack indicates a buffer size within desired range. + * + * If this buffer gets too large (because the client predicts too far ahead), meaning unneeded latency is being introduced: + * - Dilate local compute rate to decrease the rate at which we predict ahead & produce cmds until the server's ack indicates a buffer size within desired range. + */ + { + i64 cmds_ahead_on_master = (i64)master_client->ack - (i64)master_client->last_tick; + if (cmds_ahead_on_master < -3 || cmds_ahead_on_master > 10) + { + /* Cmds are too far from master time, snap step end tick */ + i64 rtt_ns = master_client->last_rtt_ns; + f64 rtt_tick_ratio = (f64)(rtt_ns + (step_dt_ns - 1)) / (f64)step_dt_ns; + i64 num_predict_ticks = RoundF64ToI64(rtt_tick_ratio) + 5; + step_end_tick = master_client->last_tick + num_predict_ticks; + compute_timescale = 1.1; + } + else if (cmds_ahead_on_master > 2) + { + /* Slow down simulation to dial back how far ahead we are predicting and bring local sim time closer to master sim time */ + compute_timescale = 1.1; + } + else if (cmds_ahead_on_master < 1) + { + /* Speed up simulation rate predict more ticks and give master more inputs to work with */ + compute_timescale = 0.9; + } + else + { + /* Server's cmd buffer is in a healthy range */ + compute_timescale = 1; + } + } + + /* Sync master with local base tick */ + PP_Snapshot *base_ss = PP_SnapshotFromTick(local_client, step_base_tick); + if (mispredicted_tick) + { + if (base_ss->valid) + { + PP_SyncSnapshotEnts(base_ss, master_ss, master_player->key, 0); + } + else + { + base_ss = PP_AcquireSnapshot(local_client, master_ss, step_base_tick); + } + } + + /* Release any existing ticks that are about to be simulated */ + PP_ReleaseSnapshotsInRange(local_client, step_base_tick + 1, U64Max); + + /* Step */ + PP_GenerateuserInputCmds(user_input_client, step_end_tick); + { + PP_SimStepCtx ctx = ZI; + ctx.is_master = is_master; + ctx.sim_dt_ns = step_dt_ns; + ctx.accel = &accel; + ctx.user_input_client = user_input_client; + ctx.master_client = master_client; + ctx.publish_client = publish_client; + + u64 step_tick = step_base_tick + 1; + PP_Snapshot *prev_ss = base_ss; + while (step_tick <= step_end_tick) + { + ctx.world = PP_AcquireSnapshot(local_client, prev_ss, step_tick); + if (!mispredicted_tick && step_tick == step_end_tick) + { + PP_SyncSnapshotEnts(ctx.world, master_ss, master_player->key, PP_SyncFlag_NoSyncPredictables); + } + PP_StepSim(&ctx); + prev_ss = ctx.world; + ++step_tick; + } + } + } + } + + /* Publish snapshot to remote clients */ + for (u64 i = 0; i < store->num_clients_reserved; ++i) + { + PP_Client *client = &store->clients[i]; + if (client->valid && client != user_input_client && client != local_client && client != publish_client) + { + BB_Writer msg_bw = BB_WriterFromBuff(&msg_writer_bb); + + BB_WriteUV(&msg_bw, client->highest_received_tick); /* ack */ + BB_WriteUV(&msg_bw, client->ack); /* double ack */ + + PP_Snapshot *base_ss = PP_SnapshotFromTick(publish_client, client->ack); + PP_Snapshot *publish_ss; + if (client == master_client) + { + /* If sending to master, start sending all snapshots since last ack */ + publish_ss = PP_SnapshotFromClosestTickGte(publish_client, base_ss->tick + 1); + } + else + { + /* If sending to slave, only send latest snapshot */ + publish_ss = PP_SnapshotFromTick(publish_client, publish_client->last_tick); + } + + while (publish_ss->valid) + { + BB_Writer snapshot_bw = BB_WriterFromBuff(&snapshot_writer_bb); + String tmp_snapshot_encoded = ZI; + { + BB_WriteUV(&snapshot_bw, base_ss->tick); + BB_WriteUV(&snapshot_bw, publish_ss->tick); + PP_EncodeSnapshot(&snapshot_bw, client, base_ss, publish_ss); + tmp_snapshot_encoded.len = BB_GetNumBytesWritten(&snapshot_bw); + tmp_snapshot_encoded.text = BB_GetWrittenRaw(&snapshot_bw); + } + BB_WriteUV(&msg_bw, tmp_snapshot_encoded.len); + BB_WriteBytes(&msg_bw, tmp_snapshot_encoded); + publish_ss = PP_SnapshotFromTick(publish_client, publish_ss->tick + 1); + } + BB_WriteUV(&msg_bw, 0); + + String encoded = ZI; + encoded.len = BB_GetNumBytesWritten(&msg_bw); + encoded.text = BB_GetWrittenRaw(&msg_bw); + N_Write(host, client->channel_id, encoded, 0); + } + } + + /* Copy local snapshot to user client */ + { + PP_Snapshot *local_ss = PP_SnapshotFromTick(local_client, local_client->last_tick); + if (local_ss->valid) + { + /* TODO: Double buffer */ + Lock lock = LockE(&g->local_to_user_client_mutex); + PP_AcquireSnapshot(g->local_to_user_client, local_ss, local_ss->tick); + i64 publish_ns = TimeNs(); + if (last_publish_to_user_ns == 0) + { + last_publish_to_user_ns = publish_ns - g->average_local_to_user_snapshot_publish_dt_ns; + } + g->local_to_user_client_publish_dt_ns = publish_ns - last_publish_to_user_ns; + g->local_to_user_client_publish_time_ns = publish_ns; + last_publish_to_user_ns = publish_ns; + PP_ReleaseSnapshotsInRange(g->local_to_user_client, 0, local_ss->tick - 1); + Unlock(&lock); + } + } + + skip_step: + + /* Send host messages */ + N_EndUpdate(host); + __profframe("Local sim"); + + EndScratch(scratch); } + } + +#if 0 + if (IsSwappingOut()) + { + TempArena scratch = BeginScratchNoConflict(); + u64 max_size = Mebi(64); + u8 *bytes = PushStructsNoZero(scratch.arena, u8, max_size); + BB_Buff bb = BB_BuffFromString(STRING(max_size, bytes)); + { + BB_Writer bw = BB_WriterFromBuff(&bb); + + u64 tick = local_client->last_tick; + PP_Snapshot *ss = PP_SnapshotFromTick(local_client, tick); + BB_WriteUBits(&bw, tick, 64); + BB_WriteUid(&bw, local_client->player_id.uid); + PP_EncodeSnapshot(&bw, local_client, PP_NilSnapshot(), ss); + WriteSwappedState(Lit("pp_snapshot"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw))); + } + EndScratch(scratch); + } #endif #if 0 - PP_ReleaseClientStore(store); - PP_ReleaseAccel(&accel); - BB_ReleaseBuff(&snapshot_writer_bb); - BB_ReleaseBuff(&msg_writer_bb); - N_ReleaseHost(host); + PP_ReleaseClientStore(store); + PP_ReleaseAccel(&accel); + BB_ReleaseBuff(&snapshot_writer_bb); + BB_ReleaseBuff(&msg_writer_bb); + N_ReleaseHost(host); #endif } diff --git a/src/pp_old/pp.h b/src/pp_old/pp.h index 09b29215..b85c3d50 100644 --- a/src/pp_old/pp.h +++ b/src/pp_old/pp.h @@ -4,98 +4,98 @@ //- Bind kinds Enum(PP_BindKind) { - PP_BindKind_None, + PP_BindKind_None, - PP_BindKind_MoveUp, - PP_BindKind_MoveDown, - PP_BindKind_MoveLeft, - PP_BindKind_MoveRight, - PP_BindKind_Walk, - PP_BindKind_Fire, - PP_BindKind_AltFire, + PP_BindKind_MoveUp, + PP_BindKind_MoveDown, + PP_BindKind_MoveLeft, + PP_BindKind_MoveRight, + PP_BindKind_Walk, + PP_BindKind_Fire, + PP_BindKind_AltFire, - PP_BindKind_TestTile, - PP_BindKind_DebugClear, - PP_BindKind_DebugSpawn1, - PP_BindKind_DebugSpawn2, - PP_BindKind_DebugSpawn3, - PP_BindKind_DebugSpawn4, - PP_BindKind_DebugWalls, - PP_BindKind_DebugFollow, - PP_BindKind_DebugDraw, - PP_BindKind_DebugConsole, - PP_BindKind_DebugCamera, - PP_BindKind_DebugLister, - PP_BindKind_DebugPause, - PP_BindKind_DebugStep, - PP_BindKind_DebugDrag, - PP_BindKind_DebugDelete, - PP_BindKind_DebugTeleport, - PP_BindKind_DebugExplode, - PP_BindKind_DebugToggleTopmost, - PP_BindKind_DebugUi, - PP_BindKind_FullscreenMod, - PP_BindKind_Fullscreen, - PP_BindKind_ZoomIn, - PP_BindKind_ZoomOut, - PP_BindKind_Pan, + PP_BindKind_TestTile, + PP_BindKind_DebugClear, + PP_BindKind_DebugSpawn1, + PP_BindKind_DebugSpawn2, + PP_BindKind_DebugSpawn3, + PP_BindKind_DebugSpawn4, + PP_BindKind_DebugWalls, + PP_BindKind_DebugFollow, + PP_BindKind_DebugDraw, + PP_BindKind_DebugConsole, + PP_BindKind_DebugCamera, + PP_BindKind_DebugLister, + PP_BindKind_DebugPause, + PP_BindKind_DebugStep, + PP_BindKind_DebugDrag, + PP_BindKind_DebugDelete, + PP_BindKind_DebugTeleport, + PP_BindKind_DebugExplode, + PP_BindKind_DebugToggleTopmost, + PP_BindKind_DebugUi, + PP_BindKind_FullscreenMod, + PP_BindKind_Fullscreen, + PP_BindKind_ZoomIn, + PP_BindKind_ZoomOut, + PP_BindKind_Pan, #if IsRtcEnabled - /* Debug */ + /* Debug */ - PP_BindKind_ResetDebugSteps, - PP_BindKind_IncrementDebugSteps, - PP_BindKind_DecrementDebugSteps, + PP_BindKind_ResetDebugSteps, + PP_BindKind_IncrementDebugSteps, + PP_BindKind_DecrementDebugSteps, #endif - PP_BindKind_Count + PP_BindKind_Count }; //- Test bindings /* TODO: Remove this */ Global Readonly PP_BindKind g_binds[Btn_Count] = { - [Btn_W] = PP_BindKind_MoveUp, - [Btn_S] = PP_BindKind_MoveDown, - [Btn_A] = PP_BindKind_MoveLeft, - [Btn_D] = PP_BindKind_MoveRight, - [Btn_M1] = PP_BindKind_Fire, - [Btn_M2] = PP_BindKind_AltFire, + [Btn_W] = PP_BindKind_MoveUp, + [Btn_S] = PP_BindKind_MoveDown, + [Btn_A] = PP_BindKind_MoveLeft, + [Btn_D] = PP_BindKind_MoveRight, + [Btn_M1] = PP_BindKind_Fire, + [Btn_M2] = PP_BindKind_AltFire, #if 0 - [Btn_Alt] = PP_BindKind_Walk, + [Btn_Alt] = PP_BindKind_Walk, #endif - /* Testing */ - [Btn_Z] = PP_BindKind_TestTile, - [Btn_M5] = PP_BindKind_DebugDrag, - [Btn_M4] = PP_BindKind_DebugDelete, - [Btn_F] = PP_BindKind_DebugExplode, - [Btn_T] = PP_BindKind_DebugTeleport, - [Btn_C] = PP_BindKind_DebugClear, - [Btn_1] = PP_BindKind_DebugSpawn1, - [Btn_2] = PP_BindKind_DebugSpawn2, - [Btn_3] = PP_BindKind_DebugSpawn3, - [Btn_4] = PP_BindKind_DebugSpawn4, - [Btn_G] = PP_BindKind_DebugWalls, - [Btn_N] = PP_BindKind_DebugStep, - [Btn_Q] = PP_BindKind_DebugFollow, - [Btn_F1] = PP_BindKind_DebugPause, - [Btn_F2] = PP_BindKind_DebugCamera, - [Btn_F3] = PP_BindKind_DebugDraw, - [Btn_Tab] = PP_BindKind_DebugLister, - [Btn_F4] = PP_BindKind_DebugToggleTopmost, - [Btn_F5] = PP_BindKind_DebugUi, - [Btn_GraveAccent] = PP_BindKind_DebugConsole, - [Btn_Alt] = PP_BindKind_FullscreenMod, - [Btn_Enter] = PP_BindKind_Fullscreen, - [Btn_MWheelUp] = PP_BindKind_ZoomIn, - [Btn_MWheelDown] = PP_BindKind_ZoomOut, - [Btn_M3] = PP_BindKind_Pan, + /* Testing */ + [Btn_Z] = PP_BindKind_TestTile, + [Btn_M5] = PP_BindKind_DebugDrag, + [Btn_M4] = PP_BindKind_DebugDelete, + [Btn_F] = PP_BindKind_DebugExplode, + [Btn_T] = PP_BindKind_DebugTeleport, + [Btn_C] = PP_BindKind_DebugClear, + [Btn_1] = PP_BindKind_DebugSpawn1, + [Btn_2] = PP_BindKind_DebugSpawn2, + [Btn_3] = PP_BindKind_DebugSpawn3, + [Btn_4] = PP_BindKind_DebugSpawn4, + [Btn_G] = PP_BindKind_DebugWalls, + [Btn_N] = PP_BindKind_DebugStep, + [Btn_Q] = PP_BindKind_DebugFollow, + [Btn_F1] = PP_BindKind_DebugPause, + [Btn_F2] = PP_BindKind_DebugCamera, + [Btn_F3] = PP_BindKind_DebugDraw, + [Btn_Tab] = PP_BindKind_DebugLister, + [Btn_F4] = PP_BindKind_DebugToggleTopmost, + [Btn_F5] = PP_BindKind_DebugUi, + [Btn_GraveAccent] = PP_BindKind_DebugConsole, + [Btn_Alt] = PP_BindKind_FullscreenMod, + [Btn_Enter] = PP_BindKind_Fullscreen, + [Btn_MWheelUp] = PP_BindKind_ZoomIn, + [Btn_MWheelDown] = PP_BindKind_ZoomOut, + [Btn_M3] = PP_BindKind_Pan, #if IsRtcEnabled - [Btn_ForwardSlash] = PP_BindKind_ResetDebugSteps, - [Btn_Comma] = PP_BindKind_DecrementDebugSteps, - [Btn_Period] = PP_BindKind_IncrementDebugSteps + [Btn_ForwardSlash] = PP_BindKind_ResetDebugSteps, + [Btn_Comma] = PP_BindKind_DecrementDebugSteps, + [Btn_Period] = PP_BindKind_IncrementDebugSteps #endif }; @@ -104,9 +104,9 @@ Global Readonly PP_BindKind g_binds[Btn_Count] = { Struct(PP_SecondsStat) { - u64 last_second_start; - u64 last_second_end; - u64 last_second; + u64 last_second_start; + u64 last_second_end; + u64 last_second; }; //////////////////////////////////////////////////////////// @@ -114,12 +114,12 @@ Struct(PP_SecondsStat) Struct(PP_ConsoleLog) { - String msg; - i32 level; - i32 color_index; - DateTime datetime; - PP_ConsoleLog *prev; - PP_ConsoleLog *next; + String msg; + i32 level; + i32 color_index; + DateTime datetime; + PP_ConsoleLog *prev; + PP_ConsoleLog *next; }; //////////////////////////////////////////////////////////// @@ -127,17 +127,17 @@ Struct(PP_ConsoleLog) Struct(PP_DecodeQueueNode) { - PP_Client *client; - u64 tick; - u64 base_tick; - String tmp_encoded; - PP_DecodeQueueNode *next; + PP_Client *client; + u64 tick; + u64 base_tick; + String tmp_encoded; + PP_DecodeQueueNode *next; }; Struct(PP_DecodeQueue) { - PP_DecodeQueueNode *first; - PP_DecodeQueueNode *last; + PP_DecodeQueueNode *first; + PP_DecodeQueueNode *last; }; //////////////////////////////////////////////////////////// @@ -145,137 +145,137 @@ Struct(PP_DecodeQueue) Struct(PP_BindState) { - b32 is_held; /* Is this bind held down this frame */ - u32 num_presses; /* How many times was this bind's pressed since last frame */ - u32 num_repeats; /* How many times was this bind's key repeated since last frame */ - u32 num_presses_and_repeats; /* Same as `num_presses` but includes key repeats as well */ - u32 num_releases; /* How many times was this bind released since last frame */ + b32 is_held; /* Is this bind held down this frame */ + u32 num_presses; /* How many times was this bind's pressed since last frame */ + u32 num_repeats; /* How many times was this bind's key repeated since last frame */ + u32 num_presses_and_repeats; /* Same as `num_presses` but includes key repeats as well */ + u32 num_releases; /* How many times was this bind released since last frame */ }; Struct(PP_SharedUserState) { - Atomic32 shutdown; + Atomic32 shutdown; - Fence shutdown_jobs_fence; - u64 shutdown_jobs_count; + Fence shutdown_jobs_fence; + u64 shutdown_jobs_count; - Arena *arena; - String connect_address_str; + Arena *arena; + String connect_address_str; - PP_ClientStore *user_client_store; - PP_Client *user_unblended_client; /* Contains snapshots received from local sim */ - PP_Client *user_blended_client; /* Contains single snapshot from result of blending local sim snapshots */ - PP_Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */ + PP_ClientStore *user_client_store; + PP_Client *user_unblended_client; /* Contains snapshots received from local sim */ + PP_Client *user_blended_client; /* Contains single snapshot from result of blending local sim snapshots */ + PP_Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */ - u64 user_tick; - u64 window_os_gen; + u64 user_tick; + u64 window_os_gen; - //- Usage stats - i64 last_second_reset_ns; - PP_SecondsStat net_bytes_read; - PP_SecondsStat net_bytes_sent; + //- Usage stats + i64 last_second_reset_ns; + PP_SecondsStat net_bytes_read; + PP_SecondsStat net_bytes_sent; - //- Renderer gbuffers - GPU_Resource *albedo; - GPU_Resource *emittance; - GPU_Resource *emittance_flood_read; - GPU_Resource *emittance_flood_target; - GPU_Resource *shade_read; - GPU_Resource *shade_target; + //- Renderer gbuffers + GPU_Resource *albedo; + GPU_Resource *emittance; + GPU_Resource *emittance_flood_read; + GPU_Resource *emittance_flood_target; + GPU_Resource *shade_read; + GPU_Resource *shade_target; - //- Renderer transient buffers - GPU_TransientBuffer material_instances_tbuff; - GPU_TransientBuffer grids_tbuff; - Arena *material_instances_arena; - Arena *grids_arena; + //- Renderer transient buffers + GPU_TransientBuffer material_instances_tbuff; + GPU_TransientBuffer grids_tbuff; + Arena *material_instances_arena; + Arena *grids_arena; - //- Renderer state - RandState frame_rand; - u64 frame_index; - i64 gpu_submit_fence_target; + //- Renderer state + RandState frame_rand; + u64 frame_index; + i64 gpu_submit_fence_target; - //- Bind state - PP_BindState bind_states[PP_BindKind_Count]; + //- Bind state + PP_BindState bind_states[PP_BindKind_Count]; - //- Window -> user - Mutex sys_window_events_mutex; - Arena *sys_window_events_arena; + //- Window -> user + Mutex sys_window_events_mutex; + Arena *sys_window_events_arena; - //- User -> sim - Mutex user_sim_cmd_mutex; - PP_ControlData user_sim_cmd_control; - PP_EntKey user_hovered_ent; - u64 last_user_sim_cmd_gen; - u64 user_sim_cmd_gen; + //- User -> sim + Mutex user_sim_cmd_mutex; + PP_ControlData user_sim_cmd_control; + PP_EntKey user_hovered_ent; + u64 last_user_sim_cmd_gen; + u64 user_sim_cmd_gen; - Atomic32 user_paused; - Atomic32 user_paused_steps; + Atomic32 user_paused; + Atomic32 user_paused_steps; - //- Sim -> user - Mutex local_to_user_client_mutex; - PP_ClientStore *local_to_user_client_store; - PP_Client *local_to_user_client; - i64 local_to_user_client_publish_dt_ns; - i64 local_to_user_client_publish_time_ns; + //- Sim -> user + Mutex local_to_user_client_mutex; + PP_ClientStore *local_to_user_client_store; + PP_Client *local_to_user_client; + i64 local_to_user_client_publish_dt_ns; + i64 local_to_user_client_publish_time_ns; - //- Local sim -> user rolling window of publish time deltas - i64 last_local_to_user_snapshot_published_at_ns; - i64 average_local_to_user_snapshot_publish_dt_ns; + //- Local sim -> user rolling window of publish time deltas + i64 last_local_to_user_snapshot_published_at_ns; + i64 average_local_to_user_snapshot_publish_dt_ns; - i64 local_sim_predicted_time_ns; /* Calculated from +