fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Cluster / Window / Base / OSGClusterWindow.cpp
blob759bdd317d2ff05862a090af7ae4cd03b86b7a7d
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
40 // Includes
41 //---------------------------------------------------------------------------
43 #include <stdlib.h>
44 #include <stdio.h>
46 #include <sstream>
48 #include "OSGConfig.h"
49 #include "OSGSystemDef.h"
50 #include "OSGClusterWindow.h"
51 #include "OSGDgramSocket.h"
52 #include "OSGStreamSocket.h"
53 #include "OSGRemoteAspect.h"
54 #include "OSGConnection.h"
55 #include "OSGBinaryMessage.h"
56 #include "OSGRemoteAspect.h"
57 #include "OSGConnectionFactory.h"
58 #include "OSGClusterNetwork.h"
59 #include "OSGGroupSockConnection.h"
60 #include "OSGStatCollector.h"
62 #if 0
63 #include "OSGDisplayCalibration.h"
64 #include "OSGImageComposer.h"
65 #endif
67 OSG_USING_NAMESPACE
69 /** \class OSG::ClusterWindow
70 * \ingroup GrpSystemCluster
71 * \brief Abstract base class for cluster configurations
73 * A ClusterWindow describes a clustering algorithm. A ClusterWindow
74 * inherits the ability to connect rendering servers and initiate
75 * remote rendering. By configuring the cluster algorithm with an
76 * OpenSG Window structure, it is possible to use cluster rendering
77 * in the same way as rendering in a GLUT or Qt window.
79 **/
81 StatElemDesc<StatTimeElem> ClusterWindow::statActivateTime
82 ("statActivateTime", "time to activate remote window");
84 StatElemDesc<StatTimeElem> ClusterWindow::statFrameInitTime
85 ("statFrameInitTime", "time to frameInit remote window");
87 StatElemDesc<StatTimeElem> ClusterWindow::statRAVTime
88 ("statRAVTime", "time to RAV remote window");
90 StatElemDesc<StatTimeElem> ClusterWindow::statSwapTime
91 ("statSwapTime", "time to swap remote window");
93 StatElemDesc<StatTimeElem> ClusterWindow::statFrameExitTime
94 ("statFrameExitTime", "time to frameExit remote window");
96 /*-------------------------------------------------------------------------*/
97 /* window functions */
99 //! react to field changes
101 void ClusterWindow::changed(ConstFieldMaskArg whichField,
102 UInt32 origin,
103 BitVector details)
105 Inherited::changed(whichField, origin, details);
108 //! output the instance for debug purposes
110 void ClusterWindow::dump( UInt32 ,
111 const BitVector ) const
113 SLOG << "Dump ClusterWindow NI" << std::endl;
116 #if 0
117 void (*ClusterWindow::getFunctionByName(const Char8 *s))()
119 return NULL;
121 #endif
123 /*! init cluster window. connect to all servers
126 void ClusterWindow::init(GLInitFunctor)
128 GroupConnection *connection;
129 RemoteAspect *remoteAspect;
130 UInt32 c, id;
131 MFString::const_iterator s;
132 Connection::Channel channel;
133 bool directConnect=false;
135 if(getNetwork()->getMainConnection())
137 SWARNING << "init called twice" << std::endl;
138 return;
141 // create connection
142 if(getConnectionType().empty())
144 setConnectionType("StreamSock");
147 connection = ConnectionFactory::the()->createGroup(getConnectionType());
149 if(connection == NULL)
151 SFATAL << "Unknown connection type "
152 << getConnectionType()
153 << std::endl;
154 return;
157 connection->setDestination(getConnectionDestination());
158 connection->setInterface (getConnectionInterface ());
159 connection->setParams (getConnectionParams ());
161 getNetwork()->setMainConnection(connection);
163 // create remote aspect
165 remoteAspect = new RemoteAspect();
167 getNetwork()->setAspect(remoteAspect);
169 if(_statistics)
170 remoteAspect->setStatistics(_statistics);
172 // autostart servers
173 std::string server;
174 std::string autostart;
175 std::string env;
177 Real32 progress = 0.0f;
178 Real32 progressStep = 1.0f / Real32(getMFServers()->size());
180 if(getMFAutostart()->size())
182 progressStep /= 2;
183 std::vector<FILE*> pipes;
185 for(id=0 ; id<getMFServers()->size() ; ++id)
187 std::ostringstream command;
189 server = (*getMFServers())[id];
190 SizeT pos = server.find(":");
192 if(pos != std::string::npos)
193 server.erase(pos);
195 autostart = (*getMFAutostart())[id % getMFAutostart()->size()];
197 for(c = 0 ; c < autostart.length() ; ++c)
199 if(autostart[c] == '%' && c+1 < autostart.length())
200 switch(autostart[++c])
202 case 's':
203 command << server;
204 break;
205 case 'n':
206 command << (*getMFServers())[id];
207 break;
208 case 'i':
209 command << id;
210 break;
211 case '{':
212 env = "" ;
213 while(++c < autostart.length() &&
214 autostart[c] != '}')
215 env += autostart[c];
216 if(getenv(env.c_str()))
217 command << getenv(env.c_str());
218 break;
219 case '%':
220 command << '%';
221 break;
222 default:
223 command << '%' << autostart[c];
225 else
226 command << autostart[c];
228 SINFO << command.str() << std::endl;
229 #ifdef WIN32
230 FILE *pipe = _popen(command.str().c_str(),"r");
231 #else
232 FILE *pipe = popen(command.str().c_str(),"r");
233 #endif
234 if(!pipe)
235 SFATAL << "Error starting: " << command.str() << std::endl;
236 pipes.push_back(pipe);
239 for(id = 0 ; id < getMFServers()->size() ; ++id)
241 if(pipes[id])
243 // update progress
244 if(_connectionFP != NULL)
246 if(!_connectionFP("Starting:", (*getMFServers())[id], progress))
248 // abort, cleanup remaining pipes
249 for( ; id<getMFServers()->size() ; ++id)
251 if(pipes[id])
253 #ifdef WIN32
254 _pclose(pipes[id]);
255 #else
256 pclose(pipes[id]);
257 #endif
259 throw AsyncCancel();
263 SINFO << "Waiting for "
264 << getServers(id)
265 << " to start."
266 << std::endl;
268 int result;
269 std::string line="";
271 while((result=fgetc(pipes[id])) != EOF)
273 line += result;
275 if(result == '\n')
277 SINFO << line;
278 line = "";
282 if(!line.empty())
283 SINFO << line << std::endl;
284 #ifdef WIN32
285 _pclose(pipes[id]);
286 #else
287 pclose(pipes[id]);
288 #endif
289 SINFO << getServers(id) << " started." << std::endl;
291 progress += progressStep;
296 // connect to all servers
297 for(s = getMFServers()->begin();
298 s!= getMFServers()->end();
299 s++)
301 DgramSocket serviceSock;
302 BinaryMessage msg;
303 std::string respServer;
304 std::string respAddress;
305 bool retry=true;
307 if(strstr((*s).c_str(),":"))
308 directConnect = true;
309 else
310 directConnect = false;
312 SINFO << "Connect to " << (*s) << std::endl;
314 serviceSock.open();
315 serviceSock.setTTL(8);
317 // set interface
318 if(!getServiceInterface().empty())
320 serviceSock.setMCastInterface(
321 SocketAddress(getServiceInterface().c_str()));
324 while(retry)
328 // update progress
329 if(_connectionFP != NULL)
331 if(!_connectionFP("Connecting:", *s, progress))
333 serviceSock.close();
334 throw AsyncCancel();
338 // try to connect with the servers name
339 try
341 if(directConnect)
343 channel = connection->connectPoint(*s,0.5);
344 if(channel >= 0)
346 retry = false;
348 SINFO << "Connected with address:"
349 << *s
350 << std::endl;
351 break;
355 catch(...)
359 // find server
360 msg.clear();
361 msg.putString(*s);
362 msg.putString(getConnectionType());
364 if(_sfServiceAddress.getValue().size() != 0)
366 SINFO << "send request to:"
367 << _sfServiceAddress.getValue()
368 << std::endl;
372 serviceSock.sendTo(
373 msg,SocketAddress(
374 _sfServiceAddress.getValue().c_str(),
375 getServicePort()));
377 catch(AsyncCancel &)
379 throw;
381 catch(OSG_STDEXCEPTION_NAMESPACE::exception &e)
383 SINFO << e.what() << std::endl;
386 SINFO << "send request to:"
387 << SocketAddress(SocketAddress::BROADCAST,
388 getServicePort()).getHost().c_str()
389 << std::endl;
393 serviceSock.sendTo(
394 msg,SocketAddress(SocketAddress::BROADCAST,
395 getServicePort()));
397 catch(AsyncCancel &)
399 throw;
401 catch(OSG_STDEXCEPTION_NAMESPACE::exception &e)
403 SINFO << e.what() << std::endl;
406 if(serviceSock.waitReadable(0.1))
408 SocketAddress from;
409 serviceSock.recvFrom(msg, from);
410 msg.getString(respServer);
411 msg.getString(respAddress);
413 if(respServer == *s)
415 GroupSockConnection *pointSock =
416 dynamic_cast<GroupSockConnection*> (connection);
418 if(pointSock != NULL)
420 /* for all socket connections ignore the
421 incoming host and use the host from
422 the last response. */
424 char port[16];
426 if(sscanf(respAddress.c_str(),
427 "%*[^:]:%15s",port) == 1)
429 respAddress = from.getHost() + ":" + port;
433 SINFO << "Found at address "
434 << respAddress
435 << std::endl;
437 // connect to server
438 channel = connection->connectPoint(respAddress);
440 if(channel >= 0)
441 retry=false;
445 catch(AsyncCancel &)
447 throw;
449 catch(OSG_STDEXCEPTION_NAMESPACE::exception &e)
451 SINFO << e.what() << std::endl;
455 serviceSock.close();
457 progress += progressStep;
460 // determine byte order
461 UInt8 serverLittleEndian;
462 UInt8 forceNetworkOrder=false;
463 #if BYTE_ORDER == LITTLE_ENDIAN
464 UInt8 littleEndian = true;
465 #else
466 UInt8 littleEndian = false;
467 #endif
469 for(UInt32 i=0;i<getMFServers()->size();++i)
471 channel = connection->selectChannel();
472 connection->subSelection(channel);
473 connection->getValue(serverLittleEndian);
475 if(serverLittleEndian != littleEndian)
477 forceNetworkOrder=true;
480 connection->resetSelection();
481 // tell the servers the encoding mode
482 connection->putValue(forceNetworkOrder);
483 connection->flush();
484 connection->setNetworkOrder((forceNetworkOrder != 0));
486 if(forceNetworkOrder)
488 SINFO << "Run clustering in network order mode" << std::endl;
491 // inform connection finished
492 if(_connectionFP != NULL)
493 _connectionFP("ClusterWindow initialization completed.", "", 1.0);
496 bool ClusterWindow::initAsync(const ConnectionCB &fp)
498 bool result;
499 ConnectionCB saveFP = _connectionFP;
501 _connectionFP = fp;
503 try
505 init();
506 result = true;
508 catch(AsyncCancel &)
510 result = false;
512 _connectionFP = saveFP;
514 return result;
517 void ClusterWindow::setConnectionCB(const ConnectionCB &fp)
519 _connectionFP = fp;
522 #ifdef OSG_OLD_RENDER_ACTION
523 void ClusterWindow::render(DrawActionBase *action)
525 activate();
526 frameInit();
527 renderAllViewports(action);
528 swap();
529 frameExit();
531 #endif
533 void ClusterWindow::render(RenderActionBase *action)
535 if(_statistics != NULL)
536 _statistics->getElem(statActivateTime)->start();
538 doActivate();
540 if(_statistics != NULL)
541 _statistics->getElem(statActivateTime)->stop();
544 if(_statistics != NULL)
545 _statistics->getElem(statFrameInitTime)->start();
547 doFrameInit();
549 if(_statistics != NULL)
550 _statistics->getElem(statFrameInitTime)->stop();
553 if(_statistics != NULL)
554 _statistics->getElem(statRAVTime)->start();
556 doRenderAllViewports(action);
558 if(_statistics != NULL)
559 _statistics->getElem(statRAVTime)->stop();
562 if(_statistics != NULL)
563 _statistics->getElem(statSwapTime)->start();
565 doSwap();
567 if(_statistics != NULL)
568 _statistics->getElem(statSwapTime)->stop();
571 if(_statistics != NULL)
572 _statistics->getElem(statFrameExitTime)->start();
574 doFrameExit();
576 if(_statistics != NULL)
577 _statistics->getElem(statFrameExitTime)->stop();
580 void ClusterWindow::activate(void)
582 this->doActivate();
585 void ClusterWindow::deactivate(void)
587 this->doDeactivate();
590 bool ClusterWindow::swap(void)
592 return this->doSwap();
595 void ClusterWindow::terminate (void)
599 void ClusterWindow::doActivate(void)
603 void ClusterWindow::doDeactivate(void)
607 bool ClusterWindow::doSwap(void)
609 if(getNetwork()->getMainConnection() && getNetwork()->getAspect())
611 clientSwap();
614 return true;
617 #ifdef OSG_OLD_RENDER_ACTION
618 void ClusterWindow::renderAllViewports(DrawActionBase *action)
620 if(getNetwork()->getMainConnection() && getNetwork()->getAspect())
622 clientRender(action);
625 #endif
627 void ClusterWindow::doRenderAllViewports(RenderActionBase *action)
629 if(getNetwork()->getMainConnection() && getNetwork()->getAspect())
631 clientRender(action);
635 bool ClusterWindow::hasContext(void)
637 return true;
640 void ClusterWindow::doFrameInit(bool reinitExtFuctions)
642 Connection *connection = getNetwork()->getMainConnection();
643 RemoteAspect *remoteAspect = getNetwork()->getAspect();
645 if(remoteAspect && connection)
647 if(_firstFrame)
649 setFrameCount(0);
651 // send sync
653 commitChanges();
654 remoteAspect->sendSync(*connection);
656 ChangeList *cl = ChangeList::create();
658 cl->clear();
659 cl->merge(*Thread::getCurrentChangeList());
661 Thread::getCurrentChangeList()->clear();
663 // init client window
664 clientInit();
665 // last chance to modifie before sync
666 clientPreSync();
667 // send sync
668 commitChanges();
669 remoteAspect->sendSync(*connection);
671 // cl.merge(*Thread::getCurrentChangeList());
672 // Thread::getCurrentChangeList()->clear();
673 Thread::getCurrentChangeList()->merge(*cl);
675 OSG::subRef(cl);
677 _firstFrame = false;
679 else
681 setFrameCount(getFrameCount() + 1);
682 clientPreSync();
684 commitChanges();
685 remoteAspect->sendSync(*connection);
690 void ClusterWindow::doFrameExit(void)
694 /*-------------------------------------------------------------------------*/
695 /* statistics */
697 void ClusterWindow::setStatistics(StatCollector *statistics)
699 _statistics = statistics;
700 if(getNetwork()->getAspect())
701 getNetwork()->getAspect()->setStatistics(statistics);
704 /*-------------------------------------------------------------------------*/
705 /* calibration */
707 /*-------------------------------------------------------------------------*/
708 /* exceptions */
710 ClusterWindow::AsyncCancel::AsyncCancel()
714 /*-------------------------------------------------------------------------*/
715 /* client methods */
717 /*! init client window. In a derived cluster window this method is called
718 * before the first sync with the rendering servers. There is no default
719 * action.
721 void ClusterWindow::clientInit(void)
725 /** client frame before sync
727 * In a derived cluster window this method is called before
728 * sync with the rendering servers. Default aciton is to activate
729 * and init the client window.
732 void ClusterWindow::clientPreSync( void )
734 if(getClientWindow() != NULL)
736 getClientWindow()->activate ();
737 getClientWindow()->frameInit();
741 /** initiate client rendering
743 * In a derived cluster window this method is called after the
744 * sync with all rendering servers. Default aciton is to render all
745 * viewports of the client window.
748 void ClusterWindow::clientRender(RenderActionBase *action)
750 if(getClientWindow() != NULL)
752 getClientWindow()->renderAllViewports(action);
756 /** swap client window
758 * In a derived cluster window this method is called after rendering
759 * Default aciton is to swap the local client window.
762 void ClusterWindow::clientSwap( void )
764 if(getClientWindow() != NULL)
766 getClientWindow()->swap ();
767 getClientWindow()->frameExit();
770 #if 0
771 if(getDirty() == true)
773 setDirty(false);
775 #endif
778 /*-------------------------------------------------------------------------*/
779 /* server methods */
783 /** initialise the cluster window on the server side
785 * This method is called after the first sync.
787 * \param window server render window
788 * \param id server id
791 void ClusterWindow::serverInit(Window *,
792 UInt32 )
796 /** render server window
798 * This method is called after synchronisation of all changes with the
799 * rendering client. Default action is to render all viewports with the
800 * given action
802 * !param window server render window
803 * !param id server id
804 * !param action action
807 #ifdef OSG_OLD_RENDER_ACTION
808 void ClusterWindow::serverRender(Window *window,
809 UInt32 id,
810 DrawActionBase *action )
812 #if 0
813 window->activate();
814 window->frameInit();
815 window->renderAllViewports(action);
816 #endif
818 window->renderNoFinish(action);
820 #if 0
821 RenderOptionsPtr ro;
823 RenderAction *ract = dynamic_cast<RenderAction *>(action);
824 if(ract != NULL)
826 MFViewportPtr::iterator portIt = window->getPort().begin();
827 MFViewportPtr::const_iterator portEnd = window->getPort().end();
828 // try to find option as an attachment of window
829 OSG::RenderOptionsPtr winRo = OSG::RenderOptionsPtr::dcast(
830 window->findAttachment(OSG::RenderOptions::getClassType()));
831 ract->setWindow(window.getCPtr());
832 while(portIt != portEnd)
834 // try to find option an attachment at the viewport
835 OSG::RenderOptionsPtr vpRo = OSG::RenderOptionsPtr::dcast(
836 (*portIt)->findAttachment(OSG::RenderOptions::getClassType()));
837 // try to find option an attachment at the root node
838 OSG::RenderOptionsPtr rootRo = NULL;
839 if((*portIt)->getRoot() != NULL)
841 rootRo = OSG::RenderOptionsPtr::dcast(
842 (*portIt)->getRoot()->findAttachment(OSG::RenderOptions::getClassType()));
844 if(rootRo != NULL)
845 ro = rootRo;
846 else
847 if(vpRo != NULL)
848 ro = vpRo;
849 else
850 ro = winRo;
851 if(ro != NULL)
852 ro->activateOptions(ract);
853 (*portIt)->render(ract);
854 ++portIt;
856 } else {
857 if(action)
858 window->renderAllViewports(action);
860 #endif
862 #endif
864 void ClusterWindow::serverRender(Window *window,
865 UInt32 id,
866 RenderActionBase *action )
868 window->activate();
869 window->frameInit();
870 window->renderAllViewports(action);
873 /** swap server window
875 * <code>serverSwap</code> is called after rendering. Default action is
876 * to swap the rendering window.
878 * !param window server render window
879 * !param id server id
880 * !param connection connection to client
882 void ClusterWindow::serverSwap(Window *window,
883 UInt32 )
885 window->swap ();
886 window->frameExit();
889 /*-------------------------------------------------------------------------*/
890 /* constructor / destructor */
892 //! Constructor
894 ClusterWindow::ClusterWindow(void) :
895 Inherited(),
896 _firstFrame (true),
897 _statistics (NULL),
898 _connectionFP(NULL),
899 _network (NULL)
903 //! Copy Constructor
905 ClusterWindow::ClusterWindow(const ClusterWindow &source) :
906 Inherited (source ),
907 _firstFrame (true ),
908 _statistics (NULL ),
909 _connectionFP(source._connectionFP),
910 _network (NULL )
914 //! Destructor
916 ClusterWindow::~ClusterWindow(void)
918 _network = NULL;
921 /*-------------------------------------------------------------------------*/
922 /* connection pool */
924 /*! Get connection pool
926 ClusterNetwork *ClusterWindow::getNetwork(void)
928 if(_network == NULL)
930 _network = ClusterNetwork::getInstance(this->getId());
933 return _network;
936 /*! initialize the static features of the class, e.g. action callbacks
939 void ClusterWindow::initMethod(InitPhase ePhase)
941 Inherited::initMethod(ePhase);
944 void ClusterWindow::exitMethod(InitPhase ePhase)
946 Inherited::exitMethod(ePhase);