Blender V2.61 - r43446

kernel_random.h

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 CCL_NAMESPACE_BEGIN
00020 
00021 typedef uint RNG;
00022 
00023 #ifdef __SOBOL__
00024 
00025 /* skip initial numbers that are not as well distributed, especially the
00026    first sequence is just 0 everywhere, which can be problematic for e.g.
00027    path termination */
00028 #define SOBOL_SKIP 64
00029 
00030 /* High Dimensional Sobol */
00031 
00032 /* van der corput radical inverse */
00033 __device uint van_der_corput(uint bits)
00034 {
00035     bits = (bits << 16) | (bits >> 16);
00036     bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8);
00037     bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4);
00038     bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2);
00039     bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1);
00040     return bits;
00041 }
00042 
00043 /* sobol radical inverse */
00044 __device uint sobol(uint i)
00045 {
00046     uint r = 0;
00047 
00048     for(uint v = 1U << 31; i; i >>= 1, v ^= v >> 1)
00049         if(i & 1)
00050             r ^= v;
00051 
00052     return r;
00053 }
00054 
00055 /* inverse of sobol radical inverse */
00056 __device uint sobol_inverse(uint i)
00057 {
00058     const uint msb = 1U << 31;
00059     uint r = 0;
00060 
00061     for(uint v = 1; i; i <<= 1, v ^= v << 1)
00062         if(i & msb)
00063             r ^= v;
00064 
00065     return r;
00066 }
00067 
00068 /* multidimensional sobol with generator matrices
00069    dimension 0 and 1 are equal to van_der_corput() and sobol() respectively */
00070 __device uint sobol_dimension(KernelGlobals *kg, int index, int dimension)
00071 {
00072     uint result = 0;
00073     uint i = index;
00074 
00075     for(uint j = 0; i; i >>= 1, j++)
00076         if(i & 1)
00077             result ^= kernel_tex_fetch(__sobol_directions, 32*dimension + j);
00078     
00079     return result;
00080 }
00081 
00082 /* lookup index and x/y coordinate, assumes m is a power of two */
00083 __device uint sobol_lookup(const uint m, const uint frame, const uint ex, const uint ey, uint *x, uint *y)
00084 {
00085     /* shift is constant per frame */
00086     const uint shift = frame << (m << 1);
00087     const uint sobol_shift = sobol(shift);
00088     /* van der Corput is its own inverse */
00089     const uint lower = van_der_corput(ex << (32 - m));
00090     /* need to compensate for ey difference and shift */
00091     const uint sobol_lower = sobol(lower);
00092     const uint mask = ~-(1 << m) << (32 - m); /* only m upper bits */
00093     const uint delta = ((ey << (32 - m)) ^ sobol_lower ^ sobol_shift) & mask;
00094     /* only use m upper bits for the index (m is a power of two) */
00095     const uint sobol_result = delta | (delta >> m);
00096     const uint upper = sobol_inverse(sobol_result);
00097     const uint index = shift | upper | lower;
00098     *x = van_der_corput(index);
00099     *y = sobol_shift ^ sobol_result ^ sobol_lower;
00100     return index;
00101 }
00102 
00103 __device_inline float path_rng(KernelGlobals *kg, RNG *rng, int sample, int dimension)
00104 {
00105 #ifdef __SOBOL_FULL_SCREEN__
00106     uint result = sobol_dimension(kg, *rng, dimension);
00107     float r = (float)result * (1.0f/(float)0xFFFFFFFF);
00108     return r;
00109 #else
00110     /* compute sobol sequence value using direction vectors */
00111     uint result = sobol_dimension(kg, sample + SOBOL_SKIP, dimension);
00112     float r = (float)result * (1.0f/(float)0xFFFFFFFF);
00113 
00114     /* Cranly-Patterson rotation using rng seed */
00115     float shift;
00116 
00117     if(dimension & 1)
00118         shift = (*rng >> 16)/((float)0xFFFF);
00119     else
00120         shift = (*rng & 0xFFFF)/((float)0xFFFF);
00121 
00122     return r + shift - floor(r + shift);
00123 #endif
00124 }
00125 
00126 __device_inline void path_rng_init(KernelGlobals *kg, __global uint *rng_state, int sample, RNG *rng, int x, int y, int offset, int stride, float *fx, float *fy)
00127 {
00128 #ifdef __SOBOL_FULL_SCREEN__
00129     uint px, py;
00130     uint bits = 16; /* limits us to 65536x65536 and 65536 samples */
00131     uint size = 1 << bits;
00132     uint frame = sample;
00133 
00134     *rng = sobol_lookup(bits, frame, x, y, &px, &py);
00135 
00136     *rng ^= kernel_data.integrator.seed;
00137 
00138     *fx = size * (float)px * (1.0f/(float)0xFFFFFFFF) - x;
00139     *fy = size * (float)py * (1.0f/(float)0xFFFFFFFF) - y;
00140 #else
00141     *rng = rng_state[offset + x + y*stride];
00142 
00143     *rng ^= kernel_data.integrator.seed;
00144 
00145     *fx = path_rng(kg, rng, sample, PRNG_FILTER_U);
00146     *fy = path_rng(kg, rng, sample, PRNG_FILTER_V);
00147 #endif
00148 }
00149 
00150 __device void path_rng_end(KernelGlobals *kg, __global uint *rng_state, RNG rng, int x, int y, int offset, int stride)
00151 {
00152     /* nothing to do */
00153 }
00154 
00155 #else
00156 
00157 /* Linear Congruential Generator */
00158 
00159 __device float path_rng(KernelGlobals *kg, RNG *rng, int sample, int dimension)
00160 {
00161     /* implicit mod 2^32 */
00162     *rng = (1103515245*(*rng) + 12345);
00163     return (float)*rng * (1.0f/(float)0xFFFFFFFF);
00164 }
00165 
00166 __device void path_rng_init(KernelGlobals *kg, __global uint *rng_state, int sample, RNG *rng, int x, int y, int offset, int stride, float *fx, float *fy)
00167 {
00168     /* load state */
00169     *rng = rng_state[offset + x + y*stride];
00170 
00171     *rng ^= kernel_data.integrator.seed;
00172 
00173     *fx = path_rng(kg, rng, sample, PRNG_FILTER_U);
00174     *fy = path_rng(kg, rng, sample, PRNG_FILTER_V);
00175 }
00176 
00177 __device void path_rng_end(KernelGlobals *kg, __global uint *rng_state, RNG rng, int x, int y, int offset, int stride)
00178 {
00179     /* store state for next sample */
00180     rng_state[offset + x + y*stride] = rng;
00181 }
00182 
00183 #endif
00184 
00185 CCL_NAMESPACE_END
00186