00001
00002
00003
00004
00005 #include <pthread.h>
00006 #include <eq/base/perThread.h>
00007
00008 #include "compositor.h"
00009
00010 #include "channel.h"
00011 #include "channelStatistics.h"
00012 #include "frame.h"
00013 #include "log.h"
00014 #include "image.h"
00015 #include "windowSystem.h"
00016
00017 #include <eq/base/debug.h>
00018
00019 #include <eq/base/executionListener.h>
00020 #include <eq/base/monitor.h>
00021
00022 #ifdef EQ_USE_PARACOMP
00023 # include <pcapi.h>
00024 #endif
00025
00026 #ifdef WIN32
00027 # define bzero( ptr, size ) memset( ptr, 0, size );
00028 #endif
00029
00030 using eq::base::Monitor;
00031 using namespace std;
00032
00033 namespace eq
00034 {
00035
00036 #define glewGetContext op.channel->glewGetContext
00037
00038 namespace
00039 {
00040
00041 static const char glslKey = 42;
00042
00043 class ResultImage : public Image
00044 {
00045 public:
00046 virtual ~ResultImage() {}
00047
00048 void notifyPerThreadDelete() { delete this; }
00049 };
00050
00051
00052
00053 static base::PerThread< ResultImage > _resultImage;
00054
00055
00056 static bool _useCPUAssembly( const FrameVector& frames, Channel* channel,
00057 const bool blendAlpha = false )
00058 {
00059
00060 if( frames.size() < 2 )
00061 return false;
00062
00063
00064
00065
00066
00067 const uint32_t desiredBuffers = blendAlpha ? Frame::BUFFER_COLOR :
00068 Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH;
00069 size_t nFrames = 0;
00070 for( FrameVector::const_iterator i = frames.begin();
00071 i != frames.end(); ++i )
00072 {
00073 const Frame* frame = *i;
00074 if( frame->getPixel() != Pixel::ALL )
00075 return false;
00076
00077 if( frame->getBuffers() == desiredBuffers )
00078 ++nFrames;
00079 }
00080 if( nFrames < 2 )
00081 return false;
00082
00083
00084
00085
00086
00087 size_t nImages = 0;
00088 uint32_t colorFormat = 0;
00089 uint32_t colorType = 0;
00090 uint32_t depthFormat = 0;
00091 uint32_t depthType = 0;
00092
00093 for( FrameVector::const_iterator i = frames.begin();
00094 i != frames.end(); ++i )
00095 {
00096 const Frame* frame = *i;
00097 {
00098 ChannelStatistics event( Statistic::CHANNEL_WAIT_FRAME, channel );
00099 frame->waitReady();
00100 }
00101
00102 const vector< Image* >& images = frame->getImages();
00103 for( vector< Image* >::const_iterator j = images.begin();
00104 j != images.end(); ++j )
00105 {
00106 const Image* image = *j;
00107
00108 const bool hasColor = image->hasPixelData( Frame::BUFFER_COLOR );
00109 const bool hasDepth = image->hasPixelData( Frame::BUFFER_DEPTH );
00110
00111 if(( blendAlpha && hasColor && image->hasAlpha( )) ||
00112 ( hasColor && hasDepth ))
00113 {
00114 if( colorFormat == 0 )
00115 {
00116 colorFormat = image->getFormat( Frame::BUFFER_COLOR );
00117 colorType = image->getType( Frame::BUFFER_COLOR );
00118 }
00119
00120 if( colorFormat != image->getFormat( Frame::BUFFER_COLOR ) ||
00121 colorType != image->getType( Frame::BUFFER_COLOR ))
00122
00123 return false;
00124
00125 if( image->hasPixelData( Frame::BUFFER_DEPTH ))
00126 {
00127 if( depthFormat == 0 )
00128 {
00129 depthFormat = image->getFormat( Frame::BUFFER_DEPTH );
00130 depthType = image->getType( Frame::BUFFER_DEPTH );
00131 }
00132
00133 if( depthFormat != image->getFormat(Frame::BUFFER_DEPTH ) ||
00134 depthType != image->getType( Frame::BUFFER_DEPTH ))
00135
00136 return false;
00137 }
00138
00139 ++nImages;
00140 }
00141 }
00142
00143 if( nImages > 1 )
00144 return true;
00145 }
00146
00147 return false;
00148 }
00149 }
00150
00151 void Compositor::assembleFrames( const FrameVector& frames,
00152 Channel* channel )
00153 {
00154 if( frames.empty( ))
00155 return;
00156
00157 if( _useCPUAssembly( frames, channel ))
00158 assembleFramesCPU( frames, channel );
00159 else
00160 assembleFramesUnsorted( frames, channel );
00161 }
00162
00163 void Compositor::assembleFramesSorted( const FrameVector& frames,
00164 Channel* channel, const bool blendAlpha )
00165 {
00166 if( frames.empty( ))
00167 return;
00168
00169 if( blendAlpha )
00170 {
00171 glEnable( GL_BLEND );
00172 glBlendFunc( GL_ONE, GL_SRC_ALPHA );
00173 }
00174
00175 if( _useCPUAssembly( frames, channel, blendAlpha ))
00176 assembleFramesCPU( frames, channel, blendAlpha );
00177 else
00178 {
00179 for( FrameVector::const_iterator i = frames.begin();
00180 i != frames.end(); ++i )
00181 {
00182 Frame* frame = *i;
00183 {
00184 ChannelStatistics event( Statistic::CHANNEL_WAIT_FRAME,
00185 channel );
00186 frame->waitReady( );
00187 }
00188 assembleFrame( frame, channel );
00189 }
00190 }
00191
00192 if( blendAlpha )
00193 glDisable( GL_BLEND );
00194 }
00195
00196 void Compositor::assembleFramesUnsorted( const FrameVector& frames,
00197 Channel* channel )
00198 {
00199 if( frames.empty( ))
00200 return;
00201
00202 EQVERB << "Unsorted GPU assembly" << endl;
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 Monitor<uint32_t> monitor;
00213 for( FrameVector::const_iterator i = frames.begin();
00214 i != frames.end(); ++i )
00215 {
00216 Frame* frame = *i;
00217 frame->addListener( monitor );
00218 }
00219
00220 uint32_t nUsedFrames = 0;
00221 FrameVector unusedFrames = frames;
00222
00223
00224 while( !unusedFrames.empty( ))
00225 {
00226 {
00227 ChannelStatistics event( Statistic::CHANNEL_WAIT_FRAME, channel );
00228 monitor.waitGE( ++nUsedFrames );
00229 }
00230
00231 for( FrameVector::iterator i = unusedFrames.begin();
00232 i != unusedFrames.end(); ++i )
00233 {
00234 Frame* frame = *i;
00235 if( !frame->isReady( ))
00236 continue;
00237
00238 assembleFrame( frame, channel );
00239 unusedFrames.erase( i );
00240 break;
00241 }
00242 }
00243
00244
00245 for( FrameVector::const_iterator i = frames.begin(); i != frames.end();
00246 ++i )
00247 {
00248 Frame* frame = *i;
00249
00250 frame->removeListener( monitor );
00251 }
00252 }
00253
00254 void Compositor::assembleFramesCPU( const FrameVector& frames,
00255 Channel* channel, const bool blendAlpha )
00256 {
00257 if( frames.empty( ))
00258 return;
00259
00260 EQVERB << "Sorted CPU assembly" << endl;
00261
00262
00263
00264
00265 const Image* result = assembleFramesCPU( frames, blendAlpha );
00266 if( !result )
00267 return;
00268
00269
00270 ImageOp operation;
00271 operation.channel = channel;
00272 operation.buffers = Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH;
00273 assembleImage( result, operation );
00274
00275 #if 0
00276 static uint32_t counter = 0;
00277 ostringstream stringstream;
00278 stringstream << "Image_" << ++counter;
00279 result->writeImages( stringstream.str( ));
00280 #endif
00281 }
00282
00283 const Image* Compositor::assembleFramesCPU( const FrameVector& frames,
00284 const bool blendAlpha )
00285 {
00286 EQVERB << "Sorted CPU assembly" << endl;
00287
00288
00289 vector< FrameImage > imagesDB;
00290 vector< FrameImage > images2D;
00291 vector< FrameImage > imagesBlend;
00292 PixelViewport resultPVP;
00293
00294 int colorFormat = GL_BGRA;
00295 int colorType = GL_UNSIGNED_BYTE;
00296 int depthFormat = GL_DEPTH_COMPONENT;
00297 int depthType = GL_FLOAT;
00298
00299 for( FrameVector::const_iterator i = frames.begin(); i != frames.end(); ++i)
00300 {
00301 Frame* frame = *i;
00302 frame->waitReady();
00303
00304 EQASSERTINFO( frame->getPixel() == Pixel::ALL,
00305 "CPU-based pixel recomposition not implemented" );
00306
00307 const vector< Image* >& images = frame->getImages();
00308 for( vector< Image* >::const_iterator j = images.begin();
00309 j != images.end(); ++j )
00310 {
00311 const Image* image = *j;
00312
00313 if( !image->hasPixelData( Frame::BUFFER_COLOR ))
00314 continue;
00315
00316 resultPVP.merge( image->getPixelViewport() + frame->getOffset( ));
00317
00318 colorFormat = image->getFormat( Frame::BUFFER_COLOR );
00319 colorType = image->getType( Frame::BUFFER_COLOR );
00320
00321 if( image->hasPixelData( Frame::BUFFER_DEPTH ))
00322 {
00323 imagesDB.push_back( FrameImage( frame, image ));
00324 depthFormat = image->getFormat( Frame::BUFFER_DEPTH );
00325 depthType = image->getType( Frame::BUFFER_DEPTH );
00326 }
00327 else if( blendAlpha && image->hasAlpha( ))
00328 imagesBlend.push_back( FrameImage( frame, image ));
00329 else
00330 images2D.push_back( FrameImage( frame, image ));
00331 }
00332 }
00333
00334 if( !resultPVP.hasArea( ))
00335 {
00336 EQWARN << "Nothing to assemble: " << resultPVP << endl;
00337 return 0;
00338 }
00339
00340
00341 Image* result = _resultImage.get();
00342 if( !result )
00343 {
00344 _resultImage = new ResultImage;
00345 result = _resultImage.get();;
00346 }
00347
00348 result->setFormat( Frame::BUFFER_COLOR, colorFormat );
00349 result->setType( Frame::BUFFER_COLOR, colorType );
00350 result->setFormat( Frame::BUFFER_DEPTH, depthFormat );
00351 result->setType( Frame::BUFFER_DEPTH, depthType );
00352 result->setPixelViewport( resultPVP );
00353 result->clearPixelData( Frame::BUFFER_COLOR );
00354 if( !imagesDB.empty( ))
00355 result->clearPixelData( Frame::BUFFER_DEPTH );
00356
00357
00358 _assembleDBImages( result, imagesDB );
00359 _assemble2DImages( result, images2D );
00360 _assembleBlendImages( result, imagesBlend );
00361
00362 return result;
00363 }
00364
00365
00366 void Compositor::_assembleDBImages( Image* result,
00367 const std::vector< FrameImage >& images )
00368 {
00369 if( images.empty( ))
00370 return;
00371
00372 EQVERB << "CPU-DB assembly of " << images.size() << " images" << endl;
00373
00374 EQASSERT( result->getFormat( Frame::BUFFER_DEPTH ) == GL_DEPTH_COMPONENT);
00375 EQASSERT( result->getType( Frame::BUFFER_DEPTH ) == GL_FLOAT );
00376
00377 const eq::PixelViewport resultPVP = result->getPixelViewport();
00378 uint32_t* destColor = reinterpret_cast< uint32_t* >
00379 ( result->getPixelPointer( Frame::BUFFER_COLOR ));
00380 float* destDepth = reinterpret_cast< float* >
00381 ( result->getPixelPointer( Frame::BUFFER_DEPTH ));
00382
00383 for( vector< FrameImage >::const_iterator i = images.begin();
00384 i != images.end(); ++i )
00385 {
00386 const Frame* frame = i->first;
00387 const Image* image = i->second;
00388 const vmml::Vector2i& offset = frame->getOffset();
00389 const PixelViewport& pvp = image->getPixelViewport();
00390
00391 EQASSERT( image->getDepth( Frame::BUFFER_COLOR ) == 4 );
00392 EQASSERT( image->getDepth( Frame::BUFFER_DEPTH ) == 4 );
00393 EQASSERT( image->hasPixelData( Frame::BUFFER_COLOR ));
00394 EQASSERT( image->hasPixelData( Frame::BUFFER_DEPTH ));
00395 EQASSERTINFO( image->getFormat( Frame::BUFFER_COLOR ) ==
00396 result->getFormat( Frame::BUFFER_COLOR ),
00397 image->getFormat( Frame::BUFFER_COLOR ) << " != "
00398 << result->getFormat( Frame::BUFFER_COLOR ));
00399 EQASSERT( image->getType( Frame::BUFFER_COLOR ) ==
00400 result->getType( Frame::BUFFER_COLOR ));
00401 EQASSERT( image->getFormat( Frame::BUFFER_DEPTH ) ==
00402 result->getFormat( Frame::BUFFER_DEPTH ));
00403 EQASSERT( image->getType( Frame::BUFFER_DEPTH ) ==
00404 result->getType( Frame::BUFFER_DEPTH ));
00405
00406 #ifdef EQ_USE_PARACOMP_DEPTH
00407 if( pvp == resultPVP && offset == vmml::Vector2i::ZERO )
00408 {
00409
00410 if( !_assembleImage_PC( PC_COMP_DEPTH, result, image ))
00411 EQWARN << "Paracomp compositing failed, using fallback" << endl;
00412 else
00413 continue;
00414 }
00415 #endif
00416
00417 const int32_t destX = offset.x + pvp.x - resultPVP.x;
00418 const int32_t destY = offset.y + pvp.y - resultPVP.y;
00419
00420 const uint32_t* color = reinterpret_cast< const uint32_t* >
00421 ( image->getPixelPointer( Frame::BUFFER_COLOR ));
00422 const float* depth = reinterpret_cast< const float* >
00423 ( image->getPixelPointer( Frame::BUFFER_DEPTH ));
00424
00425 # pragma omp parallel for
00426 for( int32_t y = 0; y < pvp.h; ++y )
00427 {
00428 const uint32_t skip = (destY + y) * resultPVP.w + destX;
00429 EQASSERT( skip * sizeof( int32_t ) <=
00430 result->getPixelDataSize( Frame::BUFFER_COLOR ));
00431 EQASSERT( skip * sizeof( float ) <=
00432 result->getPixelDataSize( Frame::BUFFER_DEPTH ));
00433
00434 uint32_t* destColorIt = destColor + skip;
00435 float* destDepthIt = destDepth + skip;
00436 const uint32_t* colorIt = color + y * pvp.w;
00437 const float* depthIt = depth + y * pvp.w;
00438
00439 for( int32_t x = 0; x < pvp.w; ++x )
00440 {
00441 if( *destDepthIt > *depthIt )
00442 {
00443 *destColorIt = *colorIt;
00444 *destDepthIt = *depthIt;
00445 }
00446
00447 ++destColorIt;
00448 ++destDepthIt;
00449 ++colorIt;
00450 ++depthIt;
00451 }
00452 }
00453 }
00454 }
00455
00456 void Compositor::_assemble2DImages( Image* result,
00457 const std::vector< FrameImage >& images )
00458 {
00459
00460 if( images.empty( ))
00461 return;
00462
00463 EQVERB << "CPU-2D assembly of " << images.size() << " images" << endl;
00464
00465 const eq::PixelViewport resultPVP = result->getPixelViewport();
00466 uint8_t* destColor = result->getPixelPointer( Frame::BUFFER_COLOR );
00467 uint8_t* destDepth = result->hasPixelData( Frame::BUFFER_DEPTH ) ?
00468 reinterpret_cast< uint8_t* >(result->getPixelPointer( Frame::BUFFER_DEPTH))
00469 : 0;
00470
00471 for( vector< FrameImage >::const_iterator i = images.begin();
00472 i != images.end(); ++i )
00473 {
00474 const Frame* frame = i->first;
00475 const Image* image = i->second;
00476 const vmml::Vector2i& offset = frame->getOffset();
00477 const PixelViewport& pvp = image->getPixelViewport();
00478 const int32_t destX = offset.x + pvp.x - resultPVP.x;
00479 const int32_t destY = offset.y + pvp.y - resultPVP.y;
00480
00481 EQASSERT( image->hasPixelData( Frame::BUFFER_COLOR ));
00482 EQASSERT( image->getFormat( Frame::BUFFER_COLOR ) ==
00483 result->getFormat( Frame::BUFFER_COLOR ));
00484 EQASSERT( image->getType( Frame::BUFFER_COLOR ) ==
00485 result->getType( Frame::BUFFER_COLOR ));
00486
00487 const uint8_t* color = image->getPixelPointer( Frame::BUFFER_COLOR );
00488 const size_t pixelSize = image->getDepth( Frame::BUFFER_COLOR );
00489 const size_t rowLength = pvp.w * pixelSize;
00490
00491 # pragma omp parallel for
00492 for( int32_t y = 0; y < pvp.h; ++y )
00493 {
00494 const size_t skip = ( (destY + y) * resultPVP.w + destX ) *
00495 pixelSize;
00496 EQASSERT( skip + rowLength <=
00497 result->getPixelDataSize( Frame::BUFFER_COLOR ));
00498
00499 memcpy( destColor + skip, color + y * pvp.w * pixelSize, rowLength);
00500 if( destDepth )
00501 {
00502 EQASSERT( pixelSize == image->getDepth( Frame::BUFFER_DEPTH ));
00503 bzero( destDepth + skip, rowLength );
00504 }
00505 }
00506 }
00507 }
00508
00509
00510 void Compositor::_assembleBlendImages( Image* result,
00511 const std::vector< FrameImage >& images )
00512 {
00513 if( images.empty( ))
00514 return;
00515
00516 EQVERB << "CPU-Blend assembly of " << images.size() <<" images"<< endl;
00517
00518 const eq::PixelViewport resultPVP = result->getPixelViewport();
00519 int32_t* destColor = reinterpret_cast< int32_t* >
00520 ( result->getPixelPointer( Frame::BUFFER_COLOR ));
00521
00522 for( vector< FrameImage >::const_iterator i = images.begin();
00523 i != images.end(); ++i )
00524 {
00525 const Frame* frame = i->first;
00526 const Image* image = i->second;
00527 const vmml::Vector2i& offset = frame->getOffset();
00528 const PixelViewport& pvp = image->getPixelViewport();
00529 const int32_t destX = offset.x + pvp.x - resultPVP.x;
00530 const int32_t destY = offset.y + pvp.y - resultPVP.y;
00531
00532 EQASSERT( image->getDepth( Frame::BUFFER_COLOR ) == 4 );
00533 EQASSERT( image->hasPixelData( Frame::BUFFER_COLOR ));
00534 EQASSERT( image->hasAlpha( ));
00535 EQASSERT( image->getFormat( Frame::BUFFER_COLOR ) ==
00536 result->getFormat( Frame::BUFFER_COLOR ));
00537 EQASSERT( image->getType( Frame::BUFFER_COLOR ) ==
00538 result->getType( Frame::BUFFER_COLOR ));
00539
00540 #ifdef EQ_USE_PARACOMP_BLEND
00541 if( pvp == resultPVP && offset == vmml::Vector2i::ZERO )
00542 {
00543
00544 if( !_assembleImage_PC( PC_COMP_ALPHA_SORT2_HP,result, image ))
00545 EQWARN << "Paracomp compositing failed, using fallback" << endl;
00546 else
00547 continue;
00548 }
00549 #endif
00550
00551 const int32_t* color = reinterpret_cast< const int32_t* >
00552 ( image->getPixelPointer( Frame::BUFFER_COLOR ));
00553
00554
00555 EQASSERT( ((destY+pvp.h-1)*resultPVP.w+destX+pvp.w)*sizeof(uint32_t) <=
00556 result->getPixelDataSize( Frame::BUFFER_COLOR ));
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568 const int32_t* colorIt = color;
00569 int32_t* destColorIt = destColor + destY*resultPVP.w + destX;
00570 const uint32_t step = sizeof( int32_t );
00571
00572 # pragma omp parallel for
00573 for( int32_t y = 0; y < pvp.h; ++y )
00574 {
00575 const unsigned char* src =
00576 reinterpret_cast< const unsigned char* >( colorIt );
00577 unsigned char* dst =
00578 reinterpret_cast< unsigned char* >( destColorIt );
00579
00580 for( int32_t x = 0; x < pvp.w; ++x )
00581 {
00582 dst[0] = EQ_MIN( src[0] + (src[3]*dst[0] >> 8), 255 );
00583 dst[1] = EQ_MIN( src[1] + (src[3]*dst[1] >> 8), 255 );
00584 dst[2] = EQ_MIN( src[2] + (src[3]*dst[2] >> 8), 255 );
00585 dst[3] = src[3]*dst[3] >> 8;
00586
00587 src += step;
00588 dst += step;
00589 }
00590 colorIt += pvp.w;
00591 destColorIt += resultPVP.w;
00592 }
00593 }
00594 }
00595
00596 #ifdef EQ_USE_PARACOMP
00597 namespace
00598 {
00599 static unsigned glToPCFormat( const unsigned glFormat, const unsigned glType )
00600 {
00601 switch( glFormat )
00602 {
00603 case GL_RGBA:
00604 case GL_RGBA8:
00605 if( glType == GL_UNSIGNED_BYTE )
00606 return PC_PF_RGBA8;
00607 break;
00608
00609 case GL_BGRA:
00610 if( glType == GL_UNSIGNED_BYTE )
00611 return PC_PF_BGRA8;
00612 break;
00613
00614 case GL_BGR:
00615 if( glType == GL_UNSIGNED_BYTE )
00616 return PC_PF_BGR8;
00617 break;
00618
00619 case GL_DEPTH_COMPONENT:
00620 if( glType == GL_FLOAT )
00621 return PC_PF_Z32F;
00622 break;
00623 }
00624
00625 return 0;
00626 }
00627 }
00628 #endif
00629
00630 bool Compositor::_assembleImage_PC( int operation, Image* result,
00631 const Image* source )
00632 {
00633 #ifdef EQ_USE_PARACOMP
00634 const unsigned colorFormat =
00635 glToPCFormat( result->getFormat( Frame::BUFFER_COLOR ),
00636 result->getType( Frame::BUFFER_COLOR ));
00637
00638 if( colorFormat == 0 )
00639 {
00640 EQWARN << "Format or type of image not supported by Paracomp" << endl;
00641 return false;
00642 }
00643
00644 PCchannel input[2];
00645 PCchannel output[2];
00646
00647 input[0].pixelFormat = colorFormat;
00648 input[0].size = result->getDepth( Frame::BUFFER_COLOR );
00649 output[0].pixelFormat = colorFormat;
00650 output[0].size = result->getDepth( Frame::BUFFER_COLOR );
00651
00652 const PixelViewport& pvp = source->getPixelViewport();
00653 EQASSERT( pvp == result->getPixelViewport( ));
00654
00655 input[0].xOffset = 0;
00656 input[0].yOffset = 0;
00657 input[0].width = pvp.w;
00658 input[0].height = pvp.h;
00659 input[0].rowLength = pvp.w * input[0].size;
00660 input[0].address = source->getPixelPointer( Frame::BUFFER_COLOR );
00661
00662 output[0].xOffset = 0;
00663 output[0].yOffset = 0;
00664 output[0].width = pvp.w;
00665 output[0].height = pvp.h;
00666 output[0].rowLength = pvp.w * output[0].size;
00667 output[0].address = result->getPixelPointer( Frame::BUFFER_COLOR );
00668
00669
00670 const bool useDepth = ( operation == PC_COMP_DEPTH );
00671 if( useDepth )
00672 {
00673 const unsigned depthFormat =
00674 glToPCFormat( result->getFormat( Frame::BUFFER_DEPTH ),
00675 result->getType( Frame::BUFFER_DEPTH ));
00676
00677 if( depthFormat == 0 )
00678 {
00679 EQWARN << "Format or type of image not supported by Paracomp"
00680 << endl;
00681 return false;
00682 }
00683
00684 input[1].pixelFormat = depthFormat;
00685 input[1].size = result->getDepth( Frame::BUFFER_DEPTH );
00686 output[1].pixelFormat = depthFormat;
00687 output[1].size = result->getDepth( Frame::BUFFER_DEPTH );
00688
00689 input[1].xOffset = 0;
00690 input[1].yOffset = 0;
00691 input[1].width = pvp.w;
00692 input[1].height = pvp.h;
00693 input[1].rowLength = pvp.w * input[1].size;
00694 input[1].address = source->getPixelPointer( Frame::BUFFER_DEPTH );
00695
00696 output[1].xOffset = 0;
00697 output[1].yOffset = 0;
00698 output[1].width = pvp.w;
00699 output[1].height = pvp.h;
00700 output[1].rowLength = pvp.w * output[1].size;
00701 output[1].address = result->getPixelPointer( Frame::BUFFER_DEPTH );
00702 }
00703
00704
00705 PCchannel* inputImages[2] = { output, input };
00706 PCchannel* outputImage[1] = { output };
00707 PCuint nInputChannels[2] = { 1, 1 };
00708 PCuint nOutputChannels[1] = { 1 };
00709
00710 if( useDepth )
00711 {
00712 nInputChannels[ 0 ] = 2;
00713 nInputChannels[ 1 ] = 2;
00714 nOutputChannels[ 0 ] = 2;
00715 }
00716
00717 const PCerr error = pcCompositeEXT( operation,
00718 2, nInputChannels, inputImages,
00719 1, nOutputChannels, outputImage );
00720 if( error != PC_NO_ERROR )
00721 {
00722 EQWARN << "Paracomp compositing failed: " << error << endl;
00723 return false;
00724 }
00725
00726 EQINFO << "Paracomp compositing successful" << endl;
00727 return true;
00728 #else
00729 return false;
00730 #endif
00731 }
00732
00733
00734 void Compositor::assembleFrame( const Frame* frame, Channel* channel )
00735 {
00736 const vector< Image* >& images = frame->getImages();
00737 if( images.empty( ))
00738 EQWARN << "No images to assemble" << endl;
00739
00740 ImageOp operation;
00741 operation.channel = channel;
00742 operation.buffers = frame->getBuffers();
00743 operation.offset = frame->getOffset();
00744 operation.pixel = frame->getPixel();
00745
00746 for( vector< Image* >::const_iterator i = images.begin();
00747 i != images.end(); ++i )
00748 {
00749 const Image* image = *i;
00750 assembleImage( image, operation );
00751 }
00752 }
00753
00754 void Compositor::assembleImage( const Image* image, const ImageOp& op )
00755 {
00756 ImageOp operation = op;
00757 operation.buffers = Frame::BUFFER_NONE;
00758
00759 if( op.buffers & Frame::BUFFER_COLOR &&
00760 image->hasPixelData( Frame::BUFFER_COLOR ))
00761
00762 operation.buffers |= Frame::BUFFER_COLOR;
00763
00764 if( op.buffers & Frame::BUFFER_DEPTH &&
00765 image->hasPixelData( Frame::BUFFER_DEPTH ))
00766
00767 operation.buffers |= Frame::BUFFER_DEPTH;
00768
00769 if( operation.buffers == Frame::BUFFER_NONE )
00770 {
00771 EQWARN << "No image attachment buffers to assemble" << endl;
00772 return;
00773 }
00774
00775 setupStencilBuffer( image, operation );
00776
00777 if( operation.buffers == Frame::BUFFER_COLOR )
00778 assembleImage2D( image, operation );
00779 else if( operation.buffers == ( Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH ))
00780 assembleImageDB( image, operation );
00781 else
00782 EQWARN << "Don't know how to assemble using buffers "
00783 << operation.buffers << endl;
00784 }
00785
00786 void Compositor::setupStencilBuffer( const Image* image, const ImageOp& op )
00787 {
00788 if( op.pixel == Pixel::ALL )
00789 return;
00790
00791
00792
00793 glClear( GL_STENCIL_BUFFER_BIT );
00794 glEnable( GL_STENCIL_TEST );
00795 glEnable( GL_DEPTH_TEST );
00796
00797 glStencilFunc( GL_ALWAYS, 1, 1 );
00798 glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE );
00799
00800 glLineWidth( 1.0f );
00801 glDepthMask( false );
00802 glColorMask( false, false, false, false );
00803
00804 const PixelViewport& pvp = image->getPixelViewport();
00805
00806 glPixelZoom( static_cast< float >( op.pixel.w ),
00807 static_cast< float >( op.pixel.h ));
00808
00809 if( op.pixel.w > 1 )
00810 {
00811 const float width = static_cast< float >( pvp.w * op.pixel.w );
00812 const float step = static_cast< float >( op.pixel.w );
00813
00814 const float startX =
00815 static_cast< float >( op.offset.x + pvp.x ) + 0.5f -
00816 static_cast< float >( op.pixel.w );
00817 const float endX = startX + width + op.pixel.w + step;
00818
00819 const float startY =
00820 static_cast< float >( op.offset.y + pvp.y + op.pixel.y );
00821 const float endY = static_cast< float >( startY + pvp.h*op.pixel.h );
00822
00823 glBegin( GL_QUADS );
00824 for( float x = startX + op.pixel.x + 1.0f ; x < endX; x += step)
00825 {
00826 glVertex3f( x-step, startY, 0.0f );
00827 glVertex3f( x-1.0f, startY, 0.0f );
00828 glVertex3f( x-1.0f, endY, 0.0f );
00829 glVertex3f( x-step, endY, 0.0f );
00830 }
00831 glEnd();
00832 }
00833 if( op.pixel.h > 1 )
00834 {
00835 const float height = static_cast< float >( pvp.h * op.pixel.h );
00836 const float step = static_cast< float >( op.pixel.h );
00837
00838 const float startX =
00839 static_cast< float >( op.offset.x + pvp.x + op.pixel.x );
00840 const float endX = static_cast< float >( startX + pvp.w*op.pixel.w );
00841
00842 const float startY =
00843 static_cast< float >( op.offset.y + pvp.y ) + 0.5f -
00844 static_cast< float >( op.pixel.h );
00845 const float endY = startY + height + op.pixel.h + step;
00846
00847 glBegin( GL_QUADS );
00848 for( float y = startY + op.pixel.y; y < endY; y += step)
00849 {
00850 glVertex3f( startX, y-step, 0.0f );
00851 glVertex3f( endX, y-step, 0.0f );
00852 glVertex3f( endX, y-1.0f, 0.0f );
00853 glVertex3f( startX, y-1.0f, 0.0f );
00854 }
00855 glEnd();
00856 }
00857
00858 glDisable( GL_DEPTH_TEST );
00859 glStencilFunc( GL_EQUAL, 0, 1 );
00860 glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
00861
00862 const ColorMask& colorMask = op.channel->getDrawBufferMask();
00863 glColorMask( colorMask.red, colorMask.green, colorMask.blue, true );
00864 glDepthMask( true );
00865 }
00866
00867 void Compositor::assembleImage2D( const Image* image, const ImageOp& op )
00868 {
00869 const PixelViewport& pvp = image->getPixelViewport();
00870
00871 EQLOG( LOG_ASSEMBLY ) << "assembleImage2D " << pvp << " offset "
00872 << op.offset << endl;
00873 EQASSERT( image->hasPixelData( Frame::BUFFER_COLOR ));
00874
00875 glRasterPos2i( op.offset.x + pvp.x, op.offset.y + pvp.y );
00876 glDrawPixels( pvp.w, pvp.h,
00877 image->getFormat( Frame::BUFFER_COLOR ),
00878 image->getType( Frame::BUFFER_COLOR ),
00879 image->getPixelPointer( Frame::BUFFER_COLOR ));
00880 }
00881
00882 void Compositor::assembleImageDB( const Image* image, const ImageOp& op )
00883 {
00884 if( GLEW_VERSION_2_0 )
00885 assembleImageDB_GLSL( image, op );
00886 else
00887 assembleImageDB_FF( image, op );
00888 }
00889
00890 void Compositor::assembleImageDB_FF( const Image* image, const ImageOp& op )
00891 {
00892 const PixelViewport& pvp = image->getPixelViewport();
00893
00894 EQLOG( LOG_ASSEMBLY ) << "assembleImageDB, fixed function " << pvp
00895 << endl;
00896 EQASSERT( image->hasPixelData( Frame::BUFFER_COLOR ));
00897 EQASSERT( image->hasPixelData( Frame::BUFFER_DEPTH ));
00898
00899
00900 glRasterPos2i( op.offset.x + pvp.x, op.offset.y + pvp.y );
00901 glEnable( GL_STENCIL_TEST );
00902
00903
00904 glEnable( GL_DEPTH_TEST );
00905
00906 const bool pixelComposite = ( op.pixel != Pixel::ALL );
00907 if( pixelComposite )
00908 {
00909 glStencilFunc( GL_EQUAL, 1, 1 );
00910 glStencilOp( GL_KEEP, GL_ZERO, GL_REPLACE );
00911 }
00912 else
00913 {
00914 glStencilFunc( GL_ALWAYS, 1, 1 );
00915 glStencilOp( GL_ZERO, GL_ZERO, GL_REPLACE );
00916 }
00917
00918 glDrawPixels( pvp.w, pvp.h, image->getFormat( Frame::BUFFER_DEPTH ),
00919 image->getType( Frame::BUFFER_DEPTH ),
00920 image->getPixelPointer( Frame::BUFFER_DEPTH ));
00921
00922 glDisable( GL_DEPTH_TEST );
00923
00924
00925 glStencilFunc( GL_EQUAL, 1, 1 );
00926 glStencilOp( GL_KEEP, GL_ZERO, GL_ZERO );
00927
00928 glDrawPixels( pvp.w, pvp.h, image->getFormat( Frame::BUFFER_COLOR ),
00929 image->getType( Frame::BUFFER_COLOR ),
00930 image->getPixelPointer( Frame::BUFFER_COLOR ));
00931
00932 glDisable( GL_STENCIL_TEST );
00933 }
00934
00935 void Compositor::assembleImageDB_GLSL( const Image* image, const ImageOp& op )
00936 {
00937 const PixelViewport& pvp = image->getPixelViewport();
00938
00939 EQLOG( LOG_ASSEMBLY ) << "assembleImageDB, GLSL " << pvp
00940 << endl;
00941
00942 Window* window = op.channel->getWindow();
00943 Window::ObjectManager* objects = window->getObjectManager();
00944
00945
00946
00947
00948
00949
00950
00951 const char* key = reinterpret_cast< char* >( window );
00952
00953 GLuint depthTexture = objects->obtainTexture( key );
00954 GLuint colorTexture = objects->obtainTexture( key+1 );
00955 GLuint program = objects->getProgram( &glslKey );
00956
00957 if( program == Window::ObjectManager::FAILED )
00958 {
00959
00960
00961 const GLuint shader = objects->newShader( &glslKey, GL_FRAGMENT_SHADER);
00962 EQASSERT( shader != Window::ObjectManager::FAILED );
00963
00964 const char* source = "uniform sampler2DRect color; uniform sampler2DRect depth; void main(void){ gl_FragColor = texture2DRect( color, gl_TexCoord[0].st ); gl_FragDepth = texture2DRect( depth, gl_TexCoord[0].st ).x; }";
00965
00966 EQ_GL_CALL( glShaderSource( shader, 1, &source, 0 ));
00967 EQ_GL_CALL( glCompileShader( shader ));
00968
00969 GLint status;
00970 glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
00971 if( !status )
00972 EQERROR << "Failed to compile fragment shader for DB compositing"
00973 << endl;
00974
00975 program = objects->newProgram( &glslKey );
00976
00977 EQ_GL_CALL( glAttachShader( program, shader ));
00978 EQ_GL_CALL( glLinkProgram( program ));
00979
00980 glGetProgramiv( program, GL_LINK_STATUS, &status );
00981 if( !status )
00982 {
00983 EQWARN << "Failed to link shader program for DB compositing"
00984 << endl;
00985 return;
00986 }
00987
00988
00989 EQ_GL_CALL( glUseProgram( program ));
00990
00991 const GLint depthParam = glGetUniformLocation( program, "depth" );
00992 glUniform1i( depthParam, 0 );
00993 const GLint colorParam = glGetUniformLocation( program, "color" );
00994 glUniform1i( colorParam, 1 );
00995
00996
00997 glFlush();
00998 }
00999 else
01000
01001 EQ_GL_CALL( glUseProgram( program ));
01002
01003
01004 glEnable( GL_TEXTURE_RECTANGLE_ARB );
01005
01006 EQ_GL_CALL( glActiveTexture( GL_TEXTURE1 ));
01007 EQ_GL_CALL( glBindTexture( GL_TEXTURE_RECTANGLE_ARB, colorTexture ));
01008 glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
01009 GL_NEAREST );
01010 glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
01011 GL_NEAREST );
01012
01013 EQ_GL_CALL( glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0,
01014 GL_RGBA,
01015 pvp.w, pvp.h, 0,
01016 image->getFormat( Frame::BUFFER_COLOR ),
01017 image->getType( Frame::BUFFER_COLOR ),
01018 image->getPixelPointer( Frame::BUFFER_COLOR )));
01019
01020 EQ_GL_CALL( glActiveTexture( GL_TEXTURE0 ));
01021 EQ_GL_CALL( glBindTexture( GL_TEXTURE_RECTANGLE_ARB, depthTexture ));
01022 glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
01023 GL_NEAREST );
01024 glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
01025 GL_NEAREST );
01026
01027 EQ_GL_CALL( glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0,
01028 GL_DEPTH_COMPONENT32_ARB,
01029 pvp.w, pvp.h, 0,
01030 image->getFormat( Frame::BUFFER_DEPTH ),
01031 image->getType( Frame::BUFFER_DEPTH ),
01032 image->getPixelPointer( Frame::BUFFER_DEPTH )));
01033
01034
01035 glEnable( GL_DEPTH_TEST );
01036 glColor3f( 1.0f, 1.0f, 1.0f );
01037
01038 const float startX = static_cast< float >
01039 ( op.offset.x + pvp.x * op.pixel.w + op.pixel.x );
01040 const float endX = static_cast< float >
01041 ( op.offset.x + (pvp.x + pvp.w) * op.pixel.w + op.pixel.x );
01042 const float startY = static_cast< float >
01043 ( op.offset.y + pvp.y * op.pixel.h + op.pixel.y );
01044 const float endY = static_cast< float >
01045 ( op.offset.y + (pvp.y + pvp.h) * op.pixel.h + op.pixel.y );
01046
01047 glBegin( GL_TRIANGLE_STRIP );
01048 glMultiTexCoord2f( GL_TEXTURE0, 0.0f, 0.0f );
01049 glMultiTexCoord2f( GL_TEXTURE1, 0.0f, 0.0f );
01050 glVertex3f( startX, startY, 0.0f );
01051
01052 glMultiTexCoord2f( GL_TEXTURE0, pvp.w, 0.0f );
01053 glMultiTexCoord2f( GL_TEXTURE1, pvp.w, 0.0f );
01054 glVertex3f( endX, startY, 0.0f );
01055
01056 glMultiTexCoord2f( GL_TEXTURE0, 0.0f, pvp.h );
01057 glMultiTexCoord2f( GL_TEXTURE1, 0.0f, pvp.h );
01058 glVertex3f( startX, endY, 0.0f );
01059
01060 glMultiTexCoord2f( GL_TEXTURE0, pvp.w, pvp.h );
01061 glMultiTexCoord2f( GL_TEXTURE1, pvp.w, pvp.h );
01062 glVertex3f( endX, endY, 0.0f );
01063
<a name="l01