270 lines
7.9 KiB
C++
270 lines
7.9 KiB
C++
/* 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<typename T> 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<typename T>
|
|
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<dual1>(stack, v.bits & 0xFFu);
|
|
}
|
|
return dual1(__uint_as_float(v.bits));
|
|
}
|
|
|
|
template<typename T>
|
|
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<dual3>(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<typename T>
|
|
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<const ccl_global T *>(
|
|
&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<typename Float3Type>
|
|
ccl_device_inline Float3Type shading_position(const ccl_private ShaderData *sd)
|
|
{
|
|
if constexpr (is_dual_v<Float3Type>) {
|
|
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<typename Float3Type>
|
|
ccl_device_inline Float3Type shading_incoming(const ccl_private ShaderData *sd)
|
|
{
|
|
if constexpr (is_dual_v<Float3Type>) {
|
|
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
|