ActionRetCodeEnum
ViewerDisplayScheduler::createFrameRenderResultsGeneric(const ViewerNodePtr& viewer,
                                                        const TreeRenderQueueProviderPtr& provider,
                                                        TimeValue time,
                                                        bool isPlayback,
                                                        const RotoStrokeItemPtr& activeDrawingStroke,
                                                        const std::vector<ViewIdx>& viewsToRender,
                                                        bool enableRenderStats,
                                                        RenderFrameResultsContainerPtr* future)
{
    // A global statistics object for this frame render if requested
    RenderStatsPtr stats;
    if (enableRenderStats) {
        stats.reset( new RenderStats(enableRenderStats) );
    }


    // Get parameters from the viewport
    bool fullFrameProcessing = viewer->isFullFrameProcessingEnabled();
    bool draftModeEnabled = viewer->getApp()->isDraftRenderEnabled();
    unsigned int mipMapLevel = getViewerMipMapLevel(viewer, draftModeEnabled, fullFrameProcessing);
    bool byPassCache = viewer->isRenderWithoutCacheEnabledAndTurnOff();
    ViewerCompositingOperatorEnum viewerBlend = viewer->getCurrentOperator();
    bool viewerBEqualsViewerA = viewer->getCurrentAInput() == viewer->getCurrentBInput();

    // Create the global results object
    ViewerRenderFrameResultsContainerPtr results(new  ViewerRenderFrameResultsContainer(provider));
    *future = results;
    results->time = time;
    results->recenterViewer = viewer->getViewerCenterPoint(&results->viewerCenter);

    std::list<RectD> rois;
    if (!viewer->isDoingPartialUpdates()) {
        rois.push_back(RectD());
    } else {

        // If the viewer is doing partial updates (i.e: during tracking we only update the markers areas)
        // Then we launch multiple renders over the partial areas
        std::list<RectD> partialUpdates = viewer->getPartialUpdateRects();
        for (std::list<RectD>::const_iterator it = partialUpdates.begin(); it != partialUpdates.end(); ++it) {
            if (!it->isNull()) {
                rois.push_back(*it);
            }
        }
    }

    for (std::list<RectD>::const_iterator it = rois.begin(); it != rois.end(); ++it) {
        // Render all requested views
        for (std::size_t view_i = 0; view_i < viewsToRender.size(); ++view_i) {
            ActionRetCodeEnum stat = createFrameRenderResultsForView(viewer, provider, results, viewsToRender[view_i], stats, isPlayback, it->isNull() ? 0 : &(*it), mipMapLevel, viewerBlend, byPassCache, draftModeEnabled, fullFrameProcessing, viewerBEqualsViewerA, activeDrawingStroke);
            if (isFailureRetCode(stat)) {
                return stat;
            }
        } // for each view

    }
    return eActionStatusOK;
} // createFrameRenderResultsGeneric
void
ViewerDisplayScheduler::getFrameRangeToRender(TimeValue &first,
                                              TimeValue &last) const
{
    ViewerNodePtr isViewer = getOutputNode()->isEffectViewerNode();
    ViewerNodePtr leadViewer = isViewer->getApp()->getLastViewerUsingTimeline();
    ViewerNodePtr v = leadViewer ? leadViewer : isViewer;
    assert(v);
    int left, right;
    v->getTimelineBounds(&left, &right);
    first = TimeValue(left);
    last = TimeValue(right);
}