Line data Source code
1 :
2 : /* Copyright (c) 2007-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * Cedric Stalder <cedric.stalder@gmail.com>
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include <lunchbox/perThread.h>
21 :
22 : #include "channel.h"
23 : #include "channelStatistics.h"
24 : #include "client.h"
25 : #include "compositor.h"
26 : #include "config.h"
27 : #include "exception.h"
28 : #include "frameData.h"
29 : #include "gl.h"
30 : #include "image.h"
31 : #include "imageOp.h"
32 : #include "log.h"
33 : #include "pixelData.h"
34 : #include "server.h"
35 : #include "window.h"
36 : #include "windowSystem.h"
37 :
38 : #include <eq/util/accum.h>
39 : #include <eq/util/objectManager.h>
40 : #include <eq/util/shader.h>
41 :
42 : #include <co/global.h>
43 : #include <lunchbox/debug.h>
44 : #include <lunchbox/monitor.h>
45 : #include <lunchbox/os.h>
46 : #include <pression/plugins/compressor.h>
47 :
48 : using lunchbox::Monitor;
49 :
50 : namespace eq
51 : {
52 :
53 : #define glewGetContext channel->glewGetContext
54 :
55 : namespace
56 : {
57 : // use to address one shader and program per shared context set
58 : static const char seed = 42;
59 : static const char* shaderDBKey = &seed;
60 14 : static const char* colorDBKey = shaderDBKey + 1;
61 14 : static const char* depthDBKey = shaderDBKey + 2;
62 :
63 : // Image used for CPU-based assembly
64 14 : static lunchbox::PerThread< Image > _resultImage;
65 :
66 : struct CPUAssemblyFormat
67 : {
68 0 : CPUAssemblyFormat( const bool blend_ )
69 0 : : colorInt(0), colorExt(0), depthInt(0), depthExt(0), blend( blend_ ) {}
70 :
71 : uint32_t colorInt;
72 : uint32_t colorExt;
73 : uint32_t depthInt;
74 : uint32_t depthExt;
75 : const bool blend;
76 : };
77 :
78 0 : bool _useCPUAssembly( const Image* image, CPUAssemblyFormat& format )
79 : {
80 0 : const bool hasColor = image->hasPixelData( Frame::BUFFER_COLOR );
81 0 : const bool hasDepth = image->hasPixelData( Frame::BUFFER_DEPTH );
82 :
83 0 : if( // Not an alpha-blending compositing
84 0 : ( !format.blend || !hasColor || !image->hasAlpha( )) &&
85 : // and not a depth-sorting compositing
86 0 : ( !hasColor || !hasDepth ))
87 : {
88 0 : return false;
89 : }
90 :
91 0 : if( format.colorInt == 0 )
92 0 : format.colorInt = image->getInternalFormat( Frame::BUFFER_COLOR );
93 0 : if( format.colorExt == 0 )
94 0 : format.colorExt = image->getExternalFormat( Frame::BUFFER_COLOR );
95 :
96 0 : if( format.colorInt != image->getInternalFormat( Frame::BUFFER_COLOR ) ||
97 0 : format.colorExt != image->getExternalFormat( Frame::BUFFER_COLOR ))
98 : {
99 0 : return false;
100 : }
101 :
102 0 : switch( format.colorExt )
103 : {
104 : case EQ_COMPRESSOR_DATATYPE_RGB10_A2:
105 : case EQ_COMPRESSOR_DATATYPE_BGR10_A2:
106 0 : if( !hasDepth )
107 : // blending of RGB10A2 not implemented
108 0 : return false;
109 0 : break;
110 :
111 : case EQ_COMPRESSOR_DATATYPE_RGBA:
112 : case EQ_COMPRESSOR_DATATYPE_BGRA:
113 0 : break;
114 :
115 : default:
116 0 : return false;
117 : }
118 :
119 0 : if( !hasDepth )
120 0 : return true;
121 :
122 0 : if( format.depthInt == 0 )
123 0 : format.depthInt = image->getInternalFormat( Frame::BUFFER_DEPTH );
124 0 : if( format.depthExt == 0 )
125 0 : format.depthExt = image->getExternalFormat( Frame::BUFFER_DEPTH );
126 :
127 0 : if( format.depthInt != image->getInternalFormat( Frame::BUFFER_DEPTH ) ||
128 0 : format.depthExt != image->getExternalFormat( Frame::BUFFER_DEPTH ))
129 : {
130 0 : return false;
131 : }
132 :
133 0 : return format.depthExt == EQ_COMPRESSOR_DATATYPE_DEPTH_UNSIGNED_INT;
134 : }
135 :
136 0 : bool _useCPUAssembly( const Frames& frames, Channel* channel,
137 : const bool blend = false )
138 : {
139 : // It doesn't make sense to use CPU-assembly for only one frame
140 0 : if( frames.size() < 2 )
141 0 : return false;
142 :
143 : // Test that the input frames have color and depth buffers or that
144 : // alpha-blended assembly is used with multiple RGBA buffers. We assume then
145 : // that we will have at least one image per frame so most likely it's worth
146 : // to wait for the images and to do a CPU-based assembly. Also test early
147 : // for unsupported decomposition modes
148 : const uint32_t desiredBuffers = blend ? Frame::BUFFER_COLOR :
149 0 : Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH;
150 0 : for( const Frame* frame : frames )
151 : {
152 0 : const RenderContext& context = frame->getFrameData()->getContext();
153 :
154 0 : if( frame->getBuffers() != desiredBuffers ||
155 0 : context.pixel != Pixel::ALL || context.subPixel != SubPixel::ALL ||
156 0 : frame->getFrameData()->getZoom() != Zoom::NONE ||
157 0 : frame->getZoom() != Zoom::NONE ) // Not supported by CPU compositor
158 : {
159 0 : return false;
160 : }
161 : }
162 :
163 : // Wait for all images to be ready and test if our assumption was correct,
164 : // that there are enough images to make a CPU-based assembly worthwhile and
165 : // all other preconditions for our CPU-based assembly code are true.
166 0 : size_t nImages = 0;
167 0 : const uint32_t timeout = channel->getConfig()->getTimeout();
168 0 : CPUAssemblyFormat format( blend );
169 :
170 0 : for( const Frame* frame : frames )
171 : {
172 : {
173 : ChannelStatistics event( Statistic::CHANNEL_FRAME_WAIT_READY,
174 0 : channel );
175 0 : frame->waitReady( timeout );
176 : }
177 :
178 0 : const Images& images = frame->getImages();
179 0 : for( const Image* image : images )
180 : {
181 0 : if( !_useCPUAssembly( image, format ))
182 0 : return false;
183 0 : ++nImages;
184 : }
185 : }
186 0 : return (nImages > 1);
187 : }
188 :
189 0 : bool _useCPUAssembly( const ImageOps& ops, const bool blend )
190 : {
191 0 : CPUAssemblyFormat format( blend );
192 0 : size_t nImages = 0;
193 :
194 0 : for( const ImageOp& op : ops )
195 : {
196 0 : if( !_useCPUAssembly( op.image, format ))
197 0 : return false;
198 0 : ++nImages;
199 : }
200 0 : return (nImages > 1);
201 : }
202 :
203 0 : uint32_t _assembleCPUImage( const Image* image, Channel* channel )
204 : {
205 0 : if( !image )
206 0 : return 0;
207 :
208 : // assemble result on dest channel
209 0 : ImageOp operation;
210 0 : operation.image = image;
211 0 : operation.buffers = Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH;
212 0 : Compositor::assembleImage( operation, channel );
213 :
214 : #if 0
215 : static uint32_t counter = 0;
216 : std::ostringstream stringstream;
217 : stringstream << "Image_" << ++counter;
218 : image->writeImages( stringstream.str( ));
219 : #endif
220 :
221 0 : return 1;
222 : }
223 :
224 84 : void _collectOutputData( const PixelData& pixelData, uint32_t& internalFormat,
225 : uint32_t& pixelSize, uint32_t& externalFormat )
226 : {
227 84 : LBASSERT( internalFormat == GL_NONE ||
228 : internalFormat == pixelData.internalFormat );
229 84 : LBASSERT( externalFormat == GL_NONE ||
230 : externalFormat == pixelData.externalFormat );
231 84 : LBASSERT( pixelSize == GL_NONE || pixelSize == pixelData.pixelSize );
232 84 : internalFormat = pixelData.internalFormat;
233 84 : pixelSize = pixelData.pixelSize;
234 84 : externalFormat = pixelData.externalFormat;
235 84 : }
236 :
237 9 : bool _collectOutputData( const ImageOps& ops, PixelViewport& destPVP,
238 : uint32_t& colorInt, uint32_t& colorPixelSize,
239 : uint32_t& colorExt, uint32_t& depthInt,
240 : uint32_t& depthPixelSize, uint32_t& depthExt )
241 : {
242 72 : for( const ImageOp& op : ops )
243 : {
244 63 : const RenderContext& context = op.image->getContext();
245 252 : if( context.pixel != Pixel::ALL || context.subPixel != SubPixel::ALL ||
246 189 : op.zoom != Zoom::NONE ||
247 63 : op.image->getStorageType() != Frame::TYPE_MEMORY )
248 : {
249 0 : return false;
250 : }
251 :
252 63 : if( !op.image->hasPixelData( Frame::BUFFER_COLOR ))
253 0 : continue;
254 :
255 63 : destPVP.merge( op.image->getPixelViewport() + op.offset );
256 :
257 63 : _collectOutputData( op.image->getPixelData( Frame::BUFFER_COLOR ),
258 63 : colorInt, colorPixelSize, colorExt );
259 :
260 63 : if( op.image->hasPixelData( Frame::BUFFER_DEPTH ))
261 : {
262 21 : _collectOutputData( op.image->getPixelData( Frame::BUFFER_DEPTH ),
263 21 : depthInt, depthPixelSize, depthExt );
264 : }
265 : }
266 :
267 9 : if( !destPVP.hasArea( ))
268 0 : LBWARN << "Nothing to assemble: " << destPVP << std::endl;
269 9 : return destPVP.hasArea();
270 : }
271 :
272 21 : void _mergeDBImage( void* destColor, void* destDepth,
273 : const PixelViewport& destPVP, const Image* image,
274 : const Vector2i& offset )
275 : {
276 21 : LBASSERT( destColor && destDepth );
277 :
278 21 : LBVERB << "CPU-DB assembly" << std::endl;
279 :
280 21 : uint32_t* destC = reinterpret_cast< uint32_t* >( destColor );
281 21 : uint32_t* destD = reinterpret_cast< uint32_t* >( destDepth );
282 :
283 21 : const PixelViewport& pvp = image->getPixelViewport();
284 :
285 21 : const int32_t destX = offset.x() + pvp.x - destPVP.x;
286 21 : const int32_t destY = offset.y() + pvp.y - destPVP.y;
287 :
288 : const uint32_t* color = reinterpret_cast< const uint32_t* >
289 21 : ( image->getPixelPointer( Frame::BUFFER_COLOR ));
290 : const uint32_t* depth = reinterpret_cast< const uint32_t* >
291 21 : ( image->getPixelPointer( Frame::BUFFER_DEPTH ));
292 :
293 : #pragma omp parallel for
294 21525 : for( int32_t y = 0; y < pvp.h; ++y )
295 : {
296 21504 : const uint32_t skip = (destY + y) * destPVP.w + destX;
297 21504 : uint32_t* destColorIt = destC + skip;
298 21504 : uint32_t* destDepthIt = destD + skip;
299 21504 : const uint32_t* colorIt = color + y * pvp.w;
300 21504 : const uint32_t* depthIt = depth + y * pvp.w;
301 :
302 27546624 : for( int32_t x = 0; x < pvp.w; ++x )
303 : {
304 27525120 : if( *destDepthIt > *depthIt )
305 : {
306 4940199 : *destColorIt = *colorIt;
307 4940199 : *destDepthIt = *depthIt;
308 : }
309 :
310 27525120 : ++destColorIt;
311 27525120 : ++destDepthIt;
312 27525120 : ++colorIt;
313 27525120 : ++depthIt;
314 : }
315 : }
316 21 : }
317 :
318 21 : void _merge2DImage( void* destColor, void* destDepth,
319 : const eq::PixelViewport& destPVP, const Image* image,
320 : const Vector2i& offset )
321 : {
322 : // This is mostly copy&paste code from _mergeDBImage :-/
323 21 : LBVERB << "CPU-2D assembly" << std::endl;
324 :
325 21 : uint8_t* destC = reinterpret_cast< uint8_t* >( destColor );
326 21 : uint8_t* destD = reinterpret_cast< uint8_t* >( destDepth );
327 :
328 21 : const PixelViewport& pvp = image->getPixelViewport();
329 21 : const int32_t destX = offset.x() + pvp.x - destPVP.x;
330 21 : const int32_t destY = offset.y() + pvp.y - destPVP.y;
331 :
332 21 : LBASSERT( image->hasPixelData( Frame::BUFFER_COLOR ));
333 :
334 21 : const uint8_t* color = image->getPixelPointer( Frame::BUFFER_COLOR );
335 21 : const size_t pixelSize = image->getPixelSize( Frame::BUFFER_COLOR );
336 21 : const size_t rowLength = pvp.w * pixelSize;
337 :
338 : #pragma omp parallel for
339 21525 : for( int32_t y = 0; y < pvp.h; ++y )
340 : {
341 21504 : const size_t skip = ( (destY + y) * destPVP.w + destX ) * pixelSize;
342 21504 : memcpy( destC + skip, color + y * pvp.w * pixelSize, rowLength);
343 : // clear depth, for depth-assembly into existing FB
344 21504 : if( destD )
345 0 : lunchbox::setZero( destD + skip, rowLength );
346 : }
347 21 : }
348 :
349 21 : void _blendImage( void* dest, const eq::PixelViewport& destPVP,
350 : const Image* image, const Vector2i& offset )
351 : {
352 21 : LBVERB << "CPU-Blend assembly" << std::endl;
353 :
354 21 : int32_t* destColor = reinterpret_cast< int32_t* >( dest );
355 :
356 21 : const PixelViewport& pvp = image->getPixelViewport();
357 21 : const int32_t destX = offset.x() + pvp.x - destPVP.x;
358 21 : const int32_t destY = offset.y() + pvp.y - destPVP.y;
359 :
360 21 : LBASSERT( image->getPixelSize( Frame::BUFFER_COLOR ) == 4 );
361 21 : LBASSERT( image->hasPixelData( Frame::BUFFER_COLOR ));
362 21 : LBASSERT( image->hasAlpha( ));
363 :
364 : const int32_t* color = reinterpret_cast< const int32_t* >
365 21 : ( image->getPixelPointer( Frame::BUFFER_COLOR ));
366 :
367 : // Blending of two slices, none of which is on final image (i.e. result
368 : // could be blended on to something else) should be performed with:
369 : // glBlendFuncSeparate( GL_ONE, GL_SRC_ALPHA, GL_ZERO, GL_SRC_ALPHA )
370 : // which means:
371 : // dstColor = 1*srcColor + srcAlpha*dstColor
372 : // dstAlpha = 0*srcAlpha + srcAlpha*dstAlpha
373 : // because we accumulate light which is go through (= 1-Alpha) and we
374 : // already have colors as Alpha*Color
375 :
376 21 : int32_t* destColorStart = destColor + destY*destPVP.w + destX;
377 21 : const uint32_t step = sizeof( int32_t );
378 :
379 : #pragma omp parallel for
380 25221 : for( int32_t y = 0; y < pvp.h; ++y )
381 : {
382 : const unsigned char* src =
383 25200 : reinterpret_cast< const uint8_t* >( color + pvp.w * y );
384 : unsigned char* dst =
385 25200 : reinterpret_cast< uint8_t* >( destColorStart + destPVP.w * y );
386 :
387 48409200 : for( int32_t x = 0; x < pvp.w; ++x )
388 : {
389 48384000 : dst[0] = LB_MIN( src[0] + (src[3]*dst[0] >> 8), 255 );
390 48384000 : dst[1] = LB_MIN( src[1] + (src[3]*dst[1] >> 8), 255 );
391 48384000 : dst[2] = LB_MIN( src[2] + (src[3]*dst[2] >> 8), 255 );
392 48384000 : dst[3] = src[3]*dst[3] >> 8;
393 :
394 48384000 : src += step;
395 48384000 : dst += step;
396 : }
397 : }
398 21 : }
399 :
400 9 : void _mergeImages( const ImageOps& ops, const bool blend, void* colorBuffer,
401 : void* depthBuffer, const PixelViewport& destPVP )
402 : {
403 72 : for( const ImageOp& op : ops )
404 : {
405 63 : if( !op.image->hasPixelData( Frame::BUFFER_COLOR ))
406 0 : continue;
407 :
408 63 : if( op.image->hasPixelData( Frame::BUFFER_DEPTH ))
409 : _mergeDBImage( colorBuffer, depthBuffer, destPVP, op.image,
410 21 : op.offset );
411 42 : else if( blend && op.image->hasAlpha( ))
412 21 : _blendImage( colorBuffer, destPVP, op.image, op.offset );
413 : else
414 : _merge2DImage( colorBuffer, depthBuffer, destPVP, op.image,
415 21 : op.offset );
416 : }
417 9 : }
418 :
419 0 : Vector4f _getCoords( const ImageOp& op, const PixelViewport& pvp )
420 : {
421 0 : const Pixel& pixel = op.image->getContext().pixel;
422 : return Vector4f(
423 0 : op.offset.x() + pvp.x * pixel.w + pixel.x,
424 0 : op.offset.x() + pvp.getXEnd() * pixel.w * op.zoom.x() + pixel.x,
425 0 : op.offset.y() + pvp.y * pixel.h + pixel.y,
426 0 : op.offset.y() + pvp.getYEnd() * pixel.h * op.zoom.y() + pixel.y );
427 : }
428 :
429 0 : bool _setupDrawPixels( const ImageOp& op, const Frame::Buffer which,
430 : Channel* channel )
431 : {
432 0 : const PixelViewport& pvp = op.image->getPixelViewport();
433 0 : const util::Texture* texture = 0;
434 0 : if( op.image->getStorageType() == Frame::TYPE_MEMORY )
435 : {
436 0 : LBASSERT( op.image->hasPixelData( which ));
437 0 : util::ObjectManager& objects = channel->getObjectManager();
438 :
439 0 : const bool coreProfile = channel->getWindow()->getIAttribute(
440 0 : WindowSettings::IATTR_HINT_CORE_PROFILE ) == ON;
441 0 : if( op.zoom == Zoom::NONE && !coreProfile )
442 : {
443 0 : op.image->upload( which, 0, op.offset, objects );
444 0 : return false;
445 : }
446 : util::Texture* ncTexture = objects.obtainEqTexture(
447 : which == Frame::BUFFER_COLOR ? colorDBKey : depthDBKey,
448 0 : GL_TEXTURE_RECTANGLE_ARB );
449 0 : texture = ncTexture;
450 :
451 0 : const Vector2i offset( -pvp.x, -pvp.y ); // will be applied with quad
452 0 : op.image->upload( which, ncTexture, offset, objects );
453 : }
454 : else // texture image
455 : {
456 0 : LBASSERT( op.image->hasTextureData( which ));
457 0 : texture = &op.image->getTexture( which );
458 : }
459 :
460 0 : EQ_GL_CALL( glActiveTexture( GL_TEXTURE0 ));
461 0 : texture->bind();
462 0 : texture->applyZoomFilter( op.zoomFilter );
463 0 : texture->applyWrap();
464 :
465 0 : if ( which == Frame::BUFFER_COLOR )
466 0 : EQ_GL_CALL( glDepthMask( false ))
467 : else
468 : {
469 0 : LBASSERT( which == Frame::BUFFER_DEPTH )
470 0 : EQ_GL_CALL( glColorMask( false, false, false, false ));
471 : }
472 0 : return true;
473 : }
474 :
475 0 : void _drawPixelsFF( const ImageOp& op, const Frame::Buffer which,
476 : Channel* channel )
477 : {
478 0 : const PixelViewport& pvp = op.image->getPixelViewport();
479 0 : LBLOG( LOG_ASSEMBLY ) << "_drawPixelsFF " << pvp << " offset " << op.offset
480 0 : << std::endl;
481 :
482 0 : if( !_setupDrawPixels( op, which, channel ))
483 0 : return;
484 :
485 0 : const Vector4f& coords = _getCoords( op, pvp );
486 :
487 0 : EQ_GL_CALL( glDisable( GL_LIGHTING ));
488 0 : EQ_GL_CALL( glEnable( GL_TEXTURE_RECTANGLE_ARB ));
489 :
490 0 : EQ_GL_CALL( glColor3f( 1.0f, 1.0f, 1.0f ));
491 :
492 0 : glBegin( GL_QUADS );
493 0 : glTexCoord2f( 0.0f, 0.0f );
494 0 : glVertex3f( coords[0], coords[2], 0.0f );
495 :
496 0 : glTexCoord2f( float( pvp.w ), 0.0f );
497 0 : glVertex3f( coords[1], coords[2], 0.0f );
498 :
499 0 : glTexCoord2f( float( pvp.w ), float( pvp.h ));
500 0 : glVertex3f( coords[1], coords[3], 0.0f );
501 :
502 0 : glTexCoord2f( 0.0f, float( pvp.h ));
503 0 : glVertex3f( coords[0], coords[3], 0.0f );
504 0 : glEnd();
505 :
506 : // restore state
507 0 : EQ_GL_CALL( glDisable( GL_TEXTURE_RECTANGLE_ARB ));
508 :
509 0 : if ( which == Frame::BUFFER_COLOR )
510 0 : EQ_GL_CALL( glDepthMask( true ))
511 : else
512 : {
513 0 : const ColorMask& colorMask = channel->getDrawBufferMask();
514 0 : EQ_GL_CALL( glColorMask( colorMask.red, colorMask.green, colorMask.blue,
515 : true ));
516 : }
517 : }
518 :
519 : template< typename T >
520 0 : void _drawTexturedQuad( const T* key, const ImageOp& op,
521 : const PixelViewport& pvp, const bool withDepth,
522 : Channel* channel )
523 : {
524 0 : util::ObjectManager& om = channel->getObjectManager();
525 0 : GLuint program = om.getProgram( key );
526 0 : GLuint vertexArray = om.getVertexArray( key );
527 0 : GLuint vertexBuffer = om.getBuffer( key );
528 0 : GLuint uvBuffer = om.getBuffer( key + 1 );
529 0 : if( program == util::ObjectManager::INVALID )
530 : {
531 0 : vertexBuffer = om.newBuffer( key );
532 0 : uvBuffer = om.newBuffer( key + 1 );
533 0 : vertexArray = om.newVertexArray( key );
534 0 : program = om.newProgram( key );
535 :
536 : const char* vertexShaderGLSL = {
537 : "#version 330 core\n"
538 : "layout(location = 0) in vec3 vert;\n"
539 : "layout(location = 1) in vec2 vertTexCoord;\n"
540 : "uniform mat4 proj;\n"
541 : "out vec2 fragTexCoord;\n"
542 : "void main() {\n"
543 : " fragTexCoord = vertTexCoord;\n"
544 : " gl_Position = proj * vec4(vert, 1);\n"
545 : "}\n"
546 0 : };
547 :
548 : const char* fragmentShaderGLSL = { withDepth ?
549 : "#version 330 core\n"
550 : "#extension GL_ARB_texture_rectangle : enable\n"
551 : "uniform sampler2DRect color;\n"
552 : "uniform sampler2DRect depth;\n"
553 : "in vec2 fragTexCoord;\n"
554 : "out vec4 finalColor;\n"
555 : "void main() {\n"
556 : " finalColor = texture2DRect(color, fragTexCoord);\n"
557 : " gl_FragDepth = texture2DRect(depth, fragTexCoord).x;\n"
558 : "}\n"
559 : : // no depth
560 : "#version 330 core\n"
561 : "#extension GL_ARB_texture_rectangle : enable\n"
562 : "uniform sampler2DRect color;\n"
563 : "in vec2 fragTexCoord;\n"
564 : "out vec4 finalColor;\n"
565 : "void main() {\n"
566 : " finalColor = texture2DRect(color, fragTexCoord);\n"
567 : "}\n"
568 0 : };
569 :
570 0 : LBCHECK( util::shader::linkProgram( glewGetContext(), program,
571 : vertexShaderGLSL,
572 : fragmentShaderGLSL ));
573 :
574 0 : EQ_GL_CALL( glUseProgram( program ));
575 :
576 0 : GLint colorParam = glGetUniformLocation( program, "color" );
577 0 : EQ_GL_CALL( glUniform1i( colorParam, 0 ));
578 0 : if( withDepth )
579 : {
580 0 : const GLint depthParam = glGetUniformLocation( program, "depth" );
581 0 : EQ_GL_CALL( glUniform1i( depthParam, 1 ));
582 : }
583 : }
584 :
585 0 : const Vector4f& coords = _getCoords( op, pvp );
586 : const GLfloat vertices[] = {
587 : coords[0], coords[2], 0.0f,
588 : coords[1], coords[2], 0.0f,
589 : coords[0], coords[3], 0.0f,
590 : coords[1], coords[3], 0.0f
591 0 : };
592 :
593 : const GLfloat uvs[] = { 0.0f, 0.0f,
594 : float( pvp.w ), 0.0f,
595 : 0.0f, float( pvp.h ),
596 0 : float( pvp.w ), float( pvp.h ) };
597 : const eq::Matrix4f& proj =
598 0 : eq::Frustumf( channel->getPixelViewport().x,
599 0 : channel->getPixelViewport().getXEnd(),
600 0 : channel->getPixelViewport().y,
601 0 : channel->getPixelViewport().getYEnd(),
602 0 : -1.0f, 1.0f ).computeOrthoMatrix();
603 0 : if( withDepth )
604 0 : EQ_GL_CALL( glEnable( GL_DEPTH_TEST ));
605 :
606 0 : EQ_GL_CALL( glBindVertexArray( vertexArray ));
607 0 : EQ_GL_CALL( glUseProgram( program ));
608 :
609 0 : const GLuint projection = glGetUniformLocation( program, "proj" );
610 0 : EQ_GL_CALL( glUniformMatrix4fv( projection, 1, GL_FALSE, proj.data( )));
611 :
612 0 : EQ_GL_CALL( glBindBuffer( GL_ARRAY_BUFFER, vertexBuffer ));
613 0 : EQ_GL_CALL( glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), vertices,
614 : GL_DYNAMIC_DRAW ));
615 0 : EQ_GL_CALL( glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, 0 ));
616 :
617 0 : EQ_GL_CALL( glBindBuffer( GL_ARRAY_BUFFER, uvBuffer ));
618 0 : EQ_GL_CALL( glBufferData( GL_ARRAY_BUFFER, sizeof(uvs), uvs,
619 : GL_DYNAMIC_DRAW ));
620 0 : EQ_GL_CALL( glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, 0 ));
621 0 : EQ_GL_CALL( glBindBuffer( GL_ARRAY_BUFFER, 0 ));
622 :
623 0 : EQ_GL_CALL( glEnableVertexAttribArray( 0 ));
624 0 : EQ_GL_CALL( glEnableVertexAttribArray( 1 ));
625 0 : EQ_GL_CALL( glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 ));
626 0 : EQ_GL_CALL( glDisableVertexAttribArray( 0 ));
627 0 : EQ_GL_CALL( glDisableVertexAttribArray( 1 ));
628 :
629 0 : EQ_GL_CALL( glBindVertexArray( 0 ));
630 0 : EQ_GL_CALL( glUseProgram( 0 ));
631 :
632 0 : if( withDepth )
633 0 : EQ_GL_CALL( glDisable( GL_DEPTH_TEST ));
634 0 : }
635 :
636 0 : void _drawPixelsGLSL( const ImageOp& op, const Frame::Buffer which,
637 : Channel* channel )
638 : {
639 0 : const PixelViewport& pvp = op.image->getPixelViewport();
640 0 : LBLOG( LOG_ASSEMBLY ) << "_drawPixelsGLSL " << pvp << " offset "
641 0 : << op.offset << std::endl;
642 :
643 0 : if( !_setupDrawPixels( op, which, channel ))
644 0 : return;
645 :
646 0 : _drawTexturedQuad( channel, op, pvp, false, channel );
647 :
648 : // restore state
649 0 : if ( which == Frame::BUFFER_COLOR )
650 0 : EQ_GL_CALL( glDepthMask( true ))
651 : else
652 : {
653 0 : const ColorMask& colorMask = channel->getDrawBufferMask();
654 0 : EQ_GL_CALL( glColorMask( colorMask.red, colorMask.green, colorMask.blue,
655 : true ));
656 : }
657 : }
658 :
659 0 : util::Accum* _obtainAccum( Channel* channel )
660 : {
661 0 : const PixelViewport& pvp = channel->getPixelViewport();
662 :
663 0 : LBASSERT( pvp.isValid( ));
664 :
665 0 : util::ObjectManager& objects = channel->getObjectManager();
666 0 : util::Accum* accum = objects.getEqAccum( channel );
667 0 : if( !accum )
668 : {
669 0 : accum = objects.newEqAccum( channel );
670 0 : if( !accum->init( pvp, channel->getWindow()->getColorFormat( )))
671 : {
672 0 : LBERROR << "Accumulation initialization failed." << std::endl;
673 : }
674 : }
675 : else
676 0 : accum->resize( pvp.w, pvp.h );
677 :
678 0 : accum->clear();
679 0 : return accum;
680 : }
681 :
682 : }
683 :
684 0 : uint32_t Compositor::assembleFrames( const Frames& frames,
685 : Channel* channel, util::Accum* accum )
686 : {
687 0 : if( frames.empty( ))
688 0 : return 0;
689 :
690 0 : if( _useCPUAssembly( frames, channel ))
691 0 : return assembleFramesCPU( frames, channel );
692 :
693 : // else
694 0 : return assembleFramesUnsorted( frames, channel, accum );
695 : }
696 :
697 0 : uint32_t Compositor::blendImages( const ImageOps& ops, Channel* channel,
698 : util::Accum* accum )
699 : {
700 0 : if( ops.empty( ))
701 0 : return 0;
702 :
703 0 : if( isSubPixelDecomposition( ops ))
704 : {
705 0 : const bool coreProfile = channel->getWindow()->getIAttribute(
706 0 : WindowSettings::IATTR_HINT_CORE_PROFILE ) == ON;
707 0 : if( coreProfile )
708 : {
709 0 : LBERROR << "No support for sub pixel assembly for OpenGL core"
710 0 : "profile, skipping assemble" << std::endl;
711 0 : return 0;
712 : }
713 :
714 0 : if( !accum )
715 : {
716 0 : accum = _obtainAccum( channel );
717 0 : accum->clear();
718 :
719 0 : const SubPixel& subPixel = ops.front().image->getContext().subPixel;
720 0 : accum->setTotalSteps( subPixel.size );
721 : }
722 :
723 0 : uint32_t count = 0;
724 0 : ImageOps opsLeft = ops;
725 0 : while( !opsLeft.empty( ))
726 : {
727 0 : ImageOps current = extractOneSubPixel( opsLeft );
728 0 : const uint32_t subCount = blendImages( current, channel, accum );
729 0 : LBASSERT( subCount < 2 );
730 :
731 0 : if( subCount > 0 )
732 0 : accum->accum();
733 0 : count += subCount;
734 0 : }
735 0 : if( count > 0 )
736 0 : accum->display();
737 0 : return count;
738 : }
739 :
740 0 : uint32_t count = 1;
741 0 : if( _useCPUAssembly( ops, true ))
742 0 : count = assembleImagesCPU( ops, channel, true );
743 0 : else for( const ImageOp& op : ops )
744 0 : assembleImage( op, channel );
745 0 : return count;
746 : }
747 :
748 0 : uint32_t Compositor::blendFrames( const Frames& frames, Channel* channel,
749 : util::Accum* accum )
750 : {
751 0 : ImageOps ops;
752 0 : for( const Frame* frame : frames )
753 : {
754 : {
755 0 : const uint32_t timeout = channel->getConfig()->getTimeout();
756 : ChannelStatistics event( Statistic::CHANNEL_FRAME_WAIT_READY,
757 0 : channel );
758 0 : frame->waitReady( timeout );
759 : }
760 :
761 0 : for( const Image* image : frame->getImages( ))
762 0 : ops.push_back( ImageOp( frame, image ));
763 : }
764 :
765 0 : return blendImages( ops, channel, accum );
766 : }
767 :
768 0 : bool Compositor::isSubPixelDecomposition( const Frames& frames )
769 : {
770 0 : if( frames.empty( ))
771 0 : return false;
772 :
773 : const SubPixel& subpixel =
774 0 : frames.front()->getFrameData()->getContext().subPixel;
775 0 : for( const Frame* frame : frames )
776 0 : if( subpixel != frame->getFrameData()->getContext().subPixel )
777 0 : return true;
778 0 : return false;
779 : }
780 :
781 0 : bool Compositor::isSubPixelDecomposition( const ImageOps& ops )
782 : {
783 0 : if( ops.empty( ))
784 0 : return false;
785 :
786 0 : const SubPixel& subPixel = ops.front().image->getContext().subPixel;
787 0 : for( const ImageOp& op : ops )
788 0 : if( op.image->getContext().subPixel != subPixel )
789 0 : return true;
790 0 : return false;
791 : }
792 :
793 0 : Frames Compositor::extractOneSubPixel( Frames& frames )
794 : {
795 0 : Frames current;
796 :
797 : const SubPixel& subPixel =
798 0 : frames.back()->getFrameData()->getContext().subPixel;
799 0 : current.push_back( frames.back( ));
800 0 : frames.pop_back();
801 :
802 0 : for( Frames::iterator i = frames.begin(); i != frames.end(); )
803 : {
804 0 : Frame* frame = *i;
805 :
806 0 : if( frame->getFrameData()->getContext().subPixel == subPixel )
807 : {
808 0 : current.push_back( frame );
809 0 : i = frames.erase( i );
810 : }
811 : else
812 0 : ++i;
813 : }
814 :
815 0 : return current;
816 : }
817 :
818 0 : ImageOps Compositor::extractOneSubPixel( ImageOps& ops )
819 : {
820 0 : ImageOps current;
821 :
822 0 : const SubPixel& subPixel = ops.back().image->getContext().subPixel;
823 0 : current.push_back( ops.back( ));
824 0 : ops.pop_back();
825 :
826 0 : for( ImageOps::iterator i = ops.begin(); i != ops.end(); )
827 : {
828 0 : ImageOp& op = *i;
829 :
830 0 : if( op.image->getContext().subPixel == subPixel )
831 : {
832 0 : current.push_back( op );
833 0 : i = ops.erase( i );
834 : }
835 : else
836 0 : ++i;
837 : }
838 :
839 0 : return current;
840 : }
841 :
842 0 : uint32_t Compositor::assembleFramesUnsorted( const Frames& frames,
843 : Channel* channel,
844 : util::Accum* accum )
845 : {
846 0 : if( frames.empty( ))
847 0 : return 0;
848 :
849 0 : LBVERB << "Unsorted GPU assembly" << std::endl;
850 0 : if( isSubPixelDecomposition( frames ))
851 : {
852 0 : const bool coreProfile = channel->getWindow()->getIAttribute(
853 0 : WindowSettings::IATTR_HINT_CORE_PROFILE ) == ON;
854 0 : if( coreProfile )
855 : {
856 0 : LBERROR << "No support for sub pixel assembly for OpenGL core"
857 0 : "profile, skipping assemble" << std::endl;
858 0 : return 0;
859 : }
860 :
861 0 : uint32_t count = 0;
862 :
863 0 : if( !accum )
864 : {
865 0 : accum = _obtainAccum( channel );
866 0 : accum->clear();
867 :
868 : const SubPixel& subPixel =
869 0 : frames.back()->getFrameData()->getContext().subPixel;
870 0 : accum->setTotalSteps( subPixel.size );
871 : }
872 :
873 0 : Frames framesLeft = frames;
874 0 : while( !framesLeft.empty( ))
875 : {
876 : // get the frames with the same subpixel compound
877 0 : Frames current = extractOneSubPixel( framesLeft );
878 :
879 : // use assembleFrames to potentially benefit from CPU assembly
880 0 : const uint32_t subCount = assembleFrames( current, channel, accum );
881 0 : LBASSERT( subCount < 2 )
882 0 : if( subCount > 0 )
883 0 : accum->accum();
884 0 : count += subCount;
885 0 : }
886 0 : if( count > 1 )
887 0 : accum->display();
888 0 : return count;
889 : }
890 :
891 : // This is an optimized assembly version. The frames are not assembled in
892 : // the saved order, but in the order they become available, which is faster
893 : // because less time is spent waiting on frame availability.
894 : //
895 : // The ready frames are counted in a monitor. Whenever a frame becomes
896 : // available, it increments the monitor which causes this code to wake up
897 : // and assemble it.
898 :
899 0 : uint32_t count = 0;
900 :
901 : // wait and assemble frames
902 0 : WaitHandle* handle = startWaitFrames( frames, channel );
903 0 : for( Frame* frame = waitFrame( handle ); frame; frame = waitFrame( handle ))
904 : {
905 0 : if( frame->getImages().empty( ))
906 0 : continue;
907 :
908 0 : count = 1;
909 0 : assembleFrame( frame, channel );
910 : }
911 :
912 0 : return count;
913 : }
914 :
915 : class Compositor::WaitHandle
916 : {
917 : public:
918 0 : WaitHandle( const Frames& frames, Channel* ch )
919 0 : : left( frames ), channel( ch ), processed( 0 ) {}
920 0 : ~WaitHandle()
921 0 : {
922 : // de-register the monitor on eventual left-overs on error/exception
923 0 : for( FramesCIter i = left.begin(); i != left.end(); ++i )
924 0 : (*i)->removeListener( monitor );
925 0 : left.clear();
926 0 : }
927 :
928 : lunchbox::Monitor< uint32_t > monitor;
929 : Frames left;
930 : Channel* const channel;
931 : uint32_t processed;
932 : };
933 :
934 0 : Compositor::WaitHandle* Compositor::startWaitFrames( const Frames& frames,
935 : Channel* channel )
936 : {
937 0 : WaitHandle* handle = new WaitHandle( frames, channel );
938 0 : for( FramesCIter i = frames.begin(); i != frames.end(); ++i )
939 0 : (*i)->addListener( handle->monitor );
940 :
941 0 : return handle;
942 : }
943 :
944 0 : Frame* Compositor::waitFrame( WaitHandle* handle )
945 : {
946 0 : if( handle->left.empty( ))
947 : {
948 0 : delete handle;
949 0 : return 0;
950 : }
951 :
952 : ChannelStatistics event( Statistic::CHANNEL_FRAME_WAIT_READY,
953 0 : handle->channel );
954 0 : Config* config = handle->channel->getConfig();
955 0 : const uint32_t timeout = config->getTimeout();
956 :
957 0 : ++handle->processed;
958 0 : if( timeout == LB_TIMEOUT_INDEFINITE )
959 0 : handle->monitor.waitGE( handle->processed );
960 : else
961 : {
962 0 : const int64_t time = config->getTime() + timeout;
963 0 : const int64_t aliveTimeout = co::Global::getKeepaliveTimeout();
964 :
965 0 : while( !handle->monitor.timedWaitGE( handle->processed, aliveTimeout ))
966 : {
967 : // pings timed out nodes
968 0 : const bool pinged = config->getLocalNode()->pingIdleNodes();
969 :
970 0 : if( config->getTime() >= time || !pinged )
971 : {
972 0 : delete handle;
973 0 : throw Exception( Exception::TIMEOUT_INPUTFRAME );
974 : }
975 : }
976 : }
977 :
978 0 : for( FramesIter i = handle->left.begin(); i != handle->left.end(); ++i )
979 : {
980 0 : Frame* frame = *i;
981 0 : if( !frame->isReady( ))
982 0 : continue;
983 :
984 0 : frame->removeListener( handle->monitor );
985 0 : handle->left.erase( i );
986 0 : return frame;
987 : }
988 :
989 0 : LBASSERTINFO( false, "Unreachable code" );
990 0 : delete handle;
991 0 : return 0;
992 : }
993 :
994 0 : uint32_t Compositor::assembleFramesCPU( const Frames& frames, Channel* channel,
995 : const bool blend )
996 : {
997 0 : if( frames.empty( ))
998 0 : return 0;
999 :
1000 : // Assembles images from DB and 2D compounds using the CPU and then
1001 : // assembles the result image. Does not support Pixel or Eye compounds.
1002 0 : LBVERB << "Sorted CPU assembly" << std::endl;
1003 :
1004 : const Image* result = mergeFramesCPU( frames, blend,
1005 0 : channel->getConfig()->getTimeout( ));
1006 0 : return _assembleCPUImage( result, channel );
1007 : }
1008 :
1009 0 : uint32_t Compositor::assembleImagesCPU( const ImageOps& images,
1010 : Channel* channel,
1011 : const bool blend )
1012 : {
1013 0 : if( images.empty( ))
1014 0 : return 0;
1015 :
1016 : // Assembles images from DB and 2D compounds using the CPU and then
1017 : // assembles the result image. Does not support Pixel or Eye compounds.
1018 0 : LBVERB << "Sorted CPU assembly" << std::endl;
1019 :
1020 0 : const Image* result = mergeImagesCPU( images, blend );
1021 0 : return _assembleCPUImage( result, channel );
1022 : }
1023 :
1024 9 : const Image* Compositor::mergeFramesCPU( const Frames& frames, const bool blend,
1025 : const uint32_t timeout )
1026 : {
1027 9 : ImageOps ops;
1028 30 : for( const Frame* frame : frames )
1029 : {
1030 21 : frame->waitReady( timeout );
1031 84 : for( const Image* image : frame->getImages( ))
1032 : {
1033 63 : ImageOp op( frame, image );
1034 63 : op.offset = frame->getOffset();
1035 63 : ops.emplace_back( op );
1036 : }
1037 : }
1038 9 : return mergeImagesCPU( ops, blend );
1039 : }
1040 :
1041 9 : const Image* Compositor::mergeImagesCPU( const ImageOps& ops, const bool blend )
1042 : {
1043 9 : LBVERB << "Sorted CPU assembly" << std::endl;
1044 :
1045 : // Collect input image information and check preconditions
1046 9 : PixelViewport destPVP;
1047 9 : uint32_t colorInt = 0;
1048 9 : uint32_t colorExt = 0;
1049 9 : uint32_t colorPixelSize = 0;
1050 9 : uint32_t depthInt = 0;
1051 9 : uint32_t depthExt = 0;
1052 9 : uint32_t depthPixelSize = 0;
1053 :
1054 9 : if( !_collectOutputData( ops, destPVP, colorInt, colorPixelSize,
1055 9 : colorExt, depthInt, depthPixelSize, depthExt ))
1056 : {
1057 0 : return 0;
1058 : }
1059 :
1060 : // prepare output image
1061 9 : if( !_resultImage )
1062 1 : _resultImage = new Image;
1063 9 : Image* result = _resultImage.get();
1064 :
1065 : // pre-condition check for current _merge implementations
1066 9 : LBASSERT( colorInt != 0 );
1067 :
1068 9 : result->setPixelViewport( destPVP );
1069 :
1070 9 : PixelData colorPixels;
1071 9 : colorPixels.internalFormat = colorInt;
1072 9 : colorPixels.externalFormat = colorExt;
1073 9 : colorPixels.pixelSize = colorPixelSize;
1074 9 : colorPixels.pvp = destPVP;
1075 9 : result->setPixelData( Frame::BUFFER_COLOR, colorPixels );
1076 :
1077 9 : void* destDepth = 0;
1078 9 : if( depthInt != 0 ) // at least one depth assembly
1079 : {
1080 3 : LBASSERT( depthExt ==
1081 : EQ_COMPRESSOR_DATATYPE_DEPTH_UNSIGNED_INT );
1082 3 : PixelData depthPixels;
1083 3 : depthPixels.internalFormat = depthInt;
1084 3 : depthPixels.externalFormat = depthExt;
1085 3 : depthPixels.pixelSize = depthPixelSize;
1086 3 : depthPixels.pvp = destPVP;
1087 3 : result->setPixelData( Frame::BUFFER_DEPTH, depthPixels );
1088 3 : destDepth = result->getPixelPointer( Frame::BUFFER_DEPTH );
1089 : }
1090 :
1091 : // assembly
1092 9 : _mergeImages( ops, blend, result->getPixelPointer( Frame::BUFFER_COLOR ),
1093 9 : destDepth, destPVP );
1094 9 : return result;
1095 : }
1096 :
1097 0 : void Compositor::assembleFrame( const Frame* frame, Channel* channel )
1098 : {
1099 0 : const Images& images = frame->getImages();
1100 0 : if( images.empty( ))
1101 0 : LBINFO << "No images to assemble" << std::endl;
1102 :
1103 0 : for( Image* image : images )
1104 : {
1105 0 : ImageOp op( frame, image );
1106 0 : op.offset = frame->getOffset();
1107 0 : assembleImage( op, channel );
1108 : }
1109 0 : }
1110 :
1111 0 : void Compositor::assembleImage( const ImageOp& op, Channel* channel )
1112 : {
1113 0 : const bool coreProfile = channel->getWindow()->getIAttribute(
1114 0 : WindowSettings::IATTR_HINT_CORE_PROFILE ) == ON;
1115 0 : if( coreProfile && op.image->getContext().pixel != Pixel::ALL )
1116 : {
1117 0 : LBERROR << "No support for pixel assembly for OpenGL core profile,"
1118 0 : "skipping image" << std::endl;
1119 0 : return;
1120 : }
1121 :
1122 0 : ImageOp operation = op;
1123 0 : operation.buffers = Frame::BUFFER_NONE;
1124 :
1125 0 : const Frame::Buffer buffer[] = { Frame::BUFFER_COLOR, Frame::BUFFER_DEPTH };
1126 0 : for( unsigned i = 0; i<2; ++i )
1127 : {
1128 0 : if( (op.buffers & buffer[i]) &&
1129 0 : ( op.image->hasPixelData( buffer[i] ) ||
1130 0 : op.image->hasTextureData( buffer[i] )) )
1131 : {
1132 0 : operation.buffers |= buffer[i];
1133 : }
1134 : }
1135 :
1136 0 : if( operation.buffers == Frame::BUFFER_NONE )
1137 : {
1138 0 : LBWARN << "No image attachment buffers to assemble" << std::endl;
1139 0 : return;
1140 : }
1141 :
1142 0 : setupStencilBuffer( operation, channel );
1143 :
1144 0 : if( operation.buffers == Frame::BUFFER_COLOR )
1145 0 : assembleImage2D( operation, channel );
1146 0 : else if( operation.buffers == ( Frame::BUFFER_COLOR | Frame::BUFFER_DEPTH ))
1147 0 : assembleImageDB( operation, channel );
1148 : else
1149 0 : LBWARN << "Don't know how to assemble using buffers "
1150 0 : << operation.buffers << std::endl;
1151 :
1152 0 : clearStencilBuffer( operation );
1153 : }
1154 :
1155 0 : void Compositor::setupStencilBuffer( const ImageOp& op, const Channel* channel )
1156 : {
1157 0 : const Pixel& pixel = op.image->getContext().pixel;
1158 0 : if( pixel == Pixel::ALL )
1159 0 : return;
1160 :
1161 : // mark stencil buffer where pixel shall not pass
1162 : // TODO: OPT!
1163 0 : EQ_GL_CALL( glClear( GL_STENCIL_BUFFER_BIT ));
1164 0 : EQ_GL_CALL( glEnable( GL_STENCIL_TEST ));
1165 0 : EQ_GL_CALL( glEnable( GL_DEPTH_TEST ));
1166 :
1167 0 : EQ_GL_CALL( glStencilFunc( GL_ALWAYS, 1, 1 ));
1168 0 : EQ_GL_CALL( glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE ));
1169 :
1170 0 : EQ_GL_CALL( glLineWidth( 1.0f ));
1171 0 : EQ_GL_CALL( glDepthMask( false ));
1172 0 : EQ_GL_CALL( glColorMask( false, false, false, false ));
1173 :
1174 0 : const PixelViewport& pvp = op.image->getPixelViewport();
1175 :
1176 0 : EQ_GL_CALL( glPixelZoom( float( pixel.w ), float( pixel.h )));
1177 :
1178 0 : if( pixel.w > 1 )
1179 : {
1180 0 : const float width = float( pvp.w * pixel.w );
1181 0 : const float step = float( pixel.w );
1182 :
1183 0 : const float startX = float( op.offset.x() + pvp.x ) + 0.5f -
1184 0 : float( pixel.w );
1185 0 : const float endX = startX + width + pixel.w + step;
1186 0 : const float startY = float( op.offset.y() + pvp.y + pixel.y );
1187 0 : const float endY = float( startY + pvp.h*pixel.h );
1188 :
1189 0 : glBegin( GL_QUADS );
1190 0 : for( float x = startX + pixel.x + 1.0f ; x < endX; x += step)
1191 : {
1192 0 : glVertex3f( x-step, startY, 0.0f );
1193 0 : glVertex3f( x-1.0f, startY, 0.0f );
1194 0 : glVertex3f( x-1.0f, endY, 0.0f );
1195 0 : glVertex3f( x-step, endY, 0.0f );
1196 : }
1197 0 : glEnd();
1198 : }
1199 0 : if( pixel.h > 1 )
1200 : {
1201 0 : const float height = float( pvp.h * pixel.h );
1202 0 : const float step = float( pixel.h );
1203 0 : const float startX = float( op.offset.x() + pvp.x + pixel.x );
1204 0 : const float endX = float( startX + pvp.w * pixel.w );
1205 0 : const float startY = float( op.offset.y() + pvp.y ) + 0.5f -
1206 0 : float( pixel.h );
1207 0 : const float endY = startY + height + pixel.h + step;
1208 :
1209 0 : glBegin( GL_QUADS );
1210 0 : for( float y = startY + pixel.y; y < endY; y += step)
1211 : {
1212 0 : glVertex3f( startX, y-step, 0.0f );
1213 0 : glVertex3f( endX, y-step, 0.0f );
1214 0 : glVertex3f( endX, y-1.0f, 0.0f );
1215 0 : glVertex3f( startX, y-1.0f, 0.0f );
1216 : }
1217 0 : glEnd();
1218 : }
1219 :
1220 0 : EQ_GL_CALL( glDisable( GL_DEPTH_TEST ));
1221 0 : EQ_GL_CALL( glStencilFunc( GL_EQUAL, 0, 1 ));
1222 0 : EQ_GL_CALL( glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ));
1223 :
1224 0 : const ColorMask& colorMask = channel->getDrawBufferMask();
1225 0 : EQ_GL_CALL( glColorMask( colorMask.red, colorMask.green, colorMask.blue,
1226 : true ));
1227 0 : EQ_GL_CALL( glDepthMask( true ));
1228 : }
1229 :
1230 0 : void Compositor::clearStencilBuffer( const ImageOp& op )
1231 : {
1232 0 : if( op.image->getContext().pixel == Pixel::ALL )
1233 0 : return;
1234 :
1235 0 : EQ_GL_CALL( glPixelZoom( 1.f, 1.f ));
1236 0 : EQ_GL_CALL( glDisable( GL_STENCIL_TEST ));
1237 : }
1238 :
1239 0 : void Compositor::assembleImage2D( const ImageOp& op, Channel* channel )
1240 : {
1241 0 : if( GLEW_VERSION_3_3 )
1242 0 : _drawPixelsGLSL( op, Frame::BUFFER_COLOR, channel );
1243 : else
1244 0 : _drawPixelsFF( op, Frame::BUFFER_COLOR, channel );
1245 0 : declareRegion( op, channel );
1246 : #if 0
1247 : static lunchbox::a_int32_t counter;
1248 : std::ostringstream stringstream;
1249 : stringstream << "Image_" << ++counter;
1250 : op.image->writeImages( stringstream.str( ));
1251 : #endif
1252 0 : }
1253 :
1254 0 : void Compositor::assembleImageDB( const ImageOp& op, Channel* channel )
1255 : {
1256 0 : if( GLEW_VERSION_3_3 )
1257 0 : assembleImageDB_GLSL( op, channel );
1258 : else
1259 0 : assembleImageDB_FF( op, channel );
1260 0 : }
1261 :
1262 0 : void Compositor::assembleImageDB_FF( const ImageOp& op, Channel* channel )
1263 : {
1264 0 : const PixelViewport& pvp = op.image->getPixelViewport();
1265 0 : LBLOG( LOG_ASSEMBLY ) << "assembleImageDB_FF " << pvp << std::endl;
1266 :
1267 : // Z-Based sort-last assembly
1268 0 : EQ_GL_CALL( glRasterPos2i( op.offset.x() + pvp.x, op.offset.y() + pvp.y ));
1269 0 : EQ_GL_CALL( glEnable( GL_STENCIL_TEST ));
1270 :
1271 : // test who is in front and mark in stencil buffer
1272 0 : EQ_GL_CALL( glEnable( GL_DEPTH_TEST ));
1273 :
1274 0 : const bool pixelComposite = ( op.image->getContext().pixel != Pixel::ALL );
1275 0 : if( pixelComposite )
1276 : { // keep already marked stencil values
1277 0 : EQ_GL_CALL( glStencilFunc( GL_EQUAL, 1, 1 ));
1278 0 : EQ_GL_CALL( glStencilOp( GL_KEEP, GL_ZERO, GL_REPLACE ));
1279 : }
1280 : else
1281 : {
1282 0 : EQ_GL_CALL( glStencilFunc( GL_ALWAYS, 1, 1 ));
1283 0 : EQ_GL_CALL( glStencilOp( GL_ZERO, GL_ZERO, GL_REPLACE ));
1284 : }
1285 :
1286 0 : _drawPixelsFF( op, Frame::BUFFER_DEPTH, channel );
1287 :
1288 0 : EQ_GL_CALL( glDisable( GL_DEPTH_TEST ));
1289 :
1290 : // draw front-most, visible pixels using stencil mask
1291 0 : EQ_GL_CALL( glStencilFunc( GL_EQUAL, 1, 1 ));
1292 0 : EQ_GL_CALL( glStencilOp( GL_KEEP, GL_ZERO, GL_ZERO ));
1293 :
1294 0 : _drawPixelsFF( op, Frame::BUFFER_COLOR, channel );
1295 :
1296 0 : EQ_GL_CALL( glDisable( GL_STENCIL_TEST ));
1297 0 : declareRegion( op, channel );
1298 0 : }
1299 :
1300 0 : void Compositor::assembleImageDB_GLSL( const ImageOp& op, Channel* channel )
1301 : {
1302 0 : const PixelViewport& pvp = op.image->getPixelViewport();
1303 0 : LBLOG( LOG_ASSEMBLY ) << "assembleImageDB_GLSL " << pvp << std::endl;
1304 :
1305 0 : util::ObjectManager& om = channel->getObjectManager();
1306 : const bool useImageTexture =
1307 0 : op.image->getStorageType() == Frame::TYPE_TEXTURE;
1308 :
1309 0 : const util::Texture* textureColor = 0;
1310 0 : const util::Texture* textureDepth = 0;
1311 0 : if ( useImageTexture )
1312 : {
1313 0 : textureColor = &op.image->getTexture( Frame::BUFFER_COLOR );
1314 0 : textureDepth = &op.image->getTexture( Frame::BUFFER_DEPTH );
1315 : }
1316 : else
1317 : {
1318 : util::Texture* ncTextureColor = om.obtainEqTexture( colorDBKey,
1319 0 : GL_TEXTURE_RECTANGLE_ARB );
1320 : util::Texture* ncTextureDepth = om.obtainEqTexture( depthDBKey,
1321 0 : GL_TEXTURE_RECTANGLE_ARB );
1322 0 : const Vector2i offset( -pvp.x, -pvp.y ); // will be applied with quad
1323 :
1324 0 : op.image->upload( Frame::BUFFER_COLOR, ncTextureColor, offset, om );
1325 0 : op.image->upload( Frame::BUFFER_DEPTH, ncTextureDepth, offset, om );
1326 :
1327 0 : textureColor = ncTextureColor;
1328 0 : textureDepth = ncTextureDepth;
1329 : }
1330 :
1331 0 : EQ_GL_CALL( glActiveTexture( GL_TEXTURE1 ));
1332 0 : textureDepth->bind();
1333 0 : textureDepth->applyZoomFilter( op.zoomFilter );
1334 :
1335 0 : EQ_GL_CALL( glActiveTexture( GL_TEXTURE0 ));
1336 0 : textureColor->bind();
1337 0 : textureColor->applyZoomFilter( op.zoomFilter );
1338 :
1339 0 : _drawTexturedQuad( shaderDBKey, op, pvp, true, channel );
1340 :
1341 0 : declareRegion( op, channel );
1342 0 : }
1343 :
1344 0 : void Compositor::declareRegion( const ImageOp& op, Channel* channel )
1345 : {
1346 0 : if( !channel )
1347 0 : return;
1348 :
1349 0 : const eq::PixelViewport area = op.image->getPixelViewport() + op.offset;
1350 0 : channel->declareRegion( area );
1351 : }
1352 :
1353 : #undef glewGetContext
1354 : #define glewGetContext() glCtx
1355 :
1356 0 : void Compositor::setupAssemblyState( const PixelViewport& pvp,
1357 : const GLEWContext* glCtx )
1358 : {
1359 0 : EQ_GL_ERROR( "before setupAssemblyState" );
1360 : glPushAttrib( GL_ENABLE_BIT | GL_STENCIL_BUFFER_BIT | GL_LINE_BIT |
1361 0 : GL_PIXEL_MODE_BIT | GL_POLYGON_BIT | GL_TEXTURE_BIT );
1362 :
1363 0 : glDisable( GL_DEPTH_TEST );
1364 0 : glDisable( GL_BLEND );
1365 0 : glDisable( GL_ALPHA_TEST );
1366 0 : glDisable( GL_STENCIL_TEST );
1367 0 : glDisable( GL_TEXTURE_1D );
1368 0 : glDisable( GL_TEXTURE_2D );
1369 0 : if( GLEW_VERSION_1_2 )
1370 0 : glDisable( GL_TEXTURE_3D );
1371 0 : glDisable( GL_FOG );
1372 0 : glDisable( GL_CLIP_PLANE0 );
1373 0 : glDisable( GL_CLIP_PLANE1 );
1374 0 : glDisable( GL_CLIP_PLANE2 );
1375 0 : glDisable( GL_CLIP_PLANE3 );
1376 0 : glDisable( GL_CLIP_PLANE4 );
1377 0 : glDisable( GL_CLIP_PLANE5 );
1378 :
1379 0 : glPolygonMode( GL_FRONT, GL_FILL );
1380 0 : if( GLEW_VERSION_1_3 )
1381 0 : glActiveTexture( GL_TEXTURE0 );
1382 :
1383 0 : glMatrixMode( GL_TEXTURE );
1384 0 : glPushMatrix();
1385 0 : glLoadIdentity();
1386 :
1387 0 : glMatrixMode( GL_PROJECTION );
1388 0 : glPushMatrix();
1389 0 : glLoadIdentity();
1390 0 : if( pvp.hasArea( ))
1391 0 : glOrtho( pvp.x, pvp.getXEnd(), pvp.y, pvp.getYEnd(), -1.0f, 1.0f );
1392 :
1393 0 : glMatrixMode( GL_MODELVIEW );
1394 0 : glPushMatrix();
1395 0 : glLoadIdentity();
1396 0 : EQ_GL_ERROR( "after setupAssemblyState" );
1397 0 : }
1398 :
1399 0 : void Compositor::resetAssemblyState()
1400 : {
1401 0 : EQ_GL_CALL( glMatrixMode( GL_TEXTURE ) );
1402 0 : EQ_GL_CALL( glPopMatrix() );
1403 0 : EQ_GL_CALL( glMatrixMode( GL_PROJECTION ) );
1404 0 : EQ_GL_CALL( glPopMatrix() );
1405 0 : EQ_GL_CALL( glMatrixMode( GL_MODELVIEW ));
1406 0 : EQ_GL_CALL( glPopMatrix());
1407 0 : EQ_GL_CALL( glPopAttrib());
1408 0 : }
1409 :
1410 42 : }
|