Deprecating vtkCompositePolyDataMapper2 in favor of vtkCompositePolyDataMapper

vtkCompositePolyDataMapper2 is used almost everywhere (in ParaView, VTK apps) for composite polydata rendering instead of vtkCompositePolyDataMapper. It is smart enough to internally use as few mappers as possible instead of naively creating a mapper per block - like vtkCompositePolyDataMapper currently does. The advantage of CPDM2 over CPDM is very few GPU uploads - a maximum of 8 for any number of blocks.

On the other hand, the original vtkCompositePolyDataMapper class is not used much. This causes some trouble when using/developing VTK.

  1. Application code needs to be aware of the two mappers and handle both of them because CPDM doesn’t allow per-block display attributes like CPDM2.
  2. Developers of new mappers that wish to use CPDM2 have to write code in the OpenGL2 module or hard link to it. It’s impossible to use CPDM2 from RenderingCore. Ex: PartitionedDataSetCollectionMapper. See discussion in https://discourse.paraview.org/t/adding-properties-for-vtkpartitioneddatasetcollection/6061/1
  3. For new rendering backends (WebGPU), CPDM2 has to be written from scratch, possibly named CPDM3?

The issue is that CPDM2 does a lot of smart stuff that’s completely unrelated to OpenGL. That logic has been lifted up into RenderingCore so that other modules can benefit from it. Related MR - vtk/vtk!10165

The performance of vtkCompositePolyDataMapper is now on par with vtkCompositePolyDataMapper2.
All occurences of vtkCompositePolyDataMapper2 in VTK have been replaced with vtkCompositePolyDataMapper. CPDM2 will be deprecated soon. If you’re subclassing vtkCompositePolyDataMapper2 in your application, this might be of interest. The transition is quite straightforward. In VTK, the CompositeSurfaceLIC mappers went through a similar process in that MR.

Old design:

vtk-cpdm-org-old

New design:
vtk-cpdm-org-new

@cory.quammen
@sankhesh
@dcthomp - FYI, regarding CMB, SMTK
@Dave_DeMarle - FYI, regarding OSPRay
@Charles_Gueunet - FYI, regarding HTG mappers

4 Likes

+1 for removing unused classes. I like the new model with a delegator/delegate approach of setting attributes.

This is one of those cases where it may not be pretty, but maybe practicality should influence us?

There is a lot of external code referencing vtkCompositePolyDataMapper2. Could we possibly just make it an alias/typedef of the new vtkCompositePolyDataMapper instead of deprecating/removing it?

Thoughts @ben.boeckel ?

It can be a name that we keep for longer. I think we should still warn that it is deprecated. Note that 9.5 is the earliest that we will remove 9.3-deprecated code; there’s nothing saying we cannot provide it for longer for more widely-used things.

The idea is that code supporting 9.1 and 9.3 at the same time can use the same code. VTK-using code can use #define VTK_DEPRECATION_LEVEL VTK_VERSION_CHECK(9, 1, 0) to say “I should work with 9.1, please do not warn about names which were deprecated afterwards”. Note that 9.3 will ignore this as 9.1 symbols are on their way out the door and force the warning since removal is much more urgent at that point.

As for the MR itself, I noticed that some methods seemed to have been removed in the process here in various places; is there any way we can keep those around as deprecated? If they’re not accessible from outside of VTK for whatever reason, then it’s fine.

It is now deprecated in the master branch. Until it’s completely removed, projects which rely on CPDM2 will display a compiler warning.

Hello @jaswantp , I am an avid user of CPDM2 and would like to ask few questions.

Usually I have plenty of data blocks (say 9000). Initially using a mapper+actor per block gave very bad rendering performance. Processing too many actors is bad.
The solution was to use a composite data object + CPDM2 leading to a single actor. I was only interested in solving the performance issue while retaining the ability to tune visual attributes of each blocks.
My questions might sound stupid but please keep in mind my original performance concern while reading them.

  • It was my understanding that the CPDM1 would spawn many mappers and could lead to the same performance issue I originally had. Why would CPDM1 be faster now than several mappers+actors?
  • Retaining the ability to edit opacity, pickability, color of each block while using a single composite object is great. With CPDM1 how should I edit each block color? With a color map?
  • You said “That logic has been lifted up into RenderingCore so that other modules can benefit from it.”. RenderingCore is about the renderer right ? Does this mean that I can now use thousands of mappers+actors is the same renderer with the same performance as with the CPDM2 and the renderer will push everything to the backend?

Thanks,

Edit: I just tested 10000 spheres using VTK master branch. The performances are as I remembered: composite2 is fast! composite1 is sluggish and no_composite is stuttering. Is this expected?

Hello @afa, I’ll try my best to answer your questions.

Because CPDM1 now works exactly like CPDM2. The performance of CPDM1 and CPDM2 is identical. The refactor was done to remove unused duplicate classes.

No, don’t go to color maps. You can edit attributes per block with CPDM1 just the same way you had done so far using CPDM2. Either use new block-id based API available from CPDM1 or fill up a vtkCompositeDataDisplayAttributes and feed it to CPDM1 - just like CPDM2. Both CPDM1 and CPDM2 have nearly the same public API.

RenderingCore is not only about the renderer. It has abstract interfaces for almost every class in RenderingOpenGL2. This includes vtkRenderer, vtkRenderWindow, vtkActor, vtkMapper, vtkPolyDataMapper, vtkGlyphMapper, vtkCamera, vtkLight and so on…

No, please do not use thousands of mappers + actors in the same renderer. Continue whatever you did before with CPDM2 using single actor+mapper and simply drop the suffix 2 everywhere.

For most users, here’s how the code change looks:

Before:

#include <vtkCompositePolyDataMapper2.h>

vtkNew<vtkCompositeDataDisplayAttributes> cda;
vtkNew<vtkCompositePolyDataMapper2> mapper;
mapper->SetInput(...);
mapper->SetDataDisplayAttributes(cda);
mapper->SetBlockOpacity(0, 0.4);

After:

#include <vtkCompositePolyDataMapper.h>

vtkNew<vtkCompositeDataDisplayAttributes> cda;
vtkNew<vtkCompositePolyDataMapper> mapper;
mapper->SetInput(...);
mapper->SetDataDisplayAttributes(cda);
mapper->SetBlockOpacity(0, 0.4);

For advanced users who sub-classed vtkCompositePolyDataMapper2, extra steps are needed where the GL delegate and delegators must also be derived. This commit 5b159e6 shows the differences.

No, this is not expected. Can you share the project files?

There’s a benchmark in VTK tests which I’ve used to check for performance regressions. After you build the tests, run ./bin/vtkRenderingCoreCxxTests TestCompositePolyDataMapper -timeit and ./bin/vtkRenderingOpenGL2CxxTests TestCompositePolyDataMapper2 -timeit. Both should report nearly identical results.

Here are the results on Linux:
CPDM1:

CPDM2:

As you can see, CPDM1 is slightly faster than CPDM2, contrary to what you observed, so I think you may be using an older VTK.

Indeed. I have redone my tests and I do not see the issue anymore.
I was surprised that I was not able to use mapper->SetDataDisplayAttributes(cda); and the fact that you mentionned it + no perfs regression made me double check my stuff.
I was using another VTK build (I need to use GetVTKVersionFull more often). Everything is fine now using master and CPDM1 is a drop-in replacement for CPDM2 as far as I am concerned.

Sorry for bothering you. I greatly appreciate the explanations though. It seems the migration will be easy.

Thanks!

1 Like

Glad it worked out for you and happy to help! :slight_smile:

Does this proposal include a way to use shaders with vtkCompositePolyDataMapper?

vtkCompositePolyDataMapper2 had a vtkCommand::UpdateShaderEvent, but I don’t see that in vttkCompositePolyDataMapper.

Thanks.

Yes. It’s handled by the delegator machinery. You can listen to the vtkCommand::UpdateShaderEvent from vtkCompositePolyDataMapper. Are your observers not invoked? Please create an issue if it doesn’t work for you.

It’s implemented in vtkOpenGLBatchedPolyDataMapper.cxx#L889

Ok, with some testing and modification, I now see vtkCommand::UpdateShaderEvent. I found that vtkCompositePolyDataMapper::GetBounds doesn’t return bounds if the Static flag is set. On the other hand, vtkCompositePolyDataMapper2::GetBounds does return initialized bounds. The result of setting Static on vtkCompositePolyDataMapper is that the actor will be culled and not rendered.

Glad it’s working for you!

GetBounds involves a pipeline update. I feel that the Static flag was not behaving correctly before. Static meant that the upstream pipeline should not respond to Update. You could call mapper->Update once before turning on the Static flag so that the bounds are retrieved.