61438241333be6920d6369932337811f8bb1c793
[platform/core/uifw/dali-core.git] / dali / internal / render / common / render-manager.cpp
1 /*
2  * Copyright (c) 2020 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/render/common/render-manager.h>
20
21 // EXTERNAL INCLUDES
22 #include <memory.h>
23
24 // INTERNAL INCLUDES
25 #include <dali/devel-api/threading/thread-pool.h>
26 #include <dali/integration-api/core.h>
27 #include <dali/integration-api/gl-context-helper-abstraction.h>
28 #include <dali/internal/event/common/scene-impl.h>
29 #include <dali/internal/render/common/render-algorithms.h>
30 #include <dali/internal/render/common/render-debug.h>
31 #include <dali/internal/render/common/render-tracker.h>
32 #include <dali/internal/render/queue/render-queue.h>
33 #include <dali/internal/render/shaders/program-controller.h>
34
35 namespace Dali
36 {
37
38 namespace Internal
39 {
40
41 namespace SceneGraph
42 {
43
44 #if defined(DEBUG_ENABLED)
45 namespace
46 {
47 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_MANAGER" );
48 } // unnamed namespace
49 #endif
50
51 struct DirtyRect
52 {
53   DirtyRect(Node* node, Render::Renderer* renderer, int frame, Rect<int>& rect)
54   : node(node),
55     renderer(renderer),
56     frame(frame),
57     rect(rect),
58     visited(true)
59   {
60   }
61
62   DirtyRect()
63   : node(nullptr),
64     renderer(nullptr),
65     frame(0),
66     rect(),
67     visited(true)
68   {
69   }
70
71   bool operator<(const DirtyRect& rhs) const
72   {
73     if (node == rhs.node)
74     {
75       if (renderer == rhs.renderer)
76       {
77         return frame > rhs.frame; // Most recent rects come first
78       }
79       else
80       {
81         return renderer < rhs.renderer;
82       }
83     }
84     else
85     {
86       return node < rhs.node;
87     }
88   }
89
90   Node* node;
91   Render::Renderer* renderer;
92   int frame;
93
94   Rect<int> rect;
95   bool visited;
96 };
97
98 /**
99  * Structure to contain internal data
100  */
101 struct RenderManager::Impl
102 {
103   Impl( Integration::GlAbstraction& glAbstraction,
104         Integration::GlSyncAbstraction& glSyncAbstraction,
105         Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
106         Integration::DepthBufferAvailable depthBufferAvailableParam,
107         Integration::StencilBufferAvailable stencilBufferAvailableParam,
108         Integration::PartialUpdateAvailable partialUpdateAvailableParam )
109   : context( glAbstraction, &sceneContextContainer ),
110     currentContext( &context ),
111     glAbstraction( glAbstraction ),
112     glSyncAbstraction( glSyncAbstraction ),
113     glContextHelperAbstraction( glContextHelperAbstraction ),
114     renderQueue(),
115     renderAlgorithms(),
116     frameCount( 0u ),
117     renderBufferIndex( SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX ),
118     defaultSurfaceRect(),
119     rendererContainer(),
120     samplerContainer(),
121     textureContainer(),
122     frameBufferContainer(),
123     lastFrameWasRendered( false ),
124     programController( glAbstraction ),
125     depthBufferAvailable( depthBufferAvailableParam ),
126     stencilBufferAvailable( stencilBufferAvailableParam ),
127     partialUpdateAvailable( partialUpdateAvailableParam ),
128     itemsCheckSum(0),
129     defaultSurfaceOrientation( 0 )
130   {
131      // Create thread pool with just one thread ( there may be a need to create more threads in the future ).
132     threadPool = std::unique_ptr<Dali::ThreadPool>( new Dali::ThreadPool() );
133     threadPool->Initialize( 1u );
134   }
135
136   ~Impl()
137   {
138     threadPool.reset( nullptr ); // reset now to maintain correct destruction order
139   }
140
141   void AddRenderTracker( Render::RenderTracker* renderTracker )
142   {
143     DALI_ASSERT_DEBUG( renderTracker != NULL );
144     mRenderTrackers.PushBack( renderTracker );
145   }
146
147   void RemoveRenderTracker( Render::RenderTracker* renderTracker )
148   {
149     mRenderTrackers.EraseObject( renderTracker );
150   }
151
152   Context* CreateSceneContext()
153   {
154     Context* context = new Context( glAbstraction );
155
156     //TODO: Need eglMakeCurrent first
157     context->GlContextCreated();
158
159     sceneContextContainer.PushBack( context );
160     return context;
161   }
162
163   void DestroySceneContext( Context* sceneContext )
164   {
165     auto iter = std::find( sceneContextContainer.Begin(), sceneContextContainer.End(), sceneContext );
166     if( iter != sceneContextContainer.End() )
167     {
168       ( *iter )->GlContextDestroyed();
169       sceneContextContainer.Erase( iter );
170     }
171   }
172
173   Context* ReplaceSceneContext( Context* oldSceneContext )
174   {
175     Context* newContext = new Context( glAbstraction );
176
177     oldSceneContext->GlContextDestroyed();
178     //TODO: Need eglMakeCurrent first
179     newContext->GlContextCreated();
180
181     std::replace( sceneContextContainer.begin(), sceneContextContainer.end(), oldSceneContext, newContext );
182     return newContext;
183   }
184
185   void UpdateTrackers()
186   {
187     for( auto&& iter : mRenderTrackers )
188     {
189       iter->PollSyncObject();
190     }
191   }
192
193   // the order is important for destruction,
194   // programs are owned by context at the moment.
195   Context                                   context;                 ///< Holds the GL state of the share resource context
196   Context*                                  currentContext;          ///< Holds the GL state of the current context for rendering
197   OwnerContainer< Context* >                sceneContextContainer;   ///< List of owned contexts holding the GL state per scene
198   Integration::GlAbstraction&               glAbstraction;           ///< GL abstraction
199   Integration::GlSyncAbstraction&           glSyncAbstraction;       ///< GL sync abstraction
200   Integration::GlContextHelperAbstraction&  glContextHelperAbstraction; ///< GL context helper abstraction
201   RenderQueue                               renderQueue;             ///< A message queue for receiving messages from the update-thread.
202
203   std::vector< SceneGraph::Scene* >         sceneContainer;          ///< List of pointers to the scene graph objects of the scenes
204
205   Render::RenderAlgorithms                  renderAlgorithms;        ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction
206
207   uint32_t                                  frameCount;              ///< The current frame count
208   BufferIndex                               renderBufferIndex;       ///< The index of the buffer to read from; this is opposite of the "update" buffer
209
210   Rect<int32_t>                             defaultSurfaceRect;      ///< Rectangle for the default surface we are rendering to
211
212   OwnerContainer< Render::Renderer* >       rendererContainer;       ///< List of owned renderers
213   OwnerContainer< Render::Sampler* >        samplerContainer;        ///< List of owned samplers
214   OwnerContainer< Render::Texture* >        textureContainer;        ///< List of owned textures
215   OwnerContainer< Render::FrameBuffer* >    frameBufferContainer;    ///< List of owned framebuffers
216   OwnerContainer< Render::PropertyBuffer* > propertyBufferContainer; ///< List of owned property buffers
217   OwnerContainer< Render::Geometry* >       geometryContainer;       ///< List of owned Geometries
218
219   bool                                      lastFrameWasRendered;    ///< Keeps track of the last frame being rendered due to having render instructions
220
221   OwnerContainer< Render::RenderTracker* >  mRenderTrackers;         ///< List of render trackers
222
223   ProgramController                         programController;        ///< Owner of the GL programs
224
225   Integration::DepthBufferAvailable         depthBufferAvailable;     ///< Whether the depth buffer is available
226   Integration::StencilBufferAvailable       stencilBufferAvailable;   ///< Whether the stencil buffer is available
227   Integration::PartialUpdateAvailable       partialUpdateAvailable;   ///< Whether the partial update is available
228
229   std::unique_ptr<Dali::ThreadPool>         threadPool;               ///< The thread pool
230   Vector<GLuint>                            boundTextures;            ///< The textures bound for rendering
231   Vector<GLuint>                            textureDependencyList;    ///< The dependency list of binded textures
232   std::size_t                               itemsCheckSum;            ///< The damaged render items checksum from previous prerender phase.
233   std::vector<DirtyRect>                    itemsDirtyRects;
234   int                                       defaultSurfaceOrientation; ///< defaultSurfaceOrientation for the default surface we are rendering to
235 };
236
237 RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction,
238                                    Integration::GlSyncAbstraction& glSyncAbstraction,
239                                    Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
240                                    Integration::DepthBufferAvailable depthBufferAvailable,
241                                    Integration::StencilBufferAvailable stencilBufferAvailable,
242                                    Integration::PartialUpdateAvailable partialUpdateAvailable )
243 {
244   RenderManager* manager = new RenderManager;
245   manager->mImpl = new Impl( glAbstraction,
246                              glSyncAbstraction,
247                              glContextHelperAbstraction,
248                              depthBufferAvailable,
249                              stencilBufferAvailable,
250                              partialUpdateAvailable );
251   return manager;
252 }
253
254 RenderManager::RenderManager()
255 : mImpl(NULL)
256 {
257 }
258
259 RenderManager::~RenderManager()
260 {
261   delete mImpl;
262 }
263
264 RenderQueue& RenderManager::GetRenderQueue()
265 {
266   return mImpl->renderQueue;
267 }
268
269 void RenderManager::ContextCreated()
270 {
271   mImpl->context.GlContextCreated();
272   mImpl->programController.GlContextCreated();
273
274   // renderers, textures and gpu buffers cannot reinitialize themselves
275   // so they rely on someone reloading the data for them
276 }
277
278 void RenderManager::ContextDestroyed()
279 {
280   mImpl->context.GlContextDestroyed();
281   mImpl->programController.GlContextDestroyed();
282
283   //Inform textures
284   for( auto&& texture : mImpl->textureContainer )
285   {
286     texture->GlContextDestroyed();
287   }
288
289   //Inform framebuffers
290   for( auto&& framebuffer : mImpl->frameBufferContainer )
291   {
292     framebuffer->GlContextDestroyed();
293   }
294
295   // inform renderers
296   for( auto&& renderer : mImpl->rendererContainer )
297   {
298     renderer->GlContextDestroyed();
299   }
300
301   // inform context
302   for( auto&& context : mImpl->sceneContextContainer )
303   {
304     context->GlContextDestroyed();
305   }
306 }
307
308 void RenderManager::SetShaderSaver( ShaderSaver& upstream )
309 {
310   mImpl->programController.SetShaderSaver( upstream );
311 }
312
313 void RenderManager::SetDefaultSurfaceRect(const Rect<int32_t>& rect)
314 {
315   mImpl->defaultSurfaceRect = rect;
316 }
317
318 void RenderManager::SetDefaultSurfaceOrientation( int orientation )
319 {
320   mImpl->defaultSurfaceOrientation = orientation;
321 }
322
323 void RenderManager::AddRenderer( OwnerPointer< Render::Renderer >& renderer )
324 {
325   // Initialize the renderer as we are now in render thread
326   renderer->Initialize( mImpl->context );
327
328   mImpl->rendererContainer.PushBack( renderer.Release() );
329 }
330
331 void RenderManager::RemoveRenderer( Render::Renderer* renderer )
332 {
333   mImpl->rendererContainer.EraseObject( renderer );
334 }
335
336 void RenderManager::AddSampler( OwnerPointer< Render::Sampler >& sampler )
337 {
338   mImpl->samplerContainer.PushBack( sampler.Release() );
339 }
340
341 void RenderManager::RemoveSampler( Render::Sampler* sampler )
342 {
343   mImpl->samplerContainer.EraseObject( sampler );
344 }
345
346 void RenderManager::AddTexture( OwnerPointer< Render::Texture >& texture )
347 {
348   texture->Initialize( mImpl->context );
349   mImpl->textureContainer.PushBack( texture.Release() );
350 }
351
352 void RenderManager::RemoveTexture( Render::Texture* texture )
353 {
354   DALI_ASSERT_DEBUG( NULL != texture );
355
356   // Find the texture, use reference to pointer so we can do the erase safely
357   for ( auto&& iter : mImpl->textureContainer )
358   {
359     if ( iter == texture )
360     {
361       texture->Destroy( mImpl->context );
362       mImpl->textureContainer.Erase( &iter ); // Texture found; now destroy it
363       return;
364     }
365   }
366 }
367
368 void RenderManager::UploadTexture( Render::Texture* texture, PixelDataPtr pixelData, const Texture::UploadParams& params )
369 {
370   texture->Upload( mImpl->context, pixelData, params );
371 }
372
373 void RenderManager::GenerateMipmaps( Render::Texture* texture )
374 {
375   texture->GenerateMipmaps( mImpl->context );
376 }
377
378 void RenderManager::SetFilterMode( Render::Sampler* sampler, uint32_t minFilterMode, uint32_t magFilterMode )
379 {
380   sampler->mMinificationFilter = static_cast<Dali::FilterMode::Type>(minFilterMode);
381   sampler->mMagnificationFilter = static_cast<Dali::FilterMode::Type>(magFilterMode );
382 }
383
384 void RenderManager::SetWrapMode( Render::Sampler* sampler, uint32_t rWrapMode, uint32_t sWrapMode, uint32_t tWrapMode )
385 {
386   sampler->mRWrapMode = static_cast<Dali::WrapMode::Type>(rWrapMode);
387   sampler->mSWrapMode = static_cast<Dali::WrapMode::Type>(sWrapMode);
388   sampler->mTWrapMode = static_cast<Dali::WrapMode::Type>(tWrapMode);
389 }
390
391 void RenderManager::AddFrameBuffer( OwnerPointer< Render::FrameBuffer >& frameBuffer )
392 {
393   Render::FrameBuffer* frameBufferPtr = frameBuffer.Release();
394   mImpl->frameBufferContainer.PushBack( frameBufferPtr );
395   frameBufferPtr->Initialize( mImpl->context );
396 }
397
398 void RenderManager::RemoveFrameBuffer( Render::FrameBuffer* frameBuffer )
399 {
400   DALI_ASSERT_DEBUG( NULL != frameBuffer );
401
402   // Find the sampler, use reference so we can safely do the erase
403   for ( auto&& iter : mImpl->frameBufferContainer )
404   {
405     if ( iter == frameBuffer )
406     {
407       frameBuffer->Destroy( mImpl->context );
408       mImpl->frameBufferContainer.Erase( &iter ); // frameBuffer found; now destroy it
409
410       break;
411     }
412   }
413 }
414 void RenderManager::InitializeScene( SceneGraph::Scene* scene )
415 {
416   scene->Initialize( *mImpl->CreateSceneContext() );
417   mImpl->sceneContainer.push_back( scene );
418 }
419
420 void RenderManager::UninitializeScene( SceneGraph::Scene* scene )
421 {
422   mImpl->DestroySceneContext( scene->GetContext() );
423
424   auto iter = std::find( mImpl->sceneContainer.begin(), mImpl->sceneContainer.end(), scene );
425   if( iter != mImpl->sceneContainer.end() )
426   {
427     mImpl->sceneContainer.erase( iter );
428   }
429 }
430
431 void RenderManager::SurfaceReplaced( SceneGraph::Scene* scene )
432 {
433   Context* newContext = mImpl->ReplaceSceneContext( scene->GetContext() );
434   scene->Initialize( *newContext );
435 }
436
437 void RenderManager::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer )
438 {
439   frameBuffer->AttachColorTexture( mImpl->context, texture, mipmapLevel, layer );
440 }
441
442 void RenderManager::AttachDepthTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel )
443 {
444   frameBuffer->AttachDepthTexture( mImpl->context, texture, mipmapLevel );
445 }
446
447 void RenderManager::AttachDepthStencilTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel )
448 {
449   frameBuffer->AttachDepthStencilTexture( mImpl->context, texture, mipmapLevel );
450 }
451
452 void RenderManager::AddPropertyBuffer( OwnerPointer< Render::PropertyBuffer >& propertyBuffer )
453 {
454   mImpl->propertyBufferContainer.PushBack( propertyBuffer.Release() );
455 }
456
457 void RenderManager::RemovePropertyBuffer( Render::PropertyBuffer* propertyBuffer )
458 {
459   mImpl->propertyBufferContainer.EraseObject( propertyBuffer );
460 }
461
462 void RenderManager::SetPropertyBufferFormat( Render::PropertyBuffer* propertyBuffer, OwnerPointer< Render::PropertyBuffer::Format>& format )
463 {
464   propertyBuffer->SetFormat( format.Release() );
465 }
466
467 void RenderManager::SetPropertyBufferData( Render::PropertyBuffer* propertyBuffer, OwnerPointer< Vector<uint8_t> >& data, uint32_t size )
468 {
469   propertyBuffer->SetData( data.Release(), size );
470 }
471
472 void RenderManager::SetIndexBuffer( Render::Geometry* geometry, Dali::Vector<uint16_t>& indices )
473 {
474   geometry->SetIndexBuffer( indices );
475 }
476
477 void RenderManager::AddGeometry( OwnerPointer< Render::Geometry >& geometry )
478 {
479   mImpl->geometryContainer.PushBack( geometry.Release() );
480 }
481
482 void RenderManager::RemoveGeometry( Render::Geometry* geometry )
483 {
484   mImpl->geometryContainer.EraseObject( geometry );
485 }
486
487 void RenderManager::AttachVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer )
488 {
489   DALI_ASSERT_DEBUG( NULL != geometry );
490
491   // Find the geometry
492   for ( auto&& iter : mImpl->geometryContainer )
493   {
494     if ( iter == geometry )
495     {
496       iter->AddPropertyBuffer( propertyBuffer );
497       break;
498     }
499   }
500 }
501
502 void RenderManager::RemoveVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer )
503 {
504   DALI_ASSERT_DEBUG( NULL != geometry );
505
506   // Find the geometry
507   for ( auto&& iter : mImpl->geometryContainer )
508   {
509     if ( iter == geometry )
510     {
511       iter->RemovePropertyBuffer( propertyBuffer );
512       break;
513     }
514   }
515 }
516
517 void RenderManager::SetGeometryType( Render::Geometry* geometry, uint32_t geometryType )
518 {
519   geometry->SetType( Render::Geometry::Type(geometryType) );
520 }
521
522 void RenderManager::AddRenderTracker( Render::RenderTracker* renderTracker )
523 {
524   mImpl->AddRenderTracker(renderTracker);
525 }
526
527 void RenderManager::RemoveRenderTracker( Render::RenderTracker* renderTracker )
528 {
529   mImpl->RemoveRenderTracker(renderTracker);
530 }
531
532 ProgramCache* RenderManager::GetProgramCache()
533 {
534   return &(mImpl->programController);
535 }
536
537 void RenderManager::PreRender( Integration::RenderStatus& status, bool forceClear, bool uploadOnly )
538 {
539   DALI_PRINT_RENDER_START( mImpl->renderBufferIndex );
540
541   // Core::Render documents that GL context must be current before calling Render
542   DALI_ASSERT_DEBUG( mImpl->context.IsGlContextCreated() );
543
544   // Increment the frame count at the beginning of each frame
545   ++mImpl->frameCount;
546
547   // Process messages queued during previous update
548   mImpl->renderQueue.ProcessMessages( mImpl->renderBufferIndex );
549
550   uint32_t count = 0u;
551   for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i )
552   {
553     count += mImpl->sceneContainer[i]->GetRenderInstructions().Count( mImpl->renderBufferIndex );
554   }
555
556   const bool haveInstructions = count > 0u;
557
558   DALI_LOG_INFO( gLogFilter, Debug::General,
559                  "Render: haveInstructions(%s) || mImpl->lastFrameWasRendered(%s) || forceClear(%s)\n",
560                  haveInstructions ? "true" : "false",
561                  mImpl->lastFrameWasRendered ? "true" : "false",
562                  forceClear ? "true" : "false" );
563
564   // Only render if we have instructions to render, or the last frame was rendered (and therefore a clear is required).
565   if( haveInstructions || mImpl->lastFrameWasRendered || forceClear )
566   {
567     DALI_LOG_INFO( gLogFilter, Debug::General, "Render: Processing\n" );
568
569     // Switch to the shared context
570     if ( mImpl->currentContext != &mImpl->context )
571     {
572       mImpl->currentContext = &mImpl->context;
573
574       if ( mImpl->currentContext->IsSurfacelessContextSupported() )
575       {
576         mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent();
577       }
578
579       // Clear the current cached program when the context is switched
580       mImpl->programController.ClearCurrentProgram();
581     }
582
583     // Upload the geometries
584     for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i )
585     {
586       RenderInstructionContainer& instructions = mImpl->sceneContainer[i]->GetRenderInstructions();
587       for ( uint32_t j = 0; j < instructions.Count( mImpl->renderBufferIndex ); ++j )
588       {
589         RenderInstruction& instruction = instructions.At( mImpl->renderBufferIndex, j );
590
591         const Matrix* viewMatrix       = instruction.GetViewMatrix( mImpl->renderBufferIndex );
592         const Matrix* projectionMatrix = instruction.GetProjectionMatrix( mImpl->renderBufferIndex );
593
594         DALI_ASSERT_DEBUG( viewMatrix );
595         DALI_ASSERT_DEBUG( projectionMatrix );
596
597         if( viewMatrix && projectionMatrix )
598         {
599           const RenderListContainer::SizeType renderListCount = instruction.RenderListCount();
600
601           // Iterate through each render list.
602           for( RenderListContainer::SizeType index = 0; index < renderListCount; ++index )
603           {
604             const RenderList* renderList = instruction.GetRenderList( index );
605
606             if( renderList && !renderList->IsEmpty() )
607             {
608               const std::size_t itemCount = renderList->Count();
609               for( uint32_t itemIndex = 0u; itemIndex < itemCount; ++itemIndex )
610               {
611                 const RenderItem& item = renderList->GetItem( itemIndex );
612                 if( DALI_LIKELY( item.mRenderer ) )
613                 {
614                   item.mRenderer->Upload( *mImpl->currentContext );
615                 }
616               }
617             }
618           }
619         }
620       }
621     }
622   }
623 }
624
625 void RenderManager::PreRender( Integration::Scene& scene, std::vector<Rect<int>>& damagedRects )
626 {
627   if (mImpl->partialUpdateAvailable != Integration::PartialUpdateAvailable::TRUE)
628   {
629     return;
630   }
631
632   // @TODO We need to do partial rendering rotation.
633   if( mImpl->defaultSurfaceOrientation != 0 )
634   {
635     return;
636   }
637
638   class DamagedRectsCleaner
639   {
640   public:
641     DamagedRectsCleaner(std::vector<Rect<int>>& damagedRects)
642     : mDamagedRects(damagedRects),
643       mCleanOnReturn(true)
644     {
645     }
646
647     void SetCleanOnReturn(bool cleanOnReturn)
648     {
649       mCleanOnReturn = cleanOnReturn;
650     }
651
652     ~DamagedRectsCleaner()
653     {
654       if (mCleanOnReturn)
655       {
656         mDamagedRects.clear();
657       }
658     }
659
660   private:
661     std::vector<Rect<int>>& mDamagedRects;
662     bool mCleanOnReturn;
663   };
664
665   Rect<int32_t> surfaceRect = Rect<int32_t>(0, 0, static_cast<int32_t>( scene.GetSize().width ), static_cast<int32_t>( scene.GetSize().height ));
666
667   // Clean collected dirty/damaged rects on exit if 3d layer or 3d node or other conditions.
668   DamagedRectsCleaner damagedRectCleaner(damagedRects);
669
670   // Mark previous dirty rects in the sorted array. The array is already sorted by node and renderer, frame number.
671   // so you don't need to sort: std::stable_sort(mImpl->itemsDirtyRects.begin(), mImpl->itemsDirtyRects.end());
672   for (DirtyRect& dirtyRect : mImpl->itemsDirtyRects)
673   {
674     dirtyRect.visited = false;
675   }
676
677   Internal::Scene& sceneInternal = GetImplementation(scene);
678   SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject();
679   uint32_t count = sceneObject->GetRenderInstructions().Count( mImpl->renderBufferIndex );
680   for (uint32_t i = 0; i < count; ++i)
681   {
682     RenderInstruction& instruction = sceneObject->GetRenderInstructions().At( mImpl->renderBufferIndex, i );
683
684     if (instruction.mFrameBuffer)
685     {
686       return; // TODO: reset, we don't deal with render tasks with framebuffers (for now)
687     }
688
689     const Camera* camera = instruction.GetCamera();
690     if (camera->mType == Camera::DEFAULT_TYPE && camera->mTargetPosition == Camera::DEFAULT_TARGET_POSITION)
691     {
692       const Node* node = instruction.GetCamera()->GetNode();
693       if (node)
694       {
695         Vector3 position;
696         Vector3 scale;
697         Quaternion orientation;
698         node->GetWorldMatrix(mImpl->renderBufferIndex).GetTransformComponents(position, orientation, scale);
699
700         Vector3 orientationAxis;
701         Radian orientationAngle;
702         orientation.ToAxisAngle( orientationAxis, orientationAngle );
703
704         if (position.x > Math::MACHINE_EPSILON_10000 ||
705             position.y > Math::MACHINE_EPSILON_10000 ||
706             orientationAxis != Vector3(0.0f, 1.0f, 0.0f) ||
707             orientationAngle != ANGLE_180 ||
708             scale != Vector3(1.0f, 1.0f, 1.0f))
709         {
710           return;
711         }
712       }
713     }
714     else
715     {
716       return;
717     }
718
719     Rect<int32_t> viewportRect;
720     if (instruction.mIsViewportSet)
721     {
722       const int32_t y = (surfaceRect.height - instruction.mViewport.height) - instruction.mViewport.y;
723       viewportRect.Set(instruction.mViewport.x,  y, instruction.mViewport.width, instruction.mViewport.height);
724       if (viewportRect.IsEmpty() || !viewportRect.IsValid())
725       {
726         return; // just skip funny use cases for now, empty viewport means it is set somewhere else
727       }
728     }
729     else
730     {
731       viewportRect = surfaceRect;
732     }
733
734     const Matrix* viewMatrix       = instruction.GetViewMatrix(mImpl->renderBufferIndex);
735     const Matrix* projectionMatrix = instruction.GetProjectionMatrix(mImpl->renderBufferIndex);
736     if (viewMatrix && projectionMatrix)
737     {
738       const RenderListContainer::SizeType count = instruction.RenderListCount();
739       for (RenderListContainer::SizeType index = 0u; index < count; ++index)
740       {
741         const RenderList* renderList = instruction.GetRenderList( index );
742         if (renderList && !renderList->IsEmpty())
743         {
744           const std::size_t count = renderList->Count();
745           for (uint32_t index = 0u; index < count; ++index)
746           {
747             RenderItem& item = renderList->GetItem( index );
748             // If the item does 3D transformation, do early exit and clean the damaged rect array
749             if (item.mUpdateSize == Vector3::ZERO)
750             {
751               return;
752             }
753
754             Rect<int> rect;
755             DirtyRect dirtyRect(item.mNode, item.mRenderer, mImpl->frameCount, rect);
756             // If the item refers to updated node or renderer.
757             if (item.mIsUpdated ||
758                 (item.mNode &&
759                 (item.mNode->Updated() || (item.mRenderer && item.mRenderer->Updated(mImpl->renderBufferIndex, item.mNode)))))
760             {
761               item.mIsUpdated = false;
762               item.mNode->SetUpdated(false);
763
764               rect = item.CalculateViewportSpaceAABB(item.mUpdateSize, viewportRect.width, viewportRect.height);
765               if (rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty())
766               {
767                 const int left = rect.x;
768                 const int top = rect.y;
769                 const int right = rect.x + rect.width;
770                 const int bottom = rect.y + rect.height;
771                 rect.x = (left / 16) * 16;
772                 rect.y = (top / 16) * 16;
773                 rect.width = ((right + 16) / 16) * 16 - rect.x;
774                 rect.height = ((bottom + 16) / 16) * 16 - rect.y;
775
776                 // Found valid dirty rect.
777                 // 1. Insert it in the sorted array of the dirty rects.
778                 // 2. Mark the related dirty rects as visited so they will not be removed below.
779                 // 3. Keep only last 3 dirty rects for the same node and renderer (Tizen uses 3 back buffers, Ubuntu 1).
780                 dirtyRect.rect = rect;
781                 auto dirtyRectPos = std::lower_bound(mImpl->itemsDirtyRects.begin(), mImpl->itemsDirtyRects.end(), dirtyRect);
782                 dirtyRectPos = mImpl->itemsDirtyRects.insert(dirtyRectPos, dirtyRect);
783
784                 int c = 1;
785                 while (++dirtyRectPos != mImpl->itemsDirtyRects.end())
786                 {
787                   if (dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer)
788                   {
789                     break;
790                   }
791
792                   dirtyRectPos->visited = true;
793                   Rect<int>& dirtRect = dirtyRectPos->rect;
794                   rect.Merge(dirtRect);
795
796                   c++;
797                   if (c > 3) // no more then 3 previous rects
798                   {
799                     mImpl->itemsDirtyRects.erase(dirtyRectPos);
800                     break;
801                   }
802                 }
803
804                 damagedRects.push_back(rect);
805               }
806             }
807             else
808             {
809               // 1. The item is not dirty, the node and renderer referenced by the item are still exist.
810               // 2. Mark the related dirty rects as visited so they will not be removed below.
811               auto dirtyRectPos = std::lower_bound(mImpl->itemsDirtyRects.begin(), mImpl->itemsDirtyRects.end(), dirtyRect);
812               while (dirtyRectPos != mImpl->itemsDirtyRects.end())
813               {
814                 if (dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer)
815                 {
816                   break;
817                 }
818
819                 dirtyRectPos->visited = true;
820                 dirtyRectPos++;
821               }
822             }
823           }
824         }
825       }
826     }
827   }
828
829   // Check removed nodes or removed renderers dirty rects
830   auto i = mImpl->itemsDirtyRects.begin();
831   auto j = mImpl->itemsDirtyRects.begin();
832   while (i != mImpl->itemsDirtyRects.end())
833   {
834     if (i->visited)
835     {
836       *j++ = *i;
837     }
838     else
839     {
840       Rect<int>& dirtRect = i->rect;
841       damagedRects.push_back(dirtRect);
842     }
843     i++;
844   }
845
846   if( j != mImpl->itemsDirtyRects.begin() )
847   {
848     mImpl->itemsDirtyRects.resize(j - mImpl->itemsDirtyRects.begin());
849   }
850   damagedRectCleaner.SetCleanOnReturn(false);
851 }
852
853 void RenderManager::RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo )
854 {
855   Rect<int> clippingRect;
856   RenderScene( status, scene, renderToFbo, clippingRect);
857 }
858
859 void RenderManager::RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect<int>& clippingRect )
860 {
861   Internal::Scene& sceneInternal = GetImplementation( scene );
862   SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject();
863
864   uint32_t count = sceneObject->GetRenderInstructions().Count( mImpl->renderBufferIndex );
865
866   for( uint32_t i = 0; i < count; ++i )
867   {
868     RenderInstruction& instruction = sceneObject->GetRenderInstructions().At( mImpl->renderBufferIndex, i );
869
870     if ( ( renderToFbo && !instruction.mFrameBuffer ) || ( !renderToFbo && instruction.mFrameBuffer ) )
871     {
872       continue; // skip
873     }
874
875     // Mark that we will require a post-render step to be performed (includes swap-buffers).
876     status.SetNeedsPostRender( true );
877
878     Rect<int32_t> viewportRect;
879     Vector4   clearColor;
880
881     if ( instruction.mIsClearColorSet )
882     {
883       clearColor = instruction.mClearColor;
884     }
885     else
886     {
887       clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR;
888     }
889
890     Rect<int32_t> surfaceRect = mImpl->defaultSurfaceRect;
891     Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable;
892     Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable;
893     int surfaceOrientation = mImpl->defaultSurfaceOrientation;
894
895     if ( instruction.mFrameBuffer )
896     {
897       // offscreen buffer
898       if ( mImpl->currentContext != &mImpl->context )
899       {
900         // Switch to shared context for off-screen buffer
901         mImpl->currentContext = &mImpl->context;
902
903         if ( mImpl->currentContext->IsSurfacelessContextSupported() )
904         {
905           mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent();
906         }
907
908         // Clear the current cached program when the context is switched
909         mImpl->programController.ClearCurrentProgram();
910       }
911     }
912     else
913     {
914       if ( mImpl->currentContext->IsSurfacelessContextSupported() )
915       {
916         if ( mImpl->currentContext != sceneObject->GetContext() )
917         {
918           // Switch the correct context if rendering to a surface
919           mImpl->currentContext = sceneObject->GetContext();
920
921           // Clear the current cached program when the context is switched
922           mImpl->programController.ClearCurrentProgram();
923         }
924       }
925
926       surfaceRect = Rect<int32_t>( 0, 0, static_cast<int32_t>( scene.GetSize().width ), static_cast<int32_t>( scene.GetSize().height ) );
927     }
928
929     DALI_ASSERT_DEBUG( mImpl->currentContext->IsGlContextCreated() );
930
931     // reset the program matrices for all programs once per frame
932     // this ensures we will set view and projection matrix once per program per camera
933     mImpl->programController.ResetProgramMatrices();
934
935     if( instruction.mFrameBuffer )
936     {
937       instruction.mFrameBuffer->Bind( *mImpl->currentContext );
938
939       // For each offscreen buffer, update the dependency list with the new texture id used by this frame buffer.
940       for (unsigned int i0 = 0, i1 = instruction.mFrameBuffer->GetColorAttachmentCount(); i0 < i1; ++i0)
941       {
942         mImpl->textureDependencyList.PushBack( instruction.mFrameBuffer->GetTextureId(i0) );
943       }
944     }
945     else
946     {
947       mImpl->currentContext->BindFramebuffer( GL_FRAMEBUFFER, 0u );
948     }
949
950     if ( !instruction.mFrameBuffer )
951     {
952       mImpl->currentContext->Viewport( surfaceRect.x,
953                                        surfaceRect.y,
954                                        surfaceRect.width,
955                                        surfaceRect.height );
956     }
957
958     // Clear the entire color, depth and stencil buffers for the default framebuffer, if required.
959     // It is important to clear all 3 buffers when they are being used, for performance on deferred renderers
960     // e.g. previously when the depth & stencil buffers were NOT cleared, it caused the DDK to exceed a "vertex count limit",
961     // and then stall. That problem is only noticeable when rendering a large number of vertices per frame.
962     GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
963
964     mImpl->currentContext->ColorMask( true );
965
966     if( depthBufferAvailable == Integration::DepthBufferAvailable::TRUE )
967     {
968       mImpl->currentContext->DepthMask( true );
969       clearMask |= GL_DEPTH_BUFFER_BIT;
970     }
971
972     if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
973     {
974       mImpl->currentContext->ClearStencil( 0 );
975       mImpl->currentContext->StencilMask( 0xFF ); // 8 bit stencil mask, all 1's
976       clearMask |= GL_STENCIL_BUFFER_BIT;
977     }
978
979     if( !instruction.mIgnoreRenderToFbo && ( instruction.mFrameBuffer != 0 ) )
980     {
981       // Offscreen buffer rendering
982       if ( instruction.mIsViewportSet )
983       {
984         // For glViewport the lower-left corner is (0,0)
985         const int32_t y = ( instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y;
986         viewportRect.Set( instruction.mViewport.x,  y, instruction.mViewport.width, instruction.mViewport.height );
987       }
988       else
989       {
990         viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
991       }
992       surfaceOrientation = 0;
993     }
994     else // No Offscreen frame buffer rendering
995     {
996       // Check whether a viewport is specified, otherwise the full surface size is used
997       if ( instruction.mIsViewportSet )
998       {
999         // For glViewport the lower-left corner is (0,0)
1000         const int32_t y = ( surfaceRect.height - instruction.mViewport.height ) - instruction.mViewport.y;
1001         viewportRect.Set( instruction.mViewport.x,  y, instruction.mViewport.width, instruction.mViewport.height );
1002       }
1003       else
1004       {
1005         viewportRect = surfaceRect;
1006       }
1007     }
1008
1009     if( surfaceOrientation == 90 || surfaceOrientation == 270 )
1010     {
1011       int temp = viewportRect.width;
1012       viewportRect.width = viewportRect.height;
1013       viewportRect.height = temp;
1014     }
1015
1016     bool clearFullFrameRect = true;
1017     if( instruction.mFrameBuffer != 0 )
1018     {
1019       Viewport frameRect( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
1020       clearFullFrameRect = ( frameRect == viewportRect );
1021     }
1022     else
1023     {
1024       clearFullFrameRect = ( surfaceRect == viewportRect );
1025     }
1026
1027     if (!clippingRect.IsEmpty())
1028     {
1029       if (!clippingRect.Intersect(viewportRect))
1030       {
1031         DALI_LOG_ERROR("Invalid clipping rect %d %d %d %d\n", clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height);
1032         clippingRect = Rect<int>();
1033       }
1034       clearFullFrameRect = false;
1035     }
1036
1037     mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
1038
1039     if (instruction.mIsClearColorSet)
1040     {
1041       mImpl->currentContext->ClearColor(clearColor.r,
1042                                         clearColor.g,
1043                                         clearColor.b,
1044                                         clearColor.a);
1045       if (!clearFullFrameRect)
1046       {
1047         if (!clippingRect.IsEmpty())
1048         {
1049           mImpl->currentContext->SetScissorTest(true);
1050           mImpl->currentContext->Scissor(clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height);
1051           mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR);
1052           mImpl->currentContext->SetScissorTest(false);
1053         }
1054         else
1055         {
1056           mImpl->currentContext->SetScissorTest(true);
1057           mImpl->currentContext->Scissor(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
1058           mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR);
1059           mImpl->currentContext->SetScissorTest(false);
1060         }
1061       }
1062       else
1063       {
1064         mImpl->currentContext->SetScissorTest(false);
1065         mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR);
1066       }
1067     }
1068
1069     // Clear the list of bound textures
1070     mImpl->boundTextures.Clear();
1071
1072     mImpl->renderAlgorithms.ProcessRenderInstruction(
1073         instruction,
1074         *mImpl->currentContext,
1075         mImpl->renderBufferIndex,
1076         depthBufferAvailable,
1077         stencilBufferAvailable,
1078         mImpl->boundTextures,
1079         clippingRect,
1080         surfaceOrientation );
1081
1082     // Synchronise the FBO/Texture access when there are multiple contexts
1083     if ( mImpl->currentContext->IsSurfacelessContextSupported() )
1084     {
1085       // Check whether any binded texture is in the dependency list
1086       bool textureFound = false;
1087
1088       if ( mImpl->boundTextures.Count() > 0u && mImpl->textureDependencyList.Count() > 0u )
1089       {
1090         for ( auto textureId : mImpl->textureDependencyList )
1091         {
1092
1093           textureFound = std::find_if( mImpl->boundTextures.Begin(), mImpl->boundTextures.End(),
1094                                        [textureId]( GLuint id )
1095                                        {
1096                                          return textureId == id;
1097                                        } ) != mImpl->boundTextures.End();
1098         }
1099       }
1100
1101       if ( textureFound )
1102       {
1103         if ( instruction.mFrameBuffer )
1104         {
1105           // For off-screen buffer
1106
1107           // Wait until all rendering calls for the currently context are executed
1108           mImpl->glContextHelperAbstraction.WaitClient();
1109
1110           // Clear the dependency list
1111           mImpl->textureDependencyList.Clear();
1112         }
1113         else
1114         {
1115           // Worker thread lambda function
1116           auto& glContextHelperAbstraction = mImpl->glContextHelperAbstraction;
1117           auto workerFunction = [&glContextHelperAbstraction]( int workerThread )
1118           {
1119             // Switch to the shared context in the worker thread
1120             glContextHelperAbstraction.MakeSurfacelessContextCurrent();
1121
1122             // Wait until all rendering calls for the shared context are executed
1123             glContextHelperAbstraction.WaitClient();
1124
1125             // Must clear the context in the worker thread
1126             // Otherwise the shared context cannot be switched to from the render thread
1127             glContextHelperAbstraction.MakeContextNull();
1128           };
1129
1130           auto future = mImpl->threadPool->SubmitTask( 0u, workerFunction );
1131           if ( future )
1132           {
1133             mImpl->threadPool->Wait();
1134
1135             // Clear the dependency list
1136             mImpl->textureDependencyList.Clear();
1137           }
1138         }
1139       }
1140     }
1141
1142     if( instruction.mRenderTracker && instruction.mFrameBuffer )
1143     {
1144       // This will create a sync object every frame this render tracker
1145       // is alive (though it should be now be created only for
1146       // render-once render tasks)
1147       instruction.mRenderTracker->CreateSyncObject( mImpl->glSyncAbstraction );
1148       instruction.mRenderTracker = nullptr; // Only create once.
1149     }
1150
1151     if ( renderToFbo )
1152     {
1153       mImpl->currentContext->Flush();
1154     }
1155   }
1156
1157   GLenum attachments[] = { GL_DEPTH, GL_STENCIL };
1158   mImpl->currentContext->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
1159 }
1160
1161 void RenderManager::PostRender( bool uploadOnly )
1162 {
1163   if ( !uploadOnly )
1164   {
1165     if ( mImpl->currentContext->IsSurfacelessContextSupported() )
1166     {
1167       mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent();
1168     }
1169
1170     GLenum attachments[] = { GL_DEPTH, GL_STENCIL };
1171     mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
1172   }
1173
1174   //Notify RenderGeometries that rendering has finished
1175   for ( auto&& iter : mImpl->geometryContainer )
1176   {
1177     iter->OnRenderFinished();
1178   }
1179
1180   mImpl->UpdateTrackers();
1181
1182
1183   uint32_t count = 0u;
1184   for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i )
1185   {
1186     count += mImpl->sceneContainer[i]->GetRenderInstructions().Count( mImpl->renderBufferIndex );
1187   }
1188
1189   const bool haveInstructions = count > 0u;
1190
1191   // If this frame was rendered due to instructions existing, we mark this so we know to clear the next frame.
1192   mImpl->lastFrameWasRendered = haveInstructions;
1193
1194   /**
1195    * The rendering has finished; swap to the next buffer.
1196    * Ideally the update has just finished using this buffer; otherwise the render thread
1197    * should block until the update has finished.
1198    */
1199   mImpl->renderBufferIndex = (0 != mImpl->renderBufferIndex) ? 0 : 1;
1200
1201   DALI_PRINT_RENDER_END();
1202 }
1203
1204 } // namespace SceneGraph
1205
1206 } // namespace Internal
1207
1208 } // namespace Dali