Views And Representations: Difference between revisions

From ParaQ Wiki
Jump to navigationJump to search
No edit summary
No edit summary
Line 46: Line 46:
for complex views like the RenderView which supports rendering on different
for complex views like the RenderView which supports rendering on different
processes. We still can use this single pass setup for client-only views or view
processes. We still can use this single pass setup for client-only views or view
that do rendering at a fixed location.
that do rendering at a fixed location e.g. spread-sheet views/chart views.


==If only life was easy!==
==If only life was easy!==
Line 53: Line 53:
render. Now this works well when you actually have data pipelines (or trivially
render. Now this works well when you actually have data pipelines (or trivially
when the representation doesn't need any input). Now in ParaView world, expecting
when the representation doesn't need any input). Now in ParaView world, expecting
the data to be present is not a legitimate expectation. The data pipelines in
the data to be present is not a legitimate expectation. The data pipelines are
only on the data-server, while the rendering components need to render either on
only on the data-server, while the rendering components need to render either on
the data-server itself, or render-server or client (based on configuration and
the data-server itself, or render-server or client (based on configuration and
Line 70: Line 70:
communicate various parameters from views to representations such as the
communicate various parameters from views to representations such as the
rendering-location decision.
rendering-location decision.
==vtkPVView==
Before we look at the complicated case of writing representations for render
view, just try to understand the core base classes vtkPVView and
vtkPVDataRepresentation.
vtkPVView is a vtkView subclass that adds some ParaView specific API to the
view. vtkPVView object is expected to be instantiated on all processes. In your
subclass you can have smarts to do the actual rendering on the appropriate
nodes.
Every vtkPVView has a Position and Size. This is essential for multi-view
configuration to work. pqQVTKWidget has code to ensure that the ViewPosition and
ViewSize properties are updated correctly whenever the widget's position/size
changes.
vtkPVView has a instance of vtkPVSynchronizedRenderWindows. This class
encapsulates the logic to synchronize render-windows among multiple processes as
well as propagate render event from the client to all the processes. If your
view needs a render window, it should use
vtkPVSynchronizedRenderWindows::NewRenderWindow() to obtain the render window to
use. vtkPVSynchronizedRenderWindows::NewRenderWindow() will return a new
vtkRenderWindow instance on the client while on the server it will reuse the
same renderwindow among all views, but internally ensure that the viewports for
the renderers for each view are setup correctly so that they don't overlap.
If vtkPVView::Initialize, one should register the window and the renderers with
the vtkPVSynchronizedRenderWindows using the id passed to the Initialize()
function. Every view must have a unique id and the same id on all processes.
This is ensured by vtkSMViewProxy.
==vtkPVDataRepresentation==
vtkPVDataRepresentation is a vtkDataRepresentation subclass that adds some
ParaView specific API to the representation.
vtkPVDataRepresentation has the following responsibilities:
* Prepare data for rendering e.g. use a geometry filter to extract the surface
* Delivery data to rendering node e.g. in case of chart views, it delivers the
data to the client.
* Map the data to rendering primitives if applicable e.g. use a
vtkPolyDataMapper/vtkActor to render geometry in the render window.
Some of the important API of vtkPVDataRepresentation is as follows:
<source lang="cpp">
// Description:
// This is called by view for processing view rendering passes. These passes
// may include requesting a vtkAlgorithm::Update() or other render-view
// specific requests such as getting geometry information etc. Subclasses
// typically check if their own visibility before responding to any view
// requests thus avoid any representation updates when the representation is
// not visible.
virtual int ProcessViewRequest(vtkInformationRequestKey* request_type,
    vtkInformation* inInfo, vtkInformation* outInfo);
  // Description:
  // This is one of the most important functions. In VTK pipelines, it's very
  // easy for the pipeline to decide when it needs to reexecute.
  // vtkAlgorithm::Update() can go up the entire pipeline to see if any filters
  // MTime changed (among other things) and if so, it can rexecute the pipeline.
  // However in case of representations, the real input connection may only be
  // present on the data-server nodes. In that case the
  // vtkPVDataRepresentation::RequestData() will only get called on the
  // data-server nodes. That means that representations won't be able to any
  // data-delivery in RequestData(). We'd need some other mechanisms to
  // synchronize data-delivery among processes. To avoid that conumdrum, the
  // vtkSMRepresentationProxy calls MarkModified() on all processes whenever any
  // filter in the pipeline is modified. In this method, the
  // vtkPVDataRepresentation subclasses should ensure that they mark all
  // delivery related filters dirty to ensure they execute then next time they
  // are updated. The vtkPVDataRepresentation also uses a special executive
  // which avoids updating the representation unless MarkModified() was called
  // since the last Update(), thus acting as a update-suppressor.
  // If the subclass has any method that results in changes that require the
  // data to be redelivered, it should call MarkModified() rather than simply
  // Modified().
  virtual void MarkModified();
</source>


==ParaView View Passes==
==ParaView View Passes==


A ParaView view, will go thorough following passes during each render. A
A ParaView view, will go through following passes during each render. A
representation is expected to do certain tasks in each of these passes. These
representation is expected to do certain tasks in each of these passes. These
are described next.
are described next.

Revision as of 10:40, 14 October 2010

UNDER CONSTRUCTION

Background

Views and their consorts, representations, have been the most complex components of the ParaView visualization pipeline. This wasn't without merit, ParaView rendering framework is indeed quite flexible and powerful, working without issues (for the most parts :) ) in different configurations and customizations.

The concept of Views and Representations is pretty simple really. A View is an abstraction that can "show" data, and Representation is an abstraction that can present/format the raw data so that it can be "shown" in the view. How the data is shown? Is it rendered as polygons in an OpenGL window or as a list of values in a QTableWidget are immaterial. At the end of any visualization pipeline, you have data that needs to be "shown" and representations and views do that for you.

This notion was found so useful that we now have views and representations in VTK itself. vtkDataRepresentation is a vtkAlgorithm subclass, a sink to be more precise. One simply connects a data source to the representation's input and dumps it in a view and voila! You have a display for your data.

vtkView, vtkDataRepresentation and their subclasses have been maturing over the past year or so in VTK repository. ParaView meanwhile has its own ServerManager level view-representation infrastructure which developed parallel to VTK's and has similar overtones but with the added backbone to support parallel rendering and client-server operations.

Besides being parallel VTK's views and representations, the main difficulty with ParaView's views/representations has been its complexity and poor readability. This was due to the large number of components involved as well as the fact that coding complex pipelines in ServerManager is much harder to debug and follow when compared with the same pipeline in VTK level.

So we decided to add new VTK-based views and representations that could leverage ParaView's parallel infrastructure for interprocess communication without adding complexity in the ServerManager level.

VTK-based Views And Representations

In brief, vtkDataRepresentation is vtkAlgorithm with no output ports. In RequestData() stage, sets up the internal rendering pipeline (typically mapper/actor). In AddToView() it adds the actor to the View's renderer. And that sums it up. The view before every render calls Update() on all representations and then triggers a render -- plain and simple. This breaks down for complex views like the RenderView which supports rendering on different processes. We still can use this single pass setup for client-only views or view that do rendering at a fixed location e.g. spread-sheet views/chart views.

If only life was easy!

As just described, all the view does is update the representation and then render. Now this works well when you actually have data pipelines (or trivially when the representation doesn't need any input). Now in ParaView world, expecting the data to be present is not a legitimate expectation. The data pipelines are only on the data-server, while the rendering components need to render either on the data-server itself, or render-server or client (based on configuration and settings). So if we assume that the vtkDataRepresentation is instantiated on all processes, then it will have valid input on some and nothing connected to the input on other nodes. A representation is responsible for converting the data to representable form. Thus a surface-representation will possibly convert an unstructured grid to polydata shell so that it can be rendered. Now this can only be done in RequestData(). The view may need to know the geometry sizes to decide where to render on server or client, for example. The view should now make that decision and send it to all representations so that they can then deliver the geometry to the right node where rendering is going to happen. Plus there's ordered compositing, which may require the geometry to be redistributed. This explanation hopefully makes it clear that we need more passes for the representations after the traditional pipeline passes, and we need mechanism to communicate various parameters from views to representations such as the rendering-location decision.

vtkPVView

Before we look at the complicated case of writing representations for render view, just try to understand the core base classes vtkPVView and vtkPVDataRepresentation.

vtkPVView is a vtkView subclass that adds some ParaView specific API to the view. vtkPVView object is expected to be instantiated on all processes. In your subclass you can have smarts to do the actual rendering on the appropriate nodes.

Every vtkPVView has a Position and Size. This is essential for multi-view configuration to work. pqQVTKWidget has code to ensure that the ViewPosition and ViewSize properties are updated correctly whenever the widget's position/size changes.

vtkPVView has a instance of vtkPVSynchronizedRenderWindows. This class encapsulates the logic to synchronize render-windows among multiple processes as well as propagate render event from the client to all the processes. If your view needs a render window, it should use vtkPVSynchronizedRenderWindows::NewRenderWindow() to obtain the render window to use. vtkPVSynchronizedRenderWindows::NewRenderWindow() will return a new vtkRenderWindow instance on the client while on the server it will reuse the same renderwindow among all views, but internally ensure that the viewports for the renderers for each view are setup correctly so that they don't overlap.

If vtkPVView::Initialize, one should register the window and the renderers with the vtkPVSynchronizedRenderWindows using the id passed to the Initialize() function. Every view must have a unique id and the same id on all processes. This is ensured by vtkSMViewProxy.

vtkPVDataRepresentation

vtkPVDataRepresentation is a vtkDataRepresentation subclass that adds some ParaView specific API to the representation.

vtkPVDataRepresentation has the following responsibilities:

  • Prepare data for rendering e.g. use a geometry filter to extract the surface
  • Delivery data to rendering node e.g. in case of chart views, it delivers the

data to the client.

  • Map the data to rendering primitives if applicable e.g. use a

vtkPolyDataMapper/vtkActor to render geometry in the render window.

Some of the important API of vtkPVDataRepresentation is as follows:

 // Description:
 // This is called by view for processing view rendering passes. These passes
 // may include requesting a vtkAlgorithm::Update() or other render-view
 // specific requests such as getting geometry information etc. Subclasses
 // typically check if their own visibility before responding to any view
 // requests thus avoid any representation updates when the representation is
 // not visible.
 virtual int ProcessViewRequest(vtkInformationRequestKey* request_type,
    vtkInformation* inInfo, vtkInformation* outInfo);

  // Description:
  // This is one of the most important functions. In VTK pipelines, it's very
  // easy for the pipeline to decide when it needs to reexecute.
  // vtkAlgorithm::Update() can go up the entire pipeline to see if any filters
  // MTime changed (among other things) and if so, it can rexecute the pipeline.
  // However in case of representations, the real input connection may only be
  // present on the data-server nodes. In that case the
  // vtkPVDataRepresentation::RequestData() will only get called on the
  // data-server nodes. That means that representations won't be able to any
  // data-delivery in RequestData(). We'd need some other mechanisms to
  // synchronize data-delivery among processes. To avoid that conumdrum, the
  // vtkSMRepresentationProxy calls MarkModified() on all processes whenever any
  // filter in the pipeline is modified. In this method, the
  // vtkPVDataRepresentation subclasses should ensure that they mark all
  // delivery related filters dirty to ensure they execute then next time they
  // are updated. The vtkPVDataRepresentation also uses a special executive
  // which avoids updating the representation unless MarkModified() was called
  // since the last Update(), thus acting as a update-suppressor.
  // If the subclass has any method that results in changes that require the
  // data to be redelivered, it should call MarkModified() rather than simply
  // Modified().
  virtual void MarkModified();

ParaView View Passes

A ParaView view, will go through following passes during each render. A representation is expected to do certain tasks in each of these passes. These are described next.

UPDATE PASS: vtkAlgorithm passes and RequestData

First pass is called vtkAlgorithm::Update() on the representations. Thus results in all the traditional algorithm passes. In RequestUpdateExtent() the representation should setup piece/time request. ViewTime and partition information is provided by the View (FIXME).

REQUEST_INFORMATION: Provide information to the View