Paraview Parallel模式下的文件解析(五)

上次依然发现没有得到我们需要的结果,原因所在有现在还是不是很清楚后台运行的一个流程,而Paraview中后台服务器的运行是由客户端的代理管理程序控制的,所以现在我们回到客户端的并行方面的程序看一看。

首先我们来看vtkSMViewProxy

这个类是所有的view代理的基类。一个view代理抽象了获取一个或者多个Representation代理的逻辑并且显示他们在视点上(例如vtkRenderWindow)。这个类或许会直接用于views的view代理在GUI层次用来做所有的渲染工作。相关的vtk类是vtkView。

vtkView* vtkSMViewProxy::GetClientSideView():获得客户端这边的View对象。

void vtkSMViewProxy::CreateVTKObjects():如果已经创建则,直接返回。否则则先运行父类的 this->Superclass::CreateVTKObjects();。然后如果是原型,则不需要继续创建。接着如果这个对象还没创建,返回。如果上面都符合,则传命令流到服务器端,执行void vtkPVRenderView::Initialize(unsigned int id)。其中参数id为 static_cast(this->GetGlobalID())。然后给这个对象加上Observer, vtkPVView::ViewTimeChangedEvent,this, &vtkSMViewProxy::ViewTimeChanged);感觉意思就是事件为vtkPVView::ViewTimeChangedEvent,如果这个函数执行了,那么执行这个类的vtkSMViewProxy::ViewTimeChanged。(还是不是这个意思?:是那个函数执行了,这个函数就不执行了?)

void vtkSMViewProxy::ViewTimeChanged():根据vtkSMPropertyHelper helper1(this, "Representations")获得其下所有vtkSMRepresentation,然后对于其下面的每一个vtkSMRepresentation,也执行 repr->ViewTimeChanged();。然后vtkSMPropertyHelper helper2(this, "HiddenRepresentations", true);获得其下所有HiddenRepresentations,同样执行 repr->ViewTimeChanged();。

void vtkSMViewProxy::StillRender():首先检测上下文是否准备好了渲染。没有则直接返回。然后直接设置 int interactive = 0;加上this->InvokeEvent(vtkCommand::StartEvent, &interactive);然后执行this->GetSession()->PrepareProgress();准备好session。接着执行: this->Update(); vtkTypeUInt32 render_location = this->PreRender(interactive==1);(这个在子类vtkSMRenderViewProxy中执行,下面会讲)。然后就是调用服务器端的StillRender。(我们这里一般是vtkSMRenderViewProxy调用vtkPVRenderView)。最后this->PostRender(interactive==1);。

void vtkSMViewProxy::InteractiveRender():与上面基本一样,就是一个全分辨率渲染,一个交互渲染。

void vtkSMViewProxy::Update():为了防止在多客户端的情况下出现竞争状态。采用一个特有的方式。任何影响并行通讯的ivar将会在相同的ExecuteStream()调用中用客户端的值覆盖。这样保证两个客户端不会进入竞争,虽然这会增加信息的长度,但是整体收益更好。这个函数中主要就是获得这个客户端的pvview。然后调用服务器端下的vtkPVRenderView的“SetUseCache”和"Update"方法。然后更新其下的所有Representation和传递更新数据。

vtkSMRepresentationProxy* vtkSMViewProxy::CreateDefaultRepresentation( vtkSMProxy* proxy, int outputPort):把传递的proxy强制转换成vtkSMSourceProxy* producer,执行const char* representationType =this->GetRepresentationType(producer, outputPort);获取Representation的类型。然后通过 p.TakeReference(pxm->NewProxy("representations", representationType));创建一个Representation代理对象,并把他的所有权转给p,然后转化为vtkSMRepresentationProxy*。最后把其注册为当前的vtkPVRenderView的Representation。

const char* vtkSMViewProxy::GetRepresentationType(vtkSMSourceProxy* producer, int outputPort):这个函数很明显,就是如果有producer的hint,则根据hint创建,没有则根据默认的DefaultRepresentationName返回,如果其中有prototype,同意添加。最后返回的就是一种类型的Representation,它是根据名字定义的。

bool vtkSMViewProxy::CanDisplayData(vtkSMSourceProxy* producer, int outputPort)根据producer和outputPort计算相对应产生的Representation的类型,如果类型存在,则pxm->GetPrototypeProxy("representations", type) != NULL获取Representation对应的原型代理,存在则表示这个Representation可以显示。

vtkSMRepresentationProxy* vtkSMViewProxy::FindRepresentation( vtkSMSourceProxy* producer, int outputPort):找到与outputPort对应的Representation。

int vtkSMViewProxy::ReadXMLAttributes(vtkSMSessionProxyManager* pm, vtkPVXMLElement* element):根据element设置this->SetDefaultRepresentationName(repr_name);

创建一个内部类vtkRendererSaveInfo

vtkImageData* vtkSMViewProxy::CaptureWindow(int magnification):创建一个window返回回去,一般是返回null,如果对window有transparency透明度的需求,则做些设定。否则直接返回return this->CaptureWindowSingle(magnification);。

vtkSMViewProxy::vtkRendererSaveInfo* vtkSMViewProxy::PrepareRendererBackground(vtkRenderer* renderer, double r, double g, double b, bool save):获取当前renderer的信息,如果以他的信息来设置渲染背景,则返回其信息,否则返回null。

void vtkSMViewProxy::RestoreRendererBackground(vtkRenderer* renderer,vtkRendererSaveInfo* info):通过info去除渲染背景赋值到renderer中。

vtkImageData* vtkSMViewProxy::CaptureWindowSingle(int magnification):获取window当前的图形(截图)。向后台传递命令,先执行PrepareForScreenshot,然后vtkImageData* capture = this->CaptureWindowInternal(magnification);再执行CleanupAfterScreenshot。这两个方法在vtkPVRenderView中。如果获取了,设置其范围和位置。然后返回。这个函数的感觉就是VTK在后台运行然后把所产生的图像传会给Paraview显示的函数。

int vtkSMViewProxy::WriteImage(const char* filename, const char* writerName, int magnification):输出当前图像。

后面的都是工具函数,在这就不细讲了。

接着我们来看它的子类:vtkSMRenderViewProxy

这个类在它父类的基础上增加了一些方法:

bool vtkSMRenderViewProxy::LastRenderWasInteractive():判断上一次渲染是否为交互交互渲染。

bool vtkSMRenderViewProxy::IsSelectionAvailable():Selection是否可用。(这个是一种操作)

const char* vtkSMRenderViewProxy::IsSelectVisibleCellsAvailable():多客户端模式,cave模式和数据服务器和渲染服务器分开的模式都不能支持selection。如果渲染窗口不存在,颜色深度不够也都不支持selection。

const char* vtkSMRenderViewProxy::IsSelectVisiblePointsAvailable():直接调用 this->IsSelectVisibleCellsAvailable();

void vtkSMRenderViewProxy::Update():this->NeedsUpdateLOD |= this->NeedsUpdate;this->Superclass::Update();设置标记NeedsUpdateLOD并且执行父类的Update。

void vtkSMRenderViewProxy::UpdateLOD():如果需要更新,执行后台vtkRenderView::UpdateLOD方法

bool vtkSMRenderViewProxy::StreamingUpdate(bool render_if_needed):不支持多客户端模式。调用后台vtkRenderView::"StreamingUpdate"方法,参数:   vtkClientServerStream::InsertArray(planes, 24)。获取是否在服务器端有什么数据进行了传输。如果有并且需要渲染,则执行this->StillRender();。

vtkTypeUInt32 vtkSMRenderViewProxy::PreRender(bool interactive):renderview中执行render的前置函数,然后再执行服务器端的StillRender,在这个函数中,如果采用LOD完成交互渲染,则执行this->UpdateLOD();接着完成数据的传输: this->DeliveryManager->Deliver(interactive);并且返回当前运行的进程是不是交互。

void vtkSMRenderViewProxy::PostRender(bool interactive):获取相机对象,并且更新属性信息,然后执行:

 this->SynchronizeCameraProperties();
 this->Superclass::PostRender(interactive);

void vtkSMRenderViewProxy::SynchronizeCameraProperties():同步相机属性。

接下来是一些获取各种view的参数的不详细讲

void vtkSMRenderViewProxy::CreateVTKObjects():先运行父类的this->Superclass::CreateVTKObjects();(就是运行服务器端初始化函数)。然后设置这边客户端的camera,如果交互,设置交互对象为自身。然后给这个加上两个Observer,添加SelectionChangedEvent和ResetCameraEvent。如果采用GetUseStereoRendering(),那么初始化tereoCapableWindow和StereoRender。

如果这次渲染是自动mpi的会话,则remote_rendering_available = false;,否则为true。如果采用远程渲染,则看能否OpenDisplay,不能依然设置为false。最后如果为false,需要传递命令告诉所有服务器关闭远程渲染。

最后this->DeliveryManager->SetViewProxy(this);设置数据传输的view代理为这个。

const char* vtkSMRenderViewProxy::GetRepresentationType(vtkSMSourceProxy* producer, int outputPort):获取输入对象的Representation类型。

void vtkSMRenderViewProxy::ZoomTo(vtkSMProxy* representation):根据所给的representation首先获取数据的输入数据,然后获取输入的边界。检测Bounds是否初始化。然后获取Representation中的:"Position","Orientation","Scale"。然后对整个坐标进行变换,设置正确的边界包围盒。最后让相机根据这个边界重新设置参数: this->ResetCamera(bounds);

void vtkSMRenderViewProxy::ResetCamera():重置相机

void vtkSMRenderViewProxy::ResetCamera(double xmin, double xmax,double ymin, double ymax,double zmin, double zmax)

void vtkSMRenderViewProxy::ResetCamera(double bounds[6]):如果还没有对vtk进行初始化,那么执行this->CreateVTKObjects();。否则调用服务器端  "ResetCamera"参数: vtkClientServerStream::InsertArray(bounds, 6);

void vtkSMRenderViewProxy::MarkDirty(vtkSMProxy* modifiedProxy)

vtkSMRepresentationProxy* vtkSMRenderViewProxy::Pick(int x, int y):面选择。

vtkSMRepresentationProxy* vtkSMRenderViewProxy::PickBlock(int x,int y,unsigned int &flatIndex):块选择(多块数据中选择每一块对应的数据)

中间一系列的应该都是界面上的一些功能,像把面显示转换为点显示,选网格,多边形等等。不细讲

void vtkSMRenderViewProxy::CaptureWindowInternalRender():获取当前是用什么模式的渲染,交互还是直接渲染。

vtkImageData* vtkSMRenderViewProxy::CaptureWindowInternal(int magnification):获取window信息。就是客户端的那个现实给我们看的那个窗口图像。首先关掉交互buffer,然后执行渲染。之后获取现在的信息赋值到显示窗口上。然后执行vtkWindowToImageFilter的Update。最后获取要现实的图像。把它返回。感觉这个有点像会在前端中的窗口中调用。渲染开始(apply)就开始调用这个函数,然后就最后获取显示的图像,相识到window上。



下面我们来总结一下我们现在知道的一个过程。我们可以看到:首先用户界面调用vtkSMRenderViewProxy下的:CaptureWindowInternal(int magnification),然后调用CaptureWindowInternalRender(),在这之中是采用StillRender还是InteractiveRender。执行StillRender则继续调用:vtkSMViewProxy::StillRender()。在这个函数中,首先调用void vtkSMRenderViewProxy::Update(),先计算是否用UpdateLOD。然后直接调用父类:void vtkSMViewProxy::Update()。在父类中,这个函数是通过调用后台Paraview中的vtkPVRenderView下的:setUseCache,参数为这之中的use_cache。然后再执行Update。并且在一层层去更新Representation。接着执行PreRender。在PreRender中,首先确立如果交互UpdateLOD。否则执行数据划分传输:this->DeliveryManager->Deliver(interactive);这里也就是执行服务器端的vtkPVRenderView::Deliver()。最后执行vtkPVRenderView下的StillRender。



所以我们可以看到数据划分就是在StillRender之前一步做的。调用顺序就是这么一个过程。下面我们来看:

vtkSMDataDeliveryManager

这个类是对服务器端vtkPVDataDeliveryManager这个类的sm封装。他管理对vtkPVDataDeliveryManager实例化方法的调用。当每一次render的调用。vtkSMRenderViewProxy都调用vtkPVDataDeliveryManager::Deliver()去保证需要传输的几何图形都已经传输了。Update-Deliver-Render的调用划分链可以在未来扩展这样的流框架。

void vtkSMDataDeliveryManager::SetViewProxy(vtkSMViewProxy* viewproxy):设置这个传输管理对象所作用的view。

void vtkSMDataDeliveryManager::Deliver(bool interactive):首先确定use_lod和use_distributed_rendering,根据是否交互和是否使用分布式渲染,确定三种delivery_type。从这里我们就可以看到use_lod就是在交互的时候把图形虚化,降低分辨率,从而实现交互的速度更快。然后获取keys_to_deliver。调用后台的vtkRenderView下的:"Deliver"函数。参数为static_cast(use_lod)和static_cast(keys_to_deliver.size()) vtkClientServerStream::InsertArray(&keys_to_deliver[0], static_cast(keys_to_deliver.size()))

bool vtkSMDataDeliveryManager::DeliverStreamedPieces():Deliver()这个函数依赖于在客户端调用服务器端关于需要在服务器端获取数据的Representation。当数据更新的时候,Deliver()能够决定在客户端的Representation对象确实需要更新(这根据vtkPVDataRepresentation子类的更新的抑制习惯)。

但是对于streaming,只有服务器端的Representation更新,因此客户端将没有这些在流中有片数据的Representations的信息。因此按一下规则做:

1.要求数据服务器提供哪些Representations有一些片数据reader的信息

2.对于那些Representations需要streamed pieces 

具体就是先执行this->ViewProxy->GatherInformation(info.GetPointer(), vtkPVSession::DATA_SERVER);获取数据服务端信息。然后执行info->GetKeys(keys_to_deliver);。最后调用vtkRenderView下的 "DeliverStreamedPieces"函数,参数为static_cast(keys_to_deliver.size())vtkClientServerStream::InsertArray(&keys_to_deliver[0], static_cast(keys_to_deliver.size()))







你可能感兴趣的:(Paraview Parallel模式下的文件解析(五))