Files
test2/intern/cycles/kernel/svm/attribute.h
Lukas Stockner 8cb5e05c48 Cleanup: Cycles: Deduplicate kernel attribute code using templating
The attribute handling code in the kernel is currently highly duplicated since
it needs to handle five different data types and we couldn't use templates
back then.
We can now, so might as well make use of it and get rid of ~1000 lines.

There are also some small fixes for the GPU OSL code:
- Wrong derivative for .w component when converting float2/float3->float4
- Different conversion for float2->float (CPU averages, GPU used to take .x)
- Removed useless code for converting to float2, not used by OSL

Pull Request: https://projects.blender.org/blender/blender/pulls/134694
2025-02-20 19:28:45 +01:00

379 lines
12 KiB
C++

/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#pragma once
#include "kernel/globals.h"
#include "kernel/geom/attribute.h"
#include "kernel/geom/object.h"
#include "kernel/geom/primitive.h"
#include "kernel/geom/volume.h"
#include "kernel/svm/util.h"
#include "kernel/util/differential.h"
CCL_NAMESPACE_BEGIN
/* Attribute Node */
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)
{
*out_offset = node.z;
*type = (NodeAttributeOutputType)node.w;
AttributeDescriptor desc;
if (sd->object != OBJECT_NONE) {
desc = find_attribute(kg, sd, node.y);
if (desc.offset == ATTR_STD_NOT_FOUND) {
desc = attribute_not_found();
desc.offset = 0;
desc.type = (NodeAttributeType)node.w;
}
}
else {
/* background */
desc = attribute_not_found();
desc.offset = 0;
desc.type = (NodeAttributeType)node.w;
}
return desc;
}
template<uint node_feature_mask>
ccl_device_noinline void svm_node_attr(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private float *stack,
const uint4 node)
{
NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
uint out_offset = 0;
const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
#ifdef __VOLUME__
IF_KERNEL_NODES_FEATURE(VOLUME)
{
/* Volumes
* NOTE: moving this into its own node type might help improve performance. */
if (primitive_is_volume_attribute(sd, desc)) {
const float4 value = volume_attribute_float4(kg, sd, desc);
if (type == NODE_ATTR_OUTPUT_FLOAT) {
const float f = volume_attribute_value<float>(value);
stack_store_float(stack, out_offset, f);
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
const float3 f = volume_attribute_value<float3>(value);
stack_store_float3(stack, out_offset, f);
}
else {
const float f = volume_attribute_alpha(value);
stack_store_float(stack, out_offset, f);
}
return;
}
}
#endif
if (sd->type == PRIMITIVE_LAMP && node.y == ATTR_STD_UV) {
stack_store_float3(stack, out_offset, make_float3(1.0f - sd->u - sd->v, sd->u, 0.0f));
return;
}
if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
/* No generated attribute, fall back to object coordinates. */
float3 f = sd->P;
if (sd->object != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &f);
}
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(f));
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, f);
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
return;
}
/* Surface. */
if (desc.type == NODE_ATTR_FLOAT) {
const float f = primitive_surface_attribute<float>(kg, sd, desc, nullptr, nullptr);
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, f);
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(f, f, f));
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
}
else if (desc.type == NODE_ATTR_FLOAT2) {
const float2 f = primitive_surface_attribute<float2>(kg, sd, desc, nullptr, nullptr);
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, f.x);
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, 0.0f));
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
}
else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
const float4 f = primitive_surface_attribute<float4>(kg, sd, desc, nullptr, nullptr);
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(make_float3(f)));
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(f));
}
else {
stack_store_float(stack, out_offset, f.w);
}
}
else {
const float3 f = primitive_surface_attribute<float3>(kg, sd, desc, nullptr, nullptr);
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(f));
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, f);
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
}
}
/* Position offsetted in x direction. */
ccl_device_forceinline float3 svm_node_bump_P_dx(const ccl_private ShaderData *sd)
{
return sd->P + differential_from_compact(sd->Ng, sd->dP).dx * BUMP_DX;
}
/* Position offsetted in y direction. */
ccl_device_forceinline float3 svm_node_bump_P_dy(const ccl_private ShaderData *sd)
{
return sd->P + differential_from_compact(sd->Ng, sd->dP).dy * BUMP_DY;
}
/* Evaluate attributes at a position shifted in x direction. */
ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private float *stack,
const uint4 node)
{
NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
uint out_offset = 0;
const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
#ifdef __VOLUME__
/* Volume */
if (primitive_is_volume_attribute(sd, desc)) {
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, 0.0f);
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f));
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
return;
}
#endif
if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
/* No generated attribute, fall back to object coordinates. */
float3 f_x = svm_node_bump_P_dx(sd);
if (sd->object != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &f_x);
}
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(f_x));
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, f_x);
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
return;
}
/* Surface */
if (desc.type == NODE_ATTR_FLOAT) {
float dfdx;
const float f = primitive_surface_attribute<float>(kg, sd, desc, &dfdx, nullptr);
const float f_x = f + dfdx * BUMP_DX;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, f_x);
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(f_x));
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
}
else if (desc.type == NODE_ATTR_FLOAT2) {
float2 dfdx;
const float2 f = primitive_surface_attribute<float2>(kg, sd, desc, &dfdx, nullptr);
const float2 f_x = f + dfdx * BUMP_DX;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, f_x.x);
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(f_x));
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
}
else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
float4 dfdx;
const float4 f = primitive_surface_attribute<float4>(kg, sd, desc, &dfdx, nullptr);
const float4 f_x = f + dfdx * BUMP_DX;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(make_float3(f_x)));
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(f_x));
}
else {
stack_store_float(stack, out_offset, f_x.w);
}
}
else {
float3 dfdx;
const float3 f = primitive_surface_attribute<float3>(kg, sd, desc, &dfdx, nullptr);
const float3 f_x = f + dfdx * BUMP_DX;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(f_x));
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, f_x);
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
}
}
/* Evaluate attributes at a position shifted in y direction. */
ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private float *stack,
const uint4 node)
{
NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
uint out_offset = 0;
const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
#ifdef __VOLUME__
/* Volume */
if (primitive_is_volume_attribute(sd, desc)) {
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, 0.0f);
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f));
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
return;
}
#endif
if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
/* No generated attribute, fall back to object coordinates. */
float3 f_y = svm_node_bump_P_dy(sd);
if (sd->object != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &f_y);
}
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(f_y));
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, f_y);
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
return;
}
/* Surface */
if (desc.type == NODE_ATTR_FLOAT) {
float dfdy;
const float f = primitive_surface_attribute<float>(kg, sd, desc, nullptr, &dfdy);
const float f_y = f + dfdy * BUMP_DY;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, f_y);
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(f_y));
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
}
else if (desc.type == NODE_ATTR_FLOAT2) {
float2 dfdy;
const float2 f = primitive_surface_attribute<float2>(kg, sd, desc, nullptr, &dfdy);
const float2 f_y = f + dfdy * BUMP_DY;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, f_y.x);
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(f_y));
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
}
else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
float4 dfdy;
const float4 f = primitive_surface_attribute<float4>(kg, sd, desc, nullptr, &dfdy);
const float4 f_y = f + dfdy * BUMP_DY;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(make_float3(f_y)));
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, make_float3(f_y));
}
else {
stack_store_float(stack, out_offset, f_y.w);
}
}
else {
float3 dfdy;
const float3 f = primitive_surface_attribute<float3>(kg, sd, desc, nullptr, &dfdy);
const float3 f_y = f + dfdy * BUMP_DY;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(f_y));
}
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
stack_store_float3(stack, out_offset, f_y);
}
else {
stack_store_float(stack, out_offset, 1.0f);
}
}
}
CCL_NAMESPACE_END