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