Cycles: Remove ccl_fetch and SOA
[blender.git] / intern / cycles / kernel / geom / geom_patch.h
1 /*
2  * Based on code from OpenSubdiv released under this license:
3  *
4  * Copyright 2013 Pixar
5  *
6  * Licensed under the Apache License, Version 2.0 (the "Apache License")
7  * with the following modification; you may not use this file except in
8  * compliance with the Apache License and the following modification to it:
9  * Section 6. Trademarks. is deleted and replaced with:
10  *
11  * 6. Trademarks. This License does not grant permission to use the trade
12  *   names, trademarks, service marks, or product names of the Licensor
13  *   and its affiliates, except as required to comply with Section 4(c) of
14  *   the License and to reproduce the content of the NOTICE file.
15  *
16  * You may obtain a copy of the Apache License at
17  *
18  *    http://www.apache.org/licenses/LICENSE-2.0
19  *
20  * Unless required by applicable law or agreed to in writing, software
21  * distributed under the Apache License with the above modification is
22  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23  * KIND, either express or implied. See the Apache License for the specific
24  * language governing permissions and limitations under the Apache License.
25  *
26  */
27
28 CCL_NAMESPACE_BEGIN
29
30 typedef struct PatchHandle {
31         int array_index, patch_index, vert_index;
32 } PatchHandle;
33
34 ccl_device_inline int patch_map_resolve_quadrant(float median, float *u, float *v)
35 {
36         int quadrant = -1;
37
38         if(*u < median) {
39                 if(*v < median) {
40                         quadrant = 0;
41                 }
42                 else {
43                         quadrant = 1;
44                         *v -= median;
45                 }
46         }
47         else {
48                 if(*v < median) {
49                         quadrant = 3;
50                 }
51                 else {
52                         quadrant = 2;
53                         *v -= median;
54                 }
55                 *u -= median;
56         }
57
58         return quadrant;
59 }
60
61 /* retrieve PatchHandle from patch coords */
62
63 ccl_device_inline PatchHandle patch_map_find_patch(KernelGlobals *kg, int object, int patch, float u, float v)
64 {
65         PatchHandle handle;
66
67         kernel_assert((u >= 0.0f) && (u <= 1.0f) && (v >= 0.0f) && (v <= 1.0f));
68
69         int node = (object_patch_map_offset(kg, object) + patch)/2;
70         float median = 0.5f;
71
72         for(int depth = 0; depth < 0xff; depth++) {
73                 float delta = median * 0.5f;
74
75                 int quadrant = patch_map_resolve_quadrant(median, &u, &v);
76                 kernel_assert(quadrant >= 0);
77
78                 uint child = kernel_tex_fetch(__patches, node + quadrant);
79
80                 /* is the quadrant a hole? */
81                 if(!(child & PATCH_MAP_NODE_IS_SET)) {
82                         handle.array_index = -1;
83                         return handle;
84                 }
85
86                 uint index = child & PATCH_MAP_NODE_INDEX_MASK;
87
88                 if(child & PATCH_MAP_NODE_IS_LEAF) {
89                         handle.array_index = kernel_tex_fetch(__patches, index + 0);
90                         handle.patch_index = kernel_tex_fetch(__patches, index + 1);
91                         handle.vert_index = kernel_tex_fetch(__patches, index + 2);
92
93                         return handle;
94                 } else {
95                         node = index;
96                 }
97
98                 median = delta;
99         }
100
101         /* no leaf found */
102         kernel_assert(0);
103
104         handle.array_index = -1;
105         return handle;
106 }
107
108 ccl_device_inline void patch_eval_bspline_weights(float t, float *point, float *deriv)
109 {
110         /* The four uniform cubic B-Spline basis functions evaluated at t */
111         float inv_6 = 1.0f / 6.0f;
112
113         float t2 = t * t;
114         float t3 = t * t2;
115
116         point[0] = inv_6 * (1.0f - 3.0f*(t - t2) - t3);
117         point[1] = inv_6 * (4.0f - 6.0f*t2 + 3.0f*t3);
118         point[2] = inv_6 * (1.0f + 3.0f*(t + t2 - t3));
119         point[3] = inv_6 * t3;
120
121         /* Derivatives of the above four basis functions at t */
122         deriv[0] = -0.5f*t2 + t - 0.5f;
123         deriv[1] =  1.5f*t2 - 2.0f*t;
124         deriv[2] = -1.5f*t2 + t + 0.5f;
125         deriv[3] =  0.5f*t2;
126 }
127
128 ccl_device_inline void patch_eval_adjust_boundary_weights(uint bits, float *s, float *t)
129 {
130         int boundary = ((bits >> 8) & 0xf);
131
132         if(boundary & 1) {
133                 t[2] -= t[0];
134                 t[1] += 2*t[0];
135                 t[0] = 0;
136         }
137
138         if(boundary & 2) {
139                 s[1] -= s[3];
140                 s[2] += 2*s[3];
141                 s[3] = 0;
142         }
143
144         if(boundary & 4) {
145                 t[1] -= t[3];
146                 t[2] += 2*t[3];
147                 t[3] = 0;
148         }
149
150         if(boundary & 8) {
151                 s[2] -= s[0];
152                 s[1] += 2*s[0];
153                 s[0] = 0;
154         }
155 }
156
157 ccl_device_inline int patch_eval_depth(uint patch_bits)
158 {
159         return (patch_bits & 0xf);
160 }
161
162 ccl_device_inline float patch_eval_param_fraction(uint patch_bits)
163 {
164         bool non_quad_root = (patch_bits >> 4) & 0x1;
165         int depth = patch_eval_depth(patch_bits);
166
167         if(non_quad_root) {
168                 return 1.0f / (float)(1 << (depth-1));
169         }
170         else {
171                 return 1.0f / (float)(1 << depth);
172         }
173 }
174
175 ccl_device_inline void patch_eval_normalize_coords(uint patch_bits, float *u, float *v)
176 {
177         float frac = patch_eval_param_fraction(patch_bits);
178
179         int iu = (patch_bits >> 22) & 0x3ff;
180         int iv = (patch_bits >> 12) & 0x3ff;
181
182         /* top left corner */
183         float pu = (float)iu*frac;
184         float pv = (float)iv*frac;
185
186         /* normalize uv coordinates */
187         *u = (*u - pu) / frac;
188         *v = (*v - pv) / frac;
189 }
190
191 /* retrieve patch control indices */
192
193 ccl_device_inline int patch_eval_indices(KernelGlobals *kg, const PatchHandle *handle, int channel,
194                                          int indices[PATCH_MAX_CONTROL_VERTS])
195 {
196         int index_base = kernel_tex_fetch(__patches, handle->array_index + 2) + handle->vert_index;
197
198         /* XXX: regular patches only */
199         for(int i = 0; i < 16; i++) {
200                 indices[i] = kernel_tex_fetch(__patches, index_base + i);
201         }
202
203         return 16;
204 }
205
206 /* evaluate patch basis functions */
207
208 ccl_device_inline void patch_eval_basis(KernelGlobals *kg, const PatchHandle *handle, float u, float v,
209                                 float weights[PATCH_MAX_CONTROL_VERTS],
210                                 float weights_du[PATCH_MAX_CONTROL_VERTS],
211                                 float weights_dv[PATCH_MAX_CONTROL_VERTS])
212 {
213         uint patch_bits = kernel_tex_fetch(__patches, handle->patch_index + 1); /* read patch param */
214         float d_scale = 1 << patch_eval_depth(patch_bits);
215
216         bool non_quad_root = (patch_bits >> 4) & 0x1;
217         if(non_quad_root) {
218                 d_scale *= 0.5f;
219         }
220
221         patch_eval_normalize_coords(patch_bits, &u, &v);
222
223         /* XXX: regular patches only for now. */
224
225         float s[4], t[4], ds[4], dt[4];
226
227         patch_eval_bspline_weights(u, s, ds);
228         patch_eval_bspline_weights(v, t, dt);
229
230         patch_eval_adjust_boundary_weights(patch_bits, s, t);
231         patch_eval_adjust_boundary_weights(patch_bits, ds, dt);
232
233         for(int k = 0; k < 4; k++) {
234                 for(int l = 0; l < 4; l++) {
235                         weights[4*k+l] = s[l] * t[k];
236                         weights_du[4*k+l] = ds[l] * t[k] * d_scale;
237                         weights_dv[4*k+l] = s[l] * dt[k] * d_scale;
238                 }
239         }
240 }
241
242 /* generic function for evaluating indices and weights from patch coords */
243
244 ccl_device_inline int patch_eval_control_verts(KernelGlobals *kg, int object, int patch, float u, float v, int channel,
245                                         int indices[PATCH_MAX_CONTROL_VERTS],
246                                         float weights[PATCH_MAX_CONTROL_VERTS],
247                                         float weights_du[PATCH_MAX_CONTROL_VERTS],
248                                         float weights_dv[PATCH_MAX_CONTROL_VERTS])
249 {
250         PatchHandle handle = patch_map_find_patch(kg, object, patch, u, v);
251         kernel_assert(handle.array_index >= 0);
252
253         int num_control = patch_eval_indices(kg, &handle, channel, indices);
254         patch_eval_basis(kg, &handle, u, v, weights, weights_du, weights_dv);
255
256         return num_control;
257 }
258
259 /* functions for evaluating attributes on patches */
260
261 ccl_device float patch_eval_float(KernelGlobals *kg, const ShaderData *sd, int offset,
262                                   int patch, float u, float v, int channel,
263                                   float *du, float* dv)
264 {
265         int indices[PATCH_MAX_CONTROL_VERTS];
266         float weights[PATCH_MAX_CONTROL_VERTS];
267         float weights_du[PATCH_MAX_CONTROL_VERTS];
268         float weights_dv[PATCH_MAX_CONTROL_VERTS];
269
270         int num_control = patch_eval_control_verts(kg, sd->object, patch, u, v, channel,
271                                                    indices, weights, weights_du, weights_dv);
272
273         float val = 0.0f;
274         if(du) *du = 0.0f;
275         if(dv) *dv = 0.0f;
276
277         for(int i = 0; i < num_control; i++) {
278                 float v = kernel_tex_fetch(__attributes_float, offset + indices[i]);
279
280                 val += v * weights[i];
281                 if(du) *du += v * weights_du[i];
282                 if(dv) *dv += v * weights_dv[i];
283         }
284
285         return val;
286 }
287
288 ccl_device float3 patch_eval_float3(KernelGlobals *kg, const ShaderData *sd, int offset,
289                                     int patch, float u, float v, int channel,
290                                     float3 *du, float3 *dv)
291 {
292         int indices[PATCH_MAX_CONTROL_VERTS];
293         float weights[PATCH_MAX_CONTROL_VERTS];
294         float weights_du[PATCH_MAX_CONTROL_VERTS];
295         float weights_dv[PATCH_MAX_CONTROL_VERTS];
296
297         int num_control = patch_eval_control_verts(kg, sd->object, patch, u, v, channel,
298                                                    indices, weights, weights_du, weights_dv);
299
300         float3 val = make_float3(0.0f, 0.0f, 0.0f);
301         if(du) *du = make_float3(0.0f, 0.0f, 0.0f);
302         if(dv) *dv = make_float3(0.0f, 0.0f, 0.0f);
303
304         for(int i = 0; i < num_control; i++) {
305                 float3 v = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + indices[i]));
306
307                 val += v * weights[i];
308                 if(du) *du += v * weights_du[i];
309                 if(dv) *dv += v * weights_dv[i];
310         }
311
312         return val;
313 }
314
315 ccl_device float3 patch_eval_uchar4(KernelGlobals *kg, const ShaderData *sd, int offset,
316                                     int patch, float u, float v, int channel,
317                                     float3 *du, float3 *dv)
318 {
319         int indices[PATCH_MAX_CONTROL_VERTS];
320         float weights[PATCH_MAX_CONTROL_VERTS];
321         float weights_du[PATCH_MAX_CONTROL_VERTS];
322         float weights_dv[PATCH_MAX_CONTROL_VERTS];
323
324         int num_control = patch_eval_control_verts(kg, sd->object, patch, u, v, channel,
325                                                    indices, weights, weights_du, weights_dv);
326
327         float3 val = make_float3(0.0f, 0.0f, 0.0f);
328         if(du) *du = make_float3(0.0f, 0.0f, 0.0f);
329         if(dv) *dv = make_float3(0.0f, 0.0f, 0.0f);
330
331         for(int i = 0; i < num_control; i++) {
332                 float3 v = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, offset + indices[i]));
333
334                 val += v * weights[i];
335                 if(du) *du += v * weights_du[i];
336                 if(dv) *dv += v * weights_dv[i];
337         }
338
339         return val;
340 }
341
342 CCL_NAMESPACE_END
343