VTK/VTK 6 Migration/Overview
Summary
One of the main goals of the pipeline re-architecture between VTK 4 and 5 was to 1) move the execution logic from data and process (algorithm) objects to a new set of classes called executives. This was to enable easy modification and extension of the pipeline (execution) code as well as to 2) separate data and execution “models” in order to simplify the code for both. The changes between VTK 4 and 5 achieved the first goal fairly well but did not tackle the second goal in order to preserve backwards compatibility with VTK 4. The work described herein has two major goals:
- To remove the VTK 4 backwards compatibility layer introduced in VTK 5 in order to simplify the toolkit.
- To carry the work started in VTK 5 to its logical conclusion by completely separating data and executions models
This work comes at a cost: many of the changes described here are not backwards compatible with VTK 4 and some of them are not backwards compatible with VTK 5. In this document, we summarize the changes introduced as part of this work as well as provide guidance in migrating existing code forward.
Overview of Changes
The changes introduced as part of this work can be classified under a few major categories:
- Removal of VTK 4 backwards compatibility superclasses: This includes vtkProcessObject, vtkSource and all of their subclasses. These classes were changed in VTK 5 in order to provide backwards compatibility. In VTK 6, all pipeline modules should subclass from vtkAlgorithm or one of its subclasses.
- Removal of the pipeline meta-data API from vtkDataObject: As of VTK 5, the main containers of all pipeline meta-data and heavy-data are vtkInformation objects that represent input and output information for algorithms. Data objects should no longer be used to store meta-data (e.g. Whole Extent, Update Extent etc.). The vtkDataObject API for pipeline meta-data was kept for backwards compatibility to VTK 4 and was removed as part of this work.
- Removal of data objects’ dependency on the pipeline code (algorithms and executives): The aims of this change are to simplify data object classes and to allow for the separation of data and execution model libraries as part of the ongoing modularization effort. This change causes a few incompatibilities explained in detail below.
- Removal of support for old compilers and operating systems. Visual Studio 7.0 and older, Borland 5.6 and older, and Mac OS X 10.4 and older are no longer supported.
Changes in Detail
Removal of VTK 4 Backwards Compatibility Superclasses
The changes to the pipeline and pipeline modules introduced in VTK are explained in detail in a PDF document in VTK’s source code distribution: VTK/Utilities/Upgrading/TheNewVTKPipeline.pdf. If you are not familiar with these changes and find that your code stopped compiling due to changes described in this section, we recommend that you review that document first. It described in more detail the changes to pipeline modules and how to migrate to VTK 5.
In order to the transition to the VTK 5 pipeline implementation as smoothly as possible, VTK 5 introduced a set of backwards compatibility classes. These included modified versions of previous algorithm superclasses including vtkProcessObject, vtkSource, vtkXXXSource (where XXX represents various data types) and vtkXXXToYYYFilter (where XXX and YYY are various data types). VTK 6 removes all of these classes and requires that all pipeline modules subclass from vtkAlgorithm or one of its subclasses and use the RequestInformation / RequestUpdateExtent / RequestData API rather than ExecutionInformation / PropagateUpdateExtent / Execute API. Below is a full list of backwards compatibility classes that were removed in VTK 6. If your code fails to compile because it refers to any of these classes, it is time to migrate to the VTK 5 API.
- Filtering/vtkDataObjectSource
- Filtering/vtkDataSetSource
- Filtering/vtkDataSetToDataSetFilter
- Filtering/vtkDataSetToImageFilter
- Filtering/vtkDataSetToPolyDataFilter
- Filtering/vtkDataSetToStructuredGridFilter
- Filtering/vtkDataSetToStructuredPointsFilter
- Filtering/vtkDataSetToUnstructuredGridFilter
- Filtering/vtkImageInPlaceFilter
- Filtering/vtkImageMultipleInputFilter
- Filtering/vtkImageMultipleInputOutputFilter
- Filtering/vtkImageSource
- Filtering/vtkImageToImageFilter
- Filtering/vtkImageTwoInputFilter
- Filtering/vtkPointSetSource
- Filtering/vtkPointSetToPointSetFilter
- Filtering/vtkPolyDataSource
- Filtering/vtkPolyDataToPolyDataFilter
- Filtering/vtkProcessObject
- Filtering/vtkRectilinearGridSource
- Filtering/vtkRectilinearGridToPolyDataFilter
- Filtering/vtkSource
- Filtering/vtkStructuredGridSource
- Filtering/vtkStructuredGridToPolyDataFilter
- Filtering/vtkStructuredGridToStructuredGridFilter
- Filtering/vtkStructuredPointsSource
- Filtering/vtkStructuredPointsToPolyDataFilter
- Filtering/vtkStructuredPointsToStructuredPointsFilter
- Filtering/vtkStructuredPointsToUnstructuredGridFilter
- Filtering/vtkUnstructuredGridSource
- Filtering/vtkUnstructuredGridToPolyDataFilter
- Filtering/vtkUnstructuredGridToUnstructuredGridFilter
- FilteringvtkStructuredPointsToUnstructuredGridFilter
- FilteringvtkUnstructuredGridToUnstructuredGridFilter
- Imaging/vtkImageSpatialFilter
Removal of All Pipeline Meta-Data API from vtkDataObject
Examples of pipeline meta-data include WholeExtent, UpdateExtent, MaximumNumberOfPieces, UpdateNumberOfPieces, UpdatePiece, UpdateGhostLevel, ScalarType and NumberOfScalarComponents. In VTK 5, this meta-data is represented by vtkInformation keys such as vtkStreamingDemandDriven::WHOLE_EXTENT() and vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT() and flow up and down the pipeline through input and output information objects passed to ProcessRequest (hence to RequestInformation, RequestUpdateExtent and RequestData). In VTK 4, this was achieved using vtkDataObjects and the vtkDataObject API (methods such as Set/GetWholeExtent, Set/GetUpdateExtent etc.). VTK 5 maintained this API as well as the associated vtkDataObject data members. The Executives had the responsibility of synching vtkDataObject data members with data in input and output information objects. The code to achieve this was hard to maintain and fragile. Furthermore, developers were often confused by the API to obtain pipeline specific meta-data (such as WholeExtent – the extent of the entire image available from a source or a reader) and data specific meta-data (such as Extent – the extent of the image data currently in memory). For example, we encountered the following in several places in VTK code as well as in other applications that used VTK:
<source lang="cpp"> vtkImageData* image = vtkImageData::New(); int extent[6] = {0, 10, 0, 10, 0, 10}; image->SetExtent(extent); image->SetUpdateExtent(extent); image->SetWholeExtent(extent); image->AllocateScalars(); </source>
The correct implementation (which only uses SetExtent) was not clear to many developers and they chose the “safe” route of setting everything related to Extent to the same value – which is not really safe since it is a bug.
VTK 6 removes all pipeline meta-data API from data object and requires the use of the appropriate information keys to create, modify and read pipeline meta-data. Refer to the Appendix for a full list of methods removed from vtkDataObject.
Removal of Data Objects’ Dependency on the Pipeline
The final set of changes introduced as part of this work remove the dependency of vtkDataObject and its subclasses on the pipeline objects (executives and algorithms) completely decoupling the VTK “data model” from the VTK “execution model”. This has two major advantages:
- Support for modularization: With these changes, it will be possible to create a small, self-contained library that only includes support for core classes and data model classes. This will enable developers to leverage VTK’s data model in their applications without significant code bloat.
- Simplification of data object and pipeline execution APIs: These changes eliminate a significant amount of API duplication between algorithms and executives simplifying the VTK API. For example, to update (i.e. to force the execution of an) algorithm, the developer now has to access one method: vtkAlgorithm:Update() rather than several distributed among data objects and algorithms.
Some of the changes introduced to remove this dependency are transparent to all but advanced users/developers of VTK. Others impact many developers that use VTK. The first of these is that all pipeline execution API was removed from vtkDataObject. Therefore, code similar to the following will not compile:
<source lang="cpp"> vtkDataObject* dobj = someAlgorithm->GetOutput(); dobj->Update(); </source>
This needs to be replaced with the following
<source lang="cpp"> someAlgorithm->Update(); </source>
The second backwards-incompatible change is probably the one that will impact the most code. In VTK 4, pipeline objects were connected as follows:
<source lang="cpp"> someFilter->SetInput(someReader->GetOutput()); </source>
In VTK 5, this was changed to:
<source lang="cpp"> someFilter->SetInputConnection(someReader->GetOutputPort()); </source>
However, the SetInput() and related methods were preserved for backwards compatibility. This method and all related functions, such as SetSource, were removed in VTK 6. The main reason behind this is that it is impossible to preserve this method while decoupling data objects from pipeline objects. In VTK 5, SetInput() was implemented under the hood using SetInputConnection() but this required access to the algorithm and its output port given a data object. In VTK 6, since the data object no longer has a reference to the algorithm that produced it, it is not possible to establish a pipeline connection given only a data object.
In order to make it easy to assign a stand-alone data object as an input to an algorithm, we introduced a set of convenience functions in VTK 6. Below is an example:
<source lang="cpp"> someFilter->SetInputData(aDataObject); </source>
Note that even though the following will compile, it will NOT create a pipeline connection and should not be used in place of SetInputConnection().
<source lang="cpp"> someFilter->SetInputData(someReader->GetOutput()); </source>
Another advantage of decoupling data objects from pipeline objects is that developers no longer need to create shallow copies of inputs in order to use internal filters. Previously, this was required for an algorithm to function properly:
<source lang="cpp"> void MyFilter::RequestData(…) {
vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT()); vtkDataObject* copy = input->NewInstance(); copy->ShallowCopy(input); this->InternalFilter->SetInput(copy); this->InternalFilter->Update(); …
} </source>
This can now be replaced with the following without any unexpected side effects:
<source lang="cpp"> void MyFilter::RequestData(…) {
vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT()); this->InternalFilter->SetInputData(input); this->InternalFilter->Update(); …
} </source>
Another advantage is that this change removes some circular references from the pipeline making it unnecessary to use the garbage collector. This should have a noticeable impact on the performance of VTK when using large pipelines.
Miscellaneous Changes
Certain classes in VTK 5 provided only a SetInput(vtkDataObject*) or similar method and not a SetInputConnection(vtkAlgorithmOutput*) (or similar) method. In all of these classes SetInput() was implemented by storing a reference to a data object. None of them were subclasses of vtkAlgorithm. We replaced all of these methods with SetInputData() as well as with SetInputConnection(), where SetInputData() does not setup a pipeline connection (hence the class does not update its input during execution) whereas SetInputConnection does (hence the class does update its input during execution). These classes include:
- vtkParallelCoordinatesActor
- vtkTkRenderWidget
- vtkEncodedGradientEstimator
- vtkGPUVolumeRayCastMapper (no longer updates “TransformedInput”)
- vtkPKdTree
- vtkBarChartActor
- vtkCaptionActor2D
- vtkCubeAxesActor2D
- vtkGridTransform
- vtkLegendBoxActor
- vtkPieChartActor
- vtkSpiderPlotActor
- vtkXYPlotActor
- vtk3DWidget
- vtkBalloonRepresentation
- vtkCheckerboardRepresentation
- vtkLogoRepresentation
- vtkPolyDataSourceWidget
- vtkSCurveSpline
- vtkKdTree
- vtkImplicitDataSet
- vtkImplicitVolume
- vtkKochanekSpline
- vtkCardinalSpline
In addition, we changed or removed a few algorithms that produced variable number of outputs. This is not supported in VTK 5 without the backwards compatibility layer. Such algorithms need to produce vtkMultiBlockDataSet instead. We removed vtkPLOT3DReader. Use vtkMultiBlockPLOT3DReader instead. We changed vtkProcrustesAlignmentFilter to produce a multi-block dataset as well as have one input port that accepts multiple connections.