-
Notifications
You must be signed in to change notification settings - Fork 70
Expand file tree
/
Copy pathalias_table.hlsl
More file actions
131 lines (112 loc) · 3.93 KB
/
alias_table.hlsl
File metadata and controls
131 lines (112 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O.
// This file is part of the "Nabla Engine".
// For conditions of distribution and use, see copyright notice in nabla.h
#ifndef _NBL_BUILTIN_HLSL_SAMPLING_ALIAS_TABLE_INCLUDED_
#define _NBL_BUILTIN_HLSL_SAMPLING_ALIAS_TABLE_INCLUDED_
#include <nbl/builtin/hlsl/cpp_compat.hlsl>
#include <nbl/builtin/hlsl/bit.hlsl>
#include <nbl/builtin/hlsl/concepts/accessors/generic_shared_data.hlsl>
namespace nbl
{
namespace hlsl
{
namespace sampling
{
// Alias Method (Vose/Walker) discrete sampler.
//
// Samples a discrete index in [0, N) with probability proportional to
// precomputed weights in O(1) time per sample, using a prebuilt alias table.
//
// Accessor template parameters must satisfy GenericReadAccessor:
// accessor.template get<V, I>(index, outVal) // void, writes to outVal
//
// - ProbabilityAccessor: reads scalar_type threshold in [0, 1] for bin i
// - AliasIndexAccessor: reads uint32_t redirect index for bin i
// - PdfAccessor: reads scalar_type weight[i] / totalWeight
//
// Satisfies TractableSampler (not BackwardTractableSampler: the mapping is discrete).
// The cache stores the PDF value looked up during generate, avoiding redundant
// storage of the codomain (sampled index) which is already the return value.
template<typename T, typename Domain, typename Codomain, typename ProbabilityAccessor, typename AliasIndexAccessor, typename PdfAccessor
NBL_PRIMARY_REQUIRES(
concepts::accessors::GenericReadAccessor<ProbabilityAccessor, T, Codomain> &&
concepts::accessors::GenericReadAccessor<AliasIndexAccessor, Codomain, Codomain> &&
concepts::accessors::GenericReadAccessor<PdfAccessor, T, Codomain>)
struct AliasTable
{
using scalar_type = T;
using domain_type = Domain;
using codomain_type = Codomain;
using density_type = scalar_type;
using weight_type = density_type;
struct cache_type
{
density_type pdf;
};
static AliasTable create(NBL_CONST_REF_ARG(ProbabilityAccessor) _probAccessor, NBL_CONST_REF_ARG(AliasIndexAccessor) _aliasAccessor, NBL_CONST_REF_ARG(PdfAccessor) _pdfAccessor, codomain_type _size)
{
AliasTable retval;
retval.probAccessor = _probAccessor;
retval.aliasAccessor = _aliasAccessor;
retval.pdfAccessor = _pdfAccessor;
// Precompute tableSize as float minus 1 ULP so that u=1.0 maps to bin N-1
const scalar_type exact = scalar_type(_size);
retval.tableSizeMinusUlp = nbl::hlsl::bit_cast<scalar_type>(nbl::hlsl::bit_cast<uint32_t>(exact) - 1u);
return retval;
}
// BasicSampler interface
codomain_type generate(const domain_type u)
{
const scalar_type scaled = u * tableSizeMinusUlp;
const codomain_type bin = codomain_type(scaled);
const scalar_type remainder = scaled - scalar_type(bin);
scalar_type prob;
probAccessor.template get<scalar_type, codomain_type>(bin, prob);
// Use if-statement to avoid select: aliasIndex is a dependent read
codomain_type result;
if (remainder < prob)
{
result = bin;
}
else
{
codomain_type alias;
aliasAccessor.template get<codomain_type, codomain_type>(bin, alias);
result = alias;
}
return result;
}
// TractableSampler interface
codomain_type generate(const domain_type u, NBL_REF_ARG(cache_type) cache)
{
const codomain_type result = generate(u);
pdfAccessor.template get<scalar_type, codomain_type>(result, cache.pdf);
return result;
}
density_type forwardPdf(NBL_CONST_REF_ARG(cache_type) cache)
{
return cache.pdf;
}
weight_type forwardWeight(NBL_CONST_REF_ARG(cache_type) cache)
{
return cache.pdf;
}
density_type backwardPdf(const codomain_type v)
{
scalar_type pdf;
pdfAccessor.template get<scalar_type, codomain_type>(v, pdf);
return pdf;
}
weight_type backwardWeight(const codomain_type v)
{
return backwardPdf(v);
}
ProbabilityAccessor probAccessor;
AliasIndexAccessor aliasAccessor;
PdfAccessor pdfAccessor;
scalar_type tableSizeMinusUlp;
};
} // namespace sampling
} // namespace hlsl
} // namespace nbl
#endif