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