Remove RenderSurface from Core
[platform/core/uifw/dali-core.git] / dali / internal / update / manager / render-task-processor.cpp
index ec99e03..0fdc554 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -40,7 +40,6 @@ namespace Dali
 namespace Internal
 {
 
-
 namespace SceneGraph
 {
 
@@ -86,17 +85,19 @@ Layer* FindLayer( Node& node )
 /**
  * Rebuild the Layer::colorRenderables and overlayRenderables members,
  * including only renderers which are included in the current render-task.
- * Returns true if all renderers have finished acquiring resources.
  *
- * @param[in] updateBufferIndex The current update buffer index.
- * @param[in] node The current node of the scene-graph.
- * @param[in] currentLayer The current layer containing lists of opaque/transparent renderables.
- * @param[in] renderTask The current render-task.
- * @param[in] inheritedDrawMode The draw mode of the parent
- * @param[in] parentDepthIndex The inherited parent node depth index
- * @param[in] currentClippingId The current Clipping Id
- *              Note: ClippingId is passed by reference, so it is permanently modified when traversing back up the tree for uniqueness.
- * @param[in] clippingDepth The current clipping depth
+ * @param[in]  updateBufferIndex The current update buffer index.
+ * @param[in]  node The current node of the scene-graph.
+ * @param[in]  currentLayer The current layer containing lists of opaque/transparent renderables.
+ * @param[in]  renderTask The current render-task.
+ * @param[in]  inheritedDrawMode The draw mode of the parent
+ * @param[in]  parentDepthIndex The inherited parent node depth index
+ * @param[in]  currentClippingId The current Clipping Id
+ *               Note: ClippingId is passed by reference, so it is permanently modified when traversing back up the tree for uniqueness.
+ * @param[in]  clippingDepth The current stencil clipping depth
+ * @param[in]  clippingDepth The current scissor clipping depth
+ * @param[out] clippingUsed  Gets set to true if any clipping nodes have been found
+ * @return true if rendering should be kept, false otherwise.
  */
 bool AddRenderablesForTask( BufferIndex updateBufferIndex,
                             Node& node,
@@ -104,21 +105,23 @@ bool AddRenderablesForTask( BufferIndex updateBufferIndex,
                             RenderTask& renderTask,
                             int inheritedDrawMode,
                             uint32_t& currentClippingId,
-                            uint32_t clippingDepth )
+                            uint32_t clippingDepth,
+                            uint32_t scissorDepth,
+                            bool& clippingUsed )
 {
-  bool resourcesFinished = true;
+  bool keepRendering = false;
 
   // Short-circuit for invisible nodes
   if( !node.IsVisible( updateBufferIndex ) )
   {
-    return resourcesFinished;
+    return keepRendering;
   }
 
   // Check whether node is exclusive to a different render-task
   const RenderTask* exclusiveTo = node.GetExclusiveRenderTask();
   if( exclusiveTo && ( exclusiveTo != &renderTask ) )
   {
-    return resourcesFinished;
+    return keepRendering;
   }
 
   // Assume all children go to this layer (if this node is a layer).
@@ -137,38 +140,50 @@ bool AddRenderablesForTask( BufferIndex updateBufferIndex,
 
   DALI_ASSERT_DEBUG( NULL != layer );
 
+  const uint32_t count = node.GetRendererCount();
+
   // Update the clipping Id and depth for this node (if clipping is enabled).
-  if( DALI_UNLIKELY( node.GetClippingMode() != ClippingMode::DISABLED ) )
+  const Dali::ClippingMode::Type clippingMode = node.GetClippingMode();
+  if( DALI_UNLIKELY( clippingMode != ClippingMode::DISABLED ) )
   {
-    ++currentClippingId; // This modifies the reference passed in as well as the local value, causing the value to be global to the recursion.
-    ++clippingDepth;     // This only modifies the local value (which is passed in when the method recurses).
+    if( DALI_LIKELY( clippingMode == ClippingMode::CLIP_TO_BOUNDING_BOX ) )
+    {
+      ++scissorDepth;        // This only modifies the local value (which is passed in when the method recurses).
+      // If we do not have any renderers, create one to house the scissor operation.
+      if( count == 0u )
+      {
+        layer->colorRenderables.PushBack( Renderable( &node, nullptr ) );
+      }
+    }
+    else
+    {
+      // We only need clipping Id for stencil clips. This means we can deliberately avoid modifying it for bounding box clips,
+      // thus allowing bounding box clipping to still detect clip depth changes without turning on the stencil buffer for non-clipped nodes.
+      ++currentClippingId;   // This modifies the reference passed in as well as the local value, causing the value to be global to the recursion.
+      ++clippingDepth;       // This only modifies the local value (which is passed in when the method recurses).
+    }
+    clippingUsed = true;
   }
   // Set the information in the node.
-  node.SetClippingInformation( currentClippingId, clippingDepth );
+  node.SetClippingInformation( currentClippingId, clippingDepth, scissorDepth );
 
-  const unsigned int count = node.GetRendererCount();
-  for( unsigned int i = 0; i < count; ++i )
+  for( uint32_t i = 0; i < count; ++i )
   {
     SceneGraph::Renderer* renderer = node.GetRendererAt( i );
-    bool ready = false;
-    bool complete = false;
-    renderer->GetReadyAndComplete( ready, complete );
-
-    DALI_LOG_INFO( gRenderTaskLogFilter, Debug::General, "Testing renderable:%p ready:%s complete:%s\n", renderer, ready ? "T" : "F", complete ? "T" : "F" );
 
-    resourcesFinished &= complete;
+    // Normal is the more-likely draw mode to occur.
+    if( DALI_LIKELY( inheritedDrawMode == DrawMode::NORMAL ) )
+    {
+      layer->colorRenderables.PushBack( Renderable( &node, renderer ) );
+    }
+    else
+    {
+      layer->overlayRenderables.PushBack( Renderable( &node, renderer ) );
+    }
 
-    if( ready ) // IE. should be rendered (all resources are available)
+    if( renderer->GetRenderingBehavior() == DevelRenderer::Rendering::CONTINUOUSLY )
     {
-      // Normal is the more-likely draw mode to occur.
-      if( DALI_LIKELY( inheritedDrawMode == DrawMode::NORMAL ) )
-      {
-        layer->colorRenderables.PushBack( Renderable( &node, renderer ) );
-      }
-      else
-      {
-        layer->overlayRenderables.PushBack( Renderable( &node, renderer ) );
-      }
+      keepRendering = true;
     }
   }
 
@@ -178,59 +193,58 @@ bool AddRenderablesForTask( BufferIndex updateBufferIndex,
   for( NodeIter iter = children.Begin(); iter != endIter; ++iter )
   {
     Node& child = **iter;
-    bool childResourcesComplete = AddRenderablesForTask( updateBufferIndex, child, *layer, renderTask, inheritedDrawMode, currentClippingId, clippingDepth );
-    resourcesFinished &= childResourcesComplete;
+    keepRendering |= AddRenderablesForTask( updateBufferIndex, child, *layer, renderTask, inheritedDrawMode, currentClippingId, clippingDepth, scissorDepth, clippingUsed );
   }
 
-  return resourcesFinished;
-}
-
-} // Anonymous namespace.
-
-
-RenderTaskProcessor::RenderTaskProcessor()
-{
+  return keepRendering;
 }
 
-RenderTaskProcessor::~RenderTaskProcessor()
-{
-}
-
-void RenderTaskProcessor::Process( BufferIndex updateBufferIndex,
-                                   RenderTaskList& renderTasks,
-                                   Layer& rootNode,
-                                   SortedLayerPointers& sortedLayers,
-                                   GeometryBatcher& geometryBatcher,
-                                   RenderInstructionContainer& instructions )
+/**
+ * Process the list of render-tasks; the output is a series of render instructions.
+ * @note When ProcessRenderTasks is called, the layers should already the transparent/opaque renderers which are ready to render.
+ * If there is only one default render-task, then no further processing is required.
+ * @param[in]  updateBufferIndex          The current update buffer index.
+ * @param[in]  taskContainer              The container of render-tasks.
+ * @param[in]  rootNode                   The root node of the scene-graph.
+ * @param[in]  sortedLayers               The layers containing lists of opaque / transparent renderables.
+ * @param[in]  context                    The context holding the GL state of rendering for the rendering instructions.
+ * @param[out] instructions               The instructions for rendering the next frame.
+ * @param[in]  renderInstructionProcessor An instance of the RenderInstructionProcessor used to sort and handle the renderers for each layer.
+ * @param[in]  renderToFboEnabled         Whether rendering into the Frame Buffer Object is enabled (used to measure FPS above 60)
+ * @param[in]  isRenderingToFbo           Whether this frame is being rendered into the Frame Buffer Object (used to measure FPS above 60)
+ * @param[in]  processOffscreen           Whether the offscreen render tasks are the ones processed. Otherwise it processes the onscreen tasks.
+ * @return true if rendering should be kept, false otherwise.
+ */
+bool ProcessTasks( BufferIndex updateBufferIndex,
+                   RenderTaskList::RenderTaskContainer& taskContainer,
+                   Layer& rootNode,
+                   SortedLayerPointers& sortedLayers,
+                   Context& context,
+                   RenderInstructionContainer& instructions,
+                   RenderInstructionProcessor& renderInstructionProcessor,
+                   bool renderToFboEnabled,
+                   bool isRenderingToFbo,
+                   bool processOffscreen )
 {
-  RenderTaskList::RenderTaskContainer& taskContainer = renderTasks.GetTasks();
-
-  if( taskContainer.IsEmpty() )
-  {
-    // Early-exit if there are no tasks to process
-    return;
-  }
-
-  // For each render-task:
-  //   1) Prepare the render-task
-  //   2) Clear the layer-stored lists of renderers (TODO check if the layer is not changed and don't clear in this case)
-  //   3) Traverse the scene-graph, filling the lists for the current render-task
-  //   4) Prepare render-instructions
-
-  DALI_LOG_INFO( gRenderTaskLogFilter, Debug::General, "RenderTaskProcessor::Process() Offscreens first\n" );
-
-  // First process off screen render tasks - we may need the results of these for the on screen renders
   uint32_t clippingId = 0u;
   bool hasClippingNodes = false;
 
-  RenderTaskList::RenderTaskContainer::ConstIterator endIter = taskContainer.End();
-  for( RenderTaskList::RenderTaskContainer::Iterator iter = taskContainer.Begin(); endIter != iter; ++iter )
+  bool isFirstRenderTask = true;
+  bool keepRendering = false;
+  for( RenderTaskList::RenderTaskContainer::Iterator iter = taskContainer.Begin(), endIter = taskContainer.End(); endIter != iter; ++iter )
   {
     RenderTask& renderTask = **iter;
 
-    // Off screen only.
-    if( ( ( 0 == renderTask.GetFrameBufferId() ) && ( renderTask.GetFrameBuffer() == 0 ) ) ||
-        ( !renderTask.ReadyToRender( updateBufferIndex ) ) )
+    const bool hasFrameBuffer = NULL != renderTask.GetFrameBuffer();
+    const bool isDefaultRenderTask = isFirstRenderTask;
+    isFirstRenderTask = false;
+
+    if( ( !renderToFboEnabled && ( ( !processOffscreen && hasFrameBuffer ) ||
+                                   ( processOffscreen && !hasFrameBuffer ) ) ) ||
+        ( renderToFboEnabled && ( ( processOffscreen && !hasFrameBuffer ) ||
+                                  ( isDefaultRenderTask && processOffscreen ) ||
+                                  ( !isDefaultRenderTask && !processOffscreen && hasFrameBuffer ) ) ) ||
+        !renderTask.ReadyToRender( updateBufferIndex ) )
     {
       // Skip to next task.
       continue;
@@ -240,7 +254,7 @@ void RenderTaskProcessor::Process( BufferIndex updateBufferIndex,
     DALI_ASSERT_DEBUG( NULL != sourceNode ); // Otherwise Prepare() should return false
 
     // Check that the source node is not exclusive to another task.
-    if( ! CheckExclusivity( *sourceNode, renderTask ) )
+    if( !CheckExclusivity( *sourceNode, renderTask ) )
     {
       continue;
     }
@@ -252,110 +266,117 @@ void RenderTaskProcessor::Process( BufferIndex updateBufferIndex,
       continue;
     }
 
-    bool resourcesFinished = false;
+    const uint32_t currentNumberOfInstructions = instructions.Count( updateBufferIndex );
+
     if( renderTask.IsRenderRequired() )
     {
-      size_t layerCount( sortedLayers.size() );
-      for( size_t i(0); i<layerCount; ++i )
+      for( auto&& sortedLayer : sortedLayers )
       {
-        sortedLayers[i]->ClearRenderables();
+        sortedLayer->ClearRenderables();
       }
 
-      resourcesFinished = AddRenderablesForTask( updateBufferIndex,
-                                                 *sourceNode,
-                                                 *layer,
-                                                 renderTask,
-                                                 sourceNode->GetDrawMode(),
-                                                 clippingId,
-                                                 0u );
-
-      renderTask.SetResourcesFinished( resourcesFinished );
-
-      // If the clipping Id is still 0 after adding all Renderables, there is no clipping required for this RenderTaskList.
-      hasClippingNodes = clippingId != 0u;
-
-      mRenderInstructionProcessor.Prepare( updateBufferIndex,
-                                  sortedLayers,
-                                  renderTask,
-                                  renderTask.GetCullMode(),
-                                  geometryBatcher,
-                                  hasClippingNodes,
-                                  instructions );
+      keepRendering |= AddRenderablesForTask( updateBufferIndex,
+                                              *sourceNode,
+                                              *layer,
+                                              renderTask,
+                                              sourceNode->GetDrawMode(),
+                                              clippingId,
+                                              0u,
+                                              0u,
+                                              hasClippingNodes );
+
+      renderInstructionProcessor.Prepare( updateBufferIndex,
+                                          sortedLayers,
+                                          context,
+                                          renderTask,
+                                          renderTask.GetCullMode(),
+                                          hasClippingNodes,
+                                          instructions );
     }
-    else
+
+    if( !processOffscreen && isDefaultRenderTask && renderToFboEnabled && !isRenderingToFbo && hasFrameBuffer )
     {
-      renderTask.SetResourcesFinished( resourcesFinished );
+      // Traverse the instructions of the default render task and mark them to be rendered into the frame buffer.
+      const uint32_t count = instructions.Count( updateBufferIndex );
+      for( uint32_t index = currentNumberOfInstructions; index < count; ++index )
+      {
+        RenderInstruction& instruction = instructions.At( updateBufferIndex, index );
+        instruction.mIgnoreRenderToFbo = true;
+      }
     }
   }
 
-  DALI_LOG_INFO( gRenderTaskLogFilter, Debug::General, "RenderTaskProcessor::Process() Onscreen\n" );
+  return keepRendering;
+}
 
-  // Now that the off screen renders are done we can process on screen render tasks.
-  // Reset the clipping Id for the OnScreen render tasks.
-  clippingId = 0u;
-  for ( RenderTaskList::RenderTaskContainer::Iterator iter = taskContainer.Begin(); endIter != iter; ++iter )
+} // Anonymous namespace.
+
+RenderTaskProcessor::RenderTaskProcessor()
+{
+}
+
+RenderTaskProcessor::~RenderTaskProcessor()
+{
+}
+
+bool RenderTaskProcessor::Process( BufferIndex updateBufferIndex,
+                                   RenderTaskList& renderTasks,
+                                   Layer& rootNode,
+                                   SortedLayerPointers& sortedLayers,
+                                   Context& context,
+                                   RenderInstructionContainer& instructions,
+                                   bool renderToFboEnabled,
+                                   bool isRenderingToFbo )
+{
+  RenderTaskList::RenderTaskContainer& taskContainer = renderTasks.GetTasks();
+  bool keepRendering = false;
+
+  if( taskContainer.IsEmpty() )
   {
-    RenderTask& renderTask = **iter;
+    // Early-exit if there are no tasks to process
+    return keepRendering;
+  }
 
-    // On screen only.
-    if( ( 0 != renderTask.GetFrameBufferId() ) ||
-        ( renderTask.GetFrameBuffer() != 0 )   ||
-        ( !renderTask.ReadyToRender( updateBufferIndex ) ) )
-    {
-      // Skip to next task.
-      continue;
-    }
+  // For each render-task:
+  //   1) Prepare the render-task
+  //   2) Clear the layer-stored lists of renderers (TODO check if the layer is not changed and don't clear in this case)
+  //   3) Traverse the scene-graph, filling the lists for the current render-task
+  //   4) Prepare render-instructions
 
-    Node* sourceNode = renderTask.GetSourceNode();
-    DALI_ASSERT_DEBUG( NULL != sourceNode ); // Otherwise Prepare() should return false.
+  DALI_LOG_INFO( gRenderTaskLogFilter, Debug::General, "RenderTaskProcessor::Process() Offscreens first\n" );
 
-    // Check that the source node is not exclusive to another task.
-    if( ! CheckExclusivity( *sourceNode, renderTask ) )
-    {
-      continue;
-    }
+  // First process off screen render tasks - we may need the results of these for the on screen renders
 
-    Layer* layer = FindLayer( *sourceNode );
-    if( !layer )
-    {
-      // Skip to next task as no layer.
-      continue;
-    }
+  keepRendering = ProcessTasks( updateBufferIndex,
+                                taskContainer,
+                                rootNode,
+                                sortedLayers,
+                                context,
+                                instructions,
+                                mRenderInstructionProcessor,
+                                renderToFboEnabled,
+                                isRenderingToFbo,
+                                true );
 
-    bool resourcesFinished = false;
-    if( renderTask.IsRenderRequired() )
-    {
-      size_t layerCount( sortedLayers.size() );
-      for( size_t i(0); i < layerCount; ++i )
-      {
-        sortedLayers[i]->ClearRenderables();
-      }
+  DALI_LOG_INFO( gRenderTaskLogFilter, Debug::General, "RenderTaskProcessor::Process() Onscreen\n" );
 
-      resourcesFinished = AddRenderablesForTask( updateBufferIndex,
-                                                 *sourceNode,
-                                                 *layer,
-                                                 renderTask,
-                                                 sourceNode->GetDrawMode(),
-                                                 clippingId,
-                                                 0u );
-
-      // If the clipping Id is still 0 after adding all Renderables, there is no clipping required for this RenderTaskList.
-      hasClippingNodes = clippingId != 0;
-
-      mRenderInstructionProcessor.Prepare( updateBufferIndex,
-                                  sortedLayers,
-                                  renderTask,
-                                  renderTask.GetCullMode(),
-                                  geometryBatcher,
-                                  hasClippingNodes,
-                                  instructions );
-    }
+  // Now that the off screen renders are done we can process on screen render tasks.
+  // Reset the clipping Id for the OnScreen render tasks.
 
-    renderTask.SetResourcesFinished( resourcesFinished );
-  }
+  keepRendering |= ProcessTasks( updateBufferIndex,
+                                 taskContainer,
+                                 rootNode,
+                                 sortedLayers,
+                                 context,
+                                 instructions,
+                                 mRenderInstructionProcessor,
+                                 renderToFboEnabled,
+                                 isRenderingToFbo,
+                                 false );
+
+  return keepRendering;
 }
 
-
 } // SceneGraph
 
 } // Internal