[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     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       if ( mImpl->currentContext->IsSurfacelessContextSupported() )
591       {
592         mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent();
593       }
594
595       GLenum attachments[] = { GL_DEPTH, GL_STENCIL };
596       mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
597       for ( auto&& context : mImpl->surfaceContextContainer )
598       {
599         context->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
600       }
601     }
602
603     //Notify RenderGeometries that rendering has finished
604     for ( auto&& iter : mImpl->geometryContainer )
605     {
606       iter->OnRenderFinished();
607     }
608   }
609   else
610   {
611     DALI_LOG_RELEASE_INFO( "RenderManager::Render: Skip rendering [%d, %d, %d]\n", haveInstructions, mImpl->lastFrameWasRendered, forceClear );
612   }
613
614   mImpl->UpdateTrackers();
615
616   // If this frame was rendered due to instructions existing, we mark this so we know to clear the next frame.
617   mImpl->lastFrameWasRendered = haveInstructions;
618
619   /**
620    * The rendering has finished; swap to the next buffer.
621    * Ideally the update has just finished using this buffer; otherwise the render thread
622    * should block until the update has finished.
623    */
624   mImpl->renderBufferIndex = (0 != mImpl->renderBufferIndex) ? 0 : 1;
625
626   DALI_PRINT_RENDER_END();
627 }
628
629 bool GetDamagedRect( Rect<int32_t> &viewportRect, RenderInstruction& instruction, Rect<int32_t> &damagedRect )
630 {
631   // merge bounding
632   int dx1 = viewportRect.width, dx2 = 0, dy1 = viewportRect.height, dy2 = 0;
633   int checkWidth = static_cast<int>( static_cast<float>( viewportRect.width ) * partialUpdateRatio );
634   int checkHeight = static_cast<int>( static_cast<float>( viewportRect.height ) * partialUpdateRatio );
635   Rect<int32_t> screenRect;
636
637   bool isPartialUpdate = false;
638
639   const RenderListContainer::SizeType renderListCount = instruction.RenderListCount();
640   // Iterate through each render list.
641
642   for( RenderListContainer::SizeType index = 0; index < renderListCount; ++index )
643   {
644     const RenderList* renderList = instruction.GetRenderList( index );
645
646     if( renderList && !renderList->IsEmpty() && renderList->IsPartialUpdateEnabled() )
647     {
648       const std::size_t itemCount = renderList->Count();
649       for( uint32_t itemIndex = 0u; itemIndex < itemCount; ++itemIndex )
650       {
651         const RenderItem& item = renderList->GetItem( itemIndex );
652
653         if( item.mPartialUpdateEnabled )
654         {
655           isPartialUpdate = true;
656
657           screenRect = item.CalculateViewportSpaceAABB( viewportRect.width, viewportRect.height, true );
658
659           dx1 = std::min( screenRect.x, dx1 );
660           dx2 = std::max( screenRect.x + screenRect.width, dx2);
661           dy1 = std::min( screenRect.y, dy1 );
662           dy2 = std::max( screenRect.y + screenRect.height, dy2 );
663
664           if( ( dx2 - dx1 )  > checkWidth && ( dy2 - dy1 ) > checkHeight )
665           {
666             return false;
667           }
668         }
669       }
670     }
671   }
672
673   if( isPartialUpdate )
674   {
675     if( dx1 < 0.0f )
676     {
677       dx1 = 0.0f;
678     }
679     if( dy1 < 0.0f )
680     {
681       dy1 = 0.0f;
682     }
683     if( dx2 > viewportRect.width )
684     {
685       dx2 = viewportRect.width;
686     }
687     if( dy2 > viewportRect.height )
688     {
689       dy2 = viewportRect.height;
690     }
691
692     damagedRect.x = dx1;
693     damagedRect.y = dy1;
694     damagedRect.width = dx2 - dx1;
695     damagedRect.height = dy2 - dy1;
696   }
697
698   return isPartialUpdate;
699 }
700
701 void RenderManager::DoRender( RenderInstruction& instruction )
702 {
703   Rect<int32_t> viewportRect;
704   Vector4   clearColor;
705   bool isPartialUpdate = false;
706   Dali::DamagedRect damagedRect;
707   Dali::DamagedRect mergedRect;
708   Dali::ClippingBox scissorBox;
709   Dali::ClippingBox intersectRect;
710
711   if ( instruction.mIsClearColorSet )
712   {
713     clearColor = instruction.mClearColor;
714   }
715   else
716   {
717     clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR;
718   }
719
720   Rect<int32_t> surfaceRect = mImpl->defaultSurfaceRect;
721   int surfaceOrientation = mImpl->defaultSurfaceOrientation;
722   Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable;
723   Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable;
724   Integration::PartialUpdateAvailable partialUpdateAvailable = mImpl->partialUpdateAvailable;
725
726   Render::SurfaceFrameBuffer* surfaceFrameBuffer = nullptr;
727   if ( instruction.mFrameBuffer != 0 )
728   {
729     if ( instruction.mFrameBuffer->IsSurfaceBacked() )
730     {
731       surfaceFrameBuffer = static_cast<Render::SurfaceFrameBuffer*>( instruction.mFrameBuffer );
732
733       if ( !surfaceFrameBuffer->IsSurfaceValid() )
734       {
735         // Skip rendering the frame buffer if the render surface becomes invalid
736         return;
737       }
738
739       if ( mImpl->currentContext->IsSurfacelessContextSupported() )
740       {
741         Context* surfaceContext = surfaceFrameBuffer->GetContext();
742         if ( mImpl->currentContext != surfaceContext )
743         {
744           // Switch the correct context if rendering to a surface
745           mImpl->currentContext = surfaceContext;
746           surfaceFrameBuffer->MakeContextCurrent();
747
748           // Clear the current cached program when the context is switched
749           mImpl->programController.ClearCurrentProgram();
750         }
751       }
752
753       surfaceRect = Rect<int32_t>( 0, 0, static_cast<int32_t>( surfaceFrameBuffer->GetWidth() ), static_cast<int32_t>( surfaceFrameBuffer->GetHeight() ) );
754     }
755     else
756     {
757       // Switch to shared context for off-screen buffer
758       mImpl->currentContext = &mImpl->context;
759
760       if ( mImpl->currentContext->IsSurfacelessContextSupported() )
761       {
762         mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent();
763       }
764     }
765   }
766
767   DALI_ASSERT_DEBUG( mImpl->currentContext->IsGlContextCreated() );
768
769   // reset the program matrices for all programs once per frame
770   // this ensures we will set view and projection matrix once per program per camera
771   mImpl->programController.ResetProgramMatrices();
772
773   if( instruction.mFrameBuffer )
774   {
775     instruction.mFrameBuffer->Bind( *mImpl->currentContext );
776
777     if ( !instruction.mFrameBuffer->IsSurfaceBacked() )
778     {
779       // For each offscreen buffer, update the dependency list with the new texture id used by this frame buffer.
780       Render::TextureFrameBuffer* textureFrameBuffer = static_cast<Render::TextureFrameBuffer*>( instruction.mFrameBuffer );
781       for (unsigned int i0 = 0, i1 = textureFrameBuffer->GetColorAttachmentCount(); i0 < i1; ++i0)
782       {
783         mImpl->textureDependencyList.PushBack( textureFrameBuffer->GetTextureId(i0) );
784       }
785     }
786   }
787   else
788   {
789     mImpl->currentContext->BindFramebuffer( GL_FRAMEBUFFER, 0u );
790   }
791
792
793   if( surfaceFrameBuffer &&
794       partialUpdateAvailable == Integration::PartialUpdateAvailable::TRUE )
795   {
796     // Iterate through each render list.
797     if( surfaceFrameBuffer->IsPartialUpdateEnabled() )
798     {
799       isPartialUpdate = GetDamagedRect( surfaceRect, instruction, damagedRect ) ;
800     }
801
802     if( !isPartialUpdate )
803     {
804       damagedRect = surfaceRect;
805     }
806
807     surfaceFrameBuffer->SetDamagedRect( damagedRect, mergedRect );
808
809     if( mergedRect.IsEmpty() )
810     {
811       isPartialUpdate = false;
812     }
813     else
814     {
815       scissorBox.x = mergedRect.x;
816       scissorBox.y = mergedRect.y;
817       scissorBox.width = mergedRect.width;
818       scissorBox.height = mergedRect.height;
819     }
820   }
821
822   if ( surfaceFrameBuffer )
823   {
824     mImpl->currentContext->Viewport( surfaceRect.x,
825                               surfaceRect.y,
826                               surfaceRect.width,
827                               surfaceRect.height );
828   }
829
830   // Clear the entire color, depth and stencil buffers for the default framebuffer, if required.
831   // It is important to clear all 3 buffers when they are being used, for performance on deferred renderers
832   // e.g. previously when the depth & stencil buffers were NOT cleared, it caused the DDK to exceed a "vertex count limit",
833   // and then stall. That problem is only noticeable when rendering a large number of vertices per frame.
834   GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
835
836   mImpl->currentContext->ColorMask( true );
837
838   if( depthBufferAvailable == Integration::DepthBufferAvailable::TRUE )
839   {
840     mImpl->currentContext->DepthMask( true );
841     clearMask |= GL_DEPTH_BUFFER_BIT;
842   }
843
844   if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
845   {
846     mImpl->currentContext->ClearStencil( 0 );
847     mImpl->currentContext->StencilMask( 0xFF ); // 8 bit stencil mask, all 1's
848     clearMask |= GL_STENCIL_BUFFER_BIT;
849   }
850
851   if( !instruction.mIgnoreRenderToFbo && ( instruction.mFrameBuffer != 0 ) )
852   {
853     if ( instruction.mFrameBuffer->IsSurfaceBacked() ) // Surface rendering
854     {
855       if ( instruction.mIsViewportSet )
856       {
857         // For glViewport the lower-left corner is (0,0)
858         // For glViewport the lower-left corner is (0,0)
859         const int32_t y = ( surfaceRect.height - instruction.mViewport.height ) - instruction.mViewport.y;
860         viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height );
861       }
862       else
863       {
864         viewportRect = surfaceRect;
865       }
866     }
867     else // Offscreen buffer rendering
868     {
869       if ( instruction.mIsViewportSet )
870       {
871         // For glViewport the lower-left corner is (0,0)
872         const int32_t y = ( instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y;
873         viewportRect.Set( instruction.mViewport.x,  y, instruction.mViewport.width, instruction.mViewport.height );
874       }
875       else
876       {
877         viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
878       }
879       surfaceOrientation = 0;
880     }
881   }
882   else // No Offscreen frame buffer rendering
883   {
884     // Check whether a viewport is specified, otherwise the full surface size is used
885     if ( instruction.mFrameBuffer != 0 )
886     {
887       if ( instruction.mIsViewportSet )
888       {
889         // For glViewport the lower-left corner is (0,0)
890         const int32_t y = ( instruction.mFrameBuffer->GetHeight() - 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.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
896       }
897     }
898     else
899     {
900       viewportRect = surfaceRect;
901     }
902   }
903
904   bool clearFullFrameRect = true;
905   if( instruction.mFrameBuffer != 0 )
906   {
907     Viewport frameRect( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
908     clearFullFrameRect = ( frameRect == viewportRect );
909   }
910   else
911   {
912     clearFullFrameRect = ( surfaceRect == viewportRect );
913   }
914
915   if ( surfaceOrientation == 90 || surfaceOrientation == 270 )
916   {
917     int temp = viewportRect.width;
918     viewportRect.width = viewportRect.height;
919     viewportRect.height = temp;
920   }
921
922   mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
923
924   if( instruction.mIsClearColorSet )
925   {
926     mImpl->currentContext->ClearColor( clearColor.r,
927                                        clearColor.g,
928                                        clearColor.b,
929                                        clearColor.a );
930
931     if( !clearFullFrameRect )
932     {
933       mImpl->currentContext->SetScissorTest( true );
934       if( isPartialUpdate )
935       {
936         intersectRect = IntersectAABB( scissorBox, viewportRect );
937         mImpl->currentContext->Scissor( intersectRect.x, intersectRect.y, intersectRect.width, intersectRect.height );
938       }
939       else
940       {
941         mImpl->currentContext->Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height );
942       }
943       mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR );
944       mImpl->currentContext->SetScissorTest( false );
945     }
946     else
947     {
948       mImpl->currentContext->SetScissorTest( false );
949       mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR );
950     }
951   }
952
953   // Clear the list of bound textures
954   mImpl->boundTextures.Clear();
955
956   mImpl->renderAlgorithms.ProcessRenderInstruction(
957       instruction,
958       *mImpl->currentContext,
959       mImpl->renderBufferIndex,
960       depthBufferAvailable,
961       stencilBufferAvailable,
962       mImpl->boundTextures,
963       surfaceOrientation,
964       scissorBox );
965
966   // Synchronise the FBO/Texture access when there are multiple contexts
967   if ( mImpl->currentContext->IsSurfacelessContextSupported() )
968   {
969     // Check whether any binded texture is in the dependency list
970     bool textureFound = false;
971
972     if ( mImpl->boundTextures.Count() > 0u && mImpl->textureDependencyList.Count() > 0u )
973     {
974       for ( auto textureId : mImpl->textureDependencyList )
975       {
976
977         textureFound = std::find_if( mImpl->boundTextures.Begin(), mImpl->boundTextures.End(),
978                                      [textureId]( GLuint id )
979                                      {
980                                        return textureId == id;
981                                      } ) != mImpl->boundTextures.End();
982       }
983     }
984
985     if ( textureFound )
986     {
987
988       if ( !instruction.mFrameBuffer || !instruction.mFrameBuffer->IsSurfaceBacked() )
989       {
990         // For off-screen buffer
991
992         // Wait until all rendering calls for the currently context are executed
993         mImpl->glContextHelperAbstraction.WaitClient();
994
995         // Clear the dependency list
996         mImpl->textureDependencyList.Clear();
997       }
998       else
999       {
1000         // For surface-backed frame buffer
1001
1002         // Worker thread lambda function
1003         auto& glContextHelperAbstraction = mImpl->glContextHelperAbstraction;
1004         auto workerFunction = [&glContextHelperAbstraction]( int workerThread )
1005         {
1006           // Switch to the shared context in the worker thread
1007           glContextHelperAbstraction.MakeSurfacelessContextCurrent();
1008
1009           // Wait until all rendering calls for the shared context are executed
1010           glContextHelperAbstraction.WaitClient();
1011
1012           // Must clear the context in the worker thread
1013           // Otherwise the shared context cannot be switched to from the render thread
1014           glContextHelperAbstraction.MakeContextNull();
1015         };
1016
1017         auto future = mImpl->threadPool->SubmitTask( 0u, workerFunction );
1018         if ( future )
1019         {
1020           mImpl->threadPool->Wait();
1021
1022           // Clear the dependency list
1023           mImpl->textureDependencyList.Clear();
1024         }
1025       }
1026     }
1027   }
1028
1029   if( instruction.mRenderTracker && ( instruction.mFrameBuffer != 0 ) )
1030   {
1031     // This will create a sync object every frame this render tracker
1032     // is alive (though it should be now be created only for
1033     // render-once render tasks)
1034     instruction.mRenderTracker->CreateSyncObject( mImpl->glSyncAbstraction );
1035     instruction.mRenderTracker = NULL; // Only create once.
1036   }
1037
1038   if ( surfaceFrameBuffer )
1039   {
1040     surfaceFrameBuffer->PostRender();
1041   }
1042   else
1043   {
1044     mImpl->currentContext->Flush();
1045   }
1046 }
1047
1048 } // namespace SceneGraph
1049
1050 } // namespace Internal
1051
1052 } // namespace Dali