/*
- * 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.
namespace Internal
{
-
namespace SceneGraph
{
/**
* 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,
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).
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;
}
}
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;
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;
}
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