Cycles: Remove separate OSL attribute map and instead always use SVM attribute map

The SVM attribute map is always generated and uses a simple
linear search to lookup by an opaque ID, so can reuse that for OSL
as well and simply use the attribute name hash as ID instead of
generating a unique value separately. This works for both object
and geometry attributes since the SVM attribute map already
stores both. Simplifies code somewhat and reduces memory
usage slightly.

This patch was split from D15902.

Differential Revision: https://developer.blender.org/D15918
This commit is contained in:
Patrick Mours 2022-09-09 11:55:35 +02:00
parent 291c313f80
commit ef7c9e793e
15 changed files with 182 additions and 332 deletions

@ -16,14 +16,14 @@ CCL_NAMESPACE_BEGIN
/* Patch index for triangle, -1 if not subdivision triangle */
ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, ccl_private const ShaderData *sd)
ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, int prim)
{
return (sd->prim != PRIM_NONE) ? kernel_data_fetch(tri_patch, sd->prim) : ~0;
return (prim != PRIM_NONE) ? kernel_data_fetch(tri_patch, prim) : ~0;
}
ccl_device_inline uint attribute_primitive_type(KernelGlobals kg, ccl_private const ShaderData *sd)
ccl_device_inline uint attribute_primitive_type(KernelGlobals kg, int prim, int type)
{
if ((sd->type & PRIMITIVE_TRIANGLE) && subd_triangle_patch(kg, sd) != ~0) {
if ((type & PRIMITIVE_TRIANGLE) && subd_triangle_patch(kg, prim) != ~0) {
return ATTR_PRIM_SUBD;
}
else {
@ -45,17 +45,16 @@ ccl_device_inline uint object_attribute_map_offset(KernelGlobals kg, int object)
return kernel_data_fetch(objects, object).attribute_map_offset;
}
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
ccl_private const ShaderData *sd,
uint id)
ccl_device_inline AttributeDescriptor
find_attribute(KernelGlobals kg, int object, int prim, int type, uint64_t id)
{
if (sd->object == OBJECT_NONE) {
if (object == OBJECT_NONE) {
return attribute_not_found();
}
/* for SVM, find attribute by unique id */
uint attr_offset = object_attribute_map_offset(kg, sd->object);
attr_offset += attribute_primitive_type(kg, sd);
uint attr_offset = object_attribute_map_offset(kg, object);
attr_offset += attribute_primitive_type(kg, prim, type);
AttributeMap attr_map = kernel_data_fetch(attributes_map, attr_offset);
while (attr_map.id != id) {
@ -77,7 +76,7 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
AttributeDescriptor desc;
desc.element = (AttributeElement)attr_map.element;
if (sd->prim == PRIM_NONE && desc.element != ATTR_ELEMENT_MESH &&
if (prim == PRIM_NONE && desc.element != ATTR_ELEMENT_MESH &&
desc.element != ATTR_ELEMENT_VOXEL && desc.element != ATTR_ELEMENT_OBJECT) {
return attribute_not_found();
}
@ -91,11 +90,16 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
return desc;
}
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
ccl_private const ShaderData *sd,
uint64_t id)
{
return find_attribute(kg, sd->object, sd->prim, sd->type, id);
}
/* Transform matrix attribute on meshes */
ccl_device Transform primitive_attribute_matrix(KernelGlobals kg,
ccl_private const ShaderData *sd,
const AttributeDescriptor desc)
ccl_device Transform primitive_attribute_matrix(KernelGlobals kg, const AttributeDescriptor desc)
{
Transform tfm;

@ -25,7 +25,7 @@ ccl_device_forceinline float primitive_surface_attribute_float(KernelGlobals kg,
ccl_private float *dy)
{
if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
if (subd_triangle_patch(kg, sd->prim) == ~0)
return triangle_attribute_float(kg, sd, desc, dx, dy);
else
return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
@ -56,7 +56,7 @@ ccl_device_forceinline float2 primitive_surface_attribute_float2(KernelGlobals k
ccl_private float2 *dy)
{
if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
if (subd_triangle_patch(kg, sd->prim) == ~0)
return triangle_attribute_float2(kg, sd, desc, dx, dy);
else
return subd_triangle_attribute_float2(kg, sd, desc, dx, dy);
@ -87,7 +87,7 @@ ccl_device_forceinline float3 primitive_surface_attribute_float3(KernelGlobals k
ccl_private float3 *dy)
{
if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
if (subd_triangle_patch(kg, sd->prim) == ~0)
return triangle_attribute_float3(kg, sd, desc, dx, dy);
else
return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
@ -118,7 +118,7 @@ ccl_device_forceinline float4 primitive_surface_attribute_float4(KernelGlobals k
ccl_private float4 *dy)
{
if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
if (subd_triangle_patch(kg, sd->prim) == ~0)
return triangle_attribute_float4(kg, sd, desc, dx, dy);
else
return subd_triangle_attribute_float4(kg, sd, desc, dx, dy);
@ -320,7 +320,7 @@ ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg,
#endif
if (sd->type & PRIMITIVE_TRIANGLE) {
/* Triangle */
if (subd_triangle_patch(kg, sd) == ~0) {
if (subd_triangle_patch(kg, sd->prim) == ~0) {
motion_pre = triangle_attribute_float3(kg, sd, desc, NULL, NULL);
desc.offset += numverts;
motion_post = triangle_attribute_float3(kg, sd, desc, NULL, NULL);

@ -87,7 +87,7 @@ ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals kg,
ccl_private float *dx,
ccl_private float *dy)
{
int patch = subd_triangle_patch(kg, sd);
int patch = subd_triangle_patch(kg, sd->prim);
#ifdef __PATCH_EVAL__
if (desc.flags & ATTR_SUBDIVIDED) {
@ -226,7 +226,7 @@ ccl_device_noinline float2 subd_triangle_attribute_float2(KernelGlobals kg,
ccl_private float2 *dx,
ccl_private float2 *dy)
{
int patch = subd_triangle_patch(kg, sd);
int patch = subd_triangle_patch(kg, sd->prim);
#ifdef __PATCH_EVAL__
if (desc.flags & ATTR_SUBDIVIDED) {
@ -368,7 +368,7 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg,
ccl_private float3 *dx,
ccl_private float3 *dy)
{
int patch = subd_triangle_patch(kg, sd);
int patch = subd_triangle_patch(kg, sd->prim);
#ifdef __PATCH_EVAL__
if (desc.flags & ATTR_SUBDIVIDED) {
@ -509,7 +509,7 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg,
ccl_private float4 *dx,
ccl_private float4 *dy)
{
int patch = subd_triangle_patch(kg, sd);
int patch = subd_triangle_patch(kg, sd->prim);
#ifdef __PATCH_EVAL__
if (desc.flags & ATTR_SUBDIVIDED) {

@ -29,7 +29,7 @@ ccl_device_inline float3 volume_normalized_position(KernelGlobals kg,
object_inverse_position_transform(kg, sd, &P);
if (desc.offset != ATTR_STD_NOT_FOUND) {
Transform tfm = primitive_attribute_matrix(kg, sd, desc);
Transform tfm = primitive_attribute_matrix(kg, desc);
P = transform_point(&tfm, P);
}

@ -56,16 +56,8 @@ struct OSLGlobals {
OSL::ShaderGroupRef background_state;
/* attributes */
struct Attribute {
TypeDesc type;
AttributeDescriptor desc;
ParamValue value;
};
typedef unordered_map<ustring, Attribute, ustringHash> AttributeMap;
typedef unordered_map<ustring, int, ustringHash> ObjectNameMap;
vector<AttributeMap> attribute_map;
ObjectNameMap object_name_map;
vector<ustring> object_names;
};

@ -740,115 +740,76 @@ static bool set_attribute_matrix(const Transform &tfm, TypeDesc type, void *val)
return false;
}
static bool get_primitive_attribute(const KernelGlobalsCPU *kg,
const ShaderData *sd,
const OSLGlobals::Attribute &attr,
const TypeDesc &type,
bool derivatives,
void *val)
{
if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
float3 fval[3];
if (primitive_is_volume_attribute(sd, attr.desc)) {
fval[0] = primitive_volume_attribute_float3(kg, sd, attr.desc);
}
else {
memset(fval, 0, sizeof(fval));
fval[0] = primitive_surface_attribute_float3(
kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
}
return set_attribute_float3(fval, type, derivatives, val);
}
else if (attr.type == TypeFloat2) {
if (primitive_is_volume_attribute(sd, attr.desc)) {
assert(!"Float2 attribute not support for volumes");
return false;
}
else {
float2 fval[3];
fval[0] = primitive_surface_attribute_float2(
kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float2(fval, type, derivatives, val);
}
}
else if (attr.type == TypeDesc::TypeFloat) {
float fval[3];
if (primitive_is_volume_attribute(sd, attr.desc)) {
memset(fval, 0, sizeof(fval));
fval[0] = primitive_volume_attribute_float(kg, sd, attr.desc);
}
else {
fval[0] = primitive_surface_attribute_float(
kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
}
return set_attribute_float(fval, type, derivatives, val);
}
else if (attr.type == TypeDesc::TypeFloat4 || attr.type == TypeRGBA) {
float4 fval[3];
if (primitive_is_volume_attribute(sd, attr.desc)) {
memset(fval, 0, sizeof(fval));
fval[0] = primitive_volume_attribute_float4(kg, sd, attr.desc);
}
else {
fval[0] = primitive_surface_attribute_float4(
kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
}
return set_attribute_float4(fval, type, derivatives, val);
}
else {
return false;
}
}
static bool get_mesh_attribute(const KernelGlobalsCPU *kg,
const ShaderData *sd,
const OSLGlobals::Attribute &attr,
const TypeDesc &type,
bool derivatives,
void *val)
{
if (attr.type == TypeDesc::TypeMatrix) {
Transform tfm = primitive_attribute_matrix(kg, sd, attr.desc);
return set_attribute_matrix(tfm, type, val);
}
else {
return false;
}
}
static bool get_object_attribute(const OSLGlobals::Attribute &attr,
TypeDesc type,
static bool get_object_attribute(const KernelGlobalsCPU *kg,
ShaderData *sd,
const AttributeDescriptor &desc,
const TypeDesc &type,
bool derivatives,
void *val)
{
if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
const float *data = (const float *)attr.value.data();
return set_attribute_float3(make_float3(data[0], data[1], data[2]), type, derivatives, val);
}
else if (attr.type == TypeFloat2) {
const float *data = (const float *)attr.value.data();
return set_attribute_float2(make_float2(data[0], data[1]), type, derivatives, val);
}
else if (attr.type == TypeDesc::TypeFloat) {
const float *data = (const float *)attr.value.data();
return set_attribute_float(data[0], type, derivatives, val);
}
else if (attr.type == TypeRGBA || attr.type == TypeDesc::TypeFloat4) {
const float *data = (const float *)attr.value.data();
return set_attribute_float4(
make_float4(data[0], data[1], data[2], data[3]), type, derivatives, val);
}
else if (attr.type == type) {
size_t datasize = attr.value.datasize();
memcpy(val, attr.value.data(), datasize);
if (derivatives) {
memset((char *)val + datasize, 0, datasize * 2);
if (desc.type == NODE_ATTR_FLOAT3) {
float3 fval[3];
#ifdef __VOLUME__
if (primitive_is_volume_attribute(sd, desc)) {
fval[0] = primitive_volume_attribute_float3(kg, sd, desc);
}
return true;
else
#endif
{
memset(fval, 0, sizeof(fval));
fval[0] = primitive_surface_attribute_float3(
kg, sd, desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
}
return set_attribute_float3(fval, type, derivatives, val);
}
else if (desc.type == NODE_ATTR_FLOAT2) {
#ifdef __VOLUME__
if (primitive_is_volume_attribute(sd, desc)) {
assert(!"Float2 attribute not support for volumes");
return false;
}
else
#endif
{
float2 fval[3];
fval[0] = primitive_surface_attribute_float2(
kg, sd, desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float2(fval, type, derivatives, val);
}
}
else if (desc.type == NODE_ATTR_FLOAT) {
float fval[3];
#ifdef __VOLUME__
if (primitive_is_volume_attribute(sd, desc)) {
memset(fval, 0, sizeof(fval));
fval[0] = primitive_volume_attribute_float(kg, sd, desc);
}
else
#endif
{
fval[0] = primitive_surface_attribute_float(
kg, sd, desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
}
return set_attribute_float(fval, type, derivatives, val);
}
else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
float4 fval[3];
#ifdef __VOLUME__
if (primitive_is_volume_attribute(sd, desc)) {
memset(fval, 0, sizeof(fval));
fval[0] = primitive_volume_attribute_float4(kg, sd, desc);
}
else
#endif
{
fval[0] = primitive_surface_attribute_float4(
kg, sd, desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
}
return set_attribute_float4(fval, type, derivatives, val);
}
else if (desc.type == NODE_ATTR_MATRIX) {
Transform tfm = primitive_attribute_matrix(kg, desc);
return set_attribute_matrix(tfm, type, val);
}
else {
return false;
@ -979,6 +940,7 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
float f = ((sd->shader & SHADER_SMOOTH_NORMAL) != 0);
return set_attribute_float(f, type, derivatives, val);
}
#ifdef __HAIR__
/* Hair Attributes */
else if (name == u_is_curve) {
float f = (sd->type & PRIMITIVE_CURVE) != 0;
@ -996,6 +958,8 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
float f = curve_random(kg, sd);
return set_attribute_float(f, type, derivatives, val);
}
#endif
#ifdef __POINTCLOUD__
/* point attributes */
else if (name == u_is_point) {
float f = (sd->type & PRIMITIVE_POINT) != 0;
@ -1013,6 +977,7 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
float f = point_random(kg, sd);
return set_attribute_float(f, type, derivatives, val);
}
#endif
else if (name == u_normal_map_normal) {
if (sd->type & PRIMITIVE_TRIANGLE) {
float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
@ -1023,7 +988,7 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
}
}
else {
return false;
return get_background_attribute(kg, sd, name, type, derivatives, val);
}
}
@ -1131,7 +1096,6 @@ bool OSLRenderServices::get_attribute(
ShaderData *sd, bool derivatives, ustring object_name, TypeDesc type, ustring name, void *val)
{
const KernelGlobalsCPU *kg = sd->osl_globals;
int prim_type = 0;
int object;
/* lookup of attribute on another object */
@ -1145,44 +1109,18 @@ bool OSLRenderServices::get_attribute(
}
else {
object = sd->object;
prim_type = attribute_primitive_type(kg, sd);
if (object == OBJECT_NONE)
return get_background_attribute(kg, sd, name, type, derivatives, val);
}
/* find attribute on object */
object = object * ATTR_PRIM_TYPES + prim_type;
OSLGlobals::AttributeMap &attribute_map = kg->osl->attribute_map[object];
OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
if (it != attribute_map.end()) {
const OSLGlobals::Attribute &attr = it->second;
if (attr.desc.element != ATTR_ELEMENT_OBJECT) {
/* triangle and vertex attributes */
if (get_primitive_attribute(kg, sd, attr, type, derivatives, val))
return true;
else
return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
}
else {
/* object attribute */
return get_object_attribute(attr, type, derivatives, val);
}
const AttributeDescriptor desc = find_attribute(
kg, object, sd->prim, object == sd->object ? sd->type : PRIMITIVE_NONE, name.hash());
if (desc.offset != ATTR_STD_NOT_FOUND) {
return get_object_attribute(kg, sd, desc, type, derivatives, val);
}
else {
/* not found in attribute, check standard object info */
bool is_std_object_attribute = get_object_standard_attribute(
kg, sd, name, type, derivatives, val);
if (is_std_object_attribute)
return true;
return get_background_attribute(kg, sd, name, type, derivatives, val);
return get_object_standard_attribute(kg, sd, name, type, derivatives, val);
}
return false;
}
bool OSLRenderServices::get_userdata(

@ -21,8 +21,6 @@
#include "kernel/util/differential.h"
// clang-format on
#include "scene/attribute.h"
CCL_NAMESPACE_BEGIN
/* Threads */
@ -386,40 +384,4 @@ void OSLShader::eval_displacement(const KernelGlobalsCPU *kg, const void *state,
sd->P = TO_FLOAT3(globals->P);
}
/* Attributes */
int OSLShader::find_attribute(const KernelGlobalsCPU *kg,
const ShaderData *sd,
uint id,
AttributeDescriptor *desc)
{
/* for OSL, a hash map is used to lookup the attribute by name. */
int object = sd->object * ATTR_PRIM_TYPES;
OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object];
ustring stdname(std::string("geom:") +
std::string(Attribute::standard_name((AttributeStandard)id)));
OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
if (it != attr_map.end()) {
const OSLGlobals::Attribute &osl_attr = it->second;
*desc = osl_attr.desc;
if (sd->prim == PRIM_NONE && (AttributeElement)osl_attr.desc.element != ATTR_ELEMENT_MESH) {
desc->offset = ATTR_STD_NOT_FOUND;
return ATTR_STD_NOT_FOUND;
}
/* return result */
if (osl_attr.desc.element == ATTR_ELEMENT_NONE) {
desc->offset = ATTR_STD_NOT_FOUND;
}
return desc->offset;
}
else {
desc->offset = ATTR_STD_NOT_FOUND;
return (int)ATTR_STD_NOT_FOUND;
}
}
CCL_NAMESPACE_END

@ -54,12 +54,6 @@ class OSLShader {
ShaderData *sd,
uint32_t path_flag);
static void eval_displacement(const KernelGlobalsCPU *kg, const void *state, ShaderData *sd);
/* attributes */
static int find_attribute(const KernelGlobalsCPU *kg,
const ShaderData *sd,
uint id,
AttributeDescriptor *desc);
};
CCL_NAMESPACE_END

@ -655,12 +655,11 @@ typedef struct AttributeDescriptor {
/* For looking up attributes on objects and geometry. */
typedef struct AttributeMap {
uint id; /* Global unique identifier. */
uint element; /* AttributeElement. */
int offset; /* Offset into __attributes global arrays. */
uint8_t type; /* NodeAttributeType. */
uint8_t flags; /* AttributeFlag. */
uint8_t pad[2];
uint64_t id; /* Global unique identifier. */
int offset; /* Offset into __attributes global arrays. */
uint16_t element; /* AttributeElement. */
uint8_t type; /* NodeAttributeType. */
uint8_t flags; /* AttributeFlag. */
} AttributeMap;
/* Closure data */

@ -302,111 +302,32 @@ GeometryManager::~GeometryManager()
{
}
void GeometryManager::update_osl_attributes(Device *device,
Scene *scene,
vector<AttributeRequestSet> &geom_attributes)
void GeometryManager::update_osl_globals(Device *device, Scene *scene)
{
#ifdef WITH_OSL
/* for OSL, a hash map is used to lookup the attribute by name. */
OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
og->object_name_map.clear();
og->attribute_map.clear();
og->object_names.clear();
og->attribute_map.resize(scene->objects.size() * ATTR_PRIM_TYPES);
for (size_t i = 0; i < scene->objects.size(); i++) {
/* set object name to object index map */
Object *object = scene->objects[i];
og->object_name_map[object->name] = i;
og->object_names.push_back(object->name);
/* set object attributes */
foreach (ParamValue &attr, object->attributes) {
OSLGlobals::Attribute osl_attr;
osl_attr.type = attr.type();
osl_attr.desc.element = ATTR_ELEMENT_OBJECT;
osl_attr.value = attr;
osl_attr.desc.offset = 0;
osl_attr.desc.flags = 0;
og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_GEOMETRY][attr.name()] = osl_attr;
og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][attr.name()] = osl_attr;
}
/* find geometry attributes */
size_t j = object->geometry->index;
assert(j < scene->geometry.size() && scene->geometry[j] == object->geometry);
AttributeRequestSet &attributes = geom_attributes[j];
/* set mesh attributes */
foreach (AttributeRequest &req, attributes.requests) {
OSLGlobals::Attribute osl_attr;
if (req.desc.element != ATTR_ELEMENT_NONE) {
osl_attr.desc = req.desc;
if (req.type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
else if (req.type == TypeDesc::TypeMatrix)
osl_attr.type = TypeDesc::TypeMatrix;
else if (req.type == TypeFloat2)
osl_attr.type = TypeFloat2;
else if (req.type == TypeRGBA)
osl_attr.type = TypeRGBA;
else
osl_attr.type = TypeDesc::TypeColor;
if (req.std != ATTR_STD_NONE) {
/* if standard attribute, add lookup by geom: name convention */
ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_GEOMETRY][stdname] = osl_attr;
}
else if (req.name != ustring()) {
/* add lookup by geometry attribute name */
og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_GEOMETRY][req.name] = osl_attr;
}
}
if (req.subd_desc.element != ATTR_ELEMENT_NONE) {
osl_attr.desc = req.subd_desc;
if (req.subd_type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
else if (req.subd_type == TypeDesc::TypeMatrix)
osl_attr.type = TypeDesc::TypeMatrix;
else if (req.subd_type == TypeFloat2)
osl_attr.type = TypeFloat2;
else if (req.subd_type == TypeRGBA)
osl_attr.type = TypeRGBA;
else
osl_attr.type = TypeDesc::TypeColor;
if (req.std != ATTR_STD_NONE) {
/* if standard attribute, add lookup by geom: name convention */
ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][stdname] = osl_attr;
}
else if (req.name != ustring()) {
/* add lookup by geometry attribute name */
og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][req.name] = osl_attr;
}
}
}
}
#else
(void)device;
(void)scene;
(void)geom_attributes;
#endif
}
/* Generate a normal attribute map entry from an attribute descriptor. */
static void emit_attribute_map_entry(
AttributeMap *attr_map, int index, uint id, TypeDesc type, const AttributeDescriptor &desc)
static void emit_attribute_map_entry(AttributeMap *attr_map,
size_t index,
uint64_t id,
TypeDesc type,
const AttributeDescriptor &desc)
{
attr_map[index].id = id;
attr_map[index].element = desc.element;
@ -431,7 +352,7 @@ static void emit_attribute_map_entry(
/* Generate an attribute map end marker, optionally including a link to another map.
* Links are used to connect object attribute maps to mesh attribute maps. */
static void emit_attribute_map_terminator(AttributeMap *attr_map,
int index,
size_t index,
bool chain,
uint chain_link)
{
@ -446,15 +367,8 @@ static void emit_attribute_map_terminator(AttributeMap *attr_map,
/* Generate all necessary attribute map entries from the attribute request. */
static void emit_attribute_mapping(
AttributeMap *attr_map, int index, Scene *scene, AttributeRequest &req, Geometry *geom)
AttributeMap *attr_map, size_t index, uint64_t id, AttributeRequest &req, Geometry *geom)
{
uint id;
if (req.std == ATTR_STD_NONE)
id = scene->shader_manager->get_attribute_id(req.name);
else
id = scene->shader_manager->get_attribute_id(req.std);
emit_attribute_map_entry(attr_map, index, id, req.type, req.desc);
if (geom->is_mesh()) {
@ -475,12 +389,26 @@ void GeometryManager::update_svm_attributes(Device *,
* attribute, based on a unique shader attribute id. */
/* compute array stride */
int attr_map_size = 0;
size_t attr_map_size = 0;
for (size_t i = 0; i < scene->geometry.size(); i++) {
Geometry *geom = scene->geometry[i];
geom->attr_map_offset = attr_map_size;
attr_map_size += (geom_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
#ifdef WITH_OSL
size_t attr_count = 0;
foreach (AttributeRequest &req, geom_attributes[i].requests) {
if (req.std != ATTR_STD_NONE &&
scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std)
attr_count += 2;
else
attr_count += 1;
}
#else
const size_t attr_count = geom_attributes[i].size();
#endif
attr_map_size += (attr_count + 1) * ATTR_PRIM_TYPES;
}
for (size_t i = 0; i < scene->objects.size(); i++) {
@ -512,11 +440,26 @@ void GeometryManager::update_svm_attributes(Device *,
AttributeRequestSet &attributes = geom_attributes[i];
/* set geometry attributes */
int index = geom->attr_map_offset;
size_t index = geom->attr_map_offset;
foreach (AttributeRequest &req, attributes.requests) {
emit_attribute_mapping(attr_map, index, scene, req, geom);
uint64_t id;
if (req.std == ATTR_STD_NONE)
id = scene->shader_manager->get_attribute_id(req.name);
else
id = scene->shader_manager->get_attribute_id(req.std);
emit_attribute_mapping(attr_map, index, id, req, geom);
index += ATTR_PRIM_TYPES;
#ifdef WITH_OSL
/* Some standard attributes are explicitly referenced via their standard ID, so add those
* again in case they were added under a different attribute ID. */
if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) {
emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req, geom);
index += ATTR_PRIM_TYPES;
}
#endif
}
emit_attribute_map_terminator(attr_map, index, false, 0);
@ -528,10 +471,16 @@ void GeometryManager::update_svm_attributes(Device *,
/* set object attributes */
if (attributes.size() > 0) {
int index = object->attr_map_offset;
size_t index = object->attr_map_offset;
foreach (AttributeRequest &req, attributes.requests) {
emit_attribute_mapping(attr_map, index, scene, req, object->geometry);
uint64_t id;
if (req.std == ATTR_STD_NONE)
id = scene->shader_manager->get_attribute_id(req.name);
else
id = scene->shader_manager->get_attribute_id(req.std);
emit_attribute_mapping(attr_map, index, id, req, object->geometry);
index += ATTR_PRIM_TYPES;
}
@ -982,7 +931,7 @@ void GeometryManager::device_update_attributes(Device *device,
/* create attribute lookup maps */
if (scene->shader_manager->use_osl())
update_osl_attributes(device, scene, geom_attributes);
update_osl_globals(device, scene);
update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes);
@ -2188,7 +2137,6 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool forc
if (og) {
og->object_name_map.clear();
og->attribute_map.clear();
og->object_names.clear();
}
#else

@ -219,9 +219,7 @@ class GeometryManager {
void create_volume_mesh(const Scene *scene, Volume *volume, Progress &progress);
/* Attributes */
void update_osl_attributes(Device *device,
Scene *scene,
vector<AttributeRequestSet> &geom_attributes);
void update_osl_globals(Device *device, Scene *scene);
void update_svm_attributes(Device *device,
DeviceScene *dscene,
Scene *scene,

@ -78,6 +78,18 @@ void OSLShaderManager::reset(Scene * /*scene*/)
shading_system_init();
}
uint64_t OSLShaderManager::get_attribute_id(ustring name)
{
return name.hash();
}
uint64_t OSLShaderManager::get_attribute_id(AttributeStandard std)
{
/* if standard attribute, use geom: name convention */
ustring stdname(string("geom:") + string(Attribute::standard_name(std)));
return stdname.hash();
}
void OSLShaderManager::device_update_specific(Device *device,
DeviceScene *dscene,
Scene *scene,

@ -66,6 +66,9 @@ class OSLShaderManager : public ShaderManager {
return true;
}
uint64_t get_attribute_id(ustring name) override;
uint64_t get_attribute_id(AttributeStandard std) override;
void device_update_specific(Device *device,
DeviceScene *dscene,
Scene *scene,

@ -414,7 +414,7 @@ ShaderManager *ShaderManager::create(int shadingsystem)
return manager;
}
uint ShaderManager::get_attribute_id(ustring name)
uint64_t ShaderManager::get_attribute_id(ustring name)
{
thread_scoped_spin_lock lock(attribute_lock_);
@ -424,14 +424,14 @@ uint ShaderManager::get_attribute_id(ustring name)
if (it != unique_attribute_id.end())
return it->second;
uint id = (uint)ATTR_STD_NUM + unique_attribute_id.size();
uint64_t id = ATTR_STD_NUM + unique_attribute_id.size();
unique_attribute_id[name] = id;
return id;
}
uint ShaderManager::get_attribute_id(AttributeStandard std)
uint64_t ShaderManager::get_attribute_id(AttributeStandard std)
{
return (uint)std;
return (uint64_t)std;
}
int ShaderManager::get_shader_id(Shader *shader, bool smooth)

@ -192,8 +192,8 @@ class ShaderManager {
void device_free_common(Device *device, DeviceScene *dscene, Scene *scene);
/* get globally unique id for a type of attribute */
uint get_attribute_id(ustring name);
uint get_attribute_id(AttributeStandard std);
virtual uint64_t get_attribute_id(ustring name);
virtual uint64_t get_attribute_id(AttributeStandard std);
/* get shader id for mesh faces */
int get_shader_id(Shader *shader, bool smooth = false);
@ -223,7 +223,7 @@ class ShaderManager {
uint32_t update_flags;
typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap;
typedef unordered_map<ustring, uint64_t, ustringHash> AttributeIDMap;
AttributeIDMap unique_attribute_id;
static thread_mutex lookup_table_mutex;