Ensuring GL Sync is only used for RefreshOnce render tasks
[platform/core/uifw/dali-core.git] / dali / internal / update / render-tasks / scene-graph-render-task.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/math/matrix.h>
23 #include <dali/internal/update/controllers/render-message-dispatcher.h>
24 #include <dali/internal/update/resources/resource-manager.h>
25 #include <dali/internal/update/nodes/node.h>
26 #include <dali/internal/render/common/render-instruction.h>
27 #include <dali/internal/render/common/render-tracker.h>
28
29 #include <dali/internal/update/render-tasks/scene-graph-render-task-debug.h>
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35
36 namespace SceneGraph
37 {
38
39 RenderTask* RenderTask::New()
40 {
41   return new RenderTask();
42 }
43
44 RenderTask::~RenderTask()
45 {
46   // Remove exclusive flag from source node
47   if( mExclusive )
48   {
49     if( mSourceNode && (this == mSourceNode->GetExclusiveRenderTask() ) )
50     {
51       mSourceNode->SetExclusiveRenderTask( NULL );
52     }
53   }
54   if( mRenderSyncTracker )
55   {
56     mRenderMessageDispatcher->RemoveRenderTracker( *mRenderSyncTracker );
57   }
58 }
59
60 void RenderTask::Initialize( RenderMessageDispatcher& renderMessageDispatcher, ResourceManager& resourceManager )
61 {
62   mRenderMessageDispatcher = &renderMessageDispatcher;
63   mResourceManager = &resourceManager;
64 }
65
66 void RenderTask::SetSourceNode( Node* node )
67 {
68   // Remove exclusive flag from the old node, if necessary
69   if ( mSourceNode &&
70        this == mSourceNode->GetExclusiveRenderTask() )
71   {
72     mSourceNode->SetExclusiveRenderTask( NULL );
73   }
74
75   mSourceNode = node;
76
77   if ( mSourceNode && mExclusive )
78   {
79     mSourceNode->SetExclusiveRenderTask( this );
80   }
81 }
82
83 Node* RenderTask::GetSourceNode() const
84 {
85   return mSourceNode;
86 }
87
88 void RenderTask::SetExclusive( bool exclusive )
89 {
90   mExclusive = exclusive;
91
92   if ( mSourceNode )
93   {
94     if ( mExclusive )
95     {
96       mSourceNode->SetExclusiveRenderTask( this );
97     }
98     else if ( this == mSourceNode->GetExclusiveRenderTask() )
99     {
100       mSourceNode->SetExclusiveRenderTask( NULL );
101     }
102   }
103 }
104
105 bool RenderTask::IsExclusive() const
106 {
107   return mExclusive;
108 }
109
110 void RenderTask::SetCameraNode( Node* cameraNode )
111 {
112   // if camera changed
113   if( cameraNode != mCameraNode )
114   {
115     if( cameraNode )
116     {
117       // get attachment. when camera node is changed we will get a message from event thread object
118       // so no need to observe the node here
119       mCameraAttachment = dynamic_cast< CameraAttachment* >( &cameraNode->GetAttachment() );
120       DALI_ASSERT_DEBUG( mCameraAttachment && "Camera without attachment" );
121     }
122     mCameraNode = cameraNode;
123   }
124 }
125
126 void RenderTask::SetFrameBufferId( unsigned int resourceId, bool isNativeFBO )
127 {
128   // note that we might already have a RenderTracker
129   mTargetIsNativeFramebuffer = isNativeFBO;
130   mFrameBufferResourceId = resourceId;
131 }
132
133 unsigned int RenderTask::GetFrameBufferId() const
134 {
135   return mFrameBufferResourceId;
136 }
137
138 bool RenderTask::QueryViewport( BufferIndex bufferIndex, Viewport& viewport ) const
139 {
140   if( ! GetViewportEnabled( bufferIndex ) )
141   {
142     return false;
143   }
144
145   viewport.x = mViewportPosition[bufferIndex].x;
146   viewport.y = mViewportPosition[bufferIndex].y;
147   viewport.width = mViewportSize[bufferIndex].width;
148   viewport.height = mViewportSize[bufferIndex].height;
149
150   return true;
151 }
152
153 void RenderTask::SetClearColor( BufferIndex updateBufferIndex, const Vector4& value )
154 {
155   mClearColor.Set( updateBufferIndex, value );
156 }
157
158 const Vector4& RenderTask::GetClearColor( BufferIndex bufferIndex ) const
159 {
160   return mClearColor[bufferIndex];
161 }
162
163 void RenderTask::BakeClearColor( BufferIndex updateBufferIndex, const Vector4& value )
164 {
165   mClearColor.Bake( updateBufferIndex, value );
166 }
167
168 void RenderTask::SetClearEnabled( bool enabled )
169 {
170   mClearEnabled = enabled;
171 }
172
173 bool RenderTask::GetClearEnabled() const
174 {
175   return mClearEnabled;
176 }
177
178 void RenderTask::SetCullMode( bool mode )
179 {
180   mCullMode = mode;
181 }
182
183 bool RenderTask::GetCullMode() const
184 {
185   return mCullMode;
186 }
187
188 void RenderTask::SetRefreshRate( unsigned int refreshRate )
189 {
190   DALI_LOG_TRACE_METHOD_FMT(gRenderTaskLogFilter, "this:%p RefreshRate:%d\n", this, refreshRate);
191
192   mRefreshRate = refreshRate;
193
194   if( mRefreshRate > 0 )
195   {
196     mState = RENDER_CONTINUOUSLY;
197   }
198   else
199   {
200     mState = RENDER_ONCE_WAITING_FOR_RESOURCES;
201     mWaitingToRender = true;
202     mNotifyTrigger = false;
203     // need at least on other render on the FBO
204     mResourceManager->SetFrameBufferBeenRenderedTo( mFrameBufferResourceId, false );
205   }
206
207   mFrameCounter = 0u;
208 }
209
210 unsigned int RenderTask::GetRefreshRate() const
211 {
212   return mRefreshRate;
213 }
214
215 bool RenderTask::ReadyToRender( BufferIndex updateBufferIndex )
216 {
217   // If the source node of the render task is invisible we should still render
218   // We want the render task to complete and possible clear colors to happen
219
220   // Check source node
221   if ( NULL == mSourceNode ||
222        ( !mSourceNode->IsRoot() && NULL == mSourceNode->GetParent() ) )
223   {
224     TASK_LOG_FMT(Debug::General, " =F  No source actor  FC:%d\n", mFrameCounter );
225
226     // Source node is missing or disconnected
227     return false;
228   }
229
230   // Check camera node
231   if ( NULL == mCameraNode ||
232        NULL == mCameraNode->GetParent() ||
233        !mCameraNode->HasAttachment() )
234   {
235     // Camera node is missing or disconnected
236     TASK_LOG_FMT(Debug::General, " =F  No Camera  FC:%d\n", mFrameCounter );
237
238     return false;
239   }
240
241   TASK_LOG_FMT(Debug::General, " =T (FBO ID:%d) FC:%d\n", mFrameBufferResourceId , mFrameCounter );
242   return true;
243 }
244
245 bool RenderTask::IsRenderRequired()
246 {
247   bool required = false;
248
249   switch( mState )
250   {
251     case RENDER_CONTINUOUSLY:
252     {
253       required = (mFrameCounter == 0);
254       break;
255     }
256     case RENDER_ONCE_WAITING_FOR_RESOURCES:
257     {
258       required = true;
259       break;
260     }
261     default:
262     {
263       required = false;
264       break;
265     }
266   }
267
268   TASK_LOG_FMT( Debug::General, " State:%s = %s\n", STATE_STRING(mState), required?"T":"F" );
269
270   return required;
271 }
272
273 void RenderTask::SetResourcesFinished( bool resourcesFinished )
274 {
275   // resourcesFinished tells us that this render task will render to its FBO
276   mResourcesFinished = resourcesFinished;
277   if( mResourcesFinished )
278   {
279     mResourceManager->SetFrameBufferBeenRenderedTo( mFrameBufferResourceId, true );
280   }
281 }
282
283 // Called every frame regardless of whether render was required.
284 // If render was not required, ignore resourcesFinished.
285 void RenderTask::UpdateState()
286 {
287   TASK_LOG_FMT( Debug::General, "(mResourcesFinished:%s)  FC:%d State:%s RR:%d\n", mResourcesFinished?"T":"F", mFrameCounter, STATE_STRING(mState), mRefreshRate );
288
289   switch( mState )
290   {
291     case RENDER_CONTINUOUSLY:
292     {
293       if( mRefreshRate != Dali::RenderTask::REFRESH_ALWAYS )
294       {
295         if( mFrameCounter == 0 )
296         {
297           if( mResourcesFinished )
298           {
299             ++mFrameCounter; // Only start skipping frames when resources are loaded
300           }
301         }
302         else // Continue counting to skip frames
303         {
304           ++mFrameCounter;
305           if( mFrameCounter >= mRefreshRate )
306           {
307             mFrameCounter = 0;
308           }
309         }
310       }
311       // else do nothing
312     }
313     break;
314
315     case RENDER_ONCE_WAITING_FOR_RESOURCES:
316     {
317       if( mResourcesFinished )
318       {
319         mState = RENDERED_ONCE;
320       }
321     }
322     break;
323
324     case RENDERED_ONCE:
325     {
326       mWaitingToRender = true;
327       mNotifyTrigger = false;
328       if( mFrameBufferResourceId > 0 )
329       {
330         if( mTargetIsNativeFramebuffer )
331         {
332           if( mRenderSyncTracker && mRenderSyncTracker->IsSynced() )
333           {
334             mWaitingToRender = false;
335             mNotifyTrigger = true;
336           }
337         }
338         else if( mResourceManager->HasFrameBufferBeenRenderedTo( mFrameBufferResourceId ) )
339         {
340           mWaitingToRender = false;
341           mNotifyTrigger = true;
342         }
343       }
344       else
345       {
346         mNotifyTrigger = true;
347       }
348     }
349
350     break;
351
352     default:
353       break;
354   }
355
356   TASK_LOG_FMT( Debug::General, " EXIT FC:%d State:%s Notify:%s\n", mFrameCounter, STATE_STRING(mState), mNotifyTrigger?"T":"F");
357 }
358
359 bool RenderTask::IsWaitingToRender()
360 {
361   TASK_LOG_FMT(Debug::Verbose, " State:%s waiting:%s \n", STATE_STRING(mState), mWaitingToRender?"T":"F");
362   return mWaitingToRender;
363 }
364
365 bool RenderTask::HasRendered()
366 {
367   bool notify = false;
368   if( mNotifyTrigger == true )
369   {
370     ++mRenderedOnceCounter;
371     mState = RENDERED_ONCE_AND_NOTIFIED;
372     mNotifyTrigger = false;
373     notify = true;
374   }
375
376   TASK_LOG_FMT(Debug::Verbose, " State:%s hasRendered:%s \n", STATE_STRING(mState), notify?"T":"F");
377   return notify;
378 }
379
380 unsigned int RenderTask::GetRenderedOnceCounter() const
381 {
382   return mRenderedOnceCounter;
383 }
384
385
386 const Matrix& RenderTask::GetViewMatrix( BufferIndex bufferIndex ) const
387 {
388   DALI_ASSERT_DEBUG( NULL != mCameraAttachment );
389
390   return mCameraAttachment->GetViewMatrix( bufferIndex );
391 }
392
393 SceneGraph::CameraAttachment& RenderTask::GetCameraAttachment() const
394 {
395   DALI_ASSERT_DEBUG( NULL != mCameraAttachment );
396   return *mCameraAttachment;
397 }
398
399 const Matrix& RenderTask::GetProjectionMatrix( BufferIndex bufferIndex ) const
400 {
401   DALI_ASSERT_DEBUG( NULL != mCameraAttachment );
402
403   return mCameraAttachment->GetProjectionMatrix( bufferIndex );
404 }
405
406 void RenderTask::PrepareRenderInstruction( RenderInstruction& instruction, BufferIndex updateBufferIndex )
407 {
408   DALI_ASSERT_DEBUG( NULL != mCameraAttachment );
409
410   TASK_LOG(Debug::General);
411
412   Viewport viewport;
413   bool viewportSet = QueryViewport( updateBufferIndex, viewport );
414
415   instruction.Reset( mCameraAttachment,
416                      GetFrameBufferId(),
417                      viewportSet ? &viewport : NULL,
418                      mClearEnabled ? &GetClearColor( updateBufferIndex ) : NULL );
419
420   if( mTargetIsNativeFramebuffer &&
421       mRefreshRate == Dali::RenderTask::REFRESH_ONCE &&
422       mResourcesFinished )
423   {
424     // create tracker if one doesn't yet exist.
425     if( !mRenderSyncTracker )
426     {
427       mRenderSyncTracker = new Render::RenderTracker();
428       mRenderMessageDispatcher->AddRenderTracker( *mRenderSyncTracker );
429     }
430     instruction.mRenderTracker = mRenderSyncTracker;
431   }
432   else
433   {
434     // no sync needed, texture FBOs are "ready" the same frame they are rendered to
435     instruction.mRenderTracker = NULL;
436   }
437 }
438
439 bool RenderTask::ViewMatrixUpdated()
440 {
441   bool retval = false;
442   if( mCameraAttachment )
443   {
444     retval = mCameraAttachment->ViewMatrixUpdated();
445   }
446   return retval;
447 }
448
449 void RenderTask::SetViewportPosition( BufferIndex updateBufferIndex, const Vector2& value )
450 {
451   mViewportPosition.Set( updateBufferIndex, value );
452 }
453
454 const Vector2& RenderTask::GetViewportPosition( BufferIndex bufferIndex ) const
455 {
456   return mViewportPosition[bufferIndex];
457 }
458
459 void RenderTask::BakeViewportPosition( BufferIndex updateBufferIndex, const Vector2& value )
460 {
461   mViewportPosition.Bake( updateBufferIndex, value );
462 }
463
464 void RenderTask::SetViewportSize( BufferIndex updateBufferIndex, const Vector2& value )
465 {
466   mViewportSize.Set( updateBufferIndex, value );
467 }
468
469 const Vector2& RenderTask::GetViewportSize( BufferIndex bufferIndex ) const
470 {
471   return mViewportSize[bufferIndex];
472 }
473
474 void RenderTask::BakeViewportSize( BufferIndex updateBufferIndex, const Vector2& value )
475 {
476   mViewportSize.Bake( updateBufferIndex, value );
477 }
478
479 bool RenderTask::GetViewportEnabled( BufferIndex bufferIndex ) const
480 {
481   if(fabsf(mViewportPosition[bufferIndex].x) > Math::MACHINE_EPSILON_1 ||
482      fabsf(mViewportPosition[bufferIndex].y) > Math::MACHINE_EPSILON_1 ||
483      fabsf(mViewportSize[bufferIndex].width) > Math::MACHINE_EPSILON_1 ||
484      fabsf(mViewportSize[bufferIndex].height) > Math::MACHINE_EPSILON_1)
485   {
486     return true;
487   }
488
489   return false;
490 }
491
492 Node* RenderTask::GetCamera() const
493 {
494   return mCameraNode;
495 }
496
497 void RenderTask::ResetDefaultProperties( BufferIndex updateBufferIndex )
498 {
499   // Reset default properties
500   mViewportPosition.ResetToBaseValue( updateBufferIndex );
501   mViewportSize.ResetToBaseValue( updateBufferIndex );
502   mClearColor.ResetToBaseValue( updateBufferIndex );
503 }
504
505 RenderTask::RenderTask()
506 : mViewportPosition( Vector2::ZERO),
507   mViewportSize( Vector2::ZERO),
508   mClearColor( Dali::RenderTask::DEFAULT_CLEAR_COLOR ),
509   mRenderMessageDispatcher( NULL ),
510   mResourceManager( NULL ),
511   mRenderSyncTracker( NULL ),
512   mSourceNode( NULL ),
513   mCameraNode( NULL ),
514   mCameraAttachment( NULL ),
515   mFrameBufferResourceId( 0 ),
516   mResourcesFinished( false ),
517   mWaitingToRender( false ),
518   mNotifyTrigger( false ),
519   mExclusive( Dali::RenderTask::DEFAULT_EXCLUSIVE ),
520   mClearEnabled( Dali::RenderTask::DEFAULT_CLEAR_ENABLED ),
521   mCullMode( Dali::RenderTask::DEFAULT_CULL_MODE ),
522   mRenderTarget( NULL ),
523   mState( (Dali::RenderTask::DEFAULT_REFRESH_RATE == Dali::RenderTask::REFRESH_ALWAYS)
524           ? RENDER_CONTINUOUSLY
525           : RENDER_ONCE_WAITING_FOR_RESOURCES ),
526   mRefreshRate( Dali::RenderTask::DEFAULT_REFRESH_RATE ),
527   mFrameCounter( 0u ),
528   mRenderedOnceCounter( 0u ),
529   mTargetIsNativeFramebuffer( false )
530 {
531 }
532
533 } // namespace SceneGraph
534
535 } // namespace Internal
536
537 } // namespace Dali