An update will be applied today, Nov30th, between 12PM and 1:00PM EST (UTC -5:00). The site may be slow during that time.

Commit bdc47e73 authored by Dave DeMarle's avatar Dave DeMarle
Browse files

Add interface to LANL's Piston GPGPU library.

This new module is a framework that adds GPGPU filters, which call
into LANL's piston library to do the computation, to VTK. The
implementation includes a new GPU centric data object type, a new
GPU enabling algorithm family, and a new mapper for GPU data, all of
which can function without bringing the data back to the CPU.

Thanks Ollie Lo, Chris Sewell and Aashish Chaudihary for assisting
with the development of this new module.

Change-Id: I948c01432b44df343e810241639ae123488a4305
parent d615e721
find_package(CUDA REQUIRED)
find_path(PISTON_INCLUDE
PistonCodingStyle.xml
"/Source/PISTON/github/PISTON"
DOC "PISTON library's source directory")
set(Module_SRCS
vtkDataSetToPiston.cxx
vtkPistonAlgorithm.cxx
vtkPistonDataObject.cxx
vtkPistonContour.cxx
vtkPistonMapper.cxx
vtkPistonToDataSet.cxx
vtkPistonScalarsColors.cxx
vtkPistonSlice.cxx
vtkPistonSort.cxx
vtkPistonThreshold.cxx
)
set( Module_CUDA_SRCS
vtkPistonConverters.cu
vtkPistonContour.cu
vtkPistonMapper.cu
vtkPistonSlice.cu
vtkPistonSort.cu
vtkPistonThreshold.cu
)
if(BUILD_SHARED_LIBS)
set(GPGPU_BUILD_TYPE SHARED)
endif()
set(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE OFF) #otherwise C_SOURCES is empty in VS
vtk_module_impl() #chicken and egg, I need list of include dirs of the module for nvcc's use before vtk_module_library is called
include_directories(${${vtk-module}_DEPENDS_INCLUDE_DIRS} ${PISTON_INCLUDE} ${CUDA_INCLUDE_DIR})
cuda_compile(Module_CUDA_C_SRCS ${Module_CUDA_SRCS} ${GPGPU_BUILD_TYPE})
set_source_files_properties(
${Module_CUDA_C_SRCS}
WRAP_EXCLUDE
)
list(APPEND Module_SRCS ${Module_CUDA_C_SRCS})
vtk_module_library(vtkAcceleratorsPiston ${Module_SRCS})
target_link_libraries(vtkAcceleratorsPiston ${CUDA_LIBRARIES})
if(APPLE)
target_link_libraries(vtkAcceleratorsPiston /usr/local/cuda/lib/libtlshook.dylib)
endif()
create_test_sourcelist(Tests ${vtk-module}CxxTests.cxx
TestUsePiston
EXTRA_INCLUDE vtkTestDriver.h
)
vtk_module_test_executable(${vtk-module}CxxTests ${Tests})
set(TestsToRun ${Tests})
list(REMOVE_ITEM TestsToRun ${vtk-module}CxxTests.cxx)
string (REPLACE "vtk" "" _baselinedname ${vtk-module})
# Add all the executables
foreach(test ${TestsToRun})
get_filename_component(TName ${test} NAME_WE)
if(VTK_DATA_ROOT)
add_test(NAME ${vtk-module}Cxx-${TName}
COMMAND ${vtk-module}CxxTests ${TName}
-D ${VTK_DATA_ROOT}
-T ${VTK_TEST_OUTPUT_DIR}
-V Baseline/${_baselinedname}/${TName}.png)
else()
add_test(NAME ${vtk-module}Cxx-${TName}
COMMAND ${vtk-module}CxxTests ${TName})
endif()
endforeach()
if(VTK_DATA_ROOT AND (VTK_MPI_MAX_NUMPROCS GREATER 1))
find_package(MPI REQUIRED)
include_directories(${MPI_INCLUDE_PATH})
set(PistonMPITests TestDMPFiltering TestCompositeRender)
foreach(test ${PistonMPITests})
vtk_module_test_executable(${vtk-module}Cxx-${test} ${test}.cxx)
if(VTK_DATA_ROOT)
add_test(NAME ${vtk-module}Cxx-${test}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${vtk-module}Cxx-${test}>
-D ${VTK_DATA_ROOT}
-T ${VTK_TEST_OUTPUT_DIR}
-V Baseline/${_baselinedname}/${test}.png
${VTK_MPI_POSTFLAGS})
else()
add_test(NAME ${vtk-module}Cxx-${test}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${vtk-module}Cxx-${test}>
${VTK_MPI_POSTFLAGS})
endif()
endforeach()
endif()
/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile$
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.
=========================================================================*/
//This test demonstrates the use of sort last distributed memory parallel
//rendering with Piston.
//
//The pipeline is created in parallel and each process is
//assigned 1 piece to process. Each node then renders its local image and
//the image results are depth composited to produce a correct image on the
//root node.
#include <mpi.h>
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkCompositeRenderManager.h"
#include "vtkContourFilter.h"
#include "vtkDataSetToPiston.h"
#include "vtkImageMandelbrotSource.h"
#include "vtkLookupTable.h"
#include "vtkMPICommunicator.h"
#include "vtkMPIController.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkPieceScalars.h"
#include "vtkPistonContour.h"
#include "vtkPistonMapper.h"
#include "vtkPolyDataMapper.h"
#include "vtkProcess.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkSphereSource.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkSynchronizedRenderWindows.h"
#include "vtkSynchronizedRenderers.h"
#include "vtkTestUtilities.h"
class MyProcess : public vtkProcess
{
public:
static MyProcess *New();
vtkTypeMacro(MyProcess, vtkProcess);
virtual void Execute();
void SetArgs(int argc, char *argv[])
{
this->Argc = argc;
this->Argv = argv;
}
void CreatePipeline(vtkRenderer *renderer)
{
int num_procs = this->Controller->GetNumberOfProcesses();
int my_id = this->Controller->GetLocalProcessId();
vtkSmartPointer<vtkImageMandelbrotSource> src =
vtkSmartPointer<vtkImageMandelbrotSource>::New();
vtkSmartPointer<vtkDataSetToPiston> d2p =
vtkSmartPointer<vtkDataSetToPiston>::New();
vtkSmartPointer<vtkPistonContour> contour =
vtkSmartPointer<vtkPistonContour>::New();
vtkSmartPointer<vtkContourFilter> vtkcontour =
vtkSmartPointer<vtkContourFilter>::New();
vtkSmartPointer<vtkSphereSource> sphere =
vtkSmartPointer<vtkSphereSource>::New();
vtkSmartPointer<vtkPieceScalars> piecescalars =
vtkSmartPointer<vtkPieceScalars>::New();
vtkSmartPointer<vtkPistonMapper> mapper =
vtkSmartPointer<vtkPistonMapper>::New();
vtkSmartPointer<vtkPolyDataMapper> pdm =
vtkSmartPointer<vtkPolyDataMapper>::New();
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
#define TESTPISTON 1
#define TESTUNSTRUCTURED 1
#if TESTPISTON
#if TESTUNSTRUCTURED
sphere->SetPhiResolution(100);
sphere->SetThetaResolution(100);
piecescalars->SetInputConnection(sphere->GetOutputPort());
piecescalars->SetScalarModeToCellData();
d2p->SetInputConnection(piecescalars->GetOutputPort());
mapper->SetInputConnection(d2p->GetOutputPort());
mapper->SetPiece(my_id);
mapper->SetNumberOfPieces(num_procs);
#else // TESTSTRUCTURED
src->SetWholeExtent(0,40,0,40,0,40);
d2p->SetInputConnection(src->GetOutputPort());
contour->SetInputConnection(d2p->GetOutputPort());
contour->SetIsoValue(50.0);
mapper->SetInputConnection(contour->GetOutputPort());
mapper->SetPiece(my_id);
mapper->SetNumberOfPieces(num_procs);
#endif
mapper->Update(); // TODO: shouldn't need this
actor->SetMapper(mapper);
#else // TESTPISTON
#if TESTUNSTRUCTURED
sphere->SetPhiResolution(100);
sphere->SetThetaResolution(100);
piecescalars->SetInputConnection(sphere->GetOutputPort());
piecescalars->SetScalarModeToCellData();
pdm->SetInputConnection(piecescalars->GetOutputPort());
pdm->SetScalarModeToUseCellFieldData();
pdm->SelectColorArray("Piece");
pdm->SetScalarRange(0, num_procs-1);
pdm->SetPiece(my_id);
pdm->SetNumberOfPieces(num_procs);
#else // TESTSTRUCTURED
src->SetWholeExtent(0,40,0,40,0,40);
vtkcontour->SetInputConnection(src->GetOutputPort());
vtkcontour->SetNumberOfContours(1);
vtkcontour->SetValue(0, 50.0);
pdm->SetInputConnection(vtkcontour->GetOutputPort());
pdm->SetPiece(my_id);
pdm->SetNumberOfPieces(num_procs);
#endif
pdm->Update(); //TODO: Why is this needed?
actor->SetMapper(pdm);
#endif
renderer->AddActor(actor);
}
protected:
MyProcess() { this->Argc = 0; this->Argv = NULL; }
int Argc;
char **Argv;
};
//#vtkCxxRevisionMacro(MyProcess, "1.0");
vtkStandardNewMacro(MyProcess);
void MyProcess::Execute()
{
int my_id = this->Controller->GetLocalProcessId();
int go;
vtkMPICommunicator *comm =
vtkMPICommunicator::SafeDownCast(this->Controller->GetCommunicator());
comm->Barrier();
// TODO: Update to utkarsh's new architecture
vtkSmartPointer<vtkCompositeRenderManager> prm =
vtkSmartPointer<vtkCompositeRenderManager>::New();
vtkRenderer *renderer = prm->MakeRenderer();
vtkRenderWindow *renWin = prm->MakeRenderWindow();
renWin->AddRenderer(renderer);
renWin->DoubleBufferOn();
renWin->Render();
// TODO: Add an argument to decide if use interop or not
vtkPistonMapper::InitCUDAGL(renWin);
this->CreatePipeline(renderer);
prm->SetRenderWindow(renWin);
prm->SetController(this->Controller);
if (my_id == 0)
{
prm->ResetAllCameras();
vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New();
iren->SetRenderWindow(renWin);
this->ReturnValue =
vtkRegressionTester::Test(this->Argc, this->Argv, renWin, 10);
if (this->ReturnValue == vtkRegressionTester::DO_INTERACTOR)
{
prm->StartInteractor();
}
iren->Delete();
this->Controller->TriggerBreakRMIs();
this->Controller->Barrier();
}
else
{
prm->StartServices();
this->Controller->Barrier();
// No testing is done here so mark it passed
this->ReturnValue = vtkTesting::PASSED;
}
renderer->Delete();
renWin->Delete();
}
int main(int argc, char **argv)
{
// This is here to avoid false leak messages from vtkDebugLeaks when
// using mpich. It appears that the root process which spawns all the
// main processes waits in MPI_Init() and calls exit() when
// the others are done, causing apparent memory leaks for any objects
// created before MPI_Init().
MPI_Init(&argc, &argv);
// Note that this will create a vtkMPIController if MPI
// is configured, vtkThreadedController otherwise.
vtkMPIController *contr = vtkMPIController::New();
contr->Initialize(&argc, &argv, 1);
int retVal = 1; // 1 == failed
int numProcs = contr->GetNumberOfProcesses();
if (numProcs < 2 && false)
{
cout << "This test requires at least 2 processes" << endl;
contr->Delete();
return retVal;
}
vtkMultiProcessController::SetGlobalController(contr);
MyProcess *p = MyProcess::New();
p->SetArgs(argc, argv);
contr->SetSingleProcessObject(p);
contr->SingleMethodExecute();
retVal = p->GetReturnValue();
p->Delete();
contr->Finalize();
contr->Delete();
vtkMultiProcessController::SetGlobalController(0);
return !retVal;
}
/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile$
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.
=========================================================================*/
//This test demonstrates the use of Distributed Memory Parallel
//processing using the Piston library.
//
//The pipeline is created in parallel and each process is
//assigned 1 piece to process. All satellite processes send their local
//result to the first process which collects and renders them as one.
#include <mpi.h>
#include "vtkActor.h"
#include "vtkAppendPolyData.h"
#include "vtkCamera.h"
#include "vtkDataSetToPiston.h"
#include "vtkDebugLeaks.h"
#include "vtkElevationFilter.h"
#include "vtkImageMandelbrotSource.h"
#include "vtkInformation.h"
#include "vtkMPIController.h"
#include "vtkPistonContour.h"
#include "vtkPistonToDataSet.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkTestUtilities.h"
#include "vtkWindowToImageFilter.h"
static const float ISO_START = 80.0;
static const float ISO_STEP = -7.0;
static const int ISO_NUM = 10;
// Just pick a tag which is available
static const int ISO_VALUE_RMI_TAG = 300;
static const int ISO_OUTPUT_TAG = 301;
struct ParallelIsoArgs_tmp
{
int argc;
char **argv;
int *retVal;
};
struct ParallelIsoRMIArgs_tmp
{
vtkPistonContour *ContourFilter;
vtkMultiProcessController *Controller;
vtkPistonToDataSet *P2D;
vtkElevationFilter *elev;
};
// Callback to set the iso surface value.
void SetIsoValueRMI(void *localArg, void *vtkNotUsed(remoteArg),
int vtkNotUsed(remoteArgLen), int vtkNotUsed(id))
{
ParallelIsoRMIArgs_tmp *args = (ParallelIsoRMIArgs_tmp*)localArg;
float val;
vtkPistonContour *iso = args->ContourFilter;
val = iso->GetIsoValue();
iso->SetIsoValue(val + ISO_STEP);
args->elev->Update();
vtkMultiProcessController *contrl = args->Controller;
contrl->Send(args->elev->GetOutput(), 0, ISO_OUTPUT_TAG);
}
// This will be called by all processes
void MyMain(vtkMultiProcessController *controller, void *arg)
{
int myid, numProcs;
float val;
ParallelIsoArgs_tmp *args = reinterpret_cast<ParallelIsoArgs_tmp*>(arg);
// Obtain the id of the running process and the total
// number of processes
myid = controller->GetLocalProcessId();
numProcs = controller->GetNumberOfProcesses();
vtkImageMandelbrotSource *src = vtkImageMandelbrotSource::New();
src->SetWholeExtent(0,40,0,40,0,40);
vtkDataSetToPiston *d2p = vtkDataSetToPiston::New();
d2p->SetInputConnection(src->GetOutputPort());
vtkPistonContour *contour = vtkPistonContour::New();
contour->SetInputConnection(d2p->GetOutputPort());
contour->SetIsoValue(ISO_START);
vtkPistonToDataSet *p2d = vtkPistonToDataSet::New();
p2d->SetInputConnection(contour->GetOutputPort());
p2d->SetOutputDataSetType(VTK_POLY_DATA);
vtkElevationFilter *elev = vtkElevationFilter::New();
elev->SetInputConnection(p2d->GetOutputPort());
val = (myid+1) / static_cast<float>(numProcs);
elev->SetScalarRange(val, val+0.001);
// Tell the pipeline which piece we want to update.
vtkStreamingDemandDrivenPipeline *exec =
vtkStreamingDemandDrivenPipeline::SafeDownCast(elev->GetExecutive());
exec->SetUpdateNumberOfPieces(exec->GetOutputInformation(0), numProcs);
exec->SetUpdatePiece(exec->GetOutputInformation(0), myid);
// Make sure all processes update at the same time.
elev->Update();
if (myid != 0)
{
// If I am not the root process
ParallelIsoRMIArgs_tmp args2;
args2.ContourFilter = contour;
args2.Controller = controller;
args2.P2D = p2d;
args2.elev = elev;
// Last, set up a RMI call back to change the iso surface value.
// This is done so that the root process can let this process
// know that it wants the contour value to change.
controller->AddRMI(SetIsoValueRMI, (void *)&args2, ISO_VALUE_RMI_TAG);
controller->ProcessRMIs();
}
else
{
// Create the rendering part of the pipeline
vtkAppendPolyData *app = vtkAppendPolyData::New();
app->UserManagedInputsOn();
app->SetNumberOfInputs(numProcs);
vtkRenderer *ren = vtkRenderer::New();
vtkRenderWindow *renWindow = vtkRenderWindow::New();
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
vtkActor *actor = vtkActor::New();
vtkCamera *cam = vtkCamera::New();
renWindow->AddRenderer(ren);
iren->SetRenderWindow(renWindow);
renWindow->SetSize(400, 400);
mapper->SetInputConnection(app->GetOutputPort());
actor->SetMapper(mapper);
ren->AddActor(actor);
cam->SetFocalPoint(0, 0, 0);
cam->SetPosition(10, 10, 10);
cam->SetViewUp(0, 0, -1);
cam->SetViewAngle(30);
ren->SetActiveCamera(cam);
// Loop through some iso surface values.
for (int j = 0; j < ISO_NUM; ++j)
{
// Set the local value
contour->SetIsoValue(contour->GetIsoValue() + ISO_STEP);
elev->Update();
for (int i = 1; i < numProcs; ++i)
{
// Trigger the RMI to change the iso surface value.
controller->TriggerRMI(i, ISO_VALUE_RMI_TAG);
}
for (int i = 1; i < numProcs; ++i)
{
vtkPolyData *pd = vtkPolyData::New();
controller->Receive(pd, i, ISO_OUTPUT_TAG);
app->SetInputDataByNumber(i, pd);
pd->Delete();
}
vtkPolyData *outputCopy = vtkPolyData::New();
outputCopy->ShallowCopy(elev->GetOutput());
app->SetInputDataByNumber(0, outputCopy);
outputCopy->Delete();
app->Update();
ren->ResetCamera();
renWindow->Render();
}
// Tell the other processors to stop processing RMIs.
for (int i = 1; i < numProcs; ++i)
{
controller->TriggerRMI(i, vtkMultiProcessController::BREAK_RMI_TAG);
}
*(args->retVal) =
vtkRegressionTester::Test(args->argc, args->argv, renWindow, 10);
if (*(args->retVal) == vtkRegressionTester::DO_INTERACTOR)
{
iren->Start();
}
// Clean up
app->Delete();
ren->Delete();
renWindow->Delete();
iren->Delete();
mapper->Delete();
actor->Delete();
cam->Delete();
}
// Clean up objects in all processes.
src->Delete();
d2p->Delete();
contour->Delete();
p2d->Delete();
elev->Delete();
}
int main(int argc, char *argv[])
{
// This is here to avoid false leak messages from vtkDebugLeaks when
// using mpich. It appears that the root process which spawns all the
// main processes waits in MPI_Init() and calls exit() when
// the others are done, causing apparent memory leaks for any objects
// created before MPI_Init().
MPI_Init(&argc, &argv);