VR-Vantage 2.4 API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
5.2 - Distributed Rendering

Table of Contents

The VR-Vantage Toolkit, and applications built on it, support distributed rendering.

Distributed rendering is the process of rendering a single scene simultaneously on two or more computers. Distributed rendering is managed by a Control Interface running in a display engine in a VR-Vantage application. The Control Interface takes input from drivers and manages its rendering system as well as those of external display engines.

In distributed rendering, the display engine sends commands to its Rendering System and to connected display engines, which execute them. Since each external display engine executes the same commands, they each display the exact same scene as the master and the objects perform the same actions in the same order. Since the scenes are synchronized across all display engines, the rendering of the scene is also synchronized. However, the scenes are only loosely synchronized, as only the scene itself is synchronized, not the rendering of the scene. VR-Vantage does not support low-level rendering synchronization such as frame locking, which ensures that each channel renders at the same frame rate, or Genlock, which ensures that each monitor refreshes the image at the same time.

The commands sent by the display engine are really just function calls. The Toolkit makes it easy to make a function call to a single C++ class instance and have that call get made on one or more objects, existing on one or more display engines.

5.2.1 Proxies

The master display engine contains the complete state of all connected display engines. However the master does not have an actual copy of all objects on the display engines. Instead, it has proxy objects. For example, there is a DtWindow object for each window. To represent a window on a distributed display engine the master display engine has a DtWindowProxy object, which is a proxy representation of the real object. Calls made on a proxy object are distributed to the display engine that has the real object, which behaves as if the call had been made directly to it.

The communication from a proxy object to a real object is performed by an agent object. An agent instance exists for each proxy/class pair. The master display engine makes calls to an agent and the agent distributes those calls automatically.

5.2.2 Distributed Objects and Agents

Objects that exist in display engines are called distributed objects. Each object in the scene is composed of an agent object and a distributed object. When the master display engine creates an agent, each external display engine simultaneously creates the distributed object that the agent will control.

An agent is created with an appropriate subset of the methods that the actual object has. For example, if a distributed object has a setLocation() method, then its agent could have it. On the master, you would call a method on the agent, as follows:

agent->setLocation(x,y,z);

The distributed rendering architecture handles all the data marshalling (encoding, transport, and decoding) and the corresponding object on each display engine has the setLocation() method called.

Note
Each display engine owns an Object Manager. This is a container of distributed objects. At any given time the contents of the Distributed Object Manager on the master display engine and on each of the external display engines is the same.

5.2.3 Distributed Rendering Transport

The VR-Vantage Toolkitprovides mechanisms for implementing communications over any protocol or medium. It uses a TCP socket connection. Once a display engine is connected, most rendering will be distributed unless the application is explicitly designed not to use the distributed rendering functionality.

5.2.4 Example of Using an Agent

The following pseudo code demonstrates use of agents. Suppose you want to add a traffic light to your scene. You want to be able to programmatically change its state from green to yellow to red.

  1. Create the TrafficLightObject. This is the object that will get created in each of the display engines and will make changes to the scene graph.

    class TrafficLightObject
    {
    public:
    ...
    void setState(int state)
    {
    myState = state;
    changeState();
    }
    void changeState()
    {
    // change the geometry in the scene graph to reflect
    // the traffic lights new state.
    }
    int state() const
    {
    return myState;
    }
    };

  2. Generate an agent. (For details about generating agents, please see 5.3 - Generating Code for Agents.) The agent will have a similar API to your object.

    class TrafficLightAgent : public DtDistributedObjectAgent
    {
    public:
    ...
    void setState(int state);
    };

  3. Create an instance of the agent in a master display engine's driver:

    TrafficLightAgent* agent = TrafficLightAgent::create();

    This causes TrafficLightObject's to get created on each display engine (the master display engine also) and added to the Distributed Object Manager.

  4. You can now make calls on the agent to set its state and each object's setState() method will get called.

    agent->setState(State_Red);

The distributed object framework guarantees that the calls will happen in the order in which you make them. For example, if you make the following calls in your driver:

trafficLightAgent1->setState(State_Red);
trafficLightAgent2->setState(State_Green);

Each display engine will execute them in order:

trafficLightObject1->setState(State_Red);
trafficLightObject2->setState(State_Green);

Some drivers are written to run asynchronously in a separate thread. These drivers each have their own interface for setting messages from agents to the implementation. These commands are executed in the order in which they are called, however they may be interspersed with commands generated in the main thread or in other threads. For example, the agent might call functions in the following order:

Thread A: fooAgent->doSomething();
Thread A: fooAgent->doSomethingElse();
Main Thread: barAgent->doSomething();
Main Thread: barAgent->doSomethingElse();

The functions might be executed in the following order:

bar->doSomething();
foo->doSomething();
foo->doSomethingElse();
bar->doSomethingElse();

[<< The Display Engine] [Home] [Top of Page] [Generating Code for Agents >>]



Copyright © 2005-2018 VT MAK. All Rights Reserved (www.mak.com)