If you would like to display two views of the same scene graph, you need to use the multiprocessing capabilities of Cosmo 3D. You might, for example, like to display a ground-view and an over-head view of the same scene at the same time. You can accomplish this by creating a thread for each view and connecting each to their own csWindow and csContext, as shown in Figure 13-1.
This chapter describes how to implement multiprocessing in the following sections:
One rule that you must follow when implementing multiprocessing is the scene graph cannot be modified during rendering. Cosmo 3D does not provide a mechanism for concurrent scene graph modification and drawing.
The consequence of this rule is that you must implement semaphores to block the action of the application or draw threads.
The following sections describe how to implement threads.
For each view of the scene graph you want to display, you use a different thread. Each thread is bound to a csWindow and a csContext.
Threads must be created using csThread. Threads created in other ways produce unpredictable results.
A thread can only have one context attached to it at a time. Conversely, each thread that attempts to draw must have a separate context. Unpredictable results occur if you try to share a context with more than one thread.
A context attached to one thread cannot be used by another thread until the first thread releases it using csContext::releaseCurrent().
To create a thread and bind it appropriately, use the following procedure:
Create a thread, as follows:
csThread* drawThread = new csThread(drawThreadEntry, NULL); |
Bind the thread to a csWindow and csContext using csContext::makeCurrent(), as follows:
static void drawThreadEntry(void* arg) { csWindow *theWindow; csContext *theContext; theContext = theWindow->getThisWindowContext(); theContext->makeCurrent(theWindow); // Context is now current; scenes will be drawn in theWindow. ... } |
Whether or not a thread runs immediately depends on the csThread constructor you use. The first form, csThread(), does not start executing. This behavior allows you to load thread-related parameters before using csThread::start() to actually start the thread.
The second form of the constructor, csThread(Entry* entryPoint, void* arg=NULL), allows you to load thread-related parameters in the argument. For that reason, it begins execution immediately.
Thread-related parameters include the following csThread methods:
numProcessors()—returns the number of usable processors on the system.
setStackSize()—sets the stack size to be used for this thread when it starts.
Exiting Threads
A thread only terminates execution when it calls csThread::exit() on itself. Cosmo 3D does not support termination of threads by other threads.
Additional Thread Controls
The following csThread methods control the execution of threads:
In general, a Cosmo 3D application has two kinds of threads:
In general, when one kind of thread is active, the other must be blocked. So while the application thread handles events and modifies the scene graph, the draw threads must be blocked and, conversely, while the draw threads are active, the application thread must be blocked from modifying the scene graph, as shown in Figure 13-2.
The general order of events displayed in Figure 13-2 is as follows:
The application and draw threads are created and initialized.
The draw threads try to render but are stopped.
The application thread modifies the scene graph.
The application thread enters the Draw Barrier (semaphore) when it is ready to render the scenes.
The application thread tries to run but is stopped by the Swap Barrier until all draw threads have run.
The remainder of the draw threads run.
The draw threads enter the Swap Barrier.
when all threads enter the Swap Barrier they are released. The draw threads immediately enter the Draw Barrier and block.
The application thread modifies the scene graph.
The procedure repeats itself starting again at step 4.
Before rendering, the application thread must call csField::cleanFields() to clean the csContext fields. This method forces the evaluation of all fields that have been dirty, thereby circumventing the normal lazy evaluation of field values. Generally, in Cosmo 3D, fields are updated only when queried.
To use this method, tracking of dirty fields must be enabled. This method enables safe traversal of a scene by parallel rendering threads; lazy evaluation is not thread-safe.
To clean the fields, you must:
To see if dirty field is enabled, use the following method:
csField::isDirtyFieldTrackingEnabled() |