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