Blender V4.5
kernel/svm/attribute.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "kernel/globals.h"
8
10#include "kernel/geom/object.h"
12#include "kernel/geom/volume.h"
13
14#include "kernel/svm/util.h"
15
17
19
20/* Attribute Node */
21
23 ccl_private ShaderData *sd,
24 const uint4 node,
26 ccl_private uint *out_offset)
27{
28 uint type_value;
29 svm_unpack_node_uchar2(node.z, out_offset, &type_value);
30 *type = (NodeAttributeOutputType)type_value;
31
33
34 if (sd->object != OBJECT_NONE) {
35 desc = find_attribute(kg, sd, node.y);
36 if (desc.offset == ATTR_STD_NOT_FOUND) {
37 desc = attribute_not_found();
38 desc.offset = 0;
39 desc.type = (NodeAttributeType)type_value;
40 }
41 }
42 else {
43 /* background */
44 desc = attribute_not_found();
45 desc.offset = 0;
46 desc.type = (NodeAttributeType)type_value;
47 }
48
49 return desc;
50}
51
52template<uint node_feature_mask>
54 ccl_private ShaderData *sd,
55 ccl_private float *stack,
56 const uint4 node)
57{
59 uint out_offset = 0;
60 const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
61
62#ifdef __VOLUME__
64 {
65 /* Volumes
66 * NOTE: moving this into its own node type might help improve performance. */
67 if (primitive_is_volume_attribute(sd, desc)) {
68 const float4 value = volume_attribute_float4(kg, sd, desc);
69
70 if (type == NODE_ATTR_OUTPUT_FLOAT) {
71 const float f = volume_attribute_value<float>(value);
72 stack_store_float(stack, out_offset, f);
73 }
74 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
75 const float3 f = volume_attribute_value<float3>(value);
76 stack_store_float3(stack, out_offset, f);
77 }
78 else {
79 const float f = volume_attribute_alpha(value);
80 stack_store_float(stack, out_offset, f);
81 }
82 return;
83 }
84 }
85#endif
86
87 if (sd->type == PRIMITIVE_LAMP && node.y == ATTR_STD_UV) {
88 stack_store_float3(stack, out_offset, make_float3(1.0f - sd->u - sd->v, sd->u, 0.0f));
89 return;
90 }
91
92 if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
93 /* No generated attribute, fall back to object coordinates. */
94 float3 f = sd->P;
95 if (sd->object != OBJECT_NONE) {
97 }
98 if (type == NODE_ATTR_OUTPUT_FLOAT) {
99 stack_store_float(stack, out_offset, average(f));
100 }
101 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
102 stack_store_float3(stack, out_offset, f);
103 }
104 else {
105 stack_store_float(stack, out_offset, 1.0f);
106 }
107 return;
108 }
109
110 /* Surface. */
111 if (desc.type == NODE_ATTR_FLOAT) {
112 const float f = primitive_surface_attribute<float>(kg, sd, desc, nullptr, nullptr);
113 if (type == NODE_ATTR_OUTPUT_FLOAT) {
114 stack_store_float(stack, out_offset, f);
115 }
116 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
117 stack_store_float3(stack, out_offset, make_float3(f, f, f));
118 }
119 else {
120 stack_store_float(stack, out_offset, 1.0f);
121 }
122 }
123 else if (desc.type == NODE_ATTR_FLOAT2) {
124 const float2 f = primitive_surface_attribute<float2>(kg, sd, desc, nullptr, nullptr);
125 if (type == NODE_ATTR_OUTPUT_FLOAT) {
126 stack_store_float(stack, out_offset, f.x);
127 }
128 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
129 stack_store_float3(stack, out_offset, make_float3(f.x, f.y, 0.0f));
130 }
131 else {
132 stack_store_float(stack, out_offset, 1.0f);
133 }
134 }
135 else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
136 const float4 f = primitive_surface_attribute<float4>(kg, sd, desc, nullptr, nullptr);
137 if (type == NODE_ATTR_OUTPUT_FLOAT) {
138 stack_store_float(stack, out_offset, average(make_float3(f)));
139 }
140 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
141 stack_store_float3(stack, out_offset, make_float3(f));
142 }
143 else {
144 stack_store_float(stack, out_offset, f.w);
145 }
146 }
147 else {
148 const float3 f = primitive_surface_attribute<float3>(kg, sd, desc, nullptr, nullptr);
149 if (type == NODE_ATTR_OUTPUT_FLOAT) {
150 stack_store_float(stack, out_offset, average(f));
151 }
152 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
153 stack_store_float3(stack, out_offset, f);
154 }
155 else {
156 stack_store_float(stack, out_offset, 1.0f);
157 }
158 }
159}
160
161/* Position offsetted in x direction. */
163 const float bump_filter_width)
164{
165 return sd->P + differential_from_compact(sd->Ng, sd->dP).dx * bump_filter_width;
166}
167
168/* Position offsetted in y direction. */
170 const float bump_filter_width)
171{
172 return sd->P + differential_from_compact(sd->Ng, sd->dP).dy * bump_filter_width;
173}
174
175/* Evaluate attributes at a position shifted in x direction. */
177 ccl_private ShaderData *sd,
178 ccl_private float *stack,
179 const uint4 node)
180{
182 uint out_offset = 0;
183 const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
184 const float bump_filter_width = __uint_as_float(node.w);
185
186#ifdef __VOLUME__
187 /* Volume */
188 if (primitive_is_volume_attribute(sd, desc)) {
189 if (type == NODE_ATTR_OUTPUT_FLOAT) {
190 stack_store_float(stack, out_offset, 0.0f);
191 }
192 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
193 stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f));
194 }
195 else {
196 stack_store_float(stack, out_offset, 1.0f);
197 }
198 return;
199 }
200#endif
201
202 if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
203 /* No generated attribute, fall back to object coordinates. */
204 float3 f_x = svm_node_bump_P_dx(sd, bump_filter_width);
205 if (sd->object != OBJECT_NONE) {
207 }
208 if (type == NODE_ATTR_OUTPUT_FLOAT) {
209 stack_store_float(stack, out_offset, average(f_x));
210 }
211 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
212 stack_store_float3(stack, out_offset, f_x);
213 }
214 else {
215 stack_store_float(stack, out_offset, 1.0f);
216 }
217 return;
218 }
219
220 /* Surface */
221 if (desc.type == NODE_ATTR_FLOAT) {
222 float dfdx;
223 const float f = primitive_surface_attribute<float>(kg, sd, desc, &dfdx, nullptr);
224 const float f_x = f + dfdx * bump_filter_width;
225 if (type == NODE_ATTR_OUTPUT_FLOAT) {
226 stack_store_float(stack, out_offset, f_x);
227 }
228 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
229 stack_store_float3(stack, out_offset, make_float3(f_x));
230 }
231 else {
232 stack_store_float(stack, out_offset, 1.0f);
233 }
234 }
235 else if (desc.type == NODE_ATTR_FLOAT2) {
236 float2 dfdx;
237 const float2 f = primitive_surface_attribute<float2>(kg, sd, desc, &dfdx, nullptr);
238 const float2 f_x = f + dfdx * bump_filter_width;
239 if (type == NODE_ATTR_OUTPUT_FLOAT) {
240 stack_store_float(stack, out_offset, f_x.x);
241 }
242 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
243 stack_store_float3(stack, out_offset, make_float3(f_x));
244 }
245 else {
246 stack_store_float(stack, out_offset, 1.0f);
247 }
248 }
249 else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
250 float4 dfdx;
251 const float4 f = primitive_surface_attribute<float4>(kg, sd, desc, &dfdx, nullptr);
252 const float4 f_x = f + dfdx * bump_filter_width;
253 if (type == NODE_ATTR_OUTPUT_FLOAT) {
254 stack_store_float(stack, out_offset, average(make_float3(f_x)));
255 }
256 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
257 stack_store_float3(stack, out_offset, make_float3(f_x));
258 }
259 else {
260 stack_store_float(stack, out_offset, f_x.w);
261 }
262 }
263 else {
264 float3 dfdx;
265 const float3 f = primitive_surface_attribute<float3>(kg, sd, desc, &dfdx, nullptr);
266 const float3 f_x = f + dfdx * bump_filter_width;
267 if (type == NODE_ATTR_OUTPUT_FLOAT) {
268 stack_store_float(stack, out_offset, average(f_x));
269 }
270 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
271 stack_store_float3(stack, out_offset, f_x);
272 }
273 else {
274 stack_store_float(stack, out_offset, 1.0f);
275 }
276 }
277}
278
279/* Evaluate attributes at a position shifted in y direction. */
281 ccl_private ShaderData *sd,
282 ccl_private float *stack,
283 const uint4 node)
284{
286 uint out_offset = 0;
287 const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
288 const float bump_filter_width = __uint_as_float(node.w);
289
290#ifdef __VOLUME__
291 /* Volume */
292 if (primitive_is_volume_attribute(sd, desc)) {
293 if (type == NODE_ATTR_OUTPUT_FLOAT) {
294 stack_store_float(stack, out_offset, 0.0f);
295 }
296 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
297 stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f));
298 }
299 else {
300 stack_store_float(stack, out_offset, 1.0f);
301 }
302 return;
303 }
304#endif
305
306 if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
307 /* No generated attribute, fall back to object coordinates. */
308 float3 f_y = svm_node_bump_P_dy(sd, bump_filter_width);
309 if (sd->object != OBJECT_NONE) {
311 }
312 if (type == NODE_ATTR_OUTPUT_FLOAT) {
313 stack_store_float(stack, out_offset, average(f_y));
314 }
315 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
316 stack_store_float3(stack, out_offset, f_y);
317 }
318 else {
319 stack_store_float(stack, out_offset, 1.0f);
320 }
321 return;
322 }
323
324 /* Surface */
325 if (desc.type == NODE_ATTR_FLOAT) {
326 float dfdy;
327 const float f = primitive_surface_attribute<float>(kg, sd, desc, nullptr, &dfdy);
328 const float f_y = f + dfdy * bump_filter_width;
329 if (type == NODE_ATTR_OUTPUT_FLOAT) {
330 stack_store_float(stack, out_offset, f_y);
331 }
332 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
333 stack_store_float3(stack, out_offset, make_float3(f_y));
334 }
335 else {
336 stack_store_float(stack, out_offset, 1.0f);
337 }
338 }
339 else if (desc.type == NODE_ATTR_FLOAT2) {
340 float2 dfdy;
341 const float2 f = primitive_surface_attribute<float2>(kg, sd, desc, nullptr, &dfdy);
342 const float2 f_y = f + dfdy * bump_filter_width;
343 if (type == NODE_ATTR_OUTPUT_FLOAT) {
344 stack_store_float(stack, out_offset, f_y.x);
345 }
346 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
347 stack_store_float3(stack, out_offset, make_float3(f_y));
348 }
349 else {
350 stack_store_float(stack, out_offset, 1.0f);
351 }
352 }
353 else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
354 float4 dfdy;
355 const float4 f = primitive_surface_attribute<float4>(kg, sd, desc, nullptr, &dfdy);
356 const float4 f_y = f + dfdy * bump_filter_width;
357 if (type == NODE_ATTR_OUTPUT_FLOAT) {
358 stack_store_float(stack, out_offset, average(make_float3(f_y)));
359 }
360 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
361 stack_store_float3(stack, out_offset, make_float3(f_y));
362 }
363 else {
364 stack_store_float(stack, out_offset, f_y.w);
365 }
366 }
367 else {
368 float3 dfdy;
369 const float3 f = primitive_surface_attribute<float3>(kg, sd, desc, nullptr, &dfdy);
370 const float3 f_y = f + dfdy * bump_filter_width;
371 if (type == NODE_ATTR_OUTPUT_FLOAT) {
372 stack_store_float(stack, out_offset, average(f_y));
373 }
374 else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
375 stack_store_float3(stack, out_offset, f_y);
376 }
377 else {
378 stack_store_float(stack, out_offset, 1.0f);
379 }
380 }
381}
382
unsigned int uint
ccl_device_inline void stack_store_float(ccl_private float *stack, const uint a, const float f)
ccl_device_inline void stack_store_float3(ccl_private float *stack, const uint a, const float3 f)
ccl_device_forceinline void svm_unpack_node_uchar2(const uint i, ccl_private uint *x, ccl_private uint *y)
#define ccl_device_forceinline
#define IF_KERNEL_NODES_FEATURE(feature)
#define ccl_device
#define OBJECT_NONE
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_noinline
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define __uint_as_float(x)
ccl_device_forceinline differential3 differential_from_compact(const float3 D, const float dD)
VecBase< float, 4 > float4
CCL_NAMESPACE_BEGIN ccl_device_inline AttributeDescriptor attribute_not_found()
ccl_device_inline void object_inverse_position_transform(KernelGlobals kg, const ccl_private ShaderData *sd, ccl_private float3 *P)
ccl_device_forceinline float3 svm_node_bump_P_dx(const ccl_private ShaderData *sd, const float bump_filter_width)
ccl_device_forceinline float3 svm_node_bump_P_dy(const ccl_private ShaderData *sd, const float bump_filter_width)
CCL_NAMESPACE_BEGIN ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals kg, ccl_private ShaderData *sd, const uint4 node, ccl_private NodeAttributeOutputType *type, ccl_private uint *out_offset)
ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, const uint4 node)
ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, const uint4 node)
ccl_device_noinline void svm_node_attr(KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, const uint4 node)
NodeAttributeOutputType
@ NODE_ATTR_OUTPUT_FLOAT
@ NODE_ATTR_OUTPUT_FLOAT3
NodeAttributeType
@ NODE_ATTR_FLOAT
@ NODE_ATTR_RGBA
@ NODE_ATTR_FLOAT2
@ NODE_ATTR_FLOAT4
@ PRIMITIVE_LAMP
@ ATTR_STD_UV
@ ATTR_STD_NOT_FOUND
@ ATTR_STD_GENERATED
@ ATTR_ELEMENT_NONE
ccl_device_inline float average(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_forceinline T primitive_surface_attribute(KernelGlobals kg, const ccl_private ShaderData *sd, const AttributeDescriptor desc, ccl_private T *dfdx, ccl_private T *dfdy)
Definition primitive.h:32
static bool find_attribute(const std::string &attributes, const char *search_attribute)
AttributeElement element
NodeAttributeType type
float x
float y
uint y
Definition types_uint4.h:13
uint z
Definition types_uint4.h:13
uint w
Definition types_uint4.h:13