TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
27 / 27
100.0%
Branches:
16 / 16
100.0%
Functions:
5 / 5, 1 excl
100.0%

random/philox.h
Line Branch Exec Source
1 /// @file
2 /// @brief The Philox4x32-10 counter-based generator for the CPU and GPU backends.
3 #pragma once
4
5 #include "terraingen/util/portable.h"
6
7 namespace terraingen {
8
9 /// Four 32-bit words: a Philox counter or output block.
10 struct U32x4 {
11 14 uint32_t x = 0; ///< First word.
12 7 uint32_t y = 0; ///< Second word.
13 6 uint32_t z = 0; ///< Third word.
14 5 uint32_t w = 0; ///< Fourth word.
15
16 #ifndef __SLANG__
17
8/8
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 4 times.
14 bool operator==(const U32x4&) const = default;
18 #endif
19 };
20
21 /// Two 32-bit words: a Philox key.
22 struct U32x2 {
23 3 uint32_t x = 0; ///< First word.
24 2 uint32_t y = 0; ///< Second word.
25
26 #ifndef __SLANG__
27
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
3 bool operator==(const U32x2&) const = default;
28 #endif
29 };
30
31 namespace detail {
32
33 /// The high (`x`) and low (`y`) words of the 64-bit product `a * b`, built from 16-bit halves on
34 /// GPUs without 64-bit integers, with the same result.
35 2052712980 constexpr U32x2 MulHiLo32(uint32_t a, uint32_t b) {
36 2052712980 U32x2 result = {};
37 #ifdef __SLANG__
38 const uint32_t aLow = a & 0xFFFFu;
39 const uint32_t aHigh = a >> 16u;
40 const uint32_t bLow = b & 0xFFFFu;
41 const uint32_t bHigh = b >> 16u;
42 const uint32_t lowHigh = aLow * bHigh;
43 const uint32_t highLow = aHigh * bLow;
44 const uint32_t middle = ((aLow * bLow) >> 16u) + (lowHigh & 0xFFFFu) + (highLow & 0xFFFFu);
45 result.x = aHigh * bHigh + (lowHigh >> 16u) + (highLow >> 16u) + (middle >> 16u);
46 result.y = a * b;
47 #else
48 2052712980 const std::uint64_t product = std::uint64_t(a) * b;
49 2052712980 result.x = uint32_t(product >> 32u);
50 2052712980 result.y = uint32_t(product);
51 #endif
52 2052712980 return result;
53 }
54
55 /// One Philox4x32 round of a block under a round key.
56 1026356490 constexpr U32x4 PhiloxRound(U32x4 counter, U32x2 key) {
57 1026356490 const U32x2 first = MulHiLo32(0xD2511F53u, counter.x);
58 1026356490 const U32x2 second = MulHiLo32(0xCD9E8D57u, counter.z);
59 1026356490 const U32x4 result = {second.x ^ counter.y ^ key.x, second.y, first.x ^ counter.w ^ key.y,
60 1026356490 first.y};
61 1026356490 return result;
62 }
63
64 } // namespace detail
65
66 /// Philox4x32-10: 128 pseudo-random bits, a bijection of the counter under the key, so any
67 /// element of any stream can be computed directly. Bit-identical on every platform and GPU.
68 757106067 constexpr U32x4 Philox4x32(U32x4 counter, U32x2 key) {
69
2/2
✓ Branch 0 taken 1026356490 times.
✓ Branch 1 taken 757106067 times.
1128992139 for (int round = 0; round < 10; ++round) {
70
2/2
✓ Branch 0 taken 923720841 times.
✓ Branch 1 taken 757106067 times.
1026356490 if (round > 0) {
71 923720841 key.x += 0x9E3779B9u;
72 923720841 key.y += 0xBB67AE85u;
73 }
74 1026356490 counter = detail::PhiloxRound(counter, key);
75 }
76 757106067 return counter;
77 }
78
79 } // namespace terraingen
80