Skip to content

Created a new example to test the compilation and concepts of samplers#252

Open
karimsayedre wants to merge 27 commits intomasterfrom
sampler-concepts
Open

Created a new example to test the compilation and concepts of samplers#252
karimsayedre wants to merge 27 commits intomasterfrom
sampler-concepts

Conversation

@karimsayedre
Copy link
Copy Markdown
Contributor

No description provided.

Comment thread 37_HLSLSamplingTests/app_resources/test_compile.comp.hlsl Outdated
Comment thread CMakeLists.txt Outdated
@devshgraphicsprogramming
Copy link
Copy Markdown
Member

devshgraphicsprogramming commented Mar 23, 2026

Everything looks good, although it would be nice to try the CDF and Alias table samples at several different PoT sizes from 8 to 128*1024^2 to find the perf crossover point across sizes

Also do a 1 Reservoir sampling from size of 2 to 32 because that will likely be faster than CDF and Alias at really small sizes (same way linear search is vs binary and hashmap due to caching effects)

@devshgraphicsprogramming
Copy link
Copy Markdown
Member

Also see if you can address any of the open comments in the BxDF testing PR
#236


pdf = rcpPdf > numeric_limits<scalar_type>::min ? (1.0 / rcpPdf) : numeric_limits<scalar_type>::max;
const scalar_type fwdPdf = pst.forwardPdf(pstCache);
pdf = fwdPdf < numeric_limits<scalar_type>::max ? fwdPdf : numeric_limits<scalar_type>::max;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this does nothing

using value_type = T;
template<typename V, typename I>
void get(I i, NBL_REF_ARG(V) val) NBL_CONST_MEMBER_FUNC { val = V(data[i]); }
T operator[](uint32_t i) NBL_CONST_MEMBER_FUNC { return data[i]; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you need operator[] for ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karimsayedre still a TODO

Comment on lines -42 to -45

float32_t2 diff = input.u - output.inverted;
output.roundtripError = nbl::hlsl::length(diff);
output.jacobianProduct = (float32_t(1.0) / output.forwardPdf) * output.backwardPdf;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even if you're no longer 100% bijective in all cases, you can perturb input.u by epsillon and work out the Jacobian * forwardPdf and compare against 1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karimsayedre add this test back in modified form, its very important

Comment on lines -39 to -44
sampling::Linear<float32_t>::cache_type cache;
output.generateInversed = _sampler.generateInverse(output.generated);
output.backwardPdf = _sampler.backwardPdf(output.generated);
}
output.roundtripError = abs(input.u - output.generateInversed);
output.jacobianProduct = (float32_t(1.0) / output.forwardPdf) * output.backwardPdf;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as bilinear

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karimsayedre add this test back in modified form, its very important

Comment on lines -41 to -48
{
sampling::ProjectedSphere<float32_t>::cache_type cache;
output.inverted = sampler.generateInverse(output.generated);
output.backwardPdf = sampler.backwardPdf(output.generated);
}
float32_t2 xyDiff = output.modifiedU.xy - output.inverted.xy;
output.roundtripError = nbl::hlsl::length(xyDiff);
output.jacobianProduct = (float32_t(1.0) / output.forwardPdf) * output.backwardPdf;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can still work out a Jacobian from perturbing u

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only for the hemisphere I guess

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karimsayedre add this test back in modified form, its very important

sampling::ProjectedSphericalTriangle<float32_t>::cache_type cache;
output.generated = sampler.generate(input.u, cache);
output.cachedPdf = cache.pdf;
output.forwardPdf = sampler.forwardPdf(cache);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can do a JAcobian test, since its bijective if you wanted to

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karimsayedre still a TODO

Comment on lines 51 to 53
output.inverted = sampler.generateInverse(output.generated);
// Backward: evaluate pdf at generated point (no cache needed)
output.backwardPdf = sampler.backwardPdf(output.generated);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

differentiated generateInverse Jacobian determinant should equal the PDF I think

while differentiated generate multiplied with PDF comes out to 1

}

output.backwardPdf = sampler.backwardPdf(output.generated);
output.separateBackwardPdf = sampler.separateBackwardPdf(output.generated);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can test a lot of things, like:

  1. separate/independent PDF multiplying together to give the scalar PDF
    2 Jacobian test follows PDF

Comment on lines +26 to +35
const float32_t toFloat = asfloat(0x2f800004u);
uint32_t2 acc = (uint32_t2)0;
uint32_t accPdf = 0;
for (uint32_t i = 0u; i < uint32_t(BENCH_ITERS); i++)
{
float32_t2 u = float32_t2(rng(), rng()) * toFloat;
sampling::SphericalRectangle<float32_t>::cache_type cache;
acc ^= asuint(sampler.generate(u, cache));
accPdf ^= asuint(sampler.forwardPdf(cache));
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need two benchmark modes, multiple samples from same create and multiple samples with create (to measure set-up overhead)

first one matters only for rejection sampling or multisampling, second one is more real use case when you only draw 1 NEE sample per path vertex so the create to generate ratio is 1:1

# Conflicts:
#	common/include/nbl/examples/Tester/ITester.h
- lots of testers for all samplers with more focus on spherical ones, then made sure they *mostly pass*
- `isValidSphericalTriangle()` is a lot more tolerant, from ~17 degrees to 1.7 degrees, which means more small triangles are tested
- pdf and weight consistency missing tests
# Conflicts:
#	31_HLSLPathTracer/CMakeLists.txt
#	31_HLSLPathTracer/app_resources/hlsl/spirv/pt.compute.rectangle.rwmc.linear.proxy.hlsl
#	31_HLSLPathTracer/app_resources/hlsl/spirv/pt.compute.variant.shared.hlsl
#	31_HLSLPathTracer/include/nbl/this_example/render_variant_info.hpp
#	31_HLSLPathTracer/main.cpp
… adapt everything tests to that, and:

- Make sure `generete()` and `generateSurfaceOffset()` are on the same page, that way we don't have to do separate tests for it
- No performance regression
- Benchmarks are done before tests
- Reduced some CPU sampler test iterations because it was too slow
- Workgroup size is now shared between tests and benchmarks, also reduced from 96 to 64
@devshgraphicsprogramming
Copy link
Copy Markdown
Member

devshgraphicsprogramming commented Apr 15, 2026

There's a fundamental problem in this PR, none of the continuous 2D samplers have Jacobian testing of generate (via numerical differentiation) which is why I think a bug on the Uniform Hemisphere sampler is not caught

I need in the next PR:

  1. selective JAcobian tests (when forward PDF is not INF) always on all 2D continuous samplers (special handling of discontinuities like projected sphere and hemisphere is needed as @AnastaZIuk pointed out)
  2. benchmark of 1:1 creation and sample drawing vs 1:16

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants