Shader Meta Data

Shader Meta Data

Introduction

Comments in shader source code can specify meta data that is recorded in the compiled shader. The syntax is as follows:

<meta id="name">data</meta>

The data is arbitrary; it can span multiple lines in block comments (but not in "//" comments). The identifier is a key that can be used to fetch the meta data. Meta data identifiers can have the same names as identifiers in shader code; they reside in a separate namespace.

  • Important

    Shaders with meta data must be compiled with the -C command-line option, which instructs the preprocessor to preserve comments.

Meta data can be useful in many stages of production. It can be used to record authoring data, dependencies, version control information, etc. For example, meta data can be used to augment the shader argument information that is available from the sloargs API: in addition to the name, type, and default value of a shader argument, an authoring tool like Slim might rely on additional information, such as the following:

/* This meta data describes a shader argument:
   <meta id="Ks_label">Specular Response</meta>
   <meta id="Ks_min">0</meta>
   <meta id="Ks_precision">0.001</meta>
 */

Since the data is arbitrary, XML can be used to describe structured meta data:

/*
   <meta id="Ks">
       <label>Specular Response</label>
       <min>0</min>
       <precision>0.001</precision>
   </meta>
 */

Other data formats, such as comma-separated values, work equally well:

/*
    <meta id="Ks">
        "label","min","precision"
        "Specular Response",0,0.001
        </meta>
 */

Scripting with Meta Data

Scripts can extract a shader's meta data using sloinfo -m, which outputs XML that has the following format:

<?xml version='1.0' encoding='ISO-8859-1' standalone='yes'?>
<shader name="...">
   <meta id="...">...</meta>
   <meta id="...">...</meta>
   ...
</shader>

The meta data can be arbitrary; if it happens to be XML, the resulting output is especially well-suited to scripting:

<shader name="myplastic">
   <meta id="Ks">
       <label>Specular Response</label>
       <min>0</min>
       <precision>0.001</precision>
   </meta>
</shader>

For example, the following Python script parses this XML into a dictionary of shader arguments, each of which is a dictionary that maps attributes to values:

from xml.dom import minidom, Node

def metaToDict(file):
    xml = minidom.parse(file).documentElement
    metaNodes = [child for child in xml.childNodes
                 if child.nodeType == Node.ELEMENT_NODE]
    return dict( [(node.getAttribute("id"), dataToDict(node))
                  for node in metaNodes] )

def dataToDict(node):
    return dict([(child.nodeName, getText(child))
                 for child in node.childNodes
                 if child.nodeType == Node.ELEMENT_NODE])

def getText(node):
    return " ".join( [child.data.strip() for child in node.childNodes
                      if child.nodeType == Node.TEXT_NODE] )

For parsers that care about whitespace, note the following:

  • Whitespace following the <meta> tag is stripped (including newlines).
  • Leading whitespace on each line of data is stripped (since the meta data is usually embedded in an indented comment).
  • Whitespace preceding the </meta> tag is stripped (including newlines).

Meta Data API

Meta data can also be accessed using the following functions from the sloargs API:

const char* Slo_GetMetaData(const char* name);
const char** Slo_GetAllMetaData();

Slo_GetMetaData returns a pointer to the meta data with the specified name, or NULL if not found. Slo_GetAllMetaData returns an array containing all the meta data in the shader. The array contains name/value pairs and is terminated by a pair of NULL pointers.

  • Important

    The array returned by Slo_GetAllMetaData must be freed by the caller (but not the strings).

For example, for the following meta data

/*
   <meta id="Ks_label">Specular Response</meta>
   <meta id="Ks_min">0</meta>
   <meta id="Ks_precision">0.001</meta>
 */

Slo_GetAllMetaData returns the following array:

{ "Ks_label", "Specular Response",
  "Ks_min", "0",
  "Ks_precision", "0.001",
  NULL, NULL }