compositor.cpp

00001 
00002 /* Copyright (c) 2007-2009, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #include <pthread.h>
00019 #include <eq/base/perThread.h>
00020 
00021 #include "channel.h"
00022 #include "channelStatistics.h"
00023 #include "client.h"
00024 #include "compositor.h"
00025 #include "image.h"
00026 #include "log.h"
00027 #include "server.h"
00028 #include "windowSystem.h"
00029 
00030 #include <eq/util/accum.h>
00031 
00032 #include <eq/base/debug.h>
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 
00046 namespace eq
00047 {
00048 
00049 #define glewGetContext channel->glewGetContext
00050 
00051 namespace
00052 {
00053 // use to address one shader and program per shared context set
00054 static const char seed = 42;
00055 static const char* shaderDBKey = &seed;
00056 static const char* colorDBKey  = shaderDBKey + 1;
00057 static const char* depthDBKey  = shaderDBKey + 2;
00058 static const char* colorKey    = shaderDBKey + 3;
00059 static const char* depthKey    = shaderDBKey + 4;
00060 
00061 class ResultImage : public Image
00062 {
00063 public:
00064     virtual ~ResultImage() {}
00065 
00066     void notifyPerThreadDelete() { delete this; }
00067 };
00068 
00069 
00070 // Image used for CPU-based assembly
00071 static base::PerThread< ResultImage > _resultImage;
00072 
00073 
00074 static bool _useCPUAssembly( const FrameVector& frames, Channel* channel, 
00075                              const bool blendAlpha = false )
00076 {
00077     // It doesn't make sense to use CPU-assembly for only one frame
00078     if( frames.size() < 2 )
00079         return false;
00080 
00081     // Test that at least two input frames have color and depth buffers or that
00082     // alpha-blended assembly is used with multiple RGBA buffers. We assume then
00083     // that we will have at least one image per frame so most likely it's worth
00084     // to wait for the images and to do a CPU-based assembly.
00085     const uint32_t desiredBuffers = blendAlpha ? Frame::BUFFER_COLOR :
00086                                     Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH;
00087     size_t nFrames = 0;
00088     for( FrameVector::const_iterator i = frames.begin();
00089          i != frames.end(); ++i )
00090     {
00091         const Frame* frame = *i;
00092         if( frame->getPixel() != Pixel::ALL ||
00093             frame->getSubPixel() != SubPixel::ALL ) // Not yet supported
00094         {
00095             return false;
00096         }
00097 
00098         if( frame->getBuffers() == desiredBuffers )
00099             ++nFrames;
00100     }
00101     if( nFrames < 2 )
00102         return false;
00103 
00104     // Now wait for all images to be ready and test if our assumption was
00105     // correct, that there are enough images to make a CPU-based assembly
00106     // worthwhile and all other preconditions for our current CPU-based assembly
00107     // code are true.
00108     size_t   nImages     = 0;
00109     uint32_t colorFormat = 0;
00110     uint32_t colorType   = 0;
00111     uint32_t depthFormat = 0;
00112     uint32_t depthType   = 0;
00113 
00114     for( FrameVector::const_iterator i = frames.begin();
00115          i != frames.end(); ++i )
00116     {
00117         const Frame* frame = *i;
00118         {
00119             ChannelStatistics event( Statistic::CHANNEL_WAIT_FRAME, channel );
00120             frame->waitReady();
00121         }
00122 
00123         const ImageVector& images = frame->getImages();        
00124         for( ImageVector::const_iterator j = images.begin(); 
00125              j != images.end(); ++j )
00126         {
00127             const Image* image = *j;
00128 
00129             const bool hasColor = image->hasPixelData( Frame::BUFFER_COLOR );
00130             const bool hasDepth = image->hasPixelData( Frame::BUFFER_DEPTH );
00131             
00132             if(( blendAlpha && hasColor && image->hasAlpha( )) ||
00133                ( hasColor && hasDepth ))
00134             {
00135                 if( colorFormat == 0 )
00136                 {
00137                     colorFormat = image->getFormat( Frame::BUFFER_COLOR );
00138                     colorType   = image->getType(   Frame::BUFFER_COLOR );
00139 
00140                     if (( colorType == GL_HALF_FLOAT ) || 
00141                         ( colorType == GL_FLOAT ))
00142                         return false;
00143                 }
00144 
00145                 if( colorFormat != image->getFormat( Frame::BUFFER_COLOR ) ||
00146                     colorType   != image->getType(   Frame::BUFFER_COLOR ))
00147 
00148                     return false;
00149 
00150                 if( image->hasPixelData( Frame::BUFFER_DEPTH ))
00151                 {
00152                     if( depthFormat == 0 )
00153                     {
00154                         depthFormat = image->getFormat( Frame::BUFFER_DEPTH );
00155                         depthType   = image->getType(   Frame::BUFFER_DEPTH );
00156                     }
00157 
00158                     if( depthFormat != image->getFormat(Frame::BUFFER_DEPTH ) ||
00159                         depthType   != image->getType(  Frame::BUFFER_DEPTH ))
00160 
00161                         return false;
00162                 }
00163 
00164                 ++nImages;
00165             }
00166         }
00167 
00168         if( nImages > 1 ) // early-out to reduce wait time
00169             return true;
00170     }
00171 
00172     return false;
00173 }
00174 }
00175 
00176 uint32_t Compositor::assembleFrames( const FrameVector& frames,
00177                                      Channel* channel, util::Accum* accum )
00178 {
00179     if( frames.empty( ))
00180         return 0;
00181 
00182     if( _useCPUAssembly( frames, channel ))
00183         return assembleFramesCPU( frames, channel );
00184 
00185     // else
00186     return assembleFramesUnsorted( frames, channel, accum );
00187 }
00188 
00189 util::Accum* Compositor::_obtainAccum( Channel* channel )
00190 {
00191     const PixelViewport& pvp = channel->getPixelViewport();
00192 
00193     EQASSERT( pvp.isValid( ));
00194 
00195     Window::ObjectManager* objects = channel->getObjectManager();
00196     util::Accum* accum = objects->getEqAccum( channel );
00197     if( !accum )
00198     {
00199         accum = objects->newEqAccum( channel );
00200         if( !accum->init( pvp, channel->getWindow()->getColorFormat( )))
00201         {
00202             EQERROR << "Accumulation initialization failed." << std::endl;
00203         }
00204     }
00205     else
00206         accum->resize( pvp.w, pvp.h );
00207 
00208     accum->clear();
00209     return accum;
00210 }
00211 
00212 uint32_t Compositor::assembleFramesSorted( const FrameVector& frames,
00213                                            Channel* channel, util::Accum* accum,
00214                                            const bool blendAlpha )
00215 {
00216     if( frames.empty( ))
00217         return 0;
00218 
00219     if( _isSubPixelDecomposition( frames ))
00220     {
00221         uint32_t count = 0;
00222         if( !accum )
00223         {
00224             accum = _obtainAccum( channel );
00225             accum->clear();
00226 
00227             const SubPixel& subpixel = frames.back()->getSubPixel();
00228             accum->setTotalSteps( subpixel.size );
00229         }
00230 
00231         FrameVector framesLeft = frames;
00232         while( !framesLeft.empty( ))
00233         {
00234             FrameVector current = _extractOneSubPixel( framesLeft );
00235             const uint32_t subCount = assembleFramesSorted( current, channel,
00236                                                             accum );
00237             EQASSERT( subCount < 2 );
00238 
00239             if( subCount > 0 )
00240                 accum->accum();
00241             count += subCount;
00242         }
00243         if( count > 0 )
00244             accum->display();
00245         return count;
00246     }
00247 
00248     uint32_t count = 0;
00249     if( blendAlpha )
00250     {
00251         glEnable( GL_BLEND );
00252         EQASSERT( GLEW_EXT_blend_func_separate );
00253         glBlendFuncSeparate( GL_ONE, GL_SRC_ALPHA, GL_ZERO, GL_SRC_ALPHA );
00254     }
00255 
00256     if( _useCPUAssembly( frames, channel, blendAlpha ))
00257         count |= assembleFramesCPU( frames, channel, blendAlpha );
00258     else
00259     {
00260         for( FrameVector::const_iterator i = frames.begin();
00261              i != frames.end(); ++i )
00262         {
00263             Frame* frame = *i;
00264             {
00265                 ChannelStatistics event( Statistic::CHANNEL_WAIT_FRAME,
00266                                          channel );
00267                 frame->waitReady( );
00268             }
00269 
00270             if( !frame->getImages().empty( ))
00271             {
00272                 count = 1;
00273                 assembleFrame( frame, channel );
00274             }
00275         }
00276     }
00277 
00278     if( blendAlpha )
00279         glDisable( GL_BLEND );
00280 
00281     return count;
00282 }
00283 
00284 bool Compositor::_isSubPixelDecomposition( const FrameVector& frames )
00285 {
00286     if( frames.empty( ))
00287         return false;
00288         
00289     FrameVector::const_iterator i = frames.begin();
00290     Frame* frame = *i;
00291     const SubPixel& subpixel = frame->getSubPixel();
00292     
00293     for( ++i; i != frames.end(); ++i)
00294     {
00295         frame = *i;
00296         if( subpixel != frame->getSubPixel( ))
00297             return true;
00298     }
00299 
00300     return false;
00301 }
00302 
00303 const FrameVector Compositor::_extractOneSubPixel( FrameVector& frames )
00304 {
00305     FrameVector current;
00306 
00307     const SubPixel& subpixel = frames.back()->getSubPixel();
00308     current.push_back( frames.back( ));
00309     frames.pop_back();
00310 
00311     for( FrameVector::iterator i = frames.begin();
00312                 i != frames.end(); )
00313     {
00314         Frame* frame = *i;
00315 
00316         if( frame->getSubPixel() == subpixel )
00317         {
00318             current.push_back( frame );
00319             i = frames.erase( i );
00320         }
00321         else
00322             ++i;
00323     }
00324 
00325     return current;
00326 }
00327 
00328 uint32_t Compositor::assembleFramesUnsorted( const FrameVector& frames,
00329                                              Channel* channel, 
00330                                              util::Accum* accum )
00331 {
00332     if( frames.empty( ))
00333         return 0;
00334 
00335     EQVERB << "Unsorted GPU assembly" << std::endl;
00336     if( _isSubPixelDecomposition( frames ))
00337     {
00338         uint32_t count = 0;
00339 
00340         if( !accum )
00341         {
00342             accum = _obtainAccum( channel );
00343             accum->clear();
00344 
00345             const SubPixel& subpixel = frames.back()->getSubPixel();
00346             accum->setTotalSteps( subpixel.size );
00347         }
00348 
00349         FrameVector framesLeft = frames;
00350         while( !framesLeft.empty( ))
00351         {
00352             // get the frames with the same subpixel compound
00353             FrameVector current = _extractOneSubPixel( framesLeft );
00354 
00355             // use assembleFrames to potentially benefit from CPU assembly
00356             const uint32_t subCount = assembleFrames( current, channel, accum );
00357             EQASSERT( subCount < 2 )
00358             if( subCount > 0 )
00359                 accum->accum();
00360             count += subCount;
00361         }
00362         if( count > 1 )
00363             accum->display();
00364         return count;
00365     }
00366 
00367     // This is an optimized assembly version. The frames are not assembled in
00368     // the saved order, but in the order they become available, which is faster
00369     // because less time is spent waiting on frame availability.
00370     //
00371     // The ready frames are counted in a monitor. Whenever a frame becomes
00372     // available, it increments the monitor which causes this code to wake up
00373     // and assemble it.
00374 
00375     // register monitor with all input frames
00376     Monitor<uint32_t> monitor;
00377     for( FrameVector::const_iterator i = frames.begin();
00378          i != frames.end(); ++i )
00379     {
00380         Frame* frame = *i;
00381         frame->addListener( monitor );
00382     }
00383 
00384     uint32_t    nUsedFrames  = 0;
00385     FrameVector unusedFrames = frames;
00386 
00387     uint32_t count = 0;
00388     // wait and assemble frames
00389     while( !unusedFrames.empty( ))
00390     {
00391         {
00392             ChannelStatistics event( Statistic::CHANNEL_WAIT_FRAME, channel );
00393             monitor.waitGE( ++nUsedFrames );
00394         }
00395 
00396         for( FrameVector::iterator i = unusedFrames.begin();
00397              i != unusedFrames.end(); ++i )
00398         {
00399             Frame* frame = *i;
00400             if( !frame->isReady( ))
00401                 continue;
00402 
00403             if( !frame->getImages().empty( ))
00404             {
00405                 count = 1;
00406                 assembleFrame( frame, channel );
00407             }
00408     
00409             unusedFrames.erase( i );
00410             break;
00411         }
00412     }
00413 
00414     // de-register the monitor
00415     for( FrameVector::const_iterator i = frames.begin(); i != frames.end();
00416          ++i )
00417     {
00418         Frame* frame = *i;
00419         // syncAssembleFrame( frame );
00420         frame->removeListener( monitor );
00421     }
00422 
00423     return count;
00424 }
00425 
00426 uint32_t Compositor::assembleFramesCPU( const FrameVector& frames,
00427                                         Channel* channel,
00428                                         const bool blendAlpha )
00429 {
00430     if( frames.empty( ))
00431         return 0;
00432 
00433     EQVERB << "Sorted CPU assembly" << std::endl;
00434     // Assembles images from DB and 2D compounds using the CPU and then
00435     // assembles the result image. Does not yet support Pixel or Eye
00436     // compounds.
00437 
00438     const Image* result = mergeFramesCPU( frames, blendAlpha );
00439     if( !result )
00440         return 0;
00441 
00442     // assemble result on dest channel
00443     ImageOp operation;
00444     operation.channel = channel;
00445     operation.buffers = Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH;
00446     assembleImage( result, operation );
00447 
00448 #if 0
00449     static uint32_t counter = 0;
00450     ostringstream stringstream;
00451     stringstream << "Image_" << ++counter;
00452     result->writeImages( stringstream.str( ));
00453 #endif
00454 
00455     return 1;
00456 }
00457 
00458 const Image* Compositor::mergeFramesCPU( const FrameVector& frames,
00459                                          const bool blendAlpha )
00460 {
00461     EQVERB << "Sorted CPU assembly" << std::endl;
00462 
00463     // Collect input image information and check preconditions
00464     PixelViewport destPVP;
00465     uint32_t colorFormat = GL_NONE;
00466     uint32_t colorType   = GL_NONE;
00467     uint32_t depthFormat = GL_NONE;
00468     uint32_t depthType   = GL_NONE;
00469 
00470     if( !_collectOutputData( frames, destPVP, 
00471                              colorFormat, colorType, depthFormat, depthType ))
00472     {
00473         return 0;
00474     }
00475 
00476     // prepare output image
00477     Image* result = _resultImage.get();
00478     if( !result )
00479     {
00480         _resultImage = new ResultImage;
00481         result       = _resultImage.get();
00482     }
00483 
00484     // pre-condition check for current _merge implementations
00485     EQASSERT( colorFormat != GL_NONE );
00486     EQASSERT( colorType   != GL_NONE );
00487 
00488     result->setFormat( Frame::BUFFER_COLOR, colorFormat );
00489     result->setType(   Frame::BUFFER_COLOR, colorType );
00490     result->setPixelViewport( destPVP );
00491     result->clearPixelData( Frame::BUFFER_COLOR );
00492 
00493     void* destDepth = 0;
00494     if( depthFormat != GL_NONE ) // at least one depth assembly
00495     {
00496         EQASSERT( depthFormat == GL_DEPTH_COMPONENT );
00497         EQASSERT( depthType   == GL_UNSIGNED_INT );
00498 
00499         result->setFormat( Frame::BUFFER_DEPTH, depthFormat );
00500         result->setType(   Frame::BUFFER_DEPTH, depthType );
00501         result->clearPixelData( Frame::BUFFER_DEPTH );
00502         destDepth = result->getPixelPointer( Frame::BUFFER_DEPTH );
00503     }
00504 
00505     // assembly
00506     _mergeFrames( frames, blendAlpha, 
00507                   result->getPixelPointer( Frame::BUFFER_COLOR ),
00508                   destDepth, destPVP );
00509     return result;
00510 }
00511 
00512 bool Compositor::_collectOutputData( const FrameVector& frames,
00513                                      PixelViewport& destPVP, 
00514                                      uint32_t& colorFormat, uint32_t& colorType,
00515                                      uint32_t& depthFormat, uint32_t& depthType)
00516 {
00517     for( FrameVector::const_iterator i = frames.begin(); i != frames.end(); ++i)
00518     {
00519         Frame* frame = *i;
00520         frame->waitReady();
00521 
00522         EQASSERTINFO( frame->getPixel() == Pixel::ALL || 
00523                       frame->getSubPixel() == SubPixel::ALL,
00524                       "CPU-based (sub)pixel recomposition not implemented" );
00525         if( frame->getPixel() != Pixel::ALL )
00526             return false;
00527 
00528         const ImageVector& images = frame->getImages();        
00529         for( ImageVector::const_iterator j = images.begin(); 
00530              j != images.end(); ++j )
00531         {
00532             const Image* image = *j;
00533             EQASSERT( image->getStorageType() == Frame::TYPE_MEMORY );
00534             if( image->getStorageType() != Frame::TYPE_MEMORY )
00535                 return false;
00536 
00537             if( !image->hasPixelData( Frame::BUFFER_COLOR ))
00538                 continue;
00539 
00540             destPVP.merge( image->getPixelViewport() + frame->getOffset( ));
00541 
00542             EQASSERT( colorFormat == GL_NONE ||
00543                       colorFormat == image->getFormat( Frame::BUFFER_COLOR ));
00544             EQASSERT( colorType == GL_NONE ||
00545                       colorType == image->getType( Frame::BUFFER_COLOR ));
00546 
00547             colorFormat = image->getFormat( Frame::BUFFER_COLOR );
00548             colorType   = image->getType( Frame::BUFFER_COLOR );
00549 
00550             if( image->hasPixelData( Frame::BUFFER_DEPTH ))
00551             {
00552                 EQASSERT( depthFormat == GL_NONE ||
00553                           depthFormat == image->getFormat(Frame::BUFFER_DEPTH));
00554                 EQASSERT( depthType == GL_NONE ||
00555                           depthType == image->getType( Frame::BUFFER_DEPTH ));
00556 
00557                 depthFormat = image->getFormat( Frame::BUFFER_DEPTH );
00558                 depthType   = image->getType( Frame::BUFFER_DEPTH );
00559             }
00560         }
00561     }
00562 
00563     if( !destPVP.hasArea( ))
00564     {
00565         EQWARN << "Nothing to assemble: " << destPVP << std::endl;
00566         return false;
00567     }
00568 
00569     return true;
00570 }
00571 
00572 bool Compositor::mergeFramesCPU( const FrameVector& frames,
00573                                  const bool blendAlpha, void* colorBuffer,
00574                                  const uint32_t colorBufferSize,
00575                                  void* depthBuffer,
00576                                  const uint32_t depthBufferSize,
00577                                  PixelViewport& outPVP )
00578 {
00579     EQASSERT( colorBuffer );
00580     EQVERB << "Sorted CPU assembly" << std::endl;
00581     
00582     // Collect input image information and check preconditions
00583     uint32_t colorFormat = GL_NONE;
00584     uint32_t colorType   = GL_NONE;
00585     uint32_t depthFormat = GL_NONE;
00586     uint32_t depthType   = GL_NONE;
00587     outPVP.invalidate();
00588 
00589     if( !_collectOutputData( frames, outPVP, 
00590                              colorFormat, colorType, depthFormat, depthType ))
00591     {
00592         return false;
00593     }
00594 
00595     // pre-condition check for current _merge implementations
00596     EQASSERT( colorFormat != GL_NONE );
00597     EQASSERT( colorType   != GL_NONE );
00598 
00599     // check output buffers
00600     const uint32_t area = outPVP.getArea();
00601     const uint32_t colorPixelDepth = (colorFormat == GL_RGB) ? 3 : 4;
00602 
00603     if( colorBufferSize < area * colorPixelDepth )
00604     {
00605         EQWARN << "Color output buffer to small" << std::endl;
00606         return false;
00607     }
00608 
00609     if( depthFormat != GL_NONE ) // at least one depth assembly
00610     {
00611         EQASSERT( depthBuffer );
00612         EQASSERT( depthFormat == GL_DEPTH_COMPONENT );
00613         EQASSERT( depthType   == GL_UNSIGNED_INT );
00614 
00615         if( !depthBuffer )
00616         {
00617             EQWARN << "No depth output buffer provided" << std::endl;
00618             return false;
00619         }
00620 
00621         if( depthBufferSize < area * 4 )
00622         {
00623             EQWARN << "Depth output buffer to small" << std::endl;
00624             return false;
00625         }
00626     }
00627 
00628     // assembly
00629     _mergeFrames( frames, blendAlpha, colorBuffer, depthBuffer, outPVP );
00630     return true;
00631 }
00632 
00633 void Compositor::_mergeFrames( const FrameVector& frames,
00634                                const bool blendAlpha, 
00635                                void* colorBuffer, void* depthBuffer,
00636                                const PixelViewport& destPVP )
00637 {
00638     for( FrameVector::const_iterator i = frames.begin(); i != frames.end(); ++i)
00639     {
00640         const Frame* frame = *i;
00641         const ImageVector& images = frame->getImages();        
00642         for( ImageVector::const_iterator j = images.begin();
00643              j != images.end(); ++j )
00644         {
00645             const Image* image = *j;
00646 
00647             if( !image->hasPixelData( Frame::BUFFER_COLOR ))
00648                 continue;
00649 
00650             if( image->hasPixelData( Frame::BUFFER_DEPTH ))
00651                 _mergeDBImage( colorBuffer, depthBuffer, destPVP,
00652                                image, frame->getOffset( ));
00653             else if( blendAlpha && image->hasAlpha( ))
00654                 _mergeBlendImage( colorBuffer, destPVP, 
00655                                   image, frame->getOffset( ));
00656             else
00657                 _merge2DImage( colorBuffer, depthBuffer, destPVP, 
00658                                image, frame->getOffset());
00659         }
00660     }
00661 }
00662 
00663 
00664 void Compositor::_mergeDBImage( void* destColor, void* destDepth,
00665                                 const PixelViewport& destPVP,
00666                                 const Image* image, 
00667                                 const Vector2i& offset )
00668 {
00669     EQASSERT( destColor && destDepth );
00670 
00671     EQVERB << "CPU-DB assembly" << std::endl;
00672 
00673     uint32_t* destC = reinterpret_cast< uint32_t* >( destColor );
00674     uint32_t* destD = reinterpret_cast< uint32_t* >( destDepth );
00675 
00676     const PixelViewport&  pvp    = image->getPixelViewport();
00677 
00678 #ifdef EQ_USE_PARACOMP_DEPTH
00679     if( pvp == destPVP && offset == eq::Vector2i::ZERO )
00680     {
00681         // Use Paracomp to composite
00682         if( _mergeImage_PC( PC_COMP_DEPTH, destColor, destDepth, image ))
00683             return;
00684 
00685         EQWARN << "Paracomp compositing failed, using fallback" << std::endl;
00686     }
00687 #endif
00688 
00689     const int32_t         destX  = offset.x() + pvp.x - destPVP.x;
00690     const int32_t         destY  = offset.y() + pvp.y - destPVP.y;
00691 
00692     const uint32_t* color = reinterpret_cast< const uint32_t* >
00693         ( image->getPixelPointer( Frame::BUFFER_COLOR ));
00694     const uint32_t* depth = reinterpret_cast< const uint32_t* >
00695         ( image->getPixelPointer( Frame::BUFFER_DEPTH ));
00696 
00697 #ifdef EQ_USE_OPENMP
00698 #  pragma omp parallel for
00699 #endif
00700     for( int32_t y = 0; y < pvp.h; ++y )
00701     {
00702         const uint32_t skip =  (destY + y) * destPVP.w + destX;
00703         uint32_t* destColorIt = destC + skip;
00704         uint32_t* destDepthIt = destD + skip;
00705         const uint32_t* colorIt = color + y * pvp.w;
00706         const uint32_t* depthIt = depth + y * pvp.w;
00707 
00708         for( int32_t x = 0; x < pvp.w; ++x )
00709         {
00710             if( *destDepthIt > *depthIt )
00711             {
00712                 *destColorIt = *colorIt;
00713                 *destDepthIt = *depthIt;
00714             }
00715             
00716             ++destColorIt;
00717             ++destDepthIt;
00718             ++colorIt;
00719             ++depthIt;
00720         }
00721     }
00722 }
00723 
00724 void Compositor::_merge2DImage( void* destColor, void* destDepth,
00725                                 const eq::PixelViewport& destPVP,
00726                                 const Image* image,
00727                                 const Vector2i& offset )
00728 {
00729     // This is mostly copy&paste code from _mergeDBImage :-/
00730     EQVERB << "CPU-2D assembly" << std::endl;
00731 
00732     uint8_t* destC = reinterpret_cast< uint8_t* >( destColor );
00733     uint8_t* destD = reinterpret_cast< uint8_t* >( destDepth );
00734 
00735     const PixelViewport&  pvp    = image->getPixelViewport();
00736     const int32_t         destX  = offset.x() + pvp.x - destPVP.x;
00737     const int32_t         destY  = offset.y() + pvp.y - destPVP.y;
00738 
00739     EQASSERT( image->hasPixelData( Frame::BUFFER_COLOR ));
00740 
00741     const uint8_t*   color = image->getPixelPointer( Frame::BUFFER_COLOR );
00742     const size_t pixelSize = image->getDepth( Frame::BUFFER_COLOR );
00743     const size_t rowLength = pvp.w * pixelSize;
00744 
00745 #ifdef EQ_USE_OPENMP
00746 #  pragma omp parallel for
00747 #endif
00748     for( int32_t y = 0; y < pvp.h; ++y )
00749     {
00750         const size_t skip = ( (destY + y) * destPVP.w + destX ) * pixelSize;
00751         memcpy( destC + skip, color + y * pvp.w * pixelSize, rowLength);
00752         if( destD ) // clear depth, for depth-assembly into existing FB
00753             bzero( destD + skip, rowLength );
00754     }
00755 }
00756 
00757 
00758 void Compositor::_mergeBlendImage( void* dest, const eq::PixelViewport& destPVP,
00759                                    const Image* image,
00760                                    const Vector2i& offset )
00761 {
00762     EQVERB << "CPU-Blend assembly"<< std::endl;
00763 
00764     int32_t* destColor = reinterpret_cast< int32_t* >( dest );
00765 
00766     const PixelViewport&  pvp    = image->getPixelViewport();
00767     const int32_t         destX  = offset.x() + pvp.x - destPVP.x;
00768     const int32_t         destY  = offset.y() + pvp.y - destPVP.y;
00769 
00770     EQASSERT( image->getDepth( Frame::BUFFER_COLOR ) == 4 );
00771     EQASSERT( image->hasPixelData( Frame::BUFFER_COLOR ));
00772     EQASSERT( image->hasAlpha( ));
00773     
00774 #ifdef EQ_USE_PARACOMP_BLEND
00775     if( pvp == destPVP && offset == eq::Vector2i::ZERO )
00776     { 
00777         // Use Paracomp to composite
00778         if( !_mergeImage_PC( PC_COMP_ALPHA_SORT2_HP, dest, 0, image ))
00779             EQWARN << "Paracomp compositing failed, using fallback" << std::endl;
00780         else
00781             return; // Go to next input image
00782     }
00783 #endif
00784 
00785     const int32_t* color = reinterpret_cast< const int32_t* >
00786                                ( image->getPixelPointer( Frame::BUFFER_COLOR ));
00787 
00788     // Blending of two slices, none of which is on final image (i.e. result
00789     // could be blended on to something else) should be performed with:
00790     // glBlendFuncSeparate( GL_ONE, GL_SRC_ALPHA, GL_ZERO, GL_SRC_ALPHA )
00791     // which means:
00792     // dstColor = 1*srcColor + srcAlpha*dstColor
00793     // dstAlpha = 0*srcAlpha + srcAlpha*dstAlpha
00794     // because we accumulate light which is go through (= 1-Alpha) and we
00795     // already have colors as Alpha*Color
00796 
00797     int32_t* destColorStart = destColor + destY*destPVP.w + destX;
00798     const uint32_t step = sizeof( int32_t );
00799 
00800 #ifdef EQ_USE_OPENMP
00801 #  pragma omp parallel for
00802 #endif
00803     for( int32_t y = 0; y < pvp.h; ++y )
00804     {
00805         const unsigned char* src =
00806             reinterpret_cast< const uint8_t* >( color + pvp.w * y );
00807         unsigned char*       dst =
00808             reinterpret_cast< uint8_t* >( destColorStart + destPVP.w * y );
00809 
00810         for( int32_t x = 0; x < pvp.w; ++x )
00811         {
00812             dst[0] = EQ_MIN( src[0] + (src[3]*dst[0] >> 8), 255 );
00813             dst[1] = EQ_MIN( src[1] + (src[3]*dst[1] >> 8), 255 );
00814             dst[2] = EQ_MIN( src[2] + (src[3]*dst[2] >> 8), 255 );
00815             dst[3] =                   src[3]*dst[3] >> 8;
00816 
00817             src += step;
00818             dst += step;
00819         }
00820     }
00821 }
00822 
00823 #ifdef EQ_USE_PARACOMP
00824 namespace
00825 {
00826 static unsigned glToPCFormat( const unsigned glFormat, const unsigned glType )
00827 {
00828     switch( glFormat )
00829     {
00830         case GL_RGBA:
00831         case GL_RGBA8:
00832             if( glType == GL_UNSIGNED_BYTE )
00833                 return PC_PF_RGBA8;
00834             break;
00835 
00836         case GL_BGRA:
00837             if( glType == GL_UNSIGNED_BYTE )
00838                 return PC_PF_BGRA8;
00839             break;
00840 
00841         case GL_BGR:
00842             if( glType == GL_UNSIGNED_BYTE )
00843                 return PC_PF_BGR8;
00844             break;
00845 
00846         case GL_DEPTH_COMPONENT:
00847             if( glType == GL_FLOAT )
00848                 return PC_PF_Z32F;
00849             break;
00850     }
00851 
00852     return 0;
00853 }
00854 }
00855 #endif
00856 
00857 bool Compositor::_mergeImage_PC( int operation, void* destColor, 
00858                                  void* destDepth, const Image* source )
00859 {
00860 #ifdef EQ_USE_PARACOMP
00861     const unsigned colorFormat = 
00862         glToPCFormat( source->getFormat( Frame::BUFFER_COLOR ),
00863                       source->getType(   Frame::BUFFER_COLOR ));
00864 
00865     if( colorFormat == 0 )
00866     {
00867         EQWARN << "Format or type of image not supported by Paracomp" << std::endl;
00868         return false;
00869     }
00870 
00871     PCchannel input[2];
00872     PCchannel output[2];
00873     
00874     input[0].pixelFormat  = colorFormat;
00875     input[0].size         = source->getDepth( Frame::BUFFER_COLOR );
00876     output[0].pixelFormat = colorFormat;
00877     output[0].size        = source->getDepth( Frame::BUFFER_COLOR );
00878 
00879     const PixelViewport& pvp = source->getPixelViewport();
00880     EQASSERT( pvp == source->getPixelViewport( ));
00881 
00882     input[0].xOffset   = 0;
00883     input[0].yOffset   = 0;
00884     input[0].width     = pvp.w;
00885     input[0].height    = pvp.h;
00886     input[0].rowLength = pvp.w * input[0].size;
00887     input[0].address   = source->getPixelPointer( Frame::BUFFER_COLOR );
00888 
00889     output[0].xOffset   = 0;
00890     output[0].yOffset   = 0;
00891     output[0].width     = pvp.w;
00892     output[0].height    = pvp.h;
00893     output[0].rowLength = pvp.w * output[0].size;
00894     output[0].address   = destColor;
00895     
00896     const bool useDepth = ( operation == PC_COMP_DEPTH );
00897     if( useDepth )
00898     {
00899         const unsigned depthFormat = 
00900             glToPCFormat( source->getFormat( Frame::BUFFER_DEPTH ),
00901                           source->getType(   Frame::BUFFER_DEPTH ));
00902 
00903         if( depthFormat == 0 )
00904         {
00905             EQWARN << "Format or type of image not supported by Paracomp" 
00906                    << std::endl;
00907             return false;
00908         }
00909 
00910         input[1].pixelFormat  = depthFormat;
00911         input[1].size         = source->getDepth( Frame::BUFFER_DEPTH );
00912         output[1].pixelFormat = depthFormat;
00913         output[1].size        = source->getDepth( Frame::BUFFER_DEPTH );
00914 
00915         input[1].xOffset   = 0;
00916         input[1].yOffset   = 0;
00917         input[1].width     = pvp.w;
00918         input[1].height    = pvp.h;
00919         input[1].rowLength = pvp.w * input[1].size;
00920         input[1].address   = source->getPixelPointer( Frame::BUFFER_DEPTH );
00921 
00922         output[1].xOffset   = 0;
00923         output[1].yOffset   = 0;
00924         output[1].width     = pvp.w;
00925         output[1].height    = pvp.h;
00926         output[1].rowLength = pvp.w * output[1].size;
00927         output[1].address   = destDepth;
00928     }
00929 
00930 
00931     PCchannel* inputImages[2]     = { output, input };
00932     PCchannel* outputImage[1]     = { output };
00933     PCuint     nInputChannels[2]  = { 1, 1 };
00934     PCuint     nOutputChannels[1] = { 1 };
00935 
00936     if( useDepth )
00937     {
00938         nInputChannels[ 0 ]  = 2;
00939         nInputChannels[ 1 ]  = 2;
00940         nOutputChannels[ 0 ] = 2;
00941     }
00942 
00943     const PCerr error = pcCompositeEXT( operation, 
00944                                         2, nInputChannels, inputImages,
00945                                         1, nOutputChannels, outputImage );
00946     if( error != PC_NO_ERROR )
00947     {
00948         EQWARN << "Paracomp compositing failed: " << error << std::endl;
00949         return false;
00950     }
00951 
00952     EQINFO << "Paracomp compositing successful" << std::endl;
00953     return true;
00954 #else
00955     return false;
00956 #endif
00957 }
00958 
00959 
00960 void Compositor::assembleFrame( const Frame* frame, Channel* channel )
00961 {
00962     const ImageVector& images = frame->getImages();
00963     if( images.empty( ))
00964         EQINFO << "No images to assemble" << std::endl;
00965 
00966     ImageOp operation;
00967     operation.channel = channel;
00968     operation.buffers = frame->getBuffers();
00969     operation.offset  = frame->getOffset();
00970     operation.pixel   = frame->getPixel();
00971     operation.zoom    = frame->getZoom();
00972 
00973     for( ImageVector::const_iterator i = images.begin(); 
00974          i != images.end(); ++i )
00975     {
00976         const Image* image = *i;
00977         assembleImage( image, operation );
00978     }
00979 }
00980 
00981 void Compositor::assembleImage( const Image* image, const ImageOp& op )
00982 {
00983     ImageOp operation = op;
00984     operation.buffers = Frame::BUFFER_NONE;
00985 
00986     if( op.buffers&Frame::BUFFER_COLOR && image->hasData( Frame::BUFFER_COLOR ))
00987         operation.buffers |= Frame::BUFFER_COLOR;
00988 
00989     if( op.buffers&Frame::BUFFER_DEPTH && image->hasData( Frame::BUFFER_DEPTH ))
00990         operation.buffers |= Frame::BUFFER_DEPTH;
00991 
00992     if( operation.buffers == Frame::BUFFER_NONE )
00993     {
00994         EQWARN << "No image attachment buffers to assemble" << std::endl;
00995         return;
00996     }
00997 
00998     setupStencilBuffer( image, operation );
00999 
01000     if( operation.buffers == Frame::BUFFER_COLOR )
01001         assembleImage2D( image, operation );
01002     else if( operation.buffers == ( Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH ))
01003         assembleImageDB( image, operation );
01004     else
01005         EQWARN << "Don't know how to assemble using buffers " 
01006                << operation.buffers << std::endl;
01007 
01008     clearStencilBuffer( operation );
01009 }
01010 
01011 void Compositor::setupStencilBuffer( const Image* image, const ImageOp& op )
01012 {
01013     if( op.pixel == Pixel::ALL )
01014         return;
01015 
01016     // mark stencil buffer where pixel shall not pass
01017     // TODO: OPT!
01018     glClear( GL_STENCIL_BUFFER_BIT );
01019     glEnable( GL_STENCIL_TEST );
01020     glEnable( GL_DEPTH_TEST );
01021 
01022     glStencilFunc( GL_ALWAYS, 1, 1 );
01023     glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE );
01024 
01025     glLineWidth( 1.0f );
01026     glDepthMask( false );
01027     glColorMask( false, false, false, false );
01028     
01029     const PixelViewport& pvp = image->getPixelViewport();
01030 
01031     glPixelZoom( static_cast< float >( op.pixel.w ),
01032                  static_cast< float >( op.pixel.h ));
01033 
01034     if( op.pixel.w > 1 )
01035     {
01036         const float width  = static_cast< float >( pvp.w * op.pixel.w );
01037         const float step   = static_cast< float >( op.pixel.w );
01038 
01039         const float startX = 
01040             static_cast< float >( op.offset.x() + pvp.x ) + 0.5f - 
01041             static_cast< float >( op.pixel.w );
01042         const float endX   = startX + width + op.pixel.w + step;
01043 
01044         const float startY = 
01045             static_cast< float >( op.offset.y() + pvp.y + op.pixel.y );
01046         const float endY   = static_cast< float >( startY + pvp.h*op.pixel.h );
01047 
01048         glBegin( GL_QUADS );
01049         for( float x = startX + op.pixel.x + 1.0f ; x < endX; x += step)
01050         {
01051             glVertex3f( x-step, startY, 0.0f );
01052             glVertex3f( x-1.0f, startY, 0.0f );
01053             glVertex3f( x-1.0f, endY, 0.0f );        
01054             glVertex3f( x-step, endY, 0.0f );        
01055         }
01056         glEnd();
01057     }
01058     if( op.pixel.h > 1 )
01059     {
01060         const float height = static_cast< float >( pvp.h * op.pixel.h );
01061         const float step   = static_cast< float >( op.pixel.h );
01062 
01063         const float startX = 
01064             static_cast< float >( op.offset.x() + pvp.x + op.pixel.x );
01065         const float endX   = static_cast< float >( startX + pvp.w*op.pixel.w );
01066 
01067         const float startY = 
01068             static_cast< float >( op.offset.y() + pvp.y ) + 0.5f - 
01069             static_cast< float >( op.pixel.h );
01070         const float endY   = startY + height + op.pixel.h + step;
01071 
01072         glBegin( GL_QUADS );
01073         for( float y = startY + op.pixel.y; y < endY; y += step)
01074         {
01075             glVertex3f( startX, y-step, 0.0f );
01076             glVertex3f( endX,   y-step, 0.0f );        
01077             glVertex3f( endX,   y-1.0f, 0.0f );        
01078             glVertex3f( startX, y-1.0f, 0.0f );
01079         }
01080         glEnd();
01081     }
01082     
01083     glDisable( GL_DEPTH_TEST );
01084     glStencilFunc( GL_EQUAL, 0, 1 );
01085     glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
01086     
01087     const ColorMask& colorMask = op.channel->getDrawBufferMask();
01088     glColorMask( colorMask.red, colorMask.green, colorMask.blue, true );
01089     glDepthMask( true );
01090 }
01091 
01092 void Compositor::clearStencilBuffer( const ImageOp& op )
01093 {
01094     if( op.pixel == Pixel::ALL )
01095         return;
01096 
01097     glPixelZoom( 1.f, 1.f );
01098     glDisable( GL_STENCIL_TEST );
01099 }
01100 
01101 void Compositor::setupAssemblyState( const PixelViewport& pvp )
01102 {
01103     EQ_GL_ERROR( "before setupAssemblyState" );
01104     glPushAttrib( GL_ENABLE_BIT | GL_STENCIL_BUFFER_BIT | GL_VIEWPORT_BIT | 
01105                   GL_SCISSOR_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT | 
01106                   GL_POLYGON_BIT );
01107 
01108     glDisable( GL_DEPTH_TEST );
01109     glDisable( GL_BLEND );
01110     glDisable( GL_ALPHA_TEST );
01111     glDisable( GL_STENCIL_TEST );
01112     glDisable( GL_TEXTURE_1D );
01113     glDisable( GL_TEXTURE_2D );
01114     glDisable( GL_TEXTURE_3D );
01115     glDisable( GL_FOG );
01116     glDisable( GL_CLIP_PLANE0 );
01117     glDisable( GL_CLIP_PLANE1 );
01118     glDisable( GL_CLIP_PLANE2 );
01119     glDisable( GL_CLIP_PLANE3 );
01120     glDisable( GL_CLIP_PLANE4 );
01121     glDisable( GL_CLIP_PLANE5 );
01122     
01123     glPolygonMode( GL_FRONT, GL_FILL );
01124 
01125     if( pvp.hasArea( ))
01126     {
01127         glViewport( pvp.x, pvp.y, pvp.w, pvp.h );
01128         glScissor( pvp.x, pvp.y, pvp.w, pvp.h );
01129     }
01130     else
01131         EQERROR << "Can't apply viewport " << pvp << std::endl;
01132 
01133     glMatrixMode( GL_PROJECTION );
01134     glPushMatrix();
01135     glLoadIdentity();
01136     if( pvp.hasArea( ))
01137         glOrtho( pvp.x, pvp.x + pvp.w, pvp.y, pvp.y + pvp.h, -1.0f, 1.0f );
01138 
01139     glMatrixMode( GL_MODELVIEW );
01140     glPushMatrix();
01141     glLoadIdentity();
01142     EQ_GL_ERROR( "after  setupAssemblyState" );
01143 }
01144 
01145 void Compositor::resetAssemblyState()
01146 {
01147     EQ_GL_ERROR( "before resetAssemblyState" );
01148     glMatrixMode( GL_PROJECTION );
01149     glPopMatrix();
01150 
01151     glMatrixMode( GL_MODELVIEW );
01152     glPopMatrix();
01153 
01154     glPopAttrib();
01155     EQ_GL_ERROR( "after  resetAssemblyState" );
01156 }
01157 
01158 void Compositor::assembleImage2D( const Image* image, const ImageOp& op )
01159 {
01160     EQASSERT( image->hasData( Frame::BUFFER_COLOR ));
01161     _drawPixels( image, op, Frame::BUFFER_COLOR );
01162 }
01163 
01164 void Compositor::_drawPixels( const Image* image, 
01165                               const ImageOp& op,
01166                               const Frame::Buffer which )
01167 {
01168     const PixelViewport& pvp = image->getPixelViewport();
01169     EQLOG( LOG_ASSEMBLY ) << "_drawPixels " << pvp << " offset " << op.offset
01170                           << std::endl;
01171     
01172     if ( image->getStorageType() == Frame::TYPE_MEMORY )
01173     {
01174         EQASSERT( image->hasPixelData( which ));
01175 
01176         if( op.zoom == eq::Zoom::NONE )
01177         {
01178             glRasterPos2i( op.offset.x() + pvp.x, op.offset.y() + pvp.y );
01179             glDrawPixels( pvp.w, pvp.h, 
01180                           image->getFormat( which ), 
01181                           image->getType( which ), 
01182                           image->getPixelPointer( which ));
01183             return;
01184         }
01185         // else use texture with filtering to zoom
01186 
01187         Channel* channel = op.channel; // needed for glewGetContext
01188         Window::ObjectManager* objects = channel->getObjectManager();
01189 
01190         util::Texture* texture = objects->obtainEqTexture(
01191             which == Frame::BUFFER_COLOR ? colorKey : depthKey );
01192 
01193         texture->upload( image, which );
01194     }
01195     else // texture image
01196     {
01197         EQASSERT( image->hasTextureData( which ));
01198         image->getTexture( which ).bind();
01199     }
01200 
01201     if ( which == Frame::BUFFER_COLOR )
01202         glDepthMask( false );
01203     else
01204     {
01205         EQASSERT( which == Frame::BUFFER_DEPTH )
01206         glColorMask( false, false, false, false );
01207     }
01208 
01209     glDisable( GL_LIGHTING );
01210     glEnable( GL_TEXTURE_RECTANGLE_ARB );
01211     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S,
01212                      GL_CLAMP_TO_EDGE );
01213     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T,
01214                      GL_CLAMP_TO_EDGE );
01215 
01216     if( op.zoom == eq::Zoom::NONE )
01217     {
01218         glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
01219                          GL_NEAREST );
01220         glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
01221                          GL_NEAREST );
01222     }else
01223     {
01224         glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
01225                          GL_LINEAR );
01226         glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
01227                          GL_LINEAR );
01228     }
01229 
01230     glColor3f( 1.0f, 1.0f, 1.0f );
01231 
01232     const float startX = static_cast< float >
01233          ( op.offset.x() + pvp.x * op.pixel.w + op.pixel.x ) * op.zoom.x();
01234     const float endX   = static_cast< float >
01235          (op.offset.x() + (pvp.x+pvp.w) * op.pixel.w + op.pixel.x) *op.zoom.x();
01236     const float startY = static_cast< float >
01237          ( op.offset.y() + pvp.y * op.pixel.h + op.pixel.y ) * op.zoom.y();
01238     const float endY   = static_cast< float >
01239          (op.offset.y() + (pvp.y+pvp.h) * op.pixel.h + op.pixel.y) *op.zoom.y();
01240 
01241     glBegin( GL_QUADS );
01242         glTexCoord2f( 0.0f, 0.0f );
01243         glVertex3f( startX, startY, 0.0f );
01244 
01245         glTexCoord2f( static_cast< float >( pvp.w ), 0.0f );
01246         glVertex3f( endX, startY, 0.0f );
01247 
01248         glTexCoord2f( static_cast<float>( pvp.w ), static_cast<float>( pvp.h ));
01249         glVertex3f( endX, endY, 0.0f );
01250         
01251         glTexCoord2f( 0.0f, static_cast< float >( pvp.h ));
01252         glVertex3f( startX, endY, 0.0f );
01253     glEnd();
01254 
01255     // restore state
01256     glDisable( GL_TEXTURE_RECTANGLE_ARB );
01257 
01258     if ( which == Frame::BUFFER_COLOR )
01259         glDepthMask( true );
01260     else
01261     {
01262         const ColorMask& colorMask = op.channel->getDrawBufferMask();
01263         glColorMask( colorMask.red, colorMask.green, colorMask.blue, true );
01264     }
01265 }
01266 
01267 void Compositor::assembleImageDB( const Image* image, const ImageOp& op )
01268 {
01269     Channel* channel = op.channel;
01270 
01271     if( GLEW_VERSION_2_0 )
01272         assembleImageDB_GLSL( image, op );
01273     else
01274         assembleImageDB_FF( image, op );
01275 }
01276 
01277 void Compositor::assembleImageDB_FF( const Image* image, const ImageOp& op )
01278 {
01279     const PixelViewport& pvp = image->getPixelViewport();
01280 
01281     EQLOG( LOG_ASSEMBLY ) << "assembleImageDB, fixed function " << pvp 
01282                           << std::endl;
01283     EQASSERT( image->hasData( Frame::BUFFER_COLOR ));
01284     EQASSERT( image->hasData( Frame::BUFFER_DEPTH ));
01285 
01286     // Z-Based sort-last assembly
01287     glRasterPos2i( op.offset.x() + pvp.x, op.offset.y() + pvp.y );
01288     glEnable( GL_STENCIL_TEST );
01289 
01290     // test who is in front and mark in stencil buffer
01291     glEnable( GL_DEPTH_TEST );
01292 
01293     const bool pixelComposite = ( op.pixel != Pixel::ALL );
01294     if( pixelComposite )
01295     {   // keep already marked stencil values
01296         glStencilFunc( GL_EQUAL, 1, 1 );
01297         glStencilOp( GL_KEEP, GL_ZERO, GL_REPLACE );
01298     }
01299     else
01300     {
01301         glStencilFunc( GL_ALWAYS, 1, 1 );
01302         glStencilOp( GL_ZERO, GL_ZERO, GL_REPLACE );
01303     }
01304 
01305     _drawPixels( image, op, Frame::BUFFER_DEPTH );
01306 
01307     glDisable( GL_DEPTH_TEST );
01308 
01309     // draw front-most, visible pixels using stencil mask
01310     glStencilFunc( GL_EQUAL, 1, 1 );
01311     glStencilOp( GL_KEEP, GL_ZERO, GL_ZERO );
01312 
01313     _drawPixels( image, op, Frame::BUFFER_COLOR );
01314 
01315     glDisable( GL_STENCIL_TEST );
01316 }
01317 
01318 void Compositor::assembleImageDB_GLSL( const Image* image, const ImageOp& op )
01319 {
01320     const PixelViewport& pvp = image->getPixelViewport();
01321 
01322     EQLOG( LOG_ASSEMBLY ) << "assembleImageDB, GLSL " << pvp 
01323                           << std::endl;
01324 
01325     Channel*               channel = op.channel; // needed for glewGetContext
01326     Window::ObjectManager* objects = channel->getObjectManager();
01327 
01328     GLuint program = objects->getProgram( shaderDBKey );
01329 
01330     if( program == Window::ObjectManager::INVALID )
01331     {
01332         // Create fragment shader which reads color and depth values from 
01333         // rectangular textures
01334         const GLuint shader = objects->newShader( shaderDBKey, 
01335                                                   GL_FRAGMENT_SHADER );
01336         EQASSERT( shader != Window::ObjectManager::INVALID );
01337 
01338         const char* source =
01339             "uniform sampler2DRect color; \
01340              uniform sampler2DRect depth; \
01341              void main(void){ \
01342                  gl_FragColor = texture2DRect( color, gl_TexCoord[0].st ); \
01343                  gl_FragDepth = texture2DRect( depth, gl_TexCoord[0].st ).x; }";
01344 
01345         EQ_GL_CALL( glShaderSource( shader, 1, &source, 0 ));
01346         EQ_GL_CALL( glCompileShader( shader ));
01347 
01348         GLint status;
01349         glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
01350         if( !status )
01351             EQERROR << "Failed to compile fragment shader for DB compositing" 
01352                     << std::endl;
01353 
01354         program = objects->newProgram( shaderDBKey );
01355 
01356         EQ_GL_CALL( glAttachShader( program, shader ));
01357         EQ_GL_CALL( glLinkProgram( program ));
01358 
01359         glGetProgramiv( program, GL_LINK_STATUS, &status );
01360         if( !status )
01361         {
01362             EQWARN << "Failed to link shader program for DB compositing" 
01363                    << std::endl;
01364             return;
01365         }
01366 
01367         // use fragment shader and setup uniforms
01368         EQ_GL_CALL( glUseProgram( program ));
01369         
01370         const GLint depthParam = glGetUniformLocation( program, "depth" );
01371         glUniform1i( depthParam, 0 );
01372         const GLint colorParam = glGetUniformLocation( program, "color" );
01373         glUniform1i( colorParam, 1 );
01374     }
01375     else
01376     {
01377         // use fragment shader
01378         EQ_GL_CALL( glUseProgram( program ));
01379     }
01380 
01381     // Enable & download color and depth textures
01382     glEnable( GL_TEXTURE_RECTANGLE_ARB );
01383 
01384     EQ_GL_CALL( glActiveTexture( GL_TEXTURE1 ));
01385     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
01386                      GL_NEAREST );
01387     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, 
01388                      GL_NEAREST );
01389 
01390     const bool useImageTexture = image->getStorageType() == Frame::TYPE_TEXTURE;
01391     if( useImageTexture )
01392         image->getTexture( Frame::BUFFER_COLOR ).bind();
01393     else
01394     {
01395         util::Texture* texture = objects->obtainEqTexture( colorDBKey );
01396         texture->upload( image, Frame::BUFFER_COLOR );
01397     }
01398 
01399     EQ_GL_CALL( glActiveTexture( GL_TEXTURE0 ));
01400     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
01401                      GL_NEAREST );
01402     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, 
01403                      GL_NEAREST );
01404 
01405     if( useImageTexture )
01406         image->getTexture( Frame::BUFFER_DEPTH ).bind();
01407     else
01408     {
01409         util::Texture* texture = objects->obtainEqTexture( depthDBKey );
01410         texture->upload( image, Frame::BUFFER_DEPTH );
01411     }
01412 
01413     // Draw a quad using shader & textures in the right place
01414     glEnable( GL_DEPTH_TEST );
01415     glColor3f( 1.0f, 1.0f, 1.0f );
01416 
01417     const float startX = static_cast< float >
01418         ( op.offset.x() + pvp.x * op.pixel.w + op.pixel.x );
01419     const float endX   = static_cast< float >
01420         ( op.offset.x() + (pvp.x + pvp.w) * op.pixel.w + op.pixel.x );
01421     const float startY = static_cast< float >
01422         ( op.offset.y() + pvp.y * op.pixel.h + op.pixel.y );
01423     const float endY   = static_cast< float >
01424         ( op.offset.y() + (pvp.y + pvp.h) * op.pixel.h + op.pixel.y );
01425     
01426     const float w = static_cast< float >( pvp.w );
01427     const float h = static_cast< float >( pvp.h );
01428 
01429     glBegin( GL_TRIANGLE_STRIP );
01430     glMultiTexCoord2f( GL_TEXTURE0, 0.0f, 0.0f );
01431     glMultiTexCoord2f( GL_TEXTURE1, 0.0f, 0.0f );
01432     glVertex3f( startX, startY, 0.0f );
01433 
01434     glMultiTexCoord2f( GL_TEXTURE0, w, 0.0f );
01435     glMultiTexCoord2f( GL_TEXTURE1, w, 0.0f );
01436     glVertex3f( endX, startY, 0.0f );
01437 
01438     glMultiTexCoord2f( GL_TEXTURE0, 0.0f, h );
01439     glMultiTexCoord2f( GL_TEXTURE1, 0.0f, h );
01440     glVertex3f( startX, endY, 0.0f );
01441 
01442     glMultiTexCoord2f( GL_TEXTURE0, w, h );
01443     glMultiTexCoord2f( GL_TEXTURE1, w, h );
01444     glVertex3f( endX, endY, 0.0f );
01445 
01446     glEnd();
01447 
01448     // restore state
01449     glDisable( GL_TEXTURE_RECTANGLE_ARB );
01450     glDisable( GL_DEPTH_TEST );
01451     EQ_GL_CALL( glUseProgram( 0 ));
01452 }
01453 
01454 
01455 }
Generated on Sat Feb 6 12:59:47 2010 for Equalizer 0.9.1 by  doxygen 1.6.1