Files
test2/intern/cycles/kernel/osl/services_gpu.h
Weizhen Huang df496eb894 Cycles: use one-tap stochastic interpolation for volume
It has ~1.2x speed-up on CPU and ~1.5x speed-up on GPU (tested on Metal
M2 Ultra).

Individual samples are noisier, but equal time renders are mostly
better.

Note that volume emission renders differently than before.

Pull Request: https://projects.blender.org/blender/blender/pulls/144451
2025-08-14 15:22:44 +02:00

1210 lines
44 KiB
C++

/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: BSD-3-Clause
*
* Adapted code from Open Shading Language. */
#include "kernel/camera/camera.h"
#include "kernel/geom/attribute.h"
#include "kernel/geom/curve.h"
#include "kernel/geom/motion_triangle.h"
#include "kernel/geom/object.h"
#include "kernel/geom/point.h"
#include "kernel/geom/primitive.h"
#include "kernel/geom/triangle.h"
#include "kernel/util/differential.h"
#include "kernel/util/ies.h"
#include "kernel/util/texture_3d.h"
#include "util/hash.h"
#include "util/transform.h"
#include "kernel/osl/osl.h"
#include "kernel/osl/services_shared.h"
namespace DeviceStrings {
/* "" */
ccl_device_constant DeviceString _emptystring_ = 0ull;
/* "common" */
ccl_device_constant DeviceString u_common = 14645198576927606093ull;
/* "world" */
ccl_device_constant DeviceString u_world = 16436542438370751598ull;
/* "shader" */
ccl_device_constant DeviceString u_shader = 4279676006089868ull;
/* "object" */
ccl_device_constant DeviceString u_object = 973692718279674627ull;
/* "NDC" */
ccl_device_constant DeviceString u_ndc = 5148305047403260775ull;
/* "screen" */
ccl_device_constant DeviceString u_screen = 14159088609039777114ull;
/* "camera" */
ccl_device_constant DeviceString u_camera = 2159505832145726196ull;
/* "raster" */
ccl_device_constant DeviceString u_raster = 7759263238610201778ull;
/* "colorsystem" */
ccl_device_constant DeviceString u_colorsystem = 1390623632464445670ull;
/* "object:location" */
ccl_device_constant DeviceString u_object_location = 7846190347358762897ull;
/* "object:color" */
ccl_device_constant DeviceString u_object_color = 12695623857059169556ull;
/* "object:alpha" */
ccl_device_constant DeviceString u_object_alpha = 11165053919428293151ull;
/* "object:index" */
ccl_device_constant DeviceString u_object_index = 6588325838217472556ull;
/* "object:is_light" */
ccl_device_constant DeviceString u_object_is_light = 13979755312845091842ull;
/* "geom:bump_map_normal" */
ccl_device_constant DeviceString u_bump_map_normal = 9592102745179132106ull;
/* "geom:dupli_generated" */
ccl_device_constant DeviceString u_geom_dupli_generated = 6715607178003388908ull;
/* "geom:dupli_uv" */
ccl_device_constant DeviceString u_geom_dupli_uv = 1294253317490155849ull;
/* "material:index" */
ccl_device_constant DeviceString u_material_index = 741770758159634623ull;
/* "object:random" */
ccl_device_constant DeviceString u_object_random = 15789063994977955884ull;
/* "particle:index" */
ccl_device_constant DeviceString u_particle_index = 9489711748229903784ull;
/* "particle:random" */
ccl_device_constant DeviceString u_particle_random = 17993722202766855761ull;
/* "particle:age" */
ccl_device_constant DeviceString u_particle_age = 7380730644710951109ull;
/* "particle:lifetime" */
ccl_device_constant DeviceString u_particle_lifetime = 16576828923156200061ull;
/* "particle:location" */
ccl_device_constant DeviceString u_particle_location = 10309536211423573010ull;
/* "particle:rotation" */
ccl_device_constant DeviceString u_particle_rotation = 17858543768041168459ull;
/* "particle:size" */
ccl_device_constant DeviceString u_particle_size = 16461524249715420389ull;
/* "particle:velocity" */
ccl_device_constant DeviceString u_particle_velocity = 13199101248768308863ull;
/* "particle:angular_velocity" */
ccl_device_constant DeviceString u_particle_angular_velocity = 16327930120486517910ull;
/* "geom:numpolyvertices" */
ccl_device_constant DeviceString u_geom_numpolyvertices = 382043551489988826ull;
/* "geom:trianglevertices" */
ccl_device_constant DeviceString u_geom_trianglevertices = 17839267571524187074ull;
/* "geom:polyvertices" */
ccl_device_constant DeviceString u_geom_polyvertices = 1345577201967881769ull;
/* "geom:name" */
ccl_device_constant DeviceString u_geom_name = 13606338128269760050ull;
/* "geom:undisplaced" */
ccl_device_constant DeviceString u_geom_undisplaced = 12431586303019276305ull;
/* "geom:is_smooth" */
ccl_device_constant DeviceString u_is_smooth = 857544214094480123ull;
/* "geom:is_curve" */
ccl_device_constant DeviceString u_is_curve = 129742495633653138ull;
/* "geom:curve_thickness" */
ccl_device_constant DeviceString u_curve_thickness = 10605802038397633852ull;
/* "geom:curve_length" */
ccl_device_constant DeviceString u_curve_length = 11423459517663715453ull;
/* "geom:curve_tangent_normal" */
ccl_device_constant DeviceString u_curve_tangent_normal = 12301397394034985633ull;
/* "geom:curve_random" */
ccl_device_constant DeviceString u_curve_random = 15293085049960492358ull;
/* "geom:is_point" */
ccl_device_constant DeviceString u_is_point = 2511357849436175953ull;
/* "geom:point_radius" */
ccl_device_constant DeviceString u_point_radius = 9956381140398668479ull;
/* "geom:point_position" */
ccl_device_constant DeviceString u_point_position = 15684484280742966916ull;
/* "geom:point_random" */
ccl_device_constant DeviceString u_point_random = 5632627207092325544ull;
/* "geom:normal_map_normal" */
ccl_device_constant DeviceString u_normal_map_normal = 10718948685686827073;
/* "path:ray_length" */
ccl_device_constant DeviceString u_path_ray_length = 16391985802412544524ull;
/* "path:ray_depth" */
ccl_device_constant DeviceString u_path_ray_depth = 16643933224879500399ull;
/* "path:diffuse_depth" */
ccl_device_constant DeviceString u_path_diffuse_depth = 13191651286699118408ull;
/* "path:glossy_depth" */
ccl_device_constant DeviceString u_path_glossy_depth = 15717768399057252940ull;
/* "path:transparent_depth" */
ccl_device_constant DeviceString u_path_transparent_depth = 7821650266475578543ull;
/* "path:transmission_depth" */
ccl_device_constant DeviceString u_path_transmission_depth = 15113408892323917624ull;
/* "path:portal_depth" */
ccl_device_constant DeviceString u_path_portal_depth = 13191651286699118408ull;
/* "cam:sensor_size" */
ccl_device_constant DeviceString u_sensor_size = 7525693591727141378ull;
/* "cam:image_resolution" */
ccl_device_constant DeviceString u_image_resolution = 5199143367706113607ull;
/* "cam:aperture_aspect_ratio" */
ccl_device_constant DeviceString u_aperture_aspect_ratio = 8708221138893210943ull;
/* "cam:aperture_size" */
ccl_device_constant DeviceString u_aperture_size = 3708482920470008383ull;
/* "cam:aperture_position" */
ccl_device_constant DeviceString u_aperture_position = 12926784411960338650ull;
/* "cam:focal_distance" */
ccl_device_constant DeviceString u_focal_distance = 7162995161881858159ull;
} // namespace DeviceStrings
/* Closure */
ccl_device_extern ccl_private OSLClosure *osl_mul_closure_color(ccl_private ShaderGlobals *sg,
ccl_private OSLClosure *a,
const ccl_private float3 *weight)
{
if (*weight == zero_float3() || !a) {
return nullptr;
}
else if (*weight == one_float3()) {
return a;
}
ccl_private uint8_t *closure_pool = sg->closure_pool;
/* Align pointer to closure struct requirement */
closure_pool = reinterpret_cast<uint8_t *>(
(reinterpret_cast<size_t>(closure_pool) + alignof(OSLClosureMul) - 1) &
(-alignof(OSLClosureMul)));
sg->closure_pool = closure_pool + sizeof(OSLClosureMul);
ccl_private OSLClosureMul *const closure = reinterpret_cast<ccl_private OSLClosureMul *>(
closure_pool);
closure->id = OSL_CLOSURE_MUL_ID;
closure->weight = *weight;
closure->closure = a;
return closure;
}
ccl_device_extern ccl_private OSLClosure *osl_mul_closure_float(ccl_private ShaderGlobals *sg,
ccl_private OSLClosure *a,
const float weight)
{
if (weight == 0.0f || !a) {
return nullptr;
}
else if (weight == 1.0f) {
return a;
}
ccl_private uint8_t *closure_pool = sg->closure_pool;
/* Align pointer to closure struct requirement */
closure_pool = reinterpret_cast<uint8_t *>(
(reinterpret_cast<size_t>(closure_pool) + alignof(OSLClosureMul) - 1) &
(-alignof(OSLClosureMul)));
sg->closure_pool = closure_pool + sizeof(OSLClosureMul);
ccl_private OSLClosureMul *const closure = reinterpret_cast<ccl_private OSLClosureMul *>(
closure_pool);
closure->id = OSL_CLOSURE_MUL_ID;
closure->weight = make_float3(weight, weight, weight);
closure->closure = a;
return closure;
}
ccl_device_extern ccl_private OSLClosure *osl_add_closure_closure(ccl_private ShaderGlobals *sg,
ccl_private OSLClosure *a,
ccl_private OSLClosure *b)
{
if (!a) {
return b;
}
if (!b) {
return a;
}
ccl_private uint8_t *closure_pool = sg->closure_pool;
/* Align pointer to closure struct requirement */
closure_pool = reinterpret_cast<uint8_t *>(
(reinterpret_cast<size_t>(closure_pool) + alignof(OSLClosureAdd) - 1) &
(-alignof(OSLClosureAdd)));
sg->closure_pool = closure_pool + sizeof(OSLClosureAdd);
ccl_private OSLClosureAdd *const closure = reinterpret_cast<ccl_private OSLClosureAdd *>(
closure_pool);
closure->id = OSL_CLOSURE_ADD_ID;
closure->closureA = a;
closure->closureB = b;
return closure;
}
ccl_device_extern ccl_private OSLClosure *osl_allocate_closure_component(
ccl_private ShaderGlobals *sg, const int id, const int size)
{
ccl_private uint8_t *closure_pool = sg->closure_pool;
/* Align pointer to closure struct requirement */
closure_pool = reinterpret_cast<uint8_t *>(
(reinterpret_cast<size_t>(closure_pool) + alignof(OSLClosureComponent) - 1) &
(-alignof(OSLClosureComponent)));
sg->closure_pool = closure_pool + sizeof(OSLClosureComponent) + size;
ccl_private OSLClosureComponent *const closure =
reinterpret_cast<ccl_private OSLClosureComponent *>(closure_pool);
closure->id = static_cast<OSLClosureType>(id);
closure->weight = one_float3();
return closure;
}
ccl_device_extern ccl_private OSLClosure *osl_allocate_weighted_closure_component(
ccl_private ShaderGlobals *sg, const int id, const int size, const ccl_private float3 *weight)
{
ccl_private uint8_t *closure_pool = sg->closure_pool;
/* Align pointer to closure struct requirement */
closure_pool = reinterpret_cast<uint8_t *>(
(reinterpret_cast<size_t>(closure_pool) + alignof(OSLClosureComponent) - 1) &
(-alignof(OSLClosureComponent)));
sg->closure_pool = closure_pool + sizeof(OSLClosureComponent) + size;
ccl_private OSLClosureComponent *const closure =
reinterpret_cast<ccl_private OSLClosureComponent *>(closure_pool);
closure->id = static_cast<OSLClosureType>(id);
closure->weight = *weight;
return closure;
}
/* Utilities */
ccl_device_extern void osl_error(ccl_private ShaderGlobals *sg, DeviceString format, void *args) {}
ccl_device_extern void osl_printf(ccl_private ShaderGlobals *sg, DeviceString format, void *args)
{
}
ccl_device_extern void osl_warning(ccl_private ShaderGlobals *sg, DeviceString format, void *args)
{
}
ccl_device_extern void osl_fprintf(ccl_private ShaderGlobals *sg,
DeviceString filename,
DeviceString format,
void *args)
{
}
ccl_device_extern uint osl_range_check_err(const int indexvalue,
const int length,
DeviceString symname,
ccl_private ShaderGlobals *sg,
DeviceString sourcefile,
const int sourceline,
DeviceString groupname,
const int layer,
DeviceString layername,
DeviceString shadername)
{
const int result = indexvalue < 0 ? 0 : indexvalue >= length ? length - 1 : indexvalue;
#if 0
if (result != indexvalue) {
printf("Index [%d] out of range\n", indexvalue);
}
#endif
return result;
}
/* Matrix Utilities */
ccl_device_forceinline void copy_matrix(ccl_private float *res, const Transform &tfm)
{
res[0] = tfm.x.x;
res[1] = tfm.y.x;
res[2] = tfm.z.x;
res[3] = 0.0f;
res[4] = tfm.x.y;
res[5] = tfm.y.y;
res[6] = tfm.z.y;
res[7] = 0.0f;
res[8] = tfm.x.z;
res[9] = tfm.y.z;
res[10] = tfm.z.z;
res[11] = 0.0f;
res[12] = tfm.x.w;
res[13] = tfm.y.w;
res[14] = tfm.z.w;
res[15] = 1.0f;
}
ccl_device_forceinline void copy_matrix(ccl_private float *res, const ProjectionTransform &tfm)
{
res[0] = tfm.x.x;
res[1] = tfm.y.x;
res[2] = tfm.z.x;
res[3] = tfm.w.x;
res[4] = tfm.x.y;
res[5] = tfm.y.y;
res[6] = tfm.z.y;
res[7] = tfm.w.y;
res[8] = tfm.x.z;
res[9] = tfm.y.z;
res[10] = tfm.z.z;
res[11] = tfm.w.z;
res[12] = tfm.x.w;
res[13] = tfm.y.w;
res[14] = tfm.z.w;
res[15] = tfm.w.w;
}
ccl_device_extern bool osl_get_matrix(ccl_private ShaderGlobals *sg,
ccl_private float *res,
DeviceString from)
{
if (from == DeviceStrings::u_common || from == DeviceStrings::u_world) {
copy_matrix(res, projection_identity());
return true;
}
if (from == DeviceStrings::u_shader || from == DeviceStrings::u_object) {
KernelGlobals kg = nullptr;
ccl_private ShaderData *const sd = sg->sd;
int object = sd->object;
if (object != OBJECT_NONE) {
const Transform tfm = object_get_transform(kg, sd);
copy_matrix(res, tfm);
return true;
}
}
else if (from == DeviceStrings::u_ndc) {
copy_matrix(res, kernel_data.cam.ndctoworld);
return true;
}
else if (from == DeviceStrings::u_raster) {
copy_matrix(res, kernel_data.cam.rastertoworld);
return true;
}
else if (from == DeviceStrings::u_screen) {
copy_matrix(res, kernel_data.cam.screentoworld);
return true;
}
else if (from == DeviceStrings::u_camera) {
copy_matrix(res, kernel_data.cam.cameratoworld);
return true;
}
return false;
}
ccl_device_extern bool osl_get_inverse_matrix(ccl_private ShaderGlobals *sg,
ccl_private float *res,
DeviceString to)
{
if (to == DeviceStrings::u_common || to == DeviceStrings::u_world) {
copy_matrix(res, projection_identity());
return true;
}
if (to == DeviceStrings::u_shader || to == DeviceStrings::u_object) {
KernelGlobals kg = nullptr;
ccl_private ShaderData *const sd = sg->sd;
int object = sd->object;
if (object != OBJECT_NONE) {
const Transform itfm = object_get_inverse_transform(kg, sd);
copy_matrix(res, itfm);
return true;
}
}
else if (to == DeviceStrings::u_ndc) {
copy_matrix(res, kernel_data.cam.worldtondc);
return true;
}
else if (to == DeviceStrings::u_raster) {
copy_matrix(res, kernel_data.cam.worldtoraster);
return true;
}
else if (to == DeviceStrings::u_screen) {
copy_matrix(res, kernel_data.cam.worldtoscreen);
return true;
}
else if (to == DeviceStrings::u_camera) {
copy_matrix(res, kernel_data.cam.worldtocamera);
return true;
}
return false;
}
/* Attributes */
ccl_device_template_spec bool set_attribute(const dual1 v,
const TypeDesc type,
bool derivatives,
ccl_private void *val)
{
const unsigned char type_basetype = type & 0xFF;
const unsigned char type_aggregate = (type >> 8) & 0xFF;
const int type_arraylen = type >> 32;
if (type_basetype == 11 /* TypeDesc::FLOAT */) {
if ((type_aggregate == 3 /* TypeDesc::VEC3 */) || (type_aggregate == 1 && type_arraylen == 3))
{
set_data_float3(make_float3(v), derivatives, val);
return true;
}
if ((type_aggregate == 4 /* TypeDesc::VEC4 */) || (type_aggregate == 1 && type_arraylen == 4))
{
set_data_float4(make_float4(make_float3(v)), derivatives, val);
return true;
}
if ((type_aggregate == 1 /* TypeDesc::SCALAR */)) {
set_data_float(v, derivatives, val);
return true;
}
}
return false;
}
ccl_device_template_spec bool set_attribute(const dual2 v,
const TypeDesc type,
bool derivatives,
ccl_private void *val)
{
const unsigned char type_basetype = type & 0xFF;
const unsigned char type_aggregate = (type >> 8) & 0xFF;
const int type_arraylen = type >> 32;
if (type_basetype == 11 /* TypeDesc::FLOAT */) {
if ((type_aggregate == 3 /* TypeDesc::VEC3 */) || (type_aggregate == 1 && type_arraylen == 3))
{
set_data_float3(make_float3(v), derivatives, val);
return true;
}
if ((type_aggregate == 4 /* TypeDesc::VEC4 */) || (type_aggregate == 1 && type_arraylen == 4))
{
set_data_float4(make_float4(make_float3(v)), derivatives, val);
}
if ((type_aggregate == 1 /* TypeDesc::SCALAR */)) {
set_data_float(average(v), derivatives, val);
return true;
}
}
return false;
}
ccl_device_template_spec bool set_attribute(const dual3 v,
const TypeDesc type,
bool derivatives,
ccl_private void *val)
{
const unsigned char type_basetype = type & 0xFF;
const unsigned char type_aggregate = (type >> 8) & 0xFF;
const int type_arraylen = type >> 32;
if (type_basetype == 11 /* TypeDesc::FLOAT */) {
if ((type_aggregate == 3 /* TypeDesc::VEC3 */) || (type_aggregate == 1 && type_arraylen == 3))
{
set_data_float3(v, derivatives, val);
return true;
}
if ((type_aggregate == 4 /* TypeDesc::VEC4 */) || (type_aggregate == 1 && type_arraylen == 4))
{
set_data_float4(make_float4(v), derivatives, val);
return true;
}
if ((type_aggregate == 1 /* TypeDesc::SCALAR */)) {
set_data_float(average(v), derivatives, val);
return true;
}
}
return false;
}
ccl_device_template_spec bool set_attribute(const dual4 v,
const TypeDesc type,
bool derivatives,
ccl_private void *val)
{
const unsigned char type_basetype = type & 0xFF;
const unsigned char type_aggregate = (type >> 8) & 0xFF;
const int type_arraylen = type >> 32;
if (type_basetype == 11 /* TypeDesc::FLOAT */) {
if ((type_aggregate == 3 /* TypeDesc::VEC3 */) || (type_aggregate == 1 && type_arraylen == 3))
{
set_data_float3(make_float3(v), derivatives, val);
return true;
}
if ((type_aggregate == 4 /* TypeDesc::VEC4 */) || (type_aggregate == 1 && type_arraylen == 4))
{
set_data_float4(v, derivatives, val);
return true;
}
if ((type_aggregate == 1 /* TypeDesc::SCALAR */)) {
set_data_float(average(make_float3(v)), derivatives, val);
return true;
}
}
return false;
}
template<typename T>
ccl_device_inline bool set_attribute(const T f,
const TypeDesc type,
bool derivatives,
ccl_private void *val)
{
return set_attribute(dual<T>(f), type, derivatives, val);
}
ccl_device_inline bool set_attribute_matrix(const ccl_private Transform &tfm,
const TypeDesc type,
ccl_private void *val)
{
const unsigned char type_basetype = type & 0xFF;
const unsigned char type_aggregate = (type >> 8) & 0xFF;
if (type_basetype == 11 /* TypeDesc::FLOAT */ && type_aggregate == 16 /* TypeDesc::MATRIX44 */) {
copy_matrix(static_cast<ccl_private float *>(val), tfm);
return true;
}
return false;
}
ccl_device_template_spec bool set_attribute(const int i,
const TypeDesc type,
bool derivatives,
ccl_private void *val)
{
ccl_private int *ival = static_cast<ccl_private int *>(val);
const unsigned char type_basetype = type & 0xFF;
const unsigned char type_aggregate = (type >> 8) & 0xFF;
const int type_arraylen = type >> 32;
if ((type_basetype == 7 /* TypeDesc::INT */) && (type_aggregate == 1 /* TypeDesc::SCALAR */) &&
type_arraylen == 0)
{
ival[0] = i;
if (derivatives) {
ival[1] = 0;
ival[2] = 0;
}
return true;
}
return false;
}
ccl_device_inline bool get_background_attribute(KernelGlobals kg,
ccl_private ShaderGlobals *sg,
ccl_private ShaderData *sd,
DeviceString name,
const TypeDesc type,
bool derivatives,
ccl_private void *val)
{
ConstIntegratorState state = (sg->shade_index > 0) ? (sg->shade_index - 1) : -1;
ConstIntegratorShadowState shadow_state = (sg->shade_index < 0) ? (-sg->shade_index - 1) : -1;
if (name == DeviceStrings::u_path_ray_length) {
/* Ray Length */
float f = sd->ray_length;
return set_attribute(f, type, derivatives, val);
}
#define READ_PATH_STATE(elem) \
((state != -1) ? INTEGRATOR_STATE(state, path, elem) : \
(shadow_state != -1) ? INTEGRATOR_STATE(shadow_state, shadow_path, elem) : \
0)
if (name == DeviceStrings::u_path_ray_depth) {
/* Ray Depth */
int f = READ_PATH_STATE(bounce);
/* Read bounce from different locations depending on if this is a shadow path. For background,
* light emission and shadow evaluation from a surface or volume we are effectively one bounce
* further. */
if (sg->raytype & (PATH_RAY_SHADOW | PATH_RAY_EMISSION)) {
f += 1;
}
return set_attribute(f, type, derivatives, val);
}
if (name == DeviceStrings::u_path_diffuse_depth) {
/* Diffuse Ray Depth */
const int f = READ_PATH_STATE(diffuse_bounce);
return set_attribute(f, type, derivatives, val);
}
if (name == DeviceStrings::u_path_glossy_depth) {
/* Glossy Ray Depth */
const int f = READ_PATH_STATE(glossy_bounce);
return set_attribute(f, type, derivatives, val);
}
if (name == DeviceStrings::u_path_transmission_depth) {
/* Transmission Ray Depth */
const int f = READ_PATH_STATE(transmission_bounce);
return set_attribute(f, type, derivatives, val);
}
if (name == DeviceStrings::u_path_transparent_depth) {
/* Transparent Ray Depth */
const int f = READ_PATH_STATE(transparent_bounce);
return set_attribute(f, type, derivatives, val);
}
if (name == DeviceStrings::u_path_portal_depth) {
/* Portal Ray Depth */
const int f = READ_PATH_STATE(portal_bounce);
return set_attribute(f, type, derivatives, val);
}
#undef READ_PATH_STATE
else if (name == DeviceStrings::u_ndc) {
/* NDC coordinates with special exception for orthographic projection. */
dual3 ndc;
if ((sg->raytype & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
{
ndc.val = camera_world_to_ndc(kg, sd, sd->ray_P);
}
else {
ndc.val = camera_world_to_ndc(kg, sd, sd->P);
if (derivatives) {
const differential3 dP = differential_from_compact(sd->Ng, sd->dP);
ndc.dx = camera_world_to_ndc(kg, sd, sd->P + dP.dx) - ndc.val;
ndc.dy = camera_world_to_ndc(kg, sd, sd->P + dP.dy) - ndc.val;
}
}
return set_attribute(ndc, type, derivatives, val);
}
return false;
}
template<typename T>
ccl_device_inline bool get_object_attribute_impl(KernelGlobals kg,
ccl_private ShaderData *sd,
const AttributeDescriptor &desc,
const TypeDesc type,
bool derivatives,
ccl_private void *val)
{
dual<T> data;
#ifdef __VOLUME__
if (primitive_is_volume_attribute(sd)) {
data.val = primitive_volume_attribute<T>(kg, sd, desc, true);
}
else
#endif
{
data = primitive_surface_attribute<T>(kg, sd, desc, derivatives, derivatives);
}
return set_attribute(data, type, derivatives, val);
}
ccl_device_inline bool get_object_attribute(KernelGlobals kg,
ccl_private ShaderData *sd,
const AttributeDescriptor &desc,
const TypeDesc type,
bool derivatives,
ccl_private void *val)
{
if (desc.type == NODE_ATTR_FLOAT) {
return get_object_attribute_impl<float>(kg, sd, desc, type, derivatives, val);
}
else if (desc.type == NODE_ATTR_FLOAT2) {
return get_object_attribute_impl<float2>(kg, sd, desc, type, derivatives, val);
}
else if (desc.type == NODE_ATTR_FLOAT3) {
return get_object_attribute_impl<float3>(kg, sd, desc, type, derivatives, val);
}
else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
return get_object_attribute_impl<float4>(kg, sd, desc, type, derivatives, val);
}
else if (desc.type == NODE_ATTR_MATRIX) {
Transform tfm = primitive_attribute_matrix(kg, desc);
return set_attribute_matrix(tfm, type, val);
}
return false;
}
ccl_device_inline bool get_object_standard_attribute(KernelGlobals kg,
ccl_private ShaderGlobals *sg,
ccl_private ShaderData *sd,
DeviceString name,
const TypeDesc type,
bool derivatives,
ccl_private void *val)
{
/* Object attributes */
if (name == DeviceStrings::u_object_location) {
float3 f = object_location(kg, sd);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_object_color) {
float3 f = object_color(kg, sd->object);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_object_alpha) {
float f = object_alpha(kg, sd->object);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_object_index) {
float f = object_pass_id(kg, sd->object);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_object_is_light) {
float f = ((sd->type & PRIMITIVE_LAMP) != 0);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_geom_dupli_generated) {
float3 f = object_dupli_generated(kg, sd->object);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_geom_dupli_uv) {
float3 f = object_dupli_uv(kg, sd->object);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_material_index) {
float f = shader_pass_id(kg, sd);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_object_random) {
const float f = object_random_number(kg, sd->object);
return set_attribute(f, type, derivatives, val);
}
/* Particle attributes */
else if (name == DeviceStrings::u_particle_index) {
int particle_id = object_particle_id(kg, sd->object);
float f = particle_index(kg, particle_id);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_particle_random) {
int particle_id = object_particle_id(kg, sd->object);
float f = hash_uint2_to_float(particle_index(kg, particle_id), 0);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_particle_age) {
int particle_id = object_particle_id(kg, sd->object);
float f = particle_age(kg, particle_id);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_particle_lifetime) {
int particle_id = object_particle_id(kg, sd->object);
float f = particle_lifetime(kg, particle_id);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_particle_location) {
int particle_id = object_particle_id(kg, sd->object);
float3 f = particle_location(kg, particle_id);
return set_attribute(f, type, derivatives, val);
}
#if 0 /* unsupported */
else if (name == DeviceStrings::u_particle_rotation) {
int particle_id = object_particle_id(kg, sd->object);
float4 f = particle_rotation(kg, particle_id);
return set_attribute4(f, type, derivatives, val);
}
#endif
else if (name == DeviceStrings::u_particle_size) {
int particle_id = object_particle_id(kg, sd->object);
float f = particle_size(kg, particle_id);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_particle_velocity) {
int particle_id = object_particle_id(kg, sd->object);
float3 f = particle_velocity(kg, particle_id);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_particle_angular_velocity) {
int particle_id = object_particle_id(kg, sd->object);
float3 f = particle_angular_velocity(kg, particle_id);
return set_attribute(f, type, derivatives, val);
}
/* Geometry attributes */
#if 0 /* TODO */
else if (name == DeviceStrings::u_geom_numpolyvertices) {
return false;
}
else if (name == DeviceStrings::u_geom_trianglevertices ||
name == DeviceStrings::u_geom_polyvertices) {
return false;
}
else if (name == DeviceStrings::u_geom_name) {
return false;
}
#endif
else if (name == DeviceStrings::u_is_smooth) {
float f = ((sd->shader & SHADER_SMOOTH_NORMAL) != 0);
return set_attribute(f, type, derivatives, val);
}
#ifdef __HAIR__
/* Hair attributes */
else if (name == DeviceStrings::u_is_curve) {
float f = (sd->type & PRIMITIVE_CURVE) != 0;
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_curve_thickness) {
float f = curve_thickness(kg, sd);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_curve_tangent_normal) {
float3 f = curve_tangent_normal(sd);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_curve_random) {
float f = curve_random(kg, sd);
return set_attribute(f, type, derivatives, val);
}
#endif
#ifdef __POINTCLOUD__
/* Point attributes */
else if (name == DeviceStrings::u_is_point) {
float f = (sd->type & PRIMITIVE_POINT) != 0;
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_point_radius) {
float f = point_radius(kg, sd);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_point_position) {
float3 f = point_position(kg, sd);
return set_attribute(f, type, derivatives, val);
}
else if (name == DeviceStrings::u_point_random) {
float f = point_random(kg, sd);
return set_attribute(f, type, derivatives, val);
}
#endif
else if (name == DeviceStrings::u_normal_map_normal) {
if (sd->type & PRIMITIVE_TRIANGLE) {
const AttributeDescriptor desc = find_attribute(
kg, sd->object, sd->prim, ATTR_STD_NORMAL_UNDISPLACED);
if (desc.offset != ATTR_STD_NOT_FOUND) {
return get_object_attribute(kg, sd, desc, type, derivatives, val);
}
float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
return set_attribute(f, type, derivatives, val);
}
else {
return false;
}
}
if (name == DeviceStrings::u_bump_map_normal) {
dual3 f;
if (!attribute_bump_map_normal(kg, sd, f)) {
return false;
}
return set_attribute(f, type, derivatives, val);
}
return get_background_attribute(kg, sg, sd, name, type, derivatives, val);
}
ccl_device_inline bool get_camera_attribute(ccl_private ShaderGlobals *sg,
KernelGlobals kg,
DeviceString name,
TypeDesc type,
bool derivatives,
ccl_private void *val)
{
if (name == DeviceStrings::u_sensor_size) {
const float2 sensor = make_float2(kernel_data.cam.sensorwidth, kernel_data.cam.sensorheight);
return set_attribute(sensor, type, derivatives, val);
}
else if (name == DeviceStrings::u_image_resolution) {
const float2 image = make_float2(kernel_data.cam.width, kernel_data.cam.height);
return set_attribute(image, type, derivatives, val);
}
else if (name == DeviceStrings::u_aperture_aspect_ratio) {
return set_attribute(1.0f / kernel_data.cam.inv_aperture_ratio, type, derivatives, val);
}
else if (name == DeviceStrings::u_aperture_size) {
return set_attribute(kernel_data.cam.aperturesize, type, derivatives, val);
}
else if (name == DeviceStrings::u_aperture_position) {
/* The random numbers for aperture sampling are packed into N. */
const float2 rand_lens = make_float2(sg->N.x, sg->N.y);
const float2 pos = camera_sample_aperture(&kernel_data.cam, rand_lens);
return set_attribute(pos * kernel_data.cam.aperturesize, type, derivatives, val);
}
else if (name == DeviceStrings::u_focal_distance) {
return set_attribute(kernel_data.cam.focaldistance, type, derivatives, val);
}
return false;
}
ccl_device_extern bool osl_get_attribute(ccl_private ShaderGlobals *sg,
const int derivatives,
DeviceString object_name,
DeviceString name,
const int array_lookup,
const int index,
const TypeDesc type,
ccl_private void *res)
{
KernelGlobals kg = nullptr;
ccl_private ShaderData *const sd = sg->sd;
int object;
if (sd == nullptr) {
/* Camera shader. */
return get_camera_attribute(sg, kg, name, type, derivatives, res);
}
if (object_name != DeviceStrings::_emptystring_) {
/* TODO: Get object index from name */
return false;
}
else {
object = sd->object;
}
const AttributeDescriptor desc = find_attribute(kg, object, sd->prim, name);
if (desc.offset != ATTR_STD_NOT_FOUND) {
return get_object_attribute(kg, sd, desc, type, derivatives, res);
}
else {
return get_object_standard_attribute(kg, sg, sd, name, type, derivatives, res);
}
}
/* Renderer services */
/* The ABI for these callbacks is different, so DeviceString and TypeDesc don't work here. */
struct RSDeviceString {
DeviceString val;
};
struct RSTypeDesc {
unsigned char basetype;
unsigned char aggregate;
unsigned char vecsemantics;
unsigned char reserved;
int arraylen;
};
ccl_device_extern bool rend_get_userdata(
RSDeviceString name, ccl_private void *data, int data_size, const RSTypeDesc &type, int index)
{
if (type.basetype == 14 /* TypeDesc::PTR */) {
kernel_assert(data_size == sizeof(void *));
ccl_private void **ptr_data = (ccl_private void **)data;
#ifdef __KERNEL_OPTIX__
if (name.val == DeviceStrings::u_colorsystem) {
*ptr_data = kernel_params.osl_colorsystem;
return true;
}
#endif
}
return false;
}
ccl_device_extern bool rs_texture(ccl_private ShaderGlobals *sg,
RSDeviceString filename,
ccl_private void *texture_handle,
ccl_private void *texture_thread_info,
ccl_private OSLTextureOptions *opt,
const float s,
const float t,
const float dsdx,
const float dtdx,
const float dsdy,
const float dtdy,
const int nchannels,
ccl_private float *result,
ccl_private float *dresultds,
ccl_private float *dresultdt,
ccl_private void *errormessage)
{
const unsigned int type = OSL_TEXTURE_HANDLE_TYPE(texture_handle);
const unsigned int slot = OSL_TEXTURE_HANDLE_SLOT(texture_handle);
switch (type) {
case OSL_TEXTURE_HANDLE_TYPE_SVM: {
const float4 rgba = kernel_tex_image_interp(nullptr, slot, s, 1.0f - t);
if (nchannels > 0) {
result[0] = rgba.x;
}
if (nchannels > 1) {
result[1] = rgba.y;
}
if (nchannels > 2) {
result[2] = rgba.z;
}
if (nchannels > 3) {
result[3] = rgba.w;
}
return true;
}
case OSL_TEXTURE_HANDLE_TYPE_IES: {
if (nchannels > 0) {
result[0] = kernel_ies_interp(nullptr, slot, s, t);
}
return true;
}
default: {
return false;
}
}
}
ccl_device_extern bool rs_texture3d(ccl_private ShaderGlobals *sg,
RSDeviceString filename,
ccl_private void *texture_handle,
ccl_private void *texture_thread_info,
ccl_private OSLTextureOptions *opt,
const ccl_private float3 *P,
const ccl_private float3 *dPdx,
const ccl_private float3 *dPdy,
const ccl_private float3 *dPdz,
const int nchannels,
ccl_private float *result,
ccl_private float *dresultds,
ccl_private float *dresultdt,
ccl_private float *dresultdr,
ccl_private void *errormessage)
{
const unsigned int type = OSL_TEXTURE_HANDLE_TYPE(texture_handle);
const unsigned int slot = OSL_TEXTURE_HANDLE_SLOT(texture_handle);
switch (type) {
case OSL_TEXTURE_HANDLE_TYPE_SVM: {
const float4 rgba = kernel_tex_image_interp_3d(
nullptr, sg->sd, slot, *P, INTERPOLATION_NONE, false);
if (nchannels > 0) {
result[0] = rgba.x;
}
if (nchannels > 1) {
result[1] = rgba.y;
}
if (nchannels > 2) {
result[2] = rgba.z;
}
if (nchannels > 3) {
result[3] = rgba.w;
}
return true;
}
default: {
return false;
}
}
}
ccl_device_extern bool rs_environment(ccl_private ShaderGlobals *sg,
RSDeviceString filename,
ccl_private void *texture_handle,
ccl_private void *texture_thread_info,
ccl_private OSLTextureOptions *opt,
const ccl_private float3 *R,
const ccl_private float3 *dRdx,
const ccl_private float3 *dRdy,
const int nchannels,
ccl_private float *result,
ccl_private float *dresultds,
ccl_private float *dresultdt,
ccl_private void *errormessage)
{
if (nchannels > 0) {
result[0] = 1.0f;
}
if (nchannels > 1) {
result[1] = 0.0f;
}
if (nchannels > 2) {
result[2] = 1.0f;
}
if (nchannels > 3) {
result[3] = 1.0f;
}
return false;
}
ccl_device_extern bool rs_get_texture_info(ccl_private ShaderGlobals *sg,
RSDeviceString filename,
ccl_private void *texture_handle,
ccl_private void *texture_thread_info,
int subimage,
RSDeviceString dataname,
RSTypeDesc datatype,
ccl_private void *data,
ccl_private void *errormessage)
{
return 0;
}
ccl_device_extern bool rs_get_texture_info_st(ccl_private ShaderGlobals *sg,
RSDeviceString filename,
ccl_private void *texture_handle,
const float s,
const float t,
ccl_private void *texture_thread_info,
int subimage,
RSDeviceString dataname,
RSTypeDesc datatype,
ccl_private void *data,
ccl_private void *errormessage)
{
return 0;
}
ccl_device_extern int rs_pointcloud_search(ccl_private ShaderGlobals *sg,
RSDeviceString filename,
const ccl_private float3 *center,
float radius,
int max_points,
bool sort,
ccl_private int *out_indices,
ccl_private float *out_distances,
int derivs_offset)
{
return 0;
}
ccl_device_extern int rs_pointcloud_get(ccl_private ShaderGlobals *sg,
RSDeviceString filename,
const ccl_private int *indices,
int count,
RSDeviceString attr_name,
RSTypeDesc attr_type,
ccl_private void *out_data)
{
return 0;
}
ccl_device_extern bool rs_pointcloud_write(ccl_private ShaderGlobals *sg,
RSDeviceString filename,
const ccl_private float3 *pos,
int nattribs,
const ccl_private DeviceString *names,
const ccl_private RSTypeDesc *types,
const ccl_private void **data)
{
return false;
}
ccl_device_extern bool rs_trace(ccl_private ShaderGlobals *sg,
ccl_private void *options,
const ccl_private float3 *P,
const ccl_private float3 *dPdx,
const ccl_private float3 *dPdy,
const ccl_private float3 *R,
const ccl_private float3 *dRdx,
const ccl_private float3 *dRdy)
{
return false;
}
ccl_device_extern bool rs_trace_get(ccl_private ShaderGlobals *sg,
RSDeviceString name,
RSTypeDesc type,
ccl_private void *data,
bool derivatives)
{
return false;
}