Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brecht@blender.org>2021-10-24 15:19:19 +0300
committerBrecht Van Lommel <brecht@blender.org>2021-10-26 16:36:39 +0300
commitd7d40745fa09061a3117bd3669c5a46bbf611eae (patch)
tree8dbaca086ecbb09aad62c25e9ece66332fe79af3 /intern/cycles/kernel/sample
parentb698fe1e047e56e8ed67ba47464c0017d9c50eea (diff)
Cycles: changes to source code folders structure
* Split render/ into scene/ and session/. The scene/ folder now contains the scene and its nodes. The session/ folder contains the render session and associated data structures like drivers and render buffers. * Move top level kernel headers into new folders kernel/camera/, kernel/film/, kernel/light/, kernel/sample/, kernel/util/ * Move integrator related kernel headers into kernel/integrator/ * Move OSL shaders from kernel/shaders/ to kernel/osl/shaders/ For patches and branches, git merge and rebase should be able to detect the renames and move over code to the right file.
Diffstat (limited to 'intern/cycles/kernel/sample')
-rw-r--r--intern/cycles/kernel/sample/sample_jitter.h169
-rw-r--r--intern/cycles/kernel/sample/sample_lcg.h51
-rw-r--r--intern/cycles/kernel/sample/sample_mapping.h177
-rw-r--r--intern/cycles/kernel/sample/sample_mis.h64
-rw-r--r--intern/cycles/kernel/sample/sample_pattern.h185
5 files changed, 646 insertions, 0 deletions
diff --git a/intern/cycles/kernel/sample/sample_jitter.h b/intern/cycles/kernel/sample/sample_jitter.h
new file mode 100644
index 00000000000..b62ec7fda42
--- /dev/null
+++ b/intern/cycles/kernel/sample/sample_jitter.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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
+ * limitations under the License.
+ */
+
+#pragma once
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline uint32_t laine_karras_permutation(uint32_t x, uint32_t seed)
+{
+ x += seed;
+ x ^= (x * 0x6c50b47cu);
+ x ^= x * 0xb82f1e52u;
+ x ^= x * 0xc7afe638u;
+ x ^= x * 0x8d22f6e6u;
+
+ return x;
+}
+
+ccl_device_inline uint32_t nested_uniform_scramble(uint32_t x, uint32_t seed)
+{
+ x = reverse_integer_bits(x);
+ x = laine_karras_permutation(x, seed);
+ x = reverse_integer_bits(x);
+
+ return x;
+}
+
+ccl_device_inline uint cmj_hash(uint i, uint p)
+{
+ 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;
+
+ return i;
+}
+
+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;
+}
+
+ccl_device_inline float cmj_randfloat(uint i, uint p)
+{
+ return cmj_hash(i, p) * (1.0f / 4294967808.0f);
+}
+
+ccl_device_inline float cmj_randfloat_simple(uint i, uint p)
+{
+ return cmj_hash_simple(i, p) * (1.0f / (float)0xFFFFFFFF);
+}
+
+ccl_device float pmj_sample_1D(KernelGlobals kg, uint sample, uint rng_hash, uint dimension)
+{
+ /* Perform Owen shuffle of the sample number to reorder the samples. */
+#ifdef _SIMPLE_HASH_
+ const uint rv = cmj_hash_simple(dimension, rng_hash);
+#else /* Use a _REGULAR_HASH_. */
+ const uint rv = cmj_hash(dimension, rng_hash);
+#endif
+#ifdef _XOR_SHUFFLE_
+# warning "Using XOR shuffle."
+ const uint s = sample ^ rv;
+#else /* Use _OWEN_SHUFFLE_ for reordering. */
+ const uint s = nested_uniform_scramble(sample, rv);
+#endif
+
+ /* Based on the sample number a sample pattern is selected and offset by the dimension. */
+ const uint sample_set = s / NUM_PMJ_SAMPLES;
+ const uint d = (dimension + sample_set);
+ const uint dim = d % NUM_PMJ_PATTERNS;
+
+ /* The PMJ sample sets contain a sample with (x,y) with NUM_PMJ_SAMPLES so for 1D
+ * the x part is used for even dims and the y for odd. */
+ int index = 2 * ((dim >> 1) * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES)) + (dim & 1);
+
+ 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
+ float dx = cmj_randfloat(d, rng_hash);
+# endif
+ /* Jitter sample locations and map back into [0 1]. */
+ fx = fx + dx;
+ fx = fx - floorf(fx);
+#else
+# warning "Not using Cranley-Patterson Rotation."
+#endif
+
+ return fx;
+}
+
+ccl_device void pmj_sample_2D(KernelGlobals kg,
+ uint sample,
+ uint rng_hash,
+ uint dimension,
+ ccl_private float *x,
+ ccl_private float *y)
+{
+ /* Perform a shuffle on the sample number to reorder the samples. */
+#ifdef _SIMPLE_HASH_
+ const uint rv = cmj_hash_simple(dimension, rng_hash);
+#else /* Use a _REGULAR_HASH_. */
+ const uint rv = cmj_hash(dimension, rng_hash);
+#endif
+#ifdef _XOR_SHUFFLE_
+# warning "Using XOR shuffle."
+ const uint s = sample ^ rv;
+#else /* Use _OWEN_SHUFFLE_ for reordering. */
+ const uint s = nested_uniform_scramble(sample, rv);
+#endif
+
+ /* Based on the sample number a sample pattern is selected and offset by the dimension. */
+ const uint sample_set = s / NUM_PMJ_SAMPLES;
+ const uint d = (dimension + sample_set);
+ 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
+ /* Jitter sample locations and map back to the unit square [0 1]x[0 1]. */
+ float sx = fx + dx;
+ float sy = fy + dy;
+ sx = sx - floorf(sx);
+ sy = sy - floorf(sy);
+#else
+# warning "Not using Cranley Patterson Rotation."
+#endif
+
+ (*x) = sx;
+ (*y) = sy;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/sample/sample_lcg.h b/intern/cycles/kernel/sample/sample_lcg.h
new file mode 100644
index 00000000000..92cfff639b4
--- /dev/null
+++ b/intern/cycles/kernel/sample/sample_lcg.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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
+ * limitations under the License.
+ */
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Linear Congruential Generator */
+
+ccl_device uint lcg_step_uint(uint *rng)
+{
+ /* implicit mod 2^32 */
+ *rng = (1103515245 * (*rng) + 12345);
+ return *rng;
+}
+
+ccl_device float lcg_step_float(uint *rng)
+{
+ /* implicit mod 2^32 */
+ *rng = (1103515245 * (*rng) + 12345);
+ return (float)*rng * (1.0f / (float)0xFFFFFFFF);
+}
+
+ccl_device uint lcg_init(uint seed)
+{
+ uint rng = seed;
+ lcg_step_uint(&rng);
+ return rng;
+}
+
+ccl_device_inline uint lcg_state_init(const uint rng_hash,
+ const uint rng_offset,
+ const uint sample,
+ const uint scramble)
+{
+ return lcg_init(rng_hash + rng_offset + sample * scramble);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/sample/sample_mapping.h b/intern/cycles/kernel/sample/sample_mapping.h
new file mode 100644
index 00000000000..3297aa2a29a
--- /dev/null
+++ b/intern/cycles/kernel/sample/sample_mapping.h
@@ -0,0 +1,177 @@
+/*
+ * Parts adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* distribute uniform xy on [0,1] over unit disk [-1,1] */
+ccl_device void to_unit_disk(ccl_private float *x, ccl_private float *y)
+{
+ float phi = M_2PI_F * (*x);
+ float r = sqrtf(*y);
+
+ *x = r * cosf(phi);
+ *y = r * sinf(phi);
+}
+
+/* return an orthogonal tangent and bitangent given a normal and tangent that
+ * may not be exactly orthogonal */
+ccl_device void make_orthonormals_tangent(const float3 N,
+ const float3 T,
+ ccl_private float3 *a,
+ ccl_private float3 *b)
+{
+ *b = normalize(cross(N, T));
+ *a = cross(*b, N);
+}
+
+/* sample direction with cosine weighted distributed in hemisphere */
+ccl_device_inline void sample_cos_hemisphere(
+ const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf)
+{
+ to_unit_disk(&randu, &randv);
+ float costheta = sqrtf(max(1.0f - randu * randu - randv * randv, 0.0f));
+ float3 T, B;
+ make_orthonormals(N, &T, &B);
+ *omega_in = randu * T + randv * B + costheta * N;
+ *pdf = costheta * M_1_PI_F;
+}
+
+/* sample direction uniformly distributed in hemisphere */
+ccl_device_inline void sample_uniform_hemisphere(
+ const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf)
+{
+ float z = randu;
+ float r = sqrtf(max(0.0f, 1.0f - z * z));
+ float phi = M_2PI_F * randv;
+ float x = r * cosf(phi);
+ float y = r * sinf(phi);
+
+ float3 T, B;
+ make_orthonormals(N, &T, &B);
+ *omega_in = x * T + y * B + z * N;
+ *pdf = 0.5f * M_1_PI_F;
+}
+
+/* sample direction uniformly distributed in cone */
+ccl_device_inline void sample_uniform_cone(const float3 N,
+ float angle,
+ float randu,
+ float randv,
+ ccl_private float3 *omega_in,
+ ccl_private float *pdf)
+{
+ float zMin = cosf(angle);
+ float z = zMin - zMin * randu + randu;
+ float r = safe_sqrtf(1.0f - sqr(z));
+ float phi = M_2PI_F * randv;
+ float x = r * cosf(phi);
+ float y = r * sinf(phi);
+
+ float3 T, B;
+ make_orthonormals(N, &T, &B);
+ *omega_in = x * T + y * B + z * N;
+ *pdf = M_1_2PI_F / (1.0f - zMin);
+}
+
+ccl_device_inline float pdf_uniform_cone(const float3 N, float3 D, float angle)
+{
+ float zMin = cosf(angle);
+ float z = dot(N, D);
+ if (z > zMin) {
+ return M_1_2PI_F / (1.0f - zMin);
+ }
+ return 0.0f;
+}
+
+/* sample uniform point on the surface of a sphere */
+ccl_device float3 sample_uniform_sphere(float u1, float u2)
+{
+ float z = 1.0f - 2.0f * u1;
+ float r = sqrtf(fmaxf(0.0f, 1.0f - z * z));
+ float phi = M_2PI_F * u2;
+ float x = r * cosf(phi);
+ float y = r * sinf(phi);
+
+ return make_float3(x, y, z);
+}
+
+/* distribute uniform xy on [0,1] over unit disk [-1,1], with concentric mapping
+ * to better preserve stratification for some RNG sequences */
+ccl_device float2 concentric_sample_disk(float u1, float u2)
+{
+ float phi, r;
+ float a = 2.0f * u1 - 1.0f;
+ float b = 2.0f * u2 - 1.0f;
+
+ if (a == 0.0f && b == 0.0f) {
+ return zero_float2();
+ }
+ else if (a * a > b * b) {
+ r = a;
+ phi = M_PI_4_F * (b / a);
+ }
+ else {
+ r = b;
+ phi = M_PI_2_F - M_PI_4_F * (a / b);
+ }
+
+ return make_float2(r * cosf(phi), r * sinf(phi));
+}
+
+/* sample point in unit polygon with given number of corners and rotation */
+ccl_device float2 regular_polygon_sample(float corners, float rotation, float u, float v)
+{
+ /* sample corner number and reuse u */
+ float corner = floorf(u * corners);
+ u = u * corners - corner;
+
+ /* uniform sampled triangle weights */
+ u = sqrtf(u);
+ v = v * u;
+ u = 1.0f - u;
+
+ /* point in triangle */
+ float angle = M_PI_F / corners;
+ float2 p = make_float2((u + v) * cosf(angle), (u - v) * sinf(angle));
+
+ /* rotate */
+ rotation += corner * 2.0f * angle;
+
+ float cr = cosf(rotation);
+ float sr = sinf(rotation);
+
+ return make_float2(cr * p.x - sr * p.y, sr * p.x + cr * p.y);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/sample/sample_mis.h b/intern/cycles/kernel/sample/sample_mis.h
new file mode 100644
index 00000000000..0878b3aac36
--- /dev/null
+++ b/intern/cycles/kernel/sample/sample_mis.h
@@ -0,0 +1,64 @@
+/*
+ * Parts adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Multiple importance sampling utilities. */
+
+ccl_device float balance_heuristic(float a, float b)
+{
+ return (a) / (a + b);
+}
+
+ccl_device float balance_heuristic_3(float a, float b, float c)
+{
+ return (a) / (a + b + c);
+}
+
+ccl_device float power_heuristic(float a, float b)
+{
+ return (a * a) / (a * a + b * b);
+}
+
+ccl_device float power_heuristic_3(float a, float b, float c)
+{
+ return (a * a) / (a * a + b * b + c * c);
+}
+
+ccl_device float max_heuristic(float a, float b)
+{
+ return (a > b) ? 1.0f : 0.0f;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/sample/sample_pattern.h b/intern/cycles/kernel/sample/sample_pattern.h
new file mode 100644
index 00000000000..95635c2c855
--- /dev/null
+++ b/intern/cycles/kernel/sample/sample_pattern.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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
+ * limitations under the License.
+ */
+#pragma once
+
+#include "kernel/sample/sample_jitter.h"
+#include "util/util_hash.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Pseudo random numbers, uncomment this for debugging correlations. Only run
+ * this single threaded on a CPU for repeatable results. */
+//#define __DEBUG_CORRELATION__
+
+/* High Dimensional Sobol.
+ *
+ * Multidimensional sobol with generator matrices. Dimension 0 and 1 are equal
+ * to classic Van der Corput and Sobol sequences. */
+
+#ifdef __SOBOL__
+
+/* Skip initial numbers that for some dimensions have clear patterns that
+ * don't cover the entire sample space. Ideally we would have a better
+ * progressive pattern that doesn't suffer from this problem, because even
+ * with this offset some dimensions are quite poor.
+ */
+# define SOBOL_SKIP 64
+
+ccl_device uint sobol_dimension(KernelGlobals kg, int index, int dimension)
+{
+ uint result = 0;
+ uint i = index + SOBOL_SKIP;
+ for (int j = 0, x; (x = find_first_set(i)); i >>= x) {
+ j += x;
+ result ^= __float_as_uint(kernel_tex_fetch(__sample_pattern_lut, 32 * dimension + j - 1));
+ }
+ return result;
+}
+
+#endif /* __SOBOL__ */
+
+ccl_device_forceinline float path_rng_1D(KernelGlobals kg,
+ uint rng_hash,
+ int sample,
+ int dimension)
+{
+#ifdef __DEBUG_CORRELATION__
+ return (float)drand48();
+#endif
+
+#ifdef __SOBOL__
+ if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ)
+#endif
+ {
+ return pmj_sample_1D(kg, sample, rng_hash, dimension);
+ }
+
+#ifdef __SOBOL__
+ /* Sobol sequence value using direction vectors. */
+ uint result = sobol_dimension(kg, sample, dimension);
+ float r = (float)result * (1.0f / (float)0xFFFFFFFF);
+
+ /* Cranly-Patterson rotation using rng seed */
+ float shift;
+
+ /* Hash rng with dimension to solve correlation issues.
+ * See T38710, T50116.
+ */
+ uint tmp_rng = cmj_hash_simple(dimension, rng_hash);
+ shift = tmp_rng * (1.0f / (float)0xFFFFFFFF);
+
+ return r + shift - floorf(r + shift);
+#endif
+}
+
+ccl_device_forceinline void path_rng_2D(KernelGlobals kg,
+ uint rng_hash,
+ int sample,
+ int dimension,
+ ccl_private float *fx,
+ ccl_private float *fy)
+{
+#ifdef __DEBUG_CORRELATION__
+ *fx = (float)drand48();
+ *fy = (float)drand48();
+ return;
+#endif
+
+#ifdef __SOBOL__
+ if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ)
+#endif
+ {
+ pmj_sample_2D(kg, sample, rng_hash, dimension, fx, fy);
+
+ return;
+ }
+
+#ifdef __SOBOL__
+ /* Sobol. */
+ *fx = path_rng_1D(kg, rng_hash, sample, dimension);
+ *fy = path_rng_1D(kg, rng_hash, sample, dimension + 1);
+#endif
+}
+
+/**
+ * 1D hash recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020
+ * See https://www.shadertoy.com/view/4tXyWN and https://www.shadertoy.com/view/XlGcRh
+ * http://www.jcgt.org/published/0009/03/02/paper.pdf
+ */
+ccl_device_inline uint hash_iqint1(uint n)
+{
+ n = (n << 13U) ^ n;
+ n = n * (n * n * 15731U + 789221U) + 1376312589U;
+
+ return n;
+}
+
+/**
+ * 2D hash recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020
+ * See https://www.shadertoy.com/view/4tXyWN and https://www.shadertoy.com/view/XlGcRh
+ * http://www.jcgt.org/published/0009/03/02/paper.pdf
+ */
+ccl_device_inline uint hash_iqnt2d(const uint x, const uint y)
+{
+ const uint qx = 1103515245U * ((x >> 1U) ^ (y));
+ const uint qy = 1103515245U * ((y >> 1U) ^ (x));
+ const uint n = 1103515245U * ((qx) ^ (qy >> 3U));
+
+ return n;
+}
+
+ccl_device_inline uint path_rng_hash_init(KernelGlobals kg,
+ const int sample,
+ const int x,
+ const int y)
+{
+ const uint rng_hash = hash_iqnt2d(x, y) ^ kernel_data.integrator.seed;
+
+#ifdef __DEBUG_CORRELATION__
+ srand48(rng_hash + sample);
+#else
+ (void)sample;
+#endif
+
+ return rng_hash;
+}
+
+ccl_device_inline bool sample_is_even(int pattern, int sample)
+{
+ if (pattern == SAMPLING_PATTERN_PMJ) {
+ /* See Section 10.2.1, "Progressive Multi-Jittered Sample Sequences", Christensen et al.
+ * We can use this to get divide sample sequence into two classes for easier variance
+ * estimation. */
+#if defined(__GNUC__) && !defined(__KERNEL_GPU__)
+ return __builtin_popcount(sample & 0xaaaaaaaa) & 1;
+#elif defined(__NVCC__)
+ return __popc(sample & 0xaaaaaaaa) & 1;
+#else
+ /* TODO(Stefan): pop-count intrinsic for Windows with fallback for older CPUs. */
+ int i = sample & 0xaaaaaaaa;
+ i = i - ((i >> 1) & 0x55555555);
+ i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
+ i = (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+ return i & 1;
+#endif
+ }
+ else {
+ /* TODO(Stefan): Are there reliable ways of dividing CMJ and Sobol into two classes? */
+ return sample & 0x1;
+ }
+}
+
+CCL_NAMESPACE_END