Line data Source code
1 :
2 : /* Copyright (c) 2011-2016, Stefan Eilemann <eile@eyescale.h>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * Julio Delgado Mangas <julio.delgadomangas@epfl.ch>
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "resources.h"
21 :
22 : #include "../compound.h"
23 : #include "../configVisitor.h"
24 : #include "../connectionDescription.h"
25 : #include "../frame.h"
26 : #include "../layout.h"
27 : #include "../node.h"
28 : #include "../pipe.h"
29 : #include "../segment.h"
30 : #include "../window.h"
31 : #include "../equalizers/loadEqualizer.h"
32 :
33 : #include <eq/fabric/configParams.h>
34 : #include <eq/fabric/gpuInfo.h>
35 :
36 : #include <hwsd/gpuInfo.h>
37 : #include <hwsd/netInfo.h>
38 : #include <hwsd/hwsd.h>
39 : #ifdef EQUALIZER_USE_hwsd_gpu_cgl
40 : # include <hwsd/gpu/cgl/module.h>
41 : #endif
42 : #ifdef EQUALIZER_USE_hwsd_gpu_glx
43 : # include <hwsd/gpu/glx/module.h>
44 : #endif
45 : #ifdef EQUALIZER_USE_hwsd_gpu_wgl
46 : # include <hwsd/gpu/wgl/module.h>
47 : #endif
48 : #ifdef EQUALIZER_USE_hwsd_gpu_dns_sd
49 : # include <hwsd/gpu/dns_sd/module.h>
50 : #endif
51 : #ifdef EQUALIZER_USE_hwsd_net_sys
52 : # include <hwsd/net/sys/module.h>
53 : #endif
54 : #ifdef EQUALIZER_USE_hwsd_net_dns_sd
55 : # include <hwsd/net/dns_sd/module.h>
56 : #endif
57 :
58 : #ifdef _MSC_VER
59 : # include <eq/os.h>
60 : # define setenv( name, value, overwrite ) \
61 : _putenv_s( name, value )
62 : #endif
63 :
64 : #define USE_IPv4
65 :
66 : namespace eq
67 : {
68 : namespace server
69 : {
70 : namespace config
71 : {
72 : namespace
73 : {
74 0 : co::ConnectionDescriptions _findConnections( const lunchbox::uint128_t& id,
75 : const hwsd::NetInfos& netInfos )
76 : {
77 : // sort connections by bandwidth
78 : typedef std::multimap< int32_t, co::ConnectionDescriptionPtr > Connections;
79 0 : Connections connections;
80 :
81 0 : for( hwsd::NetInfosCIter i = netInfos.begin(); i != netInfos.end(); ++i )
82 : {
83 0 : const hwsd::NetInfo& netInfo = *i;
84 0 : if( netInfo.id != id || !netInfo.up ||
85 0 : netInfo.type == hwsd::NetInfo::TYPE_LOOPBACK )
86 : {
87 0 : continue;
88 : }
89 :
90 0 : co::ConnectionDescriptionPtr desc = new ConnectionDescription;
91 0 : switch( netInfo.type )
92 : {
93 : case hwsd::NetInfo::TYPE_ETHERNET:
94 0 : desc->type = co::CONNECTIONTYPE_TCPIP;
95 0 : desc->bandwidth = 125000; // 1Gbit
96 0 : break;
97 :
98 : case hwsd::NetInfo::TYPE_INFINIBAND:
99 0 : desc->type = co::CONNECTIONTYPE_RDMA;
100 0 : desc->bandwidth = 2500000; // 20Gbit
101 0 : break;
102 :
103 : default:
104 0 : desc->type = co::CONNECTIONTYPE_NONE;
105 : }
106 0 : if( netInfo.linkspeed != hwsd::NetInfo::defaultValue )
107 0 : desc->bandwidth = netInfo.linkspeed * 125; // MBit -> Kbyte
108 : #ifdef USE_IPv4
109 0 : desc->hostname = netInfo.inetAddress;
110 : #else
111 : desc->hostname = netInfo.inet6Address;
112 : #endif
113 0 : connections.insert( std::make_pair( desc->bandwidth, desc ));
114 0 : }
115 :
116 0 : co::ConnectionDescriptions result;
117 0 : for( Connections::const_reverse_iterator i = connections.rbegin();
118 0 : i != connections.rend(); ++i )
119 : {
120 0 : result.push_back( i->second );
121 : }
122 0 : return result;
123 : }
124 :
125 0 : uint32_t _configureNetworkTypes( const fabric::ConfigParams& params )
126 : {
127 0 : uint32_t netTypes = 0;
128 0 : if( params.getFlags() & fabric::ConfigParams::FLAG_NETWORK_ALL )
129 : {
130 0 : if( params.getFlags() & fabric::ConfigParams::FLAG_NETWORK_ETHERNET )
131 0 : netTypes |= hwsd::NetInfo::TYPE_ETHERNET;
132 0 : if( params.getFlags() & fabric::ConfigParams::FLAG_NETWORK_INFINIBAND )
133 0 : netTypes |= hwsd::NetInfo::TYPE_INFINIBAND;
134 : }
135 : else
136 0 : netTypes = hwsd::NetInfo::TYPE_ALL ^ hwsd::NetInfo::TYPE_UNKNOWN;
137 :
138 0 : return netTypes;
139 : }
140 :
141 0 : hwsd::GPUInfos _discoverGPUs( const fabric::ConfigParams& params,
142 : hwsd::FilterPtr filter )
143 : {
144 0 : hwsd::FilterPtr gpuFilter = filter | new hwsd::MirrorFilter |
145 0 : new hwsd::GPUFilter( params.getGPUFilter( ));
146 :
147 0 : return hwsd::discoverGPUInfos( gpuFilter );
148 : }
149 :
150 0 : hwsd::NetInfos _discoverNetworks( const fabric::ConfigParams& params,
151 : hwsd::FilterPtr filter )
152 : {
153 :
154 : hwsd::FilterPtr netFilter = filter |
155 : new hwsd::NetFilter( params.getPrefixes(),
156 0 : _configureNetworkTypes( params ));
157 :
158 0 : return hwsd::discoverNetInfos( netFilter );
159 : }
160 :
161 0 : void _configureHwsdModules()
162 : {
163 : #ifdef EQUALIZER_USE_hwsd_gpu_cgl
164 : hwsd::gpu::cgl::Module::use();
165 : #elif defined(EQUALIZER_USE_hwsd_gpu_glx)
166 0 : hwsd::gpu::glx::Module::use();
167 : #endif
168 : #ifdef EQUALIZER_USE_hwsd_gpu_wgl
169 : hwsd::gpu::wgl::Module::use();
170 : #endif
171 : #ifdef EQUALIZER_USE_hwsd_gpu_dns_sd
172 : hwsd::gpu::dns_sd::Module::use();
173 : #endif
174 : #ifdef EQUALIZER_USE_hwsd_net_sys
175 0 : hwsd::net::sys::Module::use();
176 : #endif
177 : #ifdef EQUALIZER_USE_hwsd_net_dns_sd
178 : hwsd::net::dns_sd::Module::use();
179 : #endif
180 0 : }
181 :
182 0 : void _disposeHwsdModules()
183 : {
184 : #ifdef EQUALIZER_USE_hwsd_gpu_cgl
185 : hwsd::gpu::cgl::Module::dispose();
186 : #elif defined(EQUALIZER_USE_hwsd_gpu_glx)
187 0 : hwsd::gpu::glx::Module::dispose();
188 : #endif
189 : #ifdef EQUALIZER_USE_hwsd_gpu_wgl
190 : hwsd::gpu::wgl::Module::dispose();
191 : #endif
192 : #ifdef EQUALIZER_USE_hwsd_gpu_dns_sd
193 : hwsd::gpu::dns_sd::Module::dispose();
194 : #endif
195 : #ifdef EQUALIZER_USE_hwsd_net_sys
196 0 : hwsd::net::sys::Module::dispose();
197 : #endif
198 : #ifdef EQUALIZER_USE_hwsd_net_dns_sd
199 : hwsd::net::dns_sd::Module::dispose();
200 : #endif
201 0 : }
202 :
203 : } // unnamed namespace
204 :
205 28 : static lunchbox::a_int32_t _frameCounter;
206 :
207 0 : bool Resources::discover( ServerPtr server, Config* config,
208 : const std::string& session,
209 : const fabric::ConfigParams& params )
210 : {
211 0 : _configureHwsdModules();
212 :
213 0 : hwsd::FilterPtr filter = hwsd::FilterPtr( new hwsd::DuplicateFilter ) |
214 0 : new hwsd::SessionFilter( session );
215 :
216 0 : hwsd::GPUInfos gpuInfos = _discoverGPUs( params, filter );
217 0 : const hwsd::NetInfos& netInfos = _discoverNetworks( params, filter );
218 :
219 0 : _disposeHwsdModules();
220 :
221 0 : if( gpuInfos.empty( ))
222 : {
223 0 : if( hwsd::NodeInfo::isLocal( session ))
224 : {
225 0 : LBWARN << "No local GPUs found, abort configuration" << std::endl;
226 0 : return false;
227 : }
228 0 : LBINFO << "No resources found for session " << session
229 0 : << ", using default config" << std::endl;
230 0 : gpuInfos.push_back( hwsd::GPUInfo( ));
231 : }
232 :
233 : typedef stde::hash_map< uint128_t, Node* > NodeMap;
234 0 : NodeMap nodes;
235 :
236 0 : const uint32_t flags = params.getFlags();
237 :
238 0 : const bool multiProcess = flags & (fabric::ConfigParams::FLAG_MULTIPROCESS |
239 0 : fabric::ConfigParams::FLAG_MULTIPROCESS_DB );
240 0 : const bool multiNode = !hwsd::NodeInfo::isLocal( session ) ||
241 0 : ( multiProcess && gpuInfos.size() > 1 );
242 0 : size_t gpuCounter = 0;
243 0 : uint128_t appNodeID;
244 :
245 0 : std::string excludedDisplays; // for VGL_EXCLUDE
246 :
247 0 : for( const hwsd::GPUInfo& info : gpuInfos )
248 : {
249 0 : if( info.flags & hwsd::GPUInfo::FLAG_VIRTUALGL_DISPLAY )
250 0 : continue; // ignore, default $DISPLAY gpu uses this one
251 :
252 0 : Node* mtNode = nodes[ info.id ];
253 0 : Node* mpNode = 0;
254 0 : if( !mtNode )
255 : {
256 0 : const bool isApplicationNode = info.nodeName.empty();
257 0 : if( isApplicationNode )
258 0 : appNodeID = info.id;
259 0 : mtNode = new Node( config );
260 0 : mtNode->setName( info.nodeName );
261 0 : mtNode->setHost( info.nodeName );
262 0 : mtNode->setApplicationNode( isApplicationNode );
263 :
264 0 : nodes[ info.id ] = mtNode;
265 :
266 0 : if( multiNode )
267 : {
268 : const co::ConnectionDescriptions& descs =
269 0 : _findConnections( info.id, netInfos );
270 :
271 0 : if( descs.empty() && !info.nodeName.empty())
272 : {
273 0 : LBINFO << "No suitable connection found for node "
274 0 : << info.nodeName << "; node will not be used"
275 0 : << std::endl;
276 0 : nodes.erase( info.id );
277 0 : delete mtNode;
278 0 : continue;
279 : }
280 :
281 0 : for( co::ConnectionDescriptionsCIter j = descs.begin();
282 0 : j != descs.end(); ++j )
283 : {
284 0 : mtNode->addConnectionDescription( *j );
285 0 : }
286 : }
287 : }
288 0 : else if( multiProcess )
289 : {
290 0 : mpNode = new Node( config );
291 0 : mpNode->setName( info.nodeName );
292 0 : mpNode->setHost( info.nodeName );
293 :
294 0 : LBASSERT( multiNode );
295 : const co::ConnectionDescriptions& descs =
296 0 : _findConnections( info.id, netInfos );
297 :
298 0 : if( descs.empty() && !info.nodeName.empty())
299 : {
300 0 : LBINFO << "No suitable connection found for node "
301 0 : << info.nodeName << "; node will not be used"
302 0 : << std::endl;
303 0 : delete mpNode;
304 0 : continue;
305 : }
306 :
307 0 : for( co::ConnectionDescriptionsCIter j = descs.begin();
308 0 : j != descs.end(); ++j )
309 : {
310 0 : mpNode->addConnectionDescription( *j );
311 0 : }
312 : }
313 :
314 0 : std::stringstream name;
315 0 : if( info.device == LB_UNDEFINED_UINT32 &&
316 : // VirtualGL display redirects to local GPU (see continue above)
317 0 : !(info.flags & hwsd::GPUInfo::FLAG_VIRTUALGL ))
318 : {
319 0 : name << "display";
320 : }
321 : else
322 : {
323 0 : name << "GPU" << ++gpuCounter;
324 0 : if( // When running under VirtualGL, GPUs that are not VNC virtual
325 : // devices mustn't be interposed.
326 0 : ( info.flags & ( hwsd::GPUInfo::FLAG_VIRTUALGL |
327 : hwsd::GPUInfo::FLAG_VNC )) ==
328 0 : hwsd::GPUInfo::FLAG_VIRTUALGL &&
329 0 : info.device != LB_UNDEFINED_UINT32 )
330 : {
331 0 : std::ostringstream displayString;
332 0 : displayString << ":" << info.port << "." << info.device;
333 0 : excludedDisplays += displayString.str() + ",";
334 : }
335 : }
336 :
337 0 : if( mpNode ) // multi-process resource
338 : {
339 0 : Pipe* pipe = new Pipe( mpNode );
340 0 : pipe->setPort( info.port );
341 0 : pipe->setDevice( info.device );
342 0 : pipe->setPixelViewport( PixelViewport( info.pvp ));
343 0 : pipe->setName( name.str() + " mp" );
344 0 : name << " mt"; // mark companion GPU as multi-threaded only
345 : }
346 : else
347 0 : name << " mt mp"; // mark GPU as multi-threaded and multi-process
348 :
349 0 : Pipe* pipe = new Pipe( mtNode ); // standalone/multi-threaded resource
350 0 : pipe->setPort( info.port );
351 0 : pipe->setDevice( info.device );
352 0 : pipe->setPixelViewport( PixelViewport( info.pvp ));
353 0 : pipe->setName( name.str( ));
354 0 : }
355 :
356 0 : Node* node = config->findAppNode();
357 0 : if( !node )
358 : {
359 0 : node = new Node( config );
360 0 : node->setApplicationNode( true );
361 0 : node->addConnectionDescription( new ConnectionDescription );
362 : }
363 0 : if( node->getPipes().empty( )) // add display window
364 : {
365 0 : Pipe* pipe = new Pipe( node );
366 0 : pipe->setName( "display" );
367 : }
368 :
369 0 : if( config->getNodes().size() > 1 ) // add server connection for clusters
370 : {
371 0 : co::Connections connections;
372 :
373 0 : if( appNodeID == 0 )
374 : {
375 0 : co::ConnectionDescriptionPtr desc = new co::ConnectionDescription;
376 0 : co::ConnectionPtr connection = server->addListener( desc );
377 0 : LBASSERT( connection );
378 0 : if( connection )
379 0 : connections.push_back( connection );
380 : else
381 0 : LBWARN << "Could not add listener " << desc->hostname
382 0 : << " to server" << std::endl;
383 : }
384 : else
385 : {
386 : const co::ConnectionDescriptions& descs =
387 0 : _findConnections( appNodeID, netInfos );
388 :
389 0 : for( co::ConnectionDescriptionsCIter i = descs.begin();
390 0 : i != descs.end(); ++i )
391 : {
392 0 : co::ConnectionPtr connection = server->addListener( *i );
393 0 : LBASSERT( connection );
394 0 : if( connection )
395 0 : connections.push_back( connection );
396 : else
397 0 : LBWARN << "Could not add listener " << (*i)->hostname
398 0 : << " to server" << std::endl;
399 0 : }
400 : }
401 :
402 0 : config->setServerConnections( connections );
403 : }
404 :
405 0 : if( !excludedDisplays.empty( ))
406 0 : ::setenv("VGL_EXCLUDE", excludedDisplays.c_str(), 1 /*overwrite*/ );
407 :
408 0 : return true;
409 : }
410 :
411 : namespace
412 : {
413 0 : class AddSourcesVisitor : public ConfigVisitor
414 : {
415 : public:
416 0 : explicit AddSourcesVisitor( const PixelViewport& pvp ) : _pvp( pvp ) {}
417 :
418 0 : virtual VisitorResult visitPre( Pipe* pipe )
419 : {
420 0 : const Node* node = pipe->getNode();
421 0 : if( node->isApplicationNode() && node->getPipes().front() == pipe )
422 : {
423 : // display window has discrete 'affinity' GPU
424 0 : if( pipe->getName() != "display mt mp" )
425 0 : _channels.push_back( pipe->getChannel( ChannelPath( 0 )));
426 0 : return TRAVERSE_CONTINUE;
427 : }
428 :
429 0 : Window* window = new Window( pipe );
430 0 : if( !pipe->getPixelViewport().isValid( ))
431 0 : window->setPixelViewport( _pvp );
432 : window->setIAttribute( WindowSettings::IATTR_HINT_DRAWABLE,
433 0 : fabric::FBO );
434 0 : window->setName( pipe->getName() + " source window" );
435 :
436 0 : _channels.push_back( new Channel( window ));
437 0 : _channels.back()->setName( pipe->getName() + " source channel" );
438 0 : return TRAVERSE_CONTINUE;
439 : }
440 :
441 0 : const Channels& getChannels() const { return _channels; }
442 : private:
443 : const PixelViewport& _pvp;
444 : Channels _channels;
445 : };
446 : }
447 :
448 0 : Channels Resources::configureSourceChannels( Config* config )
449 : {
450 0 : const Node* node = config->findAppNode();
451 0 : LBASSERT( node );
452 0 : if( !node )
453 0 : return Channels();
454 :
455 0 : const Pipes& pipes = node->getPipes();
456 0 : LBASSERT( !pipes.empty( ));
457 0 : if( pipes.empty( ))
458 0 : return Channels();
459 :
460 0 : Pipe* pipe = pipes.front();
461 0 : PixelViewport pvp = pipe->getPixelViewport();
462 0 : if( pvp.isValid( ))
463 : {
464 0 : pvp.x = 0;
465 0 : pvp.y = 0;
466 : }
467 : else
468 0 : pvp = PixelViewport( 0, 0, 1920, 1200 );
469 :
470 0 : AddSourcesVisitor addSources( pvp );
471 0 : config->accept( addSources );
472 0 : return addSources.getChannels();
473 : }
474 :
475 : #if 0 // LB_GCC_4_5_OR_LATER
476 : # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
477 : #endif
478 0 : void Resources::configure( const Compounds& compounds, const Channels& channels,
479 : const fabric::ConfigParams& params )
480 : {
481 0 : LBASSERT( !compounds.empty( ));
482 0 : if( compounds.empty() || channels.empty( )) // No additional resources
483 0 : return;
484 :
485 : #ifndef NDEBUG
486 0 : const Canvas* canvas = 0;
487 : #endif
488 0 : for( CompoundsCIter i = compounds.begin(); i != compounds.end(); ++i )
489 : {
490 0 : const Compounds& children = (*i)->getChildren();
491 0 : LBASSERT( children.size() == 1 );
492 0 : if( children.size() != 1 )
493 0 : continue;
494 :
495 0 : Compound* segmentCompound = children.front();
496 : #ifndef NDEBUG
497 0 : const Channel* channel = segmentCompound->getChannel();
498 0 : LBASSERT( channel );
499 0 : LBASSERT( !canvas || channel->getCanvas() == canvas );
500 0 : canvas = channel->getCanvas();
501 : #endif
502 :
503 0 : _addMonoCompound( segmentCompound, channels, params );
504 0 : _addStereoCompound( segmentCompound, channels, params );
505 : }
506 : }
507 :
508 0 : static Channels _filter( const Channels& input, const std::string& filter )
509 : {
510 0 : Channels result;
511 :
512 0 : for( ChannelsCIter i = input.begin(); i != input.end(); ++i )
513 0 : if( (*i)->getName().find( filter ) != std::string::npos )
514 0 : result.push_back( *i );
515 0 : return result;
516 : }
517 :
518 0 : Compound* Resources::_addMonoCompound( Compound* root, const Channels& channels,
519 : const fabric::ConfigParams& params )
520 : {
521 0 : const Channel* channel = root->getChannel();
522 0 : const Layout* layout = channel->getLayout();
523 0 : const std::string& name = layout->getName();
524 :
525 0 : Compound* compound = 0;
526 : const bool multiProcess =
527 0 : params.getFlags() & fabric::ConfigParams::FLAG_MULTIPROCESS;
528 0 : const bool multiProcessDB = multiProcess ||
529 0 : ( params.getFlags() & fabric::ConfigParams::FLAG_MULTIPROCESS_DB );
530 : const Channels& activeChannels = _filter( channels,
531 0 : multiProcess ? " mp " : " mt " );
532 : const Channels& activeDBChannels = _filter( channels,
533 0 : multiProcessDB ? " mp ":" mt ");
534 :
535 0 : if( name == EQ_SERVER_CONFIG_LAYOUT_SIMPLE )
536 : /* nop */;
537 0 : else if( name == EQ_SERVER_CONFIG_LAYOUT_2D_DYNAMIC ||
538 0 : name == EQ_SERVER_CONFIG_LAYOUT_2D_STATIC )
539 : {
540 0 : compound = _add2DCompound( root, activeChannels, params );
541 : }
542 0 : else if( name == EQ_SERVER_CONFIG_LAYOUT_DB_DYNAMIC ||
543 0 : name == EQ_SERVER_CONFIG_LAYOUT_DB_STATIC )
544 : {
545 0 : compound = _addDBCompound( root, activeDBChannels, params );
546 : }
547 0 : else if( name == EQ_SERVER_CONFIG_LAYOUT_DB_DS )
548 0 : compound = _addDSCompound( root, activeDBChannels );
549 0 : else if( name == EQ_SERVER_CONFIG_LAYOUT_DB_2D )
550 : {
551 0 : LBASSERT( !multiProcess );
552 0 : LBASSERT( multiProcessDB );
553 0 : compound = _addDB2DCompound( root, channels, params );
554 : }
555 0 : else if( name == EQ_SERVER_CONFIG_LAYOUT_SUBPIXEL )
556 0 : compound = _addSubpixelCompound( root, activeChannels );
557 : else
558 : {
559 0 : LBASSERTINFO( false, "Unimplemented mode " << name );
560 : }
561 :
562 0 : if( compound )
563 0 : compound->setEyes( EYE_CYCLOP );
564 :
565 0 : return compound;
566 : }
567 :
568 0 : Compound* Resources::_addStereoCompound( Compound* root,
569 : const Channels& channels,
570 : const fabric::ConfigParams& params )
571 : {
572 0 : const Channel* channel = root->getChannel();
573 0 : const Layout* layout = channel->getLayout();
574 0 : const std::string& name = layout->getName();
575 0 : if( name == EQ_SERVER_CONFIG_LAYOUT_SIMPLE )
576 0 : return 0;
577 :
578 0 : Compound* compound = new Compound( root );
579 0 : compound->setName( "Stereo" );
580 0 : compound->setEyes( EYE_LEFT | EYE_RIGHT );
581 :
582 0 : const bool multiProcess = params.getFlags() &
583 : (fabric::ConfigParams::FLAG_MULTIPROCESS |
584 0 : fabric::ConfigParams::FLAG_MULTIPROCESS_DB );
585 0 : const Channels& active = name == EQ_SERVER_CONFIG_LAYOUT_DB_2D ? channels :
586 0 : _filter( channels, multiProcess ? " mp " : " mt " );
587 :
588 0 : const size_t nChannels = active.size();
589 0 : const ChannelsCIter split = active.begin() + (nChannels >> 1);
590 :
591 0 : Channels leftChannels( split - active.begin( ));
592 0 : std::copy( active.begin(), split, leftChannels.begin( ));
593 :
594 0 : Channels rightChannels( active.end() - split );
595 0 : std::copy( split, active.end(), rightChannels.begin( ));
596 :
597 0 : Compound* left = 0;
598 0 : if( leftChannels.empty() ||
599 0 : ( leftChannels.size() == 1 && leftChannels.front() == channel ))
600 : {
601 0 : left = new Compound( compound );
602 : }
603 : else
604 0 : left = _addMonoCompound( compound, leftChannels, params );
605 :
606 0 : left->setEyes( EYE_LEFT );
607 :
608 0 : Compound* right = 0;
609 0 : if( rightChannels.empty() ||
610 0 : ( rightChannels.size() == 1 && rightChannels.front() == channel ))
611 : {
612 0 : right = new Compound( compound );
613 : }
614 : else
615 0 : right = _addMonoCompound( compound, rightChannels, params );
616 :
617 0 : right->setEyes( EYE_RIGHT );
618 :
619 0 : return compound;
620 : }
621 :
622 0 : Compound* Resources::_add2DCompound( Compound* root, const Channels& channels,
623 : fabric::ConfigParams params )
624 : {
625 0 : const Channel* channel = root->getChannel();
626 0 : const Layout* layout = channel->getLayout();
627 0 : const std::string& name = layout->getName();
628 :
629 0 : Compound* compound = new Compound( root );
630 0 : compound->setName( name );
631 0 : if( params.getEqualizer().getMode() == LoadEqualizer::MODE_DB )
632 0 : params.getEqualizer().setMode( LoadEqualizer::MODE_2D );
633 :
634 0 : LoadEqualizer* lb = new LoadEqualizer( params.getEqualizer( ));
635 0 : if( name == EQ_SERVER_CONFIG_LAYOUT_2D_STATIC )
636 0 : lb->setDamping( 1.f );
637 0 : compound->addEqualizer( lb );
638 :
639 0 : _fill2DCompound( compound, channels );
640 0 : return compound;
641 : }
642 :
643 0 : void Resources::_fill2DCompound( Compound* compound, const Channels& channels )
644 : {
645 0 : const Compounds& children = _addSources( compound, channels );
646 0 : const size_t step = size_t( 100000.0f / float( children.size( )));
647 0 : size_t start = 0;
648 0 : for( CompoundsCIter i = children.begin(); i != children.end(); ++i )
649 : {
650 0 : Compound* child = *i;
651 0 : if( i+1 == children.end( )) // last - correct rounding 'error'
652 : child->setViewport(
653 : fabric::Viewport( float( start ) / 100000.f, 0.f,
654 0 : ( 100000.f - float( start ))/100000.f, 1.f ));
655 : else
656 : child->setViewport(
657 : fabric::Viewport( float( start ) / 100000.f, 0.f,
658 0 : float( step ) / 100000.f, 1.f ));
659 0 : start += step;
660 : }
661 0 : }
662 :
663 0 : Compound* Resources::_addDBCompound( Compound* root, const Channels& channels,
664 : fabric::ConfigParams params )
665 : {
666 0 : const Channel* channel = root->getChannel();
667 0 : const Layout* layout = channel->getLayout();
668 0 : const std::string& name = layout->getName();
669 :
670 0 : Compound* compound = new Compound( root );
671 0 : compound->setName( name );
672 0 : compound->setBuffers( Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH );
673 0 : if( name == EQ_SERVER_CONFIG_LAYOUT_DB_DYNAMIC )
674 : {
675 0 : if( params.getEqualizer().getMode() != LoadEqualizer::MODE_DB )
676 0 : params.getEqualizer().setMode( LoadEqualizer::MODE_DB );
677 0 : compound->addEqualizer( new LoadEqualizer( params.getEqualizer( )));
678 : }
679 :
680 0 : const Compounds& children = _addSources( compound, channels );
681 0 : const size_t step = size_t( 100000.0f / float( children.size( )));
682 0 : size_t start = 0;
683 0 : for( CompoundsCIter i = children.begin(); i != children.end(); ++i )
684 : {
685 0 : Compound* child = *i;
686 0 : if( i+1 == children.end( )) // last - correct rounding 'error'
687 0 : child->setRange( Range( float( start ) / 100000.f, 1.f ));
688 : else
689 : child->setRange( Range( float( start ) / 100000.f,
690 0 : float( start + step ) / 100000.f ));
691 0 : start += step;
692 : }
693 :
694 0 : return compound;
695 : }
696 :
697 0 : Compound* Resources::_addDSCompound( Compound* root, const Channels& channels )
698 : {
699 0 : const Channel* channel = root->getChannel();
700 0 : const Layout* layout = channel->getLayout();
701 0 : const std::string& name = layout->getName();
702 :
703 0 : Compound* compound = new Compound( root );
704 0 : compound->setName( name );
705 :
706 0 : const Compounds& children = _addSources( compound, channels );
707 0 : const size_t step = size_t( 100000.0f / float( children.size( )));
708 :
709 0 : size_t start = 0;
710 0 : for( CompoundsCIter i = children.begin(); i != children.end(); ++i )
711 : {
712 0 : Compound* child = *i;
713 :
714 : // leaf draw + tile readback compound
715 0 : Compound* drawChild = new Compound( child );
716 0 : if( i+1 == children.end( ) ) // last - correct rounding 'error'
717 0 : drawChild->setRange( Range( float( start )/100000.f, 1.f ));
718 : else
719 : drawChild->setRange( Range( float( start )/100000.f,
720 0 : float( start + step )/100000.f ));
721 :
722 0 : size_t y = 0;
723 0 : for( CompoundsCIter j = children.begin(); j != children.end(); ++j )
724 : {
725 0 : if( i != j )
726 : {
727 0 : std::ostringstream frameName;
728 0 : frameName << "tile" << j - children.begin() << ".channel"
729 0 : << i - children.begin();
730 0 : Viewport vp;
731 0 : if( j+1 == children.end( ) ) // last - correct rounding 'error'
732 : {
733 : vp = Viewport( 0.f, static_cast< float >( y )/100000.f,
734 0 : 1.f, static_cast< float >( 100000-y )/100000.f );
735 : }
736 : else
737 : vp = Viewport( 0.f, static_cast< float >( y )/100000.f,
738 0 : 1.f, static_cast< float >( step )/100000.f );
739 :
740 0 : eq::server::Frame* outputFrame = new eq::server::Frame;
741 0 : outputFrame->setName( frameName.str( ));
742 0 : outputFrame->setViewport( vp );
743 : outputFrame->setBuffers( Frame::BUFFER_COLOR |
744 0 : Frame::BUFFER_DEPTH );
745 0 : drawChild->addOutputFrame( outputFrame );
746 :
747 : // input tiles from other channels
748 0 : frameName.str("");
749 0 : frameName << "tile" << i - children.begin() << ".channel"
750 0 : << j - children.begin();
751 :
752 0 : eq::server::Frame* inputFrame = new eq::server::Frame;
753 0 : inputFrame->setName( frameName.str( ));
754 0 : child->addInputFrame( inputFrame );
755 : }
756 : // else own tile, is in place
757 :
758 0 : y += step;
759 : }
760 :
761 : // assembled color tile output, if not already in place
762 0 : if( child->getChannel() != compound->getChannel( ))
763 : {
764 0 : Frame* output = child->getOutputFrames().front();
765 :
766 0 : Viewport vp;
767 0 : if( i+1 == children.end( )) // last - correct rounding 'error'
768 : {
769 : vp = Viewport( 0.f, static_cast< float >( start )/100000.f,
770 : 1.f,
771 0 : static_cast< float >( 100000-start )/100000.f );
772 : }
773 : else
774 : vp = Viewport( 0.f, static_cast< float >( start )/100000.f,
775 0 : 1.f, static_cast< float >( step )/100000.f );
776 :
777 0 : output->setViewport( vp );
778 : }
779 0 : start += step;
780 : }
781 :
782 0 : return compound;
783 : }
784 :
785 0 : static Channels _filterLocalChannels( const Channels& input,
786 : const Compound& filter )
787 : {
788 0 : Channels result;
789 0 : for( ChannelsCIter i = input.begin(); i != input.end(); ++i )
790 : {
791 0 : const Node* node = (*i)->getNode();
792 0 : const Node* filterNode = filter.getChannel()->getNode();
793 0 : if( node == filterNode )
794 0 : result.push_back( *i );
795 : }
796 0 : return result;
797 : }
798 :
799 0 : Compound* Resources::_addDB2DCompound( Compound* root, const Channels& channels,
800 : fabric::ConfigParams params )
801 : {
802 : // TODO: Optimized compositing?
803 0 : root->setBuffers( Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH );
804 0 : const Channels& dbChannels = _filter( channels, " mt mp " );
805 0 : Compound* compound = _addDSCompound( root, dbChannels );
806 :
807 0 : const Compounds& children = compound->getChildren();
808 0 : for( CompoundsCIter i = children.begin(); i != children.end(); ++i )
809 : {
810 0 : Compound* child = *i;
811 0 : Compound* drawChild = child->getChildren().front();
812 0 : if( params.getEqualizer().getMode() == LoadEqualizer::MODE_DB )
813 0 : params.getEqualizer().setMode( LoadEqualizer::MODE_2D );
814 0 : drawChild->addEqualizer( new LoadEqualizer( params.getEqualizer( )));
815 0 : drawChild->setName( EQ_SERVER_CONFIG_LAYOUT_2D_DYNAMIC );
816 :
817 : const Channels& localChannels = _filterLocalChannels( channels,
818 0 : *child );
819 0 : _fill2DCompound( drawChild, localChannels );
820 0 : }
821 :
822 0 : return compound;
823 : }
824 :
825 0 : Compound* Resources::_addSubpixelCompound( Compound* root,
826 : const Channels& channels )
827 : {
828 0 : Compound* compound = new Compound( root );
829 0 : compound->setName( EQ_SERVER_CONFIG_LAYOUT_SUBPIXEL );
830 :
831 0 : const Compounds& children = _addSources( compound, channels, true );
832 0 : const uint32_t nChildren = uint32_t( children.size( ));
833 0 : for( CompoundsCIter i = children.begin(); i != children.end(); ++i )
834 0 : (*i)->setSubPixel( SubPixel( i - children.begin(), nChildren ));
835 :
836 0 : return compound;
837 : }
838 :
839 0 : const Compounds& Resources::_addSources( Compound* compound,
840 : const Channels& channels,
841 : const bool destChannelFrame )
842 : {
843 0 : const Channel* rootChannel = compound->getChannel();
844 0 : const Segment* segment = rootChannel->getSegment();
845 0 : const Channel* outputChannel = segment ? segment->getChannel() : 0;
846 :
847 0 : for( ChannelsCIter i = channels.begin(); i != channels.end(); ++i )
848 : {
849 0 : Channel* channel = *i;
850 0 : Compound* child = new Compound( compound );
851 :
852 0 : const bool isDestChannel = channel == outputChannel;
853 0 : if( isDestChannel && !destChannelFrame )
854 0 : continue;
855 0 : if( !isDestChannel )
856 0 : child->setChannel( channel );
857 :
858 0 : Frame* outFrame = new Frame;
859 0 : std::stringstream frameName;
860 0 : frameName << "Frame." << compound->getName() << '.' << ++_frameCounter;
861 0 : outFrame->setName( frameName.str( ));
862 0 : if( isDestChannel )
863 0 : outFrame->setType( Frame::TYPE_TEXTURE ); // OPT
864 0 : child->addOutputFrame( outFrame );
865 :
866 0 : Frame* inFrame = new Frame;
867 0 : inFrame->setName( frameName.str( ));
868 0 : compound->addInputFrame( inFrame );
869 0 : }
870 :
871 0 : return compound->getChildren();
872 : }
873 :
874 : }
875 : }
876 84 : }
|