[Tizen] Implement partial update
[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     const RenderListContainer::SizeType renderListCount = instruction.RenderListCount();
804     // Iterate through each render list.
805     if( surfaceFrameBuffer->IsPartialUpdateEnabled() )
806     {
807       isPartialUpdate = GetDamagedRect( surfaceRect, instruction, damagedRect ) ;
808     }
809
810     if( !isPartialUpdate )
811     {
812       damagedRect = surfaceRect;
813     }
814
815     surfaceFrameBuffer->SetDamagedRect( damagedRect, mergedRect );
816
817     if( mergedRect.IsEmpty() )
818     {
819       isPartialUpdate = false;
820     }
821     else
822     {
823       scissorBox.x = mergedRect.x;
824       scissorBox.y = mergedRect.y;
825       scissorBox.width = mergedRect.width;
826       scissorBox.height = mergedRect.height;
827     }
828   }
829
830   if ( surfaceFrameBuffer )
831   {
832       mImpl->currentContext->Viewport( surfaceRect.x,
833                                 surfaceRect.y,
834                                 surfaceRect.width,
835                                 surfaceRect.height );
836
837
838       mImpl->currentContext->ClearColor( backgroundColor.r,
839                                   backgroundColor.g,
840                                   backgroundColor.b,
841                                   backgroundColor.a );
842   }
843
844   // Clear the entire color, depth and stencil buffers for the default framebuffer, if required.
845   // It is important to clear all 3 buffers when they are being used, for performance on deferred renderers
846   // e.g. previously when the depth & stencil buffers were NOT cleared, it caused the DDK to exceed a "vertex count limit",
847   // and then stall. That problem is only noticeable when rendering a large number of vertices per frame.
848   if( isPartialUpdate )
849   {
850     mImpl->currentContext->SetScissorTest( true );
851     mImpl->currentContext->Scissor( scissorBox.x, scissorBox.y, scissorBox.width, scissorBox.height );
852   }
853   else
854   {
855     mImpl->currentContext->SetScissorTest( false );
856   }
857
858   GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
859
860   mImpl->currentContext->ColorMask( true );
861
862   if( depthBufferAvailable == Integration::DepthBufferAvailable::TRUE )
863   {
864     mImpl->currentContext->DepthMask( true );
865     clearMask |= GL_DEPTH_BUFFER_BIT;
866   }
867
868   if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
869   {
870     mImpl->currentContext->ClearStencil( 0 );
871     mImpl->currentContext->StencilMask( 0xFF ); // 8 bit stencil mask, all 1's
872     clearMask |= GL_STENCIL_BUFFER_BIT;
873   }
874
875   mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR );
876
877   if( isPartialUpdate )
878   {
879     mImpl->currentContext->SetScissorTest( false );
880   }
881
882
883   if( !instruction.mIgnoreRenderToFbo && ( instruction.mFrameBuffer != 0 ) )
884   {
885     if ( instruction.mFrameBuffer->IsSurfaceBacked() ) // Surface rendering
886     {
887       if ( instruction.mIsViewportSet )
888       {
889         // For glViewport the lower-left corner is (0,0)
890         // For glViewport the lower-left corner is (0,0)
891         const int32_t y = ( surfaceRect.height - instruction.mViewport.height ) - instruction.mViewport.y;
892         viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height );
893       }
894       else
895       {
896         viewportRect = surfaceRect;
897       }
898     }
899     else // Offscreen buffer rendering
900     {
901       if ( instruction.mIsViewportSet )
902       {
903         // For glViewport the lower-left corner is (0,0)
904         const int32_t y = ( instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y;
905         viewportRect.Set( instruction.mViewport.x,  y, instruction.mViewport.width, instruction.mViewport.height );
906       }
907       else
908       {
909         viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
910       }
911       surfaceOrientation = 0;
912     }
913   }
914   else // No Offscreen frame buffer rendering
915   {
916     // Check whether a viewport is specified, otherwise the full surface size is used
917     if ( instruction.mFrameBuffer != 0 )
918     {
919       if ( instruction.mIsViewportSet )
920       {
921         // For glViewport the lower-left corner is (0,0)
922         const int32_t y = ( instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y;
923         viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height );
924       }
925       else
926       {
927         viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
928       }
929     }
930     else
931     {
932       viewportRect = surfaceRect;
933     }
934   }
935
936   if ( surfaceOrientation == 90 || surfaceOrientation == 270 )
937   {
938     int temp = viewportRect.width;
939     viewportRect.width = viewportRect.height;
940     viewportRect.height = temp;
941   }
942
943   mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
944
945   if ( instruction.mIsClearColorSet )
946   {
947     mImpl->currentContext->ClearColor( clearColor.r,
948                                        clearColor.g,
949                                        clearColor.b,
950                                        clearColor.a );
951
952     // Clear the viewport area only
953     mImpl->currentContext->SetScissorTest( true );
954     if( isPartialUpdate )
955     {
956       intersectRect = IntersectAABB( scissorBox, viewportRect );
957       mImpl->currentContext->Scissor( intersectRect.x, intersectRect.y, intersectRect.width, intersectRect.height );
958     }
959     else
960     {
961       mImpl->currentContext->Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height );
962     }
963     mImpl->currentContext->ColorMask( true );
964     mImpl->currentContext->Clear( GL_COLOR_BUFFER_BIT , Context::CHECK_CACHED_VALUES );
965     mImpl->currentContext->SetScissorTest( false );
966   }
967
968   // Clear the list of bound textures
969   mImpl->boundTextures.Clear();
970
971   mImpl->renderAlgorithms.ProcessRenderInstruction(
972       instruction,
973       *mImpl->currentContext,
974       mImpl->renderBufferIndex,
975       depthBufferAvailable,
976       stencilBufferAvailable,
977       mImpl->boundTextures,
978       surfaceOrientation,
979       scissorBox );
980
981   // Synchronise the FBO/Texture access when there are multiple contexts
982   if ( mImpl->currentContext->IsSurfacelessContextSupported() )
983   {
984     // Check whether any binded texture is in the dependency list
985     bool textureFound = false;
986
987     if ( mImpl->boundTextures.Count() > 0u && mImpl->textureDependencyList.Count() > 0u )
988     {
989       for ( auto textureId : mImpl->textureDependencyList )
990       {
991
992         textureFound = std::find_if( mImpl->boundTextures.Begin(), mImpl->boundTextures.End(),
993                                      [textureId]( GLuint id )
994                                      {
995                                        return textureId == id;
996                                      } ) != mImpl->boundTextures.End();
997       }
998     }
999
1000     if ( textureFound )
1001     {
1002
1003       if ( !instruction.mFrameBuffer || !instruction.mFrameBuffer->IsSurfaceBacked() )
1004       {
1005         // For off-screen buffer
1006
1007         // Wait until all rendering calls for the currently context are executed
1008         mImpl->glContextHelperAbstraction.WaitClient();
1009
1010         // Clear the dependency list
1011         mImpl->textureDependencyList.Clear();
1012       }
1013       else
1014       {
1015         // For surface-backed frame buffer
1016
1017         // Worker thread lambda function
1018         auto& glContextHelperAbstraction = mImpl->glContextHelperAbstraction;
1019         auto workerFunction = [&glContextHelperAbstraction]( int workerThread )
1020         {
1021           // Switch to the shared context in the worker thread
1022           glContextHelperAbstraction.MakeSurfacelessContextCurrent();
1023
1024           // Wait until all rendering calls for the shared context are executed
1025           glContextHelperAbstraction.WaitClient();
1026
1027           // Must clear the context in the worker thread
1028           // Otherwise the shared context cannot be switched to from the render thread
1029           glContextHelperAbstraction.MakeContextNull();
1030         };
1031
1032         auto future = mImpl->threadPool->SubmitTask( 0u, workerFunction );
1033         if ( future )
1034         {
1035           mImpl->threadPool->Wait();
1036
1037           // Clear the dependency list
1038           mImpl->textureDependencyList.Clear();
1039         }
1040       }
1041     }
1042   }
1043
1044   if( instruction.mRenderTracker && ( instruction.mFrameBuffer != 0 ) )
1045   {
1046     // This will create a sync object every frame this render tracker
1047     // is alive (though it should be now be created only for
1048     // render-once render tasks)
1049     instruction.mRenderTracker->CreateSyncObject( mImpl->glSyncAbstraction );
1050     instruction.mRenderTracker = NULL; // Only create once.
1051   }
1052
1053   if ( surfaceFrameBuffer )
1054   {
1055     surfaceFrameBuffer->PostRender();
1056   }
1057   else
1058   {
1059     mImpl->currentContext->Flush();
1060   }
1061 }
1062
1063 } // namespace SceneGraph
1064
1065 } // namespace Internal
1066
1067 } // namespace Dali