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