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 : }
|