Author: eilemann@gmail.com
State: Design
Overview
The purpose of this feature is to allow decoupled framerates in separate views, so that the rendering performance of one view is not coupled to another view.
Requirements
- One configuration is used. The configuration is one visualization session of an application. It is not feasible to create multiple configurations, as this would require a separate mechanism for data distribution.
- The independent frame loops can be driven from one main thread. Using one thread per frame loop is the easy way, but creates numerous thread-safety issues for developers.
- Views sharing resources may be coupled. The obvious example is the update of two views sharing one window.
Implementation
Currently, the application starts a rendering for all views of a configuration
using Config::startFrame
. To synchronize the
completion, Config::finishFrame
is used, which waits on:
- The completion of all node-local draw operations of all views (with the
default thread model
draw_sync
) - The completion of all operations of all views for
frame
current-latency
For per-view frame loops, the application wants to wait on the completion of one view to request a redraw on this view, if needed. Multiple views need to be updateable at once.
while( config->isRunning( )) { version = commit(); config->startFrame( version ); View* view = config->finishView(); while no redraw needed for each ready view update view redraw state } eq::server::Config::startFrame() { generate tasks for ready, redraw views } eq::Config::finishFrame() { for each active view view->finishFrame(); view->postRedraw(); OR View* view = config->finishView(); view->postRedraw(); }
File Format
API
Implementation
Issues
1. Are the frame loops per view or per observer?
Resolved: Per view. Running per observer seems more logical at first. However, one observer might observe multiple views with different content. The observer does not necessarily require a synchronization between theses views.
2. What happens to view a, if view b is updated and they share a window?
There are two situations: view a is idle or it is actively rendering a frame. Situation two may never arise, since the resource would not be ready yet and the per-view synchronization of both views would not yet have triggered.
Option 1: All dependent destination channels are updated as well. One issue is that the data used for the redraw does no longer correspond to the data used when updating the full view, i.e., an update of view b would fully trigger an update of view a.
Option 2: Equalizer saves the front buffer before swap. A new task
method Channel::frameViewRestore
would perform a glCopyPixels
from the front to the back buffer. A possibly destroyed front buffer would not
be an issue, as this would trigger a redraw in any case. Application
3. What is the basic synchronization entity?
From an OpenGL POV, all views of a single drawable are dependent. From a multithreading POV, all views of a single thread (aka pipe) are dependent. From an application POV, all views of a single process (aka node) are dependent, if one database is used per process.
The thread model should take care of enforcing the appropriate synchronization by not allowing a new frame to start if a dependent resource is still used for another view.
4. How is the latency handled?
A configuration has a latency of n
frames. When running with
multiple framerates, one view should be able to get ahead more than n frames.
Option: Consider the latency per view.