About SmartHandle

Nitrous is designed to run in a separate nitrous rendering thread. For thread-safety, plug-ins must use SmartHandle to access the pointers of Nitrous resources including buffers, textures, render items, materials, and others in main thread or nitrous rendering thread.

SmartHandle can be considered as smart pointers. Each SmartHandle holds a reference to a resource. More than one SmartHandle can refer to the same resource. In this case, the resource is not freed until the last SmartHandle releases its reference.

The Nitrous SDK provides a list of strong typed handles. These handles are derived from SmartHandle and they have no data members, but several methods for plug-ins to manipulate the underlying resources.

The following figure shows the smarthandle types in the Nitrous SDK:

Creating SmartHandle

By default, a SmartHandle references a null object and is invalid. To make the SmartHandle valid, the plug-ins must initialize the SmartHandle or assign another valid SmartHandle to the SmartHandle.

The following example illustrates how to create a valid GeometryRenderItemHandle and how to use it:

  GeometryRenderItemHandle hRenderItem;
  assert(!hRenderItem.IsValid()); // Is invalid at this time

  hRenderItem.Initialize();
  assert(hRenderItem.IsValid()); // Is valid now

  GeometryRenderItemHandle hRenderItem2;
  // Both hRenderItem and hRenderItem2 reference to the same 
  // underlying geometry resource
  hRenderItem2 = hRenderItem;
  // Two render items are equal to each other now
  assert(hRenderItem == hRenderItem2);

  hRenderItem.SetMaterialID(31583); // Set a random material ID
  assert(hRenderItem2.GetMaterialID() == 31583); // Should be the same

Write Type and Read Type Functions

The SmartHandle methods can be categorized into two groups: write type and read type.

Any function call that does not send data from the underlying resource to the calling thread is considered a write type function. All calls to these functions are pushed to a thread-safe command queue. Nitrous chooses a proper time to flush all commands in the command queue to synchronize the underlying resource.

The SmartHandle caches the data members that cannot be changed by the rendering thread. If the plug-in needs the member data of the underlying resource, the SmartHandle returns the cached data when applicable. However, in certain cases, if the plug-in wants to retrieve a member data that requires computation in the rendering thread, Nitrous flushes all commands in the command queue, sends a data retrieving command, and waits for the rendering thread to return the result. During this process, the calling thread is blocked and the command queue is locked for exclusive use by the SmartHandle.

Plug-ins must avoid using the read functions of SmartHandle whenever possible because SmartHandle is write friendly but not read friendly.