[Tizen] Partial rendering rotation does not work
[platform/core/uifw/dali-core.git] / dali / internal / render / common / render-manager.cpp
1 /*
2  * Copyright (c) 2021 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/devel-api/threading/thread-pool.h>
26 #include <dali/integration-api/core.h>
27 #include <dali/integration-api/gl-context-helper-abstraction.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/render-tasks/scene-graph-camera.h>
33
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-instruction.h>
37 #include <dali/internal/render/common/render-tracker.h>
38 #include <dali/internal/render/queue/render-queue.h>
39 #include <dali/internal/render/renderers/render-frame-buffer.h>
40 #include <dali/internal/render/renderers/render-texture.h>
41 #include <dali/internal/render/renderers/shader-cache.h>
42 #include <dali/internal/render/renderers/uniform-buffer-manager.h>
43 #include <dali/internal/render/renderers/uniform-buffer-view-pool.h>
44 #include <dali/internal/render/shaders/program-controller.h>
45
46 #include <dali/internal/render/renderers/uniform-buffer-manager.h>
47
48 namespace Dali
49 {
50 namespace Internal
51 {
52 namespace SceneGraph
53 {
54 #if defined(DEBUG_ENABLED)
55 namespace
56 {
57 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_MANAGER");
58 } // unnamed namespace
59 #endif
60
61 /**
62  * Structure to contain internal data
63  */
64 struct RenderManager::Impl
65 {
66   Impl(Graphics::Controller&               graphicsController,
67        Integration::DepthBufferAvailable   depthBufferAvailableParam,
68        Integration::StencilBufferAvailable stencilBufferAvailableParam,
69        Integration::PartialUpdateAvailable partialUpdateAvailableParam)
70   : graphicsController(graphicsController),
71     renderQueue(),
72     renderAlgorithms(graphicsController),
73     frameCount(0u),
74     renderBufferIndex(SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX),
75     rendererContainer(),
76     samplerContainer(),
77     textureContainer(),
78     frameBufferContainer(),
79     lastFrameWasRendered(false),
80     programController(graphicsController),
81     shaderCache(graphicsController),
82     depthBufferAvailable(depthBufferAvailableParam),
83     stencilBufferAvailable(stencilBufferAvailableParam),
84     partialUpdateAvailable(partialUpdateAvailableParam)
85   {
86     // Create thread pool with just one thread ( there may be a need to create more threads in the future ).
87     threadPool = std::unique_ptr<Dali::ThreadPool>(new Dali::ThreadPool());
88     threadPool->Initialize(1u);
89
90     uniformBufferManager.reset(new Render::UniformBufferManager(&graphicsController));
91   }
92
93   ~Impl()
94   {
95     threadPool.reset(nullptr); // reset now to maintain correct destruction order
96   }
97
98   void AddRenderTracker(Render::RenderTracker* renderTracker)
99   {
100     DALI_ASSERT_DEBUG(renderTracker != nullptr);
101     mRenderTrackers.PushBack(renderTracker);
102   }
103
104   void RemoveRenderTracker(Render::RenderTracker* renderTracker)
105   {
106     mRenderTrackers.EraseObject(renderTracker);
107   }
108
109   void UpdateTrackers()
110   {
111     for(auto&& iter : mRenderTrackers)
112     {
113       iter->PollSyncObject();
114     }
115   }
116
117   // the order is important for destruction,
118   Graphics::Controller& graphicsController;
119   RenderQueue           renderQueue; ///< A message queue for receiving messages from the update-thread.
120
121   std::vector<SceneGraph::Scene*> sceneContainer; ///< List of pointers to the scene graph objects of the scenes
122
123   Render::RenderAlgorithms renderAlgorithms; ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction
124
125   uint32_t    frameCount;        ///< The current frame count
126   BufferIndex renderBufferIndex; ///< The index of the buffer to read from; this is opposite of the "update" buffer
127
128   OwnerContainer<Render::Renderer*>     rendererContainer;     ///< List of owned renderers
129   OwnerContainer<Render::Sampler*>      samplerContainer;      ///< List of owned samplers
130   OwnerContainer<Render::Texture*>      textureContainer;      ///< List of owned textures
131   OwnerContainer<Render::FrameBuffer*>  frameBufferContainer;  ///< List of owned framebuffers
132   OwnerContainer<Render::VertexBuffer*> vertexBufferContainer; ///< List of owned vertex buffers
133   OwnerContainer<Render::Geometry*>     geometryContainer;     ///< List of owned Geometries
134
135   bool lastFrameWasRendered; ///< Keeps track of the last frame being rendered due to having render instructions
136
137   OwnerContainer<Render::RenderTracker*> mRenderTrackers; ///< List of render trackers
138
139   ProgramController   programController; ///< Owner of the GL programs
140   Render::ShaderCache shaderCache;       ///< The cache for the graphics shaders
141
142   std::unique_ptr<Render::UniformBufferManager> uniformBufferManager; ///< The uniform buffer manager
143
144   Integration::DepthBufferAvailable   depthBufferAvailable;   ///< Whether the depth buffer is available
145   Integration::StencilBufferAvailable stencilBufferAvailable; ///< Whether the stencil buffer is available
146   Integration::PartialUpdateAvailable partialUpdateAvailable; ///< Whether the partial update is available
147
148   std::unique_ptr<Dali::ThreadPool> threadPool;            ///< The thread pool
149   Vector<Graphics::Texture*>        boundTextures;         ///< The textures bound for rendering
150   Vector<Graphics::Texture*>        textureDependencyList; ///< The dependency list of bound textures
151 };
152
153 RenderManager* RenderManager::New(Graphics::Controller&               graphicsController,
154                                   Integration::DepthBufferAvailable   depthBufferAvailable,
155                                   Integration::StencilBufferAvailable stencilBufferAvailable,
156                                   Integration::PartialUpdateAvailable partialUpdateAvailable)
157 {
158   auto* manager  = new RenderManager;
159   manager->mImpl = new Impl(graphicsController,
160                             depthBufferAvailable,
161                             stencilBufferAvailable,
162                             partialUpdateAvailable);
163   return manager;
164 }
165
166 RenderManager::RenderManager()
167 : mImpl(nullptr)
168 {
169 }
170
171 RenderManager::~RenderManager()
172 {
173   delete mImpl;
174 }
175
176 RenderQueue& RenderManager::GetRenderQueue()
177 {
178   return mImpl->renderQueue;
179 }
180
181 void RenderManager::SetShaderSaver(ShaderSaver& upstream)
182 {
183 }
184
185 void RenderManager::AddRenderer(OwnerPointer<Render::Renderer>& renderer)
186 {
187   // Initialize the renderer as we are now in render thread
188   renderer->Initialize(mImpl->graphicsController, mImpl->programController, mImpl->shaderCache, *(mImpl->uniformBufferManager.get()));
189
190   mImpl->rendererContainer.PushBack(renderer.Release());
191 }
192
193 void RenderManager::RemoveRenderer(Render::Renderer* renderer)
194 {
195   mImpl->rendererContainer.EraseObject(renderer);
196 }
197
198 void RenderManager::AddSampler(OwnerPointer<Render::Sampler>& sampler)
199 {
200   sampler->Initialize(mImpl->graphicsController);
201   mImpl->samplerContainer.PushBack(sampler.Release());
202 }
203
204 void RenderManager::RemoveSampler(Render::Sampler* sampler)
205 {
206   mImpl->samplerContainer.EraseObject(sampler);
207 }
208
209 void RenderManager::AddTexture(OwnerPointer<Render::Texture>& texture)
210 {
211   texture->Initialize(mImpl->graphicsController);
212   mImpl->textureContainer.PushBack(texture.Release());
213 }
214
215 void RenderManager::RemoveTexture(Render::Texture* texture)
216 {
217   DALI_ASSERT_DEBUG(NULL != texture);
218
219   // Find the texture, use reference to pointer so we can do the erase safely
220   for(auto&& iter : mImpl->textureContainer)
221   {
222     if(iter == texture)
223     {
224       texture->Destroy();
225       mImpl->textureContainer.Erase(&iter); // Texture found; now destroy it
226       return;
227     }
228   }
229 }
230
231 void RenderManager::UploadTexture(Render::Texture* texture, PixelDataPtr pixelData, const Texture::UploadParams& params)
232 {
233   texture->Upload(pixelData, params);
234 }
235
236 void RenderManager::GenerateMipmaps(Render::Texture* texture)
237 {
238   texture->GenerateMipmaps();
239 }
240
241 void RenderManager::SetFilterMode(Render::Sampler* sampler, uint32_t minFilterMode, uint32_t magFilterMode)
242 {
243   sampler->SetFilterMode(static_cast<Dali::FilterMode::Type>(minFilterMode),
244                          static_cast<Dali::FilterMode::Type>(magFilterMode));
245 }
246
247 void RenderManager::SetWrapMode(Render::Sampler* sampler, uint32_t rWrapMode, uint32_t sWrapMode, uint32_t tWrapMode)
248 {
249   sampler->SetWrapMode(static_cast<Dali::WrapMode::Type>(rWrapMode),
250                        static_cast<Dali::WrapMode::Type>(sWrapMode),
251                        static_cast<Dali::WrapMode::Type>(tWrapMode));
252 }
253
254 void RenderManager::AddFrameBuffer(OwnerPointer<Render::FrameBuffer>& frameBuffer)
255 {
256   Render::FrameBuffer* frameBufferPtr = frameBuffer.Release();
257   mImpl->frameBufferContainer.PushBack(frameBufferPtr);
258   frameBufferPtr->Initialize(mImpl->graphicsController);
259 }
260
261 void RenderManager::RemoveFrameBuffer(Render::FrameBuffer* frameBuffer)
262 {
263   DALI_ASSERT_DEBUG(nullptr != frameBuffer);
264
265   // Find the sampler, use reference so we can safely do the erase
266   for(auto&& iter : mImpl->frameBufferContainer)
267   {
268     if(iter == frameBuffer)
269     {
270       frameBuffer->Destroy();
271       mImpl->frameBufferContainer.Erase(&iter); // frameBuffer found; now destroy it
272
273       break;
274     }
275   }
276 }
277
278 void RenderManager::InitializeScene(SceneGraph::Scene* scene)
279 {
280   scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable);
281   mImpl->sceneContainer.push_back(scene);
282 }
283
284 void RenderManager::UninitializeScene(SceneGraph::Scene* scene)
285 {
286   auto iter = std::find(mImpl->sceneContainer.begin(), mImpl->sceneContainer.end(), scene);
287   if(iter != mImpl->sceneContainer.end())
288   {
289     mImpl->sceneContainer.erase(iter);
290   }
291 }
292
293 void RenderManager::SurfaceReplaced(SceneGraph::Scene* scene)
294 {
295   scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable);
296 }
297
298 void RenderManager::AttachColorTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer)
299 {
300   frameBuffer->AttachColorTexture(texture, mipmapLevel, layer);
301 }
302
303 void RenderManager::AttachDepthTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel)
304 {
305   frameBuffer->AttachDepthTexture(texture, mipmapLevel);
306 }
307
308 void RenderManager::AttachDepthStencilTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel)
309 {
310   frameBuffer->AttachDepthStencilTexture(texture, mipmapLevel);
311 }
312
313 void RenderManager::AddVertexBuffer(OwnerPointer<Render::VertexBuffer>& vertexBuffer)
314 {
315   mImpl->vertexBufferContainer.PushBack(vertexBuffer.Release());
316 }
317
318 void RenderManager::RemoveVertexBuffer(Render::VertexBuffer* vertexBuffer)
319 {
320   mImpl->vertexBufferContainer.EraseObject(vertexBuffer);
321 }
322
323 void RenderManager::SetVertexBufferFormat(Render::VertexBuffer* vertexBuffer, OwnerPointer<Render::VertexBuffer::Format>& format)
324 {
325   vertexBuffer->SetFormat(format.Release());
326 }
327
328 void RenderManager::SetVertexBufferData(Render::VertexBuffer* vertexBuffer, OwnerPointer<Vector<uint8_t>>& data, uint32_t size)
329 {
330   vertexBuffer->SetData(data.Release(), size);
331 }
332
333 void RenderManager::SetIndexBuffer(Render::Geometry* geometry, Dali::Vector<uint16_t>& indices)
334 {
335   geometry->SetIndexBuffer(indices);
336 }
337
338 void RenderManager::AddGeometry(OwnerPointer<Render::Geometry>& geometry)
339 {
340   mImpl->geometryContainer.PushBack(geometry.Release());
341 }
342
343 void RenderManager::RemoveGeometry(Render::Geometry* geometry)
344 {
345   mImpl->geometryContainer.EraseObject(geometry);
346 }
347
348 void RenderManager::AttachVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer)
349 {
350   DALI_ASSERT_DEBUG(nullptr != geometry);
351
352   // Find the geometry
353   for(auto&& iter : mImpl->geometryContainer)
354   {
355     if(iter == geometry)
356     {
357       iter->AddVertexBuffer(vertexBuffer);
358       break;
359     }
360   }
361 }
362
363 void RenderManager::RemoveVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer)
364 {
365   DALI_ASSERT_DEBUG(nullptr != geometry);
366
367   // Find the geometry
368   for(auto&& iter : mImpl->geometryContainer)
369   {
370     if(iter == geometry)
371     {
372       iter->RemoveVertexBuffer(vertexBuffer);
373       break;
374     }
375   }
376 }
377
378 void RenderManager::SetGeometryType(Render::Geometry* geometry, uint32_t geometryType)
379 {
380   geometry->SetType(Render::Geometry::Type(geometryType));
381 }
382
383 void RenderManager::AddRenderTracker(Render::RenderTracker* renderTracker)
384 {
385   mImpl->AddRenderTracker(renderTracker);
386 }
387
388 void RenderManager::RemoveRenderTracker(Render::RenderTracker* renderTracker)
389 {
390   mImpl->RemoveRenderTracker(renderTracker);
391 }
392
393 void RenderManager::PreRender(Integration::RenderStatus& status, bool forceClear, bool uploadOnly)
394 {
395   DALI_PRINT_RENDER_START(mImpl->renderBufferIndex);
396
397   // Rollback
398   mImpl->uniformBufferManager->GetUniformBufferViewPool(mImpl->renderBufferIndex)->Rollback();
399
400   // Increment the frame count at the beginning of each frame
401   ++mImpl->frameCount;
402
403   // Process messages queued during previous update
404   mImpl->renderQueue.ProcessMessages(mImpl->renderBufferIndex);
405
406   uint32_t count = 0u;
407   for(auto& i : mImpl->sceneContainer)
408   {
409     count += i->GetRenderInstructions().Count(mImpl->renderBufferIndex);
410   }
411
412   const bool haveInstructions = count > 0u;
413
414   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");
415
416   // Only render if we have instructions to render, or the last frame was rendered (and therefore a clear is required).
417   if(haveInstructions || mImpl->lastFrameWasRendered || forceClear)
418   {
419     DALI_LOG_INFO(gLogFilter, Debug::General, "Render: Processing\n");
420
421     // Upload the geometries
422     for(auto& i : mImpl->sceneContainer)
423     {
424       RenderInstructionContainer& instructions = i->GetRenderInstructions();
425       for(uint32_t j = 0; j < instructions.Count(mImpl->renderBufferIndex); ++j)
426       {
427         RenderInstruction& instruction = instructions.At(mImpl->renderBufferIndex, j);
428
429         const Matrix* viewMatrix       = instruction.GetViewMatrix(mImpl->renderBufferIndex);
430         const Matrix* projectionMatrix = instruction.GetProjectionMatrix(mImpl->renderBufferIndex);
431
432         DALI_ASSERT_DEBUG(viewMatrix);
433         DALI_ASSERT_DEBUG(projectionMatrix);
434
435         if(viewMatrix && projectionMatrix)
436         {
437           const RenderListContainer::SizeType renderListCount = instruction.RenderListCount();
438
439           // Iterate through each render list.
440           for(RenderListContainer::SizeType index = 0; index < renderListCount; ++index)
441           {
442             const RenderList* renderList = instruction.GetRenderList(index);
443
444             if(renderList && !renderList->IsEmpty())
445             {
446               const std::size_t itemCount = renderList->Count();
447               for(uint32_t itemIndex = 0u; itemIndex < itemCount; ++itemIndex)
448               {
449                 const RenderItem& item = renderList->GetItem(itemIndex);
450                 if(DALI_LIKELY(item.mRenderer))
451                 {
452                   item.mRenderer->Upload();
453                 }
454               }
455             }
456           }
457         }
458       }
459     }
460   }
461 }
462
463 void RenderManager::PreRender(Integration::Scene& scene, std::vector<Rect<int>>& damagedRects)
464 {
465   if(mImpl->partialUpdateAvailable != Integration::PartialUpdateAvailable::TRUE)
466   {
467     return;
468   }
469
470   Internal::Scene&   sceneInternal = GetImplementation(scene);
471   SceneGraph::Scene* sceneObject   = sceneInternal.GetSceneObject();
472
473   if(sceneObject->IsRenderingSkipped())
474   {
475     // We don't need to calculate dirty rects
476     return;
477   }
478
479   // @TODO We need to do partial rendering rotation.
480   if( sceneObject && sceneObject->GetSurfaceOrientation() != 0 )
481   {
482     return;
483   }
484
485   class DamagedRectsCleaner
486   {
487   public:
488     explicit DamagedRectsCleaner(std::vector<Rect<int>>& damagedRects)
489     : mDamagedRects(damagedRects),
490       mCleanOnReturn(true)
491     {
492     }
493
494     void SetCleanOnReturn(bool cleanOnReturn)
495     {
496       mCleanOnReturn = cleanOnReturn;
497     }
498
499     ~DamagedRectsCleaner()
500     {
501       if(mCleanOnReturn)
502       {
503         mDamagedRects.clear();
504       }
505     }
506
507   private:
508     std::vector<Rect<int>>& mDamagedRects;
509     bool                    mCleanOnReturn;
510   };
511
512   Rect<int32_t> surfaceRect = sceneObject->GetSurfaceRect();
513
514   // Clean collected dirty/damaged rects on exit if 3d layer or 3d node or other conditions.
515   DamagedRectsCleaner damagedRectCleaner(damagedRects);
516
517   // Mark previous dirty rects in the sorted array. The array is already sorted by node and renderer, frame number.
518   // so you don't need to sort: std::stable_sort(itemsDirtyRects.begin(), itemsDirtyRects.end());
519   std::vector<DirtyRect>& itemsDirtyRects = sceneInternal.GetItemsDirtyRects();
520   for(DirtyRect& dirtyRect : itemsDirtyRects)
521   {
522     dirtyRect.visited = false;
523   }
524
525   uint32_t instructionCount = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex);
526   for(uint32_t i = 0; i < instructionCount; ++i)
527   {
528     RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i);
529
530     if(instruction.mFrameBuffer)
531     {
532       return; // TODO: reset, we don't deal with render tasks with framebuffers (for now)
533     }
534
535     const Camera* camera = instruction.GetCamera();
536     if(camera->mType == Camera::DEFAULT_TYPE && camera->mTargetPosition == Camera::DEFAULT_TARGET_POSITION)
537     {
538       const Node* node = instruction.GetCamera()->GetNode();
539       if(node)
540       {
541         Vector3    position;
542         Vector3    scale;
543         Quaternion orientation;
544         node->GetWorldMatrix(mImpl->renderBufferIndex).GetTransformComponents(position, orientation, scale);
545
546         Vector3 orientationAxis;
547         Radian  orientationAngle;
548         orientation.ToAxisAngle(orientationAxis, orientationAngle);
549
550         if(position.x > Math::MACHINE_EPSILON_10000 ||
551            position.y > Math::MACHINE_EPSILON_10000 ||
552            orientationAxis != Vector3(0.0f, 1.0f, 0.0f) ||
553            orientationAngle != ANGLE_180 ||
554            scale != Vector3(1.0f, 1.0f, 1.0f))
555         {
556           return;
557         }
558       }
559     }
560     else
561     {
562       return;
563     }
564
565     Rect<int32_t> viewportRect;
566     if(instruction.mIsViewportSet)
567     {
568       const int32_t y = (surfaceRect.height - instruction.mViewport.height) - instruction.mViewport.y;
569       viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height);
570       if(viewportRect.IsEmpty() || !viewportRect.IsValid())
571       {
572         return; // just skip funny use cases for now, empty viewport means it is set somewhere else
573       }
574     }
575     else
576     {
577       viewportRect = surfaceRect;
578     }
579
580     const Matrix* viewMatrix       = instruction.GetViewMatrix(mImpl->renderBufferIndex);
581     const Matrix* projectionMatrix = instruction.GetProjectionMatrix(mImpl->renderBufferIndex);
582     if(viewMatrix && projectionMatrix)
583     {
584       const RenderListContainer::SizeType count = instruction.RenderListCount();
585       for(RenderListContainer::SizeType index = 0u; index < count; ++index)
586       {
587         const RenderList* renderList = instruction.GetRenderList(index);
588         if(renderList && !renderList->IsEmpty())
589         {
590           const std::size_t listCount = renderList->Count();
591           for(uint32_t listIndex = 0u; listIndex < listCount; ++listIndex)
592           {
593             RenderItem& item = renderList->GetItem(listIndex);
594             // If the item does 3D transformation, do early exit and clean the damaged rect array
595             if(item.mUpdateSize == Vector3::ZERO)
596             {
597               return;
598             }
599
600             Rect<int> rect;
601             DirtyRect dirtyRect(item.mNode, item.mRenderer, mImpl->frameCount, rect);
602             // If the item refers to updated node or renderer.
603             if(item.mIsUpdated ||
604                (item.mNode &&
605                 (item.mNode->Updated() || (item.mRenderer && item.mRenderer->Updated(mImpl->renderBufferIndex, item.mNode)))))
606             {
607               item.mIsUpdated = false;
608               item.mNode->SetUpdated(false);
609
610               rect = item.CalculateViewportSpaceAABB(item.mUpdateSize, viewportRect.width, viewportRect.height);
611               if(rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty())
612               {
613                 const int left   = rect.x;
614                 const int top    = rect.y;
615                 const int right  = rect.x + rect.width;
616                 const int bottom = rect.y + rect.height;
617                 rect.x           = (left / 16) * 16;
618                 rect.y           = (top / 16) * 16;
619                 rect.width       = ((right + 16) / 16) * 16 - rect.x;
620                 rect.height      = ((bottom + 16) / 16) * 16 - rect.y;
621
622                 // Found valid dirty rect.
623                 // 1. Insert it in the sorted array of the dirty rects.
624                 // 2. Mark the related dirty rects as visited so they will not be removed below.
625                 // 3. Keep only last 3 dirty rects for the same node and renderer (Tizen uses 3 back buffers, Ubuntu 1).
626                 dirtyRect.rect    = rect;
627                 auto dirtyRectPos = std::lower_bound(itemsDirtyRects.begin(), itemsDirtyRects.end(), dirtyRect);
628                 dirtyRectPos      = itemsDirtyRects.insert(dirtyRectPos, dirtyRect);
629
630                 int c = 1;
631                 while(++dirtyRectPos != itemsDirtyRects.end())
632                 {
633                   if(dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer)
634                   {
635                     break;
636                   }
637
638                   dirtyRectPos->visited = true;
639                   Rect<int>& dirtRect   = dirtyRectPos->rect;
640                   rect.Merge(dirtRect);
641
642                   c++;
643                   if(c > 3) // no more then 3 previous rects
644                   {
645                     itemsDirtyRects.erase(dirtyRectPos);
646                     break;
647                   }
648                 }
649
650                 damagedRects.push_back(rect);
651               }
652             }
653             else
654             {
655               // 1. The item is not dirty, the node and renderer referenced by the item are still exist.
656               // 2. Mark the related dirty rects as visited so they will not be removed below.
657               auto dirtyRectPos = std::lower_bound(itemsDirtyRects.begin(), itemsDirtyRects.end(), dirtyRect);
658               while(dirtyRectPos != itemsDirtyRects.end())
659               {
660                 if(dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer)
661                 {
662                   break;
663                 }
664
665                 dirtyRectPos->visited = true;
666                 dirtyRectPos++;
667               }
668             }
669           }
670         }
671       }
672     }
673   }
674
675   // Check removed nodes or removed renderers dirty rects
676   auto i = itemsDirtyRects.begin();
677   auto j = itemsDirtyRects.begin();
678   while(i != itemsDirtyRects.end())
679   {
680     if(i->visited)
681     {
682       *j++ = *i;
683     }
684     else
685     {
686       Rect<int>& dirtRect = i->rect;
687       damagedRects.push_back(dirtRect);
688     }
689     i++;
690   }
691
692   itemsDirtyRects.resize(j - itemsDirtyRects.begin());
693   damagedRectCleaner.SetCleanOnReturn(false);
694 }
695
696 void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo)
697 {
698   Rect<int> clippingRect;
699   RenderScene(status, scene, renderToFbo, clippingRect);
700 }
701
702 void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect<int>& clippingRect)
703 {
704   // Reset main algorithms command buffer
705   mImpl->renderAlgorithms.ResetCommandBuffer();
706
707   auto mainCommandBuffer = mImpl->renderAlgorithms.GetMainCommandBuffer();
708
709   Internal::Scene&   sceneInternal = GetImplementation(scene);
710   SceneGraph::Scene* sceneObject   = sceneInternal.GetSceneObject();
711
712   uint32_t count = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex);
713
714   std::vector<Graphics::RenderTarget*> targetstoPresent;
715
716   for(uint32_t i = 0; i < count; ++i)
717   {
718     RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i);
719
720     if((renderToFbo && !instruction.mFrameBuffer) || (!renderToFbo && instruction.mFrameBuffer))
721     {
722       continue; // skip
723     }
724
725     // Mark that we will require a post-render step to be performed (includes swap-buffers).
726     status.SetNeedsPostRender(true);
727
728     Rect<int32_t> viewportRect;
729
730     Rect<int32_t> surfaceRect        = sceneObject->GetSurfaceRect();
731     int32_t       surfaceOrientation = sceneObject->GetSurfaceOrientation();
732
733     // @todo Should these be part of scene?
734     Integration::DepthBufferAvailable   depthBufferAvailable   = mImpl->depthBufferAvailable;
735     Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable;
736
737     Graphics::RenderTarget*           currentRenderTarget = nullptr;
738     Graphics::RenderPass*             currentRenderPass   = nullptr;
739     std::vector<Graphics::ClearValue> currentClearValues{};
740
741     if(instruction.mFrameBuffer)
742     {
743       // Ensure graphics framebuffer is created, bind attachments and create render passes
744       // Only happens once per framebuffer. If the create fails, e.g. no attachments yet,
745       // then don't render to this framebuffer.
746       if(!instruction.mFrameBuffer->GetGraphicsObject())
747       {
748         const bool created = instruction.mFrameBuffer->CreateGraphicsObjects();
749         if(!created)
750         {
751           continue;
752         }
753       }
754
755       auto& clearValues = instruction.mFrameBuffer->GetGraphicsRenderPassClearValues();
756
757       // Set the clear color for first color attachment
758       if(instruction.mIsClearColorSet && !clearValues.empty())
759       {
760         clearValues[0].color = {
761           instruction.mClearColor.r,
762           instruction.mClearColor.g,
763           instruction.mClearColor.b,
764           instruction.mClearColor.a};
765       }
766
767       currentClearValues = clearValues;
768
769       auto loadOp = instruction.mIsClearColorSet ? Graphics::AttachmentLoadOp::CLEAR : Graphics::AttachmentLoadOp::LOAD;
770
771       // offscreen buffer
772       currentRenderTarget = instruction.mFrameBuffer->GetGraphicsRenderTarget();
773       currentRenderPass   = instruction.mFrameBuffer->GetGraphicsRenderPass(loadOp, Graphics::AttachmentStoreOp::STORE);
774     }
775     else // no framebuffer
776     {
777       // surface
778       auto& clearValues = sceneObject->GetGraphicsRenderPassClearValues();
779
780       if(instruction.mIsClearColorSet)
781       {
782         clearValues[0].color = {
783           instruction.mClearColor.r,
784           instruction.mClearColor.g,
785           instruction.mClearColor.b,
786           instruction.mClearColor.a};
787       }
788
789       currentClearValues = clearValues;
790
791       // @todo SceneObject should already have the depth clear / stencil clear in the clearValues array.
792       // if the window has a depth/stencil buffer.
793       if((depthBufferAvailable == Integration::DepthBufferAvailable::TRUE ||
794           stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE) &&
795          (currentClearValues.size() <= 1))
796       {
797         currentClearValues.emplace_back();
798         currentClearValues.back().depthStencil.depth   = 0;
799         currentClearValues.back().depthStencil.stencil = 0;
800       }
801
802       auto loadOp = instruction.mIsClearColorSet ? Graphics::AttachmentLoadOp::CLEAR : Graphics::AttachmentLoadOp::LOAD;
803
804       currentRenderTarget = sceneObject->GetSurfaceRenderTarget();
805       currentRenderPass   = sceneObject->GetGraphicsRenderPass(loadOp, Graphics::AttachmentStoreOp::STORE);
806     }
807
808     targetstoPresent.emplace_back(currentRenderTarget);
809
810     // reset the program matrices for all programs once per frame
811     // this ensures we will set view and projection matrix once per program per camera
812     mImpl->programController.ResetProgramMatrices();
813
814     if(instruction.mFrameBuffer)
815     {
816       // For each offscreen buffer, update the dependency list with the new texture id used by this frame buffer.
817       for(unsigned int i0 = 0, i1 = instruction.mFrameBuffer->GetColorAttachmentCount(); i0 < i1; ++i0)
818       {
819         mImpl->textureDependencyList.PushBack(instruction.mFrameBuffer->GetTexture(i0));
820       }
821     }
822
823     if(!instruction.mIgnoreRenderToFbo && (instruction.mFrameBuffer != nullptr))
824     {
825       // Offscreen buffer rendering
826       if(instruction.mIsViewportSet)
827       {
828         // For glViewport the lower-left corner is (0,0)
829         const int32_t y = (instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height) - instruction.mViewport.y;
830         viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height);
831       }
832       else
833       {
834         viewportRect.Set(0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight());
835       }
836       surfaceOrientation = 0;
837     }
838     else // No Offscreen frame buffer rendering
839     {
840       // Check whether a viewport is specified, otherwise the full surface size is used
841       if(instruction.mIsViewportSet)
842       {
843         // For glViewport the lower-left corner is (0,0)
844         const int32_t y = (surfaceRect.height - instruction.mViewport.height) - instruction.mViewport.y;
845         viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height);
846       }
847       else
848       {
849         viewportRect = surfaceRect;
850       }
851     }
852
853     // Set surface orientation
854     // @todo Inform graphics impl by another route.
855     // was: mImpl->currentContext->SetSurfaceOrientation(surfaceOrientation);
856
857     /*** Clear region of framebuffer or surface before drawing ***/
858     bool clearFullFrameRect = (surfaceRect == viewportRect);
859     if(instruction.mFrameBuffer != nullptr)
860     {
861       Viewport frameRect(0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight());
862       clearFullFrameRect = (frameRect == viewportRect);
863     }
864
865     if(!clippingRect.IsEmpty())
866     {
867       if(!clippingRect.Intersect(viewportRect))
868       {
869         DALI_LOG_ERROR("Invalid clipping rect %d %d %d %d\n", clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height);
870         clippingRect = Rect<int>();
871       }
872       clearFullFrameRect = false;
873     }
874
875     Graphics::Rect2D scissorArea{viewportRect.x, viewportRect.y, uint32_t(viewportRect.width), uint32_t(viewportRect.height)};
876     if(instruction.mIsClearColorSet)
877     {
878       if(!clearFullFrameRect)
879       {
880         if(!clippingRect.IsEmpty())
881         {
882           scissorArea = {clippingRect.x, clippingRect.y, uint32_t(clippingRect.width), uint32_t(clippingRect.height)};
883         }
884       }
885     }
886
887     // Begin render pass
888     mainCommandBuffer->BeginRenderPass(
889       currentRenderPass,
890       currentRenderTarget,
891       scissorArea,
892       currentClearValues);
893
894     mainCommandBuffer->SetViewport({float(viewportRect.x),
895                                     float(viewportRect.y),
896                                     float(viewportRect.width),
897                                     float(viewportRect.height)});
898
899     // Clear the list of bound textures
900     mImpl->boundTextures.Clear();
901
902     mImpl->renderAlgorithms.ProcessRenderInstruction(
903       instruction,
904       mImpl->renderBufferIndex,
905       depthBufferAvailable,
906       stencilBufferAvailable,
907       mImpl->boundTextures,
908       viewportRect,
909       clippingRect,
910       surfaceOrientation);
911
912     // Synchronise the FBO/Texture access
913
914     // Check whether any bound texture is in the dependency list
915     bool textureFound = false;
916
917     if(mImpl->boundTextures.Count() > 0u && mImpl->textureDependencyList.Count() > 0u)
918     {
919       for(auto texture : mImpl->textureDependencyList)
920       {
921         textureFound = std::find_if(mImpl->boundTextures.Begin(), mImpl->boundTextures.End(), [texture](Graphics::Texture* graphicsTexture) {
922                          return texture == graphicsTexture;
923                        }) != mImpl->boundTextures.End();
924       }
925     }
926
927     if(textureFound)
928     {
929       if(instruction.mFrameBuffer)
930       {
931         // For off-screen buffer
932
933         // Clear the dependency list
934         mImpl->textureDependencyList.Clear();
935       }
936       else
937       {
938         // Worker thread lambda function
939         auto& glContextHelperAbstraction = mImpl->graphicsController.GetGlContextHelperAbstraction();
940         auto  workerFunction             = [&glContextHelperAbstraction](int workerThread) {
941           // Switch to the shared context in the worker thread
942           glContextHelperAbstraction.MakeSurfacelessContextCurrent();
943
944           // Wait until all rendering calls for the shared context are executed
945           glContextHelperAbstraction.WaitClient();
946
947           // Must clear the context in the worker thread
948           // Otherwise the shared context cannot be switched to from the render thread
949           glContextHelperAbstraction.MakeContextNull();
950         };
951
952         auto future = mImpl->threadPool->SubmitTask(0u, workerFunction);
953         if(future)
954         {
955           mImpl->threadPool->Wait();
956
957           // Clear the dependency list
958           mImpl->textureDependencyList.Clear();
959         }
960       }
961     }
962
963     Graphics::SyncObject* syncObject{nullptr};
964     // If the render instruction has an associated render tracker (owned separately)
965     // and framebuffer, create a one shot sync object, and use it to determine when
966     // the render pass has finished executing on GPU.
967     if(instruction.mRenderTracker && instruction.mFrameBuffer)
968     {
969       syncObject                 = instruction.mRenderTracker->CreateSyncObject(mImpl->graphicsController);
970       instruction.mRenderTracker = nullptr;
971     }
972     mainCommandBuffer->EndRenderPass(syncObject);
973   }
974   mImpl->renderAlgorithms.SubmitCommandBuffer();
975
976   std::sort(targetstoPresent.begin(), targetstoPresent.end());
977
978   Graphics::RenderTarget* rt = nullptr;
979   for(auto& target : targetstoPresent)
980   {
981     if(target != rt)
982     {
983       mImpl->graphicsController.PresentRenderTarget(target);
984       rt = target;
985     }
986   }
987 }
988
989 void RenderManager::PostRender(bool uploadOnly)
990 {
991   // Notify RenderGeometries that rendering has finished
992   for(auto&& iter : mImpl->geometryContainer)
993   {
994     iter->OnRenderFinished();
995   }
996
997   mImpl->UpdateTrackers();
998
999   uint32_t count = 0u;
1000   for(auto& scene : mImpl->sceneContainer)
1001   {
1002     count += scene->GetRenderInstructions().Count(mImpl->renderBufferIndex);
1003   }
1004
1005   const bool haveInstructions = count > 0u;
1006
1007   // If this frame was rendered due to instructions existing, we mark this so we know to clear the next frame.
1008   mImpl->lastFrameWasRendered = haveInstructions;
1009
1010   /**
1011    * The rendering has finished; swap to the next buffer.
1012    * Ideally the update has just finished using this buffer; otherwise the render thread
1013    * should block until the update has finished.
1014    */
1015   mImpl->renderBufferIndex = (0 != mImpl->renderBufferIndex) ? 0 : 1;
1016
1017   DALI_PRINT_RENDER_END();
1018 }
1019
1020 } // namespace SceneGraph
1021
1022 } // namespace Internal
1023
1024 } // namespace Dali