void TreeEqualizer::_notifyLoadData( Node* node, Channel* channel, const uint32_t nStatistics, const Statistic* statistics ) { if( !node ) return; _notifyLoadData( node->left, channel, nStatistics, statistics ); _notifyLoadData( node->right, channel, nStatistics, statistics ); if( !node->compound || node->compound->getChannel() != channel ) return; // gather relevant load data const uint32_t taskID = node->compound->getTaskID(); int64_t startTime = std::numeric_limits< int64_t >::max(); int64_t endTime = 0; bool loadSet = false; int64_t timeTransmit = 0; for( uint32_t i = 0; i < nStatistics && !loadSet; ++i ) { const Statistic& stat = statistics[ i ]; if( stat.task != taskID ) // from different compound continue; switch( stat.type ) { case Statistic::CHANNEL_CLEAR: case Statistic::CHANNEL_DRAW: case Statistic::CHANNEL_READBACK: startTime = LB_MIN( startTime, stat.startTime ); endTime = LB_MAX( endTime, stat.endTime ); break; case Statistic::CHANNEL_ASYNC_READBACK: case Statistic::CHANNEL_FRAME_TRANSMIT: timeTransmit += stat.endTime - stat.startTime; break; // assemble blocks on input frames, stop using subsequent data case Statistic::CHANNEL_ASSEMBLE: loadSet = true; break; default: break; } } if( startTime == std::numeric_limits< int64_t >::max( )) return; node->time = endTime - startTime; node->time = LB_MAX( node->time, 1 ); node->time = LB_MAX( node->time, timeTransmit ); }
void Config::_adjustResistance( const int delta ) { View* view = _getCurrentView(); if( !view ) return; eq::Vector2i size = view->getEqualizer().getResistance2i(); size += delta; size.x() = LB_MAX( size.x(), 0 ); size.y() = LB_MAX( size.y(), 0 ); std::ostringstream stream; stream << "Set load equalizer resistance to " << size; _setMessage( stream.str( )); view->getEqualizer().setResistance( size ); }
void FramerateEqualizer::_init() { const Compound* compound = getCompound(); if( _nSamples > 0 || !compound ) return; _nSamples = 1; // Subscribe to child channel load events const Compounds& children = compound->getChildren(); LBASSERT( _loadListeners.empty( )); _loadListeners.resize( children.size( )); for( size_t i = 0; i < children.size(); ++i ) { Compound* child = children[i]; const uint32_t period = child->getInheritPeriod(); LoadListener& loadListener = _loadListeners[i]; loadListener.parent = this; loadListener.period = period; LoadSubscriber subscriber( &loadListener ); child->accept( subscriber ); _nSamples = LB_MAX( _nSamples, period ); } _nSamples = LB_MIN( _nSamples, 100 ); }
void Channel::frameViewFinish( const eq::uint128_t& frameID ) { if( stopRendering( )) return; applyBuffer(); const FrameData& frameData = _getFrameData(); Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; if( accum.buffer ) { const eq::PixelViewport& pvp = getPixelViewport(); const bool isResized = accum.buffer->resize( pvp ); if( isResized ) { const View* view = static_cast< const View* >( getView( )); accum.buffer->clear(); accum.step = view->getIdleSteps(); accum.stepsDone = 0; } else if( frameData.isIdle( )) { setupAssemblyState(); if( !_isDone() && accum.transfer ) accum.buffer->accum(); accum.buffer->display(); resetAssemblyState(); } } applyViewport(); _drawOverlay(); _drawHelp(); if( frameData.useStatistics()) drawStatistics(); int32_t steps = 0; if( frameData.isIdle( )) { for( size_t i = 0; i < eq::NUM_EYES; ++i ) steps = LB_MAX( steps, _accum[i].step ); } else { const View* view = static_cast< const View* >( getView( )); steps = view ? view->getIdleSteps() : 0; } // if _jitterStep == 0 and no user redraw event happened, the app will exit // FSAA idle mode and block on the next redraw event. eq::Config* config = getConfig(); config->sendEvent( IDLE_AA_LEFT ) << steps; eq::Channel::frameViewFinish( frameID ); }
/** Volume always represented as cube [-1,-1,-1]..[1,1,1], so if the model is not cube it's proportions should be modified. This function makes maximum proportion equal to 1.0 to prevent unnecessary rescaling. */ static void normalizeScaling(const uint32_t w, const uint32_t h, const uint32_t d, VolumeScaling& scaling) { // Correct proportions according to real size of volume float maxS = float(LB_MAX(w, LB_MAX(h, d))); scaling.W *= w / maxS; scaling.H *= h / maxS; scaling.D *= d / maxS; // Make maximum proportion equal to 1.0 maxS = LB_MAX(scaling.W, LB_MAX(scaling.H, scaling.D)); scaling.W /= maxS; scaling.H /= maxS; scaling.D /= maxS; }
void Channel::_updateNearFar( const mesh::BoundingSphere& boundingSphere ) { // compute dynamic near/far plane of whole model const FrameData& frameData = _getFrameData(); const eq::Matrix4f& rotation = frameData.getCameraRotation(); const eq::Matrix4f headTransform = getHeadTransform() * rotation; eq::Matrix4f modelInv; compute_inverse( headTransform, modelInv ); const eq::Vector3f zero = modelInv * eq::Vector3f::ZERO; eq::Vector3f front = modelInv * eq::Vector3f( 0.0f, 0.0f, -1.0f ); front -= zero; front.normalize(); front *= boundingSphere.w(); const eq::Vector3f center = frameData.getCameraPosition().get_sub_vector< 3 >() - boundingSphere.get_sub_vector< 3 >(); const eq::Vector3f nearPoint = headTransform * ( center - front ); const eq::Vector3f farPoint = headTransform * ( center + front ); if( useOrtho( )) { LBASSERTINFO( fabs( farPoint.z() - nearPoint.z() ) > std::numeric_limits< float >::epsilon(), nearPoint << " == " << farPoint ); setNearFar( -nearPoint.z(), -farPoint.z() ); } else { // estimate minimal value of near plane based on frustum size const eq::Frustumf& frustum = getFrustum(); const float width = fabs( frustum.right() - frustum.left() ); const float height = fabs( frustum.top() - frustum.bottom() ); const float size = LB_MIN( width, height ); const float minNear = frustum.near_plane() / size * .001f; const float zNear = LB_MAX( minNear, -nearPoint.z() ); const float zFar = LB_MAX( zNear * 2.f, -farPoint.z() ); setNearFar( zNear, zFar ); } }
void FrameData::adjustQuality( const float delta ) { _quality += delta; _quality = LB_MAX( _quality, 0.1f ); _quality = LB_MIN( _quality, 1.0f ); setDirty( DIRTY_FLAGS ); LBINFO << "Set non-idle image quality to " << _quality << std::endl; }
void FramerateEqualizer::LoadListener::notifyLoadData( Channel* channel, const uint32_t frameNumber, const Statistics& statistics, const Viewport& region ) { // gather required load data int64_t startTime = std::numeric_limits< int64_t >::max(); int64_t endTime = 0; for( size_t i = 0; i < statistics.size(); ++i ) { const eq::Statistic& data = statistics[i]; switch( data.type ) { case eq::Statistic::CHANNEL_CLEAR: case eq::Statistic::CHANNEL_DRAW: case eq::Statistic::CHANNEL_ASSEMBLE: case eq::Statistic::CHANNEL_READBACK: startTime = LB_MIN( startTime, data.startTime ); endTime = LB_MAX( endTime, data.endTime ); break; default: break; } } if( startTime == std::numeric_limits< int64_t >::max( )) return; if( startTime == endTime ) // very fast draws might report 0 times ++endTime; for( std::deque< FrameTime >::iterator i = parent->_times.begin(); i != parent->_times.end(); ++i ) { FrameTime& frameTime = *i; if( frameTime.first != frameNumber ) continue; const float time = static_cast< float >( endTime - startTime ) / period; frameTime.second = LB_MAX( frameTime.second, time ); LBLOG( LOG_LB2 ) << "Frame " << frameNumber << " channel " << channel->getName() << " time " << time << " period " << period << std::endl; } }
void Channel::frameAssemble( const eq::uint128_t& frameID ) { if( stopRendering( )) return; if( _isDone( )) return; Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; if( getPixelViewport() != _currentPVP ) { accum.transfer = true; if( accum.buffer && !accum.buffer->usesFBO( )) { LBWARN << "Current viewport different from view viewport, " << "idle anti-aliasing not implemented." << std::endl; accum.step = 0; } eq::Channel::frameAssemble( frameID ); return; } // else accum.transfer = true; const eq::Frames& frames = getInputFrames(); for( eq::Frames::const_iterator i = frames.begin(); i != frames.end(); ++i ) { eq::Frame* frame = *i; const eq::SubPixel& curSubPixel = frame->getSubPixel(); if( curSubPixel != eq::SubPixel::ALL ) accum.transfer = false; accum.stepsDone = LB_MAX( accum.stepsDone, frame->getSubPixel().size*frame->getPeriod( )); } applyBuffer(); applyViewport(); setupAssemblyState(); try { eq::Compositor::assembleFrames( getInputFrames(), this, accum.buffer ); } catch( const co::Exception& e ) { LBWARN << e.what() << std::endl; } resetAssemblyState(); }
void Channel::frameAssemble( const eq::uint128_t& frameID, const eq::Frames& frames ) { if( stopRendering( )) return; if( _isDone( )) return; Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; if( getPixelViewport() != _currentPVP ) { accum.transfer = true; if( accum.buffer && !accum.buffer->usesFBO( )) { LBWARN << "Current viewport different from view viewport, " << "idle anti-aliasing not implemented." << std::endl; accum.step = 0; } eq::Channel::frameAssemble( frameID, frames ); return; } // else accum.transfer = true; for( eq::Frame* frame : frames ) { const eq::SubPixel& subPixel = frame->getFrameData()->getContext().subPixel; if( subPixel != eq::SubPixel::ALL ) accum.transfer = false; accum.stepsDone = LB_MAX( accum.stepsDone, subPixel.size * frame->getFrameData()->getContext().period ); } applyBuffer(); applyViewport(); setupAssemblyState(); try { eq::Compositor::assembleFrames( frames, this, accum.buffer.get( )); } catch( const co::Exception& e ) { LBWARN << e.what() << std::endl; } resetAssemblyState(); }
void Renderer::updateNearFar( const Vector4f& boundingSphere ) { const Matrix4f& view = getViewMatrix(); Matrix4f viewInv; compute_inverse( view, viewInv ); const Vector3f& zero = viewInv * Vector3f::ZERO; Vector3f front = viewInv * Vector3f( 0.0f, 0.0f, -1.0f ); front -= zero; front.normalize(); front *= boundingSphere.w(); const Vector3f& translation = getModelMatrix().get_translation(); const Vector3f& center = translation - boundingSphere.get_sub_vector< 3 >(); const Vector3f& nearPoint = view * ( center - front ); const Vector3f& farPoint = view * ( center + front ); if( _impl->useOrtho( )) { LBASSERTINFO( fabs( farPoint.z() - nearPoint.z() ) > std::numeric_limits< float >::epsilon(), nearPoint << " == " << farPoint ); setNearFar( -nearPoint.z(), -farPoint.z() ); } else { // estimate minimal value of near plane based on frustum size const eq::Frustumf& frustum = _impl->getFrustum(); const float width = fabs( frustum.right() - frustum.left() ); const float height = fabs( frustum.top() - frustum.bottom() ); const float size = LB_MIN( width, height ); const float minNear = frustum.near_plane() / size * .001f; const float zNear = LB_MAX( minNear, -nearPoint.z() ); const float zFar = LB_MAX( zNear * 2.f, -farPoint.z() ); setNearFar( zNear, zFar ); } }
uint128_t computeMinMax() const { uint64_t xMax = 0; uint64_t xMin = std::numeric_limits<uint64_t>::max(); for (ItemsCIter i = items.begin(); i != items.end(); ++i) { const Item& item = *i; xMin = LB_MIN(xMin, item.start); xMax = LB_MAX(xMax, item.end); } return uint128_t(xMax, xMin); }
bool CameraPath::loadAnimation( const std::string& fileName ) { steps_.clear(); if( fileName.empty( ) ) return false; std::ifstream file; file.open( fileName.c_str( )); if( !file ) { LBERROR << "Path file could not be opened" << std::endl; return false; } // read model pre-rotation file >> modelRotation_.x(); file >> modelRotation_.y(); file >> modelRotation_.z(); const float m = static_cast< float >( M_PI_2 ) / 90.f; modelRotation_ *= m; uint32_t count = 0; float v[7]; totalFrameNumber_ = 0; while ( !file.eof( )) { file >> v[ count++ ]; if( count == 7 ) { count = 0; totalFrameNumber_ += LB_MAX( static_cast<int>( v[0] ), 1 ); steps_.push_back( Step( totalFrameNumber_, Vector3f( v[1] , v[2] , v[3] ), Vector3f( -v[5]*m, v[4]*m, v[6]*m ))); } } file.close(); return true; }
void OCommand::sendData( const void* buffer, const uint64_t size, const bool last ) { LBASSERT( !_impl->dispatcher ); LBASSERT( last ); LBASSERTINFO( size >= 16, size ); LBASSERT( getBuffer().getData() == buffer ); LBASSERT( getBuffer().getSize() == size ); LBASSERT( getBuffer().getMaxSize() >= COMMAND_MINSIZE ); // Update size field uint8_t* bytes = getBuffer().getData(); reinterpret_cast< uint64_t* >( bytes )[ 0 ] = _impl->size + size; const uint64_t sendSize = _impl->isLocked ? size : LB_MAX( size, COMMAND_MINSIZE); const Connections& connections = getConnections(); for( ConnectionsCIter i = connections.begin(); i != connections.end(); ++i ) { ConnectionPtr connection = *i; connection->send( bytes, sendSize, _impl->isLocked ); } }
bool Pipe::_cmdFrameStart( co::ICommand& cmd ) { LB_TS_THREAD( _pipeThread ); co::ObjectICommand command( cmd ); const uint128_t version = command.get< uint128_t >(); const uint128_t frameID = command.get< uint128_t >(); const uint32_t frameNumber = command.get< uint32_t >(); LBVERB << "handle pipe frame start " << command << " frame " << frameNumber << " id " << frameID << std::endl; LBLOG( LOG_TASKS ) << "---- TASK start frame ---- frame " << frameNumber << " id " << frameID << std::endl; sync( version ); const int64_t lastFrameTime = _impl->frameTime; _impl->frameTimeMutex.set(); LBASSERT( !_impl->frameTimes.empty( )); _impl->frameTime = _impl->frameTimes.front(); _impl->frameTimes.pop_front(); _impl->frameTimeMutex.unset(); if( lastFrameTime > 0 ) { PipeStatistics waitEvent( Statistic::PIPE_IDLE, this ); waitEvent.event.statistic.idleTime = _impl->thread ? _impl->thread->getWorkerQueue()->resetWaitTime() :0; waitEvent.event.statistic.totalTime = LB_MAX( _impl->frameTime - lastFrameTime, 1 ); // avoid SIGFPE } LBASSERTINFO( _impl->currentFrame + 1 == frameNumber, "current " <<_impl->currentFrame << " start " << frameNumber); frameStart( frameID, frameNumber ); return true; }
void FramerateEqualizer::notifyUpdatePre( Compound* compound, const uint32_t frameNumber ) { _init(); // find starting point of contiguous block const ssize_t size = static_cast< ssize_t >( _times.size( )); ssize_t from = 0; if( size > 0 ) { for( ssize_t i = size-1; i >= 0; --i ) { if( _times[i].second != 0.f ) continue; from = i; break; } } // find max / avg time in block size_t nSamples = 0; #ifdef USE_AVERAGE float sumTime = 0.f; #else float maxTime = 0.f; #endif for( ++from; from < size && nSamples < _nSamples; ++from ) { const FrameTime& time = _times[from]; LBASSERT( time.first > 0 ); LBASSERT( time.second != 0.f ); ++nSamples; #ifdef USE_AVERAGE sumTime += time.second; #else maxTime = LB_MAX( maxTime, time.second ); #endif LBLOG( LOG_LB2 ) << "Using " << time.first << ", " << time.second << "ms" << std::endl; } if( nSamples == _nSamples ) // If we have a full set while( from < static_cast< ssize_t >( _times.size( ))) _times.pop_back(); // delete all older samples if( isFrozen() || !compound->isActive() || !isActive( )) { // always execute code above to not leak memory compound->setMaxFPS( std::numeric_limits< float >::max( )); return; } if( nSamples > 0 ) { //TODO: totalTime *= 1.f - damping; #ifdef USE_AVERAGE const float time = (sumTime / nSamples) * SLOWDOWN; #else const float time = maxTime * SLOWDOWN; #endif const float fps = 1000.f / time; #ifdef VSYNC_CAP if( fps > VSYNC_CAP ) compound->setMaxFPS( std::numeric_limits< float >::max( )); else #endif compound->setMaxFPS( fps ); LBLOG( LOG_LB2 ) << fps << " Hz from " << nSamples << "/" << _times.size() << " samples, " << time << "ms" << std::endl; } _times.push_front( FrameTime( frameNumber, 0.f )); LBASSERT( _times.size() < 210 ); }
bool Config::handleEvent( eq::EventICommand command ) { switch( command.getEventType( )) { case eq::Event::KEY_PRESS: { const eq::Event& event = command.get< eq::Event >(); if( _handleKeyEvent( event.keyPress )) { _redraw = true; return true; } break; } case eq::Event::CHANNEL_POINTER_BUTTON_PRESS: { const eq::Event& event = command.get< eq::Event >(); const eq::uint128_t& viewID = event.context.view.identifier; _frameData.setCurrentViewID( viewID ); if( viewID == 0 ) { _currentCanvas = 0; return false; } const View* view = _getCurrentView(); const eq::Layout* layout = view->getLayout(); const eq::Canvases& canvases = getCanvases(); for( eq::CanvasesCIter i = canvases.begin(); i != canvases.end(); ++i ) { eq::Canvas* canvas = *i; const eq::Layout* canvasLayout = canvas->getActiveLayout(); if( canvasLayout == layout ) { _currentCanvas = canvas; return true; } } return true; } case eq::Event::CHANNEL_POINTER_BUTTON_RELEASE: { const eq::Event& event = command.get< eq::Event >(); const eq::PointerEvent& releaseEvent = event.pointerButtonRelease; if( releaseEvent.buttons == eq::PTR_BUTTON_NONE) { if( releaseEvent.button == eq::PTR_BUTTON1 ) { _spinX = releaseEvent.dy; _spinY = releaseEvent.dx; _redraw = true; return true; } if( releaseEvent.button == eq::PTR_BUTTON2 ) { _advance = -releaseEvent.dy; _redraw = true; return true; } } break; } case eq::Event::CHANNEL_POINTER_MOTION: { const eq::Event& event = command.get< eq::Event >(); switch( event.pointerMotion.buttons ) { case eq::PTR_BUTTON1: _spinX = 0; _spinY = 0; if( _frameData.usePilotMode()) _frameData.spinCamera( -0.005f * event.pointerMotion.dy, -0.005f * event.pointerMotion.dx ); else _frameData.spinModel( -0.005f * event.pointerMotion.dy, -0.005f * event.pointerMotion.dx, 0.f ); _redraw = true; return true; case eq::PTR_BUTTON2: _advance = -event.pointerMotion.dy; _frameData.moveCamera( 0.f, 0.f, .005f * _advance ); _redraw = true; return true; case eq::PTR_BUTTON3: _frameData.moveCamera( .0005f * event.pointerMotion.dx, -.0005f * event.pointerMotion.dy, 0.f ); _redraw = true; return true; } break; } case eq::Event::CHANNEL_POINTER_WHEEL: { const eq::Event& event = command.get< eq::Event >(); _frameData.moveCamera( -0.05f * event.pointerWheel.yAxis, 0.f, 0.05f * event.pointerWheel.xAxis ); _redraw = true; return true; } case eq::Event::MAGELLAN_AXIS: { const eq::Event& event = command.get< eq::Event >(); _spinX = 0; _spinY = 0; _advance = 0; _frameData.spinModel( 0.0001f * event.magellan.xRotation, 0.0001f * event.magellan.yRotation, 0.0001f * event.magellan.zRotation ); _frameData.moveCamera( 0.0001f * event.magellan.xAxis, 0.0001f * event.magellan.yAxis, 0.0001f * event.magellan.zAxis ); _redraw = true; return true; } case eq::Event::MAGELLAN_BUTTON: { const eq::Event& event = command.get< eq::Event >(); if( event.magellan.button == eq::PTR_BUTTON1 ) _frameData.toggleColorMode(); _redraw = true; return true; } case eq::Event::WINDOW_EXPOSE: case eq::Event::WINDOW_RESIZE: case eq::Event::WINDOW_CLOSE: case eq::Event::VIEW_RESIZE: _redraw = true; break; case IDLE_AA_LEFT: if( _useIdleAA ) { const int32_t steps = command.get< int32_t >(); _numFramesAA = LB_MAX( _numFramesAA, steps ); } else _numFramesAA = 0; return false; default: break; } _redraw |= eq::Config::handleEvent( command ); return _redraw; }
void ViewEqualizer::Listener::notifyLoadData(Channel* channel, const uint32_t frameNumber, const Statistics& statistics, const Viewport& /*region*/) { Load& load = _getLoad(frameNumber); if (load == Load::NONE) return; LBASSERT(_taskIDs.find(channel) != _taskIDs.end()); const uint32_t taskID = _taskIDs[channel]; // gather relevant load data int64_t startTime = std::numeric_limits<int64_t>::max(); int64_t endTime = 0; bool loadSet = false; int64_t transmitTime = 0; for (size_t i = 0; i < statistics.size() && !loadSet; ++i) { const Statistic& data = statistics[i]; if (data.task != taskID) // data from another compound continue; switch (data.type) { case Statistic::CHANNEL_CLEAR: case Statistic::CHANNEL_DRAW: case Statistic::CHANNEL_READBACK: startTime = LB_MIN(startTime, data.startTime); endTime = LB_MAX(endTime, data.endTime); break; case Statistic::CHANNEL_ASYNC_READBACK: case Statistic::CHANNEL_FRAME_TRANSMIT: transmitTime += data.startTime - data.endTime; break; case Statistic::CHANNEL_FRAME_WAIT_SENDTOKEN: transmitTime -= data.endTime - data.startTime; break; // assemble blocks on input frames, stop using subsequent data case Statistic::CHANNEL_ASSEMBLE: loadSet = true; break; default: break; } } if (startTime == std::numeric_limits<int64_t>::max()) return; LBASSERTINFO(load.missing > 0, load << " for " << channel->getName() << " " << channel->getSerial()); const int64_t time = LB_MAX(endTime - startTime, transmitTime); load.time += time; --load.missing; if (load.missing == 0) { const float rTime = float(load.time) / float(load.nResources); load.time = int64_t(rTime * sqrtf(float(load.nResources))); } LBLOG(LOG_LB1) << "Task " << taskID << ", added time " << time << " to " << load << " from " << channel->getName() << " " << channel->getSerial() << std::endl; }
void LoadEqualizer::_computeSplit( Node* node, const float time, LBDatas* datas, const Viewport& vp, const Range& range ) { LBLOG( LOG_LB2 ) << "_computeSplit " << vp << ", " << range << " time " << time << std::endl; LBASSERTINFO( vp.isValid(), vp ); LBASSERTINFO( range.isValid(), range ); LBASSERTINFO( node->resources > 0.f || !vp.hasArea() || !range.hasData(), "Assigning " << node->resources << " work to viewport " << vp << ", " << range ); Compound* compound = node->compound; if( compound ) { _assign( compound, vp, range ); return; } LBASSERT( node->left && node->right ); LBDatas workingSet = datas[ node->mode ]; const float leftTime = node->resources > 0 ? time * node->left->resources / node->resources : 0.f; float timeLeft = LB_MIN( leftTime, time ); // correct for fp rounding error switch( node->mode ) { case MODE_VERTICAL: { LBASSERT( range == Range::ALL ); float splitPos = vp.x; const float end = vp.getXEnd(); while( timeLeft > std::numeric_limits< float >::epsilon() && splitPos < end ) { LBLOG( LOG_LB2 ) << timeLeft << "ms left using " << workingSet.size() << " tiles" << std::endl; // remove all irrelevant items from working set for( LBDatas::iterator i = workingSet.begin(); i != workingSet.end(); ) { const Data& data = *i; if( data.vp.getXEnd() > splitPos ) ++i; else i = workingSet.erase( i ); } if( workingSet.empty( )) break; // find next 'discontinouity' in loads float currentPos = 1.0f; for( LBDatas::const_iterator i = workingSet.begin(); i != workingSet.end(); ++i ) { const Data& data = *i; if( data.vp.x > splitPos && data.vp.x < currentPos ) currentPos = data.vp.x; const float xEnd = data.vp.getXEnd(); if( xEnd > splitPos && xEnd < currentPos ) currentPos = xEnd; } const float width = currentPos - splitPos; LBASSERTINFO( width > 0.f, currentPos << "<=" << splitPos ); LBASSERT( currentPos <= 1.0f ); // accumulate normalized load in splitPos...currentPos LBLOG( LOG_LB2 ) << "Computing load in X " << splitPos << "..." << currentPos << std::endl; float currentTime = 0.f; for( LBDatas::const_iterator i = workingSet.begin(); i != workingSet.end(); ++i ) { const Data& data = *i; if( data.vp.x >= currentPos ) // not yet needed data sets break; float yContrib = data.vp.h; if( data.vp.y < vp.y ) yContrib -= (vp.y - data.vp.y); const float dataEnd = data.vp.getYEnd(); const float vpEnd = vp.getYEnd(); if( dataEnd > vpEnd ) yContrib -= (dataEnd - vpEnd); if( yContrib > 0.f ) { const float percentage = ( width / data.vp.w ) * ( yContrib / data.vp.h ); currentTime += ( data.time * percentage ); LBLOG( LOG_LB2 ) << data.vp << " contributes " << yContrib << " in " << vp.h << " (" << percentage << ") with " << data.time << ": " << ( data.time * percentage ) << " vp.y " << vp.y << " dataEnd " << dataEnd << " vpEnd " << vpEnd << std::endl; LBASSERT( percentage < 1.01f ) } } LBLOG( LOG_LB2 ) << splitPos << "..." << currentPos << ": t=" << currentTime << " of " << timeLeft << std::endl; if( currentTime >= timeLeft ) // found last region { splitPos += ( width * timeLeft / currentTime ); timeLeft = 0.0f; } else { timeLeft -= currentTime; splitPos = currentPos; } } LBLOG( LOG_LB2 ) << "Should split at X " << splitPos << std::endl; if( getDamping() < 1.f ) splitPos = (1.f - getDamping()) * splitPos + getDamping() * node->split; LBLOG( LOG_LB2 ) << "Dampened split at X " << splitPos << std::endl; // There might be more time left due to MIN_PIXEL rounding by parent // LBASSERTINFO( timeLeft <= .001f, timeLeft ); // Ensure minimum size const Compound* root = getCompound(); const float pvpW = static_cast< float >( root->getInheritPixelViewport().w ); const float boundary = static_cast< float >( node->boundary2i.x()) / pvpW; if( node->left->resources == 0.f ) splitPos = vp.x; else if( node->right->resources == 0.f ) splitPos = end; else if( boundary > 0 ) { const float lengthRight = vp.getXEnd() - splitPos; const float lengthLeft = splitPos - vp.x; const float maxRight = static_cast< float >( node->right->maxSize.x( )) / pvpW; const float maxLeft = static_cast< float >( node->left->maxSize.x( )) / pvpW; if( lengthRight > maxRight ) splitPos = end - maxRight; else if( lengthLeft > maxLeft ) splitPos = vp.x + maxLeft; if( (splitPos - vp.x) < boundary ) splitPos = vp.x + boundary; if( (end - splitPos) < boundary ) splitPos = end - boundary; const uint32_t ratio = static_cast< uint32_t >( splitPos / boundary + .5f ); splitPos = ratio * boundary; } splitPos = LB_MAX( splitPos, vp.x ); splitPos = LB_MIN( splitPos, end); const float newPixelW = pvpW * splitPos; const float oldPixelW = pvpW * node->split; if( int( fabs(newPixelW - oldPixelW) ) < node->resistance2i.x( )) splitPos = node->split; else node->split = splitPos; LBLOG( LOG_LB2 ) << "Constrained split " << vp << " at X " << splitPos << std::endl; // balance children Viewport childVP = vp; childVP.w = (splitPos - vp.x); _computeSplit( node->left, leftTime, datas, childVP, range ); childVP.x = childVP.getXEnd(); childVP.w = end - childVP.x; // Fix 2994111: Rounding errors with 2D LB and 16 sources // Floating point rounding may create a width for the 'right' // child which is slightly below the parent width. Correct it. while( childVP.getXEnd() < end ) childVP.w += std::numeric_limits< float >::epsilon(); _computeSplit( node->right, time-leftTime, datas, childVP, range ); break; } case MODE_HORIZONTAL: { LBASSERT( range == Range::ALL ); float splitPos = vp.y; const float end = vp.getYEnd(); while( timeLeft > std::numeric_limits< float >::epsilon() && splitPos < end ) { LBLOG( LOG_LB2 ) << timeLeft << "ms left using " << workingSet.size() << " tiles" << std::endl; // remove all unrelevant items from working set for( LBDatas::iterator i = workingSet.begin(); i != workingSet.end(); ) { const Data& data = *i; if( data.vp.getYEnd() > splitPos ) ++i; else i = workingSet.erase( i ); } if( workingSet.empty( )) break; // find next 'discontinuouity' in loads float currentPos = 1.0f; for( LBDatas::const_iterator i = workingSet.begin(); i != workingSet.end(); ++i ) { const Data& data = *i; if( data.vp.y > splitPos && data.vp.y < currentPos ) currentPos = data.vp.y; const float yEnd = data.vp.getYEnd(); if( yEnd > splitPos && yEnd < currentPos ) currentPos = yEnd; } const float height = currentPos - splitPos; LBASSERTINFO( height > 0.f, currentPos << "<=" << splitPos ); LBASSERT( currentPos <= 1.0f ); // accumulate normalized load in splitPos...currentPos LBLOG( LOG_LB2 ) << "Computing load in Y " << splitPos << "..." << currentPos << std::endl; float currentTime = 0.f; for( LBDatas::const_iterator i = workingSet.begin(); i != workingSet.end(); ++i ) { const Data& data = *i; if( data.vp.y >= currentPos ) // not yet needed data sets break; float xContrib = data.vp.w; if( data.vp.x < vp.x ) xContrib -= (vp.x - data.vp.x); const float dataEnd = data.vp.getXEnd(); const float vpEnd = vp.getXEnd(); if( dataEnd > vpEnd ) xContrib -= (dataEnd - vpEnd); if( xContrib > 0.f ) { const float percentage = ( height / data.vp.h ) * ( xContrib / data.vp.w ); currentTime += ( data.time * percentage ); LBLOG( LOG_LB2 ) << data.vp << " contributes " << xContrib << " in " << vp.w << " (" << percentage << ") with " << data.time << ": " << ( data.time * percentage ) << " total " << currentTime << " vp.x " << vp.x << " dataEnd " << dataEnd << " vpEnd " << vpEnd << std::endl; LBASSERT( percentage < 1.01f ) } } LBLOG( LOG_LB2 ) << splitPos << "..." << currentPos << ": t=" << currentTime << " of " << timeLeft << std::endl; if( currentTime >= timeLeft ) // found last region { splitPos += (height * timeLeft / currentTime ); timeLeft = 0.0f; } else { timeLeft -= currentTime; splitPos = currentPos; } } LBLOG( LOG_LB2 ) << "Should split at Y " << splitPos << std::endl; if( getDamping() < 1.f ) splitPos = (1.f - getDamping( )) * splitPos + getDamping() * node->split; LBLOG( LOG_LB2 ) << "Dampened split at Y " << splitPos << std::endl; const Compound* root = getCompound(); const float pvpH = static_cast< float >( root->getInheritPixelViewport().h ); const float boundary = static_cast< float >(node->boundary2i.y( )) / pvpH; if( node->left->resources == 0.f ) splitPos = vp.y; else if( node->right->resources == 0.f ) splitPos = end; else if ( boundary > 0 ) { const float lengthRight = vp.getYEnd() - splitPos; const float lengthLeft = splitPos - vp.y; const float maxRight = static_cast< float >( node->right->maxSize.y( )) / pvpH; const float maxLeft = static_cast< float >( node->left->maxSize.y( )) / pvpH; if( lengthRight > maxRight ) splitPos = end - maxRight; else if( lengthLeft > maxLeft ) splitPos = vp.y + maxLeft; if( (splitPos - vp.y) < boundary ) splitPos = vp.y + boundary; if( (end - splitPos) < boundary ) splitPos = end - boundary; const uint32_t ratio = static_cast< uint32_t >( splitPos / boundary + .5f ); splitPos = ratio * boundary; } splitPos = LB_MAX( splitPos, vp.y ); splitPos = LB_MIN( splitPos, end ); const float newPixelH = pvpH * splitPos; const float oldPixelH = pvpH * node->split; if( int( fabs(newPixelH - oldPixelH) ) < node->resistance2i.y( )) splitPos = node->split; else node->split = splitPos; LBLOG( LOG_LB2 ) << "Constrained split " << vp << " at Y " << splitPos << std::endl; Viewport childVP = vp; childVP.h = (splitPos - vp.y); _computeSplit( node->left, leftTime, datas, childVP, range ); childVP.y = childVP.getYEnd(); childVP.h = end - childVP.y; while( childVP.getYEnd() < end ) childVP.h += std::numeric_limits< float >::epsilon(); _computeSplit( node->right, time - leftTime, datas, childVP, range); break; } case MODE_DB: { LBASSERT( vp == Viewport::FULL ); float splitPos = range.start; const float end = range.end; while( timeLeft > std::numeric_limits< float >::epsilon() && splitPos < end ) { LBLOG( LOG_LB2 ) << timeLeft << "ms left using " << workingSet.size() << " tiles" << std::endl; // remove all irrelevant items from working set for( LBDatas::iterator i = workingSet.begin(); i != workingSet.end(); ) { const Data& data = *i; if( data.range.end > splitPos ) ++i; else i = workingSet.erase( i ); } if( workingSet.empty( )) break; // find next 'discontinouity' in loads float currentPos = 1.0f; for( LBDatas::const_iterator i = workingSet.begin(); i != workingSet.end(); ++i ) { const Data& data = *i; currentPos = LB_MIN( currentPos, data.range.end ); } const float size = currentPos - splitPos; LBASSERTINFO( size > 0.f, currentPos << "<=" << splitPos ); LBASSERT( currentPos <= 1.0f ); // accumulate normalized load in splitPos...currentPos LBLOG( LOG_LB2 ) << "Computing load in range " << splitPos << "..." << currentPos << std::endl; float currentTime = 0.f; for( LBDatas::const_iterator i = workingSet.begin(); i != workingSet.end(); ++i ) { const Data& data = *i; if( data.range.start >= currentPos ) // not yet needed data break; #if 0 // make sure we cover full area LBASSERTINFO( data.range.start <= splitPos, data.range.start << " > " << splitPos ); LBASSERTINFO( data.range.end >= currentPos, data.range.end << " < " << currentPos); #endif currentTime += data.time * size / data.range.getSize(); } LBLOG( LOG_LB2 ) << splitPos << "..." << currentPos << ": t=" << currentTime << " of " << timeLeft << std::endl; if( currentTime >= timeLeft ) // found last region { const float width = currentPos - splitPos; splitPos += (width * timeLeft / currentTime ); timeLeft = 0.0f; } else { timeLeft -= currentTime; splitPos = currentPos; } } LBLOG( LOG_LB2 ) << "Should split at " << splitPos << std::endl; if( getDamping() < 1.f ) splitPos = (1.f - getDamping( )) * splitPos + getDamping() * node->split; LBLOG( LOG_LB2 ) << "Dampened split at " << splitPos << std::endl; const float boundary( node->boundaryf ); if( node->left->resources == 0.f ) splitPos = range.start; else if( node->right->resources == 0.f ) splitPos = end; const uint32_t ratio = static_cast< uint32_t > ( splitPos / boundary + .5f ); splitPos = ratio * boundary; if( (splitPos - range.start) < boundary ) splitPos = range.start; if( (end - splitPos) < boundary ) splitPos = end; if( fabs( splitPos - node->split ) < node->resistancef ) splitPos = node->split; else node->split = splitPos; LBLOG( LOG_LB2 ) << "Constrained split " << range << " at pos " << splitPos << std::endl; Range childRange = range; childRange.end = splitPos; _computeSplit( node->left, leftTime, datas, vp, childRange ); childRange.start = childRange.end; childRange.end = range.end; _computeSplit( node->right, time - leftTime, datas, vp, childRange); break; } default: LBUNIMPLEMENTED; } }
void LoadEqualizer::_updateNode( Node* node, const Viewport& vp, const Range& range ) { Node* left = node->left; Node* right = node->right; LBASSERT( left ); LBASSERT( right ); Viewport leftVP = vp; Viewport rightVP = vp; Range leftRange = range; Range rightRange = range; switch( node->mode ) { default: LBUNIMPLEMENTED; case MODE_VERTICAL: leftVP.w = vp.w * .5f; rightVP.x = leftVP.getXEnd(); rightVP.w = vp.getXEnd() - rightVP.x; node->split = leftVP.getXEnd(); break; case MODE_HORIZONTAL: leftVP.h = vp.h * .5f; rightVP.y = leftVP.getYEnd(); rightVP.h = vp.getYEnd() - rightVP.y; node->split = leftVP.getYEnd(); break; case MODE_DB: leftRange.end = range.start + ( range.end - range.start ) * .5f; rightRange.start = leftRange.end; node->split = leftRange.end; break; } _update( left, leftVP, leftRange ); _update( right, rightVP, rightRange ); node->resources = left->resources + right->resources; if( left->resources == 0.f ) { node->maxSize = right->maxSize; node->boundary2i = right->boundary2i; node->boundaryf = right->boundaryf; node->resistance2i = right->resistance2i; node->resistancef = right->resistancef; } else if( right->resources == 0.f ) { node->maxSize = left->maxSize; node->boundary2i = left->boundary2i; node->boundaryf = left->boundaryf; node->resistance2i = left->resistance2i; node->resistancef = left->resistancef; } else { switch( node->mode ) { case MODE_VERTICAL: node->maxSize.x() = left->maxSize.x() + right->maxSize.x(); node->maxSize.y() = LB_MIN( left->maxSize.y(), right->maxSize.y()); node->boundary2i.x() = left->boundary2i.x()+ right->boundary2i.x(); node->boundary2i.y() = LB_MAX( left->boundary2i.y(), right->boundary2i.y()); node->boundaryf = LB_MAX( left->boundaryf, right->boundaryf ); node->resistance2i.x() = LB_MAX( left->resistance2i.x(), right->resistance2i.x( )); node->resistance2i.y() = LB_MAX( left->resistance2i.y(), right->resistance2i.y()); node->resistancef = LB_MAX( left->resistancef, right->resistancef ); break; case MODE_HORIZONTAL: node->maxSize.x() = LB_MIN( left->maxSize.x(), right->maxSize.x()); node->maxSize.y() = left->maxSize.y() + right->maxSize.y(); node->boundary2i.x() = LB_MAX( left->boundary2i.x(), right->boundary2i.x() ); node->boundary2i.y() = left->boundary2i.y()+ right->boundary2i.y(); node->boundaryf = LB_MAX( left->boundaryf, right->boundaryf ); node->resistance2i.x() = LB_MAX( left->resistance2i.x(), right->resistance2i.x() ); node->resistance2i.y() = LB_MAX( left->resistance2i.y(), right->resistance2i.y( )); node->resistancef = LB_MAX( left->resistancef, right->resistancef ); break; case MODE_DB: node->boundary2i.x() = LB_MAX( left->boundary2i.x(), right->boundary2i.x() ); node->boundary2i.y() = LB_MAX( left->boundary2i.y(), right->boundary2i.y() ); node->boundaryf = left->boundaryf + right->boundaryf; node->resistance2i.x() = LB_MAX( left->resistance2i.x(), right->resistance2i.x() ); node->resistance2i.y() = LB_MAX( left->resistance2i.y(), right->resistance2i.y() ); node->resistancef = LB_MAX( left->resistancef, right->resistancef ); break; default: LBUNIMPLEMENTED; } } }
void LoadEqualizer::notifyLoadData( Channel* channel, const uint32_t frameNumber, const Statistics& statistics, const Viewport& region ) { LBLOG( LOG_LB2 ) << statistics.size() << " samples from "<< channel->getName() << " @ " << frameNumber << std::endl; for( std::deque< LBFrameData >::iterator i = _history.begin(); i != _history.end(); ++i ) { LBFrameData& frameData = *i; if( frameData.first != frameNumber ) continue; // Found corresponding historical data set LBDatas& items = frameData.second; for( LBDatas::iterator j = items.begin(); j != items.end(); ++j ) { Data& data = *j; if( data.channel != channel ) continue; // Found corresponding historical data item const uint32_t taskID = data.taskID; LBASSERTINFO( taskID > 0, channel->getName( )); // gather relevant load data int64_t startTime = std::numeric_limits< int64_t >::max(); int64_t endTime = 0; bool loadSet = false; int64_t transmitTime = 0; for( size_t k = 0; k < statistics.size(); ++k ) { const Statistic& stat = statistics[k]; if( stat.task == data.destTaskID ) _updateAssembleTime( data, stat ); // from different compound if( stat.task != taskID || loadSet ) continue; switch( stat.type ) { case Statistic::CHANNEL_CLEAR: case Statistic::CHANNEL_DRAW: case Statistic::CHANNEL_READBACK: startTime = LB_MIN( startTime, stat.startTime ); endTime = LB_MAX( endTime, stat.endTime ); break; case Statistic::CHANNEL_ASYNC_READBACK: case Statistic::CHANNEL_FRAME_TRANSMIT: transmitTime += stat.endTime - stat.startTime; break; case Statistic::CHANNEL_FRAME_WAIT_SENDTOKEN: transmitTime -= stat.endTime - stat.startTime; break; // assemble blocks on input frames, stop using subsequent data case Statistic::CHANNEL_ASSEMBLE: loadSet = true; break; default: break; } } if( startTime == std::numeric_limits< int64_t >::max( )) return; data.vp.apply( region ); // Update ROI data.time = endTime - startTime; data.time = LB_MAX( data.time, 1 ); data.time = LB_MAX( data.time, transmitTime ); data.assembleTime = LB_MAX( data.assembleTime, 0 ); LBLOG( LOG_LB2 ) << "Added time " << data.time << " (+" << data.assembleTime << ") for " << channel->getName() << " " << data.vp << ", " << data.range << " @ " << frameNumber << std::endl; return; // Note: if the same channel is used twice as a child, the // load-compound association does not work. } } }
void Channel::frameDraw( const eq::uint128_t& frameID ) { if( stopRendering( )) return; _initJitter(); if( _isDone( )) return; Window* window = static_cast< Window* >( getWindow( )); VertexBufferState& state = window->getState(); const Model* oldModel = _model; const Model* model = _getModel(); if( oldModel != model ) state.setFrustumCulling( false ); // create all display lists/VBOs if( model ) _updateNearFar( model->getBoundingSphere( )); eq::Channel::frameDraw( frameID ); // Setup OpenGL state glLightfv( GL_LIGHT0, GL_POSITION, lightPosition ); glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient ); glLightfv( GL_LIGHT0, GL_DIFFUSE, lightDiffuse ); glLightfv( GL_LIGHT0, GL_SPECULAR, lightSpecular ); glMaterialfv( GL_FRONT, GL_AMBIENT, materialAmbient ); glMaterialfv( GL_FRONT, GL_DIFFUSE, materialDiffuse ); glMaterialfv( GL_FRONT, GL_SPECULAR, materialSpecular ); glMateriali( GL_FRONT, GL_SHININESS, materialShininess ); const FrameData& frameData = _getFrameData(); glPolygonMode( GL_FRONT_AND_BACK, frameData.useWireframe() ? GL_LINE : GL_FILL ); const eq::Vector3f& position = frameData.getCameraPosition(); glMultMatrixf( frameData.getCameraRotation().array ); glTranslatef( position.x(), position.y(), position.z() ); glMultMatrixf( frameData.getModelRotation().array ); if( frameData.getColorMode() == COLOR_DEMO ) { const eq::Vector3ub color = getUniqueColor(); glColor3ub( color.r(), color.g(), color.b() ); } else glColor3f( .75f, .75f, .75f ); if( model ) _drawModel( model ); else { glNormal3f( 0.f, -1.f, 0.f ); glBegin( GL_TRIANGLE_STRIP ); glVertex3f( .25f, 0.f, .25f ); glVertex3f( -.25f, 0.f, .25f ); glVertex3f( .25f, 0.f, -.25f ); glVertex3f( -.25f, 0.f, -.25f ); glEnd(); } state.setFrustumCulling( true ); Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; accum.stepsDone = LB_MAX( accum.stepsDone, getSubPixel().size * getPeriod( )); accum.transfer = true; }
void TreeEqualizer::_assign( Node* node, const Viewport& vp, const Range& range ) { LBLOG( LOG_LB2 ) << "assign " << vp << ", " << range << " time " << node->time << " split " << node->split << std::endl; LBASSERTINFO( vp.isValid(), vp ); LBASSERTINFO( range.isValid(), range ); LBASSERTINFO( node->resources > 0.f || !vp.hasArea() || !range.hasData(), "Assigning work to unused compound: " << vp << ", " << range); Compound* compound = node->compound; if( compound ) { LBASSERTINFO( vp == Viewport::FULL || range == Range::ALL, "Mixed 2D/DB load-balancing not implemented" ); compound->setViewport( vp ); compound->setRange( range ); LBLOG( LOG_LB2 ) << compound->getChannel()->getName() << " set " << vp << ", " << range << std::endl; return; } switch( node->mode ) { case MODE_VERTICAL: { // Ensure minimum size const Compound* root = getCompound(); const float pvpW = float( root->getInheritPixelViewport().w ); const float end = vp.getXEnd(); const float boundary = float( node->boundary2i.x( )) / pvpW; float absoluteSplit = vp.x + vp.w * node->split; if( node->left->resources == 0.f ) absoluteSplit = vp.x; else if( node->right->resources == 0.f ) absoluteSplit = end; else if( boundary > 0 ) { const float right = vp.getXEnd() - absoluteSplit; const float left = absoluteSplit - vp.x; const float maxRight = float( node->right->maxSize.x( )) / pvpW; const float maxLeft = float( node->left->maxSize.x( )) / pvpW; if( right > maxRight ) absoluteSplit = end - maxRight; else if( left > maxLeft ) absoluteSplit = vp.x + maxLeft; if( (absoluteSplit - vp.x) < boundary ) absoluteSplit = vp.x + boundary; if( (end - absoluteSplit) < boundary ) absoluteSplit = end - boundary; const uint32_t ratio = uint32_t( absoluteSplit / boundary + .5f ); absoluteSplit = ratio * boundary; } absoluteSplit = LB_MAX( absoluteSplit, vp.x ); absoluteSplit = LB_MIN( absoluteSplit, end); node->split = (absoluteSplit - vp.x ) / vp.w; LBLOG( LOG_LB2 ) << "Constrained split " << vp << " at X " << node->split << std::endl; // traverse children Viewport childVP = vp; childVP.w = (absoluteSplit - vp.x); _assign( node->left, childVP, range ); childVP.x = childVP.getXEnd(); childVP.w = end - childVP.x; // Fix 2994111: Rounding errors with 2D LB and 16 sources // Floating point rounding may create a width for the 'right' // child which is slightly below the parent width. Correct it. while( childVP.getXEnd() < end ) childVP.w += std::numeric_limits< float >::epsilon(); _assign( node->right, childVP, range ); break; } case MODE_HORIZONTAL: { // Ensure minimum size const Compound* root = getCompound(); const float pvpH = float( root->getInheritPixelViewport().h ); const float end = vp.getYEnd(); const float boundary = float( node->boundary2i.y( )) / pvpH; float absoluteSplit = vp.y + vp.h * node->split; if( node->left->resources == 0.f ) absoluteSplit = vp.y; else if( node->right->resources == 0.f ) absoluteSplit = end; else if( boundary > 0 ) { const float right = vp.getYEnd() - absoluteSplit; const float left = absoluteSplit - vp.y; const float maxRight = float( node->right->maxSize.y( )) / pvpH; const float maxLeft = float( node->left->maxSize.y( )) / pvpH; if( right > maxRight ) absoluteSplit = end - maxRight; else if( left > maxLeft ) absoluteSplit = vp.y + maxLeft; if( (absoluteSplit - vp.y) < boundary ) absoluteSplit = vp.y + boundary; if( (end - absoluteSplit) < boundary ) absoluteSplit = end - boundary; const uint32_t ratio = uint32_t( absoluteSplit / boundary + .5f ); absoluteSplit = ratio * boundary; } absoluteSplit = LB_MAX( absoluteSplit, vp.y ); absoluteSplit = LB_MIN( absoluteSplit, end); node->split = (absoluteSplit - vp.y ) / vp.h; LBLOG( LOG_LB2 ) << "Constrained split " << vp << " at X " << node->split << std::endl; // traverse children Viewport childVP = vp; childVP.h = (absoluteSplit - vp.y); _assign( node->left, childVP, range ); childVP.y = childVP.getYEnd(); childVP.h = end - childVP.y; // Fix 2994111: Rounding errors with 2D LB and 16 sources // Floating point rounding may create a width for the 'right' // child which is slightly below the parent width. Correct it. while( childVP.getYEnd() < end ) childVP.h += std::numeric_limits< float >::epsilon(); _assign( node->right, childVP, range ); break; } case MODE_DB: { LBASSERT( vp == Viewport::FULL ); const float end = range.end; float absoluteSplit = range.start + (range.end-range.start)*node->split; const float boundary( node->boundaryf ); if( node->left->resources == 0.f ) absoluteSplit = range.start; else if( node->right->resources == 0.f ) absoluteSplit = end; const uint32_t ratio = uint32_t( absoluteSplit / boundary + .5f ); absoluteSplit = ratio * boundary; if( (absoluteSplit - range.start) < boundary ) absoluteSplit = range.start; if( (end - absoluteSplit) < boundary ) absoluteSplit = end; node->split = (absoluteSplit-range.start) / (range.end-range.start); LBLOG( LOG_LB2 ) << "Constrained split " << range << " at pos " << node->split << std::endl; Range childRange = range; childRange.end = absoluteSplit; _assign( node->left, vp, childRange ); childRange.start = childRange.end; childRange.end = range.end; _assign( node->right, vp, childRange); break; } default: LBUNIMPLEMENTED; } }
void TreeEqualizer::_update( Node* node ) { if( !node ) return; const Compound* compound = node->compound; if( compound ) { const Channel* channel = compound->getChannel(); const PixelViewport& pvp = channel->getPixelViewport(); LBASSERT( channel ); node->resources = compound->isActive() ? compound->getUsage() : 0.f; node->maxSize.x() = pvp.w; node->maxSize.y() = pvp.h; node->boundaryf = _boundaryf; node->boundary2i = _boundary2i; return; } // else LBASSERT( node->left ); LBASSERT( node->right ); _update( node->left ); _update( node->right ); node->resources = node->left->resources + node->right->resources; if( node->left->resources == 0.f ) { node->maxSize = node->right->maxSize; node->boundary2i = node->right->boundary2i; node->boundaryf = node->right->boundaryf; node->time = node->right->time; } else if( node->right->resources == 0.f ) { node->maxSize = node->left->maxSize; node->boundary2i = node->left->boundary2i; node->boundaryf = node->left->boundaryf; node->time = node->left->time; } else { switch( node->mode ) { case MODE_VERTICAL: node->maxSize.x() = node->left->maxSize.x() + node->right->maxSize.x(); node->maxSize.y() = LB_MIN( node->left->maxSize.y(), node->right->maxSize.y() ); node->boundary2i.x() = node->left->boundary2i.x() + node->right->boundary2i.x(); node->boundary2i.y() = LB_MAX( node->left->boundary2i.y(), node->right->boundary2i.y()); node->boundaryf = LB_MAX( node->left->boundaryf, node->right->boundaryf ); break; case MODE_HORIZONTAL: node->maxSize.x() = LB_MIN( node->left->maxSize.x(), node->right->maxSize.x() ); node->maxSize.y() = node->left->maxSize.y() + node->right->maxSize.y(); node->boundary2i.x() = LB_MAX( node->left->boundary2i.x(), node->right->boundary2i.x() ); node->boundary2i.y() = node->left->boundary2i.y() + node->right->boundary2i.y(); node->boundaryf = LB_MAX( node->left->boundaryf, node->right->boundaryf ); break; case MODE_DB: node->boundary2i.x() = LB_MAX( node->left->boundary2i.x(), node->right->boundary2i.x() ); node->boundary2i.y() = LB_MAX( node->left->boundary2i.y(), node->right->boundary2i.y() ); node->boundaryf = node->left->boundaryf +node->right->boundaryf; break; default: LBUNIMPLEMENTED; } node->time = node->left->time + node->right->time; } }
bool FullMasterCM::_initSlave( const MasterCMCommand& command, const uint128_t& /*replyVersion*/, bool replyUseCache ) { _checkConsistency(); const uint128_t& version = command.getRequestedVersion(); const uint128_t oldest = _instanceDatas.front()->os.getVersion(); uint128_t start = (version == VERSION_OLDEST || version < oldest ) ? oldest : version; uint128_t end = _version; #ifndef NDEBUG if( version != VERSION_OLDEST && version < start ) LBINFO << "Mapping version " << start << " instead of requested " << version << " for " << lunchbox::className( _object ) << " " << ObjectVersion( _object->getID(), _version ) << " of " << _instanceDatas.size() << "/" << _nVersions << std::endl; #endif const uint128_t& minCachedVersion = command.getMinCachedVersion(); const uint128_t& maxCachedVersion = command.getMaxCachedVersion(); const uint128_t replyVersion = start; if( replyUseCache ) { if( minCachedVersion <= start && maxCachedVersion >= start ) { #ifdef CO_INSTRUMENT_MULTICAST _hit += maxCachedVersion + 1 - start; #endif start = maxCachedVersion + 1; } else if( maxCachedVersion == end ) { end = LB_MAX( start, minCachedVersion - 1 ); #ifdef CO_INSTRUMENT_MULTICAST _hit += _version - end; #endif } // TODO else cached block in the middle, send head and tail elements } #if 0 LBLOG( LOG_OBJECTS ) << *_object << ", instantiate on " << node->getNodeID() << " with v" << ((requested == VERSION_OLDEST) ? oldest : requested) << " (" << requested << ") sending " << start << ".." << end << " have " << _version - _nVersions << ".." << _version << " " << _instanceDatas.size() << std::endl; #endif LBASSERT( start >= oldest ); bool dataSent = false; // send all instance datas from start..end InstanceDataDeque::iterator i = _instanceDatas.begin(); while( i != _instanceDatas.end() && (*i)->os.getVersion() < start ) ++i; for( ; i != _instanceDatas.end() && (*i)->os.getVersion() <= end; ++i ) { if( !dataSent ) { _sendMapSuccess( command, true ); dataSent = true; } InstanceData* data = *i; LBASSERT( data ); data->os.sendMapData( command.getRemoteNode(), command.getInstanceID( )); #ifdef CO_INSTRUMENT_MULTICAST ++_miss; #endif } if( !dataSent ) { _sendMapSuccess( command, false ); _sendMapReply( command, replyVersion, true, replyUseCache, false ); } else _sendMapReply( command, replyVersion, true, replyUseCache, true ); #ifdef CO_INSTRUMENT_MULTICAST if( _miss % 100 == 0 ) LBINFO << "Cached " << _hit << "/" << _hit + _miss << " instance data transmissions" << std::endl; #endif return true; }
/* Compute the bounding sphere of the leaf's indexed vertices. */ const BoundingSphere& VertexBufferLeaf::updateBoundingSphere() { // We determine a bounding sphere by: // 1) Using the inner sphere of the dominant axis of the bounding box as an // estimate // 2) Test all points to be in that sphere // 3) Expand the sphere to contain all points outside. // 1a) initialize and compute a bounding box _boundingBox[0] = _globalData.vertices[ _vertexStart + _globalData.indices[_indexStart] ]; _boundingBox[1] = _globalData.vertices[ _vertexStart + _globalData.indices[_indexStart] ]; for( Index i = 1 + _indexStart; i < _indexStart + _indexLength; ++i ) { const Vertex& vertex = _globalData.vertices[ _vertexStart + _globalData.indices[ i ] ]; _boundingBox[0][0] = std::min( _boundingBox[0][0], vertex[0] ); _boundingBox[1][0] = std::max( _boundingBox[1][0], vertex[0] ); _boundingBox[0][1] = std::min( _boundingBox[0][1], vertex[1] ); _boundingBox[1][1] = std::max( _boundingBox[1][1], vertex[1] ); _boundingBox[0][2] = std::min( _boundingBox[0][2], vertex[2] ); _boundingBox[1][2] = std::max( _boundingBox[1][2], vertex[2] ); } // 1b) get inner sphere of bounding box as an initial estimate _boundingSphere.x() = ( _boundingBox[0].x() + _boundingBox[1].x() ) * 0.5f; _boundingSphere.y() = ( _boundingBox[0].y() + _boundingBox[1].y() ) * 0.5f; _boundingSphere.z() = ( _boundingBox[0].z() + _boundingBox[1].z() ) * 0.5f; _boundingSphere.w() = LB_MAX( _boundingBox[1].x() - _boundingBox[0].x(), _boundingBox[1].y() - _boundingBox[0].y() ); _boundingSphere.w() = LB_MAX( _boundingBox[1].z() - _boundingBox[0].z(), _boundingSphere.w() ); _boundingSphere.w() *= .5f; float radius = _boundingSphere.w(); float radiusSquared = radius * radius; Vertex center( _boundingSphere.array ); // 2) test all points to be in the estimated bounding sphere for( Index offset = 0; offset < _indexLength; ++offset ) { const Vertex& vertex = _globalData.vertices[ _vertexStart + _globalData.indices[_indexStart + offset] ]; const Vertex centerToPoint = vertex - center; const float distanceSquared = centerToPoint.squared_length(); if( distanceSquared <= radiusSquared ) // point is inside existing BS continue; // 3) expand sphere to contain 'outside' points const float distance = sqrtf( distanceSquared ); const float delta = distance - radius; radius = ( radius + distance ) * .5f; radiusSquared = radius * radius; const Vertex normdelta = normalize( centerToPoint ) * ( 0.5f * delta ); center += normdelta; LBASSERTINFO( Vertex( vertex-center ).squared_length() <= ( radiusSquared + 2.f * std::numeric_limits<float>::epsilon( )), vertex << " c " << center << " r " << radius << " (" << Vertex( vertex-center ).length() << ")" ); } #ifndef NDEBUG // 2a) re-test all points to be in the estimated bounding sphere for( Index offset = 0; offset < _indexLength; ++offset ) { const Vertex& vertex = _globalData.vertices[ _vertexStart + _globalData.indices[_indexStart + offset] ]; const Vertex centerToPoint = vertex - center; const float distanceSquared = centerToPoint.squared_length(); LBASSERTINFO( distanceSquared <= ( radiusSquared + 2.f * std::numeric_limits<float>::epsilon( )), vertex << " c " << center << " r " << radius << " (" << Vertex( vertex-center ).length() << ")" ); } #endif // store optimal bounding sphere _boundingSphere.x() = center.x(); _boundingSphere.y() = center.y(); _boundingSphere.z() = center.z(); _boundingSphere.w() = radius; #ifndef NDEBUG PLYLIBINFO << "updateBoundingSphere" << "( " << _boundingSphere << " )." << std::endl; #endif return _boundingSphere; }