In this post we will look at the RNA tree and use several tool functions from RNA_access.h to inspect the structure of RNA. We also will have a brief overview of polymorphism in RNA.

As a user of Blender reflection system, the first questions are where is the root of RNA tree defined and what is its lifetime/ownership?

The root of RNA tree is a BlenderRNA structure, which is a collection of structure RNAs(StructRNA):

/* File source/blender/makesrna/intern/rna_internal_types.h */

struct BlenderRNA {
    ListBase structs;

The instance of BlenderRNA is called BLENDER_RNA, which is defined in the file rna_ID_gen.c as a global variable in static storage. The BLENDER_RNA is also declared in the file RNA_access.h so you can access it by including RNA_access.h.

When a new module type is registered to Blender, a corresponding new StructRNA is created and get appended to BLENDER_RNA.

Take Blender operators as an example: When a new operator is registered, firstly a StructRNA is created by RNA_def_struct_ptr, and then passed to custom operator registration code such as MESH_OT_subdivide, where operator-specific properties will be defined. The source code of above process can be found in function WM_operatortype_append (file source/blender/windowmanager/intern/wm_operators.c):

void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
    wmOperatorType *ot;
    ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
    ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);

    /* ... */


    /* ... */

To inspect the RNA informations I write an operator called DumpRNAInfo. The source code can be found here.

This operator just iterates all RNA nodes and output the sub-tree for a given root node.

For example, the sub-tree for Lamp type is shown below:


We can use functions such as RNA_struct_is_a(also declared in the header RNA_access.h) to check runtime information of a type. For “is-a” checking, Blender has to traverse through the parent link to find a match.

As an extension reading, I suggest to look at how LLVM handles the runtime information in constant time1.