Updates will be applied April 15th at 12pm EDT (UTC-0400). GitLab could be a little slow between 12 - 12:45pm EDT.

Commit 52c7392f authored by Utkarsh Ayachit's avatar Utkarsh Ayachit

Refactors AMR streaming framework.

This commit refactors AMR streaming framework and add support for a mechanism
for streaming composite datasets in general. To try out amr streaming, run all
executables with "--enable-streaming" flag and open an AMR Flash or Enzo dataset
and render as "AMR Blocks" or "Volume" (currently, only works in builtin mode,
but will be supported in other modes soon).

vtkAMROutlineRepresentation is a example class that demonstrates how a
representation can leverage the streaming capabailities provided by
vtkPVRenderView.

vtkPVRenderView adds support to two new passes: REQUEST_STREAMING_UPDATE() and
REQUEST_PROCESS_STREAMED_PIECE().  REQUEST_STREAMING_UPDATE() is a view pass in
which the representations can update their data pipelines to request a certain
"piece" of the data. REQUEST_PROCESS_STREAMED_PIECE() is called on
representations to handle a "piece" just received by the process. This
separation makes it possible for representations to be agnostic of where the
data is processed and where it is rendered. It's the reposibility of the view
(vtkPVDataDeliveryManager in particular) to deliver the data to the
rendering nodes.

vtkPVDataDeliveryManager doesn't currently support data delivery for streamed
pieces, however. That's on the TODO list.
parent b5ce7caa
......@@ -61,7 +61,7 @@ vtkPVOptions::vtkPVOptions()
this->TellVersion = 0;
this->AMRStreaming = 0;
this->EnableStreaming = 0;
this->UseCudaInterop = 0;
......@@ -298,11 +298,10 @@ void vtkPVOptions::Initialize()
"When specified, the python script is processed symmetrically on all processes.",
vtkPVOptions::PVBATCH);
this->AddBooleanArgument("--amr-streaming", "-amr",
&this->AMRStreaming,
"EXPERIMENTAL: When specified, AMR streaming for volume rendering is "
"enabled",
vtkPVOptions::PVCLIENT | vtkPVOptions::PVSERVER);
this->AddBooleanArgument("--enable-streaming", 0, &this->EnableStreaming,
"EXPERIMENTAL: When specified, view-based streaming is enabled for certain "
"views and representation types.",
vtkPVOptions::ALLPROCESS);
this->AddBooleanArgument("--use-cuda-interop", "-cudaiop",
&this->UseCudaInterop,
......@@ -379,16 +378,6 @@ int vtkPVOptions::PostProcess(int, const char* const*)
}
#endif //PARAVIEW_ALWAYS_SECURE_CONNECTION
if (this->AMRStreaming)
{
vtkErrorMacro("FIXME");
// vtkPVView::SetEnableStreaming(true);
}
else
{
// vtkPVView::SetEnableStreaming(false);
}
return 1;
}
......@@ -538,7 +527,8 @@ void vtkPVOptions::PrintSelf(ostream& os, vtkIndent indent)
os << indent << "SymmetricMPIMode: " << this->SymmetricMPIMode << endl;
os << indent << "ServerURL: "
<< (this->ServerURL? this->ServerURL : "(none)") << endl;
os << indent << "AMRStreaming:" << this->AMRStreaming << endl;
os << indent << "EnableStreaming:" <<
(this->EnableStreaming? "yes" : "no") << endl;
os << indent << "UseCudaInterop" << this->UseCudaInterop << std::endl;
}
......@@ -150,8 +150,9 @@ public:
vtkSetStringMacro(ParaViewDataName);
// Description:
// EXPERIMENTAL: When set, AMR streaming is enabled.
vtkGetMacro(AMRStreaming, int);
// Until streaming becomes mainstream, we enable streaming support by passing
// a command line argument to all processes.
vtkGetMacro(EnableStreaming, int);
// Description:
// When set, use cuda interop feature
......@@ -258,7 +259,7 @@ private:
vtkSetStringMacro(StereoType);
char* StereoType;
int AMRStreaming;
int EnableStreaming;
int UseCudaInterop;
......
......@@ -30,6 +30,9 @@
#==========================================================================
set (Module_SRCS
vtk3DWidgetRepresentation.cxx
vtkAMROutlineRepresentation.cxx
vtkAMRStreamingPriorityQueue.cxx
vtkAMRStreamingVolumeRepresentation.cxx
vtkAMRVolumeRepresentation.cxx
vtkCaveSynchronizedRenderers.cxx
vtkChartRepresentation.cxx
......
/*=========================================================================
Program: ParaView
Module: $RCSfile$
Copyright (c) Kitware, Inc.
All rights reserved.
See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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 "vtkAMROutlineRepresentation.h"
#include "vtkAlgorithmOutput.h"
#include "vtkAMRStreamingPriorityQueue.h"
#include "vtkAppendCompositeDataLeaves.h"
#include "vtkCompositeDataPipeline.h"
#include "vtkCompositePolyDataMapper2.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkOverlappingAMR.h"
#include "vtkPolyData.h"
#include "vtkProperty.h"
#include "vtkPVGeometryFilter.h"
#include "vtkPVLODActor.h"
#include "vtkPVRenderView.h"
#include "vtkPVStreamingMacros.h"
#include "vtkPVTrivialProducer.h"
#include "vtkRenderer.h"
#include <assert.h>
vtkStandardNewMacro(vtkAMROutlineRepresentation);
//----------------------------------------------------------------------------
vtkAMROutlineRepresentation::vtkAMROutlineRepresentation()
{
this->StreamingCapablePipeline = false;
this->InStreamingUpdate = false;
this->RenderedDataProducerIsEmpty = true;
this->PriorityQueue = vtkSmartPointer<vtkAMRStreamingPriorityQueue>::New();
this->RenderedDataProducer= vtkSmartPointer<vtkTrivialProducer>::New();
vtkNew<vtkMultiBlockDataSet> tempData;
this->RenderedDataProducer->SetOutput(tempData.GetPointer());
this->Mapper = vtkSmartPointer<vtkCompositePolyDataMapper2>::New();
this->Mapper->SetInputConnection(this->RenderedDataProducer->GetOutputPort());
this->Actor = vtkSmartPointer<vtkPVLODActor>::New();
this->Actor->SetMapper(this->Mapper);
this->Actor->GetProperty()->SetRepresentationToWireframe();
this->Actor->GetProperty()->SetAmbient(1.0);
this->Actor->GetProperty()->SetDiffuse(0.0);
this->Actor->GetProperty()->SetSpecular(0.0);
this->Actor->SetPickable(0);
}
//----------------------------------------------------------------------------
vtkAMROutlineRepresentation::~vtkAMROutlineRepresentation()
{
}
//----------------------------------------------------------------------------
void vtkAMROutlineRepresentation::SetVisibility(bool val)
{
this->Actor->SetVisibility(val);
this->Superclass::SetVisibility(val);
}
//----------------------------------------------------------------------------
int vtkAMROutlineRepresentation::ProcessViewRequest(
vtkInformationRequestKey* request_type, vtkInformation* inInfo, vtkInformation* outInfo)
{
// always forward to superclass first. Superclass returns 0 if the
// representation is not visible (among other things). In which case there's
// nothing to do.
if (!this->Superclass::ProcessViewRequest(request_type, inInfo, outInfo))
{
return 0;
}
if (request_type == vtkPVView::REQUEST_UPDATE())
{
// Standard representation stuff, first.
// 1. Provide the data being rendered.
vtkPVRenderView::SetPiece(inInfo, this, this->ProcessedData);
// 2. Provide the bounds.
double bounds[6];
this->DataBounds.GetBounds(bounds);
vtkPVRenderView::SetGeometryBounds(inInfo, bounds);
// The only thing extra we need to do here is that we need to let the view
// know that this representation is streaming capable (or not).
vtkPVRenderView::SetStreamable(inInfo, this, this->GetStreamingCapablePipeline());
}
else if (request_type == vtkPVRenderView::REQUEST_STREAMING_UPDATE())
{
if (this->GetStreamingCapablePipeline())
{
// This is a streaming update request, request next piece.
double view_planes[24];
inInfo->Get(vtkPVRenderView::VIEW_PLANES(), view_planes);
if (this->StreamingUpdate(view_planes))
{
// since we indeed "had" a next piece to produce, give it to the view
// so it can deliver it to the rendering nodes.
vtkPVRenderView::SetNextStreamedPiece(
inInfo, this, this->ProcessedPiece);
}
}
}
else if (request_type == vtkPVRenderView::REQUEST_PROCESS_STREAMED_PIECE())
{
vtkDataObject* piece = vtkPVRenderView::GetCurrentStreamedPiece(inInfo, this);
if (piece)
{
assert (this->RenderedDataProducerIsEmpty == false);
vtkStreamingStatusMacro( << this << ": received new piece.");
// merge with what we are already rendering.
vtkNew<vtkAppendCompositeDataLeaves> appender;
appender->SetInputData(0, piece);
appender->AddInputConnection(0,
this->RenderedDataProducer->GetOutputPort());
appender->Update();
this->RenderedDataProducer->SetOutput(
appender->GetOutputDataObject(0));
}
}
else if (request_type == vtkPVView::REQUEST_RENDER())
{
if (this->RenderedDataProducerIsEmpty)
{
vtkStreamingStatusMacro(<< this << ": cloning delivered data.");
vtkAlgorithmOutput* producerPort = vtkPVRenderView::GetPieceProducer(inInfo, this);
vtkAlgorithm* producer = producerPort->GetProducer();
vtkDataObject* clone = producer->GetOutputDataObject(
producerPort->GetIndex())->NewInstance();
clone->ShallowCopy(producer->GetOutputDataObject(producerPort->GetIndex()));
this->RenderedDataProducer->SetOutput(clone);
clone->Delete();
this->RenderedDataProducerIsEmpty = false;
}
}
return 1;
}
//----------------------------------------------------------------------------
int vtkAMROutlineRepresentation::RequestInformation(vtkInformation *rqst,
vtkInformationVector **inputVector,
vtkInformationVector *outputVector)
{
// Determine if the input is streaming capable. A pipeline is streaming
// capable if it provides us with COMPOSITE_DATA_META_DATA() in the
// RequestInformation() pass. It implies that we can request arbitrary blocks
// from the input pipeline which implies stream-ability.
this->StreamingCapablePipeline = false;
if (inputVector[0]->GetNumberOfInformationObjects() == 1)
{
vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
if (inInfo->Has(vtkCompositeDataPipeline::COMPOSITE_DATA_META_DATA()) &&
vtkPVView::GetEnableStreaming())
{
this->StreamingCapablePipeline = true;
}
}
vtkStreamingStatusMacro(
<< this << ": streaming capable input pipeline? "
<< (this->StreamingCapablePipeline? "yes" : "no"));
return this->Superclass::RequestInformation(rqst, inputVector, outputVector);
}
//----------------------------------------------------------------------------
int vtkAMROutlineRepresentation::RequestUpdateExtent(
vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector)
{
if (!this->Superclass::RequestUpdateExtent(request, inputVector,
outputVector))
{
return 0;
}
for (int cc=0; cc < this->GetNumberOfInputPorts(); cc++)
{
for (int kk=0; kk < inputVector[cc]->GetNumberOfInformationObjects(); kk++)
{
vtkInformation* info = inputVector[cc]->GetInformationObject(kk);
if (this->InStreamingUpdate)
{
assert(this->PriorityQueue->IsEmpty() == false);
int cid = static_cast<int>(this->PriorityQueue->Pop());
vtkStreamingStatusMacro(<< this << ": requesting blocks: " << cid);
// Request the next "group of blocks" to stream.
info->Set(vtkCompositeDataPipeline::LOAD_REQUESTED_BLOCKS(), 1);
info->Set(vtkCompositeDataPipeline::UPDATE_COMPOSITE_INDICES(), &cid, 1);
}
else
{
// let the source deliver whatever is the default. What the reader does
// when the downstream doesn't request any particular blocks in poorly
// defined right now. I am assuming the reader will only read the root
// block or down to some user-specified level.
info->Remove(vtkCompositeDataPipeline::LOAD_REQUESTED_BLOCKS());
info->Remove(vtkCompositeDataPipeline::UPDATE_COMPOSITE_INDICES());
}
}
}
return 1;
}
//----------------------------------------------------------------------------
int vtkAMROutlineRepresentation::RequestData(vtkInformation *rqst,
vtkInformationVector **inputVector, vtkInformationVector *outputVector)
{
if (inputVector[0]->GetNumberOfInformationObjects() == 1)
{
vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
if (inInfo->Has(vtkCompositeDataPipeline::COMPOSITE_DATA_META_DATA()) &&
this->GetStreamingCapablePipeline() &&
!this->GetInStreamingUpdate())
{
// Since the representation reexecuted, it means that the input changed
// and we should initialize our streaming.
vtkOverlappingAMR* amr = vtkOverlappingAMR::SafeDownCast(
inInfo->Get(vtkCompositeDataPipeline::COMPOSITE_DATA_META_DATA()));
this->PriorityQueue->Initialize(amr->GetAMRInfo());
}
}
if (inputVector[0]->GetNumberOfInformationObjects() == 1)
{
// Do the streaming independent "transformation" of the data here, in our
// case, generate the outline from the input data.
// To keep things simple here, we don't bother about the "flip-book" caching
// support used for animation playback.
vtkNew<vtkPVGeometryFilter> geomFilter;
geomFilter->SetUseOutline(1);
geomFilter->SetHideInternalAMRFaces(false);
// since we want to show the real data boundaries, we force the filter to
// not use the meta-data.
geomFilter->SetUseNonOverlappingAMRMetaDataForOutlines(false);
vtkOverlappingAMR* input = vtkOverlappingAMR::GetData(inputVector[0], 0);
geomFilter->SetInputData(input);
geomFilter->Update();
if (!this->GetInStreamingUpdate())
{
this->ProcessedData = geomFilter->GetOutputDataObject(0);
this->ProcessedPiece = vtkSmartPointer<vtkMultiBlockDataSet>::New();
double bounds[6];
input->GetBounds(bounds);
this->DataBounds.SetBounds(bounds);
}
else
{
this->DataBounds.Reset();
this->ProcessedPiece = geomFilter->GetOutputDataObject(0);
}
}
else
{
// create an empty dataset. This is needed so that view knows what dataset
// to expect from the other processes on this node.
this->ProcessedData = vtkSmartPointer<vtkMultiBlockDataSet>::New();
this->ProcessedPiece = vtkSmartPointer<vtkMultiBlockDataSet>::New();
this->DataBounds.Reset();
}
if (!this->GetInStreamingUpdate())
{
// when not doing a streaming update, we reset the data that we will render.
// otherwise, we keep on accumulating the data.
vtkNew<vtkMultiBlockDataSet> tempData;
this->RenderedDataProducer->SetOutput(tempData.GetPointer());
this->RenderedDataProducerIsEmpty = true;
}
return this->Superclass::RequestData(rqst, inputVector, outputVector);
}
//----------------------------------------------------------------------------
bool vtkAMROutlineRepresentation::StreamingUpdate(const double view_planes[24])
{
assert(this->InStreamingUpdate == false);
if (!this->PriorityQueue->IsEmpty())
{
this->InStreamingUpdate = true;
vtkStreamingStatusMacro(<< this << ": doing streaming-update.")
// update the priority queue, if needed.
this->PriorityQueue->Update(view_planes);
// This ensure that the representation re-executes.
this->MarkModified();
// Execute the pipeline.
this->Update();
this->InStreamingUpdate = false;
return true;
}
return false;
}
//----------------------------------------------------------------------------
int vtkAMROutlineRepresentation::FillInputPortInformation(
int vtkNotUsed(port), vtkInformation* info)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkOverlappingAMR");
// Saying INPUT_IS_OPTIONAL() is essential, since representations don't have
// any inputs on client-side (in client-server, client-render-server mode) and
// render-server-side (in client-render-server mode).
info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
return 1;
}
//----------------------------------------------------------------------------
bool vtkAMROutlineRepresentation::AddToView(vtkView* view)
{
vtkPVRenderView* rview = vtkPVRenderView::SafeDownCast(view);
if (rview)
{
rview->GetRenderer()->AddActor(this->Actor);
return true;
}
return false;
}
//----------------------------------------------------------------------------
bool vtkAMROutlineRepresentation::RemoveFromView(vtkView* view)
{
vtkPVRenderView* rview = vtkPVRenderView::SafeDownCast(view);
if (rview)
{
rview->GetRenderer()->RemoveActor(this->Actor);
return true;
}
return false;
}
//----------------------------------------------------------------------------
void vtkAMROutlineRepresentation::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
os << indent << "StreamingCapablePipeline: " << this->StreamingCapablePipeline
<< endl;
}
/*=========================================================================
Program: ParaView
Module: $RCSfile$
Copyright (c) Kitware, Inc.
All rights reserved.
See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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.
=========================================================================*/
// .NAME vtkAMROutlineRepresentation - a simple outline representation for AMR
// datasets that supports streaming.
// .SECTION Description
// vtkAMROutlineRepresentation is a simple representation for Overlapping-AMR
// datasets that with streaming capabilities. It demonstrates how a
// representation can exploit streaming capabilities provided by ParaView's
// Render View (vtkPVRenderView).
#ifndef __vtkAMROutlineRepresentation_h
#define __vtkAMROutlineRepresentation_h
#include "vtkPVDataRepresentation.h"
#include "vtkSmartPointer.h" // for smart pointer.
#include "vtkBoundingBox.h" // needed for vtkBoundingBox.
class vtkAMRStreamingPriorityQueue;
class vtkCompositePolyDataMapper2;
class vtkPVLODActor;
class VTKPVCLIENTSERVERCORERENDERING_EXPORT vtkAMROutlineRepresentation :
public vtkPVDataRepresentation
{
public:
static vtkAMROutlineRepresentation* New();
vtkTypeMacro(vtkAMROutlineRepresentation, vtkPVDataRepresentation);
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// Overridden to handle various view passes.
virtual int ProcessViewRequest(vtkInformationRequestKey* request_type,
vtkInformation* inInfo, vtkInformation* outInfo);
// Description:
// Get/Set the visibility for this representation. When the visibility of
// representation of false, all view passes are ignored.
virtual void SetVisibility(bool val);
//BTX
protected:
vtkAMROutlineRepresentation();
~vtkAMROutlineRepresentation();
// Description:
// Adds the representation to the view. This is called from
// vtkView::AddRepresentation(). Subclasses should override this method.
// Returns true if the addition succeeds.
virtual bool AddToView(vtkView* view);
// Description:
// Removes the representation to the view. This is called from
// vtkView::RemoveRepresentation(). Subclasses should override this method.
// Returns true if the removal succeeds.
virtual bool RemoveFromView(vtkView* view);
// Description:
// Fill input port information.
int FillInputPortInformation(int port, vtkInformation* info);
// Description:
// Overridden to check if the input pipeline is streaming capable. This method
// should check if streaming is enabled i.e. vtkPVView::GetEnableStreaming()
// and the input pipeline provides necessary AMR meta-data.
virtual int RequestInformation(vtkInformation *rqst,
vtkInformationVector **inputVector,
vtkInformationVector *outputVector);
// Description:
// Setup the block request. During StreamingUpdate, this will request the
// blocks based on priorities determined by the vtkAMRStreamingPriorityQueue,
// otherwise it doesn't make any specific request. AMR sources can treat the
// absence of specific block request to mean various things. It's expected
// that read only the root block (or a few more) in that case.
virtual int RequestUpdateExtent(vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector);
// Description:
// Generate the outline for the current input.
// When not in StreamingUpdate, this also initializes the priority queue since
// the input AMR may have totally changed, including its structure.
virtual int RequestData(vtkInformation *rqst,
vtkInformationVector **inputVector,
vtkInformationVector *outputVector);
// Description:
// Returns true when the input pipeline supports streaming. It is set in
// RequestInformation().
vtkGetMacro(StreamingCapablePipeline, bool);
// Description:
// Returns true when StreamingUpdate() is being processed.
vtkGetMacro(InStreamingUpdate, bool);
// Description:
// Returns true if this representation has a "next piece" that it streamed.
// This method will update the PriorityQueue using the view planes specified
// and then call Update() on the representation, making it reexecute and
// regenerate the outline for the next "piece" of data.
bool StreamingUpdate(const double view_planes[24]);
// Description:
// This is the data object generated processed by the most recent call to
// RequestData() while not streaming.
// This is non-empty only on the data-server nodes.
vtkSmartPointer<vtkDataObject> ProcessedData;
// Description:
// This is the data object generated processed by the most recent call to
// RequestData() while streaming.
// This is non-empty only on the data-server nodes.
vtkSmartPointer<vtkDataObject> ProcessedPiece;
// Description:
// This is a trivial producer we use to feed data to the rendering pipeline.
// This doesn't need to be a vtkTrivialProducer, we could have just saved the
// data object. However, currently vtkAlgorithm doesn't provide a simple way