00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "channelUpdateVisitor.h"
00019
00020 #include "colorMask.h"
00021 #include "compound.h"
00022 #include "frame.h"
00023 #include "node.h"
00024 #include "observer.h"
00025 #include "pipe.h"
00026 #include "segment.h"
00027 #include "view.h"
00028 #include "window.h"
00029
00030 #include "channel.ipp"
00031
00032 #include <eq/client/log.h>
00033
00034 using namespace std;
00035 using namespace eq::base;
00036
00037 namespace eq
00038 {
00039 namespace server
00040 {
00041 ChannelUpdateVisitor::ChannelUpdateVisitor( Channel* channel,
00042 const uint32_t frameID,
00043 const uint32_t frameNumber )
00044 : _channel( channel )
00045 , _eye( eq::EYE_CYCLOP )
00046 , _frameID( frameID )
00047 , _frameNumber( frameNumber )
00048 , _updated( false )
00049 {}
00050
00051 bool ChannelUpdateVisitor::_skipCompound( const Compound* compound )
00052 {
00053 if( compound->getChannel() != _channel ||
00054 !compound->testInheritEye( _eye ) ||
00055 compound->getInheritTasks() == TASK_NONE )
00056 {
00057 return true;
00058 }
00059
00060 return false;
00061 }
00062
00063 VisitorResult ChannelUpdateVisitor::visitPre( const Compound* compound )
00064 {
00065 if( !compound->isActive( ))
00066 return TRAVERSE_PRUNE;
00067
00068 _updateDrawFinish( compound );
00069
00070 if( _skipCompound( compound ))
00071 return TRAVERSE_CONTINUE;
00072
00073 eq::RenderContext context;
00074 _setupRenderContext( compound, context );
00075
00076 _updateFrameRate( compound );
00077 _updateViewStart( compound, context );
00078
00079 if( compound->testInheritTask( eq::TASK_CLEAR ))
00080 {
00081 eq::ChannelFrameClearPacket clearPacket;
00082 clearPacket.context = context;
00083
00084 _channel->send( clearPacket );
00085 _updated = true;
00086 EQLOG( eq::LOG_TASKS ) << "TASK clear " << _channel->getName() << " "
00087 << &clearPacket << endl;
00088 }
00089 return TRAVERSE_CONTINUE;
00090 }
00091
00092 VisitorResult ChannelUpdateVisitor::visitLeaf( const Compound* compound )
00093 {
00094 if( !compound->isActive( ))
00095 return TRAVERSE_PRUNE;
00096
00097 if( _skipCompound( compound ))
00098 {
00099 _updateDrawFinish( compound );
00100 return TRAVERSE_CONTINUE;
00101 }
00102
00103
00104 eq::RenderContext context;
00105 _setupRenderContext( compound, context );
00106 _updateFrameRate( compound );
00107 _updateViewStart( compound, context );
00108
00109 if( compound->testInheritTask( eq::TASK_CLEAR ))
00110 {
00111 eq::ChannelFrameClearPacket clearPacket;
00112 clearPacket.context = context;
00113 _channel->send( clearPacket );
00114 _updated = true;
00115 EQLOG( eq::LOG_TASKS ) << "TASK clear " << _channel->getName() << " "
00116 << &clearPacket << endl;
00117 }
00118 if( compound->testInheritTask( eq::TASK_DRAW ))
00119 {
00120 eq::ChannelFrameDrawPacket drawPacket;
00121
00122 drawPacket.context = context;
00123 _channel->send( drawPacket );
00124 _updated = true;
00125 EQLOG( eq::LOG_TASKS ) << "TASK draw " << _channel->getName() << " "
00126 << &drawPacket << endl;
00127 }
00128
00129 _updateDrawFinish( compound );
00130 _updatePostDraw( compound, context );
00131 return TRAVERSE_CONTINUE;
00132 }
00133
00134 VisitorResult ChannelUpdateVisitor::visitPost( const Compound* compound )
00135 {
00136 if( !compound->isActive( ))
00137 return TRAVERSE_PRUNE;
00138
00139 if( _skipCompound( compound ))
00140 return TRAVERSE_CONTINUE;
00141
00142 eq::RenderContext context;
00143 _setupRenderContext( compound, context );
00144 _updatePostDraw( compound, context );
00145
00146 return TRAVERSE_CONTINUE;
00147 }
00148
00149
00150 void ChannelUpdateVisitor::_setupRenderContext( const Compound* compound,
00151 eq::RenderContext& context )
00152 {
00153 const Channel* destChannel = compound->getInheritChannel();
00154 EQASSERT( destChannel );
00155 const View* view = destChannel->getView();
00156
00157 context.frameID = _frameID;
00158 context.pvp = compound->getInheritPixelViewport();
00159 context.overdraw = compound->getInheritOverdraw();
00160 context.vp = compound->getInheritViewport();
00161 context.range = compound->getInheritRange();
00162 context.pixel = compound->getInheritPixel();
00163 context.zoom = compound->getInheritZoom();
00164 context.offset.x() = context.pvp.x;
00165 context.offset.y() = context.pvp.y;
00166 context.eye = _eye;
00167 context.buffer = _getDrawBuffer();
00168 context.bufferMask = _getDrawBufferMask( compound );
00169 context.view = view;
00170 context.taskID = compound->getTaskID();
00171
00172 if( view )
00173 {
00174
00175 const Segment* segment = destChannel->getSegment();
00176 EQASSERT( segment );
00177
00178 const PixelViewport& pvp = destChannel->getPixelViewport();
00179 if( pvp.hasArea( ))
00180 context.vp.applyView( segment->getViewport(), view->getViewport(),
00181 pvp, destChannel->getOverdraw( ));
00182 }
00183
00184 if( _channel != destChannel &&
00185 compound->getIAttribute( Compound::IATTR_HINT_OFFSET ) != eq::ON )
00186 {
00187 const eq::PixelViewport& nativePVP = _channel->getPixelViewport();
00188 context.pvp.x = nativePVP.x;
00189 context.pvp.y = nativePVP.y;
00190 }
00191
00192
00193 _computeFrustum( compound, context );
00194 }
00195
00196 void ChannelUpdateVisitor::_updateDrawFinish( const Compound* compound ) const
00197 {
00198
00199 if( compound->getInheritEyes() + 1 > static_cast< uint32_t >( 1<<( _eye+1 ))
00200
00201 || !compound->testInheritEye( _eye ))
00202 {
00203 return;
00204 }
00205
00206 const Compound* lastDrawCompound = _channel->getLastDrawCompound();
00207 if( lastDrawCompound && lastDrawCompound != compound )
00208 return;
00209
00210
00211 Node* node = _channel->getNode();
00212
00213 eq::ChannelFrameDrawFinishPacket channelPacket;
00214 channelPacket.objectID = _channel->getID();
00215 channelPacket.frameNumber = _frameNumber;
00216 channelPacket.frameID = _frameID;
00217
00218 node->send( channelPacket );
00219 EQLOG( eq::LOG_TASKS ) << "TASK channel draw finish " << _channel->getName()
00220 << " " << &channelPacket <<endl;
00221
00222 if( !lastDrawCompound )
00223 _channel->setLastDrawCompound( compound );
00224
00225
00226 Window* window = _channel->getWindow();
00227 const Channel* lastDrawChannel = window->getLastDrawChannel();
00228
00229 if( lastDrawChannel && lastDrawChannel != _channel )
00230 return;
00231
00232 eq::WindowFrameDrawFinishPacket windowPacket;
00233 windowPacket.objectID = window->getID();
00234 windowPacket.frameNumber = _frameNumber;
00235 windowPacket.frameID = _frameID;
00236
00237 node->send( windowPacket );
00238 EQLOG( eq::LOG_TASKS ) << "TASK window draw finish " << window->getName()
00239 << " " << &windowPacket << endl;
00240 if( !lastDrawChannel )
00241 window->setLastDrawChannel( _channel );
00242
00243
00244 Pipe* pipe = _channel->getPipe();
00245 const Window* lastDrawWindow = pipe->getLastDrawWindow();
00246 if( lastDrawWindow && lastDrawWindow != window )
00247 return;
00248
00249 eq::PipeFrameDrawFinishPacket pipePacket;
00250 pipePacket.objectID = pipe->getID();
00251 pipePacket.frameNumber = _frameNumber;
00252 pipePacket.frameID = _frameID;
00253
00254 node->send( pipePacket );
00255 EQLOG( eq::LOG_TASKS ) << "TASK pipe draw finish "
00256 << pipe->getName() << " " << &pipePacket << endl;
00257 if( !lastDrawWindow )
00258 pipe->setLastDrawWindow( window );
00259
00260
00261 const Pipe* lastDrawPipe = node->getLastDrawPipe();
00262 if( lastDrawPipe && lastDrawPipe != pipe )
00263 return;
00264
00265 eq::NodeFrameDrawFinishPacket nodePacket;
00266 nodePacket.objectID = node->getID();
00267 nodePacket.frameNumber = _frameNumber;
00268 nodePacket.frameID = _frameID;
00269
00270 node->send( nodePacket );
00271 EQLOG( eq::LOG_TASKS ) << "TASK node draw finish " << node->getName()
00272 << " " << &nodePacket << endl;
00273 if( !lastDrawPipe )
00274 node->setLastDrawPipe( pipe );
00275 }
00276
00277 void ChannelUpdateVisitor::_updateFrameRate( const Compound* compound ) const
00278 {
00279 const float maxFPS = compound->getInheritMaxFPS();
00280 Window* window = _channel->getWindow();
00281
00282 if( maxFPS < window->getMaxFPS())
00283 window->setMaxFPS( maxFPS );
00284 }
00285
00286 GLenum ChannelUpdateVisitor::_getDrawBuffer() const
00287 {
00288 const eq::Window::DrawableConfig& drawableConfig =
00289 _channel->getWindow()->getDrawableConfig();
00290
00291 if( !drawableConfig.stereo )
00292 {
00293 if( drawableConfig.doublebuffered )
00294 return GL_BACK;
00295
00296 return GL_FRONT;
00297 }
00298 else
00299 {
00300 if( drawableConfig.doublebuffered )
00301 {
00302 switch( _eye )
00303 {
00304 case eq::EYE_LEFT:
00305 return GL_BACK_LEFT;
00306 break;
00307 case eq::EYE_RIGHT:
00308 return GL_BACK_RIGHT;
00309 break;
00310 default:
00311 return GL_BACK;
00312 break;
00313 }
00314 }
00315
00316 switch( _eye )
00317 {
00318 case eq::EYE_LEFT:
00319 return GL_FRONT_LEFT;
00320 break;
00321 case eq::EYE_RIGHT:
00322 return GL_FRONT_RIGHT;
00323 break;
00324 default:
00325 return GL_FRONT;
00326 break;
00327 }
00328 }
00329 }
00330
00331 eq::ColorMask ChannelUpdateVisitor::_getDrawBufferMask(const Compound* compound)
00332 const
00333 {
00334 if( compound->getInheritIAttribute( Compound::IATTR_STEREO_MODE ) !=
00335 eq::ANAGLYPH )
00336 return eq::ColorMask::ALL;
00337
00338 switch( _eye )
00339 {
00340 case eq::EYE_LEFT:
00341 return ColorMask(
00342 compound->getInheritIAttribute(
00343 Compound::IATTR_STEREO_ANAGLYPH_LEFT_MASK ));
00344 case eq::EYE_RIGHT:
00345 return ColorMask(
00346 compound->getInheritIAttribute(
00347 Compound::IATTR_STEREO_ANAGLYPH_RIGHT_MASK ));
00348 default:
00349 return eq::ColorMask::ALL;
00350 }
00351 }
00352
00353 void ChannelUpdateVisitor::_computeFrustum( const Compound* compound,
00354 eq::RenderContext& context )
00355 {
00356
00357 const Vector3f eyeW = _getEyePosition( compound );
00358 const FrustumData& frustumData = compound->getInheritFrustumData();
00359 const Matrix4f& xfm = frustumData.getTransform();
00360 const Vector3f eye = xfm * eyeW;
00361
00362 EQVERB << "Eye position world: " << eyeW << " screen " << eye << endl;
00363
00364
00365 _computeFrustumCorners( context.frustum, compound, frustumData, eye, false);
00366 _computeFrustumCorners( context.ortho, compound, frustumData, eye, true );
00367
00368
00369
00370 Matrix4f& headTransform = context.headTransform;
00371 for( int i=0; i<16; i += 4 )
00372 {
00373 headTransform.array[i] = xfm.array[i] - eye[0] * xfm.array[i+3];
00374 headTransform.array[i+1] = xfm.array[i+1] - eye[1] * xfm.array[i+3];
00375 headTransform.array[i+2] = xfm.array[i+2] - eye[2] * xfm.array[i+3];
00376 headTransform.array[i+3] = xfm.array[i+3];
00377 }
00378
00379 const bool isHMD = (frustumData.getType() != Wall::TYPE_FIXED);
00380 if( isHMD )
00381 headTransform *= _getInverseHeadMatrix( compound );
00382 }
00383
00384 Vector3f ChannelUpdateVisitor::_getEyePosition( const Compound* compound )
00385 const
00386 {
00387 const FrustumData& frustumData = compound->getInheritFrustumData();
00388 const Channel* destChannel = compound->getInheritChannel();
00389 const View* view = destChannel->getView();
00390 const Observer* observer = static_cast< const Observer* >(
00391 view ? view->getObserver() : 0 );
00392
00393 if( observer && frustumData.getType() == Wall::TYPE_FIXED )
00394 return observer->getEyePosition( _eye );
00395
00396 const Config* config = compound->getConfig();
00397 const float eyeBase_2 = 0.5f * ( observer ?
00398 observer->getEyeBase() : config->getFAttribute( Config::FATTR_EYE_BASE ));
00399
00400 switch( _eye )
00401 {
00402 case eq::EYE_LEFT:
00403 return Vector3f(-eyeBase_2, 0.f, 0.f );
00404
00405 case eq::EYE_RIGHT:
00406 return Vector3f( eyeBase_2, 0.f, 0.f );
00407
00408 default:
00409 EQUNIMPLEMENTED;
00410 case eq::EYE_CYCLOP:
00411 return Vector3f( 0.f, 0.f, 0.f );
00412 }
00413 }
00414
00415 const Matrix4f& ChannelUpdateVisitor::_getInverseHeadMatrix(
00416 const Compound* compound ) const
00417 {
00418 const Channel* destChannel = compound->getInheritChannel();
00419 const View* view = destChannel->getView();
00420 const Observer* observer = static_cast< const Observer* >(
00421 view ? view->getObserver() : 0);
00422
00423 if( observer )
00424 return observer->getInverseHeadMatrix();
00425
00426 return Matrix4f::IDENTITY;
00427 }
00428
00429 void ChannelUpdateVisitor::_computeFrustumCorners( Frustumf& frustum,
00430 const Compound* compound,
00431 const FrustumData& frustumData,
00432 const Vector3f& eye,
00433 const bool ortho )
00434 {
00435 const Channel* destination = compound->getInheritChannel();
00436 destination->getNearFar( &frustum.near_plane(), &frustum.far_plane() );
00437
00438 const float ratio = ortho ? 1.0f : frustum.near_plane() / eye.z();
00439 const float width_2 = frustumData.getWidth() * .5f;
00440 const float height_2 = frustumData.getHeight() * .5f;
00441
00442 if( eye.z() > 0 || ortho )
00443 {
00444 frustum.left() = ( -width_2 - eye.x() ) * ratio;
00445 frustum.right() = ( width_2 - eye.x() ) * ratio;
00446 frustum.bottom() = ( -height_2 - eye.y() ) * ratio;
00447 frustum.top() = ( height_2 - eye.y() ) * ratio;
00448 }
00449 else
00450 {
00451 frustum.left() = ( width_2 - eye.x() ) * ratio;
00452 frustum.right() = ( -width_2 - eye.x() ) * ratio;
00453 frustum.bottom() = ( height_2 + eye.y() ) * ratio;
00454 frustum.top() = ( -height_2 + eye.y() ) * ratio;
00455 }
00456
00457
00458 const eq::Pixel& pixel = compound->getInheritPixel();
00459 if( pixel != eq::Pixel::ALL && pixel.isValid( ))
00460 {
00461 const Channel* inheritChannel = compound->getInheritChannel();
00462 const eq::PixelViewport& destPVP = inheritChannel->getPixelViewport();
00463
00464 if( pixel.w > 1 )
00465 {
00466 const float frustumWidth = frustum.right() - frustum.left();
00467 const float pixelWidth = frustumWidth /
00468 static_cast<float>( destPVP.w );
00469 const float jitter = pixelWidth * pixel.x -
00470 pixelWidth * .5f;
00471
00472 frustum.left() += jitter;
00473 frustum.right() += jitter;
00474 }
00475 if( pixel.h > 1 )
00476 {
00477 const float frustumHeight = frustum.bottom() - frustum.top();
00478 const float pixelHeight = frustumHeight /
00479 static_cast<float>( destPVP.h );
00480 const float jitter = pixelHeight * pixel.y +
00481 pixelHeight * .5f;
00482
00483 frustum.top() -= jitter;
00484 frustum.bottom() -= jitter;
00485 }
00486 }
00487
00488
00489
00490 const eq::Viewport vp = compound->getInheritViewport();
00491 if( vp != eq::Viewport::FULL && vp.isValid( ))
00492 {
00493 const float frustumWidth = frustum.right() - frustum.left();
00494 frustum.left() += frustumWidth * vp.x;
00495 frustum.right() = frustum.left() + frustumWidth * vp.w;
00496
00497 const float frustumHeight = frustum.top() - frustum.bottom();
00498 frustum.bottom() += frustumHeight * vp.y;
00499 frustum.top() = frustum.bottom() + frustumHeight * vp.h;
00500 }
00501 }
00502
00503 void ChannelUpdateVisitor::_updatePostDraw( const Compound* compound,
00504 const eq::RenderContext& context )
00505 {
00506 _updateAssemble( compound, context );
00507 _updateReadback( compound, context );
00508 _updateViewFinish( compound, context );
00509 }
00510
00511 void ChannelUpdateVisitor::_updateAssemble( const Compound* compound,
00512 const eq::RenderContext& context )
00513 {
00514 if( !compound->testInheritTask( eq::TASK_ASSEMBLE ))
00515 return;
00516
00517 const std::vector< Frame* >& inputFrames = compound->getInputFrames();
00518 EQASSERT( !inputFrames.empty( ));
00519
00520 vector<net::ObjectVersion> frameIDs;
00521 for( vector<Frame*>::const_iterator iter = inputFrames.begin();
00522 iter != inputFrames.end(); ++iter )
00523 {
00524 Frame* frame = *iter;
00525
00526 if( !frame->hasData( _eye ))
00527 continue;
00528
00529 frameIDs.push_back( net::ObjectVersion( frame ));
00530 }
00531
00532 if( frameIDs.empty() )
00533 return;
00534
00535
00536 eq::ChannelFrameAssemblePacket packet;
00537 packet.context = context;
00538 packet.nFrames = frameIDs.size();
00539
00540 EQLOG( eq::LOG_ASSEMBLY | eq::LOG_TASKS )
00541 << "TASK assemble " << _channel->getName() << " " << &packet << endl;
00542 _channel->send<net::ObjectVersion>( packet, frameIDs );
00543 _updated = true;
00544 }
00545
00546 void ChannelUpdateVisitor::_updateReadback( const Compound* compound,
00547 const eq::RenderContext& context )
00548 {
00549 if( !compound->testInheritTask( eq::TASK_READBACK ))
00550 return;
00551
00552 const std::vector< Frame* >& outputFrames = compound->getOutputFrames();
00553 EQASSERT( !outputFrames.empty( ));
00554
00555 FrameVector frames;
00556 vector<net::ObjectVersion> frameIDs;
00557 for( vector<Frame*>::const_iterator i = outputFrames.begin();
00558 i != outputFrames.end(); ++i )
00559 {
00560 Frame* frame = *i;
00561
00562 if( !frame->hasData( _eye ))
00563 continue;
00564
00565 frames.push_back( frame );
00566 frameIDs.push_back( net::ObjectVersion( frame ));
00567 }
00568
00569 if( frames.empty() )
00570 return;
00571
00572
00573 eq::ChannelFrameReadbackPacket packet;
00574 packet.context = context;
00575 packet.nFrames = frames.size();
00576
00577 _channel->send<net::ObjectVersion>( packet, frameIDs );
00578 _updated = true;
00579 EQLOG( eq::LOG_ASSEMBLY | eq::LOG_TASKS )
00580 << "TASK readback " << _channel->getName() << " " << &packet << endl;
00581
00582
00583 Node* node = _channel->getNode();
00584 net::NodePtr netNode = node->getNode();
00585 const net::NodeID& outputNodeID = netNode->getNodeID();
00586 for( vector<Frame*>::const_iterator i = frames.begin();
00587 i != frames.end(); ++i )
00588 {
00589 Frame* outputFrame = *i;
00590
00591 const vector<Frame*>& inputFrames =
00592 outputFrame->getInputFrames( context.eye);
00593
00594 vector<net::NodeID> nodeIDs;
00595 for( vector<Frame*>::const_iterator j = inputFrames.begin();
00596 j != inputFrames.end(); ++j )
00597 {
00598 const Frame* inputFrame = *j;
00599 const Node* inputNode = inputFrame->getNode();
00600 net::NodePtr inputNetNode = inputNode->getNode();
00601 net::NodeID nodeID = inputNetNode->getNodeID();
00602 EQASSERT( node );
00603
00604 if( nodeID == outputNodeID )
00605 continue;
00606
00607 nodeID.convertToNetwork();
00608 nodeIDs.push_back( nodeID );
00609 }
00610
00611
00612 stde::usort( nodeIDs );
00613
00614 if( nodeIDs.empty( ))
00615 continue;
00616
00617
00618 eq::ChannelFrameTransmitPacket transmitPacket;
00619 transmitPacket.sessionID = packet.sessionID;
00620 transmitPacket.objectID = packet.objectID;
00621 transmitPacket.context = context;
00622 transmitPacket.frame = net::ObjectVersion( outputFrame );
00623 transmitPacket.nNodes = nodeIDs.size();
00624
00625 EQLOG( eq::LOG_ASSEMBLY | eq::LOG_TASKS )
00626 << "TASK transmit " << _channel->getName() << " " <<
00627 &transmitPacket << " first " << nodeIDs[0] << endl;
00628
00629 _channel->send<net::NodeID>( transmitPacket, nodeIDs );
00630 }
00631 }
00632
00633 void ChannelUpdateVisitor::_updateViewStart( const Compound* compound,
00634 const eq::RenderContext& context )
00635 {
00636 EQASSERT( !_skipCompound( compound ));
00637 if( !compound->testInheritTask( eq::TASK_VIEW ))
00638 return;
00639
00640
00641 eq::ChannelFrameViewStartPacket packet;
00642 packet.context = context;
00643
00644 EQLOG( eq::LOG_TASKS ) << "TASK view start " << _channel->getName() << " "
00645 << &packet << endl;
00646 _channel->send( packet );
00647 }
00648
00649 void ChannelUpdateVisitor::_updateViewFinish( const Compound* compound,
00650 const eq::RenderContext& context )
00651 {
00652 EQASSERT( !_skipCompound( compound ));
00653 if( !compound->testInheritTask( eq::TASK_VIEW ))
00654 return;
00655
00656
00657 eq::ChannelFrameViewFinishPacket packet;
00658 packet.context = context;
00659
00660 EQLOG( eq::LOG_TASKS ) << "TASK view finish " << _channel->getName() << " "
00661 << &packet << endl;
00662 _channel->send( packet );
00663 }
00664
00665 }
00666 }
00667