[dali_2.3.44] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / render / common / render-manager.cpp
1 /*
2  * Copyright (c) 2024 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/integration-api/core.h>
26 #include <dali/integration-api/ordered-set.h>
27 #include <dali/integration-api/trace.h>
28
29 #include <dali/internal/event/common/scene-impl.h>
30
31 #include <dali/internal/update/common/scene-graph-scene.h>
32 #include <dali/internal/update/nodes/scene-graph-layer.h>
33 #include <dali/internal/update/render-tasks/scene-graph-camera.h>
34
35 #include <dali/internal/common/owner-key-container.h>
36
37 #include <dali/internal/render/common/render-algorithms.h>
38 #include <dali/internal/render/common/render-debug.h>
39 #include <dali/internal/render/common/render-instruction.h>
40 #include <dali/internal/render/common/render-tracker.h>
41 #include <dali/internal/render/queue/render-queue.h>
42 #include <dali/internal/render/renderers/pipeline-cache.h>
43 #include <dali/internal/render/renderers/render-frame-buffer.h>
44 #include <dali/internal/render/renderers/render-texture.h>
45 #include <dali/internal/render/renderers/uniform-buffer-manager.h>
46 #include <dali/internal/render/renderers/uniform-buffer.h>
47 #include <dali/internal/render/shaders/program-controller.h>
48
49 #include <memory>
50
51 namespace Dali
52 {
53 namespace Internal
54 {
55 namespace SceneGraph
56 {
57 #if defined(DEBUG_ENABLED)
58 namespace
59 {
60 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_MANAGER");
61 } // unnamed namespace
62 #endif
63
64 namespace
65 {
66 constexpr uint32_t PROGRAM_CACHE_CLEAN_FRAME_COUNT = 300u; // 60fps * 5sec
67
68 constexpr uint32_t INITIAL_PROGRAM_CACHE_CLEAN_THRESHOLD = 64u; // Let we trigger program cache clean if the number of shader is bigger than this value
69 constexpr uint32_t MAXIMUM_PROGRAM_CACHE_CLEAN_THRESHOLD = 1024u;
70
71 constexpr uint32_t PROGRAM_CACHE_FORCE_CLEAN_FRAME_COUNT = PROGRAM_CACHE_CLEAN_FRAME_COUNT + MAXIMUM_PROGRAM_CACHE_CLEAN_THRESHOLD;
72
73 static_assert(PROGRAM_CACHE_CLEAN_FRAME_COUNT <= PROGRAM_CACHE_FORCE_CLEAN_FRAME_COUNT);
74 static_assert(MAXIMUM_PROGRAM_CACHE_CLEAN_THRESHOLD <= PROGRAM_CACHE_FORCE_CLEAN_FRAME_COUNT);
75
76 #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED)
77 constexpr uint32_t SHRINK_TO_FIT_FRAME_COUNT = (1u << 8); ///< 256 frames. Make this value as power of 2.
78
79 /**
80  * Flag whether property has changed, during the Render phase.
81  */
82 enum ContainerRemovedFlagBits : uint8_t
83 {
84   NOTHING  = 0x00,
85   RENDERER = 0x01,
86   TEXTURE  = 0x02,
87 };
88
89 /**
90  * @brief ContainerRemovedFlags alters behaviour of implementation
91  */
92 using ContainerRemovedFlags = uint8_t;
93 #endif
94
95 inline Graphics::Rect2D RecalculateScissorArea(const Graphics::Rect2D& scissorArea, int orientation, const Rect<int32_t>& viewportRect)
96 {
97   Graphics::Rect2D newScissorArea;
98
99   if(orientation == 90)
100   {
101     newScissorArea.x      = viewportRect.height - (scissorArea.y + scissorArea.height);
102     newScissorArea.y      = scissorArea.x;
103     newScissorArea.width  = scissorArea.height;
104     newScissorArea.height = scissorArea.width;
105   }
106   else if(orientation == 180)
107   {
108     newScissorArea.x      = viewportRect.width - (scissorArea.x + scissorArea.width);
109     newScissorArea.y      = viewportRect.height - (scissorArea.y + scissorArea.height);
110     newScissorArea.width  = scissorArea.width;
111     newScissorArea.height = scissorArea.height;
112   }
113   else if(orientation == 270)
114   {
115     newScissorArea.x      = scissorArea.y;
116     newScissorArea.y      = viewportRect.width - (scissorArea.x + scissorArea.width);
117     newScissorArea.width  = scissorArea.height;
118     newScissorArea.height = scissorArea.width;
119   }
120   else
121   {
122     newScissorArea.x      = scissorArea.x;
123     newScissorArea.y      = scissorArea.y;
124     newScissorArea.width  = scissorArea.width;
125     newScissorArea.height = scissorArea.height;
126   }
127   return newScissorArea;
128 }
129
130 inline Rect<int32_t> CalculateUpdateArea(RenderItem& item, BufferIndex renderBufferIndex, const Rect<int32_t>& viewportRect)
131 {
132   Vector4 updateArea;
133   if(item.mNode && item.mNode->IsTextureUpdateAreaUsed() && item.mRenderer)
134   {
135     updateArea = item.mRenderer->GetTextureUpdateArea();
136   }
137   else
138   {
139     updateArea = item.mRenderer ? item.mRenderer->GetVisualTransformedUpdateArea(renderBufferIndex, item.mUpdateArea) : item.mUpdateArea;
140   }
141
142   return RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3(updateArea.x, updateArea.y, 0.0f), Vector3(updateArea.z, updateArea.w, 0.0f), viewportRect.width, viewportRect.height);
143 }
144
145 inline void AlignDamagedRect(Rect<int32_t>& rect)
146 {
147   const int left   = rect.x;
148   const int top    = rect.y;
149   const int right  = rect.x + rect.width;
150   const int bottom = rect.y + rect.height;
151   rect.x           = (left / 16) * 16;
152   rect.y           = (top / 16) * 16;
153   rect.width       = ((right + 16) / 16) * 16 - rect.x;
154   rect.height      = ((bottom + 16) / 16) * 16 - rect.y;
155 }
156
157 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_RENDER_PROCESS, false);
158 } // namespace
159
160 /**
161  * Structure to contain internal data
162  */
163 struct RenderManager::Impl
164 {
165   Impl(Graphics::Controller&               graphicsController,
166        Integration::DepthBufferAvailable   depthBufferAvailableParam,
167        Integration::StencilBufferAvailable stencilBufferAvailableParam,
168        Integration::PartialUpdateAvailable partialUpdateAvailableParam)
169   : graphicsController(graphicsController),
170     renderAlgorithms(graphicsController),
171     programController(graphicsController),
172 #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED)
173     containerRemovedFlags(ContainerRemovedFlagBits::NOTHING),
174 #endif
175     depthBufferAvailable(depthBufferAvailableParam),
176     stencilBufferAvailable(stencilBufferAvailableParam),
177     partialUpdateAvailable(partialUpdateAvailableParam)
178   {
179     uniformBufferManager = std::make_unique<Render::UniformBufferManager>(&graphicsController);
180     pipelineCache        = std::make_unique<Render::PipelineCache>(graphicsController);
181   }
182
183   ~Impl()
184   {
185     rendererContainer.Clear(); // clear now before the program contoller and the pipeline cache are deleted
186     pipelineCache.reset();     // clear now before the program contoller is deleted
187   }
188
189   void AddRenderTracker(Render::RenderTracker* renderTracker)
190   {
191     DALI_ASSERT_DEBUG(renderTracker != nullptr);
192     mRenderTrackers.PushBack(renderTracker);
193   }
194
195   void RemoveRenderTracker(Render::RenderTracker* renderTracker)
196   {
197     mRenderTrackers.EraseObject(renderTracker);
198   }
199
200   void UpdateTrackers()
201   {
202     for(auto&& iter : mRenderTrackers)
203     {
204       iter->PollSyncObject();
205     }
206   }
207
208   /**
209    * @brief Prepare to check used count of shader and program cache.
210    * It will be used when the size of shader and program cache is too big, so we need to collect garbages.
211    * Currently, we collect and remove programs only if the number of program/shader is bigger than threshold.
212    *
213    * @note Should be called at PreRender
214    */
215   void RequestProgramCacheCleanIfNeed()
216   {
217     if(programCacheCleanRequestedFrame == 0u)
218     {
219       if(DALI_UNLIKELY(programController.GetCachedProgramCount() > programCacheCleanRequiredThreshold))
220       {
221         // Mark current frame count
222         programCacheCleanRequestedFrame = frameCount;
223
224         DALI_LOG_RELEASE_INFO("Trigger ProgramCache GC. program : [%u]\n", programController.GetCachedProgramCount());
225
226         // Prepare to collect program used flag.
227         programController.ResetUsedFlag();
228       }
229     }
230   }
231
232   /**
233    * @brief Cleanup unused program and shader cache if need.
234    *
235    * @note Should be called at PostRender
236    */
237   void ClearUnusedProgramCacheIfNeed()
238   {
239     // Remove unused shader and programs during we render PROGRAM_CACHE_CLEAN_FRAME_COUNT frames.
240     if(programCacheCleanRequestedFrame != 0u && programCacheCleanRequestedFrame + PROGRAM_CACHE_CLEAN_FRAME_COUNT - 1u <= frameCount)
241     {
242       // Clean cache incrementally, or force clean if we spend too much frames to collect them.
243       if(!programController.ClearUnusedCacheIncrementally(programCacheCleanRequestedFrame + PROGRAM_CACHE_FORCE_CLEAN_FRAME_COUNT - 1u <= frameCount))
244       {
245         // Reset current frame count.
246         programCacheCleanRequestedFrame = 0u;
247
248         DALI_LOG_RELEASE_INFO("ProgramCache GC finished. program : [%u]\n", programController.GetCachedProgramCount());
249
250         // Double up threshold
251         programCacheCleanRequiredThreshold <<= 1;
252         programCacheCleanRequiredThreshold = std::max(programCacheCleanRequiredThreshold, programController.GetCachedProgramCount());
253
254         if(programCacheCleanRequiredThreshold > MAXIMUM_PROGRAM_CACHE_CLEAN_THRESHOLD)
255         {
256           programCacheCleanRequiredThreshold = MAXIMUM_PROGRAM_CACHE_CLEAN_THRESHOLD;
257         }
258       }
259     }
260   }
261
262   /**
263    * @brief Remove all owned render context.
264    *
265    * @note Should be called at ContextDestroyed case.
266    */
267   void ContextDestroyed()
268   {
269     sceneContainer.clear();
270     renderAlgorithms.DestroyCommandBuffer();
271
272     samplerContainer.Clear();
273     frameBufferContainer.Clear();
274     vertexBufferContainer.Clear();
275     geometryContainer.Clear();
276     rendererContainer.Clear();
277     textureContainer.Clear();
278
279     mRenderTrackers.Clear();
280
281     updatedTextures.Clear();
282     textureDiscardQueue.Clear();
283
284     pipelineCache.reset(); // clear now before the program contoller is deleted
285
286     if(DALI_LIKELY(uniformBufferManager))
287     {
288       uniformBufferManager->ContextDestroyed();
289     }
290     uniformBufferManager.reset();
291   }
292
293   // the order is important for destruction,
294   Graphics::Controller&           graphicsController;
295   RenderQueue                     renderQueue;      ///< A message queue for receiving messages from the update-thread.
296   std::vector<SceneGraph::Scene*> sceneContainer;   ///< List of pointers to the scene graph objects of the scenes
297   Render::RenderAlgorithms        renderAlgorithms; ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction
298
299   Integration::OrderedSet<Render::Sampler>      samplerContainer;      ///< List of owned samplers
300   Integration::OrderedSet<Render::FrameBuffer>  frameBufferContainer;  ///< List of owned framebuffers
301   Integration::OrderedSet<Render::VertexBuffer> vertexBufferContainer; ///< List of owned vertex buffers
302   Integration::OrderedSet<Render::Geometry>     geometryContainer;     ///< List of owned Geometries
303   OwnerKeyContainer<Render::Renderer>           rendererContainer;     ///< List of owned renderers
304   OwnerKeyContainer<Render::Texture>            textureContainer;      ///< List of owned textures
305
306   Integration::OrderedSet<Render::RenderTracker> mRenderTrackers; ///< List of owned render trackers
307
308   OwnerKeyContainer<Render::Texture> textureDiscardQueue; ///< Discarded textures
309
310   ProgramController programController; ///< Owner of the programs
311
312   std::unique_ptr<Render::UniformBufferManager> uniformBufferManager; ///< The uniform buffer manager
313   std::unique_ptr<Render::PipelineCache>        pipelineCache;
314
315 #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED)
316   ContainerRemovedFlags containerRemovedFlags; ///< cumulative container removed flags during current frame
317 #endif
318
319   Integration::DepthBufferAvailable   depthBufferAvailable;   ///< Whether the depth buffer is available
320   Integration::StencilBufferAvailable stencilBufferAvailable; ///< Whether the stencil buffer is available
321   Integration::PartialUpdateAvailable partialUpdateAvailable; ///< Whether the partial update is available
322
323   Vector<Render::TextureKey> updatedTextures{}; ///< The updated texture list
324
325   uint32_t    frameCount{0u};                                                    ///< The current frame count
326   BufferIndex renderBufferIndex{SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX}; ///< The index of the buffer to read from;
327
328   uint32_t programCacheCleanRequiredThreshold{INITIAL_PROGRAM_CACHE_CLEAN_THRESHOLD}; ///< The threshold to request program cache clean up operation.
329                                                                                       ///< It will be automatically increased after we request cache clean.
330
331   uint32_t programCacheCleanRequestedFrame{0u}; ///< 0 mean, we didn't request program cache clean. otherwise, we request cache clean.
332                                                 ///< otherwise, we request program cache clean at that frame, and now we are checking reference.
333
334   bool lastFrameWasRendered{false}; ///< Keeps track of the last frame being rendered due to having render instructions
335   bool commandBufferSubmitted{false};
336 };
337
338 RenderManager* RenderManager::New(Graphics::Controller&               graphicsController,
339                                   Integration::DepthBufferAvailable   depthBufferAvailable,
340                                   Integration::StencilBufferAvailable stencilBufferAvailable,
341                                   Integration::PartialUpdateAvailable partialUpdateAvailable)
342 {
343   auto* manager  = new RenderManager;
344   manager->mImpl = new Impl(graphicsController,
345                             depthBufferAvailable,
346                             stencilBufferAvailable,
347                             partialUpdateAvailable);
348   return manager;
349 }
350
351 RenderManager::RenderManager()
352 : mImpl(nullptr)
353 {
354 }
355
356 RenderManager::~RenderManager()
357 {
358   delete mImpl;
359
360   // Ensure to release memory pool
361   Render::Renderer::ResetMemoryPool();
362   Render::Texture::ResetMemoryPool();
363 }
364
365 void RenderManager::ContextDestroyed()
366 {
367   // Call Destroy for some items.
368   for(auto&& item : mImpl->frameBufferContainer)
369   {
370     if(DALI_LIKELY(item))
371     {
372       item->Destroy();
373     }
374   }
375   for(auto&& item : mImpl->textureContainer)
376   {
377     if(DALI_LIKELY(item))
378     {
379       item->Destroy();
380     }
381   }
382
383   // Remove owned render context
384   mImpl->ContextDestroyed();
385 }
386
387 RenderQueue& RenderManager::GetRenderQueue()
388 {
389   return mImpl->renderQueue;
390 }
391
392 void RenderManager::SetShaderSaver(ShaderSaver& upstream)
393 {
394 }
395
396 void RenderManager::AddRenderer(const Render::RendererKey& renderer)
397 {
398   // Initialize the renderer as we are now in render thread
399   renderer->Initialize(mImpl->graphicsController, mImpl->programController, *(mImpl->uniformBufferManager.get()), *(mImpl->pipelineCache.get()));
400
401   mImpl->rendererContainer.PushBack(renderer);
402 }
403
404 void RenderManager::RemoveRenderer(const Render::RendererKey& renderer)
405 {
406   mImpl->rendererContainer.EraseKey(renderer);
407 #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED)
408   mImpl->containerRemovedFlags |= ContainerRemovedFlagBits::RENDERER;
409 #endif
410 }
411
412 void RenderManager::AddSampler(OwnerPointer<Render::Sampler>& sampler)
413 {
414   sampler->Initialize(mImpl->graphicsController);
415   mImpl->samplerContainer.PushBack(sampler.Release());
416 }
417
418 void RenderManager::RemoveSampler(Render::Sampler* sampler)
419 {
420   mImpl->samplerContainer.EraseObject(sampler);
421 }
422
423 void RenderManager::AddTexture(const Render::TextureKey& textureKey)
424 {
425   DALI_ASSERT_DEBUG(textureKey && "Trying to add empty texture key");
426
427   textureKey->Initialize(mImpl->graphicsController, *this);
428   mImpl->textureContainer.PushBack(textureKey);
429   mImpl->updatedTextures.PushBack(textureKey);
430 }
431
432 void RenderManager::RemoveTexture(const Render::TextureKey& textureKey)
433 {
434   DALI_ASSERT_DEBUG(textureKey && "Trying to remove empty texture key");
435
436   // Find the texture, use std::find so we can do the erase by iterator safely
437   auto iter = std::find(mImpl->textureContainer.Begin(), mImpl->textureContainer.End(), textureKey);
438
439   if(iter != mImpl->textureContainer.End())
440   {
441     // Destroy texture.
442     textureKey->Destroy();
443
444     // Transfer ownership to the discard queue, this keeps the object alive, until the render-thread has finished with it
445     mImpl->textureDiscardQueue.PushBack(mImpl->textureContainer.Release(iter));
446
447 #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED)
448     mImpl->containerRemovedFlags |= ContainerRemovedFlagBits::TEXTURE;
449 #endif
450   }
451 }
452
453 void RenderManager::UploadTexture(const Render::TextureKey& textureKey, PixelDataPtr pixelData, const Graphics::UploadParams& params)
454 {
455   DALI_ASSERT_DEBUG(textureKey && "Trying to upload to empty texture key");
456   textureKey->Upload(pixelData, params);
457
458   mImpl->updatedTextures.PushBack(textureKey);
459 }
460
461 void RenderManager::GenerateMipmaps(const Render::TextureKey& textureKey)
462 {
463   DALI_ASSERT_DEBUG(textureKey && "Trying to generate mipmaps on empty texture key");
464   textureKey->GenerateMipmaps();
465
466   mImpl->updatedTextures.PushBack(textureKey);
467 }
468
469 void RenderManager::SetTextureSize(const Render::TextureKey& textureKey, const Dali::ImageDimensions& size)
470 {
471   DALI_ASSERT_DEBUG(textureKey && "Trying to set size on empty texture key");
472   textureKey->SetWidth(size.GetWidth());
473   textureKey->SetHeight(size.GetHeight());
474 }
475
476 void RenderManager::SetTextureFormat(const Render::TextureKey& textureKey, Dali::Pixel::Format pixelFormat)
477 {
478   DALI_ASSERT_DEBUG(textureKey && "Trying to set pixel format on empty texture key");
479   textureKey->SetPixelFormat(pixelFormat);
480 }
481
482 void RenderManager::SetTextureUpdated(const Render::TextureKey& textureKey)
483 {
484   DALI_ASSERT_DEBUG(textureKey && "Trying to set updated on empty texture key");
485   textureKey->SetUpdated(true);
486
487   mImpl->updatedTextures.PushBack(textureKey);
488 }
489
490 void RenderManager::SetFilterMode(Render::Sampler* sampler, uint32_t minFilterMode, uint32_t magFilterMode)
491 {
492   sampler->SetFilterMode(static_cast<Dali::FilterMode::Type>(minFilterMode),
493                          static_cast<Dali::FilterMode::Type>(magFilterMode));
494 }
495
496 void RenderManager::SetWrapMode(Render::Sampler* sampler, uint32_t rWrapMode, uint32_t sWrapMode, uint32_t tWrapMode)
497 {
498   sampler->SetWrapMode(static_cast<Dali::WrapMode::Type>(rWrapMode),
499                        static_cast<Dali::WrapMode::Type>(sWrapMode),
500                        static_cast<Dali::WrapMode::Type>(tWrapMode));
501 }
502
503 void RenderManager::AddFrameBuffer(OwnerPointer<Render::FrameBuffer>& frameBuffer)
504 {
505   Render::FrameBuffer* frameBufferPtr = frameBuffer.Release();
506   mImpl->frameBufferContainer.PushBack(frameBufferPtr);
507   frameBufferPtr->Initialize(mImpl->graphicsController);
508 }
509
510 void RenderManager::RemoveFrameBuffer(Render::FrameBuffer* frameBuffer)
511 {
512   DALI_ASSERT_DEBUG(nullptr != frameBuffer);
513
514   // Find the framebuffer, use OrderedSet.Find so we can safely do the erase
515   auto iter = mImpl->frameBufferContainer.Find(frameBuffer);
516
517   if(iter != mImpl->frameBufferContainer.End())
518   {
519     frameBuffer->Destroy();
520     mImpl->frameBufferContainer.Erase(iter); // frameBuffer found; now destroy it
521   }
522 }
523
524 void RenderManager::InitializeScene(SceneGraph::Scene* scene)
525 {
526   scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable);
527   mImpl->sceneContainer.push_back(scene);
528   mImpl->uniformBufferManager->RegisterScene(scene);
529 }
530
531 void RenderManager::UninitializeScene(SceneGraph::Scene* scene)
532 {
533   mImpl->uniformBufferManager->UnregisterScene(scene);
534   auto iter = std::find(mImpl->sceneContainer.begin(), mImpl->sceneContainer.end(), scene);
535   if(iter != mImpl->sceneContainer.end())
536   {
537     mImpl->sceneContainer.erase(iter);
538   }
539 }
540
541 void RenderManager::SurfaceReplaced(SceneGraph::Scene* scene)
542 {
543   scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable);
544 }
545
546 void RenderManager::AttachColorTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer)
547 {
548   frameBuffer->AttachColorTexture(texture, mipmapLevel, layer);
549 }
550
551 void RenderManager::AttachDepthTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel)
552 {
553   frameBuffer->AttachDepthTexture(texture, mipmapLevel);
554 }
555
556 void RenderManager::AttachDepthStencilTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel)
557 {
558   frameBuffer->AttachDepthStencilTexture(texture, mipmapLevel);
559 }
560
561 void RenderManager::SetMultiSamplingLevelToFrameBuffer(Render::FrameBuffer* frameBuffer, uint8_t multiSamplingLevel)
562 {
563   frameBuffer->SetMultiSamplingLevel(multiSamplingLevel);
564 }
565
566 void RenderManager::AddVertexBuffer(OwnerPointer<Render::VertexBuffer>& vertexBuffer)
567 {
568   mImpl->vertexBufferContainer.PushBack(vertexBuffer.Release());
569 }
570
571 void RenderManager::RemoveVertexBuffer(Render::VertexBuffer* vertexBuffer)
572 {
573   mImpl->vertexBufferContainer.EraseObject(vertexBuffer);
574 }
575
576 void RenderManager::SetVertexBufferFormat(Render::VertexBuffer* vertexBuffer, OwnerPointer<Render::VertexBuffer::Format>& format)
577 {
578   vertexBuffer->SetFormat(format.Release());
579 }
580
581 void RenderManager::SetVertexBufferData(Render::VertexBuffer* vertexBuffer, OwnerPointer<Vector<uint8_t>>& data, uint32_t size)
582 {
583   vertexBuffer->SetData(data.Release(), size);
584 }
585
586 void RenderManager::SetVertexBufferUpdateCallback(Render::VertexBuffer* vertexBuffer, Dali::VertexBufferUpdateCallback* callback)
587 {
588   vertexBuffer->SetVertexBufferUpdateCallback(callback);
589 }
590
591 void RenderManager::SetIndexBuffer(Render::Geometry* geometry, Render::Geometry::Uint16ContainerType& indices)
592 {
593   geometry->SetIndexBuffer(indices);
594 }
595
596 void RenderManager::SetIndexBuffer(Render::Geometry* geometry, Render::Geometry::Uint32ContainerType& indices)
597 {
598   geometry->SetIndexBuffer(indices);
599 }
600
601 void RenderManager::AddGeometry(OwnerPointer<Render::Geometry>& geometry)
602 {
603   mImpl->geometryContainer.PushBack(geometry.Release());
604 }
605
606 void RenderManager::RemoveGeometry(Render::Geometry* geometry)
607 {
608   mImpl->geometryContainer.EraseObject(geometry);
609 }
610
611 void RenderManager::AttachVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer)
612 {
613   geometry->AddVertexBuffer(vertexBuffer);
614 }
615
616 void RenderManager::RemoveVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer)
617 {
618   geometry->RemoveVertexBuffer(vertexBuffer);
619 }
620
621 void RenderManager::SetGeometryType(Render::Geometry* geometry, uint32_t geometryType)
622 {
623   geometry->SetType(Render::Geometry::Type(geometryType));
624 }
625
626 void RenderManager::AddRenderTracker(Render::RenderTracker* renderTracker)
627 {
628   mImpl->AddRenderTracker(renderTracker);
629 }
630
631 void RenderManager::RemoveRenderTracker(Render::RenderTracker* renderTracker)
632 {
633   mImpl->RemoveRenderTracker(renderTracker);
634 }
635
636 void RenderManager::PreRender(Integration::RenderStatus& status, bool forceClear)
637 {
638   DALI_PRINT_RENDER_START(mImpl->renderBufferIndex);
639   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "\n\nNewFrame %d\n", mImpl->frameCount);
640
641   // Increment the frame count at the beginning of each frame
642   ++mImpl->frameCount;
643
644   // Process messages queued during previous update
645   mImpl->renderQueue.ProcessMessages(mImpl->renderBufferIndex);
646
647   uint32_t totalInstructionCount = 0u;
648   for(auto& i : mImpl->sceneContainer)
649   {
650     totalInstructionCount += i->GetRenderInstructions().Count(mImpl->renderBufferIndex);
651   }
652
653   const bool haveInstructions = totalInstructionCount > 0u;
654
655   DALI_LOG_INFO(gLogFilter, Debug::General, "Render: haveInstructions(%s) || mImpl->lastFrameWasRendered(%s) || forceClear(%s)\n", haveInstructions ? "true" : "false", mImpl->lastFrameWasRendered ? "true" : "false", forceClear ? "true" : "false");
656
657   // Only render if we have instructions to render, or the last frame was rendered (and therefore a clear is required).
658   if(haveInstructions || mImpl->lastFrameWasRendered || forceClear)
659   {
660     DALI_LOG_INFO(gLogFilter, Debug::General, "Render: Processing\n");
661
662     // Upload the geometries
663     for(auto&& geom : mImpl->geometryContainer)
664     {
665       geom->Upload(mImpl->graphicsController);
666     }
667   }
668
669   // Reset pipeline cache before rendering
670   mImpl->pipelineCache->PreRender();
671
672   // Check we need to clean up program cache
673   mImpl->RequestProgramCacheCleanIfNeed();
674
675   mImpl->commandBufferSubmitted = false;
676 }
677
678 void RenderManager::PreRender(Integration::Scene& scene, std::vector<Rect<int>>& damagedRects)
679 {
680   if(mImpl->partialUpdateAvailable != Integration::PartialUpdateAvailable::TRUE)
681   {
682     return;
683   }
684
685   Internal::Scene&   sceneInternal = GetImplementation(scene);
686   SceneGraph::Scene* sceneObject   = sceneInternal.GetSceneObject();
687
688   if(!sceneObject || sceneObject->IsRenderingSkipped())
689   {
690     // We don't need to calculate dirty rects
691     if(!sceneObject)
692     {
693       DALI_LOG_ERROR("Scene was empty handle. Skip pre-rendering\n");
694     }
695     else
696     {
697       DALI_LOG_RELEASE_INFO("RenderingSkipped was set true. Skip pre-rendering\n");
698     }
699     return;
700   }
701
702   class DamagedRectsCleaner
703   {
704   public:
705     explicit DamagedRectsCleaner(std::vector<Rect<int>>& damagedRects, Rect<int>& surfaceRect)
706     : mDamagedRects(damagedRects),
707       mSurfaceRect(surfaceRect),
708       mCleanOnReturn(true)
709     {
710     }
711
712     void SetCleanOnReturn(bool cleanOnReturn)
713     {
714       mCleanOnReturn = cleanOnReturn;
715     }
716
717     ~DamagedRectsCleaner()
718     {
719       if(mCleanOnReturn)
720       {
721         mDamagedRects.clear();
722         mDamagedRects.push_back(mSurfaceRect);
723       }
724     }
725
726   private:
727     std::vector<Rect<int>>& mDamagedRects;
728     Rect<int>               mSurfaceRect;
729     bool                    mCleanOnReturn;
730   };
731
732   Rect<int32_t> surfaceRect = sceneObject->GetSurfaceRect();
733
734   // Clean collected dirty/damaged rects on exit if 3d layer or 3d node or other conditions.
735   DamagedRectsCleaner damagedRectCleaner(damagedRects, surfaceRect);
736   bool                cleanDamagedRect = false;
737
738   Scene::ItemsDirtyRectsContainer& itemsDirtyRects = sceneObject->GetItemsDirtyRects();
739
740   if(!sceneObject->IsPartialUpdateEnabled())
741   {
742     // Clear all dirty rects
743     // The rects will be added when partial updated is enabled again
744     itemsDirtyRects.clear();
745     return;
746   }
747
748   // Mark previous dirty rects in the std::unordered_map.
749   for(auto& dirtyRectPair : itemsDirtyRects)
750   {
751     dirtyRectPair.second.visited = false;
752   }
753
754   uint32_t instructionCount = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex);
755   for(uint32_t i = 0; i < instructionCount; ++i)
756   {
757     RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i);
758
759     if(instruction.mFrameBuffer)
760     {
761       cleanDamagedRect = true;
762       continue; // TODO: reset, we don't deal with render tasks with framebuffers (for now)
763     }
764
765     const Camera* camera = instruction.GetCamera();
766     if(camera && camera->mType == Camera::DEFAULT_TYPE && camera->mTargetPosition == Camera::DEFAULT_TARGET_POSITION)
767     {
768       Vector3    position;
769       Vector3    scale;
770       Quaternion orientation;
771       camera->GetWorldMatrix(mImpl->renderBufferIndex).GetTransformComponents(position, orientation, scale);
772
773       Vector3 orientationAxis;
774       Radian  orientationAngle;
775       orientation.ToAxisAngle(orientationAxis, orientationAngle);
776
777       if(position.x > Math::MACHINE_EPSILON_10000 ||
778          position.y > Math::MACHINE_EPSILON_10000 ||
779          orientationAxis != Vector3(0.0f, 1.0f, 0.0f) ||
780          orientationAngle != ANGLE_180 ||
781          scale != Vector3(1.0f, 1.0f, 1.0f))
782       {
783         cleanDamagedRect = true;
784         continue;
785       }
786     }
787     else
788     {
789       cleanDamagedRect = true;
790       continue;
791     }
792
793     Rect<int32_t> viewportRect;
794     if(instruction.mIsViewportSet)
795     {
796       const int32_t y = (surfaceRect.height - instruction.mViewport.height) - instruction.mViewport.y;
797       viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height);
798       if(viewportRect.IsEmpty() || !viewportRect.IsValid())
799       {
800         cleanDamagedRect = true;
801         continue; // just skip funny use cases for now, empty viewport means it is set somewhere else
802       }
803     }
804     else
805     {
806       viewportRect = surfaceRect;
807     }
808
809     const Matrix* viewMatrix       = instruction.GetViewMatrix(mImpl->renderBufferIndex);
810     const Matrix* projectionMatrix = instruction.GetProjectionMatrix(mImpl->renderBufferIndex);
811     if(viewMatrix && projectionMatrix)
812     {
813       const RenderListContainer::SizeType count = instruction.RenderListCount();
814       for(RenderListContainer::SizeType index = 0u; index < count; ++index)
815       {
816         const RenderList* renderList = instruction.GetRenderList(index);
817         if(renderList)
818         {
819           if(!renderList->IsEmpty())
820           {
821             const std::size_t listCount = renderList->Count();
822             for(uint32_t listIndex = 0u; listIndex < listCount; ++listIndex)
823             {
824               RenderItem& item = renderList->GetItem(listIndex);
825               // If the item does 3D transformation, make full update
826               if(item.mUpdateArea == Vector4::ZERO)
827               {
828                 cleanDamagedRect = true;
829
830                 // Save the full rect in the damaged list. We need it when this item is removed
831                 DirtyRectKey dirtyRectKey(item.mNode, item.mRenderer);
832                 auto         dirtyRectPos = itemsDirtyRects.find(dirtyRectKey);
833                 if(dirtyRectPos != itemsDirtyRects.end())
834                 {
835                   // Replace the rect
836                   dirtyRectPos->second.visited = true;
837                   dirtyRectPos->second.rect    = surfaceRect;
838                 }
839                 else
840                 {
841                   // Else, just insert the new dirtyrect
842                   itemsDirtyRects.insert({dirtyRectKey, surfaceRect});
843                 }
844                 continue;
845               }
846
847               Rect<int>    rect;
848               DirtyRectKey dirtyRectKey(item.mNode, item.mRenderer);
849               // If the item refers to updated node or renderer.
850               if(item.mIsUpdated ||
851                  (item.mNode &&
852                   (item.mNode->Updated() || (item.mRenderer && item.mRenderer->Updated()))))
853               {
854                 item.mIsUpdated = false;
855
856                 rect = CalculateUpdateArea(item, mImpl->renderBufferIndex, viewportRect);
857                 if(rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty())
858                 {
859                   AlignDamagedRect(rect);
860
861                   // Found valid dirty rect.
862                   auto dirtyRectPos = itemsDirtyRects.find(dirtyRectKey);
863                   if(dirtyRectPos != itemsDirtyRects.end())
864                   {
865                     Rect<int> currentRect = rect;
866
867                     // Same item, merge it with the previous rect
868                     rect.Merge(dirtyRectPos->second.rect);
869
870                     // Replace the rect as current
871                     dirtyRectPos->second.visited = true;
872                     dirtyRectPos->second.rect    = currentRect;
873                   }
874                   else
875                   {
876                     // Else, just insert the new dirtyrect
877                     itemsDirtyRects.insert({dirtyRectKey, rect});
878                   }
879
880                   damagedRects.push_back(rect);
881                 }
882               }
883               else
884               {
885                 // 1. The item is not dirty, the node and renderer referenced by the item are still exist.
886                 // 2. Mark the related dirty rects as visited so they will not be removed below.
887                 auto dirtyRectPos = itemsDirtyRects.find(dirtyRectKey);
888                 if(dirtyRectPos != itemsDirtyRects.end())
889                 {
890                   dirtyRectPos->second.visited = true;
891                 }
892                 else
893                 {
894                   // The item is not in the list for some reason. Add the current rect!
895                   rect = CalculateUpdateArea(item, mImpl->renderBufferIndex, viewportRect);
896                   if(rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty())
897                   {
898                     AlignDamagedRect(rect);
899
900                     itemsDirtyRects.insert({dirtyRectKey, rect});
901                   }
902                   cleanDamagedRect = true; // And make full update at this frame
903                 }
904               }
905             }
906           }
907         }
908       }
909     }
910   }
911
912   // Check removed nodes or removed renderers dirty rects
913 #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED)
914   for(auto iter = itemsDirtyRects.begin(); iter != itemsDirtyRects.end();)
915 #else
916   // Note, std::unordered_map end iterator is validate if we call erase.
917   for(auto iter = itemsDirtyRects.cbegin(), iterEnd = itemsDirtyRects.cend(); iter != iterEnd;)
918 #endif
919   {
920     if(!iter->second.visited)
921     {
922       damagedRects.push_back(iter->second.rect);
923       iter = itemsDirtyRects.erase(iter);
924     }
925     else
926     {
927       ++iter;
928     }
929   }
930
931   if(sceneObject->IsNeededFullUpdate())
932   {
933     cleanDamagedRect = true; // And make full update at this frame
934   }
935
936   if(!cleanDamagedRect)
937   {
938     damagedRectCleaner.SetCleanOnReturn(false);
939   }
940 }
941
942 void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo)
943 {
944   SceneGraph::Scene* sceneObject = GetImplementation(scene).GetSceneObject();
945   if(!sceneObject)
946   {
947     DALI_LOG_ERROR("Scene was empty handle. Skip rendering\n");
948     return;
949   }
950
951   Rect<int> clippingRect = sceneObject->GetSurfaceRect();
952   RenderScene(status, scene, renderToFbo, clippingRect);
953 }
954
955 void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect<int>& clippingRect)
956 {
957   if(mImpl->partialUpdateAvailable == Integration::PartialUpdateAvailable::TRUE && !renderToFbo && clippingRect.IsEmpty())
958   {
959     DALI_LOG_DEBUG_INFO("ClippingRect was empty. Skip rendering\n");
960     return;
961   }
962
963   Internal::Scene&   sceneInternal = GetImplementation(scene);
964   SceneGraph::Scene* sceneObject   = sceneInternal.GetSceneObject();
965   if(!sceneObject)
966   {
967     DALI_LOG_ERROR("Scene was empty handle. Skip rendering\n");
968     return;
969   }
970
971   uint32_t instructionCount = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex);
972
973   std::vector<Graphics::RenderTarget*> targetsToPresent;
974
975   Rect<int32_t> surfaceRect = sceneObject->GetSurfaceRect();
976   if(clippingRect == surfaceRect)
977   {
978     // Full rendering case
979     // Make clippingRect empty because we're doing full rendering now if the clippingRect is empty.
980     // To reduce side effects, keep this logic now.
981     clippingRect = Rect<int>();
982   }
983
984   // Prefetch programs before we start rendering so reflection is
985   // ready, and we can pull exact size of UBO needed (no need to resize during drawing)
986   auto totalSizeCPU = 0u;
987   auto totalSizeGPU = 0u;
988
989   std::unordered_map<Graphics::Program*, Graphics::ProgramResourceBindingInfo> programUsageCount;
990
991   for(uint32_t i = 0; i < instructionCount; ++i)
992   {
993     RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i);
994
995     if((instruction.mFrameBuffer != nullptr && renderToFbo) ||
996        (instruction.mFrameBuffer == nullptr && !renderToFbo))
997     {
998       for(auto j = 0u; j < instruction.RenderListCount(); ++j)
999       {
1000         const auto& renderList = instruction.GetRenderList(j);
1001         for(auto k = 0u; k < renderList->Count(); ++k)
1002         {
1003           auto& item = renderList->GetItem(k);
1004           if(item.mRenderer && item.mRenderer->NeedsProgram())
1005           {
1006             // Prepare and store used programs for further processing
1007             auto program = item.mRenderer->PrepareProgram(instruction);
1008             if(program)
1009             {
1010               const auto& memoryRequirements = program->GetUniformBlocksMemoryRequirements();
1011
1012               // collect how many programs we use in this frame
1013               auto key = &program->GetGraphicsProgram();
1014               auto it  = programUsageCount.find(key);
1015               if(it == programUsageCount.end())
1016               {
1017                 programUsageCount[key] = Graphics::ProgramResourceBindingInfo{.program = key, .count = 1};
1018               }
1019               else
1020               {
1021                 (*it).second.count++;
1022               }
1023
1024               totalSizeCPU += memoryRequirements.totalCpuSizeRequired;
1025               totalSizeGPU += memoryRequirements.totalGpuSizeRequired;
1026             }
1027           }
1028         }
1029       }
1030     }
1031   }
1032
1033   // Fill resource binding for the command buffer
1034   std::vector<Graphics::CommandBufferResourceBinding> commandBufferResourceBindings;
1035   if(!programUsageCount.empty())
1036   {
1037     commandBufferResourceBindings.resize(programUsageCount.size());
1038     auto iter = commandBufferResourceBindings.begin();
1039     for(auto& item : programUsageCount)
1040     {
1041       iter->type           = Graphics::ResourceType::PROGRAM;
1042       iter->programBinding = &item.second;
1043       ++iter;
1044     }
1045   }
1046
1047   // Reset main algorithms command buffer
1048   mImpl->renderAlgorithms.ResetCommandBuffer(commandBufferResourceBindings.empty() ? nullptr : &commandBufferResourceBindings);
1049
1050   auto mainCommandBuffer = mImpl->renderAlgorithms.GetMainCommandBuffer();
1051
1052   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Render scene (%s), CPU:%d GPU:%d\n", renderToFbo ? "Offscreen" : "Onscreen", totalSizeCPU, totalSizeGPU);
1053
1054   auto& uboManager = mImpl->uniformBufferManager;
1055
1056   uboManager->SetCurrentSceneRenderInfo(sceneObject, renderToFbo);
1057   uboManager->Rollback(sceneObject, renderToFbo);
1058
1059   // Respec UBOs for this frame (orphan buffers or double buffer in the GPU)
1060   if(instructionCount)
1061   {
1062     uboManager->GetUniformBufferForScene(sceneObject, renderToFbo, true)->ReSpecify(totalSizeCPU);
1063     uboManager->GetUniformBufferForScene(sceneObject, renderToFbo, false)->ReSpecify(totalSizeGPU);
1064   }
1065
1066 #if defined(DEBUG_ENABLED)
1067   auto uniformBuffer1 = uboManager->GetUniformBufferForScene(sceneObject, renderToFbo, true);
1068   auto uniformBuffer2 = uboManager->GetUniformBufferForScene(sceneObject, renderToFbo, false);
1069   if(uniformBuffer1)
1070   {
1071     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "CPU buffer: Offset(%d), Cap(%d)\n", uniformBuffer1->GetCurrentOffset(), uniformBuffer1->GetCurrentCapacity());
1072   }
1073   else
1074   {
1075     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "CPU buffer: nil\n");
1076   }
1077   if(uniformBuffer2)
1078   {
1079     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GPU buffer: Offset(%d), Cap(%d)\n", uniformBuffer2->GetCurrentOffset(), uniformBuffer2->GetCurrentCapacity());
1080   }
1081   else
1082   {
1083     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GPU buffer: nil\n");
1084   }
1085 #endif
1086
1087   for(uint32_t i = 0; i < instructionCount; ++i)
1088   {
1089     RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i);
1090
1091     if((renderToFbo && !instruction.mFrameBuffer) || (!renderToFbo && instruction.mFrameBuffer))
1092     {
1093       continue; // skip
1094     }
1095
1096     // Mark that we will require a post-render step to be performed (includes swap-buffers).
1097     status.SetNeedsPostRender(true);
1098
1099     Rect<int32_t> viewportRect;
1100
1101     int32_t surfaceOrientation = sceneObject->GetSurfaceOrientation() + sceneObject->GetScreenOrientation();
1102     if(surfaceOrientation >= 360)
1103     {
1104       surfaceOrientation -= 360;
1105     }
1106
1107     // @todo Should these be part of scene?
1108     Integration::DepthBufferAvailable   depthBufferAvailable   = mImpl->depthBufferAvailable;
1109     Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable;
1110
1111     Graphics::RenderTarget*           currentRenderTarget = nullptr;
1112     Graphics::RenderPass*             currentRenderPass   = nullptr;
1113     std::vector<Graphics::ClearValue> currentClearValues{};
1114
1115     if(instruction.mFrameBuffer)
1116     {
1117       // Ensure graphics framebuffer is created, bind attachments and create render passes
1118       // Only happens once per framebuffer. If the create fails, e.g. no attachments yet,
1119       // then don't render to this framebuffer.
1120       if(!instruction.mFrameBuffer->GetGraphicsObject())
1121       {
1122         const bool created = instruction.mFrameBuffer->CreateGraphicsObjects();
1123         if(!created)
1124         {
1125           continue;
1126         }
1127       }
1128
1129       auto& clearValues = instruction.mFrameBuffer->GetGraphicsRenderPassClearValues();
1130
1131       // Set the clear color for first color attachment
1132       if(instruction.mIsClearColorSet && !clearValues.empty())
1133       {
1134         clearValues[0].color = {
1135           instruction.mClearColor.r,
1136           instruction.mClearColor.g,
1137           instruction.mClearColor.b,
1138           instruction.mClearColor.a};
1139       }
1140
1141       currentClearValues = clearValues;
1142
1143       auto loadOp = instruction.mIsClearColorSet ? Graphics::AttachmentLoadOp::CLEAR : Graphics::AttachmentLoadOp::LOAD;
1144
1145       // offscreen buffer
1146       currentRenderTarget = instruction.mFrameBuffer->GetGraphicsRenderTarget();
1147       currentRenderPass   = instruction.mFrameBuffer->GetGraphicsRenderPass(loadOp, Graphics::AttachmentStoreOp::STORE);
1148     }
1149     else // no framebuffer
1150     {
1151       // surface
1152       auto& clearValues = sceneObject->GetGraphicsRenderPassClearValues();
1153
1154       if(instruction.mIsClearColorSet)
1155       {
1156         clearValues[0].color = {
1157           instruction.mClearColor.r,
1158           instruction.mClearColor.g,
1159           instruction.mClearColor.b,
1160           instruction.mClearColor.a};
1161       }
1162
1163       currentClearValues = clearValues;
1164
1165       // @todo SceneObject should already have the depth clear / stencil clear in the clearValues array.
1166       // if the window has a depth/stencil buffer.
1167       if((depthBufferAvailable == Integration::DepthBufferAvailable::TRUE ||
1168           stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE) &&
1169          (currentClearValues.size() <= 1))
1170       {
1171         currentClearValues.emplace_back();
1172         currentClearValues.back().depthStencil.depth   = 0;
1173         currentClearValues.back().depthStencil.stencil = 0;
1174       }
1175
1176       auto loadOp = instruction.mIsClearColorSet ? Graphics::AttachmentLoadOp::CLEAR : Graphics::AttachmentLoadOp::LOAD;
1177
1178       currentRenderTarget = sceneObject->GetSurfaceRenderTarget();
1179       currentRenderPass   = sceneObject->GetGraphicsRenderPass(loadOp, Graphics::AttachmentStoreOp::STORE);
1180     }
1181
1182     targetsToPresent.emplace_back(currentRenderTarget);
1183
1184     if(!instruction.mIgnoreRenderToFbo && (instruction.mFrameBuffer != nullptr))
1185     {
1186       // Offscreen buffer rendering
1187       if(instruction.mIsViewportSet)
1188       {
1189         // For Viewport the lower-left corner is (0,0)
1190         const int32_t y = (instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height) - instruction.mViewport.y;
1191         viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height);
1192       }
1193       else
1194       {
1195         viewportRect.Set(0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight());
1196       }
1197       surfaceOrientation = 0;
1198     }
1199     else // No Offscreen frame buffer rendering
1200     {
1201       // Check whether a viewport is specified, otherwise the full surface size is used
1202       if(instruction.mIsViewportSet)
1203       {
1204         // For Viewport the lower-left corner is (0,0)
1205         const int32_t y = (surfaceRect.height - instruction.mViewport.height) - instruction.mViewport.y;
1206         viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height);
1207       }
1208       else
1209       {
1210         viewportRect = surfaceRect;
1211       }
1212     }
1213
1214     // Set surface orientation
1215     // @todo Inform graphics impl by another route.
1216     // was: mImpl->currentContext->SetSurfaceOrientation(surfaceOrientation);
1217
1218     /*** Clear region of framebuffer or surface before drawing ***/
1219     bool clearFullFrameRect = (surfaceRect == viewportRect);
1220     if(instruction.mFrameBuffer != nullptr)
1221     {
1222       Viewport frameRect(0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight());
1223       clearFullFrameRect = (frameRect == viewportRect);
1224     }
1225
1226     if(!clippingRect.IsEmpty())
1227     {
1228       if(!clippingRect.Intersect(viewportRect))
1229       {
1230         DALI_LOG_ERROR("Invalid clipping rect %d %d %d %d\n", clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height);
1231         clippingRect = Rect<int>();
1232       }
1233       clearFullFrameRect = false;
1234     }
1235
1236     Graphics::Rect2D scissorArea{viewportRect.x, viewportRect.y, uint32_t(viewportRect.width), uint32_t(viewportRect.height)};
1237     if(instruction.mIsClearColorSet)
1238     {
1239       if(!clearFullFrameRect)
1240       {
1241         if(!clippingRect.IsEmpty())
1242         {
1243           scissorArea = {clippingRect.x, clippingRect.y, uint32_t(clippingRect.width), uint32_t(clippingRect.height)};
1244         }
1245       }
1246     }
1247
1248     // Scissor's value should be set based on the default system coordinates.
1249     // When the surface is rotated, the input values already were set with the rotated angle.
1250     // So, re-calculation is needed.
1251     scissorArea = RecalculateScissorArea(scissorArea, surfaceOrientation, surfaceRect);
1252
1253     // Begin render pass
1254     mainCommandBuffer->BeginRenderPass(
1255       currentRenderPass,
1256       currentRenderTarget,
1257       scissorArea,
1258       currentClearValues);
1259
1260     // Note, don't set the viewport/scissor on the primary command buffer.
1261
1262     mImpl->renderAlgorithms.ProcessRenderInstruction(
1263       instruction,
1264       mImpl->renderBufferIndex,
1265       depthBufferAvailable,
1266       stencilBufferAvailable,
1267       viewportRect,
1268       clippingRect,
1269       surfaceOrientation,
1270       Uint16Pair(surfaceRect.width, surfaceRect.height),
1271       currentRenderPass,
1272       currentRenderTarget);
1273
1274     Graphics::SyncObject* syncObject{nullptr};
1275     // If the render instruction has an associated render tracker (owned separately)
1276     // and framebuffer, create a one shot sync object, and use it to determine when
1277     // the render pass has finished executing on GPU.
1278     if(instruction.mRenderTracker && instruction.mFrameBuffer)
1279     {
1280       syncObject                 = instruction.mRenderTracker->CreateSyncObject(mImpl->graphicsController);
1281       instruction.mRenderTracker = nullptr;
1282     }
1283     mainCommandBuffer->EndRenderPass(syncObject);
1284   }
1285
1286   if(targetsToPresent.size() > 0u)
1287   {
1288     DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_RENDER_FINISHED", [&](std::ostringstream& oss)
1289                                             { oss << "[" << targetsToPresent.size() << "]"; });
1290   }
1291
1292   // Flush UBOs
1293   mImpl->uniformBufferManager->Flush(sceneObject, renderToFbo);
1294   mImpl->renderAlgorithms.SubmitCommandBuffer();
1295   mImpl->commandBufferSubmitted = true;
1296
1297   if(targetsToPresent.size() > 0u)
1298   {
1299     std::sort(targetsToPresent.begin(), targetsToPresent.end());
1300
1301     Graphics::RenderTarget* rt = nullptr;
1302     for(auto& target : targetsToPresent)
1303     {
1304       if(target != rt)
1305       {
1306         mImpl->graphicsController.PresentRenderTarget(target);
1307         rt = target;
1308       }
1309     }
1310
1311     DALI_TRACE_END(gTraceFilter, "DALI_RENDER_FINISHED");
1312   }
1313 }
1314
1315 void RenderManager::PostRender()
1316 {
1317   if(!mImpl->commandBufferSubmitted)
1318   {
1319     // Rendering is skipped but there may be pending tasks. Flush them.
1320     Graphics::SubmitInfo submitInfo;
1321     submitInfo.cmdBuffer.clear(); // Only flush
1322     submitInfo.flags = 0 | Graphics::SubmitFlagBits::FLUSH;
1323     mImpl->graphicsController.SubmitCommandBuffers(submitInfo);
1324
1325     mImpl->commandBufferSubmitted = true;
1326   }
1327
1328   // Notify RenderGeometries that rendering has finished
1329   for(auto&& iter : mImpl->geometryContainer)
1330   {
1331     iter->OnRenderFinished();
1332   }
1333
1334   // Notify updated RenderTexture that rendering has finished
1335   for(auto&& iter : mImpl->updatedTextures)
1336   {
1337     iter->OnRenderFinished();
1338   }
1339   mImpl->updatedTextures.Clear();
1340
1341   // Remove discarded textures after OnRenderFinished called
1342   mImpl->textureDiscardQueue.Clear();
1343
1344   mImpl->UpdateTrackers();
1345
1346   uint32_t count = 0u;
1347   for(auto& scene : mImpl->sceneContainer)
1348   {
1349     count += scene->GetRenderInstructions().Count(mImpl->renderBufferIndex);
1350   }
1351
1352   mImpl->ClearUnusedProgramCacheIfNeed();
1353
1354 #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED)
1355   // Shrink relevant containers if required.
1356   if(mImpl->containerRemovedFlags & ContainerRemovedFlagBits::RENDERER)
1357   {
1358     mImpl->rendererContainer.ShrinkToFitIfNeeded();
1359   }
1360   if(mImpl->containerRemovedFlags & ContainerRemovedFlagBits::TEXTURE)
1361   {
1362     mImpl->textureContainer.ShrinkToFitIfNeeded();
1363   }
1364
1365   // Both containers always have empty slots, so we can shrink them.
1366   // Note that we don't need to release it every frames. So just check every specific frames
1367   if((mImpl->frameCount & (SHRINK_TO_FIT_FRAME_COUNT - 1)) == 0)
1368   {
1369     mImpl->updatedTextures.ShrinkToFit();
1370     mImpl->textureDiscardQueue.ShrinkToFit();
1371   }
1372
1373   // Reset flag
1374   mImpl->containerRemovedFlags = ContainerRemovedFlagBits::NOTHING;
1375 #endif
1376
1377   const bool haveInstructions = count > 0u;
1378
1379   // If this frame was rendered due to instructions existing, we mark this so we know to clear the next frame.
1380   mImpl->lastFrameWasRendered = haveInstructions;
1381
1382   /**
1383    * The rendering has finished; swap to the next buffer.
1384    * Ideally the update has just finished using this buffer; otherwise the render thread
1385    * should block until the update has finished.
1386    */
1387   mImpl->renderBufferIndex = (0 != mImpl->renderBufferIndex) ? 0 : 1;
1388
1389   DALI_PRINT_RENDER_END();
1390 }
1391
1392 } // namespace SceneGraph
1393
1394 } // namespace Internal
1395
1396 } // namespace Dali