d32dbf80d19af08073e2e1522edfdb5740c357ee
[platform/core/uifw/dali-core.git] / dali / internal / render / common / render-manager.cpp
1 /*
2  * Copyright (c) 2019 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/public-api/actors/sampling.h>
26 #include <dali/public-api/common/dali-common.h>
27 #include <dali/public-api/common/stage.h>
28 #include <dali/public-api/render-tasks/render-task.h>
29 #include <dali/devel-api/threading/thread-pool.h>
30 #include <dali/integration-api/debug.h>
31 #include <dali/integration-api/core.h>
32 #include <dali/integration-api/gl-context-helper-abstraction.h>
33 #include <dali/internal/common/owner-pointer.h>
34 #include <dali/internal/render/common/render-algorithms.h>
35 #include <dali/internal/render/common/render-debug.h>
36 #include <dali/internal/render/common/render-tracker.h>
37 #include <dali/internal/render/common/render-instruction-container.h>
38 #include <dali/internal/render/common/render-instruction.h>
39 #include <dali/internal/render/gl-resources/context.h>
40 #include <dali/internal/render/queue/render-queue.h>
41 #include <dali/internal/render/renderers/render-frame-buffer.h>
42 #include <dali/internal/render/renderers/render-texture-frame-buffer.h>
43 #include <dali/internal/render/renderers/render-surface-frame-buffer.h>
44 #include <dali/internal/render/renderers/render-geometry.h>
45 #include <dali/internal/render/renderers/render-renderer.h>
46 #include <dali/internal/render/renderers/render-sampler.h>
47 #include <dali/internal/render/shaders/program-controller.h>
48
49 namespace Dali
50 {
51
52 namespace Internal
53 {
54
55 namespace SceneGraph
56 {
57
58 #if defined(DEBUG_ENABLED)
59 namespace
60 {
61 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_MANAGER" );
62 } // unnamed namespace
63 #endif
64
65 namespace
66 {
67 const float partialUpdateRatio = 0.8f; // If the partial update area exceeds 80%, change to full update.
68
69 /**
70  * @brief Find the intersection of two AABB rectangles.
71  * This is a logical AND operation. IE. The intersection is the area overlapped by both rectangles.
72  * @param[in]     aabbA                  Rectangle A
73  * @param[in]     aabbB                  Rectangle B
74  * @return                               The intersection of rectangle A & B (result is a rectangle)
75  */
76 inline ClippingBox IntersectAABB( const ClippingBox& aabbA, const ClippingBox& aabbB )
77 {
78   ClippingBox intersectionBox;
79
80   // First calculate the largest starting positions in X and Y.
81   intersectionBox.x = std::max( aabbA.x, aabbB.x );
82   intersectionBox.y = std::max( aabbA.y, aabbB.y );
83
84   // Now calculate the smallest ending positions, and take the largest starting
85   // positions from the result, to get the width and height respectively.
86   // If the two boxes do not intersect at all, then we need a 0 width and height clipping area.
87   // We use max here to clamp both width and height to >= 0 for this use-case.
88   intersectionBox.width =  std::max( std::min( aabbA.x + aabbA.width,  aabbB.x + aabbB.width  ) - intersectionBox.x, 0 );
89   intersectionBox.height = std::max( std::min( aabbA.y + aabbA.height, aabbB.y + aabbB.height ) - intersectionBox.y, 0 );
90
91   return intersectionBox;
92 }
93
94 }
95
96 /**
97  * Structure to contain internal data
98  */
99 struct RenderManager::Impl
100 {
101   Impl( Integration::GlAbstraction& glAbstraction,
102         Integration::GlSyncAbstraction& glSyncAbstraction,
103         Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
104         Integration::DepthBufferAvailable depthBufferAvailableParam,
105         Integration::StencilBufferAvailable stencilBufferAvailableParam,
106         Integration::PartialUpdateAvailable partialUpdateAvailableParam )
107   : context( glAbstraction, &surfaceContextContainer ),
108     currentContext( &context ),
109     glAbstraction( glAbstraction ),
110     glSyncAbstraction( glSyncAbstraction ),
111     glContextHelperAbstraction( glContextHelperAbstraction ),
112     renderQueue(),
113     instructions(),
114     renderAlgorithms(),
115     frameCount( 0u ),
116     renderBufferIndex( SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX ),
117     defaultSurfaceRect(),
118     rendererContainer(),
119     samplerContainer(),
120     textureContainer(),
121     frameBufferContainer(),
122     lastFrameWasRendered( false ),
123     programController( glAbstraction ),
124     depthBufferAvailable( depthBufferAvailableParam ),
125     stencilBufferAvailable( stencilBufferAvailableParam ),
126     partialUpdateAvailable( partialUpdateAvailableParam ),
127     defaultSurfaceOrientation( 0 )
128   {
129      // Create thread pool with just one thread ( there may be a need to create more threads in the future ).
130     threadPool = std::unique_ptr<Dali::ThreadPool>( new Dali::ThreadPool() );
131     threadPool->Initialize( 1u );
132   }
133
134   ~Impl()
135   {
136     threadPool.reset( nullptr ); // reset now to maintain correct destruction order
137   }
138
139   void AddRenderTracker( Render::RenderTracker* renderTracker )
140   {
141     DALI_ASSERT_DEBUG( renderTracker != NULL );
142     mRenderTrackers.PushBack( renderTracker );
143   }
144
145   void RemoveRenderTracker( Render::RenderTracker* renderTracker )
146   {
147     mRenderTrackers.EraseObject( renderTracker );
148   }
149
150   Context* CreateSurfaceContext()
151   {
152     surfaceContextContainer.PushBack( new Context( glAbstraction ) );
153     return surfaceContextContainer[ surfaceContextContainer.Count() - 1 ];
154   }
155
156   void DestroySurfaceContext( Context* surfaceContext )
157   {
158     surfaceContextContainer.EraseObject( surfaceContext );
159   }
160
161   void UpdateTrackers()
162   {
163     for( auto&& iter : mRenderTrackers )
164     {
165       iter->PollSyncObject();
166     }
167   }
168
169   // the order is important for destruction,
170   // programs are owned by context at the moment.
171   Context                                   context;                 ///< Holds the GL state of the share resource context
172   Context*                                  currentContext;          ///< Holds the GL state of the current context for rendering
173   OwnerContainer< Context* >                surfaceContextContainer; ///< List of owned contexts holding the GL state per surface
174   Integration::GlAbstraction&               glAbstraction;           ///< GL abstraction
175   Integration::GlSyncAbstraction&           glSyncAbstraction;       ///< GL sync abstraction
176   Integration::GlContextHelperAbstraction&  glContextHelperAbstraction; ///< GL context helper abstraction
177   RenderQueue                               renderQueue;             ///< A message queue for receiving messages from the update-thread.
178
179   // Render instructions describe what should be rendered during RenderManager::Render()
180   // Owned by RenderManager. Update manager updates instructions for the next frame while we render the current one
181   RenderInstructionContainer                instructions;
182   Render::RenderAlgorithms                  renderAlgorithms;        ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction
183
184   uint32_t                                  frameCount;              ///< The current frame count
185   BufferIndex                               renderBufferIndex;       ///< The index of the buffer to read from; this is opposite of the "update" buffer
186
187   Rect<int32_t>                             defaultSurfaceRect;      ///< Rectangle for the default surface we are rendering to
188
189   OwnerContainer< Render::Renderer* >       rendererContainer;       ///< List of owned renderers
190   OwnerContainer< Render::Sampler* >        samplerContainer;        ///< List of owned samplers
191   OwnerContainer< Render::Texture* >        textureContainer;        ///< List of owned textures
192   OwnerContainer< Render::FrameBuffer* >    frameBufferContainer;    ///< List of owned framebuffers
193   OwnerContainer< Render::PropertyBuffer* > propertyBufferContainer; ///< List of owned property buffers
194   OwnerContainer< Render::Geometry* >       geometryContainer;       ///< List of owned Geometries
195
196   bool                                      lastFrameWasRendered;    ///< Keeps track of the last frame being rendered due to having render instructions
197
198   OwnerContainer< Render::RenderTracker* >  mRenderTrackers;         ///< List of render trackers
199
200   ProgramController                         programController;        ///< Owner of the GL programs
201
202   Integration::DepthBufferAvailable         depthBufferAvailable;     ///< Whether the depth buffer is available
203   Integration::StencilBufferAvailable       stencilBufferAvailable;   ///< Whether the stencil buffer is available
204   Integration::PartialUpdateAvailable       partialUpdateAvailable;   ///< Whether the partial update is available
205
206   std::unique_ptr<Dali::ThreadPool>         threadPool;               ///< The thread pool
207   Vector<GLuint>                            boundTextures;            ///< The textures bound for rendering
208   Vector<GLuint>                            textureDependencyList;    ///< The dependency list of binded textures
209   int                                       defaultSurfaceOrientation; ///< defaultSurfaceOrientation for the default surface we are rendering to
210
211 };
212
213 RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction,
214                                    Integration::GlSyncAbstraction& glSyncAbstraction,
215                                    Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
216                                    Integration::DepthBufferAvailable depthBufferAvailable,
217                                    Integration::StencilBufferAvailable stencilBufferAvailable,
218                                    Integration::PartialUpdateAvailable partialUpdateAvailable )
219 {
220   RenderManager* manager = new RenderManager;
221   manager->mImpl = new Impl( glAbstraction,
222                              glSyncAbstraction,
223                              glContextHelperAbstraction,
224                              depthBufferAvailable,
225                              stencilBufferAvailable,
226                              partialUpdateAvailable );
227   return manager;
228 }
229
230 RenderManager::RenderManager()
231 : mImpl(NULL)
232 {
233 }
234
235 RenderManager::~RenderManager()
236 {
237   delete mImpl;
238 }
239
240 RenderQueue& RenderManager::GetRenderQueue()
241 {
242   return mImpl->renderQueue;
243 }
244
245 void RenderManager::ContextCreated()
246 {
247   mImpl->context.GlContextCreated();
248   mImpl->programController.GlContextCreated();
249
250   // renderers, textures and gpu buffers cannot reinitialize themselves
251   // so they rely on someone reloading the data for them
252 }
253
254 void RenderManager::ContextDestroyed()
255 {
256   mImpl->context.GlContextDestroyed();
257   mImpl->programController.GlContextDestroyed();
258
259   //Inform textures
260   for( auto&& texture : mImpl->textureContainer )
261   {
262     texture->GlContextDestroyed();
263   }
264
265   //Inform framebuffers
266   for( auto&& framebuffer : mImpl->frameBufferContainer )
267   {
268     framebuffer->GlContextDestroyed();
269   }
270
271   // inform renderers
272   for( auto&& renderer : mImpl->rendererContainer )
273   {
274     renderer->GlContextDestroyed();
275   }
276 }
277
278 void RenderManager::SetShaderSaver( ShaderSaver& upstream )
279 {
280   mImpl->programController.SetShaderSaver( upstream );
281 }
282
283 RenderInstructionContainer& RenderManager::GetRenderInstructionContainer()
284 {
285   return mImpl->instructions;
286 }
287
288 void RenderManager::SetDefaultSurfaceRect(const Rect<int32_t>& rect)
289 {
290   mImpl->defaultSurfaceRect = rect;
291 }
292
293 void RenderManager::SetDefaultSurfaceOrientation( int orientation )
294 {
295   mImpl->defaultSurfaceOrientation = orientation;
296 }
297
298 void RenderManager::AddRenderer( OwnerPointer< Render::Renderer >& renderer )
299 {
300   // Initialize the renderer as we are now in render thread
301   renderer->Initialize( mImpl->context );
302
303   mImpl->rendererContainer.PushBack( renderer.Release() );
304 }
305
306 void RenderManager::RemoveRenderer( Render::Renderer* renderer )
307 {
308   mImpl->rendererContainer.EraseObject( renderer );
309 }
310
311 void RenderManager::AddSampler( OwnerPointer< Render::Sampler >& sampler )
312 {
313   mImpl->samplerContainer.PushBack( sampler.Release() );
314 }
315
316 void RenderManager::RemoveSampler( Render::Sampler* sampler )
317 {
318   mImpl->samplerContainer.EraseObject( sampler );
319 }
320
321 void RenderManager::AddTexture( OwnerPointer< Render::Texture >& texture )
322 {
323   texture->Initialize( mImpl->context );
324   mImpl->textureContainer.PushBack( texture.Release() );
325 }
326
327 void RenderManager::RemoveTexture( Render::Texture* texture )
328 {
329   DALI_ASSERT_DEBUG( NULL != texture );
330
331   // Find the texture, use reference to pointer so we can do the erase safely
332   for ( auto&& iter : mImpl->textureContainer )
333   {
334     if ( iter == texture )
335     {
336       texture->Destroy( mImpl->context );
337       mImpl->textureContainer.Erase( &iter ); // Texture found; now destroy it
338       return;
339     }
340   }
341 }
342
343 void RenderManager::UploadTexture( Render::Texture* texture, PixelDataPtr pixelData, const Texture::UploadParams& params )
344 {
345   texture->Upload( mImpl->context, pixelData, params );
346 }
347
348 void RenderManager::GenerateMipmaps( Render::Texture* texture )
349 {
350   texture->GenerateMipmaps( mImpl->context );
351 }
352
353 void RenderManager::SetFilterMode( Render::Sampler* sampler, uint32_t minFilterMode, uint32_t magFilterMode )
354 {
355   sampler->mMinificationFilter = static_cast<Dali::FilterMode::Type>(minFilterMode);
356   sampler->mMagnificationFilter = static_cast<Dali::FilterMode::Type>(magFilterMode );
357 }
358
359 void RenderManager::SetWrapMode( Render::Sampler* sampler, uint32_t rWrapMode, uint32_t sWrapMode, uint32_t tWrapMode )
360 {
361   sampler->mRWrapMode = static_cast<Dali::WrapMode::Type>(rWrapMode);
362   sampler->mSWrapMode = static_cast<Dali::WrapMode::Type>(sWrapMode);
363   sampler->mTWrapMode = static_cast<Dali::WrapMode::Type>(tWrapMode);
364 }
365
366 void RenderManager::AddFrameBuffer( OwnerPointer< Render::FrameBuffer >& frameBuffer )
367 {
368   Render::FrameBuffer* frameBufferPtr = frameBuffer.Release();
369   mImpl->frameBufferContainer.PushBack( frameBufferPtr );
370   if ( frameBufferPtr->IsSurfaceBacked() )
371   {
372     frameBufferPtr->Initialize( *mImpl->CreateSurfaceContext() );
373   }
374   else
375   {
376     frameBufferPtr->Initialize( mImpl->context );
377   }
378 }
379
380 void RenderManager::RemoveFrameBuffer( Render::FrameBuffer* frameBuffer )
381 {
382   DALI_ASSERT_DEBUG( NULL != frameBuffer );
383
384   // Find the sampler, use reference so we can safely do the erase
385   for ( auto&& iter : mImpl->frameBufferContainer )
386   {
387     if ( iter == frameBuffer )
388     {
389       frameBuffer->Destroy( mImpl->context );
390
391       if ( frameBuffer->IsSurfaceBacked() )
392       {
393         auto surfaceFrameBuffer = static_cast<Render::SurfaceFrameBuffer*>( frameBuffer );
394         mImpl->DestroySurfaceContext( surfaceFrameBuffer->GetContext() );
395       }
396
397       mImpl->frameBufferContainer.Erase( &iter ); // frameBuffer found; now destroy it
398
399       break;
400     }
401   }
402 }
403
404 void RenderManager::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer )
405 {
406   if ( !frameBuffer->IsSurfaceBacked() )
407   {
408     auto textureFrameBuffer = static_cast<Render::TextureFrameBuffer*>( frameBuffer );
409     textureFrameBuffer->AttachColorTexture( mImpl->context, texture, mipmapLevel, layer );
410   }
411 }
412
413 void RenderManager::AddPropertyBuffer( OwnerPointer< Render::PropertyBuffer >& propertyBuffer )
414 {
415   mImpl->propertyBufferContainer.PushBack( propertyBuffer.Release() );
416 }
417
418 void RenderManager::RemovePropertyBuffer( Render::PropertyBuffer* propertyBuffer )
419 {
420   mImpl->propertyBufferContainer.EraseObject( propertyBuffer );
421 }
422
423 void RenderManager::SetPropertyBufferFormat( Render::PropertyBuffer* propertyBuffer, OwnerPointer< Render::PropertyBuffer::Format>& format )
424 {
425   propertyBuffer->SetFormat( format.Release() );
426 }
427
428 void RenderManager::SetPropertyBufferData( Render::PropertyBuffer* propertyBuffer, OwnerPointer< Vector<uint8_t> >& data, uint32_t size )
429 {
430   propertyBuffer->SetData( data.Release(), size );
431 }
432
433 void RenderManager::SetIndexBuffer( Render::Geometry* geometry, Dali::Vector<uint16_t>& indices )
434 {
435   geometry->SetIndexBuffer( indices );
436 }
437
438 void RenderManager::AddGeometry( OwnerPointer< Render::Geometry >& geometry )
439 {
440   mImpl->geometryContainer.PushBack( geometry.Release() );
441 }
442
443 void RenderManager::RemoveGeometry( Render::Geometry* geometry )
444 {
445   mImpl->geometryContainer.EraseObject( geometry );
446 }
447
448 void RenderManager::AttachVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer )
449 {
450   DALI_ASSERT_DEBUG( NULL != geometry );
451
452   // Find the geometry
453   for ( auto&& iter : mImpl->geometryContainer )
454   {
455     if ( iter == geometry )
456     {
457       iter->AddPropertyBuffer( propertyBuffer );
458       break;
459     }
460   }
461 }
462
463 void RenderManager::RemoveVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer )
464 {
465   DALI_ASSERT_DEBUG( NULL != geometry );
466
467   // Find the geometry
468   for ( auto&& iter : mImpl->geometryContainer )
469   {
470     if ( iter == geometry )
471     {
472       iter->RemovePropertyBuffer( propertyBuffer );
473       break;
474     }
475   }
476 }
477
478 void RenderManager::SetGeometryType( Render::Geometry* geometry, uint32_t geometryType )
479 {
480   geometry->SetType( Render::Geometry::Type(geometryType) );
481 }
482
483 void RenderManager::AddRenderTracker( Render::RenderTracker* renderTracker )
484 {
485   mImpl->AddRenderTracker(renderTracker);
486 }
487
488 void RenderManager::RemoveRenderTracker( Render::RenderTracker* renderTracker )
489 {
490   mImpl->RemoveRenderTracker(renderTracker);
491 }
492
493 ProgramCache* RenderManager::GetProgramCache()
494 {
495   return &(mImpl->programController);
496 }
497
498 void RenderManager::Render( Integration::RenderStatus& status, bool forceClear, bool uploadOnly )
499 {
500   DALI_PRINT_RENDER_START( mImpl->renderBufferIndex );
501
502   // Core::Render documents that GL context must be current before calling Render
503   DALI_ASSERT_DEBUG( mImpl->context.IsGlContextCreated() );
504
505   // Increment the frame count at the beginning of each frame
506   ++mImpl->frameCount;
507
508   // Process messages queued during previous update
509   mImpl->renderQueue.ProcessMessages( mImpl->renderBufferIndex );
510
511   const uint32_t count = mImpl->instructions.Count( mImpl->renderBufferIndex );
512   const bool haveInstructions = count > 0u;
513
514   DALI_LOG_INFO( gLogFilter, Debug::General,
515                  "Render: haveInstructions(%s) || mImpl->lastFrameWasRendered(%s) || forceClear(%s)\n",
516                  haveInstructions ? "true" : "false",
517                  mImpl->lastFrameWasRendered ? "true" : "false",
518                  forceClear ? "true" : "false" );
519
520   // Only render if we have instructions to render, or the last frame was rendered (and therefore a clear is required).
521   if( haveInstructions || mImpl->lastFrameWasRendered || forceClear )
522   {
523     DALI_LOG_INFO( gLogFilter, Debug::General, "Render: Processing\n" );
524
525     if ( !uploadOnly )
526     {
527       // Mark that we will require a post-render step to be performed (includes swap-buffers).
528       status.SetNeedsPostRender( true );
529     }
530
531     // Switch to the shared context
532     if ( mImpl->currentContext != &mImpl->context )
533     {
534       mImpl->currentContext = &mImpl->context;
535
536       if ( mImpl->currentContext->IsSurfacelessContextSupported() )
537       {
538         mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent();
539       }
540
541       // Clear the current cached program when the context is switched
542       mImpl->programController.ClearCurrentProgram();
543     }
544
545     // Upload the geometries
546     for( uint32_t i = 0; i < count; ++i )
547     {
548       RenderInstruction& instruction = mImpl->instructions.At( mImpl->renderBufferIndex, i );
549
550       const Matrix* viewMatrix       = instruction.GetViewMatrix( mImpl->renderBufferIndex );
551       const Matrix* projectionMatrix = instruction.GetProjectionMatrix( mImpl->renderBufferIndex );
552
553       DALI_ASSERT_DEBUG( viewMatrix );
554       DALI_ASSERT_DEBUG( projectionMatrix );
555
556       if( viewMatrix && projectionMatrix )
557       {
558         const RenderListContainer::SizeType renderListCount = instruction.RenderListCount();
559
560         // Iterate through each render list.
561         for( RenderListContainer::SizeType index = 0; index < renderListCount; ++index )
562         {
563           const RenderList* renderList = instruction.GetRenderList( index );
564
565           if( renderList && !renderList->IsEmpty() )
566           {
567             const std::size_t itemCount = renderList->Count();
568             for( uint32_t itemIndex = 0u; itemIndex < itemCount; ++itemIndex )
569             {
570               const RenderItem& item = renderList->GetItem( itemIndex );
571               if( DALI_LIKELY( item.mRenderer ) )
572               {
573                 item.mRenderer->Upload( *mImpl->currentContext );
574               }
575             }
576           }
577         }
578       }
579     }
580
581     if ( !uploadOnly )
582     {
583       for( uint32_t i = 0; i < count; ++i )
584       {
585         RenderInstruction& instruction = mImpl->instructions.At( mImpl->renderBufferIndex, i );
586
587         DoRender( instruction );
588       }
589     }
590
591     //Notify RenderGeometries that rendering has finished
592     for ( auto&& iter : mImpl->geometryContainer )
593     {
594       iter->OnRenderFinished();
595     }
596   }
597   else
598   {
599     DALI_LOG_RELEASE_INFO( "RenderManager::Render: Skip rendering [%d, %d, %d]\n", haveInstructions, mImpl->lastFrameWasRendered, forceClear );
600   }
601
602   mImpl->UpdateTrackers();
603
604   // If this frame was rendered due to instructions existing, we mark this so we know to clear the next frame.
605   mImpl->lastFrameWasRendered = haveInstructions;
606
607   /**
608    * The rendering has finished; swap to the next buffer.
609    * Ideally the update has just finished using this buffer; otherwise the render thread
610    * should block until the update has finished.
611    */
612   mImpl->renderBufferIndex = (0 != mImpl->renderBufferIndex) ? 0 : 1;
613
614   DALI_PRINT_RENDER_END();
615 }
616
617 bool GetDamagedRect( Rect<int32_t> &viewportRect, RenderInstruction& instruction, Rect<int32_t> &damagedRect )
618 {
619   // merge bounding
620   int dx1 = viewportRect.width, dx2 = 0, dy1 = viewportRect.height, dy2 = 0;
621   int checkWidth = static_cast<int>( static_cast<float>( viewportRect.width ) * partialUpdateRatio );
622   int checkHeight = static_cast<int>( static_cast<float>( viewportRect.height ) * partialUpdateRatio );
623   Rect<int32_t> screenRect;
624
625   bool isPartialUpdate = false;
626
627   const RenderListContainer::SizeType renderListCount = instruction.RenderListCount();
628   // Iterate through each render list.
629
630   for( RenderListContainer::SizeType index = 0; index < renderListCount; ++index )
631   {
632     const RenderList* renderList = instruction.GetRenderList( index );
633
634     if( renderList && !renderList->IsEmpty() && renderList->IsPartialUpdateEnabled() )
635     {
636       const std::size_t itemCount = renderList->Count();
637       for( uint32_t itemIndex = 0u; itemIndex < itemCount; ++itemIndex )
638       {
639         const RenderItem& item = renderList->GetItem( itemIndex );
640
641         if( item.mPartialUpdateEnabled )
642         {
643           isPartialUpdate = true;
644
645           screenRect = item.CalculateViewportSpaceAABB( viewportRect.width, viewportRect.height, true );
646
647           dx1 = std::min( screenRect.x, dx1 );
648           dx2 = std::max( screenRect.x + screenRect.width, dx2);
649           dy1 = std::min( screenRect.y, dy1 );
650           dy2 = std::max( screenRect.y + screenRect.height, dy2 );
651
652           if( ( dx2 - dx1 )  > checkWidth && ( dy2 - dy1 ) > checkHeight )
653           {
654             return false;
655           }
656         }
657       }
658     }
659   }
660
661   if( isPartialUpdate )
662   {
663     if( dx1 < 0.0f )
664     {
665       dx1 = 0.0f;
666     }
667     if( dy1 < 0.0f )
668     {
669       dy1 = 0.0f;
670     }
671     if( dx2 > viewportRect.width )
672     {
673       dx2 = viewportRect.width;
674     }
675     if( dy2 > viewportRect.height )
676     {
677       dy2 = viewportRect.height;
678     }
679
680     damagedRect.x = dx1;
681     damagedRect.y = dy1;
682     damagedRect.width = dx2 - dx1;
683     damagedRect.height = dy2 - dy1;
684   }
685
686   return isPartialUpdate;
687 }
688
689 void RenderManager::DoRender( RenderInstruction& instruction )
690 {
691   Rect<int32_t> viewportRect;
692   Vector4   clearColor;
693   bool isPartialUpdate = false;
694   Dali::DamagedRect damagedRect;
695   Dali::DamagedRect mergedRect;
696   Dali::ClippingBox scissorBox;
697   Dali::ClippingBox intersectRect;
698
699   if ( instruction.mIsClearColorSet )
700   {
701     clearColor = instruction.mClearColor;
702   }
703   else
704   {
705     clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR;
706   }
707
708   Rect<int32_t> surfaceRect = mImpl->defaultSurfaceRect;
709   int surfaceOrientation = mImpl->defaultSurfaceOrientation;
710   Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable;
711   Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable;
712   Integration::PartialUpdateAvailable partialUpdateAvailable = mImpl->partialUpdateAvailable;
713
714   Render::SurfaceFrameBuffer* surfaceFrameBuffer = nullptr;
715   if ( instruction.mFrameBuffer != 0 )
716   {
717     if ( instruction.mFrameBuffer->IsSurfaceBacked() )
718     {
719       surfaceFrameBuffer = static_cast<Render::SurfaceFrameBuffer*>( instruction.mFrameBuffer );
720
721       if ( !surfaceFrameBuffer->IsSurfaceValid() )
722       {
723         // Skip rendering the frame buffer if the render surface becomes invalid
724         return;
725       }
726
727       if ( mImpl->currentContext->IsSurfacelessContextSupported() )
728       {
729         Context* surfaceContext = surfaceFrameBuffer->GetContext();
730         if ( mImpl->currentContext != surfaceContext )
731         {
732           // Switch the correct context if rendering to a surface
733           mImpl->currentContext = surfaceContext;
734           surfaceFrameBuffer->MakeContextCurrent();
735
736           // Clear the current cached program when the context is switched
737           mImpl->programController.ClearCurrentProgram();
738         }
739       }
740
741       surfaceRect = Rect<int32_t>( 0, 0, static_cast<int32_t>( surfaceFrameBuffer->GetWidth() ), static_cast<int32_t>( surfaceFrameBuffer->GetHeight() ) );
742     }
743     else
744     {
745       // Switch to shared context for off-screen buffer
746       mImpl->currentContext = &mImpl->context;
747
748       if ( mImpl->currentContext->IsSurfacelessContextSupported() )
749       {
750         mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent();
751       }
752     }
753   }
754
755   DALI_ASSERT_DEBUG( mImpl->currentContext->IsGlContextCreated() );
756
757   // reset the program matrices for all programs once per frame
758   // this ensures we will set view and projection matrix once per program per camera
759   mImpl->programController.ResetProgramMatrices();
760
761   if( instruction.mFrameBuffer )
762   {
763     instruction.mFrameBuffer->Bind( *mImpl->currentContext );
764
765     if ( !instruction.mFrameBuffer->IsSurfaceBacked() )
766     {
767       // For each offscreen buffer, update the dependency list with the new texture id used by this frame buffer.
768       Render::TextureFrameBuffer* textureFrameBuffer = static_cast<Render::TextureFrameBuffer*>( instruction.mFrameBuffer );
769       mImpl->textureDependencyList.PushBack( textureFrameBuffer->GetTextureId() );
770     }
771   }
772   else
773   {
774     mImpl->currentContext->BindFramebuffer( GL_FRAMEBUFFER, 0u );
775   }
776
777
778   if( surfaceFrameBuffer &&
779       partialUpdateAvailable == Integration::PartialUpdateAvailable::TRUE )
780   {
781     // Iterate through each render list.
782     if( surfaceFrameBuffer->IsPartialUpdateEnabled() )
783     {
784       isPartialUpdate = GetDamagedRect( surfaceRect, instruction, damagedRect ) ;
785     }
786
787     if( !isPartialUpdate )
788     {
789       damagedRect = surfaceRect;
790     }
791
792     surfaceFrameBuffer->SetDamagedRect( damagedRect, mergedRect );
793
794     if( mergedRect.IsEmpty() )
795     {
796       isPartialUpdate = false;
797     }
798     else
799     {
800       scissorBox.x = mergedRect.x;
801       scissorBox.y = mergedRect.y;
802       scissorBox.width = mergedRect.width;
803       scissorBox.height = mergedRect.height;
804     }
805   }
806
807   if ( surfaceFrameBuffer )
808   {
809     mImpl->currentContext->Viewport( surfaceRect.x,
810                               surfaceRect.y,
811                               surfaceRect.width,
812                               surfaceRect.height );
813   }
814
815   // Clear the entire color, depth and stencil buffers for the default framebuffer, if required.
816   // It is important to clear all 3 buffers when they are being used, for performance on deferred renderers
817   // e.g. previously when the depth & stencil buffers were NOT cleared, it caused the DDK to exceed a "vertex count limit",
818   // and then stall. That problem is only noticeable when rendering a large number of vertices per frame.
819   GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
820
821   mImpl->currentContext->ColorMask( true );
822
823   if( depthBufferAvailable == Integration::DepthBufferAvailable::TRUE )
824   {
825     mImpl->currentContext->DepthMask( true );
826     clearMask |= GL_DEPTH_BUFFER_BIT;
827   }
828
829   if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
830   {
831     mImpl->currentContext->ClearStencil( 0 );
832     mImpl->currentContext->StencilMask( 0xFF ); // 8 bit stencil mask, all 1's
833     clearMask |= GL_STENCIL_BUFFER_BIT;
834   }
835
836   if( !instruction.mIgnoreRenderToFbo && ( instruction.mFrameBuffer != 0 ) )
837   {
838     if ( instruction.mFrameBuffer->IsSurfaceBacked() ) // Surface rendering
839     {
840       if ( instruction.mIsViewportSet )
841       {
842         // For glViewport the lower-left corner is (0,0)
843         // For glViewport the lower-left corner is (0,0)
844         const int32_t y = ( surfaceRect.height - instruction.mViewport.height ) - instruction.mViewport.y;
845         viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height );
846       }
847       else
848       {
849         viewportRect = surfaceRect;
850       }
851     }
852     else // Offscreen buffer rendering
853     {
854       if ( instruction.mIsViewportSet )
855       {
856         // For glViewport the lower-left corner is (0,0)
857         const int32_t y = ( instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y;
858         viewportRect.Set( instruction.mViewport.x,  y, instruction.mViewport.width, instruction.mViewport.height );
859       }
860       else
861       {
862         viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
863       }
864       surfaceOrientation = 0;
865     }
866   }
867   else // No Offscreen frame buffer rendering
868   {
869     // Check whether a viewport is specified, otherwise the full surface size is used
870     if ( instruction.mFrameBuffer != 0 )
871     {
872       if ( instruction.mIsViewportSet )
873       {
874         // For glViewport the lower-left corner is (0,0)
875         const int32_t y = ( instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y;
876         viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height );
877       }
878       else
879       {
880         viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
881       }
882     }
883     else
884     {
885       viewportRect = surfaceRect;
886     }
887   }
888
889   bool clearFullFrameRect = true;
890   if( instruction.mFrameBuffer != 0 )
891   {
892     Viewport frameRect( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
893     clearFullFrameRect = ( frameRect == viewportRect );
894   }
895   else
896   {
897     clearFullFrameRect = ( surfaceRect == viewportRect );
898   }
899
900   if ( surfaceOrientation == 90 || surfaceOrientation == 270 )
901   {
902     int temp = viewportRect.width;
903     viewportRect.width = viewportRect.height;
904     viewportRect.height = temp;
905   }
906
907   mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
908
909   if( instruction.mIsClearColorSet )
910   {
911     mImpl->currentContext->ClearColor( clearColor.r,
912                                        clearColor.g,
913                                        clearColor.b,
914                                        clearColor.a );
915
916     if( !clearFullFrameRect )
917     {
918       mImpl->currentContext->SetScissorTest( true );
919       if( isPartialUpdate )
920       {
921         intersectRect = IntersectAABB( scissorBox, viewportRect );
922         mImpl->currentContext->Scissor( intersectRect.x, intersectRect.y, intersectRect.width, intersectRect.height );
923       }
924       else
925       {
926         mImpl->currentContext->Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height );
927       }
928       mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR );
929       mImpl->currentContext->SetScissorTest( false );
930     }
931     else
932     {
933       mImpl->currentContext->SetScissorTest( false );
934       mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR );
935     }
936   }
937
938   // Clear the list of bound textures
939   mImpl->boundTextures.Clear();
940
941   mImpl->renderAlgorithms.ProcessRenderInstruction(
942       instruction,
943       *mImpl->currentContext,
944       mImpl->renderBufferIndex,
945       depthBufferAvailable,
946       stencilBufferAvailable,
947       mImpl->boundTextures,
948       surfaceOrientation,
949       scissorBox );
950
951   // Synchronise the FBO/Texture access when there are multiple contexts
952   if ( mImpl->currentContext->IsSurfacelessContextSupported() )
953   {
954     // Check whether any binded texture is in the dependency list
955     bool textureFound = false;
956
957     if ( mImpl->boundTextures.Count() > 0u && mImpl->textureDependencyList.Count() > 0u )
958     {
959       for ( auto textureId : mImpl->textureDependencyList )
960       {
961
962         textureFound = std::find_if( mImpl->boundTextures.Begin(), mImpl->boundTextures.End(),
963                                      [textureId]( GLuint id )
964                                      {
965                                        return textureId == id;
966                                      } ) != mImpl->boundTextures.End();
967       }
968     }
969
970     if ( textureFound )
971     {
972
973       if ( !instruction.mFrameBuffer || !instruction.mFrameBuffer->IsSurfaceBacked() )
974       {
975         // For off-screen buffer
976
977         // Wait until all rendering calls for the currently context are executed
978         mImpl->glContextHelperAbstraction.WaitClient();
979
980         // Clear the dependency list
981         mImpl->textureDependencyList.Clear();
982       }
983       else
984       {
985         // For surface-backed frame buffer
986
987         // Worker thread lambda function
988         auto& glContextHelperAbstraction = mImpl->glContextHelperAbstraction;
989         auto workerFunction = [&glContextHelperAbstraction]( int workerThread )
990         {
991           // Switch to the shared context in the worker thread
992           glContextHelperAbstraction.MakeSurfacelessContextCurrent();
993
994           // Wait until all rendering calls for the shared context are executed
995           glContextHelperAbstraction.WaitClient();
996
997           // Must clear the context in the worker thread
998           // Otherwise the shared context cannot be switched to from the render thread
999           glContextHelperAbstraction.MakeContextNull();
1000         };
1001
1002         auto future = mImpl->threadPool->SubmitTask( 0u, workerFunction );
1003         if ( future )
1004         {
1005           mImpl->threadPool->Wait();
1006
1007           // Clear the dependency list
1008           mImpl->textureDependencyList.Clear();
1009         }
1010       }
1011     }
1012   }
1013
1014   if( instruction.mRenderTracker && ( instruction.mFrameBuffer != 0 ) )
1015   {
1016     // This will create a sync object every frame this render tracker
1017     // is alive (though it should be now be created only for
1018     // render-once render tasks)
1019     instruction.mRenderTracker->CreateSyncObject( mImpl->glSyncAbstraction );
1020     instruction.mRenderTracker = NULL; // Only create once.
1021   }
1022
1023   if ( surfaceFrameBuffer )
1024   {
1025     surfaceFrameBuffer->PostRender();
1026   }
1027   else
1028   {
1029     mImpl->currentContext->Flush();
1030   }
1031
1032   if( instruction.mFrameBuffer && instruction.mFrameBuffer->IsSurfaceBacked() )
1033   {
1034     GLenum attachments[] = { GL_DEPTH, GL_STENCIL };
1035     mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
1036   }
1037 }
1038
1039 } // namespace SceneGraph
1040
1041 } // namespace Internal
1042
1043 } // namespace Dali