LCOV - code coverage report
Current view: top level - eq/client - roiFinder.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 6 326 1.8 %
Date: 2014-06-18 Functions: 3 16 18.8 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c)      2009, Maxim Makhinya
       3             :  *               2010-2014, Stefan Eilemann <eile@equalizergraphics.com>
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or modify it under
       6             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       7             :  * by the Free Software Foundation.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      10             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      11             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      12             :  * details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public License
      15             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      16             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      17             :  */
      18             : 
      19             : #define EQ_ROI_USE_TRACKER        // disable ROI in case it can't help
      20             : //#define EQ_ROI_USE_DEPTH_TEXTURE  // use depth texture instead of color
      21             : 
      22             : #include "roiFinder.h"
      23             : 
      24             : #ifdef EQ_ROI_USE_DEPTH_TEXTURE
      25             : #include "roiFragmentShader_glsl.h"
      26             : #else
      27             : #include "roiFragmentShaderRGB_glsl.h"
      28             : #endif
      29             : 
      30             : #include "gl.h"
      31             : #include "log.h"
      32             : 
      33             : #include <eq/util/frameBufferObject.h>
      34             : #include <eq/util/objectManager.h>
      35             : #include <lunchbox/os.h>
      36             : #include <lunchbox/plugins/compressor.h>
      37             : 
      38             : 
      39             : namespace eq
      40             : {
      41             : 
      42             : #define glewGetContext glObjects.glewGetContext
      43             : 
      44             : // use to address one shader and program per shared context set
      45             : static const char seeds = 42;
      46             : static const char* shaderRBInfo = &seeds;
      47             : 
      48             : #define GRID_SIZE 16 // will be replaced later by variable
      49             : 
      50             : 
      51           3 : ROIFinder::ROIFinder()
      52             : {
      53           3 :     _tmpAreas[0].pvp       = PixelViewport( 0, 0, 0, 0 );
      54           3 :     _tmpAreas[0].hole      = PixelViewport( 0, 0, 0, 0 );
      55           3 :     _tmpAreas[0].emptySize = 0;
      56           3 : }
      57             : 
      58           0 : void ROIFinder::_dumpDebug( const GLEWContext* gl, const uint32_t stage )
      59             : {
      60             :     static uint32_t counter = 0;
      61           0 :     std::ostringstream ss;
      62           0 :     ss << "_img_" << ++counter << "_" << stage;
      63             : 
      64           0 :     _tmpImg.reset();
      65           0 :     _tmpImg.setPixelViewport( PixelViewport( 0, 0, _wb, _hb ));
      66             : 
      67             :     _tmpImg.allocDownloader( Frame::BUFFER_COLOR,
      68             :                              EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGR,
      69           0 :                              gl );
      70             : 
      71           0 :     _tmpImg.validatePixelData( Frame::BUFFER_COLOR );
      72             : 
      73           0 :     uint8_t* dst  = _tmpImg.getPixelPointer( Frame::BUFFER_COLOR );
      74           0 :     uint8_t* src1 = &_mask[0];
      75           0 :     uint8_t* src2 = &_tmpMask[0];
      76             : 
      77           0 :     memset( dst, 0, _wbhb*3 );
      78             : 
      79           0 :     for( int32_t y = 0; y < _hb; y++ )
      80           0 :         for( int32_t x = 0; x < _wb; x++ )
      81             :         {
      82           0 :             dst[0] = *src1++;
      83           0 :             dst[1] = *src2++;
      84           0 :             dst += 3;
      85             :         }
      86             : 
      87           0 :     LBWARN << "Dumping ROI image: " << ss.str( ) << std::endl;
      88           0 :     _tmpImg.writeImages( ss.str( ));
      89           0 : }
      90             : 
      91           0 : PixelViewport ROIFinder::_getObjectPVP( const PixelViewport& pvp,
      92             :                                         const uint8_t*       src )
      93             : {
      94           0 :     LBASSERT( pvp.x >= 0 && pvp.x+pvp.w <= _wb &&
      95             :               pvp.y >= 0 && pvp.y+pvp.h <= _hb );
      96             : 
      97             :     // Calculate per-pixel histograms
      98           0 :     const uint8_t* s = src + pvp.y*_wb + pvp.x;
      99             : 
     100           0 :     memset( _histX, 0, pvp.w );
     101           0 :     memset( _histY, 0, pvp.h );
     102           0 :     for( int32_t y = 0; y < pvp.h; y++ )
     103             :     {
     104           0 :         for( int32_t x = 0; x < pvp.w; x++ )
     105             :         {
     106           0 :             const uint8_t val = s[ x ] & 1;
     107           0 :             _histX[ x ] += val;
     108           0 :             _histY[ y ] += val;
     109             :         }
     110           0 :         s += _wb;
     111             :     }
     112             : 
     113             :     // Find AABB based on X and Y axis historgams
     114           0 :     int32_t xMin = pvp.w;
     115           0 :     for( int32_t x = 0; x < pvp.w; x++ )
     116           0 :         if( _histX[x] != 0 )
     117             :         {
     118           0 :             xMin = x;
     119           0 :             break;
     120             :         }
     121             : 
     122           0 :     int32_t xMax = 0;
     123           0 :     for( int32_t x = pvp.w-1; x >= 0; x-- )
     124           0 :         if( _histX[x] != 0 )
     125             :         {
     126           0 :             xMax = x;
     127           0 :             break;
     128             :         }
     129             : 
     130           0 :     if( xMax < xMin )
     131           0 :         return PixelViewport( pvp.x, pvp.y, 0, 0 );
     132             : 
     133           0 :     int32_t yMin = pvp.h;
     134           0 :     for( int32_t y = 0; y < pvp.h; y++ )
     135           0 :         if( _histY[y] != 0 )
     136             :         {
     137           0 :             yMin = y;
     138           0 :             break;
     139             :         }
     140             : 
     141           0 :     int32_t yMax = 0;
     142           0 :     for( int32_t y = pvp.h-1; y >= 0; y-- )
     143           0 :         if( _histY[y] != 0 )
     144             :         {
     145           0 :             yMax = y;
     146           0 :             break;
     147             :         }
     148             : 
     149           0 :     if( yMax < yMin )
     150           0 :         return PixelViewport( pvp.x, pvp.y, 0, 0 );
     151             : 
     152           0 :     return PixelViewport( pvp.x+xMin, pvp.y+yMin, xMax-xMin+1, yMax-yMin+1 );
     153             : }
     154             : 
     155             : 
     156           0 : void ROIFinder::_resize( const PixelViewport& pvp )
     157             : {
     158           0 :     _pvp = pvp;
     159             : 
     160           0 :     _w   = _pvp.w;
     161           0 :     _h   = _pvp.h;
     162           0 :     _wh  = _w * _h;
     163           0 :     _wb  = _w + 1; // borders are only on left and
     164           0 :     _hb  = _h + 1; // top borders of the image
     165           0 :     _wbhb = _wb * _hb;
     166             : 
     167           0 :     if( static_cast<int32_t>(_mask.size()) < _wbhb )
     168             :     {
     169           0 :         _mask.resize( _wbhb );
     170           0 :         _tmpMask.resize( _wbhb );
     171             : 
     172             :         // w * h * sizeof( GL_FLOAT ) * RGBA
     173           0 :         _perBlockInfo.resize( _wh * 4 );
     174             :     }
     175           0 : }
     176             : 
     177             : 
     178           0 : void ROIFinder::_init( )
     179             : {
     180           0 :     _areasToCheck.clear();
     181           0 :     memset( &_mask[0]   , 0, _mask.size( ));
     182           0 :     memset( &_tmpMask[0], 0, _tmpMask.size( ));
     183             : 
     184           0 :     LBASSERT( static_cast<int32_t>(_perBlockInfo.size()) >= _w*_h*4 );
     185           0 :     LBASSERT( static_cast<int32_t>(_mask.size())         >= _wb*_h  );
     186             : 
     187           0 :     const float*    src = &_perBlockInfo[0];
     188           0 :           uint8_t*  dst = &_mask[0];
     189             : 
     190           0 :     for( int32_t y = 0; y < _h; y++ )
     191             :     {
     192           0 :         for( int32_t x = 0; x < _w; x++ )
     193             :         {
     194           0 :             if( src[x*4] < 1.0 )
     195           0 :                 dst[x] = 255;
     196             :         }
     197           0 :         src += _w*4;
     198           0 :         dst += _wb;
     199             :     }
     200           0 : }
     201             : 
     202             : 
     203           0 : void ROIFinder::_fillWithColor( const PixelViewport& pvp,
     204             :                                       uint8_t* dst, const uint8_t val )
     205             : {
     206           0 :     for( int32_t y = pvp.y; y < pvp.y + pvp.h; y++ )
     207           0 :         for( int32_t x = pvp.x; x < pvp.x + pvp.w; x++ )
     208           0 :             dst[ y * _wb + x ] = val;
     209           0 : }
     210             : 
     211           0 : void ROIFinder::_invalidateAreas( Area* areas, uint8_t num )
     212             : {
     213           0 :     for( uint8_t i = 0; i < num; i++ )
     214           0 :         areas[i].valid = false;
     215           0 : }
     216             : 
     217           0 : void ROIFinder::_updateSubArea( const uint8_t type )
     218             : {
     219           0 :     LBASSERT( type <= 16 );
     220             : 
     221           0 :     if( type == 0 )
     222           0 :         return;
     223             : 
     224           0 :     PixelViewport pvp;
     225           0 :     switch( type )
     226             :     {
     227           0 :         case 1:  pvp = PixelViewport( _dim.x1,_dim.y2,_dim.w1,_dim.h2 ); break;
     228           0 :         case 2:  pvp = PixelViewport( _dim.x2,_dim.y3,_dim.w2,_dim.h3 ); break;
     229           0 :         case 3:  pvp = PixelViewport( _dim.x3,_dim.y2,_dim.w3,_dim.h2 ); break;
     230           0 :         case 4:  pvp = PixelViewport( _dim.x2,_dim.y1,_dim.w2,_dim.h1 ); break;
     231           0 :         case 5:  pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w1,_dim.h4 ); break;
     232           0 :         case 6:  pvp = PixelViewport( _dim.x1,_dim.y3,_dim.w4,_dim.h3 ); break;
     233           0 :         case 7:  pvp = PixelViewport( _dim.x3,_dim.y2,_dim.w3,_dim.h5 ); break;
     234           0 :         case 8:  pvp = PixelViewport( _dim.x2,_dim.y1,_dim.w5,_dim.h1 ); break;
     235           0 :         case 9:  pvp = PixelViewport( _dim.x1,_dim.y2,_dim.w1,_dim.h5 ); break;
     236           0 :         case 10: pvp = PixelViewport( _dim.x2,_dim.y3,_dim.w5,_dim.h3 ); break;
     237           0 :         case 11: pvp = PixelViewport( _dim.x3,_dim.y1,_dim.w3,_dim.h4 ); break;
     238           0 :         case 12: pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w4,_dim.h1 ); break;
     239           0 :         case 13: pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w1,_dim.h6 ); break;
     240           0 :         case 14: pvp = PixelViewport( _dim.x3,_dim.y1,_dim.w3,_dim.h6 ); break;
     241           0 :         case 15: pvp = PixelViewport( _dim.x1,_dim.y3,_dim.w6,_dim.h3 ); break;
     242           0 :         case 16: pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w6,_dim.h1 ); break;
     243             :         default:
     244           0 :             LBUNIMPLEMENTED;
     245             :     }
     246             : 
     247           0 :     LBASSERT( pvp.hasArea( ));
     248           0 :     LBASSERT( pvp.x >=0 && pvp.y >=0 && pvp.x+pvp.w <=_w && pvp.y+pvp.h <=_h );
     249             : 
     250           0 :     Area& a = _tmpAreas[type];
     251             : 
     252           0 :     a.pvp = _getObjectPVP( pvp, &_mask[0] );
     253             : 
     254           0 :     a.hole = _emptyFinder.getLargestEmptyArea( a.pvp );
     255             : 
     256           0 :     a.emptySize = pvp.getArea() - a.pvp.getArea() + a.hole.getArea();
     257             : 
     258             : #ifndef NDEBUG
     259           0 :     LBASSERT( !a.valid );
     260           0 :     a.valid = true;
     261             : #endif
     262             : }
     263             : 
     264             : 
     265             : // positions of a hole:
     266             : //
     267             : //  1 7 5
     268             : //  2 8 6
     269             : //  0 4 3
     270             : //
     271             : // 0, 1, 3, 5 - corners
     272             : // 2, 4, 6, 7 - sides
     273             : // 8          - center
     274             : //
     275             : 
     276             : 
     277             : static const uint8_t _interests[10][8] =
     278             : {
     279             :     { 2, 3, 7,10, 0, 0, 0, 0 }, // corner
     280             :     { 3, 4, 8,11, 0, 0, 0, 0 }, // corner
     281             :     { 2, 3, 4, 7, 8,10,11,14 }, // side
     282             :     { 1, 2, 6, 9, 0, 0, 0, 0 }, // corner
     283             :     { 1, 2, 3, 6, 7, 9,10,15 }, // side
     284             :     { 1, 4, 5,12, 0, 0, 0, 0 }, // corner
     285             :     { 1, 2, 4, 5, 6, 9,12,13 }, // side
     286             :     { 1, 3, 4, 5, 8,11,12,16 },  // side
     287             :     { 1, 3, 0, 0, 0, 0, 0, 0 }, // vertical
     288             :     { 2, 4, 0, 0, 0, 0, 0, 0 }, // horizontal
     289             : };                              // center is 1..16
     290             : 
     291             : static const uint8_t _compilNums[11][2] =
     292             : {
     293             :     {2,2},{2,2},{4,3},{2,2},{4,3},{2,2},{4,3},{4,3},{1,2},{1,2},{18,4}
     294             : };
     295             : 
     296             : static const uint8_t _compilations[10][4][3] =
     297             : {
     298             :     {{2, 7, 0},{3,10, 0},{0,0, 0},{0,0, 0}}, // corner
     299             :     {{3, 8, 0},{4,11, 0},{0,0, 0},{0,0, 0}}, // corner
     300             :     {{2, 4,14},{4,10,11},{3,8,10},{2,7, 8}}, // side
     301             :     {{1, 6, 0},{2, 9, 0},{0,0, 0},{0,0, 0}}, // corner
     302             :     {{1, 3,15},{3, 9,10},{2,7, 9},{1,6, 7}}, // side
     303             :     {{1,12, 0},{4, 5, 0},{0,0, 0},{0,0, 0}}, // corner
     304             :     {{2, 4,13},{4, 5, 6},{1,6,12},{2,9,12}}, // side
     305             :     {{1, 3,16},{1,11,12},{5,4,11},{3,5, 8}}, // side
     306             :     {{1, 3, 0},{0, 0, 0},{0,0, 0},{0,0, 0}}, // vertical
     307             :     {{2, 4, 0},{0, 0, 0},{0,0, 0},{0,0, 0}}, // horizontal
     308             : };
     309             : 
     310             : 
     311             : static const uint8_t _compilations16[18][4] =// center
     312             : {
     313             :     {13,2, 4,14},{13,4,10,11},{13,3,8,10},{13,2,7, 8},
     314             :     {16,1, 3,15},{16,3, 9,10},{16,2,7, 9},{16,1,6, 7},
     315             :     {14,2, 4,13},{14,4, 5, 6},{14,1,6,12},{14,2,9,12},
     316             :     {15,1, 3,16},{15,1,11,12},{15,5,4,11},{15,3,5, 8},
     317             :     {5 ,6, 7, 8},{9,10,11,12}
     318             : };
     319             : 
     320             : 
     321           0 : uint8_t ROIFinder::_splitArea( Area& a )
     322             : {
     323           0 :     LBASSERT( a.hole.getArea() > 0 );
     324             : #ifndef NDEBUG
     325           0 :     _invalidateAreas( _tmpAreas, 17 );
     326             : #endif
     327             : 
     328           0 :     _dim.x1 = a.pvp.x;
     329           0 :     _dim.x2 = a.hole.x;
     330           0 :     _dim.x3 = a.hole.x + a.hole.w;
     331             : 
     332           0 :     _dim.w1 = _dim.x2 - _dim.x1;
     333           0 :     _dim.w2 = a.hole.w;
     334           0 :     _dim.w3 = a.pvp.x + a.pvp.w - _dim.x3;
     335           0 :     _dim.w4 = _dim.w1 + _dim.w2;
     336           0 :     _dim.w5 = _dim.w2 + _dim.w3;
     337           0 :     _dim.w6 = _dim.w4 + _dim.w3;
     338             : 
     339           0 :     _dim.y1 = a.pvp.y;
     340           0 :     _dim.y2 = a.hole.y;
     341           0 :     _dim.y3 = a.hole.y + a.hole.h;
     342             : 
     343           0 :     _dim.h1 = _dim.y2 - _dim.y1;
     344           0 :     _dim.h2 = a.hole.h;
     345           0 :     _dim.h3 = a.pvp.y + a.pvp.h - _dim.y3;
     346           0 :     _dim.h4 = _dim.h1 + _dim.h2;
     347           0 :     _dim.h5 = _dim.h2 + _dim.h3;
     348           0 :     _dim.h6 = _dim.h4 + _dim.h3;
     349             : 
     350             :     // other cases
     351             :     uint8_t type;
     352           0 :     if( a.pvp.h == a.hole.h ) // hole through the whole block
     353             :     {
     354           0 :         LBASSERT( a.pvp.w != a.hole.w );
     355           0 :         type = 8;
     356             :     }
     357           0 :     else if( a.pvp.w == a.hole.w ) // hole through the whole block
     358             :     {
     359           0 :         type = 9;
     360             :     }
     361           0 :     else if( a.pvp.x == a.hole.x ) // left side
     362             :     {
     363           0 :         if( a.pvp.y == a.hole.y )
     364             :             // in the lower left corner
     365           0 :             type = 0;
     366           0 :         else if( a.pvp.y + a.pvp.h == a.hole.y + a.hole.h )
     367             :             // in the upper left corner
     368           0 :             type = 1;
     369             :         else
     370             :             // in the left middle
     371           0 :             type = 2;
     372             :     }
     373           0 :     else if( a.pvp.y == a.hole.y ) // bottom side
     374             :     {
     375           0 :         if( a.pvp.x + a.pvp.w == a.hole.x + a.hole.w )
     376             :             // in the bottom right corner
     377           0 :             type = 3;
     378             :         else
     379             :             // in the bottom middle
     380           0 :             type = 4;
     381             :     }
     382           0 :     else if( a.pvp.x + a.pvp.w == a.hole.x + a.hole.w ) // right side
     383             :     {
     384           0 :         if( a.pvp.y + a.pvp.h == a.hole.y + a.hole.h )
     385             :             // in the upper right corner
     386           0 :             type = 5;
     387             :         else
     388             :             // in the right middle
     389           0 :             type = 6;
     390             :     }
     391           0 :     else if( a.pvp.y + a.pvp.h == a.hole.y + a.hole.h ) // top side
     392             :         // in the upper middle corner
     393           0 :         type = 7;
     394             :     else
     395             :         // must be in the center
     396           0 :         type = 10;
     397             : 
     398             :     // Calculate areas of interest
     399           0 :     if( type == 10 ) // center hole position
     400             :     {
     401           0 :         for( uint8_t i = 1; i <= 16; i++ )
     402           0 :             _updateSubArea( i );
     403             :     }
     404             :     else
     405             :     {
     406           0 :         for( uint8_t i = 0; i < 8; i++ )
     407           0 :             _updateSubArea( _interests[ type ][ i ] );
     408             :     }
     409             : 
     410             :     // find best combinations of areas of interest
     411           0 :     const uint8_t varaintsNum     = _compilNums[type][0];
     412           0 :     const uint8_t areasPerVariant = _compilNums[type][1];
     413             : 
     414           0 :     int32_t maxSum  = 0;
     415           0 :     int32_t variant = 0;
     416           0 :     if( type == 10 ) // center hole
     417             :     {
     418           0 :         for( uint8_t i = 0; i < varaintsNum; i++ )
     419             :         {
     420           0 :             int32_t sum = 0;
     421           0 :             for( uint8_t j = 0; j < areasPerVariant; j++ )
     422             :             {
     423           0 :                 LBASSERT( _tmpAreas[_compilations16[i][j]].valid );
     424           0 :                 sum += _tmpAreas[_compilations16[i][j]].emptySize;
     425             :             }
     426             : 
     427           0 :             if( sum > maxSum )
     428             :             {
     429           0 :                 maxSum  = sum;
     430           0 :                 variant = i;
     431             :             }
     432             :         }
     433             : 
     434           0 :         for( uint8_t j = 0; j < areasPerVariant; j++ )
     435             :         {
     436           0 :             LBASSERT( _tmpAreas[_compilations16[variant][j]].valid );
     437           0 :             _finalAreas[j] = _tmpAreas[_compilations16[variant][j]];
     438             :         }
     439             : 
     440           0 :         return areasPerVariant;
     441             :     }
     442             :     // else any other hole
     443             : 
     444           0 :     for( uint8_t i = 0; i < varaintsNum; i++ )
     445             :     {
     446           0 :         int32_t sum = 0;
     447           0 :         for( uint8_t j = 0; j < areasPerVariant; j++ )
     448             :         {
     449           0 :             LBASSERT( _tmpAreas[_compilations[type][i][j]].valid );
     450           0 :             sum += _tmpAreas[_compilations[type][i][j]].emptySize;
     451             :         }
     452             : 
     453           0 :         if( sum > maxSum )
     454             :         {
     455           0 :             maxSum  = sum;
     456           0 :             variant = i;
     457             :         }
     458             :     }
     459             : 
     460           0 :     for( uint8_t j = 0; j < areasPerVariant; j++ )
     461             :     {
     462           0 :         LBASSERT( _tmpAreas[_compilations[type][variant][j]].valid );
     463           0 :         _finalAreas[j] = _tmpAreas[_compilations[type][variant][j]];
     464             :     }
     465             : 
     466           0 :     return areasPerVariant;
     467             : }
     468             : 
     469             : 
     470           0 : void ROIFinder::_findAreas( PixelViewports& resultPVPs )
     471             : {
     472           0 :     LBASSERT( _areasToCheck.empty() );
     473             : 
     474           0 :     Area area( PixelViewport( 0, 0, _w, _h ));
     475           0 :     area.pvp  = _getObjectPVP( area.pvp, &_mask[0] );
     476             : 
     477           0 :     if( area.pvp.w <= 0 || area.pvp.h <= 0 )
     478           0 :         return;
     479             : 
     480           0 :     area.hole = _emptyFinder.getLargestEmptyArea( area.pvp );
     481             : 
     482           0 :     if( area.hole.getArea() == 0 )
     483           0 :         resultPVPs.push_back( area.pvp );
     484             :     else
     485           0 :         _areasToCheck.push_back( area );
     486             : 
     487             :     // try to split areas
     488           0 :     while( !_areasToCheck.empty() )
     489             :     {
     490           0 :         Area curArea = _areasToCheck.back();
     491           0 :         _areasToCheck.pop_back();
     492             : 
     493           0 :         uint8_t n = _splitArea( curArea );
     494           0 :         LBASSERT( n >= 2 && n <= 4 );
     495             : 
     496           0 :         for( uint8_t i = 0; i < n; i++ )
     497             :         {
     498           0 :             LBASSERT( _finalAreas[i].valid );
     499           0 :             LBASSERT( _finalAreas[i].pvp.hasArea( ));
     500             : 
     501           0 :             if( _finalAreas[i].hole.getArea() == 0 )
     502           0 :                 resultPVPs.push_back( _finalAreas[i].pvp );
     503             :             else
     504           0 :                 _areasToCheck.push_back( _finalAreas[i] );
     505             :         }
     506             :     }
     507             : 
     508             :     // correct position and sizes
     509           0 :     for( uint32_t i = 0; i < resultPVPs.size(); i++ )
     510             :     {
     511             : #ifndef NDEBUG
     512             :         // fill temporary array with found regions to
     513             :         // dump it later in _dumpDebug
     514           0 :         _fillWithColor( resultPVPs[i], &_tmpMask[0],
     515           0 :                         uint8_t( 255 - i*200/resultPVPs.size( )));
     516             : #endif
     517             : 
     518           0 :         PixelViewport& pvp = resultPVPs[i];
     519           0 :         pvp.x += _pvp.x;
     520           0 :         pvp.y += _pvp.y;
     521             : 
     522           0 :         pvp.apply( Zoom( GRID_SIZE, GRID_SIZE ));
     523             :     }
     524             : 
     525             : }
     526             : 
     527           0 : const void* ROIFinder::_getInfoKey( ) const
     528             : {
     529           0 :     return ( reinterpret_cast< const char* >( this ) + 3 );
     530             : }
     531             : 
     532             : 
     533           0 : void ROIFinder::_readbackInfo( util::ObjectManager& glObjects )
     534             : {
     535           0 :     LBASSERT( glObjects.supportsEqTexture( ));
     536           0 :     LBASSERT( glObjects.supportsEqFrameBufferObject( ));
     537             : 
     538           0 :     PixelViewport pvp = _pvp;
     539           0 :     pvp.apply( Zoom( GRID_SIZE, GRID_SIZE ));
     540           0 :     pvp.w = LB_MIN( pvp.w+pvp.x, _pvpOriginal.w+_pvpOriginal.x ) - pvp.x;
     541           0 :     pvp.h = LB_MIN( pvp.h+pvp.y, _pvpOriginal.h+_pvpOriginal.y ) - pvp.y;
     542             : 
     543           0 :     LBASSERT( pvp.isValid());
     544             : 
     545             :     // copy frame buffer to texture
     546           0 :     const void* bufferKey = _getInfoKey( );
     547             :     util::Texture* texture =
     548           0 :         glObjects.obtainEqTexture( bufferKey, GL_TEXTURE_RECTANGLE_ARB );
     549             : 
     550             : #ifdef EQ_ROI_USE_DEPTH_TEXTURE
     551             :     texture->copyFromFrameBuffer( GL_DEPTH_COMPONENT, pvp );
     552             : #else
     553           0 :     texture->copyFromFrameBuffer( GL_RGBA, pvp );
     554             : #endif
     555             : 
     556             :     // draw zoomed quad into FBO
     557           0 :     const void*     fboKey = _getInfoKey( );
     558           0 :     util::FrameBufferObject* fbo = glObjects.getEqFrameBufferObject( fboKey );
     559             : 
     560           0 :     if( fbo )
     561             :     {
     562           0 :         LBCHECK( fbo->resize( _pvp.w, _pvp.h ));
     563             :     }
     564             :     else
     565             :     {
     566           0 :         fbo = glObjects.newEqFrameBufferObject( fboKey );
     567           0 :         LBCHECK( fbo->init( _pvp.w, _pvp.h, GL_RGBA32F, 0, 0 ));
     568             :     }
     569           0 :     fbo->bind();
     570             : 
     571           0 :     texture->bind();
     572             : 
     573             :     // Enable & download depth texture
     574           0 :     glEnable( GL_TEXTURE_RECTANGLE_ARB );
     575             : 
     576           0 :     texture->applyWrap();
     577           0 :     texture->applyZoomFilter( FILTER_LINEAR );
     578             : 
     579             :     // Enable shaders
     580           0 :     GLuint program = glObjects.getProgram( shaderRBInfo );
     581           0 :     if( program == util::ObjectManager::INVALID )
     582             :     {
     583             :         // Create fragment shader which reads depth values from
     584             :         // rectangular textures
     585             :         const GLuint shader = glObjects.newShader( shaderRBInfo,
     586           0 :                                                         GL_FRAGMENT_SHADER );
     587           0 :         LBASSERT( shader != util::ObjectManager::INVALID );
     588             : 
     589             : #ifdef EQ_ROI_USE_DEPTH_TEXTURE
     590             :         const GLchar* fShaderPtr = roiFragmentShader_glsl.c_str();
     591             : #else
     592           0 :         const GLchar* fShaderPtr = roiFragmentShaderRGB_glsl.c_str();
     593             : #endif
     594           0 :         EQ_GL_CALL( glShaderSource( shader, 1, &fShaderPtr, 0 ));
     595           0 :         EQ_GL_CALL( glCompileShader( shader ));
     596             : 
     597             :         GLint status;
     598           0 :         glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
     599           0 :         if( !status )
     600           0 :             LBERROR << "Failed to compile fragment shader for ROI finder"
     601           0 :                     << std::endl;
     602             : 
     603           0 :         program = glObjects.newProgram( shaderRBInfo );
     604             : 
     605           0 :         EQ_GL_CALL( glAttachShader( program, shader ));
     606           0 :         EQ_GL_CALL( glLinkProgram( program ));
     607             : 
     608           0 :         glGetProgramiv( program, GL_LINK_STATUS, &status );
     609           0 :         if( !status )
     610             :         {
     611           0 :             LBWARN << "Failed to link shader program for ROI finder"
     612           0 :                    << std::endl;
     613           0 :             return;
     614             :         }
     615             : 
     616             :         // use fragment shader and setup uniforms
     617           0 :         EQ_GL_CALL( glUseProgram( program ));
     618             : 
     619           0 :         GLint param = glGetUniformLocation( program, "texture" );
     620           0 :         glUniform1i( param, 0 );
     621             :     }
     622             :     else
     623             :     {
     624             :         // use fragment shader
     625           0 :         EQ_GL_CALL( glUseProgram( program ));
     626             :     }
     627             : 
     628             :     // Draw Quad
     629           0 :     glDisable( GL_LIGHTING );
     630           0 :     glColor3f( 1.0f, 1.0f, 1.0f );
     631             : 
     632           0 :     glBegin( GL_QUADS );
     633           0 :         glVertex3i(      0,      0, 0 );
     634           0 :         glVertex3i( _pvp.w,      0, 0 );
     635           0 :         glVertex3i( _pvp.w, _pvp.h, 0 );
     636           0 :         glVertex3i(      0, _pvp.h, 0 );
     637           0 :     glEnd();
     638             : 
     639             :     // restore state
     640           0 :     glDisable( GL_TEXTURE_RECTANGLE_ARB );
     641           0 :     EQ_GL_CALL( glUseProgram( 0 ));
     642             : 
     643           0 :     fbo->unbind();
     644             : 
     645             :     // finish readback of info
     646           0 :     LBASSERT( static_cast<int32_t>(_perBlockInfo.size()) >= _pvp.w*_pvp.h*4 );
     647             : 
     648           0 :     texture = fbo->getColorTextures()[0];
     649           0 :     LBASSERT( texture->getFormat() == GL_RGBA );
     650           0 :     LBASSERT( texture->getType() == GL_FLOAT );
     651           0 :     texture->download( &_perBlockInfo[0] );
     652             : }
     653             : 
     654             : 
     655           0 : static PixelViewport _getBoundingPVP( const PixelViewport& pvp )
     656             : {
     657           0 :     PixelViewport pvp_;
     658             : 
     659           0 :     pvp_.x = ( pvp.x / GRID_SIZE );
     660           0 :     pvp_.y = ( pvp.y / GRID_SIZE );
     661             : 
     662           0 :     pvp_.w = (( pvp.x + pvp.w + GRID_SIZE-1 )/GRID_SIZE ) - pvp_.x;
     663           0 :     pvp_.h = (( pvp.y + pvp.h + GRID_SIZE-1 )/GRID_SIZE ) - pvp_.y;
     664             : 
     665           0 :     return pvp_;
     666             : }
     667             : 
     668             : 
     669           0 : PixelViewports ROIFinder::findRegions( const uint32_t         buffers,
     670             :                                        const PixelViewport&   pvp,
     671             :                                        const Zoom&            zoom,
     672             :                                        const uint32_t         stage,
     673             :                                        const uint128_t&       frameID,
     674             :                                        util::ObjectManager&   glObjects )
     675             : {
     676           0 :     PixelViewports result;
     677           0 :     result.push_back( pvp );
     678             : 
     679           0 :     LBLOG( LOG_ASSEMBLY ) << "ROIFinder::getObjects " << pvp << ", buffers "
     680           0 :                           << buffers << std::endl;
     681             : 
     682           0 :     if( zoom != Zoom::NONE )
     683             :     {
     684           0 :         LBWARN << "R-B optimization impossible when zoom is used"
     685           0 :                << std::endl;
     686           0 :         return result;
     687             :     }
     688             : 
     689             : #ifdef EQ_ROI_USE_TRACKER
     690             :     uint8_t* ticket;
     691           0 :     if( !_roiTracker.useROIFinder( pvp, stage, frameID, ticket ))
     692           0 :         return result;
     693             : #endif
     694             : 
     695           0 :     _pvpOriginal = pvp;
     696           0 :     _resize( _getBoundingPVP( pvp ));
     697             : 
     698             :     // go through depth buffer and check min/max/BG values
     699             :     // render to and read-back usefull info from FBO
     700           0 :     _readbackInfo( glObjects );
     701           0 :     glObjects.clear();
     702             : 
     703             :     // Analyze readed back data and find regions of interest
     704           0 :     _init( );
     705             : 
     706           0 :     _emptyFinder.update( &_mask[0], _wb, _hb );
     707           0 :     _emptyFinder.setLimits( 200, 0.002f );
     708             : 
     709           0 :     result.clear();
     710           0 :     _findAreas( result );
     711             : 
     712             : #ifdef EQ_ROI_USE_TRACKER
     713           0 :     _roiTracker.updateDelay( result, ticket );
     714             : #endif
     715             : 
     716           0 :     return result;
     717             : }
     718             : 
     719          36 : }

Generated by: LCOV version 1.10