Cycles: OpenCL split kernel refactor
[blender-staging.git] / intern / cycles / kernel / kernel_work_stealing.h
1 /*
2  * Copyright 2011-2015 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef __KERNEL_WORK_STEALING_H__
18 #define __KERNEL_WORK_STEALING_H__
19
20 CCL_NAMESPACE_BEGIN
21
22 /*
23  * Utility functions for work stealing
24  */
25
26 #ifdef __KERNEL_OPENCL__
27 #  pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
28 #endif
29
30 ccl_device_inline uint kernel_total_work_size(KernelGlobals *kg)
31 {
32         return kernel_split_params.w * kernel_split_params.h * kernel_split_params.num_samples;
33 }
34
35 ccl_device_inline uint kernel_num_work_pools(KernelGlobals *kg)
36 {
37         return ccl_global_size(0) * ccl_global_size(1) / WORK_POOL_SIZE;
38 }
39
40 ccl_device_inline uint work_pool_from_ray_index(KernelGlobals *kg, uint ray_index)
41 {
42         return ray_index / WORK_POOL_SIZE;
43 }
44
45 ccl_device_inline uint work_pool_work_size(KernelGlobals *kg, uint work_pool)
46 {
47         uint total_work_size = kernel_total_work_size(kg);
48         uint num_pools = kernel_num_work_pools(kg);
49
50         if(work_pool >= num_pools || work_pool * WORK_POOL_SIZE >= total_work_size) {
51                 return 0;
52         }
53
54         uint work_size = (total_work_size / (num_pools * WORK_POOL_SIZE)) * WORK_POOL_SIZE;
55
56         uint remainder = (total_work_size % (num_pools * WORK_POOL_SIZE));
57         if(work_pool < remainder / WORK_POOL_SIZE) {
58                 work_size += WORK_POOL_SIZE;
59         }
60         else if(work_pool == remainder / WORK_POOL_SIZE) {
61                 work_size += remainder % WORK_POOL_SIZE;
62         }
63
64         return work_size;
65 }
66
67 ccl_device_inline uint get_global_work_index(KernelGlobals *kg, uint work_index, uint ray_index)
68 {
69         uint num_pools = kernel_num_work_pools(kg);
70         uint pool = work_pool_from_ray_index(kg, ray_index);
71
72         return (work_index / WORK_POOL_SIZE) * (num_pools * WORK_POOL_SIZE)
73                + (pool * WORK_POOL_SIZE)
74                + (work_index % WORK_POOL_SIZE);
75 }
76
77 /* Returns true if there is work */
78 ccl_device bool get_next_work(KernelGlobals *kg, ccl_private uint *work_index, uint ray_index)
79 {
80         uint work_pool = work_pool_from_ray_index(kg, ray_index);
81         uint pool_size = work_pool_work_size(kg, work_pool);
82
83         if(pool_size == 0) {
84                 return false;
85         }
86
87         *work_index = atomic_fetch_and_inc_uint32(&kernel_split_params.work_pools[work_pool]);
88         return (*work_index < pool_size);
89 }
90
91 /* This function assumes that the passed `work` is valid. */
92 /* Decode sample number w.r.t. assigned `work`. */
93 ccl_device uint get_work_sample(KernelGlobals *kg, uint work_index, uint ray_index)
94 {
95         return get_global_work_index(kg, work_index, ray_index) / (kernel_split_params.w * kernel_split_params.h);
96 }
97
98 /* Decode pixel and tile position w.r.t. assigned `work`. */
99 ccl_device void get_work_pixel_tile_position(KernelGlobals *kg,
100                              ccl_private uint *pixel_x,
101                              ccl_private uint *pixel_y,
102                              ccl_private uint *tile_x,
103                              ccl_private uint *tile_y,
104                              uint work_index,
105                              uint ray_index)
106 {
107         uint pixel_index = get_global_work_index(kg, work_index, ray_index) % (kernel_split_params.w*kernel_split_params.h);
108
109         *tile_x = pixel_index % kernel_split_params.w;
110         *tile_y = pixel_index / kernel_split_params.w;
111
112         *pixel_x = *tile_x + kernel_split_params.x;
113         *pixel_y = *tile_y + kernel_split_params.y;
114 }
115
116 CCL_NAMESPACE_END
117
118 #endif  /* __KERNEL_WORK_STEALING_H__ */