/*========================================================================= Program: ParaView Module: vtkPVSynchronizedRenderWindows.cxx 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 "vtkPVSynchronizedRenderWindows.h" #include "vtkBoundingBox.h" #include "vtkCommand.h" #include "vtkDebugLeaks.h" #include "vtkMultiProcessStream.h" #include "vtkObjectFactory.h" #include "vtkProcessModule.h" #include "vtkPVAxesWidget.h" #include "vtkPVServerInformation.h" #include "vtkPVSession.h" #include "vtkRendererCollection.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkSelectionSerializer.h" #include "vtkSmartPointer.h" #include "vtkSocketController.h" #include "vtkTilesHelper.h" #include "vtkTuple.h" #include #include #include #include #include #include class vtkPVSynchronizedRenderWindows::vtkInternals { public: typedef std::pair, vtkTuple > RendererInfo; typedef std::vector VectorOfRenderers; struct RenderWindowInfo { int Size[2]; int Position[2]; unsigned long StartRenderTag; unsigned long EndRenderTag; vtkSmartPointer RenderWindow; VectorOfRenderers Renderers; RenderWindowInfo() { this->Size[0] = this->Size[1] = 0; this->Position[0] = this->Position[1] = 0; this->StartRenderTag = this->EndRenderTag = 0; } }; struct CallbackInfo { unsigned long ParallelHandle; unsigned long ClientServerHandle; unsigned long ClientDataServerHandle; CallbackInfo() { this->ParallelHandle = 0; this->ClientServerHandle = 0; this->ClientDataServerHandle = 0; } }; std::vector RMICallbacks; typedef std::map RenderWindowsMap; RenderWindowsMap RenderWindows; unsigned int GetKey(vtkRenderWindow* win) { RenderWindowsMap::iterator iter; for (iter = this->RenderWindows.begin(); iter != this->RenderWindows.end(); ++iter) { if (iter->second.RenderWindow == win) { return iter->first; } } return 0; } // Updates the viewport for all the renderers in the collection. void UpdateViewports(VectorOfRenderers& renderers, const double viewport[4]) { double dx = (viewport[2] - viewport[0]); double dy = (viewport[3] - viewport[1]); VectorOfRenderers::iterator iter; for (iter = renderers.begin(); iter != renderers.end(); ++iter) { // HACK: This allows us to skip changing the viewport for orientation // widget for now. if ((*iter).first->GetLayer() != vtkPVAxesWidget::RendererLayer) { const vtkTuple &rViewport = iter->second; (*iter).first->SetViewport( viewport[0] + dx * rViewport[0], // xmin viewport[1] + dy * rViewport[1], // ymin viewport[0] + dx * rViewport[2], // xmax viewport[1] + dy * rViewport[3] // ymax ); } } } bool ExpandTowardMin(unsigned int me, const int* my_size, int* my_pos, int dimension) { int cur_dim_min_offset = dimension; int cur_dim_max_offset = dimension+2; int other_dim_min_offset = (dimension+1)%2; int other_dim_max_offset = other_dim_min_offset + 2; int my_extents[4] = {my_pos[0], my_pos[1], my_pos[0] + my_size[0] -1, my_pos[1] + my_size[1] - 1}; int &position = my_pos[dimension]; position = 0; RenderWindowsMap::iterator iter; for (iter = this->RenderWindows.begin(); iter != this->RenderWindows.end(); ++iter) { if (iter->first == me) { continue; } // Only interested in boxes entirely to our left (or top) const int *size = iter->second.Size; const int *pos = iter->second.Position; int extents[4] = {pos[0], pos[1], pos[0] + size[0] -1, pos[1] + size[1] - 1}; if (extents[cur_dim_max_offset] > my_extents[cur_dim_min_offset] || extents[other_dim_min_offset] > my_extents[other_dim_max_offset] || extents[other_dim_max_offset] < my_extents[other_dim_min_offset]) { continue; } if (position <= extents[cur_dim_max_offset]) { position = extents[cur_dim_max_offset] + 1; } } return (position != my_extents[dimension]); } bool ExpandTop(unsigned int me, const int* my_size, int* my_pos) { return this->ExpandTowardMin(me, my_size, my_pos, 1); } bool ExpandLeft(unsigned int me, const int* my_size, int* my_pos) { return this->ExpandTowardMin(me, my_size, my_pos, 0); } bool ExpandTowardMax(unsigned int me, const int *max, int* my_size, const int *my_pos, int dimension) { int cur_dim_min_offset = dimension; int cur_dim_max_offset = dimension+2; int other_dim_min_offset = (dimension+1)%2; int other_dim_max_offset = other_dim_min_offset + 2; int my_extents[4] = {my_pos[0], my_pos[1], my_pos[0] + my_size[0] -1, my_pos[1] + my_size[1] - 1}; int &size = my_size[dimension]; size = (max[dimension] - my_extents[cur_dim_min_offset]); RenderWindowsMap::iterator iter; for (iter = this->RenderWindows.begin(); iter != this->RenderWindows.end(); ++iter) { if (iter->first == me) { continue; } // Only interested in boxes entirely to our right (or bottom) const int *_size = iter->second.Size; const int *pos = iter->second.Position; int extents[4] = {pos[0], pos[1], pos[0] + _size[0] -1, pos[1] + _size[1] - 1}; if (extents[cur_dim_min_offset] <= my_extents[cur_dim_max_offset] || extents[other_dim_min_offset] > my_extents[other_dim_max_offset] || extents[other_dim_max_offset] < my_extents[other_dim_min_offset]) { continue; } int my_extent_max = my_extents[cur_dim_min_offset] + size - 1; if ( my_extent_max >= extents[cur_dim_min_offset]) { size = extents[cur_dim_min_offset] - my_extents[cur_dim_min_offset]; } } return (size != (my_extents[cur_dim_max_offset] - my_extents[cur_dim_min_offset] + 1)); } bool ExpandRight(unsigned int me, const int *max, int* my_size, const int *my_pos) { return this->ExpandTowardMax(me, max, my_size, my_pos, 0); } bool ExpandBottom(unsigned int me, const int *max, int* my_size, const int *my_pos) { return this->ExpandTowardMax(me, max, my_size, my_pos, 1); } vtkSmartPointer SharedRenderWindow; unsigned long SharedWindowStartRenderTag; unsigned long SharedWindowEndRenderTag; unsigned int ActiveId; }; //---------------------------------------------------------------------------- class vtkPVSynchronizedRenderWindows::vtkObserver : public vtkCommand { public: static vtkObserver* New() { vtkObserver* obs = new vtkObserver(); obs->Target = NULL; return obs; } virtual void Execute(vtkObject *ocaller, unsigned long eventId, void *) { vtkRenderWindow* renWin = vtkRenderWindow::SafeDownCast(ocaller); if (this->Target && this->Target->GetEnabled()) { switch (eventId) { case vtkCommand::StartEvent: this->Target->HandleStartRender(renWin); break; case vtkCommand::EndEvent: this->Target->HandleEndRender(renWin); break; case vtkCommand::AbortCheckEvent: this->Target->HandleAbortRender(renWin); break; } } } vtkPVSynchronizedRenderWindows* Target; }; //---------------------------------------------------------------------------- namespace { void RenderRMI(void *localArg, void *remoteArg, int remoteArgLength, int vtkNotUsed(remoteProcessId)) { vtkMultiProcessStream stream; stream.SetRawData(reinterpret_cast(remoteArg), remoteArgLength); unsigned int id = 0; stream >> id; vtkPVSynchronizedRenderWindows* self = reinterpret_cast(localArg); self->Render(id); } void GetZBufferValue(void *localArg, void *remoteArg, int remoteArgLength, int vtkNotUsed(remoteProcessId)) { vtkMultiProcessStream stream; stream.SetRawData(reinterpret_cast(remoteArg), remoteArgLength); unsigned int id = 0; int x, y; stream >> id >> x >> y; vtkPVSynchronizedRenderWindows* self = reinterpret_cast(localArg); self->OnGetZBufferValue(id, x, y); } }; vtkCxxSetObjectMacro(vtkPVSynchronizedRenderWindows, ClientDataServerController, vtkMultiProcessController); //---------------------------------------------------------------------------- vtkPVSynchronizedRenderWindows* vtkPVSynchronizedRenderWindows::New( vtkPVSession* session/*=NULL*/) { #ifdef VTK_DEBUG_LEAKS vtkDebugLeaks::ConstructClass("vtkPVSynchronizedRenderWindows"); #endif // Ensure vtkProcessModule is setup correctly. vtkProcessModule* pm = vtkProcessModule::GetProcessModule(); if (!pm) { vtkGenericWarningMacro( "vtkPVSynchronizedRenderWindows cannot be used in the current\n" "setup."); return NULL; } vtkPVSession* activeSession = session? session : vtkPVSession::SafeDownCast(pm->GetActiveSession()); if (!activeSession) { vtkGenericWarningMacro( "vtkPVSynchronizedRenderWindows cannot be created with a valid session"); return NULL; } return new vtkPVSynchronizedRenderWindows(activeSession); } //---------------------------------------------------------------------------- vtkPVSynchronizedRenderWindows::vtkPVSynchronizedRenderWindows( vtkPVSession* activeSession /*NULL*/) : Session(activeSession) { this->Mode = INVALID; this->ClientServerController = 0; this->ClientDataServerController = 0; this->ParallelController = 0; this->ClientServerRMITag = 0; this->ClientServerGetZBufferValueRMITag = 0; this->ParallelRMITag = 0; this->Internals = new vtkInternals(); this->Internals->ActiveId = 0; this->Internals->SharedWindowStartRenderTag = 0; this->Internals->SharedWindowEndRenderTag = 0; this->Observer = vtkObserver::New(); this->Observer->Target = this; this->Enabled = false; // we no longer support render even propagation. This leads to unnecessary // complications since it results in code have different paths on client and // servers. this->RenderEventPropagation = false; this->RenderOneViewAtATime = false; vtkProcessModule* pm = vtkProcessModule::GetProcessModule(); int processtype = pm->GetProcessType(); switch (processtype) { case vtkProcessModule::PROCESS_BATCH: this->Mode = BATCH; this->RenderOneViewAtATime = true; break; case vtkProcessModule::PROCESS_RENDER_SERVER: case vtkProcessModule::PROCESS_SERVER: this->Mode = RENDER_SERVER; break; case vtkProcessModule::PROCESS_DATA_SERVER: this->Mode = DATA_SERVER; break; case vtkProcessModule::PROCESS_CLIENT: this->Mode = BUILTIN; if (this->Session->IsA("vtkSMSessionClient")) { this->Mode = CLIENT; } break; } // Setup the controllers for the communication. switch (this->Mode) { case BUILTIN: // nothing to do. break; case DATA_SERVER: this->SetClientDataServerController( this->Session->GetController(vtkPVSession::CLIENT)); break; case BATCH: this->SetParallelController(vtkMultiProcessController::GetGlobalController()); if (pm->GetSymmetricMPIMode()) { this->RenderEventPropagation = false; } break; case RENDER_SERVER: this->SetParallelController(vtkMultiProcessController::GetGlobalController()); // this will be NULL on satellites. this->SetClientServerController( this->Session->GetController(vtkPVSession::CLIENT)); break; case CLIENT: this->SetClientServerController( this->Session->GetController(vtkPVSession::RENDER_SERVER_ROOT)); this->SetClientDataServerController( this->Session->GetController(vtkPVSession::DATA_SERVER_ROOT)); if (this->ClientDataServerController == this->ClientServerController) { this->SetClientDataServerController(0); } break; default: vtkErrorMacro("Invalid process type."); abort(); } if (this->ClientDataServerController != NULL) { // ClientDataServerController is non-null on pvdataserver and client in // data-server/render-server mode. // synchronize tile-display parameters viz. tile-dimensions between // data-server and render-server. if (this->Mode == CLIENT) { int tile_dims[2], tile_mullions[2]; bool tile_display_mode = this->GetTileDisplayParameters(tile_dims, tile_mullions); vtkMultiProcessStream stream; stream << (tile_display_mode? 1 : 0) << tile_dims[0] << tile_dims[1] << tile_mullions[0] << tile_mullions[1]; this->ClientDataServerController->Send(stream, 1, SYNC_TILE_DISPLAY_PARAMATERS); } else if (this->Mode == DATA_SERVER) { vtkMultiProcessStream stream; this->ClientDataServerController->Receive(stream, 1, SYNC_TILE_DISPLAY_PARAMATERS); int tile_dims[2], tile_mullions[2], tile_display_mode; stream >> tile_display_mode >> tile_dims[0] >> tile_dims[1] >> tile_mullions[0] >> tile_mullions[1]; if (tile_display_mode == 1) { this->Session->GetServerInformation()->SetTileDimensions(tile_dims); this->Session->GetServerInformation()->SetTileMullions(tile_mullions); } } } } //---------------------------------------------------------------------------- vtkPVSynchronizedRenderWindows::~vtkPVSynchronizedRenderWindows() { this->SetClientServerController(0); this->SetClientDataServerController(0); this->SetParallelController(0); if (this->Internals->SharedRenderWindow) { if (this->Internals->SharedWindowStartRenderTag) { this->Internals->SharedRenderWindow->RemoveObserver( this->Internals->SharedWindowStartRenderTag); } if (this->Internals->SharedWindowEndRenderTag) { this->Internals->SharedRenderWindow->RemoveObserver( this->Internals->SharedWindowEndRenderTag); } } delete this->Internals; this->Internals = 0; this->Observer->Target = NULL; this->Observer->Delete(); this->Observer = NULL; } //---------------------------------------------------------------------------- vtkPVSession* vtkPVSynchronizedRenderWindows::GetSession() { return this->Session; } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::GetLocalProcessIsDriver() { switch (this->Mode) { case BUILTIN: return true; case CLIENT: return true; case RENDER_SERVER: return false; case BATCH: if (this->ParallelController && this->ParallelController->GetLocalProcessId() == 0) { return true; } case DATA_SERVER: default: return false; } } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::SetClientServerController( vtkMultiProcessController* controller) { if (this->ClientServerController == controller) { return; } if (this->ClientServerController && this->ClientServerRMITag) { this->ClientServerController->RemoveRMICallback(this->ClientServerRMITag); } if (this->ClientServerController && this->ClientServerGetZBufferValueRMITag) { this->ClientServerController->RemoveRMICallback( this->ClientServerGetZBufferValueRMITag); } vtkSetObjectBodyMacro( ClientServerController, vtkMultiProcessController, controller); this->ClientServerRMITag = 0; this->ClientServerGetZBufferValueRMITag = 0; // Only the RENDER_SERVER processes needs to listen to SYNC_MULTI_RENDER_WINDOW_TAG // triggers from the client. if (controller && this->Mode == RENDER_SERVER) { // Only one RMICallback for PVSynchronizedRenderWindow can live at a time controller->RemoveAllRMICallbacks(SYNC_MULTI_RENDER_WINDOW_TAG); controller->RemoveAllRMICallbacks(GET_ZBUFFER_VALUE_TAG); // Attach the one this->ClientServerRMITag = controller->AddRMICallback(::RenderRMI, this, SYNC_MULTI_RENDER_WINDOW_TAG); this->ClientServerGetZBufferValueRMITag = controller->AddRMICallback(::GetZBufferValue, this, GET_ZBUFFER_VALUE_TAG); } } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::SetParallelController( vtkMultiProcessController* controller) { if (this->ParallelController == controller) { return; } if (this->ParallelController && this->ParallelRMITag) { this->ParallelController->RemoveRMICallback(this->ParallelRMITag); } vtkSetObjectBodyMacro( ParallelController, vtkMultiProcessController, controller); this->ParallelRMITag = 0; // Only satellites listen to the SYNC_MULTI_RENDER_WINDOW_TAG // triggers from the root. if (controller && (this->Mode == RENDER_SERVER || this->Mode == BATCH) && controller->GetLocalProcessId() > 0) { this->ParallelRMITag = controller->AddRMICallback(::RenderRMI, this, SYNC_MULTI_RENDER_WINDOW_TAG); } } //---------------------------------------------------------------------------- vtkRenderWindow* vtkPVSynchronizedRenderWindows::NewRenderWindow() { switch (this->Mode) { case DATA_SERVER: { // we could very return a dummy window here. vtkRenderWindow* window = vtkRenderWindow::New(); window->SetWindowName("ParaView Data-Server"); return window; } case BUILTIN: case CLIENT: { // client always creates new window for each view in the multi layout // configuration. vtkRenderWindow* window = vtkRenderWindow::New(); window->DoubleBufferOn(); window->AlphaBitPlanesOn(); window->SetWindowName("ParaView"); window->SetSize(400, 400); // set some default size for the window. return window; } case RENDER_SERVER: case BATCH: // all views share the same render window. if (!this->Internals->SharedRenderWindow) { vtkRenderWindow* window = vtkRenderWindow::New(); window->DoubleBufferOn(); window->AlphaBitPlanesOn(); std::ostringstream name_stream; if (this->Mode == BATCH) { name_stream << "ParaView (batch)"; } else { name_stream << "ParaView Server"; } if (this->ParallelController->GetNumberOfProcesses() > 1) { name_stream << " #" << this->ParallelController->GetLocalProcessId(); } window->SetWindowName(name_stream.str().c_str()); // SwapBuffers should be ON only on root node in BATCH mode // or when operating in tile-display mode. bool swap_buffers = false; swap_buffers |= (this->Mode == BATCH && this->ParallelController->GetLocalProcessId() == 0); int not_used[2]; swap_buffers |= this->GetTileDisplayParameters(not_used, not_used); swap_buffers |= this->GetIsInCave(); window->SetSwapBuffers(swap_buffers? 1 : 0); //window->SetSwapBuffers(1); // for debugging FIXME. this->Internals->SharedRenderWindow.TakeReference(window); this->Internals->SharedRenderWindow->SetSize(400, 400); // set some default size for the window. } else { // cout << "Using shared render window" << endl; } this->Internals->SharedRenderWindow->Register(this); return this->Internals->SharedRenderWindow; case INVALID: abort(); } return NULL; } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::AddRenderWindow( unsigned int id, vtkRenderWindow* renWin) { assert(renWin != NULL && id != 0); if (this->Internals->RenderWindows.find(id) != this->Internals->RenderWindows.end() && this->Internals->RenderWindows[id].RenderWindow != NULL) { vtkErrorMacro("ID for render window already in use: " << id); return; } this->Internals->RenderWindows[id].RenderWindow = renWin; unsigned long start_tag = 0, end_tag = 0; if (!renWin->HasObserver(vtkCommand::StartEvent, this->Observer)) { start_tag = renWin->AddObserver(vtkCommand::StartEvent, this->Observer); } if (!renWin->HasObserver(vtkCommand::EndEvent, this->Observer)) { end_tag = renWin->AddObserver(vtkCommand::EndEvent, this->Observer); } if (renWin == this->Internals->SharedRenderWindow) { if (start_tag) { this->Internals->SharedWindowStartRenderTag = start_tag; } if (end_tag) { this->Internals->SharedWindowStartRenderTag = end_tag; } } else { this->Internals->RenderWindows[id].StartRenderTag = start_tag; this->Internals->RenderWindows[id].EndRenderTag = end_tag; } } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::RemoveRenderWindow(unsigned int id) { vtkInternals::RenderWindowsMap::iterator iter = this->Internals->RenderWindows.find(id); if (iter != this->Internals->RenderWindows.end()) { if (iter->second.StartRenderTag) { iter->second.RenderWindow->RemoveObserver(iter->second.StartRenderTag); } if (iter->second.EndRenderTag) { iter->second.RenderWindow->RemoveObserver(iter->second.EndRenderTag); } this->Internals->RenderWindows.erase(iter); } } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::AddRenderer(unsigned int id, vtkRenderer* renderer) { double viewport[4] = {0, 0, 1, 1 }; this->AddRenderer(id, renderer, viewport); } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::AddRenderer(unsigned int id, vtkRenderer* renderer, const double viewport[4]) { this->Internals->RenderWindows[id].Renderers.push_back( vtkInternals::RendererInfo(renderer, vtkTuple(viewport))); } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::UpdateRendererViewport(unsigned int id, vtkRenderer* renderer, const double viewport[4]) { this->Internals->RenderWindows[id].Renderers.push_back( vtkInternals::RendererInfo(renderer, vtkTuple(viewport))); vtkInternals::RenderWindowsMap::iterator iter = this->Internals->RenderWindows.find(id); if (iter == this->Internals->RenderWindows.end()) { return false; } vtkInternals::VectorOfRenderers::iterator iterRen; for (iterRen = iter->second.Renderers.begin(); iterRen != iter->second.Renderers.end(); ++iterRen) { if (iterRen->first.GetPointer() == renderer) { iterRen->second = vtkTuple(viewport); return true; } } return false; } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::RemoveAllRenderers(unsigned int id) { vtkInternals::RenderWindowsMap::iterator iter = this->Internals->RenderWindows.find(id); if (iter != this->Internals->RenderWindows.end()) { iter->second.Renderers.clear(); } } //---------------------------------------------------------------------------- vtkRenderWindow* vtkPVSynchronizedRenderWindows::GetRenderWindow(unsigned int id) { vtkInternals::RenderWindowsMap::iterator iter = this->Internals->RenderWindows.find(id); if (iter != this->Internals->RenderWindows.end()) { return iter->second.RenderWindow; } return NULL; } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::SetWindowSize(unsigned int id, int width, int height) { this->Internals->RenderWindows[id].Size[0] = width; this->Internals->RenderWindows[id].Size[1] = height; // Make sure none of the dimension is 0 width = width ? width : 10; height = height ? height : 10; if (this->Mode == BUILTIN || this->Mode == CLIENT) { vtkRenderWindow* window = this->GetRenderWindow(id); if (window && (window->GetSize()[0] != width || window->GetSize()[1] != height) ) { window->SetSize(width, height); } } } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::SetWindowPosition(unsigned int id, int px, int py) { this->Internals->RenderWindows[id].Position[0] = px; this->Internals->RenderWindows[id].Position[1] = py; } //---------------------------------------------------------------------------- const int *vtkPVSynchronizedRenderWindows::GetWindowSize(unsigned int id) { vtkInternals::RenderWindowsMap::iterator iter = this->Internals->RenderWindows.find(id); if (iter != this->Internals->RenderWindows.end()) { return iter->second.Size; } return NULL; } //---------------------------------------------------------------------------- const int *vtkPVSynchronizedRenderWindows::GetWindowPosition(unsigned int id) { vtkInternals::RenderWindowsMap::iterator iter = this->Internals->RenderWindows.find(id); if (iter != this->Internals->RenderWindows.end()) { return iter->second.Position; } return NULL; } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::UpdateRendererDrawStates(unsigned int id) { if (this->Internals->SharedRenderWindow == NULL) { // If there's no shared render window, we don't need to hide any renders // since each view is rendering in a separate render-window. return; } vtkInternals::RenderWindowsMap::iterator iter = this->Internals->RenderWindows.find(id); if (iter == this->Internals->RenderWindows.end()) { return; } std::set to_enable; vtkInternals::VectorOfRenderers::iterator iterRen; for (iterRen = iter->second.Renderers.begin(); iterRen != iter->second.Renderers.end(); ++iterRen) { to_enable.insert(iterRen->first.GetPointer()); } // disable all other renderers. vtkRendererCollection* renderers = iter->second.RenderWindow->GetRenderers(); renderers->InitTraversal(); while (vtkRenderer* ren = renderers->GetNextItem()) { if (to_enable.find(ren) != to_enable.end()) { ren->DrawOn(); } else { ren->DrawOff(); } } } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::Render(unsigned int id) { // cout << "Rendering: " << id << endl; vtkInternals::RenderWindowsMap::iterator iter = this->Internals->RenderWindows.find(id); if (iter == this->Internals->RenderWindows.end()) { return; } // FIXME: When root node tries to communicate to the satellites the active // id, there's no clean way of determining the active id since on root node // the render window is shared among all views. Hence, we have this hack :(. this->Internals->ActiveId = id; iter->second.RenderWindow->Render(); this->Internals->ActiveId = 0; // cout << "Done Rendering: " << id << endl; } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::HandleStartRender(vtkRenderWindow* renWin) { // This method is called when a render window starts rendering. This is called // on all processes. The response is different on all the processes based on // the mode/configuration. switch (this->Mode) { case CLIENT: this->ClientStartRender(renWin); break; case RENDER_SERVER: case BATCH: if (this->ParallelController->GetLocalProcessId() == 0) { // root node. this->RootStartRender(renWin); } else { this->SatelliteStartRender(renWin); } break; case BUILTIN: case DATA_SERVER: default: return; } } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::HandleEndRender(vtkRenderWindow*) { switch (this->Mode) { case CLIENT: this->ClientServerController->Barrier(); break; case RENDER_SERVER: if (this->ParallelController->GetLocalProcessId() == 0) { this->ClientServerController->Barrier(); } break; default: return; } } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::ClientStartRender(vtkRenderWindow* renWin) { // In client-server mode, the client needs to collect the window layouts and // then the active window specific parameters. this->Internals->ActiveId = this->Internals->GetKey(renWin); if (this->RenderEventPropagation) { // Tell the server-root to start rendering. vtkMultiProcessStream stream; stream << this->Internals->ActiveId; std::vector data; stream.GetRawData(data); this->ClientServerController->TriggerRMIOnAllChildren( &data[0], static_cast(data.size()), SYNC_MULTI_RENDER_WINDOW_TAG); } // when this->RenderEventPropagation, we assume that the server activates the // correct render window somehow. vtkMultiProcessStream stream; // Pass in the information about the layout for all the windows. // TODO: This gets called when rendering each render window. However, this // information does not necessarily get invalidated that frequently. Can we be // smart about it? this->SaveWindowAndLayout(renWin, stream); this->ClientServerController->Send(stream, 1, 22222); this->UpdateWindowLayout(); this->Internals->ActiveId = 0; } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::BeginRender(unsigned int id) { this->Internals->ActiveId = id; // BeginRender() is needed to be explicitly called in cases where there's a // SharedRenderWindow. if (this->Internals->SharedRenderWindow) { // BUG #14280 and BUG #13797. // When vtkPVSynchronizedRenderWindows is enabled, the // vtkPVSynchronizedRenderWindows will take care for updating the layout of // all render windows and renderer at the start of render. // However, in cases when the vtkPVSynchronizedRenderWindows is not enabled // e.g. chart-views or other views that don't do parallel rendering (except // in tile-display mode), we still need to relay out the windows and // activate correct renderers. This piece of code takes care of that. if (!this->GetEnabled() && this->GetLocalProcessIsDriver()) { this->UpdateWindowLayout(); } // Ensure the right renderers are visible in shared windows. this->UpdateRendererDrawStates(this->Internals->ActiveId); } } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::RootStartRender(vtkRenderWindow* renWin) { if (this->ClientServerController) { // * Get window layout from the server. $CODE_GET_LAYOUT_AND_UPDATE$ vtkMultiProcessStream stream; this->ClientServerController->Receive(stream, 1, 22222); // Load the layout for all the windows from the client. this->LoadWindowAndLayout(renWin, stream); } this->ShinkGaps(); // * Ensure layout i.e. all renders have correct viewports and hide inactive // renderers. this->UpdateWindowLayout(); if (this->ParallelController->GetNumberOfProcesses() <= 1) { return; } if (this->RenderEventPropagation) { // * Tell the satellites to start rendering. vtkMultiProcessStream stream; stream << this->Internals->ActiveId; std::vector data; stream.GetRawData(data); this->ParallelController->TriggerRMIOnAllChildren( &data[0], static_cast(data.size()), SYNC_MULTI_RENDER_WINDOW_TAG); } // * Send the layout and window params to the satellites. vtkMultiProcessStream stream; // Pass in the information about the layout for all the windows. // TODO: This gets called when rendering each render window. However, this // information does not necessarily get invalidated that frequently. Can we be // smart about it? this->SaveWindowAndLayout(renWin, stream); this->ParallelController->Broadcast(stream, 0); } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::SatelliteStartRender( vtkRenderWindow* renWin) { // * Get window layout from the server. $CODE_GET_LAYOUT_AND_UPDATE$ if (this->ParallelController) { vtkMultiProcessStream stream; this->ParallelController->Broadcast(stream, 0); // Load the layout for all the windows from the root. this->LoadWindowAndLayout(renWin, stream); } // * Ensure layout i.e. all renders have correct viewports and hide inactive // renderers. this->UpdateWindowLayout(); } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::SaveWindowAndLayout( vtkRenderWindow* window, vtkMultiProcessStream& stream) { int full_size[2] = {0, 0}; stream << static_cast(this->Internals->RenderWindows.size()); vtkInternals::RenderWindowsMap::iterator iter; for (iter = this->Internals->RenderWindows.begin(); iter != this->Internals->RenderWindows.end(); ++iter) { const int *actual_size = iter->second.Size; const int *position = iter->second.Position; full_size[0] = full_size[0] > (position[0] + actual_size[0])? full_size[0] : position[0] + actual_size[0]; full_size[1] = full_size[1] > (position[1] + actual_size[1])? full_size[1] : position[1] + actual_size[1]; stream << iter->first << position[0] << position[1] << actual_size[0] << actual_size[1]; } // Now push the full size. stream << full_size[0] << full_size[1]; // Now save the window's tile scale and tile-viewport. int tileScale[2]; double tileViewport[4]; window->GetTileScale(tileScale); window->GetTileViewport(tileViewport); stream << tileScale[0] << tileScale[1] << tileViewport[0] << tileViewport[1] << tileViewport[2] << tileViewport[3] << window->GetDesiredUpdateRate(); } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::LoadWindowAndLayout( vtkRenderWindow* window, vtkMultiProcessStream& stream) { unsigned int number_of_windows = 0; stream >> number_of_windows; if (number_of_windows != static_cast( this->Internals->RenderWindows.size())) { vtkErrorMacro("Mismatch is render windows on different processes. " "Aborting for debugging purposes."); abort(); } for (unsigned int cc=0; cc < number_of_windows; cc++) { int actual_size[2]; int position[2]; unsigned int key; stream >> key >> position[0] >> position[1] >> actual_size[0] >> actual_size[1]; vtkInternals::RenderWindowsMap::iterator iter = this->Internals->RenderWindows.find(key); if (iter == this->Internals->RenderWindows.end()) { vtkErrorMacro("Don't know anything about windows with key: " << key); continue; } iter->second.Size[0] = actual_size[0]; iter->second.Size[1] = actual_size[1]; iter->second.Position[0] = position[0]; iter->second.Position[1] = position[1]; } // Now load the full size. int full_size[2]; stream >> full_size[0] >> full_size[1]; // Now load the window's tile scale and tile-viewport. // tile-scale and viewport are overloaded. They are used when rendering large // images as well as when rendering in tile-display mode. The code here // handles the case when rendering large images. int tileScale[2]; double tileViewport[4]; double desiredUpdateRate; stream >> tileScale[0] >> tileScale[1] >> tileViewport[0] >> tileViewport[1] >> tileViewport[2] >> tileViewport[3] >> desiredUpdateRate; window->SetTileScale(tileScale); window->SetTileViewport(tileViewport); window->SetDesiredUpdateRate(desiredUpdateRate); } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::UpdateWindowLayout() { int full_size[2] = {0, 0}; vtkInternals::RenderWindowsMap::iterator iter; if (this->RenderOneViewAtATime) { iter = this->Internals->RenderWindows.find(this->Internals->ActiveId); if (iter != this->Internals->RenderWindows.end()) { iter->second.RenderWindow->SetSize(iter->second.Size); double viewport[4] = {0, 0, 1, 1}; this->Internals->UpdateViewports( iter->second.Renderers, viewport); } return; } // Compute full_size. for (iter = this->Internals->RenderWindows.begin(); iter != this->Internals->RenderWindows.end(); ++iter) { const int *actual_size = iter->second.Size; const int *position = iter->second.Position; full_size[0] = full_size[0] > (position[0] + actual_size[0])? full_size[0] : position[0] + actual_size[0]; full_size[1] = full_size[1] > (position[1] + actual_size[1])? full_size[1] : position[1] + actual_size[1]; } switch (this->Mode) { case CLIENT: for (iter = this->Internals->RenderWindows.begin(); iter != this->Internals->RenderWindows.end(); ++iter) { //const int *actual_size = iter->second.Size; //const int *position = iter->second.Position; // This class only supports full-viewports. double viewport[4] = {0, 0, 1, 1}; this->Internals->UpdateViewports( iter->second.Renderers, viewport); } break; case RENDER_SERVER: case BATCH: { // If we are in tile-display mode, we should update the tile-scale // and tile-viewport for the render window. That is required for the camera // as well as for the annotations to show correctly. int tile_dims[2], tile_mullions[2]; bool in_tile_display_mode = this->GetTileDisplayParameters(tile_dims, tile_mullions); bool in_cave_mode = this->GetIsInCave(); if (in_tile_display_mode) { if (vtksys::SystemTools::GetEnv("PV_ICET_WINDOW_BORDERS")) { this->Internals->SharedRenderWindow->SetSize(400, 400); } else { this->Internals->SharedRenderWindow->SetFullScreen(1); } // TileScale and TileViewport must be setup on render window correctly // so that 2D props show up correctly in tile display mode. double tile_viewport[4]; vtkTilesHelper* helper = vtkTilesHelper::New(); helper->SetTileDimensions(tile_dims); helper->SetTileMullions(tile_mullions); helper->SetTileWindowSize(this->Internals->SharedRenderWindow->GetActualSize()); helper->GetNormalizedTileViewport(NULL, this->ParallelController->GetLocalProcessId(), tile_viewport); helper->Delete(); this->Internals->SharedRenderWindow->SetTileScale(tile_dims); this->Internals->SharedRenderWindow->SetTileViewport(tile_viewport); } else if (in_cave_mode) { // Check if a custom window geometry was requested int *geometry = NULL; bool fullscreen = true; bool showborders = false; if (this->ParallelController) { int idx = this->ParallelController->GetLocalProcessId(); fullscreen = this->Session->GetServerInformation()->GetFullScreen(idx); showborders = this->Session->GetServerInformation()->GetShowBorders(idx); if (!fullscreen) { geometry = this->Session->GetServerInformation()->GetGeometry(idx); // If the geometry has not been defined, it will be 0 0 0 0. Unset the // geometry pointer in this case. if (geometry[0] <= 0 && geometry[1] <= 0 && geometry[2] <= 0 && geometry[3] <= 0) { geometry = NULL; } } int stereoType = this->Session->GetServerInformation()->GetStereoType(idx); if (stereoType != -1) { this->Internals->SharedRenderWindow->SetStereoRender(stereoType!=0); if (stereoType > 0) { this->Internals->SharedRenderWindow->SetStereoType(stereoType); } } } this->Internals->SharedRenderWindow->SetBorders(showborders ? 1 : 0); // Preserve old behavior for PV_ICET_WINDOW_BORDERS env var if (vtksys::SystemTools::GetEnv("PV_ICET_WINDOW_BORDERS")) { this->Internals->SharedRenderWindow->SetSize(400, 400); } else { if (fullscreen) { this->Internals->SharedRenderWindow->SetFullScreen(1); } else { // Use the specified geometry int x = geometry ? geometry[0] : 0; int y = geometry ? geometry[1] : 0; int w = geometry ? geometry[2] : 400; int h = geometry ? geometry[3] : 400; this->Internals->SharedRenderWindow->SetFullScreen(0); this->Internals->SharedRenderWindow->SetPosition(x, y); this->Internals->SharedRenderWindow->SetSize(w, h); } } } else { // NOTE: if you want to render a higher resolution image on the server, // you can very easily do that simply set that size here. Just ensure // that the aspect ratio remains the same. this->Internals->SharedRenderWindow->SetSize(full_size); //this->Internals->SharedRenderWindow->SetPosition(0, 0); } // Iterate over all (logical) windows and set the viewport on the // renderers to reflect the position and size of the actual window on the // client side. for (iter = this->Internals->RenderWindows.begin(); iter != this->Internals->RenderWindows.end(); ++iter) { const int *actual_size = iter->second.Size; const int *position = iter->second.Position; // This class only supports full-viewports. double viewport[4]; viewport[0] = position[0]/static_cast(full_size[0]); viewport[1] = position[1]/static_cast(full_size[1]); viewport[2] = (position[0] + actual_size[0])/ static_cast(full_size[0]); viewport[3] = (position[1] + actual_size[1])/ static_cast(full_size[1]); // As far as window-positions go, (0,0) is top-left corner, while for // viewport (0, 0) is bottom-left corner. So we flip the Y viewport. viewport[1] = 1.0 - viewport[1]; viewport[3] = 1.0 - viewport[3]; double temp = viewport[1]; viewport[1] = viewport[3]; viewport[3] = temp; // This viewport is the viewport for the renderers treating the all the // tiles as one large display. //cout << "Current Viewport:" << viewport[0] // << ", " << viewport[1] << ", " << viewport[2] // << ", " << viewport[3] << endl; this->Internals->UpdateViewports( iter->second.Renderers, viewport); } } break; case BUILTIN: case DATA_SERVER: case INVALID: abort(); } } //---------------------------------------------------------------------------- // We use the following approach: // "Top-left corner for every box is moved up-and-left till it intersects // another box" // This works well for the way ParaView splits view. void vtkPVSynchronizedRenderWindows::ShinkGaps() { bool something_expanded; int max_size[2]; do { something_expanded = false; max_size[0] = max_size[1] = 0; vtkInternals::RenderWindowsMap::iterator iter; for (iter = this->Internals->RenderWindows.begin(); iter != this->Internals->RenderWindows.end(); ++iter) { const int *size = iter->second.Size; int *position = iter->second.Position; if (this->Internals->ExpandLeft(iter->first, size, position)) { something_expanded = true; } if (this->Internals->ExpandTop(iter->first, size, position)) { something_expanded = true; } if (max_size[0] < position[0] + size[0]-1) { max_size[0] = position[0] + size[0]-1; } if (max_size[1] < position[1] + size[1]-1) { max_size[1] = position[1] + size[1]-1; } } } while (something_expanded); int temp[2]; if (!this->GetTileDisplayParameters(temp, temp)) { return; } // The above code can result in small gaps at the // very ends (bottom/right) in some configurations. We expand those gaps only // in tile-display mode, since otherwise it messes up the aspect ratio and // would end up delivering image with wrong aspect ratio of images sent to the // client. vtkInternals::RenderWindowsMap::iterator iter; for (iter = this->Internals->RenderWindows.begin(); iter != this->Internals->RenderWindows.end(); ++iter) { int *size = iter->second.Size; const int *position = iter->second.Position; this->Internals->ExpandRight(iter->first, max_size, size, position); this->Internals->ExpandBottom(iter->first, max_size, size, position); } } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::GetIsInCave() { vtkPVServerInformation* server_info = this->Session->GetServerInformation(); int temp[2]; if (!this->GetTileDisplayParameters(temp, temp)) { return server_info->GetNumberOfMachines() > 0; } return false; } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::GetTileDisplayParameters( int tile_dims[2], int tile_mullions[2]) { vtkPVServerInformation* info = this->Session->GetServerInformation(); tile_dims[0] = info->GetTileDimensions()[0]; tile_dims[1] = info->GetTileDimensions()[1]; bool in_tile_display_mode = (tile_dims[0] > 0 || tile_dims[1] > 0); tile_dims[0] = (tile_dims[0] == 0)? 1 : tile_dims[0]; tile_dims[1] = (tile_dims[1] == 0)? 1 : tile_dims[1]; info->GetTileMullions(tile_mullions); return in_tile_display_mode; } //---------------------------------------------------------------------------- namespace { template T vtkEvaluateReductionOperation(T val0, T val1, vtkPVSynchronizedRenderWindows::StandardOperations operation) { switch (operation) { case vtkPVSynchronizedRenderWindows::MAX_OP: return val0 > val1? val0 : val1; case vtkPVSynchronizedRenderWindows::MIN_OP: return val0 < val1? val0 : val1; case vtkPVSynchronizedRenderWindows::SUM_OP: return val0 + val1; } return val0; } } //---------------------------------------------------------------------------- template bool vtkPVSynchronizedRenderWindows::ReduceTemplate(T& size, vtkPVSynchronizedRenderWindows::StandardOperations operation) { // handle trivial case. if (this->Mode == BUILTIN || this->Mode == INVALID) { return true; } vtkMultiProcessController* parallelController = vtkMultiProcessController::GetGlobalController(); vtkMultiProcessController* c_rs_controller = this->GetClientServerController(); // c_ds_controller is non-null only in client-dataserver-renderserver // configuratrions. vtkMultiProcessController* c_ds_controller = this->GetClientDataServerController(); assert(c_ds_controller == NULL || c_ds_controller != c_rs_controller); // The strategy is reduce the value to client then broadcast it out to // render-server and data-server. if (parallelController) { T result = size; parallelController->Reduce(&size, &result, 1, operation, 0); size = result; } // on pvdataserver/pvrenderserver/pvserver/pvbatch, we now have collected the // size-sum on root node. switch (this->Mode) { case CLIENT: { if (c_ds_controller) { T other_size; c_ds_controller->Receive(&other_size, 1, 1, 41232); size = vtkEvaluateReductionOperation(size, other_size, operation); } if (c_rs_controller) { T other_size; c_rs_controller->Receive(&other_size, 1, 1, 41232); size = vtkEvaluateReductionOperation(size, other_size, operation); } if (c_ds_controller) { c_ds_controller->Send(&size, 1, 1, 41232); } if (c_rs_controller) { c_rs_controller->Send(&size, 1, 1, 41232); } } break; case DATA_SERVER: // both can't be set on a server process. if (c_ds_controller) { c_ds_controller->Send(&size, 1, 1, 41232); c_ds_controller->Receive(&size, 1, 1, 41232); } break; case RENDER_SERVER: if (c_rs_controller) { c_rs_controller->Send(&size, 1, 1, 41232); c_rs_controller->Receive(&size, 1, 1, 41232); } break; default: assert(c_ds_controller==NULL && c_rs_controller == NULL); } if (parallelController) { parallelController->Broadcast(&size, 1, 0); } return true; } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::SynchronizeSize(double& size) { return this->ReduceTemplate(size, SUM_OP); } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::SynchronizeSize(unsigned int& size) { return this->ReduceTemplate(size, SUM_OP); } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::Reduce( vtkIdType& value, vtkPVSynchronizedRenderWindows::StandardOperations operation) { return this->ReduceTemplate(value, operation); } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::SynchronizeBounds(double bounds[6]) { // handle trivial case. if (this->Mode == BUILTIN || this->Mode == INVALID) { return true; } vtkMultiProcessController* parallelController = vtkMultiProcessController::GetGlobalController(); vtkMultiProcessController* c_rs_controller = this->GetClientServerController(); // c_ds_controller is non-null only in client-dataserver-renderserver // configuratrions. vtkMultiProcessController* c_ds_controller = this->GetClientDataServerController(); assert(c_ds_controller == NULL || c_ds_controller != c_rs_controller); // The strategy is reduce the value to client then broadcast it out to // render-server and data-server. if (parallelController) { double min_bounds[3] = {bounds[0], bounds[2], bounds[4]}; double max_bounds[3] = {bounds[1], bounds[3], bounds[5]}; double min_result[3], max_result[3]; parallelController->Reduce(min_bounds, min_result, 3, vtkCommunicator::MIN_OP, 0); parallelController->Reduce(max_bounds, max_result, 3, vtkCommunicator::MAX_OP, 0); bounds[0] = min_result[0]; bounds[2] = min_result[1]; bounds[4] = min_result[2]; bounds[1] = max_result[0]; bounds[3] = max_result[1]; bounds[5] = max_result[2]; } // on pvdataserver/pvrenderserver/pvserver/pvbatch, we now have collected the // size-sum on root node. switch (this->Mode) { case CLIENT: { vtkBoundingBox bbox; bbox.AddBounds(bounds); if (c_ds_controller) { c_ds_controller->Receive(bounds, 6, 1, 41232); bbox.AddBounds(bounds); } if (c_rs_controller) { c_rs_controller->Receive(bounds, 6, 1, 41232); bbox.AddBounds(bounds); } bbox.GetBounds(bounds); if (c_ds_controller) { c_ds_controller->Send(bounds, 6, 1, 41232); } if (c_rs_controller) { c_rs_controller->Send(bounds, 6, 1, 41232); } } break; case DATA_SERVER: // both can't be set on a server process. if (c_ds_controller != NULL) { c_ds_controller->Send(bounds, 6, 1, 41232); c_ds_controller->Receive(bounds, 6, 1, 41232); } break; case RENDER_SERVER: if (c_rs_controller != NULL) { c_rs_controller->Send(bounds, 6, 1, 41232); c_rs_controller->Receive(bounds, 6, 1, 41232); } break; default: assert(c_ds_controller==NULL && c_rs_controller == NULL); } if (parallelController) { parallelController->Broadcast(bounds, 6, 0); } return true; } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::BroadcastToDataServer(vtkSelection* selection) { // handle trivial case. if (this->Mode == BUILTIN || this->Mode == INVALID) { return true; } if (vtkProcessModule::GetProcessType() == vtkProcessModule::PROCESS_RENDER_SERVER) { return false; } vtkMultiProcessController* parallelController = this->GetParallelController(); vtkMultiProcessController* c_rs_controller = this->GetClientServerController(); // c_ds_controller is non-null only in client-dataserver-renderserver // configuratrions. vtkMultiProcessController* c_ds_controller = this->GetClientDataServerController(); assert(c_ds_controller == NULL || c_ds_controller != c_rs_controller); if (!c_ds_controller) { c_ds_controller = c_rs_controller; } if (this->Mode == BATCH && parallelController->GetNumberOfProcesses() <= 1) { return true; } std::ostringstream xml_stream; vtkSelectionSerializer::PrintXML(xml_stream, vtkIndent(), 1, selection); vtkMultiProcessStream stream; stream << xml_stream.str(); if (this->Mode == CLIENT && c_ds_controller) { c_ds_controller->Send(stream, 1, 41233); return true; } else if (c_ds_controller) { c_ds_controller->Receive(stream, 1, 41233); } if (parallelController && parallelController->GetNumberOfProcesses() > 1) { parallelController->Broadcast(stream, 0); } std::string xml; stream >> xml; vtkSelectionSerializer::Parse(xml.c_str(), selection); return true; } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::BroadcastToRenderServer( vtkDataObject* dataObject) { // handle trivial case. if (this->Mode == BUILTIN || this->Mode == INVALID) { return true; } if (vtkProcessModule::GetProcessType() == vtkProcessModule::PROCESS_DATA_SERVER) { return false; } vtkMultiProcessController* parallelController = this->GetParallelController(); vtkMultiProcessController* c_rs_controller = this->GetClientServerController(); if (this->Mode == BATCH && parallelController->GetNumberOfProcesses() <= 1) { return true; } if (this->Mode == CLIENT && c_rs_controller) { c_rs_controller->Send(dataObject, 1, 41234); return true; } else if (c_rs_controller) { c_rs_controller->Receive(dataObject, 1, 41234); } if (parallelController && parallelController->GetNumberOfProcesses() > 1) { parallelController->Broadcast(dataObject, 0); } return true; } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::TriggerRMI( vtkMultiProcessStream& stream, int tag) { if (this->Mode == BUILTIN) { return; } // don't use this->GetParallelController() since that only works on rendering // nodes. vtkMultiProcessController* parallelController = vtkMultiProcessController::GetGlobalController(); vtkMultiProcessController* c_rs_controller = this->GetClientServerController(); // c_ds_controller is non-null only in client-dataserver-renderserver // configuratrions. vtkMultiProcessController* c_ds_controller = this->GetClientDataServerController(); assert(c_ds_controller == NULL || c_ds_controller != c_rs_controller); std::vector data; stream.GetRawData(data); if (this->Mode == CLIENT) { if (c_ds_controller) { c_ds_controller->TriggerRMIOnAllChildren( &data[0], static_cast(data.size()), tag); } if (c_rs_controller) { c_rs_controller->TriggerRMIOnAllChildren( &data[0], static_cast(data.size()), tag); } } if (parallelController && parallelController->GetNumberOfProcesses() > 1 && parallelController->GetLocalProcessId() == 0) { parallelController->TriggerRMIOnAllChildren( &data[0], static_cast(data.size()), tag); } } //---------------------------------------------------------------------------- unsigned long vtkPVSynchronizedRenderWindows::AddRMICallback( vtkRMIFunctionType callback, void* localArg, int tag) { // don't use this->GetParallelController() since that only works on rendering // nodes. vtkMultiProcessController* parallelController = vtkMultiProcessController::GetGlobalController(); vtkMultiProcessController* c_rs_controller = this->GetClientServerController(); // c_ds_controller is non-null only in client-dataserver-renderserver // configuratrions. vtkMultiProcessController* c_ds_controller = this->GetClientDataServerController(); assert(c_ds_controller == NULL || c_ds_controller != c_rs_controller); vtkInternals::CallbackInfo info; info.ParallelHandle = parallelController? parallelController->AddRMICallback(callback, localArg, tag) : 0; info.ClientServerHandle = c_rs_controller? c_rs_controller->AddRMICallback(callback, localArg, tag) : 0; info.ClientDataServerHandle = c_ds_controller? c_ds_controller->AddRMICallback(callback, localArg, tag) : 0; unsigned long handle = static_cast( this->Internals->RMICallbacks.size()); this->Internals->RMICallbacks.push_back(info); return handle; } //---------------------------------------------------------------------------- bool vtkPVSynchronizedRenderWindows::RemoveRMICallback(unsigned long id) { // don't use this->GetParallelController() since that only works on rendering // nodes. vtkMultiProcessController* parallelController = vtkMultiProcessController::GetGlobalController(); vtkMultiProcessController* c_rs_controller = this->GetClientServerController(); // c_ds_controller is non-null only in client-dataserver-renderserver // configuratrions. vtkMultiProcessController* c_ds_controller = this->GetClientDataServerController(); assert(c_ds_controller == NULL || c_ds_controller != c_rs_controller); if (this->Internals->RMICallbacks.size() > id) { vtkInternals::CallbackInfo &info = this->Internals->RMICallbacks[id]; if (info.ParallelHandle && parallelController) { parallelController->RemoveRMICallback(info.ParallelHandle); } if (info.ClientServerHandle && c_rs_controller) { c_rs_controller->RemoveRMICallback(info.ClientServerHandle); } if (info.ClientDataServerHandle && c_ds_controller) { c_ds_controller->RemoveRMICallback(info.ClientDataServerHandle); } info = vtkInternals::CallbackInfo(); return true; } return false; } //---------------------------------------------------------------------------- double vtkPVSynchronizedRenderWindows::GetZbufferDataAtPoint(int x, int y, unsigned int id) { vtkRenderWindow* window = this->GetRenderWindow(id); if (!this->Enabled || (this->Mode != vtkPVSynchronizedRenderWindows::CLIENT) || window == NULL) { return window? window->GetZbufferDataAtPoint(x, y) : 1.0; } assert(this->Mode == CLIENT && window != NULL); if (this->ClientServerController) { vtkMultiProcessStream stream; stream << id << x << y; std::vector data; stream.GetRawData(data); this->ClientServerController->TriggerRMIOnAllChildren( &data[0], static_cast(data.size()), GET_ZBUFFER_VALUE_TAG); double value = 1.0; this->ClientServerController->Receive(&value, 1, 1, GET_ZBUFFER_VALUE_TAG); return value; } return 1.0; } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::OnGetZBufferValue( unsigned int id, int x, int y) { double value = this->GetZbufferDataAtPoint(x, y, id); // FIXME: need to get the value from IceT. this->ClientServerController->Send(&value, 1, 1, GET_ZBUFFER_VALUE_TAG); } //---------------------------------------------------------------------------- void vtkPVSynchronizedRenderWindows::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }