Commit 7912d340 authored by Ken Martin's avatar Ken Martin

Rework the CompositePolyDataMapper2

The old approach used a fast path for a very narrow set of
conditions and then used a slow path for everything else.
This approach required two sets of code,

- GenericCompositePolydataMapper2
- CompositePolyDataMapper2

and had performance issues as the slow path was slower
than OpenGL1 for some cases. This reworking consolidates
the two approach together. The basic approach is that
all blocks with the same VBO structure get grouped together
and rendered as one. The number of different VBO structures is
small so this results in a a small number of things to render.

Each of those things (handled with a Helper class) gets rendered
using its own VBO and IBOs with special code to handle the cases
where uniforms have to be changed between blocks etc.

The results are generally much faster. Some additional
optimizations have resulted in further performance improvements.
Generally this new class is as fast as the old fast path and
tens to hundreds of times faster for the slow path.

This class is still complex and could probably be reworked
another three times. The complexity is largly driven by
how complex the task is as each block can have different
primitives, point/cell data arrays, etc.

This topic adds four more tests for this class. As this
class is the workhourse for ParaView it really needs far
more testing in VTK. The three additional tests cover
some use cases I know tend to cause issues.

At the same time this topic changes how point picking is
done to prevent some bad behavior. The old approach
rendered surfaces for all passes up to the primId pass.
The problem with that is that the point pass rendering may
not match up with the surface rendering resulting in point
Ids associated with incoreect composite/prop/process ids.
It mixes two sets of data haphazzardly. Very bad. This
topic cuases all point selection to be done by rendering
points.
parent bf9a674d
Pipeline #26625 passed with stage
if(VTK_RENDERING_BACKEND STREQUAL "OpenGL2")
set(extra_opengl2_tests
TestCompositePolyDataMapper2.cxx,NO_DATA
TestCompositePolyDataMapper2Picking.cxx,NO_DATA
TestCompositePolyDataMapper2Scalars.cxx,NO_DATA
TestCompositePolyDataMapper2CellScalars.cxx,NO_DATA
TestCompositePolyDataMapper2MixedGeometryCellScalars.cxx,NO_DATA
TestCompositePolyDataMapper2MixedGeometryEdges.cxx,NO_DATA
TestMultiBlockPartialArrayPointData.cxx
TestMultiBlockPartialArrayFieldData.cxx
# the following produce incorrect results in OpenGL
......@@ -9,6 +13,14 @@ if(VTK_RENDERING_BACKEND STREQUAL "OpenGL2")
TestTranslucentLUTTextureAlphaBlending.cxx
TestAreaSelections.cxx
)
else()
set(extra_opengl2_tests
TestCompositePolyDataMapper2.cxx,NO_DATA,NO_VALID
TestCompositePolyDataMapper2Scalars.cxx,NO_DATA,NO_VALID
TestCompositePolyDataMapper2CellScalars.cxx,NO_DATA,NO_VALID
TestCompositePolyDataMapper2MixedGeometryCellScalars.cxx,NO_DATA,NO_VALID
TestCompositePolyDataMapper2MixedGeometryEdges.cxx,NO_DATA,NO_VALID
)
endif()
vtk_add_test_cxx(${vtk-module}CxxTests tests
......
......@@ -43,6 +43,11 @@
int TestCompositePolyDataMapper2(int argc, char* argv[])
{
bool timeit = false;
if (argc > 1 && argv[1] && !strcmp(argv[1], "-timeit"))
{
timeit = true;
}
vtkSmartPointer<vtkRenderWindow> win =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> iren =
......@@ -67,8 +72,12 @@ int TestCompositePolyDataMapper2(int argc, char* argv[])
// build a composite dataset
vtkNew<vtkMultiBlockDataSet> data;
// int blocksPerLevel[3] = {1,64,256};
int blocksPerLevel[3] = {1,32,64};
if (timeit)
{
blocksPerLevel[1] = 64;
blocksPerLevel[2] = 256;
}
std::vector<vtkSmartPointer<vtkMultiBlockDataSet> > blocks;
blocks.push_back(data.GetPointer());
unsigned levelStart = 0;
......@@ -100,7 +109,7 @@ int TestCompositePolyDataMapper2(int argc, char* argv[])
{
mapper->SetBlockColor(parent+numLeaves+1,
vtkMath::HSVToRGB(0.8*block/nblocks, 0.2 + 0.8*((parent - levelStart) % 8)/7.0, 1.0));
mapper->SetBlockOpacity(parent+numLeaves, (block + 3) % 7 == 0 ? 0.3 : 1.0);
// mapper->SetBlockOpacity(parent+numLeaves, (block + 3) % 7 == 0 ? 0.3 : 1.0);
mapper->SetBlockVisibility(parent+numLeaves, (block % 7) != 0);
}
++numLeaves;
......@@ -141,8 +150,8 @@ int TestCompositePolyDataMapper2(int argc, char* argv[])
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
//actor->GetProperty()->SetEdgeColor(1,0,0);
//actor->GetProperty()->EdgeVisibilityOn();
actor->GetProperty()->SetEdgeColor(1,0,0);
// actor->GetProperty()->EdgeVisibilityOn();
ren->AddActor(actor);
win->SetSize(400,400);
......@@ -167,7 +176,7 @@ int TestCompositePolyDataMapper2(int argc, char* argv[])
timer->StartTimer();
int numFrames = 2;
int numFrames = (timeit ? 300 : 2);
for (int i = 0; i <= numFrames; i++)
{
ren->GetActiveCamera()->Elevation(40.0/numFrames);
......@@ -177,9 +186,11 @@ int TestCompositePolyDataMapper2(int argc, char* argv[])
}
timer->StopTimer();
double t = timer->GetElapsedTime();
cout << "Avg Frame time: " << t/numFrames << " Frame Rate: " << numFrames / t << "\n";
if (timeit)
{
double t = timer->GetElapsedTime();
cout << "Avg Frame time: " << t/numFrames << " Frame Rate: " << numFrames / t << "\n";
}
int retVal = vtkRegressionTestImageThreshold( win.GetPointer(),15);
if ( retVal == vtkRegressionTester::DO_INTERACTOR)
{
......
/*=========================================================================
Program: Visualization Toolkit
Module: vtkCompositePolyDataMapper2.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkCompositeDataSet.h"
#include "vtkCompositeDataDisplayAttributes.h"
#include "vtkCompositePolyDataMapper2.h"
#include "vtkCullerCollection.h"
#include "vtkInformation.h"
#include "vtkMath.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkNew.h"
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSmartPointer.h"
#include "vtkTimerLog.h"
#include "vtkTrivialProducer.h"
#include "vtkPointDataToCellData.h"
#include <vtkTestUtilities.h>
#include <vtkRegressionTestImage.h>
#include "vtkCylinderSource.h"
#include "vtkElevationFilter.h"
int TestCompositePolyDataMapper2CellScalars(int argc, char* argv[])
{
bool timeit = false;
if (argc > 1 && argv[1] && !strcmp(argv[1], "-timeit"))
{
timeit = true;
}
vtkSmartPointer<vtkRenderWindow> win =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> iren =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkRenderer> ren =
vtkSmartPointer<vtkRenderer>::New();
win->AddRenderer(ren);
win->SetInteractor(iren);
win->SetMultiSamples(0);
vtkSmartPointer<vtkCompositePolyDataMapper2> mapper =
vtkSmartPointer<vtkCompositePolyDataMapper2>::New();
vtkNew<vtkCompositeDataDisplayAttributes> cdsa;
mapper->SetCompositeDataDisplayAttributes(cdsa.GetPointer());
int resolution = 18;
vtkNew<vtkCylinderSource> cyl;
cyl->CappingOn();
cyl->SetRadius(0.2);
cyl->SetResolution(resolution);
vtkNew<vtkElevationFilter> elev;
elev->SetInputConnection(cyl->GetOutputPort());
vtkNew<vtkPointDataToCellData> p2c;
p2c->SetInputConnection(elev->GetOutputPort());
p2c->PassPointDataOff();
// build a composite dataset
vtkNew<vtkMultiBlockDataSet> data;
int blocksPerLevel[3] = {1,32,64};
if (timeit)
{
blocksPerLevel[1] = 64;
blocksPerLevel[2] = 256;
}
std::vector<vtkSmartPointer<vtkMultiBlockDataSet> > blocks;
blocks.push_back(data.GetPointer());
unsigned levelStart = 0;
unsigned levelEnd = 1;
int numLevels = sizeof(blocksPerLevel) / sizeof(blocksPerLevel[0]);
int numLeaves = 0;
int numNodes = 0;
vtkStdString blockName("Rolf");
for (int level = 1; level < numLevels; ++level)
{
int nblocks=blocksPerLevel[level];
for (unsigned parent = levelStart; parent < levelEnd; ++parent)
{
blocks[parent]->SetNumberOfBlocks(nblocks);
for (int block=0; block < nblocks; ++block, ++numNodes)
{
if (level == numLevels - 1)
{
vtkNew<vtkPolyData> child;
cyl->SetCenter(block*0.25, 0.0, parent*0.5);
elev->SetLowPoint(block*0.25 - 0.2 + 0.2*block/nblocks, -0.02, 0.0);
elev->SetHighPoint(block*0.25 + 0.1 + 0.2*block/nblocks, 0.02, 0.0);
p2c->Update();
child->DeepCopy(p2c->GetOutput(0));
blocks[parent]->SetBlock(
block, (block % 2) ? NULL : child.GetPointer());
blocks[parent]->GetMetaData(block)->Set(
vtkCompositeDataSet::NAME(), blockName.c_str());
// test not seting it on some
if (block % 11)
{
mapper->SetBlockVisibility(parent+numLeaves, (block % 7) != 0);
}
++numLeaves;
}
else
{
vtkNew<vtkMultiBlockDataSet> child;
blocks[parent]->SetBlock(block, child.GetPointer());
blocks.push_back(child.GetPointer());
}
}
}
levelStart = levelEnd;
levelEnd = static_cast<unsigned>(blocks.size());
}
mapper->SetInputData((vtkPolyData *)(data.GetPointer()));
mapper->SetScalarModeToUseCellData();
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetEdgeColor(1,0,0);
//actor->GetProperty()->EdgeVisibilityOn();
ren->AddActor(actor);
win->SetSize(400,400);
ren->RemoveCuller(ren->GetCullers()->GetLastItem());
ren->ResetCamera();
vtkSmartPointer<vtkTimerLog> timer = vtkSmartPointer<vtkTimerLog>::New();
win->Render(); // get the window up
// modify the data to force a rebuild of OpenGL structs
// after rendering set one cylinder to white
mapper->SetBlockColor(911,1.0,1.0,1.0);
mapper->SetBlockOpacity(911,1.0);
mapper->SetBlockVisibility(911,1.0);
timer->StartTimer();
win->Render();
timer->StopTimer();
cout << "First frame time: " << timer->GetElapsedTime() << "\n";
timer->StartTimer();
int numFrames = (timeit ? 300 : 2);
for (int i = 0; i <= numFrames; i++)
{
ren->GetActiveCamera()->Elevation(10.0/numFrames);
ren->GetActiveCamera()->Azimuth(-50.0/numFrames);
ren->GetActiveCamera()->Zoom(pow(2.5,1.0/numFrames));
ren->GetActiveCamera()->Roll(20.0/numFrames);
win->Render();
}
timer->StopTimer();
if (timeit)
{
double t = timer->GetElapsedTime();
cout << "Avg Frame time: " << t/numFrames << " Frame Rate: " << numFrames / t << "\n";
}
int retVal = vtkRegressionTestImageThreshold( win.GetPointer(),15);
if ( retVal == vtkRegressionTester::DO_INTERACTOR)
{
iren->Start();
}
return !retVal;
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkCompositePolyDataMapper2.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkCompositeDataSet.h"
#include "vtkCompositeDataDisplayAttributes.h"
#include "vtkCompositePolyDataMapper2.h"
#include "vtkCullerCollection.h"
#include "vtkInformation.h"
#include "vtkMath.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkNew.h"
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSmartPointer.h"
#include "vtkTimerLog.h"
#include "vtkTrivialProducer.h"
#include "vtkPointDataToCellData.h"
#include <vtkTestUtilities.h>
#include <vtkRegressionTestImage.h>
#include "vtkCylinderSource.h"
#include "vtkElevationFilter.h"
#include "vtkPlaneSource.h"
#include "vtkAppendPolyData.h"
#include "vtkExtractEdges.h"
int TestCompositePolyDataMapper2MixedGeometryCellScalars(int argc, char* argv[])
{
bool timeit = false;
if (argc > 1 && argv[1] && !strcmp(argv[1], "-timeit"))
{
timeit = true;
}
vtkSmartPointer<vtkRenderWindow> win =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> iren =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkRenderer> ren =
vtkSmartPointer<vtkRenderer>::New();
win->AddRenderer(ren);
win->SetInteractor(iren);
win->SetMultiSamples(0);
vtkSmartPointer<vtkCompositePolyDataMapper2> mapper =
vtkSmartPointer<vtkCompositePolyDataMapper2>::New();
vtkNew<vtkCompositeDataDisplayAttributes> cdsa;
mapper->SetCompositeDataDisplayAttributes(cdsa.GetPointer());
int resolution = 18;
vtkNew<vtkCylinderSource> cyl;
cyl->CappingOn();
cyl->SetRadius(0.2);
cyl->SetHeight(0.8);
cyl->SetResolution(resolution);
vtkNew<vtkPlaneSource> plane;
plane->SetResolution(resolution, resolution);
plane->SetOrigin(-0.2, -0.2, 0.0);
plane->SetPoint1(0.2, -0.2, 0.0);
plane->SetPoint2(-0.2, 0.2, 0.0);
vtkNew<vtkExtractEdges> extract;
extract->SetInputConnection(plane->GetOutputPort());
vtkNew<vtkAppendPolyData> append;
append->SetUserManagedInputs(1);
append->SetNumberOfInputs(2);
append->SetInputConnectionByNumber(0, cyl->GetOutputPort());
append->SetInputConnectionByNumber(1, extract->GetOutputPort());
vtkNew<vtkElevationFilter> elev;
elev->SetInputConnection(append->GetOutputPort());
vtkNew<vtkPointDataToCellData> p2c;
p2c->SetInputConnection(elev->GetOutputPort());
p2c->PassPointDataOff();
// build a composite dataset
vtkNew<vtkMultiBlockDataSet> data;
int blocksPerLevel[3] = {1,8,16};
if (timeit)
{
blocksPerLevel[1] = 64;
blocksPerLevel[2] = 256;
}
std::vector<vtkSmartPointer<vtkMultiBlockDataSet> > blocks;
blocks.push_back(data.GetPointer());
unsigned levelStart = 0;
unsigned levelEnd = 1;
int numLevels = sizeof(blocksPerLevel) / sizeof(blocksPerLevel[0]);
int numLeaves = 0;
int numNodes = 0;
vtkStdString blockName("Rolf");
for (int level = 1; level < numLevels; ++level)
{
int nblocks=blocksPerLevel[level];
for (unsigned parent = levelStart; parent < levelEnd; ++parent)
{
blocks[parent]->SetNumberOfBlocks(nblocks);
for (int block=0; block < nblocks; ++block, ++numNodes)
{
if (level == numLevels - 1)
{
vtkNew<vtkPolyData> child;
cyl->SetCenter(block*0.25, -0.3, parent*0.5);
plane->SetCenter(block*0.25, 0.5, parent*0.5);
elev->SetLowPoint(block*0.25 - 0.2 + 0.2*block/nblocks, -0.02, 0.0);
elev->SetHighPoint(block*0.25 + 0.1 + 0.2*block/nblocks, 0.02, 0.0);
p2c->Update();
child->DeepCopy(p2c->GetOutput(0));
blocks[parent]->SetBlock(
block, (block % 2) ? NULL : child.GetPointer());
blocks[parent]->GetMetaData(block)->Set(
vtkCompositeDataSet::NAME(), blockName.c_str());
// test not seting it on some
if (block % 11)
{
mapper->SetBlockVisibility(parent+numLeaves, (block % 7) != 0);
}
++numLeaves;
}
else
{
vtkNew<vtkMultiBlockDataSet> child;
blocks[parent]->SetBlock(block, child.GetPointer());
blocks.push_back(child.GetPointer());
}
}
}
levelStart = levelEnd;
levelEnd = static_cast<unsigned>(blocks.size());
}
mapper->SetInputData((vtkPolyData *)(data.GetPointer()));
mapper->SetScalarModeToUseCellData();
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetEdgeColor(1,0,0);
//actor->GetProperty()->EdgeVisibilityOn();
ren->AddActor(actor);
win->SetSize(400,400);
ren->RemoveCuller(ren->GetCullers()->GetLastItem());
ren->ResetCamera();
vtkSmartPointer<vtkTimerLog> timer = vtkSmartPointer<vtkTimerLog>::New();
win->Render(); // get the window up
// modify the data to force a rebuild of OpenGL structs
// after rendering set one cylinder to white
mapper->SetBlockColor(40,1.0,1.0,1.0);
mapper->SetBlockOpacity(40,1.0);
mapper->SetBlockVisibility(40,1.0);
timer->StartTimer();
win->Render();
timer->StopTimer();
cout << "First frame time: " << timer->GetElapsedTime() << "\n";
timer->StartTimer();
int numFrames = (timeit ? 300 : 2);
for (int i = 0; i <= numFrames; i++)
{
ren->GetActiveCamera()->Elevation(15.0/numFrames);
ren->GetActiveCamera()->Azimuth(-130.0/numFrames);
ren->GetActiveCamera()->Zoom(pow(1.6,1.0/numFrames));
ren->GetActiveCamera()->Roll(0.0/numFrames);
win->Render();
}
timer->StopTimer();
if (timeit)
{
double t = timer->GetElapsedTime();
cout << "Avg Frame time: " << t/numFrames << " Frame Rate: " << numFrames / t << "\n";
}
int retVal = vtkRegressionTestImageThreshold( win.GetPointer(),15);
if ( retVal == vtkRegressionTester::DO_INTERACTOR)
{
iren->Start();
}
return !retVal;
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkCompositePolyDataMapper2.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkCompositeDataSet.h"
#include "vtkCompositeDataDisplayAttributes.h"
#include "vtkCompositePolyDataMapper2.h"
#include "vtkCullerCollection.h"
#include "vtkInformation.h"
#include "vtkMath.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkNew.h"
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSmartPointer.h"
#include "vtkTimerLog.h"
#include "vtkTrivialProducer.h"
#include "vtkPointDataToCellData.h"
#include <vtkTestUtilities.h>
#include <vtkRegressionTestImage.h>
#include "vtkCylinderSource.h"
#include "vtkElevationFilter.h"
#include "vtkPlaneSource.h"
#include "vtkAppendPolyData.h"
#include "vtkExtractEdges.h"
int TestCompositePolyDataMapper2MixedGeometryEdges(int argc, char* argv[])
{
bool timeit = false;
if (argc > 1 && argv[1] && !strcmp(argv[1], "-timeit"))
{
timeit = true;
}
vtkSmartPointer<vtkRenderWindow> win =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> iren =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkRenderer> ren =
vtkSmartPointer<vtkRenderer>::New();
win->AddRenderer(ren);
win->SetInteractor(iren);
win->SetMultiSamples(0);
vtkSmartPointer<vtkCompositePolyDataMapper2> mapper =
vtkSmartPointer<vtkCompositePolyDataMapper2>::New();
vtkNew<vtkCompositeDataDisplayAttributes> cdsa;
mapper->SetCompositeDataDisplayAttributes(cdsa.GetPointer());
int resolution = 18;
vtkNew<vtkCylinderSource> cyl;
cyl->CappingOn();
cyl->SetRadius(0.2);
cyl->SetHeight(0.8);
cyl->SetResolution(resolution);
vtkNew<vtkPlaneSource> plane;
plane->SetResolution(resolution, resolution);
plane->SetOrigin(-0.2, -0.2, 0.0);
plane->SetPoint1(0.2, -0.2, 0.0);
plane->SetPoint2(-0.2, 0.2, 0.0);
vtkNew<vtkExtractEdges> extract;
extract->SetInputConnection(plane->GetOutputPort());
vtkNew<vtkAppendPolyData> append;
append->SetUserManagedInputs(1);
append->SetNumberOfInputs(2);
append->SetInputConnectionByNumber(0, cyl->GetOutputPort());
append->SetInputConnectionByNumber(1, extract->GetOutputPort());
vtkNew<vtkElevationFilter> elev;
elev->SetInputConnection(append->GetOutputPort());
vtkNew<vtkPointDataToCellData> p2c;
p2c->SetInputConnection(elev->GetOutputPort());
p2c->PassPointDataOff();
// build a composite dataset
vtkNew<vtkMultiBlockDataSet> data;
int blocksPerLevel[3] = {1,8,16};
if (timeit)
{