How to get a “random” number in OpenCL

后端 未结 9 837
悲&欢浪女
悲&欢浪女 2020-12-07 22:59

I\'m looking to get a random number in OpenCL. It doesn\'t have to be real random or even that random. Just something simple and quick.

I see there is a ton of rea

9条回答
  •  無奈伤痛
    2020-12-07 23:29

    I am currently implementing a Realtime Path Tracer. You might already know that Path Tracing requires many many random numbers.
    Before generating random numbers on the GPU I simply generated them on the CPU (using rand(), which sucks) and passed them to the GPU.
    That quickly became a bottleneck.
    Now I am generating the random numbers on the GPU with the Park-Miller Pseudorandom Number Generator (PRNG).
    It is extremely simple to implement and achieves very good results.
    I took thousands of samples (in the range of 0.0 to 1.0) and averaged them together.
    The resulting value was very close to 0.5 (which is what you would expect). Between different runs the divergence from 0.5 was around 0.002. Therefore it has a very uniform distribution.

    Here's a paper describing the algorithm:
    http://www.cems.uwe.ac.uk/~irjohnso/coursenotes/ufeen8-15-m/p1192-parkmiller.pdf
    And here's a paper about the above algorithm optimized for CUDA (which can easily be ported to OpenCL): http://www0.cs.ucl.ac.uk/staff/ucacbbl/ftp/papers/langdon_2009_CIGPU.pdf

    Here's an example of how I'm using it:

    int rand(int* seed) // 1 <= *seed < m
    {
        int const a = 16807; //ie 7**5
        int const m = 2147483647; //ie 2**31-1
    
        *seed = (long(*seed * a))%m;
        return(*seed);
    }
    
    kernel random_number_kernel(global int* seed_memory)
    {
        int global_id = get_global_id(1) * get_global_size(0) + get_global_id(0); // Get the global id in 1D.
    
        // Since the Park-Miller PRNG generates a SEQUENCE of random numbers
        // we have to keep track of the previous random number, because the next
        // random number will be generated using the previous one.
        int seed = seed_memory[global_id];
    
        int random_number = rand(&seed); // Generate the next random number in the sequence.
    
        seed_memory[global_id] = *seed; // Save the seed for the next time this kernel gets enqueued.
    }
    

    The code serves just as an example. I have not tested it.
    The array "seed_memory" is being filled with rand() only once before the first execution of the kernel. After that, all random number generation is happening on the GPU. I think it's also possible to simply use the kernel id instead of initializing the array with rand().

提交回复
热议问题