#include <dali/public-api/dali-core.h>
#include <dali/devel-api/images/texture-set-image.h>
+#include <dali/integration-api/system-overlay.h>
+#include <dali/integration-api/render-task-list-integ.h>
#include <cstdio>
#include <string>
DALI_PROPERTY( "stencilOperationOnZFail", INTEGER, true, false, false, Dali::Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL )
DALI_PROPERTY( "stencilOperationOnZPass", INTEGER, true, false, false, Dali::Renderer::Property::STENCIL_OPERATION_ON_Z_PASS )
DALI_PROPERTY( "opacity", FLOAT, true, true, true, Dali::DevelRenderer::Property::OPACITY )
+ DALI_PROPERTY( "renderingBehavior", INTEGER, true, false, false, Dali::DevelRenderer::Property::RENDERING_BEHAVIOR )
*/
Geometry geometry = CreateQuadGeometry();
Shader shader = CreateShader();
Renderer renderer = Renderer::New(geometry, shader);
- DALI_TEST_EQUALS( renderer.GetPropertyCount(), 25, TEST_LOCATION );
+ DALI_TEST_EQUALS( renderer.GetPropertyCount(), 26, TEST_LOCATION );
TEST_RENDERER_PROPERTY( renderer, "depthIndex", Property::INTEGER, true, false, false, Renderer::Property::DEPTH_INDEX, TEST_LOCATION );
TEST_RENDERER_PROPERTY( renderer, "faceCullingMode", Property::INTEGER, true, false, false, Renderer::Property::FACE_CULLING_MODE, TEST_LOCATION );
TEST_RENDERER_PROPERTY( renderer, "stencilOperationOnZFail", Property::INTEGER, true, false, false, Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL, TEST_LOCATION );
TEST_RENDERER_PROPERTY( renderer, "stencilOperationOnZPass", Property::INTEGER, true, false, false, Renderer::Property::STENCIL_OPERATION_ON_Z_PASS, TEST_LOCATION );
TEST_RENDERER_PROPERTY( renderer, "opacity", Property::FLOAT, true, true, true, DevelRenderer::Property::OPACITY, TEST_LOCATION );
+ TEST_RENDERER_PROPERTY( renderer, "renderingBehavior", Property::INTEGER, true, false, false, DevelRenderer::Property::RENDERING_BEHAVIOR, TEST_LOCATION );
END_TEST;
}
END_TEST;
}
+
+int UtcDaliRendererRenderingBehavior(void)
+{
+ TestApplication application;
+
+ tet_infoline( "Test RENDERING_BEHAVIOR property" );
+
+ Geometry geometry = CreateQuadGeometry();
+ Shader shader = Shader::New( "vertexSrc", "fragmentSrc" );
+ Renderer renderer = Renderer::New( geometry, shader );
+
+ Actor actor = Actor::New();
+ actor.AddRenderer( renderer );
+ actor.SetSize( 400, 400 );
+ actor.SetColor( Vector4( 1.0f, 0.0f, 1.0f, 1.0f ) );
+ Stage::GetCurrent().Add( actor );
+
+ Property::Value value = renderer.GetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR );
+ int renderingBehavior;
+ DALI_TEST_CHECK( value.Get( renderingBehavior ) );
+ DALI_TEST_EQUALS( static_cast< DevelRenderer::Rendering::Type >( renderingBehavior ), DevelRenderer::Rendering::IF_REQUIRED, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ uint32_t updateStatus = application.GetUpdateStatus();
+
+ DALI_TEST_CHECK( !( updateStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING ) );
+
+ renderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY );
+
+ value = renderer.GetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR );
+ DALI_TEST_CHECK( value.Get( renderingBehavior ) );
+ DALI_TEST_EQUALS( static_cast< DevelRenderer::Rendering::Type >( renderingBehavior ), DevelRenderer::Rendering::CONTINUOUSLY, TEST_LOCATION );
+
+ // Render and check the update status
+ application.SendNotification();
+ application.Render();
+
+ updateStatus = application.GetUpdateStatus();
+
+ DALI_TEST_CHECK( updateStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING );
+
+ value = renderer.GetCurrentProperty( DevelRenderer::Property::RENDERING_BEHAVIOR );
+ DALI_TEST_CHECK( value.Get( renderingBehavior ) );
+ DALI_TEST_EQUALS( static_cast< DevelRenderer::Rendering::Type >( renderingBehavior ), DevelRenderer::Rendering::CONTINUOUSLY, TEST_LOCATION );
+
+ // Render again and check the update status
+ application.SendNotification();
+ application.Render();
+
+ updateStatus = application.GetUpdateStatus();
+
+ DALI_TEST_CHECK( updateStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING );
+
+ // Change rendering behavior
+ renderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED );
+
+ // Render and check the update status
+ application.SendNotification();
+ application.Render();
+
+ updateStatus = application.GetUpdateStatus();
+
+ DALI_TEST_CHECK( !( updateStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING ) );
+
+ // For test coverage
+ Dali::Integration::Core& core( application.GetCore() );
+ Dali::Integration::SystemOverlay& systemOverlay( core.GetSystemOverlay() );
+
+ Dali::RenderTaskList additionalRenderTaskList = Integration::RenderTaskList::New();
+ Dali::Actor overlayRootActor = systemOverlay.GetDefaultRootActor();
+ Dali::CameraActor overlayCameraActor = systemOverlay.GetDefaultCameraActor();
+
+ // Render and check the update status
+ application.SendNotification();
+ application.Render();
+
+ END_TEST;
+}
* @details Name "opacity", type Property::FLOAT.
*/
OPACITY = STENCIL_OPERATION_ON_Z_PASS + 1,
+
+ /**
+ * @brief The rendering behavior of the renderer.
+ * @details Name "renderingBehavior", type Property::INTEGER.
+ */
+ RENDERING_BEHAVIOR = STENCIL_OPERATION_ON_Z_PASS + 2,
};
} // namespace Property
+namespace Rendering
+{
+
+/**
+ * @brief Enumeration for the rendering behavior
+ */
+enum Type
+{
+ IF_REQUIRED, ///< Default. Will only render if required to do so.
+ CONTINUOUSLY ///< Will render continuously.
+};
+
+} // namespace Rendering
+
} // namespace DevelRenderer
} // namespace Dali
// INTERNAL INCLUDES
#include <dali/public-api/rendering/renderer.h>
#include <dali/devel-api/common/stage-devel.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
#include <dali/internal/common/type-abstraction.h>
namespace Dali
namespace Internal
{
-template <> struct ParameterType< Dali::FaceCullingMode::Type > : public BasicType< Dali::FaceCullingMode::Type > {};
-template <> struct ParameterType< Dali::BlendMode::Type > : public BasicType< Dali::BlendMode::Type > {};
-template <> struct ParameterType< Dali::DepthWriteMode::Type > : public BasicType< Dali::DepthWriteMode::Type > {};
-template <> struct ParameterType< Dali::DepthTestMode::Type > : public BasicType< Dali::DepthTestMode::Type > {};
-template <> struct ParameterType< Dali::DepthFunction::Type > : public BasicType< Dali::DepthFunction::Type > {};
-template <> struct ParameterType< Dali::RenderMode::Type > : public BasicType< Dali::RenderMode::Type > {};
-template <> struct ParameterType< Dali::StencilFunction::Type > : public BasicType< Dali::StencilFunction::Type > {};
-template <> struct ParameterType< Dali::StencilOperation::Type > : public BasicType< Dali::StencilOperation::Type > {};
-template <> struct ParameterType< Dali::DevelStage::Rendering > : public BasicType< Dali::DevelStage::Rendering > {};
+template <> struct ParameterType< Dali::FaceCullingMode::Type > : public BasicType< Dali::FaceCullingMode::Type > {};
+template <> struct ParameterType< Dali::BlendMode::Type > : public BasicType< Dali::BlendMode::Type > {};
+template <> struct ParameterType< Dali::DepthWriteMode::Type > : public BasicType< Dali::DepthWriteMode::Type > {};
+template <> struct ParameterType< Dali::DepthTestMode::Type > : public BasicType< Dali::DepthTestMode::Type > {};
+template <> struct ParameterType< Dali::DepthFunction::Type > : public BasicType< Dali::DepthFunction::Type > {};
+template <> struct ParameterType< Dali::RenderMode::Type > : public BasicType< Dali::RenderMode::Type > {};
+template <> struct ParameterType< Dali::StencilFunction::Type > : public BasicType< Dali::StencilFunction::Type > {};
+template <> struct ParameterType< Dali::StencilOperation::Type > : public BasicType< Dali::StencilOperation::Type > {};
+template <> struct ParameterType< Dali::DevelStage::Rendering > : public BasicType< Dali::DevelStage::Rendering > {};
+template <> struct ParameterType< Dali::DevelRenderer::Rendering::Type > : public BasicType< Dali::DevelRenderer::Rendering::Type > {};
} //namespace Internal
// INTERNAL INCLUDES
#include <dali/devel-api/scripting/scripting.h>
-#include <dali/devel-api/rendering/renderer-devel.h>
#include <dali/public-api/object/type-registry.h>
#include <dali/internal/event/common/property-helper.h> // DALI_PROPERTY_TABLE_BEGIN, DALI_PROPERTY, DALI_PROPERTY_TABLE_END
#include <dali/internal/event/common/property-input-impl.h>
DALI_PROPERTY( "stencilOperationOnZFail", INTEGER, true, false, false, Dali::Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL )
DALI_PROPERTY( "stencilOperationOnZPass", INTEGER, true, false, false, Dali::Renderer::Property::STENCIL_OPERATION_ON_Z_PASS )
DALI_PROPERTY( "opacity", FLOAT, true, true, true, Dali::DevelRenderer::Property::OPACITY )
+DALI_PROPERTY( "renderingBehavior", INTEGER, true, false, false, Dali::DevelRenderer::Property::RENDERING_BEHAVIOR )
DALI_PROPERTY_TABLE_END( DEFAULT_RENDERER_PROPERTY_START_INDEX, RendererDefaultProperties )
// Property string to enumeration tables:
DALI_ENUM_TO_STRING_WITH_SCOPE( StencilOperation, DECREMENT_WRAP )
DALI_ENUM_TO_STRING_TABLE_END( STENCIL_OPERATION )
+DALI_ENUM_TO_STRING_TABLE_BEGIN( RENDERING_BEHAVIOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelRenderer::Rendering, IF_REQUIRED )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelRenderer::Rendering, CONTINUOUSLY )
+DALI_ENUM_TO_STRING_TABLE_END( RENDERING_BEHAVIOR )
+
BaseHandle Create()
{
return Dali::BaseHandle();
}
break;
}
+ case DevelRenderer::Property::RENDERING_BEHAVIOR:
+ {
+ DevelRenderer::Rendering::Type convertedValue = mRenderingBehavior;
+ if( Scripting::GetEnumerationProperty< DevelRenderer::Rendering::Type >( propertyValue, RENDERING_BEHAVIOR_TABLE, RENDERING_BEHAVIOR_TABLE_COUNT, convertedValue ) )
+ {
+ mRenderingBehavior = convertedValue;
+ SetRenderingBehaviorMessage( GetEventThreadServices(), GetRendererSceneObject(), convertedValue );
+ }
+ break;
+ }
}
}
mBlendMode( BlendMode::AUTO ),
mDepthWriteMode( DepthWriteMode::AUTO ),
mDepthTestMode( DepthTestMode::AUTO ),
+ mRenderingBehavior( DevelRenderer::Rendering::IF_REQUIRED ),
mPremultipledAlphaEnabled( false )
{
}
value = mOpacity;
break;
}
+ case Dali::DevelRenderer::Property::RENDERING_BEHAVIOR:
+ {
+ value = mRenderingBehavior;
+ break;
+ }
default:
{
// Must be a scene-graph only property
value = sceneObject.GetOpacity( GetEventThreadServices().GetEventBufferIndex() );
break;
}
+ case Dali::DevelRenderer::Property::RENDERING_BEHAVIOR:
+ {
+ value = sceneObject.GetRenderingBehavior();
+ break;
+ }
default:
{
// Must be an event-side only property
#include <dali/public-api/common/dali-common.h> // DALI_ASSERT_ALWAYS
#include <dali/public-api/common/intrusive-ptr.h> // Dali::IntrusivePtr
#include <dali/public-api/rendering/renderer.h> // Dali::Renderer
+#include <dali/devel-api/rendering/renderer-devel.h>
#include <dali/internal/common/blending-options.h>
#include <dali/internal/event/common/object-connector.h> // Dali::Internal::ObjectConnector
#include <dali/internal/event/common/object-impl.h> // Dali::Internal::Object
BlendMode::Type mBlendMode:3; ///< Local copy of the mode of blending
DepthWriteMode::Type mDepthWriteMode:3; ///< Local copy of the depth write mode
DepthTestMode::Type mDepthTestMode:3; ///< Local copy of the depth test mode
+ DevelRenderer::Rendering::Type mRenderingBehavior:2; ///< The rendering behavior
bool mPremultipledAlphaEnabled:1; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required
};
* @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.
*/
-void AddRenderablesForTask( BufferIndex updateBufferIndex,
+bool AddRenderablesForTask( BufferIndex updateBufferIndex,
Node& node,
Layer& currentLayer,
RenderTask& renderTask,
uint32_t scissorDepth,
bool& clippingUsed )
{
+ bool keepRendering = false;
+
// Short-circuit for invisible nodes
if( !node.IsVisible( updateBufferIndex ) )
{
- return;
+ return keepRendering;
}
// Check whether node is exclusive to a different render-task
const RenderTask* exclusiveTo = node.GetExclusiveRenderTask();
if( exclusiveTo && ( exclusiveTo != &renderTask ) )
{
- return;
+ return keepRendering;
}
// Assume all children go to this layer (if this node is a layer).
{
layer->overlayRenderables.PushBack( Renderable( &node, renderer ) );
}
+
+ if( renderer->GetRenderingBehavior() == DevelRenderer::Rendering::CONTINUOUSLY )
+ {
+ keepRendering = true;
+ }
}
// Recurse children.
for( NodeIter iter = children.Begin(); iter != endIter; ++iter )
{
Node& child = **iter;
- AddRenderablesForTask( updateBufferIndex, child, *layer, renderTask, inheritedDrawMode, currentClippingId, clippingDepth, scissorDepth, clippingUsed );
+ keepRendering |= AddRenderablesForTask( updateBufferIndex, child, *layer, renderTask, inheritedDrawMode, currentClippingId, clippingDepth, scissorDepth, clippingUsed );
}
+
+ return keepRendering;
}
/**
* @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.
*/
-void ProcessTasks( BufferIndex updateBufferIndex,
+bool ProcessTasks( BufferIndex updateBufferIndex,
RenderTaskList::RenderTaskContainer& taskContainer,
Layer& rootNode,
SortedLayerPointers& sortedLayers,
bool hasClippingNodes = false;
bool isFirstRenderTask = true;
+ bool keepRendering = false;
for( RenderTaskList::RenderTaskContainer::Iterator iter = taskContainer.Begin(), endIter = taskContainer.End(); endIter != iter; ++iter )
{
RenderTask& renderTask = **iter;
sortedLayer->ClearRenderables();
}
- AddRenderablesForTask( updateBufferIndex,
- *sourceNode,
- *layer,
- renderTask,
- sourceNode->GetDrawMode(),
- clippingId,
- 0u,
- 0u,
- hasClippingNodes );
+ keepRendering |= AddRenderablesForTask( updateBufferIndex,
+ *sourceNode,
+ *layer,
+ renderTask,
+ sourceNode->GetDrawMode(),
+ clippingId,
+ 0u,
+ 0u,
+ hasClippingNodes );
renderInstructionProcessor.Prepare( updateBufferIndex,
sortedLayers,
}
}
}
+
+ return keepRendering;
}
} // Anonymous namespace.
{
}
-void RenderTaskProcessor::Process( BufferIndex updateBufferIndex,
+bool RenderTaskProcessor::Process( BufferIndex updateBufferIndex,
RenderTaskList& renderTasks,
Layer& rootNode,
SortedLayerPointers& sortedLayers,
bool isRenderingToFbo )
{
RenderTaskList::RenderTaskContainer& taskContainer = renderTasks.GetTasks();
+ bool keepRendering = false;
if( taskContainer.IsEmpty() )
{
// Early-exit if there are no tasks to process
- return;
+ return keepRendering;
}
// For each render-task:
// First process off screen render tasks - we may need the results of these for the on screen renders
- ProcessTasks( updateBufferIndex,
- taskContainer,
- rootNode,
- sortedLayers,
- instructions,
- mRenderInstructionProcessor,
- renderToFboEnabled,
- isRenderingToFbo,
- true );
+ keepRendering = ProcessTasks( updateBufferIndex,
+ taskContainer,
+ rootNode,
+ sortedLayers,
+ instructions,
+ mRenderInstructionProcessor,
+ renderToFboEnabled,
+ isRenderingToFbo,
+ true );
DALI_LOG_INFO( gRenderTaskLogFilter, Debug::General, "RenderTaskProcessor::Process() Onscreen\n" );
// Now that the off screen renders are done we can process on screen render tasks.
// Reset the clipping Id for the OnScreen render tasks.
- ProcessTasks( updateBufferIndex,
- taskContainer,
- rootNode,
- sortedLayers,
- instructions,
- mRenderInstructionProcessor,
- renderToFboEnabled,
- isRenderingToFbo,
- false );
+ keepRendering |= ProcessTasks( updateBufferIndex,
+ taskContainer,
+ rootNode,
+ sortedLayers,
+ instructions,
+ mRenderInstructionProcessor,
+ renderToFboEnabled,
+ isRenderingToFbo,
+ false );
+
+ return keepRendering;
}
} // SceneGraph
* @param[out] instructions The instructions for rendering the next frame.
* @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)
+ * @return true if rendering should be kept, false otherwise.
*/
- void Process( BufferIndex updateBufferIndex,
+ bool Process( BufferIndex updateBufferIndex,
RenderTaskList& renderTasks,
Layer& rootNode,
SortedLayerPointers& sortedLayers,
mImpl->messageQueue.IsSceneUpdateRequired() || // ..a message that modifies the scene graph node tree is queued OR
gestureUpdated; // ..a gesture property was updated
+ bool keepRendererRendering = false;
// Although the scene-graph may not require an update, we still need to synchronize double-buffered
// values if the scene was updated in the previous frame.
{
if ( NULL != mImpl->roots[index] )
{
- mImpl->renderTaskProcessor.Process( bufferIndex,
+ keepRendererRendering |= mImpl->renderTaskProcessor.Process( bufferIndex,
*mImpl->taskLists[index],
*mImpl->roots[index],
mImpl->sortedLayerLists[index],
// Check whether further updates are required
uint32_t keepUpdating = KeepUpdatingCheck( elapsedSeconds );
+ if( keepRendererRendering )
+ {
+ keepUpdating |= KeepUpdating::STAGE_KEEP_RENDERING;
+ }
+
// tell the update manager that we're done so the queue can be given to event thread
mImpl->notificationManager.UpdateCompleted();
mBlendMode( BlendMode::AUTO ),
mDepthWriteMode( DepthWriteMode::AUTO ),
mDepthTestMode( DepthTestMode::AUTO ),
+ mRenderingBehavior( DevelRenderer::Rendering::IF_REQUIRED ),
mPremultipledAlphaEnabled( false ),
mOpacity( 1.0f ),
mDepthIndex( 0 )
return mOpacity[updateBufferIndex];
}
+void Renderer::SetRenderingBehavior( DevelRenderer::Rendering::Type renderingBehavior )
+{
+ mRenderingBehavior = renderingBehavior;
+}
+
+DevelRenderer::Rendering::Type Renderer::GetRenderingBehavior() const
+{
+ return mRenderingBehavior;
+}
+
//Called when SceneGraph::Renderer is added to update manager ( that happens when an "event-thread renderer" is created )
void Renderer::ConnectToSceneGraph( SceneController& sceneController, BufferIndex bufferIndex )
{
#include <dali/public-api/rendering/geometry.h>
#include <dali/public-api/rendering/renderer.h> // Dali::Renderer
+#include <dali/devel-api/rendering/renderer-devel.h>
#include <dali/internal/common/blending-options.h>
#include <dali/internal/common/type-abstraction-enums.h>
#include <dali/internal/event/common/event-thread-services.h>
float GetOpacity( BufferIndex updateBufferIndex ) const;
/**
+ * Sets the rendering behavior
+ * @param[in] renderingBehavior The rendering behavior required.
+ */
+ void SetRenderingBehavior( DevelRenderer::Rendering::Type renderingBehavior );
+
+ /**
+ * Gets the rendering behavior
+ * @return The rendering behavior
+ */
+ DevelRenderer::Rendering::Type GetRenderingBehavior() const;
+
+ /**
* Prepare the object for rendering.
* This is called by the UpdateManager when an object is due to be rendered in the current frame.
* @param[in] updateBufferIndex The current update buffer index.
BlendMode::Type mBlendMode:3; ///< Local copy of the mode of blending
DepthWriteMode::Type mDepthWriteMode:3; ///< Local copy of the depth write mode
DepthTestMode::Type mDepthTestMode:3; ///< Local copy of the depth test mode
+ DevelRenderer::Rendering::Type mRenderingBehavior:2; ///< The rendering behavior
bool mUniformMapChanged[2]; ///< Records if the uniform map has been altered this frame
bool mPremultipledAlphaEnabled:1; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required
new (slot) LocalType( &renderer, &Renderer::BakeOpacity, opacity );
}
+inline void SetRenderingBehaviorMessage( EventThreadServices& eventThreadServices, const Renderer& renderer, DevelRenderer::Rendering::Type renderingBehavior )
+{
+ using LocalType = MessageValue1< Renderer, DevelRenderer::Rendering::Type >;
+
+ // Reserve some memory inside the message queue
+ uint32_t* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
+
+ new (slot) LocalType( &renderer, &Renderer::SetRenderingBehavior, renderingBehavior );
+}
+
} // namespace SceneGraph
} // namespace Internal
} // namespace Dali