Пример #1
0
Natron::Status VideoEngine::renderFrame(SequenceTime time,bool singleThreaded) {
    /*pre process frame*/
    
//    Status stat = _tree.preProcessFrame();
//    if (stat == StatFailed) {
//        return stat;
//        //don't throw an exception here, this is regular behaviour when a mandatory input is not connected.
//        // We don't want to popup a dialog everytime it occurs
//        //      throw std::runtime_error("PreProcessFrame failed, mandatory inputs are probably not connected.");
//    }
    bool isSequentialRender = _currentRunArgs._frameRequestsCount > 1 || _currentRunArgs._frameRequestsCount == -1 ||
    _currentRunArgs._forceSequential;
    Status stat = StatOK;
    /*get the time at which we started rendering the frame*/
    gettimeofday(&_startRenderFrameTime, 0);
    if (_tree.isOutputAViewer() && !_tree.isOutputAnOpenFXNode()) {
        ViewerInstance* viewer = _tree.outputAsViewer();
        stat = viewer->renderViewer(time,singleThreaded,isSequentialRender);
        
        if (!_currentRunArgs._sameFrame) {
            QMutexLocker timerLocker(&_timerMutex);
            _timer->waitUntilNextFrameIsDue(); // timer synchronizing with the requested fps
            if ((_timerFrameCount % NATRON_FPS_REFRESH_RATE) == 0 && _currentRunArgs._frameRequestsCount == -1) {
                emit fpsChanged(_timer->actualFrameRate(),_timer->getDesiredFrameRate()); // refreshing fps display on the GUI
                _timerFrameCount = 1; //reseting to 1
            } else {
                ++_timerFrameCount;
            }
            
        }
        
        if (stat == StatFailed) {
            viewer->disconnectViewer();
        }
    
    } else {
        RenderScale scale;
        scale.x = scale.y = 1.;
        RectI rod;
        bool isProjectFormat;
        
        int viewsCount = _tree.getOutput()->getApp()->getProject()->getProjectViewsCount();
        int mainView = 0;
        if (isSequentialRender) {
            mainView = _tree.getOutput()->getApp()->getMainView();
        }
        
        for (int i = 0; i < viewsCount;++i) {
            
            if (isSequentialRender && i != mainView) {
                ///@see the warning in EffectInstance::evaluate
                continue;
            }
            // Do not catch exceptions: if an exception occurs here it is probably fatal, since
            // it comes from Natron itself. All exceptions from plugins are already caught
            // by the HostSupport library.
            stat = _tree.getOutput()->getRegionOfDefinition_public(time,scale,i, &rod,&isProjectFormat);
            if (stat != StatFailed) {
                ImageComponents components;
                ImageBitDepth imageDepth;
                _tree.getOutput()->getPreferredDepthAndComponents(-1, &components, &imageDepth);
                (void)_tree.getOutput()->renderRoI(EffectInstance::RenderRoIArgs(time, //< the time at which to render
                                                                                 scale, //< the scale at which to render
                                                                                 0, //< the mipmap level (redundant with the scale)
                                                                                 i , //< the view to render
                                                                                 rod, //< the region of interest (in pixel coordinates)
                                                                                 isSequentialRender, // is this sequential
                                                                                 false,  // is this render due to user interaction ?
                                                                                 false,//< bypass cache ?
                                                                                 &rod, // < any precomputed rod ?
                                                                                 components,
                                                                                 imageDepth));
            } else {
                break;
            }
        }
    }
//
//    if (stat == StatFailed) {
//        throw std::runtime_error("Render failed");
//    }
    return stat;

}
Пример #2
0
void VideoEngine::iterateKernel(bool singleThreaded) {
    for(;;){ // infinite loop
        
        {
            QMutexLocker locker(&_abortedRequestedMutex);
            if(_abortRequested > 0) {
                locker.unlock();
                return;
            }
        }
        
        Natron::OutputEffectInstance* output = dynamic_cast<Natron::OutputEffectInstance*>(_tree.getOutput());
        assert(output);
        ViewerInstance* viewer = dynamic_cast<ViewerInstance*>(output);
        
        /*update the tree inputs */
        _tree.refreshRenderInputs();
        
        
        if(viewer){
            if (singleThreaded || appPTR->isBackground()) {
                getFrameRange();
            } else {
                {
                    QMutexLocker l(&_abortedRequestedMutex);
                    if (_abortRequested > 0) {
                        return;
                    }
                }
                
                bool mustQuit;
                {
                    QMutexLocker l(&_mustQuitMutex);
                    mustQuit = _mustQuit;
                }
                
                QMutexLocker l(&_getFrameRangeMutex);
                _gettingFrameRange = true;
                emit mustGetFrameRange();
                while (_gettingFrameRange && !mustQuit) {
                    _getFrameRangeCond.wait(&_getFrameRangeMutex);
                }
                
            }
            
            //If the frame range is not locked, let the user define it.
            if (viewer->isFrameRangeLocked()) {
                _timeline->setFrameRange(_firstFrame, _lastFrame);
            }
        }
        
        int firstFrame,lastFrame;
        if (viewer) {
            firstFrame = _timeline->leftBound();
            lastFrame = _timeline->rightBound();
        } else {
            firstFrame = output->getFirstFrame();
            lastFrame = output->getLastFrame();
        }
        
        //////////////////////////////
        // Set the current frame
        //
        int currentFrame = 0;
        if (!_currentRunArgs._recursiveCall) {
            
            /*if writing on disk and not a recursive call, move back the timeline cursor to the start*/
            if (viewer) {
                currentFrame = _timeline->currentFrame();
            } else {
                output->setCurrentFrame(firstFrame);
                currentFrame = firstFrame;
            }
            
        } else if(!_currentRunArgs._sameFrame && _currentRunArgs._seekTimeline) {
            assert(_currentRunArgs._recursiveCall); // we're in the else part
            if (!viewer) {
                output->setCurrentFrame(output->getCurrentFrame()+1);
                currentFrame = output->getCurrentFrame();
                if(currentFrame > lastFrame){
                    return;
                }
            } else {
                // viewer
                assert(viewer);
                if (_currentRunArgs._forward) {
                    currentFrame = _timeline->currentFrame();
                    if (currentFrame < lastFrame) {
                        _timeline->incrementCurrentFrame(output);
                        ++currentFrame;
                    } else {
                        QMutexLocker loopModeLocker(&_loopModeMutex);
                        if (_loopMode) { // loop only for a viewer
                            currentFrame = firstFrame;
                            _timeline->seekFrame(currentFrame,output);
                        } else {
                            loopModeLocker.unlock();
                            return;
                        }
                    }
                    
                } else {
                    currentFrame = _timeline->currentFrame();
                    if (currentFrame > firstFrame) {
                        _timeline->decrementCurrentFrame(output);
                        --currentFrame;
                    } else {
                        QMutexLocker loopModeLocker(&_loopModeMutex);
                        if (_loopMode) { //loop only for a viewer
                            currentFrame = lastFrame;
                            _timeline->seekFrame(currentFrame,output);
                        } else {
                            loopModeLocker.unlock();
                            return;
                        }
                    }
                }
            }
        }
        
        ///////////////////////////////
        // Check whether we need to stop the engine or not for various reasons.
        //
        {
            QMutexLocker locker(&_abortedRequestedMutex);
            if(_abortRequested > 0 || // #1 aborted by the user
               
               (_tree.isOutputAViewer() // #2 the Tree contains only 1 frame and we rendered it
                &&  _currentRunArgs._recursiveCall
                &&  firstFrame == lastFrame
                && _currentRunArgs._frameRequestsCount == -1
                && _currentRunArgs._frameRequestIndex == 1)
               
               || _currentRunArgs._frameRequestsCount == 0// #3 the sequence ended and it was not an infinite run
               || (appPTR->getAppType() == AppManager::APP_BACKGROUND_AUTO_RUN && appPTR->hasAbortAnyProcessingBeenCalled()))
            {
                return;
            }
        }
        
        ///before rendering the frame, clear any persistent message that may be left
        _tree.clearPersistentMessages();
        
        ////////////////////////
        // Render currentFrame
        //
        // if the output is a writer, _tree.outputAsWriter() returns a valid pointer/
        Status stat;
        try {
            stat =  renderFrame(currentFrame,singleThreaded);
        } catch (const std::exception &e) {
            std::stringstream ss;
            ss << "Error while rendering" << " frame " << currentFrame << ": " << e.what();
            if (viewer) {
                //viewer->setPersistentMessage(Natron::ERROR_MESSAGE, ss.str());
                viewer->disconnectViewer();
            } else {
                std::cout << ss.str() << std::endl;
            }
            return;
            
        }
        
        if (stat == StatFailed) {
            return;
        }
        
        
        /*The frame has been rendered , we call engineLoop() which will reset all the flags,
         update viewers
         and appropriately increment counters for the next frame in the sequence.*/
        emit frameRendered(currentFrame);
        if(appPTR->isBackground()){
            QString frameStr = QString::number(currentFrame);
            appPTR->writeToOutputPipe(kFrameRenderedStringLong + frameStr,kFrameRenderedStringShort + frameStr);
        }
        
        if (singleThreaded) {
            QCoreApplication::processEvents();
            
            ///if single threaded: the user might have requested to exit and the engine might be deleted after the events process.
            if (_mustQuit) {
                return;
            }
        }
        
        if(_currentRunArgs._frameRequestIndex == 0 && _currentRunArgs._frameRequestsCount == 1 && !_currentRunArgs._sameFrame){
            _currentRunArgs._frameRequestsCount = 0;
        }else if(_currentRunArgs._frameRequestsCount!=-1){ // if the frameRequestCount is defined (i.e: not indefinitely running)
            --_currentRunArgs._frameRequestsCount;
        }
        ++_currentRunArgs._frameRequestIndex;//incrementing the frame counter
        
        _currentRunArgs._recursiveCall = true;
    } // end for(;;)
}