2013-06-07 16:06:22 +00:00
|
|
|
/*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Copyright 2011-2013 Blender Foundation
|
2013-06-07 16:06:22 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2013-06-07 16:06:22 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2013-06-07 16:06:22 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
2014-12-25 01:50:24 +00:00
|
|
|
* limitations under the License.
|
2013-06-07 16:06:22 +00:00
|
|
|
*/
|
|
|
|
|
2014-08-26 18:10:48 +00:00
|
|
|
/* TODO(sergey): Consider moving portable ctz/clz stuff to util. */
|
|
|
|
|
2013-06-07 16:06:22 +00:00
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
/* "Correlated Multi-Jittered Sampling"
|
|
|
|
* Andrew Kensler, Pixar Technical Memo 13-01, 2013 */
|
|
|
|
|
2021-02-05 05:23:34 +00:00
|
|
|
/* TODO: find good value, suggested 64 gives pattern on cornell box ceiling. */
|
2013-06-07 16:06:22 +00:00
|
|
|
#define CMJ_RANDOM_OFFSET_LIMIT 4096
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline bool cmj_is_pow2(int i)
|
2013-06-07 16:06:22 +00:00
|
|
|
{
|
2016-02-24 13:23:45 +00:00
|
|
|
return (i > 1) && ((i & (i - 1)) == 0);
|
2013-06-07 16:06:22 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline int cmj_fast_mod_pow2(int a, int b)
|
2013-06-07 16:06:22 +00:00
|
|
|
{
|
|
|
|
return (a & (b - 1));
|
|
|
|
}
|
|
|
|
|
2015-11-03 13:44:33 +00:00
|
|
|
/* b must be > 1 */
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline int cmj_fast_div_pow2(int a, int b)
|
2013-06-07 16:06:22 +00:00
|
|
|
{
|
2014-08-26 08:20:21 +00:00
|
|
|
kernel_assert(b > 1);
|
2019-08-26 13:08:46 +00:00
|
|
|
return a >> count_trailing_zeros(b);
|
2013-06-07 16:06:22 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline uint cmj_w_mask(uint w)
|
2013-06-07 16:06:22 +00:00
|
|
|
{
|
2014-08-26 08:20:21 +00:00
|
|
|
kernel_assert(w > 1);
|
2019-08-26 13:08:46 +00:00
|
|
|
return ((1 << (32 - count_leading_zeros(w))) - 1);
|
2013-06-07 16:06:22 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline uint cmj_permute(uint i, uint l, uint p)
|
2013-06-07 16:06:22 +00:00
|
|
|
{
|
|
|
|
uint w = l - 1;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2013-06-07 16:06:22 +00:00
|
|
|
if ((l & w) == 0) {
|
|
|
|
/* l is a power of two (fast) */
|
|
|
|
i ^= p;
|
|
|
|
i *= 0xe170893d;
|
|
|
|
i ^= p >> 16;
|
|
|
|
i ^= (i & w) >> 4;
|
|
|
|
i ^= p >> 8;
|
|
|
|
i *= 0x0929eb3f;
|
|
|
|
i ^= p >> 23;
|
|
|
|
i ^= (i & w) >> 1;
|
|
|
|
i *= 1 | p >> 27;
|
|
|
|
i *= 0x6935fa69;
|
|
|
|
i ^= (i & w) >> 11;
|
|
|
|
i *= 0x74dcb303;
|
|
|
|
i ^= (i & w) >> 2;
|
|
|
|
i *= 0x9e501cc3;
|
|
|
|
i ^= (i & w) >> 2;
|
|
|
|
i *= 0xc860a3df;
|
|
|
|
i &= w;
|
|
|
|
i ^= i >> 5;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2013-06-07 16:06:22 +00:00
|
|
|
return (i + p) & w;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* l is not a power of two (slow) */
|
|
|
|
w = cmj_w_mask(w);
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2013-06-07 16:06:22 +00:00
|
|
|
do {
|
|
|
|
i ^= p;
|
|
|
|
i *= 0xe170893d;
|
|
|
|
i ^= p >> 16;
|
|
|
|
i ^= (i & w) >> 4;
|
|
|
|
i ^= p >> 8;
|
|
|
|
i *= 0x0929eb3f;
|
|
|
|
i ^= p >> 23;
|
|
|
|
i ^= (i & w) >> 1;
|
|
|
|
i *= 1 | p >> 27;
|
|
|
|
i *= 0x6935fa69;
|
|
|
|
i ^= (i & w) >> 11;
|
|
|
|
i *= 0x74dcb303;
|
|
|
|
i ^= (i & w) >> 2;
|
|
|
|
i *= 0x9e501cc3;
|
|
|
|
i ^= (i & w) >> 2;
|
|
|
|
i *= 0xc860a3df;
|
|
|
|
i &= w;
|
|
|
|
i ^= i >> 5;
|
2015-03-27 19:15:15 +00:00
|
|
|
} while (i >= l);
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2013-06-07 16:06:22 +00:00
|
|
|
return (i + p) % l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline uint cmj_hash(uint i, uint p)
|
2013-06-07 16:06:22 +00:00
|
|
|
{
|
|
|
|
i ^= p;
|
|
|
|
i ^= i >> 17;
|
|
|
|
i ^= i >> 10;
|
|
|
|
i *= 0xb36534e5;
|
|
|
|
i ^= i >> 12;
|
|
|
|
i ^= i >> 21;
|
|
|
|
i *= 0x93fc4795;
|
|
|
|
i ^= 0xdf6e307f;
|
|
|
|
i ^= i >> 17;
|
|
|
|
i *= 1 | p >> 18;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2013-06-07 16:06:22 +00:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2016-11-26 16:30:02 +00:00
|
|
|
ccl_device_inline uint cmj_hash_simple(uint i, uint p)
|
|
|
|
{
|
|
|
|
i = (i ^ 61) ^ p;
|
|
|
|
i += i << 3;
|
|
|
|
i ^= i >> 4;
|
|
|
|
i *= 0x27d4eb2d;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float cmj_randfloat(uint i, uint p)
|
2013-06-07 16:06:22 +00:00
|
|
|
{
|
|
|
|
return cmj_hash(i, p) * (1.0f / 4294967808.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __CMJ__
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device float cmj_sample_1D(int s, int N, int p)
|
2013-06-07 16:06:22 +00:00
|
|
|
{
|
2013-08-23 23:04:50 +00:00
|
|
|
kernel_assert(s < N);
|
|
|
|
|
2013-06-07 16:06:22 +00:00
|
|
|
uint x = cmj_permute(s, N, p * 0x68bc21eb);
|
|
|
|
float jx = cmj_randfloat(s, p * 0x967a889b);
|
|
|
|
|
|
|
|
float invN = 1.0f / N;
|
|
|
|
return (x + jx) * invN;
|
|
|
|
}
|
|
|
|
|
2017-05-09 14:12:06 +00:00
|
|
|
/* TODO(sergey): Do some extra tests and consider moving to util_math.h. */
|
|
|
|
ccl_device_inline int cmj_isqrt(int value)
|
2013-06-07 16:06:22 +00:00
|
|
|
{
|
2015-03-13 07:14:43 +00:00
|
|
|
# if defined(__KERNEL_CUDA__)
|
2017-05-09 14:12:06 +00:00
|
|
|
return float_to_int(__fsqrt_ru(value));
|
|
|
|
# elif defined(__KERNEL_GPU__)
|
|
|
|
return float_to_int(sqrtf(value));
|
2015-03-13 07:14:43 +00:00
|
|
|
# else
|
2017-05-09 14:12:06 +00:00
|
|
|
/* This is a work around for fast-math on CPU which might replace sqrtf()
|
|
|
|
* with am approximated version.
|
|
|
|
*/
|
|
|
|
return float_to_int(sqrtf(value) + 1e-6f);
|
2015-03-13 07:14:43 +00:00
|
|
|
# endif
|
2017-05-09 14:12:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ccl_device void cmj_sample_2D(int s, int N, int p, float *fx, float *fy)
|
|
|
|
{
|
|
|
|
kernel_assert(s < N);
|
|
|
|
|
|
|
|
int m = cmj_isqrt(N);
|
2016-04-28 21:46:00 +00:00
|
|
|
int n = (N - 1) / m + 1;
|
2013-06-07 16:06:22 +00:00
|
|
|
float invN = 1.0f / N;
|
|
|
|
float invm = 1.0f / m;
|
|
|
|
float invn = 1.0f / n;
|
|
|
|
|
|
|
|
s = cmj_permute(s, N, p * 0x51633e2d);
|
|
|
|
|
|
|
|
int sdivm, smodm;
|
|
|
|
|
|
|
|
if (cmj_is_pow2(m)) {
|
|
|
|
sdivm = cmj_fast_div_pow2(s, m);
|
|
|
|
smodm = cmj_fast_mod_pow2(s, m);
|
|
|
|
}
|
|
|
|
else {
|
2021-02-05 05:23:34 +00:00
|
|
|
/* Doing `s * inmv` gives precision issues here. */
|
2014-08-28 09:15:59 +00:00
|
|
|
sdivm = s / m;
|
2013-06-07 16:06:22 +00:00
|
|
|
smodm = s - sdivm * m;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint sx = cmj_permute(smodm, m, p * 0x68bc21eb);
|
|
|
|
uint sy = cmj_permute(sdivm, n, p * 0x02e5be93);
|
|
|
|
|
|
|
|
float jx = cmj_randfloat(s, p * 0x967a889b);
|
|
|
|
float jy = cmj_randfloat(s, p * 0x368cc8b7);
|
|
|
|
|
2013-06-11 21:58:48 +00:00
|
|
|
*fx = (sx + (sy + jx) * invn) * invm;
|
|
|
|
*fy = (s + jy) * invN;
|
2013-06-07 16:06:22 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-03-02 14:12:44 +00:00
|
|
|
ccl_device float pmj_sample_1D(KernelGlobals *kg, int sample, int rng_hash, int dimension)
|
|
|
|
{
|
|
|
|
/* Fallback to random */
|
2020-03-08 20:31:47 +00:00
|
|
|
if (sample >= NUM_PMJ_SAMPLES) {
|
2020-04-22 14:27:25 +00:00
|
|
|
const int p = rng_hash + dimension;
|
2020-03-02 14:12:44 +00:00
|
|
|
return cmj_randfloat(sample, p);
|
|
|
|
}
|
2020-04-22 14:27:25 +00:00
|
|
|
else {
|
|
|
|
const uint mask = cmj_hash_simple(dimension, rng_hash) & 0x007fffff;
|
|
|
|
const int index = ((dimension % NUM_PMJ_PATTERNS) * NUM_PMJ_SAMPLES + sample) * 2;
|
|
|
|
return __uint_as_float(kernel_tex_fetch(__sample_pattern_lut, index) ^ mask) - 1.0f;
|
|
|
|
}
|
2020-03-02 14:12:44 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 14:27:25 +00:00
|
|
|
ccl_device float2 pmj_sample_2D(KernelGlobals *kg, int sample, int rng_hash, int dimension)
|
2020-03-02 14:12:44 +00:00
|
|
|
{
|
2020-03-08 20:31:47 +00:00
|
|
|
if (sample >= NUM_PMJ_SAMPLES) {
|
2020-04-22 14:27:25 +00:00
|
|
|
const int p = rng_hash + dimension;
|
|
|
|
const float fx = cmj_randfloat(sample, p);
|
|
|
|
const float fy = cmj_randfloat(sample, p + 1);
|
|
|
|
return make_float2(fx, fy);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const int index = ((dimension % NUM_PMJ_PATTERNS) * NUM_PMJ_SAMPLES + sample) * 2;
|
|
|
|
const uint maskx = cmj_hash_simple(dimension, rng_hash) & 0x007fffff;
|
|
|
|
const uint masky = cmj_hash_simple(dimension + 1, rng_hash) & 0x007fffff;
|
|
|
|
const float fx = __uint_as_float(kernel_tex_fetch(__sample_pattern_lut, index) ^ maskx) - 1.0f;
|
|
|
|
const float fy = __uint_as_float(kernel_tex_fetch(__sample_pattern_lut, index + 1) ^ masky) -
|
|
|
|
1.0f;
|
|
|
|
return make_float2(fx, fy);
|
2020-03-02 14:12:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-07 16:06:22 +00:00
|
|
|
CCL_NAMESPACE_END
|