This document is for a version of USD that is under development. See this page for the current release.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Sdr : Shader Definition Registry

In the context of Sdr, a "shader" is any program that takes input and produces output.

Sdr provides a framework in which you can register shader nodes with Sdr, and subsequently ask for information about those nodes. Additionally, shader node parsing and "discovery" are done via plugins to keep Sdr extendable.

If this is your first time working with Sdr, we recommend you read the SdrShaderProperty Types section to understand some implicit behaviors.

Sdr Organization

Sdr can be split into 5 major components, as described by the following subsections.

Sdr Registry

The core Sdr registry, SdrRegistry, is where shader node-level queries are done. Upon initialization, the registry searches for all parser and discovery plugins. During this start-up phase the discovery plugins are all run, but the nodes that are found are NOT parsed. The registry parses nodes on demand when information about a node(s) is requested in order to keep the start-up process as fast as possible.

The type of information that the Sdr registry provides includes:

  • The names of shader nodes that have been registered
  • Parsed shader node instances (created on-demand when requested)
  • Where the shader nodes were found

Sdr Shader Node

Sdr provides a node class, SdrShaderNode, which exposes information such as:

  • The shader node type
  • What the inputs and outputs are
  • Any metadata attached to the shader node

An SdrShaderNode represents a dataflow-connectable computation, intended to be a node in a computational network. A node's SdrShaderProperty's represent its computational inputs and outputs, and its URI's identify its external sources:

Sdr Shader Property

Sdr also provides a property class, SdrShaderProperty. Inputs and outputs are on a node are collectively identified as "properties".

The shader property exposes information like:

  • The input type
  • The default value, if any
  • Any metadata attached to the shader property
  • Whether the shader property is connectable

Discovery Plugins

Discovery plugins are how the shader registry finds (or "discovers") shader nodes. The registry makes no assumptions on where, or how, nodes are stored. A discovery plugin can be built to find file-based nodes on the filesystem (a typical case), search a database, a cloud service, or any other system that might contain nodes. If nodes are scattered across multiple systems, a discovery plugin can be created for each. More info about discovery plugins is available in the SdrDiscoveryPlugin documentation.

Note that a filesystem-based discovery plugin is active by default. More information on how to configure this plugin can be found in the documentation for _SdrFilesystemDiscoveryPlugin. In a nutshell, there are a few environment variables that can be configured to control its behavior. However, the more robust pattern that any renderer or shading-system plugin should follow is to provide its own DiscoveryPlugin, so that its configuration will not interfere with that of other plugins. The filesystem discovery machinery that the builtin _SdrFilesystemDiscoveryPlugin plugin uses is available for other discovery plugins to use - see SdrFsHelpersDiscoverShaderNodes().

Parser Plugins

Once the registry knows about shader nodes via the discovery plugin(s), the parser plugins parse the nodes and provide the registry with the resulting information. The parser plugins are responsible for information such as the node's type, its metadata, and all information about its inputs and outputs. In the end, the parser plugin is responsible for determining all information about the node that could not otherwise be determined via the discovery plugin. More information about parser plugins is available in the SdrParserPlugin documentation.

Custom Discovery Plugin

See the documentation for SdrDiscoveryPlugin for more information.

Custom Parser Plugin

See the documentation for SdrParserPlugin for more information.

SdrShaderProperty Types

A SdrShaderProperty's type is described using the given SdrPropertyType token, as well as SdrShaderProperty::GetArraySize(), if SdrShaderProperty::IsDynamicArray() is true. SdrPropertyType tokens are defined here.

For whether a SdrShaderProperty can connect to another SdrShaderProperty based on its type, see the implementation of SdrShaderProperty::CanConnectTo. SdrShaderProperty connectability has more flexibility than a simple type equivalence check does; for example, a property of type SdrPropertyTypes->Color can connect to another property of type SdrPropertyTypes->Vector because they both represent a "Float3".

Type determination

Sdr defines a limited set of types with SdrPropertyType tokens. These types correspond to certain SdfValueTypeNames. There are two levels of type determination described below.

  1. Type determination during SdrShaderProperty constructions.
  2. Conversion to SdfValueTypeName from SdrShaderProperty type.

Metadata-based controls may modify each type determination step. Each step is detailed in sections below.

The SdrPropertyType is not written out to a USD layer, but with the aid of other information and metadata gathered from a node's shader definition, the SdrPropertyType is mapped to an SdfValueTypeName that is written into USD layers. The SdfValueTypeNames are a much richer and wider set of types, and it is this type that is looked at during opinion composition.

Clients writing SdrParserPlugin sub-classes for Sdr need only be concerned with a property's SdrPropertyType. Sdr will handle the details of assigning the correct SdfValueTypeName.

Type determination during SdrShaderProperty construction

If the property's 'role' metadata is 'none', this triggers automatic SdrPropertyType transformation during SdrShaderProperty construction time. The SdrPropertyType will be transformed to be as generic as possible. For example, if a property of original SdrPropertyTypes->Color has 'role' specified as 'none', then the property will actually become SdrPropertyTypes->Float with an arraysize of 3.

See this map for all property construction-time type transformations from 'none' roles.

SdfValueTypeName conversion from SdrShaderProperty fields

SdfValueTypeName conversion is governed by these conversion maps and is triggered by call to SdrShaderProperty::GetTypeAsSdfType.

However, the presence of some metadata on SdrShaderProperty alters conversion. Metadata that is used for SdfValueTypeName conversion is authored either by shader writers (SdrUsdDefinitionName), or it should be injected into an SdrShaderProperty by a parser plugin writer (IsAssetIdentifier).

  • SdrPropertyMetadata->IsAssetIdentifier - This metadata tag is injected by a parser if the parser determines that the property is an asset. The presence of this metadata tag then guides the type mapping to choose SdfValueTypeNames->Asset
  • SdrPropertyMetadata->SdrUsdDefinitionType - This metadata, explicitly authored in a shader definition, specifies the SdfValueTypeName as string. Note that this metadata takes precendence in determining the SdfValueTypeName for the SdrShaderProperty. Authors of shader definition will have to provide explicit TfType value aliases (Refer SdfValueTypeName::GetAliasesAsTokens()) associated with the SdfValueTypeName, which generally match the type declarations found in a usda file. Example "bool" for SdfValueTypeNames->Bool, "bool[]" for SdfValueTypeNames->BoolArray, etc. This is specifically important in determining types which are represented as an "int" in the sdr type system but should be represented as SdfValueTypeNames->Bool in the equivalent Sdf/USD representation. When sdrUsdDefinitionType is specified, Sdr will do its best to convert the default value provided in the shader definition into the requested SdfValueType.

Special Sdr property types

Three types are specific to Sdr and have no corresponding SdfValueTypeName.

  • SdrPropertyTypes->Struct - Struct types
  • SdrPropertyTypes->Terminal - Certain properties represent 'terminal' ports (ie. surface, displacement, volume, etc)
  • SdrPropertyTypes->Vstruct - An abstract struct type that can connect to any other 'vstruct', and connections are only made if a matching vstruct member is found.

These special types have no reasonable corresponding SdfValueTypeName, so we map them to SdfValueTypeName->Token, which is typically reserved for an Unknown type.

Traditional methods of accessing type information will give incomplete info for the above special cases, for example: SdrShaderProperty::GetType returns a "struct" token without indicating what kind of struct it represents, and SdrShaderProperty::GetTypeAsSdfType().GetSdfType returns SdfValueTypeNames->Token, which is even more ambiguous than "struct".

Therefore to provide more complete type info, the 'renderType' metadata should be authored when creating a SdrShaderProperty with one of the above special types.

  • On a Struct, the metadata should be 'renderType' = 'struct structName', where structName is the actual struct's typename
  • On a Terminal, the metadata should be 'renderType' = 'terminal terminalName' where terminalName is the actual kind of terminal
  • On a Vstruct, the metadata should be 'renderType' = 'vstruct', since there is no further specific type name for a vstruct

A user can find the original struct type or terminal type of one of these properties by examining the 'renderType' metadata on the property directly.

Some examples illustrating the treatment of property types

shader TestOSLShader
(
color foo = color(1.0, 1.0 1.0),
token bar = "baz",
token surface = ""
[[
string renderType = "terminal surface"
]]
)

In the above example, the properties would be translated as follows:

Property SdrPropertyType SdfValueTypeName
foo SdrPropertyTypes->Color SdfValueTypeNames->Color
bar SdrPropertyTypes->String SdfValueTypeNames->String
surface SdrPropertyTypes->Terminal SdfValueTypeNames->Token