bool Node::_cmdFrameDataTransmit( co::ICommand& cmd ) { co::ObjectICommand command( cmd ); const co::ObjectVersion frameDataVersion = command.get< co::ObjectVersion >(); const PixelViewport pvp = command.get< PixelViewport >(); const Zoom zoom = command.get< Zoom >(); const uint32_t buffers = command.get< uint32_t >(); const uint32_t frameNumber = command.get< uint32_t >(); const bool useAlpha = command.get< bool >(); const uint8_t* data = reinterpret_cast< const uint8_t* >( command.getRemainingBuffer( command.getRemainingBufferSize( ))); LBLOG( LOG_ASSEMBLY ) << "received image data for " << frameDataVersion << ", buffers " << buffers << " pvp " << pvp << std::endl; LBASSERT( pvp.isValid( )); FrameDataPtr frameData = getFrameData( frameDataVersion ); LBASSERT( !frameData->isReady() ); NodeStatistics event( Statistic::NODE_FRAME_DECOMPRESS, this, frameNumber ); // Note on the const_cast: since the PixelData structure stores non-const // pointers, we have to go non-const at some point, even though we do not // modify the data. LBCHECK( frameData->addImage( frameDataVersion, pvp, zoom, buffers, useAlpha, const_cast< uint8_t* >( data ))); return true; }
void Viewport::applyView( const Viewport& segmentVP, const Viewport& viewVP, const PixelViewport& pvp, const Vector4i& overdraw ) { // part of view covered by segment/view channel Viewport contribution( segmentVP ); contribution.intersect( viewVP ); contribution.transform( viewVP ); // extend by overdraw percentage EQASSERT( pvp.hasArea( )); const float xDelta(( static_cast< float >( overdraw.x() + pvp.w ) / static_cast< float >( pvp.w ) - 1.0f ) * contribution.w ); contribution.x -= xDelta; contribution.w += (( static_cast< float >( overdraw.z() + pvp.w ) / static_cast< float >( pvp.w ) - 1.0f ) * contribution.w ); contribution.w += xDelta; const float yDelta(( static_cast< float >( overdraw.y() + pvp.h ) / static_cast< float >( pvp.h ) - 1.0f ) * contribution.h ); contribution.y -= yDelta; contribution.h += (( static_cast< float >( overdraw.w() + pvp.h ) / static_cast< float >( pvp.h ) - 1.0f ) * contribution.h ); contribution.h += yDelta; x = contribution.x + x * contribution.w; y = contribution.y + y * contribution.h; w *= contribution.w; h *= contribution.h; }
void ROIFinder::_updateSubArea( const uint8_t type ) { LBASSERT( type <= 16 ); if( type == 0 ) return; PixelViewport pvp; switch( type ) { case 1: pvp = PixelViewport( _dim.x1,_dim.y2,_dim.w1,_dim.h2 ); break; case 2: pvp = PixelViewport( _dim.x2,_dim.y3,_dim.w2,_dim.h3 ); break; case 3: pvp = PixelViewport( _dim.x3,_dim.y2,_dim.w3,_dim.h2 ); break; case 4: pvp = PixelViewport( _dim.x2,_dim.y1,_dim.w2,_dim.h1 ); break; case 5: pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w1,_dim.h4 ); break; case 6: pvp = PixelViewport( _dim.x1,_dim.y3,_dim.w4,_dim.h3 ); break; case 7: pvp = PixelViewport( _dim.x3,_dim.y2,_dim.w3,_dim.h5 ); break; case 8: pvp = PixelViewport( _dim.x2,_dim.y1,_dim.w5,_dim.h1 ); break; case 9: pvp = PixelViewport( _dim.x1,_dim.y2,_dim.w1,_dim.h5 ); break; case 10: pvp = PixelViewport( _dim.x2,_dim.y3,_dim.w5,_dim.h3 ); break; case 11: pvp = PixelViewport( _dim.x3,_dim.y1,_dim.w3,_dim.h4 ); break; case 12: pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w4,_dim.h1 ); break; case 13: pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w1,_dim.h6 ); break; case 14: pvp = PixelViewport( _dim.x3,_dim.y1,_dim.w3,_dim.h6 ); break; case 15: pvp = PixelViewport( _dim.x1,_dim.y3,_dim.w6,_dim.h3 ); break; case 16: pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w6,_dim.h1 ); break; default: LBUNIMPLEMENTED; } LBASSERT( pvp.hasArea( )); LBASSERT( pvp.x >=0 && pvp.y >=0 && pvp.x+pvp.w <=_w && pvp.y+pvp.h <=_h ); Area& a = _tmpAreas[type]; a.pvp = _getObjectPVP( pvp, &_mask[0] ); a.hole = _emptyFinder.getLargestEmptyArea( a.pvp ); a.emptySize = pvp.getArea() - a.pvp.getArea() + a.hole.getArea(); #ifndef NDEBUG LBASSERT( !a.valid ); a.valid = true; #endif }
void CompoundUpdateOutputVisitor::_generateTiles( TileQueue* queue, Compound* compound ) { const Vector2i& tileSize = queue->getTileSize(); const PixelViewport pvp = compound->getInheritPixelViewport(); if( !pvp.hasArea( )) return; const Vector2i dim( pvp.w / tileSize.x() + ((pvp.w%tileSize.x()) ? 1 : 0), pvp.h / tileSize.y() + ((pvp.h%tileSize.y()) ? 1 : 0)); std::vector< Vector2i > tiles; tiles.reserve( dim.x() * dim.y() ); tiles::TILE_STRATEGY strategy; strategy( tiles, dim ); _addTilesToQueue( queue, compound, tiles ); }
void LoadEqualizer::_update( Node* node, const Viewport& vp, const Range& range ) { if( !node ) return; node->mode = getMode(); if( node->mode == MODE_2D ) { PixelViewport pvp = getCompound()->getChannel()->getPixelViewport(); pvp.apply( vp ); if( pvp.w > pvp.h ) // split along longest axis node->mode = MODE_VERTICAL; else node->mode = MODE_HORIZONTAL; } if( node->compound ) _updateLeaf( node ); else _updateNode( node, vp, range ); }
void Pipe::_setCGDisplayID( CGDirectDisplayID id ) { if( _cgDisplayID == id ) return; _cgDisplayID = id; PixelViewport pvp = getPipe()->getPixelViewport(); if( pvp.isValid( )) return; if( id ) { const CGRect displayRect = CGDisplayBounds( id ); pvp.x = int32_t(displayRect.origin.x); pvp.y = int32_t(displayRect.origin.y); pvp.w = int32_t(displayRect.size.width); pvp.h = int32_t(displayRect.size.height); } else pvp.invalidate(); getPipe()->setPixelViewport( pvp ); }
void ROIFinder::_readbackInfo( util::ObjectManager& glObjects ) { LBASSERT( glObjects.supportsEqTexture( )); LBASSERT( glObjects.supportsEqFrameBufferObject( )); PixelViewport pvp = _pvp; pvp.apply( Zoom( GRID_SIZE, GRID_SIZE )); pvp.w = LB_MIN( pvp.w+pvp.x, _pvpOriginal.w+_pvpOriginal.x ) - pvp.x; pvp.h = LB_MIN( pvp.h+pvp.y, _pvpOriginal.h+_pvpOriginal.y ) - pvp.y; LBASSERT( pvp.isValid()); // copy frame buffer to texture const void* bufferKey = _getInfoKey( ); util::Texture* texture = glObjects.obtainEqTexture( bufferKey, GL_TEXTURE_RECTANGLE_ARB ); #ifdef EQ_ROI_USE_DEPTH_TEXTURE texture->copyFromFrameBuffer( GL_DEPTH_COMPONENT, pvp ); #else texture->copyFromFrameBuffer( GL_RGBA, pvp ); #endif // draw zoomed quad into FBO const void* fboKey = _getInfoKey( ); util::FrameBufferObject* fbo = glObjects.getEqFrameBufferObject( fboKey ); if( fbo ) { LBCHECK( fbo->resize( _pvp.w, _pvp.h )); } else { fbo = glObjects.newEqFrameBufferObject( fboKey ); LBCHECK( fbo->init( _pvp.w, _pvp.h, GL_RGBA32F, 0, 0 )); } fbo->bind(); texture->bind(); // Enable & download depth texture glEnable( GL_TEXTURE_RECTANGLE_ARB ); texture->applyWrap(); texture->applyZoomFilter( FILTER_LINEAR ); // Enable shaders GLuint program = glObjects.getProgram( shaderRBInfo ); if( program == util::ObjectManager::INVALID ) { // Create fragment shader which reads depth values from // rectangular textures const GLuint shader = glObjects.newShader( shaderRBInfo, GL_FRAGMENT_SHADER ); LBASSERT( shader != util::ObjectManager::INVALID ); #ifdef EQ_ROI_USE_DEPTH_TEXTURE const GLchar* fShaderPtr = roiFragmentShader_glsl.c_str(); #else const GLchar* fShaderPtr = roiFragmentShaderRGB_glsl.c_str(); #endif EQ_GL_CALL( glShaderSource( shader, 1, &fShaderPtr, 0 )); EQ_GL_CALL( glCompileShader( shader )); GLint status; glGetShaderiv( shader, GL_COMPILE_STATUS, &status ); if( !status ) LBERROR << "Failed to compile fragment shader for ROI finder" << std::endl; program = glObjects.newProgram( shaderRBInfo ); EQ_GL_CALL( glAttachShader( program, shader )); EQ_GL_CALL( glLinkProgram( program )); glGetProgramiv( program, GL_LINK_STATUS, &status ); if( !status ) { LBWARN << "Failed to link shader program for ROI finder" << std::endl; return; } // use fragment shader and setup uniforms EQ_GL_CALL( glUseProgram( program )); GLint param = glGetUniformLocation( program, "texture" ); glUniform1i( param, 0 ); } else { // use fragment shader EQ_GL_CALL( glUseProgram( program )); } // Draw Quad glDisable( GL_LIGHTING ); glColor3f( 1.0f, 1.0f, 1.0f ); glBegin( GL_QUADS ); glVertex3i( 0, 0, 0 ); glVertex3i( _pvp.w, 0, 0 ); glVertex3i( _pvp.w, _pvp.h, 0 ); glVertex3i( 0, _pvp.h, 0 ); glEnd(); // restore state glDisable( GL_TEXTURE_RECTANGLE_ARB ); EQ_GL_CALL( glUseProgram( 0 )); fbo->unbind(); // finish readback of info LBASSERT( static_cast<int32_t>(_perBlockInfo.size()) >= _pvp.w*_pvp.h*4 ); texture = fbo->getColorTextures()[0]; LBASSERT( texture->getFormat() == GL_RGBA ); LBASSERT( texture->getType() == GL_FLOAT ); texture->download( &_perBlockInfo[0] ); }
Images FrameData::startReadback( const Frame& frame, util::ObjectManager& glObjects, const DrawableConfig& config, const PixelViewports& regions ) { if( _impl->data.buffers == Frame::BUFFER_NONE ) return Images(); const Zoom& zoom = frame.getZoom(); if( !zoom.isValid( )) { LBWARN << "Invalid zoom factor, skipping frame" << std::endl; return Images(); } const eq::PixelViewport& framePVP = getPixelViewport(); const PixelViewport absPVP = framePVP + frame.getOffset(); if( !absPVP.isValid( )) return Images(); Images images; // readback the whole screen when using textures if( getType() == eq::Frame::TYPE_TEXTURE ) { Image* image = newImage( getType(), config ); if( image->startReadback( getBuffers(), absPVP, zoom, glObjects )) images.push_back( image ); image->setOffset( 0, 0 ); return images; } //else read only required regions #if 0 // TODO: issue #85: move automatic ROI detection to eq::Channel PixelViewports regions; if( _impl->data.buffers & Frame::BUFFER_DEPTH && zoom == Zoom::NONE ) regions = _impl->roiFinder->findRegions( _impl->data.buffers, absPVP, zoom, frame.getAssemblyStage(), frame.getFrameID(), glObjects); else regions.push_back( absPVP ); #endif LBASSERT( getType() == eq::Frame::TYPE_MEMORY ); const eq::Pixel& pixel = getPixel(); for( uint32_t i = 0; i < regions.size(); ++i ) { PixelViewport pvp = regions[ i ] + frame.getOffset(); pvp.intersect( absPVP ); if( !pvp.hasArea( )) continue; Image* image = newImage( getType(), config ); if( image->startReadback( getBuffers(), pvp, zoom, glObjects )) images.push_back( image ); pvp -= frame.getOffset(); pvp.apply( zoom ); image->setOffset( (pvp.x - framePVP.x) * pixel.w, (pvp.y - framePVP.y) * pixel.h ); } return images; }
bool ROITracker::useROIFinder( const PixelViewport& pvp, const uint32_t stage, const uint128_t& frameID, uint8_t*& ticket ) { LBASSERT( !_needsUpdate ); ticket = 0; const uint32_t pvpArea = pvp.getArea(); if( pvpArea < 100 ) return false; if( _lastFrameID != frameID ) // new frame { stde::hash_map< uint32_t, Stage >* tmp = _prvFrame; _prvFrame = _curFrame; _curFrame = tmp; _curFrame->clear(); _lastFrameID = frameID; } _lastStage = stage; Stage& curStage = (*_curFrame)[ stage ]; // check if proper stage is avaliable if( _prvFrame->find( stage ) == _prvFrame->end( )) // new stage { curStage.areas.push_back( Area( pvp )); return _returnPositive( ticket ); } //else existing stage, try to find matching area const Area* match = 0; uint32_t bestArea = 0; const Stage& prvStage = (*_prvFrame)[ stage ]; for( uint32_t i = 0; i < prvStage.areas.size(); i++ ) { PixelViewport tmp = prvStage.areas[i].pvp; tmp.intersect( pvp ); const uint32_t area = tmp.getArea(); if( area > bestArea ) { bestArea = area; match = &prvStage.areas[i]; if( area == pvpArea ) // full match break; } } if( bestArea < pvpArea*2/3 ) // no proper match found, new area { curStage.areas.push_back( Area( pvp )); return _returnPositive( ticket ); } // else good match if( match->skip == 0 ) // don't skip frame { curStage.areas.push_back( Area( pvp, match->lastSkip )); return _returnPositive( ticket ); } //else skip frame curStage.areas.push_back( Area( pvp, match->lastSkip, match->skip-1 )); return false; }
void Config::activateCanvas( Canvas* canvas ) { LBASSERT( canvas->isStopped( )); LBASSERT( lunchbox::find( getCanvases(), canvas ) != getCanvases().end( )); const Layouts& layouts = canvas->getLayouts(); const Segments& segments = canvas->getSegments(); for( Layouts::const_iterator i = layouts.begin(); i != layouts.end(); ++i ) { const Layout* layout = *i; if( !layout ) continue; const Views& views = layout->getViews(); for( Views::const_iterator j = views.begin(); j != views.end(); ++j ) { View* view = *j; for( Segments::const_iterator k = segments.begin(); k != segments.end(); ++k ) { Segment* segment = *k; Viewport viewport = segment->getViewport(); viewport.intersect( view->getViewport( )); if( !viewport.hasArea( )) { LBLOG( LOG_VIEW ) << "View " << view->getName() << view->getViewport() << " doesn't intersect " << segment->getName() << segment->getViewport() << std::endl; continue; } Channel* segmentChannel = segment->getChannel(); if( !segmentChannel ) { LBWARN << "Segment " << segment->getName() << " has no output channel" << std::endl; continue; } if ( findChannel( segment, view )) continue; // create and add new channel Channel* channel = new Channel( *segmentChannel ); channel->init(); // not in ctor, virtual method channel->setOutput( view, segment ); //----- compute channel viewport: // segment/view intersection in canvas space... Viewport contribution = viewport; // ... in segment space... contribution.transform( segment->getViewport( )); // segment output area if( segmentChannel->hasFixedViewport( )) { Viewport subViewport = segmentChannel->getViewport(); LBASSERT( subViewport.isValid( )); if( !subViewport.isValid( )) subViewport = eq::fabric::Viewport::FULL; // ...our part of it subViewport.apply( contribution ); channel->setViewport( subViewport ); LBLOG( LOG_VIEW ) << "View @" << (void*)view << ' ' << view->getViewport() << " intersects " << segment->getName() << segment->getViewport() << " at " << subViewport << " using channel @" << (void*)channel << std::endl; } else { PixelViewport pvp = segmentChannel->getPixelViewport(); LBASSERT( pvp.isValid( )); pvp.apply( contribution ); channel->setPixelViewport( pvp ); LBLOG( LOG_VIEW ) << "View @" << (void*)view << ' ' << view->getViewport() << " intersects " << segment->getName() << segment->getViewport() << " at " << pvp << " using channel @" << (void*)channel << std::endl; } if( channel->getWindow()->isAttached( )) // parent is already registered - register channel as well getServer()->registerObject( channel ); } } } }
//--------------------------------------------------------------------------- // WGL init //--------------------------------------------------------------------------- bool Pipe::configInit() { if ( !_configInitWGLEW() ) return false; PixelViewport pvp = getPipe()->getPixelViewport(); if( pvp.isValid( )) return true; // setup pvp // ...using gpu affinity API HGPUNV hGPU = 0; if( !_getGPUHandle( hGPU )) return false; if( hGPU != 0 ) { GPU_DEVICE gpuDevice; gpuDevice.cb = sizeof( gpuDevice ); const bool found = wglEnumGpuDevicesNV( hGPU, 0, &gpuDevice ); EQASSERT( found ); if( gpuDevice.Flags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP ) { const RECT& rect = gpuDevice.rcVirtualScreen; pvp.x = rect.left; pvp.y = rect.top; pvp.w = rect.right - rect.left; pvp.h = rect.bottom - rect.top; } else { pvp.x = 0; pvp.y = 0; pvp.w = 4096; pvp.h = 4096; } } else // ... using Win32 API { HDC dc = createWGLDisplayDC(); pvp.x = 0; pvp.y = 0; if( dc ) { pvp.w = GetDeviceCaps( dc, HORZRES ); pvp.h = GetDeviceCaps( dc, VERTRES ); DeleteDC( dc ); } else { EQWARN << "Can't create display dc query pipe resolution: " << co::base::sysError << std::endl; pvp.w = 2048; pvp.h = 2048; } } getPipe()->setPixelViewport( pvp ); EQINFO << "Pipe pixel viewport " << pvp << std::endl; return true; }