HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
15.0: Major Changes In The HDK

P Attribute Now 3-tuple

Since the common case was that the w component of P was not used, to reduce special-case code in common codepaths, P is now a float[3] attribute. The w component is created on-demand as a Pw float[1] attribute. All code in Houdini that tries to write to the w component has been swept to use GA_Detail::getPw, setPw, getPos4, setPos4, or a special handle class, which all correctly support reading/writing the w component. You can call GA_Detail::getPwAttribute to quickly check if there is a Pw attribute, instead of having to check whether the w component is 1.0 on every point, in the case where all point weights are 1.0.

P will no longer bind to a GA_ROHandleV4 or GA_RWHandleV4. Trying to access the w component with a GA_ROHandleF or GA_RWHandleF bound to P will crash, so any code that did this must be changed to use getPw, setPw, getPos4, or setPos4!

Future optimizations to the underlying data structure for numeric attributes will make use of this simplification.

Group String Parsing Functions

Many group parsing functions on SOP_Node and GOP_Manager have been deprecated, because they depend on either casting away const on input details, which is dangerous, or duplicating them, which is expensive. They are one of the thread-safety issues currently preventing SOPs from being cooked from multiple threads.

Note that some defaults and some parameter orders are different on the new functions. For example, parse groups are now unordered by default.

If you want to parse a group string to create a group that will always refer to an input detail, use the GroupCreator versions of cookInput_____Groups by passing in GroupCreator(inputgdp). The group will be a detached group, if it's not referencing an existing group, meaning that the detail has no reference to it and won't update it if the detail changes, but since the input detail won't be modified during the cook. The caller will still be responsible for locking/unlocking the input detail in this case. This sort of approach is also useful if the group must be cooked on the output detail, but you know that a detached group will always suffice, e.g. for SOPs where, after the group is created, no elements will be removed from the output detail or inserted before existing elements. Edge and vertex parse groups will always be detached.

If you want to parse a group string to create a group that will normally refer to the output detail, but when cookInputGroups is called by a viewport handle outside of a SOP cook (alone==true, gdp may be NULL), it needs to refer to an input detail, (the one that will be copied into the output detail by duplicateSource), use the non-GroupCreator version of cookInput_____Groups. It will automatically handle locking/unlocking the input detail if alone is set. Odds are high that the input is zero, since it's quite rare to duplicateSource from another input, but if it is a different input, be sure to specify it. Note that it will only look at that input number if alone is true, since otherwise, it will be creating the detail on the output detail as an internal (attached) group.

For more complicated cases, there is another GroupCreator constructor that takes a non-const detail pointer and a bool indicating whether to make detached groups (true) or attached groups (false), as well as the the parse_____Groups and parse_____GroupsCopy functions, accepting a GroupCreator.

UT_StringRef and UT_StringHolder

UT_StringRef and UT_StringHolder have led to significant performance improvements querying a UT_StringMap, because they cache the hash and length, and will just do pointer comparison if the text pointers are equal.

UT_StringRef, by default, will just reference any string passed to it, without taking ownership. However, it may own the string, using an internal Holder structure. UT_StringHolder is a subclass that, effectively, can always be assumed to own the string, (with one exception below). The Holder is reference counted, so that making copies and passing by value doesn't incur the cost of memory allocation. They also have move constructors and move assignment operators, new in C++11, so returning them by value won't even incur the cost of a reference decrement/increment.

Although UT_StringRef and UT_StringHolder existed in 14.0, their behaviour and relationship weren't as safe, so they weren't used as much.

Many functions on GA_Detail, GEO_Detail, and related classes now use UT_StringRef and UT_StringHolder in place of const char *. UT_StringRef is primarily used when querying something by name, since the query will not need to take ownership of the string. UT_StringHolder is used when a string may need to be recorded somewhere, to ensure that the string survives for the lifetime of the structure it's recorded in. If you have a string that you can be absolutely certain will already survive the lifetime of any structure it may be stored in, e.g. string literals, you can use UTmakeUnsafeRef to make a UT_StringHolder that only pretends to own its string.

Creating attributes with common names using the cached UT_StringHolder's in GA_Names means that looking up them up can be about 2x faster. Binding a GA_ROHandleT or a GA_RWHandleT is also significantly faster using GA_Names.

Using UT_StringHolder has also meant a reduction in the number of copies of each attribute name string, especially for group names, which used to have 5 separate copies each, but now only have 2 separate copies each. GA_Attribute::getName now returns a const UT_StringHolder&, so it can be used for efficient lookups later.

These, along with related performance improvements in building topology attributes, and the switch from P being 3 floats instead of 4 floats, mean that creating an empty GU_Detail is now about 50% faster.

OBJ_Node Changes

Generalization of shader nodes means that two methods in OBJ_Node needed to change their return type from SHOP_Node* to OP_Node*. One of them got also renamed:

You can use CAST_OBJNODE() macro to cast the return node to a SHOP.

SHOP_Node Changes

Factored out the following static methods that deal with shader clerks, out of SHOP_Node and into SHOP_Clerk. Also, factored out statics that deal with SHOP_TYPE and parameter default value outof SHOP_Node and into SHOP_Util class. Please, use the SHOP_Clerk and SHOP_Util classes for them now.

All these static functions were not closely tied to the SHOP nodes, but are applicable to VOP shader nodes as well. Hence this reorganisation.

Similarly, various shader-related methods in VOP_Node got refactored, refactored, or rearranged, but that should not affect HDK plugins.

VOP_Language Changes

Factored out static methods from VOP_Language to VOP_TypeInfo and renamed them:

Reorganized and unified naming of methods that return source code snippets related to variable types and initialization in a given language. In VOP_Language class, renamed:

  • getEmptyConstantString() to getEmptyConstantCode()
  • getConstantString() to getConstantCode()
  • getCodeStringFromType() to getTypeCode()
  • getVaryingStringFromType() to getVaryingTypeCode()
  • getArrayBracketsStringFromType() to getArrayBracketsCode()
  • getStructEmptyConstantString() to getStructEmptyConstantCode()
  • getStructConstantString() to getStructConstantCode()
  • getStructCodeString() to getStructTypeCode()

Factored out methods related to node parameters and PRM library out of VOP_Language class and into a new VOP_NodeParmManager class. To access these methods, please use VOP_Language::getParmManager() and call them on the returned object reference. Eg,