/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include "kernel/globals.h" #include "kernel/types.h" #include "kernel/svm/types.h" CCL_NAMESPACE_BEGIN /* Stack Load */ ccl_device_inline float stack_load_float(const ccl_private float *stack, const uint a) { kernel_assert(a < SVM_STACK_SIZE); return stack[a]; } ccl_device_inline float stack_load_float_default(const ccl_private float *stack, const uint a, const float value) { return (a == (uint)SVM_STACK_INVALID) ? value : stack_load_float(stack, a); } ccl_device_inline float3 stack_load_float3(const ccl_private float *stack, const uint a) { kernel_assert(a + 2 < SVM_STACK_SIZE); const ccl_private float *stack_a = stack + a; return make_float3(stack_a[0], stack_a[1], stack_a[2]); } ccl_device_inline float3 stack_load_float3_default(const ccl_private float *stack, const uint a, const float3 value) { return (a == (uint)SVM_STACK_INVALID) ? value : stack_load_float3(stack, a); } ccl_device_inline int stack_load_int(const ccl_private float *stack, const uint a) { kernel_assert(a < SVM_STACK_SIZE); return __float_as_int(stack[a]); } /* Type-based stack load. T can be float, float3, dual1, or dual3. * When T is a dual type, derivatives are loaded from adjacent stack slots. */ template ccl_device_inline T stack_load(const ccl_private float *stack, const uint a); ccl_device_template_spec float stack_load(const ccl_private float *stack, const uint a) { return stack_load_float(stack, a); } ccl_device_template_spec float3 stack_load(const ccl_private float *stack, const uint a) { return stack_load_float3(stack, a); } ccl_device_template_spec dual1 stack_load(const ccl_private float *stack, const uint a) { return { stack_load_float(stack, a), stack_load_float(stack, a + 1), stack_load_float(stack, a + 2)}; } ccl_device_template_spec dual3 stack_load(const ccl_private float *stack, const uint a) { return {stack_load_float3(stack, a), stack_load_float3(stack, a + 3), stack_load_float3(stack, a + 6)}; } /* Load from SVMInputFloat and SVMInputFloat3. With template versions to support duals * for loading derivatives from adjacent stack slots. */ ccl_device_inline float stack_load(const ccl_private float *ccl_restrict stack, const SVMInputFloat v) { if ((v.bits >> 8) == (SVM_INPUT_STACK_OFFSET_MASK >> 8)) { return stack_load_float(stack, v.bits & 0xFFu); } return __uint_as_float(v.bits); } ccl_device_inline float3 stack_load(const ccl_private float *ccl_restrict stack, const SVMInputFloat3 v) { if ((v.x.bits >> 8) == (SVM_INPUT_STACK_OFFSET_MASK >> 8)) { return stack_load_float3(stack, v.x.bits & 0xFFu); } return make_float3( __uint_as_float(v.x.bits), __uint_as_float(v.y.bits), __uint_as_float(v.z.bits)); } ccl_device_inline int stack_load(const ccl_private float *stack, const SVMInputInt v) { if (v.offset == SVM_STACK_INVALID) { return v.value; } return stack_load_int(stack, v.offset); } template ccl_device_inline T stack_load(const ccl_private float *stack, const SVMInputFloat v); ccl_device_template_spec float stack_load(const ccl_private float *stack, const SVMInputFloat v) { return stack_load(stack, v); } ccl_device_template_spec dual1 stack_load(const ccl_private float *stack, const SVMInputFloat v) { if ((v.bits >> 8) == (SVM_INPUT_STACK_OFFSET_MASK >> 8)) { return stack_load(stack, v.bits & 0xFFu); } return dual1(__uint_as_float(v.bits)); } template ccl_device_inline T stack_load(const ccl_private float *stack, const SVMInputFloat3 v); ccl_device_template_spec float3 stack_load(const ccl_private float *stack, const SVMInputFloat3 v) { return stack_load(stack, v); } ccl_device_template_spec dual3 stack_load(const ccl_private float *stack, const SVMInputFloat3 v) { if ((v.x.bits >> 8) == (SVM_INPUT_STACK_OFFSET_MASK >> 8)) { return stack_load(stack, v.x.bits & 0xFFu); } return dual3(make_float3( __uint_as_float(v.x.bits), __uint_as_float(v.y.bits), __uint_as_float(v.z.bits))); } /* Stack Store */ ccl_device_inline void stack_store_float(ccl_private float *stack, const uint a, const float f) { kernel_assert(a < SVM_STACK_SIZE); stack[a] = f; } ccl_device_inline void stack_store_float3(ccl_private float *stack, const uint a, const float3 f) { kernel_assert(a + 2 < SVM_STACK_SIZE); copy_v3_v3(stack + a, f); } ccl_device_inline void stack_store_int(ccl_private float *stack, const uint a, const int i) { kernel_assert(a < SVM_STACK_SIZE); stack[a] = __int_as_float(i); } /* Type-based stack store. Overloaded for plain and dual types. * For dual types, derivatives are stored in adjacent stack slots. */ ccl_device_inline void stack_store(ccl_private float *stack, const uint a, const float f) { stack_store_float(stack, a, f); } ccl_device_inline void stack_store(ccl_private float *stack, const uint a, const float3 f) { stack_store_float3(stack, a, f); } ccl_device_inline void stack_store(ccl_private float *stack, const uint a, const dual1 f) { stack_store_float(stack, a, f.val); stack_store_float(stack, a + 1, f.dx); stack_store_float(stack, a + 2, f.dy); } ccl_device_inline void stack_store(ccl_private float *stack, const uint a, const dual3 f) { stack_store_float3(stack, a, f.val); stack_store_float3(stack, a + 3, f.dx); stack_store_float3(stack, a + 6, f.dy); } /* Stack Utility */ ccl_device_inline bool stack_valid(const uint a) { return a != (uint)SVM_STACK_INVALID; } /* Reading Nodes */ /* Read a typed node struct directly from the SVM byte-code stream. The struct T must be a * multiple of sizeof(uint) and its memory layout must match the byte-code encoding. Returns * a const reference into the byte-code array and advances the offset past the struct. */ template ccl_device_inline const ccl_global T &svm_node_get(KernelGlobals kg, ccl_private int *const offset) { static_assert(alignof(T) <= alignof(uint)); static_assert(sizeof(T) % sizeof(uint) == 0); const ccl_global T &node = *reinterpret_cast( &kernel_data_fetch(svm_nodes, *offset)); *offset += sizeof(T) / sizeof(uint); return node; } ccl_device_inline float4 svm_node_get_data_float4(KernelGlobals kg, const int offset) { return make_float4(__uint_as_float(kernel_data_fetch(svm_nodes, offset)), __uint_as_float(kernel_data_fetch(svm_nodes, offset + 1)), __uint_as_float(kernel_data_fetch(svm_nodes, offset + 2)), __uint_as_float(kernel_data_fetch(svm_nodes, offset + 3))); } /* Shading Helpers */ ccl_device_forceinline float3 dPdx(const ccl_private ShaderData *sd) { return sd->dPdu * sd->du.dx + sd->dPdv * sd->dv.dx; } ccl_device_forceinline float3 dPdy(const ccl_private ShaderData *sd) { return sd->dPdu * sd->du.dy + sd->dPdv * sd->dv.dy; } /* Shading position, returns Float3Type = float3 (no derivatives) or dual3 (with derivatives). */ template ccl_device_inline Float3Type shading_position(const ccl_private ShaderData *sd) { if constexpr (is_dual_v) { dual3 P(sd->P); P.dx = dPdx(sd); P.dy = dPdy(sd); return P; } else { return sd->P; } } /* Shading incoming direction, returns Float3Type = float3 or dual3. */ template ccl_device_inline Float3Type shading_incoming(const ccl_private ShaderData *sd) { if constexpr (is_dual_v) { dual3 I(sd->wi); float3 dIdx, dIdy; make_orthonormals(sd->wi, &dIdx, &dIdy); I.dx = sd->dI * dIdx; I.dy = sd->dI * dIdy; return I; } else { return sd->wi; } } CCL_NAMESPACE_END