Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/kernel_jitter.h
| Context not available. | |||||
| */ | */ | ||||
| #pragma once | #pragma once | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| ccl_device_inline uint32_t laine_karras_permutation(uint32_t x, uint32_t seed) | /* "Correlated Multi-Jittered Sampling" | ||||
| * Andrew Kensler, Pixar Technical Memo 13-01, 2013 */ | |||||
| ccl_device_inline bool cmj_is_pow2(int i) | |||||
| { | |||||
| return (i > 1) && ((i & (i - 1)) == 0); | |||||
| } | |||||
| ccl_device_inline int cmj_fast_mod_pow2(int a, int b) | |||||
| { | { | ||||
| x += seed; | return (a & (b - 1)); | ||||
| x ^= (x * 0x6c50b47cu); | } | ||||
| x ^= x * 0xb82f1e52u; | |||||
| x ^= x * 0xc7afe638u; | |||||
| x ^= x * 0x8d22f6e6u; | |||||
| return x; | /* b must be > 1 */ | ||||
| ccl_device_inline int cmj_fast_div_pow2(int a, int b) | |||||
| { | |||||
| kernel_assert(b > 1); | |||||
| return a >> count_trailing_zeros(b); | |||||
| } | } | ||||
| ccl_device_inline uint32_t nested_uniform_scramble(uint32_t x, uint32_t seed) | ccl_device_inline uint cmj_w_mask(uint w) | ||||
| { | { | ||||
| x = reverse_integer_bits(x); | kernel_assert(w > 1); | ||||
| x = laine_karras_permutation(x, seed); | return ((1 << (32 - count_leading_zeros(w))) - 1); | ||||
| x = reverse_integer_bits(x); | } | ||||
| return x; | ccl_device_inline uint cmj_permute(uint i, uint l, uint p) | ||||
| { | |||||
| uint w = l - 1; | |||||
| 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; | |||||
| return (i + p) & w; | |||||
| } | |||||
| else { | |||||
| /* l is not a power of two (slow) */ | |||||
| w = cmj_w_mask(w); | |||||
| 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; | |||||
| } while (i >= l); | |||||
| return (i + p) % l; | |||||
| } | |||||
| } | } | ||||
| ccl_device_inline uint cmj_hash(uint i, uint p) | ccl_device_inline uint cmj_hash(uint i, uint p) | ||||
| Context not available. | |||||
| return cmj_hash(i, p) * (1.0f / 4294967808.0f); | return cmj_hash(i, p) * (1.0f / 4294967808.0f); | ||||
| } | } | ||||
| ccl_device_inline float cmj_randfloat_simple(uint i, uint p) | ccl_device float pmj_sample_1D(const KernelGlobals *kg, int sample, int rng_hash, int dimension) | ||||
| { | |||||
| return cmj_hash_simple(i, p) * (1.0f / (float)0xFFFFFFFF); | |||||
| } | |||||
| ccl_device float pmj_sample_1D(const KernelGlobals *kg, uint sample, uint rng_hash, uint dimension) | |||||
| { | { | ||||
| /* The PMJ sample sets contain a sample with (x,y) with NUM_PMJ_SAMPLES so for 1D | /* use Cranley-Patterson Rotation. */ | ||||
| * the x part is used as the sample (TODO(@leesonw): Add using both x and y parts | float r; | ||||
| * independently). */ | if(sample > NUM_PMJ_SAMPLES) { | ||||
| r = cmj_randfloat(sample, dimension); | |||||
leesonw: Again using the code on the left instead of this you could use this to generate the rv value. | |||||
| /* Perform Owen shuffle of the sample number to reorder the samples. */ | } | ||||
| #ifdef _SIMPLE_HASH_ | else { | ||||
| const uint rv = cmj_hash_simple(dimension, rng_hash); | int index = ((dimension % NUM_PMJ_PATTERNS) * NUM_PMJ_SAMPLES + sample) * 2 + (dimension & 1); | ||||
| #else /* Use a _REGULAR_HASH_. */ | r = __uint_as_float(kernel_tex_fetch(__sample_pattern_lut, index)) - 1.0f; | ||||
| const uint rv = cmj_hash(dimension, rng_hash); | } | ||||
| #endif | /* Cranly-Patterson rotation using rng seed */ | ||||
| #ifdef _XOR_SHUFFLE_ | float shift; | ||||
| # warning "Using XOR shuffle." | |||||
| const uint s = sample ^ rv; | /* Hash rng with dimension to solve correlation issues. | ||||
| #else /* Use _OWEN_SHUFFLE_ for reordering. */ | * See T38710, T50116. | ||||
| const uint s = nested_uniform_scramble(sample, rv); | */ | ||||
| #endif | uint tmp_rng = cmj_hash_simple(dimension, rng_hash); | ||||
| shift = tmp_rng * (kernel_data.integrator.scrambling_distance/(float)0xFFFFFFFF); | |||||
leesonwUnsubmitted Not Done Inline ActionsIt should be possible to put this into the CPR code on lines 102-111 to the left as they are very similar. If fact we just need to multiple dx*(1.0f/NUM_PMJ_SAMPLES) by (kernel_data.integrator.scrambling_distance/(float)0xFFFFFFFF) should do the trick. leesonw: It should be possible to put this into the CPR code on lines 102-111 to the left as they are… | |||||
| /* Based on the sample number a sample pattern is selected and offset by the dimension. */ | |||||
| const uint sample_set = s / NUM_PMJ_SAMPLES; | return r + shift - floorf(r + shift); | ||||
| const uint d = (dimension + sample_set); | |||||
| const uint dim = d % NUM_PMJ_PATTERNS; | |||||
| int index = 2 * (dim * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES)); | |||||
| float fx = kernel_tex_fetch(__sample_pattern_lut, index); | |||||
| #ifndef _NO_CRANLEY_PATTERSON_ROTATION_ | |||||
| /* Use Cranley-Patterson rotation to displace the sample pattern. */ | |||||
| # ifdef _SIMPLE_HASH_ | |||||
| float dx = cmj_randfloat_simple(d, rng_hash); | |||||
| # else | |||||
| /* Only jitter within the grid interval. */ | |||||
| float dx = cmj_randfloat(d, rng_hash); | |||||
| # endif | |||||
| fx = fx + dx * (1.0f / NUM_PMJ_SAMPLES); | |||||
| fx = fx - floorf(fx); | |||||
| #else | |||||
| # warning "Not using Cranley-Patterson Rotation." | |||||
| #endif | |||||
| return fx; | |||||
| } | } | ||||
| ccl_device void pmj_sample_2D( | ccl_device float2 pmj_sample_2D(const KernelGlobals *kg, int sample, int rng_hash, int dimension) | ||||
| const KernelGlobals *kg, uint sample, uint rng_hash, uint dimension, float *x, float *y) | |||||
| { | { | ||||
| /* Perform a shuffle on the sample number to reorder the samples. */ | if (sample >= NUM_PMJ_SAMPLES) { | ||||
| #ifdef _SIMPLE_HASH_ | const int p = rng_hash + dimension; | ||||
| const uint rv = cmj_hash_simple(dimension, rng_hash); | const float fx = cmj_randfloat(sample, p); | ||||
| #else /* Use a _REGULAR_HASH_. */ | const float fy = cmj_randfloat(sample, p + 1); | ||||
| const uint rv = cmj_hash(dimension, rng_hash); | return make_float2(fx, fy); | ||||
| #endif | } | ||||
| #ifdef _XOR_SHUFFLE_ | else { | ||||
| # warning "Using XOR shuffle." | const int index = ((dimension % NUM_PMJ_PATTERNS) * NUM_PMJ_SAMPLES + sample) * 2; | ||||
| const uint s = sample ^ rv; | const uint maskx = cmj_hash_simple(dimension, rng_hash) & 0x007fffff; | ||||
| #else /* Use _OWEN_SHUFFLE_ for reordering. */ | const uint masky = cmj_hash_simple(dimension + 1, rng_hash) & 0x007fffff; | ||||
| const uint s = nested_uniform_scramble(sample, rv); | const float fx = __uint_as_float(kernel_tex_fetch(__sample_pattern_lut, index) ^ maskx) - 1.0f; | ||||
| #endif | const float fy = __uint_as_float(kernel_tex_fetch(__sample_pattern_lut, index + 1) ^ masky) - | ||||
| 1.0f; | |||||
| /* Based on the sample number a sample pattern is selected and offset by the dimension. */ | return make_float2(fx, fy); | ||||
leesonwUnsubmitted Not Done Inline ActionsFor the code on the left just multiple 1.0f/NUM_PMJ_DIVISIONS by (kernel_data.integrator.scrambling_distance/(float)0xFFFFFFFF). leesonw: For the code on the left just multiple ##1.0f/NUM_PMJ_DIVISIONS## by ##(kernel_data.integrator. | |||||
| const uint sample_set = s / NUM_PMJ_SAMPLES; | } | ||||
| const uint d = (dimension + sample_set); | |||||
| const uint dim = d % NUM_PMJ_PATTERNS; | |||||
| int index = 2 * (dim * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES)); | |||||
| float fx = kernel_tex_fetch(__sample_pattern_lut, index); | |||||
| float fy = kernel_tex_fetch(__sample_pattern_lut, index + 1); | |||||
| #ifndef _NO_CRANLEY_PATTERSON_ROTATION_ | |||||
| /* Use Cranley-Patterson rotation to displace the sample pattern. */ | |||||
| # ifdef _SIMPLE_HASH_ | |||||
| float dx = cmj_randfloat_simple(d, rng_hash); | |||||
| float dy = cmj_randfloat_simple(d + 1, rng_hash); | |||||
| # else | |||||
| float dx = cmj_randfloat(d, rng_hash); | |||||
| float dy = cmj_randfloat(d + 1, rng_hash); | |||||
| # endif | |||||
| /* Only jitter within the grid cells. */ | |||||
| fx = fx + dx * (1.0f / NUM_PMJ_DIVISIONS); | |||||
| fy = fy + dy * (1.0f / NUM_PMJ_DIVISIONS); | |||||
| fx = fx - floorf(fx); | |||||
| fy = fy - floorf(fy); | |||||
| #else | |||||
| # warning "Not using Cranley Patterson Rotation." | |||||
| #endif | |||||
| (*x) = fx; | |||||
| (*y) = fy; | |||||
| } | } | ||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||
| Context not available. | |||||
Again using the code on the left instead of this you could use this to generate the rv value.