经过前几天的学习和分析,发现在vtk中的数据传输部分的执行不知道是不是我没有理解好,还是就是没有执行。因此今天决定回到Paraview层面来看它的整个的并行调度:
/ParaviewCore/ClientSeverCore/Rendering下一些有意思的文件:
vtkPVDataDeliveryManager::这个类管理几何结构的传递(给Rendering)。它被vtkPVRenderView使用去管理把几何结构提取到渲染发生的节点上。这个类帮助我们统一所有的提取各种类型的几何类型数据到所有节点的代码,也包括一些特质,像把提取到所有节点,把数据按组合需求重新划分等。
vtkPVRenderView::对于Paraview与vtkRenderview等效,vtkRenderview控制各种模式下多边形的Paraview渲染的操作。vtkPVRenderview必须实例化在所有的相关的进程中。vtkPVRenderview使用什么进程已经被创建的信息去决定渲染的哪部分发生在哪个进程上。
有一个类vtkObject,这个类需要看一下。
下面是vtkPVRenderView的函数分析;
vtkPVDataDeliveryManager* vtkPVRenderView::GetDeliveryManager():获得这个类中的vtkPVDataDeliveryManager,说明vtkPVDataDeliveryManager是 vtkPVRenderView中用到的一个参数。根据上面它是用来做数据传递的。所以后面数据部分肯定会用到。
vtkPVRenderView::SetUseOffscreenRendering(bool use_offscreen):用来控制是否使用OffscreenRendering。
void vtkPVRenderView::Initialize(unsigned int id):初始化,设置这个view的vtkPVSynchronizedRenderWindows,给其添加RenderWindow,3个Renderer:这个RenderView的renderer,这个的NonCompositedRenderer,还有这个的OrientationWidget的renderer。初始化session。还有父类,参数id标记所有的量,同一个id说明是同一个RenderView的量。初始化了之后设置自己的Identifier为这个id,这样就可以检测是否已经初始化过了。
void vtkPVRenderView::AddRepresentationInternal(vtkDataRepresentation* rep):把所给的Representation注册到DeliveryManager中,并且在ItemMap根据Representation的UniqueIdentifier在其中加上两个item,这两个item的representation都是这个所给的Representation。并执行父类的这个函数。
void vtkPVRenderView::RemoveRepresentationInternal(vtkDataRepresentation* rep):DeliveryManager中取消注册。
void vtkPVRenderView::RegisterPropForHardwareSelection(vtkPVDataRepresentation* repr, vtkProp* prop):把这个prop的id设为最后一个+1,并且设置这个id下的representation为这个repr。其实也就是把prop和representation对应起来。
void vtkPVRenderView::UnRegisterPropForHardwareSelection(vtkPVDataRepresentation* repr, vtkProp* prop):去掉注册
void vtkPVRenderView::AddPropToRenderer(vtkProp* prop):在这个vtkPVRenderView的RenderView中的Renderer中添加这个prop,并且给这个prop中加上这个Renderer。
void vtkPVRenderView::RemovePropFromRenderer(vtkProp* prop):互相去掉
vtkRenderer* vtkPVRenderView::GetRenderer():返回这个RenderView中的Renderer
void vtkPVRenderView::SetActiveCamera(vtkCamera* camera):设置这个RenderView中的Renderer的ActiveCamera和NonCompositedRenderer的Renderer的ActiveCamera。
vtkCamera* vtkPVRenderView::GetActiveCamera():获得ActiveCamera
vtkRenderWindow* vtkPVRenderView::GetRenderWindow():获得这个RenderView的RenderWindow。
void vtkPVRenderView::SetInteractionMode(int mode):如果交互模式与所给模式不一样,首先如果现在的交互模式是INTERACTION_MODE_3D。则设置PreviousParallelProjectionStatus(先前的并行规划的状态为ActiveCamera的ParallelProjection)。然后设置当前交互状态为所给mode。记下修改时间和事件。如果当前交互不存在,返回,然后根据mode值的不同,选择设置他的Interactor的交互风格为5个不同的方式。
void vtkPVRenderView::OnSelectionChangedEvent():获得INTERACTION_MODE_SELECTION模式:this->RubberBandStyle的起始和结束位置。这一般发生在driver(头结点或者客户端)上。数据可能不在这个进程。选择是一个数据选择不是几何形状的选择。执行this->InvokeEvent(vtkCommand::SelectionChangedEvent, ordered_region);
void vtkPVRenderView::OnPolygonSelectionEvent():应该是二维上的,感觉将,每一个Tuple有两个参数。把这个PolygonStyle下的point复制到polygonPointsArray中,然后执行this->InvokeEvent(vtkCommand::SelectionChangedEvent,polygonPointsArray.GetPointer());
void vtkPVRenderView::SelectPoints(int region[4]):根据 region[4]选择FIELD_ASSOCIATION_POINTS
void vtkPVRenderView::SelectCells(int region[4]):根据 region[4]选择FIELD_ASSOCIATION_CELLS
void vtkPVRenderView::Select(int fieldAssociation, int region[4]):如果与PrepareSelect(fieldAssociation)一样,则执行sel.TakeReference(this->Selector->Select(region));这个由vtkPVHardwareSelector下根据region[4]执行GenerateSelection。把相关选择的信息保存到sel,传给PostSelect执行,PostSelect传给FinishSelection(sel执行。
bool vtkPVRenderView::PrepareSelect(int fieldAssociation):选择只在内置和client-server mode下支持。不支持 tile-display or batch modes。这个需要注意一下。
void vtkPVRenderView::PostSelect(vtkSelection* sel):正确的selection应该只是发生在driver进程上,其他的只要渲染所传递的就行了,这样结果才能正确的组合在一起。执行this->FinishSelection(sel);。做这些的时候需要把SynchronizedWindows和SynchronizedRenderers设置为false。做完则MakingSelection = false。感觉这有选择数据的感觉啊,选择数据传给其他的进程。
void vtkPVRenderView::SelectPolygonPoints(int* polygonPoints, vtkIdType arrayLen):执行FIELD_ASSOCIATION_POINTS模式下的SelectPolygon
void vtkPVRenderView::SelectPolygonCells(int* polygonPoints, vtkIdType arrayLen):执行FIELD_ASSOCIATION_CELLS模式下的SelectPolygon
void vtkPVRenderView::SelectPolygon(int fieldAssociation, int* polygonPoints, vtkIdType arrayLen):把相关选择的信息保存到sel,传给PostSelect执行,PostSelect传给FinishSelection(sel执行。
void vtkPVRenderView::FinishSelection(vtkSelection* sel):首先转换本地的prop上的ids到ids以确保当这个selection的发生没有伴随组合时data-server能够理解。例如渲染发生在客户端上。然后继续执行this->SetLastSelection(sel);前面这些函数加起来就是把已经做好的一种选择放在sel中。
void vtkPVRenderView::ResetCameraClippingRange():重置相机边界以保证几何图形在相机范围内。
void vtkPVRenderView::SynchronizeGeometryBounds():设置同步window的边界,并且居中,并且把边界信息传给其他的进程。这个函数应该是用来初始化头结点和其他节点的RenderWindow的一个函数,其中用到了底层的Controller来进行参数的传递,所以这个函数对我们的工作有意义,需要进行测试。 this->SynchronizedWindows->SynchronizeBounds(bounds);
bool vtkPVRenderView::GetLocalProcessDoesRendering(bool using_distributed_rendering):本进程是否在执行渲染。
void vtkPVRenderView::ResetCamera():这个函数在所有进程上执行。首先更新一下,然后设置>RenderView->GetRenderer()->ResetCamera(bounds)。这个bounds是先void vtkPVRenderView::SynchronizeGeometryBounds()得的。最后this->InvokeEvent(vtkCommand::ResetCameraEvent);
void vtkPVRenderView::ResetCamera(double bounds[6]):基本同上。
bool vtkPVRenderView::TestCollaborationCounter():如果不是多客户端则直接返回true。分别获得ParallelController,ClientDataServerController,ClientServerController(应该是render和client的)三个控制器。如果ClientDataServerController!=null,则不满足这种多客户端的模式。如果当前SynchronizedWindows->GetMode()是client,发送给renderserver并对模式进行确认。其他差不太多。显然这应该是一个测试整个结构是否连接顺利的函数,且初始化一样(大致)。我们这个过程应该不用这个。
void vtkPVRenderView::SynchronizeForCollaboration():上一个检测的先使整个所有进程同步。传递stream中使用那种渲染方式等等
void vtkPVRenderView::Update():首先重置bounds中参数分别为vtk的最大和最小。然后设置DistributedRenderingRequired 和NonDistributedRenderingRequired为false。并执行父类vtkPVView的Update()函数。在这些更新后。我们将要对representation进行改变,在这之前,要进行一些参数的设置。如果其中任何一个需要NeedsOrderedCompositing或者RenderEmptyImages,则这两个参数设为true,否则为false。获取所有的representation的size,从而获得最后的local_size,然后把它设置到SynchronizedWindows中。然后设置lod-rendering and remote-rendering。 用:
this->UseLODForInteractiveRender = this->ShouldUseLODRendering(local_size);
this->UseDistributedRenderingForStillRender =this->ShouldUseDistributedRendering(local_size, /*using_lod=*/false);
如果不用UseLODForInteractiveRender,则this->UseDistributedRenderingForInteractiveRender =this->UseDistributedRenderingForStillRender;初始化this->StillRenderProcesses = this->InteractiveRenderProcesses =vtkPVSession::CLIENT;如果:
in_tile_display_mode || in_cave_mode ||this->UseDistributedRenderingForStillRender或者in_tile_display_mode || in_cave_mode ||this->UseDistributedRenderingForInteractiveRender。则 this->StillRenderProcesses = vtkPVSession::CLIENT_AND_SERVERS;this->InteractiveRenderProcesses = vtkPVSession::CLIENT_AND_SERVERS;然后执行this->SynchronizeGeometryBounds();在多进程中同步bounds。
void vtkPVRenderView::CopyViewUpdateOptions(vtkPVRenderView* otherView):复制其他View的UpdateOptions到本PVRenderView中
void vtkPVRenderView::UpdateLOD():updateLOD几何形状。首先设置 this->RequestInformation->Set(LOD_RESOLUTION(), this->LODResolution);如果使用UseOutlineForLODRendering,在this->RequestInformation->Set(USE_OUTLINE_FOR_LOD(), 1);。然后执行 this->CallProcessViewRequest(
vtkPVView::REQUEST_UPDATE_LOD(), this->RequestInformation, this->ReplyInformationVector);然后根据可视的数据的数据大小设置 local_size,并且设置进SynchronizedWindows中。然后执行this->UseDistributedRenderingForInteractiveRender =this->ShouldUseDistributedRendering(local_size, /*using_lod=*/true);和根据模式确认 this->InteractiveRenderProcesses = vtkPVSession::CLIENT_AND_SERVERS;
void vtkPVRenderView::StillRender():渲染函数,先设置需要的更新率为0.002.然后执行内部的这个RenderView的预渲染。然后执行this->Render(false, false);这个函数就是从客户端接收到的渲染的stream,然后执行这个函数。这个代表的意思是普通的渲染,不是交互的渲染。
void vtkPVRenderView::InteractiveRender():交互渲染,执行的是this->Render(true, false);更新率是5.0。
void vtkPVRenderView::Render(bool interactive, bool skip_rendering):关键渲染函数。如果同步的窗口模式不是客户端,且采用分布式渲染的StillRender或者采用分布式InteractiveRender,则如果我们现在在执行MakeingSelection,则不用执行this->SynchronizeForCollaboration();否则则要执行。
然后在每一个render上执行重置剪切面。这个过程不需要进行进程通讯,在每个render上直接执行即可。然后获取当下的bool in_tile_display_mode和 bool in_cave_mode。如果采用in_cave_mode但又没有远程渲染,则报错。
在这种StillRender下,我们采用SetLossLessCompression(!interactive),压缩不高。bool use_lod_rendering只能是在交互模式下且是采用这个模式才能使用这种渲染方式。采用这种模式,那么我们就在this->RequestInformation->Set(USE_LOD(), 1);加上这个。然后设置use_distributed_rendering的模式,是交互式还是直渲染模式。 bool use_ordered_compositing = this->GetUseOrderedCompositing();。是否要组合,如果要组合,说明要完成数据的划分。:
this->Internals->DeliveryManager->RedistributeDataForOrderedCompositing(use_lod_rendering);
this->SynchronizedRenderers->SetKdTree(this->Internals->DeliveryManager->GetKdTree());
先通过划分函数设置Kdtree,然后把它放置如同步Renderer之中。做好划分,在运行时,就可以直接按照划分的方式进行同步渲染。
然后执行this->SynchronizedRenderers->SetRenderEmptyImages(this->GetRenderEmptyImages());一直不理解这是什么意思,难道是执行渲染空的图像?
this->CallProcessViewRequest(vtkPVView::REQUEST_RENDER(),this->RequestInformation, this->ReplyInformationVector);(这个函数需要注意,渲染,数据分发什么的可能就发生在这?这个就跟基本过程中使数据映射到representation,然后再映射到renderview上的过程一样)这个程序是根据可用的几何资源渲染每一个representation。这是一个传递,使representations获得一个机会去获得现在的可用的所代表的数据并且试着去渲染它
然后获取图像的衰减系数。并且设置上一次渲染的是否使用this->UsedLODForLastRender = use_lod_rendering;
只要是采用use_distributed_rendering || in_tile_display_mode || in_cave_mode这三种中的任何一种时,就要采用并行渲染。当采用in_tile_display_mode || in_cave_mode时,要把数据复制到所有的进程上。
this->SynchronizedWindows->BeginRender(this->GetIdentifier());开始做渲染begin,使所有的进程都共用一个view。
只有在自己自己是Driver(头结点),没有获得渲染事件传播且是分布式渲染或者采用的三种并行模式中的其他两种时,才使用自己的RenderWindow进行渲染。如果我们现在没有在做MakingSelection,则把 this->SynchronizedWindows->SetEnabled(false);
this->SynchronizedRenderers->SetEnabled(false);
void vtkPVRenderView::Deliver(int use_lod,unsigned int size, unsigned int *representation_ids):在多客户端模式下,做数据划分,首先要确保TestCollaborationCounter(),所有进程在相同的状态。然后执行this->SynchronizeForCollaboration();,最后才做数据划分。
int vtkPVRenderView::GetDataDistributionMode(bool use_remote_rendering):获取数据分布式的模式。如果是cave模式则直接复制数据,如果是远程渲染且使用in_tile_display_mode,则传递并且把数据复制,如果是普通分布式渲染,则直接传递数据。如果不采用远程渲染,且采用in_tile_display_mode,则直接复制,否则直接搜集数据。
void vtkPVRenderView::SetPiece(vtkInformation* info,vtkPVDataRepresentation* repr, vtkDataObject* data,unsigned long trueSize/*=0*/):分片?(也属于数据划分里面的)
vtkAlgorithmOutput* vtkPVRenderView::GetPieceProducer(vtkInformation* info,vtkPVDataRepresentation* repr):获取这片数据的产生者。
void vtkPVRenderView::SetPieceLOD(vtkInformation* info, vtkPVDataRepresentation* repr, vtkDataObject* data):使用LOD分片
vtkAlgorithmOutput* vtkPVRenderView::GetPieceProducerLOD(vtkInformation* info,vtkPVDataRepresentation* repr):获取LOD下的片制造者
void vtkPVRenderView::MarkAsRedistributable(vtkInformation* info, vtkPVDataRepresentation* repr, bool value/*=true*/):把某个representation设置为需要再分的
void vtkPVRenderView::SetStreamable(vtkInformation* info, vtkPVDataRepresentation* repr, bool val):设置是否要通过流传播数据
void vtkPVRenderView::SetOrderedCompositingInformation(vtkInformation* info, vtkPVDataRepresentation* repr, vtkExtentTranslator* translator,const int whole_extents[6], const double origin[3], const double spacing[3]):设置组合信息
void vtkPVRenderView::SetDeliverToAllProcesses(vtkInformation* info,vtkPVDataRepresentation* repr, bool clone):设置把数据传输到所有进程上。
void vtkPVRenderView::SetDeliverToClientAndRenderingProcesses( vtkInformation* info, vtkPVDataRepresentation* repr, bool deliver_to_client, bool gather_before_delivery):设置传输数据到客户端,并且渲染进程。
void vtkPVRenderView::SetGeometryBounds(vtkInformation* info, double bounds[6], vtkMatrix4x4* matrix /*=NULL*/):设置几何机构边界
void vtkPVRenderView::SetNextStreamedPiece(vtkInformation* info, vtkPVDataRepresentation* repr, vtkDataObject* piece):设置下一片流数据
vtkDataObject* vtkPVRenderView::GetCurrentStreamedPiece( vtkInformation* info, vtkPVDataRepresentation* repr):获取现在流中那片的数据
void vtkPVRenderView::SetRequiresDistributedRendering(vtkInformation* info, vtkPVDataRepresentation* vtkNotUsed(repr), bool value, bool for_lod):设置是否需要分布式渲染
bool vtkPVRenderView::ShouldUseDistributedRendering(double geometry_size, bool using_lod):设置是否需要使用分布式渲染,阈值小于几何结构的size,则要
bool vtkPVRenderView::ShouldUseLODRendering(double geometry_size):设置是否需要使用分布式LOD渲染,阈值小于几何结构的size,则要
bool vtkPVRenderView::GetUseOrderedCompositing():获取现在是否使用了OrderedCompositing
bool vtkPVRenderView::GetRenderEmptyImages():获取是否使用了EmptyImages
void vtkPVRenderView::SetUseLightKit(bool use):设置使用SetUseLightKit
void vtkPVRenderView::SetLightSwitch(bool enable):设置是否使用LightSwitch
bool vtkPVRenderView::GetLightSwitch():获取是否使用LightSwitch
void vtkPVRenderView::UpdateCenterAxes():更新中心轴。坐标系的操作
double vtkPVRenderView::GetZbufferDataAtPoint(int x, int y):获取某一点的Zbuffer,如果是 in_tile_display_mode或者in_cave_mode,则直接根据自己的Renderw获取即可,如果是分布式渲染,则根据同步window:SynchronizedWindows,通过数据传输去所有进程中获取。
void vtkPVRenderView::StreamingUpdate(const double view_planes[24]):更新流,先写入RequestInformation,然后调用this->CallProcessViewRequest(vtkPVRenderView::REQUEST_STREAMING_UPDATE(), this->RequestInformation, this->ReplyInformationVector);
void vtkPVRenderView::DeliverStreamedPieces(unsigned int size, unsigned int *representation_ids):计划是取片,然后只是给representation作为下一片,representation能够决定要怎么处理它,包括把他加入现有的数据结构。然后如果是分布式渲染,则执行 this->CallProcessViewRequest(vtkPVRenderView::REQUEST_PROCESS_STREAMED_PIECE(),this->RequestInformation, this->ReplyInformationVector);
void vtkPVRenderView::ConfigureCompressor(const char* configuration):设置压缩,执行this->SynchronizedRenderers->ConfigureCompressor(configuration);
void vtkPVRenderView::InvalidateCachedSelection():无效的缓存选择,执行this->Selector->InvalidateCachedSelection();
void vtkPVRenderView::SetOrientationAxesInteractivity(bool v):交互时轴的取向,执行this->OrientationWidget->SetEnabled(v);好像就是我们看到的下面那个轴
void vtkPVRenderView::SetOrientationAxesLabelColor(double r, double g, double b):设置轴的颜色
后面都是设置一些参数。就不详细看了。下面我们来根据实验来看看vtkPVDataDeliveryManager:
首先我对vtkPVRenderView中的参数进行了一些测试,发现:
189::use_distributed_rendring::true
189::use_ordered_compositing::false
189::this->GetRenderWindow()->Render();
190::use_distributed_rendring::true
190::use_ordered_compositing::false
190::this->GetRenderWindow()->Render();这里非常奇怪啊,怎么190也用自己的RenderWindow啊,这不正常啊,我们对190的那几个判断参数进行一下测试:
190::RenderEventPropagation::false,这说明190没有接到渲染事件传播。这就很奇怪了。我们需要检测这个参数是在什么时候什么地方设置的。
在这之前,我们首先来看一看use_ordered_compositing为什么为false
经过测试发现:189::this->NeedsOrderedCompositing::false,这在Upadate()函数中有设置,说明没有一个info中有NEED_ORDERED_COMPOSITING()。可是这个参数是在哪设置的呢?我们可以试一下D3Filter,看这个Filter用没用:
但是发现在这个filter下,也是一样的189::this->NeedsOrderedCompositing::false依然。根据这个参数的注释,这个参数应该是由Representation中发出的。所以之后我们可以去看看这里面的事。可是他究竟运行了那个representation,我们还不知道。
接下来我们看看this->SynchronizedRenderers->SetKdTree(NULL);这之中发生的事情:这之中是传给IceT库,tree的信息。而这里是NULL,所以就啥也没有。
190::vtkPVSynchronizedRenderWindows::SatelliteStartRender
189::vtkPVSynchronizedRenderWindows::RootStartRender
证明他们确实存在这样的关系。也采用了分布式渲染。感觉现在确实是需要在representation中看看。我们可以看到,这些是在189::this->GetRenderWindow()->Render();之后,vtkPolyDataMapper:;Render
之前发生的,也就是说这些应该是在这个阶段坐下操作。这里的root节点有this->RenderEventPropagation,我们看看执行了吗?实验证明没有执行。
这里我们还发现了在头结点上:189::vtkPVSynchronizedRenderWindows::RootStartRender::ClientServerController::true;190::vtkPVSynchronizedRenderWindows::SatelliteStartRender::ParallelController::true
说明在189上他首先要根据客户端的RenderWindow的情况来确定自己的,然后再传给190,190接受之后,把自己的根据接收到的设置。且在vtkPVRenderView中,我们是先执行:vtkPVRenderView::Update,再执行数据转移,最后再执行vtkPVRenderView:;Render。
这个数据的转移发生在哪呢,怀疑是在某个representation中。